From 1eb0450e1d9eacbadcce0046847fd4c2a488a0f4 Mon Sep 17 00:00:00 2001 From: Stewart Ritchie Date: Fri, 2 Oct 2015 16:24:03 +0100 Subject: [PATCH] added dependencies to vendor dir, because WordPress is stupid --- .gitignore | 4 +- vendor/autoload.php | 7 + vendor/bin/slack | 1 + vendor/composer/ClassLoader.php | 413 ++ vendor/composer/LICENSE | 21 + vendor/composer/autoload_classmap.php | 9 + vendor/composer/autoload_namespaces.php | 12 + vendor/composer/autoload_psr4.php | 12 + vendor/composer/autoload_real.php | 50 + vendor/composer/installed.json | 329 ++ vendor/guzzle/guzzle/.gitignore | 27 + vendor/guzzle/guzzle/.travis.yml | 17 + vendor/guzzle/guzzle/CHANGELOG.md | 751 ++++ vendor/guzzle/guzzle/LICENSE | 19 + vendor/guzzle/guzzle/README.md | 57 + vendor/guzzle/guzzle/UPGRADING.md | 537 +++ vendor/guzzle/guzzle/build.xml | 45 + vendor/guzzle/guzzle/composer.json | 82 + vendor/guzzle/guzzle/docs/Makefile | 153 + .../docs/_downloads/guzzle-schema-1.0.json | 176 + .../guzzle/docs/_static/guzzle-icon.png | Bin 0 -> 803 bytes .../guzzle/guzzle/docs/_static/homepage.css | 122 + vendor/guzzle/guzzle/docs/_static/logo.png | Bin 0 -> 247678 bytes .../guzzle/guzzle/docs/_static/prettify.css | 41 + vendor/guzzle/guzzle/docs/_static/prettify.js | 28 + .../guzzle/guzzle/docs/_templates/index.html | 106 + .../guzzle/docs/_templates/leftbar.html | 0 .../guzzle/docs/_templates/nav_links.html | 5 + .../guzzle/guzzle/docs/batching/batching.rst | 183 + vendor/guzzle/guzzle/docs/conf.py | 94 + vendor/guzzle/guzzle/docs/docs.rst | 73 + .../guzzle/docs/getting-started/faq.rst | 29 + .../docs/getting-started/installation.rst | 154 + .../guzzle/docs/getting-started/overview.rst | 85 + .../guzzle/guzzle/docs/http-client/client.rst | 569 +++ .../guzzle/docs/http-client/entity-bodies.rst | 151 + .../docs/http-client/http-redirects.rst | 99 + .../guzzle/docs/http-client/request.rst | 667 +++ .../guzzle/docs/http-client/response.rst | 141 + .../guzzle/docs/http-client/uri-templates.rst | 52 + vendor/guzzle/guzzle/docs/index.rst | 5 + .../docs/iterators/guzzle-iterators.rst | 97 + .../docs/iterators/resource-iterators.rst | 149 + .../guzzle/docs/plugins/async-plugin.rst | 18 + .../guzzle/docs/plugins/backoff-plugin.rst | 22 + .../guzzle/docs/plugins/cache-plugin.rst | 169 + .../guzzle/docs/plugins/cookie-plugin.rst | 33 + .../guzzle/docs/plugins/creating-plugins.rst | 93 + .../guzzle/docs/plugins/curl-auth-plugin.rst | 32 + .../guzzle/docs/plugins/history-plugin.rst | 24 + .../guzzle/guzzle/docs/plugins/log-plugin.rst | 69 + .../docs/plugins/md5-validator-plugin.rst | 29 + .../guzzle/docs/plugins/mock-plugin.rst | 27 + .../guzzle/docs/plugins/oauth-plugin.rst | 30 + .../guzzle/docs/plugins/plugins-list.rst.inc | 9 + .../guzzle/docs/plugins/plugins-overview.rst | 59 + vendor/guzzle/guzzle/docs/requirements.txt | 2 + .../guzzle/docs/testing/unit-testing.rst | 201 + .../guzzle-service-descriptions.rst | 619 +++ .../using-the-service-builder.rst | 316 ++ .../webservice-client/webservice-client.rst | 659 +++ vendor/guzzle/guzzle/phar-stub.php | 16 + .../guzzle/guzzle/phing/build.properties.dist | 16 + .../guzzle/phing/imports/dependencies.xml | 33 + vendor/guzzle/guzzle/phing/imports/deploy.xml | 142 + .../guzzle/phing/tasks/ComposerLintTask.php | 152 + .../phing/tasks/GuzzlePearPharPackageTask.php | 338 ++ .../guzzle/phing/tasks/GuzzleSubSplitTask.php | 385 ++ vendor/guzzle/guzzle/phpunit.xml.dist | 48 + .../Guzzle/Batch/AbstractBatchDecorator.php | 66 + .../guzzle/guzzle/src/Guzzle/Batch/Batch.php | 92 + .../guzzle/src/Guzzle/Batch/BatchBuilder.php | 199 + .../src/Guzzle/Batch/BatchClosureDivisor.php | 39 + .../src/Guzzle/Batch/BatchClosureTransfer.php | 40 + .../src/Guzzle/Batch/BatchCommandTransfer.php | 75 + .../Guzzle/Batch/BatchDivisorInterface.php | 18 + .../src/Guzzle/Batch/BatchInterface.php | 32 + .../src/Guzzle/Batch/BatchRequestTransfer.php | 65 + .../src/Guzzle/Batch/BatchSizeDivisor.php | 47 + .../Guzzle/Batch/BatchTransferInterface.php | 16 + .../Exception/BatchTransferException.php | 90 + .../Guzzle/Batch/ExceptionBufferingBatch.php | 50 + .../guzzle/src/Guzzle/Batch/FlushingBatch.php | 60 + .../guzzle/src/Guzzle/Batch/HistoryBatch.php | 39 + .../src/Guzzle/Batch/NotifyingBatch.php | 38 + .../guzzle/src/Guzzle/Batch/composer.json | 31 + .../src/Guzzle/Cache/AbstractCacheAdapter.php | 21 + .../src/Guzzle/Cache/CacheAdapterFactory.php | 117 + .../Guzzle/Cache/CacheAdapterInterface.php | 55 + .../src/Guzzle/Cache/ClosureCacheAdapter.php | 57 + .../src/Guzzle/Cache/DoctrineCacheAdapter.php | 41 + .../src/Guzzle/Cache/NullCacheAdapter.php | 31 + .../src/Guzzle/Cache/Zf1CacheAdapter.php | 44 + .../src/Guzzle/Cache/Zf2CacheAdapter.php | 41 + .../guzzle/src/Guzzle/Cache/composer.json | 27 + .../Guzzle/Common/AbstractHasDispatcher.php | 49 + .../guzzle/src/Guzzle/Common/Collection.php | 403 ++ .../guzzle/guzzle/src/Guzzle/Common/Event.php | 52 + .../Exception/BadMethodCallException.php | 5 + .../Common/Exception/ExceptionCollection.php | 108 + .../Common/Exception/GuzzleException.php | 8 + .../Exception/InvalidArgumentException.php | 5 + .../Common/Exception/RuntimeException.php | 5 + .../Exception/UnexpectedValueException.php | 5 + .../src/Guzzle/Common/FromConfigInterface.php | 18 + .../Guzzle/Common/HasDispatcherInterface.php | 54 + .../src/Guzzle/Common/ToArrayInterface.php | 16 + .../guzzle/src/Guzzle/Common/Version.php | 29 + .../guzzle/src/Guzzle/Common/composer.json | 20 + .../Http/AbstractEntityBodyDecorator.php | 221 + .../src/Guzzle/Http/CachingEntityBody.php | 229 + .../guzzle/guzzle/src/Guzzle/Http/Client.php | 524 +++ .../src/Guzzle/Http/ClientInterface.php | 223 + .../src/Guzzle/Http/Curl/CurlHandle.php | 464 ++ .../guzzle/src/Guzzle/Http/Curl/CurlMulti.php | 423 ++ .../Guzzle/Http/Curl/CurlMultiInterface.php | 58 + .../src/Guzzle/Http/Curl/CurlMultiProxy.php | 150 + .../src/Guzzle/Http/Curl/CurlVersion.php | 66 + .../src/Guzzle/Http/Curl/RequestMediator.php | 147 + .../guzzle/src/Guzzle/Http/EntityBody.php | 201 + .../src/Guzzle/Http/EntityBodyInterface.php | 73 + .../Http/Exception/BadResponseException.php | 69 + .../ClientErrorResponseException.php | 8 + .../CouldNotRewindStreamException.php | 7 + .../Guzzle/Http/Exception/CurlException.php | 101 + .../Guzzle/Http/Exception/HttpException.php | 10 + .../Http/Exception/MultiTransferException.php | 145 + .../Http/Exception/RequestException.php | 39 + .../ServerErrorResponseException.php | 8 + .../Exception/TooManyRedirectsException.php | 5 + .../src/Guzzle/Http/IoEmittingEntityBody.php | 83 + .../Guzzle/Http/Message/AbstractMessage.php | 220 + .../Http/Message/EntityEnclosingRequest.php | 247 ++ .../EntityEnclosingRequestInterface.php | 137 + .../guzzle/src/Guzzle/Http/Message/Header.php | 182 + .../Http/Message/Header/CacheControl.php | 121 + .../Http/Message/Header/HeaderCollection.php | 108 + .../Http/Message/Header/HeaderFactory.php | 26 + .../Message/Header/HeaderFactoryInterface.php | 19 + .../Http/Message/Header/HeaderInterface.php | 83 + .../src/Guzzle/Http/Message/Header/Link.php | 93 + .../Guzzle/Http/Message/MessageInterface.php | 102 + .../src/Guzzle/Http/Message/PostFile.php | 124 + .../Guzzle/Http/Message/PostFileInterface.php | 83 + .../src/Guzzle/Http/Message/Request.php | 638 +++ .../Guzzle/Http/Message/RequestFactory.php | 359 ++ .../Http/Message/RequestFactoryInterface.php | 105 + .../Guzzle/Http/Message/RequestInterface.php | 318 ++ .../src/Guzzle/Http/Message/Response.php | 968 +++++ .../guzzle/src/Guzzle/Http/Mimetypes.php | 962 ++++ .../Http/QueryAggregator/CommaAggregator.php | 20 + .../QueryAggregator/DuplicateAggregator.php | 22 + .../Http/QueryAggregator/PhpAggregator.php | 27 + .../QueryAggregatorInterface.php | 22 + .../guzzle/src/Guzzle/Http/QueryString.php | 297 ++ .../src/Guzzle/Http/ReadLimitEntityBody.php | 122 + .../guzzle/src/Guzzle/Http/RedirectPlugin.php | 250 ++ .../src/Guzzle/Http/Resources/cacert.pem | 3870 +++++++++++++++++ .../guzzle/src/Guzzle/Http/StaticClient.php | 157 + vendor/guzzle/guzzle/src/Guzzle/Http/Url.php | 554 +++ .../guzzle/src/Guzzle/Http/composer.json | 32 + .../src/Guzzle/Inflection/Inflector.php | 38 + .../Guzzle/Inflection/InflectorInterface.php | 27 + .../Guzzle/Inflection/MemoizingInflector.php | 70 + .../Inflection/PreComputedInflector.php | 59 + .../src/Guzzle/Inflection/composer.json | 26 + .../src/Guzzle/Iterator/AppendIterator.php | 19 + .../src/Guzzle/Iterator/ChunkedIterator.php | 56 + .../src/Guzzle/Iterator/FilterIterator.php | 36 + .../src/Guzzle/Iterator/MapIterator.php | 34 + .../Guzzle/Iterator/MethodProxyIterator.php | 27 + .../guzzle/src/Guzzle/Iterator/README.md | 25 + .../guzzle/src/Guzzle/Iterator/composer.json | 27 + .../src/Guzzle/Log/AbstractLogAdapter.php | 16 + .../guzzle/src/Guzzle/Log/ArrayLogAdapter.php | 34 + .../src/Guzzle/Log/ClosureLogAdapter.php | 23 + .../src/Guzzle/Log/LogAdapterInterface.php | 18 + .../src/Guzzle/Log/MessageFormatter.php | 179 + .../src/Guzzle/Log/MonologLogAdapter.php | 34 + .../guzzle/src/Guzzle/Log/PsrLogAdapter.php | 36 + .../guzzle/src/Guzzle/Log/Zf1LogAdapter.php | 24 + .../guzzle/src/Guzzle/Log/Zf2LogAdapter.php | 21 + .../guzzle/src/Guzzle/Log/composer.json | 29 + .../src/Guzzle/Parser/Cookie/CookieParser.php | 131 + .../Parser/Cookie/CookieParserInterface.php | 33 + .../Parser/Message/AbstractMessageParser.php | 58 + .../Guzzle/Parser/Message/MessageParser.php | 110 + .../Parser/Message/MessageParserInterface.php | 27 + .../Parser/Message/PeclHttpMessageParser.php | 48 + .../src/Guzzle/Parser/ParserRegistry.php | 75 + .../Parser/UriTemplate/PeclUriTemplate.php | 26 + .../Guzzle/Parser/UriTemplate/UriTemplate.php | 254 ++ .../UriTemplate/UriTemplateInterface.php | 21 + .../src/Guzzle/Parser/Url/UrlParser.php | 48 + .../Guzzle/Parser/Url/UrlParserInterface.php | 19 + .../guzzle/src/Guzzle/Parser/composer.json | 19 + .../src/Guzzle/Plugin/Async/AsyncPlugin.php | 84 + .../src/Guzzle/Plugin/Async/composer.json | 27 + .../Backoff/AbstractBackoffStrategy.php | 91 + .../AbstractErrorCodeBackoffStrategy.php | 40 + .../Guzzle/Plugin/Backoff/BackoffLogger.php | 76 + .../Guzzle/Plugin/Backoff/BackoffPlugin.php | 126 + .../Backoff/BackoffStrategyInterface.php | 30 + .../Backoff/CallbackBackoffStrategy.php | 47 + .../Backoff/ConstantBackoffStrategy.php | 34 + .../Plugin/Backoff/CurlBackoffStrategy.php | 28 + .../Backoff/ExponentialBackoffStrategy.php | 25 + .../Plugin/Backoff/HttpBackoffStrategy.php | 30 + .../Plugin/Backoff/LinearBackoffStrategy.php | 36 + .../Backoff/ReasonPhraseBackoffStrategy.php | 25 + .../Backoff/TruncatedBackoffStrategy.php | 36 + .../src/Guzzle/Plugin/Backoff/composer.json | 28 + .../Cache/CacheKeyProviderInterface.php | 11 + .../src/Guzzle/Plugin/Cache/CachePlugin.php | 353 ++ .../Plugin/Cache/CacheStorageInterface.php | 43 + .../Plugin/Cache/CallbackCanCacheStrategy.php | 53 + .../Cache/CanCacheStrategyInterface.php | 30 + .../Plugin/Cache/DefaultCacheKeyProvider.php | 46 + .../Plugin/Cache/DefaultCacheStorage.php | 266 ++ .../Plugin/Cache/DefaultCanCacheStrategy.php | 32 + .../Plugin/Cache/DefaultRevalidation.php | 174 + .../Guzzle/Plugin/Cache/DenyRevalidation.php | 19 + .../Plugin/Cache/RevalidationInterface.php | 32 + .../Guzzle/Plugin/Cache/SkipRevalidation.php | 19 + .../src/Guzzle/Plugin/Cache/composer.json | 28 + .../src/Guzzle/Plugin/Cookie/Cookie.php | 538 +++ .../Cookie/CookieJar/ArrayCookieJar.php | 237 + .../Cookie/CookieJar/CookieJarInterface.php | 85 + .../Plugin/Cookie/CookieJar/FileCookieJar.php | 65 + .../src/Guzzle/Plugin/Cookie/CookiePlugin.php | 70 + .../Exception/InvalidCookieException.php | 7 + .../src/Guzzle/Plugin/Cookie/composer.json | 27 + .../Guzzle/Plugin/CurlAuth/CurlAuthPlugin.php | 46 + .../src/Guzzle/Plugin/CurlAuth/composer.json | 27 + .../ErrorResponseExceptionInterface.php | 22 + .../ErrorResponse/ErrorResponsePlugin.php | 72 + .../Exception/ErrorResponseException.php | 7 + .../Guzzle/Plugin/ErrorResponse/composer.json | 27 + .../Guzzle/Plugin/History/HistoryPlugin.php | 163 + .../src/Guzzle/Plugin/History/composer.json | 27 + .../src/Guzzle/Plugin/Log/LogPlugin.php | 161 + .../src/Guzzle/Plugin/Log/composer.json | 28 + .../Plugin/Md5/CommandContentMd5Plugin.php | 57 + .../Guzzle/Plugin/Md5/Md5ValidatorPlugin.php | 88 + .../src/Guzzle/Plugin/Md5/composer.json | 27 + .../src/Guzzle/Plugin/Mock/MockPlugin.php | 245 ++ .../src/Guzzle/Plugin/Mock/composer.json | 27 + .../src/Guzzle/Plugin/Oauth/OauthPlugin.php | 306 ++ .../src/Guzzle/Plugin/Oauth/composer.json | 27 + .../guzzle/src/Guzzle/Plugin/composer.json | 44 + .../Guzzle/Service/AbstractConfigLoader.php | 177 + .../Guzzle/Service/Builder/ServiceBuilder.php | 189 + .../Builder/ServiceBuilderInterface.php | 40 + .../Service/Builder/ServiceBuilderLoader.php | 89 + .../Guzzle/Service/CachingConfigLoader.php | 46 + .../guzzle/src/Guzzle/Service/Client.php | 297 ++ .../src/Guzzle/Service/ClientInterface.php | 68 + .../Service/Command/AbstractCommand.php | 390 ++ .../Guzzle/Service/Command/ClosureCommand.php | 41 + .../Service/Command/CommandInterface.php | 128 + .../Command/CreateResponseClassEvent.php | 32 + .../Command/DefaultRequestSerializer.php | 169 + .../Service/Command/DefaultResponseParser.php | 55 + .../Service/Command/Factory/AliasFactory.php | 39 + .../Command/Factory/CompositeFactory.php | 154 + .../Command/Factory/ConcreteClassFactory.php | 47 + .../Command/Factory/FactoryInterface.php | 21 + .../Service/Command/Factory/MapFactory.php | 27 + .../Factory/ServiceDescriptionFactory.php | 71 + .../Request/AbstractRequestVisitor.php | 69 + .../LocationVisitor/Request/BodyVisitor.php | 58 + .../LocationVisitor/Request/HeaderVisitor.php | 44 + .../LocationVisitor/Request/JsonVisitor.php | 63 + .../Request/PostFieldVisitor.php | 18 + .../Request/PostFileVisitor.php | 24 + .../LocationVisitor/Request/QueryVisitor.php | 18 + .../Request/RequestVisitorInterface.php | 31 + .../Request/ResponseBodyVisitor.php | 18 + .../LocationVisitor/Request/XmlVisitor.php | 252 ++ .../Response/AbstractResponseVisitor.php | 26 + .../LocationVisitor/Response/BodyVisitor.php | 23 + .../Response/HeaderVisitor.php | 50 + .../LocationVisitor/Response/JsonVisitor.php | 93 + .../Response/ReasonPhraseVisitor.php | 23 + .../Response/ResponseVisitorInterface.php | 46 + .../Response/StatusCodeVisitor.php | 23 + .../LocationVisitor/Response/XmlVisitor.php | 151 + .../LocationVisitor/VisitorFlyweight.php | 138 + .../Service/Command/OperationCommand.php | 89 + .../Command/OperationResponseParser.php | 195 + .../Command/RequestSerializerInterface.php | 21 + .../Command/ResponseClassInterface.php | 18 + .../Command/ResponseParserInterface.php | 18 + .../Guzzle/Service/ConfigLoaderInterface.php | 22 + .../Guzzle/Service/Description/Operation.php | 547 +++ .../Description/OperationInterface.php | 159 + .../Guzzle/Service/Description/Parameter.php | 925 ++++ .../Service/Description/SchemaFormatter.php | 156 + .../Service/Description/SchemaValidator.php | 291 ++ .../Description/ServiceDescription.php | 271 ++ .../ServiceDescriptionInterface.php | 106 + .../Description/ServiceDescriptionLoader.php | 64 + .../Description/ValidatorInterface.php | 28 + .../Service/Exception/CommandException.php | 7 + .../Exception/CommandTransferException.php | 119 + .../Exception/DescriptionBuilderException.php | 7 + .../InconsistentClientTransferException.php | 38 + .../Exception/ResponseClassException.php | 9 + .../Exception/ServiceBuilderException.php | 7 + .../Exception/ServiceNotFoundException.php | 5 + .../Service/Exception/ValidationException.php | 30 + .../AbstractResourceIteratorFactory.php | 37 + .../CompositeResourceIteratorFactory.php | 67 + .../Resource/MapResourceIteratorFactory.php | 34 + .../src/Guzzle/Service/Resource/Model.php | 64 + .../Service/Resource/ResourceIterator.php | 254 ++ .../Resource/ResourceIteratorApplyBatched.php | 111 + .../Resource/ResourceIteratorClassFactory.php | 60 + .../ResourceIteratorFactoryInterface.php | 30 + .../Resource/ResourceIteratorInterface.php | 61 + .../guzzle/src/Guzzle/Service/composer.json | 29 + .../Guzzle/Stream/PhpStreamRequestFactory.php | 284 ++ .../guzzle/src/Guzzle/Stream/Stream.php | 289 ++ .../src/Guzzle/Stream/StreamInterface.php | 218 + .../Stream/StreamRequestFactoryInterface.php | 24 + .../guzzle/src/Guzzle/Stream/composer.json | 30 + .../Batch/AbstractBatchDecoratorTest.php | 33 + .../Guzzle/Tests/Batch/BatchBuilderTest.php | 86 + .../Tests/Batch/BatchClosureDivisorTest.php | 36 + .../Tests/Batch/BatchClosureTransferTest.php | 52 + .../Tests/Batch/BatchCommandTransferTest.php | 83 + .../Tests/Batch/BatchRequestTransferTest.php | 80 + .../Tests/Batch/BatchSizeDivisorTest.php | 24 + .../tests/Guzzle/Tests/Batch/BatchTest.php | 91 + .../Batch/ExceptionBufferingBatchTest.php | 45 + .../Guzzle/Tests/Batch/FlushingBatchTest.php | 40 + .../Guzzle/Tests/Batch/HistoryBatchTest.php | 26 + .../Guzzle/Tests/Batch/NotifyingBatchTest.php | 45 + .../Tests/Cache/CacheAdapterFactoryTest.php | 64 + .../Guzzle/Tests/Cache/CacheAdapterTest.php | 68 + .../Tests/Cache/ClosureCacheAdapterTest.php | 94 + .../Tests/Cache/NullCacheAdapterTest.php | 20 + .../Tests/Cache/Zf2CacheAdapterTest.php | 58 + .../Common/AbstractHasDispatcherTest.php | 63 + .../Guzzle/Tests/Common/CollectionTest.php | 529 +++ .../tests/Guzzle/Tests/Common/EventTest.php | 62 + .../Exception/BatchTransferExceptionTest.php | 21 + .../Exception/ExceptionCollectionTest.php | 66 + .../tests/Guzzle/Tests/Common/VersionTest.php | 27 + .../tests/Guzzle/Tests/GuzzleTestCase.php | 235 + .../Http/AbstractEntityBodyDecoratorTest.php | 34 + .../Tests/Http/CachingEntityBodyTest.php | 249 ++ .../tests/Guzzle/Tests/Http/ClientTest.php | 601 +++ .../Guzzle/Tests/Http/Curl/CurlHandleTest.php | 947 ++++ .../Tests/Http/Curl/CurlMultiProxyTest.php | 110 + .../Guzzle/Tests/Http/Curl/CurlMultiTest.php | 455 ++ .../Tests/Http/Curl/CurlVersionTest.php | 39 + .../Tests/Http/Curl/RequestMediatorTest.php | 67 + .../Guzzle/Tests/Http/EntityBodyTest.php | 182 + .../Http/Exception/CurlExceptionTest.php | 27 + .../Tests/Http/Exception/ExceptionTest.php | 66 + .../Exception/MultiTransferExceptionTest.php | 51 + .../Tests/Http/IoEmittingEntityBodyTest.php | 47 + .../Http/Message/AbstractMessageTest.php | 136 + .../Message/EntityEnclosingRequestTest.php | 434 ++ .../Http/Message/Header/HeaderFactoryTest.php | 29 + .../Tests/Http/Message/Header/LinkTest.php | 63 + .../Tests/Http/Message/HeaderComparison.php | 135 + .../Http/Message/HeaderComparisonTest.php | 115 + .../Guzzle/Tests/Http/Message/HeaderTest.php | 162 + .../Tests/Http/Message/PostFileTest.php | 88 + .../Tests/Http/Message/RequestFactoryTest.php | 616 +++ .../Guzzle/Tests/Http/Message/RequestTest.php | 639 +++ .../Tests/Http/Message/ResponseTest.php | 677 +++ .../tests/Guzzle/Tests/Http/MimetypesTest.php | 31 + .../QueryAggregator/CommaAggregatorTest.php | 30 + .../DuplicateAggregatorTest.php | 30 + .../QueryAggregator/PhpAggregatorTest.php | 32 + .../Guzzle/Tests/Http/QueryStringTest.php | 233 + .../Tests/Http/ReadLimitEntityBodyTest.php | 81 + .../Guzzle/Tests/Http/RedirectPluginTest.php | 277 ++ .../guzzle/tests/Guzzle/Tests/Http/Server.php | 191 + .../Guzzle/Tests/Http/StaticClientTest.php | 67 + .../tests/Guzzle/Tests/Http/UrlTest.php | 303 ++ .../guzzle/tests/Guzzle/Tests/Http/server.js | 146 + .../Guzzle/Tests/Inflection/InflectorTest.php | 37 + .../Inflection/MemoizingInflectorTest.php | 46 + .../Inflection/PreComputedInflectorTest.php | 45 + .../Tests/Iterator/AppendIteratorTest.php | 29 + .../Tests/Iterator/ChunkedIteratorTest.php | 52 + .../Tests/Iterator/FilterIteratorTest.php | 28 + .../Guzzle/Tests/Iterator/MapIteratorTest.php | 28 + .../Iterator/MethodProxyIteratorTest.php | 28 + .../Guzzle/Tests/Log/ArrayLogAdapterTest.php | 23 + .../Tests/Log/ClosureLogAdapterTest.php | 30 + .../Guzzle/Tests/Log/MessageFormatterTest.php | 143 + .../Guzzle/Tests/Log/PsrLogAdapterTest.php | 25 + .../Guzzle/Tests/Log/Zf2LogAdapterTest.php | 51 + .../Guzzle/Tests/Mock/CustomResponseModel.php | 21 + .../Guzzle/Tests/Mock/ErrorResponseMock.php | 25 + .../tests/Guzzle/Tests/Mock/ExceptionMock.php | 11 + .../tests/Guzzle/Tests/Mock/MockMulti.php | 11 + .../tests/Guzzle/Tests/Mock/MockObserver.php | 65 + .../tests/Guzzle/Tests/Mock/MockSubject.php | 7 + .../Parser/Cookie/CookieParserProvider.php | 381 ++ .../Tests/Parser/Cookie/CookieParserTest.php | 22 + .../Parser/Message/MessageParserProvider.php | 225 + .../Parser/Message/MessageParserTest.php | 58 + .../Message/PeclHttpMessageParserTest.php | 36 + .../Tests/Parser/ParserRegistryTest.php | 33 + .../UriTemplate/AbstractUriTemplateTest.php | 113 + .../UriTemplate/PeclUriTemplateTest.php | 27 + .../Parser/UriTemplate/UriTemplateTest.php | 106 + .../Tests/Plugin/Async/AsyncPluginTest.php | 93 + .../Backoff/AbstractBackoffStrategyTest.php | 86 + .../Plugin/Backoff/BackoffLoggerTest.php | 110 + .../Plugin/Backoff/BackoffPluginTest.php | 297 ++ .../Backoff/CallbackBackoffStrategyTest.php | 31 + .../Backoff/ConstantBackoffStrategyTest.php | 20 + .../Backoff/CurlBackoffStrategyTest.php | 36 + .../ExponentialBackoffStrategyTest.php | 23 + .../Backoff/HttpBackoffStrategyTest.php | 47 + .../Backoff/LinearBackoffStrategyTest.php | 21 + .../ReasonPhraseBackoffStrategyTest.php | 32 + .../Backoff/TruncatedBackoffStrategyTest.php | 30 + .../Tests/Plugin/Cache/CachePluginTest.php | 441 ++ .../Cache/CallbackCanCacheStrategyTest.php | 72 + .../Plugin/Cache/DefaultCacheStorageTest.php | 193 + .../Cache/DefaultCanCacheStrategyTest.php | 40 + .../Plugin/Cache/DefaultRevalidationTest.php | 248 ++ .../Plugin/Cache/DenyRevalidationTest.php | 19 + .../Plugin/Cache/SkipRevalidationTest.php | 19 + .../Cookie/CookieJar/ArrayCookieJarTest.php | 385 ++ .../Cookie/CookieJar/FileCookieJarTest.php | 63 + .../Tests/Plugin/Cookie/CookiePluginTest.php | 134 + .../Guzzle/Tests/Plugin/Cookie/CookieTest.php | 223 + .../Plugin/CurlAuth/CurlAuthPluginTest.php | 39 + .../ErrorResponse/ErrorResponsePluginTest.php | 137 + .../Plugin/History/HistoryPluginTest.php | 140 + .../Guzzle/Tests/Plugin/Log/LogPluginTest.php | 95 + .../Md5/CommandContentMd5PluginTest.php | 97 + .../Plugin/Md5/Md5ValidatorPluginTest.php | 120 + .../Tests/Plugin/Mock/MockPluginTest.php | 199 + .../Tests/Plugin/Oauth/OauthPluginTest.php | 345 ++ .../Service/AbstractConfigLoaderTest.php | 149 + .../Builder/ServiceBuilderLoaderTest.php | 177 + .../Service/Builder/ServiceBuilderTest.php | 317 ++ .../Tests/Service/CachingConfigLoaderTest.php | 43 + .../tests/Guzzle/Tests/Service/ClientTest.php | 320 ++ .../Service/Command/AbstractCommandTest.php | 16 + .../Service/Command/ClosureCommandTest.php | 54 + .../Tests/Service/Command/CommandTest.php | 445 ++ .../Command/DefaultRequestSerializerTest.php | 122 + .../Command/DefaultResponseParserTest.php | 59 + .../Command/Factory/AliasFactoryTest.php | 76 + .../Command/Factory/CompositeFactoryTest.php | 124 + .../Factory/ConcreteClassFactoryTest.php | 49 + .../Command/Factory/MapFactoryTest.php | 37 + .../Factory/ServiceDescriptionFactoryTest.php | 68 + .../Request/AbstractVisitorTestCase.php | 110 + .../Request/BodyVisitorTest.php | 63 + .../Request/HeaderVisitorTest.php | 48 + .../Request/JsonVisitorTest.php | 60 + .../Request/PostFieldVisitorTest.php | 33 + .../Request/PostFileVisitorTest.php | 54 + .../Request/QueryVisitorTest.php | 48 + .../Request/ResponseBodyVisitorTest.php | 20 + .../Request/XmlVisitorTest.php | 558 +++ .../Response/AbstractResponseVisitorTest.php | 29 + .../Response/BodyVisitorTest.php | 21 + .../Response/HeaderVisitorTest.php | 98 + .../Response/JsonVisitorTest.php | 157 + .../Response/ReasonPhraseVisitorTest.php | 21 + .../Response/StatusCodeVisitorTest.php | 21 + .../Response/XmlVisitorTest.php | 431 ++ .../LocationVisitor/VisitorFlyweightTest.php | 53 + .../Service/Command/OperationCommandTest.php | 102 + .../Command/OperationResponseParserTest.php | 335 ++ .../Service/Description/OperationTest.php | 308 ++ .../Service/Description/ParameterTest.php | 411 ++ .../Description/SchemaFormatterTest.php | 61 + .../Description/SchemaValidatorTest.php | 326 ++ .../ServiceDescriptionLoaderTest.php | 177 + .../Description/ServiceDescriptionTest.php | 240 + .../CommandTransferExceptionTest.php | 66 + ...nconsistentClientTransferExceptionTest.php | 15 + .../Exception/ValidationExceptionTest.php | 17 + .../Service/Mock/Command/IterableCommand.php | 31 + .../Service/Mock/Command/MockCommand.php | 32 + .../Service/Mock/Command/OtherCommand.php | 30 + .../Tests/Service/Mock/Command/Sub/Sub.php | 7 + .../Guzzle/Tests/Service/Mock/MockClient.php | 36 + .../Mock/Model/MockCommandIterator.php | 42 + .../CompositeResourceIteratorFactoryTest.php | 37 + .../MapResourceIteratorFactoryTest.php | 40 + .../Tests/Service/Resource/ModelTest.php | 65 + .../ResourceIteratorClassFactoryTest.php | 41 + .../Service/Resource/ResourceIteratorTest.php | 184 + .../Stream/PhpStreamRequestFactoryTest.php | 172 + .../tests/Guzzle/Tests/Stream/StreamTest.php | 189 + .../tests/Guzzle/Tests/TestData/FileBody.txt | 0 .../Tests/TestData/description/bar.json | 3 + .../Tests/TestData/description/baz.json | 3 + .../Tests/TestData/description/foo.json | 8 + .../Tests/TestData/description/recursive.json | 3 + .../tests/Guzzle/Tests/TestData/mock_response | 3 + .../Guzzle/Tests/TestData/services/json1.json | 18 + .../Guzzle/Tests/TestData/services/json2.json | 11 + .../Tests/TestData/services/services.json | 71 + .../Guzzle/Tests/TestData/test_service.json | 40 + .../Guzzle/Tests/TestData/test_service2.json | 7 + .../Guzzle/Tests/TestData/test_service_3.json | 40 + vendor/guzzle/guzzle/tests/bootstrap.php | 10 + .../poweredbycoffee/slack-notifier/.gitignore | 3 + .../slack-notifier/.travis.yml | 7 + vendor/poweredbycoffee/slack-notifier/LICENSE | 7 + .../poweredbycoffee/slack-notifier/README.md | 58 + .../poweredbycoffee/slack-notifier/bin/slack | 27 + .../slack-notifier/composer.json | 23 + .../slack-notifier/phpunit.xml.dist | 26 + .../slack-notifier/src/Slack/Client.php | 15 + .../src/Slack/Command/NotifierCommand.php | 81 + .../src/Slack/Message/Message.php | 194 + .../src/Slack/Message/MessageAttachment.php | 139 + .../src/Slack/Message/MessageField.php | 76 + .../src/Slack/Message/MessageInterface.php | 7 + .../slack-notifier/src/Slack/Notifier.php | 68 + .../Normalizer/GetSetMethodNormalizer.php | 43 + .../Test/Command/NotifierCommandTest.php | 33 + .../tests/Slack/Test/NotifierTest.php | 95 + .../slack-notifier/tests/bootstrap.php | 5 + vendor/symfony/console/.gitignore | 3 + vendor/symfony/console/Application.php | 1177 +++++ vendor/symfony/console/CHANGELOG.md | 62 + vendor/symfony/console/Command/Command.php | 697 +++ .../symfony/console/Command/HelpCommand.php | 93 + .../symfony/console/Command/ListCommand.php | 97 + vendor/symfony/console/ConsoleEvents.php | 61 + .../Descriptor/ApplicationDescription.php | 157 + .../symfony/console/Descriptor/Descriptor.php | 121 + .../Descriptor/DescriptorInterface.php | 31 + .../console/Descriptor/JsonDescriptor.php | 166 + .../console/Descriptor/MarkdownDescriptor.php | 143 + .../console/Descriptor/TextDescriptor.php | 287 ++ .../console/Descriptor/XmlDescriptor.php | 263 ++ .../console/Event/ConsoleCommandEvent.php | 62 + vendor/symfony/console/Event/ConsoleEvent.php | 67 + .../console/Event/ConsoleExceptionEvent.php | 67 + .../console/Event/ConsoleTerminateEvent.php | 58 + .../console/Formatter/OutputFormatter.php | 242 ++ .../Formatter/OutputFormatterInterface.php | 83 + .../Formatter/OutputFormatterStyle.php | 229 + .../OutputFormatterStyleInterface.php | 72 + .../Formatter/OutputFormatterStyleStack.php | 121 + .../console/Helper/DebugFormatterHelper.php | 127 + .../console/Helper/DescriptorHelper.php | 96 + .../symfony/console/Helper/DialogHelper.php | 483 ++ .../console/Helper/FormatterHelper.php | 82 + vendor/symfony/console/Helper/Helper.php | 121 + .../console/Helper/HelperInterface.php | 49 + vendor/symfony/console/Helper/HelperSet.php | 116 + .../console/Helper/InputAwareHelper.php | 33 + .../symfony/console/Helper/ProcessHelper.php | 142 + vendor/symfony/console/Helper/ProgressBar.php | 615 +++ .../symfony/console/Helper/ProgressHelper.php | 465 ++ .../symfony/console/Helper/QuestionHelper.php | 441 ++ .../console/Helper/SymfonyQuestionHelper.php | 106 + vendor/symfony/console/Helper/Table.php | 606 +++ vendor/symfony/console/Helper/TableCell.php | 77 + vendor/symfony/console/Helper/TableHelper.php | 268 ++ .../symfony/console/Helper/TableSeparator.php | 29 + vendor/symfony/console/Helper/TableStyle.php | 255 ++ vendor/symfony/console/Input/ArgvInput.php | 353 ++ vendor/symfony/console/Input/ArrayInput.php | 211 + vendor/symfony/console/Input/Input.php | 226 + .../symfony/console/Input/InputArgument.php | 132 + .../console/Input/InputAwareInterface.php | 28 + .../symfony/console/Input/InputDefinition.php | 485 +++ .../symfony/console/Input/InputInterface.php | 152 + vendor/symfony/console/Input/InputOption.php | 213 + vendor/symfony/console/Input/StringInput.php | 87 + vendor/symfony/console/LICENSE | 19 + .../symfony/console/Logger/ConsoleLogger.php | 119 + .../symfony/console/Output/BufferedOutput.php | 48 + .../symfony/console/Output/ConsoleOutput.php | 149 + .../console/Output/ConsoleOutputInterface.php | 35 + vendor/symfony/console/Output/NullOutput.php | 113 + vendor/symfony/console/Output/Output.php | 165 + .../console/Output/OutputInterface.php | 113 + .../symfony/console/Output/StreamOutput.php | 103 + .../console/Question/ChoiceQuestion.php | 175 + .../console/Question/ConfirmationQuestion.php | 61 + vendor/symfony/console/Question/Question.php | 247 ++ vendor/symfony/console/README.md | 67 + .../console/Resources/bin/hiddeninput.exe | Bin 0 -> 9216 bytes vendor/symfony/console/Shell.php | 228 + vendor/symfony/console/Style/OutputStyle.php | 116 + .../symfony/console/Style/StyleInterface.php | 159 + vendor/symfony/console/Style/SymfonyStyle.php | 406 ++ .../console/Tester/ApplicationTester.php | 128 + .../symfony/console/Tester/CommandTester.php | 132 + .../symfony/console/Tests/ApplicationTest.php | 1060 +++++ .../console/Tests/Command/CommandTest.php | 337 ++ .../console/Tests/Command/HelpCommandTest.php | 70 + .../console/Tests/Command/ListCommandTest.php | 64 + .../Descriptor/AbstractDescriptorTest.php | 105 + .../Tests/Descriptor/JsonDescriptorTest.php | 35 + .../Descriptor/MarkdownDescriptorTest.php | 27 + .../Tests/Descriptor/ObjectsProvider.php | 77 + .../Tests/Descriptor/TextDescriptorTest.php | 27 + .../Tests/Descriptor/XmlDescriptorTest.php | 27 + .../console/Tests/Fixtures/BarBucCommand.php | 11 + .../Tests/Fixtures/DescriptorApplication1.php | 18 + .../Tests/Fixtures/DescriptorApplication2.php | 24 + .../Tests/Fixtures/DescriptorCommand1.php | 27 + .../Tests/Fixtures/DescriptorCommand2.php | 32 + .../console/Tests/Fixtures/DummyOutput.php | 36 + .../console/Tests/Fixtures/Foo1Command.php | 26 + .../console/Tests/Fixtures/Foo2Command.php | 21 + .../console/Tests/Fixtures/Foo3Command.php | 29 + .../console/Tests/Fixtures/Foo4Command.php | 11 + .../console/Tests/Fixtures/Foo5Command.php | 10 + .../console/Tests/Fixtures/FooCommand.php | 33 + .../Fixtures/FooSubnamespaced1Command.php | 26 + .../Fixtures/FooSubnamespaced2Command.php | 26 + .../console/Tests/Fixtures/FoobarCommand.php | 25 + .../Style/SymfonyStyle/command/command_0.php | 11 + .../Style/SymfonyStyle/command/command_1.php | 13 + .../Style/SymfonyStyle/command/command_2.php | 16 + .../Style/SymfonyStyle/command/command_3.php | 12 + .../Style/SymfonyStyle/command/command_4.php | 34 + .../Style/SymfonyStyle/command/command_5.php | 29 + .../Style/SymfonyStyle/command/command_6.php | 16 + .../Style/SymfonyStyle/command/command_7.php | 15 + .../Style/SymfonyStyle/output/output_0.txt | 3 + .../Style/SymfonyStyle/output/output_1.txt | 9 + .../Style/SymfonyStyle/output/output_2.txt | 13 + .../Style/SymfonyStyle/output/output_3.txt | 7 + .../Style/SymfonyStyle/output/output_4.txt | 32 + .../Style/SymfonyStyle/output/output_5.txt | 11 + .../Style/SymfonyStyle/output/output_6.txt | 6 + .../Style/SymfonyStyle/output/output_7.txt | 5 + .../console/Tests/Fixtures/TestCommand.php | 28 + .../console/Tests/Fixtures/application_1.json | 1 + .../console/Tests/Fixtures/application_1.md | 201 + .../console/Tests/Fixtures/application_1.txt | 17 + .../console/Tests/Fixtures/application_1.xml | 110 + .../console/Tests/Fixtures/application_2.json | 1 + .../console/Tests/Fixtures/application_2.md | 396 ++ .../console/Tests/Fixtures/application_2.txt | 22 + .../console/Tests/Fixtures/application_2.xml | 190 + .../Tests/Fixtures/application_astext1.txt | 20 + .../Tests/Fixtures/application_astext2.txt | 16 + .../Tests/Fixtures/application_asxml1.txt | 146 + .../Tests/Fixtures/application_asxml2.txt | 37 + .../Tests/Fixtures/application_gethelp.txt | 1 + .../Fixtures/application_renderexception1.txt | 8 + .../Fixtures/application_renderexception2.txt | 11 + .../Fixtures/application_renderexception3.txt | 27 + .../application_renderexception3decorated.txt | 27 + .../Fixtures/application_renderexception4.txt | 9 + ...plication_renderexception_doublewidth1.txt | 11 + ..._renderexception_doublewidth1decorated.txt | 11 + ...plication_renderexception_doublewidth2.txt | 12 + .../Tests/Fixtures/application_run1.txt | 17 + .../Tests/Fixtures/application_run2.txt | 29 + .../Tests/Fixtures/application_run3.txt | 27 + .../Tests/Fixtures/application_run4.txt | 1 + .../console/Tests/Fixtures/command_1.json | 1 + .../console/Tests/Fixtures/command_1.md | 11 + .../console/Tests/Fixtures/command_1.txt | 7 + .../console/Tests/Fixtures/command_1.xml | 12 + .../console/Tests/Fixtures/command_2.json | 1 + .../console/Tests/Fixtures/command_2.md | 33 + .../console/Tests/Fixtures/command_2.txt | 13 + .../console/Tests/Fixtures/command_2.xml | 21 + .../console/Tests/Fixtures/command_astext.txt | 18 + .../console/Tests/Fixtures/command_asxml.txt | 38 + .../Tests/Fixtures/definition_astext.txt | 11 + .../Tests/Fixtures/definition_asxml.txt | 39 + .../Tests/Fixtures/input_argument_1.json | 1 + .../Tests/Fixtures/input_argument_1.md | 7 + .../Tests/Fixtures/input_argument_1.txt | 1 + .../Tests/Fixtures/input_argument_1.xml | 5 + .../Tests/Fixtures/input_argument_2.json | 1 + .../Tests/Fixtures/input_argument_2.md | 7 + .../Tests/Fixtures/input_argument_2.txt | 1 + .../Tests/Fixtures/input_argument_2.xml | 5 + .../Tests/Fixtures/input_argument_3.json | 1 + .../Tests/Fixtures/input_argument_3.md | 7 + .../Tests/Fixtures/input_argument_3.txt | 1 + .../Tests/Fixtures/input_argument_3.xml | 7 + .../Tests/Fixtures/input_argument_4.json | 1 + .../Tests/Fixtures/input_argument_4.md | 8 + .../Tests/Fixtures/input_argument_4.txt | 2 + .../Tests/Fixtures/input_argument_4.xml | 6 + .../Tests/Fixtures/input_definition_1.json | 1 + .../Tests/Fixtures/input_definition_1.md | 0 .../Tests/Fixtures/input_definition_1.txt | 0 .../Tests/Fixtures/input_definition_1.xml | 5 + .../Tests/Fixtures/input_definition_2.json | 1 + .../Tests/Fixtures/input_definition_2.md | 9 + .../Tests/Fixtures/input_definition_2.txt | 2 + .../Tests/Fixtures/input_definition_2.xml | 10 + .../Tests/Fixtures/input_definition_3.json | 1 + .../Tests/Fixtures/input_definition_3.md | 11 + .../Tests/Fixtures/input_definition_3.txt | 2 + .../Tests/Fixtures/input_definition_3.xml | 9 + .../Tests/Fixtures/input_definition_4.json | 1 + .../Tests/Fixtures/input_definition_4.md | 21 + .../Tests/Fixtures/input_definition_4.txt | 5 + .../Tests/Fixtures/input_definition_4.xml | 14 + .../Tests/Fixtures/input_option_1.json | 1 + .../console/Tests/Fixtures/input_option_1.md | 9 + .../console/Tests/Fixtures/input_option_1.txt | 1 + .../console/Tests/Fixtures/input_option_1.xml | 4 + .../Tests/Fixtures/input_option_2.json | 1 + .../console/Tests/Fixtures/input_option_2.md | 9 + .../console/Tests/Fixtures/input_option_2.txt | 1 + .../console/Tests/Fixtures/input_option_2.xml | 7 + .../Tests/Fixtures/input_option_3.json | 1 + .../console/Tests/Fixtures/input_option_3.md | 9 + .../console/Tests/Fixtures/input_option_3.txt | 1 + .../console/Tests/Fixtures/input_option_3.xml | 5 + .../Tests/Fixtures/input_option_4.json | 1 + .../console/Tests/Fixtures/input_option_4.md | 9 + .../console/Tests/Fixtures/input_option_4.txt | 1 + .../console/Tests/Fixtures/input_option_4.xml | 5 + .../Tests/Fixtures/input_option_5.json | 1 + .../console/Tests/Fixtures/input_option_5.md | 10 + .../console/Tests/Fixtures/input_option_5.txt | 2 + .../console/Tests/Fixtures/input_option_5.xml | 6 + .../Tests/Fixtures/input_option_6.json | 1 + .../console/Tests/Fixtures/input_option_6.md | 9 + .../console/Tests/Fixtures/input_option_6.txt | 1 + .../console/Tests/Fixtures/input_option_6.xml | 5 + .../OutputFormatterStyleStackTest.php | 70 + .../Formatter/OutputFormatterStyleTest.php | 99 + .../Tests/Formatter/OutputFormatterTest.php | 273 ++ .../Tests/Helper/FormatterHelperTest.php | 99 + .../console/Tests/Helper/HelperSetTest.php | 153 + .../Tests/Helper/LegacyDialogHelperTest.php | 195 + .../Tests/Helper/LegacyProgressHelperTest.php | 227 + .../Tests/Helper/LegacyTableHelperTest.php | 324 ++ .../Tests/Helper/ProcessHelperTest.php | 117 + .../console/Tests/Helper/ProgressBarTest.php | 601 +++ .../Tests/Helper/QuestionHelperTest.php | 383 ++ .../console/Tests/Helper/TableStyleTest.php | 27 + .../console/Tests/Helper/TableTest.php | 568 +++ .../console/Tests/Input/ArgvInputTest.php | 317 ++ .../console/Tests/Input/ArrayInputTest.php | 138 + .../console/Tests/Input/InputArgumentTest.php | 111 + .../Tests/Input/InputDefinitionTest.php | 437 ++ .../console/Tests/Input/InputOptionTest.php | 204 + .../symfony/console/Tests/Input/InputTest.php | 121 + .../console/Tests/Input/StringInputTest.php | 99 + .../Tests/Logger/ConsoleLoggerTest.php | 58 + .../Tests/Output/ConsoleOutputTest.php | 25 + .../console/Tests/Output/NullOutputTest.php | 39 + .../console/Tests/Output/OutputTest.php | 156 + .../console/Tests/Output/StreamOutputTest.php | 60 + .../console/Tests/Style/SymfonyStyleTest.php | 64 + .../Tests/Tester/ApplicationTesterTest.php | 69 + .../Tests/Tester/CommandTesterTest.php | 84 + vendor/symfony/console/composer.json | 41 + vendor/symfony/console/phpunit.xml.dist | 29 + vendor/symfony/event-dispatcher/.gitignore | 3 + vendor/symfony/event-dispatcher/CHANGELOG.md | 23 + .../ContainerAwareEventDispatcher.php | 202 + .../Debug/TraceableEventDispatcher.php | 335 ++ .../TraceableEventDispatcherInterface.php | 34 + .../Debug/WrappedListener.php | 71 + .../RegisterListenersPass.php | 110 + vendor/symfony/event-dispatcher/Event.php | 134 + .../event-dispatcher/EventDispatcher.php | 185 + .../EventDispatcherInterface.php | 96 + .../EventSubscriberInterface.php | 50 + .../symfony/event-dispatcher/GenericEvent.php | 186 + .../ImmutableEventDispatcher.php | 93 + vendor/symfony/event-dispatcher/LICENSE | 19 + vendor/symfony/event-dispatcher/README.md | 27 + .../Tests/AbstractEventDispatcherTest.php | 381 ++ .../ContainerAwareEventDispatcherTest.php | 249 ++ .../Debug/TraceableEventDispatcherTest.php | 199 + .../RegisterListenersPassTest.php | 200 + .../Tests/EventDispatcherTest.php | 22 + .../event-dispatcher/Tests/EventTest.php | 96 + .../Tests/GenericEventTest.php | 139 + .../Tests/ImmutableEventDispatcherTest.php | 105 + vendor/symfony/event-dispatcher/composer.json | 42 + .../symfony/event-dispatcher/phpunit.xml.dist | 29 + vendor/symfony/serializer/.gitignore | 3 + .../symfony/serializer/Annotation/Groups.php | 64 + vendor/symfony/serializer/CHANGELOG.md | 96 + .../serializer/Encoder/ChainDecoder.php | 82 + .../serializer/Encoder/ChainEncoder.php | 104 + .../serializer/Encoder/DecoderInterface.php | 49 + .../serializer/Encoder/EncoderInterface.php | 44 + .../symfony/serializer/Encoder/JsonDecode.php | 142 + .../symfony/serializer/Encoder/JsonEncode.php | 84 + .../serializer/Encoder/JsonEncoder.php | 125 + .../Encoder/NormalizationAwareInterface.php | 24 + .../Encoder/SerializerAwareEncoder.php | 33 + .../symfony/serializer/Encoder/XmlEncoder.php | 536 +++ .../Exception/CircularReferenceException.php | 21 + .../serializer/Exception/Exception.php | 21 + .../Exception/ExceptionInterface.php | 21 + .../Exception/InvalidArgumentException.php | 21 + .../serializer/Exception/LogicException.php | 21 + .../serializer/Exception/MappingException.php | 21 + .../serializer/Exception/RuntimeException.php | 21 + .../Exception/UnexpectedValueException.php | 21 + .../Exception/UnsupportedException.php | 21 + vendor/symfony/serializer/LICENSE | 19 + .../serializer/Mapping/AttributeMetadata.php | 94 + .../Mapping/AttributeMetadataInterface.php | 50 + .../serializer/Mapping/ClassMetadata.php | 116 + .../Mapping/ClassMetadataInterface.php | 57 + .../Mapping/Factory/ClassMetadataFactory.php | 118 + .../Factory/ClassMetadataFactoryInterface.php | 53 + .../Mapping/Loader/AnnotationLoader.php | 99 + .../serializer/Mapping/Loader/FileLoader.php | 47 + .../serializer/Mapping/Loader/LoaderChain.php | 66 + .../Mapping/Loader/LoaderInterface.php | 31 + .../Mapping/Loader/XmlFileLoader.php | 92 + .../Mapping/Loader/YamlFileLoader.php | 89 + .../serializer-mapping-1.0.xsd | 56 + .../CamelCaseToSnakeCaseNameConverter.php | 82 + .../NameConverter/NameConverterInterface.php | 38 + .../Normalizer/AbstractNormalizer.php | 345 ++ .../Normalizer/CustomNormalizer.php | 66 + .../Normalizer/DenormalizableInterface.php | 38 + .../Normalizer/DenormalizerInterface.php | 43 + .../Normalizer/GetSetMethodNormalizer.php | 179 + .../Normalizer/NormalizableInterface.php | 39 + .../Normalizer/NormalizerInterface.php | 41 + .../Normalizer/ObjectNormalizer.php | 162 + .../Normalizer/PropertyNormalizer.php | 161 + .../Normalizer/SerializerAwareNormalizer.php | 36 + vendor/symfony/serializer/README.md | 15 + vendor/symfony/serializer/Serializer.php | 310 ++ .../serializer/SerializerAwareInterface.php | 27 + .../serializer/SerializerInterface.php | 43 + .../Tests/Annotation/GroupsTest.php | 52 + .../Tests/Encoder/JsonEncoderTest.php | 79 + .../Tests/Encoder/XmlEncoderTest.php | 510 +++ .../Tests/Fixtures/CircularReferenceDummy.php | 23 + .../Tests/Fixtures/DenormalizableDummy.php | 22 + .../serializer/Tests/Fixtures/Dummy.php | 43 + .../serializer/Tests/Fixtures/GroupDummy.php | 80 + .../Tests/Fixtures/GroupDummyInterface.php | 25 + .../Tests/Fixtures/GroupDummyParent.php | 49 + .../Fixtures/NormalizableTraversableDummy.php | 36 + .../PropertyCircularReferenceDummy.php | 25 + .../Tests/Fixtures/PropertySiblingHolder.php | 39 + .../serializer/Tests/Fixtures/ScalarDummy.php | 37 + .../Tests/Fixtures/SiblingHolder.php | 57 + .../Tests/Fixtures/TraversableDummy.php | 23 + .../Fixtures/VariadicConstructorArgsDummy.php | 27 + .../Tests/Fixtures/empty-mapping.yml | 0 .../Tests/Fixtures/invalid-mapping.yml | 1 + .../Tests/Fixtures/serialization.xml | 18 + .../Tests/Fixtures/serialization.yml | 6 + .../Tests/Mapping/AttributeMetadataTest.php | 67 + .../Tests/Mapping/ClassMetadataTest.php | 82 + .../Factory/ClassMetadataFactoryTest.php | 78 + .../Mapping/Loader/AnnotationLoaderTest.php | 66 + .../Mapping/Loader/XmlFileLoaderTest.php | 54 + .../Mapping/Loader/YamlFileLoaderTest.php | 69 + .../Mapping/TestClassMetadataFactory.php | 82 + .../CamelCaseToSnakeCaseNameConverterTest.php | 53 + .../Tests/Normalizer/CustomNormalizerTest.php | 69 + .../Normalizer/GetSetMethodNormalizerTest.php | 799 ++++ .../Tests/Normalizer/ObjectNormalizerTest.php | 605 +++ .../Normalizer/PropertyNormalizerTest.php | 493 +++ .../Tests/Normalizer/TestDenormalizer.php | 37 + .../Tests/Normalizer/TestNormalizer.php | 37 + .../serializer/Tests/SerializerTest.php | 267 ++ vendor/symfony/serializer/composer.json | 45 + vendor/symfony/serializer/phpunit.xml.dist | 28 + 880 files changed, 95366 insertions(+), 1 deletion(-) create mode 100644 vendor/autoload.php create mode 120000 vendor/bin/slack create mode 100644 vendor/composer/ClassLoader.php create mode 100644 vendor/composer/LICENSE create mode 100644 vendor/composer/autoload_classmap.php create mode 100644 vendor/composer/autoload_namespaces.php create mode 100644 vendor/composer/autoload_psr4.php create mode 100644 vendor/composer/autoload_real.php create mode 100644 vendor/composer/installed.json create mode 100644 vendor/guzzle/guzzle/.gitignore create mode 100644 vendor/guzzle/guzzle/.travis.yml create mode 100644 vendor/guzzle/guzzle/CHANGELOG.md create mode 100644 vendor/guzzle/guzzle/LICENSE create mode 100644 vendor/guzzle/guzzle/README.md create mode 100644 vendor/guzzle/guzzle/UPGRADING.md create mode 100644 vendor/guzzle/guzzle/build.xml create mode 100644 vendor/guzzle/guzzle/composer.json create mode 100644 vendor/guzzle/guzzle/docs/Makefile create mode 100644 vendor/guzzle/guzzle/docs/_downloads/guzzle-schema-1.0.json create mode 100644 vendor/guzzle/guzzle/docs/_static/guzzle-icon.png create mode 100644 vendor/guzzle/guzzle/docs/_static/homepage.css create mode 100644 vendor/guzzle/guzzle/docs/_static/logo.png create mode 100644 vendor/guzzle/guzzle/docs/_static/prettify.css create mode 100644 vendor/guzzle/guzzle/docs/_static/prettify.js create mode 100644 vendor/guzzle/guzzle/docs/_templates/index.html create mode 100644 vendor/guzzle/guzzle/docs/_templates/leftbar.html create mode 100644 vendor/guzzle/guzzle/docs/_templates/nav_links.html create mode 100644 vendor/guzzle/guzzle/docs/batching/batching.rst create mode 100644 vendor/guzzle/guzzle/docs/conf.py create mode 100644 vendor/guzzle/guzzle/docs/docs.rst create mode 100644 vendor/guzzle/guzzle/docs/getting-started/faq.rst create mode 100644 vendor/guzzle/guzzle/docs/getting-started/installation.rst create mode 100644 vendor/guzzle/guzzle/docs/getting-started/overview.rst create mode 100644 vendor/guzzle/guzzle/docs/http-client/client.rst create mode 100644 vendor/guzzle/guzzle/docs/http-client/entity-bodies.rst create mode 100644 vendor/guzzle/guzzle/docs/http-client/http-redirects.rst create mode 100644 vendor/guzzle/guzzle/docs/http-client/request.rst create mode 100644 vendor/guzzle/guzzle/docs/http-client/response.rst create mode 100644 vendor/guzzle/guzzle/docs/http-client/uri-templates.rst create mode 100644 vendor/guzzle/guzzle/docs/index.rst create mode 100644 vendor/guzzle/guzzle/docs/iterators/guzzle-iterators.rst create mode 100644 vendor/guzzle/guzzle/docs/iterators/resource-iterators.rst create mode 100644 vendor/guzzle/guzzle/docs/plugins/async-plugin.rst create mode 100644 vendor/guzzle/guzzle/docs/plugins/backoff-plugin.rst create mode 100644 vendor/guzzle/guzzle/docs/plugins/cache-plugin.rst create mode 100644 vendor/guzzle/guzzle/docs/plugins/cookie-plugin.rst create mode 100644 vendor/guzzle/guzzle/docs/plugins/creating-plugins.rst create mode 100644 vendor/guzzle/guzzle/docs/plugins/curl-auth-plugin.rst create mode 100644 vendor/guzzle/guzzle/docs/plugins/history-plugin.rst create mode 100644 vendor/guzzle/guzzle/docs/plugins/log-plugin.rst create mode 100644 vendor/guzzle/guzzle/docs/plugins/md5-validator-plugin.rst create mode 100644 vendor/guzzle/guzzle/docs/plugins/mock-plugin.rst create mode 100644 vendor/guzzle/guzzle/docs/plugins/oauth-plugin.rst create mode 100644 vendor/guzzle/guzzle/docs/plugins/plugins-list.rst.inc create mode 100644 vendor/guzzle/guzzle/docs/plugins/plugins-overview.rst create mode 100644 vendor/guzzle/guzzle/docs/requirements.txt create mode 100644 vendor/guzzle/guzzle/docs/testing/unit-testing.rst create mode 100644 vendor/guzzle/guzzle/docs/webservice-client/guzzle-service-descriptions.rst create mode 100644 vendor/guzzle/guzzle/docs/webservice-client/using-the-service-builder.rst create mode 100644 vendor/guzzle/guzzle/docs/webservice-client/webservice-client.rst create mode 100644 vendor/guzzle/guzzle/phar-stub.php create mode 100644 vendor/guzzle/guzzle/phing/build.properties.dist create mode 100644 vendor/guzzle/guzzle/phing/imports/dependencies.xml create mode 100644 vendor/guzzle/guzzle/phing/imports/deploy.xml create mode 100644 vendor/guzzle/guzzle/phing/tasks/ComposerLintTask.php create mode 100644 vendor/guzzle/guzzle/phing/tasks/GuzzlePearPharPackageTask.php create mode 100644 vendor/guzzle/guzzle/phing/tasks/GuzzleSubSplitTask.php create mode 100644 vendor/guzzle/guzzle/phpunit.xml.dist create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Batch/AbstractBatchDecorator.php create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Batch/Batch.php create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Batch/BatchBuilder.php create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Batch/BatchClosureDivisor.php create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Batch/BatchClosureTransfer.php create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Batch/BatchCommandTransfer.php create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Batch/BatchDivisorInterface.php create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Batch/BatchInterface.php create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Batch/BatchRequestTransfer.php create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Batch/BatchSizeDivisor.php create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Batch/BatchTransferInterface.php create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Batch/Exception/BatchTransferException.php create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Batch/ExceptionBufferingBatch.php create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Batch/FlushingBatch.php create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Batch/HistoryBatch.php create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Batch/NotifyingBatch.php create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Batch/composer.json create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Cache/AbstractCacheAdapter.php create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Cache/CacheAdapterFactory.php create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Cache/CacheAdapterInterface.php create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Cache/ClosureCacheAdapter.php create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Cache/DoctrineCacheAdapter.php create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Cache/NullCacheAdapter.php create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Cache/Zf1CacheAdapter.php create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Cache/Zf2CacheAdapter.php create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Cache/composer.json create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Common/AbstractHasDispatcher.php create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Common/Collection.php create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Common/Event.php create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Common/Exception/BadMethodCallException.php create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Common/Exception/ExceptionCollection.php create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Common/Exception/GuzzleException.php create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Common/Exception/InvalidArgumentException.php create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Common/Exception/RuntimeException.php create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Common/Exception/UnexpectedValueException.php create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Common/FromConfigInterface.php create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Common/HasDispatcherInterface.php create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Common/ToArrayInterface.php create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Common/Version.php create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Common/composer.json create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Http/AbstractEntityBodyDecorator.php create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Http/CachingEntityBody.php create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Http/Client.php create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Http/ClientInterface.php create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Http/Curl/CurlHandle.php create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Http/Curl/CurlMulti.php create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Http/Curl/CurlMultiInterface.php create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Http/Curl/CurlMultiProxy.php create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Http/Curl/CurlVersion.php create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Http/Curl/RequestMediator.php create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Http/EntityBody.php create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Http/EntityBodyInterface.php create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Http/Exception/BadResponseException.php create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Http/Exception/ClientErrorResponseException.php create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Http/Exception/CouldNotRewindStreamException.php create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Http/Exception/CurlException.php create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Http/Exception/HttpException.php create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Http/Exception/MultiTransferException.php create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Http/Exception/RequestException.php create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Http/Exception/ServerErrorResponseException.php create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Http/Exception/TooManyRedirectsException.php create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Http/IoEmittingEntityBody.php create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Http/Message/AbstractMessage.php create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Http/Message/EntityEnclosingRequest.php create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Http/Message/EntityEnclosingRequestInterface.php create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Http/Message/Header.php create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Http/Message/Header/CacheControl.php create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Http/Message/Header/HeaderCollection.php create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Http/Message/Header/HeaderFactory.php create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Http/Message/Header/HeaderFactoryInterface.php create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Http/Message/Header/HeaderInterface.php create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Http/Message/Header/Link.php create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Http/Message/MessageInterface.php create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Http/Message/PostFile.php create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Http/Message/PostFileInterface.php create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Http/Message/Request.php create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Http/Message/RequestFactory.php create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Http/Message/RequestFactoryInterface.php create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Http/Message/RequestInterface.php create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Http/Message/Response.php create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Http/Mimetypes.php create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Http/QueryAggregator/CommaAggregator.php create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Http/QueryAggregator/DuplicateAggregator.php create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Http/QueryAggregator/PhpAggregator.php create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Http/QueryAggregator/QueryAggregatorInterface.php create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Http/QueryString.php create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Http/ReadLimitEntityBody.php create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Http/RedirectPlugin.php create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Http/Resources/cacert.pem create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Http/StaticClient.php create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Http/Url.php create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Http/composer.json create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Inflection/Inflector.php create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Inflection/InflectorInterface.php create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Inflection/MemoizingInflector.php create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Inflection/PreComputedInflector.php create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Inflection/composer.json create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Iterator/AppendIterator.php create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Iterator/ChunkedIterator.php create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Iterator/FilterIterator.php create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Iterator/MapIterator.php create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Iterator/MethodProxyIterator.php create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Iterator/README.md create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Iterator/composer.json create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Log/AbstractLogAdapter.php create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Log/ArrayLogAdapter.php create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Log/ClosureLogAdapter.php create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Log/LogAdapterInterface.php create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Log/MessageFormatter.php create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Log/MonologLogAdapter.php create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Log/PsrLogAdapter.php create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Log/Zf1LogAdapter.php create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Log/Zf2LogAdapter.php create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Log/composer.json create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Parser/Cookie/CookieParser.php create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Parser/Cookie/CookieParserInterface.php create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Parser/Message/AbstractMessageParser.php create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Parser/Message/MessageParser.php create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Parser/Message/MessageParserInterface.php create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Parser/Message/PeclHttpMessageParser.php create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Parser/ParserRegistry.php create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Parser/UriTemplate/PeclUriTemplate.php create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Parser/UriTemplate/UriTemplate.php create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Parser/UriTemplate/UriTemplateInterface.php create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Parser/Url/UrlParser.php create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Parser/Url/UrlParserInterface.php create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Parser/composer.json create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Plugin/Async/AsyncPlugin.php create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Plugin/Async/composer.json create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Plugin/Backoff/AbstractBackoffStrategy.php create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Plugin/Backoff/AbstractErrorCodeBackoffStrategy.php create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Plugin/Backoff/BackoffLogger.php create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Plugin/Backoff/BackoffPlugin.php create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Plugin/Backoff/BackoffStrategyInterface.php create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Plugin/Backoff/CallbackBackoffStrategy.php create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Plugin/Backoff/ConstantBackoffStrategy.php create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Plugin/Backoff/CurlBackoffStrategy.php create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Plugin/Backoff/ExponentialBackoffStrategy.php create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Plugin/Backoff/HttpBackoffStrategy.php create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Plugin/Backoff/LinearBackoffStrategy.php create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Plugin/Backoff/ReasonPhraseBackoffStrategy.php create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Plugin/Backoff/TruncatedBackoffStrategy.php create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Plugin/Backoff/composer.json create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Plugin/Cache/CacheKeyProviderInterface.php create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Plugin/Cache/CachePlugin.php create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Plugin/Cache/CacheStorageInterface.php create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Plugin/Cache/CallbackCanCacheStrategy.php create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Plugin/Cache/CanCacheStrategyInterface.php create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Plugin/Cache/DefaultCacheKeyProvider.php create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Plugin/Cache/DefaultCacheStorage.php create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Plugin/Cache/DefaultCanCacheStrategy.php create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Plugin/Cache/DefaultRevalidation.php create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Plugin/Cache/DenyRevalidation.php create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Plugin/Cache/RevalidationInterface.php create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Plugin/Cache/SkipRevalidation.php create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Plugin/Cache/composer.json create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Plugin/Cookie/Cookie.php create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Plugin/Cookie/CookieJar/ArrayCookieJar.php create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Plugin/Cookie/CookieJar/CookieJarInterface.php create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Plugin/Cookie/CookieJar/FileCookieJar.php create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Plugin/Cookie/CookiePlugin.php create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Plugin/Cookie/Exception/InvalidCookieException.php create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Plugin/Cookie/composer.json create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Plugin/CurlAuth/CurlAuthPlugin.php create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Plugin/CurlAuth/composer.json create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Plugin/ErrorResponse/ErrorResponseExceptionInterface.php create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Plugin/ErrorResponse/ErrorResponsePlugin.php create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Plugin/ErrorResponse/Exception/ErrorResponseException.php create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Plugin/ErrorResponse/composer.json create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Plugin/History/HistoryPlugin.php create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Plugin/History/composer.json create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Plugin/Log/LogPlugin.php create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Plugin/Log/composer.json create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Plugin/Md5/CommandContentMd5Plugin.php create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Plugin/Md5/Md5ValidatorPlugin.php create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Plugin/Md5/composer.json create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Plugin/Mock/MockPlugin.php create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Plugin/Mock/composer.json create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Plugin/Oauth/OauthPlugin.php create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Plugin/Oauth/composer.json create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Plugin/composer.json create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Service/AbstractConfigLoader.php create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Service/Builder/ServiceBuilder.php create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Service/Builder/ServiceBuilderInterface.php create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Service/Builder/ServiceBuilderLoader.php create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Service/CachingConfigLoader.php create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Service/Client.php create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Service/ClientInterface.php create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Service/Command/AbstractCommand.php create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Service/Command/ClosureCommand.php create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Service/Command/CommandInterface.php create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Service/Command/CreateResponseClassEvent.php create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Service/Command/DefaultRequestSerializer.php create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Service/Command/DefaultResponseParser.php create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Service/Command/Factory/AliasFactory.php create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Service/Command/Factory/CompositeFactory.php create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Service/Command/Factory/ConcreteClassFactory.php create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Service/Command/Factory/FactoryInterface.php create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Service/Command/Factory/MapFactory.php create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Service/Command/Factory/ServiceDescriptionFactory.php create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Service/Command/LocationVisitor/Request/AbstractRequestVisitor.php create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Service/Command/LocationVisitor/Request/BodyVisitor.php create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Service/Command/LocationVisitor/Request/HeaderVisitor.php create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Service/Command/LocationVisitor/Request/JsonVisitor.php create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Service/Command/LocationVisitor/Request/PostFieldVisitor.php create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Service/Command/LocationVisitor/Request/PostFileVisitor.php create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Service/Command/LocationVisitor/Request/QueryVisitor.php create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Service/Command/LocationVisitor/Request/RequestVisitorInterface.php create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Service/Command/LocationVisitor/Request/ResponseBodyVisitor.php create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Service/Command/LocationVisitor/Request/XmlVisitor.php create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Service/Command/LocationVisitor/Response/AbstractResponseVisitor.php create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Service/Command/LocationVisitor/Response/BodyVisitor.php create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Service/Command/LocationVisitor/Response/HeaderVisitor.php create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Service/Command/LocationVisitor/Response/JsonVisitor.php create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Service/Command/LocationVisitor/Response/ReasonPhraseVisitor.php create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Service/Command/LocationVisitor/Response/ResponseVisitorInterface.php create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Service/Command/LocationVisitor/Response/StatusCodeVisitor.php create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Service/Command/LocationVisitor/Response/XmlVisitor.php create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Service/Command/LocationVisitor/VisitorFlyweight.php create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Service/Command/OperationCommand.php create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Service/Command/OperationResponseParser.php create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Service/Command/RequestSerializerInterface.php create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Service/Command/ResponseClassInterface.php create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Service/Command/ResponseParserInterface.php create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Service/ConfigLoaderInterface.php create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Service/Description/Operation.php create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Service/Description/OperationInterface.php create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Service/Description/Parameter.php create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Service/Description/SchemaFormatter.php create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Service/Description/SchemaValidator.php create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Service/Description/ServiceDescription.php create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Service/Description/ServiceDescriptionInterface.php create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Service/Description/ServiceDescriptionLoader.php create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Service/Description/ValidatorInterface.php create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Service/Exception/CommandException.php create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Service/Exception/CommandTransferException.php create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Service/Exception/DescriptionBuilderException.php create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Service/Exception/InconsistentClientTransferException.php create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Service/Exception/ResponseClassException.php create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Service/Exception/ServiceBuilderException.php create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Service/Exception/ServiceNotFoundException.php create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Service/Exception/ValidationException.php create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Service/Resource/AbstractResourceIteratorFactory.php create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Service/Resource/CompositeResourceIteratorFactory.php create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Service/Resource/MapResourceIteratorFactory.php create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Service/Resource/Model.php create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Service/Resource/ResourceIterator.php create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Service/Resource/ResourceIteratorApplyBatched.php create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Service/Resource/ResourceIteratorClassFactory.php create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Service/Resource/ResourceIteratorFactoryInterface.php create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Service/Resource/ResourceIteratorInterface.php create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Service/composer.json create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Stream/PhpStreamRequestFactory.php create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Stream/Stream.php create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Stream/StreamInterface.php create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Stream/StreamRequestFactoryInterface.php create mode 100644 vendor/guzzle/guzzle/src/Guzzle/Stream/composer.json create mode 100644 vendor/guzzle/guzzle/tests/Guzzle/Tests/Batch/AbstractBatchDecoratorTest.php create mode 100644 vendor/guzzle/guzzle/tests/Guzzle/Tests/Batch/BatchBuilderTest.php create mode 100644 vendor/guzzle/guzzle/tests/Guzzle/Tests/Batch/BatchClosureDivisorTest.php create mode 100644 vendor/guzzle/guzzle/tests/Guzzle/Tests/Batch/BatchClosureTransferTest.php create mode 100644 vendor/guzzle/guzzle/tests/Guzzle/Tests/Batch/BatchCommandTransferTest.php create mode 100644 vendor/guzzle/guzzle/tests/Guzzle/Tests/Batch/BatchRequestTransferTest.php create mode 100644 vendor/guzzle/guzzle/tests/Guzzle/Tests/Batch/BatchSizeDivisorTest.php create mode 100644 vendor/guzzle/guzzle/tests/Guzzle/Tests/Batch/BatchTest.php create mode 100644 vendor/guzzle/guzzle/tests/Guzzle/Tests/Batch/ExceptionBufferingBatchTest.php create mode 100644 vendor/guzzle/guzzle/tests/Guzzle/Tests/Batch/FlushingBatchTest.php create mode 100644 vendor/guzzle/guzzle/tests/Guzzle/Tests/Batch/HistoryBatchTest.php create mode 100644 vendor/guzzle/guzzle/tests/Guzzle/Tests/Batch/NotifyingBatchTest.php create mode 100644 vendor/guzzle/guzzle/tests/Guzzle/Tests/Cache/CacheAdapterFactoryTest.php create mode 100644 vendor/guzzle/guzzle/tests/Guzzle/Tests/Cache/CacheAdapterTest.php create mode 100644 vendor/guzzle/guzzle/tests/Guzzle/Tests/Cache/ClosureCacheAdapterTest.php create mode 100644 vendor/guzzle/guzzle/tests/Guzzle/Tests/Cache/NullCacheAdapterTest.php create mode 100644 vendor/guzzle/guzzle/tests/Guzzle/Tests/Cache/Zf2CacheAdapterTest.php create mode 100644 vendor/guzzle/guzzle/tests/Guzzle/Tests/Common/AbstractHasDispatcherTest.php create mode 100644 vendor/guzzle/guzzle/tests/Guzzle/Tests/Common/CollectionTest.php create mode 100644 vendor/guzzle/guzzle/tests/Guzzle/Tests/Common/EventTest.php create mode 100644 vendor/guzzle/guzzle/tests/Guzzle/Tests/Common/Exception/BatchTransferExceptionTest.php create mode 100644 vendor/guzzle/guzzle/tests/Guzzle/Tests/Common/Exception/ExceptionCollectionTest.php create mode 100644 vendor/guzzle/guzzle/tests/Guzzle/Tests/Common/VersionTest.php create mode 100644 vendor/guzzle/guzzle/tests/Guzzle/Tests/GuzzleTestCase.php create mode 100644 vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/AbstractEntityBodyDecoratorTest.php create mode 100644 vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/CachingEntityBodyTest.php create mode 100644 vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/ClientTest.php create mode 100644 vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/Curl/CurlHandleTest.php create mode 100644 vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/Curl/CurlMultiProxyTest.php create mode 100644 vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/Curl/CurlMultiTest.php create mode 100644 vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/Curl/CurlVersionTest.php create mode 100644 vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/Curl/RequestMediatorTest.php create mode 100644 vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/EntityBodyTest.php create mode 100644 vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/Exception/CurlExceptionTest.php create mode 100644 vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/Exception/ExceptionTest.php create mode 100644 vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/Exception/MultiTransferExceptionTest.php create mode 100644 vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/IoEmittingEntityBodyTest.php create mode 100644 vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/Message/AbstractMessageTest.php create mode 100644 vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/Message/EntityEnclosingRequestTest.php create mode 100644 vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/Message/Header/HeaderFactoryTest.php create mode 100644 vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/Message/Header/LinkTest.php create mode 100644 vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/Message/HeaderComparison.php create mode 100644 vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/Message/HeaderComparisonTest.php create mode 100644 vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/Message/HeaderTest.php create mode 100644 vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/Message/PostFileTest.php create mode 100644 vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/Message/RequestFactoryTest.php create mode 100644 vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/Message/RequestTest.php create mode 100644 vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/Message/ResponseTest.php create mode 100644 vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/MimetypesTest.php create mode 100644 vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/QueryAggregator/CommaAggregatorTest.php create mode 100644 vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/QueryAggregator/DuplicateAggregatorTest.php create mode 100644 vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/QueryAggregator/PhpAggregatorTest.php create mode 100644 vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/QueryStringTest.php create mode 100644 vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/ReadLimitEntityBodyTest.php create mode 100755 vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/RedirectPluginTest.php create mode 100644 vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/Server.php create mode 100644 vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/StaticClientTest.php create mode 100644 vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/UrlTest.php create mode 100644 vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/server.js create mode 100644 vendor/guzzle/guzzle/tests/Guzzle/Tests/Inflection/InflectorTest.php create mode 100644 vendor/guzzle/guzzle/tests/Guzzle/Tests/Inflection/MemoizingInflectorTest.php create mode 100644 vendor/guzzle/guzzle/tests/Guzzle/Tests/Inflection/PreComputedInflectorTest.php create mode 100644 vendor/guzzle/guzzle/tests/Guzzle/Tests/Iterator/AppendIteratorTest.php create mode 100644 vendor/guzzle/guzzle/tests/Guzzle/Tests/Iterator/ChunkedIteratorTest.php create mode 100644 vendor/guzzle/guzzle/tests/Guzzle/Tests/Iterator/FilterIteratorTest.php create mode 100644 vendor/guzzle/guzzle/tests/Guzzle/Tests/Iterator/MapIteratorTest.php create mode 100644 vendor/guzzle/guzzle/tests/Guzzle/Tests/Iterator/MethodProxyIteratorTest.php create mode 100644 vendor/guzzle/guzzle/tests/Guzzle/Tests/Log/ArrayLogAdapterTest.php create mode 100644 vendor/guzzle/guzzle/tests/Guzzle/Tests/Log/ClosureLogAdapterTest.php create mode 100644 vendor/guzzle/guzzle/tests/Guzzle/Tests/Log/MessageFormatterTest.php create mode 100644 vendor/guzzle/guzzle/tests/Guzzle/Tests/Log/PsrLogAdapterTest.php create mode 100644 vendor/guzzle/guzzle/tests/Guzzle/Tests/Log/Zf2LogAdapterTest.php create mode 100644 vendor/guzzle/guzzle/tests/Guzzle/Tests/Mock/CustomResponseModel.php create mode 100644 vendor/guzzle/guzzle/tests/Guzzle/Tests/Mock/ErrorResponseMock.php create mode 100644 vendor/guzzle/guzzle/tests/Guzzle/Tests/Mock/ExceptionMock.php create mode 100644 vendor/guzzle/guzzle/tests/Guzzle/Tests/Mock/MockMulti.php create mode 100644 vendor/guzzle/guzzle/tests/Guzzle/Tests/Mock/MockObserver.php create mode 100644 vendor/guzzle/guzzle/tests/Guzzle/Tests/Mock/MockSubject.php create mode 100644 vendor/guzzle/guzzle/tests/Guzzle/Tests/Parser/Cookie/CookieParserProvider.php create mode 100644 vendor/guzzle/guzzle/tests/Guzzle/Tests/Parser/Cookie/CookieParserTest.php create mode 100644 vendor/guzzle/guzzle/tests/Guzzle/Tests/Parser/Message/MessageParserProvider.php create mode 100644 vendor/guzzle/guzzle/tests/Guzzle/Tests/Parser/Message/MessageParserTest.php create mode 100644 vendor/guzzle/guzzle/tests/Guzzle/Tests/Parser/Message/PeclHttpMessageParserTest.php create mode 100644 vendor/guzzle/guzzle/tests/Guzzle/Tests/Parser/ParserRegistryTest.php create mode 100644 vendor/guzzle/guzzle/tests/Guzzle/Tests/Parser/UriTemplate/AbstractUriTemplateTest.php create mode 100644 vendor/guzzle/guzzle/tests/Guzzle/Tests/Parser/UriTemplate/PeclUriTemplateTest.php create mode 100644 vendor/guzzle/guzzle/tests/Guzzle/Tests/Parser/UriTemplate/UriTemplateTest.php create mode 100644 vendor/guzzle/guzzle/tests/Guzzle/Tests/Plugin/Async/AsyncPluginTest.php create mode 100644 vendor/guzzle/guzzle/tests/Guzzle/Tests/Plugin/Backoff/AbstractBackoffStrategyTest.php create mode 100644 vendor/guzzle/guzzle/tests/Guzzle/Tests/Plugin/Backoff/BackoffLoggerTest.php create mode 100644 vendor/guzzle/guzzle/tests/Guzzle/Tests/Plugin/Backoff/BackoffPluginTest.php create mode 100644 vendor/guzzle/guzzle/tests/Guzzle/Tests/Plugin/Backoff/CallbackBackoffStrategyTest.php create mode 100644 vendor/guzzle/guzzle/tests/Guzzle/Tests/Plugin/Backoff/ConstantBackoffStrategyTest.php create mode 100644 vendor/guzzle/guzzle/tests/Guzzle/Tests/Plugin/Backoff/CurlBackoffStrategyTest.php create mode 100644 vendor/guzzle/guzzle/tests/Guzzle/Tests/Plugin/Backoff/ExponentialBackoffStrategyTest.php create mode 100644 vendor/guzzle/guzzle/tests/Guzzle/Tests/Plugin/Backoff/HttpBackoffStrategyTest.php create mode 100644 vendor/guzzle/guzzle/tests/Guzzle/Tests/Plugin/Backoff/LinearBackoffStrategyTest.php create mode 100644 vendor/guzzle/guzzle/tests/Guzzle/Tests/Plugin/Backoff/ReasonPhraseBackoffStrategyTest.php create mode 100644 vendor/guzzle/guzzle/tests/Guzzle/Tests/Plugin/Backoff/TruncatedBackoffStrategyTest.php create mode 100644 vendor/guzzle/guzzle/tests/Guzzle/Tests/Plugin/Cache/CachePluginTest.php create mode 100644 vendor/guzzle/guzzle/tests/Guzzle/Tests/Plugin/Cache/CallbackCanCacheStrategyTest.php create mode 100644 vendor/guzzle/guzzle/tests/Guzzle/Tests/Plugin/Cache/DefaultCacheStorageTest.php create mode 100644 vendor/guzzle/guzzle/tests/Guzzle/Tests/Plugin/Cache/DefaultCanCacheStrategyTest.php create mode 100644 vendor/guzzle/guzzle/tests/Guzzle/Tests/Plugin/Cache/DefaultRevalidationTest.php create mode 100644 vendor/guzzle/guzzle/tests/Guzzle/Tests/Plugin/Cache/DenyRevalidationTest.php create mode 100644 vendor/guzzle/guzzle/tests/Guzzle/Tests/Plugin/Cache/SkipRevalidationTest.php create mode 100644 vendor/guzzle/guzzle/tests/Guzzle/Tests/Plugin/Cookie/CookieJar/ArrayCookieJarTest.php create mode 100644 vendor/guzzle/guzzle/tests/Guzzle/Tests/Plugin/Cookie/CookieJar/FileCookieJarTest.php create mode 100644 vendor/guzzle/guzzle/tests/Guzzle/Tests/Plugin/Cookie/CookiePluginTest.php create mode 100644 vendor/guzzle/guzzle/tests/Guzzle/Tests/Plugin/Cookie/CookieTest.php create mode 100644 vendor/guzzle/guzzle/tests/Guzzle/Tests/Plugin/CurlAuth/CurlAuthPluginTest.php create mode 100644 vendor/guzzle/guzzle/tests/Guzzle/Tests/Plugin/ErrorResponse/ErrorResponsePluginTest.php create mode 100644 vendor/guzzle/guzzle/tests/Guzzle/Tests/Plugin/History/HistoryPluginTest.php create mode 100644 vendor/guzzle/guzzle/tests/Guzzle/Tests/Plugin/Log/LogPluginTest.php create mode 100644 vendor/guzzle/guzzle/tests/Guzzle/Tests/Plugin/Md5/CommandContentMd5PluginTest.php create mode 100644 vendor/guzzle/guzzle/tests/Guzzle/Tests/Plugin/Md5/Md5ValidatorPluginTest.php create mode 100644 vendor/guzzle/guzzle/tests/Guzzle/Tests/Plugin/Mock/MockPluginTest.php create mode 100644 vendor/guzzle/guzzle/tests/Guzzle/Tests/Plugin/Oauth/OauthPluginTest.php create mode 100644 vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/AbstractConfigLoaderTest.php create mode 100644 vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Builder/ServiceBuilderLoaderTest.php create mode 100644 vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Builder/ServiceBuilderTest.php create mode 100644 vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/CachingConfigLoaderTest.php create mode 100644 vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/ClientTest.php create mode 100644 vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Command/AbstractCommandTest.php create mode 100644 vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Command/ClosureCommandTest.php create mode 100644 vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Command/CommandTest.php create mode 100644 vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Command/DefaultRequestSerializerTest.php create mode 100644 vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Command/DefaultResponseParserTest.php create mode 100644 vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Command/Factory/AliasFactoryTest.php create mode 100644 vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Command/Factory/CompositeFactoryTest.php create mode 100644 vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Command/Factory/ConcreteClassFactoryTest.php create mode 100644 vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Command/Factory/MapFactoryTest.php create mode 100644 vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Command/Factory/ServiceDescriptionFactoryTest.php create mode 100644 vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Command/LocationVisitor/Request/AbstractVisitorTestCase.php create mode 100644 vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Command/LocationVisitor/Request/BodyVisitorTest.php create mode 100644 vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Command/LocationVisitor/Request/HeaderVisitorTest.php create mode 100644 vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Command/LocationVisitor/Request/JsonVisitorTest.php create mode 100644 vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Command/LocationVisitor/Request/PostFieldVisitorTest.php create mode 100644 vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Command/LocationVisitor/Request/PostFileVisitorTest.php create mode 100644 vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Command/LocationVisitor/Request/QueryVisitorTest.php create mode 100644 vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Command/LocationVisitor/Request/ResponseBodyVisitorTest.php create mode 100644 vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Command/LocationVisitor/Request/XmlVisitorTest.php create mode 100644 vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Command/LocationVisitor/Response/AbstractResponseVisitorTest.php create mode 100644 vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Command/LocationVisitor/Response/BodyVisitorTest.php create mode 100644 vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Command/LocationVisitor/Response/HeaderVisitorTest.php create mode 100644 vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Command/LocationVisitor/Response/JsonVisitorTest.php create mode 100644 vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Command/LocationVisitor/Response/ReasonPhraseVisitorTest.php create mode 100644 vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Command/LocationVisitor/Response/StatusCodeVisitorTest.php create mode 100644 vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Command/LocationVisitor/Response/XmlVisitorTest.php create mode 100644 vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Command/LocationVisitor/VisitorFlyweightTest.php create mode 100644 vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Command/OperationCommandTest.php create mode 100644 vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Command/OperationResponseParserTest.php create mode 100644 vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Description/OperationTest.php create mode 100644 vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Description/ParameterTest.php create mode 100644 vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Description/SchemaFormatterTest.php create mode 100644 vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Description/SchemaValidatorTest.php create mode 100644 vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Description/ServiceDescriptionLoaderTest.php create mode 100644 vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Description/ServiceDescriptionTest.php create mode 100644 vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Exception/CommandTransferExceptionTest.php create mode 100644 vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Exception/InconsistentClientTransferExceptionTest.php create mode 100644 vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Exception/ValidationExceptionTest.php create mode 100644 vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Mock/Command/IterableCommand.php create mode 100644 vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Mock/Command/MockCommand.php create mode 100644 vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Mock/Command/OtherCommand.php create mode 100644 vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Mock/Command/Sub/Sub.php create mode 100644 vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Mock/MockClient.php create mode 100644 vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Mock/Model/MockCommandIterator.php create mode 100644 vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Resource/CompositeResourceIteratorFactoryTest.php create mode 100644 vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Resource/MapResourceIteratorFactoryTest.php create mode 100644 vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Resource/ModelTest.php create mode 100644 vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Resource/ResourceIteratorClassFactoryTest.php create mode 100644 vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Resource/ResourceIteratorTest.php create mode 100644 vendor/guzzle/guzzle/tests/Guzzle/Tests/Stream/PhpStreamRequestFactoryTest.php create mode 100644 vendor/guzzle/guzzle/tests/Guzzle/Tests/Stream/StreamTest.php create mode 100644 vendor/guzzle/guzzle/tests/Guzzle/Tests/TestData/FileBody.txt create mode 100644 vendor/guzzle/guzzle/tests/Guzzle/Tests/TestData/description/bar.json create mode 100644 vendor/guzzle/guzzle/tests/Guzzle/Tests/TestData/description/baz.json create mode 100644 vendor/guzzle/guzzle/tests/Guzzle/Tests/TestData/description/foo.json create mode 100644 vendor/guzzle/guzzle/tests/Guzzle/Tests/TestData/description/recursive.json create mode 100644 vendor/guzzle/guzzle/tests/Guzzle/Tests/TestData/mock_response create mode 100644 vendor/guzzle/guzzle/tests/Guzzle/Tests/TestData/services/json1.json create mode 100644 vendor/guzzle/guzzle/tests/Guzzle/Tests/TestData/services/json2.json create mode 100644 vendor/guzzle/guzzle/tests/Guzzle/Tests/TestData/services/services.json create mode 100644 vendor/guzzle/guzzle/tests/Guzzle/Tests/TestData/test_service.json create mode 100644 vendor/guzzle/guzzle/tests/Guzzle/Tests/TestData/test_service2.json create mode 100644 vendor/guzzle/guzzle/tests/Guzzle/Tests/TestData/test_service_3.json create mode 100644 vendor/guzzle/guzzle/tests/bootstrap.php create mode 100644 vendor/poweredbycoffee/slack-notifier/.gitignore create mode 100644 vendor/poweredbycoffee/slack-notifier/.travis.yml create mode 100644 vendor/poweredbycoffee/slack-notifier/LICENSE create mode 100644 vendor/poweredbycoffee/slack-notifier/README.md create mode 100755 vendor/poweredbycoffee/slack-notifier/bin/slack create mode 100644 vendor/poweredbycoffee/slack-notifier/composer.json create mode 100644 vendor/poweredbycoffee/slack-notifier/phpunit.xml.dist create mode 100644 vendor/poweredbycoffee/slack-notifier/src/Slack/Client.php create mode 100644 vendor/poweredbycoffee/slack-notifier/src/Slack/Command/NotifierCommand.php create mode 100644 vendor/poweredbycoffee/slack-notifier/src/Slack/Message/Message.php create mode 100644 vendor/poweredbycoffee/slack-notifier/src/Slack/Message/MessageAttachment.php create mode 100644 vendor/poweredbycoffee/slack-notifier/src/Slack/Message/MessageField.php create mode 100644 vendor/poweredbycoffee/slack-notifier/src/Slack/Message/MessageInterface.php create mode 100644 vendor/poweredbycoffee/slack-notifier/src/Slack/Notifier.php create mode 100644 vendor/poweredbycoffee/slack-notifier/src/Slack/Serializer/Normalizer/GetSetMethodNormalizer.php create mode 100644 vendor/poweredbycoffee/slack-notifier/tests/Slack/Test/Command/NotifierCommandTest.php create mode 100644 vendor/poweredbycoffee/slack-notifier/tests/Slack/Test/NotifierTest.php create mode 100644 vendor/poweredbycoffee/slack-notifier/tests/bootstrap.php create mode 100644 vendor/symfony/console/.gitignore create mode 100644 vendor/symfony/console/Application.php create mode 100644 vendor/symfony/console/CHANGELOG.md create mode 100644 vendor/symfony/console/Command/Command.php create mode 100644 vendor/symfony/console/Command/HelpCommand.php create mode 100644 vendor/symfony/console/Command/ListCommand.php create mode 100644 vendor/symfony/console/ConsoleEvents.php create mode 100644 vendor/symfony/console/Descriptor/ApplicationDescription.php create mode 100644 vendor/symfony/console/Descriptor/Descriptor.php create mode 100644 vendor/symfony/console/Descriptor/DescriptorInterface.php create mode 100644 vendor/symfony/console/Descriptor/JsonDescriptor.php create mode 100644 vendor/symfony/console/Descriptor/MarkdownDescriptor.php create mode 100644 vendor/symfony/console/Descriptor/TextDescriptor.php create mode 100644 vendor/symfony/console/Descriptor/XmlDescriptor.php create mode 100644 vendor/symfony/console/Event/ConsoleCommandEvent.php create mode 100644 vendor/symfony/console/Event/ConsoleEvent.php create mode 100644 vendor/symfony/console/Event/ConsoleExceptionEvent.php create mode 100644 vendor/symfony/console/Event/ConsoleTerminateEvent.php create mode 100644 vendor/symfony/console/Formatter/OutputFormatter.php create mode 100644 vendor/symfony/console/Formatter/OutputFormatterInterface.php create mode 100644 vendor/symfony/console/Formatter/OutputFormatterStyle.php create mode 100644 vendor/symfony/console/Formatter/OutputFormatterStyleInterface.php create mode 100644 vendor/symfony/console/Formatter/OutputFormatterStyleStack.php create mode 100644 vendor/symfony/console/Helper/DebugFormatterHelper.php create mode 100644 vendor/symfony/console/Helper/DescriptorHelper.php create mode 100644 vendor/symfony/console/Helper/DialogHelper.php create mode 100644 vendor/symfony/console/Helper/FormatterHelper.php create mode 100644 vendor/symfony/console/Helper/Helper.php create mode 100644 vendor/symfony/console/Helper/HelperInterface.php create mode 100644 vendor/symfony/console/Helper/HelperSet.php create mode 100644 vendor/symfony/console/Helper/InputAwareHelper.php create mode 100644 vendor/symfony/console/Helper/ProcessHelper.php create mode 100644 vendor/symfony/console/Helper/ProgressBar.php create mode 100644 vendor/symfony/console/Helper/ProgressHelper.php create mode 100644 vendor/symfony/console/Helper/QuestionHelper.php create mode 100644 vendor/symfony/console/Helper/SymfonyQuestionHelper.php create mode 100644 vendor/symfony/console/Helper/Table.php create mode 100644 vendor/symfony/console/Helper/TableCell.php create mode 100644 vendor/symfony/console/Helper/TableHelper.php create mode 100644 vendor/symfony/console/Helper/TableSeparator.php create mode 100644 vendor/symfony/console/Helper/TableStyle.php create mode 100644 vendor/symfony/console/Input/ArgvInput.php create mode 100644 vendor/symfony/console/Input/ArrayInput.php create mode 100644 vendor/symfony/console/Input/Input.php create mode 100644 vendor/symfony/console/Input/InputArgument.php create mode 100644 vendor/symfony/console/Input/InputAwareInterface.php create mode 100644 vendor/symfony/console/Input/InputDefinition.php create mode 100644 vendor/symfony/console/Input/InputInterface.php create mode 100644 vendor/symfony/console/Input/InputOption.php create mode 100644 vendor/symfony/console/Input/StringInput.php create mode 100644 vendor/symfony/console/LICENSE create mode 100644 vendor/symfony/console/Logger/ConsoleLogger.php create mode 100644 vendor/symfony/console/Output/BufferedOutput.php create mode 100644 vendor/symfony/console/Output/ConsoleOutput.php create mode 100644 vendor/symfony/console/Output/ConsoleOutputInterface.php create mode 100644 vendor/symfony/console/Output/NullOutput.php create mode 100644 vendor/symfony/console/Output/Output.php create mode 100644 vendor/symfony/console/Output/OutputInterface.php create mode 100644 vendor/symfony/console/Output/StreamOutput.php create mode 100644 vendor/symfony/console/Question/ChoiceQuestion.php create mode 100644 vendor/symfony/console/Question/ConfirmationQuestion.php create mode 100644 vendor/symfony/console/Question/Question.php create mode 100644 vendor/symfony/console/README.md create mode 100644 vendor/symfony/console/Resources/bin/hiddeninput.exe create mode 100644 vendor/symfony/console/Shell.php create mode 100644 vendor/symfony/console/Style/OutputStyle.php create mode 100644 vendor/symfony/console/Style/StyleInterface.php create mode 100644 vendor/symfony/console/Style/SymfonyStyle.php create mode 100644 vendor/symfony/console/Tester/ApplicationTester.php create mode 100644 vendor/symfony/console/Tester/CommandTester.php create mode 100644 vendor/symfony/console/Tests/ApplicationTest.php create mode 100644 vendor/symfony/console/Tests/Command/CommandTest.php create mode 100644 vendor/symfony/console/Tests/Command/HelpCommandTest.php create mode 100644 vendor/symfony/console/Tests/Command/ListCommandTest.php create mode 100644 vendor/symfony/console/Tests/Descriptor/AbstractDescriptorTest.php create mode 100644 vendor/symfony/console/Tests/Descriptor/JsonDescriptorTest.php create mode 100644 vendor/symfony/console/Tests/Descriptor/MarkdownDescriptorTest.php create mode 100644 vendor/symfony/console/Tests/Descriptor/ObjectsProvider.php create mode 100644 vendor/symfony/console/Tests/Descriptor/TextDescriptorTest.php create mode 100644 vendor/symfony/console/Tests/Descriptor/XmlDescriptorTest.php create mode 100644 vendor/symfony/console/Tests/Fixtures/BarBucCommand.php create mode 100644 vendor/symfony/console/Tests/Fixtures/DescriptorApplication1.php create mode 100644 vendor/symfony/console/Tests/Fixtures/DescriptorApplication2.php create mode 100644 vendor/symfony/console/Tests/Fixtures/DescriptorCommand1.php create mode 100644 vendor/symfony/console/Tests/Fixtures/DescriptorCommand2.php create mode 100644 vendor/symfony/console/Tests/Fixtures/DummyOutput.php create mode 100644 vendor/symfony/console/Tests/Fixtures/Foo1Command.php create mode 100644 vendor/symfony/console/Tests/Fixtures/Foo2Command.php create mode 100644 vendor/symfony/console/Tests/Fixtures/Foo3Command.php create mode 100644 vendor/symfony/console/Tests/Fixtures/Foo4Command.php create mode 100644 vendor/symfony/console/Tests/Fixtures/Foo5Command.php create mode 100644 vendor/symfony/console/Tests/Fixtures/FooCommand.php create mode 100644 vendor/symfony/console/Tests/Fixtures/FooSubnamespaced1Command.php create mode 100644 vendor/symfony/console/Tests/Fixtures/FooSubnamespaced2Command.php create mode 100644 vendor/symfony/console/Tests/Fixtures/FoobarCommand.php create mode 100644 vendor/symfony/console/Tests/Fixtures/Style/SymfonyStyle/command/command_0.php create mode 100644 vendor/symfony/console/Tests/Fixtures/Style/SymfonyStyle/command/command_1.php create mode 100644 vendor/symfony/console/Tests/Fixtures/Style/SymfonyStyle/command/command_2.php create mode 100644 vendor/symfony/console/Tests/Fixtures/Style/SymfonyStyle/command/command_3.php create mode 100644 vendor/symfony/console/Tests/Fixtures/Style/SymfonyStyle/command/command_4.php create mode 100644 vendor/symfony/console/Tests/Fixtures/Style/SymfonyStyle/command/command_5.php create mode 100644 vendor/symfony/console/Tests/Fixtures/Style/SymfonyStyle/command/command_6.php create mode 100644 vendor/symfony/console/Tests/Fixtures/Style/SymfonyStyle/command/command_7.php create mode 100644 vendor/symfony/console/Tests/Fixtures/Style/SymfonyStyle/output/output_0.txt create mode 100644 vendor/symfony/console/Tests/Fixtures/Style/SymfonyStyle/output/output_1.txt create mode 100644 vendor/symfony/console/Tests/Fixtures/Style/SymfonyStyle/output/output_2.txt create mode 100644 vendor/symfony/console/Tests/Fixtures/Style/SymfonyStyle/output/output_3.txt create mode 100644 vendor/symfony/console/Tests/Fixtures/Style/SymfonyStyle/output/output_4.txt create mode 100644 vendor/symfony/console/Tests/Fixtures/Style/SymfonyStyle/output/output_5.txt create mode 100644 vendor/symfony/console/Tests/Fixtures/Style/SymfonyStyle/output/output_6.txt create mode 100644 vendor/symfony/console/Tests/Fixtures/Style/SymfonyStyle/output/output_7.txt create mode 100644 vendor/symfony/console/Tests/Fixtures/TestCommand.php create mode 100644 vendor/symfony/console/Tests/Fixtures/application_1.json create mode 100644 vendor/symfony/console/Tests/Fixtures/application_1.md create mode 100644 vendor/symfony/console/Tests/Fixtures/application_1.txt create mode 100644 vendor/symfony/console/Tests/Fixtures/application_1.xml create mode 100644 vendor/symfony/console/Tests/Fixtures/application_2.json create mode 100644 vendor/symfony/console/Tests/Fixtures/application_2.md create mode 100644 vendor/symfony/console/Tests/Fixtures/application_2.txt create mode 100644 vendor/symfony/console/Tests/Fixtures/application_2.xml create mode 100644 vendor/symfony/console/Tests/Fixtures/application_astext1.txt create mode 100644 vendor/symfony/console/Tests/Fixtures/application_astext2.txt create mode 100644 vendor/symfony/console/Tests/Fixtures/application_asxml1.txt create mode 100644 vendor/symfony/console/Tests/Fixtures/application_asxml2.txt create mode 100644 vendor/symfony/console/Tests/Fixtures/application_gethelp.txt create mode 100644 vendor/symfony/console/Tests/Fixtures/application_renderexception1.txt create mode 100644 vendor/symfony/console/Tests/Fixtures/application_renderexception2.txt create mode 100644 vendor/symfony/console/Tests/Fixtures/application_renderexception3.txt create mode 100644 vendor/symfony/console/Tests/Fixtures/application_renderexception3decorated.txt create mode 100644 vendor/symfony/console/Tests/Fixtures/application_renderexception4.txt create mode 100644 vendor/symfony/console/Tests/Fixtures/application_renderexception_doublewidth1.txt create mode 100644 vendor/symfony/console/Tests/Fixtures/application_renderexception_doublewidth1decorated.txt create mode 100644 vendor/symfony/console/Tests/Fixtures/application_renderexception_doublewidth2.txt create mode 100644 vendor/symfony/console/Tests/Fixtures/application_run1.txt create mode 100644 vendor/symfony/console/Tests/Fixtures/application_run2.txt create mode 100644 vendor/symfony/console/Tests/Fixtures/application_run3.txt create mode 100644 vendor/symfony/console/Tests/Fixtures/application_run4.txt create mode 100644 vendor/symfony/console/Tests/Fixtures/command_1.json create mode 100644 vendor/symfony/console/Tests/Fixtures/command_1.md create mode 100644 vendor/symfony/console/Tests/Fixtures/command_1.txt create mode 100644 vendor/symfony/console/Tests/Fixtures/command_1.xml create mode 100644 vendor/symfony/console/Tests/Fixtures/command_2.json create mode 100644 vendor/symfony/console/Tests/Fixtures/command_2.md create mode 100644 vendor/symfony/console/Tests/Fixtures/command_2.txt create mode 100644 vendor/symfony/console/Tests/Fixtures/command_2.xml create mode 100644 vendor/symfony/console/Tests/Fixtures/command_astext.txt create mode 100644 vendor/symfony/console/Tests/Fixtures/command_asxml.txt create mode 100644 vendor/symfony/console/Tests/Fixtures/definition_astext.txt create mode 100644 vendor/symfony/console/Tests/Fixtures/definition_asxml.txt create mode 100644 vendor/symfony/console/Tests/Fixtures/input_argument_1.json create mode 100644 vendor/symfony/console/Tests/Fixtures/input_argument_1.md create mode 100644 vendor/symfony/console/Tests/Fixtures/input_argument_1.txt create mode 100644 vendor/symfony/console/Tests/Fixtures/input_argument_1.xml create mode 100644 vendor/symfony/console/Tests/Fixtures/input_argument_2.json create mode 100644 vendor/symfony/console/Tests/Fixtures/input_argument_2.md create mode 100644 vendor/symfony/console/Tests/Fixtures/input_argument_2.txt create mode 100644 vendor/symfony/console/Tests/Fixtures/input_argument_2.xml create mode 100644 vendor/symfony/console/Tests/Fixtures/input_argument_3.json create mode 100644 vendor/symfony/console/Tests/Fixtures/input_argument_3.md create mode 100644 vendor/symfony/console/Tests/Fixtures/input_argument_3.txt create mode 100644 vendor/symfony/console/Tests/Fixtures/input_argument_3.xml create mode 100644 vendor/symfony/console/Tests/Fixtures/input_argument_4.json create mode 100644 vendor/symfony/console/Tests/Fixtures/input_argument_4.md create mode 100644 vendor/symfony/console/Tests/Fixtures/input_argument_4.txt create mode 100644 vendor/symfony/console/Tests/Fixtures/input_argument_4.xml create mode 100644 vendor/symfony/console/Tests/Fixtures/input_definition_1.json create mode 100644 vendor/symfony/console/Tests/Fixtures/input_definition_1.md create mode 100644 vendor/symfony/console/Tests/Fixtures/input_definition_1.txt create mode 100644 vendor/symfony/console/Tests/Fixtures/input_definition_1.xml create mode 100644 vendor/symfony/console/Tests/Fixtures/input_definition_2.json create mode 100644 vendor/symfony/console/Tests/Fixtures/input_definition_2.md create mode 100644 vendor/symfony/console/Tests/Fixtures/input_definition_2.txt create mode 100644 vendor/symfony/console/Tests/Fixtures/input_definition_2.xml create mode 100644 vendor/symfony/console/Tests/Fixtures/input_definition_3.json create mode 100644 vendor/symfony/console/Tests/Fixtures/input_definition_3.md create mode 100644 vendor/symfony/console/Tests/Fixtures/input_definition_3.txt create mode 100644 vendor/symfony/console/Tests/Fixtures/input_definition_3.xml create mode 100644 vendor/symfony/console/Tests/Fixtures/input_definition_4.json create mode 100644 vendor/symfony/console/Tests/Fixtures/input_definition_4.md create mode 100644 vendor/symfony/console/Tests/Fixtures/input_definition_4.txt create mode 100644 vendor/symfony/console/Tests/Fixtures/input_definition_4.xml create mode 100644 vendor/symfony/console/Tests/Fixtures/input_option_1.json create mode 100644 vendor/symfony/console/Tests/Fixtures/input_option_1.md create mode 100644 vendor/symfony/console/Tests/Fixtures/input_option_1.txt create mode 100644 vendor/symfony/console/Tests/Fixtures/input_option_1.xml create mode 100644 vendor/symfony/console/Tests/Fixtures/input_option_2.json create mode 100644 vendor/symfony/console/Tests/Fixtures/input_option_2.md create mode 100644 vendor/symfony/console/Tests/Fixtures/input_option_2.txt create mode 100644 vendor/symfony/console/Tests/Fixtures/input_option_2.xml create mode 100644 vendor/symfony/console/Tests/Fixtures/input_option_3.json create mode 100644 vendor/symfony/console/Tests/Fixtures/input_option_3.md create mode 100644 vendor/symfony/console/Tests/Fixtures/input_option_3.txt create mode 100644 vendor/symfony/console/Tests/Fixtures/input_option_3.xml create mode 100644 vendor/symfony/console/Tests/Fixtures/input_option_4.json create mode 100644 vendor/symfony/console/Tests/Fixtures/input_option_4.md create mode 100644 vendor/symfony/console/Tests/Fixtures/input_option_4.txt create mode 100644 vendor/symfony/console/Tests/Fixtures/input_option_4.xml create mode 100644 vendor/symfony/console/Tests/Fixtures/input_option_5.json create mode 100644 vendor/symfony/console/Tests/Fixtures/input_option_5.md create mode 100644 vendor/symfony/console/Tests/Fixtures/input_option_5.txt create mode 100644 vendor/symfony/console/Tests/Fixtures/input_option_5.xml create mode 100644 vendor/symfony/console/Tests/Fixtures/input_option_6.json create mode 100644 vendor/symfony/console/Tests/Fixtures/input_option_6.md create mode 100644 vendor/symfony/console/Tests/Fixtures/input_option_6.txt create mode 100644 vendor/symfony/console/Tests/Fixtures/input_option_6.xml create mode 100644 vendor/symfony/console/Tests/Formatter/OutputFormatterStyleStackTest.php create mode 100644 vendor/symfony/console/Tests/Formatter/OutputFormatterStyleTest.php create mode 100644 vendor/symfony/console/Tests/Formatter/OutputFormatterTest.php create mode 100644 vendor/symfony/console/Tests/Helper/FormatterHelperTest.php create mode 100644 vendor/symfony/console/Tests/Helper/HelperSetTest.php create mode 100644 vendor/symfony/console/Tests/Helper/LegacyDialogHelperTest.php create mode 100644 vendor/symfony/console/Tests/Helper/LegacyProgressHelperTest.php create mode 100644 vendor/symfony/console/Tests/Helper/LegacyTableHelperTest.php create mode 100644 vendor/symfony/console/Tests/Helper/ProcessHelperTest.php create mode 100644 vendor/symfony/console/Tests/Helper/ProgressBarTest.php create mode 100644 vendor/symfony/console/Tests/Helper/QuestionHelperTest.php create mode 100644 vendor/symfony/console/Tests/Helper/TableStyleTest.php create mode 100644 vendor/symfony/console/Tests/Helper/TableTest.php create mode 100644 vendor/symfony/console/Tests/Input/ArgvInputTest.php create mode 100644 vendor/symfony/console/Tests/Input/ArrayInputTest.php create mode 100644 vendor/symfony/console/Tests/Input/InputArgumentTest.php create mode 100644 vendor/symfony/console/Tests/Input/InputDefinitionTest.php create mode 100644 vendor/symfony/console/Tests/Input/InputOptionTest.php create mode 100644 vendor/symfony/console/Tests/Input/InputTest.php create mode 100644 vendor/symfony/console/Tests/Input/StringInputTest.php create mode 100644 vendor/symfony/console/Tests/Logger/ConsoleLoggerTest.php create mode 100644 vendor/symfony/console/Tests/Output/ConsoleOutputTest.php create mode 100644 vendor/symfony/console/Tests/Output/NullOutputTest.php create mode 100644 vendor/symfony/console/Tests/Output/OutputTest.php create mode 100644 vendor/symfony/console/Tests/Output/StreamOutputTest.php create mode 100644 vendor/symfony/console/Tests/Style/SymfonyStyleTest.php create mode 100644 vendor/symfony/console/Tests/Tester/ApplicationTesterTest.php create mode 100644 vendor/symfony/console/Tests/Tester/CommandTesterTest.php create mode 100644 vendor/symfony/console/composer.json create mode 100644 vendor/symfony/console/phpunit.xml.dist create mode 100644 vendor/symfony/event-dispatcher/.gitignore create mode 100644 vendor/symfony/event-dispatcher/CHANGELOG.md create mode 100644 vendor/symfony/event-dispatcher/ContainerAwareEventDispatcher.php create mode 100644 vendor/symfony/event-dispatcher/Debug/TraceableEventDispatcher.php create mode 100644 vendor/symfony/event-dispatcher/Debug/TraceableEventDispatcherInterface.php create mode 100644 vendor/symfony/event-dispatcher/Debug/WrappedListener.php create mode 100644 vendor/symfony/event-dispatcher/DependencyInjection/RegisterListenersPass.php create mode 100644 vendor/symfony/event-dispatcher/Event.php create mode 100644 vendor/symfony/event-dispatcher/EventDispatcher.php create mode 100644 vendor/symfony/event-dispatcher/EventDispatcherInterface.php create mode 100644 vendor/symfony/event-dispatcher/EventSubscriberInterface.php create mode 100644 vendor/symfony/event-dispatcher/GenericEvent.php create mode 100644 vendor/symfony/event-dispatcher/ImmutableEventDispatcher.php create mode 100644 vendor/symfony/event-dispatcher/LICENSE create mode 100644 vendor/symfony/event-dispatcher/README.md create mode 100644 vendor/symfony/event-dispatcher/Tests/AbstractEventDispatcherTest.php create mode 100644 vendor/symfony/event-dispatcher/Tests/ContainerAwareEventDispatcherTest.php create mode 100644 vendor/symfony/event-dispatcher/Tests/Debug/TraceableEventDispatcherTest.php create mode 100644 vendor/symfony/event-dispatcher/Tests/DependencyInjection/RegisterListenersPassTest.php create mode 100644 vendor/symfony/event-dispatcher/Tests/EventDispatcherTest.php create mode 100644 vendor/symfony/event-dispatcher/Tests/EventTest.php create mode 100644 vendor/symfony/event-dispatcher/Tests/GenericEventTest.php create mode 100644 vendor/symfony/event-dispatcher/Tests/ImmutableEventDispatcherTest.php create mode 100644 vendor/symfony/event-dispatcher/composer.json create mode 100644 vendor/symfony/event-dispatcher/phpunit.xml.dist create mode 100644 vendor/symfony/serializer/.gitignore create mode 100644 vendor/symfony/serializer/Annotation/Groups.php create mode 100644 vendor/symfony/serializer/CHANGELOG.md create mode 100644 vendor/symfony/serializer/Encoder/ChainDecoder.php create mode 100644 vendor/symfony/serializer/Encoder/ChainEncoder.php create mode 100644 vendor/symfony/serializer/Encoder/DecoderInterface.php create mode 100644 vendor/symfony/serializer/Encoder/EncoderInterface.php create mode 100644 vendor/symfony/serializer/Encoder/JsonDecode.php create mode 100644 vendor/symfony/serializer/Encoder/JsonEncode.php create mode 100644 vendor/symfony/serializer/Encoder/JsonEncoder.php create mode 100644 vendor/symfony/serializer/Encoder/NormalizationAwareInterface.php create mode 100644 vendor/symfony/serializer/Encoder/SerializerAwareEncoder.php create mode 100644 vendor/symfony/serializer/Encoder/XmlEncoder.php create mode 100644 vendor/symfony/serializer/Exception/CircularReferenceException.php create mode 100644 vendor/symfony/serializer/Exception/Exception.php create mode 100644 vendor/symfony/serializer/Exception/ExceptionInterface.php create mode 100644 vendor/symfony/serializer/Exception/InvalidArgumentException.php create mode 100644 vendor/symfony/serializer/Exception/LogicException.php create mode 100644 vendor/symfony/serializer/Exception/MappingException.php create mode 100644 vendor/symfony/serializer/Exception/RuntimeException.php create mode 100644 vendor/symfony/serializer/Exception/UnexpectedValueException.php create mode 100644 vendor/symfony/serializer/Exception/UnsupportedException.php create mode 100644 vendor/symfony/serializer/LICENSE create mode 100644 vendor/symfony/serializer/Mapping/AttributeMetadata.php create mode 100644 vendor/symfony/serializer/Mapping/AttributeMetadataInterface.php create mode 100644 vendor/symfony/serializer/Mapping/ClassMetadata.php create mode 100644 vendor/symfony/serializer/Mapping/ClassMetadataInterface.php create mode 100644 vendor/symfony/serializer/Mapping/Factory/ClassMetadataFactory.php create mode 100644 vendor/symfony/serializer/Mapping/Factory/ClassMetadataFactoryInterface.php create mode 100644 vendor/symfony/serializer/Mapping/Loader/AnnotationLoader.php create mode 100644 vendor/symfony/serializer/Mapping/Loader/FileLoader.php create mode 100644 vendor/symfony/serializer/Mapping/Loader/LoaderChain.php create mode 100644 vendor/symfony/serializer/Mapping/Loader/LoaderInterface.php create mode 100644 vendor/symfony/serializer/Mapping/Loader/XmlFileLoader.php create mode 100644 vendor/symfony/serializer/Mapping/Loader/YamlFileLoader.php create mode 100644 vendor/symfony/serializer/Mapping/Loader/schema/dic/serializer-mapping/serializer-mapping-1.0.xsd create mode 100644 vendor/symfony/serializer/NameConverter/CamelCaseToSnakeCaseNameConverter.php create mode 100644 vendor/symfony/serializer/NameConverter/NameConverterInterface.php create mode 100644 vendor/symfony/serializer/Normalizer/AbstractNormalizer.php create mode 100644 vendor/symfony/serializer/Normalizer/CustomNormalizer.php create mode 100644 vendor/symfony/serializer/Normalizer/DenormalizableInterface.php create mode 100644 vendor/symfony/serializer/Normalizer/DenormalizerInterface.php create mode 100644 vendor/symfony/serializer/Normalizer/GetSetMethodNormalizer.php create mode 100644 vendor/symfony/serializer/Normalizer/NormalizableInterface.php create mode 100644 vendor/symfony/serializer/Normalizer/NormalizerInterface.php create mode 100644 vendor/symfony/serializer/Normalizer/ObjectNormalizer.php create mode 100644 vendor/symfony/serializer/Normalizer/PropertyNormalizer.php create mode 100644 vendor/symfony/serializer/Normalizer/SerializerAwareNormalizer.php create mode 100644 vendor/symfony/serializer/README.md create mode 100644 vendor/symfony/serializer/Serializer.php create mode 100644 vendor/symfony/serializer/SerializerAwareInterface.php create mode 100644 vendor/symfony/serializer/SerializerInterface.php create mode 100644 vendor/symfony/serializer/Tests/Annotation/GroupsTest.php create mode 100644 vendor/symfony/serializer/Tests/Encoder/JsonEncoderTest.php create mode 100644 vendor/symfony/serializer/Tests/Encoder/XmlEncoderTest.php create mode 100644 vendor/symfony/serializer/Tests/Fixtures/CircularReferenceDummy.php create mode 100644 vendor/symfony/serializer/Tests/Fixtures/DenormalizableDummy.php create mode 100644 vendor/symfony/serializer/Tests/Fixtures/Dummy.php create mode 100644 vendor/symfony/serializer/Tests/Fixtures/GroupDummy.php create mode 100644 vendor/symfony/serializer/Tests/Fixtures/GroupDummyInterface.php create mode 100644 vendor/symfony/serializer/Tests/Fixtures/GroupDummyParent.php create mode 100644 vendor/symfony/serializer/Tests/Fixtures/NormalizableTraversableDummy.php create mode 100644 vendor/symfony/serializer/Tests/Fixtures/PropertyCircularReferenceDummy.php create mode 100644 vendor/symfony/serializer/Tests/Fixtures/PropertySiblingHolder.php create mode 100644 vendor/symfony/serializer/Tests/Fixtures/ScalarDummy.php create mode 100644 vendor/symfony/serializer/Tests/Fixtures/SiblingHolder.php create mode 100644 vendor/symfony/serializer/Tests/Fixtures/TraversableDummy.php create mode 100644 vendor/symfony/serializer/Tests/Fixtures/VariadicConstructorArgsDummy.php create mode 100644 vendor/symfony/serializer/Tests/Fixtures/empty-mapping.yml create mode 100644 vendor/symfony/serializer/Tests/Fixtures/invalid-mapping.yml create mode 100644 vendor/symfony/serializer/Tests/Fixtures/serialization.xml create mode 100644 vendor/symfony/serializer/Tests/Fixtures/serialization.yml create mode 100644 vendor/symfony/serializer/Tests/Mapping/AttributeMetadataTest.php create mode 100644 vendor/symfony/serializer/Tests/Mapping/ClassMetadataTest.php create mode 100644 vendor/symfony/serializer/Tests/Mapping/Factory/ClassMetadataFactoryTest.php create mode 100644 vendor/symfony/serializer/Tests/Mapping/Loader/AnnotationLoaderTest.php create mode 100644 vendor/symfony/serializer/Tests/Mapping/Loader/XmlFileLoaderTest.php create mode 100644 vendor/symfony/serializer/Tests/Mapping/Loader/YamlFileLoaderTest.php create mode 100644 vendor/symfony/serializer/Tests/Mapping/TestClassMetadataFactory.php create mode 100644 vendor/symfony/serializer/Tests/NameConverter/CamelCaseToSnakeCaseNameConverterTest.php create mode 100644 vendor/symfony/serializer/Tests/Normalizer/CustomNormalizerTest.php create mode 100644 vendor/symfony/serializer/Tests/Normalizer/GetSetMethodNormalizerTest.php create mode 100644 vendor/symfony/serializer/Tests/Normalizer/ObjectNormalizerTest.php create mode 100644 vendor/symfony/serializer/Tests/Normalizer/PropertyNormalizerTest.php create mode 100644 vendor/symfony/serializer/Tests/Normalizer/TestDenormalizer.php create mode 100644 vendor/symfony/serializer/Tests/Normalizer/TestNormalizer.php create mode 100644 vendor/symfony/serializer/Tests/SerializerTest.php create mode 100644 vendor/symfony/serializer/composer.json create mode 100644 vendor/symfony/serializer/phpunit.xml.dist diff --git a/.gitignore b/.gitignore index 22d0d82..3fa5b2b 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,3 @@ -vendor +.DS_Store +composer.lock + diff --git a/vendor/autoload.php b/vendor/autoload.php new file mode 100644 index 0000000..0d1e09e --- /dev/null +++ b/vendor/autoload.php @@ -0,0 +1,7 @@ + + * Jordi Boggiano + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Composer\Autoload; + +/** + * ClassLoader implements a PSR-0 class loader + * + * See https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-0.md + * + * $loader = new \Composer\Autoload\ClassLoader(); + * + * // register classes with namespaces + * $loader->add('Symfony\Component', __DIR__.'/component'); + * $loader->add('Symfony', __DIR__.'/framework'); + * + * // activate the autoloader + * $loader->register(); + * + * // to enable searching the include path (eg. for PEAR packages) + * $loader->setUseIncludePath(true); + * + * In this example, if you try to use a class in the Symfony\Component + * namespace or one of its children (Symfony\Component\Console for instance), + * the autoloader will first look for the class under the component/ + * directory, and it will then fallback to the framework/ directory if not + * found before giving up. + * + * This class is loosely based on the Symfony UniversalClassLoader. + * + * @author Fabien Potencier + * @author Jordi Boggiano + */ +class ClassLoader +{ + // PSR-4 + private $prefixLengthsPsr4 = array(); + private $prefixDirsPsr4 = array(); + private $fallbackDirsPsr4 = array(); + + // PSR-0 + private $prefixesPsr0 = array(); + private $fallbackDirsPsr0 = array(); + + private $useIncludePath = false; + private $classMap = array(); + + private $classMapAuthoritative = false; + + public function getPrefixes() + { + if (!empty($this->prefixesPsr0)) { + return call_user_func_array('array_merge', $this->prefixesPsr0); + } + + return array(); + } + + public function getPrefixesPsr4() + { + return $this->prefixDirsPsr4; + } + + public function getFallbackDirs() + { + return $this->fallbackDirsPsr0; + } + + public function getFallbackDirsPsr4() + { + return $this->fallbackDirsPsr4; + } + + public function getClassMap() + { + return $this->classMap; + } + + /** + * @param array $classMap Class to filename map + */ + public function addClassMap(array $classMap) + { + if ($this->classMap) { + $this->classMap = array_merge($this->classMap, $classMap); + } else { + $this->classMap = $classMap; + } + } + + /** + * Registers a set of PSR-0 directories for a given prefix, either + * appending or prepending to the ones previously set for this prefix. + * + * @param string $prefix The prefix + * @param array|string $paths The PSR-0 root directories + * @param bool $prepend Whether to prepend the directories + */ + public function add($prefix, $paths, $prepend = false) + { + if (!$prefix) { + if ($prepend) { + $this->fallbackDirsPsr0 = array_merge( + (array) $paths, + $this->fallbackDirsPsr0 + ); + } else { + $this->fallbackDirsPsr0 = array_merge( + $this->fallbackDirsPsr0, + (array) $paths + ); + } + + return; + } + + $first = $prefix[0]; + if (!isset($this->prefixesPsr0[$first][$prefix])) { + $this->prefixesPsr0[$first][$prefix] = (array) $paths; + + return; + } + if ($prepend) { + $this->prefixesPsr0[$first][$prefix] = array_merge( + (array) $paths, + $this->prefixesPsr0[$first][$prefix] + ); + } else { + $this->prefixesPsr0[$first][$prefix] = array_merge( + $this->prefixesPsr0[$first][$prefix], + (array) $paths + ); + } + } + + /** + * Registers a set of PSR-4 directories for a given namespace, either + * appending or prepending to the ones previously set for this namespace. + * + * @param string $prefix The prefix/namespace, with trailing '\\' + * @param array|string $paths The PSR-0 base directories + * @param bool $prepend Whether to prepend the directories + * + * @throws \InvalidArgumentException + */ + public function addPsr4($prefix, $paths, $prepend = false) + { + if (!$prefix) { + // Register directories for the root namespace. + if ($prepend) { + $this->fallbackDirsPsr4 = array_merge( + (array) $paths, + $this->fallbackDirsPsr4 + ); + } else { + $this->fallbackDirsPsr4 = array_merge( + $this->fallbackDirsPsr4, + (array) $paths + ); + } + } elseif (!isset($this->prefixDirsPsr4[$prefix])) { + // Register directories for a new namespace. + $length = strlen($prefix); + if ('\\' !== $prefix[$length - 1]) { + throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator."); + } + $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length; + $this->prefixDirsPsr4[$prefix] = (array) $paths; + } elseif ($prepend) { + // Prepend directories for an already registered namespace. + $this->prefixDirsPsr4[$prefix] = array_merge( + (array) $paths, + $this->prefixDirsPsr4[$prefix] + ); + } else { + // Append directories for an already registered namespace. + $this->prefixDirsPsr4[$prefix] = array_merge( + $this->prefixDirsPsr4[$prefix], + (array) $paths + ); + } + } + + /** + * Registers a set of PSR-0 directories for a given prefix, + * replacing any others previously set for this prefix. + * + * @param string $prefix The prefix + * @param array|string $paths The PSR-0 base directories + */ + public function set($prefix, $paths) + { + if (!$prefix) { + $this->fallbackDirsPsr0 = (array) $paths; + } else { + $this->prefixesPsr0[$prefix[0]][$prefix] = (array) $paths; + } + } + + /** + * Registers a set of PSR-4 directories for a given namespace, + * replacing any others previously set for this namespace. + * + * @param string $prefix The prefix/namespace, with trailing '\\' + * @param array|string $paths The PSR-4 base directories + * + * @throws \InvalidArgumentException + */ + public function setPsr4($prefix, $paths) + { + if (!$prefix) { + $this->fallbackDirsPsr4 = (array) $paths; + } else { + $length = strlen($prefix); + if ('\\' !== $prefix[$length - 1]) { + throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator."); + } + $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length; + $this->prefixDirsPsr4[$prefix] = (array) $paths; + } + } + + /** + * Turns on searching the include path for class files. + * + * @param bool $useIncludePath + */ + public function setUseIncludePath($useIncludePath) + { + $this->useIncludePath = $useIncludePath; + } + + /** + * Can be used to check if the autoloader uses the include path to check + * for classes. + * + * @return bool + */ + public function getUseIncludePath() + { + return $this->useIncludePath; + } + + /** + * Turns off searching the prefix and fallback directories for classes + * that have not been registered with the class map. + * + * @param bool $classMapAuthoritative + */ + public function setClassMapAuthoritative($classMapAuthoritative) + { + $this->classMapAuthoritative = $classMapAuthoritative; + } + + /** + * Should class lookup fail if not found in the current class map? + * + * @return bool + */ + public function isClassMapAuthoritative() + { + return $this->classMapAuthoritative; + } + + /** + * Registers this instance as an autoloader. + * + * @param bool $prepend Whether to prepend the autoloader or not + */ + public function register($prepend = false) + { + spl_autoload_register(array($this, 'loadClass'), true, $prepend); + } + + /** + * Unregisters this instance as an autoloader. + */ + public function unregister() + { + spl_autoload_unregister(array($this, 'loadClass')); + } + + /** + * Loads the given class or interface. + * + * @param string $class The name of the class + * @return bool|null True if loaded, null otherwise + */ + public function loadClass($class) + { + if ($file = $this->findFile($class)) { + includeFile($file); + + return true; + } + } + + /** + * Finds the path to the file where the class is defined. + * + * @param string $class The name of the class + * + * @return string|false The path if found, false otherwise + */ + public function findFile($class) + { + // work around for PHP 5.3.0 - 5.3.2 https://bugs.php.net/50731 + if ('\\' == $class[0]) { + $class = substr($class, 1); + } + + // class map lookup + if (isset($this->classMap[$class])) { + return $this->classMap[$class]; + } + if ($this->classMapAuthoritative) { + return false; + } + + $file = $this->findFileWithExtension($class, '.php'); + + // Search for Hack files if we are running on HHVM + if ($file === null && defined('HHVM_VERSION')) { + $file = $this->findFileWithExtension($class, '.hh'); + } + + if ($file === null) { + // Remember that this class does not exist. + return $this->classMap[$class] = false; + } + + return $file; + } + + private function findFileWithExtension($class, $ext) + { + // PSR-4 lookup + $logicalPathPsr4 = strtr($class, '\\', DIRECTORY_SEPARATOR) . $ext; + + $first = $class[0]; + if (isset($this->prefixLengthsPsr4[$first])) { + foreach ($this->prefixLengthsPsr4[$first] as $prefix => $length) { + if (0 === strpos($class, $prefix)) { + foreach ($this->prefixDirsPsr4[$prefix] as $dir) { + if (file_exists($file = $dir . DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $length))) { + return $file; + } + } + } + } + } + + // PSR-4 fallback dirs + foreach ($this->fallbackDirsPsr4 as $dir) { + if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr4)) { + return $file; + } + } + + // PSR-0 lookup + if (false !== $pos = strrpos($class, '\\')) { + // namespaced class name + $logicalPathPsr0 = substr($logicalPathPsr4, 0, $pos + 1) + . strtr(substr($logicalPathPsr4, $pos + 1), '_', DIRECTORY_SEPARATOR); + } else { + // PEAR-like class name + $logicalPathPsr0 = strtr($class, '_', DIRECTORY_SEPARATOR) . $ext; + } + + if (isset($this->prefixesPsr0[$first])) { + foreach ($this->prefixesPsr0[$first] as $prefix => $dirs) { + if (0 === strpos($class, $prefix)) { + foreach ($dirs as $dir) { + if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) { + return $file; + } + } + } + } + } + + // PSR-0 fallback dirs + foreach ($this->fallbackDirsPsr0 as $dir) { + if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) { + return $file; + } + } + + // PSR-0 include paths. + if ($this->useIncludePath && $file = stream_resolve_include_path($logicalPathPsr0)) { + return $file; + } + } +} + +/** + * Scope isolated include. + * + * Prevents access to $this/self from included files. + */ +function includeFile($file) +{ + include $file; +} diff --git a/vendor/composer/LICENSE b/vendor/composer/LICENSE new file mode 100644 index 0000000..c8d57af --- /dev/null +++ b/vendor/composer/LICENSE @@ -0,0 +1,21 @@ + +Copyright (c) 2015 Nils Adermann, Jordi Boggiano + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is furnished +to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + diff --git a/vendor/composer/autoload_classmap.php b/vendor/composer/autoload_classmap.php new file mode 100644 index 0000000..7a91153 --- /dev/null +++ b/vendor/composer/autoload_classmap.php @@ -0,0 +1,9 @@ + array($vendorDir . '/poweredbycoffee/slack-notifier/src'), + 'Guzzle\\Tests' => array($vendorDir . '/guzzle/guzzle/tests'), + 'Guzzle' => array($vendorDir . '/guzzle/guzzle/src'), +); diff --git a/vendor/composer/autoload_psr4.php b/vendor/composer/autoload_psr4.php new file mode 100644 index 0000000..7002ff6 --- /dev/null +++ b/vendor/composer/autoload_psr4.php @@ -0,0 +1,12 @@ + array($vendorDir . '/symfony/serializer'), + 'Symfony\\Component\\EventDispatcher\\' => array($vendorDir . '/symfony/event-dispatcher'), + 'Symfony\\Component\\Console\\' => array($vendorDir . '/symfony/console'), +); diff --git a/vendor/composer/autoload_real.php b/vendor/composer/autoload_real.php new file mode 100644 index 0000000..d4c41b8 --- /dev/null +++ b/vendor/composer/autoload_real.php @@ -0,0 +1,50 @@ + $path) { + $loader->set($namespace, $path); + } + + $map = require __DIR__ . '/autoload_psr4.php'; + foreach ($map as $namespace => $path) { + $loader->setPsr4($namespace, $path); + } + + $classMap = require __DIR__ . '/autoload_classmap.php'; + if ($classMap) { + $loader->addClassMap($classMap); + } + + $loader->register(true); + + return $loader; + } +} + +function composerRequire9fcd8d40645163b46de0e17bc047d70b($file) +{ + require $file; +} diff --git a/vendor/composer/installed.json b/vendor/composer/installed.json new file mode 100644 index 0000000..56b4bb6 --- /dev/null +++ b/vendor/composer/installed.json @@ -0,0 +1,329 @@ +[ + { + "name": "symfony/serializer", + "version": "v2.7.4", + "version_normalized": "2.7.4.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/Serializer.git", + "reference": "baf24f86a8656eea9c80988f332e51461bfcb67f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/Serializer/zipball/baf24f86a8656eea9c80988f332e51461bfcb67f", + "reference": "baf24f86a8656eea9c80988f332e51461bfcb67f", + "shasum": "" + }, + "require": { + "php": ">=5.3.9" + }, + "require-dev": { + "doctrine/annotations": "~1.0", + "doctrine/cache": "~1.0", + "symfony/config": "~2.2", + "symfony/phpunit-bridge": "~2.7", + "symfony/property-access": "~2.3", + "symfony/yaml": "~2.0,>=2.0.5" + }, + "suggest": { + "doctrine/annotations": "For using the annotation mapping. You will also need doctrine/cache.", + "doctrine/cache": "For using the default cached annotation reader and metadata cache.", + "symfony/config": "For using the XML mapping loader.", + "symfony/property-access": "For using the ObjectNormalizer.", + "symfony/yaml": "For using the default YAML mapping loader." + }, + "time": "2015-08-31 16:44:53", + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.7-dev" + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "Symfony\\Component\\Serializer\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony Serializer Component", + "homepage": "https://symfony.com" + }, + { + "name": "symfony/console", + "version": "v2.7.4", + "version_normalized": "2.7.4.0", + "source": { + "type": "git", + "url": "git@github.com:symfony/Console.git", + "reference": "f1f7376766394f409b9b33a57a5675a52f8aad93" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/Console/zipball/f1f7376766394f409b9b33a57a5675a52f8aad93", + "reference": "f1f7376766394f409b9b33a57a5675a52f8aad93", + "shasum": "" + }, + "require": { + "php": ">=5.3.9" + }, + "require-dev": { + "psr/log": "~1.0", + "symfony/event-dispatcher": "~2.1", + "symfony/phpunit-bridge": "~2.7", + "symfony/process": "~2.1" + }, + "suggest": { + "psr/log": "For using the console logger", + "symfony/event-dispatcher": "", + "symfony/process": "" + }, + "time": "2015-09-03 11:40:38", + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.7-dev" + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "Symfony\\Component\\Console\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony Console Component", + "homepage": "https://symfony.com" + }, + { + "name": "symfony/event-dispatcher", + "version": "v2.7.4", + "version_normalized": "2.7.4.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/EventDispatcher.git", + "reference": "b58c916f1db03a611b72dd702564f30ad8fe83fa" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/EventDispatcher/zipball/b58c916f1db03a611b72dd702564f30ad8fe83fa", + "reference": "b58c916f1db03a611b72dd702564f30ad8fe83fa", + "shasum": "" + }, + "require": { + "php": ">=5.3.9" + }, + "require-dev": { + "psr/log": "~1.0", + "symfony/config": "~2.0,>=2.0.5", + "symfony/dependency-injection": "~2.6", + "symfony/expression-language": "~2.6", + "symfony/phpunit-bridge": "~2.7", + "symfony/stopwatch": "~2.3" + }, + "suggest": { + "symfony/dependency-injection": "", + "symfony/http-kernel": "" + }, + "time": "2015-08-24 07:13:45", + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.7-dev" + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "Symfony\\Component\\EventDispatcher\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony EventDispatcher Component", + "homepage": "https://symfony.com" + }, + { + "name": "guzzle/guzzle", + "version": "v3.9.3", + "version_normalized": "3.9.3.0", + "source": { + "type": "git", + "url": "https://github.com/guzzle/guzzle3.git", + "reference": "0645b70d953bc1c067bbc8d5bc53194706b628d9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/guzzle3/zipball/0645b70d953bc1c067bbc8d5bc53194706b628d9", + "reference": "0645b70d953bc1c067bbc8d5bc53194706b628d9", + "shasum": "" + }, + "require": { + "ext-curl": "*", + "php": ">=5.3.3", + "symfony/event-dispatcher": "~2.1" + }, + "replace": { + "guzzle/batch": "self.version", + "guzzle/cache": "self.version", + "guzzle/common": "self.version", + "guzzle/http": "self.version", + "guzzle/inflection": "self.version", + "guzzle/iterator": "self.version", + "guzzle/log": "self.version", + "guzzle/parser": "self.version", + "guzzle/plugin": "self.version", + "guzzle/plugin-async": "self.version", + "guzzle/plugin-backoff": "self.version", + "guzzle/plugin-cache": "self.version", + "guzzle/plugin-cookie": "self.version", + "guzzle/plugin-curlauth": "self.version", + "guzzle/plugin-error-response": "self.version", + "guzzle/plugin-history": "self.version", + "guzzle/plugin-log": "self.version", + "guzzle/plugin-md5": "self.version", + "guzzle/plugin-mock": "self.version", + "guzzle/plugin-oauth": "self.version", + "guzzle/service": "self.version", + "guzzle/stream": "self.version" + }, + "require-dev": { + "doctrine/cache": "~1.3", + "monolog/monolog": "~1.0", + "phpunit/phpunit": "3.7.*", + "psr/log": "~1.0", + "symfony/class-loader": "~2.1", + "zendframework/zend-cache": "2.*,<2.3", + "zendframework/zend-log": "2.*,<2.3" + }, + "suggest": { + "guzzlehttp/guzzle": "Guzzle 5 has moved to a new package name. The package you have installed, Guzzle 3, is deprecated." + }, + "time": "2015-03-18 18:23:50", + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.9-dev" + } + }, + "installation-source": "dist", + "autoload": { + "psr-0": { + "Guzzle": "src/", + "Guzzle\\Tests": "tests/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + }, + { + "name": "Guzzle Community", + "homepage": "https://github.com/guzzle/guzzle/contributors" + } + ], + "description": "PHP HTTP client. This library is deprecated in favor of https://packagist.org/packages/guzzlehttp/guzzle", + "homepage": "http://guzzlephp.org/", + "keywords": [ + "client", + "curl", + "framework", + "http", + "http client", + "rest", + "web service" + ] + }, + { + "name": "poweredbycoffee/slack-notifier", + "version": "0.2.1", + "version_normalized": "0.2.1.0", + "source": { + "type": "git", + "url": "https://github.com/stewarty/slack-notifier.git", + "reference": "6683c3058463eb6c0a2a5679a55f129e9bbad57c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/stewarty/slack-notifier/zipball/6683c3058463eb6c0a2a5679a55f129e9bbad57c", + "reference": "6683c3058463eb6c0a2a5679a55f129e9bbad57c", + "shasum": "" + }, + "require": { + "guzzle/guzzle": "~3", + "symfony/console": "~2.4", + "symfony/serializer": "~2.4" + }, + "require-dev": { + "phpunit/phpunit": "~3" + }, + "time": "2014-09-09 06:14:18", + "bin": [ + "bin/slack" + ], + "type": "library", + "installation-source": "dist", + "autoload": { + "psr-0": { + "Slack\\": "src/" + } + }, + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Paul-Emile MINY", + "email": "paulemile.miny@gmail.com" + } + ], + "description": "A simple slack wrapper", + "support": { + "source": "https://github.com/stewarty/slack-notifier/tree/0.2.1" + } + } +] diff --git a/vendor/guzzle/guzzle/.gitignore b/vendor/guzzle/guzzle/.gitignore new file mode 100644 index 0000000..893035d --- /dev/null +++ b/vendor/guzzle/guzzle/.gitignore @@ -0,0 +1,27 @@ +# Ingore common cruft +.DS_STORE +coverage +.idea + +# Ignore binary files +guzzle.phar +guzzle-min.phar + +# Ignore potentially sensitive phpunit file +phpunit.xml + +# Ignore composer generated files +composer.phar +composer.lock +composer-test.lock +vendor/ + +# Ignore build files +build/ +phing/build.properties + +# Ignore subsplit working directory +.subsplit + +docs/_build +docs/*.pyc diff --git a/vendor/guzzle/guzzle/.travis.yml b/vendor/guzzle/guzzle/.travis.yml new file mode 100644 index 0000000..209e05c --- /dev/null +++ b/vendor/guzzle/guzzle/.travis.yml @@ -0,0 +1,17 @@ +language: php + +php: + - 5.3 + - 5.4 + - 5.5 + - 5.6 + - hhvm + +before_script: + - curl --version + - pecl install uri_template-beta || echo "pecl uri_template not available" + - composer self-update + - composer install --no-interaction --prefer-source --dev + - ~/.nvm/nvm.sh install v0.6.14 + +script: composer test diff --git a/vendor/guzzle/guzzle/CHANGELOG.md b/vendor/guzzle/guzzle/CHANGELOG.md new file mode 100644 index 0000000..f0dc544 --- /dev/null +++ b/vendor/guzzle/guzzle/CHANGELOG.md @@ -0,0 +1,751 @@ +# CHANGELOG + +## 3.9.3 - 2015-03-18 + +* Ensuring Content-Length is not stripped from a request when it is `0`. +* Added more information to stream wrapper exceptions. +* Message parser will no longer throw warnings for malformed messages. +* Giving a valid cache TTL when max-age is 0. + +## 3.9.2 - 2014-09-10 + +* Retrying "Connection died, retrying a fresh connect" curl errors. +* Automatically extracting the cacert from the phar in client constructor. +* Added EntityBody support for OPTIONS requests. + +## 3.9.1 - 2014-05-07 + +* Added a fix to ReadLimitEntityBody to ensure it doesn't infinitely loop. +* Added a fix to the stream checksum function so that when the first read + returns a falsey value, it still continues to consume the stream until EOF. + +## 3.9.0 - 2014-04-23 + +* `null`, `false`, and `"_guzzle_blank_"` all now serialize as an empty value + with no trailing "=". See dc1d824277. +* No longer performing an MD5 check on the cacert each time the phar is used, + but rather copying the cacert to the temp directory. +* `"0"` can now be added as a URL path +* Deleting cookies that are set to empty +* If-Modified-Since is no longer unnecessarily added to the CachePlugin +* Cookie path matching now follows RFC 6265 s5.1.4 +* Updated service descriptions are now added to a service client's composite + factory. +* MockPlugin now throws an exception if the queue is empty. +* Properly parsing URLs that start with "http" but are not absolute +* Added the ability to configure the curl_multi_select timeout setting +* OAuth parameters are now sorted using lexicographical byte value ordering +* Fixing invalid usage of an out of range PHP feature in the ErrorResponsePlugin + +## 3.8.1 -2014-01-28 + +* Bug: Always using GET requests when redirecting from a 303 response +* Bug: CURLOPT_SSL_VERIFYHOST is now correctly set to false when setting `$certificateAuthority` to false in + `Guzzle\Http\ClientInterface::setSslVerification()` +* Bug: RedirectPlugin now uses strict RFC 3986 compliance when combining a base URL with a relative URL +* Bug: The body of a request can now be set to `"0"` +* Sending PHP stream requests no longer forces `HTTP/1.0` +* Adding more information to ExceptionCollection exceptions so that users have more context, including a stack trace of + each sub-exception +* Updated the `$ref` attribute in service descriptions to merge over any existing parameters of a schema (rather than + clobbering everything). +* Merging URLs will now use the query string object from the relative URL (thus allowing custom query aggregators) +* Query strings are now parsed in a way that they do no convert empty keys with no value to have a dangling `=`. + For example `foo&bar=baz` is now correctly parsed and recognized as `foo&bar=baz` rather than `foo=&bar=baz`. +* Now properly escaping the regular expression delimiter when matching Cookie domains. +* Network access is now disabled when loading XML documents + +## 3.8.0 - 2013-12-05 + +* Added the ability to define a POST name for a file +* JSON response parsing now properly walks additionalProperties +* cURL error code 18 is now retried automatically in the BackoffPlugin +* Fixed a cURL error when URLs contain fragments +* Fixed an issue in the BackoffPlugin retry event where it was trying to access all exceptions as if they were + CurlExceptions +* CURLOPT_PROGRESS function fix for PHP 5.5 (69fcc1e) +* Added the ability for Guzzle to work with older versions of cURL that do not support `CURLOPT_TIMEOUT_MS` +* Fixed a bug that was encountered when parsing empty header parameters +* UriTemplate now has a `setRegex()` method to match the docs +* The `debug` request parameter now checks if it is truthy rather than if it exists +* Setting the `debug` request parameter to true shows verbose cURL output instead of using the LogPlugin +* Added the ability to combine URLs using strict RFC 3986 compliance +* Command objects can now return the validation errors encountered by the command +* Various fixes to cache revalidation (#437 and 29797e5) +* Various fixes to the AsyncPlugin +* Cleaned up build scripts + +## 3.7.4 - 2013-10-02 + +* Bug fix: 0 is now an allowed value in a description parameter that has a default value (#430) +* Bug fix: SchemaFormatter now returns an integer when formatting to a Unix timestamp + (see https://github.com/aws/aws-sdk-php/issues/147) +* Bug fix: Cleaned up and fixed URL dot segment removal to properly resolve internal dots +* Minimum PHP version is now properly specified as 5.3.3 (up from 5.3.2) (#420) +* Updated the bundled cacert.pem (#419) +* OauthPlugin now supports adding authentication to headers or query string (#425) + +## 3.7.3 - 2013-09-08 + +* Added the ability to get the exception associated with a request/command when using `MultiTransferException` and + `CommandTransferException`. +* Setting `additionalParameters` of a response to false is now honored when parsing responses with a service description +* Schemas are only injected into response models when explicitly configured. +* No longer guessing Content-Type based on the path of a request. Content-Type is now only guessed based on the path of + an EntityBody. +* Bug fix: ChunkedIterator can now properly chunk a \Traversable as well as an \Iterator. +* Bug fix: FilterIterator now relies on `\Iterator` instead of `\Traversable`. +* Bug fix: Gracefully handling malformed responses in RequestMediator::writeResponseBody() +* Bug fix: Replaced call to canCache with canCacheRequest in the CallbackCanCacheStrategy of the CachePlugin +* Bug fix: Visiting XML attributes first before visting XML children when serializing requests +* Bug fix: Properly parsing headers that contain commas contained in quotes +* Bug fix: mimetype guessing based on a filename is now case-insensitive + +## 3.7.2 - 2013-08-02 + +* Bug fix: Properly URL encoding paths when using the PHP-only version of the UriTemplate expander + See https://github.com/guzzle/guzzle/issues/371 +* Bug fix: Cookie domains are now matched correctly according to RFC 6265 + See https://github.com/guzzle/guzzle/issues/377 +* Bug fix: GET parameters are now used when calculating an OAuth signature +* Bug fix: Fixed an issue with cache revalidation where the If-None-Match header was being double quoted +* `Guzzle\Common\AbstractHasDispatcher::dispatch()` now returns the event that was dispatched +* `Guzzle\Http\QueryString::factory()` now guesses the most appropriate query aggregator to used based on the input. + See https://github.com/guzzle/guzzle/issues/379 +* Added a way to add custom domain objects to service description parsing using the `operation.parse_class` event. See + https://github.com/guzzle/guzzle/pull/380 +* cURL multi cleanup and optimizations + +## 3.7.1 - 2013-07-05 + +* Bug fix: Setting default options on a client now works +* Bug fix: Setting options on HEAD requests now works. See #352 +* Bug fix: Moving stream factory before send event to before building the stream. See #353 +* Bug fix: Cookies no longer match on IP addresses per RFC 6265 +* Bug fix: Correctly parsing header parameters that are in `<>` and quotes +* Added `cert` and `ssl_key` as request options +* `Host` header can now diverge from the host part of a URL if the header is set manually +* `Guzzle\Service\Command\LocationVisitor\Request\XmlVisitor` was rewritten to change from using SimpleXML to XMLWriter +* OAuth parameters are only added via the plugin if they aren't already set +* Exceptions are now thrown when a URL cannot be parsed +* Returning `false` if `Guzzle\Http\EntityBody::getContentMd5()` fails +* Not setting a `Content-MD5` on a command if calculating the Content-MD5 fails via the CommandContentMd5Plugin + +## 3.7.0 - 2013-06-10 + +* See UPGRADING.md for more information on how to upgrade. +* Requests now support the ability to specify an array of $options when creating a request to more easily modify a + request. You can pass a 'request.options' configuration setting to a client to apply default request options to + every request created by a client (e.g. default query string variables, headers, curl options, etc). +* Added a static facade class that allows you to use Guzzle with static methods and mount the class to `\Guzzle`. + See `Guzzle\Http\StaticClient::mount`. +* Added `command.request_options` to `Guzzle\Service\Command\AbstractCommand` to pass request options to requests + created by a command (e.g. custom headers, query string variables, timeout settings, etc). +* Stream size in `Guzzle\Stream\PhpStreamRequestFactory` will now be set if Content-Length is returned in the + headers of a response +* Added `Guzzle\Common\Collection::setPath($path, $value)` to set a value into an array using a nested key + (e.g. `$collection->setPath('foo/baz/bar', 'test'); echo $collection['foo']['bar']['bar'];`) +* ServiceBuilders now support storing and retrieving arbitrary data +* CachePlugin can now purge all resources for a given URI +* CachePlugin can automatically purge matching cached items when a non-idempotent request is sent to a resource +* CachePlugin now uses the Vary header to determine if a resource is a cache hit +* `Guzzle\Http\Message\Response` now implements `\Serializable` +* Added `Guzzle\Cache\CacheAdapterFactory::fromCache()` to more easily create cache adapters +* `Guzzle\Service\ClientInterface::execute()` now accepts an array, single command, or Traversable +* Fixed a bug in `Guzzle\Http\Message\Header\Link::addLink()` +* Better handling of calculating the size of a stream in `Guzzle\Stream\Stream` using fstat() and caching the size +* `Guzzle\Common\Exception\ExceptionCollection` now creates a more readable exception message +* Fixing BC break: Added back the MonologLogAdapter implementation rather than extending from PsrLog so that older + Symfony users can still use the old version of Monolog. +* Fixing BC break: Added the implementation back in for `Guzzle\Http\Message\AbstractMessage::getTokenizedHeader()`. + Now triggering an E_USER_DEPRECATED warning when used. Use `$message->getHeader()->parseParams()`. +* Several performance improvements to `Guzzle\Common\Collection` +* Added an `$options` argument to the end of the following methods of `Guzzle\Http\ClientInterface`: + createRequest, head, delete, put, patch, post, options, prepareRequest +* Added an `$options` argument to the end of `Guzzle\Http\Message\Request\RequestFactoryInterface::createRequest()` +* Added an `applyOptions()` method to `Guzzle\Http\Message\Request\RequestFactoryInterface` +* Changed `Guzzle\Http\ClientInterface::get($uri = null, $headers = null, $body = null)` to + `Guzzle\Http\ClientInterface::get($uri = null, $headers = null, $options = array())`. You can still pass in a + resource, string, or EntityBody into the $options parameter to specify the download location of the response. +* Changed `Guzzle\Common\Collection::__construct($data)` to no longer accepts a null value for `$data` but a + default `array()` +* Added `Guzzle\Stream\StreamInterface::isRepeatable` +* Removed `Guzzle\Http\ClientInterface::setDefaultHeaders(). Use + $client->getConfig()->setPath('request.options/headers/{header_name}', 'value')`. or + $client->getConfig()->setPath('request.options/headers', array('header_name' => 'value'))`. +* Removed `Guzzle\Http\ClientInterface::getDefaultHeaders(). Use $client->getConfig()->getPath('request.options/headers')`. +* Removed `Guzzle\Http\ClientInterface::expandTemplate()` +* Removed `Guzzle\Http\ClientInterface::setRequestFactory()` +* Removed `Guzzle\Http\ClientInterface::getCurlMulti()` +* Removed `Guzzle\Http\Message\RequestInterface::canCache` +* Removed `Guzzle\Http\Message\RequestInterface::setIsRedirect` +* Removed `Guzzle\Http\Message\RequestInterface::isRedirect` +* Made `Guzzle\Http\Client::expandTemplate` and `getUriTemplate` protected methods. +* You can now enable E_USER_DEPRECATED warnings to see if you are using a deprecated method by setting + `Guzzle\Common\Version::$emitWarnings` to true. +* Marked `Guzzle\Http\Message\Request::isResponseBodyRepeatable()` as deprecated. Use + `$request->getResponseBody()->isRepeatable()` instead. +* Marked `Guzzle\Http\Message\Request::canCache()` as deprecated. Use + `Guzzle\Plugin\Cache\DefaultCanCacheStrategy->canCacheRequest()` instead. +* Marked `Guzzle\Http\Message\Request::canCache()` as deprecated. Use + `Guzzle\Plugin\Cache\DefaultCanCacheStrategy->canCacheRequest()` instead. +* Marked `Guzzle\Http\Message\Request::setIsRedirect()` as deprecated. Use the HistoryPlugin instead. +* Marked `Guzzle\Http\Message\Request::isRedirect()` as deprecated. Use the HistoryPlugin instead. +* Marked `Guzzle\Cache\CacheAdapterFactory::factory()` as deprecated +* Marked 'command.headers', 'command.response_body' and 'command.on_complete' as deprecated for AbstractCommand. + These will work through Guzzle 4.0 +* Marked 'request.params' for `Guzzle\Http\Client` as deprecated. Use [request.options][params]. +* Marked `Guzzle\Service\Client::enableMagicMethods()` as deprecated. Magic methods can no longer be disabled on a Guzzle\Service\Client. +* Marked `Guzzle\Service\Client::getDefaultHeaders()` as deprecated. Use $client->getConfig()->getPath('request.options/headers')`. +* Marked `Guzzle\Service\Client::setDefaultHeaders()` as deprecated. Use $client->getConfig()->setPath('request.options/headers/{header_name}', 'value')`. +* Marked `Guzzle\Parser\Url\UrlParser` as deprecated. Just use PHP's `parse_url()` and percent encode your UTF-8. +* Marked `Guzzle\Common\Collection::inject()` as deprecated. +* Marked `Guzzle\Plugin\CurlAuth\CurlAuthPlugin` as deprecated. Use `$client->getConfig()->setPath('request.options/auth', array('user', 'pass', 'Basic|Digest');` +* CacheKeyProviderInterface and DefaultCacheKeyProvider are no longer used. All of this logic is handled in a + CacheStorageInterface. These two objects and interface will be removed in a future version. +* Always setting X-cache headers on cached responses +* Default cache TTLs are now handled by the CacheStorageInterface of a CachePlugin +* `CacheStorageInterface::cache($key, Response $response, $ttl = null)` has changed to `cache(RequestInterface + $request, Response $response);` +* `CacheStorageInterface::fetch($key)` has changed to `fetch(RequestInterface $request);` +* `CacheStorageInterface::delete($key)` has changed to `delete(RequestInterface $request);` +* Added `CacheStorageInterface::purge($url)` +* `DefaultRevalidation::__construct(CacheKeyProviderInterface $cacheKey, CacheStorageInterface $cache, CachePlugin + $plugin)` has changed to `DefaultRevalidation::__construct(CacheStorageInterface $cache, + CanCacheStrategyInterface $canCache = null)` +* Added `RevalidationInterface::shouldRevalidate(RequestInterface $request, Response $response)` + +## 3.6.0 - 2013-05-29 + +* ServiceDescription now implements ToArrayInterface +* Added command.hidden_params to blacklist certain headers from being treated as additionalParameters +* Guzzle can now correctly parse incomplete URLs +* Mixed casing of headers are now forced to be a single consistent casing across all values for that header. +* Messages internally use a HeaderCollection object to delegate handling case-insensitive header resolution +* Removed the whole changedHeader() function system of messages because all header changes now go through addHeader(). +* Specific header implementations can be created for complex headers. When a message creates a header, it uses a + HeaderFactory which can map specific headers to specific header classes. There is now a Link header and + CacheControl header implementation. +* Removed from interface: Guzzle\Http\ClientInterface::setUriTemplate +* Removed from interface: Guzzle\Http\ClientInterface::setCurlMulti() +* Removed Guzzle\Http\Message\Request::receivedRequestHeader() and implemented this functionality in + Guzzle\Http\Curl\RequestMediator +* Removed the optional $asString parameter from MessageInterface::getHeader(). Just cast the header to a string. +* Removed the optional $tryChunkedTransfer option from Guzzle\Http\Message\EntityEnclosingRequestInterface +* Removed the $asObjects argument from Guzzle\Http\Message\MessageInterface::getHeaders() +* Removed Guzzle\Parser\ParserRegister::get(). Use getParser() +* Removed Guzzle\Parser\ParserRegister::set(). Use registerParser(). +* All response header helper functions return a string rather than mixing Header objects and strings inconsistently +* Removed cURL blacklist support. This is no longer necessary now that Expect, Accept, etc are managed by Guzzle + directly via interfaces +* Removed the injecting of a request object onto a response object. The methods to get and set a request still exist + but are a no-op until removed. +* Most classes that used to require a ``Guzzle\Service\Command\CommandInterface` typehint now request a + `Guzzle\Service\Command\ArrayCommandInterface`. +* Added `Guzzle\Http\Message\RequestInterface::startResponse()` to the RequestInterface to handle injecting a response + on a request while the request is still being transferred +* The ability to case-insensitively search for header values +* Guzzle\Http\Message\Header::hasExactHeader +* Guzzle\Http\Message\Header::raw. Use getAll() +* Deprecated cache control specific methods on Guzzle\Http\Message\AbstractMessage. Use the CacheControl header object + instead. +* `Guzzle\Service\Command\CommandInterface` now extends from ToArrayInterface and ArrayAccess +* Added the ability to cast Model objects to a string to view debug information. + +## 3.5.0 - 2013-05-13 + +* Bug: Fixed a regression so that request responses are parsed only once per oncomplete event rather than multiple times +* Bug: Better cleanup of one-time events accross the board (when an event is meant to fire once, it will now remove + itself from the EventDispatcher) +* Bug: `Guzzle\Log\MessageFormatter` now properly writes "total_time" and "connect_time" values +* Bug: Cloning an EntityEnclosingRequest now clones the EntityBody too +* Bug: Fixed an undefined index error when parsing nested JSON responses with a sentAs parameter that reference a + non-existent key +* Bug: All __call() method arguments are now required (helps with mocking frameworks) +* Deprecating Response::getRequest() and now using a shallow clone of a request object to remove a circular reference + to help with refcount based garbage collection of resources created by sending a request +* Deprecating ZF1 cache and log adapters. These will be removed in the next major version. +* Deprecating `Response::getPreviousResponse()` (method signature still exists, but it'sdeprecated). Use the + HistoryPlugin for a history. +* Added a `responseBody` alias for the `response_body` location +* Refactored internals to no longer rely on Response::getRequest() +* HistoryPlugin can now be cast to a string +* HistoryPlugin now logs transactions rather than requests and responses to more accurately keep track of the requests + and responses that are sent over the wire +* Added `getEffectiveUrl()` and `getRedirectCount()` to Response objects + +## 3.4.3 - 2013-04-30 + +* Bug fix: Fixing bug introduced in 3.4.2 where redirect responses are duplicated on the final redirected response +* Added a check to re-extract the temp cacert bundle from the phar before sending each request + +## 3.4.2 - 2013-04-29 + +* Bug fix: Stream objects now work correctly with "a" and "a+" modes +* Bug fix: Removing `Transfer-Encoding: chunked` header when a Content-Length is present +* Bug fix: AsyncPlugin no longer forces HEAD requests +* Bug fix: DateTime timezones are now properly handled when using the service description schema formatter +* Bug fix: CachePlugin now properly handles stale-if-error directives when a request to the origin server fails +* Setting a response on a request will write to the custom request body from the response body if one is specified +* LogPlugin now writes to php://output when STDERR is undefined +* Added the ability to set multiple POST files for the same key in a single call +* application/x-www-form-urlencoded POSTs now use the utf-8 charset by default +* Added the ability to queue CurlExceptions to the MockPlugin +* Cleaned up how manual responses are queued on requests (removed "queued_response" and now using request.before_send) +* Configuration loading now allows remote files + +## 3.4.1 - 2013-04-16 + +* Large refactoring to how CurlMulti handles work. There is now a proxy that sits in front of a pool of CurlMulti + handles. This greatly simplifies the implementation, fixes a couple bugs, and provides a small performance boost. +* Exceptions are now properly grouped when sending requests in parallel +* Redirects are now properly aggregated when a multi transaction fails +* Redirects now set the response on the original object even in the event of a failure +* Bug fix: Model names are now properly set even when using $refs +* Added support for PHP 5.5's CurlFile to prevent warnings with the deprecated @ syntax +* Added support for oauth_callback in OAuth signatures +* Added support for oauth_verifier in OAuth signatures +* Added support to attempt to retrieve a command first literally, then ucfirst, the with inflection + +## 3.4.0 - 2013-04-11 + +* Bug fix: URLs are now resolved correctly based on http://tools.ietf.org/html/rfc3986#section-5.2. #289 +* Bug fix: Absolute URLs with a path in a service description will now properly override the base URL. #289 +* Bug fix: Parsing a query string with a single PHP array value will now result in an array. #263 +* Bug fix: Better normalization of the User-Agent header to prevent duplicate headers. #264. +* Bug fix: Added `number` type to service descriptions. +* Bug fix: empty parameters are removed from an OAuth signature +* Bug fix: Revalidating a cache entry prefers the Last-Modified over the Date header +* Bug fix: Fixed "array to string" error when validating a union of types in a service description +* Bug fix: Removed code that attempted to determine the size of a stream when data is written to the stream +* Bug fix: Not including an `oauth_token` if the value is null in the OauthPlugin. +* Bug fix: Now correctly aggregating successful requests and failed requests in CurlMulti when a redirect occurs. +* The new default CURLOPT_TIMEOUT setting has been increased to 150 seconds so that Guzzle works on poor connections. +* Added a feature to EntityEnclosingRequest::setBody() that will automatically set the Content-Type of the request if + the Content-Type can be determined based on the entity body or the path of the request. +* Added the ability to overwrite configuration settings in a client when grabbing a throwaway client from a builder. +* Added support for a PSR-3 LogAdapter. +* Added a `command.after_prepare` event +* Added `oauth_callback` parameter to the OauthPlugin +* Added the ability to create a custom stream class when using a stream factory +* Added a CachingEntityBody decorator +* Added support for `additionalParameters` in service descriptions to define how custom parameters are serialized. +* The bundled SSL certificate is now provided in the phar file and extracted when running Guzzle from a phar. +* You can now send any EntityEnclosingRequest with POST fields or POST files and cURL will handle creating bodies +* POST requests using a custom entity body are now treated exactly like PUT requests but with a custom cURL method. This + means that the redirect behavior of POST requests with custom bodies will not be the same as POST requests that use + POST fields or files (the latter is only used when emulating a form POST in the browser). +* Lots of cleanup to CurlHandle::factory and RequestFactory::createRequest + +## 3.3.1 - 2013-03-10 + +* Added the ability to create PHP streaming responses from HTTP requests +* Bug fix: Running any filters when parsing response headers with service descriptions +* Bug fix: OauthPlugin fixes to allow for multi-dimensional array signing, and sorting parameters before signing +* Bug fix: Removed the adding of default empty arrays and false Booleans to responses in order to be consistent across + response location visitors. +* Bug fix: Removed the possibility of creating configuration files with circular dependencies +* RequestFactory::create() now uses the key of a POST file when setting the POST file name +* Added xmlAllowEmpty to serialize an XML body even if no XML specific parameters are set + +## 3.3.0 - 2013-03-03 + +* A large number of performance optimizations have been made +* Bug fix: Added 'wb' as a valid write mode for streams +* Bug fix: `Guzzle\Http\Message\Response::json()` now allows scalar values to be returned +* Bug fix: Fixed bug in `Guzzle\Http\Message\Response` where wrapping quotes were stripped from `getEtag()` +* BC: Removed `Guzzle\Http\Utils` class +* BC: Setting a service description on a client will no longer modify the client's command factories. +* BC: Emitting IO events from a RequestMediator is now a parameter that must be set in a request's curl options using + the 'emit_io' key. This was previously set under a request's parameters using 'curl.emit_io' +* BC: `Guzzle\Stream\Stream::getWrapper()` and `Guzzle\Stream\Stream::getSteamType()` are no longer converted to + lowercase +* Operation parameter objects are now lazy loaded internally +* Added ErrorResponsePlugin that can throw errors for responses defined in service description operations' errorResponses +* Added support for instantiating responseType=class responseClass classes. Classes must implement + `Guzzle\Service\Command\ResponseClassInterface` +* Added support for additionalProperties for top-level parameters in responseType=model responseClasses. These + additional properties also support locations and can be used to parse JSON responses where the outermost part of the + JSON is an array +* Added support for nested renaming of JSON models (rename sentAs to name) +* CachePlugin + * Added support for stale-if-error so that the CachePlugin can now serve stale content from the cache on error + * Debug headers can now added to cached response in the CachePlugin + +## 3.2.0 - 2013-02-14 + +* CurlMulti is no longer reused globally. A new multi object is created per-client. This helps to isolate clients. +* URLs with no path no longer contain a "/" by default +* Guzzle\Http\QueryString does no longer manages the leading "?". This is now handled in Guzzle\Http\Url. +* BadResponseException no longer includes the full request and response message +* Adding setData() to Guzzle\Service\Description\ServiceDescriptionInterface +* Adding getResponseBody() to Guzzle\Http\Message\RequestInterface +* Various updates to classes to use ServiceDescriptionInterface type hints rather than ServiceDescription +* Header values can now be normalized into distinct values when multiple headers are combined with a comma separated list +* xmlEncoding can now be customized for the XML declaration of a XML service description operation +* Guzzle\Http\QueryString now uses Guzzle\Http\QueryAggregator\QueryAggregatorInterface objects to add custom value + aggregation and no longer uses callbacks +* The URL encoding implementation of Guzzle\Http\QueryString can now be customized +* Bug fix: Filters were not always invoked for array service description parameters +* Bug fix: Redirects now use a target response body rather than a temporary response body +* Bug fix: The default exponential backoff BackoffPlugin was not giving when the request threshold was exceeded +* Bug fix: Guzzle now takes the first found value when grabbing Cache-Control directives + +## 3.1.2 - 2013-01-27 + +* Refactored how operation responses are parsed. Visitors now include a before() method responsible for parsing the + response body. For example, the XmlVisitor now parses the XML response into an array in the before() method. +* Fixed an issue where cURL would not automatically decompress responses when the Accept-Encoding header was sent +* CURLOPT_SSL_VERIFYHOST is never set to 1 because it is deprecated (see 5e0ff2ef20f839e19d1eeb298f90ba3598784444) +* Fixed a bug where redirect responses were not chained correctly using getPreviousResponse() +* Setting default headers on a client after setting the user-agent will not erase the user-agent setting + +## 3.1.1 - 2013-01-20 + +* Adding wildcard support to Guzzle\Common\Collection::getPath() +* Adding alias support to ServiceBuilder configs +* Adding Guzzle\Service\Resource\CompositeResourceIteratorFactory and cleaning up factory interface + +## 3.1.0 - 2013-01-12 + +* BC: CurlException now extends from RequestException rather than BadResponseException +* BC: Renamed Guzzle\Plugin\Cache\CanCacheStrategyInterface::canCache() to canCacheRequest() and added CanCacheResponse() +* Added getData to ServiceDescriptionInterface +* Added context array to RequestInterface::setState() +* Bug: Removing hard dependency on the BackoffPlugin from Guzzle\Http +* Bug: Adding required content-type when JSON request visitor adds JSON to a command +* Bug: Fixing the serialization of a service description with custom data +* Made it easier to deal with exceptions thrown when transferring commands or requests in parallel by providing + an array of successful and failed responses +* Moved getPath from Guzzle\Service\Resource\Model to Guzzle\Common\Collection +* Added Guzzle\Http\IoEmittingEntityBody +* Moved command filtration from validators to location visitors +* Added `extends` attributes to service description parameters +* Added getModels to ServiceDescriptionInterface + +## 3.0.7 - 2012-12-19 + +* Fixing phar detection when forcing a cacert to system if null or true +* Allowing filename to be passed to `Guzzle\Http\Message\Request::setResponseBody()` +* Cleaning up `Guzzle\Common\Collection::inject` method +* Adding a response_body location to service descriptions + +## 3.0.6 - 2012-12-09 + +* CurlMulti performance improvements +* Adding setErrorResponses() to Operation +* composer.json tweaks + +## 3.0.5 - 2012-11-18 + +* Bug: Fixing an infinite recursion bug caused from revalidating with the CachePlugin +* Bug: Response body can now be a string containing "0" +* Bug: Using Guzzle inside of a phar uses system by default but now allows for a custom cacert +* Bug: QueryString::fromString now properly parses query string parameters that contain equal signs +* Added support for XML attributes in service description responses +* DefaultRequestSerializer now supports array URI parameter values for URI template expansion +* Added better mimetype guessing to requests and post files + +## 3.0.4 - 2012-11-11 + +* Bug: Fixed a bug when adding multiple cookies to a request to use the correct glue value +* Bug: Cookies can now be added that have a name, domain, or value set to "0" +* Bug: Using the system cacert bundle when using the Phar +* Added json and xml methods to Response to make it easier to parse JSON and XML response data into data structures +* Enhanced cookie jar de-duplication +* Added the ability to enable strict cookie jars that throw exceptions when invalid cookies are added +* Added setStream to StreamInterface to actually make it possible to implement custom rewind behavior for entity bodies +* Added the ability to create any sort of hash for a stream rather than just an MD5 hash + +## 3.0.3 - 2012-11-04 + +* Implementing redirects in PHP rather than cURL +* Added PECL URI template extension and using as default parser if available +* Bug: Fixed Content-Length parsing of Response factory +* Adding rewind() method to entity bodies and streams. Allows for custom rewinding of non-repeatable streams. +* Adding ToArrayInterface throughout library +* Fixing OauthPlugin to create unique nonce values per request + +## 3.0.2 - 2012-10-25 + +* Magic methods are enabled by default on clients +* Magic methods return the result of a command +* Service clients no longer require a base_url option in the factory +* Bug: Fixed an issue with URI templates where null template variables were being expanded + +## 3.0.1 - 2012-10-22 + +* Models can now be used like regular collection objects by calling filter, map, etc +* Models no longer require a Parameter structure or initial data in the constructor +* Added a custom AppendIterator to get around a PHP bug with the `\AppendIterator` + +## 3.0.0 - 2012-10-15 + +* Rewrote service description format to be based on Swagger + * Now based on JSON schema + * Added nested input structures and nested response models + * Support for JSON and XML input and output models + * Renamed `commands` to `operations` + * Removed dot class notation + * Removed custom types +* Broke the project into smaller top-level namespaces to be more component friendly +* Removed support for XML configs and descriptions. Use arrays or JSON files. +* Removed the Validation component and Inspector +* Moved all cookie code to Guzzle\Plugin\Cookie +* Magic methods on a Guzzle\Service\Client now return the command un-executed. +* Calling getResult() or getResponse() on a command will lazily execute the command if needed. +* Now shipping with cURL's CA certs and using it by default +* Added previousResponse() method to response objects +* No longer sending Accept and Accept-Encoding headers on every request +* Only sending an Expect header by default when a payload is greater than 1MB +* Added/moved client options: + * curl.blacklist to curl.option.blacklist + * Added ssl.certificate_authority +* Added a Guzzle\Iterator component +* Moved plugins from Guzzle\Http\Plugin to Guzzle\Plugin +* Added a more robust backoff retry strategy (replaced the ExponentialBackoffPlugin) +* Added a more robust caching plugin +* Added setBody to response objects +* Updating LogPlugin to use a more flexible MessageFormatter +* Added a completely revamped build process +* Cleaning up Collection class and removing default values from the get method +* Fixed ZF2 cache adapters + +## 2.8.8 - 2012-10-15 + +* Bug: Fixed a cookie issue that caused dot prefixed domains to not match where popular browsers did + +## 2.8.7 - 2012-09-30 + +* Bug: Fixed config file aliases for JSON includes +* Bug: Fixed cookie bug on a request object by using CookieParser to parse cookies on requests +* Bug: Removing the path to a file when sending a Content-Disposition header on a POST upload +* Bug: Hardening request and response parsing to account for missing parts +* Bug: Fixed PEAR packaging +* Bug: Fixed Request::getInfo +* Bug: Fixed cases where CURLM_CALL_MULTI_PERFORM return codes were causing curl transactions to fail +* Adding the ability for the namespace Iterator factory to look in multiple directories +* Added more getters/setters/removers from service descriptions +* Added the ability to remove POST fields from OAuth signatures +* OAuth plugin now supports 2-legged OAuth + +## 2.8.6 - 2012-09-05 + +* Added the ability to modify and build service descriptions +* Added the use of visitors to apply parameters to locations in service descriptions using the dynamic command +* Added a `json` parameter location +* Now allowing dot notation for classes in the CacheAdapterFactory +* Using the union of two arrays rather than an array_merge when extending service builder services and service params +* Ensuring that a service is a string before doing strpos() checks on it when substituting services for references + in service builder config files. +* Services defined in two different config files that include one another will by default replace the previously + defined service, but you can now create services that extend themselves and merge their settings over the previous +* The JsonLoader now supports aliasing filenames with different filenames. This allows you to alias something like + '_default' with a default JSON configuration file. + +## 2.8.5 - 2012-08-29 + +* Bug: Suppressed empty arrays from URI templates +* Bug: Added the missing $options argument from ServiceDescription::factory to enable caching +* Added support for HTTP responses that do not contain a reason phrase in the start-line +* AbstractCommand commands are now invokable +* Added a way to get the data used when signing an Oauth request before a request is sent + +## 2.8.4 - 2012-08-15 + +* Bug: Custom delay time calculations are no longer ignored in the ExponentialBackoffPlugin +* Added the ability to transfer entity bodies as a string rather than streamed. This gets around curl error 65. Set `body_as_string` in a request's curl options to enable. +* Added a StreamInterface, EntityBodyInterface, and added ftell() to Guzzle\Common\Stream +* Added an AbstractEntityBodyDecorator and a ReadLimitEntityBody decorator to transfer only a subset of a decorated stream +* Stream and EntityBody objects will now return the file position to the previous position after a read required operation (e.g. getContentMd5()) +* Added additional response status codes +* Removed SSL information from the default User-Agent header +* DELETE requests can now send an entity body +* Added an EventDispatcher to the ExponentialBackoffPlugin and added an ExponentialBackoffLogger to log backoff retries +* Added the ability of the MockPlugin to consume mocked request bodies +* LogPlugin now exposes request and response objects in the extras array + +## 2.8.3 - 2012-07-30 + +* Bug: Fixed a case where empty POST requests were sent as GET requests +* Bug: Fixed a bug in ExponentialBackoffPlugin that caused fatal errors when retrying an EntityEnclosingRequest that does not have a body +* Bug: Setting the response body of a request to null after completing a request, not when setting the state of a request to new +* Added multiple inheritance to service description commands +* Added an ApiCommandInterface and added ``getParamNames()`` and ``hasParam()`` +* Removed the default 2mb size cutoff from the Md5ValidatorPlugin so that it now defaults to validating everything +* Changed CurlMulti::perform to pass a smaller timeout to CurlMulti::executeHandles + +## 2.8.2 - 2012-07-24 + +* Bug: Query string values set to 0 are no longer dropped from the query string +* Bug: A Collection object is no longer created each time a call is made to ``Guzzle\Service\Command\AbstractCommand::getRequestHeaders()`` +* Bug: ``+`` is now treated as an encoded space when parsing query strings +* QueryString and Collection performance improvements +* Allowing dot notation for class paths in filters attribute of a service descriptions + +## 2.8.1 - 2012-07-16 + +* Loosening Event Dispatcher dependency +* POST redirects can now be customized using CURLOPT_POSTREDIR + +## 2.8.0 - 2012-07-15 + +* BC: Guzzle\Http\Query + * Query strings with empty variables will always show an equal sign unless the variable is set to QueryString::BLANK (e.g. ?acl= vs ?acl) + * Changed isEncodingValues() and isEncodingFields() to isUrlEncoding() + * Changed setEncodeValues(bool) and setEncodeFields(bool) to useUrlEncoding(bool) + * Changed the aggregation functions of QueryString to be static methods + * Can now use fromString() with querystrings that have a leading ? +* cURL configuration values can be specified in service descriptions using ``curl.`` prefixed parameters +* Content-Length is set to 0 before emitting the request.before_send event when sending an empty request body +* Cookies are no longer URL decoded by default +* Bug: URI template variables set to null are no longer expanded + +## 2.7.2 - 2012-07-02 + +* BC: Moving things to get ready for subtree splits. Moving Inflection into Common. Moving Guzzle\Http\Parser to Guzzle\Parser. +* BC: Removing Guzzle\Common\Batch\Batch::count() and replacing it with isEmpty() +* CachePlugin now allows for a custom request parameter function to check if a request can be cached +* Bug fix: CachePlugin now only caches GET and HEAD requests by default +* Bug fix: Using header glue when transferring headers over the wire +* Allowing deeply nested arrays for composite variables in URI templates +* Batch divisors can now return iterators or arrays + +## 2.7.1 - 2012-06-26 + +* Minor patch to update version number in UA string +* Updating build process + +## 2.7.0 - 2012-06-25 + +* BC: Inflection classes moved to Guzzle\Inflection. No longer static methods. Can now inject custom inflectors into classes. +* BC: Removed magic setX methods from commands +* BC: Magic methods mapped to service description commands are now inflected in the command factory rather than the client __call() method +* Verbose cURL options are no longer enabled by default. Set curl.debug to true on a client to enable. +* Bug: Now allowing colons in a response start-line (e.g. HTTP/1.1 503 Service Unavailable: Back-end server is at capacity) +* Guzzle\Service\Resource\ResourceIteratorApplyBatched now internally uses the Guzzle\Common\Batch namespace +* Added Guzzle\Service\Plugin namespace and a PluginCollectionPlugin +* Added the ability to set POST fields and files in a service description +* Guzzle\Http\EntityBody::factory() now accepts objects with a __toString() method +* Adding a command.before_prepare event to clients +* Added BatchClosureTransfer and BatchClosureDivisor +* BatchTransferException now includes references to the batch divisor and transfer strategies +* Fixed some tests so that they pass more reliably +* Added Guzzle\Common\Log\ArrayLogAdapter + +## 2.6.6 - 2012-06-10 + +* BC: Removing Guzzle\Http\Plugin\BatchQueuePlugin +* BC: Removing Guzzle\Service\Command\CommandSet +* Adding generic batching system (replaces the batch queue plugin and command set) +* Updating ZF cache and log adapters and now using ZF's composer repository +* Bug: Setting the name of each ApiParam when creating through an ApiCommand +* Adding result_type, result_doc, deprecated, and doc_url to service descriptions +* Bug: Changed the default cookie header casing back to 'Cookie' + +## 2.6.5 - 2012-06-03 + +* BC: Renaming Guzzle\Http\Message\RequestInterface::getResourceUri() to getResource() +* BC: Removing unused AUTH_BASIC and AUTH_DIGEST constants from +* BC: Guzzle\Http\Cookie is now used to manage Set-Cookie data, not Cookie data +* BC: Renaming methods in the CookieJarInterface +* Moving almost all cookie logic out of the CookiePlugin and into the Cookie or CookieJar implementations +* Making the default glue for HTTP headers ';' instead of ',' +* Adding a removeValue to Guzzle\Http\Message\Header +* Adding getCookies() to request interface. +* Making it easier to add event subscribers to HasDispatcherInterface classes. Can now directly call addSubscriber() + +## 2.6.4 - 2012-05-30 + +* BC: Cleaning up how POST files are stored in EntityEnclosingRequest objects. Adding PostFile class. +* BC: Moving ApiCommand specific functionality from the Inspector and on to the ApiCommand +* Bug: Fixing magic method command calls on clients +* Bug: Email constraint only validates strings +* Bug: Aggregate POST fields when POST files are present in curl handle +* Bug: Fixing default User-Agent header +* Bug: Only appending or prepending parameters in commands if they are specified +* Bug: Not requiring response reason phrases or status codes to match a predefined list of codes +* Allowing the use of dot notation for class namespaces when using instance_of constraint +* Added any_match validation constraint +* Added an AsyncPlugin +* Passing request object to the calculateWait method of the ExponentialBackoffPlugin +* Allowing the result of a command object to be changed +* Parsing location and type sub values when instantiating a service description rather than over and over at runtime + +## 2.6.3 - 2012-05-23 + +* [BC] Guzzle\Common\FromConfigInterface no longer requires any config options. +* [BC] Refactoring how POST files are stored on an EntityEnclosingRequest. They are now separate from POST fields. +* You can now use an array of data when creating PUT request bodies in the request factory. +* Removing the requirement that HTTPS requests needed a Cache-Control: public directive to be cacheable. +* [Http] Adding support for Content-Type in multipart POST uploads per upload +* [Http] Added support for uploading multiple files using the same name (foo[0], foo[1]) +* Adding more POST data operations for easier manipulation of POST data. +* You can now set empty POST fields. +* The body of a request is only shown on EntityEnclosingRequest objects that do not use POST files. +* Split the Guzzle\Service\Inspector::validateConfig method into two methods. One to initialize when a command is created, and one to validate. +* CS updates + +## 2.6.2 - 2012-05-19 + +* [Http] Better handling of nested scope requests in CurlMulti. Requests are now always prepares in the send() method rather than the addRequest() method. + +## 2.6.1 - 2012-05-19 + +* [BC] Removing 'path' support in service descriptions. Use 'uri'. +* [BC] Guzzle\Service\Inspector::parseDocBlock is now protected. Adding getApiParamsForClass() with cache. +* [BC] Removing Guzzle\Common\NullObject. Use https://github.com/mtdowling/NullObject if you need it. +* [BC] Removing Guzzle\Common\XmlElement. +* All commands, both dynamic and concrete, have ApiCommand objects. +* Adding a fix for CurlMulti so that if all of the connections encounter some sort of curl error, then the loop exits. +* Adding checks to EntityEnclosingRequest so that empty POST files and fields are ignored. +* Making the method signature of Guzzle\Service\Builder\ServiceBuilder::factory more flexible. + +## 2.6.0 - 2012-05-15 + +* [BC] Moving Guzzle\Service\Builder to Guzzle\Service\Builder\ServiceBuilder +* [BC] Executing a Command returns the result of the command rather than the command +* [BC] Moving all HTTP parsing logic to Guzzle\Http\Parsers. Allows for faster C implementations if needed. +* [BC] Changing the Guzzle\Http\Message\Response::setProtocol() method to accept a protocol and version in separate args. +* [BC] Moving ResourceIterator* to Guzzle\Service\Resource +* [BC] Completely refactored ResourceIterators to iterate over a cloned command object +* [BC] Moved Guzzle\Http\UriTemplate to Guzzle\Http\Parser\UriTemplate\UriTemplate +* [BC] Guzzle\Guzzle is now deprecated +* Moving Guzzle\Common\Guzzle::inject to Guzzle\Common\Collection::inject +* Adding Guzzle\Version class to give version information about Guzzle +* Adding Guzzle\Http\Utils class to provide getDefaultUserAgent() and getHttpDate() +* Adding Guzzle\Curl\CurlVersion to manage caching curl_version() data +* ServiceDescription and ServiceBuilder are now cacheable using similar configs +* Changing the format of XML and JSON service builder configs. Backwards compatible. +* Cleaned up Cookie parsing +* Trimming the default Guzzle User-Agent header +* Adding a setOnComplete() method to Commands that is called when a command completes +* Keeping track of requests that were mocked in the MockPlugin +* Fixed a caching bug in the CacheAdapterFactory +* Inspector objects can be injected into a Command object +* Refactoring a lot of code and tests to be case insensitive when dealing with headers +* Adding Guzzle\Http\Message\HeaderComparison for easy comparison of HTTP headers using a DSL +* Adding the ability to set global option overrides to service builder configs +* Adding the ability to include other service builder config files from within XML and JSON files +* Moving the parseQuery method out of Url and on to QueryString::fromString() as a static factory method. + +## 2.5.0 - 2012-05-08 + +* Major performance improvements +* [BC] Simplifying Guzzle\Common\Collection. Please check to see if you are using features that are now deprecated. +* [BC] Using a custom validation system that allows a flyweight implementation for much faster validation. No longer using Symfony2 Validation component. +* [BC] No longer supporting "{{ }}" for injecting into command or UriTemplates. Use "{}" +* Added the ability to passed parameters to all requests created by a client +* Added callback functionality to the ExponentialBackoffPlugin +* Using microtime in ExponentialBackoffPlugin to allow more granular backoff strategies. +* Rewinding request stream bodies when retrying requests +* Exception is thrown when JSON response body cannot be decoded +* Added configurable magic method calls to clients and commands. This is off by default. +* Fixed a defect that added a hash to every parsed URL part +* Fixed duplicate none generation for OauthPlugin. +* Emitting an event each time a client is generated by a ServiceBuilder +* Using an ApiParams object instead of a Collection for parameters of an ApiCommand +* cache.* request parameters should be renamed to params.cache.* +* Added the ability to set arbitrary curl options on requests (disable_wire, progress, etc). See CurlHandle. +* Added the ability to disable type validation of service descriptions +* ServiceDescriptions and ServiceBuilders are now Serializable diff --git a/vendor/guzzle/guzzle/LICENSE b/vendor/guzzle/guzzle/LICENSE new file mode 100644 index 0000000..d51aa69 --- /dev/null +++ b/vendor/guzzle/guzzle/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2011 Michael Dowling, https://github.com/mtdowling + +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/guzzle/guzzle/README.md b/vendor/guzzle/guzzle/README.md new file mode 100644 index 0000000..6be06bf --- /dev/null +++ b/vendor/guzzle/guzzle/README.md @@ -0,0 +1,57 @@ +Guzzle, PHP HTTP client and webservice framework +================================================ + +# This is an old version of Guzzle + +This repository is for Guzzle 3.x. Guzzle 5.x, the new version of Guzzle, has +been released and is available at +[https://github.com/guzzle/guzzle](https://github.com/guzzle/guzzle). The +documentation for Guzzle version 5+ can be found at +[http://guzzlephp.org](http://guzzlephp.org). + +Guzzle 3 is only maintained for bug and security fixes. Guzzle 3 will be EOL +at some point in late 2015. + +### About Guzzle 3 + +[![Composer Downloads](https://poser.pugx.org/guzzle/guzzle/d/total.png)](https://packagist.org/packages/guzzle/guzzle) + [![Build Status](https://secure.travis-ci.org/guzzle/guzzle3.png?branch=master)](http://travis-ci.org/guzzle/guzzle3) + +- Extremely powerful API provides all the power of cURL with a simple interface. +- Truly take advantage of HTTP/1.1 with persistent connections, connection pooling, and parallel requests. +- Service description DSL allows you build awesome web service clients faster. +- Symfony2 event-based plugin system allows you to completely modify the behavior of a request. + +Get answers with: [Documentation](http://guzzle3.readthedocs.org/en/latest/), [Forums](https://groups.google.com/forum/?hl=en#!forum/guzzle), IRC ([#guzzlephp](irc://irc.freenode.net/#guzzlephp) @ irc.freenode.net) + +### Installing via Composer + +The recommended way to install Guzzle is through [Composer](http://getcomposer.org). + +```bash +# Install Composer +curl -sS https://getcomposer.org/installer | php + +# Add Guzzle as a dependency +php composer.phar require guzzle/guzzle:~3.9 +``` + +After installing, you need to require Composer's autoloader: + +```php +require 'vendor/autoload.php'; +``` +## Known Issues + +1. Problem following a specific redirect: https://github.com/guzzle/guzzle/issues/385. + This has been fixed in Guzzle 4/5. +2. Root XML attributes not serialized in a service description: https://github.com/guzzle/guzzle3/issues/5. + This has been fixed in Guzzle 4/5. +3. Accept-Encoding not preserved when following redirect: https://github.com/guzzle/guzzle3/issues/9 + Fixed in Guzzle 4/5. +4. String "Array" Transmitted w/ PostFiles and Duplicate Aggregator: https://github.com/guzzle/guzzle3/issues/10 + Fixed in Guzzle 4/5. +5. Recursive model references with array items: https://github.com/guzzle/guzzle3/issues/13 + Fixed in Guzzle 4/5 +6. String "Array" Transmitted w/ PostFiles and Duplicate Aggregator: https://github.com/guzzle/guzzle3/issues/10 + Fixed in Guzzle 4/5. diff --git a/vendor/guzzle/guzzle/UPGRADING.md b/vendor/guzzle/guzzle/UPGRADING.md new file mode 100644 index 0000000..f58bf11 --- /dev/null +++ b/vendor/guzzle/guzzle/UPGRADING.md @@ -0,0 +1,537 @@ +Guzzle Upgrade Guide +==================== + +3.6 to 3.7 +---------- + +### Deprecations + +- You can now enable E_USER_DEPRECATED warnings to see if you are using any deprecated methods.: + +```php +\Guzzle\Common\Version::$emitWarnings = true; +``` + +The following APIs and options have been marked as deprecated: + +- Marked `Guzzle\Http\Message\Request::isResponseBodyRepeatable()` as deprecated. Use `$request->getResponseBody()->isRepeatable()` instead. +- Marked `Guzzle\Http\Message\Request::canCache()` as deprecated. Use `Guzzle\Plugin\Cache\DefaultCanCacheStrategy->canCacheRequest()` instead. +- Marked `Guzzle\Http\Message\Request::canCache()` as deprecated. Use `Guzzle\Plugin\Cache\DefaultCanCacheStrategy->canCacheRequest()` instead. +- Marked `Guzzle\Http\Message\Request::setIsRedirect()` as deprecated. Use the HistoryPlugin instead. +- Marked `Guzzle\Http\Message\Request::isRedirect()` as deprecated. Use the HistoryPlugin instead. +- Marked `Guzzle\Cache\CacheAdapterFactory::factory()` as deprecated +- Marked `Guzzle\Service\Client::enableMagicMethods()` as deprecated. Magic methods can no longer be disabled on a Guzzle\Service\Client. +- Marked `Guzzle\Parser\Url\UrlParser` as deprecated. Just use PHP's `parse_url()` and percent encode your UTF-8. +- Marked `Guzzle\Common\Collection::inject()` as deprecated. +- Marked `Guzzle\Plugin\CurlAuth\CurlAuthPlugin` as deprecated. Use + `$client->getConfig()->setPath('request.options/auth', array('user', 'pass', 'Basic|Digest|NTLM|Any'));` or + `$client->setDefaultOption('auth', array('user', 'pass', 'Basic|Digest|NTLM|Any'));` + +3.7 introduces `request.options` as a parameter for a client configuration and as an optional argument to all creational +request methods. When paired with a client's configuration settings, these options allow you to specify default settings +for various aspects of a request. Because these options make other previous configuration options redundant, several +configuration options and methods of a client and AbstractCommand have been deprecated. + +- Marked `Guzzle\Service\Client::getDefaultHeaders()` as deprecated. Use `$client->getDefaultOption('headers')`. +- Marked `Guzzle\Service\Client::setDefaultHeaders()` as deprecated. Use `$client->setDefaultOption('headers/{header_name}', 'value')`. +- Marked 'request.params' for `Guzzle\Http\Client` as deprecated. Use `$client->setDefaultOption('params/{param_name}', 'value')` +- Marked 'command.headers', 'command.response_body' and 'command.on_complete' as deprecated for AbstractCommand. These will work through Guzzle 4.0 + + $command = $client->getCommand('foo', array( + 'command.headers' => array('Test' => '123'), + 'command.response_body' => '/path/to/file' + )); + + // Should be changed to: + + $command = $client->getCommand('foo', array( + 'command.request_options' => array( + 'headers' => array('Test' => '123'), + 'save_as' => '/path/to/file' + ) + )); + +### Interface changes + +Additions and changes (you will need to update any implementations or subclasses you may have created): + +- Added an `$options` argument to the end of the following methods of `Guzzle\Http\ClientInterface`: + createRequest, head, delete, put, patch, post, options, prepareRequest +- Added an `$options` argument to the end of `Guzzle\Http\Message\Request\RequestFactoryInterface::createRequest()` +- Added an `applyOptions()` method to `Guzzle\Http\Message\Request\RequestFactoryInterface` +- Changed `Guzzle\Http\ClientInterface::get($uri = null, $headers = null, $body = null)` to + `Guzzle\Http\ClientInterface::get($uri = null, $headers = null, $options = array())`. You can still pass in a + resource, string, or EntityBody into the $options parameter to specify the download location of the response. +- Changed `Guzzle\Common\Collection::__construct($data)` to no longer accepts a null value for `$data` but a + default `array()` +- Added `Guzzle\Stream\StreamInterface::isRepeatable` +- Made `Guzzle\Http\Client::expandTemplate` and `getUriTemplate` protected methods. + +The following methods were removed from interfaces. All of these methods are still available in the concrete classes +that implement them, but you should update your code to use alternative methods: + +- Removed `Guzzle\Http\ClientInterface::setDefaultHeaders(). Use + `$client->getConfig()->setPath('request.options/headers/{header_name}', 'value')`. or + `$client->getConfig()->setPath('request.options/headers', array('header_name' => 'value'))` or + `$client->setDefaultOption('headers/{header_name}', 'value')`. or + `$client->setDefaultOption('headers', array('header_name' => 'value'))`. +- Removed `Guzzle\Http\ClientInterface::getDefaultHeaders(). Use `$client->getConfig()->getPath('request.options/headers')`. +- Removed `Guzzle\Http\ClientInterface::expandTemplate()`. This is an implementation detail. +- Removed `Guzzle\Http\ClientInterface::setRequestFactory()`. This is an implementation detail. +- Removed `Guzzle\Http\ClientInterface::getCurlMulti()`. This is a very specific implementation detail. +- Removed `Guzzle\Http\Message\RequestInterface::canCache`. Use the CachePlugin. +- Removed `Guzzle\Http\Message\RequestInterface::setIsRedirect`. Use the HistoryPlugin. +- Removed `Guzzle\Http\Message\RequestInterface::isRedirect`. Use the HistoryPlugin. + +### Cache plugin breaking changes + +- CacheKeyProviderInterface and DefaultCacheKeyProvider are no longer used. All of this logic is handled in a + CacheStorageInterface. These two objects and interface will be removed in a future version. +- Always setting X-cache headers on cached responses +- Default cache TTLs are now handled by the CacheStorageInterface of a CachePlugin +- `CacheStorageInterface::cache($key, Response $response, $ttl = null)` has changed to `cache(RequestInterface + $request, Response $response);` +- `CacheStorageInterface::fetch($key)` has changed to `fetch(RequestInterface $request);` +- `CacheStorageInterface::delete($key)` has changed to `delete(RequestInterface $request);` +- Added `CacheStorageInterface::purge($url)` +- `DefaultRevalidation::__construct(CacheKeyProviderInterface $cacheKey, CacheStorageInterface $cache, CachePlugin + $plugin)` has changed to `DefaultRevalidation::__construct(CacheStorageInterface $cache, + CanCacheStrategyInterface $canCache = null)` +- Added `RevalidationInterface::shouldRevalidate(RequestInterface $request, Response $response)` + +3.5 to 3.6 +---------- + +* Mixed casing of headers are now forced to be a single consistent casing across all values for that header. +* Messages internally use a HeaderCollection object to delegate handling case-insensitive header resolution +* Removed the whole changedHeader() function system of messages because all header changes now go through addHeader(). + For example, setHeader() first removes the header using unset on a HeaderCollection and then calls addHeader(). + Keeping the Host header and URL host in sync is now handled by overriding the addHeader method in Request. +* Specific header implementations can be created for complex headers. When a message creates a header, it uses a + HeaderFactory which can map specific headers to specific header classes. There is now a Link header and + CacheControl header implementation. +* Moved getLinks() from Response to just be used on a Link header object. + +If you previously relied on Guzzle\Http\Message\Header::raw(), then you will need to update your code to use the +HeaderInterface (e.g. toArray(), getAll(), etc). + +### Interface changes + +* Removed from interface: Guzzle\Http\ClientInterface::setUriTemplate +* Removed from interface: Guzzle\Http\ClientInterface::setCurlMulti() +* Removed Guzzle\Http\Message\Request::receivedRequestHeader() and implemented this functionality in + Guzzle\Http\Curl\RequestMediator +* Removed the optional $asString parameter from MessageInterface::getHeader(). Just cast the header to a string. +* Removed the optional $tryChunkedTransfer option from Guzzle\Http\Message\EntityEnclosingRequestInterface +* Removed the $asObjects argument from Guzzle\Http\Message\MessageInterface::getHeaders() + +### Removed deprecated functions + +* Removed Guzzle\Parser\ParserRegister::get(). Use getParser() +* Removed Guzzle\Parser\ParserRegister::set(). Use registerParser(). + +### Deprecations + +* The ability to case-insensitively search for header values +* Guzzle\Http\Message\Header::hasExactHeader +* Guzzle\Http\Message\Header::raw. Use getAll() +* Deprecated cache control specific methods on Guzzle\Http\Message\AbstractMessage. Use the CacheControl header object + instead. + +### Other changes + +* All response header helper functions return a string rather than mixing Header objects and strings inconsistently +* Removed cURL blacklist support. This is no longer necessary now that Expect, Accept, etc are managed by Guzzle + directly via interfaces +* Removed the injecting of a request object onto a response object. The methods to get and set a request still exist + but are a no-op until removed. +* Most classes that used to require a ``Guzzle\Service\Command\CommandInterface` typehint now request a + `Guzzle\Service\Command\ArrayCommandInterface`. +* Added `Guzzle\Http\Message\RequestInterface::startResponse()` to the RequestInterface to handle injecting a response + on a request while the request is still being transferred +* `Guzzle\Service\Command\CommandInterface` now extends from ToArrayInterface and ArrayAccess + +3.3 to 3.4 +---------- + +Base URLs of a client now follow the rules of http://tools.ietf.org/html/rfc3986#section-5.2.2 when merging URLs. + +3.2 to 3.3 +---------- + +### Response::getEtag() quote stripping removed + +`Guzzle\Http\Message\Response::getEtag()` no longer strips quotes around the ETag response header + +### Removed `Guzzle\Http\Utils` + +The `Guzzle\Http\Utils` class was removed. This class was only used for testing. + +### Stream wrapper and type + +`Guzzle\Stream\Stream::getWrapper()` and `Guzzle\Stream\Stream::getSteamType()` are no longer converted to lowercase. + +### curl.emit_io became emit_io + +Emitting IO events from a RequestMediator is now a parameter that must be set in a request's curl options using the +'emit_io' key. This was previously set under a request's parameters using 'curl.emit_io' + +3.1 to 3.2 +---------- + +### CurlMulti is no longer reused globally + +Before 3.2, the same CurlMulti object was reused globally for each client. This can cause issue where plugins added +to a single client can pollute requests dispatched from other clients. + +If you still wish to reuse the same CurlMulti object with each client, then you can add a listener to the +ServiceBuilder's `service_builder.create_client` event to inject a custom CurlMulti object into each client as it is +created. + +```php +$multi = new Guzzle\Http\Curl\CurlMulti(); +$builder = Guzzle\Service\Builder\ServiceBuilder::factory('/path/to/config.json'); +$builder->addListener('service_builder.create_client', function ($event) use ($multi) { + $event['client']->setCurlMulti($multi); +} +}); +``` + +### No default path + +URLs no longer have a default path value of '/' if no path was specified. + +Before: + +```php +$request = $client->get('http://www.foo.com'); +echo $request->getUrl(); +// >> http://www.foo.com/ +``` + +After: + +```php +$request = $client->get('http://www.foo.com'); +echo $request->getUrl(); +// >> http://www.foo.com +``` + +### Less verbose BadResponseException + +The exception message for `Guzzle\Http\Exception\BadResponseException` no longer contains the full HTTP request and +response information. You can, however, get access to the request and response object by calling `getRequest()` or +`getResponse()` on the exception object. + +### Query parameter aggregation + +Multi-valued query parameters are no longer aggregated using a callback function. `Guzzle\Http\Query` now has a +setAggregator() method that accepts a `Guzzle\Http\QueryAggregator\QueryAggregatorInterface` object. This object is +responsible for handling the aggregation of multi-valued query string variables into a flattened hash. + +2.8 to 3.x +---------- + +### Guzzle\Service\Inspector + +Change `\Guzzle\Service\Inspector::fromConfig` to `\Guzzle\Common\Collection::fromConfig` + +**Before** + +```php +use Guzzle\Service\Inspector; + +class YourClient extends \Guzzle\Service\Client +{ + public static function factory($config = array()) + { + $default = array(); + $required = array('base_url', 'username', 'api_key'); + $config = Inspector::fromConfig($config, $default, $required); + + $client = new self( + $config->get('base_url'), + $config->get('username'), + $config->get('api_key') + ); + $client->setConfig($config); + + $client->setDescription(ServiceDescription::factory(__DIR__ . DIRECTORY_SEPARATOR . 'client.json')); + + return $client; + } +``` + +**After** + +```php +use Guzzle\Common\Collection; + +class YourClient extends \Guzzle\Service\Client +{ + public static function factory($config = array()) + { + $default = array(); + $required = array('base_url', 'username', 'api_key'); + $config = Collection::fromConfig($config, $default, $required); + + $client = new self( + $config->get('base_url'), + $config->get('username'), + $config->get('api_key') + ); + $client->setConfig($config); + + $client->setDescription(ServiceDescription::factory(__DIR__ . DIRECTORY_SEPARATOR . 'client.json')); + + return $client; + } +``` + +### Convert XML Service Descriptions to JSON + +**Before** + +```xml + + + + + + Get a list of groups + + + Uses a search query to get a list of groups + + + + Create a group + + + + + Delete a group by ID + + + + + + + Update a group + + + + + + +``` + +**After** + +```json +{ + "name": "Zendesk REST API v2", + "apiVersion": "2012-12-31", + "description":"Provides access to Zendesk views, groups, tickets, ticket fields, and users", + "operations": { + "list_groups": { + "httpMethod":"GET", + "uri": "groups.json", + "summary": "Get a list of groups" + }, + "search_groups":{ + "httpMethod":"GET", + "uri": "search.json?query=\"{query} type:group\"", + "summary": "Uses a search query to get a list of groups", + "parameters":{ + "query":{ + "location": "uri", + "description":"Zendesk Search Query", + "type": "string", + "required": true + } + } + }, + "create_group": { + "httpMethod":"POST", + "uri": "groups.json", + "summary": "Create a group", + "parameters":{ + "data": { + "type": "array", + "location": "body", + "description":"Group JSON", + "filters": "json_encode", + "required": true + }, + "Content-Type":{ + "type": "string", + "location":"header", + "static": "application/json" + } + } + }, + "delete_group": { + "httpMethod":"DELETE", + "uri": "groups/{id}.json", + "summary": "Delete a group", + "parameters":{ + "id":{ + "location": "uri", + "description":"Group to delete by ID", + "type": "integer", + "required": true + } + } + }, + "get_group": { + "httpMethod":"GET", + "uri": "groups/{id}.json", + "summary": "Get a ticket", + "parameters":{ + "id":{ + "location": "uri", + "description":"Group to get by ID", + "type": "integer", + "required": true + } + } + }, + "update_group": { + "httpMethod":"PUT", + "uri": "groups/{id}.json", + "summary": "Update a group", + "parameters":{ + "id": { + "location": "uri", + "description":"Group to update by ID", + "type": "integer", + "required": true + }, + "data": { + "type": "array", + "location": "body", + "description":"Group JSON", + "filters": "json_encode", + "required": true + }, + "Content-Type":{ + "type": "string", + "location":"header", + "static": "application/json" + } + } + } +} +``` + +### Guzzle\Service\Description\ServiceDescription + +Commands are now called Operations + +**Before** + +```php +use Guzzle\Service\Description\ServiceDescription; + +$sd = new ServiceDescription(); +$sd->getCommands(); // @returns ApiCommandInterface[] +$sd->hasCommand($name); +$sd->getCommand($name); // @returns ApiCommandInterface|null +$sd->addCommand($command); // @param ApiCommandInterface $command +``` + +**After** + +```php +use Guzzle\Service\Description\ServiceDescription; + +$sd = new ServiceDescription(); +$sd->getOperations(); // @returns OperationInterface[] +$sd->hasOperation($name); +$sd->getOperation($name); // @returns OperationInterface|null +$sd->addOperation($operation); // @param OperationInterface $operation +``` + +### Guzzle\Common\Inflection\Inflector + +Namespace is now `Guzzle\Inflection\Inflector` + +### Guzzle\Http\Plugin + +Namespace is now `Guzzle\Plugin`. Many other changes occur within this namespace and are detailed in their own sections below. + +### Guzzle\Http\Plugin\LogPlugin and Guzzle\Common\Log + +Now `Guzzle\Plugin\Log\LogPlugin` and `Guzzle\Log` respectively. + +**Before** + +```php +use Guzzle\Common\Log\ClosureLogAdapter; +use Guzzle\Http\Plugin\LogPlugin; + +/** @var \Guzzle\Http\Client */ +$client; + +// $verbosity is an integer indicating desired message verbosity level +$client->addSubscriber(new LogPlugin(new ClosureLogAdapter(function($m) { echo $m; }, $verbosity = LogPlugin::LOG_VERBOSE); +``` + +**After** + +```php +use Guzzle\Log\ClosureLogAdapter; +use Guzzle\Log\MessageFormatter; +use Guzzle\Plugin\Log\LogPlugin; + +/** @var \Guzzle\Http\Client */ +$client; + +// $format is a string indicating desired message format -- @see MessageFormatter +$client->addSubscriber(new LogPlugin(new ClosureLogAdapter(function($m) { echo $m; }, $format = MessageFormatter::DEBUG_FORMAT); +``` + +### Guzzle\Http\Plugin\CurlAuthPlugin + +Now `Guzzle\Plugin\CurlAuth\CurlAuthPlugin`. + +### Guzzle\Http\Plugin\ExponentialBackoffPlugin + +Now `Guzzle\Plugin\Backoff\BackoffPlugin`, and other changes. + +**Before** + +```php +use Guzzle\Http\Plugin\ExponentialBackoffPlugin; + +$backoffPlugin = new ExponentialBackoffPlugin($maxRetries, array_merge( + ExponentialBackoffPlugin::getDefaultFailureCodes(), array(429) + )); + +$client->addSubscriber($backoffPlugin); +``` + +**After** + +```php +use Guzzle\Plugin\Backoff\BackoffPlugin; +use Guzzle\Plugin\Backoff\HttpBackoffStrategy; + +// Use convenient factory method instead -- see implementation for ideas of what +// you can do with chaining backoff strategies +$backoffPlugin = BackoffPlugin::getExponentialBackoff($maxRetries, array_merge( + HttpBackoffStrategy::getDefaultFailureCodes(), array(429) + )); +$client->addSubscriber($backoffPlugin); +``` + +### Known Issues + +#### [BUG] Accept-Encoding header behavior changed unintentionally. + +(See #217) (Fixed in 09daeb8c666fb44499a0646d655a8ae36456575e) + +In version 2.8 setting the `Accept-Encoding` header would set the CURLOPT_ENCODING option, which permitted cURL to +properly handle gzip/deflate compressed responses from the server. In versions affected by this bug this does not happen. +See issue #217 for a workaround, or use a version containing the fix. diff --git a/vendor/guzzle/guzzle/build.xml b/vendor/guzzle/guzzle/build.xml new file mode 100644 index 0000000..2aa62ba --- /dev/null +++ b/vendor/guzzle/guzzle/build.xml @@ -0,0 +1,45 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vendor/guzzle/guzzle/composer.json b/vendor/guzzle/guzzle/composer.json new file mode 100644 index 0000000..59424b3 --- /dev/null +++ b/vendor/guzzle/guzzle/composer.json @@ -0,0 +1,82 @@ +{ + "name": "guzzle/guzzle", + "type": "library", + "description": "PHP HTTP client. This library is deprecated in favor of https://packagist.org/packages/guzzlehttp/guzzle", + "keywords": ["framework", "http", "rest", "web service", "curl", "client", "HTTP client"], + "homepage": "http://guzzlephp.org/", + "license": "MIT", + + "authors": [ + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + }, + { + "name": "Guzzle Community", + "homepage": "https://github.com/guzzle/guzzle/contributors" + } + ], + + "replace": { + "guzzle/batch": "self.version", + "guzzle/cache": "self.version", + "guzzle/common": "self.version", + "guzzle/http": "self.version", + "guzzle/inflection": "self.version", + "guzzle/iterator": "self.version", + "guzzle/log": "self.version", + "guzzle/parser": "self.version", + "guzzle/plugin": "self.version", + "guzzle/plugin-async": "self.version", + "guzzle/plugin-backoff": "self.version", + "guzzle/plugin-cache": "self.version", + "guzzle/plugin-cookie": "self.version", + "guzzle/plugin-curlauth": "self.version", + "guzzle/plugin-error-response": "self.version", + "guzzle/plugin-history": "self.version", + "guzzle/plugin-log": "self.version", + "guzzle/plugin-md5": "self.version", + "guzzle/plugin-mock": "self.version", + "guzzle/plugin-oauth": "self.version", + "guzzle/service": "self.version", + "guzzle/stream": "self.version" + }, + + "require": { + "php": ">=5.3.3", + "ext-curl": "*", + "symfony/event-dispatcher": "~2.1" + }, + + "autoload": { + "psr-0": { + "Guzzle": "src/", + "Guzzle\\Tests": "tests/" + } + }, + + "suggest": { + "guzzlehttp/guzzle": "Guzzle 5 has moved to a new package name. The package you have installed, Guzzle 3, is deprecated." + }, + + "scripts": { + "test": "phpunit" + }, + + "require-dev": { + "doctrine/cache": "~1.3", + "symfony/class-loader": "~2.1", + "monolog/monolog": "~1.0", + "psr/log": "~1.0", + "zendframework/zend-cache": "2.*,<2.3", + "zendframework/zend-log": "2.*,<2.3", + "phpunit/phpunit": "3.7.*" + }, + + "extra": { + "branch-alias": { + "dev-master": "3.9-dev" + } + } +} diff --git a/vendor/guzzle/guzzle/docs/Makefile b/vendor/guzzle/guzzle/docs/Makefile new file mode 100644 index 0000000..d92e03f --- /dev/null +++ b/vendor/guzzle/guzzle/docs/Makefile @@ -0,0 +1,153 @@ +# Makefile for Sphinx documentation +# + +# You can set these variables from the command line. +SPHINXOPTS = +SPHINXBUILD = sphinx-build +PAPER = +BUILDDIR = _build + +# Internal variables. +PAPEROPT_a4 = -D latex_paper_size=a4 +PAPEROPT_letter = -D latex_paper_size=letter +ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . +# the i18n builder cannot share the environment and doctrees with the others +I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . + +.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext + +help: + @echo "Please use \`make ' where is one of" + @echo " html to make standalone HTML files" + @echo " dirhtml to make HTML files named index.html in directories" + @echo " singlehtml to make a single large HTML file" + @echo " pickle to make pickle files" + @echo " json to make JSON files" + @echo " htmlhelp to make HTML files and a HTML help project" + @echo " qthelp to make HTML files and a qthelp project" + @echo " devhelp to make HTML files and a Devhelp project" + @echo " epub to make an epub" + @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" + @echo " latexpdf to make LaTeX files and run them through pdflatex" + @echo " text to make text files" + @echo " man to make manual pages" + @echo " texinfo to make Texinfo files" + @echo " info to make Texinfo files and run them through makeinfo" + @echo " gettext to make PO message catalogs" + @echo " changes to make an overview of all changed/added/deprecated items" + @echo " linkcheck to check all external links for integrity" + @echo " doctest to run all doctests embedded in the documentation (if enabled)" + +clean: + -rm -rf $(BUILDDIR)/* + +html: + $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html + @echo + @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." + +dirhtml: + $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml + @echo + @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." + +singlehtml: + $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml + @echo + @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." + +pickle: + $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle + @echo + @echo "Build finished; now you can process the pickle files." + +json: + $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json + @echo + @echo "Build finished; now you can process the JSON files." + +htmlhelp: + $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp + @echo + @echo "Build finished; now you can run HTML Help Workshop with the" \ + ".hhp project file in $(BUILDDIR)/htmlhelp." + +qthelp: + $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp + @echo + @echo "Build finished; now you can run "qcollectiongenerator" with the" \ + ".qhcp project file in $(BUILDDIR)/qthelp, like this:" + @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/Guzzle.qhcp" + @echo "To view the help file:" + @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/Guzzle.qhc" + +devhelp: + $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp + @echo + @echo "Build finished." + @echo "To view the help file:" + @echo "# mkdir -p $$HOME/.local/share/devhelp/Guzzle" + @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/Guzzle" + @echo "# devhelp" + +epub: + $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub + @echo + @echo "Build finished. The epub file is in $(BUILDDIR)/epub." + +latex: + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex + @echo + @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." + @echo "Run \`make' in that directory to run these through (pdf)latex" \ + "(use \`make latexpdf' here to do that automatically)." + +latexpdf: + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex + @echo "Running LaTeX files through pdflatex..." + $(MAKE) -C $(BUILDDIR)/latex all-pdf + @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." + +text: + $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text + @echo + @echo "Build finished. The text files are in $(BUILDDIR)/text." + +man: + $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man + @echo + @echo "Build finished. The manual pages are in $(BUILDDIR)/man." + +texinfo: + $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo + @echo + @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo." + @echo "Run \`make' in that directory to run these through makeinfo" \ + "(use \`make info' here to do that automatically)." + +info: + $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo + @echo "Running Texinfo files through makeinfo..." + make -C $(BUILDDIR)/texinfo info + @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo." + +gettext: + $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale + @echo + @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale." + +changes: + $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes + @echo + @echo "The overview file is in $(BUILDDIR)/changes." + +linkcheck: + $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck + @echo + @echo "Link check complete; look for any errors in the above output " \ + "or in $(BUILDDIR)/linkcheck/output.txt." + +doctest: + $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest + @echo "Testing of doctests in the sources finished, look at the " \ + "results in $(BUILDDIR)/doctest/output.txt." diff --git a/vendor/guzzle/guzzle/docs/_downloads/guzzle-schema-1.0.json b/vendor/guzzle/guzzle/docs/_downloads/guzzle-schema-1.0.json new file mode 100644 index 0000000..8168302 --- /dev/null +++ b/vendor/guzzle/guzzle/docs/_downloads/guzzle-schema-1.0.json @@ -0,0 +1,176 @@ +{ + "additionalProperties": true, + "name": { + "type": "string", + "description": "Name of the web service" + }, + "apiVersion": { + "type": ["string", "number"], + "description": "Version identifier that the service description is compatible with" + }, + "baseUrl": { + "type": "string", + "description": "Base URL of the web service. Any relative URI specified in an operation will be merged with the baseUrl using the process defined in RFC 2396" + }, + "basePath": { + "type": "string", + "description": "Alias of baseUrl" + }, + "_description": { + "type": "string", + "description": "Short summary of the web service. This is actually called 'description' but this JSON schema wont validate using just description." + }, + "operations": { + "description": "Operations of the web service", + "type": "object", + "properties": { + "extends": { + "type": "string", + "description": "Extend from another operation by name. The parent operation must be defined before the child." + }, + "httpMethod": { + "type": "string", + "description": "HTTP method used with the operation (e.g. GET, POST, PUT, DELETE, PATCH, etc)" + }, + "uri": { + "type": "string", + "description": "URI of the operation. The uri attribute can contain URI templates. The variables of the URI template are parameters of the operation with a location value of uri" + }, + "summary": { + "type": "string", + "description": "Short summary of what the operation does" + }, + "class": { + "type": "string", + "description": "Custom class to instantiate instead of the default Guzzle\\Service\\Command\\OperationCommand" + }, + "responseClass": { + "type": "string", + "description": "This is what is returned from the method. Can be a primitive, class name, or model name." + }, + "responseNotes": { + "type": "string", + "description": "A description of the response returned by the operation" + }, + "responseType": { + "type": "string", + "description": "The type of response that the operation creates. If not specified, this value will be automatically inferred based on whether or not there is a model matching the name, if a matching class name is found, or set to 'primitive' by default.", + "enum": [ "primitive", "class", "model", "documentation" ] + }, + "deprecated": { + "type": "boolean", + "description": "Whether or not the operation is deprecated" + }, + "errorResponses": { + "description": "Errors that could occur while executing the operation", + "type": "array", + "items": { + "type": "object", + "properties": { + "code": { + "type": "number", + "description": "HTTP response status code of the error" + }, + "reason": { + "type": "string", + "description": "Response reason phrase or description of the error" + }, + "class": { + "type": "string", + "description": "A custom exception class that would be thrown if the error is encountered" + } + } + } + }, + "data": { + "type": "object", + "additionalProperties": "true" + }, + "parameters": { + "$ref": "parameters", + "description": "Parameters of the operation. Parameters are used to define how input data is serialized into a HTTP request." + }, + "additionalParameters": { + "$ref": "parameters", + "description": "Validation and serialization rules for any parameter supplied to the operation that was not explicitly defined." + } + } + }, + "models": { + "description": "Schema models that can be referenced throughout the service description. Models can be used to define how an HTTP response is parsed into a Guzzle\\Service\\Resource\\Model object.", + "type": "object", + "properties": { + "$ref": "parameters", + "description": "Parameters of the model. When a model is referenced in a responseClass attribute of an operation, parameters define how a HTTP response message is parsed into a Guzzle\\Service\\Resource\\Model." + } + }, + "includes": { + "description": "Service description files to include and extend from (can be a .json, .js, or .php file)", + "type": "array", + "items": { + "type": "string", + "pattern": ".+\\.(js|json|php)$" + } + }, + "definitions": { + "parameters": { + "extends": "http://json-schema.org/schema", + "id": "parameters", + "name": { + "type": "string", + "description": "Unique name of the parameter" + }, + "type": { + "type": ["string", "array"], + "description": "Type of variable (string, number, integer, boolean, object, array, numeric, null, any). Types are using for validation and determining the structure of a parameter. You can use a union type by providing an array of simple types. If one of the union types matches the provided value, then the value is valid." + }, + "instanceOf": { + "type": "string", + "description": "When the type is an object, you can specify the class that the object must implement" + }, + "required": { + "type": "boolean", + "description": "Whether or not the parameter is required" + }, + "default": { + "description": "Default value to use if no value is supplied" + }, + "static": { + "type": "bool", + "description": "Set to true to specify that the parameter value cannot be changed from the default setting" + }, + "description": { + "type": "string", + "description": "Documentation of the parameter" + }, + "location": { + "type": "string", + "description": "The location of a request used to apply a parameter. Custom locations can be registered with a command, but the defaults are uri, query, statusCode, reasonPhrase, header, body, json, xml, postField, postFile, responseBody" + }, + "sentAs": { + "type": "string", + "description": "Specifies how the data being modeled is sent over the wire. For example, you may wish to include certain headers in a response model that have a normalized casing of FooBar, but the actual header is x-foo-bar. In this case, sentAs would be set to x-foo-bar." + }, + "filters": { + "type": "array", + "description": "Array of static method names to to run a parameter value through. Each value in the array must be a string containing the full class path to a static method or an array of complex filter information. You can specify static methods of classes using the full namespace class name followed by ‘::’ (e.g. FooBar::baz()). Some filters require arguments in order to properly filter a value. For complex filters, use a hash containing a ‘method’ key pointing to a static method, and an ‘args’ key containing an array of positional arguments to pass to the method. Arguments can contain keywords that are replaced when filtering a value: '@value‘ is replaced with the value being validated, '@api‘ is replaced with the Parameter object.", + "items": { + "type": ["string", { + "object": { + "properties": { + "method": { + "type": "string", + "description": "PHP function to call", + "required": true + }, + "args": { + "type": "array" + } + } + } + }] + } + } + } + } +} diff --git a/vendor/guzzle/guzzle/docs/_static/guzzle-icon.png b/vendor/guzzle/guzzle/docs/_static/guzzle-icon.png new file mode 100644 index 0000000000000000000000000000000000000000..f1017f7e6028c14a9e0694c66a6cfbb2d546adf5 GIT binary patch literal 803 zcmV+;1Kj+HP)@ zosv>1reIXPlo1y){RjSw2_NWGX5O-#W+NK3tBQ_IN%bh7xZ1Yehws80|4azI;aWIJ z_%xhlcTubTO7Dbx z)F-R8gg5MzGv|t4=e_El4GCwW0m6?C;0bG4DRC^TH6-pa>y8_h*QBud6Ms>Qf{oN> z=Q($Dn|DINB{`Ea{)h&^x;i{)XQ{?Z&id71eOkRPqgl17&E%|dJIC&SCwnd zY4oUR`OVorB8A||QZjLWS~cr&OD?HEtM@^bIovNUC5An6?z`xDgJL2H2Mya@dku<1YUfi&QvS8KS8=~uOs!oaF z8OMF7-5yyh}yDkaCp7Ob8b;wv(27WLL#lglguF0fh3d(d@ zP%vrDIA~G}dL)X;YnCMSE4ZM-gfVsYTLItd3J`~_vw^k=W%C_MlG002ovPDHLkV1oLqbt3=( literal 0 HcmV?d00001 diff --git a/vendor/guzzle/guzzle/docs/_static/homepage.css b/vendor/guzzle/guzzle/docs/_static/homepage.css new file mode 100644 index 0000000..70c46d8 --- /dev/null +++ b/vendor/guzzle/guzzle/docs/_static/homepage.css @@ -0,0 +1,122 @@ +/* Hero unit on homepage */ + +.hero-unit h1 { + font-size: 49px; + margin-bottom: 12px; +} + +.hero-unit { + padding: 40px; +} + +.hero-unit p { + font-size: 17px; +} + +.masthead img { + float: left; + margin-right: 17px; +} + +.hero-unit ul li { + margin-left: 220px; +} + +.hero-unit .buttons { + text-align: center; +} + +.jumbotron { + position: relative; + padding: 40px 0; + color: #fff; + text-shadow: 0 1px 3px rgba(0,0,0,.4), 0 0 30px rgba(0,0,0,.075); + background: #00312F; + background: -moz-linear-gradient(45deg, #002F31 0%, #335A6D 100%); + background: -webkit-gradient(linear, left bottom, right top, color-stop(0%,#00312D), color-stop(100%,#33566D)); + background: -webkit-linear-gradient(45deg, #020031 0%,#334F6D 100%); + background: -o-linear-gradient(45deg, #002D31 0%,#334D6D 100%); + background: -ms-linear-gradient(45deg, #002F31 0%,#33516D 100%); + background: linear-gradient(45deg, #020031 0%,#33516D 100%); + filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#020031', endColorstr='#6d3353',GradientType=1 ); + -webkit-box-shadow: inset 0 3px 7px rgba(0, 0, 0, .2), inset 0 -3px 7px rgba(0, 0, 0, .2); + -moz-box-shadow: inset 0 3px 7px rgba(0,0,0,.2), inset 0 -3px 7px rgba(0,0,0,.2); + box-shadow: inset 0 3px 7px rgba(0, 0, 0, .2), inset 0 -3px 7px rgba(0, 0, 0, .2); +} + +.jumbotron h1 { + font-size: 80px; + font-weight: bold; + letter-spacing: -1px; + line-height: 1; +} + +.jumbotron p { + font-size: 24px; + font-weight: 300; + line-height: 1.25; + margin-bottom: 30px; +} + +.masthead { + padding: 40px 0 30px; + margin-bottom: 0; + color: #fff; + margin-top: -19px; +} + +.masthead h1 { + display: none; +} + +.masthead p { + font-size: 40px; + font-weight: 200; + line-height: 1.25; + margin: 12px 0 0 0; +} + +.masthead .btn { + padding: 19px 24px; + font-size: 24px; + font-weight: 200; + border: 0; +} + +/* Social bar on homepage */ + +.social { + padding: 2px 0; + text-align: center; + background-color: #f5f5f5; + border-top: 1px solid #fff; + border-bottom: 1px solid #ddd; + margin: 0 0 20px 0; +} + +.social ul { + margin-top: 0; +} + +.social-buttons { + margin-left: 0; + margin-bottom: 0; + padding-left: 0; + list-style: none; +} + +.social-buttons li { + display: inline-block; + padding: 5px 8px; + line-height: 1; + *display: inline; + *zoom: 1; +} + +.center-announcement { + padding: 10px; + background-color: rgb(238, 243, 255); + border-radius: 8px; + text-align: center; + margin: 24px 0; +} diff --git a/vendor/guzzle/guzzle/docs/_static/logo.png b/vendor/guzzle/guzzle/docs/_static/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..965a4ef4139180ea7d33594feba2394dfce6774a GIT binary patch literal 247678 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%0ARzX0ax0O>7%athq>_G8o_) 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 Q^3R@b2)1Zk0&5+MNyUSR-V=Sej)GD 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�{XQapLL3s@DiJOewb9vk!Lb} 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

kl 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

2-cn6gsGIE2zEilUdg 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

Z5%j-C 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%0A=e`l9AQljxQ1J>rUJsDX<`+@ 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 literal 0 HcmV?d00001 diff --git a/vendor/guzzle/guzzle/docs/_static/prettify.css b/vendor/guzzle/guzzle/docs/_static/prettify.css new file mode 100644 index 0000000..4d410b1 --- /dev/null +++ b/vendor/guzzle/guzzle/docs/_static/prettify.css @@ -0,0 +1,41 @@ +.com { + color: #93A1A1; +} +.lit { + color: #195F91; +} +.pun, .opn, .clo { + color: #93A1A1; +} +.fun { + color: #DC322F; +} +.str, .atv { + color: #DD1144; +} +.kwd, .linenums .tag { + color: #1E347B; +} +.typ, .atn, .dec, .var { + color: teal; +} +.pln { + color: #48484C; +} +.prettyprint { + background-color: #F7F7F9; + border: 1px solid #E1E1E8; + padding: 8px; +} +.prettyprint.linenums { + box-shadow: 40px 0 0 #FBFBFC inset, 41px 0 0 #ECECF0 inset; +} +ol.linenums { + margin: 0 0 0 33px; +} +ol.linenums li { + color: #BEBEC5; + line-height: 18px; + padding-left: 12px; + text-shadow: 0 1px 0 #FFFFFF; +} diff --git a/vendor/guzzle/guzzle/docs/_static/prettify.js b/vendor/guzzle/guzzle/docs/_static/prettify.js new file mode 100644 index 0000000..eef5ad7 --- /dev/null +++ b/vendor/guzzle/guzzle/docs/_static/prettify.js @@ -0,0 +1,28 @@ +var q=null;window.PR_SHOULD_USE_CONTINUATION=!0; +(function(){function L(a){function m(a){var f=a.charCodeAt(0);if(f!==92)return f;var b=a.charAt(1);return(f=r[b])?f:"0"<=b&&b<="7"?parseInt(a.substring(1),8):b==="u"||b==="x"?parseInt(a.substring(2),16):a.charCodeAt(1)}function e(a){if(a<32)return(a<16?"\\x0":"\\x")+a.toString(16);a=String.fromCharCode(a);if(a==="\\"||a==="-"||a==="["||a==="]")a="\\"+a;return a}function h(a){for(var f=a.substring(1,a.length-1).match(/\\u[\dA-Fa-f]{4}|\\x[\dA-Fa-f]{2}|\\[0-3][0-7]{0,2}|\\[0-7]{1,2}|\\[\S\s]|[^\\]/g),a= +[],b=[],o=f[0]==="^",c=o?1:0,i=f.length;c122||(d<65||j>90||b.push([Math.max(65,j)|32,Math.min(d,90)|32]),d<97||j>122||b.push([Math.max(97,j)&-33,Math.min(d,122)&-33]))}}b.sort(function(a,f){return a[0]-f[0]||f[1]-a[1]});f=[];j=[NaN,NaN];for(c=0;ci[0]&&(i[1]+1>i[0]&&b.push("-"),b.push(e(i[1])));b.push("]");return b.join("")}function y(a){for(var f=a.source.match(/\[(?:[^\\\]]|\\[\S\s])*]|\\u[\dA-Fa-f]{4}|\\x[\dA-Fa-f]{2}|\\\d+|\\[^\dux]|\(\?[!:=]|[()^]|[^()[\\^]+/g),b=f.length,d=[],c=0,i=0;c=2&&a==="["?f[c]=h(j):a!=="\\"&&(f[c]=j.replace(/[A-Za-z]/g,function(a){a=a.charCodeAt(0);return"["+String.fromCharCode(a&-33,a|32)+"]"}));return f.join("")}for(var t=0,s=!1,l=!1,p=0,d=a.length;p=5&&"lang-"===b.substring(0,5))&&!(o&&typeof o[1]==="string"))c=!1,b="src";c||(r[f]=b)}i=d;d+=f.length;if(c){c=o[1];var j=f.indexOf(c),k=j+c.length;o[2]&&(k=f.length-o[2].length,j=k-c.length);b=b.substring(5);B(l+i,f.substring(0,j),e,p);B(l+i+j,c,C(b,c),p);B(l+i+k,f.substring(k),e,p)}else p.push(l+i,b)}a.e=p}var h={},y;(function(){for(var e=a.concat(m), +l=[],p={},d=0,g=e.length;d=0;)h[n.charAt(k)]=r;r=r[1];n=""+r;p.hasOwnProperty(n)||(l.push(r),p[n]=q)}l.push(/[\S\s]/);y=L(l)})();var t=m.length;return e}function u(a){var m=[],e=[];a.tripleQuotedStrings?m.push(["str",/^(?:'''(?:[^'\\]|\\[\S\s]|''?(?=[^']))*(?:'''|$)|"""(?:[^"\\]|\\[\S\s]|""?(?=[^"]))*(?:"""|$)|'(?:[^'\\]|\\[\S\s])*(?:'|$)|"(?:[^"\\]|\\[\S\s])*(?:"|$))/,q,"'\""]):a.multiLineStrings?m.push(["str",/^(?:'(?:[^'\\]|\\[\S\s])*(?:'|$)|"(?:[^"\\]|\\[\S\s])*(?:"|$)|`(?:[^\\`]|\\[\S\s])*(?:`|$))/, +q,"'\"`"]):m.push(["str",/^(?:'(?:[^\n\r'\\]|\\.)*(?:'|$)|"(?:[^\n\r"\\]|\\.)*(?:"|$))/,q,"\"'"]);a.verbatimStrings&&e.push(["str",/^@"(?:[^"]|"")*(?:"|$)/,q]);var h=a.hashComments;h&&(a.cStyleComments?(h>1?m.push(["com",/^#(?:##(?:[^#]|#(?!##))*(?:###|$)|.*)/,q,"#"]):m.push(["com",/^#(?:(?:define|elif|else|endif|error|ifdef|include|ifndef|line|pragma|undef|warning)\b|[^\n\r]*)/,q,"#"]),e.push(["str",/^<(?:(?:(?:\.\.\/)*|\/?)(?:[\w-]+(?:\/[\w-]+)+)?[\w-]+\.h|[a-z]\w*)>/,q])):m.push(["com",/^#[^\n\r]*/, +q,"#"]));a.cStyleComments&&(e.push(["com",/^\/\/[^\n\r]*/,q]),e.push(["com",/^\/\*[\S\s]*?(?:\*\/|$)/,q]));a.regexLiterals&&e.push(["lang-regex",/^(?:^^\.?|[!+-]|!=|!==|#|%|%=|&|&&|&&=|&=|\(|\*|\*=|\+=|,|-=|->|\/|\/=|:|::|;|<|<<|<<=|<=|=|==|===|>|>=|>>|>>=|>>>|>>>=|[?@[^]|\^=|\^\^|\^\^=|{|\||\|=|\|\||\|\|=|~|break|case|continue|delete|do|else|finally|instanceof|return|throw|try|typeof)\s*(\/(?=[^*/])(?:[^/[\\]|\\[\S\s]|\[(?:[^\\\]]|\\[\S\s])*(?:]|$))+\/)/]);(h=a.types)&&e.push(["typ",h]);a=(""+a.keywords).replace(/^ | $/g, +"");a.length&&e.push(["kwd",RegExp("^(?:"+a.replace(/[\s,]+/g,"|")+")\\b"),q]);m.push(["pln",/^\s+/,q," \r\n\t\xa0"]);e.push(["lit",/^@[$_a-z][\w$@]*/i,q],["typ",/^(?:[@_]?[A-Z]+[a-z][\w$@]*|\w+_t\b)/,q],["pln",/^[$_a-z][\w$@]*/i,q],["lit",/^(?:0x[\da-f]+|(?:\d(?:_\d+)*\d*(?:\.\d*)?|\.\d\+)(?:e[+-]?\d+)?)[a-z]*/i,q,"0123456789"],["pln",/^\\[\S\s]?/,q],["pun",/^.[^\s\w"-$'./@\\`]*/,q]);return x(m,e)}function D(a,m){function e(a){switch(a.nodeType){case 1:if(k.test(a.className))break;if("BR"===a.nodeName)h(a), +a.parentNode&&a.parentNode.removeChild(a);else for(a=a.firstChild;a;a=a.nextSibling)e(a);break;case 3:case 4:if(p){var b=a.nodeValue,d=b.match(t);if(d){var c=b.substring(0,d.index);a.nodeValue=c;(b=b.substring(d.index+d[0].length))&&a.parentNode.insertBefore(s.createTextNode(b),a.nextSibling);h(a);c||a.parentNode.removeChild(a)}}}}function h(a){function b(a,d){var e=d?a.cloneNode(!1):a,f=a.parentNode;if(f){var f=b(f,1),g=a.nextSibling;f.appendChild(e);for(var h=g;h;h=g)g=h.nextSibling,f.appendChild(h)}return e} +for(;!a.nextSibling;)if(a=a.parentNode,!a)return;for(var a=b(a.nextSibling,0),e;(e=a.parentNode)&&e.nodeType===1;)a=e;d.push(a)}var k=/(?:^|\s)nocode(?:\s|$)/,t=/\r\n?|\n/,s=a.ownerDocument,l;a.currentStyle?l=a.currentStyle.whiteSpace:window.getComputedStyle&&(l=s.defaultView.getComputedStyle(a,q).getPropertyValue("white-space"));var p=l&&"pre"===l.substring(0,3);for(l=s.createElement("LI");a.firstChild;)l.appendChild(a.firstChild);for(var d=[l],g=0;g=0;){var h=m[e];A.hasOwnProperty(h)?window.console&&console.warn("cannot override language handler %s",h):A[h]=a}}function C(a,m){if(!a||!A.hasOwnProperty(a))a=/^\s*=o&&(h+=2);e>=c&&(a+=2)}}catch(w){"console"in window&&console.log(w&&w.stack?w.stack:w)}}var v=["break,continue,do,else,for,if,return,while"],w=[[v,"auto,case,char,const,default,double,enum,extern,float,goto,int,long,register,short,signed,sizeof,static,struct,switch,typedef,union,unsigned,void,volatile"], +"catch,class,delete,false,import,new,operator,private,protected,public,this,throw,true,try,typeof"],F=[w,"alignof,align_union,asm,axiom,bool,concept,concept_map,const_cast,constexpr,decltype,dynamic_cast,explicit,export,friend,inline,late_check,mutable,namespace,nullptr,reinterpret_cast,static_assert,static_cast,template,typeid,typename,using,virtual,where"],G=[w,"abstract,boolean,byte,extends,final,finally,implements,import,instanceof,null,native,package,strictfp,super,synchronized,throws,transient"], +H=[G,"as,base,by,checked,decimal,delegate,descending,dynamic,event,fixed,foreach,from,group,implicit,in,interface,internal,into,is,lock,object,out,override,orderby,params,partial,readonly,ref,sbyte,sealed,stackalloc,string,select,uint,ulong,unchecked,unsafe,ushort,var"],w=[w,"debugger,eval,export,function,get,null,set,undefined,var,with,Infinity,NaN"],I=[v,"and,as,assert,class,def,del,elif,except,exec,finally,from,global,import,in,is,lambda,nonlocal,not,or,pass,print,raise,try,with,yield,False,True,None"], +J=[v,"alias,and,begin,case,class,def,defined,elsif,end,ensure,false,in,module,next,nil,not,or,redo,rescue,retry,self,super,then,true,undef,unless,until,when,yield,BEGIN,END"],v=[v,"case,done,elif,esac,eval,fi,function,in,local,set,then,until"],K=/^(DIR|FILE|vector|(de|priority_)?queue|list|stack|(const_)?iterator|(multi)?(set|map)|bitset|u?(int|float)\d*)/,N=/\S/,O=u({keywords:[F,H,w,"caller,delete,die,do,dump,elsif,eval,exit,foreach,for,goto,if,import,last,local,my,next,no,our,print,package,redo,require,sub,undef,unless,until,use,wantarray,while,BEGIN,END"+ +I,J,v],hashComments:!0,cStyleComments:!0,multiLineStrings:!0,regexLiterals:!0}),A={};k(O,["default-code"]);k(x([],[["pln",/^[^]*(?:>|$)/],["com",/^<\!--[\S\s]*?(?:--\>|$)/],["lang-",/^<\?([\S\s]+?)(?:\?>|$)/],["lang-",/^<%([\S\s]+?)(?:%>|$)/],["pun",/^(?:<[%?]|[%?]>)/],["lang-",/^]*>([\S\s]+?)<\/xmp\b[^>]*>/i],["lang-js",/^]*>([\S\s]*?)(<\/script\b[^>]*>)/i],["lang-css",/^]*>([\S\s]*?)(<\/style\b[^>]*>)/i],["lang-in.tag",/^(<\/?[a-z][^<>]*>)/i]]), +["default-markup","htm","html","mxml","xhtml","xml","xsl"]);k(x([["pln",/^\s+/,q," \t\r\n"],["atv",/^(?:"[^"]*"?|'[^']*'?)/,q,"\"'"]],[["tag",/^^<\/?[a-z](?:[\w-.:]*\w)?|\/?>$/i],["atn",/^(?!style[\s=]|on)[a-z](?:[\w:-]*\w)?/i],["lang-uq.val",/^=\s*([^\s"'>]*(?:[^\s"'/>]|\/(?=\s)))/],["pun",/^[/<->]+/],["lang-js",/^on\w+\s*=\s*"([^"]+)"/i],["lang-js",/^on\w+\s*=\s*'([^']+)'/i],["lang-js",/^on\w+\s*=\s*([^\s"'>]+)/i],["lang-css",/^style\s*=\s*"([^"]+)"/i],["lang-css",/^style\s*=\s*'([^']+)'/i],["lang-css", +/^style\s*=\s*([^\s"'>]+)/i]]),["in.tag"]);k(x([],[["atv",/^[\S\s]+/]]),["uq.val"]);k(u({keywords:F,hashComments:!0,cStyleComments:!0,types:K}),["c","cc","cpp","cxx","cyc","m"]);k(u({keywords:"null,true,false"}),["json"]);k(u({keywords:H,hashComments:!0,cStyleComments:!0,verbatimStrings:!0,types:K}),["cs"]);k(u({keywords:G,cStyleComments:!0}),["java"]);k(u({keywords:v,hashComments:!0,multiLineStrings:!0}),["bsh","csh","sh"]);k(u({keywords:I,hashComments:!0,multiLineStrings:!0,tripleQuotedStrings:!0}), +["cv","py"]);k(u({keywords:"caller,delete,die,do,dump,elsif,eval,exit,foreach,for,goto,if,import,last,local,my,next,no,our,print,package,redo,require,sub,undef,unless,until,use,wantarray,while,BEGIN,END",hashComments:!0,multiLineStrings:!0,regexLiterals:!0}),["perl","pl","pm"]);k(u({keywords:J,hashComments:!0,multiLineStrings:!0,regexLiterals:!0}),["rb"]);k(u({keywords:w,cStyleComments:!0,regexLiterals:!0}),["js"]);k(u({keywords:"all,and,by,catch,class,else,extends,false,finally,for,if,in,is,isnt,loop,new,no,not,null,of,off,on,or,return,super,then,true,try,unless,until,when,while,yes", +hashComments:3,cStyleComments:!0,multilineStrings:!0,tripleQuotedStrings:!0,regexLiterals:!0}),["coffee"]);k(x([],[["str",/^[\S\s]+/]]),["regex"]);window.prettyPrintOne=function(a,m,e){var h=document.createElement("PRE");h.innerHTML=a;e&&D(h,e);E({g:m,i:e,h:h});return h.innerHTML};window.prettyPrint=function(a){function m(){for(var e=window.PR_SHOULD_USE_CONTINUATION?l.now()+250:Infinity;p=0){var k=k.match(g),f,b;if(b= +!k){b=n;for(var o=void 0,c=b.firstChild;c;c=c.nextSibling)var i=c.nodeType,o=i===1?o?b:c:i===3?N.test(c.nodeValue)?b:o:o;b=(f=o===b?void 0:o)&&"CODE"===f.tagName}b&&(k=f.className.match(g));k&&(k=k[1]);b=!1;for(o=n.parentNode;o;o=o.parentNode)if((o.tagName==="pre"||o.tagName==="code"||o.tagName==="xmp")&&o.className&&o.className.indexOf("prettyprint")>=0){b=!0;break}b||((b=(b=n.className.match(/\blinenums\b(?::(\d+))?/))?b[1]&&b[1].length?+b[1]:!0:!1)&&D(n,b),d={g:k,h:n,i:b},E(d))}}p + + + +

+
+ guzzle +

Guzzle

+

Guzzle is a PHP HTTP client
& framework for building RESTful web service clients.

+

+ View Guzzle on GitHub + Read the docs +

+
+
+ + + +
+ +

Introducing Guzzle

+ +

Guzzle takes the pain out of sending HTTP requests and the redundancy out of creating web service clients. It's + a framework that includes the tools needed to create a robust web service client, including: + Service descriptions for defining the inputs and outputs of an API, resource iterators for traversing + paginated resources, batching for sending a large number of requests as efficiently as possible.

+ +
    +
  • All the power of cURL with a simple interface.
  • +
  • Persistent connections and parallel requests.
  • +
  • Streams request and response bodies
  • +
  • Service descriptions for quickly building clients.
  • +
  • Powered by the Symfony2 EventDispatcher.
  • +
  • Use all of the code or only specific components.
  • +
  • Plugins for caching, logging, OAuth, mocks, and more
  • +
  • Includes a custom node.js webserver to test your clients.
  • +
+ +
+ Guzzle is now part of Drupal 8 core and powers the official AWS SDK for PHP +
+ +

GitHub Example

+ +
<?php
+require_once 'vendor/autoload.php';
+use Guzzle\Http\Client;
+
+// Create a client and provide a base URL
+$client = new Client('https://api.github.com');
+// Create a request with basic Auth
+$request = $client->get('/user')->setAuth('user', 'pass');
+// Send the request and get the response
+$response = $request->send();
+echo $response->getBody();
+// >>> {"type":"User", ...
+echo $response->getHeader('Content-Length');
+// >>> 792
+
+ +

Twitter Example

+
<?php
+// Create a client to work with the Twitter API
+$client = new Client('https://api.twitter.com/{version}', array(
+    'version' => '1.1'
+));
+
+// Sign all requests with the OauthPlugin
+$client->addSubscriber(new Guzzle\Plugin\Oauth\OauthPlugin(array(
+    'consumer_key'  => '***',
+    'consumer_secret' => '***',
+    'token'       => '***',
+    'token_secret'  => '***'
+)));
+
+echo $client->get('statuses/user_timeline.json')->send()->getBody();
+// >>> {"public_gists":6,"type":"User" ...
+
+// Create a tweet using POST
+$request = $client->post('statuses/update.json', null, array(
+    'status' => 'Tweeted with Guzzle, http://guzzlephp.org'
+));
+
+// Send the request and parse the JSON response into an array
+$data = $request->send()->json();
+echo $data['text'];
+// >>> Tweeted with Guzzle, http://t.co/kngJMfRk
+
+
+ + diff --git a/vendor/guzzle/guzzle/docs/_templates/leftbar.html b/vendor/guzzle/guzzle/docs/_templates/leftbar.html new file mode 100644 index 0000000..e69de29 diff --git a/vendor/guzzle/guzzle/docs/_templates/nav_links.html b/vendor/guzzle/guzzle/docs/_templates/nav_links.html new file mode 100644 index 0000000..d4f2165 --- /dev/null +++ b/vendor/guzzle/guzzle/docs/_templates/nav_links.html @@ -0,0 +1,5 @@ +
  • Docs
  • +
  • API
  • +
  • GitHub
  • +
  • Forum
  • +
  • IRC
  • diff --git a/vendor/guzzle/guzzle/docs/batching/batching.rst b/vendor/guzzle/guzzle/docs/batching/batching.rst new file mode 100644 index 0000000..57f04d8 --- /dev/null +++ b/vendor/guzzle/guzzle/docs/batching/batching.rst @@ -0,0 +1,183 @@ +======== +Batching +======== + +Guzzle provides a fairly generic and very customizable batching framework that allows developers to efficiently +transfer requests in parallel. + +Sending requests and commands in parallel +----------------------------------------- + +You can send HTTP requests in parallel by passing an array of ``Guzzle\Http\Message\RequestInterface`` objects to +``Guzzle\Http\Client::send()``: + +.. code-block:: php + + $responses = $client->send(array( + $client->get('http://www.example.com/foo'), + $client->get('http://www.example.com/baz') + $client->get('http://www.example.com/bar') + )); + +You can send commands in parallel by passing an array of ``Guzzle\Service\Command\CommandInterface`` objects +``Guzzle\Service\Client::execute()``: + +.. code-block:: php + + $commands = $client->execute(array( + $client->getCommand('foo'), + $client->getCommand('baz'), + $client->getCommand('bar') + )); + +These approaches work well for most use-cases. When you need more control over the requests that are sent in +parallel or you need to send a large number of requests, you need to use the functionality provided in the +``Guzzle\Batch`` namespace. + +Batching overview +----------------- + +The batch object, ``Guzzle\Batch\Batch``, is a queue. You add requests to the queue until you are ready to transfer +all of the requests. In order to efficiently transfer the items in the queue, the batch object delegates the +responsibility of dividing the queue into manageable parts to a divisor (``Guzzle\Batch\BatchDivisorInterface``). +The batch object then iterates over each array of items created by the divisor and sends them to the batch object's +``Guzzle\Batch\BatchTransferInterface``. + +.. code-block:: php + + use Guzzle\Batch\Batch; + use Guzzle\Http\BatchRequestTransfer; + + // BatchRequestTransfer acts as both the divisor and transfer strategy + $transferStrategy = new BatchRequestTransfer(10); + $divisorStrategy = $transferStrategy; + + $batch = new Batch($transferStrategy, $divisorStrategy); + + // Add some requests to the batch queue + $batch->add($request1) + ->add($request2) + ->add($request3); + + // Flush the queue and retrieve the flushed items + $arrayOfTransferredRequests = $batch->flush(); + +.. note:: + + You might find that your transfer strategy will need to act as both the divisor and transfer strategy. + +Using the BatchBuilder +---------------------- + +The ``Guzzle\Batch\BatchBuilder`` makes it easier to create batch objects. The batch builder also provides an easier +way to add additional behaviors to your batch object. + +Transferring requests +~~~~~~~~~~~~~~~~~~~~~ + +The ``Guzzle\Http\BatchRequestTransfer`` class efficiently transfers HTTP requests in parallel by grouping batches of +requests by the curl_multi handle that is used to transfer the requests. + +.. code-block:: php + + use Guzzle\Batch\BatchBuilder; + + $batch = BatchBuilder::factory() + ->transferRequests(10) + ->build(); + +Transferring commands +~~~~~~~~~~~~~~~~~~~~~ + +The ``Guzzle\Service\Command\BatchCommandTransfer`` class efficiently transfers service commands by grouping commands +by the client that is used to transfer them. You can add commands to a batch object that are transferred by different +clients, and the batch will handle the rest. + +.. code-block:: php + + use Guzzle\Batch\BatchBuilder; + + $batch = BatchBuilder::factory() + ->transferCommands(10) + ->build(); + + $batch->add($client->getCommand('foo')) + ->add($client->getCommand('baz')) + ->add($client->getCommand('bar')); + + $commands = $batch->flush(); + +Batch behaviors +--------------- + +You can add various behaviors to your batch that allow for more customizable transfers. + +Automatically flushing a queue +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Use the ``Guzzle\Batch\FlushingBatch`` decorator when you want to pump a large number of items into a batch queue and +have the queue automatically flush when the size of the queue reaches a certain threshold. + +.. code-block:: php + + use Guzzle\Batch\BatchBuilder; + + $batch = BatchBuilder::factory() + ->transferRequests(10) + ->autoFlushAt(10) + ->build(); + +Batch builder method: ``autoFlushAt($threshold)`` + +Notifying on flush +~~~~~~~~~~~~~~~~~~ + +Use the ``Guzzle\Batch\NotifyingBatch`` decorator if you want a function to be notified each time the batch queue is +flushed. This is useful when paired with the flushing batch decorator. Pass a callable to the ``notify()`` method of +a batch builder to use this decorator with the builder. + +.. code-block:: php + + use Guzzle\Batch\BatchBuilder; + + $batch = BatchBuilder::factory() + ->transferRequests(10) + ->autoFlushAt(10) + ->notify(function (array $transferredItems) { + echo 'Transferred ' . count($transferredItems) . "items\n"; + }) + ->build(); + +Batch builder method:: ``notify(callable $callback)`` + +Keeping a history +~~~~~~~~~~~~~~~~~ + +Use the ``Guzzle\Batch\HistoryBatch`` decorator if you want to maintain a history of all the items transferred with +the batch queue. + +.. code-block:: php + + use Guzzle\Batch\BatchBuilder; + + $batch = BatchBuilder::factory() + ->transferRequests(10) + ->keepHistory() + ->build(); + +After transferring items, you can use the ``getHistory()`` of a batch to retrieve an array of transferred items. Be +sure to periodically clear the history using ``clearHistory()``. + +Batch builder method: ``keepHistory()`` + +Exception buffering +~~~~~~~~~~~~~~~~~~~ + +Use the ``Guzzle\Batch\ExceptionBufferingBatch`` decorator to buffer exceptions during a transfer so that you can +transfer as many items as possible then deal with the errored batches after the transfer completes. After transfer, +use the ``getExceptions()`` method of a batch to retrieve an array of +``Guzzle\Batch\Exception\BatchTransferException`` objects. You can use these exceptions to attempt to retry the +failed batches. Be sure to clear the buffered exceptions when you are done with them by using the +``clearExceptions()`` method. + +Batch builder method: ``bufferExceptions()`` diff --git a/vendor/guzzle/guzzle/docs/conf.py b/vendor/guzzle/guzzle/docs/conf.py new file mode 100644 index 0000000..92bc46b --- /dev/null +++ b/vendor/guzzle/guzzle/docs/conf.py @@ -0,0 +1,94 @@ +import sys, os +from sphinx.highlighting import lexers +from pygments.lexers.web import PhpLexer + +lexers['php'] = PhpLexer(startinline=True, linenos=1) +lexers['php-annotations'] = PhpLexer(startinline=True, linenos=1) +primary_domain = 'php' + +# -- General configuration ----------------------------------------------------- + +extensions = [] +templates_path = ['_templates'] +source_suffix = '.rst' +master_doc = 'index' + +project = u'Guzzle' +copyright = u'2012, Michael Dowling' +version = '3.0.0' +release = '3.0.0' + +exclude_patterns = ['_build'] + +# -- Options for HTML output --------------------------------------------------- + +# The name for this set of Sphinx documents. If None, it defaults to +# " v documentation". +html_title = "Guzzle documentation" +html_short_title = "Guzzle" + +# Add any paths that contain custom static files (such as style sheets) here, +# relative to this directory. They are copied after the builtin static files, +# so a file named "default.css" will overwrite the builtin "default.css". +html_static_path = ['_static'] + +# Custom sidebar templates, maps document names to template names. +html_sidebars = { + '**': ['localtoc.html', 'leftbar.html', 'searchbox.html'] +} + +# Output file base name for HTML help builder. +htmlhelp_basename = 'Guzzledoc' + +# -- Guzzle Sphinx theme setup ------------------------------------------------ + +sys.path.insert(0, '/Users/dowling/projects/guzzle_sphinx_theme') + +import guzzle_sphinx_theme +html_translator_class = 'guzzle_sphinx_theme.HTMLTranslator' +html_theme_path = guzzle_sphinx_theme.html_theme_path() +html_theme = 'guzzle_sphinx_theme' + +# Guzzle theme options (see theme.conf for more information) +html_theme_options = { + "index_template": "index.html", + "project_nav_name": "Guzzle", + "github_user": "guzzle", + "github_repo": "guzzle", + "disqus_comments_shortname": "guzzle", + "google_analytics_account": "UA-22752917-1" +} + +# -- Options for LaTeX output -------------------------------------------------- + +latex_elements = {} + +# Grouping the document tree into LaTeX files. List of tuples +# (source start file, target name, title, author, documentclass [howto/manual]). +latex_documents = [ + ('index', 'Guzzle.tex', u'Guzzle Documentation', + u'Michael Dowling', 'manual'), +] + +# -- Options for manual page output -------------------------------------------- + +# One entry per manual page. List of tuples +# (source start file, name, description, authors, manual section). +man_pages = [ + ('index', 'guzzle', u'Guzzle Documentation', + [u'Michael Dowling'], 1) +] + +# If true, show URL addresses after external links. +#man_show_urls = False + +# -- Options for Texinfo output ------------------------------------------------ + +# Grouping the document tree into Texinfo files. List of tuples +# (source start file, target name, title, author, +# dir menu entry, description, category) +texinfo_documents = [ + ('index', 'Guzzle', u'Guzzle Documentation', + u'Michael Dowling', 'Guzzle', 'One line description of project.', + 'Miscellaneous'), +] diff --git a/vendor/guzzle/guzzle/docs/docs.rst b/vendor/guzzle/guzzle/docs/docs.rst new file mode 100644 index 0000000..cf87908 --- /dev/null +++ b/vendor/guzzle/guzzle/docs/docs.rst @@ -0,0 +1,73 @@ +.. title:: Guzzle | PHP HTTP client and framework for consuming RESTful web services + +==================== +Guzzle Documentation +==================== + +Getting started +--------------- + +.. toctree:: + :maxdepth: 1 + + getting-started/overview + getting-started/installation + getting-started/faq + +The HTTP client +--------------- + +.. toctree:: + :maxdepth: 2 + + http-client/client + http-client/request + http-client/response + http-client/entity-bodies + http-client/http-redirects + http-client/uri-templates + +Plugins +------- + +.. toctree:: + :maxdepth: 1 + + plugins/plugins-overview + plugins/creating-plugins + plugins/async-plugin + plugins/backoff-plugin + plugins/cache-plugin + plugins/cookie-plugin + plugins/curl-auth-plugin + plugins/history-plugin + plugins/log-plugin + plugins/md5-validator-plugin + plugins/mock-plugin + plugins/oauth-plugin + +The web service client +---------------------- + +.. toctree:: + :maxdepth: 1 + + webservice-client/webservice-client + webservice-client/using-the-service-builder + webservice-client/guzzle-service-descriptions + batching/batching + iterators/resource-iterators + iterators/guzzle-iterators + +Testing +------- + +.. toctree:: + :maxdepth: 2 + + testing/unit-testing + +API Docs +-------- + +`Read the API docs `_ diff --git a/vendor/guzzle/guzzle/docs/getting-started/faq.rst b/vendor/guzzle/guzzle/docs/getting-started/faq.rst new file mode 100644 index 0000000..a0a3fdb --- /dev/null +++ b/vendor/guzzle/guzzle/docs/getting-started/faq.rst @@ -0,0 +1,29 @@ +=== +FAQ +=== + +What should I do if I get this error: Fatal error: Maximum function nesting level of '100' reached, aborting! +------------------------------------------------------------------------------------------------------------- + +You could run into this error if you have the XDebug extension installed and you execute a lot of requests in +callbacks. This error message comes specifically from the XDebug extension. PHP itself does not have a function +nesting limit. Change this setting in your php.ini to increase the limit:: + + xdebug.max_nesting_level = 1000 + +[`source `_] + +How can I speed up my client? +----------------------------- + +There are several things you can do to speed up your client: + +1. Utilize a C based HTTP message parser (e.g. ``Guzzle\Parser\Message\PeclHttpMessageParser``) +2. Disable operation validation by setting the ``command.disable_validation`` option to true on a command + +Why am I getting a 417 error response? +-------------------------------------- + +This can occur for a number of reasons, but if you are sending PUT, POST, or PATCH requests with an +``Expect: 100-Continue`` header, a server that does not support this header will return a 417 response. You can work +around this by calling ``$request->removeHeader('Expect');`` after setting the entity body of a request. diff --git a/vendor/guzzle/guzzle/docs/getting-started/installation.rst b/vendor/guzzle/guzzle/docs/getting-started/installation.rst new file mode 100644 index 0000000..77d4001 --- /dev/null +++ b/vendor/guzzle/guzzle/docs/getting-started/installation.rst @@ -0,0 +1,154 @@ +============ +Installation +============ + +Requirements +------------ + +#. PHP 5.3.3+ compiled with the cURL extension +#. A recent version of cURL 7.16.2+ compiled with OpenSSL and zlib + +Installing Guzzle +----------------- + +Composer +~~~~~~~~ + +The recommended way to install Guzzle is with `Composer `_. Composer is a dependency +management tool for PHP that allows you to declare the dependencies your project needs and installs them into your +project. + +.. code-block:: bash + + # Install Composer + curl -sS https://getcomposer.org/installer | php + + # Add Guzzle as a dependency + php composer.phar require guzzle/guzzle:~3.9 + +After installing, you need to require Composer's autoloader: + +.. code-block:: php + + require 'vendor/autoload.php'; + +You can find out more on how to install Composer, configure autoloading, and other best-practices for defining +dependencies at `getcomposer.org `_. + +Using only specific parts of Guzzle +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +While you can always just rely on ``guzzle/guzzle``, Guzzle provides several smaller parts of Guzzle as individual +packages available through Composer. + ++-----------------------------------------------------------------------------------------------+------------------------------------------+ +| Package name | Description | ++===============================================================================================+==========================================+ +| `guzzle/common `_ | Provides ``Guzzle\Common`` | ++-----------------------------------------------------------------------------------------------+------------------------------------------+ +| `guzzle/http `_ | Provides ``Guzzle\Http`` | ++-----------------------------------------------------------------------------------------------+------------------------------------------+ +| `guzzle/parser `_ | Provides ``Guzzle\Parser`` | ++-----------------------------------------------------------------------------------------------+------------------------------------------+ +| `guzzle/batch `_ | Provides ``Guzzle\Batch`` | ++-----------------------------------------------------------------------------------------------+------------------------------------------+ +| `guzzle/cache `_ | Provides ``Guzzle\Cache`` | ++-----------------------------------------------------------------------------------------------+------------------------------------------+ +| `guzzle/inflection `_ | Provides ``Guzzle\Inflection`` | ++-----------------------------------------------------------------------------------------------+------------------------------------------+ +| `guzzle/iterator `_ | Provides ``Guzzle\Iterator`` | ++-----------------------------------------------------------------------------------------------+------------------------------------------+ +| `guzzle/log `_ | Provides ``Guzzle\Log`` | ++-----------------------------------------------------------------------------------------------+------------------------------------------+ +| `guzzle/plugin `_ | Provides ``Guzzle\Plugin`` (all plugins) | ++-----------------------------------------------------------------------------------------------+------------------------------------------+ +| `guzzle/plugin-async `_ | Provides ``Guzzle\Plugin\Async`` | ++-----------------------------------------------------------------------------------------------+------------------------------------------+ +| `guzzle/plugin-backoff `_ | Provides ``Guzzle\Plugin\BackoffPlugin`` | ++-----------------------------------------------------------------------------------------------+------------------------------------------+ +| `guzzle/plugin-cache `_ | Provides ``Guzzle\Plugin\Cache`` | ++-----------------------------------------------------------------------------------------------+------------------------------------------+ +| `guzzle/plugin-cookie `_ | Provides ``Guzzle\Plugin\Cookie`` | ++-----------------------------------------------------------------------------------------------+------------------------------------------+ +| `guzzle/plugin-error-response `_ | Provides ``Guzzle\Plugin\ErrorResponse`` | ++-----------------------------------------------------------------------------------------------+------------------------------------------+ +| `guzzle/plugin-history `_ | Provides ``Guzzle\Plugin\History`` | ++-----------------------------------------------------------------------------------------------+------------------------------------------+ +| `guzzle/plugin-log `_ | Provides ``Guzzle\Plugin\Log`` | ++-----------------------------------------------------------------------------------------------+------------------------------------------+ +| `guzzle/plugin-md5 `_ | Provides ``Guzzle\Plugin\Md5`` | ++-----------------------------------------------------------------------------------------------+------------------------------------------+ +| `guzzle/plugin-mock `_ | Provides ``Guzzle\Plugin\Mock`` | ++-----------------------------------------------------------------------------------------------+------------------------------------------+ +| `guzzle/plugin-oauth `_ | Provides ``Guzzle\Plugin\Oauth`` | ++-----------------------------------------------------------------------------------------------+------------------------------------------+ +| `guzzle/service `_ | Provides ``Guzzle\Service`` | ++-----------------------------------------------------------------------------------------------+------------------------------------------+ +| `guzzle/stream `_ | Provides ``Guzzle\Stream`` | ++-----------------------------------------------------------------------------------------------+------------------------------------------+ + +Bleeding edge +^^^^^^^^^^^^^ + +During your development, you can keep up with the latest changes on the master branch by setting the version +requirement for Guzzle to ``dev-master``. + +.. code-block:: js + + { + "require": { + "guzzle/guzzle": "dev-master" + } + } + +PEAR +~~~~ + +Guzzle can be installed through PEAR: + +.. code-block:: bash + + pear channel-discover guzzlephp.org/pear + pear install guzzle/guzzle + +You can install a specific version of Guzzle by providing a version number suffix: + +.. code-block:: bash + + pear install guzzle/guzzle-3.9.0 + +Contributing to Guzzle +---------------------- + +In order to contribute, you'll need to checkout the source from GitHub and install Guzzle's dependencies using +Composer: + +.. code-block:: bash + + git clone https://github.com/guzzle/guzzle.git + cd guzzle && curl -s http://getcomposer.org/installer | php && ./composer.phar install --dev + +Guzzle is unit tested with PHPUnit. You will need to create your own phpunit.xml file in order to run the unit tests +(or just copy phpunit.xml.dist to phpunit.xml). Run the tests using the vendored PHPUnit binary: + +.. code-block:: bash + + vendor/bin/phpunit + +You'll need to install node.js v0.5.0 or newer in order to test the cURL implementation. + +Framework integrations +---------------------- + +Using Guzzle with Symfony +~~~~~~~~~~~~~~~~~~~~~~~~~ + +Bundles are available on GitHub: + +- `DdeboerGuzzleBundle `_ for Guzzle 2 +- `MisdGuzzleBundle `_ for Guzzle 3 + +Using Guzzle with Silex +~~~~~~~~~~~~~~~~~~~~~~~ + +A `Guzzle Silex service provider `_ is available on GitHub. diff --git a/vendor/guzzle/guzzle/docs/getting-started/overview.rst b/vendor/guzzle/guzzle/docs/getting-started/overview.rst new file mode 100644 index 0000000..505b409 --- /dev/null +++ b/vendor/guzzle/guzzle/docs/getting-started/overview.rst @@ -0,0 +1,85 @@ +================= +Welcome to Guzzle +================= + +What is Guzzle? +~~~~~~~~~~~~~~~ + +Guzzle is a PHP HTTP client and framework for building web service clients. Guzzle takes the pain out of sending HTTP +requests and the redundancy out of creating web service clients. + +Features at a glance +-------------------- + +- All the power of cURL with a simple interface. +- Persistent connections and parallel requests. +- Streams request and response bodies +- Service descriptions for quickly building clients. +- Powered by the Symfony2 EventDispatcher. +- Use all of the code or only specific components. +- Plugins for caching, logging, OAuth, mocks, and more +- Includes a custom node.js webserver to test your clients. +- Service descriptions for defining the inputs and outputs of an API +- Resource iterators for traversing paginated resources +- Batching for sending a large number of requests as efficiently as possible + +.. code-block:: php + + // Really simple using a static facade + Guzzle\Http\StaticClient::mount(); + $response = Guzzle::get('http://guzzlephp.org'); + + // More control using a client class + $client = new \Guzzle\Http\Client('http://guzzlephp.org'); + $request = $client->get('/'); + $response = $request->send(); + +License +------- + +Licensed using the `MIT license `_. + + Copyright (c) 2013 Michael Dowling + + 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. + +Contributing +------------ + +Guidelines +~~~~~~~~~~ + +This is still a work in progress, but there are only a few rules: + +1. Guzzle follows PSR-0, PSR-1, and PSR-2 +2. All pull requests must include unit tests to ensure the change works as expected and to prevent future regressions + +Reporting a security vulnerability +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +We want to ensure that Guzzle is a secure HTTP client library for everyone. If you've discovered a security +vulnerability in Guzzle, we appreciate your help in disclosing it to us in a +`responsible manner `_. + +Publicly disclosing a vulnerability can put the entire community at risk. If you've discovered a security concern, +please email us at security@guzzlephp.org. We'll work with you to make sure that we understand the scope of the issue, +and that we fully address your concern. We consider correspondence sent to security@guzzlephp.org our highest priority, +and work to address any issues that arise as quickly as possible. + +After a security vulnerability has been corrected, a security hotfix release will be deployed as soon as possible. diff --git a/vendor/guzzle/guzzle/docs/http-client/client.rst b/vendor/guzzle/guzzle/docs/http-client/client.rst new file mode 100644 index 0000000..723d729 --- /dev/null +++ b/vendor/guzzle/guzzle/docs/http-client/client.rst @@ -0,0 +1,569 @@ +====================== +The Guzzle HTTP client +====================== + +Guzzle gives PHP developers complete control over HTTP requests while utilizing HTTP/1.1 best practices. Guzzle's HTTP +functionality is a robust framework built on top of the `PHP libcurl bindings `_. + +The three main parts of the Guzzle HTTP client are: + ++--------------+-------------------------------------------------------------------------------------------------------+ +| Clients | ``Guzzle\Http\Client`` (creates and sends requests, associates a response with a request) | ++--------------+-------------------------------------------------------------------------------------------------------+ +| Requests | ``Guzzle\Http\Message\Request`` (requests with no body), | +| | ``Guzzle\Http\Message\EntityEnclosingRequest`` (requests with a body) | ++--------------+-------------------------------------------------------------------------------------------------------+ +| Responses | ``Guzzle\Http\Message\Response`` | ++--------------+-------------------------------------------------------------------------------------------------------+ + +Creating a Client +----------------- + +Clients create requests, send requests, and set responses on a request object. When instantiating a client object, +you can pass an optional "base URL" and optional array of configuration options. A base URL is a +:doc:`URI template ` that contains the URL of a remote server. When creating requests with a relative +URL, the base URL of a client will be merged into the request's URL. + +.. code-block:: php + + use Guzzle\Http\Client; + + // Create a client and provide a base URL + $client = new Client('https://api.github.com'); + + $request = $client->get('/user'); + $request->setAuth('user', 'pass'); + echo $request->getUrl(); + // >>> https://api.github.com/user + + // You must send a request in order for the transfer to occur + $response = $request->send(); + + echo $response->getBody(); + // >>> {"type":"User", ... + + echo $response->getHeader('Content-Length'); + // >>> 792 + + $data = $response->json(); + echo $data['type']; + // >>> User + +Base URLs +~~~~~~~~~ + +Notice that the URL provided to the client's ``get()`` method is relative. Relative URLs will always merge into the +base URL of the client. There are a few rules that control how the URLs are merged. + +.. tip:: + + Guzzle follows `RFC 3986 `_ when merging base URLs and + relative URLs. + +In the above example, we passed ``/user`` to the ``get()`` method of the client. This is a relative URL, so it will +merge into the base URL of the client-- resulting in the derived URL of ``https://api.github.com/users``. + +``/user`` is a relative URL but uses an absolute path because it contains the leading slash. Absolute paths will +overwrite any existing path of the base URL. If an absolute path is provided (e.g. ``/path/to/something``), then the +path specified in the base URL of the client will be replaced with the absolute path, and the query string provided +by the relative URL will replace the query string of the base URL. + +Omitting the leading slash and using relative paths will add to the path of the base URL of the client. So using a +client base URL of ``https://api.twitter.com/v1.1`` and creating a GET request with ``statuses/user_timeline.json`` +will result in a URL of ``https://api.twitter.com/v1.1/statuses/user_timeline.json``. If a relative path and a query +string are provided, then the relative path will be appended to the base URL path, and the query string provided will +be merged into the query string of the base URL. + +If an absolute URL is provided (e.g. ``http://httpbin.org/ip``), then the request will completely use the absolute URL +as-is without merging in any of the URL parts specified in the base URL. + +Configuration options +~~~~~~~~~~~~~~~~~~~~~ + +The second argument of the client's constructor is an array of configuration data. This can include URI template data +or special options that alter the client's behavior: + ++-------------------------------+-------------------------------------------------------------------------------------+ +| ``request.options`` | Associative array of :ref:`Request options ` to apply to every | +| | request created by the client. | ++-------------------------------+-------------------------------------------------------------------------------------+ +| ``redirect.disable`` | Disable HTTP redirects for every request created by the client. | ++-------------------------------+-------------------------------------------------------------------------------------+ +| ``curl.options`` | Associative array of cURL options to apply to every request created by the client. | +| | if either the key or value of an entry in the array is a string, Guzzle will | +| | attempt to find a matching defined cURL constant automatically (e.g. | +| | "CURLOPT_PROXY" will be converted to the constant ``CURLOPT_PROXY``). | ++-------------------------------+-------------------------------------------------------------------------------------+ +| ``ssl.certificate_authority`` | Set to true to use the Guzzle bundled SSL certificate bundle (this is used by | +| | default, 'system' to use the bundle on your system, a string pointing to a file to | +| | use a specific certificate file, a string pointing to a directory to use multiple | +| | certificates, or ``false`` to disable SSL validation (not recommended). | +| | | +| | When using Guzzle inside of a phar file, the bundled SSL certificate will be | +| | extracted to your system's temp folder, and each time a client is created an MD5 | +| | check will be performed to ensure the integrity of the certificate. | ++-------------------------------+-------------------------------------------------------------------------------------+ +| ``command.params`` | When using a ``Guzzle\Service\Client`` object, this is an associative array of | +| | default options to set on each command created by the client. | ++-------------------------------+-------------------------------------------------------------------------------------+ + +Here's an example showing how to set various configuration options, including default headers to send with each request, +default query string parameters to add to each request, a default auth scheme for each request, and a proxy to use for +each request. Values can be injected into the client's base URL using variables from the configuration array. + +.. code-block:: php + + use Guzzle\Http\Client; + + $client = new Client('https://api.twitter.com/{version}', array( + 'version' => 'v1.1', + 'request.options' => array( + 'headers' => array('Foo' => 'Bar'), + 'query' => array('testing' => '123'), + 'auth' => array('username', 'password', 'Basic|Digest|NTLM|Any'), + 'proxy' => 'tcp://localhost:80' + ) + )); + +Setting a custom User-Agent +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The default Guzzle User-Agent header is ``Guzzle/ curl/ PHP/``. You can +customize the User-Agent header of a client by calling the ``setUserAgent()`` method of a Client object. + +.. code-block:: php + + // Completely override the default User-Agent + $client->setUserAgent('Test/123'); + + // Prepend a string to the default User-Agent + $client->setUserAgent('Test/123', true); + +Creating requests with a client +------------------------------- + +A Client object exposes several methods used to create Request objects: + +* Create a custom HTTP request: ``$client->createRequest($method, $uri, array $headers, $body, $options)`` +* Create a GET request: ``$client->get($uri, array $headers, $options)`` +* Create a HEAD request: ``$client->head($uri, array $headers, $options)`` +* Create a DELETE request: ``$client->delete($uri, array $headers, $body, $options)`` +* Create a POST request: ``$client->post($uri, array $headers, $postBody, $options)`` +* Create a PUT request: ``$client->put($uri, array $headers, $body, $options)`` +* Create a PATCH request: ``$client->patch($uri, array $headers, $body, $options)`` + +.. code-block:: php + + use Guzzle\Http\Client; + + $client = new Client('http://baseurl.com/api/v1'); + + // Create a GET request using Relative to base URL + // URL of the request: http://baseurl.com/api/v1/path?query=123&value=abc) + $request = $client->get('path?query=123&value=abc'); + $response = $request->send(); + + // Create HEAD request using a relative URL with an absolute path + // URL of the request: http://baseurl.com/path?query=123&value=abc + $request = $client->head('/path?query=123&value=abc'); + $response = $request->send(); + + // Create a DELETE request using an absolute URL + $request = $client->delete('http://www.example.com/path?query=123&value=abc'); + $response = $request->send(); + + // Create a PUT request using the contents of a PHP stream as the body + // Specify custom HTTP headers + $request = $client->put('http://www.example.com/upload', array( + 'X-Header' => 'My Header' + ), fopen('http://www.test.com/', 'r')); + $response = $request->send(); + + // Create a POST request and add the POST files manually + $request = $client->post('http://localhost:8983/solr/update') + ->addPostFiles(array('file' => '/path/to/documents.xml')); + $response = $request->send(); + + // Check if a resource supports the DELETE method + $supportsDelete = $client->options('/path')->send()->isMethodAllowed('DELETE'); + $response = $request->send(); + +Client objects create Request objects using a request factory (``Guzzle\Http\Message\RequestFactoryInterface``). +You can inject a custom request factory into the Client using ``$client->setRequestFactory()``, but you can typically +rely on a Client's default request factory. + +Static clients +-------------- + +You can use Guzzle's static client facade to more easily send simple HTTP requests. + +.. code-block:: php + + // Mount the client so that you can access it at \Guzzle + Guzzle\Http\StaticClient::mount(); + $response = Guzzle::get('http://guzzlephp.org'); + +Each request method of the static client (e.g. ``get()``, ``post()`, ``put()``, etc) accepts an associative array of request +options to apply to the request. + +.. code-block:: php + + $response = Guzzle::post('http://test.com', array( + 'headers' => array('X-Foo' => 'Bar'), + 'body' => array('Test' => '123'), + 'timeout' => 10 + )); + +.. _request-options: + +Request options +--------------- + +Request options can be specified when creating a request or in the ``request.options`` parameter of a client. These +options can control various aspects of a request including: headers to send, query string data, where the response +should be downloaded, proxies, auth, etc. + +headers +~~~~~~~ + +Associative array of headers to apply to the request. When specified in the ``$options`` argument of a client creational +method (e.g. ``get()``, ``post()``, etc), the headers in the ``$options`` array will overwrite headers specified in the +``$headers`` array. + +.. code-block:: php + + $request = $client->get($url, array(), array( + 'headers' => array('X-Foo' => 'Bar') + )); + +Headers can be specified on a client to add default headers to every request sent by a client. + +.. code-block:: php + + $client = new Guzzle\Http\Client(); + + // Set a single header using path syntax + $client->setDefaultOption('headers/X-Foo', 'Bar'); + + // Set all headers + $client->setDefaultOption('headers', array('X-Foo' => 'Bar')); + +.. note:: + + In addition to setting request options when creating requests or using the ``setDefaultOption()`` method, any + default client request option can be set using a client's config object: + + .. code-block:: php + + $client->getConfig()->setPath('request.options/headers/X-Foo', 'Bar'); + +query +~~~~~ + +Associative array of query string parameters to the request. When specified in the ``$options`` argument of a client +creational method, the query string parameters in the ``$options`` array will overwrite query string parameters +specified in the `$url`. + +.. code-block:: php + + $request = $client->get($url, array(), array( + 'query' => array('abc' => '123') + )); + +Query string parameters can be specified on a client to add default query string parameters to every request sent by a +client. + +.. code-block:: php + + $client = new Guzzle\Http\Client(); + + // Set a single query string parameter using path syntax + $client->setDefaultOption('query/abc', '123'); + + // Set an array of default query string parameters + $client->setDefaultOption('query', array('abc' => '123')); + +body +~~~~ + +Sets the body of a request. The value supplied to the body option can be a ``Guzzle\Http\EntityBodyInterface``, string, +fopen resource, or array when sending POST requests. When a ``body`` request option is supplied, the option value will +overwrite the ``$body`` argument of a client creational method. + +auth +~~~~ + +Specifies and array of HTTP authorization parameters parameters to use with the request. The array must contain the +username in index [0], the password in index [1], and can optionally contain the authentication type in index [2]. +The available authentication types are: "Basic" (default), "Digest", "NTLM", or "Any". + +.. code-block:: php + + $request = $client->get($url, array(), array( + 'auth' => array('username', 'password', 'Digest') + )); + + // You can add auth headers to every request of a client + $client->setDefaultOption('auth', array('username', 'password', 'Digest')); + +cookies +~~~~~~~ + +Specifies an associative array of cookies to add to the request. + +allow_redirects +~~~~~~~~~~~~~~~ + +Specifies whether or not the request should follow redirects. Requests will follow redirects by default. Set +``allow_redirects`` to ``false`` to disable redirects. + +save_to +~~~~~~~ + +The ``save_to`` option specifies where the body of a response is downloaded. You can pass the path to a file, an fopen +resource, or a ``Guzzle\Http\EntityBodyInterface`` object. + +See :ref:`Changing where a response is downloaded ` for more information on setting the +`save_to` option. + +events +~~~~~~ + +The `events` option makes it easy to attach listeners to the various events emitted by a request object. The `events` +options must be an associative array mapping an event name to a Closure or array the contains a Closure and the +priority of the event. + +.. code-block:: php + + $request = $client->get($url, array(), array( + 'events' => array( + 'request.before_send' => function (\Guzzle\Common\Event $e) { + echo 'About to send ' . $e['request']; + } + ) + )); + + // Using the static client: + Guzzle::get($url, array( + 'events' => array( + 'request.before_send' => function (\Guzzle\Common\Event $e) { + echo 'About to send ' . $e['request']; + } + ) + )); + +plugins +~~~~~~~ + +The `plugins` options makes it easy to attach an array of plugins to a request. + +.. code-block:: php + + // Using the static client: + Guzzle::get($url, array( + 'plugins' => array( + new Guzzle\Plugin\Cache\CachePlugin(), + new Guzzle\Plugin\Cookie\CookiePlugin() + ) + )); + +exceptions +~~~~~~~~~~ + +The `exceptions` option can be used to disable throwing exceptions for unsuccessful HTTP response codes +(e.g. 404, 500, etc). Set `exceptions` to false to not throw exceptions. + +params +~~~~~~ + +The `params` options can be used to specify an associative array of data parameters to add to a request. Note that +these are not query string parameters. + +timeout / connect_timeout +~~~~~~~~~~~~~~~~~~~~~~~~~ + +You can specify the maximum number of seconds to allow for an entire transfer to take place before timing out using +the `timeout` request option. You can specify the maximum number of seconds to wait while trying to connect using the +`connect_timeout` request option. Set either of these options to 0 to wait indefinitely. + +.. code-block:: php + + $request = $client->get('http://www.example.com', array(), array( + 'timeout' => 20, + 'connect_timeout' => 1.5 + )); + +verify +~~~~~~ + +Set to true to enable SSL certificate validation (the default), false to disable SSL certificate validation, or supply +the path to a CA bundle to enable verification using a custom certificate. + +cert +~~~~ + +The `cert` option lets you specify a PEM formatted SSL client certificate to use with servers that require one. If the +certificate requires a password, provide an array with the password as the second item. + +This would typically be used in conjunction with the `ssl_key` option. + +.. code-block:: php + + $request = $client->get('https://www.example.com', array(), array( + 'cert' => '/etc/pki/client_certificate.pem' + ) + + $request = $client->get('https://www.example.com', array(), array( + 'cert' => array('/etc/pki/client_certificate.pem', 's3cr3tp455w0rd') + ) + +ssl_key +~~~~~~~ + +The `ssl_key` option lets you specify a file containing your PEM formatted private key, optionally protected by a password. +Note: your password is sensitive, keep the PHP script containing it safe. + +This would typically be used in conjunction with the `cert` option. + +.. code-block:: php + + $request = $client->get('https://www.example.com', array(), array( + 'ssl_key' => '/etc/pki/private_key.pem' + ) + + $request = $client->get('https://www.example.com', array(), array( + 'ssl_key' => array('/etc/pki/private_key.pem', 's3cr3tp455w0rd') + ) + +proxy +~~~~~ + +The `proxy` option is used to specify an HTTP proxy (e.g. `http://username:password@192.168.16.1:10`). + +debug +~~~~~ + +The `debug` option is used to show verbose cURL output for a transfer. + +stream +~~~~~~ + +When using a static client, you can set the `stream` option to true to return a `Guzzle\Stream\Stream` object that can +be used to pull data from a stream as needed (rather than have cURL download the entire contents of a response to a +stream all at once). + +.. code-block:: php + + $stream = Guzzle::get('http://guzzlephp.org', array('stream' => true)); + while (!$stream->feof()) { + echo $stream->readLine(); + } + +Sending requests +---------------- + +Requests can be sent by calling the ``send()`` method of a Request object, but you can also send requests using the +``send()`` method of a Client. + +.. code-block:: php + + $request = $client->get('http://www.amazon.com'); + $response = $client->send($request); + +Sending requests in parallel +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The Client's ``send()`` method accept a single ``Guzzle\Http\Message\RequestInterface`` object or an array of +RequestInterface objects. When an array is specified, the requests will be sent in parallel. + +Sending many HTTP requests serially (one at a time) can cause an unnecessary delay in a script's execution. Each +request must complete before a subsequent request can be sent. By sending requests in parallel, a pool of HTTP +requests can complete at the speed of the slowest request in the pool, significantly reducing the amount of time +needed to execute multiple HTTP requests. Guzzle provides a wrapper for the curl_multi functions in PHP. + +Here's an example of sending three requests in parallel using a client object: + +.. code-block:: php + + use Guzzle\Common\Exception\MultiTransferException; + + try { + $responses = $client->send(array( + $client->get('http://www.google.com/'), + $client->head('http://www.google.com/'), + $client->get('https://www.github.com/') + )); + } catch (MultiTransferException $e) { + + echo "The following exceptions were encountered:\n"; + foreach ($e as $exception) { + echo $exception->getMessage() . "\n"; + } + + echo "The following requests failed:\n"; + foreach ($e->getFailedRequests() as $request) { + echo $request . "\n\n"; + } + + echo "The following requests succeeded:\n"; + foreach ($e->getSuccessfulRequests() as $request) { + echo $request . "\n\n"; + } + } + +If the requests succeed, an array of ``Guzzle\Http\Message\Response`` objects are returned. A single request failure +will not cause the entire pool of requests to fail. Any exceptions thrown while transferring a pool of requests will +be aggregated into a ``Guzzle\Common\Exception\MultiTransferException`` exception. + +Plugins and events +------------------ + +Guzzle provides easy to use request plugins that add behavior to requests based on signal slot event notifications +powered by the +`Symfony2 Event Dispatcher component `_. Any +event listener or subscriber attached to a Client object will automatically be attached to each request created by the +client. + +Using the same cookie session for each request +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Attach a ``Guzzle\Plugin\Cookie\CookiePlugin`` to a client which will in turn add support for cookies to every request +created by a client, and each request will use the same cookie session: + +.. code-block:: php + + use Guzzle\Plugin\Cookie\CookiePlugin; + use Guzzle\Plugin\Cookie\CookieJar\ArrayCookieJar; + + // Create a new cookie plugin + $cookiePlugin = new CookiePlugin(new ArrayCookieJar()); + + // Add the cookie plugin to the client + $client->addSubscriber($cookiePlugin); + +.. _client-events: + +Events emitted from a client +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +A ``Guzzle\Http\Client`` object emits the following events: + ++------------------------------+--------------------------------------------+------------------------------------------+ +| Event name | Description | Event data | ++==============================+============================================+==========================================+ +| client.create_request | Called when a client creates a request | * client: The client | +| | | * request: The created request | ++------------------------------+--------------------------------------------+------------------------------------------+ + +.. code-block:: php + + use Guzzle\Common\Event; + use Guzzle\Http\Client; + + $client = new Client(); + + // Add a listener that will echo out requests as they are created + $client->getEventDispatcher()->addListener('client.create_request', function (Event $e) { + echo 'Client object: ' . spl_object_hash($e['client']) . "\n"; + echo "Request object: {$e['request']}\n"; + }); diff --git a/vendor/guzzle/guzzle/docs/http-client/entity-bodies.rst b/vendor/guzzle/guzzle/docs/http-client/entity-bodies.rst new file mode 100644 index 0000000..823b0c0 --- /dev/null +++ b/vendor/guzzle/guzzle/docs/http-client/entity-bodies.rst @@ -0,0 +1,151 @@ +=========================== +Request and response bodies +=========================== + +`Entity body `_ is the term used for the body of an HTTP +message. The entity body of requests and responses is inherently a +`PHP stream `_ in Guzzle. The body of the request can be either a string or +a PHP stream which are converted into a ``Guzzle\Http\EntityBody`` object using its factory method. When using a +string, the entity body is stored in a `temp PHP stream `_. The use of +temp PHP streams helps to protect your application from running out of memory when sending or receiving large entity +bodies in your messages. When more than 2MB of data is stored in a temp stream, it automatically stores the data on +disk rather than in memory. + +EntityBody objects provide a great deal of functionality: compression, decompression, calculate the Content-MD5, +calculate the Content-Length (when the resource is repeatable), guessing the Content-Type, and more. Guzzle doesn't +need to load an entire entity body into a string when sending or retrieving data; entity bodies are streamed when +being uploaded and downloaded. + +Here's an example of gzip compressing a text file then sending the file to a URL: + +.. code-block:: php + + use Guzzle\Http\EntityBody; + + $body = EntityBody::factory(fopen('/path/to/file.txt', 'r+')); + echo $body->read(1024); + $body->seek(0, SEEK_END); + $body->write('foo'); + echo $body->ftell(); + $body->rewind(); + + // Send a request using the body + $response = $client->put('http://localhost:8080/uploads', null, $body)->send(); + +The body of the request can be specified in the ``Client::put()`` or ``Client::post()`` method, or, you can specify +the body of the request by calling the ``setBody()`` method of any +``Guzzle\Http\Message\EntityEnclosingRequestInterface`` object. + +Compression +----------- + +You can compress the contents of an EntityBody object using the ``compress()`` method. The compress method accepts a +filter that must match to one of the supported +`PHP stream filters `_ on your system (e.g. `zlib.deflate`, +``bzip2.compress``, etc). Compressing an entity body will stream the entire entity body through a stream compression +filter into a temporary PHP stream. You can uncompress an entity body using the ``uncompress()`` method and passing +the PHP stream filter to use when decompressing the stream (e.g. ``zlib.inflate``). + +.. code-block:: php + + use Guzzle\Http\EntityBody; + + $body = EntityBody::factory(fopen('/tmp/test.txt', 'r+')); + echo $body->getSize(); + // >>> 1048576 + + // Compress using the default zlib.deflate filter + $body->compress(); + echo $body->getSize(); + // >>> 314572 + + // Decompress the stream + $body->uncompress(); + echo $body->getSize(); + // >>> 1048576 + +Decorators +---------- + +Guzzle provides several EntityBody decorators that can be used to add functionality to an EntityBody at runtime. + +IoEmittingEntityBody +~~~~~~~~~~~~~~~~~~~~ + +This decorator will emit events when data is read from a stream or written to a stream. Add an event subscriber to the +entity body's ``body.read`` or ``body.write`` methods to receive notifications when data data is transferred. + +.. code-block:: php + + use Guzzle\Common\Event; + use Guzzle\Http\EntityBody; + use Guzzle\Http\IoEmittingEntityBody; + + $original = EntityBody::factory(fopen('/tmp/test.txt', 'r+')); + $body = new IoEmittingEntityBody($original); + + // Listen for read events + $body->getEventDispatcher()->addListener('body.read', function (Event $e) { + // Grab data from the event + $entityBody = $e['body']; + // Amount of data retrieved from the body + $lengthOfData = $e['length']; + // The actual data that was read + $data = $e['read']; + }); + + // Listen for write events + $body->getEventDispatcher()->addListener('body.write', function (Event $e) { + // Grab data from the event + $entityBody = $e['body']; + // The data that was written + $data = $e['write']; + // The actual amount of data that was written + $data = $e['read']; + }); + +ReadLimitEntityBody +~~~~~~~~~~~~~~~~~~~ + +The ReadLimitEntityBody decorator can be used to transfer a subset or slice of an existing EntityBody object. This can +be useful for breaking a large file into smaller pieces to be sent in chunks (e.g. Amazon S3's multipart upload API). + +.. code-block:: php + + use Guzzle\Http\EntityBody; + use Guzzle\Http\ReadLimitEntityBody; + + $original = EntityBody::factory(fopen('/tmp/test.txt', 'r+')); + echo $original->getSize(); + // >>> 1048576 + + // Limit the size of the body to 1024 bytes and start reading from byte 2048 + $body = new ReadLimitEntityBody($original, 1024, 2048); + echo $body->getSize(); + // >>> 1024 + echo $body->ftell(); + // >>> 0 + +CachingEntityBody +~~~~~~~~~~~~~~~~~ + +The CachingEntityBody decorator is used to allow seeking over previously read bytes on non-seekable read streams. This +can be useful when transferring a non-seekable entity body fails due to needing to rewind the stream (for example, +resulting from a redirect). Data that is read from the remote stream will be buffered in a PHP temp stream so that +previously read bytes are cached first in memory, then on disk. + +.. code-block:: php + + use Guzzle\Http\EntityBody; + use Guzzle\Http\CachingEntityBody; + + $original = EntityBody::factory(fopen('http://www.google.com', 'r')); + $body = new CachingEntityBody($original); + + $body->read(1024); + echo $body->ftell(); + // >>> 1024 + + $body->seek(0); + echo $body->ftell(); + // >>> 0 diff --git a/vendor/guzzle/guzzle/docs/http-client/http-redirects.rst b/vendor/guzzle/guzzle/docs/http-client/http-redirects.rst new file mode 100644 index 0000000..32ba268 --- /dev/null +++ b/vendor/guzzle/guzzle/docs/http-client/http-redirects.rst @@ -0,0 +1,99 @@ +============== +HTTP redirects +============== + +By default, Guzzle will automatically follow redirects using the non-RFC compliant implementation used by most web +browsers. This means that redirects for POST requests are followed by a GET request. You can force RFC compliance by +enabling the strict mode on a request's parameter object: + +.. code-block:: php + + // Set per request + $request = $client->post(); + $request->getParams()->set('redirect.strict', true); + + // You can set globally on a client so all requests use strict redirects + $client->getConfig()->set('request.params', array( + 'redirect.strict' => true + )); + +By default, Guzzle will redirect up to 5 times before throwing a ``Guzzle\Http\Exception\TooManyRedirectsException``. +You can raise or lower this value using the ``redirect.max`` parameter of a request object: + +.. code-block:: php + + $request->getParams()->set('redirect.max', 2); + +Redirect history +---------------- + +You can get the number of redirects of a request using the resulting response object's ``getRedirectCount()`` method. +Similar to cURL's ``effective_url`` property, Guzzle provides the effective URL, or the last redirect URL that returned +the request, in a response's ``getEffectiveUrl()`` method. + +When testing or debugging, it is often useful to see a history of redirects for a particular request. This can be +achieved using the HistoryPlugin. + +.. code-block:: php + + $request = $client->get('/'); + $history = new Guzzle\Plugin\History\HistoryPlugin(); + $request->addSubscriber($history); + $response = $request->send(); + + // Get the last redirect URL or the URL of the request that received + // this response + echo $response->getEffectiveUrl(); + + // Get the number of redirects + echo $response->getRedirectCount(); + + // Iterate over each sent request and response + foreach ($history->getAll() as $transaction) { + // Request object + echo $transaction['request']->getUrl() . "\n"; + // Response object + echo $transaction['response']->getEffectiveUrl() . "\n"; + } + + // Or, simply cast the HistoryPlugin to a string to view each request and response + echo $history; + +Disabling redirects +------------------- + +You can disable redirects on a client by passing a configuration option in the client's constructor: + +.. code-block:: php + + $client = new Client(null, array('redirect.disable' => true)); + +You can also disable redirects per request: + +.. code-block:: php + + $request = $client->get($url, array(), array('allow_redirects' => false)); + +Redirects and non-repeatable streams +------------------------------------ + +If you are redirected when sending data from a non-repeatable stream and some of the data has been read off of the +stream, then you will get a ``Guzzle\Http\Exception\CouldNotRewindStreamException``. You can get around this error by +adding a custom rewind method to the entity body object being sent in the request. + +.. code-block:: php + + $request = $client->post( + 'http://httpbin.com/redirect/2', + null, + fopen('http://httpbin.com/get', 'r') + ); + + // Add a custom function that can be used to rewind the stream + // (reopen in this example) + $request->getBody()->setRewindFunction(function ($body) { + $body->setStream(fopen('http://httpbin.com/get', 'r')); + return true; + ); + + $response = $client->send(); diff --git a/vendor/guzzle/guzzle/docs/http-client/request.rst b/vendor/guzzle/guzzle/docs/http-client/request.rst new file mode 100644 index 0000000..a8387a9 --- /dev/null +++ b/vendor/guzzle/guzzle/docs/http-client/request.rst @@ -0,0 +1,667 @@ +===================== +Using Request objects +===================== + +HTTP request messages +--------------------- + +Request objects are all about building an HTTP message. Each part of an HTTP request message can be set individually +using methods on the request object or set in bulk using the ``setUrl()`` method. Here's the format of an HTTP request +with each part of the request referencing the method used to change it:: + + PUT(a) /path(b)?query=123(c) HTTP/1.1(d) + X-Header(e): header + Content-Length(e): 4 + + data(f) + ++-------------------------+---------------------------------------------------------------------------------+ +| a. **Method** | The request method can only be set when instantiating a request | ++-------------------------+---------------------------------------------------------------------------------+ +| b. **Path** | ``$request->setPath('/path');`` | ++-------------------------+---------------------------------------------------------------------------------+ +| c. **Query** | ``$request->getQuery()->set('query', '123');`` | ++-------------------------+---------------------------------------------------------------------------------+ +| d. **Protocol version** | ``$request->setProtocolVersion('1.1');`` | ++-------------------------+---------------------------------------------------------------------------------+ +| e. **Header** | ``$request->setHeader('X-Header', 'header');`` | ++-------------------------+---------------------------------------------------------------------------------+ +| f. **Entity Body** | ``$request->setBody('data'); // Only available with PUT, POST, PATCH, DELETE`` | ++-------------------------+---------------------------------------------------------------------------------+ + +Creating requests with a client +------------------------------- + +Client objects are responsible for creating HTTP request objects. + +GET requests +~~~~~~~~~~~~ + +`GET requests `_ are the most common form of HTTP +requests. When you visit a website in your browser, the HTML of the website is downloaded using a GET request. GET +requests are idempotent requests that are typically used to download content (an entity) identified by a request URL. + +.. code-block:: php + + use Guzzle\Http\Client; + + $client = new Client(); + + // Create a request that has a query string and an X-Foo header + $request = $client->get('http://www.amazon.com?a=1', array('X-Foo' => 'Bar')); + + // Send the request and get the response + $response = $request->send(); + +You can change where the body of a response is downloaded on any request using the +``$request->setResponseBody(string|EntityBodyInterface|resource)`` method of a request. You can also set the ``save_to`` +option of a request: + +.. code-block:: php + + // Send the response body to a file + $request = $client->get('http://test.com', array(), array('save_to' => '/path/to/file')); + + // Send the response body to an fopen resource + $request = $client->get('http://test.com', array(), array('save_to' => fopen('/path/to/file', 'w'))); + +HEAD requests +~~~~~~~~~~~~~ + +`HEAD requests `_ work exactly like GET requests except +that they do not actually download the response body (entity) of the response message. HEAD requests are useful for +retrieving meta information about an entity identified by a Request-URI. + +.. code-block:: php + + $client = new Guzzle\Http\Client(); + $request = $client->head('http://www.amazon.com'); + $response = $request->send(); + echo $response->getContentLength(); + // >>> Will output the Content-Length header value + +DELETE requests +~~~~~~~~~~~~~~~ + +A `DELETE method `_ requests that the origin server +delete the resource identified by the Request-URI. + +.. code-block:: php + + $client = new Guzzle\Http\Client(); + $request = $client->delete('http://example.com'); + $response = $request->send(); + +POST requests +~~~~~~~~~~~~~ + +While `POST requests `_ can be used for a number of +reasons, POST requests are often used when submitting HTML form data to a website. POST requests can include an entity +body in the HTTP request. + +POST requests in Guzzle are sent with an ``application/x-www-form-urlencoded`` Content-Type header if POST fields are +present but no files are being sent in the POST. If files are specified in the POST request, then the Content-Type +header will become ``multipart/form-data``. + +The ``post()`` method of a client object accepts four arguments: the URL, optional headers, post fields, and an array of +request options. To send files in the POST request, prepend the ``@`` symbol to the array value (just like you would if +you were using the PHP ``curl_setopt`` function). + +Here's how to create a multipart/form-data POST request containing files and fields: + +.. code-block:: php + + $request = $client->post('http://httpbin.org/post', array(), array( + 'custom_field' => 'my custom value', + 'file_field' => '@/path/to/file.xml' + )); + + $response = $request->send(); + +.. note:: + + Remember to **always** sanitize user input when sending POST requests: + + .. code-block:: php + + // Prevent users from accessing sensitive files by sanitizing input + $_POST = array('firstname' => '@/etc/passwd'); + $request = $client->post('http://www.example.com', array(), array ( + 'firstname' => str_replace('@', '', $_POST['firstname']) + )); + +You can alternatively build up the contents of a POST request. + +.. code-block:: php + + $request = $client->post('http://httpbin.org/post') + ->setPostField('custom_field', 'my custom value') + ->addPostFile('file', '/path/to/file.xml'); + + $response = $request->send(); + +Raw POST data +^^^^^^^^^^^^^ + +POST requests can also contain raw POST data that is not related to HTML forms. + +.. code-block:: php + + $request = $client->post('http://httpbin.org/post', array(), 'this is the body'); + $response = $request->send(); + +You can set the body of POST request using the ``setBody()`` method of the +``Guzzle\Http\Message\EntityEnclosingRequest`` object. This method accepts a string, a resource returned from +``fopen``, or a ``Guzzle\Http\EntityBodyInterface`` object. + +.. code-block:: php + + $request = $client->post('http://httpbin.org/post'); + // Set the body of the POST to stream the contents of /path/to/large_body.txt + $request->setBody(fopen('/path/to/large_body.txt', 'r')); + $response = $request->send(); + +PUT requests +~~~~~~~~~~~~ + +The `PUT method `_ requests that the enclosed entity be +stored under the supplied Request-URI. PUT requests are similar to POST requests in that they both can send an entity +body in the request message. + +The body of a PUT request (any any ``Guzzle\Http\Message\EntityEnclosingRequestInterface`` object) is always stored as +a ``Guzzle\Http\Message\EntityBodyInterface`` object. This allows a great deal of flexibility when sending data to a +remote server. For example, you can stream the contents of a stream returned by fopen, stream the contents of a +callback function, or simply send a string of data. + +.. code-block:: php + + $request = $client->put('http://httpbin.org/put', array(), 'this is the body'); + $response = $request->send(); + +Just like with POST, PATH, and DELETE requests, you can set the body of a PUT request using the ``setBody()`` method. + +.. code-block:: php + + $request = $client->put('http://httpbin.org/put'); + $request->setBody(fopen('/path/to/large_body.txt', 'r')); + $response = $request->send(); + +PATCH requests +~~~~~~~~~~~~~~ + +`PATCH requests `_ are used to modify a resource. + +.. code-block:: php + + $request = $client->patch('http://httpbin.org', array(), 'this is the body'); + $response = $request->send(); + +OPTIONS requests +~~~~~~~~~~~~~~~~ + +The `OPTIONS method `_ represents a request for +information about the communication options available on the request/response chain identified by the Request-URI. + +.. code-block:: php + + $request = $client->options('http://httpbin.org'); + $response = $request->send(); + + // Check if the PUT method is supported by this resource + var_export($response->isMethodAllows('PUT')); + +Custom requests +~~~~~~~~~~~~~~~ + +You can create custom HTTP requests that use non-standard HTTP methods using the ``createRequest()`` method of a +client object. + +.. code-block:: php + + $request = $client->createRequest('COPY', 'http://example.com/foo', array( + 'Destination' => 'http://example.com/bar', + 'Overwrite' => 'T' + )); + $response = $request->send(); + +Query string parameters +----------------------- + +Query string parameters of a request are owned by a request's ``Guzzle\Http\Query`` object that is accessible by +calling ``$request->getQuery()``. The Query class extends from ``Guzzle\Common\Collection`` and allows you to set one +or more query string parameters as key value pairs. You can set a parameter on a Query object using the +``set($key, $value)`` method or access the query string object like an associative array. Any previously specified +value for a key will be overwritten when using ``set()``. Use ``add($key, $value)`` to add a value to query string +object, and in the event of a collision with an existing value at a specific key, the value will be converted to an +array that contains all of the previously set values. + +.. code-block:: php + + $request = new Guzzle\Http\Message\Request('GET', 'http://www.example.com?foo=bar&abc=123'); + + $query = $request->getQuery(); + echo "{$query}\n"; + // >>> foo=bar&abc=123 + + $query->remove('abc'); + echo "{$query}\n"; + // >>> foo=bar + + $query->set('foo', 'baz'); + echo "{$query}\n"; + // >>> foo=baz + + $query->add('foo', 'bar'); + echo "{$query}\n"; + // >>> foo%5B0%5D=baz&foo%5B1%5D=bar + +Whoah! What happened there? When ``foo=bar`` was added to the existing ``foo=baz`` query string parameter, the +aggregator associated with the Query object was used to help convert multi-value query string parameters into a string. +Let's disable URL-encoding to better see what's happening. + +.. code-block:: php + + $query->useUrlEncoding(false); + echo "{$query}\n"; + // >>> foo[0]=baz&foo[1]=bar + +.. note:: + + URL encoding can be disabled by passing false, enabled by passing true, set to use RFC 1738 by passing + ``Query::FORM_URLENCODED`` (internally uses PHP's ``urlencode`` function), or set to RFC 3986 by passing + ``Query::RFC_3986`` (this is the default and internally uses PHP's ``rawurlencode`` function). + +As you can see, the multiple values were converted into query string parameters following the default PHP convention of +adding numerically indexed square bracket suffixes to each key (``foo[0]=baz&foo[1]=bar``). The strategy used to convert +multi-value parameters into a string can be customized using the ``setAggregator()`` method of the Query class. Guzzle +ships with the following query string aggregators by default: + +1. ``Guzzle\Http\QueryAggregator\PhpAggregator``: Aggregates using PHP style brackets (e.g. ``foo[0]=baz&foo[1]=bar``) +2. ``Guzzle\Http\QueryAggregator\DuplicateAggregator``: Performs no aggregation and allows for key value pairs to be + repeated in a URL (e.g. ``foo=baz&foo=bar``) +3. ``Guzzle\Http\QueryAggregator\CommaAggregator``: Aggregates using commas (e.g. ``foo=baz,bar``) + +.. _http-message-headers: + +HTTP Message Headers +-------------------- + +HTTP message headers are case insensitive, multiple occurrences of any header can be present in an HTTP message +(whether it's valid or not), and some servers require specific casing of particular headers. Because of this, request +and response headers are stored in ``Guzzle\Http\Message\Header`` objects. The Header object can be cast as a string, +counted, or iterated to retrieve each value from the header. Casting a Header object to a string will return all of +the header values concatenated together using a glue string (typically ", "). + +A request (and response) object have several methods that allow you to retrieve and modify headers. + +* ``getHeaders()``: Get all of the headers of a message as a ``Guzzle\Http\Message\Header\HeaderCollection`` object. +* ``getHeader($header)``: Get a specific header from a message. If the header exists, you'll get a + ``Guzzle\Http\Message\Header`` object. If the header does not exist, this methods returns ``null``. +* ``hasHeader($header)``: Returns true or false based on if the message has a particular header. +* ``setHeader($header, $value)``: Set a header value and overwrite any previously set value for this header. +* ``addHeader($header, $value)``: Add a header with a particular name. If a previous value was already set by the same, + then the header will contain multiple values. +* ``removeHeader($header)``: Remove a header by name from the message. + +.. code-block:: php + + $request = new Request('GET', 'http://httpbin.com/cookies'); + // addHeader will set and append to any existing header values + $request->addHeader('Foo', 'bar'); + $request->addHeader('foo', 'baz'); + // setHeader overwrites any existing values + $request->setHeader('Test', '123'); + + // Request headers can be cast as a string + echo $request->getHeader('Foo'); + // >>> bar, baz + echo $request->getHeader('Test'); + // >>> 123 + + // You can count the number of headers of a particular case insensitive name + echo count($request->getHeader('foO')); + // >>> 2 + + // You can iterate over Header objects + foreach ($request->getHeader('foo') as $header) { + echo $header . "\n"; + } + + // You can get all of the request headers as a Guzzle\Http\Message\Header\HeaderCollection object + $headers = $request->getHeaders(); + + // Missing headers return NULL + var_export($request->getHeader('Missing')); + // >>> null + + // You can see all of the different variations of a header by calling raw() on the Header + var_export($request->getHeader('foo')->raw()); + +Setting the body of a request +----------------------------- + +Requests that can send a body (e.g. PUT, POST, DELETE, PATCH) are instances of +``Guzzle\Http\Message\EntityEnclosingRequestInterface``. Entity enclosing requests contain several methods that allow +you to specify the body to send with a request. + +Use the ``setBody()`` method of a request to set the body that will be sent with a request. This method accepts a +string, a resource returned by ``fopen()``, an array, or an instance of ``Guzzle\Http\EntityBodyInterface``. The body +will then be streamed from the underlying ``EntityBodyInterface`` object owned by the request. When setting the body +of the request, you can optionally specify a Content-Type header and whether or not to force the request to use +chunked Transfer-Encoding. + +.. code-block:: php + + $request = $client->put('/user.json'); + $request->setBody('{"foo":"baz"}', 'application/json'); + +Content-Type header +~~~~~~~~~~~~~~~~~~~ + +Guzzle will automatically add a Content-Type header to a request if the Content-Type can be guessed based on the file +extension of the payload being sent or the file extension present in the path of a request. + +.. code-block:: php + + $request = $client->put('/user.json', array(), '{"foo":"bar"}'); + // The Content-Type was guessed based on the path of the request + echo $request->getHeader('Content-Type'); + // >>> application/json + + $request = $client->put('/user.json'); + $request->setBody(fopen('/tmp/user_data.json', 'r')); + // The Content-Type was guessed based on the path of the entity body + echo $request->getHeader('Content-Type'); + // >>> application/json + +Transfer-Encoding: chunked header +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +When sending HTTP requests that contain a payload, you must let the remote server know how to determine when the entire +message has been sent. This usually is done by supplying a ``Content-Length`` header that tells the origin server the +size of the body that is to be sent. In some cases, the size of the payload being sent in a request cannot be known +before initiating the transfer. In these cases (when using HTTP/1.1), you can use the ``Transfer-Encoding: chunked`` +header. + +If the Content-Length cannot be determined (i.e. using a PHP ``http://`` stream), then Guzzle will automatically add +the ``Transfer-Encoding: chunked`` header to the request. + +.. code-block:: php + + $request = $client->put('/user.json'); + $request->setBody(fopen('http://httpbin.org/get', 'r')); + + // The Content-Length could not be determined + echo $request->getHeader('Transfer-Encoding'); + // >>> chunked + +See :doc:`/http-client/entity-bodies` for more information on entity bodies. + +Expect: 100-Continue header +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The ``Expect: 100-Continue`` header is used to help a client prevent sending a large payload to a server that will +reject the request. This allows clients to fail fast rather than waste bandwidth sending an erroneous payload. Guzzle +will automatically add the ``Expect: 100-Continue`` header to a request when the size of the payload exceeds 1MB or if +the body of the request is not seekable (this helps to prevent errors when a non-seekable body request is redirected). + +.. note:: + + If you find that your larger requests are taking too long to complete, you should first check if the + ``Expect: 100-Continue`` header is being sent with the request. Some servers do not respond well to this header, + which causes cURL to sleep for `1 second `_. + +POST fields and files +~~~~~~~~~~~~~~~~~~~~~ + +Any entity enclosing request can send POST style fields and files. This includes POST, PUT, PATCH, and DELETE requests. +Any request that has set POST fields or files will use cURL's POST message functionality. + +.. code-block:: php + + $request = $client->post('/post'); + // Set an overwrite any previously specified value + $request->setPostField('foo', 'bar'); + // Append a value to any existing values + $request->getPostFields()->add('foo', 'baz'); + // Remove a POST field by name + $request->removePostField('fizz'); + + // Add a file to upload (forces multipart/form-data) + $request->addPostFile('my_file', '/path/to/file', 'plain/text'); + // Remove a POST file by POST key name + $request->removePostFile('my_other_file'); + +.. tip:: + + Adding a large number of POST fields to a POST request is faster if you use the ``addPostFields()`` method so that + you can add and process multiple fields with a single call. Adding multiple POST files is also faster using + ``addPostFiles()``. + +Working with cookies +-------------------- + +Cookies can be modified and retrieved from a request using the following methods: + +.. code-block:: php + + $request->addCookie($name, $value); + $request->removeCookie($name); + $value = $request->getCookie($name); + $valueArray = $request->getCookies(); + +Use the :doc:`cookie plugin ` if you need to reuse cookies between requests. + +.. _request-set-response-body: + +Changing where a response is downloaded +---------------------------------------- + +When a request is sent, the body of the response will be stored in a PHP temp stream by default. You can change the +location in which the response will be downloaded using ``$request->setResponseBody($body)`` or the ``save_to`` request +option. This can be useful for downloading the contents of a URL to a specific file. + +Here's an example of using request options: + +.. code-block:: php + + $request = $this->client->get('http://example.com/large.mov', array(), array( + 'save_to' => '/tmp/large_file.mov' + )); + $request->send(); + var_export(file_exists('/tmp/large_file.mov')); + // >>> true + +Here's an example of using ``setResponseBody()``: + +.. code-block:: php + + $body = fopen('/tmp/large_file.mov', 'w'); + $request = $this->client->get('http://example.com/large.mov'); + $request->setResponseBody($body); + + // You can more easily specify the name of a file to save the contents + // of the response to by passing a string to ``setResponseBody()``. + + $request = $this->client->get('http://example.com/large.mov'); + $request->setResponseBody('/tmp/large_file.mov'); + +Custom cURL options +------------------- + +Most of the functionality implemented in the libcurl bindings has been simplified and abstracted by Guzzle. Developers +who need access to `cURL specific functionality `_ can still add cURL handle +specific behavior to Guzzle HTTP requests by modifying the cURL options collection of a request: + +.. code-block:: php + + $request->getCurlOptions()->set(CURLOPT_LOW_SPEED_LIMIT, 200); + +Other special options that can be set in the ``curl.options`` array include: + ++-------------------------+---------------------------------------------------------------------------------+ +| debug | Adds verbose cURL output to a temp stream owned by the cURL handle object | ++-------------------------+---------------------------------------------------------------------------------+ +| progress | Instructs cURL to emit events when IO events occur. This allows you to be | +| | notified when bytes are transferred over the wire by subscribing to a request's | +| | ``curl.callback.read``, ``curl.callback.write``, and ``curl.callback.progress`` | +| | events. | ++-------------------------+---------------------------------------------------------------------------------+ + +Request options +--------------- + +Requests options can be specified when creating a request or in the ``request.options`` parameter of a client. These +options can control various aspects of a request including: headers to send, query string data, where the response +should be downloaded, proxies, auth, etc. + +.. code-block:: php + + $request = $client->get($url, $headers, array('proxy' => 'http://proxy.com')); + +See :ref:`Request options ` for more information. + +Working with errors +------------------- + +HTTP errors +~~~~~~~~~~~ + +Requests that receive a 4xx or 5xx response will throw a ``Guzzle\Http\Exception\BadResponseException``. More +specifically, 4xx errors throw a ``Guzzle\Http\Exception\ClientErrorResponseException``, and 5xx errors throw a +``Guzzle\Http\Exception\ServerErrorResponseException``. You can catch the specific exceptions or just catch the +BadResponseException to deal with either type of error. Here's an example of catching a generic BadResponseException: + +.. code-block:: php + + try { + $response = $client->get('/not_found.xml')->send(); + } catch (Guzzle\Http\Exception\BadResponseException $e) { + echo 'Uh oh! ' . $e->getMessage(); + echo 'HTTP request URL: ' . $e->getRequest()->getUrl() . "\n"; + echo 'HTTP request: ' . $e->getRequest() . "\n"; + echo 'HTTP response status: ' . $e->getResponse()->getStatusCode() . "\n"; + echo 'HTTP response: ' . $e->getResponse() . "\n"; + } + +Throwing an exception when a 4xx or 5xx response is encountered is the default behavior of Guzzle requests. This +behavior can be overridden by adding an event listener with a higher priority than -255 that stops event propagation. +You can subscribe to ``request.error`` to receive notifications any time an unsuccessful response is received. + +You can change the response that will be associated with the request by calling ``setResponse()`` on the +``$event['request']`` object passed into your listener, or by changing the ``$event['response']`` value of the +``Guzzle\Common\Event`` object that is passed to your listener. Transparently changing the response associated with a +request by modifying the event allows you to retry failed requests without complicating the code that uses the client. +This might be useful for sending requests to a web service that has expiring auth tokens. When a response shows that +your token has expired, you can get a new token, retry the request with the new token, and return the successful +response to the user. + +Here's an example of retrying a request using updated authorization credentials when a 401 response is received, +overriding the response of the original request with the new response, and still allowing the default exception +behavior to be called when other non-200 response status codes are encountered: + +.. code-block:: php + + // Add custom error handling to any request created by this client + $client->getEventDispatcher()->addListener('request.error', function(Event $event) { + + if ($event['response']->getStatusCode() == 401) { + + $newRequest = $event['request']->clone(); + $newRequest->setHeader('X-Auth-Header', MyApplication::getNewAuthToken()); + $newResponse = $newRequest->send(); + + // Set the response object of the request without firing more events + $event['response'] = $newResponse; + + // You can also change the response and fire the normal chain of + // events by calling $event['request']->setResponse($newResponse); + + // Stop other events from firing when you override 401 responses + $event->stopPropagation(); + } + + }); + +cURL errors +~~~~~~~~~~~ + +Connection problems and cURL specific errors can also occur when transferring requests using Guzzle. When Guzzle +encounters cURL specific errors while transferring a single request, a ``Guzzle\Http\Exception\CurlException`` is +thrown with an informative error message and access to the cURL error message. + +A ``Guzzle\Http\Exception\MultiTransferException`` exception is thrown when a cURL specific error occurs while +transferring multiple requests in parallel. You can then iterate over all of the exceptions encountered during the +transfer. + +Plugins and events +------------------ + +Guzzle request objects expose various events that allow you to hook in custom logic. A request object owns a +``Symfony\Component\EventDispatcher\EventDispatcher`` object that can be accessed by calling +``$request->getEventDispatcher()``. You can use the event dispatcher to add listeners (a simple callback function) or +event subscribers (classes that listen to specific events of a dispatcher). You can add event subscribers to a request +directly by just calling ``$request->addSubscriber($mySubscriber);``. + +.. _request-events: + +Events emitted from a request +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +A ``Guzzle\Http\Message\Request`` and ``Guzzle\Http\Message\EntityEnclosingRequest`` object emit the following events: + ++------------------------------+--------------------------------------------+------------------------------------------+ +| Event name | Description | Event data | ++==============================+============================================+==========================================+ +| request.before_send | About to send request | * request: Request to be sent | ++------------------------------+--------------------------------------------+------------------------------------------+ +| request.sent | Sent the request | * request: Request that was sent | +| | | * response: Received response | ++------------------------------+--------------------------------------------+------------------------------------------+ +| request.complete | Completed a full HTTP transaction | * request: Request that was sent | +| | | * response: Received response | ++------------------------------+--------------------------------------------+------------------------------------------+ +| request.success | Completed a successful request | * request: Request that was sent | +| | | * response: Received response | ++------------------------------+--------------------------------------------+------------------------------------------+ +| request.error | Completed an unsuccessful request | * request: Request that was sent | +| | | * response: Received response | ++------------------------------+--------------------------------------------+------------------------------------------+ +| request.exception | An unsuccessful response was | * request: Request | +| | received. | * response: Received response | +| | | * exception: BadResponseException | ++------------------------------+--------------------------------------------+------------------------------------------+ +| request.receive.status_line | Received the start of a response | * line: Full response start line | +| | | * status_code: Status code | +| | | * reason_phrase: Reason phrase | +| | | * previous_response: (e.g. redirect) | ++------------------------------+--------------------------------------------+------------------------------------------+ +| curl.callback.progress | cURL progress event (only dispatched when | * handle: CurlHandle | +| | ``emit_io`` is set on a request's curl | * download_size: Total download size | +| | options) | * downloaded: Bytes downloaded | +| | | * upload_size: Total upload bytes | +| | | * uploaded: Bytes uploaded | ++------------------------------+--------------------------------------------+------------------------------------------+ +| curl.callback.write | cURL event called when data is written to | * request: Request | +| | an outgoing stream | * write: Data being written | ++------------------------------+--------------------------------------------+------------------------------------------+ +| curl.callback.read | cURL event called when data is written to | * request: Request | +| | an incoming stream | * read: Data being read | ++------------------------------+--------------------------------------------+------------------------------------------+ + +Creating a request event listener +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Here's an example that listens to the ``request.complete`` event of a request and prints the request and response. + +.. code-block:: php + + use Guzzle\Common\Event; + + $request = $client->get('http://www.google.com'); + + // Echo out the response that was received + $request->getEventDispatcher()->addListener('request.complete', function (Event $e) { + echo $e['request'] . "\n\n"; + echo $e['response']; + }); diff --git a/vendor/guzzle/guzzle/docs/http-client/response.rst b/vendor/guzzle/guzzle/docs/http-client/response.rst new file mode 100644 index 0000000..ba48731 --- /dev/null +++ b/vendor/guzzle/guzzle/docs/http-client/response.rst @@ -0,0 +1,141 @@ +====================== +Using Response objects +====================== + +Sending a request will return a ``Guzzle\Http\Message\Response`` object. You can view the raw HTTP response message by +casting the Response object to a string. Casting the response to a string will return the entity body of the response +as a string too, so this might be an expensive operation if the entity body is stored in a file or network stream. If +you only want to see the response headers, you can call ``getRawHeaders()``. + +Response status line +-------------------- + +The different parts of a response's `status line `_ +(the first line of the response HTTP message) are easily retrievable. + +.. code-block:: php + + $response = $client->get('http://www.amazon.com')->send(); + + echo $response->getStatusCode(); // >>> 200 + echo $response->getReasonPhrase(); // >>> OK + echo $response->getProtocol(); // >>> HTTP + echo $response->getProtocolVersion(); // >>> 1.1 + +You can determine the type of the response using several helper methods: + +.. code-block:: php + + $response->isSuccessful(); // true + $response->isInformational(); + $response->isRedirect(); + $response->isClientError(); + $response->isServerError(); + +Response headers +---------------- + +The Response object contains helper methods for retrieving common response headers. These helper methods normalize the +variations of HTTP response headers. + +.. code-block:: php + + $response->getCacheControl(); + $response->getContentType(); + $response->getContentLength(); + $response->getContentEncoding(); + $response->getContentMd5(); + $response->getEtag(); + // etc... There are methods for every known response header + +You can interact with the Response headers using the same exact methods used to interact with Request headers. See +:ref:`http-message-headers` for more information. + +.. code-block:: php + + echo $response->getHeader('Content-Type'); + echo $response->getHeader('Content-Length'); + echo $response->getHeaders()['Content-Type']; // PHP 5.4 + +Response body +------------- + +The entity body object of a response can be retrieved by calling ``$response->getBody()``. The response EntityBody can +be cast to a string, or you can pass ``true`` to this method to retrieve the body as a string. + +.. code-block:: php + + $request = $client->get('http://www.amazon.com'); + $response = $request->send(); + echo $response->getBody(); + +See :doc:`/http-client/entity-bodies` for more information on entity bodies. + +JSON Responses +~~~~~~~~~~~~~~ + +You can easily parse and use a JSON response as an array using the ``json()`` method of a response. This method will +always return an array if the response is valid JSON or if the response body is empty. You will get an exception if you +call this method and the response is not valid JSON. + +.. code-block:: php + + $data = $response->json(); + echo gettype($data); + // >>> array + +XML Responses +~~~~~~~~~~~~~ + +You can easily parse and use a XML response as SimpleXMLElement object using the ``xml()`` method of a response. This +method will always return a SimpleXMLElement object if the response is valid XML or if the response body is empty. You +will get an exception if you call this method and the response is not valid XML. + +.. code-block:: php + + $xml = $response->xml(); + echo $xml->foo; + // >>> Bar! + +Streaming responses +------------------- + +Some web services provide streaming APIs that allow a client to keep a HTTP request open for an extended period of +time while polling and reading. Guzzle provides a simple way to convert HTTP request messages into +``Guzzle\Stream\Stream`` objects so that you can send the initial headers of a request, read the response headers, and +pull in the response body manually as needed. + +Here's an example using the Twitter Streaming API to track the keyword "bieber": + +.. code-block:: php + + use Guzzle\Http\Client; + use Guzzle\Stream\PhpStreamRequestFactory; + + $client = new Client('https://stream.twitter.com/1'); + + $request = $client->post('statuses/filter.json', null, array( + 'track' => 'bieber' + )); + + $request->setAuth('myusername', 'mypassword'); + + $factory = new PhpStreamRequestFactory(); + $stream = $factory->fromRequest($request); + + // Read until the stream is closed + while (!$stream->feof()) { + // Read a line from the stream + $line = $stream->readLine(); + // JSON decode the line of data + $data = json_decode($line, true); + } + +You can use the ``stream`` request option when using a static client to more easily create a streaming response. + +.. code-block:: php + + $stream = Guzzle::get('http://guzzlephp.org', array('stream' => true)); + while (!$stream->feof()) { + echo $stream->readLine(); + } diff --git a/vendor/guzzle/guzzle/docs/http-client/uri-templates.rst b/vendor/guzzle/guzzle/docs/http-client/uri-templates.rst new file mode 100644 index 0000000..c18ac3e --- /dev/null +++ b/vendor/guzzle/guzzle/docs/http-client/uri-templates.rst @@ -0,0 +1,52 @@ +============= +URI templates +============= + +The ``$uri`` passed to one of the client's request creational methods or the base URL of a client can utilize URI +templates. Guzzle supports the entire `URI templates RFC `_. URI templates add a +special syntax to URIs that replace template place holders with user defined variables. + +Every request created by a Guzzle HTTP client passes through a URI template so that URI template expressions are +automatically expanded: + +.. code-block:: php + + $client = new Guzzle\Http\Client('https://example.com/', array('a' => 'hi')); + $request = $client->get('/{a}'); + +Because of URI template expansion, the URL of the above request will become ``https://example.com/hi``. Notice that +the template was expanded using configuration variables of the client. You can pass in custom URI template variables +by passing the URI of your request as an array where the first index of the array is the URI template and the second +index of the array are template variables that are merged into the client's configuration variables. + +.. code-block:: php + + $request = $client->get(array('/test{?a,b}', array('b' => 'there'))); + +The URL for this request will become ``https://test.com?a=hi&b=there``. URI templates aren't limited to just simple +variable replacements; URI templates can provide an enormous amount of flexibility when creating request URIs. + +.. code-block:: php + + $request = $client->get(array('http://example.com{+path}{/segments*}{?query,data*}', array( + 'path' => '/foo/bar', + 'segments' => array('one', 'two'), + 'query' => 'test', + 'data' => array( + 'more' => 'value' + ) + ))); + +The resulting URL would become ``http://example.com/foo/bar/one/two?query=test&more=value``. + +By default, URI template expressions are enclosed in an opening and closing brace (e.g. ``{var}``). If you are working +with a web service that actually uses braces (e.g. Solr), then you can specify a custom regular expression to use to +match URI template expressions. + +.. code-block:: php + + $client->getUriTemplate()->setRegex('/\<\$(.+)\>/'); + $client->get('/<$a>'); + +You can learn about all of the different features of URI templates by reading the +`URI templates RFC `_. diff --git a/vendor/guzzle/guzzle/docs/index.rst b/vendor/guzzle/guzzle/docs/index.rst new file mode 100644 index 0000000..f76f3bb --- /dev/null +++ b/vendor/guzzle/guzzle/docs/index.rst @@ -0,0 +1,5 @@ +.. title:: Guzzle | PHP HTTP client and framework for consuming RESTful web services +.. toctree:: + :hidden: + + docs.rst diff --git a/vendor/guzzle/guzzle/docs/iterators/guzzle-iterators.rst b/vendor/guzzle/guzzle/docs/iterators/guzzle-iterators.rst new file mode 100644 index 0000000..a5c7fd3 --- /dev/null +++ b/vendor/guzzle/guzzle/docs/iterators/guzzle-iterators.rst @@ -0,0 +1,97 @@ +================ +Guzzle iterators +================ + +Guzzle provides several SPL iterators that can be used with other SPL iterators, including Guzzle resource iterators. +Guzzle's ``guzzle/iterator`` component can also be used independently of the rest of Guzzle through Packagist and +Composer: https://packagist.org/packages/guzzle/iterator + +ChunkedIterator +--------------- + +Pulls out multiple values from an inner iterator and yields and array of values for each outer iteration -- essentially +pulling out chunks of values from the inner iterator. + +.. code-block:: php + + use Guzzle\Iterator\ChunkedIterator; + + $inner = new ArrayIterator(range(0, 8)); + $chunkedIterator = new ChunkedIterator($inner, 2); + + foreach ($chunkedIterator as $chunk) { + echo implode(', ', $chunk) . "\n"; + } + + // >>> 0, 1 + // >>> 2, 3 + // >>> 4, 5 + // >>> 6, 7 + // >>> 8 + +FilterIterator +-------------- + +This iterator is used to filter values out of the inner iterator. This iterator can be used when PHP 5.4's +CallbackFilterIterator is not available. + +.. code-block:: php + + use Guzzle\Iterator\FilterIterator; + + $inner = new ArrayIterator(range(1, 10)); + $filterIterator = new FilterIterator($inner, function ($value) { + return $value % 2; + }); + + foreach ($filterIterator as $value) { + echo $value . "\n"; + } + + // >>> 2 + // >>> 4 + // >>> 6 + // >>> 8 + // >>> 10 + +MapIterator +----------- + +This iterator modifies the values of the inner iterator before yielding. + +.. code-block:: php + + use Guzzle\Iterator\MapIterator; + + $inner = new ArrayIterator(range(0, 3)); + + $mapIterator = new MapIterator($inner, function ($value) { + return $value * 10; + }); + + foreach ($mapIterator as $value) { + echo $value . "\n"; + } + + // >>> 0 + // >>> 10 + // >>> 20 + // >>> 30 + +MethodProxyIterator +------------------- + +This decorator is useful when you need to expose a specific method from an inner iterator that might be wrapper +by one or more iterator decorators. This decorator proxies missing method calls to each inner iterator until one +of the inner iterators can fulfill the call. + +.. code-block:: php + + use Guzzle\Iterator\MethodProxyIterator; + + $inner = new \ArrayIterator(); + $proxy = new MethodProxyIterator($inner); + + // Proxy method calls to the ArrayIterator + $proxy->append('a'); + $proxy->append('b'); diff --git a/vendor/guzzle/guzzle/docs/iterators/resource-iterators.rst b/vendor/guzzle/guzzle/docs/iterators/resource-iterators.rst new file mode 100644 index 0000000..ce0bee5 --- /dev/null +++ b/vendor/guzzle/guzzle/docs/iterators/resource-iterators.rst @@ -0,0 +1,149 @@ +================== +Resource iterators +================== + +Web services often implement pagination in their responses which requires the end-user to issue a series of consecutive +requests in order to fetch all of the data they asked for. Users of your web service client should not be responsible +for implementing the logic involved in iterating through pages of results. Guzzle provides a simple resource iterator +foundation to make it easier on web service client developers to offer a useful abstraction layer. + +Getting an iterator from a client +--------------------------------- + + ResourceIteratorInterface Guzzle\Service\Client::getIterator($command [, array $commandOptions, array $iteratorOptions ]) + +The ``getIterator`` method of a ``Guzzle\Service\ClientInterface`` object provides a convenient interface for +instantiating a resource iterator for a specific command. This method implicitly uses a +``Guzzle\Service\Resource\ResourceIteratorFactoryInterface`` object to create resource iterators. Pass an +instantiated command object or the name of a command in the first argument. When passing the name of a command, the +command factory of the client will create the command by name using the ``$commandOptions`` array. The third argument +may be used to pass an array of options to the constructor of the instantiated ``ResourceIteratorInterface`` object. + +.. code-block:: php + + $iterator = $client->getIterator('get_users'); + + foreach ($iterator as $user) { + echo $user['name'] . ' age ' . $user['age'] . PHP_EOL; + } + +The above code sample might execute a single request or a thousand requests. As a consumer of a web service, I don't +care. I just want to iterate over all of the users. + +Iterator options +~~~~~~~~~~~~~~~~ + +The two universal options that iterators should support are ``limit`` and ``page_size``. Using the ``limit`` option +tells the resource iterator to attempt to limit the total number of iterated resources to a specific amount. Keep in +mind that this is not always possible due to limitations that may be inherent to a web service. The ``page_size`` +option is used to tell a resource iterator how many resources to request per page of results. Much like the ``limit`` +option, you can not rely on getting back exactly the number of resources your specify in the ``page_size`` option. + +.. note:: + + The ``limit`` and ``page_size`` options can also be specified on an iterator using the ``setLimit($limit)`` and + ``setPageSize($pageSize)`` methods. + +Resolving iterator class names +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The default resource iterator factory of a client object expects that your iterators are stored under the ``Model`` +folder of your client and that an iterator is names after the CamelCase name of a command followed by the word +"Iterator". For example, if you wanted to create an iterator for the ``get_users`` command, then your iterator class +would be ``Model\GetUsersIterator`` and would be stored in ``Model/GetUsersIterator.php``. + +Creating an iterator +-------------------- + +While not required, resource iterators in Guzzle typically iterate using a ``Guzzle\Service\Command\CommandInterface`` +object. ``Guzzle\Service\Resource\ResourceIterator``, the default iterator implementation that you should extend, +accepts a command object and array of iterator options in its constructor. The command object passed to the resource +iterator is expected to be ready to execute and not previously executed. The resource iterator keeps a reference of +this command and clones the original command each time a subsequent request needs to be made to fetch more data. + +Implement the sendRequest method +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The most important thing (and usually the only thing) you need to do when creating a resource iterator is to implement +the ``sendRequest()`` method of the resource iterator. The ``sendRequest()`` method is called when you begin +iterating or if there are no resources left to iterate and it you expect to retrieve more resources by making a +subsequent request. The ``$this->command`` property of the resource iterator is updated with a cloned copy of the +original command object passed into the constructor of the iterator. Use this command object to issue your subsequent +requests. + +The ``sendRequest()`` method must return an array of the resources you retrieved from making the subsequent call. +Returning an empty array will stop the iteration. If you suspect that your web service client will occasionally return +an empty result set but still requires further iteration, then you must implement a sort of loop in your +``sendRequest()`` method that will continue to issue subsequent requests until your reach the end of the paginated +result set or until additional resources are retrieved from the web service. + +Update the nextToken property +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Beyond fetching more results, the ``sendRequest()`` method is responsible for updating the ``$this->nextToken`` +property of the iterator. Setting this property to anything other than null tells the iterator that issuing a +subsequent request using the nextToken value will probably return more results. You must continually update this +value in your ``sendRequest()`` method as each response is received from the web service. + +Example iterator +---------------- + +Let's say you want to implement a resource iterator for the ``get_users`` command of your web service. The +``get_users`` command receives a response that contains a list of users, and if there are more pages of results to +retrieve, returns a value called ``next_user``. This return value is known as the **next token** and should be used to +issue subsequent requests. + +Assume the response to a ``get_users`` command returns JSON data that looks like this: + +.. code-block:: javascript + + { + "users": [ + { "name": "Craig Johnson", "age": 10 }, + { "name": "Tom Barker", "age": 20 }, + { "name": "Bob Mitchell", "age": 74 } + ], + "next_user": "Michael Dowling" + } + +Assume that because there is a ``next_user`` value, there will be more users if a subsequent request is issued. If the +``next_user`` value is missing or null, then we know there are no more results to fetch. Let's implement a resource +iterator for this command. + +.. code-block:: php + + namespace MyService\Model; + + use Guzzle\Service\Resource\ResourceIterator; + + /** + * Iterate over a get_users command + */ + class GetUsersIterator extends ResourceIterator + { + protected function sendRequest() + { + // If a next token is set, then add it to the command + if ($this->nextToken) { + $this->command->set('next_user', $this->nextToken); + } + + // Execute the command and parse the result + $result = $this->command->execute(); + + // Parse the next token + $this->nextToken = isset($result['next_user']) ? $result['next_user'] : false; + + return $result['users']; + } + } + +As you can see, it's pretty simple to implement an iterator. There are a few things that you should notice from this +example: + +1. You do not need to create a new command in the ``sendRequest()`` method. A new command object is cloned from the + original command passed into the constructor of the iterator before the ``sendRequest()`` method is called. + Remember that the resource iterator expects a command that has not been executed. +2. When the ``sendRequest()`` method is first called, you will not have a ``$this->nextToken`` value, so always check + before setting it on a command. Notice that the next token is being updated each time a request is sent. +3. After fetching more resources from the service, always return an array of resources. diff --git a/vendor/guzzle/guzzle/docs/plugins/async-plugin.rst b/vendor/guzzle/guzzle/docs/plugins/async-plugin.rst new file mode 100644 index 0000000..9bd8f42 --- /dev/null +++ b/vendor/guzzle/guzzle/docs/plugins/async-plugin.rst @@ -0,0 +1,18 @@ +============ +Async plugin +============ + +The AsyncPlugin allows you to send requests that do not wait on a response. This is handled through cURL by utilizing +the progress event. When a request has sent all of its data to the remote server, Guzzle adds a 1ms timeout on the +request and instructs cURL to not download the body of the response. The async plugin then catches the exception and +adds a mock response to the request, along with an X-Guzzle-Async header to let you know that the response was not +fully downloaded. + +.. code-block:: php + + use Guzzle\Http\Client; + use Guzzle\Plugin\Async\AsyncPlugin; + + $client = new Client('http://www.example.com'); + $client->addSubscriber(new AsyncPlugin()); + $response = $client->get()->send(); diff --git a/vendor/guzzle/guzzle/docs/plugins/backoff-plugin.rst b/vendor/guzzle/guzzle/docs/plugins/backoff-plugin.rst new file mode 100644 index 0000000..5a76941 --- /dev/null +++ b/vendor/guzzle/guzzle/docs/plugins/backoff-plugin.rst @@ -0,0 +1,22 @@ +==================== +Backoff retry plugin +==================== + +The ``Guzzle\Plugin\Backoff\BackoffPlugin`` automatically retries failed HTTP requests using custom backoff strategies: + +.. code-block:: php + + use Guzzle\Http\Client; + use Guzzle\Plugin\Backoff\BackoffPlugin; + + $client = new Client('http://www.test.com/'); + // Use a static factory method to get a backoff plugin using the exponential backoff strategy + $backoffPlugin = BackoffPlugin::getExponentialBackoff(); + + // Add the backoff plugin to the client object + $client->addSubscriber($backoffPlugin); + +The BackoffPlugin's constructor accepts a ``Guzzle\Plugin\Backoff\BackoffStrategyInterface`` object that is used to +determine when a retry should be issued and how long to delay between retries. The above code example shows how to +attach a BackoffPlugin to a client that is pre-configured to retry failed 500 and 503 responses using truncated +exponential backoff (emulating the behavior of Guzzle 2's ExponentialBackoffPlugin). diff --git a/vendor/guzzle/guzzle/docs/plugins/cache-plugin.rst b/vendor/guzzle/guzzle/docs/plugins/cache-plugin.rst new file mode 100644 index 0000000..d2fd5df --- /dev/null +++ b/vendor/guzzle/guzzle/docs/plugins/cache-plugin.rst @@ -0,0 +1,169 @@ +================= +HTTP Cache plugin +================= + +Guzzle can leverage HTTP's caching specifications using the ``Guzzle\Plugin\Cache\CachePlugin``. The CachePlugin +provides a private transparent proxy cache that caches HTTP responses. The caching logic, based on +`RFC 2616 `_, uses HTTP headers to control caching behavior, +cache lifetime, and supports Vary, ETag, and Last-Modified based revalidation: + +.. code-block:: php + + use Guzzle\Http\Client; + use Doctrine\Common\Cache\FilesystemCache; + use Guzzle\Cache\DoctrineCacheAdapter; + use Guzzle\Plugin\Cache\CachePlugin; + use Guzzle\Plugin\Cache\DefaultCacheStorage; + + $client = new Client('http://www.test.com/'); + + $cachePlugin = new CachePlugin(array( + 'storage' => new DefaultCacheStorage( + new DoctrineCacheAdapter( + new FilesystemCache('/path/to/cache/files') + ) + ) + )); + + // Add the cache plugin to the client object + $client->addSubscriber($cachePlugin); + $client->get('http://www.wikipedia.org/')->send(); + + // The next request will revalidate against the origin server to see if it + // has been modified. If a 304 response is received the response will be + // served from cache + $client->get('http://www.wikipedia.org/')->send(); + +The cache plugin intercepts GET and HEAD requests before they are actually transferred to the origin server. The cache +plugin then generates a hash key based on the request method and URL, and checks to see if a response exists in the cache. If +a response exists in the cache, the cache adapter then checks to make sure that the caching rules associated with the response +satisfy the request, and ensures that response still fresh. If the response is acceptable for the request any required +revalidation, then the cached response is served instead of contacting the origin server. + +Vary +---- + +Cache keys are derived from a request method and a request URL. Multiple responses can map to the same cache key and +stored in Guzzle's underlying cache storage object. You should use the ``Vary`` HTTP header to tell the cache storage +object that the cache response must have been cached for a request that matches the headers specified in the Vary header +of the request. This allows you to have specific cache entries for the same request URL but variations in a request's +headers determine which cache entry is served. Please see the http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.44 +for more information. + +Cache options +------------- + +There are several options you can add to requests or clients to modify the behavior of the cache plugin. + +Override cache TTL +~~~~~~~~~~~~~~~~~~ + +You can override the number of seconds a cacheable response is stored in the cache by setting the +``cache.override_ttl`` parameter on the params object of a request: + +.. code-block:: php + + // If the response to the request is cacheable, then the response will be cached for 100 seconds + $request->getParams()->set('cache.override_ttl', 100); + +If a response doesn't specify any freshness policy, it will be kept in cache for 3600 seconds by default. + +Custom caching decision +~~~~~~~~~~~~~~~~~~~~~~~ + +If the service you are interacting with does not return caching headers or returns responses that are normally +something that would not be cached, you can set a custom ``can_cache`` object on the constructor of the CachePlugin +and provide a ``Guzzle\Plugin\Cache\CanCacheInterface`` object. You can use the +``Guzzle\Plugin\Cache\CallbackCanCacheStrategy`` to easily make a caching decision based on an HTTP request and +response. + +Revalidation options +~~~~~~~~~~~~~~~~~~~~ + +You can change the revalidation behavior of a request using the ``cache.revalidate`` parameter. Setting this +parameter to ``never`` will ensure that a revalidation request is never sent, and the response is always served from +the origin server. Setting this parameter to ``skip`` will never revalidate and uses the response stored in the cache. + +Normalizing requests for caching +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Use the ``cache.key_filter`` parameter if you wish to strip certain query string parameters from your +request before creating a unique hash for the request. This parameter can be useful if your requests have query +string values that cause each request URL to be unique (thus preventing a cache hit). The ``cache.key_filter`` +format is simply a comma separated list of query string values to remove from the URL when creating a cache key. +For example, here we are saying that the ``a`` and ``q`` query string variables should be ignored when generating a +cache key for the request: + +.. code-block:: php + + $request->getParams()->set('cache.key_filter', 'a, q'); + +Other options +~~~~~~~~~~~~~ + +There are many other options available to the CachePlugin that can meet almost any caching requirement, including +custom revalidation implementations, custom cache key generators, custom caching decision strategies, and custom +cache storage objects. Take a look the constructor of ``Guzzle\Plugin\Cache\CachePlugin`` for more information. + +Setting Client-wide cache settings +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +You can specify cache settings for every request created by a client by adding cache settings to the configuration +options of a client. + +.. code-block:: php + + $client = new Guzzle\Http\Client('http://www.test.com', array( + 'request.params' => array( + 'cache.override_ttl' => 3600, + 'params.cache.revalidate' => 'never' + ) + )); + + echo $client->get('/')->getParams()->get('cache.override_ttl'); + // >>> 3600 + + echo $client->get('/')->getParams()->get('cache.revalidate'); + // >>> never + +Cache revalidation +------------------ + +If the cache plugin determines that a response to a GET request needs revalidation, a conditional GET is transferred +to the origin server. If the origin server returns a 304 response, then a response containing the merged headers of +the cached response with the new response and the entity body of the cached response is returned. Custom revalidation +strategies can be injected into a CachePlugin if needed. + +Cache adapters +-------------- + +Guzzle doesn't try to reinvent the wheel when it comes to caching or logging. Plenty of other frameworks have +excellent solutions in place that you are probably already using in your applications. Guzzle uses adapters for +caching and logging. The cache plugin requires a cache adapter so that is can store responses in a cache. Guzzle +currently supports cache adapters for `Doctrine 2.0 `_ and the +`Zend Framework `_. + +Doctrine cache adapter +~~~~~~~~~~~~~~~~~~~~~~ + +.. code-block:: php + + use Doctrine\Common\Cache\ArrayCache; + use Guzzle\Cache\DoctrineCacheAdapter; + use Guzzle\Plugin\Cache\CachePlugin; + + $backend = new ArrayCache(); + $adapter = new DoctrineCacheAdapter($backend); + $cache = new CachePlugin($adapter); + +Zend Framework cache adapter +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. code-block:: php + + use Guzzle\Cache\ZendCacheAdapter; + use Zend\Cache\Backend\TestBackend; + + $backend = new TestBackend(); + $adapter = new ZendCacheAdapter($backend); + $cache = new CachePlugin($adapter); diff --git a/vendor/guzzle/guzzle/docs/plugins/cookie-plugin.rst b/vendor/guzzle/guzzle/docs/plugins/cookie-plugin.rst new file mode 100644 index 0000000..a6cc7d9 --- /dev/null +++ b/vendor/guzzle/guzzle/docs/plugins/cookie-plugin.rst @@ -0,0 +1,33 @@ +============= +Cookie plugin +============= + +Some web services require a Cookie in order to maintain a session. The ``Guzzle\Plugin\Cookie\CookiePlugin`` will add +cookies to requests and parse cookies from responses using a CookieJar object: + +.. code-block:: php + + use Guzzle\Http\Client; + use Guzzle\Plugin\Cookie\CookiePlugin; + use Guzzle\Plugin\Cookie\CookieJar\ArrayCookieJar; + + $cookiePlugin = new CookiePlugin(new ArrayCookieJar()); + + // Add the cookie plugin to a client + $client = new Client('http://www.test.com/'); + $client->addSubscriber($cookiePlugin); + + // Send the request with no cookies and parse the returned cookies + $client->get('http://www.yahoo.com/')->send(); + + // Send the request again, noticing that cookies are being sent + $request = $client->get('http://www.yahoo.com/'); + $request->send(); + + echo $request; + +You can disable cookies per-request by setting the ``cookies.disable`` value to true on a request's params object. + +.. code-block:: php + + $request->getParams()->set('cookies.disable', true); diff --git a/vendor/guzzle/guzzle/docs/plugins/creating-plugins.rst b/vendor/guzzle/guzzle/docs/plugins/creating-plugins.rst new file mode 100644 index 0000000..0870155 --- /dev/null +++ b/vendor/guzzle/guzzle/docs/plugins/creating-plugins.rst @@ -0,0 +1,93 @@ +================ +Creating plugins +================ + +.. highlight:: php + +Guzzle is extremely extensible because of the behavioral modifications that can be added to requests, clients, and +commands using an event system. Before and after the majority of actions are taken in the library, an event is emitted +with the name of the event and context surrounding the event. Observers can subscribe to a subject and modify the +subject based on the events received. Guzzle's event system utilizes the Symfony2 EventDispatcher and is the backbone +of its plugin architecture. + +Overview +-------- + +Plugins must implement the ``Symfony\Component\EventDispatcher\EventSubscriberInterface`` interface. The +``EventSubscriberInterface`` requires that your class implements a static method, ``getSubscribedEvents()``, that +returns an associative array mapping events to methods on the object. See the +`Symfony2 documentation `_ for more information. + +Plugins can be attached to any subject, or object in Guzzle that implements that +``Guzzle\Common\HasDispatcherInterface``. + +Subscribing to a subject +~~~~~~~~~~~~~~~~~~~~~~~~ + +You can subscribe an instantiated observer to an event by calling ``addSubscriber`` on a subject. + +.. code-block:: php + + $testPlugin = new TestPlugin(); + $client->addSubscriber($testPlugin); + +You can also subscribe to only specific events using a closure:: + + $client->getEventDispatcher()->addListener('request.create', function(Event $event) { + echo $event->getName(); + echo $event['request']; + }); + +``Guzzle\Common\Event`` objects are passed to notified functions. The Event object has a ``getName()`` method which +return the name of the emitted event and may contain contextual information that can be accessed like an array. + +Knowing what events to listen to +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Any class that implements the ``Guzzle\Common\HasDispatcherInterface`` must implement a static method, +``getAllEvents()``, that returns an array of the events that are emitted from the object. You can browse the source +to see each event, or you can call the static method directly in your code to get a list of available events. + +Event hooks +----------- + +* :ref:`client-events` +* :ref:`service-client-events` +* :ref:`request-events` +* ``Guzzle\Http\Curl\CurlMulti``: +* :ref:`service-builder-events` + +Examples of the event system +---------------------------- + +Simple Echo plugin +~~~~~~~~~~~~~~~~~~ + +This simple plugin prints a string containing the request that is about to be sent by listening to the +``request.before_send`` event:: + + use Symfony\Component\EventDispatcher\EventSubscriberInterface; + + class EchoPlugin implements EventSubscriberInterface + { + public static function getSubscribedEvents() + { + return array('request.before_send' => 'onBeforeSend'); + } + + public function onBeforeSend(Guzzle\Common\Event $event) + { + echo 'About to send a request: ' . $event['request'] . "\n"; + } + } + + $client = new Guzzle\Service\Client('http://www.test.com/'); + + // Create the plugin and add it as an event subscriber + $plugin = new EchoPlugin(); + $client->addSubscriber($plugin); + + // Send a request and notice that the request is printed to the screen + $client->get('/')->send(); + +Running the above code will print a string containing the HTTP request that is about to be sent. diff --git a/vendor/guzzle/guzzle/docs/plugins/curl-auth-plugin.rst b/vendor/guzzle/guzzle/docs/plugins/curl-auth-plugin.rst new file mode 100644 index 0000000..66d4a01 --- /dev/null +++ b/vendor/guzzle/guzzle/docs/plugins/curl-auth-plugin.rst @@ -0,0 +1,32 @@ +========================== +cURL authentication plugin +========================== + +.. warning:: + + The CurlAuthPlugin is deprecated. You should use the `auth` parameter of a client to add authorization headers to + every request created by a client. + + .. code-block:: php + + $client->setDefaultOption('auth', array('username', 'password', 'Basic|Digest|NTLM|Any')); + +If your web service client requires basic authorization, then you can use the CurlAuthPlugin to easily add an +Authorization header to each request sent by the client. + +.. code-block:: php + + use Guzzle\Http\Client; + use Guzzle\Plugin\CurlAuth\CurlAuthPlugin; + + $client = new Client('http://www.test.com/'); + + // Add the auth plugin to the client object + $authPlugin = new CurlAuthPlugin('username', 'password'); + $client->addSubscriber($authPlugin); + + $response = $client->get('projects/1/people')->send(); + $xml = new SimpleXMLElement($response->getBody(true)); + foreach ($xml->person as $person) { + echo $person->email . "\n"; + } diff --git a/vendor/guzzle/guzzle/docs/plugins/history-plugin.rst b/vendor/guzzle/guzzle/docs/plugins/history-plugin.rst new file mode 100644 index 0000000..b96befe --- /dev/null +++ b/vendor/guzzle/guzzle/docs/plugins/history-plugin.rst @@ -0,0 +1,24 @@ +============== +History plugin +============== + +The history plugin tracks all of the requests and responses sent through a request or client. This plugin can be +useful for crawling or unit testing. By default, the history plugin stores up to 10 requests and responses. + +.. code-block:: php + + use Guzzle\Http\Client; + use Guzzle\Plugin\History\HistoryPlugin; + + $client = new Client('http://www.test.com/'); + + // Add the history plugin to the client object + $history = new HistoryPlugin(); + $history->setLimit(5); + $client->addSubscriber($history); + + $client->get('http://www.yahoo.com/')->send(); + + echo $history->getLastRequest(); + echo $history->getLastResponse(); + echo count($history); diff --git a/vendor/guzzle/guzzle/docs/plugins/log-plugin.rst b/vendor/guzzle/guzzle/docs/plugins/log-plugin.rst new file mode 100644 index 0000000..3e2b229 --- /dev/null +++ b/vendor/guzzle/guzzle/docs/plugins/log-plugin.rst @@ -0,0 +1,69 @@ +========== +Log plugin +========== + +Use the ``Guzzle\Plugin\Log\LogPlugin`` to view all data sent over the wire, including entity bodies and redirects. + +.. code-block:: php + + use Guzzle\Http\Client; + use Guzzle\Log\Zf1LogAdapter; + use Guzzle\Plugin\Log\LogPlugin; + use Guzzle\Log\MessageFormatter; + + $client = new Client('http://www.test.com/'); + + $adapter = new Zf1LogAdapter( + new \Zend_Log(new \Zend_Log_Writer_Stream('php://output')) + ); + $logPlugin = new LogPlugin($adapter, MessageFormatter::DEBUG_FORMAT); + + // Attach the plugin to the client, which will in turn be attached to all + // requests generated by the client + $client->addSubscriber($logPlugin); + + $response = $client->get('http://google.com')->send(); + +The code sample above wraps a ``Zend_Log`` object using a ``Guzzle\Log\Zf1LogAdapter``. After attaching the plugin to +the client, all data sent over the wire will be logged to stdout. + +The first argument of the LogPlugin's constructor accepts a ``Guzzle\Log\LogAdapterInterface`` object. This object is +an adapter that allows you to use the logging capabilities of your favorite log implementation. The second argument of +the constructor accepts a ``Guzzle\Log\MessageFormatter`` or a log messaged format string. The format string uses +variable substitution and allows you to define the log data that is important to your application. The different +variables that can be injected are as follows: + +================== ==================================================================================== +Variable Substitution +================== ==================================================================================== +{request} Full HTTP request message +{response} Full HTTP response message +{ts} Timestamp +{host} Host of the request +{method} Method of the request +{url} URL of the request +{host} Host of the request +{protocol} Request protocol +{version} Protocol version +{resource} Resource of the request (path + query + fragment) +{port} Port of the request +{hostname} Hostname of the machine that sent the request +{code} Status code of the response (if available) +{phrase} Reason phrase of the response (if available) +{curl_error} Curl error message (if available) +{curl_code} Curl error code (if available) +{curl_stderr} Curl standard error (if available) +{connect_time} Time in seconds it took to establish the connection (if available) +{total_time} Total transaction time in seconds for last transfer (if available) +{req_header_*} Replace `*` with the lowercased name of a request header to add to the message +{res_header_*} Replace `*` with the lowercased name of a response header to add to the message +{req_body} Request body +{res_body} Response body +================== ==================================================================================== + +The LogPlugin has a helper method that can be used when debugging that will output the full HTTP request and +response of a transaction: + +.. code-block:: php + + $client->addSubscriber(LogPlugin::getDebugPlugin()); diff --git a/vendor/guzzle/guzzle/docs/plugins/md5-validator-plugin.rst b/vendor/guzzle/guzzle/docs/plugins/md5-validator-plugin.rst new file mode 100644 index 0000000..1b1cfa8 --- /dev/null +++ b/vendor/guzzle/guzzle/docs/plugins/md5-validator-plugin.rst @@ -0,0 +1,29 @@ +==================== +MD5 validator plugin +==================== + +Entity bodies can sometimes be modified over the wire due to a faulty TCP transport or misbehaving proxy. If an HTTP +response contains a Content-MD5 header, then a MD5 hash of the entity body of a response can be compared against the +Content-MD5 header of the response to determine if the response was delivered intact. The +``Guzzle\Plugin\Md5\Md5ValidatorPlugin`` will throw an ``UnexpectedValueException`` if the calculated MD5 hash does +not match the Content-MD5 header value: + +.. code-block:: php + + use Guzzle\Http\Client; + use Guzzle\Plugin\Md5\Md5ValidatorPlugin; + + $client = new Client('http://www.test.com/'); + + $md5Plugin = new Md5ValidatorPlugin(); + + // Add the md5 plugin to the client object + $client->addSubscriber($md5Plugin); + + $request = $client->get('http://www.yahoo.com/'); + $request->send(); + +Calculating the MD5 hash of a large entity body or an entity body that was transferred using a Content-Encoding is an +expensive operation. When working in high performance applications, you might consider skipping the MD5 hash +validation for entity bodies bigger than a certain size or Content-Encoded entity bodies +(see ``Guzzle\Plugin\Md5\Md5ValidatorPlugin`` for more information). diff --git a/vendor/guzzle/guzzle/docs/plugins/mock-plugin.rst b/vendor/guzzle/guzzle/docs/plugins/mock-plugin.rst new file mode 100644 index 0000000..4900cb5 --- /dev/null +++ b/vendor/guzzle/guzzle/docs/plugins/mock-plugin.rst @@ -0,0 +1,27 @@ +=========== +Mock plugin +=========== + +The mock plugin is useful for testing Guzzle clients. The mock plugin allows you to queue an array of responses that +will satisfy requests sent from a client by consuming the request queue in FIFO order. + +.. code-block:: php + + use Guzzle\Http\Client; + use Guzzle\Plugin\Mock\MockPlugin; + use Guzzle\Http\Message\Response; + + $client = new Client('http://www.test.com/'); + + $mock = new MockPlugin(); + $mock->addResponse(new Response(200)) + ->addResponse(new Response(404)); + + // Add the mock plugin to the client object + $client->addSubscriber($mock); + + // The following request will receive a 200 response from the plugin + $client->get('http://www.example.com/')->send(); + + // The following request will receive a 404 response from the plugin + $client->get('http://www.test.com/')->send(); diff --git a/vendor/guzzle/guzzle/docs/plugins/oauth-plugin.rst b/vendor/guzzle/guzzle/docs/plugins/oauth-plugin.rst new file mode 100644 index 0000000..e67eaba --- /dev/null +++ b/vendor/guzzle/guzzle/docs/plugins/oauth-plugin.rst @@ -0,0 +1,30 @@ +============ +OAuth plugin +============ + +Guzzle ships with an OAuth 1.0 plugin that can sign requests using a consumer key, consumer secret, OAuth token, +and OAuth secret. Here's an example showing how to send an authenticated request to the Twitter REST API: + +.. code-block:: php + + use Guzzle\Http\Client; + use Guzzle\Plugin\Oauth\OauthPlugin; + + $client = new Client('http://api.twitter.com/1'); + $oauth = new OauthPlugin(array( + 'consumer_key' => 'my_key', + 'consumer_secret' => 'my_secret', + 'token' => 'my_token', + 'token_secret' => 'my_token_secret' + )); + $client->addSubscriber($oauth); + + $response = $client->get('statuses/public_timeline.json')->send(); + +If you need to use a custom signing method, you can pass a ``signature_method`` configuration option in the +constructor of the OAuth plugin. The ``signature_method`` option must be a callable variable that accepts a string to +sign and signing key and returns a signed string. + +.. note:: + + You can omit the ``token`` and ``token_secret`` options to use two-legged OAuth. diff --git a/vendor/guzzle/guzzle/docs/plugins/plugins-list.rst.inc b/vendor/guzzle/guzzle/docs/plugins/plugins-list.rst.inc new file mode 100644 index 0000000..8d6d09b --- /dev/null +++ b/vendor/guzzle/guzzle/docs/plugins/plugins-list.rst.inc @@ -0,0 +1,9 @@ +* :doc:`/plugins/async-plugin` +* :doc:`/plugins/backoff-plugin` +* :doc:`/plugins/cache-plugin` +* :doc:`/plugins/cookie-plugin` +* :doc:`/plugins/history-plugin` +* :doc:`/plugins/log-plugin` +* :doc:`/plugins/md5-validator-plugin` +* :doc:`/plugins/mock-plugin` +* :doc:`/plugins/oauth-plugin` diff --git a/vendor/guzzle/guzzle/docs/plugins/plugins-overview.rst b/vendor/guzzle/guzzle/docs/plugins/plugins-overview.rst new file mode 100644 index 0000000..19ae57e --- /dev/null +++ b/vendor/guzzle/guzzle/docs/plugins/plugins-overview.rst @@ -0,0 +1,59 @@ +====================== +Plugin system overview +====================== + +The workflow of sending a request and parsing a response is driven by Guzzle's event system, which is powered by the +`Symfony2 Event Dispatcher component `_. + +Any object in Guzzle that emits events will implement the ``Guzzle\Common\HasEventDispatcher`` interface. You can add +event subscribers directly to these objects using the ``addSubscriber()`` method, or you can grab the +``Symfony\Component\EventDispatcher\EventDispatcher`` object owned by the object using ``getEventDispatcher()`` and +add a listener or event subscriber. + +Adding event subscribers to clients +----------------------------------- + +Any event subscriber or event listener attached to the EventDispatcher of a ``Guzzle\Http\Client`` or +``Guzzle\Service\Client`` object will automatically be attached to all request objects created by the client. This +allows you to attach, for example, a HistoryPlugin to a client object, and from that point on, every request sent +through that client will utilize the HistoryPlugin. + +.. code-block:: php + + use Guzzle\Plugin\History\HistoryPlugin; + use Guzzle\Service\Client; + + $client = new Client(); + + // Create a history plugin and attach it to the client + $history = new HistoryPlugin(); + $client->addSubscriber($history); + + // Create and send a request. This request will also utilize the HistoryPlugin + $client->get('http://httpbin.org')->send(); + + // Echo out the last sent request by the client + echo $history->getLastRequest(); + +.. tip:: + + :doc:`Create event subscribers `, or *plugins*, to implement reusable logic that can be + shared across clients. Event subscribers are also easier to test than anonymous functions. + +Pre-Built plugins +----------------- + +Guzzle provides easy to use request plugins that add behavior to requests based on signal slot event notifications +powered by the Symfony2 Event Dispatcher component. + +* :doc:`async-plugin` +* :doc:`backoff-plugin` +* :doc:`cache-plugin` +* :doc:`cookie-plugin` +* :doc:`curl-auth-plugin` +* :doc:`history-plugin` +* :doc:`log-plugin` +* :doc:`md5-validator-plugin` +* :doc:`mock-plugin` +* :doc:`oauth-plugin` + diff --git a/vendor/guzzle/guzzle/docs/requirements.txt b/vendor/guzzle/guzzle/docs/requirements.txt new file mode 100644 index 0000000..f62e318 --- /dev/null +++ b/vendor/guzzle/guzzle/docs/requirements.txt @@ -0,0 +1,2 @@ +Sphinx>=1.2b1 +guzzle_sphinx_theme>=0.5.0 diff --git a/vendor/guzzle/guzzle/docs/testing/unit-testing.rst b/vendor/guzzle/guzzle/docs/testing/unit-testing.rst new file mode 100644 index 0000000..f4297af --- /dev/null +++ b/vendor/guzzle/guzzle/docs/testing/unit-testing.rst @@ -0,0 +1,201 @@ +=========================== +Unit Testing Guzzle clients +=========================== + +Guzzle provides several tools that will enable you to easily unit test your web service clients. + +* PHPUnit integration +* Mock responses +* node.js web server for integration testing + +PHPUnit integration +------------------- + +Guzzle is unit tested using `PHPUnit `_. Your web service client's unit tests should extend +``Guzzle\Tests\GuzzleTestCase`` so that you can take advantage of some of the built in helpers. + +In order to unit test your client, a developer would need to copy phpunit.xml.dist to phpunit.xml and make any needed +modifications. As a best practice and security measure for you and your contributors, it is recommended to add an +ignore statement to your SCM so that phpunit.xml is ignored. + +Bootstrapping +~~~~~~~~~~~~~ + +Your web service client should have a tests/ folder that contains a bootstrap.php file. The bootstrap.php file +responsible for autoloading and configuring a ``Guzzle\Service\Builder\ServiceBuilder`` that is used throughout your +unit tests for loading a configured client. You can add custom parameters to your phpunit.xml file that expects users +to provide the path to their configuration data. + +.. code-block:: php + + Guzzle\Tests\GuzzleTestCase::setServiceBuilder(Aws\Common\Aws::factory($_SERVER['CONFIG'])); + + Guzzle\Tests\GuzzleTestCase::setServiceBuilder(Guzzle\Service\Builder\ServiceBuilder::factory(array( + 'test.unfuddle' => array( + 'class' => 'Guzzle.Unfuddle.UnfuddleClient', + 'params' => array( + 'username' => 'test_user', + 'password' => '****', + 'subdomain' => 'test' + ) + ) + ))); + +The above code registers a service builder that can be used throughout your unit tests. You would then be able to +retrieve an instantiated and configured Unfuddle client by calling ``$this->getServiceBuilder()->get('test.unfuddle)``. +The above code assumes that ``$_SERVER['CONFIG']`` contains the path to a file that stores service description +configuration. + +Unit testing remote APIs +------------------------ + +Mock responses +~~~~~~~~~~~~~~ + +One of the benefits of unit testing is the ability to quickly determine if there are errors in your code. If your +unit tests run slowly, then they become tedious and will likely be run less frequently. Guzzle's philosophy on unit +testing web service clients is that no network access should be required to run the unit tests. This means that +responses are served from mock responses or local servers. By adhering to this principle, tests will run much faster +and will not require an external resource to be available. The problem with this approach is that your mock responses +must first be gathered and then subsequently updated each time the remote API changes. + +Integration testing over the internet +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +You can perform integration testing with a web service over the internet by making calls directly to the service. If +the web service you are requesting uses a complex signing algorithm or some other specific implementation, then you +may want to include at least one actual network test that can be run specifically through the command line using +`PHPUnit group annotations `_. + +@group internet annotation +^^^^^^^^^^^^^^^^^^^^^^^^^^ + +When creating tests that require an internet connection, it is recommended that you add ``@group internet`` annotations +to your unit tests to specify which tests require network connectivity. + +You can then `run PHPUnit tests `_ that exclude the @internet +group by running ``phpunit --exclude-group internet``. + +API credentials +^^^^^^^^^^^^^^^ + +If API credentials are required to run your integration tests, you must add ```` parameters to your +phpunit.xml.dist file and extract these parameters in your bootstrap.php file. + +.. code-block:: xml + + + + + + + + + + + + + ./Tests + + + + +You can then extract the ``server`` variables in your bootstrap.php file by grabbing them from the ``$_SERVER`` +superglobal: ``$apiUser = $_SERVER['API_USER'];`` + +Further reading +^^^^^^^^^^^^^^^ + +A good discussion on the topic of testing remote APIs can be found in Sebastian Bergmann's +`Real-World Solutions for Developing High-Quality PHP Frameworks and Applications `_. + +Queueing Mock responses +----------------------- + +Mock responses can be used to test if requests are being generated correctly and responses and handled correctly by +your client. Mock responses can be queued up for a client using the ``$this->setMockResponse($client, $path)`` method +of your test class. Pass the client you are adding mock responses to and a single path or array of paths to mock +response files relative to the ``/tests/mock/ folder``. This will queue one or more mock responses for your client by +creating a simple observer on the client. Mock response files must contain a full HTTP response message: + +.. code-block:: none + + HTTP/1.1 200 OK + Date: Wed, 25 Nov 2009 12:00:00 GMT + Connection: close + Server: AmazonS3 + Content-Type: application/xml + + + EU + +After queuing mock responses for a client, you can get an array of the requests that were sent by the client that +were issued a mock response by calling ``$this->getMockedRequests()``. + +You can also use the ``Guzzle\Plugin\Mock\MockPlugin`` object directly with your clients. + +.. code-block:: php + + $plugin = new Guzzle\Plugin\Mock\MockPlugin(); + $plugin->addResponse(new Guzzle\Http\Message\Response(200)); + $client = new Guzzle\Http\Client(); + $client->addSubscriber($plugin); + + // The following request will get the mock response from the plugin in FIFO order + $request = $client->get('http://www.test.com/'); + $request->send(); + + // The MockPlugin maintains a list of requests that were mocked + $this->assertContainsOnly($request, $plugin->getReceivedRequests()); + +node.js web server for integration testing +------------------------------------------ + +Using mock responses is usually enough when testing a web service client. If your client needs to add custom cURL +options to requests, then you should use the node.js test web server to ensure that your HTTP request message is +being created correctly. + +Guzzle is based around PHP's libcurl bindings. cURL sometimes modifies an HTTP request message based on +``CURLOPT_*`` options. Headers that are added to your request by cURL will not be accounted for if you inject mock +responses into your tests. Additionally, some request entity bodies cannot be loaded by the client before transmitting +it to the sever (for example, when using a client as a sort of proxy and streaming content from a remote server). You +might also need to inspect the entity body of a ``multipart/form-data`` POST request. + +.. note:: + + You can skip all of the tests that require the node.js test web server by excluding the ``server`` group: + ``phpunit --exclude-group server`` + +Using the test server +~~~~~~~~~~~~~~~~~~~~~ + +The node.js test server receives requests and returns queued responses. The test server exposes a simple API that is +used to enqueue responses and inspect the requests that it has received. + +Retrieve the server object by calling ``$this->getServer()``. If the node.js server is not running, it will be +started as a forked process and an object that interfaces with the server will be returned. (note: stopping the +server is handled internally by Guzzle.) + +You can queue an HTTP response or an array of responses by calling ``$this->getServer()->enqueue()``: + +.. code-block:: php + + $this->getServer()->enqueue("HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n"); + +The above code queues a single 200 response with an empty body. Responses are queued using a FIFO order; this +response will be returned by the server when it receives the first request and then removed from the queue. If a +request is received by a server with no queued responses, an exception will be thrown in your unit test. + +You can inspect the requests that the server has retrieved by calling ``$this->getServer()->getReceivedRequests()``. +This method accepts an optional ``$hydrate`` parameter that specifies if you are retrieving an array of string HTTP +requests or an array of ``Guzzle\Http\RequestInterface`` subclassed objects. "Hydrating" the requests will allow +greater flexibility in your unit tests so that you can easily assert the state of the various parts of a request. + +You will need to modify the base_url of your web service client in order to use it against the test server. + +.. code-block:: php + + $client = $this->getServiceBuilder()->get('my_client'); + $client->setBaseUrl($this->getServer()->getUrl()); + +After running the above code, all calls made from the ``$client`` object will be sent to the test web server. diff --git a/vendor/guzzle/guzzle/docs/webservice-client/guzzle-service-descriptions.rst b/vendor/guzzle/guzzle/docs/webservice-client/guzzle-service-descriptions.rst new file mode 100644 index 0000000..ad6070b --- /dev/null +++ b/vendor/guzzle/guzzle/docs/webservice-client/guzzle-service-descriptions.rst @@ -0,0 +1,619 @@ +=========================== +Guzzle service descriptions +=========================== + +Guzzle allows you to serialize HTTP requests and parse HTTP responses using a DSL called a service descriptions. +Service descriptions define web service APIs by documenting each operation, the operation's parameters, validation +options for each parameter, an operation's response, how the response is parsed, and any errors that can be raised for +an operation. Writing a service description for a web service allows you to more quickly consume a web service than +writing concrete commands for each web service operation. + +Guzzle service descriptions can be representing using a PHP array or JSON document. Guzzle's service descriptions are +heavily inspired by `Swagger `_. + +Service description schema +========================== + +A Guzzle Service description must match the following JSON schema document. This document can also serve as a guide when +implementing a Guzzle service description. + +Download the schema here: :download:`Guzzle JSON schema document ` + +.. class:: overflow-height-500px + + .. literalinclude:: ../_downloads/guzzle-schema-1.0.json + :language: json + +Top-level attributes +-------------------- + +Service descriptions are comprised of the following top-level attributes: + +.. code-block:: json + + { + "name": "string", + "apiVersion": "string|number", + "baseUrl": "string", + "description": "string", + "operations": {}, + "models": {}, + "includes": ["string.php", "string.json"] + } + ++-----------------------------------------+-------------------------+-----------------------------------------------------------------------------------------------------------------------+ +| Property Name | Value | Description | ++=========================================+=========================+=======================================================================================================================+ +| name | string | Name of the web service | ++-----------------------------------------+-------------------------+-----------------------------------------------------------------------------------------------------------------------+ +| apiVersion | string|number | Version identifier that the service description is compatible with | ++-----------------------------------------+-------------------------+-----------------------------------------------------------------------------------------------------------------------+ +| baseUrl or basePath | string | Base URL of the web service. Any relative URI specified in an operation will be merged with the baseUrl using the | +| | | process defined in RFC 2396. Some clients require custom logic to determine the baseUrl. In those cases, it is best | +| | | to not include a baseUrl in the service description, but rather allow the factory method of the client to configure | +| | | the client’s baseUrl. | ++-----------------------------------------+-------------------------+-----------------------------------------------------------------------------------------------------------------------+ +| description | string | Short summary of the web service | ++-----------------------------------------+-------------------------+-----------------------------------------------------------------------------------------------------------------------+ +| operations | object containing | Operations of the service. The key is the name of the operation and value is the attributes of the operation. | +| | :ref:`operation-schema` | | +| | | | ++-----------------------------------------+-------------------------+-----------------------------------------------------------------------------------------------------------------------+ +| models | object containing | Schema models that can be referenced throughout the service description. Models can be used to define how an HTTP | +| | :ref:`model-schema` | response is parsed into a ``Guzzle\Service\Resource\Model`` object when an operation uses a ``model`` ``responseType``| ++-----------------------------------------+-------------------------+-----------------------------------------------------------------------------------------------------------------------+ +| includes | array of .js, | Service description files to include and extend from (can be a .json, .js, or .php file) | +| | .json, or .php | | +| | files. | | ++-----------------------------------------+-------------------------+-----------------------------------------------------------------------------------------------------------------------+ +| (any additional properties) | mixed | Any additional properties specified as top-level attributes are allowed and will be treated as arbitrary data | ++-----------------------------------------+-------------------------+-----------------------------------------------------------------------------------------------------------------------+ + +.. _operation-schema: + +Operations +---------- + +Operations are the actions that can be taken on a service. Each operation is given a unique name and has a distinct +endpoint and HTTP method. If an API has a ``DELETE /users/:id`` operation, a satisfactory operation name might be +``DeleteUser`` with a parameter of ``id`` that is inserted into the URI. + +.. class:: overflow-height-250px + + .. code-block:: json + + { + "operations": { + "operationName": { + "extends": "string", + "httpMethod": "GET|POST|PUT|DELETE|PATCH|string", + "uri": "string", + "summary": "string", + "class": "string", + "responseClass": "string", + "responseNotes": "string", + "type": "string", + "description": "string", + "responseType": "primitive|class|(model by name)|documentation|(string)", + "deprecated": false, + "errorResponses": [ + { + "code": 500, + "reason": "Unexpected Error", + "class": "string" + } + ], + "data": { + "foo": "bar", + "baz": "bam" + }, + "parameters": {} + } + } + } + +.. csv-table:: + :header: "Property Name", "Value", "Description" + :widths: 20, 15, 65 + + "extends", "string", "Extend from another operation by name. The parent operation must be defined before the child." + "httpMethod", "string", "HTTP method used with the operation (e.g. GET, POST, PUT, DELETE, PATCH, etc)" + "uri", "string", "URI of the operation. The uri attribute can contain URI templates. The variables of the URI template are parameters of the operation with a location value of uri" + "summary", "string", "Short summary of what the operation does" + "class", "string", "Custom class to instantiate instead of the default Guzzle\\Service\\Command\\OperationCommand. Using this attribute allows you to define an operation using a service description, but allows more customized logic to be implemented in user-land code." + "responseClass", "string", "Defined what is returned from the method. Can be a primitive, class name, or model name. You can specify the name of a class to return a more customized result from the operation (for example, a domain model object). When using the name of a PHP class, the class must implement ``Guzzle\Service\Command\ResponseClassInterface``." + "responseNotes", "string", "A description of the response returned by the operation" + "responseType", "string", "The type of response that the operation creates: one of primitive, class, model, or documentation. If not specified, this value will be automatically inferred based on whether or not there is a model matching the name, if a matching class name is found, or set to 'primitive' by default." + "deprecated", "boolean", "Whether or not the operation is deprecated" + "errorResponses", "array", "Errors that could occur while executing the operation. Each item of the array is an object that can contain a 'code' (HTTP response status code of the error), 'reason' (reason phrase or description of the error), and 'class' (an exception class that will be raised when this error is encountered)" + "data", "object", "Any arbitrary data to associate with the operation" + "parameters", "object containing :ref:`parameter-schema` objects", "Parameters of the operation. Parameters are used to define how input data is serialized into a HTTP request." + "additionalParameters", "A single :ref:`parameter-schema` object", "Validation and serialization rules for any parameter supplied to the operation that was not explicitly defined." + +additionalParameters +~~~~~~~~~~~~~~~~~~~~ + +When a webservice offers a large number of parameters that all are set in the same location (for example the query +string or a JSON document), defining each parameter individually can require a lot of time and repetition. Furthermore, +some web services allow for completely arbitrary parameters to be supplied for an operation. The +``additionalParameters`` attribute can be used to solve both of these issues. + +As an example, we can define a Twitter API operation quite easily using ``additionalParameters``. The +GetMentions operation accepts a large number of query string parameters. Defining each of these parameters +is ideal because it provide much more introspection for the client and opens the possibility to use the description with +other tools (e.g. a documentation generator). However, you can very quickly provide a "catch-all" serialization rule +that will place any custom parameters supplied to an operation the generated request's query string parameters. + +.. class:: overflow-height-250px + + .. code-block:: json + + { + "name": "Twitter", + "apiVersion": "1.1", + "baseUrl": "https://api.twitter.com/1.1", + "operations": { + "GetMentions": { + "httpMethod": "GET", + "uri": "statuses/mentions_timeline.json", + "responseClass": "GetMentionsOutput", + "additionalParameters": { + "location": "query" + } + } + }, + "models": { + "GetMentionsOutput": { + "type": "object", + "additionalProperties": { + "location": "json" + } + } + } + } + +responseClass +~~~~~~~~~~~~~ + +The ``responseClass`` attribute is used to define the return value of an operation (what is returned by calling the +``getResult()`` method of a command object). The value set in the responseClass attribute can be one of "primitive" +(meaning the result with be primitive type like a string), a class name meaning the result will be an instance of a +specific user-land class, or a model name meaning the result will be a ``Guzzle\Service\Resource\Model`` object that +uses a :ref:`model schema ` to define how the HTTP response is parsed. + +.. note:: + + Using a class name with a ``responseClass`` will only work if it is supported by the ``class`` that is instantiated + for the operation. Keep this in mind when specifying a custom ``class`` attribute that points to a custom + ``Guzzle\Service\Command\CommandInterface`` class. The default ``class``, + ``Guzzle\Service\Command\OperationCommand``, does support setting custom ``class`` attributes. + +You can specify the name of a class to return a more customized result from the operation (for example, a domain model +object). When using the name of a PHP class, the class must implement ``Guzzle\Service\Command\ResponseClassInterface``. +Here's a very simple example of implementing a custom responseClass object. + +.. code-block:: json + + { + "operations": { + "test": { + "responseClass": "MyApplication\\User" + } + } + } + +.. code-block:: php + + namespace MyApplication; + + use Guzzle\Service\Command\ResponseClassInterface; + use Guzzle\Service\Command\OperationCommand; + + class User implements ResponseClassInterface + { + protected $name; + + public static function fromCommand(OperationCommand $command) + { + $response = $command->getResponse(); + $xml = $response->xml(); + + return new self((string) $xml->name); + } + + public function __construct($name) + { + $this->name = $name; + } + } + +errorResponses +~~~~~~~~~~~~~~ + +``errorResponses`` is an array containing objects that define the errors that could occur while executing the +operation. Each item of the array is an object that can contain a 'code' (HTTP response status code of the error), +'reason' (reason phrase or description of the error), and 'class' (an exception class that will be raised when this +error is encountered). + +ErrorResponsePlugin +^^^^^^^^^^^^^^^^^^^ + +Error responses are by default only used for documentation. If you don't need very complex exception logic for your web +service errors, then you can use the ``Guzzle\Plugin\ErrorResponse\ErrorResponsePlugin`` to automatically throw defined +exceptions when one of the ``errorResponse`` rules are matched. The error response plugin will listen for the +``request.complete`` event of a request created by a command object. Every response (including a successful response) is +checked against the list of error responses for an exact match using the following order of checks: + +1. Does the errorResponse have a defined ``class``? +2. Is the errorResponse ``code`` equal to the status code of the response? +3. Is the errorResponse ``reason`` equal to the reason phrase of the response? +4. Throw the exception stored in the ``class`` attribute of the errorResponse. + +The ``class`` attribute must point to a class that implements +``Guzzle\Plugin\ErrorResponse\ErrorResponseExceptionInterface``. This interface requires that an error response class +implements ``public static function fromCommand(CommandInterface $command, Response $response)``. This method must +return an object that extends from ``\Exception``. After an exception is returned, it is thrown by the plugin. + +.. _parameter-schema: + +Parameter schema +---------------- + +Parameters in both operations and models are represented using the +`JSON schema `_ syntax. + +.. csv-table:: + :header: "Property Name", "Value", "Description" + :widths: 20, 15, 65 + + "name", "string", "Unique name of the parameter" + "type", "string|array", "Type of variable (string, number, integer, boolean, object, array, numeric, null, any). Types are using for validation and determining the structure of a parameter. You can use a union type by providing an array of simple types. If one of the union types matches the provided value, then the value is valid." + "instanceOf", "string", "When the type is an object, you can specify the class that the object must implement" + "required", "boolean", "Whether or not the parameter is required" + "default", "mixed", "Default value to use if no value is supplied" + "static", "boolean", "Set to true to specify that the parameter value cannot be changed from the default setting" + "description", "string", "Documentation of the parameter" + "location", "string", "The location of a request used to apply a parameter. Custom locations can be registered with a command, but the defaults are uri, query, statusCode, reasonPhrase, header, body, json, xml, postField, postFile, responseBody" + "sentAs", "string", "Specifies how the data being modeled is sent over the wire. For example, you may wish to include certain headers in a response model that have a normalized casing of FooBar, but the actual header is x-foo-bar. In this case, sentAs would be set to x-foo-bar." + "filters", "array", "Array of functions to to run a parameter value through." + +filters +~~~~~~~ + +Each value in the array must be a string containing the full class path to a static method or an array of complex +filter information. You can specify static methods of classes using the full namespace class name followed by +"::" (e.g. ``FooBar::baz()``). Some filters require arguments in order to properly filter a value. For complex filters, +use an object containing a ``method`` attribute pointing to a function, and an ``args`` attribute containing an +array of positional arguments to pass to the function. Arguments can contain keywords that are replaced when filtering +a value: ``@value`` is replaced with the value being filtered, and ``@api`` is replaced with the actual Parameter +object. + +.. code-block:: json + + { + "filters": [ + "strtolower", + { + "method": "MyClass::convertString", + "args": [ "test", "@value", "@api" ] + } + ] + } + +The above example will filter a parameter using ``strtolower``. It will then call the ``convertString`` static method +of ``MyClass``, passing in "test", the actual value of the parameter, and a ``Guzzle\Service\Description\Parameter`` +object. + +Operation parameter location attributes +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The location field of top-level parameters control how a parameter is serialized when generating a request. + +uri location +^^^^^^^^^^^^ + +Parameters are injected into the ``uri`` attribute of the operation using +`URI-template expansion `_. + +.. code-block:: json + + { + "operations": { + "uriTest": { + "uri": "/test/{testValue}", + "parameters": { + "testValue": { + "location": "uri" + } + } + } + } + } + +query location +^^^^^^^^^^^^^^ + +Parameters are injected into the query string of a request. Query values can be nested, which would result in a PHP +style nested query string. The name of a parameter is the default name of the query string parameter added to the +request. You can override this behavior by specifying the ``sentAs`` attribute on the parameter. + +.. code-block:: json + + { + "operations": { + "queryTest": { + "parameters": { + "testValue": { + "location": "query", + "sentAs": "test_value" + } + } + } + } + } + +header location +^^^^^^^^^^^^^^^ + +Parameters are injected as headers on an HTTP request. The name of the parameter is used as the name of the header by +default. You can change the name of the header created by the parameter using the ``sentAs`` attribute. + +Headers that are of type ``object`` will be added as multiple headers to a request using the key of the input array as +the header key. Setting a ``sentAs`` attribute along with a type ``object`` will use the value of ``sentAs`` as a +prefix for each header key. + +body location +^^^^^^^^^^^^^ + +Parameters are injected as the body of a request. The input of these parameters may be anything that can be cast to a +string or a ``Guzzle\Http\EntityBodyInterface`` object. + +postField location +^^^^^^^^^^^^^^^^^^ + +Parameters are inserted as POST fields in a request. Nested values may be supplied and will be represented using +PHP style nested query strings. The POST field name is the same as the parameter name by default. You can use the +``sentAs`` parameter to override the POST field name. + +postFile location +^^^^^^^^^^^^^^^^^ + +Parameters are added as POST files. A postFile value may be a string pointing to a local filename or a +``Guzzle\Http\Message\PostFileInterface`` object. The name of the POST file will be the name of the parameter by +default. You can use a custom POST file name by using the ``sentAs`` attribute. + +Supports "string" and "array" types. + +json location +^^^^^^^^^^^^^ + +Parameters are added to the body of a request as top level keys of a JSON document. Nested values may be specified, +with any number of nested ``Guzzle\Common\ToArrayInterface`` objects. When JSON parameters are specified, the +``Content-Type`` of the request will change to ``application/json`` if a ``Content-Type`` has not already been specified +on the request. + +xml location +^^^^^^^^^^^^ + +Parameters are added to the body of a request as top level nodes of an XML document. Nested values may be specified, +with any number of nested ``Guzzle\Common\ToArrayInterface`` objects. When XML parameters are specified, the +``Content-Type`` of the request will change to ``application/xml`` if a ``Content-Type`` has not already been specified +on the request. + +responseBody location +^^^^^^^^^^^^^^^^^^^^^ + +Specifies the EntityBody of a response. This can be used to download the response body to a file or a custom Guzzle +EntityBody object. + +No location +^^^^^^^^^^^ + +If a parameter has no location attribute, then the parameter is simply used as a data value. + +Other locations +^^^^^^^^^^^^^^^ + +Custom locations can be registered as new locations or override default locations if needed. + +.. _model-schema: + +Model Schema +------------ + +Models are used in service descriptions to provide generic JSON schema definitions that can be extended from or used in +``$ref`` attributes. Models can also be referenced in a ``responseClass`` attribute to provide valuable output to an +operation. Models are JSON schema documents and use the exact syntax and attributes used in parameters. + +Response Models +~~~~~~~~~~~~~~~ + +Response models describe how a response is parsed into a ``Guzzle\Service\Resource\Model`` object. Response models are +always modeled as JSON schema objects. When an HTTP response is parsed using a response model, the rules specified on +each property of a response model will translate 1:1 as keys in a PHP associative array. When a ``sentAs`` attribute is +found in response model parameters, the value retrieved from the HTTP response is retrieved using the ``sentAs`` +parameter but stored in the response model using the name of the parameter. + +The location field of top-level parameters in a response model tell response parsers how data is retrieved from a +response. + +statusCode location +^^^^^^^^^^^^^^^^^^^ + +Retrieves the status code of the response. + +reasonPhrase location +^^^^^^^^^^^^^^^^^^^^^ + +Retrieves the reason phrase of the response. + +header location +^^^^^^^^^^^^^^^ + +Retrieves a header from the HTTP response. + +body location +^^^^^^^^^^^^^ + +Retrieves the body of an HTTP response. + +json location +^^^^^^^^^^^^^ + +Retrieves a top-level parameter from a JSON document contained in an HTTP response. + +You can use ``additionalProperties`` if the JSON document is wrapped in an outer array. This allows you to parse the +contents of each item in the array using the parsing rules defined in the ``additionalProperties`` schema. + +xml location +^^^^^^^^^^^^ + +Retrieves a top-level node value from an XML document contained in an HTTP response. + +Other locations +^^^^^^^^^^^^^^^ + +Custom locations can be registered as new locations or override default locations if needed. + +Example service description +--------------------------- + +Let's say you're interacting with a web service called 'Foo' that allows for the following routes and methods:: + + GET/POST /users + GET/DELETE /users/:id + +The following JSON service description implements this simple web service: + +.. class:: overflow-height-500px + + .. code-block:: json + + { + "name": "Foo", + "apiVersion": "2012-10-14", + "baseUrl": "http://api.foo.com", + "description": "Foo is an API that allows you to Baz Bar", + "operations": { + "GetUsers": { + "httpMethod": "GET", + "uri": "/users", + "summary": "Gets a list of users", + "responseClass": "GetUsersOutput" + }, + "CreateUser": { + "httpMethod": "POST", + "uri": "/users", + "summary": "Creates a new user", + "responseClass": "CreateUserOutput", + "parameters": { + "name": { + "location": "json", + "type": "string" + }, + "age": { + "location": "json", + "type": "integer" + } + } + }, + "GetUser": { + "httpMethod": "GET", + "uri": "/users/{id}", + "summary": "Retrieves a single user", + "responseClass": "GetUserOutput", + "parameters": { + "id": { + "location": "uri", + "description": "User to retrieve by ID", + "required": true + } + } + }, + "DeleteUser": { + "httpMethod": "DELETE", + "uri": "/users/{id}", + "summary": "Deletes a user", + "responseClass": "DeleteUserOutput", + "parameters": { + "id": { + "location": "uri", + "description": "User to delete by ID", + "required": true + } + } + } + }, + "models": { + "GetUsersOutput": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "location": "json", + "type": "string" + }, + "age": { + "location": "json", + "type": "integer" + } + } + } + }, + "CreateUserOutput": { + "type": "object", + "properties": { + "id": { + "location": "json", + "type": "string" + }, + "location": { + "location": "header", + "sentAs": "Location", + "type": "string" + } + } + }, + "GetUserOutput": { + "type": "object", + "properties": { + "name": { + "location": "json", + "type": "string" + }, + "age": { + "location": "json", + "type": "integer" + } + } + }, + "DeleteUserOutput": { + "type": "object", + "properties": { + "status": { + "location": "statusCode", + "type": "integer" + } + } + } + } + } + +If you attach this service description to a client, you would completely configure the client to interact with the +Foo web service and provide valuable response models for each operation. + +.. code-block:: php + + use Guzzle\Service\Description\ServiceDescription; + + $description = ServiceDescription::factory('/path/to/client.json'); + $client->setDescription($description); + + $command = $client->getCommand('DeleteUser', array('id' => 123)); + $responseModel = $client->execute($command); + echo $responseModel['status']; + +.. note:: + + You can add the service description to your client's factory method or constructor. diff --git a/vendor/guzzle/guzzle/docs/webservice-client/using-the-service-builder.rst b/vendor/guzzle/guzzle/docs/webservice-client/using-the-service-builder.rst new file mode 100644 index 0000000..b7113d6 --- /dev/null +++ b/vendor/guzzle/guzzle/docs/webservice-client/using-the-service-builder.rst @@ -0,0 +1,316 @@ +======================= +Using a service builder +======================= + +The best way to instantiate Guzzle web service clients is to let Guzzle handle building the clients for you using a +ServiceBuilder. A ServiceBuilder is responsible for creating concrete client objects based on configuration settings +and helps to manage credentials for different environments. + +You don't have to use a service builder, but they help to decouple your application from concrete classes and help to +share configuration data across multiple clients. Consider the following example. Here we are creating two clients that +require the same API public key and secret key. The clients are created using their ``factory()`` methods. + +.. code-block:: php + + use MyService\FooClient; + use MyService\BarClient; + + $foo = FooClient::factory(array( + 'key' => 'abc', + 'secret' => '123', + 'custom' => 'and above all' + )); + + $bar = BarClient::factory(array( + 'key' => 'abc', + 'secret' => '123', + 'custom' => 'listen to me' + )); + +The redundant specification of the API keys can be removed using a service builder. + +.. code-block:: php + + use Guzzle\Service\Builder\ServiceBuilder; + + $builder = ServiceBuilder::factory(array( + 'services' => array( + 'abstract_client' => array( + 'params' => array( + 'key' => 'abc', + 'secret' => '123' + ) + ), + 'foo' => array( + 'extends' => 'abstract_client', + 'class' => 'MyService\FooClient', + 'params' => array( + 'custom' => 'and above all' + ) + ), + 'bar' => array( + 'extends' => 'abstract_client', + 'class' => 'MyService\FooClient', + 'params' => array( + 'custom' => 'listen to me' + ) + ) + ) + )); + + $foo = $builder->get('foo'); + $bar = $builder->get('bar'); + +You can make managing your API keys even easier by saving the service builder configuration in a JSON format in a +.json file. + +Creating a service builder +-------------------------- + +A ServiceBuilder can source information from an array, an PHP include file that returns an array, or a JSON file. + +.. code-block:: php + + use Guzzle\Service\Builder\ServiceBuilder; + + // Source service definitions from a JSON file + $builder = ServiceBuilder::factory('services.json'); + +Sourcing data from an array +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Data can be source from a PHP array. The array must contain an associative ``services`` array that maps the name of a +client to the configuration information used by the service builder to create the client. Clients are given names +which are used to identify how a client is retrieved from a service builder. This can be useful for using multiple +accounts for the same service or creating development clients vs. production clients. + +.. code-block:: php + + $services = array( + 'includes' => array( + '/path/to/other/services.json', + '/path/to/other/php_services.php' + ), + 'services' => array( + 'abstract.foo' => array( + 'params' => array( + 'username' => 'foo', + 'password' => 'bar' + ) + ), + 'bar' => array( + 'extends' => 'abstract.foo', + 'class' => 'MyClientClass', + 'params' => array( + 'other' => 'abc' + ) + ) + ) + ); + +A service builder configuration array contains two top-level array keys: + ++------------+---------------------------------------------------------------------------------------------------------+ +| Key | Description | ++============+=========================================================================================================+ +| includes | Array of paths to JSON or PHP include files to include in the configuration. | ++------------+---------------------------------------------------------------------------------------------------------+ +| services | Associative array of defined services that can be created by the service builder. Each service can | +| | contain the following keys: | +| | | +| | +------------+----------------------------------------------------------------------------------------+ | +| | | Key | Description | | +| | +============+========================================================================================+ | +| | | class | The concrete class to instantiate that implements the | | +| | | | ``Guzzle\Common\FromConfigInterface``. | | +| | +------------+----------------------------------------------------------------------------------------+ | +| | | extends | The name of a previously defined service to extend from | | +| | +------------+----------------------------------------------------------------------------------------+ | +| | | params | Associative array of parameters to pass to the factory method of the service it is | | +| | | | instantiated | | +| | +------------+----------------------------------------------------------------------------------------+ | +| | | alias | An alias that can be used in addition to the array key for retrieving a client from | | +| | | | the service builder. | | +| | +------------+----------------------------------------------------------------------------------------+ | ++------------+---------------------------------------------------------------------------------------------------------+ + +The first client defined, ``abstract.foo``, is used as a placeholder of shared configuration values. Any service +extending abstract.foo will inherit its params. As an example, this can be useful when clients share the same username +and password. + +The next client, ``bar``, extends from ``abstract.foo`` using the ``extends`` attribute referencing the client from +which to extend. Additional parameters can be merged into the original service definition when extending a parent +service. + +.. important:: + + Each client that you intend to instantiate must specify a ``class`` attribute that references the full class name + of the client being created. The class referenced in the ``class`` parameter must implement a static ``factory()`` + method that accepts an array or ``Guzzle\Common\Collection`` object and returns an instantiated object. + +Sourcing from a PHP include +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +You can create service builder configurations using a PHP include file. This can be useful if you wish to take +advantage of an opcode cache like APC to speed up the process of loading and processing the configuration. The PHP +include file is the same format as an array, but you simply create a PHP script that returns an array and save the +file with the .php file extension. + +.. code-block:: php + + '...'); + // Saved as config.php + +This configuration file can then be used with a service builder. + +.. code-block:: php + + $builder = ServiceBuilder::factory('/path/to/config.php'); + +Sourcing from a JSON document +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +You can use JSON documents to serialize your service descriptions. The JSON format uses the exact same structure as +the PHP array syntax, but it's just serialized using JSON. + +.. code-block:: javascript + + { + "includes": ["/path/to/other/services.json", "/path/to/other/php_services.php"], + "services": { + "abstract.foo": { + "params": { + "username": "foo", + "password": "bar" + } + }, + "bar": { + "extends": "abstract.foo", + "class": "MyClientClass", + "params": { + "other": "abc" + } + } + } + } + +Referencing other clients in parameters +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +If one of your clients depends on another client as one of its parameters, you can reference that client by name by +enclosing the client's reference key in ``{}``. + +.. code-block:: javascript + + { + "services": { + "token": { + "class": "My\Token\TokenFactory", + "params": { + "access_key": "xyz" + } + }, + "client": { + "class": "My\Client", + "params": { + "token_client": "{token}", + "version": "1.0" + } + } + } + } + +When ``client`` is constructed by the service builder, the service builder will first create the ``token`` service +and then inject the token service into ``client``'s factory method in the ``token_client`` parameter. + +Retrieving clients from a service builder +----------------------------------------- + +Clients are referenced using a customizable name you provide in your service definition. The ServiceBuilder is a sort +of multiton object-- it will only instantiate a client once and return that client for subsequent retrievals. Clients +are retrieved by name (the array key used in the configuration) or by the ``alias`` setting of a service. + +Here's an example of retrieving a client from your ServiceBuilder: + +.. code-block:: php + + $client = $builder->get('foo'); + + // You can also use the ServiceBuilder object as an array + $client = $builder['foo']; + +Creating throwaway clients +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +You can get a "throwaway" client (a client that is not persisted by the ServiceBuilder) by passing ``true`` in the +second argument of ``ServiceBuilder::get()``. This allows you to create a client that will not be returned by other +parts of your code that use the service builder. Instead of passing ``true``, you can pass an array of configuration +settings that will override the configuration settings specified in the service builder. + +.. code-block:: php + + // Get a throwaway client and overwrite the "custom" setting of the client + $foo = $builder->get('foo', array( + 'custom' => 'in this world there are rules' + )); + +Getting raw configuration settings +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +You can get the raw configuration settings provided to the service builder for a specific service using the +``getData($name)`` method of a service builder. This method will null if the service was not found in the service +builder or an array of configuration settings if the service was found. + +.. code-block:: php + + $data = $builder->getData('foo'); + echo $data['key'] . "\n"; + echo $data['secret'] . "\n"; + echo $data['custom'] . "\n"; + +Adding a plugin to all clients +------------------------------ + +You can add a plugin to all clients created by a service builder using the ``addGlobalPlugin($plugin)`` method of a +service builder and passing a ``Symfony\Component\EventDispatcher\EventSubscriberInterface`` object. The service builder +will then attach each global plugin to every client as it is created. This allows you to, for example, add a LogPlugin +to every request created by a service builder for easy debugging. + +.. code-block:: php + + use Guzzle\Plugin\Log\LogPlugin; + + // Add a debug log plugin to every client as it is created + $builder->addGlobalPlugin(LogPlugin::getDebugPlugin()); + + $foo = $builder->get('foo'); + $foo->get('/')->send(); + // Should output all of the data sent over the wire + +.. _service-builder-events: + +Events emitted from a service builder +------------------------------------- + +A ``Guzzle\Service\Builder\ServiceBuilder`` object emits the following events: + ++-------------------------------+--------------------------------------------+-----------------------------------------+ +| Event name | Description | Event data | ++===============================+============================================+=========================================+ +| service_builder.create_client | Called when a client is created | * client: The created client object | ++-------------------------------+--------------------------------------------+-----------------------------------------+ + +.. code-block:: php + + use Guzzle\Common\Event; + use Guzzle\Service\Builder\ServiceBuilder; + + $builder = ServiceBuilder::factory('/path/to/config.json'); + + // Add an event listener to print out each client client as it is created + $builder->getEventDispatcher()->addListener('service_builder.create_client', function (Event $e) { + echo 'Client created: ' . get_class($e['client']) . "\n"; + }); + + $foo = $builder->get('foo'); + // Should output the class used for the "foo" client diff --git a/vendor/guzzle/guzzle/docs/webservice-client/webservice-client.rst b/vendor/guzzle/guzzle/docs/webservice-client/webservice-client.rst new file mode 100644 index 0000000..7ec771e --- /dev/null +++ b/vendor/guzzle/guzzle/docs/webservice-client/webservice-client.rst @@ -0,0 +1,659 @@ +====================== +The web service client +====================== + +The ``Guzzle\Service`` namespace contains various abstractions that help to make it easier to interact with a web +service API, including commands, service descriptions, and resource iterators. + +In this chapter, we'll build a simple `Twitter API client `_. + +Creating a client +================= + +A class that extends from ``Guzzle\Service\Client`` or implements ``Guzzle\Service\ClientInterface`` must implement a +``factory()`` method in order to be used with a :doc:`service builder `. + +Factory method +-------------- + +You can use the ``factory()`` method of a client directly if you do not need a service builder. + +.. code-block:: php + + use mtdowling\TwitterClient; + + // Create a client and pass an array of configuration data + $twitter = TwitterClient::factory(array( + 'consumer_key' => '****', + 'consumer_secret' => '****', + 'token' => '****', + 'token_secret' => '****' + )); + +.. note:: + + If you'd like to follow along, here's how to get your Twitter API credentials: + + 1. Visit https://dev.twitter.com/apps + 2. Click on an application that you've created + 3. Click on the "OAuth tool" tab + 4. Copy all of the settings under "OAuth Settings" + +Implementing a factory method +----------------------------- + +Creating a client and its factory method is pretty simple. You just need to implement ``Guzzle\Service\ClientInterface`` +or extend from ``Guzzle\Service\Client``. + +.. code-block:: php + + namespace mtdowling; + + use Guzzle\Common\Collection; + use Guzzle\Plugin\Oauth\OauthPlugin; + use Guzzle\Service\Client; + use Guzzle\Service\Description\ServiceDescription; + + /** + * A simple Twitter API client + */ + class TwitterClient extends Client + { + public static function factory($config = array()) + { + // Provide a hash of default client configuration options + $default = array('base_url' => 'https://api.twitter.com/1.1'); + + // The following values are required when creating the client + $required = array( + 'base_url', + 'consumer_key', + 'consumer_secret', + 'token', + 'token_secret' + ); + + // Merge in default settings and validate the config + $config = Collection::fromConfig($config, $default, $required); + + // Create a new Twitter client + $client = new self($config->get('base_url'), $config); + + // Ensure that the OauthPlugin is attached to the client + $client->addSubscriber(new OauthPlugin($config->toArray())); + + return $client; + } + } + +Service Builder +--------------- + +A service builder is used to easily create web service clients, provides a simple configuration driven approach to +creating clients, and allows you to share configuration settings across multiple clients. You can find out more about +Guzzle's service builder in :doc:`using-the-service-builder`. + +.. code-block:: php + + use Guzzle\Service\Builder\ServiceBuilder; + + // Create a service builder and provide client configuration data + $builder = ServiceBuilder::factory('/path/to/client_config.json'); + + // Get the client from the service builder by name + $twitter = $builder->get('twitter'); + +The above example assumes you have JSON data similar to the following stored in "/path/to/client_config.json": + +.. code-block:: json + + { + "services": { + "twitter": { + "class": "mtdowling\\TwitterClient", + "params": { + "consumer_key": "****", + "consumer_secret": "****", + "token": "****", + "token_secret": "****" + } + } + } + } + +.. note:: + + A service builder becomes much more valuable when using multiple web service clients in a single application or + if you need to utilize the same client with varying configuration settings (e.g. multiple accounts). + +Commands +======== + +Commands are a concept in Guzzle that helps to hide the underlying implementation of an API by providing an easy to use +parameter driven object for each action of an API. A command is responsible for accepting an array of configuration +parameters, serializing an HTTP request, and parsing an HTTP response. Following the +`command pattern `_, commands in Guzzle offer a greater level of +flexibility when implementing and utilizing a web service client. + +Executing commands +------------------ + +You must explicitly execute a command after creating a command using the ``getCommand()`` method. A command has an +``execute()`` method that may be called, or you can use the ``execute()`` method of a client object and pass in the +command object. Calling either of these execute methods will return the result value of the command. The result value is +the result of parsing the HTTP response with the ``process()`` method. + +.. code-block:: php + + // Get a command from the client and pass an array of parameters + $command = $twitter->getCommand('getMentions', array( + 'count' => 5 + )); + + // Other parameters can be set on the command after it is created + $command['trim_user'] = false; + + // Execute the command using the command object. + // The result value contains an array of JSON data from the response + $result = $command->execute(); + + // You can retrieve the result of the command later too + $result = $command->getResult(). + +Command object also contains methods that allow you to inspect the HTTP request and response that was utilized with +the command. + +.. code-block:: php + + $request = $command->getRequest(); + $response = $command->getResponse(); + +.. note:: + + The format and notation used to retrieve commands from a client can be customized by injecting a custom command + factory, ``Guzzle\Service\Command\Factory\FactoryInterface``, on the client using ``$client->setCommandFactory()``. + +Executing with magic methods +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +When using method missing magic methods with a command, the command will be executed right away and the result of the +command is returned. + +.. code-block:: php + + $jsonData = $twitter->getMentions(array( + 'count' => 5, + 'trim_user' => true + )); + +Creating commands +----------------- + +Commands are created using either the ``getCommand()`` method of a client or a magic missing method of a client. Using +the ``getCommand()`` method allows you to create a command without executing it, allowing for customization of the +command or the request serialized by the command. + +When a client attempts to create a command, it uses the client's ``Guzzle\Service\Command\Factory\FactoryInterface``. +By default, Guzzle will utilize a command factory that first looks for a concrete class for a particular command +(concrete commands) followed by a command defined by a service description (operation commands). We'll learn more about +concrete commands and operation commands later in this chapter. + +.. code-block:: php + + // Get a command from the twitter client. + $command = $twitter->getCommand('getMentions'); + $result = $command->execute(); + +Unless you've skipped ahead, running the above code will throw an exception. + + PHP Fatal error: Uncaught exception 'Guzzle\Common\Exception\InvalidArgumentException' with message + 'Command was not found matching getMentions' + +This exception was thrown because the "getMentions" command has not yet been implemented. Let's implement one now. + +Concrete commands +~~~~~~~~~~~~~~~~~ + +Commands can be created in one of two ways: create a concrete command class that extends +``Guzzle\Service\Command\AbstractCommand`` or +:doc:`create an OperationCommand based on a service description `. The recommended +approach is to use a service description to define your web service, but you can use concrete commands when custom +logic must be implemented for marshaling or unmarshaling a HTTP message. + +Commands are the method in which you abstract away the underlying format of the requests that need to be sent to take +action on a web service. Commands in Guzzle are meant to be built by executing a series of setter methods on a command +object. Commands are only validated right before they are executed. A ``Guzzle\Service\Client`` object is responsible +for executing commands. Commands created for your web service must implement +``Guzzle\Service\Command\CommandInterface``, but it's easier to extend the ``Guzzle\Service\Command\AbstractCommand`` +class, implement the ``build()`` method, and optionally implement the ``process()`` method. + +Serializing requests +^^^^^^^^^^^^^^^^^^^^ + +The ``build()`` method of a command is responsible for using the arguments of the command to build and serialize a +HTTP request and set the request on the ``$request`` property of the command object. This step is usually taken care of +for you when using a service description driven command that uses the default +``Guzzle\Service\Command\OperationCommand``. You may wish to implement the process method yourself when you aren't +using a service description or need to implement more complex request serialization. + +.. important:::: + + When implementing a custom ``build()`` method, be sure to set the class property of ``$this->request`` to an + instantiated and ready to send request. + +The following example shows how to implement the ``getMentions`` +`Twitter API `_ method using a concrete command. + +.. code-block:: php + + namespace mtdowling\Twitter\Command; + + use Guzzle\Service\Command\AbstractCommand; + + class GetMentions extends AbstractCommand + { + protected function build() + { + // Create the request property of the command + $this->request = $this->client->get('statuses/mentions_timeline.json'); + + // Grab the query object of the request because we will use it for + // serializing command parameters on the request + $query = $this->request->getQuery(); + + if ($this['count']) { + $query->set('count', $this['count']); + } + + if ($this['since_id']) { + $query->set('since_id', $this['since_id']); + } + + if ($this['max_id']) { + $query->set('max_id', $this['max_id']); + } + + if ($this['trim_user'] !== null) { + $query->set('trim_user', $this['trim_user'] ? 'true' : 'false'); + } + + if ($this['contributor_details'] !== null) { + $query->set('contributor_details', $this['contributor_details'] ? 'true' : 'false'); + } + + if ($this['include_entities'] !== null) { + $query->set('include_entities', $this['include_entities'] ? 'true' : 'false'); + } + } + } + +By default, a client will attempt to find concrete command classes under the ``Command`` namespace of a client. First +the client will attempt to find an exact match for the name of the command to the name of the command class. If an +exact match is not found, the client will calculate a class name using inflection. This is calculated based on the +folder hierarchy of a command and converting the CamelCased named commands into snake_case. Here are some examples on +how the command names are calculated: + +#. ``Foo\Command\JarJar`` **->** jar_jar +#. ``Foo\Command\Test`` **->** test +#. ``Foo\Command\People\GetCurrentPerson`` **->** people.get_current_person + +Notice how any sub-namespace beneath ``Command`` is converted from ``\`` to ``.`` (a period). CamelCasing is converted +to lowercased snake_casing (e.g. JarJar == jar_jar). + +Parsing responses +^^^^^^^^^^^^^^^^^ + +The ``process()`` method of a command is responsible for converting an HTTP response into something more useful. For +example, a service description operation that has specified a model object in the ``responseClass`` attribute of the +operation will set a ``Guzzle\Service\Resource\Model`` object as the result of the command. This behavior can be +completely modified as needed-- even if you are using operations and responseClass models. Simply implement a custom +``process()`` method that sets the ``$this->result`` class property to whatever you choose. You can reuse parts of the +default Guzzle response parsing functionality or get inspiration from existing code by using +``Guzzle\Service\Command\OperationResponseParser`` and ``Guzzle\Service\Command\DefaultResponseParser`` classes. + +If you do not implement a custom ``process()`` method and are not using a service description, then Guzzle will attempt +to guess how a response should be processed based on the Content-Type header of the response. Because the Twitter API +sets a ``Content-Type: application/json`` header on this response, we do not need to implement any custom response +parsing. + +Operation commands +~~~~~~~~~~~~~~~~~~ + +Operation commands are commands in which the serialization of an HTTP request and the parsing of an HTTP response are +driven by a Guzzle service description. Because request serialization, validation, and response parsing are +described using a DSL, creating operation commands is a much faster process than writing concrete commands. + +Creating operation commands for our Twitter client can remove a great deal of redundancy from the previous concrete +command, and allows for a deeper runtime introspection of the API. Here's an example service description we can use to +create the Twitter API client: + +.. code-block:: json + + { + "name": "Twitter", + "apiVersion": "1.1", + "baseUrl": "https://api.twitter.com/1.1", + "description": "Twitter REST API client", + "operations": { + "GetMentions": { + "httpMethod": "GET", + "uri": "statuses/mentions_timeline.json", + "summary": "Returns the 20 most recent mentions for the authenticating user.", + "responseClass": "GetMentionsOutput", + "parameters": { + "count": { + "description": "Specifies the number of tweets to try and retrieve", + "type": "integer", + "location": "query" + }, + "since_id": { + "description": "Returns results with an ID greater than the specified ID", + "type": "integer", + "location": "query" + }, + "max_id": { + "description": "Returns results with an ID less than or equal to the specified ID.", + "type": "integer", + "location": "query" + }, + "trim_user": { + "description": "Limits the amount of data returned for each user", + "type": "boolean", + "location": "query" + }, + "contributor_details": { + "description": "Adds more data to contributor elements", + "type": "boolean", + "location": "query" + }, + "include_entities": { + "description": "The entities node will be disincluded when set to false.", + "type": "boolean", + "location": "query" + } + } + } + }, + "models": { + "GetMentionsOutput": { + "type": "object", + "additionalProperties": { + "location": "json" + } + } + } + } + +If you're lazy, you can define the API in a less descriptive manner using ``additionalParameters``. +``additionalParameters`` define the serialization and validation rules of parameters that are not explicitly defined +in a service description. + +.. code-block:: json + + { + "name": "Twitter", + "apiVersion": "1.1", + "baseUrl": "https://api.twitter.com/1.1", + "description": "Twitter REST API client", + "operations": { + "GetMentions": { + "httpMethod": "GET", + "uri": "statuses/mentions_timeline.json", + "summary": "Returns the 20 most recent mentions for the authenticating user.", + "responseClass": "GetMentionsOutput", + "additionalParameters": { + "location": "query" + } + } + }, + "models": { + "GetMentionsOutput": { + "type": "object", + "additionalProperties": { + "location": "json" + } + } + } + } + +You should attach the service description to the client at the end of the client's factory method: + +.. code-block:: php + + // ... + class TwitterClient extends Client + { + public static function factory($config = array()) + { + // ... same code as before ... + + // Set the service description + $client->setDescription(ServiceDescription::factory('path/to/twitter.json')); + + return $client; + } + } + +The client can now use operations defined in the service description instead of requiring you to create concrete +command classes. Feel free to delete the concrete command class we created earlier. + +.. code-block:: php + + $jsonData = $twitter->getMentions(array( + 'count' => 5, + 'trim_user' => true + )); + +Executing commands in parallel +------------------------------ + +Much like HTTP requests, Guzzle allows you to send multiple commands in parallel. You can send commands in parallel by +passing an array of command objects to a client's ``execute()`` method. The client will serialize each request and +send them all in parallel. If an error is encountered during the transfer, then a +``Guzzle\Service\Exception\CommandTransferException`` is thrown, which allows you to retrieve a list of commands that +succeeded and a list of commands that failed. + +.. code-block:: php + + use Guzzle\Service\Exception\CommandTransferException; + + $commands = array(); + $commands[] = $twitter->getCommand('getMentions'); + $commands[] = $twitter->getCommand('otherCommandName'); + // etc... + + try { + $result = $client->execute($commands); + foreach ($result as $command) { + echo $command->getName() . ': ' . $command->getResponse()->getStatusCode() . "\n"; + } + } catch (CommandTransferException $e) { + // Get an array of the commands that succeeded + foreach ($e->getSuccessfulCommands() as $command) { + echo $command->getName() . " succeeded\n"; + } + // Get an array of the commands that failed + foreach ($e->getFailedCommands() as $command) { + echo $command->getName() . " failed\n"; + } + } + +.. note:: + + All commands executed from a client using an array must originate from the same client. + +Special command options +----------------------- + +Guzzle exposes several options that help to control how commands are validated, serialized, and parsed. +Command options can be specified when creating a command or in the ``command.params`` parameter in the +``Guzzle\Service\Client``. + +=========================== ============================================================================================ +command.request_options Option used to add :ref:`Request options ` to the request created by a + command +command.hidden_params An array of the names of parameters ignored by the ``additionalParameters`` parameter schema +command.disable_validation Set to true to disable JSON schema validation of the command's input parameters +command.response_processing Determines how the default response parser will parse the command. One of "raw" no parsing, + "model" (the default method used to parse commands using response models defined in service + descriptions) +command.headers (deprecated) Option used to specify custom headers. Use ``command.request_options`` instead +command.on_complete (deprecated) Option used to add an onComplete method to a command. Use + ``command.after_send`` event instead +command.response_body (deprecated) Option used to change the entity body used to store a response. + Use ``command.request_options`` instead +=========================== ============================================================================================ + +Advanced client configuration +============================= + +Default command parameters +-------------------------- + +When creating a client object, you can specify default command parameters to pass into all commands. Any key value pair +present in the ``command.params`` settings of a client will be added as default parameters to any command created +by the client. + +.. code-block:: php + + $client = new Guzzle\Service\Client(array( + 'command.params' => array( + 'default_1' => 'foo', + 'another' => 'bar' + ) + )); + +Magic methods +------------- + +Client objects will, by default, attempt to create and execute commands when a missing method is invoked on a client. +This powerful concept applies to both concrete commands and operation commands powered by a service description. This +makes it appear to the end user that you have defined actual methods on a client object, when in fact, the methods are +invoked using PHP's magic ``__call`` method. + +The ``__call`` method uses the ``getCommand()`` method of a client, which uses the client's internal +``Guzzle\Service\Command\Factory\FactoryInterface`` object. The default command factory allows you to instantiate +operations defined in a client's service description. The method in which a client determines which command to +execute is defined as follows: + +1. The client will first try to find a literal match for an operation in the service description. +2. If the literal match is not found, the client will try to uppercase the first character of the operation and find + the match again. +3. If a match is still not found, the command factory will inflect the method name from CamelCase to snake_case and + attempt to find a matching command. +4. If a command still does not match, an exception is thrown. + +.. code-block:: php + + // Use the magic method + $result = $twitter->getMentions(); + + // This is exactly the same as: + $result = $twitter->getCommand('getMentions')->execute(); + +You can disable magic methods on a client by passing ``false`` to the ``enableMagicMethod()`` method. + +Custom command factory +---------------------- + +A client by default uses the ``Guzzle\Service\Command\Factory\CompositeFactory`` which allows multiple command +factories to attempt to create a command by a certain name. The default CompositeFactory uses a ``ConcreteClassFactory`` +and a ``ServiceDescriptionFactory`` if a service description is specified on a client. You can specify a custom +command factory if your client requires custom command creation logic using the ``setCommandFactory()`` method of +a client. + +Custom resource Iterator factory +-------------------------------- + +Resource iterators can be retrieved from a client using the ``getIterator($name)`` method of a client. This method uses +a client's internal ``Guzzle\Service\Resource\ResourceIteratorFactoryInterface`` object. A client by default uses a +``Guzzle\Service\Resource\ResourceIteratorClassFactory`` to attempt to find concrete classes that implement resource +iterators. The default factory will first look for matching iterators in the ``Iterator`` subdirectory of the client +followed by the ``Model`` subdirectory of a client. Use the ``setResourceIteratorFactory()`` method of a client to +specify a custom resource iterator factory. + +Plugins and events +================== + +``Guzzle\Service\Client`` exposes various events that allow you to hook in custom logic. A client object owns a +``Symfony\Component\EventDispatcher\EventDispatcher`` object that can be accessed by calling +``$client->getEventDispatcher()``. You can use the event dispatcher to add listeners (a simple callback function) or +event subscribers (classes that listen to specific events of a dispatcher). + +.. _service-client-events: + +Events emitted from a Service Client +------------------------------------ + +A ``Guzzle\Service\Client`` object emits the following events: + ++------------------------------+--------------------------------------------+------------------------------------------+ +| Event name | Description | Event data | ++==============================+============================================+==========================================+ +| client.command.create | The client created a command object | * client: Client object | +| | | * command: Command object | ++------------------------------+--------------------------------------------+------------------------------------------+ +| command.before_prepare | Before a command is validated and built. | * command: Command being prepared | +| | This is also before a request is created. | | ++------------------------------+--------------------------------------------+------------------------------------------+ +| command.after_prepare | After a command instantiates and | * command: Command that was prepared | +| | configures its request object. | | ++------------------------------+--------------------------------------------+------------------------------------------+ +| command.before_send | The client is about to execute a prepared | * command: Command to execute | +| | command | | ++------------------------------+--------------------------------------------+------------------------------------------+ +| command.after_send | The client successfully completed | * command: The command that was executed | +| | executing a command | | ++------------------------------+--------------------------------------------+------------------------------------------+ +| command.parse_response | Called when ``responseType`` is ``class`` | * command: The command with a response | +| | and the response is about to be parsed. | about to be parsed. | ++------------------------------+--------------------------------------------+------------------------------------------+ + +.. code-block:: php + + use Guzzle\Common\Event; + use Guzzle\Service\Client; + + $client = new Client(); + + // create an event listener that operates on request objects + $client->getEventDispatcher()->addListener('command.after_prepare', function (Event $event) { + $command = $event['command']; + $request = $command->getRequest(); + + // do something with request + }); + +.. code-block:: php + + use Guzzle\Common\Event; + use Guzzle\Common\Client; + use Symfony\Component\EventDispatcher\EventSubscriberInterface; + + class EventSubscriber implements EventSubscriberInterface + { + public static function getSubscribedEvents() + { + return array( + 'client.command.create' => 'onCommandCreate', + 'command.parse_response' => 'onParseResponse' + ); + } + + public function onCommandCreate(Event $event) + { + $client = $event['client']; + $command = $event['command']; + // operate on client and command + } + + public function onParseResponse(Event $event) + { + $command = $event['command']; + // operate on the command + } + } + + $client = new Client(); + + $client->addSubscriber(new EventSubscriber()); diff --git a/vendor/guzzle/guzzle/phar-stub.php b/vendor/guzzle/guzzle/phar-stub.php new file mode 100644 index 0000000..cc2b53f --- /dev/null +++ b/vendor/guzzle/guzzle/phar-stub.php @@ -0,0 +1,16 @@ +registerNamespaces(array( + 'Guzzle' => 'phar://guzzle.phar/src', + 'Symfony\\Component\\EventDispatcher' => 'phar://guzzle.phar/vendor/symfony/event-dispatcher', + 'Doctrine' => 'phar://guzzle.phar/vendor/doctrine/common/lib', + 'Monolog' => 'phar://guzzle.phar/vendor/monolog/monolog/src' +)); +$classLoader->register(); + +__HALT_COMPILER(); diff --git a/vendor/guzzle/guzzle/phing/build.properties.dist b/vendor/guzzle/guzzle/phing/build.properties.dist new file mode 100644 index 0000000..c60d3d9 --- /dev/null +++ b/vendor/guzzle/guzzle/phing/build.properties.dist @@ -0,0 +1,16 @@ +# you may need to update this if you're working on a fork. +guzzle.remote=git@github.com:guzzle/guzzle.git + +# github credentials -- only used by GitHub API calls to create subtree repos +github.basicauth=username:password +# for the subtree split and testing +github.org=guzzle + +# your git path +cmd.git=git + +# your composer command +cmd.composer=composer + +# test server start +cmd.testserver=node diff --git a/vendor/guzzle/guzzle/phing/imports/dependencies.xml b/vendor/guzzle/guzzle/phing/imports/dependencies.xml new file mode 100644 index 0000000..e40e037 --- /dev/null +++ b/vendor/guzzle/guzzle/phing/imports/dependencies.xml @@ -0,0 +1,33 @@ + + + + + + + + + + + + + + + + + using git at ${cmd.git} + + + + found git at ${cmd.git} + + + + + + + + + + diff --git a/vendor/guzzle/guzzle/phing/imports/deploy.xml b/vendor/guzzle/guzzle/phing/imports/deploy.xml new file mode 100644 index 0000000..109e5ec --- /dev/null +++ b/vendor/guzzle/guzzle/phing/imports/deploy.xml @@ -0,0 +1,142 @@ + + + + + + + + + + + + On branch ${head} + + + + + + + + + + working directory clean + + + ${git.status} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ChangeLog Match: ${version.changelog} + Guzzle\Common\Version Match: ${version.version} + + + + releasing: phing -Dnew.version=3.0.x -Dhead=master release + -- + + + + + + + + + + + + + + + BEGINNING RELEASE FOR ${new.version} + + + + + + + + + + + + + + + + + + + + + + + + Tip: to create a new release, do: phing -Dnew.version=[TAG] -Dhead=[BRANCH] release + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vendor/guzzle/guzzle/phing/tasks/ComposerLintTask.php b/vendor/guzzle/guzzle/phing/tasks/ComposerLintTask.php new file mode 100644 index 0000000..3b70409 --- /dev/null +++ b/vendor/guzzle/guzzle/phing/tasks/ComposerLintTask.php @@ -0,0 +1,152 @@ + + * @license http://claylo.mit-license.org/2012/ MIT License + */ + +require_once 'phing/Task.php'; + +class ComposerLintTask extends Task +{ + protected $dir = null; + protected $file = null; + protected $passthru = false; + protected $composer = null; + + /** + * The setter for the dir + * + * @param string $str Directory to crawl recursively for composer files + */ + public function setDir($str) + { + $this->dir = $str; + } + + /** + * The setter for the file + * + * @param string $str Individual file to validate + */ + public function setFile($str) + { + $this->file = $str; + } + + /** + * Whether to use PHP's passthru() function instead of exec() + * + * @param boolean $passthru If passthru shall be used + */ + public function setPassthru($passthru) + { + $this->passthru = (bool) $passthru; + } + + /** + * Composer to execute. If unset, will attempt composer.phar in project + * basedir, and if that fails, will attempt global composer + * installation. + * + * @param string $str Individual file to validate + */ + public function setComposer($str) + { + $this->file = $str; + } + + /** + * The init method: do init steps + */ + public function init() + { + // nothing needed here + } + + /** + * The main entry point + */ + public function main() + { + if ($this->composer === null) { + $this->findComposer(); + } + + $files = array(); + if (!empty($this->file) && file_exists($this->file)) { + $files[] = $this->file; + } + + if (!empty($this->dir)) { + $found = $this->findFiles(); + foreach ($found as $file) { + $files[] = $this->dir . DIRECTORY_SEPARATOR . $file; + } + } + + foreach ($files as $file) { + + $cmd = $this->composer . ' validate ' . $file; + $cmd = escapeshellcmd($cmd); + + if ($this->passthru) { + $retval = null; + passthru($cmd, $retval); + if ($retval == 1) { + throw new BuildException('invalid composer.json'); + } + } else { + $out = array(); + $retval = null; + exec($cmd, $out, $retval); + if ($retval == 1) { + $err = join("\n", $out); + throw new BuildException($err); + } else { + $this->log($out[0]); + } + } + + } + + } + + /** + * Find the composer.json files using Phing's directory scanner + * + * @return array + */ + protected function findFiles() + { + $ds = new DirectoryScanner(); + $ds->setBasedir($this->dir); + $ds->setIncludes(array('**/composer.json')); + $ds->scan(); + return $ds->getIncludedFiles(); + } + + /** + * Find composer installation + * + */ + protected function findComposer() + { + $basedir = $this->project->getBasedir(); + $php = $this->project->getProperty('php.interpreter'); + + if (file_exists($basedir . '/composer.phar')) { + $this->composer = "$php $basedir/composer.phar"; + } else { + $out = array(); + exec('which composer', $out); + if (empty($out)) { + throw new BuildException( + 'Could not determine composer location.' + ); + } + $this->composer = $out[0]; + } + } +} diff --git a/vendor/guzzle/guzzle/phing/tasks/GuzzlePearPharPackageTask.php b/vendor/guzzle/guzzle/phing/tasks/GuzzlePearPharPackageTask.php new file mode 100644 index 0000000..f72a6b5 --- /dev/null +++ b/vendor/guzzle/guzzle/phing/tasks/GuzzlePearPharPackageTask.php @@ -0,0 +1,338 @@ + + * @license http://claylo.mit-license.org/2012/ MIT License + */ + +require_once 'phing/Task.php'; +require_once 'PEAR/PackageFileManager2.php'; +require_once 'PEAR/PackageFileManager/File.php'; +require_once 'PEAR/Packager.php'; + +class GuzzlePearPharPackageTask extends Task +{ + private $version; + private $deploy = true; + private $makephar = true; + + private $subpackages = array(); + + public function setVersion($str) + { + $this->version = $str; + } + + public function getVersion() + { + return $this->version; + } + + public function setDeploy($deploy) + { + $this->deploy = (bool) $deploy; + } + + public function getDeploy() + { + return $this->deploy; + } + + public function setMakephar($makephar) + { + $this->makephar = (bool) $makephar; + } + + public function getMakephar() + { + return $this->makephar; + } + + private $basedir; + private $guzzleinfo; + private $changelog_release_date; + private $changelog_notes = '-'; + + public function main() + { + $this->basedir = $this->getProject()->getBasedir(); + + if (!is_dir((string) $this->basedir.'/.subsplit')) { + throw new BuildException('PEAR packaging requires .subsplit directory'); + } + + // main composer file + $composer_file = file_get_contents((string) $this->basedir.'/.subsplit/composer.json'); + $this->guzzleinfo = json_decode($composer_file, true); + + // make sure we have a target + $pearwork = (string) $this->basedir . '/build/pearwork'; + if (!is_dir($pearwork)) { + mkdir($pearwork, 0777, true); + } + $pearlogs = (string) $this->basedir . '/build/artifacts/logs'; + if (!is_dir($pearlogs)) { + mkdir($pearlogs, 0777, true); + } + + $version = $this->getVersion(); + $this->grabChangelog(); + if ($version[0] == '2') { + $this->log('building single PEAR package'); + $this->buildSinglePackage(); + } else { + // $this->log("building PEAR subpackages"); + // $this->createSubPackages(); + // $this->log("building PEAR bundle package"); + $this->buildSinglePackage(); + } + + if ($this->getMakephar()) { + $this->log("building PHAR"); + $this->getProject()->executeTarget('package-phar'); + } + + if ($this->getDeploy()) { + $this->doDeployment(); + } + } + + public function doDeployment() + { + $basedir = (string) $this->basedir; + $this->log('beginning PEAR/PHAR deployment'); + + chdir($basedir . '/build/pearwork'); + if (!is_dir('./channel')) { + mkdir('./channel'); + } + + // Pull the PEAR channel down locally + passthru('aws s3 sync s3://pear.guzzlephp.org ./channel'); + + // add PEAR packages + foreach (scandir('./') as $file) { + if (substr($file, -4) == '.tgz') { + passthru('pirum add ./channel ' . $file); + } + } + + // if we have a new phar, add it + if ($this->getMakephar() && file_exists($basedir . '/build/artifacts/guzzle.phar')) { + rename($basedir . '/build/artifacts/guzzle.phar', './channel/guzzle.phar'); + } + + // Sync up with the S3 bucket + chdir($basedir . '/build/pearwork/channel'); + passthru('aws s3 sync . s3://pear.guzzlephp.org'); + } + + public function buildSinglePackage() + { + $v = $this->getVersion(); + $apiversion = $v[0] . '.0.0'; + + $opts = array( + 'packagedirectory' => (string) $this->basedir . '/.subsplit/src/', + 'filelistgenerator' => 'file', + 'ignore' => array('*composer.json'), + 'baseinstalldir' => '/', + 'packagefile' => 'package.xml' + //'outputdirectory' => (string) $this->basedir . '/build/pearwork/' + ); + $pfm = new PEAR_PackageFileManager2(); + $pfm->setOptions($opts); + $pfm->addRole('md', 'doc'); + $pfm->addRole('pem', 'php'); + $pfm->setPackage('Guzzle'); + $pfm->setSummary("Object-oriented PHP HTTP Client for PHP 5.3+"); + $pfm->setDescription($this->guzzleinfo['description']); + $pfm->setPackageType('php'); + $pfm->setChannel('guzzlephp.org/pear'); + $pfm->setAPIVersion($apiversion); + $pfm->setReleaseVersion($this->getVersion()); + $pfm->setAPIStability('stable'); + $pfm->setReleaseStability('stable'); + $pfm->setNotes($this->changelog_notes); + $pfm->setPackageType('php'); + $pfm->setLicense('MIT', 'http://github.com/guzzle/guzzle/blob/master/LICENSE'); + $pfm->addMaintainer('lead', 'mtdowling', 'Michael Dowling', 'mtdowling@gmail.com', 'yes'); + $pfm->setDate($this->changelog_release_date); + $pfm->generateContents(); + + $phpdep = $this->guzzleinfo['require']['php']; + $phpdep = str_replace('>=', '', $phpdep); + $pfm->setPhpDep($phpdep); + $pfm->addExtensionDep('required', 'curl'); + $pfm->setPearinstallerDep('1.4.6'); + $pfm->addPackageDepWithChannel('required', 'EventDispatcher', 'pear.symfony.com', '2.1.0'); + if (!empty($this->subpackages)) { + foreach ($this->subpackages as $package) { + $pkg = dirname($package); + $pkg = str_replace('/', '_', $pkg); + $pfm->addConflictingPackageDepWithChannel($pkg, 'guzzlephp.org/pear', false, $apiversion); + } + } + + ob_start(); + $startdir = getcwd(); + chdir((string) $this->basedir . '/build/pearwork'); + + echo "DEBUGGING GENERATED PACKAGE FILE\n"; + $result = $pfm->debugPackageFile(); + if ($result) { + $out = $pfm->writePackageFile(); + echo "\n\n\nWRITE PACKAGE FILE RESULT:\n"; + var_dump($out); + // load up package file and build package + $packager = new PEAR_Packager(); + echo "\n\n\nBUILDING PACKAGE FROM PACKAGE FILE:\n"; + $dest_package = $packager->package($opts['packagedirectory'].'package.xml'); + var_dump($dest_package); + } else { + echo "\n\n\nDEBUGGING RESULT:\n"; + var_dump($result); + } + echo "removing package.xml"; + unlink($opts['packagedirectory'].'package.xml'); + $log = ob_get_clean(); + file_put_contents((string) $this->basedir . '/build/artifacts/logs/pear_package.log', $log); + chdir($startdir); + } + + public function createSubPackages() + { + $this->findComponents(); + + foreach ($this->subpackages as $package) { + $baseinstalldir = dirname($package); + $dir = (string) $this->basedir.'/.subsplit/src/' . $baseinstalldir; + $composer_file = file_get_contents((string) $this->basedir.'/.subsplit/src/'. $package); + $package_info = json_decode($composer_file, true); + $this->log('building ' . $package_info['target-dir'] . ' subpackage'); + $this->buildSubPackage($dir, $baseinstalldir, $package_info); + } + } + + public function buildSubPackage($dir, $baseinstalldir, $info) + { + $package = str_replace('/', '_', $baseinstalldir); + $opts = array( + 'packagedirectory' => $dir, + 'filelistgenerator' => 'file', + 'ignore' => array('*composer.json', '*package.xml'), + 'baseinstalldir' => '/' . $info['target-dir'], + 'packagefile' => 'package.xml' + ); + $pfm = new PEAR_PackageFileManager2(); + $pfm->setOptions($opts); + $pfm->setPackage($package); + $pfm->setSummary($info['description']); + $pfm->setDescription($info['description']); + $pfm->setPackageType('php'); + $pfm->setChannel('guzzlephp.org/pear'); + $pfm->setAPIVersion('3.0.0'); + $pfm->setReleaseVersion($this->getVersion()); + $pfm->setAPIStability('stable'); + $pfm->setReleaseStability('stable'); + $pfm->setNotes($this->changelog_notes); + $pfm->setPackageType('php'); + $pfm->setLicense('MIT', 'http://github.com/guzzle/guzzle/blob/master/LICENSE'); + $pfm->addMaintainer('lead', 'mtdowling', 'Michael Dowling', 'mtdowling@gmail.com', 'yes'); + $pfm->setDate($this->changelog_release_date); + $pfm->generateContents(); + + $phpdep = $this->guzzleinfo['require']['php']; + $phpdep = str_replace('>=', '', $phpdep); + $pfm->setPhpDep($phpdep); + $pfm->setPearinstallerDep('1.4.6'); + + foreach ($info['require'] as $type => $version) { + if ($type == 'php') { + continue; + } + if ($type == 'symfony/event-dispatcher') { + $pfm->addPackageDepWithChannel('required', 'EventDispatcher', 'pear.symfony.com', '2.1.0'); + } + if ($type == 'ext-curl') { + $pfm->addExtensionDep('required', 'curl'); + } + if (substr($type, 0, 6) == 'guzzle') { + $gdep = str_replace('/', ' ', $type); + $gdep = ucwords($gdep); + $gdep = str_replace(' ', '_', $gdep); + $pfm->addPackageDepWithChannel('required', $gdep, 'guzzlephp.org/pear', $this->getVersion()); + } + } + + // can't have main Guzzle package AND sub-packages + $pfm->addConflictingPackageDepWithChannel('Guzzle', 'guzzlephp.org/pear', false, $apiversion); + + ob_start(); + $startdir = getcwd(); + chdir((string) $this->basedir . '/build/pearwork'); + + echo "DEBUGGING GENERATED PACKAGE FILE\n"; + $result = $pfm->debugPackageFile(); + if ($result) { + $out = $pfm->writePackageFile(); + echo "\n\n\nWRITE PACKAGE FILE RESULT:\n"; + var_dump($out); + // load up package file and build package + $packager = new PEAR_Packager(); + echo "\n\n\nBUILDING PACKAGE FROM PACKAGE FILE:\n"; + $dest_package = $packager->package($opts['packagedirectory'].'/package.xml'); + var_dump($dest_package); + } else { + echo "\n\n\nDEBUGGING RESULT:\n"; + var_dump($result); + } + echo "removing package.xml"; + unlink($opts['packagedirectory'].'/package.xml'); + $log = ob_get_clean(); + file_put_contents((string) $this->basedir . '/build/artifacts/logs/pear_package_'.$package.'.log', $log); + chdir($startdir); + } + + public function findComponents() + { + $ds = new DirectoryScanner(); + $ds->setBasedir((string) $this->basedir.'/.subsplit/src'); + $ds->setIncludes(array('**/composer.json')); + $ds->scan(); + $files = $ds->getIncludedFiles(); + $this->subpackages = $files; + } + + public function grabChangelog() + { + $cl = file((string) $this->basedir.'/.subsplit/CHANGELOG.md'); + $notes = ''; + $in_version = false; + $release_date = null; + + foreach ($cl as $line) { + $line = trim($line); + if (preg_match('/^\* '.$this->getVersion().' \(([0-9\-]+)\)$/', $line, $matches)) { + $release_date = $matches[1]; + $in_version = true; + continue; + } + if ($in_version && empty($line) && empty($notes)) { + continue; + } + if ($in_version && ! empty($line)) { + $notes .= $line."\n"; + } + if ($in_version && empty($line) && !empty($notes)) { + $in_version = false; + } + } + $this->changelog_release_date = $release_date; + + if (! empty($notes)) { + $this->changelog_notes = $notes; + } + } +} diff --git a/vendor/guzzle/guzzle/phing/tasks/GuzzleSubSplitTask.php b/vendor/guzzle/guzzle/phing/tasks/GuzzleSubSplitTask.php new file mode 100644 index 0000000..5d56a5b --- /dev/null +++ b/vendor/guzzle/guzzle/phing/tasks/GuzzleSubSplitTask.php @@ -0,0 +1,385 @@ + + * @license http://claylo.mit-license.org/2012/ MIT License + */ + +require_once 'phing/tasks/ext/git/GitBaseTask.php'; + +// base - base of tree to split out +// subIndicatorFile - composer.json, package.xml? +class GuzzleSubSplitTask extends GitBaseTask +{ + /** + * What git repository to pull from and publish to + */ + protected $remote = null; + + /** + * Publish for comma-separated heads instead of all heads + */ + protected $heads = null; + + /** + * Publish for comma-separated tags instead of all tags + */ + protected $tags = null; + + /** + * Base of the tree RELATIVE TO .subsplit working dir + */ + protected $base = null; + + /** + * The presence of this file will indicate that the directory it resides + * in is at the top level of a split. + */ + protected $subIndicatorFile = 'composer.json'; + + /** + * Do everything except actually send the update. + */ + protected $dryRun = null; + + /** + * Do not sync any heads. + */ + protected $noHeads = false; + + /** + * Do not sync any tags. + */ + protected $noTags = false; + + /** + * The splits we found in the heads + */ + protected $splits; + + public function setRemote($str) + { + $this->remote = $str; + } + + public function getRemote() + { + return $this->remote; + } + + public function setHeads($str) + { + $this->heads = explode(',', $str); + } + + public function getHeads() + { + return $this->heads; + } + + public function setTags($str) + { + $this->tags = explode(',', $str); + } + + public function getTags() + { + return $this->tags; + } + + public function setBase($str) + { + $this->base = $str; + } + + public function getBase() + { + return $this->base; + } + + public function setSubIndicatorFile($str) + { + $this->subIndicatorFile = $str; + } + + public function getSubIndicatorFile() + { + return $this->subIndicatorFile; + } + + public function setDryRun($bool) + { + $this->dryRun = (bool) $bool; + } + + public function getDryRun() + { + return $this->dryRun; + } + + public function setNoHeads($bool) + { + $this->noHeads = (bool) $bool; + } + + public function getNoHeads() + { + return $this->noHeads; + } + + public function setNoTags($bool) + { + $this->noTags = (bool) $bool; + } + + public function getNoTags() + { + return $this->noTags; + } + + /** + * GitClient from VersionControl_Git + */ + protected $client = null; + + /** + * The main entry point + */ + public function main() + { + $repo = $this->getRepository(); + if (empty($repo)) { + throw new BuildException('"repository" is a required parameter'); + } + + $remote = $this->getRemote(); + if (empty($remote)) { + throw new BuildException('"remote" is a required parameter'); + } + + chdir($repo); + $this->client = $this->getGitClient(false, $repo); + + // initalized yet? + if (!is_dir('.subsplit')) { + $this->subsplitInit(); + } else { + // update + $this->subsplitUpdate(); + } + + // find all splits based on heads requested + $this->findSplits(); + + // check that GitHub has the repos + $this->verifyRepos(); + + // execute the subsplits + $this->publish(); + } + + public function publish() + { + $this->log('DRY RUN ONLY FOR NOW'); + $base = $this->getBase(); + $base = rtrim($base, '/') . '/'; + $org = $this->getOwningTarget()->getProject()->getProperty('github.org'); + + $splits = array(); + + $heads = $this->getHeads(); + foreach ($heads as $head) { + foreach ($this->splits[$head] as $component => $meta) { + $splits[] = $base . $component . ':git@github.com:'. $org.'/'.$meta['repo']; + } + + $cmd = 'git subsplit publish '; + $cmd .= escapeshellarg(implode(' ', $splits)); + + if ($this->getNoHeads()) { + $cmd .= ' --no-heads'; + } else { + $cmd .= ' --heads='.$head; + } + + if ($this->getNoTags()) { + $cmd .= ' --no-tags'; + } else { + if ($this->getTags()) { + $cmd .= ' --tags=' . escapeshellarg(implode(' ', $this->getTags())); + } + } + + passthru($cmd); + } + } + + /** + * Runs `git subsplit update` + */ + public function subsplitUpdate() + { + $repo = $this->getRepository(); + $this->log('git-subsplit update...'); + $cmd = $this->client->getCommand('subsplit'); + $cmd->addArgument('update'); + try { + $cmd->execute(); + } catch (Exception $e) { + throw new BuildException('git subsplit update failed'. $e); + } + chdir($repo . '/.subsplit'); + passthru('php ../composer.phar update --dev'); + chdir($repo); + } + + /** + * Runs `git subsplit init` based on the remote repository. + */ + public function subsplitInit() + { + $remote = $this->getRemote(); + $cmd = $this->client->getCommand('subsplit'); + $this->log('running git-subsplit init ' . $remote); + + $cmd->setArguments(array( + 'init', + $remote + )); + + try { + $output = $cmd->execute(); + } catch (Exception $e) { + throw new BuildException('git subsplit init failed'. $e); + } + $this->log(trim($output), Project::MSG_INFO); + $repo = $this->getRepository(); + chdir($repo . '/.subsplit'); + passthru('php ../composer.phar install --dev'); + chdir($repo); + } + + /** + * Find the composer.json files using Phing's directory scanner + * + * @return array + */ + protected function findSplits() + { + $this->log("checking heads for subsplits"); + $repo = $this->getRepository(); + $base = $this->getBase(); + + $splits = array(); + $heads = $this->getHeads(); + + if (!empty($base)) { + $base = '/' . ltrim($base, '/'); + } else { + $base = '/'; + } + + chdir($repo . '/.subsplit'); + foreach ($heads as $head) { + $splits[$head] = array(); + + // check each head requested *BEFORE* the actual subtree split command gets it + passthru("git checkout '$head'"); + $ds = new DirectoryScanner(); + $ds->setBasedir($repo . '/.subsplit' . $base); + $ds->setIncludes(array('**/'.$this->subIndicatorFile)); + $ds->scan(); + $files = $ds->getIncludedFiles(); + + // Process the files we found + foreach ($files as $file) { + $pkg = file_get_contents($repo . '/.subsplit' . $base .'/'. $file); + $pkg_json = json_decode($pkg, true); + $name = $pkg_json['name']; + $component = str_replace('/composer.json', '', $file); + // keep this for split cmd + $tmpreponame = explode('/', $name); + $reponame = $tmpreponame[1]; + $splits[$head][$component]['repo'] = $reponame; + $nscomponent = str_replace('/', '\\', $component); + $splits[$head][$component]['desc'] = "[READ ONLY] Subtree split of $nscomponent: " . $pkg_json['description']; + } + } + + // go back to how we found it + passthru("git checkout master"); + chdir($repo); + $this->splits = $splits; + } + + /** + * Based on list of repositories we determined we *should* have, talk + * to GitHub and make sure they're all there. + * + */ + protected function verifyRepos() + { + $this->log('verifying GitHub target repos'); + $github_org = $this->getOwningTarget()->getProject()->getProperty('github.org'); + $github_creds = $this->getOwningTarget()->getProject()->getProperty('github.basicauth'); + + if ($github_creds == 'username:password') { + $this->log('Skipping GitHub repo checks. Update github.basicauth in build.properties to verify repos.', 1); + return; + } + + $ch = curl_init('https://api.github.com/orgs/'.$github_org.'/repos?type=all'); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); + curl_setopt($ch, CURLOPT_USERPWD, $github_creds); + // change this when we know we can use our bundled CA bundle! + curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); + $result = curl_exec($ch); + curl_close($ch); + $repos = json_decode($result, true); + $existing_repos = array(); + + // parse out the repos we found on GitHub + foreach ($repos as $repo) { + $tmpreponame = explode('/', $repo['full_name']); + $reponame = $tmpreponame[1]; + $existing_repos[$reponame] = $repo['description']; + } + + $heads = $this->getHeads(); + foreach ($heads as $head) { + foreach ($this->splits[$head] as $component => $meta) { + + $reponame = $meta['repo']; + + if (!isset($existing_repos[$reponame])) { + $this->log("Creating missing repo $reponame"); + $payload = array( + 'name' => $reponame, + 'description' => $meta['desc'], + 'homepage' => 'http://www.guzzlephp.org/', + 'private' => true, + 'has_issues' => false, + 'has_wiki' => false, + 'has_downloads' => true, + 'auto_init' => false + ); + $ch = curl_init('https://api.github.com/orgs/'.$github_org.'/repos'); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); + curl_setopt($ch, CURLOPT_USERPWD, $github_creds); + curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-Type: application/json')); + curl_setopt($ch, CURLOPT_POST, 1); + curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($payload)); + // change this when we know we can use our bundled CA bundle! + curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); + $result = curl_exec($ch); + echo "Response code: ".curl_getinfo($ch, CURLINFO_HTTP_CODE)."\n"; + curl_close($ch); + } else { + $this->log("Repo $reponame exists", 2); + } + } + } + } +} diff --git a/vendor/guzzle/guzzle/phpunit.xml.dist b/vendor/guzzle/guzzle/phpunit.xml.dist new file mode 100644 index 0000000..208fdc0 --- /dev/null +++ b/vendor/guzzle/guzzle/phpunit.xml.dist @@ -0,0 +1,48 @@ + + + + + + ./tests/Guzzle/Tests + + + + + + + + + + ./src/Guzzle + + ./src/Guzzle + ./src/Guzzle/Common/Exception/GuzzleException.php + ./src/Guzzle/Http/Exception/HttpException.php + ./src/Guzzle/Http/Exception/ServerErrorResponseException.php + ./src/Guzzle/Http/Exception/ClientErrorResponseException.php + ./src/Guzzle/Http/Exception/TooManyRedirectsException.php + ./src/Guzzle/Http/Exception/CouldNotRewindStreamException.php + ./src/Guzzle/Common/Exception/BadMethodCallException.php + ./src/Guzzle/Common/Exception/InvalidArgumentException.php + ./src/Guzzle/Common/Exception/RuntimeException.php + ./src/Guzzle/Common/Exception/UnexpectedValueException.php + ./src/Guzzle/Service/Exception/ClientNotFoundException.php + ./src/Guzzle/Service/Exception/CommandException.php + ./src/Guzzle/Service/Exception/DescriptionBuilderException.php + ./src/Guzzle/Service/Exception/ServiceBuilderException.php + ./src/Guzzle/Service/Exception/ServiceNotFoundException.php + ./src/Guzzle/Service/Exception/ValidationException.php + ./src/Guzzle/Service/Exception/JsonException.php + + + + + diff --git a/vendor/guzzle/guzzle/src/Guzzle/Batch/AbstractBatchDecorator.php b/vendor/guzzle/guzzle/src/Guzzle/Batch/AbstractBatchDecorator.php new file mode 100644 index 0000000..0625d71 --- /dev/null +++ b/vendor/guzzle/guzzle/src/Guzzle/Batch/AbstractBatchDecorator.php @@ -0,0 +1,66 @@ +decoratedBatch = $decoratedBatch; + } + + /** + * Allow decorators to implement custom methods + * + * @param string $method Missing method name + * @param array $args Method arguments + * + * @return mixed + * @codeCoverageIgnore + */ + public function __call($method, array $args) + { + return call_user_func_array(array($this->decoratedBatch, $method), $args); + } + + public function add($item) + { + $this->decoratedBatch->add($item); + + return $this; + } + + public function flush() + { + return $this->decoratedBatch->flush(); + } + + public function isEmpty() + { + return $this->decoratedBatch->isEmpty(); + } + + /** + * Trace the decorators associated with the batch + * + * @return array + */ + public function getDecorators() + { + $found = array($this); + if (method_exists($this->decoratedBatch, 'getDecorators')) { + $found = array_merge($found, $this->decoratedBatch->getDecorators()); + } + + return $found; + } +} diff --git a/vendor/guzzle/guzzle/src/Guzzle/Batch/Batch.php b/vendor/guzzle/guzzle/src/Guzzle/Batch/Batch.php new file mode 100644 index 0000000..4d41c54 --- /dev/null +++ b/vendor/guzzle/guzzle/src/Guzzle/Batch/Batch.php @@ -0,0 +1,92 @@ +transferStrategy = $transferStrategy; + $this->divisionStrategy = $divisionStrategy; + $this->queue = new \SplQueue(); + $this->queue->setIteratorMode(\SplQueue::IT_MODE_DELETE); + $this->dividedBatches = array(); + } + + public function add($item) + { + $this->queue->enqueue($item); + + return $this; + } + + public function flush() + { + $this->createBatches(); + + $items = array(); + foreach ($this->dividedBatches as $batchIndex => $dividedBatch) { + while ($dividedBatch->valid()) { + $batch = $dividedBatch->current(); + $dividedBatch->next(); + try { + $this->transferStrategy->transfer($batch); + $items = array_merge($items, $batch); + } catch (\Exception $e) { + throw new BatchTransferException($batch, $items, $e, $this->transferStrategy, $this->divisionStrategy); + } + } + // Keep the divided batch down to a minimum in case of a later exception + unset($this->dividedBatches[$batchIndex]); + } + + return $items; + } + + public function isEmpty() + { + return count($this->queue) == 0 && count($this->dividedBatches) == 0; + } + + /** + * Create batches for any queued items + */ + protected function createBatches() + { + if (count($this->queue)) { + if ($batches = $this->divisionStrategy->createBatches($this->queue)) { + // Convert arrays into iterators + if (is_array($batches)) { + $batches = new \ArrayIterator($batches); + } + $this->dividedBatches[] = $batches; + } + } + } +} diff --git a/vendor/guzzle/guzzle/src/Guzzle/Batch/BatchBuilder.php b/vendor/guzzle/guzzle/src/Guzzle/Batch/BatchBuilder.php new file mode 100644 index 0000000..ea99b4d --- /dev/null +++ b/vendor/guzzle/guzzle/src/Guzzle/Batch/BatchBuilder.php @@ -0,0 +1,199 @@ + 'Guzzle\Batch\BatchRequestTransfer', + 'command' => 'Guzzle\Batch\BatchCommandTransfer' + ); + + /** + * Create a new instance of the BatchBuilder + * + * @return BatchBuilder + */ + public static function factory() + { + return new self(); + } + + /** + * Automatically flush the batch when the size of the queue reaches a certain threshold. Adds {@see FlushingBatch}. + * + * @param $threshold Number of items to allow in the queue before a flush + * + * @return BatchBuilder + */ + public function autoFlushAt($threshold) + { + $this->autoFlush = $threshold; + + return $this; + } + + /** + * Maintain a history of all items that have been transferred using the batch. Adds {@see HistoryBatch}. + * + * @return BatchBuilder + */ + public function keepHistory() + { + $this->history = true; + + return $this; + } + + /** + * Buffer exceptions thrown during transfer so that you can transfer as much as possible, and after a transfer + * completes, inspect each exception that was thrown. Enables the {@see ExceptionBufferingBatch} decorator. + * + * @return BatchBuilder + */ + public function bufferExceptions() + { + $this->exceptionBuffering = true; + + return $this; + } + + /** + * Notify a callable each time a batch flush completes. Enables the {@see NotifyingBatch} decorator. + * + * @param mixed $callable Callable function to notify + * + * @return BatchBuilder + * @throws InvalidArgumentException if the argument is not callable + */ + public function notify($callable) + { + $this->afterFlush = $callable; + + return $this; + } + + /** + * Configures the batch to transfer batches of requests. Associates a {@see \Guzzle\Http\BatchRequestTransfer} + * object as both the transfer and divisor strategy. + * + * @param int $batchSize Batch size for each batch of requests + * + * @return BatchBuilder + */ + public function transferRequests($batchSize = 50) + { + $className = self::$mapping['request']; + $this->transferStrategy = new $className($batchSize); + $this->divisorStrategy = $this->transferStrategy; + + return $this; + } + + /** + * Configures the batch to transfer batches commands. Associates as + * {@see \Guzzle\Service\Command\BatchCommandTransfer} as both the transfer and divisor strategy. + * + * @param int $batchSize Batch size for each batch of commands + * + * @return BatchBuilder + */ + public function transferCommands($batchSize = 50) + { + $className = self::$mapping['command']; + $this->transferStrategy = new $className($batchSize); + $this->divisorStrategy = $this->transferStrategy; + + return $this; + } + + /** + * Specify the strategy used to divide the queue into an array of batches + * + * @param BatchDivisorInterface $divisorStrategy Strategy used to divide a batch queue into batches + * + * @return BatchBuilder + */ + public function createBatchesWith(BatchDivisorInterface $divisorStrategy) + { + $this->divisorStrategy = $divisorStrategy; + + return $this; + } + + /** + * Specify the strategy used to transport the items when flush is called + * + * @param BatchTransferInterface $transferStrategy How items are transferred + * + * @return BatchBuilder + */ + public function transferWith(BatchTransferInterface $transferStrategy) + { + $this->transferStrategy = $transferStrategy; + + return $this; + } + + /** + * Create and return the instantiated batch + * + * @return BatchInterface + * @throws RuntimeException if no transfer strategy has been specified + */ + public function build() + { + if (!$this->transferStrategy) { + throw new RuntimeException('No transfer strategy has been specified'); + } + + if (!$this->divisorStrategy) { + throw new RuntimeException('No divisor strategy has been specified'); + } + + $batch = new Batch($this->transferStrategy, $this->divisorStrategy); + + if ($this->exceptionBuffering) { + $batch = new ExceptionBufferingBatch($batch); + } + + if ($this->afterFlush) { + $batch = new NotifyingBatch($batch, $this->afterFlush); + } + + if ($this->autoFlush) { + $batch = new FlushingBatch($batch, $this->autoFlush); + } + + if ($this->history) { + $batch = new HistoryBatch($batch); + } + + return $batch; + } +} diff --git a/vendor/guzzle/guzzle/src/Guzzle/Batch/BatchClosureDivisor.php b/vendor/guzzle/guzzle/src/Guzzle/Batch/BatchClosureDivisor.php new file mode 100644 index 0000000..e0a2d95 --- /dev/null +++ b/vendor/guzzle/guzzle/src/Guzzle/Batch/BatchClosureDivisor.php @@ -0,0 +1,39 @@ +callable = $callable; + $this->context = $context; + } + + public function createBatches(\SplQueue $queue) + { + return call_user_func($this->callable, $queue, $this->context); + } +} diff --git a/vendor/guzzle/guzzle/src/Guzzle/Batch/BatchClosureTransfer.php b/vendor/guzzle/guzzle/src/Guzzle/Batch/BatchClosureTransfer.php new file mode 100644 index 0000000..9cbf1ab --- /dev/null +++ b/vendor/guzzle/guzzle/src/Guzzle/Batch/BatchClosureTransfer.php @@ -0,0 +1,40 @@ +callable = $callable; + $this->context = $context; + } + + public function transfer(array $batch) + { + return empty($batch) ? null : call_user_func($this->callable, $batch, $this->context); + } +} diff --git a/vendor/guzzle/guzzle/src/Guzzle/Batch/BatchCommandTransfer.php b/vendor/guzzle/guzzle/src/Guzzle/Batch/BatchCommandTransfer.php new file mode 100644 index 0000000..d55ac7d --- /dev/null +++ b/vendor/guzzle/guzzle/src/Guzzle/Batch/BatchCommandTransfer.php @@ -0,0 +1,75 @@ +batchSize = $batchSize; + } + + /** + * Creates batches by grouping commands by their associated client + * {@inheritdoc} + */ + public function createBatches(\SplQueue $queue) + { + $groups = new \SplObjectStorage(); + foreach ($queue as $item) { + if (!$item instanceof CommandInterface) { + throw new InvalidArgumentException('All items must implement Guzzle\Service\Command\CommandInterface'); + } + $client = $item->getClient(); + if (!$groups->contains($client)) { + $groups->attach($client, new \ArrayObject(array($item))); + } else { + $groups[$client]->append($item); + } + } + + $batches = array(); + foreach ($groups as $batch) { + $batches = array_merge($batches, array_chunk($groups[$batch]->getArrayCopy(), $this->batchSize)); + } + + return $batches; + } + + public function transfer(array $batch) + { + if (empty($batch)) { + return; + } + + // Get the client of the first found command + $client = reset($batch)->getClient(); + + // Keep a list of all commands with invalid clients + $invalid = array_filter($batch, function ($command) use ($client) { + return $command->getClient() !== $client; + }); + + if (!empty($invalid)) { + throw new InconsistentClientTransferException($invalid); + } + + $client->execute($batch); + } +} diff --git a/vendor/guzzle/guzzle/src/Guzzle/Batch/BatchDivisorInterface.php b/vendor/guzzle/guzzle/src/Guzzle/Batch/BatchDivisorInterface.php new file mode 100644 index 0000000..0214f05 --- /dev/null +++ b/vendor/guzzle/guzzle/src/Guzzle/Batch/BatchDivisorInterface.php @@ -0,0 +1,18 @@ +batchSize = $batchSize; + } + + /** + * Creates batches of requests by grouping requests by their associated curl multi object. + * {@inheritdoc} + */ + public function createBatches(\SplQueue $queue) + { + // Create batches by client objects + $groups = new \SplObjectStorage(); + foreach ($queue as $item) { + if (!$item instanceof RequestInterface) { + throw new InvalidArgumentException('All items must implement Guzzle\Http\Message\RequestInterface'); + } + $client = $item->getClient(); + if (!$groups->contains($client)) { + $groups->attach($client, array($item)); + } else { + $current = $groups[$client]; + $current[] = $item; + $groups[$client] = $current; + } + } + + $batches = array(); + foreach ($groups as $batch) { + $batches = array_merge($batches, array_chunk($groups[$batch], $this->batchSize)); + } + + return $batches; + } + + public function transfer(array $batch) + { + if ($batch) { + reset($batch)->getClient()->send($batch); + } + } +} diff --git a/vendor/guzzle/guzzle/src/Guzzle/Batch/BatchSizeDivisor.php b/vendor/guzzle/guzzle/src/Guzzle/Batch/BatchSizeDivisor.php new file mode 100644 index 0000000..67f90a5 --- /dev/null +++ b/vendor/guzzle/guzzle/src/Guzzle/Batch/BatchSizeDivisor.php @@ -0,0 +1,47 @@ +size = $size; + } + + /** + * Set the size of each batch + * + * @param int $size Size of each batch + * + * @return BatchSizeDivisor + */ + public function setSize($size) + { + $this->size = $size; + + return $this; + } + + /** + * Get the size of each batch + * + * @return int + */ + public function getSize() + { + return $this->size; + } + + public function createBatches(\SplQueue $queue) + { + return array_chunk(iterator_to_array($queue, false), $this->size); + } +} diff --git a/vendor/guzzle/guzzle/src/Guzzle/Batch/BatchTransferInterface.php b/vendor/guzzle/guzzle/src/Guzzle/Batch/BatchTransferInterface.php new file mode 100644 index 0000000..2e0b60d --- /dev/null +++ b/vendor/guzzle/guzzle/src/Guzzle/Batch/BatchTransferInterface.php @@ -0,0 +1,16 @@ +batch = $batch; + $this->transferredItems = $transferredItems; + $this->transferStrategy = $transferStrategy; + $this->divisorStrategy = $divisorStrategy; + parent::__construct( + 'Exception encountered while transferring batch: ' . $exception->getMessage(), + $exception->getCode(), + $exception + ); + } + + /** + * Get the batch that we being sent when the exception occurred + * + * @return array + */ + public function getBatch() + { + return $this->batch; + } + + /** + * Get the items transferred at the point in which the exception was encountered + * + * @return array + */ + public function getTransferredItems() + { + return $this->transferredItems; + } + + /** + * Get the transfer strategy + * + * @return TransferStrategy + */ + public function getTransferStrategy() + { + return $this->transferStrategy; + } + + /** + * Get the divisor strategy + * + * @return DivisorStrategy + */ + public function getDivisorStrategy() + { + return $this->divisorStrategy; + } +} diff --git a/vendor/guzzle/guzzle/src/Guzzle/Batch/ExceptionBufferingBatch.php b/vendor/guzzle/guzzle/src/Guzzle/Batch/ExceptionBufferingBatch.php new file mode 100644 index 0000000..d7a8928 --- /dev/null +++ b/vendor/guzzle/guzzle/src/Guzzle/Batch/ExceptionBufferingBatch.php @@ -0,0 +1,50 @@ +decoratedBatch->isEmpty()) { + try { + $transferredItems = $this->decoratedBatch->flush(); + } catch (BatchTransferException $e) { + $this->exceptions[] = $e; + $transferredItems = $e->getTransferredItems(); + } + $items = array_merge($items, $transferredItems); + } + + return $items; + } + + /** + * Get the buffered exceptions + * + * @return array Array of BatchTransferException objects + */ + public function getExceptions() + { + return $this->exceptions; + } + + /** + * Clear the buffered exceptions + */ + public function clearExceptions() + { + $this->exceptions = array(); + } +} diff --git a/vendor/guzzle/guzzle/src/Guzzle/Batch/FlushingBatch.php b/vendor/guzzle/guzzle/src/Guzzle/Batch/FlushingBatch.php new file mode 100644 index 0000000..367b684 --- /dev/null +++ b/vendor/guzzle/guzzle/src/Guzzle/Batch/FlushingBatch.php @@ -0,0 +1,60 @@ +threshold = $threshold; + parent::__construct($decoratedBatch); + } + + /** + * Set the auto-flush threshold + * + * @param int $threshold The auto-flush threshold + * + * @return FlushingBatch + */ + public function setThreshold($threshold) + { + $this->threshold = $threshold; + + return $this; + } + + /** + * Get the auto-flush threshold + * + * @return int + */ + public function getThreshold() + { + return $this->threshold; + } + + public function add($item) + { + $this->decoratedBatch->add($item); + if (++$this->currentTotal >= $this->threshold) { + $this->currentTotal = 0; + $this->decoratedBatch->flush(); + } + + return $this; + } +} diff --git a/vendor/guzzle/guzzle/src/Guzzle/Batch/HistoryBatch.php b/vendor/guzzle/guzzle/src/Guzzle/Batch/HistoryBatch.php new file mode 100644 index 0000000..e345fdc --- /dev/null +++ b/vendor/guzzle/guzzle/src/Guzzle/Batch/HistoryBatch.php @@ -0,0 +1,39 @@ +history[] = $item; + $this->decoratedBatch->add($item); + + return $this; + } + + /** + * Get the batch history + * + * @return array + */ + public function getHistory() + { + return $this->history; + } + + /** + * Clear the batch history + */ + public function clearHistory() + { + $this->history = array(); + } +} diff --git a/vendor/guzzle/guzzle/src/Guzzle/Batch/NotifyingBatch.php b/vendor/guzzle/guzzle/src/Guzzle/Batch/NotifyingBatch.php new file mode 100644 index 0000000..96d04da --- /dev/null +++ b/vendor/guzzle/guzzle/src/Guzzle/Batch/NotifyingBatch.php @@ -0,0 +1,38 @@ +callable = $callable; + parent::__construct($decoratedBatch); + } + + public function flush() + { + $items = $this->decoratedBatch->flush(); + call_user_func($this->callable, $items); + + return $items; + } +} diff --git a/vendor/guzzle/guzzle/src/Guzzle/Batch/composer.json b/vendor/guzzle/guzzle/src/Guzzle/Batch/composer.json new file mode 100644 index 0000000..12404d3 --- /dev/null +++ b/vendor/guzzle/guzzle/src/Guzzle/Batch/composer.json @@ -0,0 +1,31 @@ +{ + "name": "guzzle/batch", + "description": "Guzzle batch component for batching requests, commands, or custom transfers", + "homepage": "http://guzzlephp.org/", + "keywords": ["batch", "HTTP", "REST", "guzzle"], + "license": "MIT", + "authors": [ + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + } + ], + "require": { + "php": ">=5.3.2", + "guzzle/common": "self.version" + }, + "autoload": { + "psr-0": { "Guzzle\\Batch": "" } + }, + "suggest": { + "guzzle/http": "self.version", + "guzzle/service": "self.version" + }, + "target-dir": "Guzzle/Batch", + "extra": { + "branch-alias": { + "dev-master": "3.7-dev" + } + } +} diff --git a/vendor/guzzle/guzzle/src/Guzzle/Cache/AbstractCacheAdapter.php b/vendor/guzzle/guzzle/src/Guzzle/Cache/AbstractCacheAdapter.php new file mode 100644 index 0000000..a5c5271 --- /dev/null +++ b/vendor/guzzle/guzzle/src/Guzzle/Cache/AbstractCacheAdapter.php @@ -0,0 +1,21 @@ +cache; + } +} diff --git a/vendor/guzzle/guzzle/src/Guzzle/Cache/CacheAdapterFactory.php b/vendor/guzzle/guzzle/src/Guzzle/Cache/CacheAdapterFactory.php new file mode 100644 index 0000000..94e6234 --- /dev/null +++ b/vendor/guzzle/guzzle/src/Guzzle/Cache/CacheAdapterFactory.php @@ -0,0 +1,117 @@ +newInstanceArgs($args); + } + } catch (\Exception $e) { + throw new RuntimeException($e->getMessage(), $e->getCode(), $e); + } + } +} diff --git a/vendor/guzzle/guzzle/src/Guzzle/Cache/CacheAdapterInterface.php b/vendor/guzzle/guzzle/src/Guzzle/Cache/CacheAdapterInterface.php new file mode 100644 index 0000000..970c9e2 --- /dev/null +++ b/vendor/guzzle/guzzle/src/Guzzle/Cache/CacheAdapterInterface.php @@ -0,0 +1,55 @@ +callables = $callables; + } + + public function contains($id, array $options = null) + { + return call_user_func($this->callables['contains'], $id, $options); + } + + public function delete($id, array $options = null) + { + return call_user_func($this->callables['delete'], $id, $options); + } + + public function fetch($id, array $options = null) + { + return call_user_func($this->callables['fetch'], $id, $options); + } + + public function save($id, $data, $lifeTime = false, array $options = null) + { + return call_user_func($this->callables['save'], $id, $data, $lifeTime, $options); + } +} diff --git a/vendor/guzzle/guzzle/src/Guzzle/Cache/DoctrineCacheAdapter.php b/vendor/guzzle/guzzle/src/Guzzle/Cache/DoctrineCacheAdapter.php new file mode 100644 index 0000000..e1aaf9f --- /dev/null +++ b/vendor/guzzle/guzzle/src/Guzzle/Cache/DoctrineCacheAdapter.php @@ -0,0 +1,41 @@ +cache = $cache; + } + + public function contains($id, array $options = null) + { + return $this->cache->contains($id); + } + + public function delete($id, array $options = null) + { + return $this->cache->delete($id); + } + + public function fetch($id, array $options = null) + { + return $this->cache->fetch($id); + } + + public function save($id, $data, $lifeTime = false, array $options = null) + { + return $this->cache->save($id, $data, $lifeTime !== false ? $lifeTime : 0); + } +} diff --git a/vendor/guzzle/guzzle/src/Guzzle/Cache/NullCacheAdapter.php b/vendor/guzzle/guzzle/src/Guzzle/Cache/NullCacheAdapter.php new file mode 100644 index 0000000..68bd4af --- /dev/null +++ b/vendor/guzzle/guzzle/src/Guzzle/Cache/NullCacheAdapter.php @@ -0,0 +1,31 @@ +cache = $cache; + } + + public function contains($id, array $options = null) + { + return $this->cache->test($id); + } + + public function delete($id, array $options = null) + { + return $this->cache->remove($id); + } + + public function fetch($id, array $options = null) + { + return $this->cache->load($id); + } + + public function save($id, $data, $lifeTime = false, array $options = null) + { + return $this->cache->save($data, $id, array(), $lifeTime); + } +} diff --git a/vendor/guzzle/guzzle/src/Guzzle/Cache/Zf2CacheAdapter.php b/vendor/guzzle/guzzle/src/Guzzle/Cache/Zf2CacheAdapter.php new file mode 100644 index 0000000..1fc18a5 --- /dev/null +++ b/vendor/guzzle/guzzle/src/Guzzle/Cache/Zf2CacheAdapter.php @@ -0,0 +1,41 @@ +cache = $cache; + } + + public function contains($id, array $options = null) + { + return $this->cache->hasItem($id); + } + + public function delete($id, array $options = null) + { + return $this->cache->removeItem($id); + } + + public function fetch($id, array $options = null) + { + return $this->cache->getItem($id); + } + + public function save($id, $data, $lifeTime = false, array $options = null) + { + return $this->cache->setItem($id, $data); + } +} diff --git a/vendor/guzzle/guzzle/src/Guzzle/Cache/composer.json b/vendor/guzzle/guzzle/src/Guzzle/Cache/composer.json new file mode 100644 index 0000000..a5d999b --- /dev/null +++ b/vendor/guzzle/guzzle/src/Guzzle/Cache/composer.json @@ -0,0 +1,27 @@ +{ + "name": "guzzle/cache", + "description": "Guzzle cache adapter component", + "homepage": "http://guzzlephp.org/", + "keywords": ["cache", "adapter", "zf", "doctrine", "guzzle"], + "license": "MIT", + "authors": [ + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + } + ], + "require": { + "php": ">=5.3.2", + "guzzle/common": "self.version" + }, + "autoload": { + "psr-0": { "Guzzle\\Cache": "" } + }, + "target-dir": "Guzzle/Cache", + "extra": { + "branch-alias": { + "dev-master": "3.7-dev" + } + } +} diff --git a/vendor/guzzle/guzzle/src/Guzzle/Common/AbstractHasDispatcher.php b/vendor/guzzle/guzzle/src/Guzzle/Common/AbstractHasDispatcher.php new file mode 100644 index 0000000..d1e842b --- /dev/null +++ b/vendor/guzzle/guzzle/src/Guzzle/Common/AbstractHasDispatcher.php @@ -0,0 +1,49 @@ +eventDispatcher = $eventDispatcher; + + return $this; + } + + public function getEventDispatcher() + { + if (!$this->eventDispatcher) { + $this->eventDispatcher = new EventDispatcher(); + } + + return $this->eventDispatcher; + } + + public function dispatch($eventName, array $context = array()) + { + return $this->getEventDispatcher()->dispatch($eventName, new Event($context)); + } + + public function addSubscriber(EventSubscriberInterface $subscriber) + { + $this->getEventDispatcher()->addSubscriber($subscriber); + + return $this; + } +} diff --git a/vendor/guzzle/guzzle/src/Guzzle/Common/Collection.php b/vendor/guzzle/guzzle/src/Guzzle/Common/Collection.php new file mode 100644 index 0000000..5cb1535 --- /dev/null +++ b/vendor/guzzle/guzzle/src/Guzzle/Common/Collection.php @@ -0,0 +1,403 @@ +data = $data; + } + + /** + * Create a new collection from an array, validate the keys, and add default values where missing + * + * @param array $config Configuration values to apply. + * @param array $defaults Default parameters + * @param array $required Required parameter names + * + * @return self + * @throws InvalidArgumentException if a parameter is missing + */ + public static function fromConfig(array $config = array(), array $defaults = array(), array $required = array()) + { + $data = $config + $defaults; + + if ($missing = array_diff($required, array_keys($data))) { + throw new InvalidArgumentException('Config is missing the following keys: ' . implode(', ', $missing)); + } + + return new self($data); + } + + public function count() + { + return count($this->data); + } + + public function getIterator() + { + return new \ArrayIterator($this->data); + } + + public function toArray() + { + return $this->data; + } + + /** + * Removes all key value pairs + * + * @return Collection + */ + public function clear() + { + $this->data = array(); + + return $this; + } + + /** + * Get all or a subset of matching key value pairs + * + * @param array $keys Pass an array of keys to retrieve only a subset of key value pairs + * + * @return array Returns an array of all matching key value pairs + */ + public function getAll(array $keys = null) + { + return $keys ? array_intersect_key($this->data, array_flip($keys)) : $this->data; + } + + /** + * Get a specific key value. + * + * @param string $key Key to retrieve. + * + * @return mixed|null Value of the key or NULL + */ + public function get($key) + { + return isset($this->data[$key]) ? $this->data[$key] : null; + } + + /** + * Set a key value pair + * + * @param string $key Key to set + * @param mixed $value Value to set + * + * @return Collection Returns a reference to the object + */ + public function set($key, $value) + { + $this->data[$key] = $value; + + return $this; + } + + /** + * Add a value to a key. If a key of the same name has already been added, the key value will be converted into an + * array and the new value will be pushed to the end of the array. + * + * @param string $key Key to add + * @param mixed $value Value to add to the key + * + * @return Collection Returns a reference to the object. + */ + public function add($key, $value) + { + if (!array_key_exists($key, $this->data)) { + $this->data[$key] = $value; + } elseif (is_array($this->data[$key])) { + $this->data[$key][] = $value; + } else { + $this->data[$key] = array($this->data[$key], $value); + } + + return $this; + } + + /** + * Remove a specific key value pair + * + * @param string $key A key to remove + * + * @return Collection + */ + public function remove($key) + { + unset($this->data[$key]); + + return $this; + } + + /** + * Get all keys in the collection + * + * @return array + */ + public function getKeys() + { + return array_keys($this->data); + } + + /** + * Returns whether or not the specified key is present. + * + * @param string $key The key for which to check the existence. + * + * @return bool + */ + public function hasKey($key) + { + return array_key_exists($key, $this->data); + } + + /** + * Case insensitive search the keys in the collection + * + * @param string $key Key to search for + * + * @return bool|string Returns false if not found, otherwise returns the key + */ + public function keySearch($key) + { + foreach (array_keys($this->data) as $k) { + if (!strcasecmp($k, $key)) { + return $k; + } + } + + return false; + } + + /** + * Checks if any keys contains a certain value + * + * @param string $value Value to search for + * + * @return mixed Returns the key if the value was found FALSE if the value was not found. + */ + public function hasValue($value) + { + return array_search($value, $this->data); + } + + /** + * Replace the data of the object with the value of an array + * + * @param array $data Associative array of data + * + * @return Collection Returns a reference to the object + */ + public function replace(array $data) + { + $this->data = $data; + + return $this; + } + + /** + * Add and merge in a Collection or array of key value pair data. + * + * @param Collection|array $data Associative array of key value pair data + * + * @return Collection Returns a reference to the object. + */ + public function merge($data) + { + foreach ($data as $key => $value) { + $this->add($key, $value); + } + + return $this; + } + + /** + * Over write key value pairs in this collection with all of the data from an array or collection. + * + * @param array|\Traversable $data Values to override over this config + * + * @return self + */ + public function overwriteWith($data) + { + if (is_array($data)) { + $this->data = $data + $this->data; + } elseif ($data instanceof Collection) { + $this->data = $data->toArray() + $this->data; + } else { + foreach ($data as $key => $value) { + $this->data[$key] = $value; + } + } + + return $this; + } + + /** + * Returns a Collection containing all the elements of the collection after applying the callback function to each + * one. The Closure should accept three parameters: (string) $key, (string) $value, (array) $context and return a + * modified value + * + * @param \Closure $closure Closure to apply + * @param array $context Context to pass to the closure + * @param bool $static Set to TRUE to use the same class as the return rather than returning a Collection + * + * @return Collection + */ + public function map(\Closure $closure, array $context = array(), $static = true) + { + $collection = $static ? new static() : new self(); + foreach ($this as $key => $value) { + $collection->add($key, $closure($key, $value, $context)); + } + + return $collection; + } + + /** + * Iterates over each key value pair in the collection passing them to the Closure. If the Closure function returns + * true, the current value from input is returned into the result Collection. The Closure must accept three + * parameters: (string) $key, (string) $value and return Boolean TRUE or FALSE for each value. + * + * @param \Closure $closure Closure evaluation function + * @param bool $static Set to TRUE to use the same class as the return rather than returning a Collection + * + * @return Collection + */ + public function filter(\Closure $closure, $static = true) + { + $collection = ($static) ? new static() : new self(); + foreach ($this->data as $key => $value) { + if ($closure($key, $value)) { + $collection->add($key, $value); + } + } + + return $collection; + } + + public function offsetExists($offset) + { + return isset($this->data[$offset]); + } + + public function offsetGet($offset) + { + return isset($this->data[$offset]) ? $this->data[$offset] : null; + } + + public function offsetSet($offset, $value) + { + $this->data[$offset] = $value; + } + + public function offsetUnset($offset) + { + unset($this->data[$offset]); + } + + /** + * Set a value into a nested array key. Keys will be created as needed to set the value. + * + * @param string $path Path to set + * @param mixed $value Value to set at the key + * + * @return self + * @throws RuntimeException when trying to setPath using a nested path that travels through a scalar value + */ + public function setPath($path, $value) + { + $current =& $this->data; + $queue = explode('/', $path); + while (null !== ($key = array_shift($queue))) { + if (!is_array($current)) { + throw new RuntimeException("Trying to setPath {$path}, but {$key} is set and is not an array"); + } elseif (!$queue) { + $current[$key] = $value; + } elseif (isset($current[$key])) { + $current =& $current[$key]; + } else { + $current[$key] = array(); + $current =& $current[$key]; + } + } + + return $this; + } + + /** + * Gets a value from the collection using an array path (e.g. foo/baz/bar would retrieve bar from two nested arrays) + * Allows for wildcard searches which recursively combine matches up to the level at which the wildcard occurs. This + * can be useful for accepting any key of a sub-array and combining matching keys from each diverging path. + * + * @param string $path Path to traverse and retrieve a value from + * @param string $separator Character used to add depth to the search + * @param mixed $data Optional data to descend into (used when wildcards are encountered) + * + * @return mixed|null + */ + public function getPath($path, $separator = '/', $data = null) + { + if ($data === null) { + $data =& $this->data; + } + + $path = is_array($path) ? $path : explode($separator, $path); + while (null !== ($part = array_shift($path))) { + if (!is_array($data)) { + return null; + } elseif (isset($data[$part])) { + $data =& $data[$part]; + } elseif ($part != '*') { + return null; + } else { + // Perform a wildcard search by diverging and merging paths + $result = array(); + foreach ($data as $value) { + if (!$path) { + $result = array_merge_recursive($result, (array) $value); + } elseif (null !== ($test = $this->getPath($path, $separator, $value))) { + $result = array_merge_recursive($result, (array) $test); + } + } + return $result; + } + } + + return $data; + } + + /** + * Inject configuration settings into an input string + * + * @param string $input Input to inject + * + * @return string + * @deprecated + */ + public function inject($input) + { + Version::warn(__METHOD__ . ' is deprecated'); + $replace = array(); + foreach ($this->data as $key => $val) { + $replace['{' . $key . '}'] = $val; + } + + return strtr($input, $replace); + } +} diff --git a/vendor/guzzle/guzzle/src/Guzzle/Common/Event.php b/vendor/guzzle/guzzle/src/Guzzle/Common/Event.php new file mode 100644 index 0000000..fad76a9 --- /dev/null +++ b/vendor/guzzle/guzzle/src/Guzzle/Common/Event.php @@ -0,0 +1,52 @@ +context = $context; + } + + public function getIterator() + { + return new \ArrayIterator($this->context); + } + + public function offsetGet($offset) + { + return isset($this->context[$offset]) ? $this->context[$offset] : null; + } + + public function offsetSet($offset, $value) + { + $this->context[$offset] = $value; + } + + public function offsetExists($offset) + { + return isset($this->context[$offset]); + } + + public function offsetUnset($offset) + { + unset($this->context[$offset]); + } + + public function toArray() + { + return $this->context; + } +} diff --git a/vendor/guzzle/guzzle/src/Guzzle/Common/Exception/BadMethodCallException.php b/vendor/guzzle/guzzle/src/Guzzle/Common/Exception/BadMethodCallException.php new file mode 100644 index 0000000..08d1c72 --- /dev/null +++ b/vendor/guzzle/guzzle/src/Guzzle/Common/Exception/BadMethodCallException.php @@ -0,0 +1,5 @@ +shortMessage = $message; + } + + /** + * Set all of the exceptions + * + * @param array $exceptions Array of exceptions + * + * @return self + */ + public function setExceptions(array $exceptions) + { + $this->exceptions = array(); + foreach ($exceptions as $exception) { + $this->add($exception); + } + + return $this; + } + + /** + * Add exceptions to the collection + * + * @param ExceptionCollection|\Exception $e Exception to add + * + * @return ExceptionCollection; + */ + public function add($e) + { + $this->exceptions[] = $e; + if ($this->message) { + $this->message .= "\n"; + } + + $this->message .= $this->getExceptionMessage($e, 0); + + return $this; + } + + /** + * Get the total number of request exceptions + * + * @return int + */ + public function count() + { + return count($this->exceptions); + } + + /** + * Allows array-like iteration over the request exceptions + * + * @return \ArrayIterator + */ + public function getIterator() + { + return new \ArrayIterator($this->exceptions); + } + + /** + * Get the first exception in the collection + * + * @return \Exception + */ + public function getFirst() + { + return $this->exceptions ? $this->exceptions[0] : null; + } + + private function getExceptionMessage(\Exception $e, $depth = 0) + { + static $sp = ' '; + $prefix = $depth ? str_repeat($sp, $depth) : ''; + $message = "{$prefix}(" . get_class($e) . ') ' . $e->getFile() . ' line ' . $e->getLine() . "\n"; + + if ($e instanceof self) { + if ($e->shortMessage) { + $message .= "\n{$prefix}{$sp}" . str_replace("\n", "\n{$prefix}{$sp}", $e->shortMessage) . "\n"; + } + foreach ($e as $ee) { + $message .= "\n" . $this->getExceptionMessage($ee, $depth + 1); + } + } else { + $message .= "\n{$prefix}{$sp}" . str_replace("\n", "\n{$prefix}{$sp}", $e->getMessage()) . "\n"; + $message .= "\n{$prefix}{$sp}" . str_replace("\n", "\n{$prefix}{$sp}", $e->getTraceAsString()) . "\n"; + } + + return str_replace(getcwd(), '.', $message); + } +} diff --git a/vendor/guzzle/guzzle/src/Guzzle/Common/Exception/GuzzleException.php b/vendor/guzzle/guzzle/src/Guzzle/Common/Exception/GuzzleException.php new file mode 100644 index 0000000..458e6f2 --- /dev/null +++ b/vendor/guzzle/guzzle/src/Guzzle/Common/Exception/GuzzleException.php @@ -0,0 +1,8 @@ +=5.3.2", + "symfony/event-dispatcher": ">=2.1" + }, + "autoload": { + "psr-0": { "Guzzle\\Common": "" } + }, + "target-dir": "Guzzle/Common", + "extra": { + "branch-alias": { + "dev-master": "3.7-dev" + } + } +} diff --git a/vendor/guzzle/guzzle/src/Guzzle/Http/AbstractEntityBodyDecorator.php b/vendor/guzzle/guzzle/src/Guzzle/Http/AbstractEntityBodyDecorator.php new file mode 100644 index 0000000..5005a88 --- /dev/null +++ b/vendor/guzzle/guzzle/src/Guzzle/Http/AbstractEntityBodyDecorator.php @@ -0,0 +1,221 @@ +body = $body; + } + + public function __toString() + { + return (string) $this->body; + } + + /** + * Allow decorators to implement custom methods + * + * @param string $method Missing method name + * @param array $args Method arguments + * + * @return mixed + */ + public function __call($method, array $args) + { + return call_user_func_array(array($this->body, $method), $args); + } + + public function close() + { + return $this->body->close(); + } + + public function setRewindFunction($callable) + { + $this->body->setRewindFunction($callable); + + return $this; + } + + public function rewind() + { + return $this->body->rewind(); + } + + public function compress($filter = 'zlib.deflate') + { + return $this->body->compress($filter); + } + + public function uncompress($filter = 'zlib.inflate') + { + return $this->body->uncompress($filter); + } + + public function getContentLength() + { + return $this->getSize(); + } + + public function getContentType() + { + return $this->body->getContentType(); + } + + public function getContentMd5($rawOutput = false, $base64Encode = false) + { + $hash = Stream::getHash($this, 'md5', $rawOutput); + + return $hash && $base64Encode ? base64_encode($hash) : $hash; + } + + public function getContentEncoding() + { + return $this->body->getContentEncoding(); + } + + public function getMetaData($key = null) + { + return $this->body->getMetaData($key); + } + + public function getStream() + { + return $this->body->getStream(); + } + + public function setStream($stream, $size = 0) + { + $this->body->setStream($stream, $size); + + return $this; + } + + public function detachStream() + { + $this->body->detachStream(); + + return $this; + } + + public function getWrapper() + { + return $this->body->getWrapper(); + } + + public function getWrapperData() + { + return $this->body->getWrapperData(); + } + + public function getStreamType() + { + return $this->body->getStreamType(); + } + + public function getUri() + { + return $this->body->getUri(); + } + + public function getSize() + { + return $this->body->getSize(); + } + + public function isReadable() + { + return $this->body->isReadable(); + } + + public function isRepeatable() + { + return $this->isSeekable() && $this->isReadable(); + } + + public function isWritable() + { + return $this->body->isWritable(); + } + + public function isConsumed() + { + return $this->body->isConsumed(); + } + + /** + * Alias of isConsumed() + * {@inheritdoc} + */ + public function feof() + { + return $this->isConsumed(); + } + + public function isLocal() + { + return $this->body->isLocal(); + } + + public function isSeekable() + { + return $this->body->isSeekable(); + } + + public function setSize($size) + { + $this->body->setSize($size); + + return $this; + } + + public function seek($offset, $whence = SEEK_SET) + { + return $this->body->seek($offset, $whence); + } + + public function read($length) + { + return $this->body->read($length); + } + + public function write($string) + { + return $this->body->write($string); + } + + public function readLine($maxLength = null) + { + return $this->body->readLine($maxLength); + } + + public function ftell() + { + return $this->body->ftell(); + } + + public function getCustomData($key) + { + return $this->body->getCustomData($key); + } + + public function setCustomData($key, $value) + { + $this->body->setCustomData($key, $value); + + return $this; + } +} diff --git a/vendor/guzzle/guzzle/src/Guzzle/Http/CachingEntityBody.php b/vendor/guzzle/guzzle/src/Guzzle/Http/CachingEntityBody.php new file mode 100644 index 0000000..c65c136 --- /dev/null +++ b/vendor/guzzle/guzzle/src/Guzzle/Http/CachingEntityBody.php @@ -0,0 +1,229 @@ +remoteStream = $body; + $this->body = new EntityBody(fopen('php://temp', 'r+')); + } + + /** + * Will give the contents of the buffer followed by the exhausted remote stream. + * + * Warning: Loads the entire stream into memory + * + * @return string + */ + public function __toString() + { + $pos = $this->ftell(); + $this->rewind(); + + $str = ''; + while (!$this->isConsumed()) { + $str .= $this->read(16384); + } + + $this->seek($pos); + + return $str; + } + + public function getSize() + { + return max($this->body->getSize(), $this->remoteStream->getSize()); + } + + /** + * {@inheritdoc} + * @throws RuntimeException When seeking with SEEK_END or when seeking past the total size of the buffer stream + */ + public function seek($offset, $whence = SEEK_SET) + { + if ($whence == SEEK_SET) { + $byte = $offset; + } elseif ($whence == SEEK_CUR) { + $byte = $offset + $this->ftell(); + } else { + throw new RuntimeException(__CLASS__ . ' supports only SEEK_SET and SEEK_CUR seek operations'); + } + + // You cannot skip ahead past where you've read from the remote stream + if ($byte > $this->body->getSize()) { + throw new RuntimeException( + "Cannot seek to byte {$byte} when the buffered stream only contains {$this->body->getSize()} bytes" + ); + } + + return $this->body->seek($byte); + } + + public function rewind() + { + return $this->seek(0); + } + + /** + * Does not support custom rewind functions + * + * @throws RuntimeException + */ + public function setRewindFunction($callable) + { + throw new RuntimeException(__CLASS__ . ' does not support custom stream rewind functions'); + } + + public function read($length) + { + // Perform a regular read on any previously read data from the buffer + $data = $this->body->read($length); + $remaining = $length - strlen($data); + + // More data was requested so read from the remote stream + if ($remaining) { + // If data was written to the buffer in a position that would have been filled from the remote stream, + // then we must skip bytes on the remote stream to emulate overwriting bytes from that position. This + // mimics the behavior of other PHP stream wrappers. + $remoteData = $this->remoteStream->read($remaining + $this->skipReadBytes); + + if ($this->skipReadBytes) { + $len = strlen($remoteData); + $remoteData = substr($remoteData, $this->skipReadBytes); + $this->skipReadBytes = max(0, $this->skipReadBytes - $len); + } + + $data .= $remoteData; + $this->body->write($remoteData); + } + + return $data; + } + + public function write($string) + { + // When appending to the end of the currently read stream, you'll want to skip bytes from being read from + // the remote stream to emulate other stream wrappers. Basically replacing bytes of data of a fixed length. + $overflow = (strlen($string) + $this->ftell()) - $this->remoteStream->ftell(); + if ($overflow > 0) { + $this->skipReadBytes += $overflow; + } + + return $this->body->write($string); + } + + /** + * {@inheritdoc} + * @link http://php.net/manual/en/function.fgets.php + */ + public function readLine($maxLength = null) + { + $buffer = ''; + $size = 0; + while (!$this->isConsumed()) { + $byte = $this->read(1); + $buffer .= $byte; + // Break when a new line is found or the max length - 1 is reached + if ($byte == PHP_EOL || ++$size == $maxLength - 1) { + break; + } + } + + return $buffer; + } + + public function isConsumed() + { + return $this->body->isConsumed() && $this->remoteStream->isConsumed(); + } + + /** + * Close both the remote stream and buffer stream + */ + public function close() + { + return $this->remoteStream->close() && $this->body->close(); + } + + public function setStream($stream, $size = 0) + { + $this->remoteStream->setStream($stream, $size); + } + + public function getContentType() + { + return $this->remoteStream->getContentType(); + } + + public function getContentEncoding() + { + return $this->remoteStream->getContentEncoding(); + } + + public function getMetaData($key = null) + { + return $this->remoteStream->getMetaData($key); + } + + public function getStream() + { + return $this->remoteStream->getStream(); + } + + public function getWrapper() + { + return $this->remoteStream->getWrapper(); + } + + public function getWrapperData() + { + return $this->remoteStream->getWrapperData(); + } + + public function getStreamType() + { + return $this->remoteStream->getStreamType(); + } + + public function getUri() + { + return $this->remoteStream->getUri(); + } + + /** + * Always retrieve custom data from the remote stream + * {@inheritdoc} + */ + public function getCustomData($key) + { + return $this->remoteStream->getCustomData($key); + } + + /** + * Always set custom data on the remote stream + * {@inheritdoc} + */ + public function setCustomData($key, $value) + { + $this->remoteStream->setCustomData($key, $value); + + return $this; + } +} diff --git a/vendor/guzzle/guzzle/src/Guzzle/Http/Client.php b/vendor/guzzle/guzzle/src/Guzzle/Http/Client.php new file mode 100644 index 0000000..3d7298d --- /dev/null +++ b/vendor/guzzle/guzzle/src/Guzzle/Http/Client.php @@ -0,0 +1,524 @@ +setConfig($config ?: new Collection()); + $this->initSsl(); + $this->setBaseUrl($baseUrl); + $this->defaultHeaders = new Collection(); + $this->setRequestFactory(RequestFactory::getInstance()); + $this->userAgent = $this->getDefaultUserAgent(); + if (!$this->config[self::DISABLE_REDIRECTS]) { + $this->addSubscriber(new RedirectPlugin()); + } + } + + final public function setConfig($config) + { + if ($config instanceof Collection) { + $this->config = $config; + } elseif (is_array($config)) { + $this->config = new Collection($config); + } else { + throw new InvalidArgumentException('Config must be an array or Collection'); + } + + return $this; + } + + final public function getConfig($key = false) + { + return $key ? $this->config[$key] : $this->config; + } + + /** + * Set a default request option on the client that will be used as a default for each request + * + * @param string $keyOrPath request.options key (e.g. allow_redirects) or path to a nested key (e.g. headers/foo) + * @param mixed $value Value to set + * + * @return $this + */ + public function setDefaultOption($keyOrPath, $value) + { + $keyOrPath = self::REQUEST_OPTIONS . '/' . $keyOrPath; + $this->config->setPath($keyOrPath, $value); + + return $this; + } + + /** + * Retrieve a default request option from the client + * + * @param string $keyOrPath request.options key (e.g. allow_redirects) or path to a nested key (e.g. headers/foo) + * + * @return mixed|null + */ + public function getDefaultOption($keyOrPath) + { + $keyOrPath = self::REQUEST_OPTIONS . '/' . $keyOrPath; + + return $this->config->getPath($keyOrPath); + } + + final public function setSslVerification($certificateAuthority = true, $verifyPeer = true, $verifyHost = 2) + { + $opts = $this->config[self::CURL_OPTIONS] ?: array(); + + if ($certificateAuthority === true) { + // use bundled CA bundle, set secure defaults + $opts[CURLOPT_CAINFO] = __DIR__ . '/Resources/cacert.pem'; + $opts[CURLOPT_SSL_VERIFYPEER] = true; + $opts[CURLOPT_SSL_VERIFYHOST] = 2; + } elseif ($certificateAuthority === false) { + unset($opts[CURLOPT_CAINFO]); + $opts[CURLOPT_SSL_VERIFYPEER] = false; + $opts[CURLOPT_SSL_VERIFYHOST] = 0; + } elseif ($verifyPeer !== true && $verifyPeer !== false && $verifyPeer !== 1 && $verifyPeer !== 0) { + throw new InvalidArgumentException('verifyPeer must be 1, 0 or boolean'); + } elseif ($verifyHost !== 0 && $verifyHost !== 1 && $verifyHost !== 2) { + throw new InvalidArgumentException('verifyHost must be 0, 1 or 2'); + } else { + $opts[CURLOPT_SSL_VERIFYPEER] = $verifyPeer; + $opts[CURLOPT_SSL_VERIFYHOST] = $verifyHost; + if (is_file($certificateAuthority)) { + unset($opts[CURLOPT_CAPATH]); + $opts[CURLOPT_CAINFO] = $certificateAuthority; + } elseif (is_dir($certificateAuthority)) { + unset($opts[CURLOPT_CAINFO]); + $opts[CURLOPT_CAPATH] = $certificateAuthority; + } else { + throw new RuntimeException( + 'Invalid option passed to ' . self::SSL_CERT_AUTHORITY . ': ' . $certificateAuthority + ); + } + } + + $this->config->set(self::CURL_OPTIONS, $opts); + + return $this; + } + + public function createRequest($method = 'GET', $uri = null, $headers = null, $body = null, array $options = array()) + { + if (!$uri) { + $url = $this->getBaseUrl(); + } else { + if (!is_array($uri)) { + $templateVars = null; + } else { + list($uri, $templateVars) = $uri; + } + if (strpos($uri, '://')) { + // Use absolute URLs as-is + $url = $this->expandTemplate($uri, $templateVars); + } else { + $url = Url::factory($this->getBaseUrl())->combine($this->expandTemplate($uri, $templateVars)); + } + } + + // If default headers are provided, then merge them under any explicitly provided headers for the request + if (count($this->defaultHeaders)) { + if (!$headers) { + $headers = $this->defaultHeaders->toArray(); + } elseif (is_array($headers)) { + $headers += $this->defaultHeaders->toArray(); + } elseif ($headers instanceof Collection) { + $headers = $headers->toArray() + $this->defaultHeaders->toArray(); + } + } + + return $this->prepareRequest($this->requestFactory->create($method, (string) $url, $headers, $body), $options); + } + + public function getBaseUrl($expand = true) + { + return $expand ? $this->expandTemplate($this->baseUrl) : $this->baseUrl; + } + + public function setBaseUrl($url) + { + $this->baseUrl = $url; + + return $this; + } + + public function setUserAgent($userAgent, $includeDefault = false) + { + if ($includeDefault) { + $userAgent .= ' ' . $this->getDefaultUserAgent(); + } + $this->userAgent = $userAgent; + + return $this; + } + + /** + * Get the default User-Agent string to use with Guzzle + * + * @return string + */ + public function getDefaultUserAgent() + { + return 'Guzzle/' . Version::VERSION + . ' curl/' . CurlVersion::getInstance()->get('version') + . ' PHP/' . PHP_VERSION; + } + + public function get($uri = null, $headers = null, $options = array()) + { + // BC compat: $options can be a string, resource, etc to specify where the response body is downloaded + return is_array($options) + ? $this->createRequest('GET', $uri, $headers, null, $options) + : $this->createRequest('GET', $uri, $headers, $options); + } + + public function head($uri = null, $headers = null, array $options = array()) + { + return $this->createRequest('HEAD', $uri, $headers, null, $options); + } + + public function delete($uri = null, $headers = null, $body = null, array $options = array()) + { + return $this->createRequest('DELETE', $uri, $headers, $body, $options); + } + + public function put($uri = null, $headers = null, $body = null, array $options = array()) + { + return $this->createRequest('PUT', $uri, $headers, $body, $options); + } + + public function patch($uri = null, $headers = null, $body = null, array $options = array()) + { + return $this->createRequest('PATCH', $uri, $headers, $body, $options); + } + + public function post($uri = null, $headers = null, $postBody = null, array $options = array()) + { + return $this->createRequest('POST', $uri, $headers, $postBody, $options); + } + + public function options($uri = null, array $options = array()) + { + return $this->createRequest('OPTIONS', $uri, $options); + } + + public function send($requests) + { + if (!($requests instanceof RequestInterface)) { + return $this->sendMultiple($requests); + } + + try { + /** @var $requests RequestInterface */ + $this->getCurlMulti()->add($requests)->send(); + return $requests->getResponse(); + } catch (ExceptionCollection $e) { + throw $e->getFirst(); + } + } + + /** + * Set a curl multi object to be used internally by the client for transferring requests. + * + * @param CurlMultiInterface $curlMulti Multi object + * + * @return self + */ + public function setCurlMulti(CurlMultiInterface $curlMulti) + { + $this->curlMulti = $curlMulti; + + return $this; + } + + /** + * @return CurlMultiInterface|CurlMultiProxy + */ + public function getCurlMulti() + { + if (!$this->curlMulti) { + $this->curlMulti = new CurlMultiProxy( + self::MAX_HANDLES, + $this->getConfig('select_timeout') ?: self::DEFAULT_SELECT_TIMEOUT + ); + } + + return $this->curlMulti; + } + + public function setRequestFactory(RequestFactoryInterface $factory) + { + $this->requestFactory = $factory; + + return $this; + } + + /** + * Set the URI template expander to use with the client + * + * @param UriTemplateInterface $uriTemplate URI template expander + * + * @return self + */ + public function setUriTemplate(UriTemplateInterface $uriTemplate) + { + $this->uriTemplate = $uriTemplate; + + return $this; + } + + /** + * Expand a URI template while merging client config settings into the template variables + * + * @param string $template Template to expand + * @param array $variables Variables to inject + * + * @return string + */ + protected function expandTemplate($template, array $variables = null) + { + $expansionVars = $this->getConfig()->toArray(); + if ($variables) { + $expansionVars = $variables + $expansionVars; + } + + return $this->getUriTemplate()->expand($template, $expansionVars); + } + + /** + * Get the URI template expander used by the client + * + * @return UriTemplateInterface + */ + protected function getUriTemplate() + { + if (!$this->uriTemplate) { + $this->uriTemplate = ParserRegistry::getInstance()->getParser('uri_template'); + } + + return $this->uriTemplate; + } + + /** + * Send multiple requests in parallel + * + * @param array $requests Array of RequestInterface objects + * + * @return array Returns an array of Response objects + */ + protected function sendMultiple(array $requests) + { + $curlMulti = $this->getCurlMulti(); + foreach ($requests as $request) { + $curlMulti->add($request); + } + $curlMulti->send(); + + /** @var $request RequestInterface */ + $result = array(); + foreach ($requests as $request) { + $result[] = $request->getResponse(); + } + + return $result; + } + + /** + * Prepare a request to be sent from the Client by adding client specific behaviors and properties to the request. + * + * @param RequestInterface $request Request to prepare for the client + * @param array $options Options to apply to the request + * + * @return RequestInterface + */ + protected function prepareRequest(RequestInterface $request, array $options = array()) + { + $request->setClient($this)->setEventDispatcher(clone $this->getEventDispatcher()); + + if ($curl = $this->config[self::CURL_OPTIONS]) { + $request->getCurlOptions()->overwriteWith(CurlHandle::parseCurlConfig($curl)); + } + + if ($params = $this->config[self::REQUEST_PARAMS]) { + Version::warn('request.params is deprecated. Use request.options to add default request options.'); + $request->getParams()->overwriteWith($params); + } + + if ($this->userAgent && !$request->hasHeader('User-Agent')) { + $request->setHeader('User-Agent', $this->userAgent); + } + + if ($defaults = $this->config[self::REQUEST_OPTIONS]) { + $this->requestFactory->applyOptions($request, $defaults, RequestFactoryInterface::OPTIONS_AS_DEFAULTS); + } + + if ($options) { + $this->requestFactory->applyOptions($request, $options); + } + + $this->dispatch('client.create_request', array('client' => $this, 'request' => $request)); + + return $request; + } + + /** + * Initializes SSL settings + */ + protected function initSsl() + { + $authority = $this->config[self::SSL_CERT_AUTHORITY]; + + if ($authority === 'system') { + return; + } + + if ($authority === null) { + $authority = true; + } + + if ($authority === true && substr(__FILE__, 0, 7) == 'phar://') { + $authority = self::extractPharCacert(__DIR__ . '/Resources/cacert.pem'); + } + + $this->setSslVerification($authority); + } + + /** + * @deprecated + */ + public function getDefaultHeaders() + { + Version::warn(__METHOD__ . ' is deprecated. Use the request.options array to retrieve default request options'); + return $this->defaultHeaders; + } + + /** + * @deprecated + */ + public function setDefaultHeaders($headers) + { + Version::warn(__METHOD__ . ' is deprecated. Use the request.options array to specify default request options'); + if ($headers instanceof Collection) { + $this->defaultHeaders = $headers; + } elseif (is_array($headers)) { + $this->defaultHeaders = new Collection($headers); + } else { + throw new InvalidArgumentException('Headers must be an array or Collection'); + } + + return $this; + } + + /** + * @deprecated + */ + public function preparePharCacert($md5Check = true) + { + return sys_get_temp_dir() . '/guzzle-cacert.pem'; + } + + /** + * Copies the phar cacert from a phar into the temp directory. + * + * @param string $pharCacertPath Path to the phar cacert. For example: + * 'phar://aws.phar/Guzzle/Http/Resources/cacert.pem' + * + * @return string Returns the path to the extracted cacert file. + * @throws \RuntimeException Throws if the phar cacert cannot be found or + * the file cannot be copied to the temp dir. + */ + public static function extractPharCacert($pharCacertPath) + { + // Copy the cacert.pem file from the phar if it is not in the temp + // folder. + $certFile = sys_get_temp_dir() . '/guzzle-cacert.pem'; + + if (!file_exists($pharCacertPath)) { + throw new \RuntimeException("Could not find $pharCacertPath"); + } + + if (!file_exists($certFile) || + filesize($certFile) != filesize($pharCacertPath) + ) { + if (!copy($pharCacertPath, $certFile)) { + throw new \RuntimeException( + "Could not copy {$pharCacertPath} to {$certFile}: " + . var_export(error_get_last(), true) + ); + } + } + + return $certFile; + } +} diff --git a/vendor/guzzle/guzzle/src/Guzzle/Http/ClientInterface.php b/vendor/guzzle/guzzle/src/Guzzle/Http/ClientInterface.php new file mode 100644 index 0000000..10e4de2 --- /dev/null +++ b/vendor/guzzle/guzzle/src/Guzzle/Http/ClientInterface.php @@ -0,0 +1,223 @@ +getCurlOptions(); + $mediator = new RequestMediator($request, $requestCurlOptions->get('emit_io')); + $tempContentLength = null; + $method = $request->getMethod(); + $bodyAsString = $requestCurlOptions->get(self::BODY_AS_STRING); + + // Prepare url + $url = (string)$request->getUrl(); + if(($pos = strpos($url, '#')) !== false ){ + // strip fragment from url + $url = substr($url, 0, $pos); + } + + // Array of default cURL options. + $curlOptions = array( + CURLOPT_URL => $url, + CURLOPT_CONNECTTIMEOUT => 150, + CURLOPT_RETURNTRANSFER => false, + CURLOPT_HEADER => false, + CURLOPT_PORT => $request->getPort(), + CURLOPT_HTTPHEADER => array(), + CURLOPT_WRITEFUNCTION => array($mediator, 'writeResponseBody'), + CURLOPT_HEADERFUNCTION => array($mediator, 'receiveResponseHeader'), + CURLOPT_HTTP_VERSION => $request->getProtocolVersion() === '1.0' + ? CURL_HTTP_VERSION_1_0 : CURL_HTTP_VERSION_1_1, + // Verifies the authenticity of the peer's certificate + CURLOPT_SSL_VERIFYPEER => 1, + // Certificate must indicate that the server is the server to which you meant to connect + CURLOPT_SSL_VERIFYHOST => 2 + ); + + if (defined('CURLOPT_PROTOCOLS')) { + // Allow only HTTP and HTTPS protocols + $curlOptions[CURLOPT_PROTOCOLS] = CURLPROTO_HTTP | CURLPROTO_HTTPS; + } + + // Add CURLOPT_ENCODING if Accept-Encoding header is provided + if ($acceptEncodingHeader = $request->getHeader('Accept-Encoding')) { + $curlOptions[CURLOPT_ENCODING] = (string) $acceptEncodingHeader; + // Let cURL set the Accept-Encoding header, prevents duplicate values + $request->removeHeader('Accept-Encoding'); + } + + // Enable curl debug information if the 'debug' param was set + if ($requestCurlOptions->get('debug')) { + $curlOptions[CURLOPT_STDERR] = fopen('php://temp', 'r+'); + // @codeCoverageIgnoreStart + if (false === $curlOptions[CURLOPT_STDERR]) { + throw new RuntimeException('Unable to create a stream for CURLOPT_STDERR'); + } + // @codeCoverageIgnoreEnd + $curlOptions[CURLOPT_VERBOSE] = true; + } + + // Specify settings according to the HTTP method + if ($method == 'GET') { + $curlOptions[CURLOPT_HTTPGET] = true; + } elseif ($method == 'HEAD') { + $curlOptions[CURLOPT_NOBODY] = true; + // HEAD requests do not use a write function + unset($curlOptions[CURLOPT_WRITEFUNCTION]); + } elseif (!($request instanceof EntityEnclosingRequest)) { + $curlOptions[CURLOPT_CUSTOMREQUEST] = $method; + } else { + + $curlOptions[CURLOPT_CUSTOMREQUEST] = $method; + + // Handle sending raw bodies in a request + if ($request->getBody()) { + // You can send the body as a string using curl's CURLOPT_POSTFIELDS + if ($bodyAsString) { + $curlOptions[CURLOPT_POSTFIELDS] = (string) $request->getBody(); + // Allow curl to add the Content-Length for us to account for the times when + // POST redirects are followed by GET requests + if ($tempContentLength = $request->getHeader('Content-Length')) { + $tempContentLength = (int) (string) $tempContentLength; + } + // Remove the curl generated Content-Type header if none was set manually + if (!$request->hasHeader('Content-Type')) { + $curlOptions[CURLOPT_HTTPHEADER][] = 'Content-Type:'; + } + } else { + $curlOptions[CURLOPT_UPLOAD] = true; + // Let cURL handle setting the Content-Length header + if ($tempContentLength = $request->getHeader('Content-Length')) { + $tempContentLength = (int) (string) $tempContentLength; + $curlOptions[CURLOPT_INFILESIZE] = $tempContentLength; + } + // Add a callback for curl to read data to send with the request only if a body was specified + $curlOptions[CURLOPT_READFUNCTION] = array($mediator, 'readRequestBody'); + // Attempt to seek to the start of the stream + $request->getBody()->seek(0); + } + + } else { + + // Special handling for POST specific fields and files + $postFields = false; + if (count($request->getPostFiles())) { + $postFields = $request->getPostFields()->useUrlEncoding(false)->urlEncode(); + foreach ($request->getPostFiles() as $key => $data) { + $prefixKeys = count($data) > 1; + foreach ($data as $index => $file) { + // Allow multiple files in the same key + $fieldKey = $prefixKeys ? "{$key}[{$index}]" : $key; + $postFields[$fieldKey] = $file->getCurlValue(); + } + } + } elseif (count($request->getPostFields())) { + $postFields = (string) $request->getPostFields()->useUrlEncoding(true); + } + + if ($postFields !== false) { + if ($method == 'POST') { + unset($curlOptions[CURLOPT_CUSTOMREQUEST]); + $curlOptions[CURLOPT_POST] = true; + } + $curlOptions[CURLOPT_POSTFIELDS] = $postFields; + $request->removeHeader('Content-Length'); + } + } + + // If the Expect header is not present, prevent curl from adding it + if (!$request->hasHeader('Expect')) { + $curlOptions[CURLOPT_HTTPHEADER][] = 'Expect:'; + } + } + + // If a Content-Length header was specified but we want to allow curl to set one for us + if (null !== $tempContentLength) { + $request->removeHeader('Content-Length'); + } + + // Set custom cURL options + foreach ($requestCurlOptions->toArray() as $key => $value) { + if (is_numeric($key)) { + $curlOptions[$key] = $value; + } + } + + // Do not set an Accept header by default + if (!isset($curlOptions[CURLOPT_ENCODING])) { + $curlOptions[CURLOPT_HTTPHEADER][] = 'Accept:'; + } + + // Add any custom headers to the request. Empty headers will cause curl to not send the header at all. + foreach ($request->getHeaderLines() as $line) { + $curlOptions[CURLOPT_HTTPHEADER][] = $line; + } + + // Add the content-length header back if it was temporarily removed + if (null !== $tempContentLength) { + $request->setHeader('Content-Length', $tempContentLength); + } + + // Apply the options to a new cURL handle. + $handle = curl_init(); + + // Enable the progress function if the 'progress' param was set + if ($requestCurlOptions->get('progress')) { + // Wrap the function in a function that provides the curl handle to the mediator's progress function + // Using this rather than injecting the handle into the mediator prevents a circular reference + $curlOptions[CURLOPT_PROGRESSFUNCTION] = function () use ($mediator, $handle) { + $args = func_get_args(); + $args[] = $handle; + + // PHP 5.5 pushed the handle onto the start of the args + if (is_resource($args[0])) { + array_shift($args); + } + + call_user_func_array(array($mediator, 'progress'), $args); + }; + $curlOptions[CURLOPT_NOPROGRESS] = false; + } + + curl_setopt_array($handle, $curlOptions); + + return new static($handle, $curlOptions); + } + + /** + * Construct a new CurlHandle object that wraps a cURL handle + * + * @param resource $handle Configured cURL handle resource + * @param Collection|array $options Curl options to use with the handle + * + * @throws InvalidArgumentException + */ + public function __construct($handle, $options) + { + if (!is_resource($handle)) { + throw new InvalidArgumentException('Invalid handle provided'); + } + if (is_array($options)) { + $this->options = new Collection($options); + } elseif ($options instanceof Collection) { + $this->options = $options; + } else { + throw new InvalidArgumentException('Expected array or Collection'); + } + $this->handle = $handle; + } + + /** + * Destructor + */ + public function __destruct() + { + $this->close(); + } + + /** + * Close the curl handle + */ + public function close() + { + if (is_resource($this->handle)) { + curl_close($this->handle); + } + $this->handle = null; + } + + /** + * Check if the handle is available and still OK + * + * @return bool + */ + public function isAvailable() + { + return is_resource($this->handle); + } + + /** + * Get the last error that occurred on the cURL handle + * + * @return string + */ + public function getError() + { + return $this->isAvailable() ? curl_error($this->handle) : ''; + } + + /** + * Get the last error number that occurred on the cURL handle + * + * @return int + */ + public function getErrorNo() + { + if ($this->errorNo) { + return $this->errorNo; + } + + return $this->isAvailable() ? curl_errno($this->handle) : CURLE_OK; + } + + /** + * Set the curl error number + * + * @param int $error Error number to set + * + * @return CurlHandle + */ + public function setErrorNo($error) + { + $this->errorNo = $error; + + return $this; + } + + /** + * Get cURL curl_getinfo data + * + * @param int $option Option to retrieve. Pass null to retrieve all data as an array. + * + * @return array|mixed + */ + public function getInfo($option = null) + { + if (!is_resource($this->handle)) { + return null; + } + + if (null !== $option) { + return curl_getinfo($this->handle, $option) ?: null; + } + + return curl_getinfo($this->handle) ?: array(); + } + + /** + * Get the stderr output + * + * @param bool $asResource Set to TRUE to get an fopen resource + * + * @return string|resource|null + */ + public function getStderr($asResource = false) + { + $stderr = $this->getOptions()->get(CURLOPT_STDERR); + if (!$stderr) { + return null; + } + + if ($asResource) { + return $stderr; + } + + fseek($stderr, 0); + $e = stream_get_contents($stderr); + fseek($stderr, 0, SEEK_END); + + return $e; + } + + /** + * Get the URL that this handle is connecting to + * + * @return Url + */ + public function getUrl() + { + return Url::factory($this->options->get(CURLOPT_URL)); + } + + /** + * Get the wrapped curl handle + * + * @return resource|null Returns the cURL handle or null if it was closed + */ + public function getHandle() + { + return $this->isAvailable() ? $this->handle : null; + } + + /** + * Get the cURL setopt options of the handle. Changing values in the return object will have no effect on the curl + * handle after it is created. + * + * @return Collection + */ + public function getOptions() + { + return $this->options; + } + + /** + * Update a request based on the log messages of the CurlHandle + * + * @param RequestInterface $request Request to update + */ + public function updateRequestFromTransfer(RequestInterface $request) + { + if (!$request->getResponse()) { + return; + } + + // Update the transfer stats of the response + $request->getResponse()->setInfo($this->getInfo()); + + if (!$log = $this->getStderr(true)) { + return; + } + + // Parse the cURL stderr output for outgoing requests + $headers = ''; + fseek($log, 0); + while (($line = fgets($log)) !== false) { + if ($line && $line[0] == '>') { + $headers = substr(trim($line), 2) . "\r\n"; + while (($line = fgets($log)) !== false) { + if ($line[0] == '*' || $line[0] == '<') { + break; + } else { + $headers .= trim($line) . "\r\n"; + } + } + } + } + + // Add request headers to the request exactly as they were sent + if ($headers) { + $parsed = ParserRegistry::getInstance()->getParser('message')->parseRequest($headers); + if (!empty($parsed['headers'])) { + $request->setHeaders(array()); + foreach ($parsed['headers'] as $name => $value) { + $request->setHeader($name, $value); + } + } + if (!empty($parsed['version'])) { + $request->setProtocolVersion($parsed['version']); + } + } + } + + /** + * Parse the config and replace curl.* configurators into the constant based values so it can be used elsewhere + * + * @param array|Collection $config The configuration we want to parse + * + * @return array + */ + public static function parseCurlConfig($config) + { + $curlOptions = array(); + foreach ($config as $key => $value) { + if (is_string($key) && defined($key)) { + // Convert constants represented as string to constant int values + $key = constant($key); + } + if (is_string($value) && defined($value)) { + $value = constant($value); + } + $curlOptions[$key] = $value; + } + + return $curlOptions; + } +} diff --git a/vendor/guzzle/guzzle/src/Guzzle/Http/Curl/CurlMulti.php b/vendor/guzzle/guzzle/src/Guzzle/Http/Curl/CurlMulti.php new file mode 100644 index 0000000..9e4e637 --- /dev/null +++ b/vendor/guzzle/guzzle/src/Guzzle/Http/Curl/CurlMulti.php @@ -0,0 +1,423 @@ + array('CURLM_BAD_HANDLE', 'The passed-in handle is not a valid CURLM handle.'), + CURLM_BAD_EASY_HANDLE => array('CURLM_BAD_EASY_HANDLE', "An easy handle was not good/valid. It could mean that it isn't an easy handle at all, or possibly that the handle already is in used by this or another multi handle."), + CURLM_OUT_OF_MEMORY => array('CURLM_OUT_OF_MEMORY', 'You are doomed.'), + CURLM_INTERNAL_ERROR => array('CURLM_INTERNAL_ERROR', 'This can only be returned if libcurl bugs. Please report it to us!') + ); + + /** @var float */ + protected $selectTimeout; + + public function __construct($selectTimeout = 1.0) + { + $this->selectTimeout = $selectTimeout; + $this->multiHandle = curl_multi_init(); + // @codeCoverageIgnoreStart + if ($this->multiHandle === false) { + throw new CurlException('Unable to create multi handle'); + } + // @codeCoverageIgnoreEnd + $this->reset(); + } + + public function __destruct() + { + if (is_resource($this->multiHandle)) { + curl_multi_close($this->multiHandle); + } + } + + public function add(RequestInterface $request) + { + $this->requests[] = $request; + // If requests are currently transferring and this is async, then the + // request must be prepared now as the send() method is not called. + $this->beforeSend($request); + $this->dispatch(self::ADD_REQUEST, array('request' => $request)); + + return $this; + } + + public function all() + { + return $this->requests; + } + + public function remove(RequestInterface $request) + { + $this->removeHandle($request); + if (($index = array_search($request, $this->requests, true)) !== false) { + $request = $this->requests[$index]; + unset($this->requests[$index]); + $this->requests = array_values($this->requests); + $this->dispatch(self::REMOVE_REQUEST, array('request' => $request)); + return true; + } + + return false; + } + + public function reset($hard = false) + { + // Remove each request + if ($this->requests) { + foreach ($this->requests as $request) { + $this->remove($request); + } + } + + $this->handles = new \SplObjectStorage(); + $this->requests = $this->resourceHash = $this->exceptions = $this->successful = array(); + } + + public function send() + { + $this->perform(); + $exceptions = $this->exceptions; + $successful = $this->successful; + $this->reset(); + + if ($exceptions) { + $this->throwMultiException($exceptions, $successful); + } + } + + public function count() + { + return count($this->requests); + } + + /** + * Build and throw a MultiTransferException + * + * @param array $exceptions Exceptions encountered + * @param array $successful Successful requests + * @throws MultiTransferException + */ + protected function throwMultiException(array $exceptions, array $successful) + { + $multiException = new MultiTransferException('Errors during multi transfer'); + + while ($e = array_shift($exceptions)) { + $multiException->addFailedRequestWithException($e['request'], $e['exception']); + } + + // Add successful requests + foreach ($successful as $request) { + if (!$multiException->containsRequest($request)) { + $multiException->addSuccessfulRequest($request); + } + } + + throw $multiException; + } + + /** + * Prepare for sending + * + * @param RequestInterface $request Request to prepare + * @throws \Exception on error preparing the request + */ + protected function beforeSend(RequestInterface $request) + { + try { + $state = $request->setState(RequestInterface::STATE_TRANSFER); + if ($state == RequestInterface::STATE_TRANSFER) { + $this->addHandle($request); + } else { + // Requests might decide they don't need to be sent just before + // transfer (e.g. CachePlugin) + $this->remove($request); + if ($state == RequestInterface::STATE_COMPLETE) { + $this->successful[] = $request; + } + } + } catch (\Exception $e) { + // Queue the exception to be thrown when sent + $this->removeErroredRequest($request, $e); + } + } + + private function addHandle(RequestInterface $request) + { + $handle = $this->createCurlHandle($request)->getHandle(); + $this->checkCurlResult( + curl_multi_add_handle($this->multiHandle, $handle) + ); + } + + /** + * Create a curl handle for a request + * + * @param RequestInterface $request Request + * + * @return CurlHandle + */ + protected function createCurlHandle(RequestInterface $request) + { + $wrapper = CurlHandle::factory($request); + $this->handles[$request] = $wrapper; + $this->resourceHash[(int) $wrapper->getHandle()] = $request; + + return $wrapper; + } + + /** + * Get the data from the multi handle + */ + protected function perform() + { + $event = new Event(array('curl_multi' => $this)); + + while ($this->requests) { + // Notify each request as polling + $blocking = $total = 0; + foreach ($this->requests as $request) { + ++$total; + $event['request'] = $request; + $request->getEventDispatcher()->dispatch(self::POLLING_REQUEST, $event); + // The blocking variable just has to be non-falsey to block the loop + if ($request->getParams()->hasKey(self::BLOCKING)) { + ++$blocking; + } + } + if ($blocking == $total) { + // Sleep to prevent eating CPU because no requests are actually pending a select call + usleep(500); + } else { + $this->executeHandles(); + } + } + } + + /** + * Execute and select curl handles + */ + private function executeHandles() + { + // The first curl_multi_select often times out no matter what, but is usually required for fast transfers + $selectTimeout = 0.001; + $active = false; + do { + while (($mrc = curl_multi_exec($this->multiHandle, $active)) == CURLM_CALL_MULTI_PERFORM); + $this->checkCurlResult($mrc); + $this->processMessages(); + if ($active && curl_multi_select($this->multiHandle, $selectTimeout) === -1) { + // Perform a usleep if a select returns -1: https://bugs.php.net/bug.php?id=61141 + usleep(150); + } + $selectTimeout = $this->selectTimeout; + } while ($active); + } + + /** + * Process any received curl multi messages + */ + private function processMessages() + { + while ($done = curl_multi_info_read($this->multiHandle)) { + $request = $this->resourceHash[(int) $done['handle']]; + try { + $this->processResponse($request, $this->handles[$request], $done); + $this->successful[] = $request; + } catch (\Exception $e) { + $this->removeErroredRequest($request, $e); + } + } + } + + /** + * Remove a request that encountered an exception + * + * @param RequestInterface $request Request to remove + * @param \Exception $e Exception encountered + */ + protected function removeErroredRequest(RequestInterface $request, \Exception $e = null) + { + $this->exceptions[] = array('request' => $request, 'exception' => $e); + $this->remove($request); + $this->dispatch(self::MULTI_EXCEPTION, array('exception' => $e, 'all_exceptions' => $this->exceptions)); + } + + /** + * Check for errors and fix headers of a request based on a curl response + * + * @param RequestInterface $request Request to process + * @param CurlHandle $handle Curl handle object + * @param array $curl Array returned from curl_multi_info_read + * + * @throws CurlException on Curl error + */ + protected function processResponse(RequestInterface $request, CurlHandle $handle, array $curl) + { + // Set the transfer stats on the response + $handle->updateRequestFromTransfer($request); + // Check if a cURL exception occurred, and if so, notify things + $curlException = $this->isCurlException($request, $handle, $curl); + + // Always remove completed curl handles. They can be added back again + // via events if needed (e.g. ExponentialBackoffPlugin) + $this->removeHandle($request); + + if (!$curlException) { + if ($this->validateResponseWasSet($request)) { + $state = $request->setState( + RequestInterface::STATE_COMPLETE, + array('handle' => $handle) + ); + // Only remove the request if it wasn't resent as a result of + // the state change + if ($state != RequestInterface::STATE_TRANSFER) { + $this->remove($request); + } + } + return; + } + + // Set the state of the request to an error + $state = $request->setState(RequestInterface::STATE_ERROR, array('exception' => $curlException)); + // Allow things to ignore the error if possible + if ($state != RequestInterface::STATE_TRANSFER) { + $this->remove($request); + } + + // The error was not handled, so fail + if ($state == RequestInterface::STATE_ERROR) { + /** @var CurlException $curlException */ + throw $curlException; + } + } + + /** + * Remove a curl handle from the curl multi object + * + * @param RequestInterface $request Request that owns the handle + */ + protected function removeHandle(RequestInterface $request) + { + if (isset($this->handles[$request])) { + $handle = $this->handles[$request]; + curl_multi_remove_handle($this->multiHandle, $handle->getHandle()); + unset($this->handles[$request]); + unset($this->resourceHash[(int) $handle->getHandle()]); + $handle->close(); + } + } + + /** + * Check if a cURL transfer resulted in what should be an exception + * + * @param RequestInterface $request Request to check + * @param CurlHandle $handle Curl handle object + * @param array $curl Array returned from curl_multi_info_read + * + * @return CurlException|bool + */ + private function isCurlException(RequestInterface $request, CurlHandle $handle, array $curl) + { + if (CURLM_OK == $curl['result'] || CURLM_CALL_MULTI_PERFORM == $curl['result']) { + return false; + } + + $handle->setErrorNo($curl['result']); + $e = new CurlException(sprintf('[curl] %s: %s [url] %s', + $handle->getErrorNo(), $handle->getError(), $handle->getUrl())); + $e->setCurlHandle($handle) + ->setRequest($request) + ->setCurlInfo($handle->getInfo()) + ->setError($handle->getError(), $handle->getErrorNo()); + + return $e; + } + + /** + * Throw an exception for a cURL multi response if needed + * + * @param int $code Curl response code + * @throws CurlException + */ + private function checkCurlResult($code) + { + if ($code != CURLM_OK && $code != CURLM_CALL_MULTI_PERFORM) { + throw new CurlException(isset($this->multiErrors[$code]) + ? "cURL error: {$code} ({$this->multiErrors[$code][0]}): cURL message: {$this->multiErrors[$code][1]}" + : 'Unexpected cURL error: ' . $code + ); + } + } + + /** + * @link https://github.com/guzzle/guzzle/issues/710 + */ + private function validateResponseWasSet(RequestInterface $request) + { + if ($request->getResponse()) { + return true; + } + + $body = $request instanceof EntityEnclosingRequestInterface + ? $request->getBody() + : null; + + if (!$body) { + $rex = new RequestException( + 'No response was received for a request with no body. This' + . ' could mean that you are saturating your network.' + ); + $rex->setRequest($request); + $this->removeErroredRequest($request, $rex); + } elseif (!$body->isSeekable() || !$body->seek(0)) { + // Nothing we can do with this. Sorry! + $rex = new RequestException( + 'The connection was unexpectedly closed. The request would' + . ' have been retried, but attempting to rewind the' + . ' request body failed.' + ); + $rex->setRequest($request); + $this->removeErroredRequest($request, $rex); + } else { + $this->remove($request); + // Add the request back to the batch to retry automatically. + $this->requests[] = $request; + $this->addHandle($request); + } + + return false; + } +} diff --git a/vendor/guzzle/guzzle/src/Guzzle/Http/Curl/CurlMultiInterface.php b/vendor/guzzle/guzzle/src/Guzzle/Http/Curl/CurlMultiInterface.php new file mode 100644 index 0000000..0ead757 --- /dev/null +++ b/vendor/guzzle/guzzle/src/Guzzle/Http/Curl/CurlMultiInterface.php @@ -0,0 +1,58 @@ +maxHandles = $maxHandles; + $this->selectTimeout = $selectTimeout; + // You can get some weird "Too many open files" errors when sending a large amount of requests in parallel. + // These two statements autoload classes before a system runs out of file descriptors so that you can get back + // valuable error messages if you run out. + class_exists('Guzzle\Http\Message\Response'); + class_exists('Guzzle\Http\Exception\CurlException'); + } + + public function add(RequestInterface $request) + { + $this->queued[] = $request; + + return $this; + } + + public function all() + { + $requests = $this->queued; + foreach ($this->handles as $handle) { + $requests = array_merge($requests, $handle->all()); + } + + return $requests; + } + + public function remove(RequestInterface $request) + { + foreach ($this->queued as $i => $r) { + if ($request === $r) { + unset($this->queued[$i]); + return true; + } + } + + foreach ($this->handles as $handle) { + if ($handle->remove($request)) { + return true; + } + } + + return false; + } + + public function reset($hard = false) + { + $this->queued = array(); + $this->groups = array(); + foreach ($this->handles as $handle) { + $handle->reset(); + } + if ($hard) { + $this->handles = array(); + } + + return $this; + } + + public function send() + { + if ($this->queued) { + $group = $this->getAvailableHandle(); + // Add this handle to a list of handles than is claimed + $this->groups[] = $group; + while ($request = array_shift($this->queued)) { + $group->add($request); + } + try { + $group->send(); + array_pop($this->groups); + $this->cleanupHandles(); + } catch (\Exception $e) { + // Remove the group and cleanup if an exception was encountered and no more requests in group + if (!$group->count()) { + array_pop($this->groups); + $this->cleanupHandles(); + } + throw $e; + } + } + } + + public function count() + { + return count($this->all()); + } + + /** + * Get an existing available CurlMulti handle or create a new one + * + * @return CurlMulti + */ + protected function getAvailableHandle() + { + // Grab a handle that is not claimed + foreach ($this->handles as $h) { + if (!in_array($h, $this->groups, true)) { + return $h; + } + } + + // All are claimed, so create one + $handle = new CurlMulti($this->selectTimeout); + $handle->setEventDispatcher($this->getEventDispatcher()); + $this->handles[] = $handle; + + return $handle; + } + + /** + * Trims down unused CurlMulti handles to limit the number of open connections + */ + protected function cleanupHandles() + { + if ($diff = max(0, count($this->handles) - $this->maxHandles)) { + for ($i = count($this->handles) - 1; $i > 0 && $diff > 0; $i--) { + if (!count($this->handles[$i])) { + unset($this->handles[$i]); + $diff--; + } + } + $this->handles = array_values($this->handles); + } + } +} diff --git a/vendor/guzzle/guzzle/src/Guzzle/Http/Curl/CurlVersion.php b/vendor/guzzle/guzzle/src/Guzzle/Http/Curl/CurlVersion.php new file mode 100644 index 0000000..c3f99dd --- /dev/null +++ b/vendor/guzzle/guzzle/src/Guzzle/Http/Curl/CurlVersion.php @@ -0,0 +1,66 @@ +version) { + $this->version = curl_version(); + } + + return $this->version; + } + + /** + * Get a specific type of curl information + * + * @param string $type Version information to retrieve. This value is one of: + * - version_number: cURL 24 bit version number + * - version: cURL version number, as a string + * - ssl_version_number: OpenSSL 24 bit version number + * - ssl_version: OpenSSL version number, as a string + * - libz_version: zlib version number, as a string + * - host: Information about the host where cURL was built + * - features: A bitmask of the CURL_VERSION_XXX constants + * - protocols: An array of protocols names supported by cURL + * + * @return string|float|bool if the $type is found, and false if not found + */ + public function get($type) + { + $version = $this->getAll(); + + return isset($version[$type]) ? $version[$type] : false; + } +} diff --git a/vendor/guzzle/guzzle/src/Guzzle/Http/Curl/RequestMediator.php b/vendor/guzzle/guzzle/src/Guzzle/Http/Curl/RequestMediator.php new file mode 100644 index 0000000..5d1a0cd --- /dev/null +++ b/vendor/guzzle/guzzle/src/Guzzle/Http/Curl/RequestMediator.php @@ -0,0 +1,147 @@ +request = $request; + $this->emitIo = $emitIo; + } + + /** + * Receive a response header from curl + * + * @param resource $curl Curl handle + * @param string $header Received header + * + * @return int + */ + public function receiveResponseHeader($curl, $header) + { + static $normalize = array("\r", "\n"); + $length = strlen($header); + $header = str_replace($normalize, '', $header); + + if (strpos($header, 'HTTP/') === 0) { + + $startLine = explode(' ', $header, 3); + $code = $startLine[1]; + $status = isset($startLine[2]) ? $startLine[2] : ''; + + // Only download the body of the response to the specified response + // body when a successful response is received. + if ($code >= 200 && $code < 300) { + $body = $this->request->getResponseBody(); + } else { + $body = EntityBody::factory(); + } + + $response = new Response($code, null, $body); + $response->setStatus($code, $status); + $this->request->startResponse($response); + + $this->request->dispatch('request.receive.status_line', array( + 'request' => $this, + 'line' => $header, + 'status_code' => $code, + 'reason_phrase' => $status + )); + + } elseif ($pos = strpos($header, ':')) { + $this->request->getResponse()->addHeader( + trim(substr($header, 0, $pos)), + trim(substr($header, $pos + 1)) + ); + } + + return $length; + } + + /** + * Received a progress notification + * + * @param int $downloadSize Total download size + * @param int $downloaded Amount of bytes downloaded + * @param int $uploadSize Total upload size + * @param int $uploaded Amount of bytes uploaded + * @param resource $handle CurlHandle object + */ + public function progress($downloadSize, $downloaded, $uploadSize, $uploaded, $handle = null) + { + $this->request->dispatch('curl.callback.progress', array( + 'request' => $this->request, + 'handle' => $handle, + 'download_size' => $downloadSize, + 'downloaded' => $downloaded, + 'upload_size' => $uploadSize, + 'uploaded' => $uploaded + )); + } + + /** + * Write data to the response body of a request + * + * @param resource $curl Curl handle + * @param string $write Data that was received + * + * @return int + */ + public function writeResponseBody($curl, $write) + { + if ($this->emitIo) { + $this->request->dispatch('curl.callback.write', array( + 'request' => $this->request, + 'write' => $write + )); + } + + if ($response = $this->request->getResponse()) { + return $response->getBody()->write($write); + } else { + // Unexpected data received before response headers - abort transfer + return 0; + } + } + + /** + * Read data from the request body and send it to curl + * + * @param resource $ch Curl handle + * @param resource $fd File descriptor + * @param int $length Amount of data to read + * + * @return string + */ + public function readRequestBody($ch, $fd, $length) + { + if (!($body = $this->request->getBody())) { + return ''; + } + + $read = (string) $body->read($length); + if ($this->emitIo) { + $this->request->dispatch('curl.callback.read', array('request' => $this->request, 'read' => $read)); + } + + return $read; + } +} diff --git a/vendor/guzzle/guzzle/src/Guzzle/Http/EntityBody.php b/vendor/guzzle/guzzle/src/Guzzle/Http/EntityBody.php new file mode 100644 index 0000000..b60d170 --- /dev/null +++ b/vendor/guzzle/guzzle/src/Guzzle/Http/EntityBody.php @@ -0,0 +1,201 @@ +rewindFunction = $callable; + + return $this; + } + + public function rewind() + { + return $this->rewindFunction ? call_user_func($this->rewindFunction, $this) : parent::rewind(); + } + + /** + * Create a new EntityBody from a string + * + * @param string $string String of data + * + * @return EntityBody + */ + public static function fromString($string) + { + $stream = fopen('php://temp', 'r+'); + if ($string !== '') { + fwrite($stream, $string); + rewind($stream); + } + + return new static($stream); + } + + public function compress($filter = 'zlib.deflate') + { + $result = $this->handleCompression($filter); + $this->contentEncoding = $result ? $filter : false; + + return $result; + } + + public function uncompress($filter = 'zlib.inflate') + { + $offsetStart = 0; + + // When inflating gzipped data, the first 10 bytes must be stripped + // if a gzip header is present + if ($filter == 'zlib.inflate') { + // @codeCoverageIgnoreStart + if (!$this->isReadable() || ($this->isConsumed() && !$this->isSeekable())) { + return false; + } + // @codeCoverageIgnoreEnd + if (stream_get_contents($this->stream, 3, 0) === "\x1f\x8b\x08") { + $offsetStart = 10; + } + } + + $this->contentEncoding = false; + + return $this->handleCompression($filter, $offsetStart); + } + + public function getContentLength() + { + return $this->getSize(); + } + + public function getContentType() + { + return $this->getUri() ? Mimetypes::getInstance()->fromFilename($this->getUri()) : null; + } + + public function getContentMd5($rawOutput = false, $base64Encode = false) + { + if ($hash = self::getHash($this, 'md5', $rawOutput)) { + return $hash && $base64Encode ? base64_encode($hash) : $hash; + } else { + return false; + } + } + + /** + * Calculate the MD5 hash of an entity body + * + * @param EntityBodyInterface $body Entity body to calculate the hash for + * @param bool $rawOutput Whether or not to use raw output + * @param bool $base64Encode Whether or not to base64 encode raw output (only if raw output is true) + * + * @return bool|string Returns an MD5 string on success or FALSE on failure + * @deprecated This will be deprecated soon + * @codeCoverageIgnore + */ + public static function calculateMd5(EntityBodyInterface $body, $rawOutput = false, $base64Encode = false) + { + Version::warn(__CLASS__ . ' is deprecated. Use getContentMd5()'); + return $body->getContentMd5($rawOutput, $base64Encode); + } + + public function setStreamFilterContentEncoding($streamFilterContentEncoding) + { + $this->contentEncoding = $streamFilterContentEncoding; + + return $this; + } + + public function getContentEncoding() + { + return strtr($this->contentEncoding, array( + 'zlib.deflate' => 'gzip', + 'bzip2.compress' => 'compress' + )) ?: false; + } + + protected function handleCompression($filter, $offsetStart = 0) + { + // @codeCoverageIgnoreStart + if (!$this->isReadable() || ($this->isConsumed() && !$this->isSeekable())) { + return false; + } + // @codeCoverageIgnoreEnd + + $handle = fopen('php://temp', 'r+'); + $filter = @stream_filter_append($handle, $filter, STREAM_FILTER_WRITE); + if (!$filter) { + return false; + } + + // Seek to the offset start if possible + $this->seek($offsetStart); + while ($data = fread($this->stream, 8096)) { + fwrite($handle, $data); + } + + fclose($this->stream); + $this->stream = $handle; + stream_filter_remove($filter); + $stat = fstat($this->stream); + $this->size = $stat['size']; + $this->rebuildCache(); + $this->seek(0); + + // Remove any existing rewind function as the underlying stream has been replaced + $this->rewindFunction = null; + + return true; + } +} diff --git a/vendor/guzzle/guzzle/src/Guzzle/Http/EntityBodyInterface.php b/vendor/guzzle/guzzle/src/Guzzle/Http/EntityBodyInterface.php new file mode 100644 index 0000000..e640f57 --- /dev/null +++ b/vendor/guzzle/guzzle/src/Guzzle/Http/EntityBodyInterface.php @@ -0,0 +1,73 @@ +isClientError()) { + $label = 'Client error response'; + $class = __NAMESPACE__ . '\\ClientErrorResponseException'; + } elseif ($response->isServerError()) { + $label = 'Server error response'; + $class = __NAMESPACE__ . '\\ServerErrorResponseException'; + } else { + $label = 'Unsuccessful response'; + $class = __CLASS__; + } + + $message = $label . PHP_EOL . implode(PHP_EOL, array( + '[status code] ' . $response->getStatusCode(), + '[reason phrase] ' . $response->getReasonPhrase(), + '[url] ' . $request->getUrl(), + )); + + $e = new $class($message); + $e->setResponse($response); + $e->setRequest($request); + + return $e; + } + + /** + * Set the response that caused the exception + * + * @param Response $response Response to set + */ + public function setResponse(Response $response) + { + $this->response = $response; + } + + /** + * Get the response that caused the exception + * + * @return Response + */ + public function getResponse() + { + return $this->response; + } +} diff --git a/vendor/guzzle/guzzle/src/Guzzle/Http/Exception/ClientErrorResponseException.php b/vendor/guzzle/guzzle/src/Guzzle/Http/Exception/ClientErrorResponseException.php new file mode 100644 index 0000000..04d7ddc --- /dev/null +++ b/vendor/guzzle/guzzle/src/Guzzle/Http/Exception/ClientErrorResponseException.php @@ -0,0 +1,8 @@ +curlError = $error; + $this->curlErrorNo = $number; + + return $this; + } + + /** + * Set the associated curl handle + * + * @param CurlHandle $handle Curl handle + * + * @return self + */ + public function setCurlHandle(CurlHandle $handle) + { + $this->handle = $handle; + + return $this; + } + + /** + * Get the associated cURL handle + * + * @return CurlHandle|null + */ + public function getCurlHandle() + { + return $this->handle; + } + + /** + * Get the associated cURL error message + * + * @return string|null + */ + public function getError() + { + return $this->curlError; + } + + /** + * Get the associated cURL error number + * + * @return int|null + */ + public function getErrorNo() + { + return $this->curlErrorNo; + } + + /** + * Returns curl information about the transfer + * + * @return array + */ + public function getCurlInfo() + { + return $this->curlInfo; + } + + /** + * Set curl transfer information + * + * @param array $info Array of curl transfer information + * + * @return self + * @link http://php.net/manual/en/function.curl-getinfo.php + */ + public function setCurlInfo(array $info) + { + $this->curlInfo = $info; + + return $this; + } +} diff --git a/vendor/guzzle/guzzle/src/Guzzle/Http/Exception/HttpException.php b/vendor/guzzle/guzzle/src/Guzzle/Http/Exception/HttpException.php new file mode 100644 index 0000000..ee87295 --- /dev/null +++ b/vendor/guzzle/guzzle/src/Guzzle/Http/Exception/HttpException.php @@ -0,0 +1,10 @@ +successfulRequests, $this->failedRequests); + } + + /** + * Add to the array of successful requests + * + * @param RequestInterface $request Successful request + * + * @return self + */ + public function addSuccessfulRequest(RequestInterface $request) + { + $this->successfulRequests[] = $request; + + return $this; + } + + /** + * Add to the array of failed requests + * + * @param RequestInterface $request Failed request + * + * @return self + */ + public function addFailedRequest(RequestInterface $request) + { + $this->failedRequests[] = $request; + + return $this; + } + + /** + * Add to the array of failed requests and associate with exceptions + * + * @param RequestInterface $request Failed request + * @param \Exception $exception Exception to add and associate with + * + * @return self + */ + public function addFailedRequestWithException(RequestInterface $request, \Exception $exception) + { + $this->add($exception) + ->addFailedRequest($request) + ->exceptionForRequest[spl_object_hash($request)] = $exception; + + return $this; + } + + /** + * Get the Exception that caused the given $request to fail + * + * @param RequestInterface $request Failed command + * + * @return \Exception|null + */ + public function getExceptionForFailedRequest(RequestInterface $request) + { + $oid = spl_object_hash($request); + + return isset($this->exceptionForRequest[$oid]) ? $this->exceptionForRequest[$oid] : null; + } + + /** + * Set all of the successful requests + * + * @param array Array of requests + * + * @return self + */ + public function setSuccessfulRequests(array $requests) + { + $this->successfulRequests = $requests; + + return $this; + } + + /** + * Set all of the failed requests + * + * @param array Array of requests + * + * @return self + */ + public function setFailedRequests(array $requests) + { + $this->failedRequests = $requests; + + return $this; + } + + /** + * Get an array of successful requests sent in the multi transfer + * + * @return array + */ + public function getSuccessfulRequests() + { + return $this->successfulRequests; + } + + /** + * Get an array of failed requests sent in the multi transfer + * + * @return array + */ + public function getFailedRequests() + { + return $this->failedRequests; + } + + /** + * Check if the exception object contains a request + * + * @param RequestInterface $request Request to check + * + * @return bool + */ + public function containsRequest(RequestInterface $request) + { + return in_array($request, $this->failedRequests, true) || in_array($request, $this->successfulRequests, true); + } +} diff --git a/vendor/guzzle/guzzle/src/Guzzle/Http/Exception/RequestException.php b/vendor/guzzle/guzzle/src/Guzzle/Http/Exception/RequestException.php new file mode 100644 index 0000000..274df2c --- /dev/null +++ b/vendor/guzzle/guzzle/src/Guzzle/Http/Exception/RequestException.php @@ -0,0 +1,39 @@ +request = $request; + + return $this; + } + + /** + * Get the request that caused the exception + * + * @return RequestInterface + */ + public function getRequest() + { + return $this->request; + } +} diff --git a/vendor/guzzle/guzzle/src/Guzzle/Http/Exception/ServerErrorResponseException.php b/vendor/guzzle/guzzle/src/Guzzle/Http/Exception/ServerErrorResponseException.php new file mode 100644 index 0000000..f0f7cfe --- /dev/null +++ b/vendor/guzzle/guzzle/src/Guzzle/Http/Exception/ServerErrorResponseException.php @@ -0,0 +1,8 @@ +eventDispatcher = $eventDispatcher; + + return $this; + } + + public function getEventDispatcher() + { + if (!$this->eventDispatcher) { + $this->eventDispatcher = new EventDispatcher(); + } + + return $this->eventDispatcher; + } + + public function dispatch($eventName, array $context = array()) + { + return $this->getEventDispatcher()->dispatch($eventName, new Event($context)); + } + + /** + * {@inheritdoc} + * @codeCoverageIgnore + */ + public function addSubscriber(EventSubscriberInterface $subscriber) + { + $this->getEventDispatcher()->addSubscriber($subscriber); + + return $this; + } + + public function read($length) + { + $event = array( + 'body' => $this, + 'length' => $length, + 'read' => $this->body->read($length) + ); + $this->dispatch('body.read', $event); + + return $event['read']; + } + + public function write($string) + { + $event = array( + 'body' => $this, + 'write' => $string, + 'result' => $this->body->write($string) + ); + $this->dispatch('body.write', $event); + + return $event['result']; + } +} diff --git a/vendor/guzzle/guzzle/src/Guzzle/Http/Message/AbstractMessage.php b/vendor/guzzle/guzzle/src/Guzzle/Http/Message/AbstractMessage.php new file mode 100644 index 0000000..0d066ff --- /dev/null +++ b/vendor/guzzle/guzzle/src/Guzzle/Http/Message/AbstractMessage.php @@ -0,0 +1,220 @@ +params = new Collection(); + $this->headerFactory = new HeaderFactory(); + $this->headers = new HeaderCollection(); + } + + /** + * Set the header factory to use to create headers + * + * @param HeaderFactoryInterface $factory + * + * @return self + */ + public function setHeaderFactory(HeaderFactoryInterface $factory) + { + $this->headerFactory = $factory; + + return $this; + } + + public function getParams() + { + return $this->params; + } + + public function addHeader($header, $value) + { + if (isset($this->headers[$header])) { + $this->headers[$header]->add($value); + } elseif ($value instanceof HeaderInterface) { + $this->headers[$header] = $value; + } else { + $this->headers[$header] = $this->headerFactory->createHeader($header, $value); + } + + return $this; + } + + public function addHeaders(array $headers) + { + foreach ($headers as $key => $value) { + $this->addHeader($key, $value); + } + + return $this; + } + + public function getHeader($header) + { + return $this->headers[$header]; + } + + public function getHeaders() + { + return $this->headers; + } + + public function getHeaderLines() + { + $headers = array(); + foreach ($this->headers as $value) { + $headers[] = $value->getName() . ': ' . $value; + } + + return $headers; + } + + public function setHeader($header, $value) + { + unset($this->headers[$header]); + $this->addHeader($header, $value); + + return $this; + } + + public function setHeaders(array $headers) + { + $this->headers->clear(); + foreach ($headers as $key => $value) { + $this->addHeader($key, $value); + } + + return $this; + } + + public function hasHeader($header) + { + return isset($this->headers[$header]); + } + + public function removeHeader($header) + { + unset($this->headers[$header]); + + return $this; + } + + /** + * @deprecated Use $message->getHeader()->parseParams() + * @codeCoverageIgnore + */ + public function getTokenizedHeader($header, $token = ';') + { + Version::warn(__METHOD__ . ' is deprecated. Use $message->getHeader()->parseParams()'); + if ($this->hasHeader($header)) { + $data = new Collection(); + foreach ($this->getHeader($header)->parseParams() as $values) { + foreach ($values as $key => $value) { + if ($value === '') { + $data->set($data->count(), $key); + } else { + $data->add($key, $value); + } + } + } + return $data; + } + } + + /** + * @deprecated + * @codeCoverageIgnore + */ + public function setTokenizedHeader($header, $data, $token = ';') + { + Version::warn(__METHOD__ . ' is deprecated.'); + return $this; + } + + /** + * @deprecated + * @codeCoverageIgnore + */ + public function getCacheControlDirective($directive) + { + Version::warn(__METHOD__ . ' is deprecated. Use $message->getHeader(\'Cache-Control\')->getDirective()'); + if (!($header = $this->getHeader('Cache-Control'))) { + return null; + } + + return $header->getDirective($directive); + } + + /** + * @deprecated + * @codeCoverageIgnore + */ + public function hasCacheControlDirective($directive) + { + Version::warn(__METHOD__ . ' is deprecated. Use $message->getHeader(\'Cache-Control\')->hasDirective()'); + if ($header = $this->getHeader('Cache-Control')) { + return $header->hasDirective($directive); + } else { + return false; + } + } + + /** + * @deprecated + * @codeCoverageIgnore + */ + public function addCacheControlDirective($directive, $value = true) + { + Version::warn(__METHOD__ . ' is deprecated. Use $message->getHeader(\'Cache-Control\')->addDirective()'); + if (!($header = $this->getHeader('Cache-Control'))) { + $this->addHeader('Cache-Control', ''); + $header = $this->getHeader('Cache-Control'); + } + + $header->addDirective($directive, $value); + + return $this; + } + + /** + * @deprecated + * @codeCoverageIgnore + */ + public function removeCacheControlDirective($directive) + { + Version::warn(__METHOD__ . ' is deprecated. Use $message->getHeader(\'Cache-Control\')->removeDirective()'); + if ($header = $this->getHeader('Cache-Control')) { + $header->removeDirective($directive); + } + + return $this; + } +} diff --git a/vendor/guzzle/guzzle/src/Guzzle/Http/Message/EntityEnclosingRequest.php b/vendor/guzzle/guzzle/src/Guzzle/Http/Message/EntityEnclosingRequest.php new file mode 100644 index 0000000..212850a --- /dev/null +++ b/vendor/guzzle/guzzle/src/Guzzle/Http/Message/EntityEnclosingRequest.php @@ -0,0 +1,247 @@ +postFields = new QueryString(); + parent::__construct($method, $url, $headers); + } + + /** + * @return string + */ + public function __toString() + { + // Only attempt to include the POST data if it's only fields + if (count($this->postFields) && empty($this->postFiles)) { + return parent::__toString() . (string) $this->postFields; + } + + return parent::__toString() . $this->body; + } + + public function setState($state, array $context = array()) + { + parent::setState($state, $context); + if ($state == self::STATE_TRANSFER && !$this->body && !count($this->postFields) && !count($this->postFiles)) { + $this->setHeader('Content-Length', 0)->removeHeader('Transfer-Encoding'); + } + + return $this->state; + } + + public function setBody($body, $contentType = null) + { + $this->body = EntityBody::factory($body); + + // Auto detect the Content-Type from the path of the request if possible + if ($contentType === null && !$this->hasHeader('Content-Type')) { + $contentType = $this->body->getContentType(); + } + + if ($contentType) { + $this->setHeader('Content-Type', $contentType); + } + + // Always add the Expect 100-Continue header if the body cannot be rewound. This helps with redirects. + if (!$this->body->isSeekable() && $this->expectCutoff !== false) { + $this->setHeader('Expect', '100-Continue'); + } + + // Set the Content-Length header if it can be determined + $size = $this->body->getContentLength(); + if ($size !== null && $size !== false) { + $this->setHeader('Content-Length', $size); + if ($size > $this->expectCutoff) { + $this->setHeader('Expect', '100-Continue'); + } + } elseif (!$this->hasHeader('Content-Length')) { + if ('1.1' == $this->protocolVersion) { + $this->setHeader('Transfer-Encoding', 'chunked'); + } else { + throw new RequestException( + 'Cannot determine Content-Length and cannot use chunked Transfer-Encoding when using HTTP/1.0' + ); + } + } + + return $this; + } + + public function getBody() + { + return $this->body; + } + + /** + * Set the size that the entity body of the request must exceed before adding the Expect: 100-Continue header. + * + * @param int|bool $size Cutoff in bytes. Set to false to never send the expect header (even with non-seekable data) + * + * @return self + */ + public function setExpectHeaderCutoff($size) + { + $this->expectCutoff = $size; + if ($size === false || !$this->body) { + $this->removeHeader('Expect'); + } elseif ($this->body && $this->body->getSize() && $this->body->getSize() > $size) { + $this->setHeader('Expect', '100-Continue'); + } + + return $this; + } + + public function configureRedirects($strict = false, $maxRedirects = 5) + { + $this->getParams()->set(RedirectPlugin::STRICT_REDIRECTS, $strict); + if ($maxRedirects == 0) { + $this->getParams()->set(RedirectPlugin::DISABLE, true); + } else { + $this->getParams()->set(RedirectPlugin::MAX_REDIRECTS, $maxRedirects); + } + + return $this; + } + + public function getPostField($field) + { + return $this->postFields->get($field); + } + + public function getPostFields() + { + return $this->postFields; + } + + public function setPostField($key, $value) + { + $this->postFields->set($key, $value); + $this->processPostFields(); + + return $this; + } + + public function addPostFields($fields) + { + $this->postFields->merge($fields); + $this->processPostFields(); + + return $this; + } + + public function removePostField($field) + { + $this->postFields->remove($field); + $this->processPostFields(); + + return $this; + } + + public function getPostFiles() + { + return $this->postFiles; + } + + public function getPostFile($fieldName) + { + return isset($this->postFiles[$fieldName]) ? $this->postFiles[$fieldName] : null; + } + + public function removePostFile($fieldName) + { + unset($this->postFiles[$fieldName]); + $this->processPostFields(); + + return $this; + } + + public function addPostFile($field, $filename = null, $contentType = null, $postname = null) + { + $data = null; + + if ($field instanceof PostFileInterface) { + $data = $field; + } elseif (is_array($filename)) { + // Allow multiple values to be set in a single key + foreach ($filename as $file) { + $this->addPostFile($field, $file, $contentType); + } + return $this; + } elseif (!is_string($filename)) { + throw new RequestException('The path to a file must be a string'); + } elseif (!empty($filename)) { + // Adding an empty file will cause cURL to error out + $data = new PostFile($field, $filename, $contentType, $postname); + } + + if ($data) { + if (!isset($this->postFiles[$data->getFieldName()])) { + $this->postFiles[$data->getFieldName()] = array($data); + } else { + $this->postFiles[$data->getFieldName()][] = $data; + } + $this->processPostFields(); + } + + return $this; + } + + public function addPostFiles(array $files) + { + foreach ($files as $key => $file) { + if ($file instanceof PostFileInterface) { + $this->addPostFile($file, null, null, false); + } elseif (is_string($file)) { + // Convert non-associative array keys into 'file' + if (is_numeric($key)) { + $key = 'file'; + } + $this->addPostFile($key, $file, null, false); + } else { + throw new RequestException('File must be a string or instance of PostFileInterface'); + } + } + + return $this; + } + + /** + * Determine what type of request should be sent based on post fields + */ + protected function processPostFields() + { + if (!$this->postFiles) { + $this->removeHeader('Expect')->setHeader('Content-Type', self::URL_ENCODED); + } else { + $this->setHeader('Content-Type', self::MULTIPART); + if ($this->expectCutoff !== false) { + $this->setHeader('Expect', '100-Continue'); + } + } + } +} diff --git a/vendor/guzzle/guzzle/src/Guzzle/Http/Message/EntityEnclosingRequestInterface.php b/vendor/guzzle/guzzle/src/Guzzle/Http/Message/EntityEnclosingRequestInterface.php new file mode 100644 index 0000000..49ad459 --- /dev/null +++ b/vendor/guzzle/guzzle/src/Guzzle/Http/Message/EntityEnclosingRequestInterface.php @@ -0,0 +1,137 @@ + filenames where filename can be a string or PostFileInterface + * + * @return self + */ + public function addPostFiles(array $files); + + /** + * Configure how redirects are handled for the request + * + * @param bool $strict Set to true to follow strict RFC compliance when redirecting POST requests. Most + * browsers with follow a 301-302 redirect for a POST request with a GET request. This is + * the default behavior of Guzzle. Enable strict redirects to redirect these responses + * with a POST rather than a GET request. + * @param int $maxRedirects Specify the maximum number of allowed redirects. Set to 0 to disable redirects. + * + * @return self + */ + public function configureRedirects($strict = false, $maxRedirects = 5); +} diff --git a/vendor/guzzle/guzzle/src/Guzzle/Http/Message/Header.php b/vendor/guzzle/guzzle/src/Guzzle/Http/Message/Header.php new file mode 100644 index 0000000..50597b2 --- /dev/null +++ b/vendor/guzzle/guzzle/src/Guzzle/Http/Message/Header.php @@ -0,0 +1,182 @@ +header = trim($header); + $this->glue = $glue; + + foreach ((array) $values as $value) { + foreach ((array) $value as $v) { + $this->values[] = $v; + } + } + } + + public function __toString() + { + return implode($this->glue . ' ', $this->toArray()); + } + + public function add($value) + { + $this->values[] = $value; + + return $this; + } + + public function getName() + { + return $this->header; + } + + public function setName($name) + { + $this->header = $name; + + return $this; + } + + public function setGlue($glue) + { + $this->glue = $glue; + + return $this; + } + + public function getGlue() + { + return $this->glue; + } + + /** + * Normalize the header to be a single header with an array of values. + * + * If any values of the header contains the glue string value (e.g. ","), then the value will be exploded into + * multiple entries in the header. + * + * @return self + */ + public function normalize() + { + $values = $this->toArray(); + + for ($i = 0, $total = count($values); $i < $total; $i++) { + if (strpos($values[$i], $this->glue) !== false) { + // Explode on glue when the glue is not inside of a comma + foreach (preg_split('/' . preg_quote($this->glue) . '(?=([^"]*"[^"]*")*[^"]*$)/', $values[$i]) as $v) { + $values[] = trim($v); + } + unset($values[$i]); + } + } + + $this->values = array_values($values); + + return $this; + } + + public function hasValue($searchValue) + { + return in_array($searchValue, $this->toArray()); + } + + public function removeValue($searchValue) + { + $this->values = array_values(array_filter($this->values, function ($value) use ($searchValue) { + return $value != $searchValue; + })); + + return $this; + } + + public function toArray() + { + return $this->values; + } + + public function count() + { + return count($this->toArray()); + } + + public function getIterator() + { + return new \ArrayIterator($this->toArray()); + } + + public function parseParams() + { + $params = $matches = array(); + $callback = array($this, 'trimHeader'); + + // Normalize the header into a single array and iterate over all values + foreach ($this->normalize()->toArray() as $val) { + $part = array(); + foreach (preg_split('/;(?=([^"]*"[^"]*")*[^"]*$)/', $val) as $kvp) { + if (!preg_match_all('/<[^>]+>|[^=]+/', $kvp, $matches)) { + continue; + } + $pieces = array_map($callback, $matches[0]); + $part[$pieces[0]] = isset($pieces[1]) ? $pieces[1] : ''; + } + if ($part) { + $params[] = $part; + } + } + + return $params; + } + + /** + * @deprecated + * @codeCoverageIgnore + */ + public function hasExactHeader($header) + { + Version::warn(__METHOD__ . ' is deprecated'); + return $this->header == $header; + } + + /** + * @deprecated + * @codeCoverageIgnore + */ + public function raw() + { + Version::warn(__METHOD__ . ' is deprecated. Use toArray()'); + return $this->toArray(); + } + + /** + * Trim a header by removing excess spaces and wrapping quotes + * + * @param $str + * + * @return string + */ + protected function trimHeader($str) + { + static $trimmed = "\"' \n\t"; + + return trim($str, $trimmed); + } +} diff --git a/vendor/guzzle/guzzle/src/Guzzle/Http/Message/Header/CacheControl.php b/vendor/guzzle/guzzle/src/Guzzle/Http/Message/Header/CacheControl.php new file mode 100644 index 0000000..77789e5 --- /dev/null +++ b/vendor/guzzle/guzzle/src/Guzzle/Http/Message/Header/CacheControl.php @@ -0,0 +1,121 @@ +directives = null; + } + + public function removeValue($searchValue) + { + parent::removeValue($searchValue); + $this->directives = null; + } + + /** + * Check if a specific cache control directive exists + * + * @param string $param Directive to retrieve + * + * @return bool + */ + public function hasDirective($param) + { + $directives = $this->getDirectives(); + + return isset($directives[$param]); + } + + /** + * Get a specific cache control directive + * + * @param string $param Directive to retrieve + * + * @return string|bool|null + */ + public function getDirective($param) + { + $directives = $this->getDirectives(); + + return isset($directives[$param]) ? $directives[$param] : null; + } + + /** + * Add a cache control directive + * + * @param string $param Directive to add + * @param string $value Value to set + * + * @return self + */ + public function addDirective($param, $value) + { + $directives = $this->getDirectives(); + $directives[$param] = $value; + $this->updateFromDirectives($directives); + + return $this; + } + + /** + * Remove a cache control directive by name + * + * @param string $param Directive to remove + * + * @return self + */ + public function removeDirective($param) + { + $directives = $this->getDirectives(); + unset($directives[$param]); + $this->updateFromDirectives($directives); + + return $this; + } + + /** + * Get an associative array of cache control directives + * + * @return array + */ + public function getDirectives() + { + if ($this->directives === null) { + $this->directives = array(); + foreach ($this->parseParams() as $collection) { + foreach ($collection as $key => $value) { + $this->directives[$key] = $value === '' ? true : $value; + } + } + } + + return $this->directives; + } + + /** + * Updates the header value based on the parsed directives + * + * @param array $directives Array of cache control directives + */ + protected function updateFromDirectives(array $directives) + { + $this->directives = $directives; + $this->values = array(); + + foreach ($directives as $key => $value) { + $this->values[] = $value === true ? $key : "{$key}={$value}"; + } + } +} diff --git a/vendor/guzzle/guzzle/src/Guzzle/Http/Message/Header/HeaderCollection.php b/vendor/guzzle/guzzle/src/Guzzle/Http/Message/Header/HeaderCollection.php new file mode 100644 index 0000000..8c7f6ae --- /dev/null +++ b/vendor/guzzle/guzzle/src/Guzzle/Http/Message/Header/HeaderCollection.php @@ -0,0 +1,108 @@ +headers = $headers; + } + + public function __clone() + { + foreach ($this->headers as &$header) { + $header = clone $header; + } + } + + /** + * Clears the header collection + */ + public function clear() + { + $this->headers = array(); + } + + /** + * Set a header on the collection + * + * @param HeaderInterface $header Header to add + * + * @return self + */ + public function add(HeaderInterface $header) + { + $this->headers[strtolower($header->getName())] = $header; + + return $this; + } + + /** + * Get an array of header objects + * + * @return array + */ + public function getAll() + { + return $this->headers; + } + + /** + * Alias of offsetGet + */ + public function get($key) + { + return $this->offsetGet($key); + } + + public function count() + { + return count($this->headers); + } + + public function offsetExists($offset) + { + return isset($this->headers[strtolower($offset)]); + } + + public function offsetGet($offset) + { + $l = strtolower($offset); + + return isset($this->headers[$l]) ? $this->headers[$l] : null; + } + + public function offsetSet($offset, $value) + { + $this->add($value); + } + + public function offsetUnset($offset) + { + unset($this->headers[strtolower($offset)]); + } + + public function getIterator() + { + return new \ArrayIterator($this->headers); + } + + public function toArray() + { + $result = array(); + foreach ($this->headers as $header) { + $result[$header->getName()] = $header->toArray(); + } + + return $result; + } +} diff --git a/vendor/guzzle/guzzle/src/Guzzle/Http/Message/Header/HeaderFactory.php b/vendor/guzzle/guzzle/src/Guzzle/Http/Message/Header/HeaderFactory.php new file mode 100644 index 0000000..0273be5 --- /dev/null +++ b/vendor/guzzle/guzzle/src/Guzzle/Http/Message/Header/HeaderFactory.php @@ -0,0 +1,26 @@ + 'Guzzle\Http\Message\Header\CacheControl', + 'link' => 'Guzzle\Http\Message\Header\Link', + ); + + public function createHeader($header, $value = null) + { + $lowercase = strtolower($header); + + return isset($this->mapping[$lowercase]) + ? new $this->mapping[$lowercase]($header, $value) + : new Header($header, $value); + } +} diff --git a/vendor/guzzle/guzzle/src/Guzzle/Http/Message/Header/HeaderFactoryInterface.php b/vendor/guzzle/guzzle/src/Guzzle/Http/Message/Header/HeaderFactoryInterface.php new file mode 100644 index 0000000..9457cf6 --- /dev/null +++ b/vendor/guzzle/guzzle/src/Guzzle/Http/Message/Header/HeaderFactoryInterface.php @@ -0,0 +1,19 @@ +", "rel=\"{$rel}\""); + + foreach ($params as $k => $v) { + $values[] = "{$k}=\"{$v}\""; + } + + return $this->add(implode('; ', $values)); + } + + /** + * Check if a specific link exists for a given rel attribute + * + * @param string $rel rel value + * + * @return bool + */ + public function hasLink($rel) + { + return $this->getLink($rel) !== null; + } + + /** + * Get a specific link for a given rel attribute + * + * @param string $rel Rel value + * + * @return array|null + */ + public function getLink($rel) + { + foreach ($this->getLinks() as $link) { + if (isset($link['rel']) && $link['rel'] == $rel) { + return $link; + } + } + + return null; + } + + /** + * Get an associative array of links + * + * For example: + * Link: ; rel=front; type="image/jpeg", ; rel=back; type="image/jpeg" + * + * + * var_export($response->getLinks()); + * array( + * array( + * 'url' => 'http:/.../front.jpeg', + * 'rel' => 'back', + * 'type' => 'image/jpeg', + * ) + * ) + * + * + * @return array + */ + public function getLinks() + { + $links = $this->parseParams(); + + foreach ($links as &$link) { + $key = key($link); + unset($link[$key]); + $link['url'] = trim($key, '<> '); + } + + return $links; + } +} diff --git a/vendor/guzzle/guzzle/src/Guzzle/Http/Message/MessageInterface.php b/vendor/guzzle/guzzle/src/Guzzle/Http/Message/MessageInterface.php new file mode 100644 index 0000000..62bcd43 --- /dev/null +++ b/vendor/guzzle/guzzle/src/Guzzle/Http/Message/MessageInterface.php @@ -0,0 +1,102 @@ +fieldName = $fieldName; + $this->setFilename($filename); + $this->postname = $postname ? $postname : basename($filename); + $this->contentType = $contentType ?: $this->guessContentType(); + } + + public function setFieldName($name) + { + $this->fieldName = $name; + + return $this; + } + + public function getFieldName() + { + return $this->fieldName; + } + + public function setFilename($filename) + { + // Remove leading @ symbol + if (strpos($filename, '@') === 0) { + $filename = substr($filename, 1); + } + + if (!is_readable($filename)) { + throw new InvalidArgumentException("Unable to open {$filename} for reading"); + } + + $this->filename = $filename; + + return $this; + } + + public function setPostname($postname) + { + $this->postname = $postname; + + return $this; + } + + public function getFilename() + { + return $this->filename; + } + + public function getPostname() + { + return $this->postname; + } + + public function setContentType($type) + { + $this->contentType = $type; + + return $this; + } + + public function getContentType() + { + return $this->contentType; + } + + public function getCurlValue() + { + // PHP 5.5 introduced a CurlFile object that deprecates the old @filename syntax + // See: https://wiki.php.net/rfc/curl-file-upload + if (function_exists('curl_file_create')) { + return curl_file_create($this->filename, $this->contentType, $this->postname); + } + + // Use the old style if using an older version of PHP + $value = "@{$this->filename};filename=" . $this->postname; + if ($this->contentType) { + $value .= ';type=' . $this->contentType; + } + + return $value; + } + + /** + * @deprecated + * @codeCoverageIgnore + */ + public function getCurlString() + { + Version::warn(__METHOD__ . ' is deprecated. Use getCurlValue()'); + return $this->getCurlValue(); + } + + /** + * Determine the Content-Type of the file + */ + protected function guessContentType() + { + return Mimetypes::getInstance()->fromFilename($this->filename) ?: 'application/octet-stream'; + } +} diff --git a/vendor/guzzle/guzzle/src/Guzzle/Http/Message/PostFileInterface.php b/vendor/guzzle/guzzle/src/Guzzle/Http/Message/PostFileInterface.php new file mode 100644 index 0000000..7f0779d --- /dev/null +++ b/vendor/guzzle/guzzle/src/Guzzle/Http/Message/PostFileInterface.php @@ -0,0 +1,83 @@ +method = strtoupper($method); + $this->curlOptions = new Collection(); + $this->setUrl($url); + + if ($headers) { + // Special handling for multi-value headers + foreach ($headers as $key => $value) { + // Deal with collisions with Host and Authorization + if ($key == 'host' || $key == 'Host') { + $this->setHeader($key, $value); + } elseif ($value instanceof HeaderInterface) { + $this->addHeader($key, $value); + } else { + foreach ((array) $value as $v) { + $this->addHeader($key, $v); + } + } + } + } + + $this->setState(self::STATE_NEW); + } + + public function __clone() + { + if ($this->eventDispatcher) { + $this->eventDispatcher = clone $this->eventDispatcher; + } + $this->curlOptions = clone $this->curlOptions; + $this->params = clone $this->params; + $this->url = clone $this->url; + $this->response = $this->responseBody = null; + $this->headers = clone $this->headers; + + $this->setState(RequestInterface::STATE_NEW); + $this->dispatch('request.clone', array('request' => $this)); + } + + /** + * Get the HTTP request as a string + * + * @return string + */ + public function __toString() + { + return $this->getRawHeaders() . "\r\n\r\n"; + } + + /** + * Default method that will throw exceptions if an unsuccessful response is received. + * + * @param Event $event Received + * @throws BadResponseException if the response is not successful + */ + public static function onRequestError(Event $event) + { + $e = BadResponseException::factory($event['request'], $event['response']); + $event['request']->setState(self::STATE_ERROR, array('exception' => $e) + $event->toArray()); + throw $e; + } + + public function setClient(ClientInterface $client) + { + $this->client = $client; + + return $this; + } + + public function getClient() + { + return $this->client; + } + + public function getRawHeaders() + { + $protocolVersion = $this->protocolVersion ?: '1.1'; + + return trim($this->method . ' ' . $this->getResource()) . ' ' + . strtoupper(str_replace('https', 'http', $this->url->getScheme())) + . '/' . $protocolVersion . "\r\n" . implode("\r\n", $this->getHeaderLines()); + } + + public function setUrl($url) + { + if ($url instanceof Url) { + $this->url = $url; + } else { + $this->url = Url::factory($url); + } + + // Update the port and host header + $this->setPort($this->url->getPort()); + + if ($this->url->getUsername() || $this->url->getPassword()) { + $this->setAuth($this->url->getUsername(), $this->url->getPassword()); + // Remove the auth info from the URL + $this->url->setUsername(null); + $this->url->setPassword(null); + } + + return $this; + } + + public function send() + { + if (!$this->client) { + throw new RuntimeException('A client must be set on the request'); + } + + return $this->client->send($this); + } + + public function getResponse() + { + return $this->response; + } + + public function getQuery($asString = false) + { + return $asString + ? (string) $this->url->getQuery() + : $this->url->getQuery(); + } + + public function getMethod() + { + return $this->method; + } + + public function getScheme() + { + return $this->url->getScheme(); + } + + public function setScheme($scheme) + { + $this->url->setScheme($scheme); + + return $this; + } + + public function getHost() + { + return $this->url->getHost(); + } + + public function setHost($host) + { + $this->url->setHost($host); + $this->setPort($this->url->getPort()); + + return $this; + } + + public function getProtocolVersion() + { + return $this->protocolVersion; + } + + public function setProtocolVersion($protocol) + { + $this->protocolVersion = $protocol; + + return $this; + } + + public function getPath() + { + return '/' . ltrim($this->url->getPath(), '/'); + } + + public function setPath($path) + { + $this->url->setPath($path); + + return $this; + } + + public function getPort() + { + return $this->url->getPort(); + } + + public function setPort($port) + { + $this->url->setPort($port); + + // Include the port in the Host header if it is not the default port for the scheme of the URL + $scheme = $this->url->getScheme(); + if ($port && (($scheme == 'http' && $port != 80) || ($scheme == 'https' && $port != 443))) { + $this->headers['host'] = $this->headerFactory->createHeader('Host', $this->url->getHost() . ':' . $port); + } else { + $this->headers['host'] = $this->headerFactory->createHeader('Host', $this->url->getHost()); + } + + return $this; + } + + public function getUsername() + { + return $this->username; + } + + public function getPassword() + { + return $this->password; + } + + public function setAuth($user, $password = '', $scheme = CURLAUTH_BASIC) + { + static $authMap = array( + 'basic' => CURLAUTH_BASIC, + 'digest' => CURLAUTH_DIGEST, + 'ntlm' => CURLAUTH_NTLM, + 'any' => CURLAUTH_ANY + ); + + // If we got false or null, disable authentication + if (!$user) { + $this->password = $this->username = null; + $this->removeHeader('Authorization'); + $this->getCurlOptions()->remove(CURLOPT_HTTPAUTH); + return $this; + } + + if (!is_numeric($scheme)) { + $scheme = strtolower($scheme); + if (!isset($authMap[$scheme])) { + throw new InvalidArgumentException($scheme . ' is not a valid authentication type'); + } + $scheme = $authMap[$scheme]; + } + + $this->username = $user; + $this->password = $password; + + // Bypass CURL when using basic auth to promote connection reuse + if ($scheme == CURLAUTH_BASIC) { + $this->getCurlOptions()->remove(CURLOPT_HTTPAUTH); + $this->setHeader('Authorization', 'Basic ' . base64_encode($this->username . ':' . $this->password)); + } else { + $this->getCurlOptions() + ->set(CURLOPT_HTTPAUTH, $scheme) + ->set(CURLOPT_USERPWD, $this->username . ':' . $this->password); + } + + return $this; + } + + public function getResource() + { + $resource = $this->getPath(); + if ($query = (string) $this->url->getQuery()) { + $resource .= '?' . $query; + } + + return $resource; + } + + public function getUrl($asObject = false) + { + return $asObject ? clone $this->url : (string) $this->url; + } + + public function getState() + { + return $this->state; + } + + public function setState($state, array $context = array()) + { + $oldState = $this->state; + $this->state = $state; + + switch ($state) { + case self::STATE_NEW: + $this->response = null; + break; + case self::STATE_TRANSFER: + if ($oldState !== $state) { + // Fix Content-Length and Transfer-Encoding collisions + if ($this->hasHeader('Transfer-Encoding') && $this->hasHeader('Content-Length')) { + $this->removeHeader('Transfer-Encoding'); + } + $this->dispatch('request.before_send', array('request' => $this)); + } + break; + case self::STATE_COMPLETE: + if ($oldState !== $state) { + $this->processResponse($context); + $this->responseBody = null; + } + break; + case self::STATE_ERROR: + if (isset($context['exception'])) { + $this->dispatch('request.exception', array( + 'request' => $this, + 'response' => isset($context['response']) ? $context['response'] : $this->response, + 'exception' => isset($context['exception']) ? $context['exception'] : null + )); + } + } + + return $this->state; + } + + public function getCurlOptions() + { + return $this->curlOptions; + } + + public function startResponse(Response $response) + { + $this->state = self::STATE_TRANSFER; + $response->setEffectiveUrl((string) $this->getUrl()); + $this->response = $response; + + return $this; + } + + public function setResponse(Response $response, $queued = false) + { + $response->setEffectiveUrl((string) $this->url); + + if ($queued) { + $ed = $this->getEventDispatcher(); + $ed->addListener('request.before_send', $f = function ($e) use ($response, &$f, $ed) { + $e['request']->setResponse($response); + $ed->removeListener('request.before_send', $f); + }, -9999); + } else { + $this->response = $response; + // If a specific response body is specified, then use it instead of the response's body + if ($this->responseBody && !$this->responseBody->getCustomData('default') && !$response->isRedirect()) { + $this->getResponseBody()->write((string) $this->response->getBody()); + } else { + $this->responseBody = $this->response->getBody(); + } + $this->setState(self::STATE_COMPLETE); + } + + return $this; + } + + public function setResponseBody($body) + { + // Attempt to open a file for writing if a string was passed + if (is_string($body)) { + // @codeCoverageIgnoreStart + if (!($body = fopen($body, 'w+'))) { + throw new InvalidArgumentException('Could not open ' . $body . ' for writing'); + } + // @codeCoverageIgnoreEnd + } + + $this->responseBody = EntityBody::factory($body); + + return $this; + } + + public function getResponseBody() + { + if ($this->responseBody === null) { + $this->responseBody = EntityBody::factory()->setCustomData('default', true); + } + + return $this->responseBody; + } + + /** + * Determine if the response body is repeatable (readable + seekable) + * + * @return bool + * @deprecated Use getResponseBody()->isSeekable() + * @codeCoverageIgnore + */ + public function isResponseBodyRepeatable() + { + Version::warn(__METHOD__ . ' is deprecated. Use $request->getResponseBody()->isRepeatable()'); + return !$this->responseBody ? true : $this->responseBody->isRepeatable(); + } + + public function getCookies() + { + if ($cookie = $this->getHeader('Cookie')) { + $data = ParserRegistry::getInstance()->getParser('cookie')->parseCookie($cookie); + return $data['cookies']; + } + + return array(); + } + + public function getCookie($name) + { + $cookies = $this->getCookies(); + + return isset($cookies[$name]) ? $cookies[$name] : null; + } + + public function addCookie($name, $value) + { + if (!$this->hasHeader('Cookie')) { + $this->setHeader('Cookie', "{$name}={$value}"); + } else { + $this->getHeader('Cookie')->add("{$name}={$value}"); + } + + // Always use semicolons to separate multiple cookie headers + $this->getHeader('Cookie')->setGlue(';'); + + return $this; + } + + public function removeCookie($name) + { + if ($cookie = $this->getHeader('Cookie')) { + foreach ($cookie as $cookieValue) { + if (strpos($cookieValue, $name . '=') === 0) { + $cookie->removeValue($cookieValue); + } + } + } + + return $this; + } + + public function setEventDispatcher(EventDispatcherInterface $eventDispatcher) + { + $this->eventDispatcher = $eventDispatcher; + $this->eventDispatcher->addListener('request.error', array(__CLASS__, 'onRequestError'), -255); + + return $this; + } + + public function getEventDispatcher() + { + if (!$this->eventDispatcher) { + $this->setEventDispatcher(new EventDispatcher()); + } + + return $this->eventDispatcher; + } + + public function dispatch($eventName, array $context = array()) + { + $context['request'] = $this; + + return $this->getEventDispatcher()->dispatch($eventName, new Event($context)); + } + + public function addSubscriber(EventSubscriberInterface $subscriber) + { + $this->getEventDispatcher()->addSubscriber($subscriber); + + return $this; + } + + /** + * Get an array containing the request and response for event notifications + * + * @return array + */ + protected function getEventArray() + { + return array( + 'request' => $this, + 'response' => $this->response + ); + } + + /** + * Process a received response + * + * @param array $context Contextual information + * @throws RequestException|BadResponseException on unsuccessful responses + */ + protected function processResponse(array $context = array()) + { + if (!$this->response) { + // If no response, then processResponse shouldn't have been called + $e = new RequestException('Error completing request'); + $e->setRequest($this); + throw $e; + } + + $this->state = self::STATE_COMPLETE; + + // A request was sent, but we don't know if we'll send more or if the final response will be successful + $this->dispatch('request.sent', $this->getEventArray() + $context); + + // Some response processors will remove the response or reset the state (example: ExponentialBackoffPlugin) + if ($this->state == RequestInterface::STATE_COMPLETE) { + + // The request completed, so the HTTP transaction is complete + $this->dispatch('request.complete', $this->getEventArray()); + + // If the response is bad, allow listeners to modify it or throw exceptions. You can change the response by + // modifying the Event object in your listeners or calling setResponse() on the request + if ($this->response->isError()) { + $event = new Event($this->getEventArray()); + $this->getEventDispatcher()->dispatch('request.error', $event); + // Allow events of request.error to quietly change the response + if ($event['response'] !== $this->response) { + $this->response = $event['response']; + } + } + + // If a successful response was received, dispatch an event + if ($this->response->isSuccessful()) { + $this->dispatch('request.success', $this->getEventArray()); + } + } + } + + /** + * @deprecated Use Guzzle\Plugin\Cache\DefaultCanCacheStrategy + * @codeCoverageIgnore + */ + public function canCache() + { + Version::warn(__METHOD__ . ' is deprecated. Use Guzzle\Plugin\Cache\DefaultCanCacheStrategy.'); + if (class_exists('Guzzle\Plugin\Cache\DefaultCanCacheStrategy')) { + $canCache = new \Guzzle\Plugin\Cache\DefaultCanCacheStrategy(); + return $canCache->canCacheRequest($this); + } else { + return false; + } + } + + /** + * @deprecated Use the history plugin (not emitting a warning as this is built-into the RedirectPlugin for now) + * @codeCoverageIgnore + */ + public function setIsRedirect($isRedirect) + { + $this->isRedirect = $isRedirect; + + return $this; + } + + /** + * @deprecated Use the history plugin + * @codeCoverageIgnore + */ + public function isRedirect() + { + Version::warn(__METHOD__ . ' is deprecated. Use the HistoryPlugin to track this.'); + return $this->isRedirect; + } +} diff --git a/vendor/guzzle/guzzle/src/Guzzle/Http/Message/RequestFactory.php b/vendor/guzzle/guzzle/src/Guzzle/Http/Message/RequestFactory.php new file mode 100644 index 0000000..ba00a76 --- /dev/null +++ b/vendor/guzzle/guzzle/src/Guzzle/Http/Message/RequestFactory.php @@ -0,0 +1,359 @@ +methods = array_flip(get_class_methods(__CLASS__)); + } + + public function fromMessage($message) + { + $parsed = ParserRegistry::getInstance()->getParser('message')->parseRequest($message); + + if (!$parsed) { + return false; + } + + $request = $this->fromParts($parsed['method'], $parsed['request_url'], + $parsed['headers'], $parsed['body'], $parsed['protocol'], + $parsed['version']); + + // EntityEnclosingRequest adds an "Expect: 100-Continue" header when using a raw request body for PUT or POST + // requests. This factory method should accurately reflect the message, so here we are removing the Expect + // header if one was not supplied in the message. + if (!isset($parsed['headers']['Expect']) && !isset($parsed['headers']['expect'])) { + $request->removeHeader('Expect'); + } + + return $request; + } + + public function fromParts( + $method, + array $urlParts, + $headers = null, + $body = null, + $protocol = 'HTTP', + $protocolVersion = '1.1' + ) { + return $this->create($method, Url::buildUrl($urlParts), $headers, $body) + ->setProtocolVersion($protocolVersion); + } + + public function create($method, $url, $headers = null, $body = null, array $options = array()) + { + $method = strtoupper($method); + + if ($method == 'GET' || $method == 'HEAD' || $method == 'TRACE') { + // Handle non-entity-enclosing request methods + $request = new $this->requestClass($method, $url, $headers); + if ($body) { + // The body is where the response body will be stored + $type = gettype($body); + if ($type == 'string' || $type == 'resource' || $type == 'object') { + $request->setResponseBody($body); + } + } + } else { + // Create an entity enclosing request by default + $request = new $this->entityEnclosingRequestClass($method, $url, $headers); + if ($body || $body === '0') { + // Add POST fields and files to an entity enclosing request if an array is used + if (is_array($body) || $body instanceof Collection) { + // Normalize PHP style cURL uploads with a leading '@' symbol + foreach ($body as $key => $value) { + if (is_string($value) && substr($value, 0, 1) == '@') { + $request->addPostFile($key, $value); + unset($body[$key]); + } + } + // Add the fields if they are still present and not all files + $request->addPostFields($body); + } else { + // Add a raw entity body body to the request + $request->setBody($body, (string) $request->getHeader('Content-Type')); + if ((string) $request->getHeader('Transfer-Encoding') == 'chunked') { + $request->removeHeader('Content-Length'); + } + } + } + } + + if ($options) { + $this->applyOptions($request, $options); + } + + return $request; + } + + /** + * Clone a request while changing the method. Emulates the behavior of + * {@see Guzzle\Http\Message\Request::clone}, but can change the HTTP method. + * + * @param RequestInterface $request Request to clone + * @param string $method Method to set + * + * @return RequestInterface + */ + public function cloneRequestWithMethod(RequestInterface $request, $method) + { + // Create the request with the same client if possible + if ($request->getClient()) { + $cloned = $request->getClient()->createRequest($method, $request->getUrl(), $request->getHeaders()); + } else { + $cloned = $this->create($method, $request->getUrl(), $request->getHeaders()); + } + + $cloned->getCurlOptions()->replace($request->getCurlOptions()->toArray()); + $cloned->setEventDispatcher(clone $request->getEventDispatcher()); + // Ensure that that the Content-Length header is not copied if changing to GET or HEAD + if (!($cloned instanceof EntityEnclosingRequestInterface)) { + $cloned->removeHeader('Content-Length'); + } elseif ($request instanceof EntityEnclosingRequestInterface) { + $cloned->setBody($request->getBody()); + } + $cloned->getParams()->replace($request->getParams()->toArray()); + $cloned->dispatch('request.clone', array('request' => $cloned)); + + return $cloned; + } + + public function applyOptions(RequestInterface $request, array $options = array(), $flags = self::OPTIONS_NONE) + { + // Iterate over each key value pair and attempt to apply a config using function visitors + foreach ($options as $key => $value) { + $method = "visit_{$key}"; + if (isset($this->methods[$method])) { + $this->{$method}($request, $value, $flags); + } + } + } + + protected function visit_headers(RequestInterface $request, $value, $flags) + { + if (!is_array($value)) { + throw new InvalidArgumentException('headers value must be an array'); + } + + if ($flags & self::OPTIONS_AS_DEFAULTS) { + // Merge headers in but do not overwrite existing values + foreach ($value as $key => $header) { + if (!$request->hasHeader($key)) { + $request->setHeader($key, $header); + } + } + } else { + $request->addHeaders($value); + } + } + + protected function visit_body(RequestInterface $request, $value, $flags) + { + if ($request instanceof EntityEnclosingRequestInterface) { + $request->setBody($value); + } else { + throw new InvalidArgumentException('Attempting to set a body on a non-entity-enclosing request'); + } + } + + protected function visit_allow_redirects(RequestInterface $request, $value, $flags) + { + if ($value === false) { + $request->getParams()->set(RedirectPlugin::DISABLE, true); + } + } + + protected function visit_auth(RequestInterface $request, $value, $flags) + { + if (!is_array($value)) { + throw new InvalidArgumentException('auth value must be an array'); + } + + $request->setAuth($value[0], isset($value[1]) ? $value[1] : null, isset($value[2]) ? $value[2] : 'basic'); + } + + protected function visit_query(RequestInterface $request, $value, $flags) + { + if (!is_array($value)) { + throw new InvalidArgumentException('query value must be an array'); + } + + if ($flags & self::OPTIONS_AS_DEFAULTS) { + // Merge query string values in but do not overwrite existing values + $query = $request->getQuery(); + $query->overwriteWith(array_diff_key($value, $query->toArray())); + } else { + $request->getQuery()->overwriteWith($value); + } + } + + protected function visit_cookies(RequestInterface $request, $value, $flags) + { + if (!is_array($value)) { + throw new InvalidArgumentException('cookies value must be an array'); + } + + foreach ($value as $name => $v) { + $request->addCookie($name, $v); + } + } + + protected function visit_events(RequestInterface $request, $value, $flags) + { + if (!is_array($value)) { + throw new InvalidArgumentException('events value must be an array'); + } + + foreach ($value as $name => $method) { + if (is_array($method)) { + $request->getEventDispatcher()->addListener($name, $method[0], $method[1]); + } else { + $request->getEventDispatcher()->addListener($name, $method); + } + } + } + + protected function visit_plugins(RequestInterface $request, $value, $flags) + { + if (!is_array($value)) { + throw new InvalidArgumentException('plugins value must be an array'); + } + + foreach ($value as $plugin) { + $request->addSubscriber($plugin); + } + } + + protected function visit_exceptions(RequestInterface $request, $value, $flags) + { + if ($value === false || $value === 0) { + $dispatcher = $request->getEventDispatcher(); + foreach ($dispatcher->getListeners('request.error') as $listener) { + if (is_array($listener) && $listener[0] == 'Guzzle\Http\Message\Request' && $listener[1] = 'onRequestError') { + $dispatcher->removeListener('request.error', $listener); + break; + } + } + } + } + + protected function visit_save_to(RequestInterface $request, $value, $flags) + { + $request->setResponseBody($value); + } + + protected function visit_params(RequestInterface $request, $value, $flags) + { + if (!is_array($value)) { + throw new InvalidArgumentException('params value must be an array'); + } + + $request->getParams()->overwriteWith($value); + } + + protected function visit_timeout(RequestInterface $request, $value, $flags) + { + if (defined('CURLOPT_TIMEOUT_MS')) { + $request->getCurlOptions()->set(CURLOPT_TIMEOUT_MS, $value * 1000); + } else { + $request->getCurlOptions()->set(CURLOPT_TIMEOUT, $value); + } + } + + protected function visit_connect_timeout(RequestInterface $request, $value, $flags) + { + if (defined('CURLOPT_CONNECTTIMEOUT_MS')) { + $request->getCurlOptions()->set(CURLOPT_CONNECTTIMEOUT_MS, $value * 1000); + } else { + $request->getCurlOptions()->set(CURLOPT_CONNECTTIMEOUT, $value); + } + } + + protected function visit_debug(RequestInterface $request, $value, $flags) + { + if ($value) { + $request->getCurlOptions()->set(CURLOPT_VERBOSE, true); + } + } + + protected function visit_verify(RequestInterface $request, $value, $flags) + { + $curl = $request->getCurlOptions(); + if ($value === true || is_string($value)) { + $curl[CURLOPT_SSL_VERIFYHOST] = 2; + $curl[CURLOPT_SSL_VERIFYPEER] = true; + if ($value !== true) { + $curl[CURLOPT_CAINFO] = $value; + } + } elseif ($value === false) { + unset($curl[CURLOPT_CAINFO]); + $curl[CURLOPT_SSL_VERIFYHOST] = 0; + $curl[CURLOPT_SSL_VERIFYPEER] = false; + } + } + + protected function visit_proxy(RequestInterface $request, $value, $flags) + { + $request->getCurlOptions()->set(CURLOPT_PROXY, $value, $flags); + } + + protected function visit_cert(RequestInterface $request, $value, $flags) + { + if (is_array($value)) { + $request->getCurlOptions()->set(CURLOPT_SSLCERT, $value[0]); + $request->getCurlOptions()->set(CURLOPT_SSLCERTPASSWD, $value[1]); + } else { + $request->getCurlOptions()->set(CURLOPT_SSLCERT, $value); + } + } + + protected function visit_ssl_key(RequestInterface $request, $value, $flags) + { + if (is_array($value)) { + $request->getCurlOptions()->set(CURLOPT_SSLKEY, $value[0]); + $request->getCurlOptions()->set(CURLOPT_SSLKEYPASSWD, $value[1]); + } else { + $request->getCurlOptions()->set(CURLOPT_SSLKEY, $value); + } + } +} diff --git a/vendor/guzzle/guzzle/src/Guzzle/Http/Message/RequestFactoryInterface.php b/vendor/guzzle/guzzle/src/Guzzle/Http/Message/RequestFactoryInterface.php new file mode 100644 index 0000000..6088f10 --- /dev/null +++ b/vendor/guzzle/guzzle/src/Guzzle/Http/Message/RequestFactoryInterface.php @@ -0,0 +1,105 @@ + 'Continue', + 101 => 'Switching Protocols', + 102 => 'Processing', + 200 => 'OK', + 201 => 'Created', + 202 => 'Accepted', + 203 => 'Non-Authoritative Information', + 204 => 'No Content', + 205 => 'Reset Content', + 206 => 'Partial Content', + 207 => 'Multi-Status', + 208 => 'Already Reported', + 226 => 'IM Used', + 300 => 'Multiple Choices', + 301 => 'Moved Permanently', + 302 => 'Found', + 303 => 'See Other', + 304 => 'Not Modified', + 305 => 'Use Proxy', + 307 => 'Temporary Redirect', + 308 => 'Permanent Redirect', + 400 => 'Bad Request', + 401 => 'Unauthorized', + 402 => 'Payment Required', + 403 => 'Forbidden', + 404 => 'Not Found', + 405 => 'Method Not Allowed', + 406 => 'Not Acceptable', + 407 => 'Proxy Authentication Required', + 408 => 'Request Timeout', + 409 => 'Conflict', + 410 => 'Gone', + 411 => 'Length Required', + 412 => 'Precondition Failed', + 413 => 'Request Entity Too Large', + 414 => 'Request-URI Too Long', + 415 => 'Unsupported Media Type', + 416 => 'Requested Range Not Satisfiable', + 417 => 'Expectation Failed', + 422 => 'Unprocessable Entity', + 423 => 'Locked', + 424 => 'Failed Dependency', + 425 => 'Reserved for WebDAV advanced collections expired proposal', + 426 => 'Upgrade required', + 428 => 'Precondition Required', + 429 => 'Too Many Requests', + 431 => 'Request Header Fields Too Large', + 500 => 'Internal Server Error', + 501 => 'Not Implemented', + 502 => 'Bad Gateway', + 503 => 'Service Unavailable', + 504 => 'Gateway Timeout', + 505 => 'HTTP Version Not Supported', + 506 => 'Variant Also Negotiates (Experimental)', + 507 => 'Insufficient Storage', + 508 => 'Loop Detected', + 510 => 'Not Extended', + 511 => 'Network Authentication Required', + ); + + /** @var EntityBodyInterface The response body */ + protected $body; + + /** @var string The reason phrase of the response (human readable code) */ + protected $reasonPhrase; + + /** @var string The status code of the response */ + protected $statusCode; + + /** @var array Information about the request */ + protected $info = array(); + + /** @var string The effective URL that returned this response */ + protected $effectiveUrl; + + /** @var array Cacheable response codes (see RFC 2616:13.4) */ + protected static $cacheResponseCodes = array(200, 203, 206, 300, 301, 410); + + /** + * Create a new Response based on a raw response message + * + * @param string $message Response message + * + * @return self|bool Returns false on error + */ + public static function fromMessage($message) + { + $data = ParserRegistry::getInstance()->getParser('message')->parseResponse($message); + if (!$data) { + return false; + } + + $response = new static($data['code'], $data['headers'], $data['body']); + $response->setProtocol($data['protocol'], $data['version']) + ->setStatus($data['code'], $data['reason_phrase']); + + // Set the appropriate Content-Length if the one set is inaccurate (e.g. setting to X) + $contentLength = (string) $response->getHeader('Content-Length'); + $actualLength = strlen($data['body']); + if (strlen($data['body']) > 0 && $contentLength != $actualLength) { + $response->setHeader('Content-Length', $actualLength); + } + + return $response; + } + + /** + * Construct the response + * + * @param string $statusCode The response status code (e.g. 200, 404, etc) + * @param ToArrayInterface|array $headers The response headers + * @param string|resource|EntityBodyInterface $body The body of the response + * + * @throws BadResponseException if an invalid response code is given + */ + public function __construct($statusCode, $headers = null, $body = null) + { + parent::__construct(); + $this->setStatus($statusCode); + $this->body = EntityBody::factory($body !== null ? $body : ''); + + if ($headers) { + if (is_array($headers)) { + $this->setHeaders($headers); + } elseif ($headers instanceof ToArrayInterface) { + $this->setHeaders($headers->toArray()); + } else { + throw new BadResponseException('Invalid headers argument received'); + } + } + } + + /** + * @return string + */ + public function __toString() + { + return $this->getMessage(); + } + + public function serialize() + { + return json_encode(array( + 'status' => $this->statusCode, + 'body' => (string) $this->body, + 'headers' => $this->headers->toArray() + )); + } + + public function unserialize($serialize) + { + $data = json_decode($serialize, true); + $this->__construct($data['status'], $data['headers'], $data['body']); + } + + /** + * Get the response entity body + * + * @param bool $asString Set to TRUE to return a string of the body rather than a full body object + * + * @return EntityBodyInterface|string + */ + public function getBody($asString = false) + { + return $asString ? (string) $this->body : $this->body; + } + + /** + * Set the response entity body + * + * @param EntityBodyInterface|string $body Body to set + * + * @return self + */ + public function setBody($body) + { + $this->body = EntityBody::factory($body); + + return $this; + } + + /** + * Set the protocol and protocol version of the response + * + * @param string $protocol Response protocol + * @param string $version Protocol version + * + * @return self + */ + public function setProtocol($protocol, $version) + { + $this->protocol = $protocol; + $this->protocolVersion = $version; + + return $this; + } + + /** + * Get the protocol used for the response (e.g. HTTP) + * + * @return string + */ + public function getProtocol() + { + return $this->protocol; + } + + /** + * Get the HTTP protocol version + * + * @return string + */ + public function getProtocolVersion() + { + return $this->protocolVersion; + } + + /** + * Get a cURL transfer information + * + * @param string $key A single statistic to check + * + * @return array|string|null Returns all stats if no key is set, a single stat if a key is set, or null if a key + * is set and not found + * @link http://www.php.net/manual/en/function.curl-getinfo.php + */ + public function getInfo($key = null) + { + if ($key === null) { + return $this->info; + } elseif (array_key_exists($key, $this->info)) { + return $this->info[$key]; + } else { + return null; + } + } + + /** + * Set the transfer information + * + * @param array $info Array of cURL transfer stats + * + * @return self + */ + public function setInfo(array $info) + { + $this->info = $info; + + return $this; + } + + /** + * Set the response status + * + * @param int $statusCode Response status code to set + * @param string $reasonPhrase Response reason phrase + * + * @return self + * @throws BadResponseException when an invalid response code is received + */ + public function setStatus($statusCode, $reasonPhrase = '') + { + $this->statusCode = (int) $statusCode; + + if (!$reasonPhrase && isset(self::$statusTexts[$this->statusCode])) { + $this->reasonPhrase = self::$statusTexts[$this->statusCode]; + } else { + $this->reasonPhrase = $reasonPhrase; + } + + return $this; + } + + /** + * Get the response status code + * + * @return integer + */ + public function getStatusCode() + { + return $this->statusCode; + } + + /** + * Get the entire response as a string + * + * @return string + */ + public function getMessage() + { + $message = $this->getRawHeaders(); + + // Only include the body in the message if the size is < 2MB + $size = $this->body->getSize(); + if ($size < 2097152) { + $message .= (string) $this->body; + } + + return $message; + } + + /** + * Get the the raw message headers as a string + * + * @return string + */ + public function getRawHeaders() + { + $headers = 'HTTP/1.1 ' . $this->statusCode . ' ' . $this->reasonPhrase . "\r\n"; + $lines = $this->getHeaderLines(); + if (!empty($lines)) { + $headers .= implode("\r\n", $lines) . "\r\n"; + } + + return $headers . "\r\n"; + } + + /** + * Get the response reason phrase- a human readable version of the numeric + * status code + * + * @return string + */ + public function getReasonPhrase() + { + return $this->reasonPhrase; + } + + /** + * Get the Accept-Ranges HTTP header + * + * @return string Returns what partial content range types this server supports. + */ + public function getAcceptRanges() + { + return (string) $this->getHeader('Accept-Ranges'); + } + + /** + * Calculate the age of the response + * + * @return integer + */ + public function calculateAge() + { + $age = $this->getHeader('Age'); + + if ($age === null && $this->getDate()) { + $age = time() - strtotime($this->getDate()); + } + + return $age === null ? null : (int) (string) $age; + } + + /** + * Get the Age HTTP header + * + * @return integer|null Returns the age the object has been in a proxy cache in seconds. + */ + public function getAge() + { + return (string) $this->getHeader('Age'); + } + + /** + * Get the Allow HTTP header + * + * @return string|null Returns valid actions for a specified resource. To be used for a 405 Method not allowed. + */ + public function getAllow() + { + return (string) $this->getHeader('Allow'); + } + + /** + * Check if an HTTP method is allowed by checking the Allow response header + * + * @param string $method Method to check + * + * @return bool + */ + public function isMethodAllowed($method) + { + $allow = $this->getHeader('Allow'); + if ($allow) { + foreach (explode(',', $allow) as $allowable) { + if (!strcasecmp(trim($allowable), $method)) { + return true; + } + } + } + + return false; + } + + /** + * Get the Cache-Control HTTP header + * + * @return string + */ + public function getCacheControl() + { + return (string) $this->getHeader('Cache-Control'); + } + + /** + * Get the Connection HTTP header + * + * @return string + */ + public function getConnection() + { + return (string) $this->getHeader('Connection'); + } + + /** + * Get the Content-Encoding HTTP header + * + * @return string|null + */ + public function getContentEncoding() + { + return (string) $this->getHeader('Content-Encoding'); + } + + /** + * Get the Content-Language HTTP header + * + * @return string|null Returns the language the content is in. + */ + public function getContentLanguage() + { + return (string) $this->getHeader('Content-Language'); + } + + /** + * Get the Content-Length HTTP header + * + * @return integer Returns the length of the response body in bytes + */ + public function getContentLength() + { + return (int) (string) $this->getHeader('Content-Length'); + } + + /** + * Get the Content-Location HTTP header + * + * @return string|null Returns an alternate location for the returned data (e.g /index.htm) + */ + public function getContentLocation() + { + return (string) $this->getHeader('Content-Location'); + } + + /** + * Get the Content-Disposition HTTP header + * + * @return string|null Returns the Content-Disposition header + */ + public function getContentDisposition() + { + return (string) $this->getHeader('Content-Disposition'); + } + + /** + * Get the Content-MD5 HTTP header + * + * @return string|null Returns a Base64-encoded binary MD5 sum of the content of the response. + */ + public function getContentMd5() + { + return (string) $this->getHeader('Content-MD5'); + } + + /** + * Get the Content-Range HTTP header + * + * @return string Returns where in a full body message this partial message belongs (e.g. bytes 21010-47021/47022). + */ + public function getContentRange() + { + return (string) $this->getHeader('Content-Range'); + } + + /** + * Get the Content-Type HTTP header + * + * @return string Returns the mime type of this content. + */ + public function getContentType() + { + return (string) $this->getHeader('Content-Type'); + } + + /** + * Checks if the Content-Type is of a certain type. This is useful if the + * Content-Type header contains charset information and you need to know if + * the Content-Type matches a particular type. + * + * @param string $type Content type to check against + * + * @return bool + */ + public function isContentType($type) + { + return stripos($this->getHeader('Content-Type'), $type) !== false; + } + + /** + * Get the Date HTTP header + * + * @return string|null Returns the date and time that the message was sent. + */ + public function getDate() + { + return (string) $this->getHeader('Date'); + } + + /** + * Get the ETag HTTP header + * + * @return string|null Returns an identifier for a specific version of a resource, often a Message digest. + */ + public function getEtag() + { + return (string) $this->getHeader('ETag'); + } + + /** + * Get the Expires HTTP header + * + * @return string|null Returns the date/time after which the response is considered stale. + */ + public function getExpires() + { + return (string) $this->getHeader('Expires'); + } + + /** + * Get the Last-Modified HTTP header + * + * @return string|null Returns the last modified date for the requested object, in RFC 2822 format + * (e.g. Tue, 15 Nov 1994 12:45:26 GMT) + */ + public function getLastModified() + { + return (string) $this->getHeader('Last-Modified'); + } + + /** + * Get the Location HTTP header + * + * @return string|null Used in redirection, or when a new resource has been created. + */ + public function getLocation() + { + return (string) $this->getHeader('Location'); + } + + /** + * Get the Pragma HTTP header + * + * @return Header|null Returns the implementation-specific headers that may have various effects anywhere along + * the request-response chain. + */ + public function getPragma() + { + return (string) $this->getHeader('Pragma'); + } + + /** + * Get the Proxy-Authenticate HTTP header + * + * @return string|null Authentication to access the proxy (e.g. Basic) + */ + public function getProxyAuthenticate() + { + return (string) $this->getHeader('Proxy-Authenticate'); + } + + /** + * Get the Retry-After HTTP header + * + * @return int|null If an entity is temporarily unavailable, this instructs the client to try again after a + * specified period of time. + */ + public function getRetryAfter() + { + return (string) $this->getHeader('Retry-After'); + } + + /** + * Get the Server HTTP header + * + * @return string|null A name for the server + */ + public function getServer() + { + return (string) $this->getHeader('Server'); + } + + /** + * Get the Set-Cookie HTTP header + * + * @return string|null An HTTP cookie. + */ + public function getSetCookie() + { + return (string) $this->getHeader('Set-Cookie'); + } + + /** + * Get the Trailer HTTP header + * + * @return string|null The Trailer general field value indicates that the given set of header fields is present in + * the trailer of a message encoded with chunked transfer-coding. + */ + public function getTrailer() + { + return (string) $this->getHeader('Trailer'); + } + + /** + * Get the Transfer-Encoding HTTP header + * + * @return string|null The form of encoding used to safely transfer the entity to the user + */ + public function getTransferEncoding() + { + return (string) $this->getHeader('Transfer-Encoding'); + } + + /** + * Get the Vary HTTP header + * + * @return string|null Tells downstream proxies how to match future request headers to decide whether the cached + * response can be used rather than requesting a fresh one from the origin server. + */ + public function getVary() + { + return (string) $this->getHeader('Vary'); + } + + /** + * Get the Via HTTP header + * + * @return string|null Informs the client of proxies through which the response was sent. + */ + public function getVia() + { + return (string) $this->getHeader('Via'); + } + + /** + * Get the Warning HTTP header + * + * @return string|null A general warning about possible problems with the entity body + */ + public function getWarning() + { + return (string) $this->getHeader('Warning'); + } + + /** + * Get the WWW-Authenticate HTTP header + * + * @return string|null Indicates the authentication scheme that should be used to access the requested entity + */ + public function getWwwAuthenticate() + { + return (string) $this->getHeader('WWW-Authenticate'); + } + + /** + * Checks if HTTP Status code is a Client Error (4xx) + * + * @return bool + */ + public function isClientError() + { + return $this->statusCode >= 400 && $this->statusCode < 500; + } + + /** + * Checks if HTTP Status code is Server OR Client Error (4xx or 5xx) + * + * @return boolean + */ + public function isError() + { + return $this->isClientError() || $this->isServerError(); + } + + /** + * Checks if HTTP Status code is Information (1xx) + * + * @return bool + */ + public function isInformational() + { + return $this->statusCode < 200; + } + + /** + * Checks if HTTP Status code is a Redirect (3xx) + * + * @return bool + */ + public function isRedirect() + { + return $this->statusCode >= 300 && $this->statusCode < 400; + } + + /** + * Checks if HTTP Status code is Server Error (5xx) + * + * @return bool + */ + public function isServerError() + { + return $this->statusCode >= 500 && $this->statusCode < 600; + } + + /** + * Checks if HTTP Status code is Successful (2xx | 304) + * + * @return bool + */ + public function isSuccessful() + { + return ($this->statusCode >= 200 && $this->statusCode < 300) || $this->statusCode == 304; + } + + /** + * Check if the response can be cached based on the response headers + * + * @return bool Returns TRUE if the response can be cached or false if not + */ + public function canCache() + { + // Check if the response is cacheable based on the code + if (!in_array((int) $this->getStatusCode(), self::$cacheResponseCodes)) { + return false; + } + + // Make sure a valid body was returned and can be cached + if ((!$this->getBody()->isReadable() || !$this->getBody()->isSeekable()) + && ($this->getContentLength() > 0 || $this->getTransferEncoding() == 'chunked')) { + return false; + } + + // Never cache no-store resources (this is a private cache, so private + // can be cached) + if ($this->getHeader('Cache-Control') && $this->getHeader('Cache-Control')->hasDirective('no-store')) { + return false; + } + + return $this->isFresh() || $this->getFreshness() === null || $this->canValidate(); + } + + /** + * Gets the number of seconds from the current time in which this response is still considered fresh + * + * @return int|null Returns the number of seconds + */ + public function getMaxAge() + { + if ($header = $this->getHeader('Cache-Control')) { + // s-max-age, then max-age, then Expires + if ($age = $header->getDirective('s-maxage')) { + return $age; + } + if ($age = $header->getDirective('max-age')) { + return $age; + } + } + + if ($this->getHeader('Expires')) { + return strtotime($this->getExpires()) - time(); + } + + return null; + } + + /** + * Check if the response is considered fresh. + * + * A response is considered fresh when its age is less than or equal to the freshness lifetime (maximum age) of the + * response. + * + * @return bool|null + */ + public function isFresh() + { + $fresh = $this->getFreshness(); + + return $fresh === null ? null : $fresh >= 0; + } + + /** + * Check if the response can be validated against the origin server using a conditional GET request. + * + * @return bool + */ + public function canValidate() + { + return $this->getEtag() || $this->getLastModified(); + } + + /** + * Get the freshness of the response by returning the difference of the maximum lifetime of the response and the + * age of the response (max-age - age). + * + * Freshness values less than 0 mean that the response is no longer fresh and is ABS(freshness) seconds expired. + * Freshness values of greater than zero is the number of seconds until the response is no longer fresh. A NULL + * result means that no freshness information is available. + * + * @return int + */ + public function getFreshness() + { + $maxAge = $this->getMaxAge(); + $age = $this->calculateAge(); + + return $maxAge && $age ? ($maxAge - $age) : null; + } + + /** + * Parse the JSON response body and return an array + * + * @return array|string|int|bool|float + * @throws RuntimeException if the response body is not in JSON format + */ + public function json() + { + $data = json_decode((string) $this->body, true); + if (JSON_ERROR_NONE !== json_last_error()) { + throw new RuntimeException('Unable to parse response body into JSON: ' . json_last_error()); + } + + return $data === null ? array() : $data; + } + + /** + * Parse the XML response body and return a \SimpleXMLElement. + * + * In order to prevent XXE attacks, this method disables loading external + * entities. If you rely on external entities, then you must parse the + * XML response manually by accessing the response body directly. + * + * @return \SimpleXMLElement + * @throws RuntimeException if the response body is not in XML format + * @link http://websec.io/2012/08/27/Preventing-XXE-in-PHP.html + */ + public function xml() + { + $errorMessage = null; + $internalErrors = libxml_use_internal_errors(true); + $disableEntities = libxml_disable_entity_loader(true); + libxml_clear_errors(); + + try { + $xml = new \SimpleXMLElement((string) $this->body ?: '', LIBXML_NONET); + if ($error = libxml_get_last_error()) { + $errorMessage = $error->message; + } + } catch (\Exception $e) { + $errorMessage = $e->getMessage(); + } + + libxml_clear_errors(); + libxml_use_internal_errors($internalErrors); + libxml_disable_entity_loader($disableEntities); + + if ($errorMessage) { + throw new RuntimeException('Unable to parse response body into XML: ' . $errorMessage); + } + + return $xml; + } + + /** + * Get the redirect count of this response + * + * @return int + */ + public function getRedirectCount() + { + return (int) $this->params->get(RedirectPlugin::REDIRECT_COUNT); + } + + /** + * Set the effective URL that resulted in this response (e.g. the last redirect URL) + * + * @param string $url The effective URL + * + * @return self + */ + public function setEffectiveUrl($url) + { + $this->effectiveUrl = $url; + + return $this; + } + + /** + * Get the effective URL that resulted in this response (e.g. the last redirect URL) + * + * @return string + */ + public function getEffectiveUrl() + { + return $this->effectiveUrl; + } + + /** + * @deprecated + * @codeCoverageIgnore + */ + public function getPreviousResponse() + { + Version::warn(__METHOD__ . ' is deprecated. Use the HistoryPlugin.'); + return null; + } + + /** + * @deprecated + * @codeCoverageIgnore + */ + public function setRequest($request) + { + Version::warn(__METHOD__ . ' is deprecated'); + return $this; + } + + /** + * @deprecated + * @codeCoverageIgnore + */ + public function getRequest() + { + Version::warn(__METHOD__ . ' is deprecated'); + return null; + } +} diff --git a/vendor/guzzle/guzzle/src/Guzzle/Http/Mimetypes.php b/vendor/guzzle/guzzle/src/Guzzle/Http/Mimetypes.php new file mode 100644 index 0000000..d71586a --- /dev/null +++ b/vendor/guzzle/guzzle/src/Guzzle/Http/Mimetypes.php @@ -0,0 +1,962 @@ + 'text/vnd.in3d.3dml', + '3g2' => 'video/3gpp2', + '3gp' => 'video/3gpp', + '7z' => 'application/x-7z-compressed', + 'aab' => 'application/x-authorware-bin', + 'aac' => 'audio/x-aac', + 'aam' => 'application/x-authorware-map', + 'aas' => 'application/x-authorware-seg', + 'abw' => 'application/x-abiword', + 'ac' => 'application/pkix-attr-cert', + 'acc' => 'application/vnd.americandynamics.acc', + 'ace' => 'application/x-ace-compressed', + 'acu' => 'application/vnd.acucobol', + 'acutc' => 'application/vnd.acucorp', + 'adp' => 'audio/adpcm', + 'aep' => 'application/vnd.audiograph', + 'afm' => 'application/x-font-type1', + 'afp' => 'application/vnd.ibm.modcap', + 'ahead' => 'application/vnd.ahead.space', + 'ai' => 'application/postscript', + 'aif' => 'audio/x-aiff', + 'aifc' => 'audio/x-aiff', + 'aiff' => 'audio/x-aiff', + 'air' => 'application/vnd.adobe.air-application-installer-package+zip', + 'ait' => 'application/vnd.dvb.ait', + 'ami' => 'application/vnd.amiga.ami', + 'apk' => 'application/vnd.android.package-archive', + 'application' => 'application/x-ms-application', + 'apr' => 'application/vnd.lotus-approach', + 'asa' => 'text/plain', + 'asax' => 'application/octet-stream', + 'asc' => 'application/pgp-signature', + 'ascx' => 'text/plain', + 'asf' => 'video/x-ms-asf', + 'ashx' => 'text/plain', + 'asm' => 'text/x-asm', + 'asmx' => 'text/plain', + 'aso' => 'application/vnd.accpac.simply.aso', + 'asp' => 'text/plain', + 'aspx' => 'text/plain', + 'asx' => 'video/x-ms-asf', + 'atc' => 'application/vnd.acucorp', + 'atom' => 'application/atom+xml', + 'atomcat' => 'application/atomcat+xml', + 'atomsvc' => 'application/atomsvc+xml', + 'atx' => 'application/vnd.antix.game-component', + 'au' => 'audio/basic', + 'avi' => 'video/x-msvideo', + 'aw' => 'application/applixware', + 'axd' => 'text/plain', + 'azf' => 'application/vnd.airzip.filesecure.azf', + 'azs' => 'application/vnd.airzip.filesecure.azs', + 'azw' => 'application/vnd.amazon.ebook', + 'bat' => 'application/x-msdownload', + 'bcpio' => 'application/x-bcpio', + 'bdf' => 'application/x-font-bdf', + 'bdm' => 'application/vnd.syncml.dm+wbxml', + 'bed' => 'application/vnd.realvnc.bed', + 'bh2' => 'application/vnd.fujitsu.oasysprs', + 'bin' => 'application/octet-stream', + 'bmi' => 'application/vnd.bmi', + 'bmp' => 'image/bmp', + 'book' => 'application/vnd.framemaker', + 'box' => 'application/vnd.previewsystems.box', + 'boz' => 'application/x-bzip2', + 'bpk' => 'application/octet-stream', + 'btif' => 'image/prs.btif', + 'bz' => 'application/x-bzip', + 'bz2' => 'application/x-bzip2', + 'c' => 'text/x-c', + 'c11amc' => 'application/vnd.cluetrust.cartomobile-config', + 'c11amz' => 'application/vnd.cluetrust.cartomobile-config-pkg', + 'c4d' => 'application/vnd.clonk.c4group', + 'c4f' => 'application/vnd.clonk.c4group', + 'c4g' => 'application/vnd.clonk.c4group', + 'c4p' => 'application/vnd.clonk.c4group', + 'c4u' => 'application/vnd.clonk.c4group', + 'cab' => 'application/vnd.ms-cab-compressed', + 'car' => 'application/vnd.curl.car', + 'cat' => 'application/vnd.ms-pki.seccat', + 'cc' => 'text/x-c', + 'cct' => 'application/x-director', + 'ccxml' => 'application/ccxml+xml', + 'cdbcmsg' => 'application/vnd.contact.cmsg', + 'cdf' => 'application/x-netcdf', + 'cdkey' => 'application/vnd.mediastation.cdkey', + 'cdmia' => 'application/cdmi-capability', + 'cdmic' => 'application/cdmi-container', + 'cdmid' => 'application/cdmi-domain', + 'cdmio' => 'application/cdmi-object', + 'cdmiq' => 'application/cdmi-queue', + 'cdx' => 'chemical/x-cdx', + 'cdxml' => 'application/vnd.chemdraw+xml', + 'cdy' => 'application/vnd.cinderella', + 'cer' => 'application/pkix-cert', + 'cfc' => 'application/x-coldfusion', + 'cfm' => 'application/x-coldfusion', + 'cgm' => 'image/cgm', + 'chat' => 'application/x-chat', + 'chm' => 'application/vnd.ms-htmlhelp', + 'chrt' => 'application/vnd.kde.kchart', + 'cif' => 'chemical/x-cif', + 'cii' => 'application/vnd.anser-web-certificate-issue-initiation', + 'cil' => 'application/vnd.ms-artgalry', + 'cla' => 'application/vnd.claymore', + 'class' => 'application/java-vm', + 'clkk' => 'application/vnd.crick.clicker.keyboard', + 'clkp' => 'application/vnd.crick.clicker.palette', + 'clkt' => 'application/vnd.crick.clicker.template', + 'clkw' => 'application/vnd.crick.clicker.wordbank', + 'clkx' => 'application/vnd.crick.clicker', + 'clp' => 'application/x-msclip', + 'cmc' => 'application/vnd.cosmocaller', + 'cmdf' => 'chemical/x-cmdf', + 'cml' => 'chemical/x-cml', + 'cmp' => 'application/vnd.yellowriver-custom-menu', + 'cmx' => 'image/x-cmx', + 'cod' => 'application/vnd.rim.cod', + 'com' => 'application/x-msdownload', + 'conf' => 'text/plain', + 'cpio' => 'application/x-cpio', + 'cpp' => 'text/x-c', + 'cpt' => 'application/mac-compactpro', + 'crd' => 'application/x-mscardfile', + 'crl' => 'application/pkix-crl', + 'crt' => 'application/x-x509-ca-cert', + 'cryptonote' => 'application/vnd.rig.cryptonote', + 'cs' => 'text/plain', + 'csh' => 'application/x-csh', + 'csml' => 'chemical/x-csml', + 'csp' => 'application/vnd.commonspace', + 'css' => 'text/css', + 'cst' => 'application/x-director', + 'csv' => 'text/csv', + 'cu' => 'application/cu-seeme', + 'curl' => 'text/vnd.curl', + 'cww' => 'application/prs.cww', + 'cxt' => 'application/x-director', + 'cxx' => 'text/x-c', + 'dae' => 'model/vnd.collada+xml', + 'daf' => 'application/vnd.mobius.daf', + 'dataless' => 'application/vnd.fdsn.seed', + 'davmount' => 'application/davmount+xml', + 'dcr' => 'application/x-director', + 'dcurl' => 'text/vnd.curl.dcurl', + 'dd2' => 'application/vnd.oma.dd2+xml', + 'ddd' => 'application/vnd.fujixerox.ddd', + 'deb' => 'application/x-debian-package', + 'def' => 'text/plain', + 'deploy' => 'application/octet-stream', + 'der' => 'application/x-x509-ca-cert', + 'dfac' => 'application/vnd.dreamfactory', + 'dic' => 'text/x-c', + 'dir' => 'application/x-director', + 'dis' => 'application/vnd.mobius.dis', + 'dist' => 'application/octet-stream', + 'distz' => 'application/octet-stream', + 'djv' => 'image/vnd.djvu', + 'djvu' => 'image/vnd.djvu', + 'dll' => 'application/x-msdownload', + 'dmg' => 'application/octet-stream', + 'dms' => 'application/octet-stream', + 'dna' => 'application/vnd.dna', + 'doc' => 'application/msword', + 'docm' => 'application/vnd.ms-word.document.macroenabled.12', + 'docx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', + 'dot' => 'application/msword', + 'dotm' => 'application/vnd.ms-word.template.macroenabled.12', + 'dotx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.template', + 'dp' => 'application/vnd.osgi.dp', + 'dpg' => 'application/vnd.dpgraph', + 'dra' => 'audio/vnd.dra', + 'dsc' => 'text/prs.lines.tag', + 'dssc' => 'application/dssc+der', + 'dtb' => 'application/x-dtbook+xml', + 'dtd' => 'application/xml-dtd', + 'dts' => 'audio/vnd.dts', + 'dtshd' => 'audio/vnd.dts.hd', + 'dump' => 'application/octet-stream', + 'dvi' => 'application/x-dvi', + 'dwf' => 'model/vnd.dwf', + 'dwg' => 'image/vnd.dwg', + 'dxf' => 'image/vnd.dxf', + 'dxp' => 'application/vnd.spotfire.dxp', + 'dxr' => 'application/x-director', + 'ecelp4800' => 'audio/vnd.nuera.ecelp4800', + 'ecelp7470' => 'audio/vnd.nuera.ecelp7470', + 'ecelp9600' => 'audio/vnd.nuera.ecelp9600', + 'ecma' => 'application/ecmascript', + 'edm' => 'application/vnd.novadigm.edm', + 'edx' => 'application/vnd.novadigm.edx', + 'efif' => 'application/vnd.picsel', + 'ei6' => 'application/vnd.pg.osasli', + 'elc' => 'application/octet-stream', + 'eml' => 'message/rfc822', + 'emma' => 'application/emma+xml', + 'eol' => 'audio/vnd.digital-winds', + 'eot' => 'application/vnd.ms-fontobject', + 'eps' => 'application/postscript', + 'epub' => 'application/epub+zip', + 'es3' => 'application/vnd.eszigno3+xml', + 'esf' => 'application/vnd.epson.esf', + 'et3' => 'application/vnd.eszigno3+xml', + 'etx' => 'text/x-setext', + 'exe' => 'application/x-msdownload', + 'exi' => 'application/exi', + 'ext' => 'application/vnd.novadigm.ext', + 'ez' => 'application/andrew-inset', + 'ez2' => 'application/vnd.ezpix-album', + 'ez3' => 'application/vnd.ezpix-package', + 'f' => 'text/x-fortran', + 'f4v' => 'video/x-f4v', + 'f77' => 'text/x-fortran', + 'f90' => 'text/x-fortran', + 'fbs' => 'image/vnd.fastbidsheet', + 'fcs' => 'application/vnd.isac.fcs', + 'fdf' => 'application/vnd.fdf', + 'fe_launch' => 'application/vnd.denovo.fcselayout-link', + 'fg5' => 'application/vnd.fujitsu.oasysgp', + 'fgd' => 'application/x-director', + 'fh' => 'image/x-freehand', + 'fh4' => 'image/x-freehand', + 'fh5' => 'image/x-freehand', + 'fh7' => 'image/x-freehand', + 'fhc' => 'image/x-freehand', + 'fig' => 'application/x-xfig', + 'fli' => 'video/x-fli', + 'flo' => 'application/vnd.micrografx.flo', + 'flv' => 'video/x-flv', + 'flw' => 'application/vnd.kde.kivio', + 'flx' => 'text/vnd.fmi.flexstor', + 'fly' => 'text/vnd.fly', + 'fm' => 'application/vnd.framemaker', + 'fnc' => 'application/vnd.frogans.fnc', + 'for' => 'text/x-fortran', + 'fpx' => 'image/vnd.fpx', + 'frame' => 'application/vnd.framemaker', + 'fsc' => 'application/vnd.fsc.weblaunch', + 'fst' => 'image/vnd.fst', + 'ftc' => 'application/vnd.fluxtime.clip', + 'fti' => 'application/vnd.anser-web-funds-transfer-initiation', + 'fvt' => 'video/vnd.fvt', + 'fxp' => 'application/vnd.adobe.fxp', + 'fxpl' => 'application/vnd.adobe.fxp', + 'fzs' => 'application/vnd.fuzzysheet', + 'g2w' => 'application/vnd.geoplan', + 'g3' => 'image/g3fax', + 'g3w' => 'application/vnd.geospace', + 'gac' => 'application/vnd.groove-account', + 'gdl' => 'model/vnd.gdl', + 'geo' => 'application/vnd.dynageo', + 'gex' => 'application/vnd.geometry-explorer', + 'ggb' => 'application/vnd.geogebra.file', + 'ggt' => 'application/vnd.geogebra.tool', + 'ghf' => 'application/vnd.groove-help', + 'gif' => 'image/gif', + 'gim' => 'application/vnd.groove-identity-message', + 'gmx' => 'application/vnd.gmx', + 'gnumeric' => 'application/x-gnumeric', + 'gph' => 'application/vnd.flographit', + 'gqf' => 'application/vnd.grafeq', + 'gqs' => 'application/vnd.grafeq', + 'gram' => 'application/srgs', + 'gre' => 'application/vnd.geometry-explorer', + 'grv' => 'application/vnd.groove-injector', + 'grxml' => 'application/srgs+xml', + 'gsf' => 'application/x-font-ghostscript', + 'gtar' => 'application/x-gtar', + 'gtm' => 'application/vnd.groove-tool-message', + 'gtw' => 'model/vnd.gtw', + 'gv' => 'text/vnd.graphviz', + 'gxt' => 'application/vnd.geonext', + 'h' => 'text/x-c', + 'h261' => 'video/h261', + 'h263' => 'video/h263', + 'h264' => 'video/h264', + 'hal' => 'application/vnd.hal+xml', + 'hbci' => 'application/vnd.hbci', + 'hdf' => 'application/x-hdf', + 'hh' => 'text/x-c', + 'hlp' => 'application/winhlp', + 'hpgl' => 'application/vnd.hp-hpgl', + 'hpid' => 'application/vnd.hp-hpid', + 'hps' => 'application/vnd.hp-hps', + 'hqx' => 'application/mac-binhex40', + 'hta' => 'application/octet-stream', + 'htc' => 'text/html', + 'htke' => 'application/vnd.kenameaapp', + 'htm' => 'text/html', + 'html' => 'text/html', + 'hvd' => 'application/vnd.yamaha.hv-dic', + 'hvp' => 'application/vnd.yamaha.hv-voice', + 'hvs' => 'application/vnd.yamaha.hv-script', + 'i2g' => 'application/vnd.intergeo', + 'icc' => 'application/vnd.iccprofile', + 'ice' => 'x-conference/x-cooltalk', + 'icm' => 'application/vnd.iccprofile', + 'ico' => 'image/x-icon', + 'ics' => 'text/calendar', + 'ief' => 'image/ief', + 'ifb' => 'text/calendar', + 'ifm' => 'application/vnd.shana.informed.formdata', + 'iges' => 'model/iges', + 'igl' => 'application/vnd.igloader', + 'igm' => 'application/vnd.insors.igm', + 'igs' => 'model/iges', + 'igx' => 'application/vnd.micrografx.igx', + 'iif' => 'application/vnd.shana.informed.interchange', + 'imp' => 'application/vnd.accpac.simply.imp', + 'ims' => 'application/vnd.ms-ims', + 'in' => 'text/plain', + 'ini' => 'text/plain', + 'ipfix' => 'application/ipfix', + 'ipk' => 'application/vnd.shana.informed.package', + 'irm' => 'application/vnd.ibm.rights-management', + 'irp' => 'application/vnd.irepository.package+xml', + 'iso' => 'application/octet-stream', + 'itp' => 'application/vnd.shana.informed.formtemplate', + 'ivp' => 'application/vnd.immervision-ivp', + 'ivu' => 'application/vnd.immervision-ivu', + 'jad' => 'text/vnd.sun.j2me.app-descriptor', + 'jam' => 'application/vnd.jam', + 'jar' => 'application/java-archive', + 'java' => 'text/x-java-source', + 'jisp' => 'application/vnd.jisp', + 'jlt' => 'application/vnd.hp-jlyt', + 'jnlp' => 'application/x-java-jnlp-file', + 'joda' => 'application/vnd.joost.joda-archive', + 'jpe' => 'image/jpeg', + 'jpeg' => 'image/jpeg', + 'jpg' => 'image/jpeg', + 'jpgm' => 'video/jpm', + 'jpgv' => 'video/jpeg', + 'jpm' => 'video/jpm', + 'js' => 'text/javascript', + 'json' => 'application/json', + 'kar' => 'audio/midi', + 'karbon' => 'application/vnd.kde.karbon', + 'kfo' => 'application/vnd.kde.kformula', + 'kia' => 'application/vnd.kidspiration', + 'kml' => 'application/vnd.google-earth.kml+xml', + 'kmz' => 'application/vnd.google-earth.kmz', + 'kne' => 'application/vnd.kinar', + 'knp' => 'application/vnd.kinar', + 'kon' => 'application/vnd.kde.kontour', + 'kpr' => 'application/vnd.kde.kpresenter', + 'kpt' => 'application/vnd.kde.kpresenter', + 'ksp' => 'application/vnd.kde.kspread', + 'ktr' => 'application/vnd.kahootz', + 'ktx' => 'image/ktx', + 'ktz' => 'application/vnd.kahootz', + 'kwd' => 'application/vnd.kde.kword', + 'kwt' => 'application/vnd.kde.kword', + 'lasxml' => 'application/vnd.las.las+xml', + 'latex' => 'application/x-latex', + 'lbd' => 'application/vnd.llamagraphics.life-balance.desktop', + 'lbe' => 'application/vnd.llamagraphics.life-balance.exchange+xml', + 'les' => 'application/vnd.hhe.lesson-player', + 'lha' => 'application/octet-stream', + 'link66' => 'application/vnd.route66.link66+xml', + 'list' => 'text/plain', + 'list3820' => 'application/vnd.ibm.modcap', + 'listafp' => 'application/vnd.ibm.modcap', + 'log' => 'text/plain', + 'lostxml' => 'application/lost+xml', + 'lrf' => 'application/octet-stream', + 'lrm' => 'application/vnd.ms-lrm', + 'ltf' => 'application/vnd.frogans.ltf', + 'lvp' => 'audio/vnd.lucent.voice', + 'lwp' => 'application/vnd.lotus-wordpro', + 'lzh' => 'application/octet-stream', + 'm13' => 'application/x-msmediaview', + 'm14' => 'application/x-msmediaview', + 'm1v' => 'video/mpeg', + 'm21' => 'application/mp21', + 'm2a' => 'audio/mpeg', + 'm2v' => 'video/mpeg', + 'm3a' => 'audio/mpeg', + 'm3u' => 'audio/x-mpegurl', + 'm3u8' => 'application/vnd.apple.mpegurl', + 'm4a' => 'audio/mp4', + 'm4u' => 'video/vnd.mpegurl', + 'm4v' => 'video/mp4', + 'ma' => 'application/mathematica', + 'mads' => 'application/mads+xml', + 'mag' => 'application/vnd.ecowin.chart', + 'maker' => 'application/vnd.framemaker', + 'man' => 'text/troff', + 'mathml' => 'application/mathml+xml', + 'mb' => 'application/mathematica', + 'mbk' => 'application/vnd.mobius.mbk', + 'mbox' => 'application/mbox', + 'mc1' => 'application/vnd.medcalcdata', + 'mcd' => 'application/vnd.mcd', + 'mcurl' => 'text/vnd.curl.mcurl', + 'mdb' => 'application/x-msaccess', + 'mdi' => 'image/vnd.ms-modi', + 'me' => 'text/troff', + 'mesh' => 'model/mesh', + 'meta4' => 'application/metalink4+xml', + 'mets' => 'application/mets+xml', + 'mfm' => 'application/vnd.mfmp', + 'mgp' => 'application/vnd.osgeo.mapguide.package', + 'mgz' => 'application/vnd.proteus.magazine', + 'mid' => 'audio/midi', + 'midi' => 'audio/midi', + 'mif' => 'application/vnd.mif', + 'mime' => 'message/rfc822', + 'mj2' => 'video/mj2', + 'mjp2' => 'video/mj2', + 'mlp' => 'application/vnd.dolby.mlp', + 'mmd' => 'application/vnd.chipnuts.karaoke-mmd', + 'mmf' => 'application/vnd.smaf', + 'mmr' => 'image/vnd.fujixerox.edmics-mmr', + 'mny' => 'application/x-msmoney', + 'mobi' => 'application/x-mobipocket-ebook', + 'mods' => 'application/mods+xml', + 'mov' => 'video/quicktime', + 'movie' => 'video/x-sgi-movie', + 'mp2' => 'audio/mpeg', + 'mp21' => 'application/mp21', + 'mp2a' => 'audio/mpeg', + 'mp3' => 'audio/mpeg', + 'mp4' => 'video/mp4', + 'mp4a' => 'audio/mp4', + 'mp4s' => 'application/mp4', + 'mp4v' => 'video/mp4', + 'mpc' => 'application/vnd.mophun.certificate', + 'mpe' => 'video/mpeg', + 'mpeg' => 'video/mpeg', + 'mpg' => 'video/mpeg', + 'mpg4' => 'video/mp4', + 'mpga' => 'audio/mpeg', + 'mpkg' => 'application/vnd.apple.installer+xml', + 'mpm' => 'application/vnd.blueice.multipass', + 'mpn' => 'application/vnd.mophun.application', + 'mpp' => 'application/vnd.ms-project', + 'mpt' => 'application/vnd.ms-project', + 'mpy' => 'application/vnd.ibm.minipay', + 'mqy' => 'application/vnd.mobius.mqy', + 'mrc' => 'application/marc', + 'mrcx' => 'application/marcxml+xml', + 'ms' => 'text/troff', + 'mscml' => 'application/mediaservercontrol+xml', + 'mseed' => 'application/vnd.fdsn.mseed', + 'mseq' => 'application/vnd.mseq', + 'msf' => 'application/vnd.epson.msf', + 'msh' => 'model/mesh', + 'msi' => 'application/x-msdownload', + 'msl' => 'application/vnd.mobius.msl', + 'msty' => 'application/vnd.muvee.style', + 'mts' => 'model/vnd.mts', + 'mus' => 'application/vnd.musician', + 'musicxml' => 'application/vnd.recordare.musicxml+xml', + 'mvb' => 'application/x-msmediaview', + 'mwf' => 'application/vnd.mfer', + 'mxf' => 'application/mxf', + 'mxl' => 'application/vnd.recordare.musicxml', + 'mxml' => 'application/xv+xml', + 'mxs' => 'application/vnd.triscape.mxs', + 'mxu' => 'video/vnd.mpegurl', + 'n-gage' => 'application/vnd.nokia.n-gage.symbian.install', + 'n3' => 'text/n3', + 'nb' => 'application/mathematica', + 'nbp' => 'application/vnd.wolfram.player', + 'nc' => 'application/x-netcdf', + 'ncx' => 'application/x-dtbncx+xml', + 'ngdat' => 'application/vnd.nokia.n-gage.data', + 'nlu' => 'application/vnd.neurolanguage.nlu', + 'nml' => 'application/vnd.enliven', + 'nnd' => 'application/vnd.noblenet-directory', + 'nns' => 'application/vnd.noblenet-sealer', + 'nnw' => 'application/vnd.noblenet-web', + 'npx' => 'image/vnd.net-fpx', + 'nsf' => 'application/vnd.lotus-notes', + 'oa2' => 'application/vnd.fujitsu.oasys2', + 'oa3' => 'application/vnd.fujitsu.oasys3', + 'oas' => 'application/vnd.fujitsu.oasys', + 'obd' => 'application/x-msbinder', + 'oda' => 'application/oda', + 'odb' => 'application/vnd.oasis.opendocument.database', + 'odc' => 'application/vnd.oasis.opendocument.chart', + 'odf' => 'application/vnd.oasis.opendocument.formula', + 'odft' => 'application/vnd.oasis.opendocument.formula-template', + 'odg' => 'application/vnd.oasis.opendocument.graphics', + 'odi' => 'application/vnd.oasis.opendocument.image', + 'odm' => 'application/vnd.oasis.opendocument.text-master', + 'odp' => 'application/vnd.oasis.opendocument.presentation', + 'ods' => 'application/vnd.oasis.opendocument.spreadsheet', + 'odt' => 'application/vnd.oasis.opendocument.text', + 'oga' => 'audio/ogg', + 'ogg' => 'audio/ogg', + 'ogv' => 'video/ogg', + 'ogx' => 'application/ogg', + 'onepkg' => 'application/onenote', + 'onetmp' => 'application/onenote', + 'onetoc' => 'application/onenote', + 'onetoc2' => 'application/onenote', + 'opf' => 'application/oebps-package+xml', + 'oprc' => 'application/vnd.palm', + 'org' => 'application/vnd.lotus-organizer', + 'osf' => 'application/vnd.yamaha.openscoreformat', + 'osfpvg' => 'application/vnd.yamaha.openscoreformat.osfpvg+xml', + 'otc' => 'application/vnd.oasis.opendocument.chart-template', + 'otf' => 'application/x-font-otf', + 'otg' => 'application/vnd.oasis.opendocument.graphics-template', + 'oth' => 'application/vnd.oasis.opendocument.text-web', + 'oti' => 'application/vnd.oasis.opendocument.image-template', + 'otp' => 'application/vnd.oasis.opendocument.presentation-template', + 'ots' => 'application/vnd.oasis.opendocument.spreadsheet-template', + 'ott' => 'application/vnd.oasis.opendocument.text-template', + 'oxt' => 'application/vnd.openofficeorg.extension', + 'p' => 'text/x-pascal', + 'p10' => 'application/pkcs10', + 'p12' => 'application/x-pkcs12', + 'p7b' => 'application/x-pkcs7-certificates', + 'p7c' => 'application/pkcs7-mime', + 'p7m' => 'application/pkcs7-mime', + 'p7r' => 'application/x-pkcs7-certreqresp', + 'p7s' => 'application/pkcs7-signature', + 'p8' => 'application/pkcs8', + 'pas' => 'text/x-pascal', + 'paw' => 'application/vnd.pawaafile', + 'pbd' => 'application/vnd.powerbuilder6', + 'pbm' => 'image/x-portable-bitmap', + 'pcf' => 'application/x-font-pcf', + 'pcl' => 'application/vnd.hp-pcl', + 'pclxl' => 'application/vnd.hp-pclxl', + 'pct' => 'image/x-pict', + 'pcurl' => 'application/vnd.curl.pcurl', + 'pcx' => 'image/x-pcx', + 'pdb' => 'application/vnd.palm', + 'pdf' => 'application/pdf', + 'pfa' => 'application/x-font-type1', + 'pfb' => 'application/x-font-type1', + 'pfm' => 'application/x-font-type1', + 'pfr' => 'application/font-tdpfr', + 'pfx' => 'application/x-pkcs12', + 'pgm' => 'image/x-portable-graymap', + 'pgn' => 'application/x-chess-pgn', + 'pgp' => 'application/pgp-encrypted', + 'php' => 'text/x-php', + 'phps' => 'application/x-httpd-phps', + 'pic' => 'image/x-pict', + 'pkg' => 'application/octet-stream', + 'pki' => 'application/pkixcmp', + 'pkipath' => 'application/pkix-pkipath', + 'plb' => 'application/vnd.3gpp.pic-bw-large', + 'plc' => 'application/vnd.mobius.plc', + 'plf' => 'application/vnd.pocketlearn', + 'pls' => 'application/pls+xml', + 'pml' => 'application/vnd.ctc-posml', + 'png' => 'image/png', + 'pnm' => 'image/x-portable-anymap', + 'portpkg' => 'application/vnd.macports.portpkg', + 'pot' => 'application/vnd.ms-powerpoint', + 'potm' => 'application/vnd.ms-powerpoint.template.macroenabled.12', + 'potx' => 'application/vnd.openxmlformats-officedocument.presentationml.template', + 'ppam' => 'application/vnd.ms-powerpoint.addin.macroenabled.12', + 'ppd' => 'application/vnd.cups-ppd', + 'ppm' => 'image/x-portable-pixmap', + 'pps' => 'application/vnd.ms-powerpoint', + 'ppsm' => 'application/vnd.ms-powerpoint.slideshow.macroenabled.12', + 'ppsx' => 'application/vnd.openxmlformats-officedocument.presentationml.slideshow', + 'ppt' => 'application/vnd.ms-powerpoint', + 'pptm' => 'application/vnd.ms-powerpoint.presentation.macroenabled.12', + 'pptx' => 'application/vnd.openxmlformats-officedocument.presentationml.presentation', + 'pqa' => 'application/vnd.palm', + 'prc' => 'application/x-mobipocket-ebook', + 'pre' => 'application/vnd.lotus-freelance', + 'prf' => 'application/pics-rules', + 'ps' => 'application/postscript', + 'psb' => 'application/vnd.3gpp.pic-bw-small', + 'psd' => 'image/vnd.adobe.photoshop', + 'psf' => 'application/x-font-linux-psf', + 'pskcxml' => 'application/pskc+xml', + 'ptid' => 'application/vnd.pvi.ptid1', + 'pub' => 'application/x-mspublisher', + 'pvb' => 'application/vnd.3gpp.pic-bw-var', + 'pwn' => 'application/vnd.3m.post-it-notes', + 'pya' => 'audio/vnd.ms-playready.media.pya', + 'pyv' => 'video/vnd.ms-playready.media.pyv', + 'qam' => 'application/vnd.epson.quickanime', + 'qbo' => 'application/vnd.intu.qbo', + 'qfx' => 'application/vnd.intu.qfx', + 'qps' => 'application/vnd.publishare-delta-tree', + 'qt' => 'video/quicktime', + 'qwd' => 'application/vnd.quark.quarkxpress', + 'qwt' => 'application/vnd.quark.quarkxpress', + 'qxb' => 'application/vnd.quark.quarkxpress', + 'qxd' => 'application/vnd.quark.quarkxpress', + 'qxl' => 'application/vnd.quark.quarkxpress', + 'qxt' => 'application/vnd.quark.quarkxpress', + 'ra' => 'audio/x-pn-realaudio', + 'ram' => 'audio/x-pn-realaudio', + 'rar' => 'application/x-rar-compressed', + 'ras' => 'image/x-cmu-raster', + 'rb' => 'text/plain', + 'rcprofile' => 'application/vnd.ipunplugged.rcprofile', + 'rdf' => 'application/rdf+xml', + 'rdz' => 'application/vnd.data-vision.rdz', + 'rep' => 'application/vnd.businessobjects', + 'res' => 'application/x-dtbresource+xml', + 'resx' => 'text/xml', + 'rgb' => 'image/x-rgb', + 'rif' => 'application/reginfo+xml', + 'rip' => 'audio/vnd.rip', + 'rl' => 'application/resource-lists+xml', + 'rlc' => 'image/vnd.fujixerox.edmics-rlc', + 'rld' => 'application/resource-lists-diff+xml', + 'rm' => 'application/vnd.rn-realmedia', + 'rmi' => 'audio/midi', + 'rmp' => 'audio/x-pn-realaudio-plugin', + 'rms' => 'application/vnd.jcp.javame.midlet-rms', + 'rnc' => 'application/relax-ng-compact-syntax', + 'roff' => 'text/troff', + 'rp9' => 'application/vnd.cloanto.rp9', + 'rpss' => 'application/vnd.nokia.radio-presets', + 'rpst' => 'application/vnd.nokia.radio-preset', + 'rq' => 'application/sparql-query', + 'rs' => 'application/rls-services+xml', + 'rsd' => 'application/rsd+xml', + 'rss' => 'application/rss+xml', + 'rtf' => 'application/rtf', + 'rtx' => 'text/richtext', + 's' => 'text/x-asm', + 'saf' => 'application/vnd.yamaha.smaf-audio', + 'sbml' => 'application/sbml+xml', + 'sc' => 'application/vnd.ibm.secure-container', + 'scd' => 'application/x-msschedule', + 'scm' => 'application/vnd.lotus-screencam', + 'scq' => 'application/scvp-cv-request', + 'scs' => 'application/scvp-cv-response', + 'scurl' => 'text/vnd.curl.scurl', + 'sda' => 'application/vnd.stardivision.draw', + 'sdc' => 'application/vnd.stardivision.calc', + 'sdd' => 'application/vnd.stardivision.impress', + 'sdkd' => 'application/vnd.solent.sdkm+xml', + 'sdkm' => 'application/vnd.solent.sdkm+xml', + 'sdp' => 'application/sdp', + 'sdw' => 'application/vnd.stardivision.writer', + 'see' => 'application/vnd.seemail', + 'seed' => 'application/vnd.fdsn.seed', + 'sema' => 'application/vnd.sema', + 'semd' => 'application/vnd.semd', + 'semf' => 'application/vnd.semf', + 'ser' => 'application/java-serialized-object', + 'setpay' => 'application/set-payment-initiation', + 'setreg' => 'application/set-registration-initiation', + 'sfd-hdstx' => 'application/vnd.hydrostatix.sof-data', + 'sfs' => 'application/vnd.spotfire.sfs', + 'sgl' => 'application/vnd.stardivision.writer-global', + 'sgm' => 'text/sgml', + 'sgml' => 'text/sgml', + 'sh' => 'application/x-sh', + 'shar' => 'application/x-shar', + 'shf' => 'application/shf+xml', + 'sig' => 'application/pgp-signature', + 'silo' => 'model/mesh', + 'sis' => 'application/vnd.symbian.install', + 'sisx' => 'application/vnd.symbian.install', + 'sit' => 'application/x-stuffit', + 'sitx' => 'application/x-stuffitx', + 'skd' => 'application/vnd.koan', + 'skm' => 'application/vnd.koan', + 'skp' => 'application/vnd.koan', + 'skt' => 'application/vnd.koan', + 'sldm' => 'application/vnd.ms-powerpoint.slide.macroenabled.12', + 'sldx' => 'application/vnd.openxmlformats-officedocument.presentationml.slide', + 'slt' => 'application/vnd.epson.salt', + 'sm' => 'application/vnd.stepmania.stepchart', + 'smf' => 'application/vnd.stardivision.math', + 'smi' => 'application/smil+xml', + 'smil' => 'application/smil+xml', + 'snd' => 'audio/basic', + 'snf' => 'application/x-font-snf', + 'so' => 'application/octet-stream', + 'spc' => 'application/x-pkcs7-certificates', + 'spf' => 'application/vnd.yamaha.smaf-phrase', + 'spl' => 'application/x-futuresplash', + 'spot' => 'text/vnd.in3d.spot', + 'spp' => 'application/scvp-vp-response', + 'spq' => 'application/scvp-vp-request', + 'spx' => 'audio/ogg', + 'src' => 'application/x-wais-source', + 'sru' => 'application/sru+xml', + 'srx' => 'application/sparql-results+xml', + 'sse' => 'application/vnd.kodak-descriptor', + 'ssf' => 'application/vnd.epson.ssf', + 'ssml' => 'application/ssml+xml', + 'st' => 'application/vnd.sailingtracker.track', + 'stc' => 'application/vnd.sun.xml.calc.template', + 'std' => 'application/vnd.sun.xml.draw.template', + 'stf' => 'application/vnd.wt.stf', + 'sti' => 'application/vnd.sun.xml.impress.template', + 'stk' => 'application/hyperstudio', + 'stl' => 'application/vnd.ms-pki.stl', + 'str' => 'application/vnd.pg.format', + 'stw' => 'application/vnd.sun.xml.writer.template', + 'sub' => 'image/vnd.dvb.subtitle', + 'sus' => 'application/vnd.sus-calendar', + 'susp' => 'application/vnd.sus-calendar', + 'sv4cpio' => 'application/x-sv4cpio', + 'sv4crc' => 'application/x-sv4crc', + 'svc' => 'application/vnd.dvb.service', + 'svd' => 'application/vnd.svd', + 'svg' => 'image/svg+xml', + 'svgz' => 'image/svg+xml', + 'swa' => 'application/x-director', + 'swf' => 'application/x-shockwave-flash', + 'swi' => 'application/vnd.aristanetworks.swi', + 'sxc' => 'application/vnd.sun.xml.calc', + 'sxd' => 'application/vnd.sun.xml.draw', + 'sxg' => 'application/vnd.sun.xml.writer.global', + 'sxi' => 'application/vnd.sun.xml.impress', + 'sxm' => 'application/vnd.sun.xml.math', + 'sxw' => 'application/vnd.sun.xml.writer', + 't' => 'text/troff', + 'tao' => 'application/vnd.tao.intent-module-archive', + 'tar' => 'application/x-tar', + 'tcap' => 'application/vnd.3gpp2.tcap', + 'tcl' => 'application/x-tcl', + 'teacher' => 'application/vnd.smart.teacher', + 'tei' => 'application/tei+xml', + 'teicorpus' => 'application/tei+xml', + 'tex' => 'application/x-tex', + 'texi' => 'application/x-texinfo', + 'texinfo' => 'application/x-texinfo', + 'text' => 'text/plain', + 'tfi' => 'application/thraud+xml', + 'tfm' => 'application/x-tex-tfm', + 'thmx' => 'application/vnd.ms-officetheme', + 'tif' => 'image/tiff', + 'tiff' => 'image/tiff', + 'tmo' => 'application/vnd.tmobile-livetv', + 'torrent' => 'application/x-bittorrent', + 'tpl' => 'application/vnd.groove-tool-template', + 'tpt' => 'application/vnd.trid.tpt', + 'tr' => 'text/troff', + 'tra' => 'application/vnd.trueapp', + 'trm' => 'application/x-msterminal', + 'tsd' => 'application/timestamped-data', + 'tsv' => 'text/tab-separated-values', + 'ttc' => 'application/x-font-ttf', + 'ttf' => 'application/x-font-ttf', + 'ttl' => 'text/turtle', + 'twd' => 'application/vnd.simtech-mindmapper', + 'twds' => 'application/vnd.simtech-mindmapper', + 'txd' => 'application/vnd.genomatix.tuxedo', + 'txf' => 'application/vnd.mobius.txf', + 'txt' => 'text/plain', + 'u32' => 'application/x-authorware-bin', + 'udeb' => 'application/x-debian-package', + 'ufd' => 'application/vnd.ufdl', + 'ufdl' => 'application/vnd.ufdl', + 'umj' => 'application/vnd.umajin', + 'unityweb' => 'application/vnd.unity', + 'uoml' => 'application/vnd.uoml+xml', + 'uri' => 'text/uri-list', + 'uris' => 'text/uri-list', + 'urls' => 'text/uri-list', + 'ustar' => 'application/x-ustar', + 'utz' => 'application/vnd.uiq.theme', + 'uu' => 'text/x-uuencode', + 'uva' => 'audio/vnd.dece.audio', + 'uvd' => 'application/vnd.dece.data', + 'uvf' => 'application/vnd.dece.data', + 'uvg' => 'image/vnd.dece.graphic', + 'uvh' => 'video/vnd.dece.hd', + 'uvi' => 'image/vnd.dece.graphic', + 'uvm' => 'video/vnd.dece.mobile', + 'uvp' => 'video/vnd.dece.pd', + 'uvs' => 'video/vnd.dece.sd', + 'uvt' => 'application/vnd.dece.ttml+xml', + 'uvu' => 'video/vnd.uvvu.mp4', + 'uvv' => 'video/vnd.dece.video', + 'uvva' => 'audio/vnd.dece.audio', + 'uvvd' => 'application/vnd.dece.data', + 'uvvf' => 'application/vnd.dece.data', + 'uvvg' => 'image/vnd.dece.graphic', + 'uvvh' => 'video/vnd.dece.hd', + 'uvvi' => 'image/vnd.dece.graphic', + 'uvvm' => 'video/vnd.dece.mobile', + 'uvvp' => 'video/vnd.dece.pd', + 'uvvs' => 'video/vnd.dece.sd', + 'uvvt' => 'application/vnd.dece.ttml+xml', + 'uvvu' => 'video/vnd.uvvu.mp4', + 'uvvv' => 'video/vnd.dece.video', + 'uvvx' => 'application/vnd.dece.unspecified', + 'uvx' => 'application/vnd.dece.unspecified', + 'vcd' => 'application/x-cdlink', + 'vcf' => 'text/x-vcard', + 'vcg' => 'application/vnd.groove-vcard', + 'vcs' => 'text/x-vcalendar', + 'vcx' => 'application/vnd.vcx', + 'vis' => 'application/vnd.visionary', + 'viv' => 'video/vnd.vivo', + 'vor' => 'application/vnd.stardivision.writer', + 'vox' => 'application/x-authorware-bin', + 'vrml' => 'model/vrml', + 'vsd' => 'application/vnd.visio', + 'vsf' => 'application/vnd.vsf', + 'vss' => 'application/vnd.visio', + 'vst' => 'application/vnd.visio', + 'vsw' => 'application/vnd.visio', + 'vtu' => 'model/vnd.vtu', + 'vxml' => 'application/voicexml+xml', + 'w3d' => 'application/x-director', + 'wad' => 'application/x-doom', + 'wav' => 'audio/x-wav', + 'wax' => 'audio/x-ms-wax', + 'wbmp' => 'image/vnd.wap.wbmp', + 'wbs' => 'application/vnd.criticaltools.wbs+xml', + 'wbxml' => 'application/vnd.wap.wbxml', + 'wcm' => 'application/vnd.ms-works', + 'wdb' => 'application/vnd.ms-works', + 'weba' => 'audio/webm', + 'webm' => 'video/webm', + 'webp' => 'image/webp', + 'wg' => 'application/vnd.pmi.widget', + 'wgt' => 'application/widget', + 'wks' => 'application/vnd.ms-works', + 'wm' => 'video/x-ms-wm', + 'wma' => 'audio/x-ms-wma', + 'wmd' => 'application/x-ms-wmd', + 'wmf' => 'application/x-msmetafile', + 'wml' => 'text/vnd.wap.wml', + 'wmlc' => 'application/vnd.wap.wmlc', + 'wmls' => 'text/vnd.wap.wmlscript', + 'wmlsc' => 'application/vnd.wap.wmlscriptc', + 'wmv' => 'video/x-ms-wmv', + 'wmx' => 'video/x-ms-wmx', + 'wmz' => 'application/x-ms-wmz', + 'woff' => 'application/x-font-woff', + 'wpd' => 'application/vnd.wordperfect', + 'wpl' => 'application/vnd.ms-wpl', + 'wps' => 'application/vnd.ms-works', + 'wqd' => 'application/vnd.wqd', + 'wri' => 'application/x-mswrite', + 'wrl' => 'model/vrml', + 'wsdl' => 'application/wsdl+xml', + 'wspolicy' => 'application/wspolicy+xml', + 'wtb' => 'application/vnd.webturbo', + 'wvx' => 'video/x-ms-wvx', + 'x32' => 'application/x-authorware-bin', + 'x3d' => 'application/vnd.hzn-3d-crossword', + 'xap' => 'application/x-silverlight-app', + 'xar' => 'application/vnd.xara', + 'xbap' => 'application/x-ms-xbap', + 'xbd' => 'application/vnd.fujixerox.docuworks.binder', + 'xbm' => 'image/x-xbitmap', + 'xdf' => 'application/xcap-diff+xml', + 'xdm' => 'application/vnd.syncml.dm+xml', + 'xdp' => 'application/vnd.adobe.xdp+xml', + 'xdssc' => 'application/dssc+xml', + 'xdw' => 'application/vnd.fujixerox.docuworks', + 'xenc' => 'application/xenc+xml', + 'xer' => 'application/patch-ops-error+xml', + 'xfdf' => 'application/vnd.adobe.xfdf', + 'xfdl' => 'application/vnd.xfdl', + 'xht' => 'application/xhtml+xml', + 'xhtml' => 'application/xhtml+xml', + 'xhvml' => 'application/xv+xml', + 'xif' => 'image/vnd.xiff', + 'xla' => 'application/vnd.ms-excel', + 'xlam' => 'application/vnd.ms-excel.addin.macroenabled.12', + 'xlc' => 'application/vnd.ms-excel', + 'xlm' => 'application/vnd.ms-excel', + 'xls' => 'application/vnd.ms-excel', + 'xlsb' => 'application/vnd.ms-excel.sheet.binary.macroenabled.12', + 'xlsm' => 'application/vnd.ms-excel.sheet.macroenabled.12', + 'xlsx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', + 'xlt' => 'application/vnd.ms-excel', + 'xltm' => 'application/vnd.ms-excel.template.macroenabled.12', + 'xltx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.template', + 'xlw' => 'application/vnd.ms-excel', + 'xml' => 'application/xml', + 'xo' => 'application/vnd.olpc-sugar', + 'xop' => 'application/xop+xml', + 'xpi' => 'application/x-xpinstall', + 'xpm' => 'image/x-xpixmap', + 'xpr' => 'application/vnd.is-xpr', + 'xps' => 'application/vnd.ms-xpsdocument', + 'xpw' => 'application/vnd.intercon.formnet', + 'xpx' => 'application/vnd.intercon.formnet', + 'xsl' => 'application/xml', + 'xslt' => 'application/xslt+xml', + 'xsm' => 'application/vnd.syncml+xml', + 'xspf' => 'application/xspf+xml', + 'xul' => 'application/vnd.mozilla.xul+xml', + 'xvm' => 'application/xv+xml', + 'xvml' => 'application/xv+xml', + 'xwd' => 'image/x-xwindowdump', + 'xyz' => 'chemical/x-xyz', + 'yaml' => 'text/yaml', + 'yang' => 'application/yang', + 'yin' => 'application/yin+xml', + 'yml' => 'text/yaml', + 'zaz' => 'application/vnd.zzazz.deck+xml', + 'zip' => 'application/zip', + 'zir' => 'application/vnd.zul', + 'zirz' => 'application/vnd.zul', + 'zmm' => 'application/vnd.handheld-entertainment+xml' + ); + + /** + * Get a singleton instance of the class + * + * @return self + * @codeCoverageIgnore + */ + public static function getInstance() + { + if (!self::$instance) { + self::$instance = new self(); + } + + return self::$instance; + } + + /** + * Get a mimetype value from a file extension + * + * @param string $extension File extension + * + * @return string|null + * + */ + public function fromExtension($extension) + { + $extension = strtolower($extension); + + return isset($this->mimetypes[$extension]) ? $this->mimetypes[$extension] : null; + } + + /** + * Get a mimetype from a filename + * + * @param string $filename Filename to generate a mimetype from + * + * @return string|null + */ + public function fromFilename($filename) + { + return $this->fromExtension(pathinfo($filename, PATHINFO_EXTENSION)); + } +} diff --git a/vendor/guzzle/guzzle/src/Guzzle/Http/QueryAggregator/CommaAggregator.php b/vendor/guzzle/guzzle/src/Guzzle/Http/QueryAggregator/CommaAggregator.php new file mode 100644 index 0000000..4b4e49d --- /dev/null +++ b/vendor/guzzle/guzzle/src/Guzzle/Http/QueryAggregator/CommaAggregator.php @@ -0,0 +1,20 @@ +isUrlEncoding()) { + return array($query->encodeValue($key) => implode(',', array_map(array($query, 'encodeValue'), $value))); + } else { + return array($key => implode(',', $value)); + } + } +} diff --git a/vendor/guzzle/guzzle/src/Guzzle/Http/QueryAggregator/DuplicateAggregator.php b/vendor/guzzle/guzzle/src/Guzzle/Http/QueryAggregator/DuplicateAggregator.php new file mode 100644 index 0000000..1bf1730 --- /dev/null +++ b/vendor/guzzle/guzzle/src/Guzzle/Http/QueryAggregator/DuplicateAggregator.php @@ -0,0 +1,22 @@ +isUrlEncoding()) { + return array($query->encodeValue($key) => array_map(array($query, 'encodeValue'), $value)); + } else { + return array($key => $value); + } + } +} diff --git a/vendor/guzzle/guzzle/src/Guzzle/Http/QueryAggregator/PhpAggregator.php b/vendor/guzzle/guzzle/src/Guzzle/Http/QueryAggregator/PhpAggregator.php new file mode 100644 index 0000000..133ea2b --- /dev/null +++ b/vendor/guzzle/guzzle/src/Guzzle/Http/QueryAggregator/PhpAggregator.php @@ -0,0 +1,27 @@ + $v) { + $k = "{$key}[{$k}]"; + if (is_array($v)) { + $ret = array_merge($ret, self::aggregate($k, $v, $query)); + } else { + $ret[$query->encodeValue($k)] = $query->encodeValue($v); + } + } + + return $ret; + } +} diff --git a/vendor/guzzle/guzzle/src/Guzzle/Http/QueryAggregator/QueryAggregatorInterface.php b/vendor/guzzle/guzzle/src/Guzzle/Http/QueryAggregator/QueryAggregatorInterface.php new file mode 100644 index 0000000..72bee62 --- /dev/null +++ b/vendor/guzzle/guzzle/src/Guzzle/Http/QueryAggregator/QueryAggregatorInterface.php @@ -0,0 +1,22 @@ +add($key, $value); + $foundDuplicates = true; + } elseif ($paramIsPhpStyleArray) { + $q[$key] = array($value); + } else { + $q[$key] = $value; + } + } else { + // Uses false by default to represent keys with no trailing "=" sign. + $q->add($key, false); + } + } + + // Use the duplicate aggregator if duplicates were found and not using PHP style arrays + if ($foundDuplicates && !$foundPhpStyle) { + $q->setAggregator(new DuplicateAggregator()); + } + + return $q; + } + + /** + * Convert the query string parameters to a query string string + * + * @return string + * @throws RuntimeException + */ + public function __toString() + { + if (!$this->data) { + return ''; + } + + $queryList = array(); + foreach ($this->prepareData($this->data) as $name => $value) { + $queryList[] = $this->convertKvp($name, $value); + } + + return implode($this->fieldSeparator, $queryList); + } + + /** + * Get the query string field separator + * + * @return string + */ + public function getFieldSeparator() + { + return $this->fieldSeparator; + } + + /** + * Get the query string value separator + * + * @return string + */ + public function getValueSeparator() + { + return $this->valueSeparator; + } + + /** + * Returns the type of URL encoding used by the query string + * + * One of: false, "RFC 3986", or "application/x-www-form-urlencoded" + * + * @return bool|string + */ + public function getUrlEncoding() + { + return $this->urlEncode; + } + + /** + * Returns true or false if using URL encoding + * + * @return bool + */ + public function isUrlEncoding() + { + return $this->urlEncode !== false; + } + + /** + * Provide a function for combining multi-valued query string parameters into a single or multiple fields + * + * @param null|QueryAggregatorInterface $aggregator Pass in a QueryAggregatorInterface object to handle converting + * deeply nested query string variables into a flattened array. + * Pass null to use the default PHP style aggregator. For legacy + * reasons, this function accepts a callable that must accepts a + * $key, $value, and query object. + * @return self + * @see \Guzzle\Http\QueryString::aggregateUsingComma() + */ + public function setAggregator(QueryAggregatorInterface $aggregator = null) + { + // Use the default aggregator if none was set + if (!$aggregator) { + if (!self::$defaultAggregator) { + self::$defaultAggregator = new PhpAggregator(); + } + $aggregator = self::$defaultAggregator; + } + + $this->aggregator = $aggregator; + + return $this; + } + + /** + * Set whether or not field names and values should be rawurlencoded + * + * @param bool|string $encode Set to TRUE to use RFC 3986 encoding (rawurlencode), false to disable encoding, or + * form_urlencoding to use application/x-www-form-urlencoded encoding (urlencode) + * @return self + */ + public function useUrlEncoding($encode) + { + $this->urlEncode = ($encode === true) ? self::RFC_3986 : $encode; + + return $this; + } + + /** + * Set the query string separator + * + * @param string $separator The query string separator that will separate fields + * + * @return self + */ + public function setFieldSeparator($separator) + { + $this->fieldSeparator = $separator; + + return $this; + } + + /** + * Set the query string value separator + * + * @param string $separator The query string separator that will separate values from fields + * + * @return self + */ + public function setValueSeparator($separator) + { + $this->valueSeparator = $separator; + + return $this; + } + + /** + * Returns an array of url encoded field names and values + * + * @return array + */ + public function urlEncode() + { + return $this->prepareData($this->data); + } + + /** + * URL encodes a value based on the url encoding type of the query string object + * + * @param string $value Value to encode + * + * @return string + */ + public function encodeValue($value) + { + if ($this->urlEncode == self::RFC_3986) { + return rawurlencode($value); + } elseif ($this->urlEncode == self::FORM_URLENCODED) { + return urlencode($value); + } else { + return (string) $value; + } + } + + /** + * Url encode parameter data and convert nested query strings into a flattened hash. + * + * @param array $data The data to encode + * + * @return array Returns an array of encoded values and keys + */ + protected function prepareData(array $data) + { + // If no aggregator is present then set the default + if (!$this->aggregator) { + $this->setAggregator(null); + } + + $temp = array(); + foreach ($data as $key => $value) { + if ($value === false || $value === null) { + // False and null will not include the "=". Use an empty string to include the "=". + $temp[$this->encodeValue($key)] = $value; + } elseif (is_array($value)) { + $temp = array_merge($temp, $this->aggregator->aggregate($key, $value, $this)); + } else { + $temp[$this->encodeValue($key)] = $this->encodeValue($value); + } + } + + return $temp; + } + + /** + * Converts a key value pair that can contain strings, nulls, false, or arrays + * into a single string. + * + * @param string $name Name of the field + * @param mixed $value Value of the field + * @return string + */ + private function convertKvp($name, $value) + { + if ($value === self::BLANK || $value === null || $value === false) { + return $name; + } elseif (!is_array($value)) { + return $name . $this->valueSeparator . $value; + } + + $result = ''; + foreach ($value as $v) { + $result .= $this->convertKvp($name, $v) . $this->fieldSeparator; + } + + return rtrim($result, $this->fieldSeparator); + } +} diff --git a/vendor/guzzle/guzzle/src/Guzzle/Http/ReadLimitEntityBody.php b/vendor/guzzle/guzzle/src/Guzzle/Http/ReadLimitEntityBody.php new file mode 100644 index 0000000..ef28273 --- /dev/null +++ b/vendor/guzzle/guzzle/src/Guzzle/Http/ReadLimitEntityBody.php @@ -0,0 +1,122 @@ +setLimit($limit)->setOffset($offset); + } + + /** + * Returns only a subset of the decorated entity body when cast as a string + * {@inheritdoc} + */ + public function __toString() + { + if (!$this->body->isReadable() || + (!$this->body->isSeekable() && $this->body->isConsumed()) + ) { + return ''; + } + + $originalPos = $this->body->ftell(); + $this->body->seek($this->offset); + $data = ''; + while (!$this->feof()) { + $data .= $this->read(1048576); + } + $this->body->seek($originalPos); + + return (string) $data ?: ''; + } + + public function isConsumed() + { + return $this->body->isConsumed() || + ($this->body->ftell() >= $this->offset + $this->limit); + } + + /** + * Returns the Content-Length of the limited subset of data + * {@inheritdoc} + */ + public function getContentLength() + { + $length = $this->body->getContentLength(); + + return $length === false + ? $this->limit + : min($this->limit, min($length, $this->offset + $this->limit) - $this->offset); + } + + /** + * Allow for a bounded seek on the read limited entity body + * {@inheritdoc} + */ + public function seek($offset, $whence = SEEK_SET) + { + return $whence === SEEK_SET + ? $this->body->seek(max($this->offset, min($this->offset + $this->limit, $offset))) + : false; + } + + /** + * Set the offset to start limiting from + * + * @param int $offset Offset to seek to and begin byte limiting from + * + * @return self + */ + public function setOffset($offset) + { + $this->body->seek($offset); + $this->offset = $offset; + + return $this; + } + + /** + * Set the limit of bytes that the decorator allows to be read from the stream + * + * @param int $limit Total number of bytes to allow to be read from the stream + * + * @return self + */ + public function setLimit($limit) + { + $this->limit = $limit; + + return $this; + } + + public function read($length) + { + // Check if the current position is less than the total allowed bytes + original offset + $remaining = ($this->offset + $this->limit) - $this->body->ftell(); + if ($remaining > 0) { + // Only return the amount of requested data, ensuring that the byte limit is not exceeded + return $this->body->read(min($remaining, $length)); + } else { + return false; + } + } +} diff --git a/vendor/guzzle/guzzle/src/Guzzle/Http/RedirectPlugin.php b/vendor/guzzle/guzzle/src/Guzzle/Http/RedirectPlugin.php new file mode 100644 index 0000000..1a824b8 --- /dev/null +++ b/vendor/guzzle/guzzle/src/Guzzle/Http/RedirectPlugin.php @@ -0,0 +1,250 @@ + array('onRequestSent', 100), + 'request.clone' => 'cleanupRequest', + 'request.before_send' => 'cleanupRequest' + ); + } + + /** + * Clean up the parameters of a request when it is cloned + * + * @param Event $event Event emitted + */ + public function cleanupRequest(Event $event) + { + $params = $event['request']->getParams(); + unset($params[self::REDIRECT_COUNT]); + unset($params[self::PARENT_REQUEST]); + } + + /** + * Called when a request receives a redirect response + * + * @param Event $event Event emitted + */ + public function onRequestSent(Event $event) + { + $response = $event['response']; + $request = $event['request']; + + // Only act on redirect requests with Location headers + if (!$response || $request->getParams()->get(self::DISABLE)) { + return; + } + + // Trace the original request based on parameter history + $original = $this->getOriginalRequest($request); + + // Terminating condition to set the effective response on the original request + if (!$response->isRedirect() || !$response->hasHeader('Location')) { + if ($request !== $original) { + // This is a terminating redirect response, so set it on the original request + $response->getParams()->set(self::REDIRECT_COUNT, $original->getParams()->get(self::REDIRECT_COUNT)); + $original->setResponse($response); + $response->setEffectiveUrl($request->getUrl()); + } + return; + } + + $this->sendRedirectRequest($original, $request, $response); + } + + /** + * Get the original request that initiated a series of redirects + * + * @param RequestInterface $request Request to get the original request from + * + * @return RequestInterface + */ + protected function getOriginalRequest(RequestInterface $request) + { + $original = $request; + // The number of redirects is held on the original request, so determine which request that is + while ($parent = $original->getParams()->get(self::PARENT_REQUEST)) { + $original = $parent; + } + + return $original; + } + + /** + * Create a redirect request for a specific request object + * + * Takes into account strict RFC compliant redirection (e.g. redirect POST with POST) vs doing what most clients do + * (e.g. redirect POST with GET). + * + * @param RequestInterface $request Request being redirected + * @param RequestInterface $original Original request + * @param int $statusCode Status code of the redirect + * @param string $location Location header of the redirect + * + * @return RequestInterface Returns a new redirect request + * @throws CouldNotRewindStreamException If the body needs to be rewound but cannot + */ + protected function createRedirectRequest( + RequestInterface $request, + $statusCode, + $location, + RequestInterface $original + ) { + $redirectRequest = null; + $strict = $original->getParams()->get(self::STRICT_REDIRECTS); + + // Switch method to GET for 303 redirects. 301 and 302 redirects also switch to GET unless we are forcing RFC + // compliance to emulate what most browsers do. NOTE: IE only switches methods on 301/302 when coming from a POST. + if ($request instanceof EntityEnclosingRequestInterface && ($statusCode == 303 || (!$strict && $statusCode <= 302))) { + $redirectRequest = RequestFactory::getInstance()->cloneRequestWithMethod($request, 'GET'); + } else { + $redirectRequest = clone $request; + } + + $redirectRequest->setIsRedirect(true); + // Always use the same response body when redirecting + $redirectRequest->setResponseBody($request->getResponseBody()); + + $location = Url::factory($location); + // If the location is not absolute, then combine it with the original URL + if (!$location->isAbsolute()) { + $originalUrl = $redirectRequest->getUrl(true); + // Remove query string parameters and just take what is present on the redirect Location header + $originalUrl->getQuery()->clear(); + $location = $originalUrl->combine((string) $location, true); + } + + $redirectRequest->setUrl($location); + + // Add the parent request to the request before it sends (make sure it's before the onRequestClone event too) + $redirectRequest->getEventDispatcher()->addListener( + 'request.before_send', + $func = function ($e) use (&$func, $request, $redirectRequest) { + $redirectRequest->getEventDispatcher()->removeListener('request.before_send', $func); + $e['request']->getParams()->set(RedirectPlugin::PARENT_REQUEST, $request); + } + ); + + // Rewind the entity body of the request if needed + if ($redirectRequest instanceof EntityEnclosingRequestInterface && $redirectRequest->getBody()) { + $body = $redirectRequest->getBody(); + // Only rewind the body if some of it has been read already, and throw an exception if the rewind fails + if ($body->ftell() && !$body->rewind()) { + throw new CouldNotRewindStreamException( + 'Unable to rewind the non-seekable entity body of the request after redirecting. cURL probably ' + . 'sent part of body before the redirect occurred. Try adding acustom rewind function using on the ' + . 'entity body of the request using setRewindFunction().' + ); + } + } + + return $redirectRequest; + } + + /** + * Prepare the request for redirection and enforce the maximum number of allowed redirects per client + * + * @param RequestInterface $original Original request + * @param RequestInterface $request Request to prepare and validate + * @param Response $response The current response + * + * @return RequestInterface + */ + protected function prepareRedirection(RequestInterface $original, RequestInterface $request, Response $response) + { + $params = $original->getParams(); + // This is a new redirect, so increment the redirect counter + $current = $params[self::REDIRECT_COUNT] + 1; + $params[self::REDIRECT_COUNT] = $current; + // Use a provided maximum value or default to a max redirect count of 5 + $max = isset($params[self::MAX_REDIRECTS]) ? $params[self::MAX_REDIRECTS] : $this->defaultMaxRedirects; + + // Throw an exception if the redirect count is exceeded + if ($current > $max) { + $this->throwTooManyRedirectsException($original, $max); + return false; + } else { + // Create a redirect request based on the redirect rules set on the request + return $this->createRedirectRequest( + $request, + $response->getStatusCode(), + trim($response->getLocation()), + $original + ); + } + } + + /** + * Send a redirect request and handle any errors + * + * @param RequestInterface $original The originating request + * @param RequestInterface $request The current request being redirected + * @param Response $response The response of the current request + * + * @throws BadResponseException|\Exception + */ + protected function sendRedirectRequest(RequestInterface $original, RequestInterface $request, Response $response) + { + // Validate and create a redirect request based on the original request and current response + if ($redirectRequest = $this->prepareRedirection($original, $request, $response)) { + try { + $redirectRequest->send(); + } catch (BadResponseException $e) { + $e->getResponse(); + if (!$e->getResponse()) { + throw $e; + } + } + } + } + + /** + * Throw a too many redirects exception for a request + * + * @param RequestInterface $original Request + * @param int $max Max allowed redirects + * + * @throws TooManyRedirectsException when too many redirects have been issued + */ + protected function throwTooManyRedirectsException(RequestInterface $original, $max) + { + $original->getEventDispatcher()->addListener( + 'request.complete', + $func = function ($e) use (&$func, $original, $max) { + $original->getEventDispatcher()->removeListener('request.complete', $func); + $str = "{$max} redirects were issued for this request:\n" . $e['request']->getRawHeaders(); + throw new TooManyRedirectsException($str); + } + ); + } +} diff --git a/vendor/guzzle/guzzle/src/Guzzle/Http/Resources/cacert.pem b/vendor/guzzle/guzzle/src/Guzzle/Http/Resources/cacert.pem new file mode 100644 index 0000000..18ce703 --- /dev/null +++ b/vendor/guzzle/guzzle/src/Guzzle/Http/Resources/cacert.pem @@ -0,0 +1,3870 @@ +## +## Bundle of CA Root Certificates +## +## Certificate data from Mozilla downloaded on: Wed Aug 13 21:49:32 2014 +## +## This is a bundle of X.509 certificates of public Certificate Authorities +## (CA). These were automatically extracted from Mozilla's root certificates +## file (certdata.txt). This file can be found in the mozilla source tree: +## http://hg.mozilla.org/releases/mozilla-release/raw-file/default/security/nss/lib/ckfw/builtins/certdata.txt +## +## It contains the certificates in PEM format and therefore +## can be directly used with curl / libcurl / php_curl, or with +## an Apache+mod_ssl webserver for SSL client authentication. +## Just configure this file as the SSLCACertificateFile. +## +## Conversion done with mk-ca-bundle.pl verison 1.22. +## SHA1: bf2c15b3019e696660321d2227d942936dc50aa7 +## + + +GTE CyberTrust Global Root +========================== +-----BEGIN CERTIFICATE----- +MIICWjCCAcMCAgGlMA0GCSqGSIb3DQEBBAUAMHUxCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9HVEUg +Q29ycG9yYXRpb24xJzAlBgNVBAsTHkdURSBDeWJlclRydXN0IFNvbHV0aW9ucywgSW5jLjEjMCEG +A1UEAxMaR1RFIEN5YmVyVHJ1c3QgR2xvYmFsIFJvb3QwHhcNOTgwODEzMDAyOTAwWhcNMTgwODEz +MjM1OTAwWjB1MQswCQYDVQQGEwJVUzEYMBYGA1UEChMPR1RFIENvcnBvcmF0aW9uMScwJQYDVQQL +Ex5HVEUgQ3liZXJUcnVzdCBTb2x1dGlvbnMsIEluYy4xIzAhBgNVBAMTGkdURSBDeWJlclRydXN0 +IEdsb2JhbCBSb290MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCVD6C28FCc6HrHiM3dFw4u +sJTQGz0O9pTAipTHBsiQl8i4ZBp6fmw8U+E3KHNgf7KXUwefU/ltWJTSr41tiGeA5u2ylc9yMcql +HHK6XALnZELn+aks1joNrI1CqiQBOeacPwGFVw1Yh0X404Wqk2kmhXBIgD8SFcd5tB8FLztimQID +AQABMA0GCSqGSIb3DQEBBAUAA4GBAG3rGwnpXtlR22ciYaQqPEh346B8pt5zohQDhT37qw4wxYMW +M4ETCJ57NE7fQMh017l93PR2VX2bY1QY6fDq81yx2YtCHrnAlU66+tXifPVoYb+O7AWXX1uw16OF +NMQkpw0PlZPvy5TYnh+dXIVtx6quTx8itc2VrbqnzPmrC3p/ +-----END CERTIFICATE----- + +Thawte Server CA +================ +-----BEGIN CERTIFICATE----- +MIIDEzCCAnygAwIBAgIBATANBgkqhkiG9w0BAQQFADCBxDELMAkGA1UEBhMCWkExFTATBgNVBAgT +DFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3duMR0wGwYDVQQKExRUaGF3dGUgQ29uc3Vs +dGluZyBjYzEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjEZMBcGA1UE +AxMQVGhhd3RlIFNlcnZlciBDQTEmMCQGCSqGSIb3DQEJARYXc2VydmVyLWNlcnRzQHRoYXd0ZS5j +b20wHhcNOTYwODAxMDAwMDAwWhcNMjAxMjMxMjM1OTU5WjCBxDELMAkGA1UEBhMCWkExFTATBgNV +BAgTDFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3duMR0wGwYDVQQKExRUaGF3dGUgQ29u +c3VsdGluZyBjYzEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjEZMBcG +A1UEAxMQVGhhd3RlIFNlcnZlciBDQTEmMCQGCSqGSIb3DQEJARYXc2VydmVyLWNlcnRzQHRoYXd0 +ZS5jb20wgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBANOkUG7I/1Zr5s9dtuoMaHVHoqrC2oQl +/Kj0R1HahbUgdJSGHg91yekIYfUGbTBuFRkC6VLAYttNmZ7iagxEOM3+vuNkCXDF/rFrKbYvScg7 +1CcEJRCXL+eQbcAoQpnXTEPew/UhbVSfXcNY4cDk2VuwuNy0e982OsK1ZiIS1ocNAgMBAAGjEzAR +MA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEEBQADgYEAB/pMaVz7lcxG7oWDTSEwjsrZqG9J +GubaUeNgcGyEYRGhGshIPllDfU+VPaGLtwtimHp1it2ITk6eQNuozDJ0uW8NxuOzRAvZim+aKZuZ +GCg70eNAKJpaPNW15yAbi8qkq43pUdniTCxZqdq5snUb9kLy78fyGPmJvKP/iiMucEc= +-----END CERTIFICATE----- + +Thawte Premium Server CA +======================== +-----BEGIN CERTIFICATE----- +MIIDJzCCApCgAwIBAgIBATANBgkqhkiG9w0BAQQFADCBzjELMAkGA1UEBhMCWkExFTATBgNVBAgT +DFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3duMR0wGwYDVQQKExRUaGF3dGUgQ29uc3Vs +dGluZyBjYzEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjEhMB8GA1UE +AxMYVGhhd3RlIFByZW1pdW0gU2VydmVyIENBMSgwJgYJKoZIhvcNAQkBFhlwcmVtaXVtLXNlcnZl +ckB0aGF3dGUuY29tMB4XDTk2MDgwMTAwMDAwMFoXDTIwMTIzMTIzNTk1OVowgc4xCzAJBgNVBAYT +AlpBMRUwEwYDVQQIEwxXZXN0ZXJuIENhcGUxEjAQBgNVBAcTCUNhcGUgVG93bjEdMBsGA1UEChMU +VGhhd3RlIENvbnN1bHRpbmcgY2MxKDAmBgNVBAsTH0NlcnRpZmljYXRpb24gU2VydmljZXMgRGl2 +aXNpb24xITAfBgNVBAMTGFRoYXd0ZSBQcmVtaXVtIFNlcnZlciBDQTEoMCYGCSqGSIb3DQEJARYZ +cHJlbWl1bS1zZXJ2ZXJAdGhhd3RlLmNvbTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA0jY2 +aovXwlue2oFBYo847kkEVdbQ7xwblRZH7xhINTpS9CtqBo87L+pW46+GjZ4X9560ZXUCTe/LCaIh +Udib0GfQug2SBhRz1JPLlyoAnFxODLz6FVL88kRu2hFKbgifLy3j+ao6hnO2RlNYyIkFvYMRuHM/ +qgeN9EJN50CdHDcCAwEAAaMTMBEwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQQFAAOBgQAm +SCwWwlj66BZ0DKqqX1Q/8tfJeGBeXm43YyJ3Nn6yF8Q0ufUIhfzJATj/Tb7yFkJD57taRvvBxhEf +8UqwKEbJw8RCfbz6q1lu1bdRiBHjpIUZa4JMpAwSremkrj/xw0llmozFyD4lt5SZu5IycQfwhl7t +UCemDaYj+bvLpgcUQg== +-----END CERTIFICATE----- + +Equifax Secure CA +================= +-----BEGIN CERTIFICATE----- +MIIDIDCCAomgAwIBAgIENd70zzANBgkqhkiG9w0BAQUFADBOMQswCQYDVQQGEwJVUzEQMA4GA1UE +ChMHRXF1aWZheDEtMCsGA1UECxMkRXF1aWZheCBTZWN1cmUgQ2VydGlmaWNhdGUgQXV0aG9yaXR5 +MB4XDTk4MDgyMjE2NDE1MVoXDTE4MDgyMjE2NDE1MVowTjELMAkGA1UEBhMCVVMxEDAOBgNVBAoT +B0VxdWlmYXgxLTArBgNVBAsTJEVxdWlmYXggU2VjdXJlIENlcnRpZmljYXRlIEF1dGhvcml0eTCB +nzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAwV2xWGcIYu6gmi0fCG2RFGiYCh7+2gRvE4RiIcPR +fM6fBeC4AfBONOziipUEZKzxa1NfBbPLZ4C/QgKO/t0BCezhABRP/PvwDN1Dulsr4R+AcJkVV5MW +8Q+XarfCaCMczE1ZMKxRHjuvK9buY0V7xdlfUNLjUA86iOe/FP3gx7kCAwEAAaOCAQkwggEFMHAG +A1UdHwRpMGcwZaBjoGGkXzBdMQswCQYDVQQGEwJVUzEQMA4GA1UEChMHRXF1aWZheDEtMCsGA1UE +CxMkRXF1aWZheCBTZWN1cmUgQ2VydGlmaWNhdGUgQXV0aG9yaXR5MQ0wCwYDVQQDEwRDUkwxMBoG +A1UdEAQTMBGBDzIwMTgwODIyMTY0MTUxWjALBgNVHQ8EBAMCAQYwHwYDVR0jBBgwFoAUSOZo+SvS +spXXR9gjIBBPM5iQn9QwHQYDVR0OBBYEFEjmaPkr0rKV10fYIyAQTzOYkJ/UMAwGA1UdEwQFMAMB +Af8wGgYJKoZIhvZ9B0EABA0wCxsFVjMuMGMDAgbAMA0GCSqGSIb3DQEBBQUAA4GBAFjOKer89961 +zgK5F7WF0bnj4JXMJTENAKaSbn+2kmOeUJXRmm/kEd5jhW6Y7qj/WsjTVbJmcVfewCHrPSqnI0kB +BIZCe/zuf6IWUrVnZ9NA2zsmWLIodz2uFHdh1voqZiegDfqnc1zqcPGUIWVEX/r87yloqaKHee95 +70+sB3c4 +-----END CERTIFICATE----- + +Verisign Class 3 Public Primary Certification Authority +======================================================= +-----BEGIN CERTIFICATE----- +MIICPDCCAaUCEHC65B0Q2Sk0tjjKewPMur8wDQYJKoZIhvcNAQECBQAwXzELMAkGA1UEBhMCVVMx +FzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFzcyAzIFB1YmxpYyBQcmltYXJ5 +IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTk2MDEyOTAwMDAwMFoXDTI4MDgwMTIzNTk1OVow +XzELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFzcyAz +IFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGfMA0GCSqGSIb3DQEBAQUA +A4GNADCBiQKBgQDJXFme8huKARS0EN8EQNvjV69qRUCPhAwL0TPZ2RHP7gJYHyX3KqhEBarsAx94 +f56TuZoAqiN91qyFomNFx3InzPRMxnVx0jnvT0Lwdd8KkMaOIG+YD/isI19wKTakyYbnsZogy1Ol +hec9vn2a/iRFM9x2Fe0PonFkTGUugWhFpwIDAQABMA0GCSqGSIb3DQEBAgUAA4GBALtMEivPLCYA +TxQT3ab7/AoRhIzzKBxnki98tsX63/Dolbwdj2wsqFHMc9ikwFPwTtYmwHYBV4GSXiHx0bH/59Ah +WM1pF+NEHJwZRDmJXNycAA9WjQKZ7aKQRUzkuxCkPfAyAw7xzvjoyVGM5mKf5p/AfbdynMk2Omuf +Tqj/ZA1k +-----END CERTIFICATE----- + +Verisign Class 3 Public Primary Certification Authority - G2 +============================================================ +-----BEGIN CERTIFICATE----- +MIIDAjCCAmsCEH3Z/gfPqB63EHln+6eJNMYwDQYJKoZIhvcNAQEFBQAwgcExCzAJBgNVBAYTAlVT +MRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoGA1UECxMzQ2xhc3MgMyBQdWJsaWMgUHJpbWFy +eSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEcyMTowOAYDVQQLEzEoYykgMTk5OCBWZXJpU2ln +biwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MR8wHQYDVQQLExZWZXJpU2lnbiBUcnVz +dCBOZXR3b3JrMB4XDTk4MDUxODAwMDAwMFoXDTI4MDgwMTIzNTk1OVowgcExCzAJBgNVBAYTAlVT +MRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoGA1UECxMzQ2xhc3MgMyBQdWJsaWMgUHJpbWFy +eSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEcyMTowOAYDVQQLEzEoYykgMTk5OCBWZXJpU2ln +biwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MR8wHQYDVQQLExZWZXJpU2lnbiBUcnVz +dCBOZXR3b3JrMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDMXtERXVxp0KvTuWpMmR9ZmDCO +FoUgRm1HP9SFIIThbbP4pO0M8RcPO/mn+SXXwc+EY/J8Y8+iR/LGWzOOZEAEaMGAuWQcRXfH2G71 +lSk8UOg013gfqLptQ5GVj0VXXn7F+8qkBOvqlzdUMG+7AUcyM83cV5tkaWH4mx0ciU9cZwIDAQAB +MA0GCSqGSIb3DQEBBQUAA4GBAFFNzb5cy5gZnBWyATl4Lk0PZ3BwmcYQWpSkU01UbSuvDV1Ai2TT +1+7eVmGSX6bEHRBhNtMsJzzoKQm5EWR0zLVznxxIqbxhAe7iF6YM40AIOw7n60RzKprxaZLvcRTD +Oaxxp5EJb+RxBrO6WVcmeQD2+A2iMzAo1KpYoJ2daZH9 +-----END CERTIFICATE----- + +GlobalSign Root CA +================== +-----BEGIN CERTIFICATE----- +MIIDdTCCAl2gAwIBAgILBAAAAAABFUtaw5QwDQYJKoZIhvcNAQEFBQAwVzELMAkGA1UEBhMCQkUx +GTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExEDAOBgNVBAsTB1Jvb3QgQ0ExGzAZBgNVBAMTEkds +b2JhbFNpZ24gUm9vdCBDQTAeFw05ODA5MDExMjAwMDBaFw0yODAxMjgxMjAwMDBaMFcxCzAJBgNV +BAYTAkJFMRkwFwYDVQQKExBHbG9iYWxTaWduIG52LXNhMRAwDgYDVQQLEwdSb290IENBMRswGQYD +VQQDExJHbG9iYWxTaWduIFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDa +DuaZjc6j40+Kfvvxi4Mla+pIH/EqsLmVEQS98GPR4mdmzxzdzxtIK+6NiY6arymAZavpxy0Sy6sc +THAHoT0KMM0VjU/43dSMUBUc71DuxC73/OlS8pF94G3VNTCOXkNz8kHp1Wrjsok6Vjk4bwY8iGlb +Kk3Fp1S4bInMm/k8yuX9ifUSPJJ4ltbcdG6TRGHRjcdGsnUOhugZitVtbNV4FpWi6cgKOOvyJBNP +c1STE4U6G7weNLWLBYy5d4ux2x8gkasJU26Qzns3dLlwR5EiUWMWea6xrkEmCMgZK9FGqkjWZCrX +gzT/LCrBbBlDSgeF59N89iFo7+ryUp9/k5DPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNV +HRMBAf8EBTADAQH/MB0GA1UdDgQWBBRge2YaRQ2XyolQL30EzTSo//z9SzANBgkqhkiG9w0BAQUF +AAOCAQEA1nPnfE920I2/7LqivjTFKDK1fPxsnCwrvQmeU79rXqoRSLblCKOzyj1hTdNGCbM+w6Dj +Y1Ub8rrvrTnhQ7k4o+YviiY776BQVvnGCv04zcQLcFGUl5gE38NflNUVyRRBnMRddWQVDf9VMOyG +j/8N7yy5Y0b2qvzfvGn9LhJIZJrglfCm7ymPAbEVtQwdpf5pLGkkeB6zpxxxYu7KyJesF12KwvhH +hm4qxFYxldBniYUr+WymXUadDKqC5JlR3XC321Y9YeRq4VzW9v493kHMB65jUr9TU/Qr6cf9tveC +X4XSQRjbgbMEHMUfpIBvFSDJ3gyICh3WZlXi/EjJKSZp4A== +-----END CERTIFICATE----- + +GlobalSign Root CA - R2 +======================= +-----BEGIN CERTIFICATE----- +MIIDujCCAqKgAwIBAgILBAAAAAABD4Ym5g0wDQYJKoZIhvcNAQEFBQAwTDEgMB4GA1UECxMXR2xv +YmFsU2lnbiBSb290IENBIC0gUjIxEzARBgNVBAoTCkdsb2JhbFNpZ24xEzARBgNVBAMTCkdsb2Jh +bFNpZ24wHhcNMDYxMjE1MDgwMDAwWhcNMjExMjE1MDgwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxT +aWduIFJvb3QgQ0EgLSBSMjETMBEGA1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2ln +bjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKbPJA6+Lm8omUVCxKs+IVSbC9N/hHD6 +ErPLv4dfxn+G07IwXNb9rfF73OX4YJYJkhD10FPe+3t+c4isUoh7SqbKSaZeqKeMWhG8eoLrvozp +s6yWJQeXSpkqBy+0Hne/ig+1AnwblrjFuTosvNYSuetZfeLQBoZfXklqtTleiDTsvHgMCJiEbKjN +S7SgfQx5TfC4LcshytVsW33hoCmEofnTlEnLJGKRILzdC9XZzPnqJworc5HGnRusyMvo4KD0L5CL +TfuwNhv2GXqF4G3yYROIXJ/gkwpRl4pazq+r1feqCapgvdzZX99yqWATXgAByUr6P6TqBwMhAo6C +ygPCm48CAwEAAaOBnDCBmTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4E +FgQUm+IHV2ccHsBqBt5ZtJot39wZhi4wNgYDVR0fBC8wLTAroCmgJ4YlaHR0cDovL2NybC5nbG9i +YWxzaWduLm5ldC9yb290LXIyLmNybDAfBgNVHSMEGDAWgBSb4gdXZxwewGoG3lm0mi3f3BmGLjAN +BgkqhkiG9w0BAQUFAAOCAQEAmYFThxxol4aR7OBKuEQLq4GsJ0/WwbgcQ3izDJr86iw8bmEbTUsp +9Z8FHSbBuOmDAGJFtqkIk7mpM0sYmsL4h4hO291xNBrBVNpGP+DTKqttVCL1OmLNIG+6KYnX3ZHu +01yiPqFbQfXf5WRDLenVOavSot+3i9DAgBkcRcAtjOj4LaR0VknFBbVPFd5uRHg5h6h+u/N5GJG7 +9G+dwfCMNYxdAfvDbbnvRG15RjF+Cv6pgsH/76tuIMRQyV+dTZsXjAzlAcmgQWpzU/qlULRuJQ/7 +TBj0/VLZjmmx6BEP3ojY+x1J96relc8geMJgEtslQIxq/H5COEBkEveegeGTLg== +-----END CERTIFICATE----- + +ValiCert Class 1 VA +=================== +-----BEGIN CERTIFICATE----- +MIIC5zCCAlACAQEwDQYJKoZIhvcNAQEFBQAwgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0IFZhbGlkYXRp +b24gTmV0d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAzBgNVBAsTLFZhbGlDZXJ0IENs +YXNzIDEgUG9saWN5IFZhbGlkYXRpb24gQXV0aG9yaXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZh +bGljZXJ0LmNvbS8xIDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMB4XDTk5MDYyNTIy +MjM0OFoXDTE5MDYyNTIyMjM0OFowgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0IFZhbGlkYXRpb24gTmV0 +d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAzBgNVBAsTLFZhbGlDZXJ0IENsYXNzIDEg +UG9saWN5IFZhbGlkYXRpb24gQXV0aG9yaXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZhbGljZXJ0 +LmNvbS8xIDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMIGfMA0GCSqGSIb3DQEBAQUA +A4GNADCBiQKBgQDYWYJ6ibiWuqYvaG9YLqdUHAZu9OqNSLwxlBfw8068srg1knaw0KWlAdcAAxIi +GQj4/xEjm84H9b9pGib+TunRf50sQB1ZaG6m+FiwnRqP0z/x3BkGgagO4DrdyFNFCQbmD3DD+kCm +DuJWBQ8YTfwggtFzVXSNdnKgHZ0dwN0/cQIDAQABMA0GCSqGSIb3DQEBBQUAA4GBAFBoPUn0LBwG +lN+VYH+Wexf+T3GtZMjdd9LvWVXoP+iOBSoh8gfStadS/pyxtuJbdxdA6nLWI8sogTLDAHkY7FkX +icnGah5xyf23dKUlRWnFSKsZ4UWKJWsZ7uW7EvV/96aNUcPwnXS3qT6gpf+2SQMT2iLM7XGCK5nP +Orf1LXLI +-----END CERTIFICATE----- + +ValiCert Class 2 VA +=================== +-----BEGIN CERTIFICATE----- +MIIC5zCCAlACAQEwDQYJKoZIhvcNAQEFBQAwgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0IFZhbGlkYXRp +b24gTmV0d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAzBgNVBAsTLFZhbGlDZXJ0IENs +YXNzIDIgUG9saWN5IFZhbGlkYXRpb24gQXV0aG9yaXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZh +bGljZXJ0LmNvbS8xIDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMB4XDTk5MDYyNjAw +MTk1NFoXDTE5MDYyNjAwMTk1NFowgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0IFZhbGlkYXRpb24gTmV0 +d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAzBgNVBAsTLFZhbGlDZXJ0IENsYXNzIDIg +UG9saWN5IFZhbGlkYXRpb24gQXV0aG9yaXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZhbGljZXJ0 +LmNvbS8xIDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMIGfMA0GCSqGSIb3DQEBAQUA +A4GNADCBiQKBgQDOOnHK5avIWZJV16vYdA757tn2VUdZZUcOBVXc65g2PFxTXdMwzzjsvUGJ7SVC +CSRrCl6zfN1SLUzm1NZ9WlmpZdRJEy0kTRxQb7XBhVQ7/nHk01xC+YDgkRoKWzk2Z/M/VXwbP7Rf +ZHM047QSv4dk+NoS/zcnwbNDu+97bi5p9wIDAQABMA0GCSqGSIb3DQEBBQUAA4GBADt/UG9vUJSZ +SWI4OB9L+KXIPqeCgfYrx+jFzug6EILLGACOTb2oWH+heQC1u+mNr0HZDzTuIYEZoDJJKPTEjlbV +UjP9UNV+mWwD5MlM/Mtsq2azSiGM5bUMMj4QssxsodyamEwCW/POuZ6lcg5Ktz885hZo+L7tdEy8 +W9ViH0Pd +-----END CERTIFICATE----- + +RSA Root Certificate 1 +====================== +-----BEGIN CERTIFICATE----- +MIIC5zCCAlACAQEwDQYJKoZIhvcNAQEFBQAwgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0IFZhbGlkYXRp +b24gTmV0d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAzBgNVBAsTLFZhbGlDZXJ0IENs +YXNzIDMgUG9saWN5IFZhbGlkYXRpb24gQXV0aG9yaXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZh +bGljZXJ0LmNvbS8xIDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMB4XDTk5MDYyNjAw +MjIzM1oXDTE5MDYyNjAwMjIzM1owgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0IFZhbGlkYXRpb24gTmV0 +d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAzBgNVBAsTLFZhbGlDZXJ0IENsYXNzIDMg +UG9saWN5IFZhbGlkYXRpb24gQXV0aG9yaXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZhbGljZXJ0 +LmNvbS8xIDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMIGfMA0GCSqGSIb3DQEBAQUA +A4GNADCBiQKBgQDjmFGWHOjVsQaBalfDcnWTq8+epvzzFlLWLU2fNUSoLgRNB0mKOCn1dzfnt6td +3zZxFJmP3MKS8edgkpfs2Ejcv8ECIMYkpChMMFp2bbFc893enhBxoYjHW5tBbcqwuI4V7q0zK89H +BFx1cQqYJJgpp0lZpd34t0NiYfPT4tBVPwIDAQABMA0GCSqGSIb3DQEBBQUAA4GBAFa7AliEZwgs +3x/be0kz9dNnnfS0ChCzycUs4pJqcXgn8nCDQtM+z6lU9PHYkhaM0QTLS6vJn0WuPIqpsHEzXcjF +V9+vqDWzf4mH6eglkrh/hXqu1rweN1gqZ8mRzyqBPu3GOd/APhmcGcwTTYJBtYze4D1gCCAPRX5r +on+jjBXu +-----END CERTIFICATE----- + +Verisign Class 3 Public Primary Certification Authority - G3 +============================================================ +-----BEGIN CERTIFICATE----- +MIIEGjCCAwICEQCbfgZJoz5iudXukEhxKe9XMA0GCSqGSIb3DQEBBQUAMIHKMQswCQYDVQQGEwJV +UzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRydXN0IE5ldHdv +cmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWduLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNl +IG9ubHkxRTBDBgNVBAMTPFZlcmlTaWduIENsYXNzIDMgUHVibGljIFByaW1hcnkgQ2VydGlmaWNh +dGlvbiBBdXRob3JpdHkgLSBHMzAeFw05OTEwMDEwMDAwMDBaFw0zNjA3MTYyMzU5NTlaMIHKMQsw +CQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRy +dXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWduLCBJbmMuIC0gRm9yIGF1dGhv +cml6ZWQgdXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlTaWduIENsYXNzIDMgUHVibGljIFByaW1hcnkg +Q2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBHMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC +ggEBAMu6nFL8eB8aHm8bN3O9+MlrlBIwT/A2R/XQkQr1F8ilYcEWQE37imGQ5XYgwREGfassbqb1 +EUGO+i2tKmFZpGcmTNDovFJbcCAEWNF6yaRpvIMXZK0Fi7zQWM6NjPXr8EJJC52XJ2cybuGukxUc +cLwgTS8Y3pKI6GyFVxEa6X7jJhFUokWWVYPKMIno3Nij7SqAP395ZVc+FSBmCC+Vk7+qRy+oRpfw +EuL+wgorUeZ25rdGt+INpsyow0xZVYnm6FNcHOqd8GIWC6fJXwzw3sJ2zq/3avL6QaaiMxTJ5Xpj +055iN9WFZZ4O5lMkdBteHRJTW8cs54NJOxWuimi5V5cCAwEAATANBgkqhkiG9w0BAQUFAAOCAQEA +ERSWwauSCPc/L8my/uRan2Te2yFPhpk0djZX3dAVL8WtfxUfN2JzPtTnX84XA9s1+ivbrmAJXx5f +j267Cz3qWhMeDGBvtcC1IyIuBwvLqXTLR7sdwdela8wv0kL9Sd2nic9TutoAWii/gt/4uhMdUIaC +/Y4wjylGsB49Ndo4YhYYSq3mtlFs3q9i6wHQHiT+eo8SGhJouPtmmRQURVyu565pF4ErWjfJXir0 +xuKhXFSbplQAz/DxwceYMBo7Nhbbo27q/a2ywtrvAkcTisDxszGtTxzhT5yvDwyd93gN2PQ1VoDa +t20Xj50egWTh/sVFuq1ruQp6Tk9LhO5L8X3dEQ== +-----END CERTIFICATE----- + +Verisign Class 4 Public Primary Certification Authority - G3 +============================================================ +-----BEGIN CERTIFICATE----- +MIIEGjCCAwICEQDsoKeLbnVqAc/EfMwvlF7XMA0GCSqGSIb3DQEBBQUAMIHKMQswCQYDVQQGEwJV +UzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRydXN0IE5ldHdv +cmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWduLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNl +IG9ubHkxRTBDBgNVBAMTPFZlcmlTaWduIENsYXNzIDQgUHVibGljIFByaW1hcnkgQ2VydGlmaWNh +dGlvbiBBdXRob3JpdHkgLSBHMzAeFw05OTEwMDEwMDAwMDBaFw0zNjA3MTYyMzU5NTlaMIHKMQsw +CQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRy +dXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWduLCBJbmMuIC0gRm9yIGF1dGhv +cml6ZWQgdXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlTaWduIENsYXNzIDQgUHVibGljIFByaW1hcnkg +Q2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBHMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC +ggEBAK3LpRFpxlmr8Y+1GQ9Wzsy1HyDkniYlS+BzZYlZ3tCD5PUPtbut8XzoIfzk6AzufEUiGXaS +tBO3IFsJ+mGuqPKljYXCKtbeZjbSmwL0qJJgfJxptI8kHtCGUvYynEFYHiK9zUVilQhu0GbdU6LM +8BDcVHOLBKFGMzNcF0C5nk3T875Vg+ixiY5afJqWIpA7iCXy0lOIAgwLePLmNxdLMEYH5IBtptiW +Lugs+BGzOA1mppvqySNb247i8xOOGlktqgLw7KSHZtzBP/XYufTsgsbSPZUd5cBPhMnZo0QoBmrX +Razwa2rvTl/4EYIeOGM0ZlDUPpNz+jDDZq3/ky2X7wMCAwEAATANBgkqhkiG9w0BAQUFAAOCAQEA +j/ola09b5KROJ1WrIhVZPMq1CtRK26vdoV9TxaBXOcLORyu+OshWv8LZJxA6sQU8wHcxuzrTBXtt +mhwwjIDLk5Mqg6sFUYICABFna/OIYUdfA5PVWw3g8dShMjWFsjrbsIKr0csKvE+MW8VLADsfKoKm +fjaF3H48ZwC15DtS4KjrXRX5xm3wrR0OhbepmnMUWluPQSjA1egtTaRezarZ7c7c2NU8Qh0XwRJd +RTjDOPP8hS6DRkiy1yBfkjaP53kPmF6Z6PDQpLv1U70qzlmwr25/bLvSHgCwIe34QWKCudiyxLtG +UPMxxY8BqHTr9Xgn2uf3ZkPznoM+IKrDNWCRzg== +-----END CERTIFICATE----- + +Entrust.net Secure Server CA +============================ +-----BEGIN CERTIFICATE----- +MIIE2DCCBEGgAwIBAgIEN0rSQzANBgkqhkiG9w0BAQUFADCBwzELMAkGA1UEBhMCVVMxFDASBgNV +BAoTC0VudHJ1c3QubmV0MTswOQYDVQQLEzJ3d3cuZW50cnVzdC5uZXQvQ1BTIGluY29ycC4gYnkg +cmVmLiAobGltaXRzIGxpYWIuKTElMCMGA1UECxMcKGMpIDE5OTkgRW50cnVzdC5uZXQgTGltaXRl +ZDE6MDgGA1UEAxMxRW50cnVzdC5uZXQgU2VjdXJlIFNlcnZlciBDZXJ0aWZpY2F0aW9uIEF1dGhv +cml0eTAeFw05OTA1MjUxNjA5NDBaFw0xOTA1MjUxNjM5NDBaMIHDMQswCQYDVQQGEwJVUzEUMBIG +A1UEChMLRW50cnVzdC5uZXQxOzA5BgNVBAsTMnd3dy5lbnRydXN0Lm5ldC9DUFMgaW5jb3JwLiBi +eSByZWYuIChsaW1pdHMgbGlhYi4pMSUwIwYDVQQLExwoYykgMTk5OSBFbnRydXN0Lm5ldCBMaW1p +dGVkMTowOAYDVQQDEzFFbnRydXN0Lm5ldCBTZWN1cmUgU2VydmVyIENlcnRpZmljYXRpb24gQXV0 +aG9yaXR5MIGdMA0GCSqGSIb3DQEBAQUAA4GLADCBhwKBgQDNKIM0VBuJ8w+vN5Ex/68xYMmo6LIQ +aO2f55M28Qpku0f1BBc/I0dNxScZgSYMVHINiC3ZH5oSn7yzcdOAGT9HZnuMNSjSuQrfJNqc1lB5 +gXpa0zf3wkrYKZImZNHkmGw6AIr1NJtl+O3jEP/9uElY3KDegjlrgbEWGWG5VLbmQwIBA6OCAdcw +ggHTMBEGCWCGSAGG+EIBAQQEAwIABzCCARkGA1UdHwSCARAwggEMMIHeoIHboIHYpIHVMIHSMQsw +CQYDVQQGEwJVUzEUMBIGA1UEChMLRW50cnVzdC5uZXQxOzA5BgNVBAsTMnd3dy5lbnRydXN0Lm5l +dC9DUFMgaW5jb3JwLiBieSByZWYuIChsaW1pdHMgbGlhYi4pMSUwIwYDVQQLExwoYykgMTk5OSBF +bnRydXN0Lm5ldCBMaW1pdGVkMTowOAYDVQQDEzFFbnRydXN0Lm5ldCBTZWN1cmUgU2VydmVyIENl +cnRpZmljYXRpb24gQXV0aG9yaXR5MQ0wCwYDVQQDEwRDUkwxMCmgJ6AlhiNodHRwOi8vd3d3LmVu +dHJ1c3QubmV0L0NSTC9uZXQxLmNybDArBgNVHRAEJDAigA8xOTk5MDUyNTE2MDk0MFqBDzIwMTkw +NTI1MTYwOTQwWjALBgNVHQ8EBAMCAQYwHwYDVR0jBBgwFoAU8BdiE1U9s/8KAGv7UISX8+1i0Bow +HQYDVR0OBBYEFPAXYhNVPbP/CgBr+1CEl/PtYtAaMAwGA1UdEwQFMAMBAf8wGQYJKoZIhvZ9B0EA +BAwwChsEVjQuMAMCBJAwDQYJKoZIhvcNAQEFBQADgYEAkNwwAvpkdMKnCqV8IY00F6j7Rw7/JXyN +Ewr75Ji174z4xRAN95K+8cPV1ZVqBLssziY2ZcgxxufuP+NXdYR6Ee9GTxj005i7qIcyunL2POI9 +n9cd2cNgQ4xYDiKWL2KjLB+6rQXvqzJ4h6BUcxm1XAX5Uj5tLUUL9wqT6u0G+bI= +-----END CERTIFICATE----- + +Entrust.net Premium 2048 Secure Server CA +========================================= +-----BEGIN CERTIFICATE----- +MIIEKjCCAxKgAwIBAgIEOGPe+DANBgkqhkiG9w0BAQUFADCBtDEUMBIGA1UEChMLRW50cnVzdC5u +ZXQxQDA+BgNVBAsUN3d3dy5lbnRydXN0Lm5ldC9DUFNfMjA0OCBpbmNvcnAuIGJ5IHJlZi4gKGxp +bWl0cyBsaWFiLikxJTAjBgNVBAsTHChjKSAxOTk5IEVudHJ1c3QubmV0IExpbWl0ZWQxMzAxBgNV +BAMTKkVudHJ1c3QubmV0IENlcnRpZmljYXRpb24gQXV0aG9yaXR5ICgyMDQ4KTAeFw05OTEyMjQx +NzUwNTFaFw0yOTA3MjQxNDE1MTJaMIG0MRQwEgYDVQQKEwtFbnRydXN0Lm5ldDFAMD4GA1UECxQ3 +d3d3LmVudHJ1c3QubmV0L0NQU18yMDQ4IGluY29ycC4gYnkgcmVmLiAobGltaXRzIGxpYWIuKTEl +MCMGA1UECxMcKGMpIDE5OTkgRW50cnVzdC5uZXQgTGltaXRlZDEzMDEGA1UEAxMqRW50cnVzdC5u +ZXQgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgKDIwNDgpMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A +MIIBCgKCAQEArU1LqRKGsuqjIAcVFmQqK0vRvwtKTY7tgHalZ7d4QMBzQshowNtTK91euHaYNZOL +Gp18EzoOH1u3Hs/lJBQesYGpjX24zGtLA/ECDNyrpUAkAH90lKGdCCmziAv1h3edVc3kw37XamSr +hRSGlVuXMlBvPci6Zgzj/L24ScF2iUkZ/cCovYmjZy/Gn7xxGWC4LeksyZB2ZnuU4q941mVTXTzW +nLLPKQP5L6RQstRIzgUyVYr9smRMDuSYB3Xbf9+5CFVghTAp+XtIpGmG4zU/HoZdenoVve8AjhUi +VBcAkCaTvA5JaJG/+EfTnZVCwQ5N328mz8MYIWJmQ3DW1cAH4QIDAQABo0IwQDAOBgNVHQ8BAf8E +BAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUVeSB0RGAvtiJuQijMfmhJAkWuXAwDQYJ +KoZIhvcNAQEFBQADggEBADubj1abMOdTmXx6eadNl9cZlZD7Bh/KM3xGY4+WZiT6QBshJ8rmcnPy +T/4xmf3IDExoU8aAghOY+rat2l098c5u9hURlIIM7j+VrxGrD9cv3h8Dj1csHsm7mhpElesYT6Yf +zX1XEC+bBAlahLVu2B064dae0Wx5XnkcFMXj0EyTO2U87d89vqbllRrDtRnDvV5bu/8j72gZyxKT +J1wDLW8w0B62GqzeWvfRqqgnpv55gcR5mTNXuhKwqeBCbJPKVt7+bYQLCIt+jerXmCHG8+c8eS9e +nNFMFY3h7CI3zJpDC5fcgJCNs2ebb0gIFVbPv/ErfF6adulZkMV8gzURZVE= +-----END CERTIFICATE----- + +Baltimore CyberTrust Root +========================= +-----BEGIN CERTIFICATE----- +MIIDdzCCAl+gAwIBAgIEAgAAuTANBgkqhkiG9w0BAQUFADBaMQswCQYDVQQGEwJJRTESMBAGA1UE +ChMJQmFsdGltb3JlMRMwEQYDVQQLEwpDeWJlclRydXN0MSIwIAYDVQQDExlCYWx0aW1vcmUgQ3li +ZXJUcnVzdCBSb290MB4XDTAwMDUxMjE4NDYwMFoXDTI1MDUxMjIzNTkwMFowWjELMAkGA1UEBhMC +SUUxEjAQBgNVBAoTCUJhbHRpbW9yZTETMBEGA1UECxMKQ3liZXJUcnVzdDEiMCAGA1UEAxMZQmFs +dGltb3JlIEN5YmVyVHJ1c3QgUm9vdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKME +uyKrmD1X6CZymrV51Cni4eiVgLGw41uOKymaZN+hXe2wCQVt2yguzmKiYv60iNoS6zjrIZ3AQSsB +UnuId9Mcj8e6uYi1agnnc+gRQKfRzMpijS3ljwumUNKoUMMo6vWrJYeKmpYcqWe4PwzV9/lSEy/C +G9VwcPCPwBLKBsua4dnKM3p31vjsufFoREJIE9LAwqSuXmD+tqYF/LTdB1kC1FkYmGP1pWPgkAx9 +XbIGevOF6uvUA65ehD5f/xXtabz5OTZydc93Uk3zyZAsuT3lySNTPx8kmCFcB5kpvcY67Oduhjpr +l3RjM71oGDHweI12v/yejl0qhqdNkNwnGjkCAwEAAaNFMEMwHQYDVR0OBBYEFOWdWTCCR1jMrPoI +VDaGezq1BE3wMBIGA1UdEwEB/wQIMAYBAf8CAQMwDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEB +BQUAA4IBAQCFDF2O5G9RaEIFoN27TyclhAO992T9Ldcw46QQF+vaKSm2eT929hkTI7gQCvlYpNRh +cL0EYWoSihfVCr3FvDB81ukMJY2GQE/szKN+OMY3EU/t3WgxjkzSswF07r51XgdIGn9w/xZchMB5 +hbgF/X++ZRGjD8ACtPhSNzkE1akxehi/oCr0Epn3o0WC4zxe9Z2etciefC7IpJ5OCBRLbf1wbWsa +Y71k5h+3zvDyny67G7fyUIhzksLi4xaNmjICq44Y3ekQEe5+NauQrz4wlHrQMz2nZQ/1/I6eYs9H +RCwBXbsdtTLSR9I4LtD+gdwyah617jzV/OeBHRnDJELqYzmp +-----END CERTIFICATE----- + +Equifax Secure Global eBusiness CA +================================== +-----BEGIN CERTIFICATE----- +MIICkDCCAfmgAwIBAgIBATANBgkqhkiG9w0BAQQFADBaMQswCQYDVQQGEwJVUzEcMBoGA1UEChMT +RXF1aWZheCBTZWN1cmUgSW5jLjEtMCsGA1UEAxMkRXF1aWZheCBTZWN1cmUgR2xvYmFsIGVCdXNp +bmVzcyBDQS0xMB4XDTk5MDYyMTA0MDAwMFoXDTIwMDYyMTA0MDAwMFowWjELMAkGA1UEBhMCVVMx +HDAaBgNVBAoTE0VxdWlmYXggU2VjdXJlIEluYy4xLTArBgNVBAMTJEVxdWlmYXggU2VjdXJlIEds +b2JhbCBlQnVzaW5lc3MgQ0EtMTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAuucXkAJlsTRV +PEnCUdXfp9E3j9HngXNBUmCbnaEXJnitx7HoJpQytd4zjTov2/KaelpzmKNc6fuKcxtc58O/gGzN +qfTWK8D3+ZmqY6KxRwIP1ORROhI8bIpaVIRw28HFkM9yRcuoWcDNM50/o5brhTMhHD4ePmBudpxn +hcXIw2ECAwEAAaNmMGQwEQYJYIZIAYb4QgEBBAQDAgAHMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0j +BBgwFoAUvqigdHJQa0S3ySPY+6j/s1draGwwHQYDVR0OBBYEFL6ooHRyUGtEt8kj2Puo/7NXa2hs +MA0GCSqGSIb3DQEBBAUAA4GBADDiAVGqx+pf2rnQZQ8w1j7aDRRJbpGTJxQx78T3LUX47Me/okEN +I7SS+RkAZ70Br83gcfxaz2TE4JaY0KNA4gGK7ycH8WUBikQtBmV1UsCGECAhX2xrD2yuCRyv8qIY +NMR1pHMc8Y3c7635s3a0kr/clRAevsvIO1qEYBlWlKlV +-----END CERTIFICATE----- + +Equifax Secure eBusiness CA 1 +============================= +-----BEGIN CERTIFICATE----- +MIICgjCCAeugAwIBAgIBBDANBgkqhkiG9w0BAQQFADBTMQswCQYDVQQGEwJVUzEcMBoGA1UEChMT +RXF1aWZheCBTZWN1cmUgSW5jLjEmMCQGA1UEAxMdRXF1aWZheCBTZWN1cmUgZUJ1c2luZXNzIENB +LTEwHhcNOTkwNjIxMDQwMDAwWhcNMjAwNjIxMDQwMDAwWjBTMQswCQYDVQQGEwJVUzEcMBoGA1UE +ChMTRXF1aWZheCBTZWN1cmUgSW5jLjEmMCQGA1UEAxMdRXF1aWZheCBTZWN1cmUgZUJ1c2luZXNz +IENBLTEwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAM4vGbwXt3fek6lfWg0XTzQaDJj0ItlZ +1MRoRvC0NcWFAyDGr0WlIVFFQesWWDYyb+JQYmT5/VGcqiTZ9J2DKocKIdMSODRsjQBuWqDZQu4a +IZX5UkxVWsUPOE9G+m34LjXWHXzr4vCwdYDIqROsvojvOm6rXyo4YgKwEnv+j6YDAgMBAAGjZjBk +MBEGCWCGSAGG+EIBAQQEAwIABzAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFEp4MlIR21kW +Nl7fwRQ2QGpHfEyhMB0GA1UdDgQWBBRKeDJSEdtZFjZe38EUNkBqR3xMoTANBgkqhkiG9w0BAQQF +AAOBgQB1W6ibAxHm6VZMzfmpTMANmvPMZWnmJXbMWbfWVMMdzZmsGd20hdXgPfxiIKeES1hl8eL5 +lSE/9dR+WB5Hh1Q+WKG1tfgq73HnvMP2sUlG4tega+VWeponmHxGYhTnyfxuAxJ5gDgdSIKN/Bf+ +KpYrtWKmpj29f5JZzVoqgrI3eQ== +-----END CERTIFICATE----- + +AddTrust Low-Value Services Root +================================ +-----BEGIN CERTIFICATE----- +MIIEGDCCAwCgAwIBAgIBATANBgkqhkiG9w0BAQUFADBlMQswCQYDVQQGEwJTRTEUMBIGA1UEChML +QWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRUUCBOZXR3b3JrMSEwHwYDVQQDExhBZGRU +cnVzdCBDbGFzcyAxIENBIFJvb3QwHhcNMDAwNTMwMTAzODMxWhcNMjAwNTMwMTAzODMxWjBlMQsw +CQYDVQQGEwJTRTEUMBIGA1UEChMLQWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRUUCBO +ZXR3b3JrMSEwHwYDVQQDExhBZGRUcnVzdCBDbGFzcyAxIENBIFJvb3QwggEiMA0GCSqGSIb3DQEB +AQUAA4IBDwAwggEKAoIBAQCWltQhSWDia+hBBwzexODcEyPNwTXH+9ZOEQpnXvUGW2ulCDtbKRY6 +54eyNAbFvAWlA3yCyykQruGIgb3WntP+LVbBFc7jJp0VLhD7Bo8wBN6ntGO0/7Gcrjyvd7ZWxbWr +oulpOj0OM3kyP3CCkplhbY0wCI9xP6ZIVxn4JdxLZlyldI+Yrsj5wAYi56xz36Uu+1LcsRVlIPo1 +Zmne3yzxbrww2ywkEtvrNTVokMsAsJchPXQhI2U0K7t4WaPW4XY5mqRJjox0r26kmqPZm9I4XJui +GMx1I4S+6+JNM3GOGvDC+Mcdoq0Dlyz4zyXG9rgkMbFjXZJ/Y/AlyVMuH79NAgMBAAGjgdIwgc8w +HQYDVR0OBBYEFJWxtPCUtr3H2tERCSG+wa9J/RB7MAsGA1UdDwQEAwIBBjAPBgNVHRMBAf8EBTAD +AQH/MIGPBgNVHSMEgYcwgYSAFJWxtPCUtr3H2tERCSG+wa9J/RB7oWmkZzBlMQswCQYDVQQGEwJT +RTEUMBIGA1UEChMLQWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRUUCBOZXR3b3JrMSEw +HwYDVQQDExhBZGRUcnVzdCBDbGFzcyAxIENBIFJvb3SCAQEwDQYJKoZIhvcNAQEFBQADggEBACxt +ZBsfzQ3duQH6lmM0MkhHma6X7f1yFqZzR1r0693p9db7RcwpiURdv0Y5PejuvE1Uhh4dbOMXJ0Ph +iVYrqW9yTkkz43J8KiOavD7/KCrto/8cI7pDVwlnTUtiBi34/2ydYB7YHEt9tTEv2dB8Xfjea4MY +eDdXL+gzB2ffHsdrKpV2ro9Xo/D0UrSpUwjP4E/TelOL/bscVjby/rK25Xa71SJlpz/+0WatC7xr +mYbvP33zGDLKe8bjq2RGlfgmadlVg3sslgf/WSxEo8bl6ancoWOAWiFeIc9TVPC6b4nbqKqVz4vj +ccweGyBECMB6tkD9xOQ14R0WHNC8K47Wcdk= +-----END CERTIFICATE----- + +AddTrust External Root +====================== +-----BEGIN CERTIFICATE----- +MIIENjCCAx6gAwIBAgIBATANBgkqhkiG9w0BAQUFADBvMQswCQYDVQQGEwJTRTEUMBIGA1UEChML +QWRkVHJ1c3QgQUIxJjAkBgNVBAsTHUFkZFRydXN0IEV4dGVybmFsIFRUUCBOZXR3b3JrMSIwIAYD +VQQDExlBZGRUcnVzdCBFeHRlcm5hbCBDQSBSb290MB4XDTAwMDUzMDEwNDgzOFoXDTIwMDUzMDEw +NDgzOFowbzELMAkGA1UEBhMCU0UxFDASBgNVBAoTC0FkZFRydXN0IEFCMSYwJAYDVQQLEx1BZGRU +cnVzdCBFeHRlcm5hbCBUVFAgTmV0d29yazEiMCAGA1UEAxMZQWRkVHJ1c3QgRXh0ZXJuYWwgQ0Eg +Um9vdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALf3GjPm8gAELTngTlvtH7xsD821 ++iO2zt6bETOXpClMfZOfvUq8k+0DGuOPz+VtUFrWlymUWoCwSXrbLpX9uMq/NzgtHj6RQa1wVsfw +Tz/oMp50ysiQVOnGXw94nZpAPA6sYapeFI+eh6FqUNzXmk6vBbOmcZSccbNQYArHE504B4YCqOmo +aSYYkKtMsE8jqzpPhNjfzp/haW+710LXa0Tkx63ubUFfclpxCDezeWWkWaCUN/cALw3CknLa0Dhy +2xSoRcRdKn23tNbE7qzNE0S3ySvdQwAl+mG5aWpYIxG3pzOPVnVZ9c0p10a3CitlttNCbxWyuHv7 +7+ldU9U0WicCAwEAAaOB3DCB2TAdBgNVHQ4EFgQUrb2YejS0Jvf6xCZU7wO94CTLVBowCwYDVR0P +BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wgZkGA1UdIwSBkTCBjoAUrb2YejS0Jvf6xCZU7wO94CTL +VBqhc6RxMG8xCzAJBgNVBAYTAlNFMRQwEgYDVQQKEwtBZGRUcnVzdCBBQjEmMCQGA1UECxMdQWRk +VHJ1c3QgRXh0ZXJuYWwgVFRQIE5ldHdvcmsxIjAgBgNVBAMTGUFkZFRydXN0IEV4dGVybmFsIENB +IFJvb3SCAQEwDQYJKoZIhvcNAQEFBQADggEBALCb4IUlwtYj4g+WBpKdQZic2YR5gdkeWxQHIzZl +j7DYd7usQWxHYINRsPkyPef89iYTx4AWpb9a/IfPeHmJIZriTAcKhjW88t5RxNKWt9x+Tu5w/Rw5 +6wwCURQtjr0W4MHfRnXnJK3s9EK0hZNwEGe6nQY1ShjTK3rMUUKhemPR5ruhxSvCNr4TDea9Y355 +e6cJDUCrat2PisP29owaQgVR1EX1n6diIWgVIEM8med8vSTYqZEXc4g/VhsxOBi0cQ+azcgOno4u +G+GMmIPLHzHxREzGBHNJdmAPx/i9F4BrLunMTA5amnkPIAou1Z5jJh5VkpTYghdae9C8x49OhgQ= +-----END CERTIFICATE----- + +AddTrust Public Services Root +============================= +-----BEGIN CERTIFICATE----- +MIIEFTCCAv2gAwIBAgIBATANBgkqhkiG9w0BAQUFADBkMQswCQYDVQQGEwJTRTEUMBIGA1UEChML +QWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRUUCBOZXR3b3JrMSAwHgYDVQQDExdBZGRU +cnVzdCBQdWJsaWMgQ0EgUm9vdDAeFw0wMDA1MzAxMDQxNTBaFw0yMDA1MzAxMDQxNTBaMGQxCzAJ +BgNVBAYTAlNFMRQwEgYDVQQKEwtBZGRUcnVzdCBBQjEdMBsGA1UECxMUQWRkVHJ1c3QgVFRQIE5l +dHdvcmsxIDAeBgNVBAMTF0FkZFRydXN0IFB1YmxpYyBDQSBSb290MIIBIjANBgkqhkiG9w0BAQEF +AAOCAQ8AMIIBCgKCAQEA6Rowj4OIFMEg2Dybjxt+A3S72mnTRqX4jsIMEZBRpS9mVEBV6tsfSlbu +nyNu9DnLoblv8n75XYcmYZ4c+OLspoH4IcUkzBEMP9smcnrHAZcHF/nXGCwwfQ56HmIexkvA/X1i +d9NEHif2P0tEs7c42TkfYNVRknMDtABp4/MUTu7R3AnPdzRGULD4EfL+OHn3Bzn+UZKXC1sIXzSG +Aa2Il+tmzV7R/9x98oTaunet3IAIx6eH1lWfl2royBFkuucZKT8Rs3iQhCBSWxHveNCD9tVIkNAw +HM+A+WD+eeSI8t0A65RF62WUaUC6wNW0uLp9BBGo6zEFlpROWCGOn9Bg/QIDAQABo4HRMIHOMB0G +A1UdDgQWBBSBPjfYkrAfd59ctKtzquf2NGAv+jALBgNVHQ8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB +/zCBjgYDVR0jBIGGMIGDgBSBPjfYkrAfd59ctKtzquf2NGAv+qFopGYwZDELMAkGA1UEBhMCU0Ux +FDASBgNVBAoTC0FkZFRydXN0IEFCMR0wGwYDVQQLExRBZGRUcnVzdCBUVFAgTmV0d29yazEgMB4G +A1UEAxMXQWRkVHJ1c3QgUHVibGljIENBIFJvb3SCAQEwDQYJKoZIhvcNAQEFBQADggEBAAP3FUr4 +JNojVhaTdt02KLmuG7jD8WS6IBh4lSknVwW8fCr0uVFV2ocC3g8WFzH4qnkuCRO7r7IgGRLlk/lL ++YPoRNWyQSW/iHVv/xD8SlTQX/D67zZzfRs2RcYhbbQVuE7PnFylPVoAjgbjPGsye/Kf8Lb93/Ao +GEjwxrzQvzSAlsJKsW2Ox5BF3i9nrEUEo3rcVZLJR2bYGozH7ZxOmuASu7VqTITh4SINhwBk/ox9 +Yjllpu9CtoAlEmEBqCQTcAARJl/6NVDFSMwGR+gn2HCNX2TmoUQmXiLsks3/QppEIW1cxeMiHV9H +EufOX1362KqxMy3ZdvJOOjMMK7MtkAY= +-----END CERTIFICATE----- + +AddTrust Qualified Certificates Root +==================================== +-----BEGIN CERTIFICATE----- +MIIEHjCCAwagAwIBAgIBATANBgkqhkiG9w0BAQUFADBnMQswCQYDVQQGEwJTRTEUMBIGA1UEChML +QWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRUUCBOZXR3b3JrMSMwIQYDVQQDExpBZGRU +cnVzdCBRdWFsaWZpZWQgQ0EgUm9vdDAeFw0wMDA1MzAxMDQ0NTBaFw0yMDA1MzAxMDQ0NTBaMGcx +CzAJBgNVBAYTAlNFMRQwEgYDVQQKEwtBZGRUcnVzdCBBQjEdMBsGA1UECxMUQWRkVHJ1c3QgVFRQ +IE5ldHdvcmsxIzAhBgNVBAMTGkFkZFRydXN0IFF1YWxpZmllZCBDQSBSb290MIIBIjANBgkqhkiG +9w0BAQEFAAOCAQ8AMIIBCgKCAQEA5B6a/twJWoekn0e+EV+vhDTbYjx5eLfpMLXsDBwqxBb/4Oxx +64r1EW7tTw2R0hIYLUkVAcKkIhPHEWT/IhKauY5cLwjPcWqzZwFZ8V1G87B4pfYOQnrjfxvM0PC3 +KP0q6p6zsLkEqv32x7SxuCqg+1jxGaBvcCV+PmlKfw8i2O+tCBGaKZnhqkRFmhJePp1tUvznoD1o +L/BLcHwTOK28FSXx1s6rosAx1i+f4P8UWfyEk9mHfExUE+uf0S0R+Bg6Ot4l2ffTQO2kBhLEO+GR +wVY18BTcZTYJbqukB8c10cIDMzZbdSZtQvESa0NvS3GU+jQd7RNuyoB/mC9suWXY6QIDAQABo4HU +MIHRMB0GA1UdDgQWBBQ5lYtii1zJ1IC6WA+XPxUIQ8yYpzALBgNVHQ8EBAMCAQYwDwYDVR0TAQH/ +BAUwAwEB/zCBkQYDVR0jBIGJMIGGgBQ5lYtii1zJ1IC6WA+XPxUIQ8yYp6FrpGkwZzELMAkGA1UE +BhMCU0UxFDASBgNVBAoTC0FkZFRydXN0IEFCMR0wGwYDVQQLExRBZGRUcnVzdCBUVFAgTmV0d29y +azEjMCEGA1UEAxMaQWRkVHJ1c3QgUXVhbGlmaWVkIENBIFJvb3SCAQEwDQYJKoZIhvcNAQEFBQAD +ggEBABmrder4i2VhlRO6aQTvhsoToMeqT2QbPxj2qC0sVY8FtzDqQmodwCVRLae/DLPt7wh/bDxG +GuoYQ992zPlmhpwsaPXpF/gxsxjE1kh9I0xowX67ARRvxdlu3rsEQmr49lx95dr6h+sNNVJn0J6X +dgWTP5XHAeZpVTh/EGGZyeNfpso+gmNIquIISD6q8rKFYqa0p9m9N5xotS1WfbC3P6CxB9bpT9ze +RXEwMn8bLgn5v1Kh7sKAPgZcLlVAwRv1cEWw3F369nJad9Jjzc9YiQBCYz95OdBEsIJuQRno3eDB +iFrRHnGTHyQwdOUeqN48Jzd/g66ed8/wMLH/S5noxqE= +-----END CERTIFICATE----- + +Entrust Root Certification Authority +==================================== +-----BEGIN CERTIFICATE----- +MIIEkTCCA3mgAwIBAgIERWtQVDANBgkqhkiG9w0BAQUFADCBsDELMAkGA1UEBhMCVVMxFjAUBgNV +BAoTDUVudHJ1c3QsIEluYy4xOTA3BgNVBAsTMHd3dy5lbnRydXN0Lm5ldC9DUFMgaXMgaW5jb3Jw +b3JhdGVkIGJ5IHJlZmVyZW5jZTEfMB0GA1UECxMWKGMpIDIwMDYgRW50cnVzdCwgSW5jLjEtMCsG +A1UEAxMkRW50cnVzdCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTA2MTEyNzIwMjM0 +MloXDTI2MTEyNzIwNTM0MlowgbAxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1FbnRydXN0LCBJbmMu +MTkwNwYDVQQLEzB3d3cuZW50cnVzdC5uZXQvQ1BTIGlzIGluY29ycG9yYXRlZCBieSByZWZlcmVu +Y2UxHzAdBgNVBAsTFihjKSAyMDA2IEVudHJ1c3QsIEluYy4xLTArBgNVBAMTJEVudHJ1c3QgUm9v +dCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB +ALaVtkNC+sZtKm9I35RMOVcF7sN5EUFoNu3s/poBj6E4KPz3EEZmLk0eGrEaTsbRwJWIsMn/MYsz +A9u3g3s+IIRe7bJWKKf44LlAcTfFy0cOlypowCKVYhXbR9n10Cv/gkvJrT7eTNuQgFA/CYqEAOww +Cj0Yzfv9KlmaI5UXLEWeH25DeW0MXJj+SKfFI0dcXv1u5x609mhF0YaDW6KKjbHjKYD+JXGIrb68 +j6xSlkuqUY3kEzEZ6E5Nn9uss2rVvDlUccp6en+Q3X0dgNmBu1kmwhH+5pPi94DkZfs0Nw4pgHBN +rziGLp5/V6+eF67rHMsoIV+2HNjnogQi+dPa2MsCAwEAAaOBsDCBrTAOBgNVHQ8BAf8EBAMCAQYw +DwYDVR0TAQH/BAUwAwEB/zArBgNVHRAEJDAigA8yMDA2MTEyNzIwMjM0MlqBDzIwMjYxMTI3MjA1 +MzQyWjAfBgNVHSMEGDAWgBRokORnpKZTgMeGZqTx90tD+4S9bTAdBgNVHQ4EFgQUaJDkZ6SmU4DH +hmak8fdLQ/uEvW0wHQYJKoZIhvZ9B0EABBAwDhsIVjcuMTo0LjADAgSQMA0GCSqGSIb3DQEBBQUA +A4IBAQCT1DCw1wMgKtD5Y+iRDAUgqV8ZyntyTtSx29CW+1RaGSwMCPeyvIWonX9tO1KzKtvn1ISM +Y/YPyyYBkVBs9F8U4pN0wBOeMDpQ47RgxRzwIkSNcUesyBrJ6ZuaAGAT/3B+XxFNSRuzFVJ7yVTa +v52Vr2ua2J7p8eRDjeIRRDq/r72DQnNSi6q7pynP9WQcCk3RvKqsnyrQ/39/2n3qse0wJcGE2jTS +W3iDVuycNsMm4hH2Z0kdkquM++v/eu6FSqdQgPCnXEqULl8FmTxSQeDNtGPPAUO6nIPcj2A781q0 +tHuu2guQOHXvgR1m0vdXcDazv/wor3ElhVsT/h5/WrQ8 +-----END CERTIFICATE----- + +RSA Security 2048 v3 +==================== +-----BEGIN CERTIFICATE----- +MIIDYTCCAkmgAwIBAgIQCgEBAQAAAnwAAAAKAAAAAjANBgkqhkiG9w0BAQUFADA6MRkwFwYDVQQK +ExBSU0EgU2VjdXJpdHkgSW5jMR0wGwYDVQQLExRSU0EgU2VjdXJpdHkgMjA0OCBWMzAeFw0wMTAy +MjIyMDM5MjNaFw0yNjAyMjIyMDM5MjNaMDoxGTAXBgNVBAoTEFJTQSBTZWN1cml0eSBJbmMxHTAb +BgNVBAsTFFJTQSBTZWN1cml0eSAyMDQ4IFYzMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC +AQEAt49VcdKA3XtpeafwGFAyPGJn9gqVB93mG/Oe2dJBVGutn3y+Gc37RqtBaB4Y6lXIL5F4iSj7 +Jylg/9+PjDvJSZu1pJTOAeo+tWN7fyb9Gd3AIb2E0S1PRsNO3Ng3OTsor8udGuorryGlwSMiuLgb +WhOHV4PR8CDn6E8jQrAApX2J6elhc5SYcSa8LWrg903w8bYqODGBDSnhAMFRD0xS+ARaqn1y07iH +KrtjEAMqs6FPDVpeRrc9DvV07Jmf+T0kgYim3WBU6JU2PcYJk5qjEoAAVZkZR73QpXzDuvsf9/UP ++Ky5tfQ3mBMY3oVbtwyCO4dvlTlYMNpuAWgXIszACwIDAQABo2MwYTAPBgNVHRMBAf8EBTADAQH/ +MA4GA1UdDwEB/wQEAwIBBjAfBgNVHSMEGDAWgBQHw1EwpKrpRa41JPr/JCwz0LGdjDAdBgNVHQ4E +FgQUB8NRMKSq6UWuNST6/yQsM9CxnYwwDQYJKoZIhvcNAQEFBQADggEBAF8+hnZuuDU8TjYcHnmY +v/3VEhF5Ug7uMYm83X/50cYVIeiKAVQNOvtUudZj1LGqlk2iQk3UUx+LEN5/Zb5gEydxiKRz44Rj +0aRV4VCT5hsOedBnvEbIvz8XDZXmxpBp3ue0L96VfdASPz0+f00/FGj1EVDVwfSQpQgdMWD/YIwj +VAqv/qFuxdF6Kmh4zx6CCiC0H63lhbJqaHVOrSU3lIW+vaHU6rcMSzyd6BIA8F+sDeGscGNz9395 +nzIlQnQFgCi/vcEkllgVsRch6YlL2weIZ/QVrXA+L02FO8K32/6YaCOJ4XQP3vTFhGMpG8zLB8kA +pKnXwiJPZ9d37CAFYd4= +-----END CERTIFICATE----- + +GeoTrust Global CA +================== +-----BEGIN CERTIFICATE----- +MIIDVDCCAjygAwIBAgIDAjRWMA0GCSqGSIb3DQEBBQUAMEIxCzAJBgNVBAYTAlVTMRYwFAYDVQQK +Ew1HZW9UcnVzdCBJbmMuMRswGQYDVQQDExJHZW9UcnVzdCBHbG9iYWwgQ0EwHhcNMDIwNTIxMDQw +MDAwWhcNMjIwNTIxMDQwMDAwWjBCMQswCQYDVQQGEwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5j +LjEbMBkGA1UEAxMSR2VvVHJ1c3QgR2xvYmFsIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB +CgKCAQEA2swYYzD99BcjGlZ+W988bDjkcbd4kdS8odhM+KhDtgPpTSEHCIjaWC9mOSm9BXiLnTjo +BbdqfnGk5sRgprDvgOSJKA+eJdbtg/OtppHHmMlCGDUUna2YRpIuT8rxh0PBFpVXLVDviS2Aelet +8u5fa9IAjbkU+BQVNdnARqN7csiRv8lVK83Qlz6cJmTM386DGXHKTubU1XupGc1V3sjs0l44U+Vc +T4wt/lAjNvxm5suOpDkZALeVAjmRCw7+OC7RHQWa9k0+bw8HHa8sHo9gOeL6NlMTOdReJivbPagU +vTLrGAMoUgRx5aszPeE4uwc2hGKceeoWMPRfwCvocWvk+QIDAQABo1MwUTAPBgNVHRMBAf8EBTAD +AQH/MB0GA1UdDgQWBBTAephojYn7qwVkDBF9qn1luMrMTjAfBgNVHSMEGDAWgBTAephojYn7qwVk +DBF9qn1luMrMTjANBgkqhkiG9w0BAQUFAAOCAQEANeMpauUvXVSOKVCUn5kaFOSPeCpilKInZ57Q +zxpeR+nBsqTP3UEaBU6bS+5Kb1VSsyShNwrrZHYqLizz/Tt1kL/6cdjHPTfStQWVYrmm3ok9Nns4 +d0iXrKYgjy6myQzCsplFAMfOEVEiIuCl6rYVSAlk6l5PdPcFPseKUgzbFbS9bZvlxrFUaKnjaZC2 +mqUPuLk/IH2uSrW4nOQdtqvmlKXBx4Ot2/Unhw4EbNX/3aBd7YdStysVAq45pmp06drE57xNNB6p +XE0zX5IJL4hmXXeXxx12E6nV5fEWCRE11azbJHFwLJhWC9kXtNHjUStedejV0NxPNO3CBWaAocvm +Mw== +-----END CERTIFICATE----- + +GeoTrust Global CA 2 +==================== +-----BEGIN CERTIFICATE----- +MIIDZjCCAk6gAwIBAgIBATANBgkqhkiG9w0BAQUFADBEMQswCQYDVQQGEwJVUzEWMBQGA1UEChMN +R2VvVHJ1c3QgSW5jLjEdMBsGA1UEAxMUR2VvVHJ1c3QgR2xvYmFsIENBIDIwHhcNMDQwMzA0MDUw +MDAwWhcNMTkwMzA0MDUwMDAwWjBEMQswCQYDVQQGEwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5j +LjEdMBsGA1UEAxMUR2VvVHJ1c3QgR2xvYmFsIENBIDIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw +ggEKAoIBAQDvPE1APRDfO1MA4Wf+lGAVPoWI8YkNkMgoI5kF6CsgncbzYEbYwbLVjDHZ3CB5JIG/ +NTL8Y2nbsSpr7iFY8gjpeMtvy/wWUsiRxP89c96xPqfCfWbB9X5SJBri1WeR0IIQ13hLTytCOb1k +LUCgsBDTOEhGiKEMuzozKmKY+wCdE1l/bztyqu6mD4b5BWHqZ38MN5aL5mkWRxHCJ1kDs6ZgwiFA +Vvqgx306E+PsV8ez1q6diYD3Aecs9pYrEw15LNnA5IZ7S4wMcoKK+xfNAGw6EzywhIdLFnopsk/b +HdQL82Y3vdj2V7teJHq4PIu5+pIaGoSe2HSPqht/XvT+RSIhAgMBAAGjYzBhMA8GA1UdEwEB/wQF +MAMBAf8wHQYDVR0OBBYEFHE4NvICMVNHK266ZUapEBVYIAUJMB8GA1UdIwQYMBaAFHE4NvICMVNH +K266ZUapEBVYIAUJMA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQUFAAOCAQEAA/e1K6tdEPx7 +srJerJsOflN4WT5CBP51o62sgU7XAotexC3IUnbHLB/8gTKY0UvGkpMzNTEv/NgdRN3ggX+d6Yvh +ZJFiCzkIjKx0nVnZellSlxG5FntvRdOW2TF9AjYPnDtuzywNA0ZF66D0f0hExghAzN4bcLUprbqL +OzRldRtxIR0sFAqwlpW41uryZfspuk/qkZN0abby/+Ea0AzRdoXLiiW9l14sbxWZJue2Kf8i7MkC +x1YAzUm5s2x7UwQa4qjJqhIFI8LO57sEAszAR6LkxCkvW0VXiVHuPOtSCP8HNR6fNWpHSlaY0VqF +H4z1Ir+rzoPz4iIprn2DQKi6bA== +-----END CERTIFICATE----- + +GeoTrust Universal CA +===================== +-----BEGIN CERTIFICATE----- +MIIFaDCCA1CgAwIBAgIBATANBgkqhkiG9w0BAQUFADBFMQswCQYDVQQGEwJVUzEWMBQGA1UEChMN +R2VvVHJ1c3QgSW5jLjEeMBwGA1UEAxMVR2VvVHJ1c3QgVW5pdmVyc2FsIENBMB4XDTA0MDMwNDA1 +MDAwMFoXDTI5MDMwNDA1MDAwMFowRTELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUdlb1RydXN0IElu +Yy4xHjAcBgNVBAMTFUdlb1RydXN0IFVuaXZlcnNhbCBDQTCCAiIwDQYJKoZIhvcNAQEBBQADggIP +ADCCAgoCggIBAKYVVaCjxuAfjJ0hUNfBvitbtaSeodlyWL0AG0y/YckUHUWCq8YdgNY96xCcOq9t +JPi8cQGeBvV8Xx7BDlXKg5pZMK4ZyzBIle0iN430SppyZj6tlcDgFgDgEB8rMQ7XlFTTQjOgNB0e +RXbdT8oYN+yFFXoZCPzVx5zw8qkuEKmS5j1YPakWaDwvdSEYfyh3peFhF7em6fgemdtzbvQKoiFs +7tqqhZJmr/Z6a4LauiIINQ/PQvE1+mrufislzDoR5G2vc7J2Ha3QsnhnGqQ5HFELZ1aD/ThdDc7d +8Lsrlh/eezJS/R27tQahsiFepdaVaH/wmZ7cRQg+59IJDTWU3YBOU5fXtQlEIGQWFwMCTFMNaN7V +qnJNk22CDtucvc+081xdVHppCZbW2xHBjXWotM85yM48vCR85mLK4b19p71XZQvk/iXttmkQ3Cga +Rr0BHdCXteGYO8A3ZNY9lO4L4fUorgtWv3GLIylBjobFS1J72HGrH4oVpjuDWtdYAVHGTEHZf9hB +Z3KiKN9gg6meyHv8U3NyWfWTehd2Ds735VzZC1U0oqpbtWpU5xPKV+yXbfReBi9Fi1jUIxaS5BZu +KGNZMN9QAZxjiRqf2xeUgnA3wySemkfWWspOqGmJch+RbNt+nhutxx9z3SxPGWX9f5NAEC7S8O08 +ni4oPmkmM8V7AgMBAAGjYzBhMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFNq7LqqwDLiIJlF0 +XG0D08DYj3rWMB8GA1UdIwQYMBaAFNq7LqqwDLiIJlF0XG0D08DYj3rWMA4GA1UdDwEB/wQEAwIB +hjANBgkqhkiG9w0BAQUFAAOCAgEAMXjmx7XfuJRAyXHEqDXsRh3ChfMoWIawC/yOsjmPRFWrZIRc +aanQmjg8+uUfNeVE44B5lGiku8SfPeE0zTBGi1QrlaXv9z+ZhP015s8xxtxqv6fXIwjhmF7DWgh2 +qaavdy+3YL1ERmrvl/9zlcGO6JP7/TG37FcREUWbMPEaiDnBTzynANXH/KttgCJwpQzgXQQpAvvL +oJHRfNbDflDVnVi+QTjruXU8FdmbyUqDWcDaU/0zuzYYm4UPFd3uLax2k7nZAY1IEKj79TiG8dsK +xr2EoyNB3tZ3b4XUhRxQ4K5RirqNPnbiucon8l+f725ZDQbYKxek0nxru18UGkiPGkzns0ccjkxF +KyDuSN/n3QmOGKjaQI2SJhFTYXNd673nxE0pN2HrrDktZy4W1vUAg4WhzH92xH3kt0tm7wNFYGm2 +DFKWkoRepqO1pD4r2czYG0eq8kTaT/kD6PAUyz/zg97QwVTjt+gKN02LIFkDMBmhLMi9ER/frslK +xfMnZmaGrGiR/9nmUxwPi1xpZQomyB40w11Re9epnAahNt3ViZS82eQtDF4JbAiXfKM9fJP/P6EU +p8+1Xevb2xzEdt+Iub1FBZUbrvxGakyvSOPOrg/SfuvmbJxPgWp6ZKy7PtXny3YuxadIwVyQD8vI +P/rmMuGNG2+k5o7Y+SlIis5z/iw= +-----END CERTIFICATE----- + +GeoTrust Universal CA 2 +======================= +-----BEGIN CERTIFICATE----- +MIIFbDCCA1SgAwIBAgIBATANBgkqhkiG9w0BAQUFADBHMQswCQYDVQQGEwJVUzEWMBQGA1UEChMN +R2VvVHJ1c3QgSW5jLjEgMB4GA1UEAxMXR2VvVHJ1c3QgVW5pdmVyc2FsIENBIDIwHhcNMDQwMzA0 +MDUwMDAwWhcNMjkwMzA0MDUwMDAwWjBHMQswCQYDVQQGEwJVUzEWMBQGA1UEChMNR2VvVHJ1c3Qg +SW5jLjEgMB4GA1UEAxMXR2VvVHJ1c3QgVW5pdmVyc2FsIENBIDIwggIiMA0GCSqGSIb3DQEBAQUA +A4ICDwAwggIKAoICAQCzVFLByT7y2dyxUxpZKeexw0Uo5dfR7cXFS6GqdHtXr0om/Nj1XqduGdt0 +DE81WzILAePb63p3NeqqWuDW6KFXlPCQo3RWlEQwAx5cTiuFJnSCegx2oG9NzkEtoBUGFF+3Qs17 +j1hhNNwqCPkuwwGmIkQcTAeC5lvO0Ep8BNMZcyfwqph/Lq9O64ceJHdqXbboW0W63MOhBW9Wjo8Q +JqVJwy7XQYci4E+GymC16qFjwAGXEHm9ADwSbSsVsaxLse4YuU6W3Nx2/zu+z18DwPw76L5GG//a +QMJS9/7jOvdqdzXQ2o3rXhhqMcceujwbKNZrVMaqW9eiLBsZzKIC9ptZvTdrhrVtgrrY6slWvKk2 +WP0+GfPtDCapkzj4T8FdIgbQl+rhrcZV4IErKIM6+vR7IVEAvlI4zs1meaj0gVbi0IMJR1FbUGrP +20gaXT73y/Zl92zxlfgCOzJWgjl6W70viRu/obTo/3+NjN8D8WBOWBFM66M/ECuDmgFz2ZRthAAn +ZqzwcEAJQpKtT5MNYQlRJNiS1QuUYbKHsu3/mjX/hVTK7URDrBs8FmtISgocQIgfksILAAX/8sgC +SqSqqcyZlpwvWOB94b67B9xfBHJcMTTD7F8t4D1kkCLm0ey4Lt1ZrtmhN79UNdxzMk+MBB4zsslG +8dhcyFVQyWi9qLo2CQIDAQABo2MwYTAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBR281Xh+qQ2 ++/CfXGJx7Tz0RzgQKzAfBgNVHSMEGDAWgBR281Xh+qQ2+/CfXGJx7Tz0RzgQKzAOBgNVHQ8BAf8E +BAMCAYYwDQYJKoZIhvcNAQEFBQADggIBAGbBxiPz2eAubl/oz66wsCVNK/g7WJtAJDday6sWSf+z +dXkzoS9tcBc0kf5nfo/sm+VegqlVHy/c1FEHEv6sFj4sNcZj/NwQ6w2jqtB8zNHQL1EuxBRa3ugZ +4T7GzKQp5y6EqgYweHZUcyiYWTjgAA1i00J9IZ+uPTqM1fp3DRgrFg5fNuH8KrUwJM/gYwx7WBr+ +mbpCErGR9Hxo4sjoryzqyX6uuyo9DRXcNJW2GHSoag/HtPQTxORb7QrSpJdMKu0vbBKJPfEncKpq +A1Ihn0CoZ1Dy81of398j9tx4TuaYT1U6U+Pv8vSfx3zYWK8pIpe44L2RLrB27FcRz+8pRPPphXpg +Y+RdM4kX2TGq2tbzGDVyz4crL2MjhF2EjD9XoIj8mZEoJmmZ1I+XRL6O1UixpCgp8RW04eWe3fiP +pm8m1wk8OhwRDqZsN/etRIcsKMfYdIKz0G9KV7s1KSegi+ghp4dkNl3M2Basx7InQJJVOCiNUW7d +FGdTbHFcJoRNdVq2fmBWqU2t+5sel/MN2dKXVHfaPRK34B7vCAas+YWH6aLcr34YEoP9VhdBLtUp +gn2Z9DH2canPLAEnpQW5qrJITirvn5NSUZU8UnOOVkwXQMAJKOSLakhT2+zNVVXxxvjpoixMptEm +X36vWkzaH6byHCx+rgIW0lbQL1dTR+iS +-----END CERTIFICATE----- + +America Online Root Certification Authority 1 +============================================= +-----BEGIN CERTIFICATE----- +MIIDpDCCAoygAwIBAgIBATANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJVUzEcMBoGA1UEChMT +QW1lcmljYSBPbmxpbmUgSW5jLjE2MDQGA1UEAxMtQW1lcmljYSBPbmxpbmUgUm9vdCBDZXJ0aWZp +Y2F0aW9uIEF1dGhvcml0eSAxMB4XDTAyMDUyODA2MDAwMFoXDTM3MTExOTIwNDMwMFowYzELMAkG +A1UEBhMCVVMxHDAaBgNVBAoTE0FtZXJpY2EgT25saW5lIEluYy4xNjA0BgNVBAMTLUFtZXJpY2Eg +T25saW5lIFJvb3QgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgMTCCASIwDQYJKoZIhvcNAQEBBQAD +ggEPADCCAQoCggEBAKgv6KRpBgNHw+kqmP8ZonCaxlCyfqXfaE0bfA+2l2h9LaaLl+lkhsmj76CG +v2BlnEtUiMJIxUo5vxTjWVXlGbR0yLQFOVwWpeKVBeASrlmLojNoWBym1BW32J/X3HGrfpq/m44z +DyL9Hy7nBzbvYjnF3cu6JRQj3gzGPTzOggjmZj7aUTsWOqMFf6Dch9Wc/HKpoH145LcxVR5lu9Rh +sCFg7RAycsWSJR74kEoYeEfffjA3PlAb2xzTa5qGUwew76wGePiEmf4hjUyAtgyC9mZweRrTT6PP +8c9GsEsPPt2IYriMqQkoO3rHl+Ee5fSfwMCuJKDIodkP1nsmgmkyPacCAwEAAaNjMGEwDwYDVR0T +AQH/BAUwAwEB/zAdBgNVHQ4EFgQUAK3Zo/Z59m50qX8zPYEX10zPM94wHwYDVR0jBBgwFoAUAK3Z +o/Z59m50qX8zPYEX10zPM94wDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3DQEBBQUAA4IBAQB8itEf +GDeC4Liwo+1WlchiYZwFos3CYiZhzRAW18y0ZTTQEYqtqKkFZu90821fnZmv9ov761KyBZiibyrF +VL0lvV+uyIbqRizBs73B6UlwGBaXCBOMIOAbLjpHyx7kADCVW/RFo8AasAFOq73AI25jP4BKxQft +3OJvx8Fi8eNy1gTIdGcL+oiroQHIb/AUr9KZzVGTfu0uOMe9zkZQPXLjeSWdm4grECDdpbgyn43g +Kd8hdIaC2y+CMMbHNYaz+ZZfRtsMRf3zUMNvxsNIrUam4SdHCh0Om7bCd39j8uB9Gr784N/Xx6ds +sPmuujz9dLQR6FgNgLzTqIA6me11zEZ7 +-----END CERTIFICATE----- + +America Online Root Certification Authority 2 +============================================= +-----BEGIN CERTIFICATE----- +MIIFpDCCA4ygAwIBAgIBATANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJVUzEcMBoGA1UEChMT +QW1lcmljYSBPbmxpbmUgSW5jLjE2MDQGA1UEAxMtQW1lcmljYSBPbmxpbmUgUm9vdCBDZXJ0aWZp +Y2F0aW9uIEF1dGhvcml0eSAyMB4XDTAyMDUyODA2MDAwMFoXDTM3MDkyOTE0MDgwMFowYzELMAkG +A1UEBhMCVVMxHDAaBgNVBAoTE0FtZXJpY2EgT25saW5lIEluYy4xNjA0BgNVBAMTLUFtZXJpY2Eg +T25saW5lIFJvb3QgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgMjCCAiIwDQYJKoZIhvcNAQEBBQAD +ggIPADCCAgoCggIBAMxBRR3pPU0Q9oyxQcngXssNt79Hc9PwVU3dxgz6sWYFas14tNwC206B89en +fHG8dWOgXeMHDEjsJcQDIPT/DjsS/5uN4cbVG7RtIuOx238hZK+GvFciKtZHgVdEglZTvYYUAQv8 +f3SkWq7xuhG1m1hagLQ3eAkzfDJHA1zEpYNI9FdWboE2JxhP7JsowtS013wMPgwr38oE18aO6lhO +qKSlGBxsRZijQdEt0sdtjRnxrXm3gT+9BoInLRBYBbV4Bbkv2wxrkJB+FFk4u5QkE+XRnRTf04JN +RvCAOVIyD+OEsnpD8l7eXz8d3eOyG6ChKiMDbi4BFYdcpnV1x5dhvt6G3NRI270qv0pV2uh9UPu0 +gBe4lL8BPeraunzgWGcXuVjgiIZGZ2ydEEdYMtA1fHkqkKJaEBEjNa0vzORKW6fIJ/KD3l67Xnfn +6KVuY8INXWHQjNJsWiEOyiijzirplcdIz5ZvHZIlyMbGwcEMBawmxNJ10uEqZ8A9W6Wa6897Gqid +FEXlD6CaZd4vKL3Ob5Rmg0gp2OpljK+T2WSfVVcmv2/LNzGZo2C7HK2JNDJiuEMhBnIMoVxtRsX6 +Kc8w3onccVvdtjc+31D1uAclJuW8tf48ArO3+L5DwYcRlJ4jbBeKuIonDFRH8KmzwICMoCfrHRnj +B453cMor9H124HhnAgMBAAGjYzBhMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFE1FwWg4u3Op +aaEg5+31IqEjFNeeMB8GA1UdIwQYMBaAFE1FwWg4u3OpaaEg5+31IqEjFNeeMA4GA1UdDwEB/wQE +AwIBhjANBgkqhkiG9w0BAQUFAAOCAgEAZ2sGuV9FOypLM7PmG2tZTiLMubekJcmnxPBUlgtk87FY +T15R/LKXeydlwuXK5w0MJXti4/qftIe3RUavg6WXSIylvfEWK5t2LHo1YGwRgJfMqZJS5ivmae2p ++DYtLHe/YUjRYwu5W1LtGLBDQiKmsXeu3mnFzcccobGlHBD7GL4acN3Bkku+KVqdPzW+5X1R+FXg +JXUjhx5c3LqdsKyzadsXg8n33gy8CNyRnqjQ1xU3c6U1uPx+xURABsPr+CKAXEfOAuMRn0T//Zoy +zH1kUQ7rVyZ2OuMeIjzCpjbdGe+n/BLzJsBZMYVMnNjP36TMzCmT/5RtdlwTCJfy7aULTd3oyWgO +ZtMADjMSW7yV5TKQqLPGbIOtd+6Lfn6xqavT4fG2wLHqiMDn05DpKJKUe2h7lyoKZy2FAjgQ5ANh +1NolNscIWC2hp1GvMApJ9aZphwctREZ2jirlmjvXGKL8nDgQzMY70rUXOm/9riW99XJZZLF0Kjhf +GEzfz3EEWjbUvy+ZnOjZurGV5gJLIaFb1cFPj65pbVPbAZO1XB4Y3WRayhgoPmMEEf0cjQAPuDff +Z4qdZqkCapH/E8ovXYO8h5Ns3CRRFgQlZvqz2cK6Kb6aSDiCmfS/O0oxGfm/jiEzFMpPVF/7zvuP +cX/9XhmgD0uRuMRUvAawRY8mkaKO/qk= +-----END CERTIFICATE----- + +Visa eCommerce Root +=================== +-----BEGIN CERTIFICATE----- +MIIDojCCAoqgAwIBAgIQE4Y1TR0/BvLB+WUF1ZAcYjANBgkqhkiG9w0BAQUFADBrMQswCQYDVQQG +EwJVUzENMAsGA1UEChMEVklTQTEvMC0GA1UECxMmVmlzYSBJbnRlcm5hdGlvbmFsIFNlcnZpY2Ug +QXNzb2NpYXRpb24xHDAaBgNVBAMTE1Zpc2EgZUNvbW1lcmNlIFJvb3QwHhcNMDIwNjI2MDIxODM2 +WhcNMjIwNjI0MDAxNjEyWjBrMQswCQYDVQQGEwJVUzENMAsGA1UEChMEVklTQTEvMC0GA1UECxMm +VmlzYSBJbnRlcm5hdGlvbmFsIFNlcnZpY2UgQXNzb2NpYXRpb24xHDAaBgNVBAMTE1Zpc2EgZUNv +bW1lcmNlIFJvb3QwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCvV95WHm6h2mCxlCfL +F9sHP4CFT8icttD0b0/Pmdjh28JIXDqsOTPHH2qLJj0rNfVIsZHBAk4ElpF7sDPwsRROEW+1QK8b +RaVK7362rPKgH1g/EkZgPI2h4H3PVz4zHvtH8aoVlwdVZqW1LS7YgFmypw23RuwhY/81q6UCzyr0 +TP579ZRdhE2o8mCP2w4lPJ9zcc+U30rq299yOIzzlr3xF7zSujtFWsan9sYXiwGd/BmoKoMWuDpI +/k4+oKsGGelT84ATB+0tvz8KPFUgOSwsAGl0lUq8ILKpeeUYiZGo3BxN77t+Nwtd/jmliFKMAGzs +GHxBvfaLdXe6YJ2E5/4tAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEG +MB0GA1UdDgQWBBQVOIMPPyw/cDMezUb+B4wg4NfDtzANBgkqhkiG9w0BAQUFAAOCAQEAX/FBfXxc +CLkr4NWSR/pnXKUTwwMhmytMiUbPWU3J/qVAtmPN3XEolWcRzCSs00Rsca4BIGsDoo8Ytyk6feUW +YFN4PMCvFYP3j1IzJL1kk5fui/fbGKhtcbP3LBfQdCVp9/5rPJS+TUtBjE7ic9DjkCJzQ83z7+pz +zkWKsKZJ/0x9nXGIxHYdkFsd7v3M9+79YKWxehZx0RbQfBI8bGmX265fOZpwLwU8GUYEmSA20GBu +YQa7FkKMcPcw++DbZqMAAb3mLNqRX6BGi01qnD093QVG/na/oAo85ADmJ7f/hC3euiInlhBx6yLt +398znM/jra6O1I7mT1GvFpLgXPYHDw== +-----END CERTIFICATE----- + +Certum Root CA +============== +-----BEGIN CERTIFICATE----- +MIIDDDCCAfSgAwIBAgIDAQAgMA0GCSqGSIb3DQEBBQUAMD4xCzAJBgNVBAYTAlBMMRswGQYDVQQK +ExJVbml6ZXRvIFNwLiB6IG8uby4xEjAQBgNVBAMTCUNlcnR1bSBDQTAeFw0wMjA2MTExMDQ2Mzla +Fw0yNzA2MTExMDQ2MzlaMD4xCzAJBgNVBAYTAlBMMRswGQYDVQQKExJVbml6ZXRvIFNwLiB6IG8u +by4xEjAQBgNVBAMTCUNlcnR1bSBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAM6x +wS7TT3zNJc4YPk/EjG+AanPIW1H4m9LcuwBcsaD8dQPugfCI7iNS6eYVM42sLQnFdvkrOYCJ5JdL +kKWoePhzQ3ukYbDYWMzhbGZ+nPMJXlVjhNWo7/OxLjBos8Q82KxujZlakE403Daaj4GIULdtlkIJ +89eVgw1BS7Bqa/j8D35in2fE7SZfECYPCE/wpFcozo+47UX2bu4lXapuOb7kky/ZR6By6/qmW6/K +Uz/iDsaWVhFu9+lmqSbYf5VT7QqFiLpPKaVCjF62/IUgAKpoC6EahQGcxEZjgoi2IrHu/qpGWX7P +NSzVttpd90gzFFS269lvzs2I1qsb2pY7HVkCAwEAAaMTMBEwDwYDVR0TAQH/BAUwAwEB/zANBgkq +hkiG9w0BAQUFAAOCAQEAuI3O7+cUus/usESSbLQ5PqKEbq24IXfS1HeCh+YgQYHu4vgRt2PRFze+ +GXYkHAQaTOs9qmdvLdTN/mUxcMUbpgIKumB7bVjCmkn+YzILa+M6wKyrO7Do0wlRjBCDxjTgxSvg +GrZgFCdsMneMvLJymM/NzD+5yCRCFNZX/OYmQ6kd5YCQzgNUKD73P9P4Te1qCjqTE5s7FCMTY5w/ +0YcneeVMUeMBrYVdGjux1XMQpNPyvG5k9VpWkKjHDkx0Dy5xO/fIR/RpbxXyEV6DHpx8Uq79AtoS +qFlnGNu8cN2bsWntgM6JQEhqDjXKKWYVIZQs6GAqm4VKQPNriiTsBhYscw== +-----END CERTIFICATE----- + +Comodo AAA Services root +======================== +-----BEGIN CERTIFICATE----- +MIIEMjCCAxqgAwIBAgIBATANBgkqhkiG9w0BAQUFADB7MQswCQYDVQQGEwJHQjEbMBkGA1UECAwS +R3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHDAdTYWxmb3JkMRowGAYDVQQKDBFDb21vZG8gQ0Eg +TGltaXRlZDEhMB8GA1UEAwwYQUFBIENlcnRpZmljYXRlIFNlcnZpY2VzMB4XDTA0MDEwMTAwMDAw +MFoXDTI4MTIzMTIzNTk1OVowezELMAkGA1UEBhMCR0IxGzAZBgNVBAgMEkdyZWF0ZXIgTWFuY2hl +c3RlcjEQMA4GA1UEBwwHU2FsZm9yZDEaMBgGA1UECgwRQ29tb2RvIENBIExpbWl0ZWQxITAfBgNV +BAMMGEFBQSBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC +ggEBAL5AnfRu4ep2hxxNRUSOvkbIgwadwSr+GB+O5AL686tdUIoWMQuaBtDFcCLNSS1UY8y2bmhG +C1Pqy0wkwLxyTurxFa70VJoSCsN6sjNg4tqJVfMiWPPe3M/vg4aijJRPn2jymJBGhCfHdr/jzDUs +i14HZGWCwEiwqJH5YZ92IFCokcdmtet4YgNW8IoaE+oxox6gmf049vYnMlhvB/VruPsUK6+3qszW +Y19zjNoFmag4qMsXeDZRrOme9Hg6jc8P2ULimAyrL58OAd7vn5lJ8S3frHRNG5i1R8XlKdH5kBjH +Ypy+g8cmez6KJcfA3Z3mNWgQIJ2P2N7Sw4ScDV7oL8kCAwEAAaOBwDCBvTAdBgNVHQ4EFgQUoBEK +Iz6W8Qfs4q8p74Klf9AwpLQwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wewYDVR0f +BHQwcjA4oDagNIYyaHR0cDovL2NybC5jb21vZG9jYS5jb20vQUFBQ2VydGlmaWNhdGVTZXJ2aWNl +cy5jcmwwNqA0oDKGMGh0dHA6Ly9jcmwuY29tb2RvLm5ldC9BQUFDZXJ0aWZpY2F0ZVNlcnZpY2Vz +LmNybDANBgkqhkiG9w0BAQUFAAOCAQEACFb8AvCb6P+k+tZ7xkSAzk/ExfYAWMymtrwUSWgEdujm +7l3sAg9g1o1QGE8mTgHj5rCl7r+8dFRBv/38ErjHT1r0iWAFf2C3BUrz9vHCv8S5dIa2LX1rzNLz +Rt0vxuBqw8M0Ayx9lt1awg6nCpnBBYurDC/zXDrPbDdVCYfeU0BsWO/8tqtlbgT2G9w84FoVxp7Z +8VlIMCFlA2zs6SFz7JsDoeA3raAVGI/6ugLOpyypEBMs1OUIJqsil2D4kF501KKaU73yqWjgom7C +12yxow+ev+to51byrvLjKzg6CYG1a4XXvi3tPxq3smPi9WIsgtRqAEFQ8TmDn5XpNpaYbg== +-----END CERTIFICATE----- + +Comodo Secure Services root +=========================== +-----BEGIN CERTIFICATE----- +MIIEPzCCAyegAwIBAgIBATANBgkqhkiG9w0BAQUFADB+MQswCQYDVQQGEwJHQjEbMBkGA1UECAwS +R3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHDAdTYWxmb3JkMRowGAYDVQQKDBFDb21vZG8gQ0Eg +TGltaXRlZDEkMCIGA1UEAwwbU2VjdXJlIENlcnRpZmljYXRlIFNlcnZpY2VzMB4XDTA0MDEwMTAw +MDAwMFoXDTI4MTIzMTIzNTk1OVowfjELMAkGA1UEBhMCR0IxGzAZBgNVBAgMEkdyZWF0ZXIgTWFu +Y2hlc3RlcjEQMA4GA1UEBwwHU2FsZm9yZDEaMBgGA1UECgwRQ29tb2RvIENBIExpbWl0ZWQxJDAi +BgNVBAMMG1NlY3VyZSBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczCCASIwDQYJKoZIhvcNAQEBBQADggEP +ADCCAQoCggEBAMBxM4KK0HDrc4eCQNUd5MvJDkKQ+d40uaG6EfQlhfPMcm3ye5drswfxdySRXyWP +9nQ95IDC+DwN879A6vfIUtFyb+/Iq0G4bi4XKpVpDM3SHpR7LZQdqnXXs5jLrLxkU0C8j6ysNstc +rbvd4JQX7NFc0L/vpZXJkMWwrPsbQ996CF23uPJAGysnnlDOXmWCiIxe004MeuoIkbY2qitC++rC +oznl2yY4rYsK7hljxxwk3wN42ubqwUcaCwtGCd0C/N7Lh1/XMGNooa7cMqG6vv5Eq2i2pRcV/b3V +p6ea5EQz6YiO/O1R65NxTq0B50SOqy3LqP4BSUjwwN3HaNiS/j0CAwEAAaOBxzCBxDAdBgNVHQ4E +FgQUPNiTiMLAggnMAZkGkyDpnnAJY08wDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8w +gYEGA1UdHwR6MHgwO6A5oDeGNWh0dHA6Ly9jcmwuY29tb2RvY2EuY29tL1NlY3VyZUNlcnRpZmlj +YXRlU2VydmljZXMuY3JsMDmgN6A1hjNodHRwOi8vY3JsLmNvbW9kby5uZXQvU2VjdXJlQ2VydGlm +aWNhdGVTZXJ2aWNlcy5jcmwwDQYJKoZIhvcNAQEFBQADggEBAIcBbSMdflsXfcFhMs+P5/OKlFlm +4J4oqF7Tt/Q05qo5spcWxYJvMqTpjOev/e/C6LlLqqP05tqNZSH7uoDrJiiFGv45jN5bBAS0VPmj +Z55B+glSzAVIqMk/IQQezkhr/IXownuvf7fM+F86/TXGDe+X3EyrEeFryzHRbPtIgKvcnDe4IRRL +DXE97IMzbtFuMhbsmMcWi1mmNKsFVy2T96oTy9IT4rcuO81rUBcJaD61JlfutuC23bkpgHl9j6Pw +pCikFcSF9CfUa7/lXORlAnZUtOM3ZiTTGWHIUhDlizeauan5Hb/qmZJhlv8BzaFfDbxxvA6sCx1H +RR3B7Hzs/Sk= +-----END CERTIFICATE----- + +Comodo Trusted Services root +============================ +-----BEGIN CERTIFICATE----- +MIIEQzCCAyugAwIBAgIBATANBgkqhkiG9w0BAQUFADB/MQswCQYDVQQGEwJHQjEbMBkGA1UECAwS +R3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHDAdTYWxmb3JkMRowGAYDVQQKDBFDb21vZG8gQ0Eg +TGltaXRlZDElMCMGA1UEAwwcVHJ1c3RlZCBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczAeFw0wNDAxMDEw +MDAwMDBaFw0yODEyMzEyMzU5NTlaMH8xCzAJBgNVBAYTAkdCMRswGQYDVQQIDBJHcmVhdGVyIE1h +bmNoZXN0ZXIxEDAOBgNVBAcMB1NhbGZvcmQxGjAYBgNVBAoMEUNvbW9kbyBDQSBMaW1pdGVkMSUw +IwYDVQQDDBxUcnVzdGVkIENlcnRpZmljYXRlIFNlcnZpY2VzMIIBIjANBgkqhkiG9w0BAQEFAAOC +AQ8AMIIBCgKCAQEA33FvNlhTWvI2VFeAxHQIIO0Yfyod5jWaHiWsnOWWfnJSoBVC21ndZHoa0Lh7 +3TkVvFVIxO06AOoxEbrycXQaZ7jPM8yoMa+j49d/vzMtTGo87IvDktJTdyR0nAducPy9C1t2ul/y +/9c3S0pgePfw+spwtOpZqqPOSC+pw7ILfhdyFgymBwwbOM/JYrc/oJOlh0Hyt3BAd9i+FHzjqMB6 +juljatEPmsbS9Is6FARW1O24zG71++IsWL1/T2sr92AkWCTOJu80kTrV44HQsvAEAtdbtz6SrGsS +ivnkBbA7kUlcsutT6vifR4buv5XAwAaf0lteERv0xwQ1KdJVXOTt6wIDAQABo4HJMIHGMB0GA1Ud +DgQWBBTFe1i97doladL3WRaoszLAeydb9DAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB +/zCBgwYDVR0fBHwwejA8oDqgOIY2aHR0cDovL2NybC5jb21vZG9jYS5jb20vVHJ1c3RlZENlcnRp +ZmljYXRlU2VydmljZXMuY3JsMDqgOKA2hjRodHRwOi8vY3JsLmNvbW9kby5uZXQvVHJ1c3RlZENl +cnRpZmljYXRlU2VydmljZXMuY3JsMA0GCSqGSIb3DQEBBQUAA4IBAQDIk4E7ibSvuIQSTI3S8Ntw +uleGFTQQuS9/HrCoiWChisJ3DFBKmwCL2Iv0QeLQg4pKHBQGsKNoBXAxMKdTmw7pSqBYaWcOrp32 +pSxBvzwGa+RZzG0Q8ZZvH9/0BAKkn0U+yNj6NkZEUD+Cl5EfKNsYEYwq5GWDVxISjBc/lDb+XbDA +BHcTuPQV1T84zJQ6VdCsmPW6AF/ghhmBeC8owH7TzEIK9a5QoNE+xqFx7D+gIIxmOom0jtTYsU0l +R+4viMi14QVFwL4Ucd56/Y57fU0IlqUSc/AtyjcndBInTMu2l+nZrghtWjlA3QVHdWpaIbOjGM9O +9y5Xt5hwXsjEeLBi +-----END CERTIFICATE----- + +QuoVadis Root CA +================ +-----BEGIN CERTIFICATE----- +MIIF0DCCBLigAwIBAgIEOrZQizANBgkqhkiG9w0BAQUFADB/MQswCQYDVQQGEwJCTTEZMBcGA1UE +ChMQUXVvVmFkaXMgTGltaXRlZDElMCMGA1UECxMcUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0 +eTEuMCwGA1UEAxMlUXVvVmFkaXMgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wMTAz +MTkxODMzMzNaFw0yMTAzMTcxODMzMzNaMH8xCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRp +cyBMaW1pdGVkMSUwIwYDVQQLExxSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MS4wLAYDVQQD +EyVRdW9WYWRpcyBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIIBIjANBgkqhkiG9w0BAQEF +AAOCAQ8AMIIBCgKCAQEAv2G1lVO6V/z68mcLOhrfEYBklbTRvM16z/Ypli4kVEAkOPcahdxYTMuk +J0KX0J+DisPkBgNbAKVRHnAEdOLB1Dqr1607BxgFjv2DrOpm2RgbaIr1VxqYuvXtdj182d6UajtL +F8HVj71lODqV0D1VNk7feVcxKh7YWWVJWCCYfqtffp/p1k3sg3Spx2zY7ilKhSoGFPlU5tPaZQeL +YzcS19Dsw3sgQUSj7cugF+FxZc4dZjH3dgEZyH0DWLaVSR2mEiboxgx24ONmy+pdpibu5cxfvWen +AScOospUxbF6lR1xHkopigPcakXBpBlebzbNw6Kwt/5cOOJSvPhEQ+aQuwIDAQABo4ICUjCCAk4w +PQYIKwYBBQUHAQEEMTAvMC0GCCsGAQUFBzABhiFodHRwczovL29jc3AucXVvdmFkaXNvZmZzaG9y +ZS5jb20wDwYDVR0TAQH/BAUwAwEB/zCCARoGA1UdIASCAREwggENMIIBCQYJKwYBBAG+WAABMIH7 +MIHUBggrBgEFBQcCAjCBxxqBxFJlbGlhbmNlIG9uIHRoZSBRdW9WYWRpcyBSb290IENlcnRpZmlj +YXRlIGJ5IGFueSBwYXJ0eSBhc3N1bWVzIGFjY2VwdGFuY2Ugb2YgdGhlIHRoZW4gYXBwbGljYWJs +ZSBzdGFuZGFyZCB0ZXJtcyBhbmQgY29uZGl0aW9ucyBvZiB1c2UsIGNlcnRpZmljYXRpb24gcHJh +Y3RpY2VzLCBhbmQgdGhlIFF1b1ZhZGlzIENlcnRpZmljYXRlIFBvbGljeS4wIgYIKwYBBQUHAgEW +Fmh0dHA6Ly93d3cucXVvdmFkaXMuYm0wHQYDVR0OBBYEFItLbe3TKbkGGew5Oanwl4Rqy+/fMIGu +BgNVHSMEgaYwgaOAFItLbe3TKbkGGew5Oanwl4Rqy+/foYGEpIGBMH8xCzAJBgNVBAYTAkJNMRkw +FwYDVQQKExBRdW9WYWRpcyBMaW1pdGVkMSUwIwYDVQQLExxSb290IENlcnRpZmljYXRpb24gQXV0 +aG9yaXR5MS4wLAYDVQQDEyVRdW9WYWRpcyBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5ggQ6 +tlCLMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQUFAAOCAQEAitQUtf70mpKnGdSkfnIYj9lo +fFIk3WdvOXrEql494liwTXCYhGHoG+NpGA7O+0dQoE7/8CQfvbLO9Sf87C9TqnN7Az10buYWnuul +LsS/VidQK2K6vkscPFVcQR0kvoIgR13VRH56FmjffU1RcHhXHTMe/QKZnAzNCgVPx7uOpHX6Sm2x +gI4JVrmcGmD+XcHXetwReNDWXcG31a0ymQM6isxUJTkxgXsTIlG6Rmyhu576BGxJJnSP0nPrzDCi +5upZIof4l/UO/erMkqQWxFIY6iHOsfHmhIHluqmGKPJDWl0Snawe2ajlCmqnf6CHKc/yiU3U7MXi +5nrQNiOKSnQ2+Q== +-----END CERTIFICATE----- + +QuoVadis Root CA 2 +================== +-----BEGIN CERTIFICATE----- +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 +-----END CERTIFICATE----- + +QuoVadis Root CA 3 +================== +-----BEGIN CERTIFICATE----- +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 +-----END CERTIFICATE----- + +Security Communication Root CA +============================== +-----BEGIN CERTIFICATE----- +MIIDWjCCAkKgAwIBAgIBADANBgkqhkiG9w0BAQUFADBQMQswCQYDVQQGEwJKUDEYMBYGA1UEChMP +U0VDT00gVHJ1c3QubmV0MScwJQYDVQQLEx5TZWN1cml0eSBDb21tdW5pY2F0aW9uIFJvb3RDQTEw +HhcNMDMwOTMwMDQyMDQ5WhcNMjMwOTMwMDQyMDQ5WjBQMQswCQYDVQQGEwJKUDEYMBYGA1UEChMP +U0VDT00gVHJ1c3QubmV0MScwJQYDVQQLEx5TZWN1cml0eSBDb21tdW5pY2F0aW9uIFJvb3RDQTEw +ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCzs/5/022x7xZ8V6UMbXaKL0u/ZPtM7orw +8yl89f/uKuDp6bpbZCKamm8sOiZpUQWZJtzVHGpxxpp9Hp3dfGzGjGdnSj74cbAZJ6kJDKaVv0uM +DPpVmDvY6CKhS3E4eayXkmmziX7qIWgGmBSWh9JhNrxtJ1aeV+7AwFb9Ms+k2Y7CI9eNqPPYJayX +5HA49LY6tJ07lyZDo6G8SVlyTCMwhwFY9k6+HGhWZq/NQV3Is00qVUarH9oe4kA92819uZKAnDfd +DJZkndwi92SL32HeFZRSFaB9UslLqCHJxrHty8OVYNEP8Ktw+N/LTX7s1vqr2b1/VPKl6Xn62dZ2 +JChzAgMBAAGjPzA9MB0GA1UdDgQWBBSgc0mZaNyFW2XjmygvV5+9M7wHSDALBgNVHQ8EBAMCAQYw +DwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQUFAAOCAQEAaECpqLvkT115swW1F7NgE+vGkl3g +0dNq/vu+m22/xwVtWSDEHPC32oRYAmP6SBbvT6UL90qY8j+eG61Ha2POCEfrUj94nK9NrvjVT8+a +mCoQQTlSxN3Zmw7vkwGusi7KaEIkQmywszo+zenaSMQVy+n5Bw+SUEmK3TGXX8npN6o7WWWXlDLJ +s58+OmJYxUmtYg5xpTKqL8aJdkNAExNnPaJUJRDL8Try2frbSVa7pv6nQTXD4IhhyYjH3zYQIphZ +6rBK+1YWc26sTfcioU+tHXotRSflMMFe8toTyyVCUZVHA4xsIcx0Qu1T/zOLjw9XARYvz6buyXAi +FL39vmwLAw== +-----END CERTIFICATE----- + +Sonera Class 2 Root CA +====================== +-----BEGIN CERTIFICATE----- +MIIDIDCCAgigAwIBAgIBHTANBgkqhkiG9w0BAQUFADA5MQswCQYDVQQGEwJGSTEPMA0GA1UEChMG +U29uZXJhMRkwFwYDVQQDExBTb25lcmEgQ2xhc3MyIENBMB4XDTAxMDQwNjA3Mjk0MFoXDTIxMDQw +NjA3Mjk0MFowOTELMAkGA1UEBhMCRkkxDzANBgNVBAoTBlNvbmVyYTEZMBcGA1UEAxMQU29uZXJh +IENsYXNzMiBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJAXSjWdyvANlsdE+hY3 +/Ei9vX+ALTU74W+oZ6m/AxxNjG8yR9VBaKQTBME1DJqEQ/xcHf+Js+gXGM2RX/uJ4+q/Tl18GybT +dXnt5oTjV+WtKcT0OijnpXuENmmz/V52vaMtmdOQTiMofRhj8VQ7Jp12W5dCsv+u8E7s3TmVToMG +f+dJQMjFAbJUWmYdPfz56TwKnoG4cPABi+QjVHzIrviQHgCWctRUz2EjvOr7nQKV0ba5cTppCD8P +tOFCx4j1P5iop7oc4HFx71hXgVB6XGt0Rg6DA5jDjqhu8nYybieDwnPz3BjotJPqdURrBGAgcVeH +nfO+oJAjPYok4doh28MCAwEAAaMzMDEwDwYDVR0TAQH/BAUwAwEB/zARBgNVHQ4ECgQISqCqWITT +XjwwCwYDVR0PBAQDAgEGMA0GCSqGSIb3DQEBBQUAA4IBAQBazof5FnIVV0sd2ZvnoiYw7JNn39Yt +0jSv9zilzqsWuasvfDXLrNAPtEwr/IDva4yRXzZ299uzGxnq9LIR/WFxRL8oszodv7ND6J+/3DEI +cbCdjdY0RzKQxmUk96BKfARzjzlvF4xytb1LyHr4e4PDKE6cCepnP7JnBBvDFNr450kkkdAdavph +Oe9r5yF1BgfYErQhIHBCcYHaPJo2vqZbDWpsmh+Re/n570K6Tk6ezAyNlNzZRZxe7EJQY670XcSx +EtzKO6gunRRaBXW37Ndj4ro1tgQIkejanZz2ZrUYrAqmVCY0M9IbwdR/GjqOC6oybtv8TyWf2TLH +llpwrN9M +-----END CERTIFICATE----- + +Staat der Nederlanden Root CA +============================= +-----BEGIN CERTIFICATE----- +MIIDujCCAqKgAwIBAgIEAJiWijANBgkqhkiG9w0BAQUFADBVMQswCQYDVQQGEwJOTDEeMBwGA1UE +ChMVU3RhYXQgZGVyIE5lZGVybGFuZGVuMSYwJAYDVQQDEx1TdGFhdCBkZXIgTmVkZXJsYW5kZW4g +Um9vdCBDQTAeFw0wMjEyMTcwOTIzNDlaFw0xNTEyMTYwOTE1MzhaMFUxCzAJBgNVBAYTAk5MMR4w +HAYDVQQKExVTdGFhdCBkZXIgTmVkZXJsYW5kZW4xJjAkBgNVBAMTHVN0YWF0IGRlciBOZWRlcmxh +bmRlbiBSb290IENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAmNK1URF6gaYUmHFt +vsznExvWJw56s2oYHLZhWtVhCb/ekBPHZ+7d89rFDBKeNVU+LCeIQGv33N0iYfXCxw719tV2U02P +jLwYdjeFnejKScfST5gTCaI+Ioicf9byEGW07l8Y1Rfj+MX94p2i71MOhXeiD+EwR+4A5zN9RGca +C1Hoi6CeUJhoNFIfLm0B8mBF8jHrqTFoKbt6QZ7GGX+UtFE5A3+y3qcym7RHjm+0Sq7lr7HcsBth +vJly3uSJt3omXdozSVtSnA71iq3DuD3oBmrC1SoLbHuEvVYFy4ZlkuxEK7COudxwC0barbxjiDn6 +22r+I/q85Ej0ZytqERAhSQIDAQABo4GRMIGOMAwGA1UdEwQFMAMBAf8wTwYDVR0gBEgwRjBEBgRV +HSAAMDwwOgYIKwYBBQUHAgEWLmh0dHA6Ly93d3cucGtpb3ZlcmhlaWQubmwvcG9saWNpZXMvcm9v +dC1wb2xpY3kwDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBSofeu8Y6R0E3QA7Jbg0zTBLL9s+DAN +BgkqhkiG9w0BAQUFAAOCAQEABYSHVXQ2YcG70dTGFagTtJ+k/rvuFbQvBgwp8qiSpGEN/KtcCFtR +EytNwiphyPgJWPwtArI5fZlmgb9uXJVFIGzmeafR2Bwp/MIgJ1HI8XxdNGdphREwxgDS1/PTfLbw +MVcoEoJz6TMvplW0C5GUR5z6u3pCMuiufi3IvKwUv9kP2Vv8wfl6leF9fpb8cbDCTMjfRTTJzg3y +nGQI0DvDKcWy7ZAEwbEpkcUwb8GpcjPM/l0WFywRaed+/sWDCN+83CI6LiBpIzlWYGeQiy52OfsR +iJf2fL1LuCAWZwWN4jvBcj+UlTfHXbme2JOhF4//DGYVwSR8MnwDHTuhWEUykw== +-----END CERTIFICATE----- + +TDC Internet Root CA +==================== +-----BEGIN CERTIFICATE----- +MIIEKzCCAxOgAwIBAgIEOsylTDANBgkqhkiG9w0BAQUFADBDMQswCQYDVQQGEwJESzEVMBMGA1UE +ChMMVERDIEludGVybmV0MR0wGwYDVQQLExRUREMgSW50ZXJuZXQgUm9vdCBDQTAeFw0wMTA0MDUx +NjMzMTdaFw0yMTA0MDUxNzAzMTdaMEMxCzAJBgNVBAYTAkRLMRUwEwYDVQQKEwxUREMgSW50ZXJu +ZXQxHTAbBgNVBAsTFFREQyBJbnRlcm5ldCBSb290IENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A +MIIBCgKCAQEAxLhAvJHVYx/XmaCLDEAedLdInUaMArLgJF/wGROnN4NrXceO+YQwzho7+vvOi20j +xsNuZp+Jpd/gQlBn+h9sHvTQBda/ytZO5GhgbEaqHF1j4QeGDmUApy6mcca8uYGoOn0a0vnRrEvL +znWv3Hv6gXPU/Lq9QYjUdLP5Xjg6PEOo0pVOd20TDJ2PeAG3WiAfAzc14izbSysseLlJ28TQx5yc +5IogCSEWVmb/Bexb4/DPqyQkXsN/cHoSxNK1EKC2IeGNeGlVRGn1ypYcNIUXJXfi9i8nmHj9eQY6 +otZaQ8H/7AQ77hPv01ha/5Lr7K7a8jcDR0G2l8ktCkEiu7vmpwIDAQABo4IBJTCCASEwEQYJYIZI +AYb4QgEBBAQDAgAHMGUGA1UdHwReMFwwWqBYoFakVDBSMQswCQYDVQQGEwJESzEVMBMGA1UEChMM +VERDIEludGVybmV0MR0wGwYDVQQLExRUREMgSW50ZXJuZXQgUm9vdCBDQTENMAsGA1UEAxMEQ1JM +MTArBgNVHRAEJDAigA8yMDAxMDQwNTE2MzMxN1qBDzIwMjEwNDA1MTcwMzE3WjALBgNVHQ8EBAMC +AQYwHwYDVR0jBBgwFoAUbGQBx/2FbazI2p5QCIUItTxWqFAwHQYDVR0OBBYEFGxkAcf9hW2syNqe +UAiFCLU8VqhQMAwGA1UdEwQFMAMBAf8wHQYJKoZIhvZ9B0EABBAwDhsIVjUuMDo0LjADAgSQMA0G +CSqGSIb3DQEBBQUAA4IBAQBOQ8zR3R0QGwZ/t6T609lN+yOfI1Rb5osvBCiLtSdtiaHsmGnc540m +gwV5dOy0uaOXwTUA/RXaOYE6lTGQ3pfphqiZdwzlWqCE/xIWrG64jcN7ksKsLtB9KOy282A4aW8+ +2ARVPp7MVdK6/rtHBNcK2RYKNCn1WBPVT8+PVkuzHu7TmHnaCB4Mb7j4Fifvwm899qNLPg7kbWzb +O0ESm70NRyN/PErQr8Cv9u8btRXE64PECV90i9kR+8JWsTz4cMo0jUNAE4z9mQNUecYu6oah9jrU +Cbz0vGbMPVjQV0kK7iXiQe4T+Zs4NNEA9X7nlB38aQNiuJkFBT1reBK9sG9l +-----END CERTIFICATE----- + +UTN DATACorp SGC Root CA +======================== +-----BEGIN CERTIFICATE----- +MIIEXjCCA0agAwIBAgIQRL4Mi1AAIbQR0ypoBqmtaTANBgkqhkiG9w0BAQUFADCBkzELMAkGA1UE +BhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2UgQ2l0eTEeMBwGA1UEChMVVGhl +IFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExhodHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xGzAZ +BgNVBAMTElVUTiAtIERBVEFDb3JwIFNHQzAeFw05OTA2MjQxODU3MjFaFw0xOTA2MjQxOTA2MzBa +MIGTMQswCQYDVQQGEwJVUzELMAkGA1UECBMCVVQxFzAVBgNVBAcTDlNhbHQgTGFrZSBDaXR5MR4w +HAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxITAfBgNVBAsTGGh0dHA6Ly93d3cudXNlcnRy +dXN0LmNvbTEbMBkGA1UEAxMSVVROIC0gREFUQUNvcnAgU0dDMIIBIjANBgkqhkiG9w0BAQEFAAOC +AQ8AMIIBCgKCAQEA3+5YEKIrblXEjr8uRgnn4AgPLit6E5Qbvfa2gI5lBZMAHryv4g+OGQ0SR+ys +raP6LnD43m77VkIVni5c7yPeIbkFdicZD0/Ww5y0vpQZY/KmEQrrU0icvvIpOxboGqBMpsn0GFlo +wHDyUwDAXlCCpVZvNvlK4ESGoE1O1kduSUrLZ9emxAW5jh70/P/N5zbgnAVssjMiFdC04MwXwLLA +9P4yPykqlXvY8qdOD1R8oQ2AswkDwf9c3V6aPryuvEeKaq5xyh+xKrhfQgUL7EYw0XILyulWbfXv +33i+Ybqypa4ETLyorGkVl73v67SMvzX41MPRKA5cOp9wGDMgd8SirwIDAQABo4GrMIGoMAsGA1Ud +DwQEAwIBxjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRTMtGzz3/64PGgXYVOktKeRR20TzA9 +BgNVHR8ENjA0MDKgMKAuhixodHRwOi8vY3JsLnVzZXJ0cnVzdC5jb20vVVROLURBVEFDb3JwU0dD +LmNybDAqBgNVHSUEIzAhBggrBgEFBQcDAQYKKwYBBAGCNwoDAwYJYIZIAYb4QgQBMA0GCSqGSIb3 +DQEBBQUAA4IBAQAnNZcAiosovcYzMB4p/OL31ZjUQLtgyr+rFywJNn9Q+kHcrpY6CiM+iVnJowft +Gzet/Hy+UUla3joKVAgWRcKZsYfNjGjgaQPpxE6YsjuMFrMOoAyYUJuTqXAJyCyjj98C5OBxOvG0 +I3KgqgHf35g+FFCgMSa9KOlaMCZ1+XtgHI3zzVAmbQQnmt/VDUVHKWss5nbZqSl9Mt3JNjy9rjXx +EZ4du5A/EkdOjtd+D2JzHVImOBwYSf0wdJrE5SIv2MCN7ZF6TACPcn9d2t0bi0Vr591pl6jFVkwP +DPafepE39peC4N1xaf92P2BNPM/3mfnGV/TJVTl4uix5yaaIK/QI +-----END CERTIFICATE----- + +UTN USERFirst Hardware Root CA +============================== +-----BEGIN CERTIFICATE----- +MIIEdDCCA1ygAwIBAgIQRL4Mi1AAJLQR0zYq/mUK/TANBgkqhkiG9w0BAQUFADCBlzELMAkGA1UE +BhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2UgQ2l0eTEeMBwGA1UEChMVVGhl +IFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExhodHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xHzAd +BgNVBAMTFlVUTi1VU0VSRmlyc3QtSGFyZHdhcmUwHhcNOTkwNzA5MTgxMDQyWhcNMTkwNzA5MTgx +OTIyWjCBlzELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2UgQ2l0 +eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExhodHRwOi8vd3d3LnVz +ZXJ0cnVzdC5jb20xHzAdBgNVBAMTFlVUTi1VU0VSRmlyc3QtSGFyZHdhcmUwggEiMA0GCSqGSIb3 +DQEBAQUAA4IBDwAwggEKAoIBAQCx98M4P7Sof885glFn0G2f0v9Y8+efK+wNiVSZuTiZFvfgIXlI +wrthdBKWHTxqctU8EGc6Oe0rE81m65UJM6Rsl7HoxuzBdXmcRl6Nq9Bq/bkqVRcQVLMZ8Jr28bFd +tqdt++BxF2uiiPsA3/4aMXcMmgF6sTLjKwEHOG7DpV4jvEWbe1DByTCP2+UretNb+zNAHqDVmBe8 +i4fDidNdoI6yqqr2jmmIBsX6iSHzCJ1pLgkzmykNRg+MzEk0sGlRvfkGzWitZky8PqxhvQqIDsjf +Pe58BEydCl5rkdbux+0ojatNh4lz0G6k0B4WixThdkQDf2Os5M1JnMWS9KsyoUhbAgMBAAGjgbkw +gbYwCwYDVR0PBAQDAgHGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFKFyXyYbKJhDlV0HN9WF +lp1L0sNFMEQGA1UdHwQ9MDswOaA3oDWGM2h0dHA6Ly9jcmwudXNlcnRydXN0LmNvbS9VVE4tVVNF +UkZpcnN0LUhhcmR3YXJlLmNybDAxBgNVHSUEKjAoBggrBgEFBQcDAQYIKwYBBQUHAwUGCCsGAQUF +BwMGBggrBgEFBQcDBzANBgkqhkiG9w0BAQUFAAOCAQEARxkP3nTGmZev/K0oXnWO6y1n7k57K9cM +//bey1WiCuFMVGWTYGufEpytXoMs61quwOQt9ABjHbjAbPLPSbtNk28GpgoiskliCE7/yMgUsogW +XecB5BKV5UU0s4tpvc+0hY91UZ59Ojg6FEgSxvunOxqNDYJAB+gECJChicsZUN/KHAG8HQQZexB2 +lzvukJDKxA4fFm517zP4029bHpbj4HR3dHuKom4t3XbWOTCC8KucUvIqx69JXn7HaOWCgchqJ/kn +iCrVWFCVH/A7HFe7fRQ5YiuayZSSKqMiDP+JJn1fIytH1xUdqWqeUQ0qUZ6B+dQ7XnASfxAynB67 +nfhmqA== +-----END CERTIFICATE----- + +Camerfirma Chambers of Commerce Root +==================================== +-----BEGIN CERTIFICATE----- +MIIEvTCCA6WgAwIBAgIBADANBgkqhkiG9w0BAQUFADB/MQswCQYDVQQGEwJFVTEnMCUGA1UEChMe +QUMgQ2FtZXJmaXJtYSBTQSBDSUYgQTgyNzQzMjg3MSMwIQYDVQQLExpodHRwOi8vd3d3LmNoYW1i +ZXJzaWduLm9yZzEiMCAGA1UEAxMZQ2hhbWJlcnMgb2YgQ29tbWVyY2UgUm9vdDAeFw0wMzA5MzAx +NjEzNDNaFw0zNzA5MzAxNjEzNDRaMH8xCzAJBgNVBAYTAkVVMScwJQYDVQQKEx5BQyBDYW1lcmZp +cm1hIFNBIENJRiBBODI3NDMyODcxIzAhBgNVBAsTGmh0dHA6Ly93d3cuY2hhbWJlcnNpZ24ub3Jn +MSIwIAYDVQQDExlDaGFtYmVycyBvZiBDb21tZXJjZSBSb290MIIBIDANBgkqhkiG9w0BAQEFAAOC +AQ0AMIIBCAKCAQEAtzZV5aVdGDDg2olUkfzIx1L4L1DZ77F1c2VHfRtbunXF/KGIJPov7coISjlU +xFF6tdpg6jg8gbLL8bvZkSM/SAFwdakFKq0fcfPJVD0dBmpAPrMMhe5cG3nCYsS4No41XQEMIwRH +NaqbYE6gZj3LJgqcQKH0XZi/caulAGgq7YN6D6IUtdQis4CwPAxaUWktWBiP7Zme8a7ileb2R6jW +DA+wWFjbw2Y3npuRVDM30pQcakjJyfKl2qUMI/cjDpwyVV5xnIQFUZot/eZOKjRa3spAN2cMVCFV +d9oKDMyXroDclDZK9D7ONhMeU+SsTjoF7Nuucpw4i9A5O4kKPnf+dQIBA6OCAUQwggFAMBIGA1Ud +EwEB/wQIMAYBAf8CAQwwPAYDVR0fBDUwMzAxoC+gLYYraHR0cDovL2NybC5jaGFtYmVyc2lnbi5v +cmcvY2hhbWJlcnNyb290LmNybDAdBgNVHQ4EFgQU45T1sU3p26EpW1eLTXYGduHRooowDgYDVR0P +AQH/BAQDAgEGMBEGCWCGSAGG+EIBAQQEAwIABzAnBgNVHREEIDAegRxjaGFtYmVyc3Jvb3RAY2hh +bWJlcnNpZ24ub3JnMCcGA1UdEgQgMB6BHGNoYW1iZXJzcm9vdEBjaGFtYmVyc2lnbi5vcmcwWAYD +VR0gBFEwTzBNBgsrBgEEAYGHLgoDATA+MDwGCCsGAQUFBwIBFjBodHRwOi8vY3BzLmNoYW1iZXJz +aWduLm9yZy9jcHMvY2hhbWJlcnNyb290Lmh0bWwwDQYJKoZIhvcNAQEFBQADggEBAAxBl8IahsAi +fJ/7kPMa0QOx7xP5IV8EnNrJpY0nbJaHkb5BkAFyk+cefV/2icZdp0AJPaxJRUXcLo0waLIJuvvD +L8y6C98/d3tGfToSJI6WjzwFCm/SlCgdbQzALogi1djPHRPH8EjX1wWnz8dHnjs8NMiAT9QUu/wN +UPf6s+xCX6ndbcj0dc97wXImsQEcXCz9ek60AcUFV7nnPKoF2YjpB0ZBzu9Bga5Y34OirsrXdx/n +ADydb47kMgkdTXg0eDQ8lJsm7U9xxhl6vSAiSFr+S30Dt+dYvsYyTnQeaN2oaFuzPu5ifdmA6Ap1 +erfutGWaIZDgqtCYvDi1czyL+Nw= +-----END CERTIFICATE----- + +Camerfirma Global Chambersign Root +================================== +-----BEGIN CERTIFICATE----- +MIIExTCCA62gAwIBAgIBADANBgkqhkiG9w0BAQUFADB9MQswCQYDVQQGEwJFVTEnMCUGA1UEChMe +QUMgQ2FtZXJmaXJtYSBTQSBDSUYgQTgyNzQzMjg3MSMwIQYDVQQLExpodHRwOi8vd3d3LmNoYW1i +ZXJzaWduLm9yZzEgMB4GA1UEAxMXR2xvYmFsIENoYW1iZXJzaWduIFJvb3QwHhcNMDMwOTMwMTYx +NDE4WhcNMzcwOTMwMTYxNDE4WjB9MQswCQYDVQQGEwJFVTEnMCUGA1UEChMeQUMgQ2FtZXJmaXJt +YSBTQSBDSUYgQTgyNzQzMjg3MSMwIQYDVQQLExpodHRwOi8vd3d3LmNoYW1iZXJzaWduLm9yZzEg +MB4GA1UEAxMXR2xvYmFsIENoYW1iZXJzaWduIFJvb3QwggEgMA0GCSqGSIb3DQEBAQUAA4IBDQAw +ggEIAoIBAQCicKLQn0KuWxfH2H3PFIP8T8mhtxOviteePgQKkotgVvq0Mi+ITaFgCPS3CU6gSS9J +1tPfnZdan5QEcOw/Wdm3zGaLmFIoCQLfxS+EjXqXd7/sQJ0lcqu1PzKY+7e3/HKE5TWH+VX6ox8O +by4o3Wmg2UIQxvi1RMLQQ3/bvOSiPGpVeAp3qdjqGTK3L/5cPxvusZjsyq16aUXjlg9V9ubtdepl +6DJWk0aJqCWKZQbua795B9Dxt6/tLE2Su8CoX6dnfQTyFQhwrJLWfQTSM/tMtgsL+xrJxI0DqX5c +8lCrEqWhz0hQpe/SyBoT+rB/sYIcd2oPX9wLlY/vQ37mRQklAgEDo4IBUDCCAUwwEgYDVR0TAQH/ +BAgwBgEB/wIBDDA/BgNVHR8EODA2MDSgMqAwhi5odHRwOi8vY3JsLmNoYW1iZXJzaWduLm9yZy9j +aGFtYmVyc2lnbnJvb3QuY3JsMB0GA1UdDgQWBBRDnDafsJ4wTcbOX60Qq+UDpfqpFDAOBgNVHQ8B +Af8EBAMCAQYwEQYJYIZIAYb4QgEBBAQDAgAHMCoGA1UdEQQjMCGBH2NoYW1iZXJzaWducm9vdEBj +aGFtYmVyc2lnbi5vcmcwKgYDVR0SBCMwIYEfY2hhbWJlcnNpZ25yb290QGNoYW1iZXJzaWduLm9y +ZzBbBgNVHSAEVDBSMFAGCysGAQQBgYcuCgEBMEEwPwYIKwYBBQUHAgEWM2h0dHA6Ly9jcHMuY2hh +bWJlcnNpZ24ub3JnL2Nwcy9jaGFtYmVyc2lnbnJvb3QuaHRtbDANBgkqhkiG9w0BAQUFAAOCAQEA +PDtwkfkEVCeR4e3t/mh/YV3lQWVPMvEYBZRqHN4fcNs+ezICNLUMbKGKfKX0j//U2K0X1S0E0T9Y +gOKBWYi+wONGkyT+kL0mojAt6JcmVzWJdJYY9hXiryQZVgICsroPFOrGimbBhkVVi76SvpykBMdJ +PJ7oKXqJ1/6v/2j1pReQvayZzKWGVwlnRtvWFsJG8eSpUPWP0ZIV018+xgBJOm5YstHRJw0lyDL4 +IBHNfTIzSJRUTN3cecQwn+uOuFW114hcxWokPbLTBQNRxgfvzBRydD1ucs4YKIxKoHflCStFREes +t2d/AYoFWpO+ocH/+OcOZ6RHSXZddZAa9SaP8A== +-----END CERTIFICATE----- + +NetLock Notary (Class A) Root +============================= +-----BEGIN CERTIFICATE----- +MIIGfTCCBWWgAwIBAgICAQMwDQYJKoZIhvcNAQEEBQAwga8xCzAJBgNVBAYTAkhVMRAwDgYDVQQI +EwdIdW5nYXJ5MREwDwYDVQQHEwhCdWRhcGVzdDEnMCUGA1UEChMeTmV0TG9jayBIYWxvemF0Yml6 +dG9uc2FnaSBLZnQuMRowGAYDVQQLExFUYW51c2l0dmFueWtpYWRvazE2MDQGA1UEAxMtTmV0TG9j +ayBLb3pqZWd5em9pIChDbGFzcyBBKSBUYW51c2l0dmFueWtpYWRvMB4XDTk5MDIyNDIzMTQ0N1oX +DTE5MDIxOTIzMTQ0N1owga8xCzAJBgNVBAYTAkhVMRAwDgYDVQQIEwdIdW5nYXJ5MREwDwYDVQQH +EwhCdWRhcGVzdDEnMCUGA1UEChMeTmV0TG9jayBIYWxvemF0Yml6dG9uc2FnaSBLZnQuMRowGAYD +VQQLExFUYW51c2l0dmFueWtpYWRvazE2MDQGA1UEAxMtTmV0TG9jayBLb3pqZWd5em9pIChDbGFz +cyBBKSBUYW51c2l0dmFueWtpYWRvMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvHSM +D7tM9DceqQWC2ObhbHDqeLVu0ThEDaiDzl3S1tWBxdRL51uUcCbbO51qTGL3cfNk1mE7PetzozfZ +z+qMkjvN9wfcZnSX9EUi3fRc4L9t875lM+QVOr/bmJBVOMTtplVjC7B4BPTjbsE/jvxReB+SnoPC +/tmwqcm8WgD/qaiYdPv2LD4VOQ22BFWoDpggQrOxJa1+mm9dU7GrDPzr4PN6s6iz/0b2Y6LYOph7 +tqyF/7AlT3Rj5xMHpQqPBffAZG9+pyeAlt7ULoZgx2srXnN7F+eRP2QM2EsiNCubMvJIH5+hCoR6 +4sKtlz2O1cH5VqNQ6ca0+pii7pXmKgOM3wIDAQABo4ICnzCCApswDgYDVR0PAQH/BAQDAgAGMBIG +A1UdEwEB/wQIMAYBAf8CAQQwEQYJYIZIAYb4QgEBBAQDAgAHMIICYAYJYIZIAYb4QgENBIICURaC +Ak1GSUdZRUxFTSEgRXplbiB0YW51c2l0dmFueSBhIE5ldExvY2sgS2Z0LiBBbHRhbGFub3MgU3pv +bGdhbHRhdGFzaSBGZWx0ZXRlbGVpYmVuIGxlaXJ0IGVsamFyYXNvayBhbGFwamFuIGtlc3p1bHQu +IEEgaGl0ZWxlc2l0ZXMgZm9seWFtYXRhdCBhIE5ldExvY2sgS2Z0LiB0ZXJtZWtmZWxlbG9zc2Vn +LWJpenRvc2l0YXNhIHZlZGkuIEEgZGlnaXRhbGlzIGFsYWlyYXMgZWxmb2dhZGFzYW5hayBmZWx0 +ZXRlbGUgYXogZWxvaXJ0IGVsbGVub3J6ZXNpIGVsamFyYXMgbWVndGV0ZWxlLiBBeiBlbGphcmFz +IGxlaXJhc2EgbWVndGFsYWxoYXRvIGEgTmV0TG9jayBLZnQuIEludGVybmV0IGhvbmxhcGphbiBh +IGh0dHBzOi8vd3d3Lm5ldGxvY2submV0L2RvY3MgY2ltZW4gdmFneSBrZXJoZXRvIGF6IGVsbGVu +b3J6ZXNAbmV0bG9jay5uZXQgZS1tYWlsIGNpbWVuLiBJTVBPUlRBTlQhIFRoZSBpc3N1YW5jZSBh +bmQgdGhlIHVzZSBvZiB0aGlzIGNlcnRpZmljYXRlIGlzIHN1YmplY3QgdG8gdGhlIE5ldExvY2sg +Q1BTIGF2YWlsYWJsZSBhdCBodHRwczovL3d3dy5uZXRsb2NrLm5ldC9kb2NzIG9yIGJ5IGUtbWFp +bCBhdCBjcHNAbmV0bG9jay5uZXQuMA0GCSqGSIb3DQEBBAUAA4IBAQBIJEb3ulZv+sgoA0BO5TE5 +ayZrU3/b39/zcT0mwBQOxmd7I6gMc90Bu8bKbjc5VdXHjFYgDigKDtIqpLBJUsY4B/6+CgmM0ZjP +ytoUMaFP0jn8DxEsQ8Pdq5PHVT5HfBgaANzze9jyf1JsIPQLX2lS9O74silg6+NJMSEN1rUQQeJB +CWziGppWS3cC9qCbmieH6FUpccKQn0V4GuEVZD3QDtigdp+uxdAu6tYPVuxkf1qbFFgBJ34TUMdr +KuZoPL9coAob4Q566eKAw+np9v1sEZ7Q5SgnK1QyQhSCdeZK8CtmdWOMovsEPoMOmzbwGOQmIMOM +8CgHrTwXZoi1/baI +-----END CERTIFICATE----- + +NetLock Business (Class B) Root +=============================== +-----BEGIN CERTIFICATE----- +MIIFSzCCBLSgAwIBAgIBaTANBgkqhkiG9w0BAQQFADCBmTELMAkGA1UEBhMCSFUxETAPBgNVBAcT +CEJ1ZGFwZXN0MScwJQYDVQQKEx5OZXRMb2NrIEhhbG96YXRiaXp0b25zYWdpIEtmdC4xGjAYBgNV +BAsTEVRhbnVzaXR2YW55a2lhZG9rMTIwMAYDVQQDEylOZXRMb2NrIFV6bGV0aSAoQ2xhc3MgQikg +VGFudXNpdHZhbnlraWFkbzAeFw05OTAyMjUxNDEwMjJaFw0xOTAyMjAxNDEwMjJaMIGZMQswCQYD +VQQGEwJIVTERMA8GA1UEBxMIQnVkYXBlc3QxJzAlBgNVBAoTHk5ldExvY2sgSGFsb3phdGJpenRv +bnNhZ2kgS2Z0LjEaMBgGA1UECxMRVGFudXNpdHZhbnlraWFkb2sxMjAwBgNVBAMTKU5ldExvY2sg +VXpsZXRpIChDbGFzcyBCKSBUYW51c2l0dmFueWtpYWRvMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCB +iQKBgQCx6gTsIKAjwo84YM/HRrPVG/77uZmeBNwcf4xKgZjupNTKihe5In+DCnVMm8Bp2GQ5o+2S +o/1bXHQawEfKOml2mrriRBf8TKPV/riXiK+IA4kfpPIEPsgHC+b5sy96YhQJRhTKZPWLgLViqNhr +1nGTLbO/CVRY7QbrqHvcQ7GhaQIDAQABo4ICnzCCApswEgYDVR0TAQH/BAgwBgEB/wIBBDAOBgNV +HQ8BAf8EBAMCAAYwEQYJYIZIAYb4QgEBBAQDAgAHMIICYAYJYIZIAYb4QgENBIICURaCAk1GSUdZ +RUxFTSEgRXplbiB0YW51c2l0dmFueSBhIE5ldExvY2sgS2Z0LiBBbHRhbGFub3MgU3pvbGdhbHRh +dGFzaSBGZWx0ZXRlbGVpYmVuIGxlaXJ0IGVsamFyYXNvayBhbGFwamFuIGtlc3p1bHQuIEEgaGl0 +ZWxlc2l0ZXMgZm9seWFtYXRhdCBhIE5ldExvY2sgS2Z0LiB0ZXJtZWtmZWxlbG9zc2VnLWJpenRv +c2l0YXNhIHZlZGkuIEEgZGlnaXRhbGlzIGFsYWlyYXMgZWxmb2dhZGFzYW5hayBmZWx0ZXRlbGUg +YXogZWxvaXJ0IGVsbGVub3J6ZXNpIGVsamFyYXMgbWVndGV0ZWxlLiBBeiBlbGphcmFzIGxlaXJh +c2EgbWVndGFsYWxoYXRvIGEgTmV0TG9jayBLZnQuIEludGVybmV0IGhvbmxhcGphbiBhIGh0dHBz +Oi8vd3d3Lm5ldGxvY2submV0L2RvY3MgY2ltZW4gdmFneSBrZXJoZXRvIGF6IGVsbGVub3J6ZXNA +bmV0bG9jay5uZXQgZS1tYWlsIGNpbWVuLiBJTVBPUlRBTlQhIFRoZSBpc3N1YW5jZSBhbmQgdGhl +IHVzZSBvZiB0aGlzIGNlcnRpZmljYXRlIGlzIHN1YmplY3QgdG8gdGhlIE5ldExvY2sgQ1BTIGF2 +YWlsYWJsZSBhdCBodHRwczovL3d3dy5uZXRsb2NrLm5ldC9kb2NzIG9yIGJ5IGUtbWFpbCBhdCBj +cHNAbmV0bG9jay5uZXQuMA0GCSqGSIb3DQEBBAUAA4GBAATbrowXr/gOkDFOzT4JwG06sPgzTEdM +43WIEJessDgVkcYplswhwG08pXTP2IKlOcNl40JwuyKQ433bNXbhoLXan3BukxowOR0w2y7jfLKR +stE3Kfq51hdcR0/jHTjrn9V7lagonhVK0dHQKwCXoOKSNitjrFgBazMpUIaD8QFI +-----END CERTIFICATE----- + +NetLock Express (Class C) Root +============================== +-----BEGIN CERTIFICATE----- +MIIFTzCCBLigAwIBAgIBaDANBgkqhkiG9w0BAQQFADCBmzELMAkGA1UEBhMCSFUxETAPBgNVBAcT +CEJ1ZGFwZXN0MScwJQYDVQQKEx5OZXRMb2NrIEhhbG96YXRiaXp0b25zYWdpIEtmdC4xGjAYBgNV +BAsTEVRhbnVzaXR2YW55a2lhZG9rMTQwMgYDVQQDEytOZXRMb2NrIEV4cHJlc3N6IChDbGFzcyBD +KSBUYW51c2l0dmFueWtpYWRvMB4XDTk5MDIyNTE0MDgxMVoXDTE5MDIyMDE0MDgxMVowgZsxCzAJ +BgNVBAYTAkhVMREwDwYDVQQHEwhCdWRhcGVzdDEnMCUGA1UEChMeTmV0TG9jayBIYWxvemF0Yml6 +dG9uc2FnaSBLZnQuMRowGAYDVQQLExFUYW51c2l0dmFueWtpYWRvazE0MDIGA1UEAxMrTmV0TG9j +ayBFeHByZXNzeiAoQ2xhc3MgQykgVGFudXNpdHZhbnlraWFkbzCBnzANBgkqhkiG9w0BAQEFAAOB +jQAwgYkCgYEA6+ywbGGKIyWvYCDj2Z/8kwvbXY2wobNAOoLO/XXgeDIDhlqGlZHtU/qdQPzm6N3Z +W3oDvV3zOwzDUXmbrVWg6dADEK8KuhRC2VImESLH0iDMgqSaqf64gXadarfSNnU+sYYJ9m5tfk63 +euyucYT2BDMIJTLrdKwWRMbkQJMdf60CAwEAAaOCAp8wggKbMBIGA1UdEwEB/wQIMAYBAf8CAQQw +DgYDVR0PAQH/BAQDAgAGMBEGCWCGSAGG+EIBAQQEAwIABzCCAmAGCWCGSAGG+EIBDQSCAlEWggJN +RklHWUVMRU0hIEV6ZW4gdGFudXNpdHZhbnkgYSBOZXRMb2NrIEtmdC4gQWx0YWxhbm9zIFN6b2xn +YWx0YXRhc2kgRmVsdGV0ZWxlaWJlbiBsZWlydCBlbGphcmFzb2sgYWxhcGphbiBrZXN6dWx0LiBB +IGhpdGVsZXNpdGVzIGZvbHlhbWF0YXQgYSBOZXRMb2NrIEtmdC4gdGVybWVrZmVsZWxvc3NlZy1i +aXp0b3NpdGFzYSB2ZWRpLiBBIGRpZ2l0YWxpcyBhbGFpcmFzIGVsZm9nYWRhc2FuYWsgZmVsdGV0 +ZWxlIGF6IGVsb2lydCBlbGxlbm9yemVzaSBlbGphcmFzIG1lZ3RldGVsZS4gQXogZWxqYXJhcyBs +ZWlyYXNhIG1lZ3RhbGFsaGF0byBhIE5ldExvY2sgS2Z0LiBJbnRlcm5ldCBob25sYXBqYW4gYSBo +dHRwczovL3d3dy5uZXRsb2NrLm5ldC9kb2NzIGNpbWVuIHZhZ3kga2VyaGV0byBheiBlbGxlbm9y +emVzQG5ldGxvY2submV0IGUtbWFpbCBjaW1lbi4gSU1QT1JUQU5UISBUaGUgaXNzdWFuY2UgYW5k +IHRoZSB1c2Ugb2YgdGhpcyBjZXJ0aWZpY2F0ZSBpcyBzdWJqZWN0IHRvIHRoZSBOZXRMb2NrIENQ +UyBhdmFpbGFibGUgYXQgaHR0cHM6Ly93d3cubmV0bG9jay5uZXQvZG9jcyBvciBieSBlLW1haWwg +YXQgY3BzQG5ldGxvY2submV0LjANBgkqhkiG9w0BAQQFAAOBgQAQrX/XDDKACtiG8XmYta3UzbM2 +xJZIwVzNmtkFLp++UOv0JhQQLdRmF/iewSf98e3ke0ugbLWrmldwpu2gpO0u9f38vf5NNwgMvOOW +gyL1SRt/Syu0VMGAfJlOHdCM7tCs5ZL6dVb+ZKATj7i4Fp1hBWeAyNDYpQcCNJgEjTME1A== +-----END CERTIFICATE----- + +XRamp Global CA Root +==================== +-----BEGIN CERTIFICATE----- +MIIEMDCCAxigAwIBAgIQUJRs7Bjq1ZxN1ZfvdY+grTANBgkqhkiG9w0BAQUFADCBgjELMAkGA1UE +BhMCVVMxHjAcBgNVBAsTFXd3dy54cmFtcHNlY3VyaXR5LmNvbTEkMCIGA1UEChMbWFJhbXAgU2Vj +dXJpdHkgU2VydmljZXMgSW5jMS0wKwYDVQQDEyRYUmFtcCBHbG9iYWwgQ2VydGlmaWNhdGlvbiBB +dXRob3JpdHkwHhcNMDQxMTAxMTcxNDA0WhcNMzUwMTAxMDUzNzE5WjCBgjELMAkGA1UEBhMCVVMx +HjAcBgNVBAsTFXd3dy54cmFtcHNlY3VyaXR5LmNvbTEkMCIGA1UEChMbWFJhbXAgU2VjdXJpdHkg +U2VydmljZXMgSW5jMS0wKwYDVQQDEyRYUmFtcCBHbG9iYWwgQ2VydGlmaWNhdGlvbiBBdXRob3Jp +dHkwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCYJB69FbS638eMpSe2OAtp87ZOqCwu +IR1cRN8hXX4jdP5efrRKt6atH67gBhbim1vZZ3RrXYCPKZ2GG9mcDZhtdhAoWORlsH9KmHmf4MMx +foArtYzAQDsRhtDLooY2YKTVMIJt2W7QDxIEM5dfT2Fa8OT5kavnHTu86M/0ay00fOJIYRyO82FE +zG+gSqmUsE3a56k0enI4qEHMPJQRfevIpoy3hsvKMzvZPTeL+3o+hiznc9cKV6xkmxnr9A8ECIqs +AxcZZPRaJSKNNCyy9mgdEm3Tih4U2sSPpuIjhdV6Db1q4Ons7Be7QhtnqiXtRYMh/MHJfNViPvry +xS3T/dRlAgMBAAGjgZ8wgZwwEwYJKwYBBAGCNxQCBAYeBABDAEEwCwYDVR0PBAQDAgGGMA8GA1Ud +EwEB/wQFMAMBAf8wHQYDVR0OBBYEFMZPoj0GY4QJnM5i5ASsjVy16bYbMDYGA1UdHwQvMC0wK6Ap +oCeGJWh0dHA6Ly9jcmwueHJhbXBzZWN1cml0eS5jb20vWEdDQS5jcmwwEAYJKwYBBAGCNxUBBAMC +AQEwDQYJKoZIhvcNAQEFBQADggEBAJEVOQMBG2f7Shz5CmBbodpNl2L5JFMn14JkTpAuw0kbK5rc +/Kh4ZzXxHfARvbdI4xD2Dd8/0sm2qlWkSLoC295ZLhVbO50WfUfXN+pfTXYSNrsf16GBBEYgoyxt +qZ4Bfj8pzgCT3/3JknOJiWSe5yvkHJEs0rnOfc5vMZnT5r7SHpDwCRR5XCOrTdLaIR9NmXmd4c8n +nxCbHIgNsIpkQTG4DmyQJKSbXHGPurt+HBvbaoAPIbzp26a3QPSyi6mx5O+aGtA9aZnuqCij4Tyz +8LIRnM98QObd50N9otg6tamN8jSZxNQQ4Qb9CYQQO+7ETPTsJ3xCwnR8gooJybQDJbw= +-----END CERTIFICATE----- + +Go Daddy Class 2 CA +=================== +-----BEGIN CERTIFICATE----- +MIIEADCCAuigAwIBAgIBADANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJVUzEhMB8GA1UEChMY +VGhlIEdvIERhZGR5IEdyb3VwLCBJbmMuMTEwLwYDVQQLEyhHbyBEYWRkeSBDbGFzcyAyIENlcnRp +ZmljYXRpb24gQXV0aG9yaXR5MB4XDTA0MDYyOTE3MDYyMFoXDTM0MDYyOTE3MDYyMFowYzELMAkG +A1UEBhMCVVMxITAfBgNVBAoTGFRoZSBHbyBEYWRkeSBHcm91cCwgSW5jLjExMC8GA1UECxMoR28g +RGFkZHkgQ2xhc3MgMiBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCCASAwDQYJKoZIhvcNAQEBBQAD +ggENADCCAQgCggEBAN6d1+pXGEmhW+vXX0iG6r7d/+TvZxz0ZWizV3GgXne77ZtJ6XCAPVYYYwhv +2vLM0D9/AlQiVBDYsoHUwHU9S3/Hd8M+eKsaA7Ugay9qK7HFiH7Eux6wwdhFJ2+qN1j3hybX2C32 +qRe3H3I2TqYXP2WYktsqbl2i/ojgC95/5Y0V4evLOtXiEqITLdiOr18SPaAIBQi2XKVlOARFmR6j +YGB0xUGlcmIbYsUfb18aQr4CUWWoriMYavx4A6lNf4DD+qta/KFApMoZFv6yyO9ecw3ud72a9nmY +vLEHZ6IVDd2gWMZEewo+YihfukEHU1jPEX44dMX4/7VpkI+EdOqXG68CAQOjgcAwgb0wHQYDVR0O +BBYEFNLEsNKR1EwRcbNhyz2h/t2oatTjMIGNBgNVHSMEgYUwgYKAFNLEsNKR1EwRcbNhyz2h/t2o +atTjoWekZTBjMQswCQYDVQQGEwJVUzEhMB8GA1UEChMYVGhlIEdvIERhZGR5IEdyb3VwLCBJbmMu +MTEwLwYDVQQLEyhHbyBEYWRkeSBDbGFzcyAyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5ggEAMAwG +A1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBADJL87LKPpH8EsahB4yOd6AzBhRckB4Y9wim +PQoZ+YeAEW5p5JYXMP80kWNyOO7MHAGjHZQopDH2esRU1/blMVgDoszOYtuURXO1v0XJJLXVggKt +I3lpjbi2Tc7PTMozI+gciKqdi0FuFskg5YmezTvacPd+mSYgFFQlq25zheabIZ0KbIIOqPjCDPoQ +HmyW74cNxA9hi63ugyuV+I6ShHI56yDqg+2DzZduCLzrTia2cyvk0/ZM/iZx4mERdEr/VxqHD3VI +Ls9RaRegAhJhldXRQLIQTO7ErBBDpqWeCtWVYpoNz4iCxTIM5CufReYNnyicsbkqWletNw+vHX/b +vZ8= +-----END CERTIFICATE----- + +Starfield Class 2 CA +==================== +-----BEGIN CERTIFICATE----- +MIIEDzCCAvegAwIBAgIBADANBgkqhkiG9w0BAQUFADBoMQswCQYDVQQGEwJVUzElMCMGA1UEChMc +U3RhcmZpZWxkIFRlY2hub2xvZ2llcywgSW5jLjEyMDAGA1UECxMpU3RhcmZpZWxkIENsYXNzIDIg +Q2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDQwNjI5MTczOTE2WhcNMzQwNjI5MTczOTE2WjBo +MQswCQYDVQQGEwJVUzElMCMGA1UEChMcU3RhcmZpZWxkIFRlY2hub2xvZ2llcywgSW5jLjEyMDAG +A1UECxMpU3RhcmZpZWxkIENsYXNzIDIgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggEgMA0GCSqG +SIb3DQEBAQUAA4IBDQAwggEIAoIBAQC3Msj+6XGmBIWtDBFk385N78gDGIc/oav7PKaf8MOh2tTY +bitTkPskpD6E8J7oX+zlJ0T1KKY/e97gKvDIr1MvnsoFAZMej2YcOadN+lq2cwQlZut3f+dZxkqZ +JRRU6ybH838Z1TBwj6+wRir/resp7defqgSHo9T5iaU0X9tDkYI22WY8sbi5gv2cOj4QyDvvBmVm +epsZGD3/cVE8MC5fvj13c7JdBmzDI1aaK4UmkhynArPkPw2vCHmCuDY96pzTNbO8acr1zJ3o/WSN +F4Azbl5KXZnJHoe0nRrA1W4TNSNe35tfPe/W93bC6j67eA0cQmdrBNj41tpvi/JEoAGrAgEDo4HF +MIHCMB0GA1UdDgQWBBS/X7fRzt0fhvRbVazc1xDCDqmI5zCBkgYDVR0jBIGKMIGHgBS/X7fRzt0f +hvRbVazc1xDCDqmI56FspGowaDELMAkGA1UEBhMCVVMxJTAjBgNVBAoTHFN0YXJmaWVsZCBUZWNo +bm9sb2dpZXMsIEluYy4xMjAwBgNVBAsTKVN0YXJmaWVsZCBDbGFzcyAyIENlcnRpZmljYXRpb24g +QXV0aG9yaXR5ggEAMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAAWdP4id0ckaVaGs +afPzWdqbAYcaT1epoXkJKtv3L7IezMdeatiDh6GX70k1PncGQVhiv45YuApnP+yz3SFmH8lU+nLM +PUxA2IGvd56Deruix/U0F47ZEUD0/CwqTRV/p2JdLiXTAAsgGh1o+Re49L2L7ShZ3U0WixeDyLJl +xy16paq8U4Zt3VekyvggQQto8PT7dL5WXXp59fkdheMtlb71cZBDzI0fmgAKhynpVSJYACPq4xJD +KVtHCN2MQWplBqjlIapBtJUhlbl90TSrE9atvNziPTnNvT51cKEYWQPJIrSPnNVeKtelttQKbfi3 +QBFGmh95DmK/D5fs4C8fF5Q= +-----END CERTIFICATE----- + +StartCom Certification Authority +================================ +-----BEGIN CERTIFICATE----- +MIIHyTCCBbGgAwIBAgIBATANBgkqhkiG9w0BAQUFADB9MQswCQYDVQQGEwJJTDEWMBQGA1UEChMN +U3RhcnRDb20gTHRkLjErMCkGA1UECxMiU2VjdXJlIERpZ2l0YWwgQ2VydGlmaWNhdGUgU2lnbmlu +ZzEpMCcGA1UEAxMgU3RhcnRDb20gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDYwOTE3MTk0 +NjM2WhcNMzYwOTE3MTk0NjM2WjB9MQswCQYDVQQGEwJJTDEWMBQGA1UEChMNU3RhcnRDb20gTHRk +LjErMCkGA1UECxMiU2VjdXJlIERpZ2l0YWwgQ2VydGlmaWNhdGUgU2lnbmluZzEpMCcGA1UEAxMg +U3RhcnRDb20gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAw +ggIKAoICAQDBiNsJvGxGfHiflXu1M5DycmLWwTYgIiRezul38kMKogZkpMyONvg45iPwbm2xPN1y +o4UcodM9tDMr0y+v/uqwQVlntsQGfQqedIXWeUyAN3rfOQVSWff0G0ZDpNKFhdLDcfN1YjS6LIp/ +Ho/u7TTQEceWzVI9ujPW3U3eCztKS5/CJi/6tRYccjV3yjxd5srhJosaNnZcAdt0FCX+7bWgiA/d +eMotHweXMAEtcnn6RtYTKqi5pquDSR3l8u/d5AGOGAqPY1MWhWKpDhk6zLVmpsJrdAfkK+F2PrRt +2PZE4XNiHzvEvqBTViVsUQn3qqvKv3b9bZvzndu/PWa8DFaqr5hIlTpL36dYUNk4dalb6kMMAv+Z +6+hsTXBbKWWc3apdzK8BMewM69KN6Oqce+Zu9ydmDBpI125C4z/eIT574Q1w+2OqqGwaVLRcJXrJ +osmLFqa7LH4XXgVNWG4SHQHuEhANxjJ/GP/89PrNbpHoNkm+Gkhpi8KWTRoSsmkXwQqQ1vp5Iki/ +untp+HDH+no32NgN0nZPV/+Qt+OR0t3vwmC3Zzrd/qqc8NSLf3Iizsafl7b4r4qgEKjZ+xjGtrVc +UjyJthkqcwEKDwOzEmDyei+B26Nu/yYwl/WL3YlXtq09s68rxbd2AvCl1iuahhQqcvbjM4xdCUsT +37uMdBNSSwIDAQABo4ICUjCCAk4wDAYDVR0TBAUwAwEB/zALBgNVHQ8EBAMCAa4wHQYDVR0OBBYE +FE4L7xqkQFulF2mHMMo0aEPQQa7yMGQGA1UdHwRdMFswLKAqoCiGJmh0dHA6Ly9jZXJ0LnN0YXJ0 +Y29tLm9yZy9zZnNjYS1jcmwuY3JsMCugKaAnhiVodHRwOi8vY3JsLnN0YXJ0Y29tLm9yZy9zZnNj +YS1jcmwuY3JsMIIBXQYDVR0gBIIBVDCCAVAwggFMBgsrBgEEAYG1NwEBATCCATswLwYIKwYBBQUH +AgEWI2h0dHA6Ly9jZXJ0LnN0YXJ0Y29tLm9yZy9wb2xpY3kucGRmMDUGCCsGAQUFBwIBFilodHRw +Oi8vY2VydC5zdGFydGNvbS5vcmcvaW50ZXJtZWRpYXRlLnBkZjCB0AYIKwYBBQUHAgIwgcMwJxYg +U3RhcnQgQ29tbWVyY2lhbCAoU3RhcnRDb20pIEx0ZC4wAwIBARqBl0xpbWl0ZWQgTGlhYmlsaXR5 +LCByZWFkIHRoZSBzZWN0aW9uICpMZWdhbCBMaW1pdGF0aW9ucyogb2YgdGhlIFN0YXJ0Q29tIENl +cnRpZmljYXRpb24gQXV0aG9yaXR5IFBvbGljeSBhdmFpbGFibGUgYXQgaHR0cDovL2NlcnQuc3Rh +cnRjb20ub3JnL3BvbGljeS5wZGYwEQYJYIZIAYb4QgEBBAQDAgAHMDgGCWCGSAGG+EIBDQQrFilT +dGFydENvbSBGcmVlIFNTTCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTANBgkqhkiG9w0BAQUFAAOC +AgEAFmyZ9GYMNPXQhV59CuzaEE44HF7fpiUFS5Eyweg78T3dRAlbB0mKKctmArexmvclmAk8jhvh +3TaHK0u7aNM5Zj2gJsfyOZEdUauCe37Vzlrk4gNXcGmXCPleWKYK34wGmkUWFjgKXlf2Ysd6AgXm +vB618p70qSmD+LIU424oh0TDkBreOKk8rENNZEXO3SipXPJzewT4F+irsfMuXGRuczE6Eri8sxHk +fY+BUZo7jYn0TZNmezwD7dOaHZrzZVD1oNB1ny+v8OqCQ5j4aZyJecRDjkZy42Q2Eq/3JR44iZB3 +fsNrarnDy0RLrHiQi+fHLB5LEUTINFInzQpdn4XBidUaePKVEFMy3YCEZnXZtWgo+2EuvoSoOMCZ +EoalHmdkrQYuL6lwhceWD3yJZfWOQ1QOq92lgDmUYMA0yZZwLKMS9R9Ie70cfmu3nZD0Ijuu+Pwq +yvqCUqDvr0tVk+vBtfAii6w0TiYiBKGHLHVKt+V9E9e4DGTANtLJL4YSjCMJwRuCO3NJo2pXh5Tl +1njFmUNj403gdy3hZZlyaQQaRwnmDwFWJPsfvw55qVguucQJAX6Vum0ABj6y6koQOdjQK/W/7HW/ +lwLFCRsI3FU34oH7N4RDYiDK51ZLZer+bMEkkyShNOsF/5oirpt9P/FlUQqmMGqz9IgcgA38coro +g14= +-----END CERTIFICATE----- + +Taiwan GRCA +=========== +-----BEGIN CERTIFICATE----- +MIIFcjCCA1qgAwIBAgIQH51ZWtcvwgZEpYAIaeNe9jANBgkqhkiG9w0BAQUFADA/MQswCQYDVQQG +EwJUVzEwMC4GA1UECgwnR292ZXJubWVudCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4X +DTAyMTIwNTEzMjMzM1oXDTMyMTIwNTEzMjMzM1owPzELMAkGA1UEBhMCVFcxMDAuBgNVBAoMJ0dv +dmVybm1lbnQgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCCAiIwDQYJKoZIhvcNAQEBBQAD +ggIPADCCAgoCggIBAJoluOzMonWoe/fOW1mKydGGEghU7Jzy50b2iPN86aXfTEc2pBsBHH8eV4qN +w8XRIePaJD9IK/ufLqGU5ywck9G/GwGHU5nOp/UKIXZ3/6m3xnOUT0b3EEk3+qhZSV1qgQdW8or5 +BtD3cCJNtLdBuTK4sfCxw5w/cP1T3YGq2GN49thTbqGsaoQkclSGxtKyyhwOeYHWtXBiCAEuTk8O +1RGvqa/lmr/czIdtJuTJV6L7lvnM4T9TjGxMfptTCAtsF/tnyMKtsc2AtJfcdgEWFelq16TheEfO +htX7MfP6Mb40qij7cEwdScevLJ1tZqa2jWR+tSBqnTuBto9AAGdLiYa4zGX+FVPpBMHWXx1E1wov +J5pGfaENda1UhhXcSTvxls4Pm6Dso3pdvtUqdULle96ltqqvKKyskKw4t9VoNSZ63Pc78/1Fm9G7 +Q3hub/FCVGqY8A2tl+lSXunVanLeavcbYBT0peS2cWeqH+riTcFCQP5nRhc4L0c/cZyu5SHKYS1t +B6iEfC3uUSXxY5Ce/eFXiGvviiNtsea9P63RPZYLhY3Naye7twWb7LuRqQoHEgKXTiCQ8P8NHuJB +O9NAOueNXdpm5AKwB1KYXA6OM5zCppX7VRluTI6uSw+9wThNXo+EHWbNxWCWtFJaBYmOlXqYwZE8 +lSOyDvR5tMl8wUohAgMBAAGjajBoMB0GA1UdDgQWBBTMzO/MKWCkO7GStjz6MmKPrCUVOzAMBgNV +HRMEBTADAQH/MDkGBGcqBwAEMTAvMC0CAQAwCQYFKw4DAhoFADAHBgVnKgMAAAQUA5vwIhP/lSg2 +09yewDL7MTqKUWUwDQYJKoZIhvcNAQEFBQADggIBAECASvomyc5eMN1PhnR2WPWus4MzeKR6dBcZ +TulStbngCnRiqmjKeKBMmo4sIy7VahIkv9Ro04rQ2JyftB8M3jh+Vzj8jeJPXgyfqzvS/3WXy6Tj +Zwj/5cAWtUgBfen5Cv8b5Wppv3ghqMKnI6mGq3ZW6A4M9hPdKmaKZEk9GhiHkASfQlK3T8v+R0F2 +Ne//AHY2RTKbxkaFXeIksB7jSJaYV0eUVXoPQbFEJPPB/hprv4j9wabak2BegUqZIJxIZhm1AHlU +D7gsL0u8qV1bYH+Mh6XgUmMqvtg7hUAV/h62ZT/FS9p+tXo1KaMuephgIqP0fSdOLeq0dDzpD6Qz +DxARvBMB1uUO07+1EqLhRSPAzAhuYbeJq4PjJB7mXQfnHyA+z2fI56wwbSdLaG5LKlwCCDTb+Hbk +Z6MmnD+iMsJKxYEYMRBWqoTvLQr/uB930r+lWKBi5NdLkXWNiYCYfm3LU05er/ayl4WXudpVBrkk +7tfGOB5jGxI7leFYrPLfhNVfmS8NVVvmONsuP3LpSIXLuykTjx44VbnzssQwmSNOXfJIoRIM3BKQ +CZBUkQM8R+XVyWXgt0t97EfTsws+rZ7QdAAO671RrcDeLMDDav7v3Aun+kbfYNucpllQdSNpc5Oy ++fwC00fmcc4QAu4njIT/rEUNE1yDMuAlpYYsfPQS +-----END CERTIFICATE----- + +Swisscom Root CA 1 +================== +-----BEGIN CERTIFICATE----- +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 +NY6E0F/6MBr1mmz0DlP5OlvRHA== +-----END CERTIFICATE----- + +DigiCert Assured ID Root CA +=========================== +-----BEGIN CERTIFICATE----- +MIIDtzCCAp+gAwIBAgIQDOfg5RfYRv6P5WD8G/AwOTANBgkqhkiG9w0BAQUFADBlMQswCQYDVQQG +EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSQw +IgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgQ0EwHhcNMDYxMTEwMDAwMDAwWhcNMzEx +MTEwMDAwMDAwWjBlMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQL +ExB3d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgQ0Ew +ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCtDhXO5EOAXLGH87dg+XESpa7cJpSIqvTO +9SA5KFhgDPiA2qkVlTJhPLWxKISKityfCgyDF3qPkKyK53lTXDGEKvYPmDI2dsze3Tyoou9q+yHy +UmHfnyDXH+Kx2f4YZNISW1/5WBg1vEfNoTb5a3/UsDg+wRvDjDPZ2C8Y/igPs6eD1sNuRMBhNZYW +/lmci3Zt1/GiSw0r/wty2p5g0I6QNcZ4VYcgoc/lbQrISXwxmDNsIumH0DJaoroTghHtORedmTpy +oeb6pNnVFzF1roV9Iq4/AUaG9ih5yLHa5FcXxH4cDrC0kqZWs72yl+2qp/C3xag/lRbQ/6GW6whf +GHdPAgMBAAGjYzBhMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRF +66Kv9JLLgjEtUYunpyGd823IDzAfBgNVHSMEGDAWgBRF66Kv9JLLgjEtUYunpyGd823IDzANBgkq +hkiG9w0BAQUFAAOCAQEAog683+Lt8ONyc3pklL/3cmbYMuRCdWKuh+vy1dneVrOfzM4UKLkNl2Bc +EkxY5NM9g0lFWJc1aRqoR+pWxnmrEthngYTffwk8lOa4JiwgvT2zKIn3X/8i4peEH+ll74fg38Fn +SbNd67IJKusm7Xi+fT8r87cmNW1fiQG2SVufAQWbqz0lwcy2f8Lxb4bG+mRo64EtlOtCt/qMHt1i +8b5QZ7dsvfPxH2sMNgcWfzd8qVttevESRmCD1ycEvkvOl77DZypoEd+A5wwzZr8TDRRu838fYxAe ++o0bJW1sj6W3YQGx0qMmoRBxna3iw/nDmVG3KwcIzi7mULKn+gpFL6Lw8g== +-----END CERTIFICATE----- + +DigiCert Global Root CA +======================= +-----BEGIN CERTIFICATE----- +MIIDrzCCApegAwIBAgIQCDvgVpBCRrGhdWrJWZHHSjANBgkqhkiG9w0BAQUFADBhMQswCQYDVQQG +EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSAw +HgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBDQTAeFw0wNjExMTAwMDAwMDBaFw0zMTExMTAw +MDAwMDBaMGExCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3 +dy5kaWdpY2VydC5jb20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IENBMIIBIjANBgkq +hkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4jvhEXLeqKTTo1eqUKKPC3eQyaKl7hLOllsBCSDMAZOn +TjC3U/dDxGkAV53ijSLdhwZAAIEJzs4bg7/fzTtxRuLWZscFs3YnFo97nh6Vfe63SKMI2tavegw5 +BmV/Sl0fvBf4q77uKNd0f3p4mVmFaG5cIzJLv07A6Fpt43C/dxC//AH2hdmoRBBYMql1GNXRor5H +4idq9Joz+EkIYIvUX7Q6hL+hqkpMfT7PT19sdl6gSzeRntwi5m3OFBqOasv+zbMUZBfHWymeMr/y +7vrTC0LUq7dBMtoM1O/4gdW7jVg/tRvoSSiicNoxBN33shbyTApOB6jtSj1etX+jkMOvJwIDAQAB +o2MwYTAOBgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUA95QNVbRTLtm +8KPiGxvDl7I90VUwHwYDVR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUwDQYJKoZIhvcNAQEF +BQADggEBAMucN6pIExIK+t1EnE9SsPTfrgT1eXkIoyQY/EsrhMAtudXH/vTBH1jLuG2cenTnmCmr +EbXjcKChzUyImZOMkXDiqw8cvpOp/2PV5Adg06O/nVsJ8dWO41P0jmP6P6fbtGbfYmbW0W5BjfIt +tep3Sp+dWOIrWcBAI+0tKIJFPnlUkiaY4IBIqDfv8NZ5YBberOgOzW6sRBc4L0na4UU+Krk2U886 +UAb3LujEV0lsYSEY1QSteDwsOoBrp+uvFRTp2InBuThs4pFsiv9kuXclVzDAGySj4dzp30d8tbQk +CAUw7C29C79Fv1C5qfPrmAESrciIxpg0X40KPMbp1ZWVbd4= +-----END CERTIFICATE----- + +DigiCert High Assurance EV Root CA +================================== +-----BEGIN CERTIFICATE----- +MIIDxTCCAq2gAwIBAgIQAqxcJmoLQJuPC3nyrkYldzANBgkqhkiG9w0BAQUFADBsMQswCQYDVQQG +EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSsw +KQYDVQQDEyJEaWdpQ2VydCBIaWdoIEFzc3VyYW5jZSBFViBSb290IENBMB4XDTA2MTExMDAwMDAw +MFoXDTMxMTExMDAwMDAwMFowbDELMAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZ +MBcGA1UECxMQd3d3LmRpZ2ljZXJ0LmNvbTErMCkGA1UEAxMiRGlnaUNlcnQgSGlnaCBBc3N1cmFu +Y2UgRVYgUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMbM5XPm+9S75S0t +Mqbf5YE/yc0lSbZxKsPVlDRnogocsF9ppkCxxLeyj9CYpKlBWTrT3JTWPNt0OKRKzE0lgvdKpVMS +OO7zSW1xkX5jtqumX8OkhPhPYlG++MXs2ziS4wblCJEMxChBVfvLWokVfnHoNb9Ncgk9vjo4UFt3 +MRuNs8ckRZqnrG0AFFoEt7oT61EKmEFBIk5lYYeBQVCmeVyJ3hlKV9Uu5l0cUyx+mM0aBhakaHPQ +NAQTXKFx01p8VdteZOE3hzBWBOURtCmAEvF5OYiiAhF8J2a3iLd48soKqDirCmTCv2ZdlYTBoSUe +h10aUAsgEsxBu24LUTi4S8sCAwEAAaNjMGEwDgYDVR0PAQH/BAQDAgGGMA8GA1UdEwEB/wQFMAMB +Af8wHQYDVR0OBBYEFLE+w2kD+L9HAdSYJhoIAu9jZCvDMB8GA1UdIwQYMBaAFLE+w2kD+L9HAdSY +JhoIAu9jZCvDMA0GCSqGSIb3DQEBBQUAA4IBAQAcGgaX3NecnzyIZgYIVyHbIUf4KmeqvxgydkAQ +V8GK83rZEWWONfqe/EW1ntlMMUu4kehDLI6zeM7b41N5cdblIZQB2lWHmiRk9opmzN6cN82oNLFp +myPInngiK3BD41VHMWEZ71jFhS9OMPagMRYjyOfiZRYzy78aG6A9+MpeizGLYAiJLQwGXFK3xPkK +mNEVX58Svnw2Yzi9RKR/5CYrCsSXaQ3pjOLAEFe4yHYSkVXySGnYvCoCWw9E1CAx2/S6cCZdkGCe +vEsXCS+0yx5DaMkHJ8HSXPfqIbloEpw8nL+e/IBcm2PN7EeqJSdnoDfzAIJ9VNep+OkuE6N36B9K +-----END CERTIFICATE----- + +Certplus Class 2 Primary CA +=========================== +-----BEGIN CERTIFICATE----- +MIIDkjCCAnqgAwIBAgIRAIW9S/PY2uNp9pTXX8OlRCMwDQYJKoZIhvcNAQEFBQAwPTELMAkGA1UE +BhMCRlIxETAPBgNVBAoTCENlcnRwbHVzMRswGQYDVQQDExJDbGFzcyAyIFByaW1hcnkgQ0EwHhcN +OTkwNzA3MTcwNTAwWhcNMTkwNzA2MjM1OTU5WjA9MQswCQYDVQQGEwJGUjERMA8GA1UEChMIQ2Vy +dHBsdXMxGzAZBgNVBAMTEkNsYXNzIDIgUHJpbWFyeSBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEP +ADCCAQoCggEBANxQltAS+DXSCHh6tlJw/W/uz7kRy1134ezpfgSN1sxvc0NXYKwzCkTsA18cgCSR +5aiRVhKC9+Ar9NuuYS6JEI1rbLqzAr3VNsVINyPi8Fo3UjMXEuLRYE2+L0ER4/YXJQyLkcAbmXuZ +Vg2v7tK8R1fjeUl7NIknJITesezpWE7+Tt9avkGtrAjFGA7v0lPubNCdEgETjdyAYveVqUSISnFO +YFWe2yMZeVYHDD9jC1yw4r5+FfyUM1hBOHTE4Y+L3yasH7WLO7dDWWuwJKZtkIvEcupdM5i3y95e +e++U8Rs+yskhwcWYAqqi9lt3m/V+llU0HGdpwPFC40es/CgcZlUCAwEAAaOBjDCBiTAPBgNVHRME +CDAGAQH/AgEKMAsGA1UdDwQEAwIBBjAdBgNVHQ4EFgQU43Mt38sOKAze3bOkynm4jrvoMIkwEQYJ +YIZIAYb4QgEBBAQDAgEGMDcGA1UdHwQwMC4wLKAqoCiGJmh0dHA6Ly93d3cuY2VydHBsdXMuY29t +L0NSTC9jbGFzczIuY3JsMA0GCSqGSIb3DQEBBQUAA4IBAQCnVM+IRBnL39R/AN9WM2K191EBkOvD +P9GIROkkXe/nFL0gt5o8AP5tn9uQ3Nf0YtaLcF3n5QRIqWh8yfFC82x/xXp8HVGIutIKPidd3i1R +TtMTZGnkLuPT55sJmabglZvOGtd/vjzOUrMRFcEPF80Du5wlFbqidon8BvEY0JNLDnyCt6X09l/+ +7UCmnYR0ObncHoUW2ikbhiMAybuJfm6AiB4vFLQDJKgybwOaRywwvlbGp0ICcBvqQNi6BQNwB6SW +//1IMwrh3KWBkJtN3X3n57LNXMhqlfil9o3EXXgIvnsG1knPGTZQIy4I5p4FTUcY1Rbpsda2ENW7 +l7+ijrRU +-----END CERTIFICATE----- + +DST Root CA X3 +============== +-----BEGIN CERTIFICATE----- +MIIDSjCCAjKgAwIBAgIQRK+wgNajJ7qJMDmGLvhAazANBgkqhkiG9w0BAQUFADA/MSQwIgYDVQQK +ExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMTDkRTVCBSb290IENBIFgzMB4X +DTAwMDkzMDIxMTIxOVoXDTIxMDkzMDE0MDExNVowPzEkMCIGA1UEChMbRGlnaXRhbCBTaWduYXR1 +cmUgVHJ1c3QgQ28uMRcwFQYDVQQDEw5EU1QgUm9vdCBDQSBYMzCCASIwDQYJKoZIhvcNAQEBBQAD +ggEPADCCAQoCggEBAN+v6ZdQCINXtMxiZfaQguzH0yxrMMpb7NnDfcdAwRgUi+DoM3ZJKuM/IUmT +rE4Orz5Iy2Xu/NMhD2XSKtkyj4zl93ewEnu1lcCJo6m67XMuegwGMoOifooUMM0RoOEqOLl5CjH9 +UL2AZd+3UWODyOKIYepLYYHsUmu5ouJLGiifSKOeDNoJjj4XLh7dIN9bxiqKqy69cK3FCxolkHRy +xXtqqzTWMIn/5WgTe1QLyNau7Fqckh49ZLOMxt+/yUFw7BZy1SbsOFU5Q9D8/RhcQPGX69Wam40d +utolucbY38EVAjqr2m7xPi71XAicPNaDaeQQmxkqtilX4+U9m5/wAl0CAwEAAaNCMEAwDwYDVR0T +AQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFMSnsaR7LHH62+FLkHX/xBVghYkQ +MA0GCSqGSIb3DQEBBQUAA4IBAQCjGiybFwBcqR7uKGY3Or+Dxz9LwwmglSBd49lZRNI+DT69ikug +dB/OEIKcdBodfpga3csTS7MgROSR6cz8faXbauX+5v3gTt23ADq1cEmv8uXrAvHRAosZy5Q6XkjE +GB5YGV8eAlrwDPGxrancWYaLbumR9YbK+rlmM6pZW87ipxZzR8srzJmwN0jP41ZL9c8PDHIyh8bw +RLtTcm1D9SZImlJnt1ir/md2cXjbDaJWFBM5JDGFoqgCWjBH4d1QB7wCCZAA62RjYJsWvIjJEubS +fZGL+T0yjWW06XyxV3bqxbYoOb8VZRzI9neWagqNdwvYkQsEjgfbKbYK7p2CNTUQ +-----END CERTIFICATE----- + +DST ACES CA X6 +============== +-----BEGIN CERTIFICATE----- +MIIECTCCAvGgAwIBAgIQDV6ZCtadt3js2AdWO4YV2TANBgkqhkiG9w0BAQUFADBbMQswCQYDVQQG +EwJVUzEgMB4GA1UEChMXRGlnaXRhbCBTaWduYXR1cmUgVHJ1c3QxETAPBgNVBAsTCERTVCBBQ0VT +MRcwFQYDVQQDEw5EU1QgQUNFUyBDQSBYNjAeFw0wMzExMjAyMTE5NThaFw0xNzExMjAyMTE5NTha +MFsxCzAJBgNVBAYTAlVTMSAwHgYDVQQKExdEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdDERMA8GA1UE +CxMIRFNUIEFDRVMxFzAVBgNVBAMTDkRTVCBBQ0VTIENBIFg2MIIBIjANBgkqhkiG9w0BAQEFAAOC +AQ8AMIIBCgKCAQEAuT31LMmU3HWKlV1j6IR3dma5WZFcRt2SPp/5DgO0PWGSvSMmtWPuktKe1jzI +DZBfZIGxqAgNTNj50wUoUrQBJcWVHAx+PhCEdc/BGZFjz+iokYi5Q1K7gLFViYsx+tC3dr5BPTCa +pCIlF3PoHuLTrCq9Wzgh1SpL11V94zpVvddtawJXa+ZHfAjIgrrep4c9oW24MFbCswKBXy314pow +GCi4ZtPLAZZv6opFVdbgnf9nKxcCpk4aahELfrd755jWjHZvwTvbUJN+5dCOHze4vbrGn2zpfDPy +MjwmR/onJALJfh1biEITajV8fTXpLmaRcpPVMibEdPVTo7NdmvYJywIDAQABo4HIMIHFMA8GA1Ud +EwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgHGMB8GA1UdEQQYMBaBFHBraS1vcHNAdHJ1c3Rkc3Qu +Y29tMGIGA1UdIARbMFkwVwYKYIZIAWUDAgEBATBJMEcGCCsGAQUFBwIBFjtodHRwOi8vd3d3LnRy +dXN0ZHN0LmNvbS9jZXJ0aWZpY2F0ZXMvcG9saWN5L0FDRVMtaW5kZXguaHRtbDAdBgNVHQ4EFgQU +CXIGThhDD+XWzMNqizF7eI+og7gwDQYJKoZIhvcNAQEFBQADggEBAKPYjtay284F5zLNAdMEA+V2 +5FYrnJmQ6AgwbN99Pe7lv7UkQIRJ4dEorsTCOlMwiPH1d25Ryvr/ma8kXxug/fKshMrfqfBfBC6t +Fr8hlxCBPeP/h40y3JTlR4peahPJlJU90u7INJXQgNStMgiAVDzgvVJT11J8smk/f3rPanTK+gQq +nExaBqXpIK1FZg9p8d2/6eMyi/rgwYZNcjwu2JN4Cir42NInPRmJX1p7ijvMDNpRrscL9yuwNwXs +vFcj4jjSm2jzVhKIT0J8uDHEtdvkyCE06UgRNe76x5JXxZ805Mf29w4LTJxoeHtxMcfrHuBnQfO3 +oKfN5XozNmr6mis= +-----END CERTIFICATE----- + +TURKTRUST Certificate Services Provider Root 1 +============================================== +-----BEGIN CERTIFICATE----- +MIID+zCCAuOgAwIBAgIBATANBgkqhkiG9w0BAQUFADCBtzE/MD0GA1UEAww2VMOcUktUUlVTVCBF +bGVrdHJvbmlrIFNlcnRpZmlrYSBIaXptZXQgU2HEn2xhecSxY8Sxc8SxMQswCQYDVQQGDAJUUjEP +MA0GA1UEBwwGQU5LQVJBMVYwVAYDVQQKDE0oYykgMjAwNSBUw5xSS1RSVVNUIEJpbGdpIMSwbGV0 +acWfaW0gdmUgQmlsacWfaW0gR8O8dmVubGnEn2kgSGl6bWV0bGVyaSBBLsWeLjAeFw0wNTA1MTMx +MDI3MTdaFw0xNTAzMjIxMDI3MTdaMIG3MT8wPQYDVQQDDDZUw5xSS1RSVVNUIEVsZWt0cm9uaWsg +U2VydGlmaWthIEhpem1ldCBTYcSfbGF5xLFjxLFzxLExCzAJBgNVBAYMAlRSMQ8wDQYDVQQHDAZB +TktBUkExVjBUBgNVBAoMTShjKSAyMDA1IFTDnFJLVFJVU1QgQmlsZ2kgxLBsZXRpxZ9pbSB2ZSBC +aWxpxZ9pbSBHw7x2ZW5sacSfaSBIaXptZXRsZXJpIEEuxZ4uMIIBIjANBgkqhkiG9w0BAQEFAAOC +AQ8AMIIBCgKCAQEAylIF1mMD2Bxf3dJ7XfIMYGFbazt0K3gNfUW9InTojAPBxhEqPZW8qZSwu5GX +yGl8hMW0kWxsE2qkVa2kheiVfrMArwDCBRj1cJ02i67L5BuBf5OI+2pVu32Fks66WJ/bMsW9Xe8i +Si9BB35JYbOG7E6mQW6EvAPs9TscyB/C7qju6hJKjRTP8wrgUDn5CDX4EVmt5yLqS8oUBt5CurKZ +8y1UiBAG6uEaPj1nH/vO+3yC6BFdSsG5FOpU2WabfIl9BJpiyelSPJ6c79L1JuTm5Rh8i27fbMx4 +W09ysstcP4wFjdFMjK2Sx+F4f2VsSQZQLJ4ywtdKxnWKWU51b0dewQIDAQABoxAwDjAMBgNVHRME +BTADAQH/MA0GCSqGSIb3DQEBBQUAA4IBAQAV9VX/N5aAWSGk/KEVTCD21F/aAyT8z5Aa9CEKmu46 +sWrv7/hg0Uw2ZkUd82YCdAR7kjCo3gp2D++Vbr3JN+YaDayJSFvMgzbC9UZcWYJWtNX+I7TYVBxE +q8Sn5RTOPEFhfEPmzcSBCYsk+1Ql1haolgxnB2+zUEfjHCQo3SqYpGH+2+oSN7wBGjSFvW5P55Fy +B0SFHljKVETd96y5y4khctuPwGkplyqjrhgjlxxBKot8KsF8kOipKMDTkcatKIdAaLX/7KfS0zgY +nNN9aV3wxqUeJBujR/xpB2jn5Jq07Q+hh4cCzofSSE7hvP/L8XKSRGQDJereW26fyfJOrN3H +-----END CERTIFICATE----- + +TURKTRUST Certificate Services Provider Root 2 +============================================== +-----BEGIN CERTIFICATE----- +MIIEPDCCAySgAwIBAgIBATANBgkqhkiG9w0BAQUFADCBvjE/MD0GA1UEAww2VMOcUktUUlVTVCBF +bGVrdHJvbmlrIFNlcnRpZmlrYSBIaXptZXQgU2HEn2xhecSxY8Sxc8SxMQswCQYDVQQGEwJUUjEP +MA0GA1UEBwwGQW5rYXJhMV0wWwYDVQQKDFRUw5xSS1RSVVNUIEJpbGdpIMSwbGV0acWfaW0gdmUg +QmlsacWfaW0gR8O8dmVubGnEn2kgSGl6bWV0bGVyaSBBLsWeLiAoYykgS2FzxLFtIDIwMDUwHhcN +MDUxMTA3MTAwNzU3WhcNMTUwOTE2MTAwNzU3WjCBvjE/MD0GA1UEAww2VMOcUktUUlVTVCBFbGVr +dHJvbmlrIFNlcnRpZmlrYSBIaXptZXQgU2HEn2xhecSxY8Sxc8SxMQswCQYDVQQGEwJUUjEPMA0G +A1UEBwwGQW5rYXJhMV0wWwYDVQQKDFRUw5xSS1RSVVNUIEJpbGdpIMSwbGV0acWfaW0gdmUgQmls +acWfaW0gR8O8dmVubGnEn2kgSGl6bWV0bGVyaSBBLsWeLiAoYykgS2FzxLFtIDIwMDUwggEiMA0G +CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCpNn7DkUNMwxmYCMjHWHtPFoylzkkBH3MOrHUTpvqe +LCDe2JAOCtFp0if7qnefJ1Il4std2NiDUBd9irWCPwSOtNXwSadktx4uXyCcUHVPr+G1QRT0mJKI +x+XlZEdhR3n9wFHxwZnn3M5q+6+1ATDcRhzviuyV79z/rxAc653YsKpqhRgNF8k+v/Gb0AmJQv2g +QrSdiVFVKc8bcLyEVK3BEx+Y9C52YItdP5qtygy/p1Zbj3e41Z55SZI/4PGXJHpsmxcPbe9TmJEr +5A++WXkHeLuXlfSfadRYhwqp48y2WBmfJiGxxFmNskF1wK1pzpwACPI2/z7woQ8arBT9pmAPAgMB +AAGjQzBBMB0GA1UdDgQWBBTZN7NOBf3Zz58SFq62iS/rJTqIHDAPBgNVHQ8BAf8EBQMDBwYAMA8G +A1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAHJglrfJ3NgpXiOFX7KzLXb7iNcX/ntt +Rbj2hWyfIvwqECLsqrkw9qtY1jkQMZkpAL2JZkH7dN6RwRgLn7Vhy506vvWolKMiVW4XSf/SKfE4 +Jl3vpao6+XF75tpYHdN0wgH6PmlYX63LaL4ULptswLbcoCb6dxriJNoaN+BnrdFzgw2lGh1uEpJ+ +hGIAF728JRhX8tepb1mIvDS3LoV4nZbcFMMsilKbloxSZj2GFotHuFEJjOp9zYhys2AzsfAKRO8P +9Qk3iCQOLGsgOqL6EfJANZxEaGM7rDNvY7wsu/LSy3Z9fYjYHcgFHW68lKlmjHdxx/qR+i9Rnuk5 +UrbnBEI= +-----END CERTIFICATE----- + +SwissSign Gold CA - G2 +====================== +-----BEGIN CERTIFICATE----- +MIIFujCCA6KgAwIBAgIJALtAHEP1Xk+wMA0GCSqGSIb3DQEBBQUAMEUxCzAJBgNVBAYTAkNIMRUw +EwYDVQQKEwxTd2lzc1NpZ24gQUcxHzAdBgNVBAMTFlN3aXNzU2lnbiBHb2xkIENBIC0gRzIwHhcN +MDYxMDI1MDgzMDM1WhcNMzYxMDI1MDgzMDM1WjBFMQswCQYDVQQGEwJDSDEVMBMGA1UEChMMU3dp +c3NTaWduIEFHMR8wHQYDVQQDExZTd2lzc1NpZ24gR29sZCBDQSAtIEcyMIICIjANBgkqhkiG9w0B +AQEFAAOCAg8AMIICCgKCAgEAr+TufoskDhJuqVAtFkQ7kpJcyrhdhJJCEyq8ZVeCQD5XJM1QiyUq +t2/876LQwB8CJEoTlo8jE+YoWACjR8cGp4QjK7u9lit/VcyLwVcfDmJlD909Vopz2q5+bbqBHH5C +jCA12UNNhPqE21Is8w4ndwtrvxEvcnifLtg+5hg3Wipy+dpikJKVyh+c6bM8K8vzARO/Ws/BtQpg +vd21mWRTuKCWs2/iJneRjOBiEAKfNA+k1ZIzUd6+jbqEemA8atufK+ze3gE/bk3lUIbLtK/tREDF +ylqM2tIrfKjuvqblCqoOpd8FUrdVxyJdMmqXl2MT28nbeTZ7hTpKxVKJ+STnnXepgv9VHKVxaSvR +AiTysybUa9oEVeXBCsdtMDeQKuSeFDNeFhdVxVu1yzSJkvGdJo+hB9TGsnhQ2wwMC3wLjEHXuend +jIj3o02yMszYF9rNt85mndT9Xv+9lz4pded+p2JYryU0pUHHPbwNUMoDAw8IWh+Vc3hiv69yFGkO +peUDDniOJihC8AcLYiAQZzlG+qkDzAQ4embvIIO1jEpWjpEA/I5cgt6IoMPiaG59je883WX0XaxR +7ySArqpWl2/5rX3aYT+YdzylkbYcjCbaZaIJbcHiVOO5ykxMgI93e2CaHt+28kgeDrpOVG2Y4OGi +GqJ3UM/EY5LsRxmd6+ZrzsECAwEAAaOBrDCBqTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUw +AwEB/zAdBgNVHQ4EFgQUWyV7lqRlUX64OfPAeGZe6Drn8O4wHwYDVR0jBBgwFoAUWyV7lqRlUX64 +OfPAeGZe6Drn8O4wRgYDVR0gBD8wPTA7BglghXQBWQECAQEwLjAsBggrBgEFBQcCARYgaHR0cDov +L3JlcG9zaXRvcnkuc3dpc3NzaWduLmNvbS8wDQYJKoZIhvcNAQEFBQADggIBACe645R88a7A3hfm +5djV9VSwg/S7zV4Fe0+fdWavPOhWfvxyeDgD2StiGwC5+OlgzczOUYrHUDFu4Up+GC9pWbY9ZIEr +44OE5iKHjn3g7gKZYbge9LgriBIWhMIxkziWMaa5O1M/wySTVltpkuzFwbs4AOPsF6m43Md8AYOf +Mke6UiI0HTJ6CVanfCU2qT1L2sCCbwq7EsiHSycR+R4tx5M/nttfJmtS2S6K8RTGRI0Vqbe/vd6m +Gu6uLftIdxf+u+yvGPUqUfA5hJeVbG4bwyvEdGB5JbAKJ9/fXtI5z0V9QkvfsywexcZdylU6oJxp +mo/a77KwPJ+HbBIrZXAVUjEaJM9vMSNQH4xPjyPDdEFjHFWoFN0+4FFQz/EbMFYOkrCChdiDyyJk +vC24JdVUorgG6q2SpCSgwYa1ShNqR88uC1aVVMvOmttqtKay20EIhid392qgQmwLOM7XdVAyksLf +KzAiSNDVQTglXaTpXZ/GlHXQRf0wl0OPkKsKx4ZzYEppLd6leNcG2mqeSz53OiATIgHQv2ieY2Br +NU0LbbqhPcCT4H8js1WtciVORvnSFu+wZMEBnunKoGqYDs/YYPIvSbjkQuE4NRb0yG5P94FW6Lqj +viOvrv1vA+ACOzB2+httQc8Bsem4yWb02ybzOqR08kkkW8mw0FfB+j564ZfJ +-----END CERTIFICATE----- + +SwissSign Silver CA - G2 +======================== +-----BEGIN CERTIFICATE----- +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 +-----END CERTIFICATE----- + +GeoTrust Primary Certification Authority +======================================== +-----BEGIN CERTIFICATE----- +MIIDfDCCAmSgAwIBAgIQGKy1av1pthU6Y2yv2vrEoTANBgkqhkiG9w0BAQUFADBYMQswCQYDVQQG +EwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjExMC8GA1UEAxMoR2VvVHJ1c3QgUHJpbWFyeSBD +ZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wNjExMjcwMDAwMDBaFw0zNjA3MTYyMzU5NTlaMFgx +CzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMTEwLwYDVQQDEyhHZW9UcnVzdCBQ +cmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB +CgKCAQEAvrgVe//UfH1nrYNke8hCUy3f9oQIIGHWAVlqnEQRr+92/ZV+zmEwu3qDXwK9AWbK7hWN +b6EwnL2hhZ6UOvNWiAAxz9juapYC2e0DjPt1befquFUWBRaa9OBesYjAZIVcFU2Ix7e64HXprQU9 +nceJSOC7KMgD4TCTZF5SwFlwIjVXiIrxlQqD17wxcwE07e9GceBrAqg1cmuXm2bgyxx5X9gaBGge +RwLmnWDiNpcB3841kt++Z8dtd1k7j53WkBWUvEI0EME5+bEnPn7WinXFsq+W06Lem+SYvn3h6YGt +tm/81w7a4DSwDRp35+MImO9Y+pyEtzavwt+s0vQQBnBxNQIDAQABo0IwQDAPBgNVHRMBAf8EBTAD +AQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQULNVQQZcVi/CPNmFbSvtr2ZnJM5IwDQYJKoZI +hvcNAQEFBQADggEBAFpwfyzdtzRP9YZRqSa+S7iq8XEN3GHHoOo0Hnp3DwQ16CePbJC/kRYkRj5K +Ts4rFtULUh38H2eiAkUxT87z+gOneZ1TatnaYzr4gNfTmeGl4b7UVXGYNTq+k+qurUKykG/g/CFN +NWMziUnWm07Kx+dOCQD32sfvmWKZd7aVIl6KoKv0uHiYyjgZmclynnjNS6yvGaBzEi38wkG6gZHa +Floxt/m0cYASSJlyc1pZU8FjUjPtp8nSOQJw+uCxQmYpqptR7TBUIhRf2asdweSU8Pj1K/fqynhG +1riR/aYNKxoUAT6A8EKglQdebc3MS6RFjasS6LPeWuWgfOgPIh1a6Vk= +-----END CERTIFICATE----- + +thawte Primary Root CA +====================== +-----BEGIN CERTIFICATE----- +MIIEIDCCAwigAwIBAgIQNE7VVyDV7exJ9C/ON9srbTANBgkqhkiG9w0BAQUFADCBqTELMAkGA1UE +BhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5jLjEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBTZXJ2 +aWNlcyBEaXZpc2lvbjE4MDYGA1UECxMvKGMpIDIwMDYgdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhv +cml6ZWQgdXNlIG9ubHkxHzAdBgNVBAMTFnRoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EwHhcNMDYxMTE3 +MDAwMDAwWhcNMzYwNzE2MjM1OTU5WjCBqTELMAkGA1UEBhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwg +SW5jLjEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjE4MDYGA1UECxMv +KGMpIDIwMDYgdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxHzAdBgNVBAMT +FnRoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCs +oPD7gFnUnMekz52hWXMJEEUMDSxuaPFsW0hoSVk3/AszGcJ3f8wQLZU0HObrTQmnHNK4yZc2AreJ +1CRfBsDMRJSUjQJib+ta3RGNKJpchJAQeg29dGYvajig4tVUROsdB58Hum/u6f1OCyn1PoSgAfGc +q/gcfomk6KHYcWUNo1F77rzSImANuVud37r8UVsLr5iy6S7pBOhih94ryNdOwUxkHt3Ph1i6Sk/K +aAcdHJ1KxtUvkcx8cXIcxcBn6zL9yZJclNqFwJu/U30rCfSMnZEfl2pSy94JNqR32HuHUETVPm4p +afs5SSYeCaWAe0At6+gnhcn+Yf1+5nyXHdWdAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYD +VR0PAQH/BAQDAgEGMB0GA1UdDgQWBBR7W0XPr87Lev0xkhpqtvNG61dIUDANBgkqhkiG9w0BAQUF +AAOCAQEAeRHAS7ORtvzw6WfUDW5FvlXok9LOAz/t2iWwHVfLHjp2oEzsUHboZHIMpKnxuIvW1oeE +uzLlQRHAd9mzYJ3rG9XRbkREqaYB7FViHXe4XI5ISXycO1cRrK1zN44veFyQaEfZYGDm/Ac9IiAX +xPcW6cTYcvnIc3zfFi8VqT79aie2oetaupgf1eNNZAqdE8hhuvU5HIe6uL17In/2/qxAeeWsEG89 +jxt5dovEN7MhGITlNgDrYyCZuen+MwS7QcjBAvlEYyCegc5C09Y/LHbTY5xZ3Y+m4Q6gLkH3LpVH +z7z9M/P2C2F+fpErgUfCJzDupxBdN49cOSvkBPB7jVaMaA== +-----END CERTIFICATE----- + +VeriSign Class 3 Public Primary Certification Authority - G5 +============================================================ +-----BEGIN CERTIFICATE----- +MIIE0zCCA7ugAwIBAgIQGNrRniZ96LtKIVjNzGs7SjANBgkqhkiG9w0BAQUFADCByjELMAkGA1UE +BhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZWZXJpU2lnbiBUcnVzdCBO +ZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNiBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVk +IHVzZSBvbmx5MUUwQwYDVQQDEzxWZXJpU2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRp +ZmljYXRpb24gQXV0aG9yaXR5IC0gRzUwHhcNMDYxMTA4MDAwMDAwWhcNMzYwNzE2MjM1OTU5WjCB +yjELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZWZXJpU2ln +biBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNiBWZXJpU2lnbiwgSW5jLiAtIEZvciBh +dXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxWZXJpU2lnbiBDbGFzcyAzIFB1YmxpYyBQcmlt +YXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRzUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw +ggEKAoIBAQCvJAgIKXo1nmAMqudLO07cfLw8RRy7K+D+KQL5VwijZIUVJ/XxrcgxiV0i6CqqpkKz +j/i5Vbext0uz/o9+B1fs70PbZmIVYc9gDaTY3vjgw2IIPVQT60nKWVSFJuUrjxuf6/WhkcIzSdhD +Y2pSS9KP6HBRTdGJaXvHcPaz3BJ023tdS1bTlr8Vd6Gw9KIl8q8ckmcY5fQGBO+QueQA5N06tRn/ +Arr0PO7gi+s3i+z016zy9vA9r911kTMZHRxAy3QkGSGT2RT+rCpSx4/VBEnkjWNHiDxpg8v+R70r +fk/Fla4OndTRQ8Bnc+MUCH7lP59zuDMKz10/NIeWiu5T6CUVAgMBAAGjgbIwga8wDwYDVR0TAQH/ +BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwbQYIKwYBBQUHAQwEYTBfoV2gWzBZMFcwVRYJaW1hZ2Uv +Z2lmMCEwHzAHBgUrDgMCGgQUj+XTGoasjY5rw8+AatRIGCx7GS4wJRYjaHR0cDovL2xvZ28udmVy +aXNpZ24uY29tL3ZzbG9nby5naWYwHQYDVR0OBBYEFH/TZafC3ey78DAJ80M5+gKvMzEzMA0GCSqG +SIb3DQEBBQUAA4IBAQCTJEowX2LP2BqYLz3q3JktvXf2pXkiOOzEp6B4Eq1iDkVwZMXnl2YtmAl+ +X6/WzChl8gGqCBpH3vn5fJJaCGkgDdk+bW48DW7Y5gaRQBi5+MHt39tBquCWIMnNZBU4gcmU7qKE +KQsTb47bDN0lAtukixlE0kF6BWlKWE9gyn6CagsCqiUXObXbf+eEZSqVir2G3l6BFoMtEMze/aiC +Km0oHw0LxOXnGiYZ4fQRbxC1lfznQgUy286dUV4otp6F01vvpX1FQHKOtw5rDgb7MzVIcbidJ4vE +ZV8NhnacRHr2lVz2XTIIM6RUthg/aFzyQkqFOFSDX9HoLPKsEdao7WNq +-----END CERTIFICATE----- + +SecureTrust CA +============== +-----BEGIN CERTIFICATE----- +MIIDuDCCAqCgAwIBAgIQDPCOXAgWpa1Cf/DrJxhZ0DANBgkqhkiG9w0BAQUFADBIMQswCQYDVQQG +EwJVUzEgMB4GA1UEChMXU2VjdXJlVHJ1c3QgQ29ycG9yYXRpb24xFzAVBgNVBAMTDlNlY3VyZVRy +dXN0IENBMB4XDTA2MTEwNzE5MzExOFoXDTI5MTIzMTE5NDA1NVowSDELMAkGA1UEBhMCVVMxIDAe +BgNVBAoTF1NlY3VyZVRydXN0IENvcnBvcmF0aW9uMRcwFQYDVQQDEw5TZWN1cmVUcnVzdCBDQTCC +ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKukgeWVzfX2FI7CT8rU4niVWJxB4Q2ZQCQX +OZEzZum+4YOvYlyJ0fwkW2Gz4BERQRwdbvC4u/jep4G6pkjGnx29vo6pQT64lO0pGtSO0gMdA+9t +DWccV9cGrcrI9f4Or2YlSASWC12juhbDCE/RRvgUXPLIXgGZbf2IzIaowW8xQmxSPmjL8xk037uH +GFaAJsTQ3MBv396gwpEWoGQRS0S8Hvbn+mPeZqx2pHGj7DaUaHp3pLHnDi+BeuK1cobvomuL8A/b +01k/unK8RCSc43Oz969XL0Imnal0ugBS8kvNU3xHCzaFDmapCJcWNFfBZveA4+1wVMeT4C4oFVmH +ursCAwEAAaOBnTCBmjATBgkrBgEEAYI3FAIEBh4EAEMAQTALBgNVHQ8EBAMCAYYwDwYDVR0TAQH/ +BAUwAwEB/zAdBgNVHQ4EFgQUQjK2FvoE/f5dS3rD/fdMQB1aQ68wNAYDVR0fBC0wKzApoCegJYYj +aHR0cDovL2NybC5zZWN1cmV0cnVzdC5jb20vU1RDQS5jcmwwEAYJKwYBBAGCNxUBBAMCAQAwDQYJ +KoZIhvcNAQEFBQADggEBADDtT0rhWDpSclu1pqNlGKa7UTt36Z3q059c4EVlew3KW+JwULKUBRSu +SceNQQcSc5R+DCMh/bwQf2AQWnL1mA6s7Ll/3XpvXdMc9P+IBWlCqQVxyLesJugutIxq/3HcuLHf +mbx8IVQr5Fiiu1cprp6poxkmD5kuCLDv/WnPmRoJjeOnnyvJNjR7JLN4TJUXpAYmHrZkUjZfYGfZ +nMUFdAvnZyPSCPyI6a6Lf+Ew9Dd+/cYy2i2eRDAwbO4H3tI0/NL/QPZL9GZGBlSm8jIKYyYwa5vR +3ItHuuG51WLQoqD0ZwV4KWMabwTW+MZMo5qxN7SN5ShLHZ4swrhovO0C7jE= +-----END CERTIFICATE----- + +Secure Global CA +================ +-----BEGIN CERTIFICATE----- +MIIDvDCCAqSgAwIBAgIQB1YipOjUiolN9BPI8PjqpTANBgkqhkiG9w0BAQUFADBKMQswCQYDVQQG +EwJVUzEgMB4GA1UEChMXU2VjdXJlVHJ1c3QgQ29ycG9yYXRpb24xGTAXBgNVBAMTEFNlY3VyZSBH +bG9iYWwgQ0EwHhcNMDYxMTA3MTk0MjI4WhcNMjkxMjMxMTk1MjA2WjBKMQswCQYDVQQGEwJVUzEg +MB4GA1UEChMXU2VjdXJlVHJ1c3QgQ29ycG9yYXRpb24xGTAXBgNVBAMTEFNlY3VyZSBHbG9iYWwg +Q0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCvNS7YrGxVaQZx5RNoJLNP2MwhR/jx +YDiJiQPpvepeRlMJ3Fz1Wuj3RSoC6zFh1ykzTM7HfAo3fg+6MpjhHZevj8fcyTiW89sa/FHtaMbQ +bqR8JNGuQsiWUGMu4P51/pinX0kuleM5M2SOHqRfkNJnPLLZ/kG5VacJjnIFHovdRIWCQtBJwB1g +8NEXLJXr9qXBkqPFwqcIYA1gBBCWeZ4WNOaptvolRTnIHmX5k/Wq8VLcmZg9pYYaDDUz+kulBAYV +HDGA76oYa8J719rO+TMg1fW9ajMtgQT7sFzUnKPiXB3jqUJ1XnvUd+85VLrJChgbEplJL4hL/VBi +0XPnj3pDAgMBAAGjgZ0wgZowEwYJKwYBBAGCNxQCBAYeBABDAEEwCwYDVR0PBAQDAgGGMA8GA1Ud +EwEB/wQFMAMBAf8wHQYDVR0OBBYEFK9EBMJBfkiD2045AuzshHrmzsmkMDQGA1UdHwQtMCswKaAn +oCWGI2h0dHA6Ly9jcmwuc2VjdXJldHJ1c3QuY29tL1NHQ0EuY3JsMBAGCSsGAQQBgjcVAQQDAgEA +MA0GCSqGSIb3DQEBBQUAA4IBAQBjGghAfaReUw132HquHw0LURYD7xh8yOOvaliTFGCRsoTciE6+ +OYo68+aCiV0BN7OrJKQVDpI1WkpEXk5X+nXOH0jOZvQ8QCaSmGwb7iRGDBezUqXbpZGRzzfTb+cn +CDpOGR86p1hcF895P4vkp9MmI50mD1hp/Ed+stCNi5O/KU9DaXR2Z0vPB4zmAve14bRDtUstFJ/5 +3CYNv6ZHdAbYiNE6KTCEztI5gGIbqMdXSbxqVVFnFUq+NQfk1XWYN3kwFNspnWzFacxHVaIw98xc +f8LDmBxrThaA63p4ZUWiABqvDA1VZDRIuJK58bRQKfJPIx/abKwfROHdI3hRW8cW +-----END CERTIFICATE----- + +COMODO Certification Authority +============================== +-----BEGIN CERTIFICATE----- +MIIEHTCCAwWgAwIBAgIQToEtioJl4AsC7j41AkblPTANBgkqhkiG9w0BAQUFADCBgTELMAkGA1UE +BhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgG +A1UEChMRQ09NT0RPIENBIExpbWl0ZWQxJzAlBgNVBAMTHkNPTU9ETyBDZXJ0aWZpY2F0aW9uIEF1 +dGhvcml0eTAeFw0wNjEyMDEwMDAwMDBaFw0yOTEyMzEyMzU5NTlaMIGBMQswCQYDVQQGEwJHQjEb +MBkGA1UECBMSR3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHEwdTYWxmb3JkMRowGAYDVQQKExFD +T01PRE8gQ0EgTGltaXRlZDEnMCUGA1UEAxMeQ09NT0RPIENlcnRpZmljYXRpb24gQXV0aG9yaXR5 +MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0ECLi3LjkRv3UcEbVASY06m/weaKXTuH ++7uIzg3jLz8GlvCiKVCZrts7oVewdFFxze1CkU1B/qnI2GqGd0S7WWaXUF601CxwRM/aN5VCaTww +xHGzUvAhTaHYujl8HJ6jJJ3ygxaYqhZ8Q5sVW7euNJH+1GImGEaaP+vB+fGQV+useg2L23IwambV +4EajcNxo2f8ESIl33rXp+2dtQem8Ob0y2WIC8bGoPW43nOIv4tOiJovGuFVDiOEjPqXSJDlqR6sA +1KGzqSX+DT+nHbrTUcELpNqsOO9VUCQFZUaTNE8tja3G1CEZ0o7KBWFxB3NH5YoZEr0ETc5OnKVI +rLsm9wIDAQABo4GOMIGLMB0GA1UdDgQWBBQLWOWLxkwVN6RAqTCpIb5HNlpW/zAOBgNVHQ8BAf8E +BAMCAQYwDwYDVR0TAQH/BAUwAwEB/zBJBgNVHR8EQjBAMD6gPKA6hjhodHRwOi8vY3JsLmNvbW9k +b2NhLmNvbS9DT01PRE9DZXJ0aWZpY2F0aW9uQXV0aG9yaXR5LmNybDANBgkqhkiG9w0BAQUFAAOC +AQEAPpiem/Yb6dc5t3iuHXIYSdOH5EOC6z/JqvWote9VfCFSZfnVDeFs9D6Mk3ORLgLETgdxb8CP +OGEIqB6BCsAvIC9Bi5HcSEW88cbeunZrM8gALTFGTO3nnc+IlP8zwFboJIYmuNg4ON8qa90SzMc/ +RxdMosIGlgnW2/4/PEZB31jiVg88O8EckzXZOFKs7sjsLjBOlDW0JB9LeGna8gI4zJVSk/BwJVmc +IGfE7vmLV2H0knZ9P4SNVbfo5azV8fUZVqZa+5Acr5Pr5RzUZ5ddBA6+C4OmF4O5MBKgxTMVBbkN ++8cFduPYSo38NBejxiEovjBFMR7HeL5YYTisO+IBZQ== +-----END CERTIFICATE----- + +Network Solutions Certificate Authority +======================================= +-----BEGIN CERTIFICATE----- +MIID5jCCAs6gAwIBAgIQV8szb8JcFuZHFhfjkDFo4DANBgkqhkiG9w0BAQUFADBiMQswCQYDVQQG +EwJVUzEhMB8GA1UEChMYTmV0d29yayBTb2x1dGlvbnMgTC5MLkMuMTAwLgYDVQQDEydOZXR3b3Jr +IFNvbHV0aW9ucyBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkwHhcNMDYxMjAxMDAwMDAwWhcNMjkxMjMx +MjM1OTU5WjBiMQswCQYDVQQGEwJVUzEhMB8GA1UEChMYTmV0d29yayBTb2x1dGlvbnMgTC5MLkMu +MTAwLgYDVQQDEydOZXR3b3JrIFNvbHV0aW9ucyBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkwggEiMA0G +CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDkvH6SMG3G2I4rC7xGzuAnlt7e+foS0zwzc7MEL7xx +jOWftiJgPl9dzgn/ggwbmlFQGiaJ3dVhXRncEg8tCqJDXRfQNJIg6nPPOCwGJgl6cvf6UDL4wpPT +aaIjzkGxzOTVHzbRijr4jGPiFFlp7Q3Tf2vouAPlT2rlmGNpSAW+Lv8ztumXWWn4Zxmuk2GWRBXT +crA/vGp97Eh/jcOrqnErU2lBUzS1sLnFBgrEsEX1QV1uiUV7PTsmjHTC5dLRfbIR1PtYMiKagMnc +/Qzpf14Dl847ABSHJ3A4qY5usyd2mFHgBeMhqxrVhSI8KbWaFsWAqPS7azCPL0YCorEMIuDTAgMB +AAGjgZcwgZQwHQYDVR0OBBYEFCEwyfsA106Y2oeqKtCnLrFAMadMMA4GA1UdDwEB/wQEAwIBBjAP +BgNVHRMBAf8EBTADAQH/MFIGA1UdHwRLMEkwR6BFoEOGQWh0dHA6Ly9jcmwubmV0c29sc3NsLmNv +bS9OZXR3b3JrU29sdXRpb25zQ2VydGlmaWNhdGVBdXRob3JpdHkuY3JsMA0GCSqGSIb3DQEBBQUA +A4IBAQC7rkvnt1frf6ott3NHhWrB5KUd5Oc86fRZZXe1eltajSU24HqXLjjAV2CDmAaDn7l2em5Q +4LqILPxFzBiwmZVRDuwduIj/h1AcgsLj4DKAv6ALR8jDMe+ZZzKATxcheQxpXN5eNK4CtSbqUN9/ +GGUsyfJj4akH/nxxH2szJGoeBfcFaMBqEssuXmHLrijTfsK0ZpEmXzwuJF/LWA/rKOyvEZbz3Htv +wKeI8lN3s2Berq4o2jUsbzRF0ybh3uxbTydrFny9RAQYgrOJeRcQcT16ohZO9QHNpGxlaKFJdlxD +ydi8NmdspZS11My5vWo1ViHe2MPr+8ukYEywVaCge1ey +-----END CERTIFICATE----- + +WellsSecure Public Root Certificate Authority +============================================= +-----BEGIN CERTIFICATE----- +MIIEvTCCA6WgAwIBAgIBATANBgkqhkiG9w0BAQUFADCBhTELMAkGA1UEBhMCVVMxIDAeBgNVBAoM +F1dlbGxzIEZhcmdvIFdlbGxzU2VjdXJlMRwwGgYDVQQLDBNXZWxscyBGYXJnbyBCYW5rIE5BMTYw +NAYDVQQDDC1XZWxsc1NlY3VyZSBQdWJsaWMgUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkwHhcN +MDcxMjEzMTcwNzU0WhcNMjIxMjE0MDAwNzU0WjCBhTELMAkGA1UEBhMCVVMxIDAeBgNVBAoMF1dl +bGxzIEZhcmdvIFdlbGxzU2VjdXJlMRwwGgYDVQQLDBNXZWxscyBGYXJnbyBCYW5rIE5BMTYwNAYD +VQQDDC1XZWxsc1NlY3VyZSBQdWJsaWMgUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkwggEiMA0G +CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDub7S9eeKPCCGeOARBJe+rWxxTkqxtnt3CxC5FlAM1 +iGd0V+PfjLindo8796jE2yljDpFoNoqXjopxaAkH5OjUDk/41itMpBb570OYj7OeUt9tkTmPOL13 +i0Nj67eT/DBMHAGTthP796EfvyXhdDcsHqRePGj4S78NuR4uNuip5Kf4D8uCdXw1LSLWwr8L87T8 +bJVhHlfXBIEyg1J55oNjz7fLY4sR4r1e6/aN7ZVyKLSsEmLpSjPmgzKuBXWVvYSV2ypcm44uDLiB +K0HmOFafSZtsdvqKXfcBeYF8wYNABf5x/Qw/zE5gCQ5lRxAvAcAFP4/4s0HvWkJ+We/SlwxlAgMB +AAGjggE0MIIBMDAPBgNVHRMBAf8EBTADAQH/MDkGA1UdHwQyMDAwLqAsoCqGKGh0dHA6Ly9jcmwu +cGtpLndlbGxzZmFyZ28uY29tL3dzcHJjYS5jcmwwDgYDVR0PAQH/BAQDAgHGMB0GA1UdDgQWBBQm +lRkQ2eihl5H/3BnZtQQ+0nMKajCBsgYDVR0jBIGqMIGngBQmlRkQ2eihl5H/3BnZtQQ+0nMKaqGB +i6SBiDCBhTELMAkGA1UEBhMCVVMxIDAeBgNVBAoMF1dlbGxzIEZhcmdvIFdlbGxzU2VjdXJlMRww +GgYDVQQLDBNXZWxscyBGYXJnbyBCYW5rIE5BMTYwNAYDVQQDDC1XZWxsc1NlY3VyZSBQdWJsaWMg +Um9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHmCAQEwDQYJKoZIhvcNAQEFBQADggEBALkVsUSRzCPI +K0134/iaeycNzXK7mQDKfGYZUMbVmO2rvwNa5U3lHshPcZeG1eMd/ZDJPHV3V3p9+N701NX3leZ0 +bh08rnyd2wIDBSxxSyU+B+NemvVmFymIGjifz6pBA4SXa5M4esowRBskRDPQ5NHcKDj0E0M1NSlj +qHyita04pO2t/caaH/+Xc/77szWnk4bGdpEA5qxRFsQnMlzbc9qlk1eOPm01JghZ1edE13YgY+es +E2fDbbFwRnzVlhE9iW9dqKHrjQrawx0zbKPqZxmamX9LPYNRKh3KL4YMon4QLSvUFpULB6ouFJJJ +tylv2G0xffX8oRAHh84vWdw+WNs= +-----END CERTIFICATE----- + +COMODO ECC Certification Authority +================================== +-----BEGIN CERTIFICATE----- +MIICiTCCAg+gAwIBAgIQH0evqmIAcFBUTAGem2OZKjAKBggqhkjOPQQDAzCBhTELMAkGA1UEBhMC +R0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgGA1UE +ChMRQ09NT0RPIENBIExpbWl0ZWQxKzApBgNVBAMTIkNPTU9ETyBFQ0MgQ2VydGlmaWNhdGlvbiBB +dXRob3JpdHkwHhcNMDgwMzA2MDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBhTELMAkGA1UEBhMCR0Ix +GzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgGA1UEChMR +Q09NT0RPIENBIExpbWl0ZWQxKzApBgNVBAMTIkNPTU9ETyBFQ0MgQ2VydGlmaWNhdGlvbiBBdXRo +b3JpdHkwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQDR3svdcmCFYX7deSRFtSrYpn1PlILBs5BAH+X +4QokPB0BBO490o0JlwzgdeT6+3eKKvUDYEs2ixYjFq0JcfRK9ChQtP6IHG4/bC8vCVlbpVsLM5ni +wz2J+Wos77LTBumjQjBAMB0GA1UdDgQWBBR1cacZSBm8nZ3qQUfflMRId5nTeTAOBgNVHQ8BAf8E +BAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAwNoADBlAjEA7wNbeqy3eApyt4jf/7VG +FAkK+qDmfQjGGoe9GKhzvSbKYAydzpmfz1wPMOG+FDHqAjAU9JM8SaczepBGR7NjfRObTrdvGDeA +U/7dIOA1mjbRxwG55tzd8/8dLDoWV9mSOdY= +-----END CERTIFICATE----- + +IGC/A +===== +-----BEGIN CERTIFICATE----- +MIIEAjCCAuqgAwIBAgIFORFFEJQwDQYJKoZIhvcNAQEFBQAwgYUxCzAJBgNVBAYTAkZSMQ8wDQYD +VQQIEwZGcmFuY2UxDjAMBgNVBAcTBVBhcmlzMRAwDgYDVQQKEwdQTS9TR0ROMQ4wDAYDVQQLEwVE +Q1NTSTEOMAwGA1UEAxMFSUdDL0ExIzAhBgkqhkiG9w0BCQEWFGlnY2FAc2dkbi5wbS5nb3V2LmZy +MB4XDTAyMTIxMzE0MjkyM1oXDTIwMTAxNzE0MjkyMlowgYUxCzAJBgNVBAYTAkZSMQ8wDQYDVQQI +EwZGcmFuY2UxDjAMBgNVBAcTBVBhcmlzMRAwDgYDVQQKEwdQTS9TR0ROMQ4wDAYDVQQLEwVEQ1NT +STEOMAwGA1UEAxMFSUdDL0ExIzAhBgkqhkiG9w0BCQEWFGlnY2FAc2dkbi5wbS5nb3V2LmZyMIIB +IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsh/R0GLFMzvABIaIs9z4iPf930Pfeo2aSVz2 +TqrMHLmh6yeJ8kbpO0px1R2OLc/mratjUMdUC24SyZA2xtgv2pGqaMVy/hcKshd+ebUyiHDKcMCW +So7kVc0dJ5S/znIq7Fz5cyD+vfcuiWe4u0dzEvfRNWk68gq5rv9GQkaiv6GFGvm/5P9JhfejcIYy +HF2fYPepraX/z9E0+X1bF8bc1g4oa8Ld8fUzaJ1O/Id8NhLWo4DoQw1VYZTqZDdH6nfK0LJYBcNd +frGoRpAxVs5wKpayMLh35nnAvSk7/ZR3TL0gzUEl4C7HG7vupARB0l2tEmqKm0f7yd1GQOGdPDPQ +tQIDAQABo3cwdTAPBgNVHRMBAf8EBTADAQH/MAsGA1UdDwQEAwIBRjAVBgNVHSAEDjAMMAoGCCqB +egF5AQEBMB0GA1UdDgQWBBSjBS8YYFDCiQrdKyFP/45OqDAxNjAfBgNVHSMEGDAWgBSjBS8YYFDC +iQrdKyFP/45OqDAxNjANBgkqhkiG9w0BAQUFAAOCAQEABdwm2Pp3FURo/C9mOnTgXeQp/wYHE4RK +q89toB9RlPhJy3Q2FLwV3duJL92PoF189RLrn544pEfMs5bZvpwlqwN+Mw+VgQ39FuCIvjfwbF3Q +MZsyK10XZZOYYLxuj7GoPB7ZHPOpJkL5ZB3C55L29B5aqhlSXa/oovdgoPaN8In1buAKBQGVyYsg +Crpa/JosPL3Dt8ldeCUFP1YUmwza+zpI/pdpXsoQhvdOlgQITeywvl3cO45Pwf2aNjSaTFR+FwNI +lQgRHAdvhQh+XU3Endv7rs6y0bO4g2wdsrN58dhwmX7wEwLOXt1R0982gaEbeC9xs/FZTEYYKKuF +0mBWWg== +-----END CERTIFICATE----- + +Security Communication EV RootCA1 +================================= +-----BEGIN CERTIFICATE----- +MIIDfTCCAmWgAwIBAgIBADANBgkqhkiG9w0BAQUFADBgMQswCQYDVQQGEwJKUDElMCMGA1UEChMc +U0VDT00gVHJ1c3QgU3lzdGVtcyBDTy4sTFRELjEqMCgGA1UECxMhU2VjdXJpdHkgQ29tbXVuaWNh +dGlvbiBFViBSb290Q0ExMB4XDTA3MDYwNjAyMTIzMloXDTM3MDYwNjAyMTIzMlowYDELMAkGA1UE +BhMCSlAxJTAjBgNVBAoTHFNFQ09NIFRydXN0IFN5c3RlbXMgQ08uLExURC4xKjAoBgNVBAsTIVNl +Y3VyaXR5IENvbW11bmljYXRpb24gRVYgUm9vdENBMTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC +AQoCggEBALx/7FebJOD+nLpCeamIivqA4PUHKUPqjgo0No0c+qe1OXj/l3X3L+SqawSERMqm4miO +/VVQYg+kcQ7OBzgtQoVQrTyWb4vVog7P3kmJPdZkLjjlHmy1V4qe70gOzXppFodEtZDkBp2uoQSX +WHnvIEqCa4wiv+wfD+mEce3xDuS4GBPMVjZd0ZoeUWs5bmB2iDQL87PRsJ3KYeJkHcFGB7hj3R4z +ZbOOCVVSPbW9/wfrrWFVGCypaZhKqkDFMxRldAD5kd6vA0jFQFTcD4SQaCDFkpbcLuUCRarAX1T4 +bepJz11sS6/vmsJWXMY1VkJqMF/Cq/biPT+zyRGPMUzXn0kCAwEAAaNCMEAwHQYDVR0OBBYEFDVK +9U2vP9eCOKyrcWUXdYydVZPmMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MA0GCSqG +SIb3DQEBBQUAA4IBAQCoh+ns+EBnXcPBZsdAS5f8hxOQWsTvoMpfi7ent/HWtWS3irO4G8za+6xm +iEHO6Pzk2x6Ipu0nUBsCMCRGef4Eh3CXQHPRwMFXGZpppSeZq51ihPZRwSzJIxXYKLerJRO1RuGG +Av8mjMSIkh1W/hln8lXkgKNrnKt34VFxDSDbEJrbvXZ5B3eZKK2aXtqxT0QsNY6llsf9g/BYxnnW +mHyojf6GPgcWkuF75x3sM3Z+Qi5KhfmRiWiEA4Glm5q+4zfFVKtWOxgtQaQM+ELbmaDgcm+7XeEW +T1MKZPlO9L9OVL14bIjqv5wTJMJwaaJ/D8g8rQjJsJhAoyrniIPtd490 +-----END CERTIFICATE----- + +OISTE WISeKey Global Root GA CA +=============================== +-----BEGIN CERTIFICATE----- +MIID8TCCAtmgAwIBAgIQQT1yx/RrH4FDffHSKFTfmjANBgkqhkiG9w0BAQUFADCBijELMAkGA1UE +BhMCQ0gxEDAOBgNVBAoTB1dJU2VLZXkxGzAZBgNVBAsTEkNvcHlyaWdodCAoYykgMjAwNTEiMCAG +A1UECxMZT0lTVEUgRm91bmRhdGlvbiBFbmRvcnNlZDEoMCYGA1UEAxMfT0lTVEUgV0lTZUtleSBH +bG9iYWwgUm9vdCBHQSBDQTAeFw0wNTEyMTExNjAzNDRaFw0zNzEyMTExNjA5NTFaMIGKMQswCQYD +VQQGEwJDSDEQMA4GA1UEChMHV0lTZUtleTEbMBkGA1UECxMSQ29weXJpZ2h0IChjKSAyMDA1MSIw +IAYDVQQLExlPSVNURSBGb3VuZGF0aW9uIEVuZG9yc2VkMSgwJgYDVQQDEx9PSVNURSBXSVNlS2V5 +IEdsb2JhbCBSb290IEdBIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAy0+zAJs9 +Nt350UlqaxBJH+zYK7LG+DKBKUOVTJoZIyEVRd7jyBxRVVuuk+g3/ytr6dTqvirdqFEr12bDYVxg +Asj1znJ7O7jyTmUIms2kahnBAbtzptf2w93NvKSLtZlhuAGio9RN1AU9ka34tAhxZK9w8RxrfvbD +d50kc3vkDIzh2TbhmYsFmQvtRTEJysIA2/dyoJaqlYfQjse2YXMNdmaM3Bu0Y6Kff5MTMPGhJ9vZ +/yxViJGg4E8HsChWjBgbl0SOid3gF27nKu+POQoxhILYQBRJLnpB5Kf+42TMwVlxSywhp1t94B3R +LoGbw9ho972WG6xwsRYUC9tguSYBBQIDAQABo1EwTzALBgNVHQ8EBAMCAYYwDwYDVR0TAQH/BAUw +AwEB/zAdBgNVHQ4EFgQUswN+rja8sHnR3JQmthG+IbJphpQwEAYJKwYBBAGCNxUBBAMCAQAwDQYJ +KoZIhvcNAQEFBQADggEBAEuh/wuHbrP5wUOxSPMowB0uyQlB+pQAHKSkq0lPjz0e701vvbyk9vIm +MMkQyh2I+3QZH4VFvbBsUfk2ftv1TDI6QU9bR8/oCy22xBmddMVHxjtqD6wU2zz0c5ypBd8A3HR4 ++vg1YFkCExh8vPtNsCBtQ7tgMHpnM1zFmdH4LTlSc/uMqpclXHLZCB6rTjzjgTGfA6b7wP4piFXa +hNVQA7bihKOmNqoROgHhGEvWRGizPflTdISzRpFGlgC3gCy24eMQ4tui5yiPAZZiFj4A4xylNoEY +okxSdsARo27mHbrjWr42U8U+dY+GaSlYU7Wcu2+fXMUY7N0v4ZjJ/L7fCg0= +-----END CERTIFICATE----- + +Microsec e-Szigno Root CA +========================= +-----BEGIN CERTIFICATE----- +MIIHqDCCBpCgAwIBAgIRAMy4579OKRr9otxmpRwsDxEwDQYJKoZIhvcNAQEFBQAwcjELMAkGA1UE +BhMCSFUxETAPBgNVBAcTCEJ1ZGFwZXN0MRYwFAYDVQQKEw1NaWNyb3NlYyBMdGQuMRQwEgYDVQQL +EwtlLVN6aWdubyBDQTEiMCAGA1UEAxMZTWljcm9zZWMgZS1Temlnbm8gUm9vdCBDQTAeFw0wNTA0 +MDYxMjI4NDRaFw0xNzA0MDYxMjI4NDRaMHIxCzAJBgNVBAYTAkhVMREwDwYDVQQHEwhCdWRhcGVz +dDEWMBQGA1UEChMNTWljcm9zZWMgTHRkLjEUMBIGA1UECxMLZS1Temlnbm8gQ0ExIjAgBgNVBAMT +GU1pY3Jvc2VjIGUtU3ppZ25vIFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB +AQDtyADVgXvNOABHzNuEwSFpLHSQDCHZU4ftPkNEU6+r+ICbPHiN1I2uuO/TEdyB5s87lozWbxXG +d36hL+BfkrYn13aaHUM86tnsL+4582pnS4uCzyL4ZVX+LMsvfUh6PXX5qqAnu3jCBspRwn5mS6/N +oqdNAoI/gqyFxuEPkEeZlApxcpMqyabAvjxWTHOSJ/FrtfX9/DAFYJLG65Z+AZHCabEeHXtTRbjc +QR/Ji3HWVBTji1R4P770Yjtb9aPs1ZJ04nQw7wHb4dSrmZsqa/i9phyGI0Jf7Enemotb9HI6QMVJ +PqW+jqpx62z69Rrkav17fVVA71hu5tnVvCSrwe+3AgMBAAGjggQ3MIIEMzBnBggrBgEFBQcBAQRb +MFkwKAYIKwYBBQUHMAGGHGh0dHBzOi8vcmNhLmUtc3ppZ25vLmh1L29jc3AwLQYIKwYBBQUHMAKG +IWh0dHA6Ly93d3cuZS1zemlnbm8uaHUvUm9vdENBLmNydDAPBgNVHRMBAf8EBTADAQH/MIIBcwYD +VR0gBIIBajCCAWYwggFiBgwrBgEEAYGoGAIBAQEwggFQMCgGCCsGAQUFBwIBFhxodHRwOi8vd3d3 +LmUtc3ppZ25vLmh1L1NaU1ovMIIBIgYIKwYBBQUHAgIwggEUHoIBEABBACAAdABhAG4A+gBzAO0A +dAB2AOEAbgB5ACAA6QByAHQAZQBsAG0AZQB6AOkAcwDpAGgAZQB6ACAA6QBzACAAZQBsAGYAbwBn +AGEAZADhAHMA4QBoAG8AegAgAGEAIABTAHoAbwBsAGcA4QBsAHQAYQB0APMAIABTAHoAbwBsAGcA +4QBsAHQAYQB0AOEAcwBpACAAUwB6AGEAYgDhAGwAeQB6AGEAdABhACAAcwB6AGUAcgBpAG4AdAAg +AGsAZQBsAGwAIABlAGwAagDhAHIAbgBpADoAIABoAHQAdABwADoALwAvAHcAdwB3AC4AZQAtAHMA +egBpAGcAbgBvAC4AaAB1AC8AUwBaAFMAWgAvMIHIBgNVHR8EgcAwgb0wgbqggbeggbSGIWh0dHA6 +Ly93d3cuZS1zemlnbm8uaHUvUm9vdENBLmNybIaBjmxkYXA6Ly9sZGFwLmUtc3ppZ25vLmh1L0NO +PU1pY3Jvc2VjJTIwZS1Temlnbm8lMjBSb290JTIwQ0EsT1U9ZS1Temlnbm8lMjBDQSxPPU1pY3Jv +c2VjJTIwTHRkLixMPUJ1ZGFwZXN0LEM9SFU/Y2VydGlmaWNhdGVSZXZvY2F0aW9uTGlzdDtiaW5h +cnkwDgYDVR0PAQH/BAQDAgEGMIGWBgNVHREEgY4wgYuBEGluZm9AZS1zemlnbm8uaHWkdzB1MSMw +IQYDVQQDDBpNaWNyb3NlYyBlLVN6aWduw7MgUm9vdCBDQTEWMBQGA1UECwwNZS1TemlnbsOzIEhT +WjEWMBQGA1UEChMNTWljcm9zZWMgS2Z0LjERMA8GA1UEBxMIQnVkYXBlc3QxCzAJBgNVBAYTAkhV +MIGsBgNVHSMEgaQwgaGAFMegSXUWYYTbMUuE0vE3QJDvTtz3oXakdDByMQswCQYDVQQGEwJIVTER +MA8GA1UEBxMIQnVkYXBlc3QxFjAUBgNVBAoTDU1pY3Jvc2VjIEx0ZC4xFDASBgNVBAsTC2UtU3pp +Z25vIENBMSIwIAYDVQQDExlNaWNyb3NlYyBlLVN6aWdubyBSb290IENBghEAzLjnv04pGv2i3Gal +HCwPETAdBgNVHQ4EFgQUx6BJdRZhhNsxS4TS8TdAkO9O3PcwDQYJKoZIhvcNAQEFBQADggEBANMT +nGZjWS7KXHAM/IO8VbH0jgdsZifOwTsgqRy7RlRw7lrMoHfqaEQn6/Ip3Xep1fvj1KcExJW4C+FE +aGAHQzAxQmHl7tnlJNUb3+FKG6qfx1/4ehHqE5MAyopYse7tDk2016g2JnzgOsHVV4Lxdbb9iV/a +86g4nzUGCM4ilb7N1fy+W955a9x6qWVmvrElWl/tftOsRm1M9DKHtCAE4Gx4sHfRhUZLphK3dehK +yVZs15KrnfVJONJPU+NVkBHbmJbGSfI+9J8b4PeI3CVimUTYc78/MPMMNz7UwiiAc7EBt51alhQB +S6kRnSlqLtBdgcDPsiBDxwPgN05dCtxZICU= +-----END CERTIFICATE----- + +Certigna +======== +-----BEGIN CERTIFICATE----- +MIIDqDCCApCgAwIBAgIJAP7c4wEPyUj/MA0GCSqGSIb3DQEBBQUAMDQxCzAJBgNVBAYTAkZSMRIw +EAYDVQQKDAlEaGlteW90aXMxETAPBgNVBAMMCENlcnRpZ25hMB4XDTA3MDYyOTE1MTMwNVoXDTI3 +MDYyOTE1MTMwNVowNDELMAkGA1UEBhMCRlIxEjAQBgNVBAoMCURoaW15b3RpczERMA8GA1UEAwwI +Q2VydGlnbmEwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDIaPHJ1tazNHUmgh7stL7q +XOEm7RFHYeGifBZ4QCHkYJ5ayGPhxLGWkv8YbWkj4Sti993iNi+RB7lIzw7sebYs5zRLcAglozyH +GxnygQcPOJAZ0xH+hrTy0V4eHpbNgGzOOzGTtvKg0KmVEn2lmsxryIRWijOp5yIVUxbwzBfsV1/p +ogqYCd7jX5xv3EjjhQsVWqa6n6xI4wmy9/Qy3l40vhx4XUJbzg4ij02Q130yGLMLLGq/jj8UEYkg +DncUtT2UCIf3JR7VsmAA7G8qKCVuKj4YYxclPz5EIBb2JsglrgVKtOdjLPOMFlN+XPsRGgjBRmKf +Irjxwo1p3Po6WAbfAgMBAAGjgbwwgbkwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUGu3+QTmQ +tCRZvgHyUtVF9lo53BEwZAYDVR0jBF0wW4AUGu3+QTmQtCRZvgHyUtVF9lo53BGhOKQ2MDQxCzAJ +BgNVBAYTAkZSMRIwEAYDVQQKDAlEaGlteW90aXMxETAPBgNVBAMMCENlcnRpZ25hggkA/tzjAQ/J +SP8wDgYDVR0PAQH/BAQDAgEGMBEGCWCGSAGG+EIBAQQEAwIABzANBgkqhkiG9w0BAQUFAAOCAQEA +hQMeknH2Qq/ho2Ge6/PAD/Kl1NqV5ta+aDY9fm4fTIrv0Q8hbV6lUmPOEvjvKtpv6zf+EwLHyzs+ +ImvaYS5/1HI93TDhHkxAGYwP15zRgzB7mFncfca5DClMoTOi62c6ZYTTluLtdkVwj7Ur3vkj1klu +PBS1xp81HlDQwY9qcEQCYsuuHWhBp6pX6FOqB9IG9tUUBguRA3UsbHK1YZWaDYu5Def131TN3ubY +1gkIl2PlwS6wt0QmwCbAr1UwnjvVNioZBPRcHv/PLLf/0P2HQBHVESO7SMAhqaQoLf0V+LBOK/Qw +WyH8EZE0vkHve52Xdf+XlcCWWC/qu0bXu+TZLg== +-----END CERTIFICATE----- + +AC Ra\xC3\xADz Certic\xC3\xA1mara S.A. +====================================== +-----BEGIN CERTIFICATE----- +MIIGZjCCBE6gAwIBAgIPB35Sk3vgFeNX8GmMy+wMMA0GCSqGSIb3DQEBBQUAMHsxCzAJBgNVBAYT +AkNPMUcwRQYDVQQKDD5Tb2NpZWRhZCBDYW1lcmFsIGRlIENlcnRpZmljYWNpw7NuIERpZ2l0YWwg +LSBDZXJ0aWPDoW1hcmEgUy5BLjEjMCEGA1UEAwwaQUMgUmHDrXogQ2VydGljw6FtYXJhIFMuQS4w +HhcNMDYxMTI3MjA0NjI5WhcNMzAwNDAyMjE0MjAyWjB7MQswCQYDVQQGEwJDTzFHMEUGA1UECgw+ +U29jaWVkYWQgQ2FtZXJhbCBkZSBDZXJ0aWZpY2FjacOzbiBEaWdpdGFsIC0gQ2VydGljw6FtYXJh +IFMuQS4xIzAhBgNVBAMMGkFDIFJhw616IENlcnRpY8OhbWFyYSBTLkEuMIICIjANBgkqhkiG9w0B +AQEFAAOCAg8AMIICCgKCAgEAq2uJo1PMSCMI+8PPUZYILrgIem08kBeGqentLhM0R7LQcNzJPNCN +yu5LF6vQhbCnIwTLqKL85XXbQMpiiY9QngE9JlsYhBzLfDe3fezTf3MZsGqy2IiKLUV0qPezuMDU +2s0iiXRNWhU5cxh0T7XrmafBHoi0wpOQY5fzp6cSsgkiBzPZkc0OnB8OIMfuuzONj8LSWKdf/WU3 +4ojC2I+GdV75LaeHM/J4Ny+LvB2GNzmxlPLYvEqcgxhaBvzz1NS6jBUJJfD5to0EfhcSM2tXSExP +2yYe68yQ54v5aHxwD6Mq0Do43zeX4lvegGHTgNiRg0JaTASJaBE8rF9ogEHMYELODVoqDA+bMMCm +8Ibbq0nXl21Ii/kDwFJnmxL3wvIumGVC2daa49AZMQyth9VXAnow6IYm+48jilSH5L887uvDdUhf +HjlvgWJsxS3EF1QZtzeNnDeRyPYL1epjb4OsOMLzP96a++EjYfDIJss2yKHzMI+ko6Kh3VOz3vCa +Mh+DkXkwwakfU5tTohVTP92dsxA7SH2JD/ztA/X7JWR1DhcZDY8AFmd5ekD8LVkH2ZD6mq093ICK +5lw1omdMEWux+IBkAC1vImHFrEsm5VoQgpukg3s0956JkSCXjrdCx2bD0Omk1vUgjcTDlaxECp1b +czwmPS9KvqfJpxAe+59QafMCAwEAAaOB5jCB4zAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQE +AwIBBjAdBgNVHQ4EFgQU0QnQ6dfOeXRU+Tows/RtLAMDG2gwgaAGA1UdIASBmDCBlTCBkgYEVR0g +ADCBiTArBggrBgEFBQcCARYfaHR0cDovL3d3dy5jZXJ0aWNhbWFyYS5jb20vZHBjLzBaBggrBgEF +BQcCAjBOGkxMaW1pdGFjaW9uZXMgZGUgZ2FyYW507WFzIGRlIGVzdGUgY2VydGlmaWNhZG8gc2Ug +cHVlZGVuIGVuY29udHJhciBlbiBsYSBEUEMuMA0GCSqGSIb3DQEBBQUAA4ICAQBclLW4RZFNjmEf +AygPU3zmpFmps4p6xbD/CHwso3EcIRNnoZUSQDWDg4902zNc8El2CoFS3UnUmjIz75uny3XlesuX +EpBcunvFm9+7OSPI/5jOCk0iAUgHforA1SBClETvv3eiiWdIG0ADBaGJ7M9i4z0ldma/Jre7Ir5v +/zlXdLp6yQGVwZVR6Kss+LGGIOk/yzVb0hfpKv6DExdA7ohiZVvVO2Dpezy4ydV/NgIlqmjCMRW3 +MGXrfx1IebHPOeJCgBbT9ZMj/EyXyVo3bHwi2ErN0o42gzmRkBDI8ck1fj+404HGIGQatlDCIaR4 +3NAvO2STdPCWkPHv+wlaNECW8DYSwaN0jJN+Qd53i+yG2dIPPy3RzECiiWZIHiCznCNZc6lEc7wk +eZBWN7PGKX6jD/EpOe9+XCgycDWs2rjIdWb8m0w5R44bb5tNAlQiM+9hup4phO9OSzNHdpdqy35f +/RWmnkJDW2ZaiogN9xa5P1FlK2Zqi9E4UqLWRhH6/JocdJ6PlwsCT2TG9WjTSy3/pDceiz+/RL5h +RqGEPQgnTIEgd4kI6mdAXmwIUV80WoyWaM3X94nCHNMyAK9Sy9NgWyo6R35rMDOhYil/SrnhLecU +Iw4OGEfhefwVVdCx/CVxY3UzHCMrr1zZ7Ud3YA47Dx7SwNxkBYn8eNZcLCZDqQ== +-----END CERTIFICATE----- + +TC TrustCenter Class 2 CA II +============================ +-----BEGIN CERTIFICATE----- +MIIEqjCCA5KgAwIBAgIOLmoAAQACH9dSISwRXDswDQYJKoZIhvcNAQEFBQAwdjELMAkGA1UEBhMC +REUxHDAaBgNVBAoTE1RDIFRydXN0Q2VudGVyIEdtYkgxIjAgBgNVBAsTGVRDIFRydXN0Q2VudGVy +IENsYXNzIDIgQ0ExJTAjBgNVBAMTHFRDIFRydXN0Q2VudGVyIENsYXNzIDIgQ0EgSUkwHhcNMDYw +MTEyMTQzODQzWhcNMjUxMjMxMjI1OTU5WjB2MQswCQYDVQQGEwJERTEcMBoGA1UEChMTVEMgVHJ1 +c3RDZW50ZXIgR21iSDEiMCAGA1UECxMZVEMgVHJ1c3RDZW50ZXIgQ2xhc3MgMiBDQTElMCMGA1UE +AxMcVEMgVHJ1c3RDZW50ZXIgQ2xhc3MgMiBDQSBJSTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC +AQoCggEBAKuAh5uO8MN8h9foJIIRszzdQ2Lu+MNF2ujhoF/RKrLqk2jftMjWQ+nEdVl//OEd+DFw +IxuInie5e/060smp6RQvkL4DUsFJzfb95AhmC1eKokKguNV/aVyQMrKXDcpK3EY+AlWJU+MaWss2 +xgdW94zPEfRMuzBwBJWl9jmM/XOBCH2JXjIeIqkiRUuwZi4wzJ9l/fzLganx4Duvo4bRierERXlQ +Xa7pIXSSTYtZgo+U4+lK8edJsBTj9WLL1XK9H7nSn6DNqPoByNkN39r8R52zyFTfSUrxIan+GE7u +SNQZu+995OKdy1u2bv/jzVrndIIFuoAlOMvkaZ6vQaoahPUCAwEAAaOCATQwggEwMA8GA1UdEwEB +/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBTjq1RMgKHbVkO3kUrL84J6E1wIqzCB +7QYDVR0fBIHlMIHiMIHfoIHcoIHZhjVodHRwOi8vd3d3LnRydXN0Y2VudGVyLmRlL2NybC92Mi90 +Y19jbGFzc18yX2NhX0lJLmNybIaBn2xkYXA6Ly93d3cudHJ1c3RjZW50ZXIuZGUvQ049VEMlMjBU +cnVzdENlbnRlciUyMENsYXNzJTIwMiUyMENBJTIwSUksTz1UQyUyMFRydXN0Q2VudGVyJTIwR21i +SCxPVT1yb290Y2VydHMsREM9dHJ1c3RjZW50ZXIsREM9ZGU/Y2VydGlmaWNhdGVSZXZvY2F0aW9u +TGlzdD9iYXNlPzANBgkqhkiG9w0BAQUFAAOCAQEAjNfffu4bgBCzg/XbEeprS6iSGNn3Bzn1LL4G +dXpoUxUc6krtXvwjshOg0wn/9vYua0Fxec3ibf2uWWuFHbhOIprtZjluS5TmVfwLG4t3wVMTZonZ +KNaL80VKY7f9ewthXbhtvsPcW3nS7Yblok2+XnR8au0WOB9/WIFaGusyiC2y8zl3gK9etmF1Kdsj +TYjKUCjLhdLTEKJZbtOTVAB6okaVhgWcqRmY5TFyDADiZ9lA4CQze28suVyrZZ0srHbqNZn1l7kP +JOzHdiEoZa5X6AeIdUpWoNIFOqTmjZKILPPy4cHGYdtBxceb9w4aUUXCYWvcZCcXjFq32nQozZfk +vQ== +-----END CERTIFICATE----- + +TC TrustCenter Class 3 CA II +============================ +-----BEGIN CERTIFICATE----- +MIIEqjCCA5KgAwIBAgIOSkcAAQAC5aBd1j8AUb8wDQYJKoZIhvcNAQEFBQAwdjELMAkGA1UEBhMC +REUxHDAaBgNVBAoTE1RDIFRydXN0Q2VudGVyIEdtYkgxIjAgBgNVBAsTGVRDIFRydXN0Q2VudGVy +IENsYXNzIDMgQ0ExJTAjBgNVBAMTHFRDIFRydXN0Q2VudGVyIENsYXNzIDMgQ0EgSUkwHhcNMDYw +MTEyMTQ0MTU3WhcNMjUxMjMxMjI1OTU5WjB2MQswCQYDVQQGEwJERTEcMBoGA1UEChMTVEMgVHJ1 +c3RDZW50ZXIgR21iSDEiMCAGA1UECxMZVEMgVHJ1c3RDZW50ZXIgQ2xhc3MgMyBDQTElMCMGA1UE +AxMcVEMgVHJ1c3RDZW50ZXIgQ2xhc3MgMyBDQSBJSTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC +AQoCggEBALTgu1G7OVyLBMVMeRwjhjEQY0NVJz/GRcekPewJDRoeIMJWHt4bNwcwIi9v8Qbxq63W +yKthoy9DxLCyLfzDlml7forkzMA5EpBCYMnMNWju2l+QVl/NHE1bWEnrDgFPZPosPIlY2C8u4rBo +6SI7dYnWRBpl8huXJh0obazovVkdKyT21oQDZogkAHhg8fir/gKya/si+zXmFtGt9i4S5Po1auUZ +uV3bOx4a+9P/FRQI2AlqukWdFHlgfa9Aigdzs5OW03Q0jTo3Kd5c7PXuLjHCINy+8U9/I1LZW+Jk +2ZyqBwi1Rb3R0DHBq1SfqdLDYmAD8bs5SpJKPQq5ncWg/jcCAwEAAaOCATQwggEwMA8GA1UdEwEB +/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBTUovyfs8PYA9NXXAek0CSnwPIA1DCB +7QYDVR0fBIHlMIHiMIHfoIHcoIHZhjVodHRwOi8vd3d3LnRydXN0Y2VudGVyLmRlL2NybC92Mi90 +Y19jbGFzc18zX2NhX0lJLmNybIaBn2xkYXA6Ly93d3cudHJ1c3RjZW50ZXIuZGUvQ049VEMlMjBU +cnVzdENlbnRlciUyMENsYXNzJTIwMyUyMENBJTIwSUksTz1UQyUyMFRydXN0Q2VudGVyJTIwR21i +SCxPVT1yb290Y2VydHMsREM9dHJ1c3RjZW50ZXIsREM9ZGU/Y2VydGlmaWNhdGVSZXZvY2F0aW9u +TGlzdD9iYXNlPzANBgkqhkiG9w0BAQUFAAOCAQEANmDkcPcGIEPZIxpC8vijsrlNirTzwppVMXzE +O2eatN9NDoqTSheLG43KieHPOh6sHfGcMrSOWXaiQYUlN6AT0PV8TtXqluJucsG7Kv5sbviRmEb8 +yRtXW+rIGjs/sFGYPAfaLFkB2otE6OF0/ado3VS6g0bsyEa1+K+XwDsJHI/OcpY9M1ZwvJbL2NV9 +IJqDnxrcOfHFcqMRA/07QlIp2+gB95tejNaNhk4Z+rwcvsUhpYeeeC422wlxo3I0+GzjBgnyXlal +092Y+tTmBvTwtiBjS+opvaqCZh77gaqnN60TGOaSw4HBM7uIHqHn4rS9MWwOUT1v+5ZWgOI2F9Hc +5A== +-----END CERTIFICATE----- + +TC TrustCenter Universal CA I +============================= +-----BEGIN CERTIFICATE----- +MIID3TCCAsWgAwIBAgIOHaIAAQAC7LdggHiNtgYwDQYJKoZIhvcNAQEFBQAweTELMAkGA1UEBhMC +REUxHDAaBgNVBAoTE1RDIFRydXN0Q2VudGVyIEdtYkgxJDAiBgNVBAsTG1RDIFRydXN0Q2VudGVy +IFVuaXZlcnNhbCBDQTEmMCQGA1UEAxMdVEMgVHJ1c3RDZW50ZXIgVW5pdmVyc2FsIENBIEkwHhcN +MDYwMzIyMTU1NDI4WhcNMjUxMjMxMjI1OTU5WjB5MQswCQYDVQQGEwJERTEcMBoGA1UEChMTVEMg +VHJ1c3RDZW50ZXIgR21iSDEkMCIGA1UECxMbVEMgVHJ1c3RDZW50ZXIgVW5pdmVyc2FsIENBMSYw +JAYDVQQDEx1UQyBUcnVzdENlbnRlciBVbml2ZXJzYWwgQ0EgSTCCASIwDQYJKoZIhvcNAQEBBQAD +ggEPADCCAQoCggEBAKR3I5ZEr5D0MacQ9CaHnPM42Q9e3s9B6DGtxnSRJJZ4Hgmgm5qVSkr1YnwC +qMqs+1oEdjneX/H5s7/zA1hV0qq34wQi0fiU2iIIAI3TfCZdzHd55yx4Oagmcw6iXSVphU9VDprv +xrlE4Vc93x9UIuVvZaozhDrzznq+VZeujRIPFDPiUHDDSYcTvFHe15gSWu86gzOSBnWLknwSaHtw +ag+1m7Z3W0hZneTvWq3zwZ7U10VOylY0Ibw+F1tvdwxIAUMpsN0/lm7mlaoMwCC2/T42J5zjXM9O +gdwZu5GQfezmlwQek8wiSdeXhrYTCjxDI3d+8NzmzSQfO4ObNDqDNOMCAwEAAaNjMGEwHwYDVR0j +BBgwFoAUkqR1LKSevoFE63n8isWVpesQdXMwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC +AYYwHQYDVR0OBBYEFJKkdSyknr6BROt5/IrFlaXrEHVzMA0GCSqGSIb3DQEBBQUAA4IBAQAo0uCG +1eb4e/CX3CJrO5UUVg8RMKWaTzqwOuAGy2X17caXJ/4l8lfmXpWMPmRgFVp/Lw0BxbFg/UU1z/Cy +vwbZ71q+s2IhtNerNXxTPqYn8aEt2hojnczd7Dwtnic0XQ/CNnm8yUpiLe1r2X1BQ3y2qsrtYbE3 +ghUJGooWMNjsydZHcnhLEEYUjl8Or+zHL6sQ17bxbuyGssLoDZJz3KL0Dzq/YSMQiZxIQG5wALPT +ujdEWBF6AmqI8Dc08BnprNRlc/ZpjGSUOnmFKbAWKwyCPwacx/0QK54PLLae4xW/2TYcuiUaUj0a +7CIMHOCkoj3w6DnPgcB77V0fb8XQC9eY +-----END CERTIFICATE----- + +Deutsche Telekom Root CA 2 +========================== +-----BEGIN CERTIFICATE----- +MIIDnzCCAoegAwIBAgIBJjANBgkqhkiG9w0BAQUFADBxMQswCQYDVQQGEwJERTEcMBoGA1UEChMT +RGV1dHNjaGUgVGVsZWtvbSBBRzEfMB0GA1UECxMWVC1UZWxlU2VjIFRydXN0IENlbnRlcjEjMCEG +A1UEAxMaRGV1dHNjaGUgVGVsZWtvbSBSb290IENBIDIwHhcNOTkwNzA5MTIxMTAwWhcNMTkwNzA5 +MjM1OTAwWjBxMQswCQYDVQQGEwJERTEcMBoGA1UEChMTRGV1dHNjaGUgVGVsZWtvbSBBRzEfMB0G +A1UECxMWVC1UZWxlU2VjIFRydXN0IENlbnRlcjEjMCEGA1UEAxMaRGV1dHNjaGUgVGVsZWtvbSBS +b290IENBIDIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCrC6M14IspFLEUha88EOQ5 +bzVdSq7d6mGNlUn0b2SjGmBmpKlAIoTZ1KXleJMOaAGtuU1cOs7TuKhCQN/Po7qCWWqSG6wcmtoI +KyUn+WkjR/Hg6yx6m/UTAtB+NHzCnjwAWav12gz1MjwrrFDa1sPeg5TKqAyZMg4ISFZbavva4VhY +AUlfckE8FQYBjl2tqriTtM2e66foai1SNNs671x1Udrb8zH57nGYMsRUFUQM+ZtV7a3fGAigo4aK +Se5TBY8ZTNXeWHmb0mocQqvF1afPaA+W5OFhmHZhyJF81j4A4pFQh+GdCuatl9Idxjp9y7zaAzTV +jlsB9WoHtxa2bkp/AgMBAAGjQjBAMB0GA1UdDgQWBBQxw3kbuvVT1xfgiXotF2wKsyudMzAPBgNV +HRMECDAGAQH/AgEFMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQUFAAOCAQEAlGRZrTlk5ynr +E/5aw4sTV8gEJPB0d8Bg42f76Ymmg7+Wgnxu1MM9756AbrsptJh6sTtU6zkXR34ajgv8HzFZMQSy +zhfzLMdiNlXiItiJVbSYSKpk+tYcNthEeFpaIzpXl/V6ME+un2pMSyuOoAPjPuCp1NJ70rOo4nI8 +rZ7/gFnkm0W09juwzTkZmDLl6iFhkOQxIY40sfcvNUqFENrnijchvllj4PKFiDFT1FQUhXB59C4G +dyd1Lx+4ivn+xbrYNuSD7Odlt79jWvNGr4GUN9RBjNYj1h7P9WgbRGOiWrqnNVmh5XAFmw4jV5mU +Cm26OWMohpLzGITY+9HPBVZkVw== +-----END CERTIFICATE----- + +ComSign Secured CA +================== +-----BEGIN CERTIFICATE----- +MIIDqzCCApOgAwIBAgIRAMcoRwmzuGxFjB36JPU2TukwDQYJKoZIhvcNAQEFBQAwPDEbMBkGA1UE +AxMSQ29tU2lnbiBTZWN1cmVkIENBMRAwDgYDVQQKEwdDb21TaWduMQswCQYDVQQGEwJJTDAeFw0w +NDAzMjQxMTM3MjBaFw0yOTAzMTYxNTA0NTZaMDwxGzAZBgNVBAMTEkNvbVNpZ24gU2VjdXJlZCBD +QTEQMA4GA1UEChMHQ29tU2lnbjELMAkGA1UEBhMCSUwwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw +ggEKAoIBAQDGtWhfHZQVw6QIVS3joFd67+l0Kru5fFdJGhFeTymHDEjWaueP1H5XJLkGieQcPOqs +49ohgHMhCu95mGwfCP+hUH3ymBvJVG8+pSjsIQQPRbsHPaHA+iqYHU4Gk/v1iDurX8sWv+bznkqH +7Rnqwp9D5PGBpX8QTz7RSmKtUxvLg/8HZaWSLWapW7ha9B20IZFKF3ueMv5WJDmyVIRD9YTC2LxB +kMyd1mja6YJQqTtoz7VdApRgFrFD2UNd3V2Hbuq7s8lr9gOUCXDeFhF6K+h2j0kQmHe5Y1yLM5d1 +9guMsqtb3nQgJT/j8xH5h2iGNXHDHYwt6+UarA9z1YJZQIDTAgMBAAGjgacwgaQwDAYDVR0TBAUw +AwEB/zBEBgNVHR8EPTA7MDmgN6A1hjNodHRwOi8vZmVkaXIuY29tc2lnbi5jby5pbC9jcmwvQ29t +U2lnblNlY3VyZWRDQS5jcmwwDgYDVR0PAQH/BAQDAgGGMB8GA1UdIwQYMBaAFMFL7XC29z58ADsA +j8c+DkWfHl3sMB0GA1UdDgQWBBTBS+1wtvc+fAA7AI/HPg5Fnx5d7DANBgkqhkiG9w0BAQUFAAOC +AQEAFs/ukhNQq3sUnjO2QiBq1BW9Cav8cujvR3qQrFHBZE7piL1DRYHjZiM/EoZNGeQFsOY3wo3a +BijJD4mkU6l1P7CW+6tMM1X5eCZGbxs2mPtCdsGCuY7e+0X5YxtiOzkGynd6qDwJz2w2PQ8KRUtp +FhpFfTMDZflScZAmlaxMDPWLkz/MdXSFmLr/YnpNH4n+rr2UAJm/EaXc4HnFFgt9AmEd6oX5AhVP +51qJThRv4zdLhfXBPGHg/QVBspJ/wx2g0K5SZGBrGMYmnNj1ZOQ2GmKfig8+/21OGVZOIJFsnzQz +OjRXUDpvgV4GxvU+fE6OK85lBi5d0ipTdF7Tbieejw== +-----END CERTIFICATE----- + +Cybertrust Global Root +====================== +-----BEGIN CERTIFICATE----- +MIIDoTCCAomgAwIBAgILBAAAAAABD4WqLUgwDQYJKoZIhvcNAQEFBQAwOzEYMBYGA1UEChMPQ3li +ZXJ0cnVzdCwgSW5jMR8wHQYDVQQDExZDeWJlcnRydXN0IEdsb2JhbCBSb290MB4XDTA2MTIxNTA4 +MDAwMFoXDTIxMTIxNTA4MDAwMFowOzEYMBYGA1UEChMPQ3liZXJ0cnVzdCwgSW5jMR8wHQYDVQQD +ExZDeWJlcnRydXN0IEdsb2JhbCBSb290MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA ++Mi8vRRQZhP/8NN57CPytxrHjoXxEnOmGaoQ25yiZXRadz5RfVb23CO21O1fWLE3TdVJDm71aofW +0ozSJ8bi/zafmGWgE07GKmSb1ZASzxQG9Dvj1Ci+6A74q05IlG2OlTEQXO2iLb3VOm2yHLtgwEZL +AfVJrn5GitB0jaEMAs7u/OePuGtm839EAL9mJRQr3RAwHQeWP032a7iPt3sMpTjr3kfb1V05/Iin +89cqdPHoWqI7n1C6poxFNcJQZZXcY4Lv3b93TZxiyWNzFtApD0mpSPCzqrdsxacwOUBdrsTiXSZT +8M4cIwhhqJQZugRiQOwfOHB3EgZxpzAYXSUnpQIDAQABo4GlMIGiMA4GA1UdDwEB/wQEAwIBBjAP +BgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBS2CHsNesysIEyGVjJez6tuhS1wVzA/BgNVHR8EODA2 +MDSgMqAwhi5odHRwOi8vd3d3Mi5wdWJsaWMtdHJ1c3QuY29tL2NybC9jdC9jdHJvb3QuY3JsMB8G +A1UdIwQYMBaAFLYIew16zKwgTIZWMl7Pq26FLXBXMA0GCSqGSIb3DQEBBQUAA4IBAQBW7wojoFRO +lZfJ+InaRcHUowAl9B8Tq7ejhVhpwjCt2BWKLePJzYFa+HMjWqd8BfP9IjsO0QbE2zZMcwSO5bAi +5MXzLqXZI+O4Tkogp24CJJ8iYGd7ix1yCcUxXOl5n4BHPa2hCwcUPUf/A2kaDAtE52Mlp3+yybh2 +hO0j9n0Hq0V+09+zv+mKts2oomcrUtW3ZfA5TGOgkXmTUg9U3YO7n9GPp1Nzw8v/MOx8BLjYRB+T +X3EJIrduPuocA06dGiBh+4E37F78CkWr1+cXVdCg6mCbpvbjjFspwgZgFJ0tl0ypkxWdYcQBX0jW +WL1WMRJOEcgh4LMRkWXbtKaIOM5V +-----END CERTIFICATE----- + +ePKI Root Certification Authority +================================= +-----BEGIN CERTIFICATE----- +MIIFsDCCA5igAwIBAgIQFci9ZUdcr7iXAF7kBtK8nTANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQG +EwJUVzEjMCEGA1UECgwaQ2h1bmdod2EgVGVsZWNvbSBDby4sIEx0ZC4xKjAoBgNVBAsMIWVQS0kg +Um9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wNDEyMjAwMjMxMjdaFw0zNDEyMjAwMjMx +MjdaMF4xCzAJBgNVBAYTAlRXMSMwIQYDVQQKDBpDaHVuZ2h3YSBUZWxlY29tIENvLiwgTHRkLjEq +MCgGA1UECwwhZVBLSSBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIICIjANBgkqhkiG9w0B +AQEFAAOCAg8AMIICCgKCAgEA4SUP7o3biDN1Z82tH306Tm2d0y8U82N0ywEhajfqhFAHSyZbCUNs +IZ5qyNUD9WBpj8zwIuQf5/dqIjG3LBXy4P4AakP/h2XGtRrBp0xtInAhijHyl3SJCRImHJ7K2RKi +lTza6We/CKBk49ZCt0Xvl/T29de1ShUCWH2YWEtgvM3XDZoTM1PRYfl61dd4s5oz9wCGzh1NlDiv +qOx4UXCKXBCDUSH3ET00hl7lSM2XgYI1TBnsZfZrxQWh7kcT1rMhJ5QQCtkkO7q+RBNGMD+XPNjX +12ruOzjjK9SXDrkb5wdJfzcq+Xd4z1TtW0ado4AOkUPB1ltfFLqfpo0kR0BZv3I4sjZsN/+Z0V0O +WQqraffAsgRFelQArr5T9rXn4fg8ozHSqf4hUmTFpmfwdQcGlBSBVcYn5AGPF8Fqcde+S/uUWH1+ +ETOxQvdibBjWzwloPn9s9h6PYq2lY9sJpx8iQkEeb5mKPtf5P0B6ebClAZLSnT0IFaUQAS2zMnao +lQ2zepr7BxB4EW/hj8e6DyUadCrlHJhBmd8hh+iVBmoKs2pHdmX2Os+PYhcZewoozRrSgx4hxyy/ +vv9haLdnG7t4TY3OZ+XkwY63I2binZB1NJipNiuKmpS5nezMirH4JYlcWrYvjB9teSSnUmjDhDXi +Zo1jDiVN1Rmy5nk3pyKdVDECAwEAAaNqMGgwHQYDVR0OBBYEFB4M97Zn8uGSJglFwFU5Lnc/Qkqi +MAwGA1UdEwQFMAMBAf8wOQYEZyoHAAQxMC8wLQIBADAJBgUrDgMCGgUAMAcGBWcqAwAABBRFsMLH +ClZ87lt4DJX5GFPBphzYEDANBgkqhkiG9w0BAQUFAAOCAgEACbODU1kBPpVJufGBuvl2ICO1J2B0 +1GqZNF5sAFPZn/KmsSQHRGoqxqWOeBLoR9lYGxMqXnmbnwoqZ6YlPwZpVnPDimZI+ymBV3QGypzq +KOg4ZyYr8dW1P2WT+DZdjo2NQCCHGervJ8A9tDkPJXtoUHRVnAxZfVo9QZQlUgjgRywVMRnVvwdV +xrsStZf0X4OFunHB2WyBEXYKCrC/gpf36j36+uwtqSiUO1bd0lEursC9CBWMd1I0ltabrNMdjmEP +NXubrjlpC2JgQCA2j6/7Nu4tCEoduL+bXPjqpRugc6bY+G7gMwRfaKonh+3ZwZCc7b3jajWvY9+r +GNm65ulK6lCKD2GTHuItGeIwlDWSXQ62B68ZgI9HkFFLLk3dheLSClIKF5r8GrBQAuUBo2M3IUxE +xJtRmREOc5wGj1QupyheRDmHVi03vYVElOEMSyycw5KFNGHLD7ibSkNS/jQ6fbjpKdx2qcgw+BRx +gMYeNkh0IkFch4LoGHGLQYlE535YW6i4jRPpp2zDR+2zGp1iro2C6pSe3VkQw63d4k3jMdXH7Ojy +sP6SHhYKGvzZ8/gntsm+HbRsZJB/9OTEW9c3rkIO3aQab3yIVMUWbuF6aC74Or8NpDyJO3inTmOD +BCEIZ43ygknQW/2xzQ+DhNQ+IIX3Sj0rnP0qCglN6oH4EZw= +-----END CERTIFICATE----- + +T\xc3\x9c\x42\xC4\xB0TAK UEKAE K\xC3\xB6k Sertifika Hizmet Sa\xC4\x9Flay\xc4\xb1\x63\xc4\xb1s\xc4\xb1 - S\xC3\xBCr\xC3\xBCm 3 +============================================================================================================================= +-----BEGIN CERTIFICATE----- +MIIFFzCCA/+gAwIBAgIBETANBgkqhkiG9w0BAQUFADCCASsxCzAJBgNVBAYTAlRSMRgwFgYDVQQH +DA9HZWJ6ZSAtIEtvY2FlbGkxRzBFBgNVBAoMPlTDvHJraXllIEJpbGltc2VsIHZlIFRla25vbG9q +aWsgQXJhxZ90xLFybWEgS3VydW11IC0gVMOcQsSwVEFLMUgwRgYDVQQLDD9VbHVzYWwgRWxla3Ry +b25payB2ZSBLcmlwdG9sb2ppIEFyYcWfdMSxcm1hIEVuc3RpdMO8c8O8IC0gVUVLQUUxIzAhBgNV +BAsMGkthbXUgU2VydGlmaWthc3lvbiBNZXJrZXppMUowSAYDVQQDDEFUw5xCxLBUQUsgVUVLQUUg +S8O2ayBTZXJ0aWZpa2EgSGl6bWV0IFNhxJ9sYXnEsWPEsXPEsSAtIFPDvHLDvG0gMzAeFw0wNzA4 +MjQxMTM3MDdaFw0xNzA4MjExMTM3MDdaMIIBKzELMAkGA1UEBhMCVFIxGDAWBgNVBAcMD0dlYnpl +IC0gS29jYWVsaTFHMEUGA1UECgw+VMO8cmtpeWUgQmlsaW1zZWwgdmUgVGVrbm9sb2ppayBBcmHF +n3TEsXJtYSBLdXJ1bXUgLSBUw5xCxLBUQUsxSDBGBgNVBAsMP1VsdXNhbCBFbGVrdHJvbmlrIHZl +IEtyaXB0b2xvamkgQXJhxZ90xLFybWEgRW5zdGl0w7xzw7wgLSBVRUtBRTEjMCEGA1UECwwaS2Ft +dSBTZXJ0aWZpa2FzeW9uIE1lcmtlemkxSjBIBgNVBAMMQVTDnELEsFRBSyBVRUtBRSBLw7ZrIFNl +cnRpZmlrYSBIaXptZXQgU2HEn2xhecSxY8Sxc8SxIC0gU8O8csO8bSAzMIIBIjANBgkqhkiG9w0B +AQEFAAOCAQ8AMIIBCgKCAQEAim1L/xCIOsP2fpTo6iBkcK4hgb46ezzb8R1Sf1n68yJMlaCQvEhO +Eav7t7WNeoMojCZG2E6VQIdhn8WebYGHV2yKO7Rm6sxA/OOqbLLLAdsyv9Lrhc+hDVXDWzhXcLh1 +xnnRFDDtG1hba+818qEhTsXOfJlfbLm4IpNQp81McGq+agV/E5wrHur+R84EpW+sky58K5+eeROR +6Oqeyjh1jmKwlZMq5d/pXpduIF9fhHpEORlAHLpVK/swsoHvhOPc7Jg4OQOFCKlUAwUp8MmPi+oL +hmUZEdPpCSPeaJMDyTYcIW7OjGbxmTDY17PDHfiBLqi9ggtm/oLL4eAagsNAgQIDAQABo0IwQDAd +BgNVHQ4EFgQUvYiHyY/2pAoLquvF/pEjnatKijIwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQF +MAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAB18+kmPNOm3JpIWmgV050vQbTlswyb2zrgxvMTfvCr4 +N5EY3ATIZJkrGG2AA1nJrvhY0D7twyOfaTyGOBye79oneNGEN3GKPEs5z35FBtYt2IpNeBLWrcLT +y9LQQfMmNkqblWwM7uXRQydmwYj3erMgbOqwaSvHIOgMA8RBBZniP+Rr+KCGgceExh/VS4ESshYh +LBOhgLJeDEoTniDYYkCrkOpkSi+sDQESeUWoL4cZaMjihccwsnX5OD+ywJO0a+IDRM5noN+J1q2M +dqMTw5RhK2vZbMEHCiIHhWyFJEapvj+LeISCfiQMnf2BN+MlqO02TpUsyZyQ2uypQjyttgI= +-----END CERTIFICATE----- + +Buypass Class 2 CA 1 +==================== +-----BEGIN CERTIFICATE----- +MIIDUzCCAjugAwIBAgIBATANBgkqhkiG9w0BAQUFADBLMQswCQYDVQQGEwJOTzEdMBsGA1UECgwU +QnV5cGFzcyBBUy05ODMxNjMzMjcxHTAbBgNVBAMMFEJ1eXBhc3MgQ2xhc3MgMiBDQSAxMB4XDTA2 +MTAxMzEwMjUwOVoXDTE2MTAxMzEwMjUwOVowSzELMAkGA1UEBhMCTk8xHTAbBgNVBAoMFEJ1eXBh +c3MgQVMtOTgzMTYzMzI3MR0wGwYDVQQDDBRCdXlwYXNzIENsYXNzIDIgQ0EgMTCCASIwDQYJKoZI +hvcNAQEBBQADggEPADCCAQoCggEBAIs8B0XY9t/mx8q6jUPFR42wWsE425KEHK8T1A9vNkYgxC7M +cXA0ojTTNy7Y3Tp3L8DrKehc0rWpkTSHIln+zNvnma+WwajHQN2lFYxuyHyXA8vmIPLXl18xoS83 +0r7uvqmtqEyeIWZDO6i88wmjONVZJMHCR3axiFyCO7srpgTXjAePzdVBHfCuuCkslFJgNJQ72uA4 +0Z0zPhX0kzLFANq1KWYOOngPIVJfAuWSeyXTkh4vFZ2B5J2O6O+JzhRMVB0cgRJNcKi+EAUXfh/R +uFdV7c27UsKwHnjCTTZoy1YmwVLBvXb3WNVyfh9EdrsAiR0WnVE1703CVu9r4Iw7DekCAwEAAaNC +MEAwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUP42aWYv8e3uco684sDntkHGA1sgwDgYDVR0P +AQH/BAQDAgEGMA0GCSqGSIb3DQEBBQUAA4IBAQAVGn4TirnoB6NLJzKyQJHyIdFkhb5jatLPgcIV +1Xp+DCmsNx4cfHZSldq1fyOhKXdlyTKdqC5Wq2B2zha0jX94wNWZUYN/Xtm+DKhQ7SLHrQVMdvvt +7h5HZPb3J31cKA9FxVxiXqaakZG3Uxcu3K1gnZZkOb1naLKuBctN518fV4bVIJwo+28TOPX2EZL2 +fZleHwzoq0QkKXJAPTZSr4xYkHPB7GEseaHsh7U/2k3ZIQAw3pDaDtMaSKk+hQsUi4y8QZ5q9w5w +wDX3OaJdZtB7WZ+oRxKaJyOkLY4ng5IgodcVf/EuGO70SH8vf/GhGLWhC5SgYiAynB321O+/TIho +-----END CERTIFICATE----- + +Buypass Class 3 CA 1 +==================== +-----BEGIN CERTIFICATE----- +MIIDUzCCAjugAwIBAgIBAjANBgkqhkiG9w0BAQUFADBLMQswCQYDVQQGEwJOTzEdMBsGA1UECgwU +QnV5cGFzcyBBUy05ODMxNjMzMjcxHTAbBgNVBAMMFEJ1eXBhc3MgQ2xhc3MgMyBDQSAxMB4XDTA1 +MDUwOTE0MTMwM1oXDTE1MDUwOTE0MTMwM1owSzELMAkGA1UEBhMCTk8xHTAbBgNVBAoMFEJ1eXBh +c3MgQVMtOTgzMTYzMzI3MR0wGwYDVQQDDBRCdXlwYXNzIENsYXNzIDMgQ0EgMTCCASIwDQYJKoZI +hvcNAQEBBQADggEPADCCAQoCggEBAKSO13TZKWTeXx+HgJHqTjnmGcZEC4DVC69TB4sSveZn8AKx +ifZgisRbsELRwCGoy+Gb72RRtqfPFfV0gGgEkKBYouZ0plNTVUhjP5JW3SROjvi6K//zNIqeKNc0 +n6wv1g/xpC+9UrJJhW05NfBEMJNGJPO251P7vGGvqaMU+8IXF4Rs4HyI+MkcVyzwPX6UvCWThOia +AJpFBUJXgPROztmuOfbIUxAMZTpHe2DC1vqRycZxbL2RhzyRhkmr8w+gbCZ2Xhysm3HljbybIR6c +1jh+JIAVMYKWsUnTYjdbiAwKYjT+p0h+mbEwi5A3lRyoH6UsjfRVyNvdWQrCrXig9IsCAwEAAaNC +MEAwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUOBTmyPCppAP0Tj4io1vy1uCtQHQwDgYDVR0P +AQH/BAQDAgEGMA0GCSqGSIb3DQEBBQUAA4IBAQABZ6OMySU9E2NdFm/soT4JXJEVKirZgCFPBdy7 +pYmrEzMqnji3jG8CcmPHc3ceCQa6Oyh7pEfJYWsICCD8igWKH7y6xsL+z27sEzNxZy5p+qksP2bA +EllNC1QCkoS72xLvg3BweMhT+t/Gxv/ciC8HwEmdMldg0/L2mSlf56oBzKwzqBwKu5HEA6BvtjT5 +htOzdlSY9EqBs1OdTUDs5XcTRa9bqh/YL0yCe/4qxFi7T/ye/QNlGioOw6UgFpRreaaiErS7GqQj +el/wroQk5PMr+4okoyeYZdowdXb8GZHo2+ubPzK/QJcHJrrM85SFSnonk8+QQtS4Wxam58tAA915 +-----END CERTIFICATE----- + +EBG Elektronik Sertifika Hizmet Sa\xC4\x9Flay\xc4\xb1\x63\xc4\xb1s\xc4\xb1 +========================================================================== +-----BEGIN CERTIFICATE----- +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 +-----END CERTIFICATE----- + +certSIGN ROOT CA +================ +-----BEGIN CERTIFICATE----- +MIIDODCCAiCgAwIBAgIGIAYFFnACMA0GCSqGSIb3DQEBBQUAMDsxCzAJBgNVBAYTAlJPMREwDwYD +VQQKEwhjZXJ0U0lHTjEZMBcGA1UECxMQY2VydFNJR04gUk9PVCBDQTAeFw0wNjA3MDQxNzIwMDRa +Fw0zMTA3MDQxNzIwMDRaMDsxCzAJBgNVBAYTAlJPMREwDwYDVQQKEwhjZXJ0U0lHTjEZMBcGA1UE +CxMQY2VydFNJR04gUk9PVCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALczuX7I +JUqOtdu0KBuqV5Do0SLTZLrTk+jUrIZhQGpgV2hUhE28alQCBf/fm5oqrl0Hj0rDKH/v+yv6efHH +rfAQUySQi2bJqIirr1qjAOm+ukbuW3N7LBeCgV5iLKECZbO9xSsAfsT8AzNXDe3i+s5dRdY4zTW2 +ssHQnIFKquSyAVwdj1+ZxLGt24gh65AIgoDzMKND5pCCrlUoSe1b16kQOA7+j0xbm0bqQfWwCHTD +0IgztnzXdN/chNFDDnU5oSVAKOp4yw4sLjmdjItuFhwvJoIQ4uNllAoEwF73XVv4EOLQunpL+943 +AAAaWyjj0pxzPjKHmKHJUS/X3qwzs08CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8B +Af8EBAMCAcYwHQYDVR0OBBYEFOCMm9slSbPxfIbWskKHC9BroNnkMA0GCSqGSIb3DQEBBQUAA4IB +AQA+0hyJLjX8+HXd5n9liPRyTMks1zJO890ZeUe9jjtbkw9QSSQTaxQGcu8J06Gh40CEyecYMnQ8 +SG4Pn0vU9x7Tk4ZkVJdjclDVVc/6IJMCopvDI5NOFlV2oHB5bc0hH88vLbwZ44gx+FkagQnIl6Z0 +x2DEW8xXjrJ1/RsCCdtZb3KTafcxQdaIOL+Hsr0Wefmq5L6IJd1hJyMctTEHBDa0GpC9oHRxUIlt +vBTjD4au8as+x6AJzKNI0eDbZOeStc+vckNwi/nDhDwTqn6Sm1dTk/pwwpEOMfmbZ13pljheX7Nz +TogVZ96edhBiIL5VaZVDADlN9u6wWk5JRFRYX0KD +-----END CERTIFICATE----- + +CNNIC ROOT +========== +-----BEGIN CERTIFICATE----- +MIIDVTCCAj2gAwIBAgIESTMAATANBgkqhkiG9w0BAQUFADAyMQswCQYDVQQGEwJDTjEOMAwGA1UE +ChMFQ05OSUMxEzARBgNVBAMTCkNOTklDIFJPT1QwHhcNMDcwNDE2MDcwOTE0WhcNMjcwNDE2MDcw +OTE0WjAyMQswCQYDVQQGEwJDTjEOMAwGA1UEChMFQ05OSUMxEzARBgNVBAMTCkNOTklDIFJPT1Qw +ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDTNfc/c3et6FtzF8LRb+1VvG7q6KR5smzD +o+/hn7E7SIX1mlwhIhAsxYLO2uOabjfhhyzcuQxauohV3/2q2x8x6gHx3zkBwRP9SFIhxFXf2tiz +VHa6dLG3fdfA6PZZxU3Iva0fFNrfWEQlMhkqx35+jq44sDB7R3IJMfAw28Mbdim7aXZOV/kbZKKT +VrdvmW7bCgScEeOAH8tjlBAKqeFkgjH5jCftppkA9nCTGPihNIaj3XrCGHn2emU1z5DrvTOTn1Or +czvmmzQgLx3vqR1jGqCA2wMv+SYahtKNu6m+UjqHZ0gNv7Sg2Ca+I19zN38m5pIEo3/PIKe38zrK +y5nLAgMBAAGjczBxMBEGCWCGSAGG+EIBAQQEAwIABzAfBgNVHSMEGDAWgBRl8jGtKvf33VKWCscC +wQ7vptU7ETAPBgNVHRMBAf8EBTADAQH/MAsGA1UdDwQEAwIB/jAdBgNVHQ4EFgQUZfIxrSr3991S +lgrHAsEO76bVOxEwDQYJKoZIhvcNAQEFBQADggEBAEs17szkrr/Dbq2flTtLP1se31cpolnKOOK5 +Gv+e5m4y3R6u6jW39ZORTtpC4cMXYFDy0VwmuYK36m3knITnA3kXr5g9lNvHugDnuL8BV8F3RTIM +O/G0HAiw/VGgod2aHRM2mm23xzy54cXZF/qD1T0VoDy7HgviyJA/qIYM/PmLXoXLT1tLYhFHxUV8 +BS9BsZ4QaRuZluBVeftOhpm4lNqGOGqTo+fLbuXf6iFViZx9fX+Y9QCJ7uOEwFyWtcVG6kbghVW2 +G8kS1sHNzYDzAgE8yGnLRUhj2JTQ7IUOO04RZfSCjKY9ri4ilAnIXOo8gV0WKgOXFlUJ24pBgp5m +mxE= +-----END CERTIFICATE----- + +ApplicationCA - Japanese Government +=================================== +-----BEGIN CERTIFICATE----- +MIIDoDCCAoigAwIBAgIBMTANBgkqhkiG9w0BAQUFADBDMQswCQYDVQQGEwJKUDEcMBoGA1UEChMT +SmFwYW5lc2UgR292ZXJubWVudDEWMBQGA1UECxMNQXBwbGljYXRpb25DQTAeFw0wNzEyMTIxNTAw +MDBaFw0xNzEyMTIxNTAwMDBaMEMxCzAJBgNVBAYTAkpQMRwwGgYDVQQKExNKYXBhbmVzZSBHb3Zl +cm5tZW50MRYwFAYDVQQLEw1BcHBsaWNhdGlvbkNBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB +CgKCAQEAp23gdE6Hj6UG3mii24aZS2QNcfAKBZuOquHMLtJqO8F6tJdhjYq+xpqcBrSGUeQ3DnR4 +fl+Kf5Sk10cI/VBaVuRorChzoHvpfxiSQE8tnfWuREhzNgaeZCw7NCPbXCbkcXmP1G55IrmTwcrN +wVbtiGrXoDkhBFcsovW8R0FPXjQilbUfKW1eSvNNcr5BViCH/OlQR9cwFO5cjFW6WY2H/CPek9AE +jP3vbb3QesmlOmpyM8ZKDQUXKi17safY1vC+9D/qDihtQWEjdnjDuGWk81quzMKq2edY3rZ+nYVu +nyoKb58DKTCXKB28t89UKU5RMfkntigm/qJj5kEW8DOYRwIDAQABo4GeMIGbMB0GA1UdDgQWBBRU +WssmP3HMlEYNllPqa0jQk/5CdTAOBgNVHQ8BAf8EBAMCAQYwWQYDVR0RBFIwUKROMEwxCzAJBgNV +BAYTAkpQMRgwFgYDVQQKDA/ml6XmnKzlm73mlL/lupwxIzAhBgNVBAsMGuOCouODl+ODquOCseOD +vOOCt+ODp+ODs0NBMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBADlqRHZ3ODrs +o2dGD/mLBqj7apAxzn7s2tGJfHrrLgy9mTLnsCTWw//1sogJhyzjVOGjprIIC8CFqMjSnHH2HZ9g +/DgzE+Ge3Atf2hZQKXsvcJEPmbo0NI2VdMV+eKlmXb3KIXdCEKxmJj3ekav9FfBv7WxfEPjzFvYD +io+nEhEMy/0/ecGc/WLuo89UDNErXxc+4z6/wCs+CZv+iKZ+tJIX/COUgb1up8WMwusRRdv4QcmW +dupwX3kSa+SjB1oF7ydJzyGfikwJcGapJsErEU4z0g781mzSDjJkaP+tBXhfAx2o45CsJOAPQKdL +rosot4LKGAfmt1t06SAZf7IbiVQ= +-----END CERTIFICATE----- + +GeoTrust Primary Certification Authority - G3 +============================================= +-----BEGIN CERTIFICATE----- +MIID/jCCAuagAwIBAgIQFaxulBmyeUtB9iepwxgPHzANBgkqhkiG9w0BAQsFADCBmDELMAkGA1UE +BhMCVVMxFjAUBgNVBAoTDUdlb1RydXN0IEluYy4xOTA3BgNVBAsTMChjKSAyMDA4IEdlb1RydXN0 +IEluYy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25seTE2MDQGA1UEAxMtR2VvVHJ1c3QgUHJpbWFy +eSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEczMB4XDTA4MDQwMjAwMDAwMFoXDTM3MTIwMTIz +NTk1OVowgZgxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMTkwNwYDVQQLEzAo +YykgMjAwOCBHZW9UcnVzdCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxNjA0BgNVBAMT +LUdlb1RydXN0IFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBHMzCCASIwDQYJKoZI +hvcNAQEBBQADggEPADCCAQoCggEBANziXmJYHTNXOTIz+uvLh4yn1ErdBojqZI4xmKU4kB6Yzy5j +K/BGvESyiaHAKAxJcCGVn2TAppMSAmUmhsalifD614SgcK9PGpc/BkTVyetyEH3kMSj7HGHmKAdE +c5IiaacDiGydY8hS2pgn5whMcD60yRLBxWeDXTPzAxHsatBT4tG6NmCUgLthY2xbF37fQJQeqw3C +IShwiP/WJmxsYAQlTlV+fe+/lEjetx3dcI0FX4ilm/LC7urRQEFtYjgdVgbFA0dRIBn8exALDmKu +dlW/X3e+PkkBUz2YJQN2JFodtNuJ6nnltrM7P7pMKEF/BqxqjsHQ9gUdfeZChuOl1UcCAwEAAaNC +MEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFMR5yo6hTgMdHNxr +2zFblD4/MH8tMA0GCSqGSIb3DQEBCwUAA4IBAQAtxRPPVoB7eni9n64smefv2t+UXglpp+duaIy9 +cr5HqQ6XErhK8WTTOd8lNNTBzU6B8A8ExCSzNJbGpqow32hhc9f5joWJ7w5elShKKiePEI4ufIbE +Ap7aDHdlDkQNkv39sxY2+hENHYwOB4lqKVb3cvTdFZx3NWZXqxNT2I7BQMXXExZacse3aQHEerGD +AWh9jUGhlBjBJVz88P6DAod8DQ3PLghcSkANPuyBYeYk28rgDi0Hsj5W3I31QYUHSJsMC8tJP33s +t/3LjWeJGqvtux6jAAgIFyqCXDFdRootD4abdNlF+9RAsXqqaC2Gspki4cErx5z481+oghLrGREt +-----END CERTIFICATE----- + +thawte Primary Root CA - G2 +=========================== +-----BEGIN CERTIFICATE----- +MIICiDCCAg2gAwIBAgIQNfwmXNmET8k9Jj1Xm67XVjAKBggqhkjOPQQDAzCBhDELMAkGA1UEBhMC +VVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5jLjE4MDYGA1UECxMvKGMpIDIwMDcgdGhhd3RlLCBJbmMu +IC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxJDAiBgNVBAMTG3RoYXd0ZSBQcmltYXJ5IFJvb3Qg +Q0EgLSBHMjAeFw0wNzExMDUwMDAwMDBaFw0zODAxMTgyMzU5NTlaMIGEMQswCQYDVQQGEwJVUzEV +MBMGA1UEChMMdGhhd3RlLCBJbmMuMTgwNgYDVQQLEy8oYykgMjAwNyB0aGF3dGUsIEluYy4gLSBG +b3IgYXV0aG9yaXplZCB1c2Ugb25seTEkMCIGA1UEAxMbdGhhd3RlIFByaW1hcnkgUm9vdCBDQSAt +IEcyMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEotWcgnuVnfFSeIf+iha/BebfowJPDQfGAFG6DAJS +LSKkQjnE/o/qycG+1E3/n3qe4rF8mq2nhglzh9HnmuN6papu+7qzcMBniKI11KOasf2twu8x+qi5 +8/sIxpHR+ymVo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQU +mtgAMADna3+FGO6Lts6KDPgR4bswCgYIKoZIzj0EAwMDaQAwZgIxAN344FdHW6fmCsO99YCKlzUN +G4k8VIZ3KMqh9HneteY4sPBlcIx/AlTCv//YoT7ZzwIxAMSNlPzcU9LcnXgWHxUzI1NS41oxXZ3K +rr0TKUQNJ1uo52icEvdYPy5yAlejj6EULg== +-----END CERTIFICATE----- + +thawte Primary Root CA - G3 +=========================== +-----BEGIN CERTIFICATE----- +MIIEKjCCAxKgAwIBAgIQYAGXt0an6rS0mtZLL/eQ+zANBgkqhkiG9w0BAQsFADCBrjELMAkGA1UE +BhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5jLjEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBTZXJ2 +aWNlcyBEaXZpc2lvbjE4MDYGA1UECxMvKGMpIDIwMDggdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhv +cml6ZWQgdXNlIG9ubHkxJDAiBgNVBAMTG3RoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EgLSBHMzAeFw0w +ODA0MDIwMDAwMDBaFw0zNzEyMDEyMzU5NTlaMIGuMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMdGhh +d3RlLCBJbmMuMSgwJgYDVQQLEx9DZXJ0aWZpY2F0aW9uIFNlcnZpY2VzIERpdmlzaW9uMTgwNgYD +VQQLEy8oYykgMjAwOCB0aGF3dGUsIEluYy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25seTEkMCIG +A1UEAxMbdGhhd3RlIFByaW1hcnkgUm9vdCBDQSAtIEczMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A +MIIBCgKCAQEAsr8nLPvb2FvdeHsbnndmgcs+vHyu86YnmjSjaDFxODNi5PNxZnmxqWWjpYvVj2At +P0LMqmsywCPLLEHd5N/8YZzic7IilRFDGF/Eth9XbAoFWCLINkw6fKXRz4aviKdEAhN0cXMKQlkC ++BsUa0Lfb1+6a4KinVvnSr0eAXLbS3ToO39/fR8EtCab4LRarEc9VbjXsCZSKAExQGbY2SS99irY +7CFJXJv2eul/VTV+lmuNk5Mny5K76qxAwJ/C+IDPXfRa3M50hqY+bAtTyr2SzhkGcuYMXDhpxwTW +vGzOW/b3aJzcJRVIiKHpqfiYnODz1TEoYRFsZ5aNOZnLwkUkOQIDAQABo0IwQDAPBgNVHRMBAf8E +BTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUrWyqlGCc7eT/+j4KdCtjA/e2Wb8wDQYJ +KoZIhvcNAQELBQADggEBABpA2JVlrAmSicY59BDlqQ5mU1143vokkbvnRFHfxhY0Cu9qRFHqKweK +A3rD6z8KLFIWoCtDuSWQP3CpMyVtRRooOyfPqsMpQhvfO0zAMzRbQYi/aytlryjvsvXDqmbOe1bu +t8jLZ8HJnBoYuMTDSQPxYA5QzUbF83d597YV4Djbxy8ooAw/dyZ02SUS2jHaGh7cKUGRIjxpp7sC +8rZcJwOJ9Abqm+RyguOhCcHpABnTPtRwa7pxpqpYrvS76Wy274fMm7v/OeZWYdMKp8RcTGB7BXcm +er/YB1IsYvdwY9k5vG8cwnncdimvzsUsZAReiDZuMdRAGmI0Nj81Aa6sY6A= +-----END CERTIFICATE----- + +GeoTrust Primary Certification Authority - G2 +============================================= +-----BEGIN CERTIFICATE----- +MIICrjCCAjWgAwIBAgIQPLL0SAoA4v7rJDteYD7DazAKBggqhkjOPQQDAzCBmDELMAkGA1UEBhMC +VVMxFjAUBgNVBAoTDUdlb1RydXN0IEluYy4xOTA3BgNVBAsTMChjKSAyMDA3IEdlb1RydXN0IElu +Yy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25seTE2MDQGA1UEAxMtR2VvVHJ1c3QgUHJpbWFyeSBD +ZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEcyMB4XDTA3MTEwNTAwMDAwMFoXDTM4MDExODIzNTk1 +OVowgZgxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMTkwNwYDVQQLEzAoYykg +MjAwNyBHZW9UcnVzdCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxNjA0BgNVBAMTLUdl +b1RydXN0IFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBHMjB2MBAGByqGSM49AgEG +BSuBBAAiA2IABBWx6P0DFUPlrOuHNxFi79KDNlJ9RVcLSo17VDs6bl8VAsBQps8lL33KSLjHUGMc +KiEIfJo22Av+0SbFWDEwKCXzXV2juLaltJLtbCyf691DiaI8S0iRHVDsJt/WYC69IaNCMEAwDwYD +VR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFBVfNVdRVfslsq0DafwBo/q+ +EVXVMAoGCCqGSM49BAMDA2cAMGQCMGSWWaboCd6LuvpaiIjwH5HTRqjySkwCY/tsXzjbLkGTqQ7m +ndwxHLKgpxgceeHHNgIwOlavmnRs9vuD4DPTCF+hnMJbn0bWtsuRBmOiBuczrD6ogRLQy7rQkgu2 +npaqBA+K +-----END CERTIFICATE----- + +VeriSign Universal Root Certification Authority +=============================================== +-----BEGIN CERTIFICATE----- +MIIEuTCCA6GgAwIBAgIQQBrEZCGzEyEDDrvkEhrFHTANBgkqhkiG9w0BAQsFADCBvTELMAkGA1UE +BhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZWZXJpU2lnbiBUcnVzdCBO +ZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwOCBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVk +IHVzZSBvbmx5MTgwNgYDVQQDEy9WZXJpU2lnbiBVbml2ZXJzYWwgUm9vdCBDZXJ0aWZpY2F0aW9u +IEF1dGhvcml0eTAeFw0wODA0MDIwMDAwMDBaFw0zNzEyMDEyMzU5NTlaMIG9MQswCQYDVQQGEwJV +UzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRydXN0IE5ldHdv +cmsxOjA4BgNVBAsTMShjKSAyMDA4IFZlcmlTaWduLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNl +IG9ubHkxODA2BgNVBAMTL1ZlcmlTaWduIFVuaXZlcnNhbCBSb290IENlcnRpZmljYXRpb24gQXV0 +aG9yaXR5MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAx2E3XrEBNNti1xWb/1hajCMj +1mCOkdeQmIN65lgZOIzF9uVkhbSicfvtvbnazU0AtMgtc6XHaXGVHzk8skQHnOgO+k1KxCHfKWGP +MiJhgsWHH26MfF8WIFFE0XBPV+rjHOPMee5Y2A7Cs0WTwCznmhcrewA3ekEzeOEz4vMQGn+HLL72 +9fdC4uW/h2KJXwBL38Xd5HVEMkE6HnFuacsLdUYI0crSK5XQz/u5QGtkjFdN/BMReYTtXlT2NJ8I +AfMQJQYXStrxHXpma5hgZqTZ79IugvHw7wnqRMkVauIDbjPTrJ9VAMf2CGqUuV/c4DPxhGD5WycR +tPwW8rtWaoAljQIDAQABo4GyMIGvMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMG0G +CCsGAQUFBwEMBGEwX6FdoFswWTBXMFUWCWltYWdlL2dpZjAhMB8wBwYFKw4DAhoEFI/l0xqGrI2O +a8PPgGrUSBgsexkuMCUWI2h0dHA6Ly9sb2dvLnZlcmlzaWduLmNvbS92c2xvZ28uZ2lmMB0GA1Ud +DgQWBBS2d/ppSEefUxLVwuoHMnYH0ZcHGTANBgkqhkiG9w0BAQsFAAOCAQEASvj4sAPmLGd75JR3 +Y8xuTPl9Dg3cyLk1uXBPY/ok+myDjEedO2Pzmvl2MpWRsXe8rJq+seQxIcaBlVZaDrHC1LGmWazx +Y8u4TB1ZkErvkBYoH1quEPuBUDgMbMzxPcP1Y+Oz4yHJJDnp/RVmRvQbEdBNc6N9Rvk97ahfYtTx +P/jgdFcrGJ2BtMQo2pSXpXDrrB2+BxHw1dvd5Yzw1TKwg+ZX4o+/vqGqvz0dtdQ46tewXDpPaj+P +wGZsY6rp2aQW9IHRlRQOfc2VNNnSj3BzgXucfr2YYdhFh5iQxeuGMMY1v/D/w1WIg0vvBZIGcfK4 +mJO37M2CYfE45k+XmCpajQ== +-----END CERTIFICATE----- + +VeriSign Class 3 Public Primary Certification Authority - G4 +============================================================ +-----BEGIN CERTIFICATE----- +MIIDhDCCAwqgAwIBAgIQL4D+I4wOIg9IZxIokYesszAKBggqhkjOPQQDAzCByjELMAkGA1UEBhMC +VVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZWZXJpU2lnbiBUcnVzdCBOZXR3 +b3JrMTowOAYDVQQLEzEoYykgMjAwNyBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVz +ZSBvbmx5MUUwQwYDVQQDEzxWZXJpU2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmlj +YXRpb24gQXV0aG9yaXR5IC0gRzQwHhcNMDcxMTA1MDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCByjEL +MAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZWZXJpU2lnbiBU +cnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNyBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRo +b3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxWZXJpU2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5 +IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRzQwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAASnVnp8 +Utpkmw4tXNherJI9/gHmGUo9FANL+mAnINmDiWn6VMaaGF5VKmTeBvaNSjutEDxlPZCIBIngMGGz +rl0Bp3vefLK+ymVhAIau2o970ImtTR1ZmkGxvEeA3J5iw/mjgbIwga8wDwYDVR0TAQH/BAUwAwEB +/zAOBgNVHQ8BAf8EBAMCAQYwbQYIKwYBBQUHAQwEYTBfoV2gWzBZMFcwVRYJaW1hZ2UvZ2lmMCEw +HzAHBgUrDgMCGgQUj+XTGoasjY5rw8+AatRIGCx7GS4wJRYjaHR0cDovL2xvZ28udmVyaXNpZ24u +Y29tL3ZzbG9nby5naWYwHQYDVR0OBBYEFLMWkf3upm7ktS5Jj4d4gYDs5bG1MAoGCCqGSM49BAMD +A2gAMGUCMGYhDBgmYFo4e1ZC4Kf8NoRRkSAsdk1DPcQdhCPQrNZ8NQbOzWm9kA3bbEhCHQ6qQgIx +AJw9SDkjOVgaFRJZap7v1VmyHVIsmXHNxynfGyphe3HR3vPA5Q06Sqotp9iGKt0uEA== +-----END CERTIFICATE----- + +NetLock Arany (Class Gold) Főtanúsítvány +============================================ +-----BEGIN CERTIFICATE----- +MIIEFTCCAv2gAwIBAgIGSUEs5AAQMA0GCSqGSIb3DQEBCwUAMIGnMQswCQYDVQQGEwJIVTERMA8G +A1UEBwwIQnVkYXBlc3QxFTATBgNVBAoMDE5ldExvY2sgS2Z0LjE3MDUGA1UECwwuVGFuw7pzw610 +dsOhbnlraWFkw7NrIChDZXJ0aWZpY2F0aW9uIFNlcnZpY2VzKTE1MDMGA1UEAwwsTmV0TG9jayBB +cmFueSAoQ2xhc3MgR29sZCkgRsWRdGFuw7pzw610dsOhbnkwHhcNMDgxMjExMTUwODIxWhcNMjgx +MjA2MTUwODIxWjCBpzELMAkGA1UEBhMCSFUxETAPBgNVBAcMCEJ1ZGFwZXN0MRUwEwYDVQQKDAxO +ZXRMb2NrIEtmdC4xNzA1BgNVBAsMLlRhbsO6c8OtdHbDoW55a2lhZMOzayAoQ2VydGlmaWNhdGlv +biBTZXJ2aWNlcykxNTAzBgNVBAMMLE5ldExvY2sgQXJhbnkgKENsYXNzIEdvbGQpIEbFkXRhbsO6 +c8OtdHbDoW55MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxCRec75LbRTDofTjl5Bu +0jBFHjzuZ9lk4BqKf8owyoPjIMHj9DrTlF8afFttvzBPhCf2nx9JvMaZCpDyD/V/Q4Q3Y1GLeqVw +/HpYzY6b7cNGbIRwXdrzAZAj/E4wqX7hJ2Pn7WQ8oLjJM2P+FpD/sLj916jAwJRDC7bVWaaeVtAk +H3B5r9s5VA1lddkVQZQBr17s9o3x/61k/iCa11zr/qYfCGSji3ZVrR47KGAuhyXoqq8fxmRGILdw +fzzeSNuWU7c5d+Qa4scWhHaXWy+7GRWF+GmF9ZmnqfI0p6m2pgP8b4Y9VHx2BJtr+UBdADTHLpl1 +neWIA6pN+APSQnbAGwIDAKiLo0UwQzASBgNVHRMBAf8ECDAGAQH/AgEEMA4GA1UdDwEB/wQEAwIB +BjAdBgNVHQ4EFgQUzPpnk/C2uNClwB7zU/2MU9+D15YwDQYJKoZIhvcNAQELBQADggEBAKt/7hwW +qZw8UQCgwBEIBaeZ5m8BiFRhbvG5GK1Krf6BQCOUL/t1fC8oS2IkgYIL9WHxHG64YTjrgfpioTta +YtOUZcTh5m2C+C8lcLIhJsFyUR+MLMOEkMNaj7rP9KdlpeuY0fsFskZ1FSNqb4VjMIDw1Z4fKRzC +bLBQWV2QWzuoDTDPv31/zvGdg73JRm4gpvlhUbohL3u+pRVjodSVh/GeufOJ8z2FuLjbvrW5Kfna +NwUASZQDhETnv0Mxz3WLJdH0pmT1kvarBes96aULNmLazAZfNou2XjG4Kvte9nHfRCaexOYNkbQu +dZWAUWpLMKawYqGT8ZvYzsRjdT9ZR7E= +-----END CERTIFICATE----- + +Staat der Nederlanden Root CA - G2 +================================== +-----BEGIN CERTIFICATE----- +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 +66+KAQ== +-----END CERTIFICATE----- + +CA Disig +======== +-----BEGIN CERTIFICATE----- +MIIEDzCCAvegAwIBAgIBATANBgkqhkiG9w0BAQUFADBKMQswCQYDVQQGEwJTSzETMBEGA1UEBxMK +QnJhdGlzbGF2YTETMBEGA1UEChMKRGlzaWcgYS5zLjERMA8GA1UEAxMIQ0EgRGlzaWcwHhcNMDYw +MzIyMDEzOTM0WhcNMTYwMzIyMDEzOTM0WjBKMQswCQYDVQQGEwJTSzETMBEGA1UEBxMKQnJhdGlz +bGF2YTETMBEGA1UEChMKRGlzaWcgYS5zLjERMA8GA1UEAxMIQ0EgRGlzaWcwggEiMA0GCSqGSIb3 +DQEBAQUAA4IBDwAwggEKAoIBAQCS9jHBfYj9mQGp2HvycXXxMcbzdWb6UShGhJd4NLxs/LxFWYgm +GErENx+hSkS943EE9UQX4j/8SFhvXJ56CbpRNyIjZkMhsDxkovhqFQ4/61HhVKndBpnXmjxUizkD +Pw/Fzsbrg3ICqB9x8y34dQjbYkzo+s7552oftms1grrijxaSfQUMbEYDXcDtab86wYqg6I7ZuUUo +hwjstMoVvoLdtUSLLa2GDGhibYVW8qwUYzrG0ZmsNHhWS8+2rT+MitcE5eN4TPWGqvWP+j1scaMt +ymfraHtuM6kMgiioTGohQBUgDCZbg8KpFhXAJIJdKxatymP2dACw30PEEGBWZ2NFAgMBAAGjgf8w +gfwwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUjbJJaJ1yCCW5wCf1UJNWSEZx+Y8wDgYDVR0P +AQH/BAQDAgEGMDYGA1UdEQQvMC2BE2Nhb3BlcmF0b3JAZGlzaWcuc2uGFmh0dHA6Ly93d3cuZGlz +aWcuc2svY2EwZgYDVR0fBF8wXTAtoCugKYYnaHR0cDovL3d3dy5kaXNpZy5zay9jYS9jcmwvY2Ff +ZGlzaWcuY3JsMCygKqAohiZodHRwOi8vY2EuZGlzaWcuc2svY2EvY3JsL2NhX2Rpc2lnLmNybDAa +BgNVHSAEEzARMA8GDSuBHpGT5goAAAABAQEwDQYJKoZIhvcNAQEFBQADggEBAF00dGFMrzvY/59t +WDYcPQuBDRIrRhCA/ec8J9B6yKm2fnQwM6M6int0wHl5QpNt/7EpFIKrIYwvF/k/Ji/1WcbvgAa3 +mkkp7M5+cTxqEEHA9tOasnxakZzArFvITV734VP/Q3f8nktnbNfzg9Gg4H8l37iYC5oyOGwwoPP/ +CBUz91BKez6jPiCp3C9WgArtQVCwyfTssuMmRAAOb54GvCKWU3BlxFAKRmukLyeBEicTXxChds6K +ezfqwzlhA5WYOudsiCUI/HloDYd9Yvi0X/vF2Ey9WLw/Q1vUHgFNPGO+I++MzVpQuGhU+QqZMxEA +4Z7CRneC9VkGjCFMhwnN5ag= +-----END CERTIFICATE----- + +Juur-SK +======= +-----BEGIN CERTIFICATE----- +MIIE5jCCA86gAwIBAgIEO45L/DANBgkqhkiG9w0BAQUFADBdMRgwFgYJKoZIhvcNAQkBFglwa2lA +c2suZWUxCzAJBgNVBAYTAkVFMSIwIAYDVQQKExlBUyBTZXJ0aWZpdHNlZXJpbWlza2Vza3VzMRAw +DgYDVQQDEwdKdXVyLVNLMB4XDTAxMDgzMDE0MjMwMVoXDTE2MDgyNjE0MjMwMVowXTEYMBYGCSqG +SIb3DQEJARYJcGtpQHNrLmVlMQswCQYDVQQGEwJFRTEiMCAGA1UEChMZQVMgU2VydGlmaXRzZWVy +aW1pc2tlc2t1czEQMA4GA1UEAxMHSnV1ci1TSzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC +ggEBAIFxNj4zB9bjMI0TfncyRsvPGbJgMUaXhvSYRqTCZUXP00B841oiqBB4M8yIsdOBSvZiF3tf +TQou0M+LI+5PAk676w7KvRhj6IAcjeEcjT3g/1tf6mTll+g/mX8MCgkzABpTpyHhOEvWgxutr2TC ++Rx6jGZITWYfGAriPrsfB2WThbkasLnE+w0R9vXW+RvHLCu3GFH+4Hv2qEivbDtPL+/40UceJlfw +UR0zlv/vWT3aTdEVNMfqPxZIe5EcgEMPPbgFPtGzlc3Yyg/CQ2fbt5PgIoIuvvVoKIO5wTtpeyDa +Tpxt4brNj3pssAki14sL2xzVWiZbDcDq5WDQn/413z8CAwEAAaOCAawwggGoMA8GA1UdEwEB/wQF +MAMBAf8wggEWBgNVHSAEggENMIIBCTCCAQUGCisGAQQBzh8BAQEwgfYwgdAGCCsGAQUFBwICMIHD +HoHAAFMAZQBlACAAcwBlAHIAdABpAGYAaQBrAGEAYQB0ACAAbwBuACAAdgDkAGwAagBhAHMAdABh +AHQAdQBkACAAQQBTAC0AaQBzACAAUwBlAHIAdABpAGYAaQB0AHMAZQBlAHIAaQBtAGkAcwBrAGUA +cwBrAHUAcwAgAGEAbABhAG0ALQBTAEsAIABzAGUAcgB0AGkAZgBpAGsAYQBhAHQAaQBkAGUAIABr +AGkAbgBuAGkAdABhAG0AaQBzAGUAawBzMCEGCCsGAQUFBwIBFhVodHRwOi8vd3d3LnNrLmVlL2Nw +cy8wKwYDVR0fBCQwIjAgoB6gHIYaaHR0cDovL3d3dy5zay5lZS9qdXVyL2NybC8wHQYDVR0OBBYE +FASqekej5ImvGs8KQKcYP2/v6X2+MB8GA1UdIwQYMBaAFASqekej5ImvGs8KQKcYP2/v6X2+MA4G +A1UdDwEB/wQEAwIB5jANBgkqhkiG9w0BAQUFAAOCAQEAe8EYlFOiCfP+JmeaUOTDBS8rNXiRTHyo +ERF5TElZrMj3hWVcRrs7EKACr81Ptcw2Kuxd/u+gkcm2k298gFTsxwhwDY77guwqYHhpNjbRxZyL +abVAyJRld/JXIWY7zoVAtjNjGr95HvxcHdMdkxuLDF2FvZkwMhgJkVLpfKG6/2SSmuz+Ne6ML678 +IIbsSt4beDI3poHSna9aEhbKmVv8b20OxaAehsmR0FyYgl9jDIpaq9iVpszLita/ZEuOyoqysOkh +Mp6qqIWYNIE5ITuoOlIyPfZrN4YGWhWY3PARZv40ILcD9EEQfTmEeZZyY7aWAuVrua0ZTbvGRNs2 +yyqcjg== +-----END CERTIFICATE----- + +Hongkong Post Root CA 1 +======================= +-----BEGIN CERTIFICATE----- +MIIDMDCCAhigAwIBAgICA+gwDQYJKoZIhvcNAQEFBQAwRzELMAkGA1UEBhMCSEsxFjAUBgNVBAoT +DUhvbmdrb25nIFBvc3QxIDAeBgNVBAMTF0hvbmdrb25nIFBvc3QgUm9vdCBDQSAxMB4XDTAzMDUx +NTA1MTMxNFoXDTIzMDUxNTA0NTIyOVowRzELMAkGA1UEBhMCSEsxFjAUBgNVBAoTDUhvbmdrb25n +IFBvc3QxIDAeBgNVBAMTF0hvbmdrb25nIFBvc3QgUm9vdCBDQSAxMIIBIjANBgkqhkiG9w0BAQEF +AAOCAQ8AMIIBCgKCAQEArP84tulmAknjorThkPlAj3n54r15/gK97iSSHSL22oVyaf7XPwnU3ZG1 +ApzQjVrhVcNQhrkpJsLj2aDxaQMoIIBFIi1WpztUlVYiWR8o3x8gPW2iNr4joLFutbEnPzlTCeqr +auh0ssJlXI6/fMN4hM2eFvz1Lk8gKgifd/PFHsSaUmYeSF7jEAaPIpjhZY4bXSNmO7ilMlHIhqqh +qZ5/dpTCpmy3QfDVyAY45tQM4vM7TG1QjMSDJ8EThFk9nnV0ttgCXjqQesBCNnLsak3c78QA3xMY +V18meMjWCnl3v/evt3a5pQuEF10Q6m/hq5URX208o1xNg1vysxmKgIsLhwIDAQABoyYwJDASBgNV +HRMBAf8ECDAGAQH/AgEDMA4GA1UdDwEB/wQEAwIBxjANBgkqhkiG9w0BAQUFAAOCAQEADkbVPK7i +h9legYsCmEEIjEy82tvuJxuC52pF7BaLT4Wg87JwvVqWuspube5Gi27nKi6Wsxkz67SfqLI37pio +l7Yutmcn1KZJ/RyTZXaeQi/cImyaT/JaFTmxcdcrUehtHJjA2Sr0oYJ71clBoiMBdDhViw+5Lmei +IAQ32pwL0xch4I+XeTRvhEgCIDMb5jREn5Fw9IBehEPCKdJsEhTkYY2sEJCehFC78JZvRZ+K88ps +T/oROhUVRsPNH4NbLUES7VBnQRM9IauUiqpOfMGx+6fWtScvl6tu4B3i0RwsH0Ti/L6RoZz71ilT +c4afU9hDDl3WY4JxHYB0yvbiAmvZWg== +-----END CERTIFICATE----- + +SecureSign RootCA11 +=================== +-----BEGIN CERTIFICATE----- +MIIDbTCCAlWgAwIBAgIBATANBgkqhkiG9w0BAQUFADBYMQswCQYDVQQGEwJKUDErMCkGA1UEChMi +SmFwYW4gQ2VydGlmaWNhdGlvbiBTZXJ2aWNlcywgSW5jLjEcMBoGA1UEAxMTU2VjdXJlU2lnbiBS +b290Q0ExMTAeFw0wOTA0MDgwNDU2NDdaFw0yOTA0MDgwNDU2NDdaMFgxCzAJBgNVBAYTAkpQMSsw +KQYDVQQKEyJKYXBhbiBDZXJ0aWZpY2F0aW9uIFNlcnZpY2VzLCBJbmMuMRwwGgYDVQQDExNTZWN1 +cmVTaWduIFJvb3RDQTExMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA/XeqpRyQBTvL +TJszi1oURaTnkBbR31fSIRCkF/3frNYfp+TbfPfs37gD2pRY/V1yfIw/XwFndBWW4wI8h9uuywGO +wvNmxoVF9ALGOrVisq/6nL+k5tSAMJjzDbaTj6nU2DbysPyKyiyhFTOVMdrAG/LuYpmGYz+/3ZMq +g6h2uRMft85OQoWPIucuGvKVCbIFtUROd6EgvanyTgp9UK31BQ1FT0Zx/Sg+U/sE2C3XZR1KG/rP +O7AxmjVuyIsG0wCR8pQIZUyxNAYAeoni8McDWc/V1uinMrPmmECGxc0nEovMe863ETxiYAcjPitA +bpSACW22s293bzUIUPsCh8U+iQIDAQABo0IwQDAdBgNVHQ4EFgQUW/hNT7KlhtQ60vFjmqC+CfZX +t94wDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAKCh +OBZmLqdWHyGcBvod7bkixTgm2E5P7KN/ed5GIaGHd48HCJqypMWvDzKYC3xmKbabfSVSSUOrTC4r +bnpwrxYO4wJs+0LmGJ1F2FXI6Dvd5+H0LgscNFxsWEr7jIhQX5Ucv+2rIrVls4W6ng+4reV6G4pQ +Oh29Dbx7VFALuUKvVaAYga1lme++5Jy/xIWrQbJUb9wlze144o4MjQlJ3WN7WmmWAiGovVJZ6X01 +y8hSyn+B/tlr0/cR7SXf+Of5pPpyl4RTDaXQMhhRdlkUbA/r7F+AjHVDg8OFmP9Mni0N5HeDk061 +lgeLKBObjBmNQSdJQO7e5iNEOdyhIta6A/I= +-----END CERTIFICATE----- + +ACEDICOM Root +============= +-----BEGIN CERTIFICATE----- +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 +-----END CERTIFICATE----- + +Verisign Class 3 Public Primary Certification Authority +======================================================= +-----BEGIN CERTIFICATE----- +MIICPDCCAaUCEDyRMcsf9tAbDpq40ES/Er4wDQYJKoZIhvcNAQEFBQAwXzELMAkGA1UEBhMCVVMx +FzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFzcyAzIFB1YmxpYyBQcmltYXJ5 +IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTk2MDEyOTAwMDAwMFoXDTI4MDgwMjIzNTk1OVow +XzELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFzcyAz +IFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGfMA0GCSqGSIb3DQEBAQUA +A4GNADCBiQKBgQDJXFme8huKARS0EN8EQNvjV69qRUCPhAwL0TPZ2RHP7gJYHyX3KqhEBarsAx94 +f56TuZoAqiN91qyFomNFx3InzPRMxnVx0jnvT0Lwdd8KkMaOIG+YD/isI19wKTakyYbnsZogy1Ol +hec9vn2a/iRFM9x2Fe0PonFkTGUugWhFpwIDAQABMA0GCSqGSIb3DQEBBQUAA4GBABByUqkFFBky +CEHwxWsKzH4PIRnN5GfcX6kb5sroc50i2JhucwNhkcV8sEVAbkSdjbCxlnRhLQ2pRdKkkirWmnWX +bj9T/UWZYB2oK0z5XqcJ2HUw19JlYD1n1khVdWk/kfVIC0dpImmClr7JyDiGSnoscxlIaU5rfGW/ +D/xwzoiQ +-----END CERTIFICATE----- + +Microsec e-Szigno Root CA 2009 +============================== +-----BEGIN CERTIFICATE----- +MIIECjCCAvKgAwIBAgIJAMJ+QwRORz8ZMA0GCSqGSIb3DQEBCwUAMIGCMQswCQYDVQQGEwJIVTER +MA8GA1UEBwwIQnVkYXBlc3QxFjAUBgNVBAoMDU1pY3Jvc2VjIEx0ZC4xJzAlBgNVBAMMHk1pY3Jv +c2VjIGUtU3ppZ25vIFJvb3QgQ0EgMjAwOTEfMB0GCSqGSIb3DQEJARYQaW5mb0BlLXN6aWduby5o +dTAeFw0wOTA2MTYxMTMwMThaFw0yOTEyMzAxMTMwMThaMIGCMQswCQYDVQQGEwJIVTERMA8GA1UE +BwwIQnVkYXBlc3QxFjAUBgNVBAoMDU1pY3Jvc2VjIEx0ZC4xJzAlBgNVBAMMHk1pY3Jvc2VjIGUt +U3ppZ25vIFJvb3QgQ0EgMjAwOTEfMB0GCSqGSIb3DQEJARYQaW5mb0BlLXN6aWduby5odTCCASIw +DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAOn4j/NjrdqG2KfgQvvPkd6mJviZpWNwrZuuyjNA +fW2WbqEORO7hE52UQlKavXWFdCyoDh2Tthi3jCyoz/tccbna7P7ofo/kLx2yqHWH2Leh5TvPmUpG +0IMZfcChEhyVbUr02MelTTMuhTlAdX4UfIASmFDHQWe4oIBhVKZsTh/gnQ4H6cm6M+f+wFUoLAKA +pxn1ntxVUwOXewdI/5n7N4okxFnMUBBjjqqpGrCEGob5X7uxUG6k0QrM1XF+H6cbfPVTbiJfyyvm +1HxdrtbCxkzlBQHZ7Vf8wSN5/PrIJIOV87VqUQHQd9bpEqH5GoP7ghu5sJf0dgYzQ0mg/wu1+rUC +AwEAAaOBgDB+MA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBTLD8bf +QkPMPcu1SCOhGnqmKrs0aDAfBgNVHSMEGDAWgBTLD8bfQkPMPcu1SCOhGnqmKrs0aDAbBgNVHREE +FDASgRBpbmZvQGUtc3ppZ25vLmh1MA0GCSqGSIb3DQEBCwUAA4IBAQDJ0Q5eLtXMs3w+y/w9/w0o +lZMEyL/azXm4Q5DwpL7v8u8hmLzU1F0G9u5C7DBsoKqpyvGvivo/C3NqPuouQH4frlRheesuCDfX +I/OMn74dseGkddug4lQUsbocKaQY9hK6ohQU4zE1yED/t+AFdlfBHFny+L/k7SViXITwfn4fs775 +tyERzAMBVnCnEJIeGzSBHq2cGsMEPO0CYdYeBvNfOofyK/FFh+U9rNHHV4S9a67c2Pm2G2JwCz02 +yULyMtd6YebS2z3PyKnJm9zbWETXbzivf3jTo60adbocwTZ8jx5tHMN1Rq41Bab2XD0h7lbwyYIi +LXpUq3DDfSJlgnCW +-----END CERTIFICATE----- + +E-Guven Kok Elektronik Sertifika Hizmet Saglayicisi +=================================================== +-----BEGIN CERTIFICATE----- +MIIDtjCCAp6gAwIBAgIQRJmNPMADJ72cdpW56tustTANBgkqhkiG9w0BAQUFADB1MQswCQYDVQQG +EwJUUjEoMCYGA1UEChMfRWxla3Ryb25payBCaWxnaSBHdXZlbmxpZ2kgQS5TLjE8MDoGA1UEAxMz +ZS1HdXZlbiBLb2sgRWxla3Ryb25payBTZXJ0aWZpa2EgSGl6bWV0IFNhZ2xheWljaXNpMB4XDTA3 +MDEwNDExMzI0OFoXDTE3MDEwNDExMzI0OFowdTELMAkGA1UEBhMCVFIxKDAmBgNVBAoTH0VsZWt0 +cm9uaWsgQmlsZ2kgR3V2ZW5saWdpIEEuUy4xPDA6BgNVBAMTM2UtR3V2ZW4gS29rIEVsZWt0cm9u +aWsgU2VydGlmaWthIEhpem1ldCBTYWdsYXlpY2lzaTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC +AQoCggEBAMMSIJ6wXgBljU5Gu4Bc6SwGl9XzcslwuedLZYDBS75+PNdUMZTe1RK6UxYC6lhj71vY +8+0qGqpxSKPcEC1fX+tcS5yWCEIlKBHMilpiAVDV6wlTL/jDj/6z/P2douNffb7tC+Bg62nsM+3Y +jfsSSYMAyYuXjDtzKjKzEve5TfL0TW3H5tYmNwjy2f1rXKPlSFxYvEK+A1qBuhw1DADT9SN+cTAI +JjjcJRFHLfO6IxClv7wC90Nex/6wN1CZew+TzuZDLMN+DfIcQ2Zgy2ExR4ejT669VmxMvLz4Bcpk +9Ok0oSy1c+HCPujIyTQlCFzz7abHlJ+tiEMl1+E5YP6sOVkCAwEAAaNCMEAwDgYDVR0PAQH/BAQD +AgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFJ/uRLOU1fqRTy7ZVZoEVtstxNulMA0GCSqG +SIb3DQEBBQUAA4IBAQB/X7lTW2M9dTLn+sR0GstG30ZpHFLPqk/CaOv/gKlR6D1id4k9CnU58W5d +F4dvaAXBlGzZXd/aslnLpRCKysw5zZ/rTt5S/wzw9JKp8mxTq5vSR6AfdPebmvEvFZ96ZDAYBzwq +D2fK/A+JYZ1lpTzlvBNbCNvj/+27BrtqBrF6T2XGgv0enIu1De5Iu7i9qgi0+6N8y5/NkHZchpZ4 +Vwpm+Vganf2XKWDeEaaQHBkc7gGWIjQ0LpH5t8Qn0Xvmv/uARFoW5evg1Ao4vOSR49XrXMGs3xtq +fJ7lddK2l4fbzIcrQzqECK+rPNv3PGYxhrCdU3nt+CPeQuMtgvEP5fqX +-----END CERTIFICATE----- + +GlobalSign Root CA - R3 +======================= +-----BEGIN CERTIFICATE----- +MIIDXzCCAkegAwIBAgILBAAAAAABIVhTCKIwDQYJKoZIhvcNAQELBQAwTDEgMB4GA1UECxMXR2xv +YmFsU2lnbiBSb290IENBIC0gUjMxEzARBgNVBAoTCkdsb2JhbFNpZ24xEzARBgNVBAMTCkdsb2Jh +bFNpZ24wHhcNMDkwMzE4MTAwMDAwWhcNMjkwMzE4MTAwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxT +aWduIFJvb3QgQ0EgLSBSMzETMBEGA1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2ln +bjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMwldpB5BngiFvXAg7aEyiie/QV2EcWt +iHL8RgJDx7KKnQRfJMsuS+FggkbhUqsMgUdwbN1k0ev1LKMPgj0MK66X17YUhhB5uzsTgHeMCOFJ +0mpiLx9e+pZo34knlTifBtc+ycsmWQ1z3rDI6SYOgxXG71uL0gRgykmmKPZpO/bLyCiR5Z2KYVc3 +rHQU3HTgOu5yLy6c+9C7v/U9AOEGM+iCK65TpjoWc4zdQQ4gOsC0p6Hpsk+QLjJg6VfLuQSSaGjl +OCZgdbKfd/+RFO+uIEn8rUAVSNECMWEZXriX7613t2Saer9fwRPvm2L7DWzgVGkWqQPabumDk3F2 +xmmFghcCAwEAAaNCMEAwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYE +FI/wS3+oLkUkrk1Q+mOai97i3Ru8MA0GCSqGSIb3DQEBCwUAA4IBAQBLQNvAUKr+yAzv95ZURUm7 +lgAJQayzE4aGKAczymvmdLm6AC2upArT9fHxD4q/c2dKg8dEe3jgr25sbwMpjjM5RcOO5LlXbKr8 +EpbsU8Yt5CRsuZRj+9xTaGdWPoO4zzUhw8lo/s7awlOqzJCK6fBdRoyV3XpYKBovHd7NADdBj+1E +bddTKJd+82cEHhXXipa0095MJ6RMG3NzdvQXmcIfeg7jLQitChws/zyrVQ4PkX4268NXSb7hLi18 +YIvDQVETI53O9zJrlAGomecsMx86OyXShkDOOyyGeMlhLxS67ttVb9+E7gUJTb0o2HLO02JQZR7r +kpeDMdmztcpHWD9f +-----END CERTIFICATE----- + +Autoridad de Certificacion Firmaprofesional CIF A62634068 +========================================================= +-----BEGIN CERTIFICATE----- +MIIGFDCCA/ygAwIBAgIIU+w77vuySF8wDQYJKoZIhvcNAQEFBQAwUTELMAkGA1UEBhMCRVMxQjBA +BgNVBAMMOUF1dG9yaWRhZCBkZSBDZXJ0aWZpY2FjaW9uIEZpcm1hcHJvZmVzaW9uYWwgQ0lGIEE2 +MjYzNDA2ODAeFw0wOTA1MjAwODM4MTVaFw0zMDEyMzEwODM4MTVaMFExCzAJBgNVBAYTAkVTMUIw +QAYDVQQDDDlBdXRvcmlkYWQgZGUgQ2VydGlmaWNhY2lvbiBGaXJtYXByb2Zlc2lvbmFsIENJRiBB +NjI2MzQwNjgwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDKlmuO6vj78aI14H9M2uDD +Utd9thDIAl6zQyrET2qyyhxdKJp4ERppWVevtSBC5IsP5t9bpgOSL/UR5GLXMnE42QQMcas9UX4P +B99jBVzpv5RvwSmCwLTaUbDBPLutN0pcyvFLNg4kq7/DhHf9qFD0sefGL9ItWY16Ck6WaVICqjaY +7Pz6FIMMNx/Jkjd/14Et5cS54D40/mf0PmbR0/RAz15iNA9wBj4gGFrO93IbJWyTdBSTo3OxDqqH +ECNZXyAFGUftaI6SEspd/NYrspI8IM/hX68gvqB2f3bl7BqGYTM+53u0P6APjqK5am+5hyZvQWyI +plD9amML9ZMWGxmPsu2bm8mQ9QEM3xk9Dz44I8kvjwzRAv4bVdZO0I08r0+k8/6vKtMFnXkIoctX +MbScyJCyZ/QYFpM6/EfY0XiWMR+6KwxfXZmtY4laJCB22N/9q06mIqqdXuYnin1oKaPnirjaEbsX +LZmdEyRG98Xi2J+Of8ePdG1asuhy9azuJBCtLxTa/y2aRnFHvkLfuwHb9H/TKI8xWVvTyQKmtFLK +bpf7Q8UIJm+K9Lv9nyiqDdVF8xM6HdjAeI9BZzwelGSuewvF6NkBiDkal4ZkQdU7hwxu+g/GvUgU +vzlN1J5Bto+WHWOWk9mVBngxaJ43BjuAiUVhOSPHG0SjFeUc+JIwuwIDAQABo4HvMIHsMBIGA1Ud +EwEB/wQIMAYBAf8CAQEwDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBRlzeurNR4APn7VdMActHNH +DhpkLzCBpgYDVR0gBIGeMIGbMIGYBgRVHSAAMIGPMC8GCCsGAQUFBwIBFiNodHRwOi8vd3d3LmZp +cm1hcHJvZmVzaW9uYWwuY29tL2NwczBcBggrBgEFBQcCAjBQHk4AUABhAHMAZQBvACAAZABlACAA +bABhACAAQgBvAG4AYQBuAG8AdgBhACAANAA3ACAAQgBhAHIAYwBlAGwAbwBuAGEAIAAwADgAMAAx +ADcwDQYJKoZIhvcNAQEFBQADggIBABd9oPm03cXF661LJLWhAqvdpYhKsg9VSytXjDvlMd3+xDLx +51tkljYyGOylMnfX40S2wBEqgLk9am58m9Ot/MPWo+ZkKXzR4Tgegiv/J2Wv+xYVxC5xhOW1//qk +R71kMrv2JYSiJ0L1ILDCExARzRAVukKQKtJE4ZYm6zFIEv0q2skGz3QeqUvVhyj5eTSSPi5E6PaP +T481PyWzOdxjKpBrIF/EUhJOlywqrJ2X3kjyo2bbwtKDlaZmp54lD+kLM5FlClrD2VQS3a/DTg4f +Jl4N3LON7NWBcN7STyQF82xO9UxJZo3R/9ILJUFI/lGExkKvgATP0H5kSeTy36LssUzAKh3ntLFl +osS88Zj0qnAHY7S42jtM+kAiMFsRpvAFDsYCA0irhpuF3dvd6qJ2gHN99ZwExEWN57kci57q13XR +crHedUTnQn3iV2t93Jm8PYMo6oCTjcVMZcFwgbg4/EMxsvYDNEeyrPsiBsse3RdHHF9mudMaotoR +saS8I8nkvof/uZS2+F0gStRf571oe2XyFR7SOqkt6dhrJKyXWERHrVkY8SFlcN7ONGCoQPHzPKTD +KCOM/iczQ0CgFzzr6juwcqajuUpLXhZI9LK8yIySxZ2frHI2vDSANGupi5LAuBft7HZT9SQBjLMi +6Et8Vcad+qMUu2WFbm5PEn4KPJ2V +-----END CERTIFICATE----- + +Izenpe.com +========== +-----BEGIN CERTIFICATE----- +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 +-----END CERTIFICATE----- + +Chambers of Commerce Root - 2008 +================================ +-----BEGIN CERTIFICATE----- +MIIHTzCCBTegAwIBAgIJAKPaQn6ksa7aMA0GCSqGSIb3DQEBBQUAMIGuMQswCQYDVQQGEwJFVTFD +MEEGA1UEBxM6TWFkcmlkIChzZWUgY3VycmVudCBhZGRyZXNzIGF0IHd3dy5jYW1lcmZpcm1hLmNv +bS9hZGRyZXNzKTESMBAGA1UEBRMJQTgyNzQzMjg3MRswGQYDVQQKExJBQyBDYW1lcmZpcm1hIFMu +QS4xKTAnBgNVBAMTIENoYW1iZXJzIG9mIENvbW1lcmNlIFJvb3QgLSAyMDA4MB4XDTA4MDgwMTEy +Mjk1MFoXDTM4MDczMTEyMjk1MFowga4xCzAJBgNVBAYTAkVVMUMwQQYDVQQHEzpNYWRyaWQgKHNl +ZSBjdXJyZW50IGFkZHJlc3MgYXQgd3d3LmNhbWVyZmlybWEuY29tL2FkZHJlc3MpMRIwEAYDVQQF +EwlBODI3NDMyODcxGzAZBgNVBAoTEkFDIENhbWVyZmlybWEgUy5BLjEpMCcGA1UEAxMgQ2hhbWJl +cnMgb2YgQ29tbWVyY2UgUm9vdCAtIDIwMDgwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoIC +AQCvAMtwNyuAWko6bHiUfaN/Gh/2NdW928sNRHI+JrKQUrpjOyhYb6WzbZSm891kDFX29ufyIiKA +XuFixrYp4YFs8r/lfTJqVKAyGVn+H4vXPWCGhSRv4xGzdz4gljUha7MI2XAuZPeEklPWDrCQiorj +h40G072QDuKZoRuGDtqaCrsLYVAGUvGef3bsyw/QHg3PmTA9HMRFEFis1tPo1+XqxQEHd9ZR5gN/ +ikilTWh1uem8nk4ZcfUyS5xtYBkL+8ydddy/Js2Pk3g5eXNeJQ7KXOt3EgfLZEFHcpOrUMPrCXZk +NNI5t3YRCQ12RcSprj1qr7V9ZS+UWBDsXHyvfuK2GNnQm05aSd+pZgvMPMZ4fKecHePOjlO+Bd5g +D2vlGts/4+EhySnB8esHnFIbAURRPHsl18TlUlRdJQfKFiC4reRB7noI/plvg6aRArBsNlVq5331 +lubKgdaX8ZSD6e2wsWsSaR6s+12pxZjptFtYer49okQ6Y1nUCyXeG0+95QGezdIp1Z8XGQpvvwyQ +0wlf2eOKNcx5Wk0ZN5K3xMGtr/R5JJqyAQuxr1yW84Ay+1w9mPGgP0revq+ULtlVmhduYJ1jbLhj +ya6BXBg14JC7vjxPNyK5fuvPnnchpj04gftI2jE9K+OJ9dC1vX7gUMQSibMjmhAxhduub+84Mxh2 +EQIDAQABo4IBbDCCAWgwEgYDVR0TAQH/BAgwBgEB/wIBDDAdBgNVHQ4EFgQU+SSsD7K1+HnA+mCI +G8TZTQKeFxkwgeMGA1UdIwSB2zCB2IAU+SSsD7K1+HnA+mCIG8TZTQKeFxmhgbSkgbEwga4xCzAJ +BgNVBAYTAkVVMUMwQQYDVQQHEzpNYWRyaWQgKHNlZSBjdXJyZW50IGFkZHJlc3MgYXQgd3d3LmNh +bWVyZmlybWEuY29tL2FkZHJlc3MpMRIwEAYDVQQFEwlBODI3NDMyODcxGzAZBgNVBAoTEkFDIENh +bWVyZmlybWEgUy5BLjEpMCcGA1UEAxMgQ2hhbWJlcnMgb2YgQ29tbWVyY2UgUm9vdCAtIDIwMDiC +CQCj2kJ+pLGu2jAOBgNVHQ8BAf8EBAMCAQYwPQYDVR0gBDYwNDAyBgRVHSAAMCowKAYIKwYBBQUH +AgEWHGh0dHA6Ly9wb2xpY3kuY2FtZXJmaXJtYS5jb20wDQYJKoZIhvcNAQEFBQADggIBAJASryI1 +wqM58C7e6bXpeHxIvj99RZJe6dqxGfwWPJ+0W2aeaufDuV2I6A+tzyMP3iU6XsxPpcG1Lawk0lgH +3qLPaYRgM+gQDROpI9CF5Y57pp49chNyM/WqfcZjHwj0/gF/JM8rLFQJ3uIrbZLGOU8W6jx+ekbU +RWpGqOt1glanq6B8aBMz9p0w8G8nOSQjKpD9kCk18pPfNKXG9/jvjA9iSnyu0/VU+I22mlaHFoI6 +M6taIgj3grrqLuBHmrS1RaMFO9ncLkVAO+rcf+g769HsJtg1pDDFOqxXnrN2pSB7+R5KBWIBpih1 +YJeSDW4+TTdDDZIVnBgizVGZoCkaPF+KMjNbMMeJL0eYD6MDxvbxrN8y8NmBGuScvfaAFPDRLLmF +9dijscilIeUcE5fuDr3fKanvNFNb0+RqE4QGtjICxFKuItLcsiFCGtpA8CnJ7AoMXOLQusxI0zcK +zBIKinmwPQN/aUv0NCB9szTqjktk9T79syNnFQ0EuPAtwQlRPLJsFfClI9eDdOTlLsn+mCdCxqvG +nrDQWzilm1DefhiYtUU79nm06PcaewaD+9CL2rvHvRirCG88gGtAPxkZumWK5r7VXNM21+9AUiRg +OGcEMeyP84LG3rlV8zsxkVrctQgVrXYlCg17LofiDKYGvCYQbTed7N14jHyAxfDZd0jQ +-----END CERTIFICATE----- + +Global Chambersign Root - 2008 +============================== +-----BEGIN CERTIFICATE----- +MIIHSTCCBTGgAwIBAgIJAMnN0+nVfSPOMA0GCSqGSIb3DQEBBQUAMIGsMQswCQYDVQQGEwJFVTFD +MEEGA1UEBxM6TWFkcmlkIChzZWUgY3VycmVudCBhZGRyZXNzIGF0IHd3dy5jYW1lcmZpcm1hLmNv +bS9hZGRyZXNzKTESMBAGA1UEBRMJQTgyNzQzMjg3MRswGQYDVQQKExJBQyBDYW1lcmZpcm1hIFMu +QS4xJzAlBgNVBAMTHkdsb2JhbCBDaGFtYmVyc2lnbiBSb290IC0gMjAwODAeFw0wODA4MDExMjMx +NDBaFw0zODA3MzExMjMxNDBaMIGsMQswCQYDVQQGEwJFVTFDMEEGA1UEBxM6TWFkcmlkIChzZWUg +Y3VycmVudCBhZGRyZXNzIGF0IHd3dy5jYW1lcmZpcm1hLmNvbS9hZGRyZXNzKTESMBAGA1UEBRMJ +QTgyNzQzMjg3MRswGQYDVQQKExJBQyBDYW1lcmZpcm1hIFMuQS4xJzAlBgNVBAMTHkdsb2JhbCBD +aGFtYmVyc2lnbiBSb290IC0gMjAwODCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMDf +VtPkOpt2RbQT2//BthmLN0EYlVJH6xedKYiONWwGMi5HYvNJBL99RDaxccy9Wglz1dmFRP+RVyXf +XjaOcNFccUMd2drvXNL7G706tcuto8xEpw2uIRU/uXpbknXYpBI4iRmKt4DS4jJvVpyR1ogQC7N0 +ZJJ0YPP2zxhPYLIj0Mc7zmFLmY/CDNBAspjcDahOo7kKrmCgrUVSY7pmvWjg+b4aqIG7HkF4ddPB +/gBVsIdU6CeQNR1MM62X/JcumIS/LMmjv9GYERTtY/jKmIhYF5ntRQOXfjyGHoiMvvKRhI9lNNgA +TH23MRdaKXoKGCQwoze1eqkBfSbW+Q6OWfH9GzO1KTsXO0G2Id3UwD2ln58fQ1DJu7xsepeY7s2M +H/ucUa6LcL0nn3HAa6x9kGbo1106DbDVwo3VyJ2dwW3Q0L9R5OP4wzg2rtandeavhENdk5IMagfe +Ox2YItaswTXbo6Al/3K1dh3ebeksZixShNBFks4c5eUzHdwHU1SjqoI7mjcv3N2gZOnm3b2u/GSF +HTynyQbehP9r6GsaPMWis0L7iwk+XwhSx2LE1AVxv8Rk5Pihg+g+EpuoHtQ2TS9x9o0o9oOpE9Jh +wZG7SMA0j0GMS0zbaRL/UJScIINZc+18ofLx/d33SdNDWKBWY8o9PeU1VlnpDsogzCtLkykPAgMB +AAGjggFqMIIBZjASBgNVHRMBAf8ECDAGAQH/AgEMMB0GA1UdDgQWBBS5CcqcHtvTbDprru1U8VuT +BjUuXjCB4QYDVR0jBIHZMIHWgBS5CcqcHtvTbDprru1U8VuTBjUuXqGBsqSBrzCBrDELMAkGA1UE +BhMCRVUxQzBBBgNVBAcTOk1hZHJpZCAoc2VlIGN1cnJlbnQgYWRkcmVzcyBhdCB3d3cuY2FtZXJm +aXJtYS5jb20vYWRkcmVzcykxEjAQBgNVBAUTCUE4Mjc0MzI4NzEbMBkGA1UEChMSQUMgQ2FtZXJm +aXJtYSBTLkEuMScwJQYDVQQDEx5HbG9iYWwgQ2hhbWJlcnNpZ24gUm9vdCAtIDIwMDiCCQDJzdPp +1X0jzjAOBgNVHQ8BAf8EBAMCAQYwPQYDVR0gBDYwNDAyBgRVHSAAMCowKAYIKwYBBQUHAgEWHGh0 +dHA6Ly9wb2xpY3kuY2FtZXJmaXJtYS5jb20wDQYJKoZIhvcNAQEFBQADggIBAICIf3DekijZBZRG +/5BXqfEv3xoNa/p8DhxJJHkn2EaqbylZUohwEurdPfWbU1Rv4WCiqAm57OtZfMY18dwY6fFn5a+6 +ReAJ3spED8IXDneRRXozX1+WLGiLwUePmJs9wOzL9dWCkoQ10b42OFZyMVtHLaoXpGNR6woBrX/s +dZ7LoR/xfxKxueRkf2fWIyr0uDldmOghp+G9PUIadJpwr2hsUF1Jz//7Dl3mLEfXgTpZALVza2Mg +9jFFCDkO9HB+QHBaP9BrQql0PSgvAm11cpUJjUhjxsYjV5KTXjXBjfkK9yydYhz2rXzdpjEetrHH +foUm+qRqtdpjMNHvkzeyZi99Bffnt0uYlDXA2TopwZ2yUDMdSqlapskD7+3056huirRXhOukP9Du +qqqHW2Pok+JrqNS4cnhrG+055F3Lm6qH1U9OAP7Zap88MQ8oAgF9mOinsKJknnn4SPIVqczmyETr +P3iZ8ntxPjzxmKfFGBI/5rsoM0LpRQp8bfKGeS/Fghl9CYl8slR2iK7ewfPM4W7bMdaTrpmg7yVq +c5iJWzouE4gev8CSlDQb4ye3ix5vQv/n6TebUB0tovkC7stYWDpxvGjjqsGvHCgfotwjZT+B6q6Z +09gwzxMNTxXJhLynSC34MCN32EZLeW32jO06f2ARePTpm67VVMB0gNELQp/B +-----END CERTIFICATE----- + +Go Daddy Root Certificate Authority - G2 +======================================== +-----BEGIN CERTIFICATE----- +MIIDxTCCAq2gAwIBAgIBADANBgkqhkiG9w0BAQsFADCBgzELMAkGA1UEBhMCVVMxEDAOBgNVBAgT +B0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxGjAYBgNVBAoTEUdvRGFkZHkuY29tLCBJbmMu +MTEwLwYDVQQDEyhHbyBEYWRkeSBSb290IENlcnRpZmljYXRlIEF1dGhvcml0eSAtIEcyMB4XDTA5 +MDkwMTAwMDAwMFoXDTM3MTIzMTIzNTk1OVowgYMxCzAJBgNVBAYTAlVTMRAwDgYDVQQIEwdBcml6 +b25hMRMwEQYDVQQHEwpTY290dHNkYWxlMRowGAYDVQQKExFHb0RhZGR5LmNvbSwgSW5jLjExMC8G +A1UEAxMoR28gRGFkZHkgUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkgLSBHMjCCASIwDQYJKoZI +hvcNAQEBBQADggEPADCCAQoCggEBAL9xYgjx+lk09xvJGKP3gElY6SKDE6bFIEMBO4Tx5oVJnyfq +9oQbTqC023CYxzIBsQU+B07u9PpPL1kwIuerGVZr4oAH/PMWdYA5UXvl+TW2dE6pjYIT5LY/qQOD ++qK+ihVqf94Lw7YZFAXK6sOoBJQ7RnwyDfMAZiLIjWltNowRGLfTshxgtDj6AozO091GB94KPutd +fMh8+7ArU6SSYmlRJQVhGkSBjCypQ5Yj36w6gZoOKcUcqeldHraenjAKOc7xiID7S13MMuyFYkMl +NAJWJwGRtDtwKj9useiciAF9n9T521NtYJ2/LOdYq7hfRvzOxBsDPAnrSTFcaUaz4EcCAwEAAaNC +MEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFDqahQcQZyi27/a9 +BUFuIMGU2g/eMA0GCSqGSIb3DQEBCwUAA4IBAQCZ21151fmXWWcDYfF+OwYxdS2hII5PZYe096ac +vNjpL9DbWu7PdIxztDhC2gV7+AJ1uP2lsdeu9tfeE8tTEH6KRtGX+rcuKxGrkLAngPnon1rpN5+r +5N9ss4UXnT3ZJE95kTXWXwTrgIOrmgIttRD02JDHBHNA7XIloKmf7J6raBKZV8aPEjoJpL1E/QYV +N8Gb5DKj7Tjo2GTzLH4U/ALqn83/B2gX2yKQOC16jdFU8WnjXzPKej17CuPKf1855eJ1usV2GDPO +LPAvTK33sefOT6jEm0pUBsV/fdUID+Ic/n4XuKxe9tQWskMJDE32p2u0mYRlynqI4uJEvlz36hz1 +-----END CERTIFICATE----- + +Starfield Root Certificate Authority - G2 +========================================= +-----BEGIN CERTIFICATE----- +MIID3TCCAsWgAwIBAgIBADANBgkqhkiG9w0BAQsFADCBjzELMAkGA1UEBhMCVVMxEDAOBgNVBAgT +B0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxJTAjBgNVBAoTHFN0YXJmaWVsZCBUZWNobm9s +b2dpZXMsIEluYy4xMjAwBgNVBAMTKVN0YXJmaWVsZCBSb290IENlcnRpZmljYXRlIEF1dGhvcml0 +eSAtIEcyMB4XDTA5MDkwMTAwMDAwMFoXDTM3MTIzMTIzNTk1OVowgY8xCzAJBgNVBAYTAlVTMRAw +DgYDVQQIEwdBcml6b25hMRMwEQYDVQQHEwpTY290dHNkYWxlMSUwIwYDVQQKExxTdGFyZmllbGQg +VGVjaG5vbG9naWVzLCBJbmMuMTIwMAYDVQQDEylTdGFyZmllbGQgUm9vdCBDZXJ0aWZpY2F0ZSBB +dXRob3JpdHkgLSBHMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAL3twQP89o/8ArFv +W59I2Z154qK3A2FWGMNHttfKPTUuiUP3oWmb3ooa/RMgnLRJdzIpVv257IzdIvpy3Cdhl+72WoTs +bhm5iSzchFvVdPtrX8WJpRBSiUZV9Lh1HOZ/5FSuS/hVclcCGfgXcVnrHigHdMWdSL5stPSksPNk +N3mSwOxGXn/hbVNMYq/NHwtjuzqd+/x5AJhhdM8mgkBj87JyahkNmcrUDnXMN/uLicFZ8WJ/X7Nf +ZTD4p7dNdloedl40wOiWVpmKs/B/pM293DIxfJHP4F8R+GuqSVzRmZTRouNjWwl2tVZi4Ut0HZbU +JtQIBFnQmA4O5t78w+wfkPECAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC +AQYwHQYDVR0OBBYEFHwMMh+n2TB/xH1oo2Kooc6rB1snMA0GCSqGSIb3DQEBCwUAA4IBAQARWfol +TwNvlJk7mh+ChTnUdgWUXuEok21iXQnCoKjUsHU48TRqneSfioYmUeYs0cYtbpUgSpIB7LiKZ3sx +4mcujJUDJi5DnUox9g61DLu34jd/IroAow57UvtruzvE03lRTs2Q9GcHGcg8RnoNAX3FWOdt5oUw +F5okxBDgBPfg8n/Uqgr/Qh037ZTlZFkSIHc40zI+OIF1lnP6aI+xy84fxez6nH7PfrHxBy22/L/K +pL/QlwVKvOoYKAKQvVR4CSFx09F9HdkWsKlhPdAKACL8x3vLCWRFCztAgfd9fDL1mMpYjn0q7pBZ +c2T5NnReJaH1ZgUufzkVqSr7UIuOhWn0 +-----END CERTIFICATE----- + +Starfield Services Root Certificate Authority - G2 +================================================== +-----BEGIN CERTIFICATE----- +MIID7zCCAtegAwIBAgIBADANBgkqhkiG9w0BAQsFADCBmDELMAkGA1UEBhMCVVMxEDAOBgNVBAgT +B0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxJTAjBgNVBAoTHFN0YXJmaWVsZCBUZWNobm9s +b2dpZXMsIEluYy4xOzA5BgNVBAMTMlN0YXJmaWVsZCBTZXJ2aWNlcyBSb290IENlcnRpZmljYXRl +IEF1dGhvcml0eSAtIEcyMB4XDTA5MDkwMTAwMDAwMFoXDTM3MTIzMTIzNTk1OVowgZgxCzAJBgNV +BAYTAlVTMRAwDgYDVQQIEwdBcml6b25hMRMwEQYDVQQHEwpTY290dHNkYWxlMSUwIwYDVQQKExxT +dGFyZmllbGQgVGVjaG5vbG9naWVzLCBJbmMuMTswOQYDVQQDEzJTdGFyZmllbGQgU2VydmljZXMg +Um9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkgLSBHMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC +AQoCggEBANUMOsQq+U7i9b4Zl1+OiFOxHz/Lz58gE20pOsgPfTz3a3Y4Y9k2YKibXlwAgLIvWX/2 +h/klQ4bnaRtSmpDhcePYLQ1Ob/bISdm28xpWriu2dBTrz/sm4xq6HZYuajtYlIlHVv8loJNwU4Pa +hHQUw2eeBGg6345AWh1KTs9DkTvnVtYAcMtS7nt9rjrnvDH5RfbCYM8TWQIrgMw0R9+53pBlbQLP +LJGmpufehRhJfGZOozptqbXuNC66DQO4M99H67FrjSXZm86B0UVGMpZwh94CDklDhbZsc7tk6mFB +rMnUVN+HL8cisibMn1lUaJ/8viovxFUcdUBgF4UCVTmLfwUCAwEAAaNCMEAwDwYDVR0TAQH/BAUw +AwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFJxfAN+qAdcwKziIorhtSpzyEZGDMA0GCSqG +SIb3DQEBCwUAA4IBAQBLNqaEd2ndOxmfZyMIbw5hyf2E3F/YNoHN2BtBLZ9g3ccaaNnRbobhiCPP +E95Dz+I0swSdHynVv/heyNXBve6SbzJ08pGCL72CQnqtKrcgfU28elUSwhXqvfdqlS5sdJ/PHLTy +xQGjhdByPq1zqwubdQxtRbeOlKyWN7Wg0I8VRw7j6IPdj/3vQQF3zCepYoUz8jcI73HPdwbeyBkd +iEDPfUYd/x7H4c7/I9vG+o1VTqkC50cRRj70/b17KSa7qWFiNyi2LSr2EIZkyXCn0q23KXB56jza +YyWf/Wi3MOxw+3WKt21gZ7IeyLnp2KhvAotnDU0mV3HaIPzBSlCNsSi6 +-----END CERTIFICATE----- + +AffirmTrust Commercial +====================== +-----BEGIN CERTIFICATE----- +MIIDTDCCAjSgAwIBAgIId3cGJyapsXwwDQYJKoZIhvcNAQELBQAwRDELMAkGA1UEBhMCVVMxFDAS +BgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZpcm1UcnVzdCBDb21tZXJjaWFsMB4XDTEw +MDEyOTE0MDYwNloXDTMwMTIzMTE0MDYwNlowRDELMAkGA1UEBhMCVVMxFDASBgNVBAoMC0FmZmly +bVRydXN0MR8wHQYDVQQDDBZBZmZpcm1UcnVzdCBDb21tZXJjaWFsMIIBIjANBgkqhkiG9w0BAQEF +AAOCAQ8AMIIBCgKCAQEA9htPZwcroRX1BiLLHwGy43NFBkRJLLtJJRTWzsO3qyxPxkEylFf6Eqdb +DuKPHx6GGaeqtS25Xw2Kwq+FNXkyLbscYjfysVtKPcrNcV/pQr6U6Mje+SJIZMblq8Yrba0F8PrV +C8+a5fBQpIs7R6UjW3p6+DM/uO+Zl+MgwdYoic+U+7lF7eNAFxHUdPALMeIrJmqbTFeurCA+ukV6 +BfO9m2kVrn1OIGPENXY6BwLJN/3HR+7o8XYdcxXyl6S1yHp52UKqK39c/s4mT6NmgTWvRLpUHhww +MmWd5jyTXlBOeuM61G7MGvv50jeuJCqrVwMiKA1JdX+3KNp1v47j3A55MQIDAQABo0IwQDAdBgNV +HQ4EFgQUnZPGU4teyq8/nx4P5ZmVvCT2lI8wDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC +AQYwDQYJKoZIhvcNAQELBQADggEBAFis9AQOzcAN/wr91LoWXym9e2iZWEnStB03TX8nfUYGXUPG +hi4+c7ImfU+TqbbEKpqrIZcUsd6M06uJFdhrJNTxFq7YpFzUf1GO7RgBsZNjvbz4YYCanrHOQnDi +qX0GJX0nof5v7LMeJNrjS1UaADs1tDvZ110w/YETifLCBivtZ8SOyUOyXGsViQK8YvxO8rUzqrJv +0wqiUOP2O+guRMLbZjipM1ZI8W0bM40NjD9gN53Tym1+NH4Nn3J2ixufcv1SNUFFApYvHLKac0kh +sUlHRUe072o0EclNmsxZt9YCnlpOZbWUrhvfKbAW8b8Angc6F2S1BLUjIZkKlTuXfO8= +-----END CERTIFICATE----- + +AffirmTrust Networking +====================== +-----BEGIN CERTIFICATE----- +MIIDTDCCAjSgAwIBAgIIfE8EORzUmS0wDQYJKoZIhvcNAQEFBQAwRDELMAkGA1UEBhMCVVMxFDAS +BgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZpcm1UcnVzdCBOZXR3b3JraW5nMB4XDTEw +MDEyOTE0MDgyNFoXDTMwMTIzMTE0MDgyNFowRDELMAkGA1UEBhMCVVMxFDASBgNVBAoMC0FmZmly +bVRydXN0MR8wHQYDVQQDDBZBZmZpcm1UcnVzdCBOZXR3b3JraW5nMIIBIjANBgkqhkiG9w0BAQEF +AAOCAQ8AMIIBCgKCAQEAtITMMxcua5Rsa2FSoOujz3mUTOWUgJnLVWREZY9nZOIG41w3SfYvm4SE +Hi3yYJ0wTsyEheIszx6e/jarM3c1RNg1lho9Nuh6DtjVR6FqaYvZ/Ls6rnla1fTWcbuakCNrmreI +dIcMHl+5ni36q1Mr3Lt2PpNMCAiMHqIjHNRqrSK6mQEubWXLviRmVSRLQESxG9fhwoXA3hA/Pe24 +/PHxI1Pcv2WXb9n5QHGNfb2V1M6+oF4nI979ptAmDgAp6zxG8D1gvz9Q0twmQVGeFDdCBKNwV6gb +h+0t+nvujArjqWaJGctB+d1ENmHP4ndGyH329JKBNv3bNPFyfvMMFr20FQIDAQABo0IwQDAdBgNV +HQ4EFgQUBx/S55zawm6iQLSwelAQUHTEyL0wDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC +AQYwDQYJKoZIhvcNAQEFBQADggEBAIlXshZ6qML91tmbmzTCnLQyFE2npN/svqe++EPbkTfOtDIu +UFUaNU52Q3Eg75N3ThVwLofDwR1t3Mu1J9QsVtFSUzpE0nPIxBsFZVpikpzuQY0x2+c06lkh1QF6 +12S4ZDnNye2v7UsDSKegmQGA3GWjNq5lWUhPgkvIZfFXHeVZLgo/bNjR9eUJtGxUAArgFU2HdW23 +WJZa3W3SAKD0m0i+wzekujbgfIeFlxoVot4uolu9rxj5kFDNcFn4J2dHy8egBzp90SxdbBk6ZrV9 +/ZFvgrG+CJPbFEfxojfHRZ48x3evZKiT3/Zpg4Jg8klCNO1aAFSFHBY2kgxc+qatv9s= +-----END CERTIFICATE----- + +AffirmTrust Premium +=================== +-----BEGIN CERTIFICATE----- +MIIFRjCCAy6gAwIBAgIIbYwURrGmCu4wDQYJKoZIhvcNAQEMBQAwQTELMAkGA1UEBhMCVVMxFDAS +BgNVBAoMC0FmZmlybVRydXN0MRwwGgYDVQQDDBNBZmZpcm1UcnVzdCBQcmVtaXVtMB4XDTEwMDEy +OTE0MTAzNloXDTQwMTIzMTE0MTAzNlowQTELMAkGA1UEBhMCVVMxFDASBgNVBAoMC0FmZmlybVRy +dXN0MRwwGgYDVQQDDBNBZmZpcm1UcnVzdCBQcmVtaXVtMIICIjANBgkqhkiG9w0BAQEFAAOCAg8A +MIICCgKCAgEAxBLfqV/+Qd3d9Z+K4/as4Tx4mrzY8H96oDMq3I0gW64tb+eT2TZwamjPjlGjhVtn +BKAQJG9dKILBl1fYSCkTtuG+kU3fhQxTGJoeJKJPj/CihQvL9Cl/0qRY7iZNyaqoe5rZ+jjeRFcV +5fiMyNlI4g0WJx0eyIOFJbe6qlVBzAMiSy2RjYvmia9mx+n/K+k8rNrSs8PhaJyJ+HoAVt70VZVs ++7pk3WKL3wt3MutizCaam7uqYoNMtAZ6MMgpv+0GTZe5HMQxK9VfvFMSF5yZVylmd2EhMQcuJUmd +GPLu8ytxjLW6OQdJd/zvLpKQBY0tL3d770O/Nbua2Plzpyzy0FfuKE4mX4+QaAkvuPjcBukumj5R +p9EixAqnOEhss/n/fauGV+O61oV4d7pD6kh/9ti+I20ev9E2bFhc8e6kGVQa9QPSdubhjL08s9NI +S+LI+H+SqHZGnEJlPqQewQcDWkYtuJfzt9WyVSHvutxMAJf7FJUnM7/oQ0dG0giZFmA7mn7S5u04 +6uwBHjxIVkkJx0w3AJ6IDsBz4W9m6XJHMD4Q5QsDyZpCAGzFlH5hxIrff4IaC1nEWTJ3s7xgaVY5 +/bQGeyzWZDbZvUjthB9+pSKPKrhC9IK31FOQeE4tGv2Bb0TXOwF0lkLgAOIua+rF7nKsu7/+6qqo ++Nz2snmKtmcCAwEAAaNCMEAwHQYDVR0OBBYEFJ3AZ6YMItkm9UWrpmVSESfYRaxjMA8GA1UdEwEB +/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEBDAUAA4ICAQCzV00QYk465KzquByv +MiPIs0laUZx2KI15qldGF9X1Uva3ROgIRL8YhNILgM3FEv0AVQVhh0HctSSePMTYyPtwni94loMg +Nt58D2kTiKV1NpgIpsbfrM7jWNa3Pt668+s0QNiigfV4Py/VpfzZotReBA4Xrf5B8OWycvpEgjNC +6C1Y91aMYj+6QrCcDFx+LmUmXFNPALJ4fqENmS2NuB2OosSw/WDQMKSOyARiqcTtNd56l+0OOF6S +L5Nwpamcb6d9Ex1+xghIsV5n61EIJenmJWtSKZGc0jlzCFfemQa0W50QBuHCAKi4HEoCChTQwUHK ++4w1IX2COPKpVJEZNZOUbWo6xbLQu4mGk+ibyQ86p3q4ofB4Rvr8Ny/lioTz3/4E2aFooC8k4gmV +BtWVyuEklut89pMFu+1z6S3RdTnX5yTb2E5fQ4+e0BQ5v1VwSJlXMbSc7kqYA5YwH2AG7hsj/oFg +IxpHYoWlzBk0gG+zrBrjn/B7SK3VAdlntqlyk+otZrWyuOQ9PLLvTIzq6we/qzWaVYa8GKa1qF60 +g2xraUDTn9zxw2lrueFtCfTxqlB2Cnp9ehehVZZCmTEJ3WARjQUwfuaORtGdFNrHF+QFlozEJLUb +zxQHskD4o55BhrwE0GuWyCqANP2/7waj3VjFhT0+j/6eKeC2uAloGRwYQw== +-----END CERTIFICATE----- + +AffirmTrust Premium ECC +======================= +-----BEGIN CERTIFICATE----- +MIIB/jCCAYWgAwIBAgIIdJclisc/elQwCgYIKoZIzj0EAwMwRTELMAkGA1UEBhMCVVMxFDASBgNV +BAoMC0FmZmlybVRydXN0MSAwHgYDVQQDDBdBZmZpcm1UcnVzdCBQcmVtaXVtIEVDQzAeFw0xMDAx +MjkxNDIwMjRaFw00MDEyMzExNDIwMjRaMEUxCzAJBgNVBAYTAlVTMRQwEgYDVQQKDAtBZmZpcm1U +cnVzdDEgMB4GA1UEAwwXQWZmaXJtVHJ1c3QgUHJlbWl1bSBFQ0MwdjAQBgcqhkjOPQIBBgUrgQQA +IgNiAAQNMF4bFZ0D0KF5Nbc6PJJ6yhUczWLznCZcBz3lVPqj1swS6vQUX+iOGasvLkjmrBhDeKzQ +N8O9ss0s5kfiGuZjuD0uL3jET9v0D6RoTFVya5UdThhClXjMNzyR4ptlKymjQjBAMB0GA1UdDgQW +BBSaryl6wBE1NSZRMADDav5A1a7WPDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAK +BggqhkjOPQQDAwNnADBkAjAXCfOHiFBar8jAQr9HX/VsaobgxCd05DhT1wV/GzTjxi+zygk8N53X +57hG8f2h4nECMEJZh0PUUd+60wkyWs6Iflc9nF9Ca/UHLbXwgpP5WW+uZPpY5Yse42O+tYHNbwKM +eQ== +-----END CERTIFICATE----- + +Certum Trusted Network CA +========================= +-----BEGIN CERTIFICATE----- +MIIDuzCCAqOgAwIBAgIDBETAMA0GCSqGSIb3DQEBBQUAMH4xCzAJBgNVBAYTAlBMMSIwIAYDVQQK +ExlVbml6ZXRvIFRlY2hub2xvZ2llcyBTLkEuMScwJQYDVQQLEx5DZXJ0dW0gQ2VydGlmaWNhdGlv +biBBdXRob3JpdHkxIjAgBgNVBAMTGUNlcnR1bSBUcnVzdGVkIE5ldHdvcmsgQ0EwHhcNMDgxMDIy +MTIwNzM3WhcNMjkxMjMxMTIwNzM3WjB+MQswCQYDVQQGEwJQTDEiMCAGA1UEChMZVW5pemV0byBU +ZWNobm9sb2dpZXMgUy5BLjEnMCUGA1UECxMeQ2VydHVtIENlcnRpZmljYXRpb24gQXV0aG9yaXR5 +MSIwIAYDVQQDExlDZXJ0dW0gVHJ1c3RlZCBOZXR3b3JrIENBMIIBIjANBgkqhkiG9w0BAQEFAAOC +AQ8AMIIBCgKCAQEA4/t9o3K6wvDJFIf1awFO4W5AB7ptJ11/91sts1rHUV+rpDKmYYe2bg+G0jAC +l/jXaVehGDldamR5xgFZrDwxSjh80gTSSyjoIF87B6LMTXPb865Px1bVWqeWifrzq2jUI4ZZJ88J +J7ysbnKDHDBy3+Ci6dLhdHUZvSqeexVUBBvXQzmtVSjF4hq79MDkrjhJM8x2hZ85RdKknvISjFH4 +fOQtf/WsX+sWn7Et0brMkUJ3TCXJkDhv2/DM+44el1k+1WBO5gUo7Ul5E0u6SNsv+XLTOcr+H9g0 +cvW0QM8xAcPs3hEtF10fuFDRXhmnad4HMyjKUJX5p1TLVIZQRan5SQIDAQABo0IwQDAPBgNVHRMB +Af8EBTADAQH/MB0GA1UdDgQWBBQIds3LB/8k9sXN7buQvOKEN0Z19zAOBgNVHQ8BAf8EBAMCAQYw +DQYJKoZIhvcNAQEFBQADggEBAKaorSLOAT2mo/9i0Eidi15ysHhE49wcrwn9I0j6vSrEuVUEtRCj +jSfeC4Jj0O7eDDd5QVsisrCaQVymcODU0HfLI9MA4GxWL+FpDQ3Zqr8hgVDZBqWo/5U30Kr+4rP1 +mS1FhIrlQgnXdAIv94nYmem8J9RHjboNRhx3zxSkHLmkMcScKHQDNP8zGSal6Q10tz6XxnboJ5aj +Zt3hrvJBW8qYVoNzcOSGGtIxQbovvi0TWnZvTuhOgQ4/WwMioBK+ZlgRSssDxLQqKi2WF+A5VLxI +03YnnZotBqbJ7DnSq9ufmgsnAjUpsUCV5/nonFWIGUbWtzT1fs45mtk48VH3Tyw= +-----END CERTIFICATE----- + +Certinomis - Autorité Racine +============================= +-----BEGIN CERTIFICATE----- +MIIFnDCCA4SgAwIBAgIBATANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJGUjETMBEGA1UEChMK +Q2VydGlub21pczEXMBUGA1UECxMOMDAwMiA0MzM5OTg5MDMxJjAkBgNVBAMMHUNlcnRpbm9taXMg +LSBBdXRvcml0w6kgUmFjaW5lMB4XDTA4MDkxNzA4Mjg1OVoXDTI4MDkxNzA4Mjg1OVowYzELMAkG +A1UEBhMCRlIxEzARBgNVBAoTCkNlcnRpbm9taXMxFzAVBgNVBAsTDjAwMDIgNDMzOTk4OTAzMSYw +JAYDVQQDDB1DZXJ0aW5vbWlzIC0gQXV0b3JpdMOpIFJhY2luZTCCAiIwDQYJKoZIhvcNAQEBBQAD +ggIPADCCAgoCggIBAJ2Fn4bT46/HsmtuM+Cet0I0VZ35gb5j2CN2DpdUzZlMGvE5x4jYF1AMnmHa +wE5V3udauHpOd4cN5bjr+p5eex7Ezyh0x5P1FMYiKAT5kcOrJ3NqDi5N8y4oH3DfVS9O7cdxbwly +Lu3VMpfQ8Vh30WC8Tl7bmoT2R2FFK/ZQpn9qcSdIhDWerP5pqZ56XjUl+rSnSTV3lqc2W+HN3yNw +2F1MpQiD8aYkOBOo7C+ooWfHpi2GR+6K/OybDnT0K0kCe5B1jPyZOQE51kqJ5Z52qz6WKDgmi92N +jMD2AR5vpTESOH2VwnHu7XSu5DaiQ3XV8QCb4uTXzEIDS3h65X27uK4uIJPT5GHfceF2Z5c/tt9q +c1pkIuVC28+BA5PY9OMQ4HL2AHCs8MF6DwV/zzRpRbWT5BnbUhYjBYkOjUjkJW+zeL9i9Qf6lSTC +lrLooyPCXQP8w9PlfMl1I9f09bze5N/NgL+RiH2nE7Q5uiy6vdFrzPOlKO1Enn1So2+WLhl+HPNb +xxaOu2B9d2ZHVIIAEWBsMsGoOBvrbpgT1u449fCfDu/+MYHB0iSVL1N6aaLwD4ZFjliCK0wi1F6g +530mJ0jfJUaNSih8hp75mxpZuWW/Bd22Ql095gBIgl4g9xGC3srYn+Y3RyYe63j3YcNBZFgCQfna +4NH4+ej9Uji29YnfAgMBAAGjWzBZMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0G +A1UdDgQWBBQNjLZh2kS40RR9w759XkjwzspqsDAXBgNVHSAEEDAOMAwGCiqBegFWAgIAAQEwDQYJ +KoZIhvcNAQEFBQADggIBACQ+YAZ+He86PtvqrxyaLAEL9MW12Ukx9F1BjYkMTv9sov3/4gbIOZ/x +WqndIlgVqIrTseYyCYIDbNc/CMf4uboAbbnW/FIyXaR/pDGUu7ZMOH8oMDX/nyNTt7buFHAAQCva +R6s0fl6nVjBhK4tDrP22iCj1a7Y+YEq6QpA0Z43q619FVDsXrIvkxmUP7tCMXWY5zjKn2BCXwH40 +nJ+U8/aGH88bc62UeYdocMMzpXDn2NU4lG9jeeu/Cg4I58UvD0KgKxRA/yHgBcUn4YQRE7rWhh1B +CxMjidPJC+iKunqjo3M3NYB9Ergzd0A4wPpeMNLytqOx1qKVl4GbUu1pTP+A5FPbVFsDbVRfsbjv +JL1vnxHDx2TCDyhihWZeGnuyt++uNckZM6i4J9szVb9o4XVIRFb7zdNIu0eJOqxp9YDG5ERQL1TE +qkPFMTFYvZbF6nVsmnWxTfj3l/+WFvKXTej28xH5On2KOG4Ey+HTRRWqpdEdnV1j6CTmNhTih60b +WfVEm/vXd3wfAXBioSAaosUaKPQhA+4u2cGA6rnZgtZbdsLLO7XSAPCjDuGtbkD326C00EauFddE +wk01+dIL8hf2rGbVJLJP0RyZwG71fet0BLj5TXcJ17TPBzAJ8bgAVtkXFhYKK4bfjwEZGuW7gmP/ +vgt2Fl43N+bYdJeimUV5 +-----END CERTIFICATE----- + +Root CA Generalitat Valenciana +============================== +-----BEGIN CERTIFICATE----- +MIIGizCCBXOgAwIBAgIEO0XlaDANBgkqhkiG9w0BAQUFADBoMQswCQYDVQQGEwJFUzEfMB0GA1UE +ChMWR2VuZXJhbGl0YXQgVmFsZW5jaWFuYTEPMA0GA1UECxMGUEtJR1ZBMScwJQYDVQQDEx5Sb290 +IENBIEdlbmVyYWxpdGF0IFZhbGVuY2lhbmEwHhcNMDEwNzA2MTYyMjQ3WhcNMjEwNzAxMTUyMjQ3 +WjBoMQswCQYDVQQGEwJFUzEfMB0GA1UEChMWR2VuZXJhbGl0YXQgVmFsZW5jaWFuYTEPMA0GA1UE +CxMGUEtJR1ZBMScwJQYDVQQDEx5Sb290IENBIEdlbmVyYWxpdGF0IFZhbGVuY2lhbmEwggEiMA0G +CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDGKqtXETcvIorKA3Qdyu0togu8M1JAJke+WmmmO3I2 +F0zo37i7L3bhQEZ0ZQKQUgi0/6iMweDHiVYQOTPvaLRfX9ptI6GJXiKjSgbwJ/BXufjpTjJ3Cj9B +ZPPrZe52/lSqfR0grvPXdMIKX/UIKFIIzFVd0g/bmoGlu6GzwZTNVOAydTGRGmKy3nXiz0+J2ZGQ +D0EbtFpKd71ng+CT516nDOeB0/RSrFOyA8dEJvt55cs0YFAQexvba9dHq198aMpunUEDEO5rmXte +JajCq+TA81yc477OMUxkHl6AovWDfgzWyoxVjr7gvkkHD6MkQXpYHYTqWBLI4bft75PelAgxAgMB +AAGjggM7MIIDNzAyBggrBgEFBQcBAQQmMCQwIgYIKwYBBQUHMAGGFmh0dHA6Ly9vY3NwLnBraS5n +dmEuZXMwEgYDVR0TAQH/BAgwBgEB/wIBAjCCAjQGA1UdIASCAiswggInMIICIwYKKwYBBAG/VQIB +ADCCAhMwggHoBggrBgEFBQcCAjCCAdoeggHWAEEAdQB0AG8AcgBpAGQAYQBkACAAZABlACAAQwBl +AHIAdABpAGYAaQBjAGEAYwBpAPMAbgAgAFIAYQDtAHoAIABkAGUAIABsAGEAIABHAGUAbgBlAHIA +YQBsAGkAdABhAHQAIABWAGEAbABlAG4AYwBpAGEAbgBhAC4ADQAKAEwAYQAgAEQAZQBjAGwAYQBy +AGEAYwBpAPMAbgAgAGQAZQAgAFAAcgDhAGMAdABpAGMAYQBzACAAZABlACAAQwBlAHIAdABpAGYA +aQBjAGEAYwBpAPMAbgAgAHEAdQBlACAAcgBpAGcAZQAgAGUAbAAgAGYAdQBuAGMAaQBvAG4AYQBt +AGkAZQBuAHQAbwAgAGQAZQAgAGwAYQAgAHAAcgBlAHMAZQBuAHQAZQAgAEEAdQB0AG8AcgBpAGQA +YQBkACAAZABlACAAQwBlAHIAdABpAGYAaQBjAGEAYwBpAPMAbgAgAHMAZQAgAGUAbgBjAHUAZQBu +AHQAcgBhACAAZQBuACAAbABhACAAZABpAHIAZQBjAGMAaQDzAG4AIAB3AGUAYgAgAGgAdAB0AHAA +OgAvAC8AdwB3AHcALgBwAGsAaQAuAGcAdgBhAC4AZQBzAC8AYwBwAHMwJQYIKwYBBQUHAgEWGWh0 +dHA6Ly93d3cucGtpLmd2YS5lcy9jcHMwHQYDVR0OBBYEFHs100DSHHgZZu90ECjcPk+yeAT8MIGV +BgNVHSMEgY0wgYqAFHs100DSHHgZZu90ECjcPk+yeAT8oWykajBoMQswCQYDVQQGEwJFUzEfMB0G +A1UEChMWR2VuZXJhbGl0YXQgVmFsZW5jaWFuYTEPMA0GA1UECxMGUEtJR1ZBMScwJQYDVQQDEx5S +b290IENBIEdlbmVyYWxpdGF0IFZhbGVuY2lhbmGCBDtF5WgwDQYJKoZIhvcNAQEFBQADggEBACRh +TvW1yEICKrNcda3FbcrnlD+laJWIwVTAEGmiEi8YPyVQqHxK6sYJ2fR1xkDar1CdPaUWu20xxsdz +Ckj+IHLtb8zog2EWRpABlUt9jppSCS/2bxzkoXHPjCpaF3ODR00PNvsETUlR4hTJZGH71BTg9J63 +NI8KJr2XXPR5OkowGcytT6CYirQxlyric21+eLj4iIlPsSKRZEv1UN4D2+XFducTZnV+ZfsBn5OH +iJ35Rld8TWCvmHMTI6QgkYH60GFmuH3Rr9ZvHmw96RH9qfmCIoaZM3Fa6hlXPZHNqcCjbgcTpsnt ++GijnsNacgmHKNHEc8RzGF9QdRYxn7fofMM= +-----END CERTIFICATE----- + +A-Trust-nQual-03 +================ +-----BEGIN CERTIFICATE----- +MIIDzzCCAregAwIBAgIDAWweMA0GCSqGSIb3DQEBBQUAMIGNMQswCQYDVQQGEwJBVDFIMEYGA1UE +Cgw/QS1UcnVzdCBHZXMuIGYuIFNpY2hlcmhlaXRzc3lzdGVtZSBpbSBlbGVrdHIuIERhdGVudmVy +a2VociBHbWJIMRkwFwYDVQQLDBBBLVRydXN0LW5RdWFsLTAzMRkwFwYDVQQDDBBBLVRydXN0LW5R +dWFsLTAzMB4XDTA1MDgxNzIyMDAwMFoXDTE1MDgxNzIyMDAwMFowgY0xCzAJBgNVBAYTAkFUMUgw +RgYDVQQKDD9BLVRydXN0IEdlcy4gZi4gU2ljaGVyaGVpdHNzeXN0ZW1lIGltIGVsZWt0ci4gRGF0 +ZW52ZXJrZWhyIEdtYkgxGTAXBgNVBAsMEEEtVHJ1c3QtblF1YWwtMDMxGTAXBgNVBAMMEEEtVHJ1 +c3QtblF1YWwtMDMwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCtPWFuA/OQO8BBC4SA +zewqo51ru27CQoT3URThoKgtUaNR8t4j8DRE/5TrzAUjlUC5B3ilJfYKvUWG6Nm9wASOhURh73+n +yfrBJcyFLGM/BWBzSQXgYHiVEEvc+RFZznF/QJuKqiTfC0Li21a8StKlDJu3Qz7dg9MmEALP6iPE +SU7l0+m0iKsMrmKS1GWH2WrX9IWf5DMiJaXlyDO6w8dB3F/GaswADm0yqLaHNgBid5seHzTLkDx4 +iHQF63n1k3Flyp3HaxgtPVxO59X4PzF9j4fsCiIvI+n+u33J4PTs63zEsMMtYrWacdaxaujs2e3V +cuy+VwHOBVWf3tFgiBCzAgMBAAGjNjA0MA8GA1UdEwEB/wQFMAMBAf8wEQYDVR0OBAoECERqlWdV +eRFPMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQUFAAOCAQEAVdRU0VlIXLOThaq/Yy/kgM40 +ozRiPvbY7meIMQQDbwvUB/tOdQ/TLtPAF8fGKOwGDREkDg6lXb+MshOWcdzUzg4NCmgybLlBMRmr +sQd7TZjTXLDR8KdCoLXEjq/+8T/0709GAHbrAvv5ndJAlseIOrifEXnzgGWovR/TeIGgUUw3tKZd +JXDRZslo+S4RFGjxVJgIrCaSD96JntT6s3kr0qN51OyLrIdTaEJMUVF0HhsnLuP1Hyl0Te2v9+GS +mYHovjrHF1D2t8b8m7CKa9aIA5GPBnc6hQLdmNVDeD/GMBWsm2vLV7eJUYs66MmEDNuxUCAKGkq6 +ahq97BvIxYSazQ== +-----END CERTIFICATE----- + +TWCA Root Certification Authority +================================= +-----BEGIN CERTIFICATE----- +MIIDezCCAmOgAwIBAgIBATANBgkqhkiG9w0BAQUFADBfMQswCQYDVQQGEwJUVzESMBAGA1UECgwJ +VEFJV0FOLUNBMRAwDgYDVQQLDAdSb290IENBMSowKAYDVQQDDCFUV0NBIFJvb3QgQ2VydGlmaWNh +dGlvbiBBdXRob3JpdHkwHhcNMDgwODI4MDcyNDMzWhcNMzAxMjMxMTU1OTU5WjBfMQswCQYDVQQG +EwJUVzESMBAGA1UECgwJVEFJV0FOLUNBMRAwDgYDVQQLDAdSb290IENBMSowKAYDVQQDDCFUV0NB +IFJvb3QgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK +AoIBAQCwfnK4pAOU5qfeCTiRShFAh6d8WWQUe7UREN3+v9XAu1bihSX0NXIP+FPQQeFEAcK0HMMx +QhZHhTMidrIKbw/lJVBPhYa+v5guEGcevhEFhgWQxFnQfHgQsIBct+HHK3XLfJ+utdGdIzdjp9xC +oi2SBBtQwXu4PhvJVgSLL1KbralW6cH/ralYhzC2gfeXRfwZVzsrb+RH9JlF/h3x+JejiB03HFyP +4HYlmlD4oFT/RJB2I9IyxsOrBr/8+7/zrX2SYgJbKdM1o5OaQ2RgXbL6Mv87BK9NQGr5x+PvI/1r +y+UPizgN7gr8/g+YnzAx3WxSZfmLgb4i4RxYA7qRG4kHAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIB +BjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRqOFsmjd6LWvJPelSDGRjjCDWmujANBgkqhkiG +9w0BAQUFAAOCAQEAPNV3PdrfibqHDAhUaiBQkr6wQT25JmSDCi/oQMCXKCeCMErJk/9q56YAf4lC +mtYR5VPOL8zy2gXE/uJQxDqGfczafhAJO5I1KlOy/usrBdlsXebQ79NqZp4VKIV66IIArB6nCWlW +QtNoURi+VJq/REG6Sb4gumlc7rh3zc5sH62Dlhh9DrUUOYTxKOkto557HnpyWoOzeW/vtPzQCqVY +T0bf+215WfKEIlKuD8z7fDvnaspHYcN6+NOSBB+4IIThNlQWx0DeO4pz3N/GCUzf7Nr/1FNCocny +Yh0igzyXxfkZYiesZSLX0zzG5Y6yU8xJzrww/nsOM5D77dIUkR8Hrw== +-----END CERTIFICATE----- + +Security Communication RootCA2 +============================== +-----BEGIN CERTIFICATE----- +MIIDdzCCAl+gAwIBAgIBADANBgkqhkiG9w0BAQsFADBdMQswCQYDVQQGEwJKUDElMCMGA1UEChMc +U0VDT00gVHJ1c3QgU3lzdGVtcyBDTy4sTFRELjEnMCUGA1UECxMeU2VjdXJpdHkgQ29tbXVuaWNh +dGlvbiBSb290Q0EyMB4XDTA5MDUyOTA1MDAzOVoXDTI5MDUyOTA1MDAzOVowXTELMAkGA1UEBhMC +SlAxJTAjBgNVBAoTHFNFQ09NIFRydXN0IFN5c3RlbXMgQ08uLExURC4xJzAlBgNVBAsTHlNlY3Vy +aXR5IENvbW11bmljYXRpb24gUm9vdENBMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB +ANAVOVKxUrO6xVmCxF1SrjpDZYBLx/KWvNs2l9amZIyoXvDjChz335c9S672XewhtUGrzbl+dp++ ++T42NKA7wfYxEUV0kz1XgMX5iZnK5atq1LXaQZAQwdbWQonCv/Q4EpVMVAX3NuRFg3sUZdbcDE3R +3n4MqzvEFb46VqZab3ZpUql6ucjrappdUtAtCms1FgkQhNBqyjoGADdH5H5XTz+L62e4iKrFvlNV +spHEfbmwhRkGeC7bYRr6hfVKkaHnFtWOojnflLhwHyg/i/xAXmODPIMqGplrz95Zajv8bxbXH/1K +EOtOghY6rCcMU/Gt1SSwawNQwS08Ft1ENCcadfsCAwEAAaNCMEAwHQYDVR0OBBYEFAqFqXdlBZh8 +QIH4D5csOPEK7DzPMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEB +CwUAA4IBAQBMOqNErLlFsceTfsgLCkLfZOoc7llsCLqJX2rKSpWeeo8HxdpFcoJxDjrSzG+ntKEj +u/Ykn8sX/oymzsLS28yN/HH8AynBbF0zX2S2ZTuJbxh2ePXcokgfGT+Ok+vx+hfuzU7jBBJV1uXk +3fs+BXziHV7Gp7yXT2g69ekuCkO2r1dcYmh8t/2jioSgrGK+KwmHNPBqAbubKVY8/gA3zyNs8U6q +tnRGEmyR7jTV7JqR50S+kDFy1UkC9gLl9B/rfNmWVan/7Ir5mUf/NVoCqgTLiluHcSmRvaS0eg29 +mvVXIwAHIRc/SjnRBUkLp7Y3gaVdjKozXoEofKd9J+sAro03 +-----END CERTIFICATE----- + +EC-ACC +====== +-----BEGIN CERTIFICATE----- +MIIFVjCCBD6gAwIBAgIQ7is969Qh3hSoYqwE893EATANBgkqhkiG9w0BAQUFADCB8zELMAkGA1UE +BhMCRVMxOzA5BgNVBAoTMkFnZW5jaWEgQ2F0YWxhbmEgZGUgQ2VydGlmaWNhY2lvIChOSUYgUS0w +ODAxMTc2LUkpMSgwJgYDVQQLEx9TZXJ2ZWlzIFB1YmxpY3MgZGUgQ2VydGlmaWNhY2lvMTUwMwYD +VQQLEyxWZWdldSBodHRwczovL3d3dy5jYXRjZXJ0Lm5ldC92ZXJhcnJlbCAoYykwMzE1MDMGA1UE +CxMsSmVyYXJxdWlhIEVudGl0YXRzIGRlIENlcnRpZmljYWNpbyBDYXRhbGFuZXMxDzANBgNVBAMT +BkVDLUFDQzAeFw0wMzAxMDcyMzAwMDBaFw0zMTAxMDcyMjU5NTlaMIHzMQswCQYDVQQGEwJFUzE7 +MDkGA1UEChMyQWdlbmNpYSBDYXRhbGFuYSBkZSBDZXJ0aWZpY2FjaW8gKE5JRiBRLTA4MDExNzYt +SSkxKDAmBgNVBAsTH1NlcnZlaXMgUHVibGljcyBkZSBDZXJ0aWZpY2FjaW8xNTAzBgNVBAsTLFZl +Z2V1IGh0dHBzOi8vd3d3LmNhdGNlcnQubmV0L3ZlcmFycmVsIChjKTAzMTUwMwYDVQQLEyxKZXJh +cnF1aWEgRW50aXRhdHMgZGUgQ2VydGlmaWNhY2lvIENhdGFsYW5lczEPMA0GA1UEAxMGRUMtQUND +MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsyLHT+KXQpWIR4NA9h0X84NzJB5R85iK +w5K4/0CQBXCHYMkAqbWUZRkiFRfCQ2xmRJoNBD45b6VLeqpjt4pEndljkYRm4CgPukLjbo73FCeT +ae6RDqNfDrHrZqJyTxIThmV6PttPB/SnCWDaOkKZx7J/sxaVHMf5NLWUhdWZXqBIoH7nF2W4onW4 +HvPlQn2v7fOKSGRdghST2MDk/7NQcvJ29rNdQlB50JQ+awwAvthrDk4q7D7SzIKiGGUzE3eeml0a +E9jD2z3Il3rucO2n5nzbcc8tlGLfbdb1OL4/pYUKGbio2Al1QnDE6u/LDsg0qBIimAy4E5S2S+zw +0JDnJwIDAQABo4HjMIHgMB0GA1UdEQQWMBSBEmVjX2FjY0BjYXRjZXJ0Lm5ldDAPBgNVHRMBAf8E +BTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUoMOLRKo3pUW/l4Ba0fF4opvpXY0wfwYD +VR0gBHgwdjB0BgsrBgEEAfV4AQMBCjBlMCwGCCsGAQUFBwIBFiBodHRwczovL3d3dy5jYXRjZXJ0 +Lm5ldC92ZXJhcnJlbDA1BggrBgEFBQcCAjApGidWZWdldSBodHRwczovL3d3dy5jYXRjZXJ0Lm5l +dC92ZXJhcnJlbCAwDQYJKoZIhvcNAQEFBQADggEBAKBIW4IB9k1IuDlVNZyAelOZ1Vr/sXE7zDkJ +lF7W2u++AVtd0x7Y/X1PzaBB4DSTv8vihpw3kpBWHNzrKQXlxJ7HNd+KDM3FIUPpqojlNcAZQmNa +Al6kSBg6hW/cnbw/nZzBh7h6YQjpdwt/cKt63dmXLGQehb+8dJahw3oS7AwaboMMPOhyRp/7SNVe +l+axofjk70YllJyJ22k4vuxcDlbHZVHlUIiIv0LVKz3l+bqeLrPK9HOSAgu+TGbrIP65y7WZf+a2 +E/rKS03Z7lNGBjvGTq2TWoF+bCpLagVFjPIhpDGQh2xlnJ2lYJU6Un/10asIbvPuW/mIPX64b24D +5EI= +-----END CERTIFICATE----- + +Hellenic Academic and Research Institutions RootCA 2011 +======================================================= +-----BEGIN CERTIFICATE----- +MIIEMTCCAxmgAwIBAgIBADANBgkqhkiG9w0BAQUFADCBlTELMAkGA1UEBhMCR1IxRDBCBgNVBAoT +O0hlbGxlbmljIEFjYWRlbWljIGFuZCBSZXNlYXJjaCBJbnN0aXR1dGlvbnMgQ2VydC4gQXV0aG9y +aXR5MUAwPgYDVQQDEzdIZWxsZW5pYyBBY2FkZW1pYyBhbmQgUmVzZWFyY2ggSW5zdGl0dXRpb25z +IFJvb3RDQSAyMDExMB4XDTExMTIwNjEzNDk1MloXDTMxMTIwMTEzNDk1MlowgZUxCzAJBgNVBAYT +AkdSMUQwQgYDVQQKEztIZWxsZW5pYyBBY2FkZW1pYyBhbmQgUmVzZWFyY2ggSW5zdGl0dXRpb25z +IENlcnQuIEF1dGhvcml0eTFAMD4GA1UEAxM3SGVsbGVuaWMgQWNhZGVtaWMgYW5kIFJlc2VhcmNo +IEluc3RpdHV0aW9ucyBSb290Q0EgMjAxMTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB +AKlTAOMupvaO+mDYLZU++CwqVE7NuYRhlFhPjz2L5EPzdYmNUeTDN9KKiE15HrcS3UN4SoqS5tdI +1Q+kOilENbgH9mgdVc04UfCMJDGFr4PJfel3r+0ae50X+bOdOFAPplp5kYCvN66m0zH7tSYJnTxa +71HFK9+WXesyHgLacEnsbgzImjeN9/E2YEsmLIKe0HjzDQ9jpFEw4fkrJxIH2Oq9GGKYsFk3fb7u +8yBRQlqD75O6aRXxYp2fmTmCobd0LovUxQt7L/DICto9eQqakxylKHJzkUOap9FNhYS5qXSPFEDH +3N6sQWRstBmbAmNtJGSPRLIl6s5ddAxjMlyNh+UCAwEAAaOBiTCBhjAPBgNVHRMBAf8EBTADAQH/ +MAsGA1UdDwQEAwIBBjAdBgNVHQ4EFgQUppFC/RNhSiOeCKQp5dgTBCPuQSUwRwYDVR0eBEAwPqA8 +MAWCAy5ncjAFggMuZXUwBoIELmVkdTAGggQub3JnMAWBAy5ncjAFgQMuZXUwBoEELmVkdTAGgQQu +b3JnMA0GCSqGSIb3DQEBBQUAA4IBAQAf73lB4XtuP7KMhjdCSk4cNx6NZrokgclPEg8hwAOXhiVt +XdMiKahsog2p6z0GW5k6x8zDmjR/qw7IThzh+uTczQ2+vyT+bOdrwg3IBp5OjWEopmr95fZi6hg8 +TqBTnbI6nOulnJEWtk2C4AwFSKls9cz4y51JtPACpf1wA+2KIaWuE4ZJwzNzvoc7dIsXRSZMFpGD +/md9zU1jZ/rzAxKWeAaNsWftjj++n08C9bMJL/NMh98qy5V8AcysNnq/onN694/BtZqhFLKPM58N +7yLcZnuEvUUXBj08yrl3NI/K6s8/MT7jiOOASSXIl7WdmplNsDz4SgCbZN2fOUvRJ9e4 +-----END CERTIFICATE----- + +Actalis Authentication Root CA +============================== +-----BEGIN CERTIFICATE----- +MIIFuzCCA6OgAwIBAgIIVwoRl0LE48wwDQYJKoZIhvcNAQELBQAwazELMAkGA1UEBhMCSVQxDjAM +BgNVBAcMBU1pbGFuMSMwIQYDVQQKDBpBY3RhbGlzIFMucC5BLi8wMzM1ODUyMDk2NzEnMCUGA1UE +AwweQWN0YWxpcyBBdXRoZW50aWNhdGlvbiBSb290IENBMB4XDTExMDkyMjExMjIwMloXDTMwMDky +MjExMjIwMlowazELMAkGA1UEBhMCSVQxDjAMBgNVBAcMBU1pbGFuMSMwIQYDVQQKDBpBY3RhbGlz +IFMucC5BLi8wMzM1ODUyMDk2NzEnMCUGA1UEAwweQWN0YWxpcyBBdXRoZW50aWNhdGlvbiBSb290 +IENBMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAp8bEpSmkLO/lGMWwUKNvUTufClrJ +wkg4CsIcoBh/kbWHuUA/3R1oHwiD1S0eiKD4j1aPbZkCkpAW1V8IbInX4ay8IMKx4INRimlNAJZa +by/ARH6jDuSRzVju3PvHHkVH3Se5CAGfpiEd9UEtL0z9KK3giq0itFZljoZUj5NDKd45RnijMCO6 +zfB9E1fAXdKDa0hMxKufgFpbOr3JpyI/gCczWw63igxdBzcIy2zSekciRDXFzMwujt0q7bd9Zg1f +YVEiVRvjRuPjPdA1YprbrxTIW6HMiRvhMCb8oJsfgadHHwTrozmSBp+Z07/T6k9QnBn+locePGX2 +oxgkg4YQ51Q+qDp2JE+BIcXjDwL4k5RHILv+1A7TaLndxHqEguNTVHnd25zS8gebLra8Pu2Fbe8l +EfKXGkJh90qX6IuxEAf6ZYGyojnP9zz/GPvG8VqLWeICrHuS0E4UT1lF9gxeKF+w6D9Fz8+vm2/7 +hNN3WpVvrJSEnu68wEqPSpP4RCHiMUVhUE4Q2OM1fEwZtN4Fv6MGn8i1zeQf1xcGDXqVdFUNaBr8 +EBtiZJ1t4JWgw5QHVw0U5r0F+7if5t+L4sbnfpb2U8WANFAoWPASUHEXMLrmeGO89LKtmyuy/uE5 +jF66CyCU3nuDuP/jVo23Eek7jPKxwV2dpAtMK9myGPW1n0sCAwEAAaNjMGEwHQYDVR0OBBYEFFLY +iDrIn3hm7YnzezhwlMkCAjbQMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAUUtiIOsifeGbt +ifN7OHCUyQICNtAwDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEBCwUAA4ICAQALe3KHwGCmSUyI +WOYdiPcUZEim2FgKDk8TNd81HdTtBjHIgT5q1d07GjLukD0R0i70jsNjLiNmsGe+b7bAEzlgqqI0 +JZN1Ut6nna0Oh4lScWoWPBkdg/iaKWW+9D+a2fDzWochcYBNy+A4mz+7+uAwTc+G02UQGRjRlwKx +K3JCaKygvU5a2hi/a5iB0P2avl4VSM0RFbnAKVy06Ij3Pjaut2L9HmLecHgQHEhb2rykOLpn7VU+ +Xlff1ANATIGk0k9jpwlCCRT8AKnCgHNPLsBA2RF7SOp6AsDT6ygBJlh0wcBzIm2Tlf05fbsq4/aC +4yyXX04fkZT6/iyj2HYauE2yOE+b+h1IYHkm4vP9qdCa6HCPSXrW5b0KDtst842/6+OkfcvHlXHo +2qN8xcL4dJIEG4aspCJTQLas/kx2z/uUMsA1n3Y/buWQbqCmJqK4LL7RK4X9p2jIugErsWx0Hbhz +lefut8cl8ABMALJ+tguLHPPAUJ4lueAI3jZm/zel0btUZCzJJ7VLkn5l/9Mt4blOvH+kQSGQQXem +OR/qnuOf0GZvBeyqdn6/axag67XH/JJULysRJyU3eExRarDzzFhdFPFqSBX/wge2sY0PjlxQRrM9 +vwGYT7JZVEc+NHt4bVaTLnPqZih4zR0Uv6CPLy64Lo7yFIrM6bV8+2ydDKXhlg== +-----END CERTIFICATE----- + +Trustis FPS Root CA +=================== +-----BEGIN CERTIFICATE----- +MIIDZzCCAk+gAwIBAgIQGx+ttiD5JNM2a/fH8YygWTANBgkqhkiG9w0BAQUFADBFMQswCQYDVQQG +EwJHQjEYMBYGA1UEChMPVHJ1c3RpcyBMaW1pdGVkMRwwGgYDVQQLExNUcnVzdGlzIEZQUyBSb290 +IENBMB4XDTAzMTIyMzEyMTQwNloXDTI0MDEyMTExMzY1NFowRTELMAkGA1UEBhMCR0IxGDAWBgNV +BAoTD1RydXN0aXMgTGltaXRlZDEcMBoGA1UECxMTVHJ1c3RpcyBGUFMgUm9vdCBDQTCCASIwDQYJ +KoZIhvcNAQEBBQADggEPADCCAQoCggEBAMVQe547NdDfxIzNjpvto8A2mfRC6qc+gIMPpqdZh8mQ +RUN+AOqGeSoDvT03mYlmt+WKVoaTnGhLaASMk5MCPjDSNzoiYYkchU59j9WvezX2fihHiTHcDnlk +H5nSW7r+f2C/revnPDgpai/lkQtV/+xvWNUtyd5MZnGPDNcE2gfmHhjjvSkCqPoc4Vu5g6hBSLwa +cY3nYuUtsuvffM/bq1rKMfFMIvMFE/eC+XN5DL7XSxzA0RU8k0Fk0ea+IxciAIleH2ulrG6nS4zt +o3Lmr2NNL4XSFDWaLk6M6jKYKIahkQlBOrTh4/L68MkKokHdqeMDx4gVOxzUGpTXn2RZEm0CAwEA +AaNTMFEwDwYDVR0TAQH/BAUwAwEB/zAfBgNVHSMEGDAWgBS6+nEleYtXQSUhhgtx67JkDoshZzAd +BgNVHQ4EFgQUuvpxJXmLV0ElIYYLceuyZA6LIWcwDQYJKoZIhvcNAQEFBQADggEBAH5Y//01GX2c +GE+esCu8jowU/yyg2kdbw++BLa8F6nRIW/M+TgfHbcWzk88iNVy2P3UnXwmWzaD+vkAMXBJV+JOC +yinpXj9WV4s4NvdFGkwozZ5BuO1WTISkQMi4sKUraXAEasP41BIy+Q7DsdwyhEQsb8tGD+pmQQ9P +8Vilpg0ND2HepZ5dfWWhPBfnqFVO76DH7cZEf1T1o+CP8HxVIo8ptoGj4W1OLBuAZ+ytIJ8MYmHV +l/9D7S3B2l0pKoU/rGXuhg8FjZBf3+6f9L/uHfuY5H+QK4R4EA5sSVPvFVtlRkpdr7r7OnIdzfYl +iB6XzCGcKQENZetX2fNXlrtIzYE= +-----END CERTIFICATE----- + +StartCom Certification Authority +================================ +-----BEGIN CERTIFICATE----- +MIIHhzCCBW+gAwIBAgIBLTANBgkqhkiG9w0BAQsFADB9MQswCQYDVQQGEwJJTDEWMBQGA1UEChMN +U3RhcnRDb20gTHRkLjErMCkGA1UECxMiU2VjdXJlIERpZ2l0YWwgQ2VydGlmaWNhdGUgU2lnbmlu +ZzEpMCcGA1UEAxMgU3RhcnRDb20gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDYwOTE3MTk0 +NjM3WhcNMzYwOTE3MTk0NjM2WjB9MQswCQYDVQQGEwJJTDEWMBQGA1UEChMNU3RhcnRDb20gTHRk +LjErMCkGA1UECxMiU2VjdXJlIERpZ2l0YWwgQ2VydGlmaWNhdGUgU2lnbmluZzEpMCcGA1UEAxMg +U3RhcnRDb20gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAw +ggIKAoICAQDBiNsJvGxGfHiflXu1M5DycmLWwTYgIiRezul38kMKogZkpMyONvg45iPwbm2xPN1y +o4UcodM9tDMr0y+v/uqwQVlntsQGfQqedIXWeUyAN3rfOQVSWff0G0ZDpNKFhdLDcfN1YjS6LIp/ +Ho/u7TTQEceWzVI9ujPW3U3eCztKS5/CJi/6tRYccjV3yjxd5srhJosaNnZcAdt0FCX+7bWgiA/d +eMotHweXMAEtcnn6RtYTKqi5pquDSR3l8u/d5AGOGAqPY1MWhWKpDhk6zLVmpsJrdAfkK+F2PrRt +2PZE4XNiHzvEvqBTViVsUQn3qqvKv3b9bZvzndu/PWa8DFaqr5hIlTpL36dYUNk4dalb6kMMAv+Z +6+hsTXBbKWWc3apdzK8BMewM69KN6Oqce+Zu9ydmDBpI125C4z/eIT574Q1w+2OqqGwaVLRcJXrJ +osmLFqa7LH4XXgVNWG4SHQHuEhANxjJ/GP/89PrNbpHoNkm+Gkhpi8KWTRoSsmkXwQqQ1vp5Iki/ +untp+HDH+no32NgN0nZPV/+Qt+OR0t3vwmC3Zzrd/qqc8NSLf3Iizsafl7b4r4qgEKjZ+xjGtrVc +UjyJthkqcwEKDwOzEmDyei+B26Nu/yYwl/WL3YlXtq09s68rxbd2AvCl1iuahhQqcvbjM4xdCUsT +37uMdBNSSwIDAQABo4ICEDCCAgwwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYD +VR0OBBYEFE4L7xqkQFulF2mHMMo0aEPQQa7yMB8GA1UdIwQYMBaAFE4L7xqkQFulF2mHMMo0aEPQ +Qa7yMIIBWgYDVR0gBIIBUTCCAU0wggFJBgsrBgEEAYG1NwEBATCCATgwLgYIKwYBBQUHAgEWImh0 +dHA6Ly93d3cuc3RhcnRzc2wuY29tL3BvbGljeS5wZGYwNAYIKwYBBQUHAgEWKGh0dHA6Ly93d3cu +c3RhcnRzc2wuY29tL2ludGVybWVkaWF0ZS5wZGYwgc8GCCsGAQUFBwICMIHCMCcWIFN0YXJ0IENv +bW1lcmNpYWwgKFN0YXJ0Q29tKSBMdGQuMAMCAQEagZZMaW1pdGVkIExpYWJpbGl0eSwgcmVhZCB0 +aGUgc2VjdGlvbiAqTGVnYWwgTGltaXRhdGlvbnMqIG9mIHRoZSBTdGFydENvbSBDZXJ0aWZpY2F0 +aW9uIEF1dGhvcml0eSBQb2xpY3kgYXZhaWxhYmxlIGF0IGh0dHA6Ly93d3cuc3RhcnRzc2wuY29t +L3BvbGljeS5wZGYwEQYJYIZIAYb4QgEBBAQDAgAHMDgGCWCGSAGG+EIBDQQrFilTdGFydENvbSBG +cmVlIFNTTCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTANBgkqhkiG9w0BAQsFAAOCAgEAjo/n3JR5 +fPGFf59Jb2vKXfuM/gTFwWLRfUKKvFO3lANmMD+x5wqnUCBVJX92ehQN6wQOQOY+2IirByeDqXWm +N3PH/UvSTa0XQMhGvjt/UfzDtgUx3M2FIk5xt/JxXrAaxrqTi3iSSoX4eA+D/i+tLPfkpLst0OcN +Org+zvZ49q5HJMqjNTbOx8aHmNrs++myziebiMMEofYLWWivydsQD032ZGNcpRJvkrKTlMeIFw6T +tn5ii5B/q06f/ON1FE8qMt9bDeD1e5MNq6HPh+GlBEXoPBKlCcWw0bdT82AUuoVpaiF8H3VhFyAX +e2w7QSlc4axa0c2Mm+tgHRns9+Ww2vl5GKVFP0lDV9LdJNUso/2RjSe15esUBppMeyG7Oq0wBhjA +2MFrLH9ZXF2RsXAiV+uKa0hK1Q8p7MZAwC+ITGgBF3f0JBlPvfrhsiAhS90a2Cl9qrjeVOwhVYBs +HvUwyKMQ5bLmKhQxw4UtjJixhlpPiVktucf3HMiKf8CdBUrmQk9io20ppB+Fq9vlgcitKj1MXVuE +JnHEhV5xJMqlG2zYYdMa4FTbzrqpMrUi9nNBCV24F10OD5mQ1kfabwo6YigUZ4LZ8dCAWZvLMdib +D4x3TrVoivJs9iQOLWxwxXPR3hTQcY+203sC9uO41Alua551hDnmfyWl8kgAwKQB2j8= +-----END CERTIFICATE----- + +StartCom Certification Authority G2 +=================================== +-----BEGIN CERTIFICATE----- +MIIFYzCCA0ugAwIBAgIBOzANBgkqhkiG9w0BAQsFADBTMQswCQYDVQQGEwJJTDEWMBQGA1UEChMN +U3RhcnRDb20gTHRkLjEsMCoGA1UEAxMjU3RhcnRDb20gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkg +RzIwHhcNMTAwMTAxMDEwMDAxWhcNMzkxMjMxMjM1OTAxWjBTMQswCQYDVQQGEwJJTDEWMBQGA1UE +ChMNU3RhcnRDb20gTHRkLjEsMCoGA1UEAxMjU3RhcnRDb20gQ2VydGlmaWNhdGlvbiBBdXRob3Jp +dHkgRzIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC2iTZbB7cgNr2Cu+EWIAOVeq8O +o1XJJZlKxdBWQYeQTSFgpBSHO839sj60ZwNq7eEPS8CRhXBF4EKe3ikj1AENoBB5uNsDvfOpL9HG +4A/LnooUCri99lZi8cVytjIl2bLzvWXFDSxu1ZJvGIsAQRSCb0AgJnooD/Uefyf3lLE3PbfHkffi +Aez9lInhzG7TNtYKGXmu1zSCZf98Qru23QumNK9LYP5/Q0kGi4xDuFby2X8hQxfqp0iVAXV16iul +Q5XqFYSdCI0mblWbq9zSOdIxHWDirMxWRST1HFSr7obdljKF+ExP6JV2tgXdNiNnvP8V4so75qbs +O+wmETRIjfaAKxojAuuKHDp2KntWFhxyKrOq42ClAJ8Em+JvHhRYW6Vsi1g8w7pOOlz34ZYrPu8H +vKTlXcxNnw3h3Kq74W4a7I/htkxNeXJdFzULHdfBR9qWJODQcqhaX2YtENwvKhOuJv4KHBnM0D4L +nMgJLvlblnpHnOl68wVQdJVznjAJ85eCXuaPOQgeWeU1FEIT/wCc976qUM/iUUjXuG+v+E5+M5iS +FGI6dWPPe/regjupuznixL0sAA7IF6wT700ljtizkC+p2il9Ha90OrInwMEePnWjFqmveiJdnxMa +z6eg6+OGCtP95paV1yPIN93EfKo2rJgaErHgTuixO/XWb/Ew1wIDAQABo0IwQDAPBgNVHRMBAf8E +BTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUS8W0QGutHLOlHGVuRjaJhwUMDrYwDQYJ +KoZIhvcNAQELBQADggIBAHNXPyzVlTJ+N9uWkusZXn5T50HsEbZH77Xe7XRcxfGOSeD8bpkTzZ+K +2s06Ctg6Wgk/XzTQLwPSZh0avZyQN8gMjgdalEVGKua+etqhqaRpEpKwfTbURIfXUfEpY9Z1zRbk +J4kd+MIySP3bmdCPX1R0zKxnNBFi2QwKN4fRoxdIjtIXHfbX/dtl6/2o1PXWT6RbdejF0mCy2wl+ +JYt7ulKSnj7oxXehPOBKc2thz4bcQ///If4jXSRK9dNtD2IEBVeC2m6kMyV5Sy5UGYvMLD0w6dEG +/+gyRr61M3Z3qAFdlsHB1b6uJcDJHgoJIIihDsnzb02CVAAgp9KP5DlUFy6NHrgbuxu9mk47EDTc +nIhT76IxW1hPkWLIwpqazRVdOKnWvvgTtZ8SafJQYqz7Fzf07rh1Z2AQ+4NQ+US1dZxAF7L+/Xld +blhYXzD8AK6vM8EOTmy6p6ahfzLbOOCxchcKK5HsamMm7YnUeMx0HgX4a/6ManY5Ka5lIxKVCCIc +l85bBu4M4ru8H0ST9tg4RQUh7eStqxK2A6RCLi3ECToDZ2mEmuFZkIoohdVddLHRDiBYmxOlsGOm +7XtH/UVVMKTumtTm4ofvmMkyghEpIrwACjFeLQ/Ajulrso8uBtjRkcfGEvRM/TAXw8HaOFvjqerm +obp573PYtlNXLfbQ4ddI +-----END CERTIFICATE----- + +Buypass Class 2 Root CA +======================= +-----BEGIN CERTIFICATE----- +MIIFWTCCA0GgAwIBAgIBAjANBgkqhkiG9w0BAQsFADBOMQswCQYDVQQGEwJOTzEdMBsGA1UECgwU +QnV5cGFzcyBBUy05ODMxNjMzMjcxIDAeBgNVBAMMF0J1eXBhc3MgQ2xhc3MgMiBSb290IENBMB4X +DTEwMTAyNjA4MzgwM1oXDTQwMTAyNjA4MzgwM1owTjELMAkGA1UEBhMCTk8xHTAbBgNVBAoMFEJ1 +eXBhc3MgQVMtOTgzMTYzMzI3MSAwHgYDVQQDDBdCdXlwYXNzIENsYXNzIDIgUm9vdCBDQTCCAiIw +DQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBANfHXvfBB9R3+0Mh9PT1aeTuMgHbo4Yf5FkNuud1 +g1Lr6hxhFUi7HQfKjK6w3Jad6sNgkoaCKHOcVgb/S2TwDCo3SbXlzwx87vFKu3MwZfPVL4O2fuPn +9Z6rYPnT8Z2SdIrkHJasW4DptfQxh6NR/Md+oW+OU3fUl8FVM5I+GC911K2GScuVr1QGbNgGE41b +/+EmGVnAJLqBcXmQRFBoJJRfuLMR8SlBYaNByyM21cHxMlAQTn/0hpPshNOOvEu/XAFOBz3cFIqU +CqTqc/sLUegTBxj6DvEr0VQVfTzh97QZQmdiXnfgolXsttlpF9U6r0TtSsWe5HonfOV116rLJeff +awrbD02TTqigzXsu8lkBarcNuAeBfos4GzjmCleZPe4h6KP1DBbdi+w0jpwqHAAVF41og9JwnxgI +zRFo1clrUs3ERo/ctfPYV3Me6ZQ5BL/T3jjetFPsaRyifsSP5BtwrfKi+fv3FmRmaZ9JUaLiFRhn +Bkp/1Wy1TbMz4GHrXb7pmA8y1x1LPC5aAVKRCfLf6o3YBkBjqhHk/sM3nhRSP/TizPJhk9H9Z2vX +Uq6/aKtAQ6BXNVN48FP4YUIHZMbXb5tMOA1jrGKvNouicwoN9SG9dKpN6nIDSdvHXx1iY8f93ZHs +M+71bbRuMGjeyNYmsHVee7QHIJihdjK4TWxPAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wHQYD +VR0OBBYEFMmAd+BikoL1RpzzuvdMw964o605MA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQsF +AAOCAgEAU18h9bqwOlI5LJKwbADJ784g7wbylp7ppHR/ehb8t/W2+xUbP6umwHJdELFx7rxP462s +A20ucS6vxOOto70MEae0/0qyexAQH6dXQbLArvQsWdZHEIjzIVEpMMpghq9Gqx3tOluwlN5E40EI +osHsHdb9T7bWR9AUC8rmyrV7d35BH16Dx7aMOZawP5aBQW9gkOLo+fsicdl9sz1Gv7SEr5AcD48S +aq/v7h56rgJKihcrdv6sVIkkLE8/trKnToyokZf7KcZ7XC25y2a2t6hbElGFtQl+Ynhw/qlqYLYd +DnkM/crqJIByw5c/8nerQyIKx+u2DISCLIBrQYoIwOula9+ZEsuK1V6ADJHgJgg2SMX6OBE1/yWD +LfJ6v9r9jv6ly0UsH8SIU653DtmadsWOLB2jutXsMq7Aqqz30XpN69QH4kj3Io6wpJ9qzo6ysmD0 +oyLQI+uUWnpp3Q+/QFesa1lQ2aOZ4W7+jQF5JyMV3pKdewlNWudLSDBaGOYKbeaP4NK75t98biGC +wWg5TbSYWGZizEqQXsP6JwSxeRV0mcy+rSDeJmAc61ZRpqPq5KM/p/9h3PFaTWwyI0PurKju7koS +CTxdccK+efrCh2gdC/1cacwG0Jp9VJkqyTkaGa9LKkPzY11aWOIv4x3kqdbQCtCev9eBCfHJxyYN +rJgWVqA= +-----END CERTIFICATE----- + +Buypass Class 3 Root CA +======================= +-----BEGIN CERTIFICATE----- +MIIFWTCCA0GgAwIBAgIBAjANBgkqhkiG9w0BAQsFADBOMQswCQYDVQQGEwJOTzEdMBsGA1UECgwU +QnV5cGFzcyBBUy05ODMxNjMzMjcxIDAeBgNVBAMMF0J1eXBhc3MgQ2xhc3MgMyBSb290IENBMB4X +DTEwMTAyNjA4Mjg1OFoXDTQwMTAyNjA4Mjg1OFowTjELMAkGA1UEBhMCTk8xHTAbBgNVBAoMFEJ1 +eXBhc3MgQVMtOTgzMTYzMzI3MSAwHgYDVQQDDBdCdXlwYXNzIENsYXNzIDMgUm9vdCBDQTCCAiIw +DQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAKXaCpUWUOOV8l6ddjEGMnqb8RB2uACatVI2zSRH +sJ8YZLya9vrVediQYkwiL944PdbgqOkcLNt4EemOaFEVcsfzM4fkoF0LXOBXByow9c3EN3coTRiR +5r/VUv1xLXA+58bEiuPwKAv0dpihi4dVsjoT/Lc+JzeOIuOoTyrvYLs9tznDDgFHmV0ST9tD+leh +7fmdvhFHJlsTmKtdFoqwNxxXnUX/iJY2v7vKB3tvh2PX0DJq1l1sDPGzbjniazEuOQAnFN44wOwZ +ZoYS6J1yFhNkUsepNxz9gjDthBgd9K5c/3ATAOux9TN6S9ZV+AWNS2mw9bMoNlwUxFFzTWsL8TQH +2xc519woe2v1n/MuwU8XKhDzzMro6/1rqy6any2CbgTUUgGTLT2G/H783+9CHaZr77kgxve9oKeV +/afmiSTYzIw0bOIjL9kSGiG5VZFvC5F5GQytQIgLcOJ60g7YaEi7ghM5EFjp2CoHxhLbWNvSO1UQ +RwUVZ2J+GGOmRj8JDlQyXr8NYnon74Do29lLBlo3WiXQCBJ31G8JUJc9yB3D34xFMFbG02SrZvPA +Xpacw8Tvw3xrizp5f7NJzz3iiZ+gMEuFuZyUJHmPfWupRWgPK9Dx2hzLabjKSWJtyNBjYt1gD1iq +j6G8BaVmos8bdrKEZLFMOVLAMLrwjEsCsLa3AgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wHQYD +VR0OBBYEFEe4zf/lb+74suwvTg75JbCOPGvDMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQsF +AAOCAgEAACAjQTUEkMJAYmDv4jVM1z+s4jSQuKFvdvoWFqRINyzpkMLyPPgKn9iB5btb2iUspKdV +cSQy9sgL8rxq+JOssgfCX5/bzMiKqr5qb+FJEMwx14C7u8jYog5kV+qi9cKpMRXSIGrs/CIBKM+G +uIAeqcwRpTzyFrNHnfzSgCHEy9BHcEGhyoMZCCxt8l13nIoUE9Q2HJLw5QY33KbmkJs4j1xrG0aG +Q0JfPgEHU1RdZX33inOhmlRaHylDFCfChQ+1iHsaO5S3HWCntZznKWlXWpuTekMwGwPXYshApqr8 +ZORK15FTAaggiG6cX0S5y2CBNOxv033aSF/rtJC8LakcC6wc1aJoIIAE1vyxjy+7SjENSoYc6+I2 +KSb12tjE8nVhz36udmNKekBlk4f4HoCMhuWG1o8O/FMsYOgWYRqiPkN7zTlgVGr18okmAWiDSKIz +6MkEkbIRNBE+6tBDGR8Dk5AM/1E9V/RBbuHLoL7ryWPNbczk+DaqaJ3tvV2XcEQNtg413OEMXbug +UZTLfhbrES+jkkXITHHZvMmZUldGL1DPvTVp9D0VzgalLA8+9oG6lLvDu79leNKGef9JOxqDDPDe +eOzI8k1MGt6CKfjBWtrt7uYnXuhF0J0cUahoq0Tj0Itq4/g7u9xN12TyUb7mqqta6THuBrxzvxNi +Cp/HuZc= +-----END CERTIFICATE----- + +T-TeleSec GlobalRoot Class 3 +============================ +-----BEGIN CERTIFICATE----- +MIIDwzCCAqugAwIBAgIBATANBgkqhkiG9w0BAQsFADCBgjELMAkGA1UEBhMCREUxKzApBgNVBAoM +IlQtU3lzdGVtcyBFbnRlcnByaXNlIFNlcnZpY2VzIEdtYkgxHzAdBgNVBAsMFlQtU3lzdGVtcyBU +cnVzdCBDZW50ZXIxJTAjBgNVBAMMHFQtVGVsZVNlYyBHbG9iYWxSb290IENsYXNzIDMwHhcNMDgx +MDAxMTAyOTU2WhcNMzMxMDAxMjM1OTU5WjCBgjELMAkGA1UEBhMCREUxKzApBgNVBAoMIlQtU3lz +dGVtcyBFbnRlcnByaXNlIFNlcnZpY2VzIEdtYkgxHzAdBgNVBAsMFlQtU3lzdGVtcyBUcnVzdCBD +ZW50ZXIxJTAjBgNVBAMMHFQtVGVsZVNlYyBHbG9iYWxSb290IENsYXNzIDMwggEiMA0GCSqGSIb3 +DQEBAQUAA4IBDwAwggEKAoIBAQC9dZPwYiJvJK7genasfb3ZJNW4t/zN8ELg63iIVl6bmlQdTQyK +9tPPcPRStdiTBONGhnFBSivwKixVA9ZIw+A5OO3yXDw/RLyTPWGrTs0NvvAgJ1gORH8EGoel15YU +NpDQSXuhdfsaa3Ox+M6pCSzyU9XDFES4hqX2iys52qMzVNn6chr3IhUciJFrf2blw2qAsCTz34ZF +iP0Zf3WHHx+xGwpzJFu5ZeAsVMhg02YXP+HMVDNzkQI6pn97djmiH5a2OK61yJN0HZ65tOVgnS9W +0eDrXltMEnAMbEQgqxHY9Bn20pxSN+f6tsIxO0rUFJmtxxr1XV/6B7h8DR/Wgx6zAgMBAAGjQjBA +MA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBS1A/d2O2GCahKqGFPr +AyGUv/7OyjANBgkqhkiG9w0BAQsFAAOCAQEAVj3vlNW92nOyWL6ukK2YJ5f+AbGwUgC4TeQbIXQb +fsDuXmkqJa9c1h3a0nnJ85cp4IaH3gRZD/FZ1GSFS5mvJQQeyUapl96Cshtwn5z2r3Ex3XsFpSzT +ucpH9sry9uetuUg/vBa3wW306gmv7PO15wWeph6KU1HWk4HMdJP2udqmJQV0eVp+QD6CSyYRMG7h +P0HHRwA11fXT91Q+gT3aSWqas+8QPebrb9HIIkfLzM8BMZLZGOMivgkeGj5asuRrDFR6fUNOuIml +e9eiPZaGzPImNC1qkp2aGtAw4l1OBLBfiyB+d8E9lYLRRpo7PHi4b6HQDWSieB4pTpPDpFQUWw== +-----END CERTIFICATE----- + +EE Certification Centre Root CA +=============================== +-----BEGIN CERTIFICATE----- +MIIEAzCCAuugAwIBAgIQVID5oHPtPwBMyonY43HmSjANBgkqhkiG9w0BAQUFADB1MQswCQYDVQQG +EwJFRTEiMCAGA1UECgwZQVMgU2VydGlmaXRzZWVyaW1pc2tlc2t1czEoMCYGA1UEAwwfRUUgQ2Vy +dGlmaWNhdGlvbiBDZW50cmUgUm9vdCBDQTEYMBYGCSqGSIb3DQEJARYJcGtpQHNrLmVlMCIYDzIw +MTAxMDMwMTAxMDMwWhgPMjAzMDEyMTcyMzU5NTlaMHUxCzAJBgNVBAYTAkVFMSIwIAYDVQQKDBlB +UyBTZXJ0aWZpdHNlZXJpbWlza2Vza3VzMSgwJgYDVQQDDB9FRSBDZXJ0aWZpY2F0aW9uIENlbnRy +ZSBSb290IENBMRgwFgYJKoZIhvcNAQkBFglwa2lAc2suZWUwggEiMA0GCSqGSIb3DQEBAQUAA4IB +DwAwggEKAoIBAQDIIMDs4MVLqwd4lfNE7vsLDP90jmG7sWLqI9iroWUyeuuOF0+W2Ap7kaJjbMeM +TC55v6kF/GlclY1i+blw7cNRfdCT5mzrMEvhvH2/UpvObntl8jixwKIy72KyaOBhU8E2lf/slLo2 +rpwcpzIP5Xy0xm90/XsY6KxX7QYgSzIwWFv9zajmofxwvI6Sc9uXp3whrj3B9UiHbCe9nyV0gVWw +93X2PaRka9ZP585ArQ/dMtO8ihJTmMmJ+xAdTX7Nfh9WDSFwhfYggx/2uh8Ej+p3iDXE/+pOoYtN +P2MbRMNE1CV2yreN1x5KZmTNXMWcg+HCCIia7E6j8T4cLNlsHaFLAgMBAAGjgYowgYcwDwYDVR0T +AQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFBLyWj7qVhy/zQas8fElyalL1BSZ +MEUGA1UdJQQ+MDwGCCsGAQUFBwMCBggrBgEFBQcDAQYIKwYBBQUHAwMGCCsGAQUFBwMEBggrBgEF +BQcDCAYIKwYBBQUHAwkwDQYJKoZIhvcNAQEFBQADggEBAHv25MANqhlHt01Xo/6tu7Fq1Q+e2+Rj +xY6hUFaTlrg4wCQiZrxTFGGVv9DHKpY5P30osxBAIWrEr7BSdxjhlthWXePdNl4dp1BUoMUq5KqM +lIpPnTX/dqQGE5Gion0ARD9V04I8GtVbvFZMIi5GQ4okQC3zErg7cBqklrkar4dBGmoYDQZPxz5u +uSlNDUmJEYcyW+ZLBMjkXOZ0c5RdFpgTlf7727FE5TpwrDdr5rMzcijJs1eg9gIWiAYLtqZLICjU +3j2LrTcFU3T+bsy8QxdxXvnFzBqpYe73dgzzcvRyrc9yAjYHR8/vGVCJYMzpJJUPwssd8m92kMfM +dcGWxZ0= +-----END CERTIFICATE----- + +TURKTRUST Certificate Services Provider Root 2007 +================================================= +-----BEGIN CERTIFICATE----- +MIIEPTCCAyWgAwIBAgIBATANBgkqhkiG9w0BAQUFADCBvzE/MD0GA1UEAww2VMOcUktUUlVTVCBF +bGVrdHJvbmlrIFNlcnRpZmlrYSBIaXptZXQgU2HEn2xhecSxY8Sxc8SxMQswCQYDVQQGEwJUUjEP +MA0GA1UEBwwGQW5rYXJhMV4wXAYDVQQKDFVUw5xSS1RSVVNUIEJpbGdpIMSwbGV0acWfaW0gdmUg +QmlsacWfaW0gR8O8dmVubGnEn2kgSGl6bWV0bGVyaSBBLsWeLiAoYykgQXJhbMSxayAyMDA3MB4X +DTA3MTIyNTE4MzcxOVoXDTE3MTIyMjE4MzcxOVowgb8xPzA9BgNVBAMMNlTDnFJLVFJVU1QgRWxl +a3Ryb25payBTZXJ0aWZpa2EgSGl6bWV0IFNhxJ9sYXnEsWPEsXPEsTELMAkGA1UEBhMCVFIxDzAN +BgNVBAcMBkFua2FyYTFeMFwGA1UECgxVVMOcUktUUlVTVCBCaWxnaSDEsGxldGnFn2ltIHZlIEJp +bGnFn2ltIEfDvHZlbmxpxJ9pIEhpem1ldGxlcmkgQS7Fni4gKGMpIEFyYWzEsWsgMjAwNzCCASIw +DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKu3PgqMyKVYFeaK7yc9SrToJdPNM8Ig3BnuiD9N +YvDdE3ePYakqtdTyuTFYKTsvP2qcb3N2Je40IIDu6rfwxArNK4aUyeNgsURSsloptJGXg9i3phQv +KUmi8wUG+7RP2qFsmmaf8EMJyupyj+sA1zU511YXRxcw9L6/P8JorzZAwan0qafoEGsIiveGHtya +KhUG9qPw9ODHFNRRf8+0222vR5YXm3dx2KdxnSQM9pQ/hTEST7ruToK4uT6PIzdezKKqdfcYbwnT +rqdUKDT74eA7YH2gvnmJhsifLfkKS8RQouf9eRbHegsYz85M733WB2+Y8a+xwXrXgTW4qhe04MsC +AwEAAaNCMEAwHQYDVR0OBBYEFCnFkKslrxHkYb+j/4hhkeYO/pyBMA4GA1UdDwEB/wQEAwIBBjAP +BgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBBQUAA4IBAQAQDdr4Ouwo0RSVgrESLFF6QSU2TJ/s +Px+EnWVUXKgWAkD6bho3hO9ynYYKVZ1WKKxmLNA6VpM0ByWtCLCPyA8JWcqdmBzlVPi5RX9ql2+I +aE1KBiY3iAIOtsbWcpnOa3faYjGkVh+uX4132l32iPwa2Z61gfAyuOOI0JzzaqC5mxRZNTZPz/OO +Xl0XrRWV2N2y1RVuAE6zS89mlOTgzbUF2mNXi+WzqtvALhyQRNsaXRik7r4EW5nVcV9VZWRi1aKb +BFmGyGJ353yCRWo9F7/snXUMrqNvWtMvmDb08PUZqxFdyKbjKlhqQgnDvZImZjINXQhVdP+MmNAK +poRq0Tl9 +-----END CERTIFICATE----- + +D-TRUST Root Class 3 CA 2 2009 +============================== +-----BEGIN CERTIFICATE----- +MIIEMzCCAxugAwIBAgIDCYPzMA0GCSqGSIb3DQEBCwUAME0xCzAJBgNVBAYTAkRFMRUwEwYDVQQK +DAxELVRydXN0IEdtYkgxJzAlBgNVBAMMHkQtVFJVU1QgUm9vdCBDbGFzcyAzIENBIDIgMjAwOTAe +Fw0wOTExMDUwODM1NThaFw0yOTExMDUwODM1NThaME0xCzAJBgNVBAYTAkRFMRUwEwYDVQQKDAxE +LVRydXN0IEdtYkgxJzAlBgNVBAMMHkQtVFJVU1QgUm9vdCBDbGFzcyAzIENBIDIgMjAwOTCCASIw +DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANOySs96R+91myP6Oi/WUEWJNTrGa9v+2wBoqOAD +ER03UAifTUpolDWzU9GUY6cgVq/eUXjsKj3zSEhQPgrfRlWLJ23DEE0NkVJD2IfgXU42tSHKXzlA +BF9bfsyjxiupQB7ZNoTWSPOSHjRGICTBpFGOShrvUD9pXRl/RcPHAY9RySPocq60vFYJfxLLHLGv +KZAKyVXMD9O0Gu1HNVpK7ZxzBCHQqr0ME7UAyiZsxGsMlFqVlNpQmvH/pStmMaTJOKDfHR+4CS7z +p+hnUquVH+BGPtikw8paxTGA6Eian5Rp/hnd2HN8gcqW3o7tszIFZYQ05ub9VxC1X3a/L7AQDcUC +AwEAAaOCARowggEWMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFP3aFMSfMN4hvR5COfyrYyNJ +4PGEMA4GA1UdDwEB/wQEAwIBBjCB0wYDVR0fBIHLMIHIMIGAoH6gfIZ6bGRhcDovL2RpcmVjdG9y +eS5kLXRydXN0Lm5ldC9DTj1ELVRSVVNUJTIwUm9vdCUyMENsYXNzJTIwMyUyMENBJTIwMiUyMDIw +MDksTz1ELVRydXN0JTIwR21iSCxDPURFP2NlcnRpZmljYXRlcmV2b2NhdGlvbmxpc3QwQ6BBoD+G +PWh0dHA6Ly93d3cuZC10cnVzdC5uZXQvY3JsL2QtdHJ1c3Rfcm9vdF9jbGFzc18zX2NhXzJfMjAw +OS5jcmwwDQYJKoZIhvcNAQELBQADggEBAH+X2zDI36ScfSF6gHDOFBJpiBSVYEQBrLLpME+bUMJm +2H6NMLVwMeniacfzcNsgFYbQDfC+rAF1hM5+n02/t2A7nPPKHeJeaNijnZflQGDSNiH+0LS4F9p0 +o3/U37CYAqxva2ssJSRyoWXuJVrl5jLn8t+rSfrzkGkj2wTZ51xY/GXUl77M/C4KzCUqNQT4YJEV +dT1B/yMfGchs64JTBKbkTCJNjYy6zltz7GRUUG3RnFX7acM2w4y8PIWmawomDeCTmGCufsYkl4ph +X5GOZpIJhzbNi5stPvZR1FDUWSi9g/LMKHtThm3YJohw1+qRzT65ysCQblrGXnRl11z+o+I= +-----END CERTIFICATE----- + +D-TRUST Root Class 3 CA 2 EV 2009 +================================= +-----BEGIN CERTIFICATE----- +MIIEQzCCAyugAwIBAgIDCYP0MA0GCSqGSIb3DQEBCwUAMFAxCzAJBgNVBAYTAkRFMRUwEwYDVQQK +DAxELVRydXN0IEdtYkgxKjAoBgNVBAMMIUQtVFJVU1QgUm9vdCBDbGFzcyAzIENBIDIgRVYgMjAw +OTAeFw0wOTExMDUwODUwNDZaFw0yOTExMDUwODUwNDZaMFAxCzAJBgNVBAYTAkRFMRUwEwYDVQQK +DAxELVRydXN0IEdtYkgxKjAoBgNVBAMMIUQtVFJVU1QgUm9vdCBDbGFzcyAzIENBIDIgRVYgMjAw +OTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJnxhDRwui+3MKCOvXwEz75ivJn9gpfS +egpnljgJ9hBOlSJzmY3aFS3nBfwZcyK3jpgAvDw9rKFs+9Z5JUut8Mxk2og+KbgPCdM03TP1YtHh +zRnp7hhPTFiu4h7WDFsVWtg6uMQYZB7jM7K1iXdODL/ZlGsTl28So/6ZqQTMFexgaDbtCHu39b+T +7WYxg4zGcTSHThfqr4uRjRxWQa4iN1438h3Z0S0NL2lRp75mpoo6Kr3HGrHhFPC+Oh25z1uxav60 +sUYgovseO3Dvk5h9jHOW8sXvhXCtKSb8HgQ+HKDYD8tSg2J87otTlZCpV6LqYQXY+U3EJ/pure35 +11H3a6UCAwEAAaOCASQwggEgMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFNOUikxiEyoZLsyv +cop9NteaHNxnMA4GA1UdDwEB/wQEAwIBBjCB3QYDVR0fBIHVMIHSMIGHoIGEoIGBhn9sZGFwOi8v +ZGlyZWN0b3J5LmQtdHJ1c3QubmV0L0NOPUQtVFJVU1QlMjBSb290JTIwQ2xhc3MlMjAzJTIwQ0El +MjAyJTIwRVYlMjAyMDA5LE89RC1UcnVzdCUyMEdtYkgsQz1ERT9jZXJ0aWZpY2F0ZXJldm9jYXRp +b25saXN0MEagRKBChkBodHRwOi8vd3d3LmQtdHJ1c3QubmV0L2NybC9kLXRydXN0X3Jvb3RfY2xh +c3NfM19jYV8yX2V2XzIwMDkuY3JsMA0GCSqGSIb3DQEBCwUAA4IBAQA07XtaPKSUiO8aEXUHL7P+ +PPoeUSbrh/Yp3uDx1MYkCenBz1UbtDDZzhr+BlGmFaQt77JLvyAoJUnRpjZ3NOhk31KxEcdzes05 +nsKtjHEh8lprr988TlWvsoRlFIm5d8sqMb7Po23Pb0iUMkZv53GMoKaEGTcH8gNFCSuGdXzfX2lX +ANtu2KZyIktQ1HWYVt+3GP9DQ1CuekR78HlR10M9p9OB0/DJT7naxpeG0ILD5EJt/rDiZE4OJudA +NCa1CInXCGNjOCd1HjPqbqjdn5lPdE2BiYBL3ZqXKVwvvoFBuYz/6n1gBp7N1z3TLqMVvKjmJuVv +w9y4AyHqnxbxLFS1 +-----END CERTIFICATE----- + +PSCProcert +========== +-----BEGIN CERTIFICATE----- +MIIJhjCCB26gAwIBAgIBCzANBgkqhkiG9w0BAQsFADCCAR4xPjA8BgNVBAMTNUF1dG9yaWRhZCBk +ZSBDZXJ0aWZpY2FjaW9uIFJhaXogZGVsIEVzdGFkbyBWZW5lem9sYW5vMQswCQYDVQQGEwJWRTEQ +MA4GA1UEBxMHQ2FyYWNhczEZMBcGA1UECBMQRGlzdHJpdG8gQ2FwaXRhbDE2MDQGA1UEChMtU2lz +dGVtYSBOYWNpb25hbCBkZSBDZXJ0aWZpY2FjaW9uIEVsZWN0cm9uaWNhMUMwQQYDVQQLEzpTdXBl +cmludGVuZGVuY2lhIGRlIFNlcnZpY2lvcyBkZSBDZXJ0aWZpY2FjaW9uIEVsZWN0cm9uaWNhMSUw +IwYJKoZIhvcNAQkBFhZhY3JhaXpAc3VzY2VydGUuZ29iLnZlMB4XDTEwMTIyODE2NTEwMFoXDTIw +MTIyNTIzNTk1OVowgdExJjAkBgkqhkiG9w0BCQEWF2NvbnRhY3RvQHByb2NlcnQubmV0LnZlMQ8w +DQYDVQQHEwZDaGFjYW8xEDAOBgNVBAgTB01pcmFuZGExKjAoBgNVBAsTIVByb3ZlZWRvciBkZSBD +ZXJ0aWZpY2Fkb3MgUFJPQ0VSVDE2MDQGA1UEChMtU2lzdGVtYSBOYWNpb25hbCBkZSBDZXJ0aWZp +Y2FjaW9uIEVsZWN0cm9uaWNhMQswCQYDVQQGEwJWRTETMBEGA1UEAxMKUFNDUHJvY2VydDCCAiIw +DQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBANW39KOUM6FGqVVhSQ2oh3NekS1wwQYalNo97BVC +wfWMrmoX8Yqt/ICV6oNEolt6Vc5Pp6XVurgfoCfAUFM+jbnADrgV3NZs+J74BCXfgI8Qhd19L3uA +3VcAZCP4bsm+lU/hdezgfl6VzbHvvnpC2Mks0+saGiKLt38GieU89RLAu9MLmV+QfI4tL3czkkoh +RqipCKzx9hEC2ZUWno0vluYC3XXCFCpa1sl9JcLB/KpnheLsvtF8PPqv1W7/U0HU9TI4seJfxPmO +EO8GqQKJ/+MMbpfg353bIdD0PghpbNjU5Db4g7ayNo+c7zo3Fn2/omnXO1ty0K+qP1xmk6wKImG2 +0qCZyFSTXai20b1dCl53lKItwIKOvMoDKjSuc/HUtQy9vmebVOvh+qBa7Dh+PsHMosdEMXXqP+UH +0quhJZb25uSgXTcYOWEAM11G1ADEtMo88aKjPvM6/2kwLkDd9p+cJsmWN63nOaK/6mnbVSKVUyqU +td+tFjiBdWbjxywbk5yqjKPK2Ww8F22c3HxT4CAnQzb5EuE8XL1mv6JpIzi4mWCZDlZTOpx+FIyw +Bm/xhnaQr/2v/pDGj59/i5IjnOcVdo/Vi5QTcmn7K2FjiO/mpF7moxdqWEfLcU8UC17IAggmosvp +r2uKGcfLFFb14dq12fy/czja+eevbqQ34gcnAgMBAAGjggMXMIIDEzASBgNVHRMBAf8ECDAGAQH/ +AgEBMDcGA1UdEgQwMC6CD3N1c2NlcnRlLmdvYi52ZaAbBgVghl4CAqASDBBSSUYtRy0yMDAwNDAz +Ni0wMB0GA1UdDgQWBBRBDxk4qpl/Qguk1yeYVKIXTC1RVDCCAVAGA1UdIwSCAUcwggFDgBStuyId +xuDSAaj9dlBSk+2YwU2u06GCASakggEiMIIBHjE+MDwGA1UEAxM1QXV0b3JpZGFkIGRlIENlcnRp +ZmljYWNpb24gUmFpeiBkZWwgRXN0YWRvIFZlbmV6b2xhbm8xCzAJBgNVBAYTAlZFMRAwDgYDVQQH +EwdDYXJhY2FzMRkwFwYDVQQIExBEaXN0cml0byBDYXBpdGFsMTYwNAYDVQQKEy1TaXN0ZW1hIE5h +Y2lvbmFsIGRlIENlcnRpZmljYWNpb24gRWxlY3Ryb25pY2ExQzBBBgNVBAsTOlN1cGVyaW50ZW5k +ZW5jaWEgZGUgU2VydmljaW9zIGRlIENlcnRpZmljYWNpb24gRWxlY3Ryb25pY2ExJTAjBgkqhkiG +9w0BCQEWFmFjcmFpekBzdXNjZXJ0ZS5nb2IudmWCAQowDgYDVR0PAQH/BAQDAgEGME0GA1UdEQRG +MESCDnByb2NlcnQubmV0LnZloBUGBWCGXgIBoAwMClBTQy0wMDAwMDKgGwYFYIZeAgKgEgwQUklG +LUotMzE2MzUzNzMtNzB2BgNVHR8EbzBtMEagRKBChkBodHRwOi8vd3d3LnN1c2NlcnRlLmdvYi52 +ZS9sY3IvQ0VSVElGSUNBRE8tUkFJWi1TSEEzODRDUkxERVIuY3JsMCOgIaAfhh1sZGFwOi8vYWNy +YWl6LnN1c2NlcnRlLmdvYi52ZTA3BggrBgEFBQcBAQQrMCkwJwYIKwYBBQUHMAGGG2h0dHA6Ly9v +Y3NwLnN1c2NlcnRlLmdvYi52ZTBBBgNVHSAEOjA4MDYGBmCGXgMBAjAsMCoGCCsGAQUFBwIBFh5o +dHRwOi8vd3d3LnN1c2NlcnRlLmdvYi52ZS9kcGMwDQYJKoZIhvcNAQELBQADggIBACtZ6yKZu4Sq +T96QxtGGcSOeSwORR3C7wJJg7ODU523G0+1ng3dS1fLld6c2suNUvtm7CpsR72H0xpkzmfWvADmN +g7+mvTV+LFwxNG9s2/NkAZiqlCxB3RWGymspThbASfzXg0gTB1GEMVKIu4YXx2sviiCtxQuPcD4q +uxtxj7mkoP3YldmvWb8lK5jpY5MvYB7Eqvh39YtsL+1+LrVPQA3uvFd359m21D+VJzog1eWuq2w1 +n8GhHVnchIHuTQfiSLaeS5UtQbHh6N5+LwUeaO6/u5BlOsju6rEYNxxik6SgMexxbJHmpHmJWhSn +FFAFTKQAVzAswbVhltw+HoSvOULP5dAssSS830DD7X9jSr3hTxJkhpXzsOfIt+FTvZLm8wyWuevo +5pLtp4EJFAv8lXrPj9Y0TzYS3F7RNHXGRoAvlQSMx4bEqCaJqD8Zm4G7UaRKhqsLEQ+xrmNTbSjq +3TNWOByyrYDT13K9mmyZY+gAu0F2BbdbmRiKw7gSXFbPVgx96OLP7bx0R/vu0xdOIk9W/1DzLuY5 +poLWccret9W6aAjtmcz9opLLabid+Qqkpj5PkygqYWwHJgD/ll9ohri4zspV4KuxPX+Y1zMOWj3Y +eMLEYC/HYvBhkdI4sPaeVdtAgAUSM84dkpvRabP/v/GSCmE1P93+hvS84Bpxs2Km +-----END CERTIFICATE----- + +China Internet Network Information Center EV Certificates Root +============================================================== +-----BEGIN CERTIFICATE----- +MIID9zCCAt+gAwIBAgIESJ8AATANBgkqhkiG9w0BAQUFADCBijELMAkGA1UEBhMCQ04xMjAwBgNV +BAoMKUNoaW5hIEludGVybmV0IE5ldHdvcmsgSW5mb3JtYXRpb24gQ2VudGVyMUcwRQYDVQQDDD5D +aGluYSBJbnRlcm5ldCBOZXR3b3JrIEluZm9ybWF0aW9uIENlbnRlciBFViBDZXJ0aWZpY2F0ZXMg +Um9vdDAeFw0xMDA4MzEwNzExMjVaFw0zMDA4MzEwNzExMjVaMIGKMQswCQYDVQQGEwJDTjEyMDAG +A1UECgwpQ2hpbmEgSW50ZXJuZXQgTmV0d29yayBJbmZvcm1hdGlvbiBDZW50ZXIxRzBFBgNVBAMM +PkNoaW5hIEludGVybmV0IE5ldHdvcmsgSW5mb3JtYXRpb24gQ2VudGVyIEVWIENlcnRpZmljYXRl +cyBSb290MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAm35z7r07eKpkQ0H1UN+U8i6y +jUqORlTSIRLIOTJCBumD1Z9S7eVnAztUwYyZmczpwA//DdmEEbK40ctb3B75aDFk4Zv6dOtouSCV +98YPjUesWgbdYavi7NifFy2cyjw1l1VxzUOFsUcW9SxTgHbP0wBkvUCZ3czY28Sf1hNfQYOL+Q2H +klY0bBoQCxfVWhyXWIQ8hBouXJE0bhlffxdpxWXvayHG1VA6v2G5BY3vbzQ6sm8UY78WO5upKv23 +KzhmBsUs4qpnHkWnjQRmQvaPK++IIGmPMowUc9orhpFjIpryp9vOiYurXccUwVswah+xt54ugQEC +7c+WXmPbqOY4twIDAQABo2MwYTAfBgNVHSMEGDAWgBR8cks5x8DbYqVPm6oYNJKiyoOCWTAPBgNV +HRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUfHJLOcfA22KlT5uqGDSSosqD +glkwDQYJKoZIhvcNAQEFBQADggEBACrDx0M3j92tpLIM7twUbY8opJhJywyA6vPtI2Z1fcXTIWd5 +0XPFtQO3WKwMVC/GVhMPMdoG52U7HW8228gd+f2ABsqjPWYWqJ1MFn3AlUa1UeTiH9fqBk1jjZaM +7+czV0I664zBechNdn3e9rG3geCg+aF4RhcaVpjwTj2rHO3sOdwHSPdj/gauwqRcalsyiMXHM4Ws +ZkJHwlgkmeHlPuV1LI5D1l08eB6olYIpUNHRFrrvwb562bTYzB5MRuF3sTGrvSrIzo9uoV1/A3U0 +5K2JRVRevq4opbs/eHnrc7MKDf2+yfdWrPa37S+bISnHOLaVxATywy39FCqQmbkHzJ8= +-----END CERTIFICATE----- + +Swisscom Root CA 2 +================== +-----BEGIN CERTIFICATE----- +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 +5OfNeOI5wSsSnqaeG8XmDtkx2Q== +-----END CERTIFICATE----- + +Swisscom Root EV CA 2 +===================== +-----BEGIN CERTIFICATE----- +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 +l8PVP3wbI+2ksx0WckNLIOFZfsLorSa/ovc= +-----END CERTIFICATE----- + +CA Disig Root R1 +================ +-----BEGIN CERTIFICATE----- +MIIFaTCCA1GgAwIBAgIJAMMDmu5QkG4oMA0GCSqGSIb3DQEBBQUAMFIxCzAJBgNVBAYTAlNLMRMw +EQYDVQQHEwpCcmF0aXNsYXZhMRMwEQYDVQQKEwpEaXNpZyBhLnMuMRkwFwYDVQQDExBDQSBEaXNp +ZyBSb290IFIxMB4XDTEyMDcxOTA5MDY1NloXDTQyMDcxOTA5MDY1NlowUjELMAkGA1UEBhMCU0sx +EzARBgNVBAcTCkJyYXRpc2xhdmExEzARBgNVBAoTCkRpc2lnIGEucy4xGTAXBgNVBAMTEENBIERp +c2lnIFJvb3QgUjEwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCqw3j33Jijp1pedxiy +3QRkD2P9m5YJgNXoqqXinCaUOuiZc4yd39ffg/N4T0Dhf9Kn0uXKE5Pn7cZ3Xza1lK/oOI7bm+V8 +u8yN63Vz4STN5qctGS7Y1oprFOsIYgrY3LMATcMjfF9DCCMyEtztDK3AfQ+lekLZWnDZv6fXARz2 +m6uOt0qGeKAeVjGu74IKgEH3G8muqzIm1Cxr7X1r5OJeIgpFy4QxTaz+29FHuvlglzmxZcfe+5nk +CiKxLU3lSCZpq+Kq8/v8kiky6bM+TR8noc2OuRf7JT7JbvN32g0S9l3HuzYQ1VTW8+DiR0jm3hTa +YVKvJrT1cU/J19IG32PK/yHoWQbgCNWEFVP3Q+V8xaCJmGtzxmjOZd69fwX3se72V6FglcXM6pM6 +vpmumwKjrckWtc7dXpl4fho5frLABaTAgqWjR56M6ly2vGfb5ipN0gTco65F97yLnByn1tUD3AjL +LhbKXEAz6GfDLuemROoRRRw1ZS0eRWEkG4IupZ0zXWX4Qfkuy5Q/H6MMMSRE7cderVC6xkGbrPAX +ZcD4XW9boAo0PO7X6oifmPmvTiT6l7Jkdtqr9O3jw2Dv1fkCyC2fg69naQanMVXVz0tv/wQFx1is +XxYb5dKj6zHbHzMVTdDypVP1y+E9Tmgt2BLdqvLmTZtJ5cUoobqwWsagtQIDAQABo0IwQDAPBgNV +HRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUiQq0OJMa5qvum5EY+fU8PjXQ +04IwDQYJKoZIhvcNAQEFBQADggIBADKL9p1Kyb4U5YysOMo6CdQbzoaz3evUuii+Eq5FLAR0rBNR +xVgYZk2C2tXck8An4b58n1KeElb21Zyp9HWc+jcSjxyT7Ff+Bw+r1RL3D65hXlaASfX8MPWbTx9B +LxyE04nH4toCdu0Jz2zBuByDHBb6lM19oMgY0sidbvW9adRtPTXoHqJPYNcHKfyyo6SdbhWSVhlM +CrDpfNIZTUJG7L399ldb3Zh+pE3McgODWF3vkzpBemOqfDqo9ayk0d2iLbYq/J8BjuIQscTK5Gfb +VSUZP/3oNn6z4eGBrxEWi1CXYBmCAMBrTXO40RMHPuq2MU/wQppt4hF05ZSsjYSVPCGvxdpHyN85 +YmLLW1AL14FABZyb7bq2ix4Eb5YgOe2kfSnbSM6C3NQCjR0EMVrHS/BsYVLXtFHCgWzN4funodKS +ds+xDzdYpPJScWc/DIh4gInByLUfkmO+p3qKViwaqKactV2zY9ATIKHrkWzQjX2v3wvkF7mGnjix +lAxYjOBVqjtjbZqJYLhkKpLGN/R+Q0O3c+gB53+XD9fyexn9GtePyfqFa3qdnom2piiZk4hA9z7N +UaPK6u95RyG1/jLix8NRb76AdPCkwzryT+lf3xkK8jsTQ6wxpLPn6/wY1gGp8yqPNg7rtLG8t0zJ +a7+h89n07eLw4+1knj0vllJPgFOL +-----END CERTIFICATE----- + +CA Disig Root R2 +================ +-----BEGIN CERTIFICATE----- +MIIFaTCCA1GgAwIBAgIJAJK4iNuwisFjMA0GCSqGSIb3DQEBCwUAMFIxCzAJBgNVBAYTAlNLMRMw +EQYDVQQHEwpCcmF0aXNsYXZhMRMwEQYDVQQKEwpEaXNpZyBhLnMuMRkwFwYDVQQDExBDQSBEaXNp +ZyBSb290IFIyMB4XDTEyMDcxOTA5MTUzMFoXDTQyMDcxOTA5MTUzMFowUjELMAkGA1UEBhMCU0sx +EzARBgNVBAcTCkJyYXRpc2xhdmExEzARBgNVBAoTCkRpc2lnIGEucy4xGTAXBgNVBAMTEENBIERp +c2lnIFJvb3QgUjIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCio8QACdaFXS1tFPbC +w3OeNcJxVX6B+6tGUODBfEl45qt5WDza/3wcn9iXAng+a0EE6UG9vgMsRfYvZNSrXaNHPWSb6Wia +xswbP7q+sos0Ai6YVRn8jG+qX9pMzk0DIaPY0jSTVpbLTAwAFjxfGs3Ix2ymrdMxp7zo5eFm1tL7 +A7RBZckQrg4FY8aAamkw/dLukO8NJ9+flXP04SXabBbeQTg06ov80egEFGEtQX6sx3dOy1FU+16S +GBsEWmjGycT6txOgmLcRK7fWV8x8nhfRyyX+hk4kLlYMeE2eARKmK6cBZW58Yh2EhN/qwGu1pSqV +g8NTEQxzHQuyRpDRQjrOQG6Vrf/GlK1ul4SOfW+eioANSW1z4nuSHsPzwfPrLgVv2RvPN3YEyLRa +5Beny912H9AZdugsBbPWnDTYltxhh5EF5EQIM8HauQhl1K6yNg3ruji6DOWbnuuNZt2Zz9aJQfYE +koopKW1rOhzndX0CcQ7zwOe9yxndnWCywmZgtrEE7snmhrmaZkCo5xHtgUUDi/ZnWejBBhG93c+A +Ak9lQHhcR1DIm+YfgXvkRKhbhZri3lrVx/k6RGZL5DJUfORsnLMOPReisjQS1n6yqEm70XooQL6i +Fh/f5DcfEXP7kAplQ6INfPgGAVUzfbANuPT1rqVCV3w2EYx7XsQDnYx5nQIDAQABo0IwQDAPBgNV +HRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUtZn4r7CU9eMg1gqtzk5WpC5u +Qu0wDQYJKoZIhvcNAQELBQADggIBACYGXnDnZTPIgm7ZnBc6G3pmsgH2eDtpXi/q/075KMOYKmFM +tCQSin1tERT3nLXK5ryeJ45MGcipvXrA1zYObYVybqjGom32+nNjf7xueQgcnYqfGopTpti72TVV +sRHFqQOzVju5hJMiXn7B9hJSi+osZ7z+Nkz1uM/Rs0mSO9MpDpkblvdhuDvEK7Z4bLQjb/D907Je +dR+Zlais9trhxTF7+9FGs9K8Z7RiVLoJ92Owk6Ka+elSLotgEqv89WBW7xBci8QaQtyDW2QOy7W8 +1k/BfDxujRNt+3vrMNDcTa/F1balTFtxyegxvug4BkihGuLq0t4SOVga/4AOgnXmt8kHbA7v/zjx +mHHEt38OFdAlab0inSvtBfZGR6ztwPDUO+Ls7pZbkBNOHlY667DvlruWIxG68kOGdGSVyCh13x01 +utI3gzhTODY7z2zp+WsO0PsE6E9312UBeIYMej4hYvF/Y3EMyZ9E26gnonW+boE+18DrG5gPcFw0 +sorMwIUY6256s/daoQe/qUKS82Ail+QUoQebTnbAjn39pCXHR+3/H3OszMOl6W8KjptlwlCFtaOg +UxLMVYdh84GuEEZhvUQhuMI9dM9+JDX6HAcOmz0iyu8xL4ysEr3vQCj8KWefshNPZiTEUxnpHikV +7+ZtsH8tZ/3zbBt1RqPlShfppNcL +-----END CERTIFICATE----- + +ACCVRAIZ1 +========= +-----BEGIN CERTIFICATE----- +MIIH0zCCBbugAwIBAgIIXsO3pkN/pOAwDQYJKoZIhvcNAQEFBQAwQjESMBAGA1UEAwwJQUNDVlJB +SVoxMRAwDgYDVQQLDAdQS0lBQ0NWMQ0wCwYDVQQKDARBQ0NWMQswCQYDVQQGEwJFUzAeFw0xMTA1 +MDUwOTM3MzdaFw0zMDEyMzEwOTM3MzdaMEIxEjAQBgNVBAMMCUFDQ1ZSQUlaMTEQMA4GA1UECwwH +UEtJQUNDVjENMAsGA1UECgwEQUNDVjELMAkGA1UEBhMCRVMwggIiMA0GCSqGSIb3DQEBAQUAA4IC +DwAwggIKAoICAQCbqau/YUqXry+XZpp0X9DZlv3P4uRm7x8fRzPCRKPfmt4ftVTdFXxpNRFvu8gM +jmoYHtiP2Ra8EEg2XPBjs5BaXCQ316PWywlxufEBcoSwfdtNgM3802/J+Nq2DoLSRYWoG2ioPej0 +RGy9ocLLA76MPhMAhN9KSMDjIgro6TenGEyxCQ0jVn8ETdkXhBilyNpAlHPrzg5XPAOBOp0KoVdD +aaxXbXmQeOW1tDvYvEyNKKGno6e6Ak4l0Squ7a4DIrhrIA8wKFSVf+DuzgpmndFALW4ir50awQUZ +0m/A8p/4e7MCQvtQqR0tkw8jq8bBD5L/0KIV9VMJcRz/RROE5iZe+OCIHAr8Fraocwa48GOEAqDG +WuzndN9wrqODJerWx5eHk6fGioozl2A3ED6XPm4pFdahD9GILBKfb6qkxkLrQaLjlUPTAYVtjrs7 +8yM2x/474KElB0iryYl0/wiPgL/AlmXz7uxLaL2diMMxs0Dx6M/2OLuc5NF/1OVYm3z61PMOm3WR +5LpSLhl+0fXNWhn8ugb2+1KoS5kE3fj5tItQo05iifCHJPqDQsGH+tUtKSpacXpkatcnYGMN285J +9Y0fkIkyF/hzQ7jSWpOGYdbhdQrqeWZ2iE9x6wQl1gpaepPluUsXQA+xtrn13k/c4LOsOxFwYIRK +Q26ZIMApcQrAZQIDAQABo4ICyzCCAscwfQYIKwYBBQUHAQEEcTBvMEwGCCsGAQUFBzAChkBodHRw +Oi8vd3d3LmFjY3YuZXMvZmlsZWFkbWluL0FyY2hpdm9zL2NlcnRpZmljYWRvcy9yYWl6YWNjdjEu +Y3J0MB8GCCsGAQUFBzABhhNodHRwOi8vb2NzcC5hY2N2LmVzMB0GA1UdDgQWBBTSh7Tj3zcnk1X2 +VuqB5TbMjB4/vTAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFNKHtOPfNyeTVfZW6oHlNsyM +Hj+9MIIBcwYDVR0gBIIBajCCAWYwggFiBgRVHSAAMIIBWDCCASIGCCsGAQUFBwICMIIBFB6CARAA +QQB1AHQAbwByAGkAZABhAGQAIABkAGUAIABDAGUAcgB0AGkAZgBpAGMAYQBjAGkA8wBuACAAUgBh +AO0AegAgAGQAZQAgAGwAYQAgAEEAQwBDAFYAIAAoAEEAZwBlAG4AYwBpAGEAIABkAGUAIABUAGUA +YwBuAG8AbABvAGcA7QBhACAAeQAgAEMAZQByAHQAaQBmAGkAYwBhAGMAaQDzAG4AIABFAGwAZQBj +AHQAcgDzAG4AaQBjAGEALAAgAEMASQBGACAAUQA0ADYAMAAxADEANQA2AEUAKQAuACAAQwBQAFMA +IABlAG4AIABoAHQAdABwADoALwAvAHcAdwB3AC4AYQBjAGMAdgAuAGUAczAwBggrBgEFBQcCARYk +aHR0cDovL3d3dy5hY2N2LmVzL2xlZ2lzbGFjaW9uX2MuaHRtMFUGA1UdHwROMEwwSqBIoEaGRGh0 +dHA6Ly93d3cuYWNjdi5lcy9maWxlYWRtaW4vQXJjaGl2b3MvY2VydGlmaWNhZG9zL3JhaXphY2N2 +MV9kZXIuY3JsMA4GA1UdDwEB/wQEAwIBBjAXBgNVHREEEDAOgQxhY2N2QGFjY3YuZXMwDQYJKoZI +hvcNAQEFBQADggIBAJcxAp/n/UNnSEQU5CmH7UwoZtCPNdpNYbdKl02125DgBS4OxnnQ8pdpD70E +R9m+27Up2pvZrqmZ1dM8MJP1jaGo/AaNRPTKFpV8M9xii6g3+CfYCS0b78gUJyCpZET/LtZ1qmxN +YEAZSUNUY9rizLpm5U9EelvZaoErQNV/+QEnWCzI7UiRfD+mAM/EKXMRNt6GGT6d7hmKG9Ww7Y49 +nCrADdg9ZuM8Db3VlFzi4qc1GwQA9j9ajepDvV+JHanBsMyZ4k0ACtrJJ1vnE5Bc5PUzolVt3OAJ +TS+xJlsndQAJxGJ3KQhfnlmstn6tn1QwIgPBHnFk/vk4CpYY3QIUrCPLBhwepH2NDd4nQeit2hW3 +sCPdK6jT2iWH7ehVRE2I9DZ+hJp4rPcOVkkO1jMl1oRQQmwgEh0q1b688nCBpHBgvgW1m54ERL5h +I6zppSSMEYCUWqKiuUnSwdzRp+0xESyeGabu4VXhwOrPDYTkF7eifKXeVSUG7szAh1xA2syVP1Xg +Nce4hL60Xc16gwFy7ofmXx2utYXGJt/mwZrpHgJHnyqobalbz+xFd3+YJ5oyXSrjhO7FmGYvliAd +3djDJ9ew+f7Zfc3Qn48LFFhRny+Lwzgt3uiP1o2HpPVWQxaZLPSkVrQ0uGE3ycJYgBugl6H8WY3p +EfbRD0tVNEYqi4Y7 +-----END CERTIFICATE----- + +TWCA Global Root CA +=================== +-----BEGIN CERTIFICATE----- +MIIFQTCCAymgAwIBAgICDL4wDQYJKoZIhvcNAQELBQAwUTELMAkGA1UEBhMCVFcxEjAQBgNVBAoT +CVRBSVdBTi1DQTEQMA4GA1UECxMHUm9vdCBDQTEcMBoGA1UEAxMTVFdDQSBHbG9iYWwgUm9vdCBD +QTAeFw0xMjA2MjcwNjI4MzNaFw0zMDEyMzExNTU5NTlaMFExCzAJBgNVBAYTAlRXMRIwEAYDVQQK +EwlUQUlXQU4tQ0ExEDAOBgNVBAsTB1Jvb3QgQ0ExHDAaBgNVBAMTE1RXQ0EgR2xvYmFsIFJvb3Qg +Q0EwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCwBdvI64zEbooh745NnHEKH1Jw7W2C +nJfF10xORUnLQEK1EjRsGcJ0pDFfhQKX7EMzClPSnIyOt7h52yvVavKOZsTuKwEHktSz0ALfUPZV +r2YOy+BHYC8rMjk1Ujoog/h7FsYYuGLWRyWRzvAZEk2tY/XTP3VfKfChMBwqoJimFb3u/Rk28OKR +Q4/6ytYQJ0lM793B8YVwm8rqqFpD/G2Gb3PpN0Wp8DbHzIh1HrtsBv+baz4X7GGqcXzGHaL3SekV +tTzWoWH1EfcFbx39Eb7QMAfCKbAJTibc46KokWofwpFFiFzlmLhxpRUZyXx1EcxwdE8tmx2RRP1W +KKD+u4ZqyPpcC1jcxkt2yKsi2XMPpfRaAok/T54igu6idFMqPVMnaR1sjjIsZAAmY2E2TqNGtz99 +sy2sbZCilaLOz9qC5wc0GZbpuCGqKX6mOL6OKUohZnkfs8O1CWfe1tQHRvMq2uYiN2DLgbYPoA/p +yJV/v1WRBXrPPRXAb94JlAGD1zQbzECl8LibZ9WYkTunhHiVJqRaCPgrdLQABDzfuBSO6N+pjWxn +kjMdwLfS7JLIvgm/LCkFbwJrnu+8vyq8W8BQj0FwcYeyTbcEqYSjMq+u7msXi7Kx/mzhkIyIqJdI +zshNy/MGz19qCkKxHh53L46g5pIOBvwFItIm4TFRfTLcDwIDAQABoyMwITAOBgNVHQ8BAf8EBAMC +AQYwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAgEAXzSBdu+WHdXltdkCY4QWwa6g +cFGn90xHNcgL1yg9iXHZqjNB6hQbbCEAwGxCGX6faVsgQt+i0trEfJdLjbDorMjupWkEmQqSpqsn +LhpNgb+E1HAerUf+/UqdM+DyucRFCCEK2mlpc3INvjT+lIutwx4116KD7+U4x6WFH6vPNOw/KP4M +8VeGTslV9xzU2KV9Bnpv1d8Q34FOIWWxtuEXeZVFBs5fzNxGiWNoRI2T9GRwoD2dKAXDOXC4Ynsg +/eTb6QihuJ49CcdP+yz4k3ZB3lLg4VfSnQO8d57+nile98FRYB/e2guyLXW3Q0iT5/Z5xoRdgFlg +lPx4mI88k1HtQJAH32RjJMtOcQWh15QaiDLxInQirqWm2BJpTGCjAu4r7NRjkgtevi92a6O2JryP +A9gK8kxkRr05YuWW6zRjESjMlfGt7+/cgFhI6Uu46mWs6fyAtbXIRfmswZ/ZuepiiI7E8UuDEq3m +i4TWnsLrgxifarsbJGAzcMzs9zLzXNl5fe+epP7JI8Mk7hWSsT2RTyaGvWZzJBPqpK5jwa19hAM8 +EHiGG3njxPPyBJUgriOCxLM6AGK/5jYk4Ve6xx6QddVfP5VhK8E7zeWzaGHQRiapIVJpLesux+t3 +zqY6tQMzT3bR51xUAV3LePTJDL/PEo4XLSNolOer/qmyKwbQBM0= +-----END CERTIFICATE----- + +TeliaSonera Root CA v1 +====================== +-----BEGIN CERTIFICATE----- +MIIFODCCAyCgAwIBAgIRAJW+FqD3LkbxezmCcvqLzZYwDQYJKoZIhvcNAQEFBQAwNzEUMBIGA1UE +CgwLVGVsaWFTb25lcmExHzAdBgNVBAMMFlRlbGlhU29uZXJhIFJvb3QgQ0EgdjEwHhcNMDcxMDE4 +MTIwMDUwWhcNMzIxMDE4MTIwMDUwWjA3MRQwEgYDVQQKDAtUZWxpYVNvbmVyYTEfMB0GA1UEAwwW +VGVsaWFTb25lcmEgUm9vdCBDQSB2MTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMK+ +6yfwIaPzaSZVfp3FVRaRXP3vIb9TgHot0pGMYzHw7CTww6XScnwQbfQ3t+XmfHnqjLWCi65ItqwA +3GV17CpNX8GH9SBlK4GoRz6JI5UwFpB/6FcHSOcZrr9FZ7E3GwYq/t75rH2D+1665I+XZ75Ljo1k +B1c4VWk0Nj0TSO9P4tNmHqTPGrdeNjPUtAa9GAH9d4RQAEX1jF3oI7x+/jXh7VB7qTCNGdMJjmhn +Xb88lxhTuylixcpecsHHltTbLaC0H2kD7OriUPEMPPCs81Mt8Bz17Ww5OXOAFshSsCPN4D7c3TxH +oLs1iuKYaIu+5b9y7tL6pe0S7fyYGKkmdtwoSxAgHNN/Fnct7W+A90m7UwW7XWjH1Mh1Fj+JWov3 +F0fUTPHSiXk+TT2YqGHeOh7S+F4D4MHJHIzTjU3TlTazN19jY5szFPAtJmtTfImMMsJu7D0hADnJ +oWjiUIMusDor8zagrC/kb2HCUQk5PotTubtn2txTuXZZNp1D5SDgPTJghSJRt8czu90VL6R4pgd7 +gUY2BIbdeTXHlSw7sKMXNeVzH7RcWe/a6hBle3rQf5+ztCo3O3CLm1u5K7fsslESl1MpWtTwEhDc +TwK7EpIvYtQ/aUN8Ddb8WHUBiJ1YFkveupD/RwGJBmr2X7KQarMCpgKIv7NHfirZ1fpoeDVNAgMB +AAGjPzA9MA8GA1UdEwEB/wQFMAMBAf8wCwYDVR0PBAQDAgEGMB0GA1UdDgQWBBTwj1k4ALP1j5qW +DNXr+nuqF+gTEjANBgkqhkiG9w0BAQUFAAOCAgEAvuRcYk4k9AwI//DTDGjkk0kiP0Qnb7tt3oNm +zqjMDfz1mgbldxSR651Be5kqhOX//CHBXfDkH1e3damhXwIm/9fH907eT/j3HEbAek9ALCI18Bmx +0GtnLLCo4MBANzX2hFxc469CeP6nyQ1Q6g2EdvZR74NTxnr/DlZJLo961gzmJ1TjTQpgcmLNkQfW +pb/ImWvtxBnmq0wROMVvMeJuScg/doAmAyYp4Db29iBT4xdwNBedY2gea+zDTYa4EzAvXUYNR0PV +G6pZDrlcjQZIrXSHX8f8MVRBE+LHIQ6e4B4N4cB7Q4WQxYpYxmUKeFfyxiMPAdkgS94P+5KFdSpc +c41teyWRyu5FrgZLAMzTsVlQ2jqIOylDRl6XK1TOU2+NSueW+r9xDkKLfP0ooNBIytrEgUy7onOT +JsjrDNYmiLbAJM+7vVvrdX3pCI6GMyx5dwlppYn8s3CQh3aP0yK7Qs69cwsgJirQmz1wHiRszYd2 +qReWt88NkvuOGKmYSdGe/mBEciG5Ge3C9THxOUiIkCR1VBatzvT4aRRkOfujuLpwQMcnHL/EVlP6 +Y2XQ8xwOFvVrhlhNGNTkDY6lnVuR3HYkUD/GKvvZt5y11ubQ2egZixVxSK236thZiNSQvxaz2ems +WWFUyBy6ysHK4bkgTI86k4mloMy/0/Z1pHWWbVY= +-----END CERTIFICATE----- + +E-Tugra Certification Authority +=============================== +-----BEGIN CERTIFICATE----- +MIIGSzCCBDOgAwIBAgIIamg+nFGby1MwDQYJKoZIhvcNAQELBQAwgbIxCzAJBgNVBAYTAlRSMQ8w +DQYDVQQHDAZBbmthcmExQDA+BgNVBAoMN0UtVHXEn3JhIEVCRyBCaWxpxZ9pbSBUZWtub2xvamls +ZXJpIHZlIEhpem1ldGxlcmkgQS7Fni4xJjAkBgNVBAsMHUUtVHVncmEgU2VydGlmaWthc3lvbiBN +ZXJrZXppMSgwJgYDVQQDDB9FLVR1Z3JhIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTEzMDMw +NTEyMDk0OFoXDTIzMDMwMzEyMDk0OFowgbIxCzAJBgNVBAYTAlRSMQ8wDQYDVQQHDAZBbmthcmEx +QDA+BgNVBAoMN0UtVHXEn3JhIEVCRyBCaWxpxZ9pbSBUZWtub2xvamlsZXJpIHZlIEhpem1ldGxl +cmkgQS7Fni4xJjAkBgNVBAsMHUUtVHVncmEgU2VydGlmaWthc3lvbiBNZXJrZXppMSgwJgYDVQQD +DB9FLVR1Z3JhIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIICIjANBgkqhkiG9w0BAQEFAAOCAg8A +MIICCgKCAgEA4vU/kwVRHoViVF56C/UYB4Oufq9899SKa6VjQzm5S/fDxmSJPZQuVIBSOTkHS0vd +hQd2h8y/L5VMzH2nPbxHD5hw+IyFHnSOkm0bQNGZDbt1bsipa5rAhDGvykPL6ys06I+XawGb1Q5K +CKpbknSFQ9OArqGIW66z6l7LFpp3RMih9lRozt6Plyu6W0ACDGQXwLWTzeHxE2bODHnv0ZEoq1+g +ElIwcxmOj+GMB6LDu0rw6h8VqO4lzKRG+Bsi77MOQ7osJLjFLFzUHPhdZL3Dk14opz8n8Y4e0ypQ +BaNV2cvnOVPAmJ6MVGKLJrD3fY185MaeZkJVgkfnsliNZvcHfC425lAcP9tDJMW/hkd5s3kc91r0 +E+xs+D/iWR+V7kI+ua2oMoVJl0b+SzGPWsutdEcf6ZG33ygEIqDUD13ieU/qbIWGvaimzuT6w+Gz +rt48Ue7LE3wBf4QOXVGUnhMMti6lTPk5cDZvlsouDERVxcr6XQKj39ZkjFqzAQqptQpHF//vkUAq +jqFGOjGY5RH8zLtJVor8udBhmm9lbObDyz51Sf6Pp+KJxWfXnUYTTjF2OySznhFlhqt/7x3U+Lzn +rFpct1pHXFXOVbQicVtbC/DP3KBhZOqp12gKY6fgDT+gr9Oq0n7vUaDmUStVkhUXU8u3Zg5mTPj5 +dUyQ5xJwx0UCAwEAAaNjMGEwHQYDVR0OBBYEFC7j27JJ0JxUeVz6Jyr+zE7S6E5UMA8GA1UdEwEB +/wQFMAMBAf8wHwYDVR0jBBgwFoAULuPbsknQnFR5XPonKv7MTtLoTlQwDgYDVR0PAQH/BAQDAgEG +MA0GCSqGSIb3DQEBCwUAA4ICAQAFNzr0TbdF4kV1JI+2d1LoHNgQk2Xz8lkGpD4eKexd0dCrfOAK +kEh47U6YA5n+KGCRHTAduGN8qOY1tfrTYXbm1gdLymmasoR6d5NFFxWfJNCYExL/u6Au/U5Mh/jO +XKqYGwXgAEZKgoClM4so3O0409/lPun++1ndYYRP0lSWE2ETPo+Aab6TR7U1Q9Jauz1c77NCR807 +VRMGsAnb/WP2OogKmW9+4c4bU2pEZiNRCHu8W1Ki/QY3OEBhj0qWuJA3+GbHeJAAFS6LrVE1Uweo +a2iu+U48BybNCAVwzDk/dr2l02cmAYamU9JgO3xDf1WKvJUawSg5TB9D0pH0clmKuVb8P7Sd2nCc +dlqMQ1DujjByTd//SffGqWfZbawCEeI6FiWnWAjLb1NBnEg4R2gz0dfHj9R0IdTDBZB6/86WiLEV +KV0jq9BgoRJP3vQXzTLlyb/IQ639Lo7xr+L0mPoSHyDYwKcMhcWQ9DstliaxLL5Mq+ux0orJ23gT +Dx4JnW2PAJ8C2sH6H3p6CcRK5ogql5+Ji/03X186zjhZhkuvcQu02PJwT58yE+Owp1fl2tpDy4Q0 +8ijE6m30Ku/Ba3ba+367hTzSU8JNvnHhRdH9I2cNE3X7z2VnIp2usAnRCf8dNL/+I5c30jn6PQ0G +C7TbO6Orb1wdtn7os4I07QZcJA== +-----END CERTIFICATE----- + +T-TeleSec GlobalRoot Class 2 +============================ +-----BEGIN CERTIFICATE----- +MIIDwzCCAqugAwIBAgIBATANBgkqhkiG9w0BAQsFADCBgjELMAkGA1UEBhMCREUxKzApBgNVBAoM +IlQtU3lzdGVtcyBFbnRlcnByaXNlIFNlcnZpY2VzIEdtYkgxHzAdBgNVBAsMFlQtU3lzdGVtcyBU +cnVzdCBDZW50ZXIxJTAjBgNVBAMMHFQtVGVsZVNlYyBHbG9iYWxSb290IENsYXNzIDIwHhcNMDgx +MDAxMTA0MDE0WhcNMzMxMDAxMjM1OTU5WjCBgjELMAkGA1UEBhMCREUxKzApBgNVBAoMIlQtU3lz +dGVtcyBFbnRlcnByaXNlIFNlcnZpY2VzIEdtYkgxHzAdBgNVBAsMFlQtU3lzdGVtcyBUcnVzdCBD +ZW50ZXIxJTAjBgNVBAMMHFQtVGVsZVNlYyBHbG9iYWxSb290IENsYXNzIDIwggEiMA0GCSqGSIb3 +DQEBAQUAA4IBDwAwggEKAoIBAQCqX9obX+hzkeXaXPSi5kfl82hVYAUdAqSzm1nzHoqvNK38DcLZ +SBnuaY/JIPwhqgcZ7bBcrGXHX+0CfHt8LRvWurmAwhiCFoT6ZrAIxlQjgeTNuUk/9k9uN0goOA/F +vudocP05l03Sx5iRUKrERLMjfTlH6VJi1hKTXrcxlkIF+3anHqP1wvzpesVsqXFP6st4vGCvx970 +2cu+fjOlbpSD8DT6IavqjnKgP6TeMFvvhk1qlVtDRKgQFRzlAVfFmPHmBiiRqiDFt1MmUUOyCxGV +WOHAD3bZwI18gfNycJ5v/hqO2V81xrJvNHy+SE/iWjnX2J14np+GPgNeGYtEotXHAgMBAAGjQjBA +MA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBS/WSA2AHmgoCJrjNXy +YdK4LMuCSjANBgkqhkiG9w0BAQsFAAOCAQEAMQOiYQsfdOhyNsZt+U2e+iKo4YFWz827n+qrkRk4 +r6p8FU3ztqONpfSO9kSpp+ghla0+AGIWiPACuvxhI+YzmzB6azZie60EI4RYZeLbK4rnJVM3YlNf +vNoBYimipidx5joifsFvHZVwIEoHNN/q/xWA5brXethbdXwFeilHfkCoMRN3zUA7tFFHei4R40cR +3p1m0IvVVGb6g1XqfMIpiRvpb7PO4gWEyS8+eIVibslfwXhjdFjASBgMmTnrpMwatXlajRWc2BQN +9noHV8cigwUtPJslJj0Ys6lDfMjIq2SPDqO/nBudMNva0Bkuqjzx+zOAduTNrRlPBSeOE6Fuwg== +-----END CERTIFICATE----- + +Atos TrustedRoot 2011 +===================== +-----BEGIN CERTIFICATE----- +MIIDdzCCAl+gAwIBAgIIXDPLYixfszIwDQYJKoZIhvcNAQELBQAwPDEeMBwGA1UEAwwVQXRvcyBU +cnVzdGVkUm9vdCAyMDExMQ0wCwYDVQQKDARBdG9zMQswCQYDVQQGEwJERTAeFw0xMTA3MDcxNDU4 +MzBaFw0zMDEyMzEyMzU5NTlaMDwxHjAcBgNVBAMMFUF0b3MgVHJ1c3RlZFJvb3QgMjAxMTENMAsG +A1UECgwEQXRvczELMAkGA1UEBhMCREUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCV +hTuXbyo7LjvPpvMpNb7PGKw+qtn4TaA+Gke5vJrf8v7MPkfoepbCJI419KkM/IL9bcFyYie96mvr +54rMVD6QUM+A1JX76LWC1BTFtqlVJVfbsVD2sGBkWXppzwO3bw2+yj5vdHLqqjAqc2K+SZFhyBH+ +DgMq92og3AIVDV4VavzjgsG1xZ1kCWyjWZgHJ8cblithdHFsQ/H3NYkQ4J7sVaE3IqKHBAUsR320 +HLliKWYoyrfhk/WklAOZuXCFteZI6o1Q/NnezG8HDt0Lcp2AMBYHlT8oDv3FdU9T1nSatCQujgKR +z3bFmx5VdJx4IbHwLfELn8LVlhgf8FQieowHAgMBAAGjfTB7MB0GA1UdDgQWBBSnpQaxLKYJYO7R +l+lwrrw7GWzbITAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFKelBrEspglg7tGX6XCuvDsZ +bNshMBgGA1UdIAQRMA8wDQYLKwYBBAGwLQMEAQEwDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3DQEB +CwUAA4IBAQAmdzTblEiGKkGdLD4GkGDEjKwLVLgfuXvTBznk+j57sj1O7Z8jvZfza1zv7v1Apt+h +k6EKhqzvINB5Ab149xnYJDE0BAGmuhWawyfc2E8PzBhj/5kPDpFrdRbhIfzYJsdHt6bPWHJxfrrh +TZVHO8mvbaG0weyJ9rQPOLXiZNwlz6bb65pcmaHFCN795trV1lpFDMS3wrUU77QR/w4VtfX128a9 +61qn8FYiqTxlVMYVqL2Gns2Dlmh6cYGJ4Qvh6hEbaAjMaZ7snkGeRDImeuKHCnE96+RapNLbxc3G +3mB/ufNPRJLvKrcYPqcZ2Qt9sTdBQrC6YB3y/gkRsPCHe6ed +-----END CERTIFICATE----- + diff --git a/vendor/guzzle/guzzle/src/Guzzle/Http/StaticClient.php b/vendor/guzzle/guzzle/src/Guzzle/Http/StaticClient.php new file mode 100644 index 0000000..dbd4c18 --- /dev/null +++ b/vendor/guzzle/guzzle/src/Guzzle/Http/StaticClient.php @@ -0,0 +1,157 @@ +createRequest($method, $url, null, null, $options); + + if (isset($options['stream'])) { + if ($options['stream'] instanceof StreamRequestFactoryInterface) { + return $options['stream']->fromRequest($request); + } elseif ($options['stream'] == true) { + $streamFactory = new PhpStreamRequestFactory(); + return $streamFactory->fromRequest($request); + } + } + + return $request->send(); + } + + /** + * Send a GET request + * + * @param string $url URL of the request + * @param array $options Array of request options + * + * @return \Guzzle\Http\Message\Response + * @see Guzzle::request for a list of available options + */ + public static function get($url, $options = array()) + { + return self::request('GET', $url, $options); + } + + /** + * Send a HEAD request + * + * @param string $url URL of the request + * @param array $options Array of request options + * + * @return \Guzzle\Http\Message\Response + * @see Guzzle::request for a list of available options + */ + public static function head($url, $options = array()) + { + return self::request('HEAD', $url, $options); + } + + /** + * Send a DELETE request + * + * @param string $url URL of the request + * @param array $options Array of request options + * + * @return \Guzzle\Http\Message\Response + * @see Guzzle::request for a list of available options + */ + public static function delete($url, $options = array()) + { + return self::request('DELETE', $url, $options); + } + + /** + * Send a POST request + * + * @param string $url URL of the request + * @param array $options Array of request options + * + * @return \Guzzle\Http\Message\Response + * @see Guzzle::request for a list of available options + */ + public static function post($url, $options = array()) + { + return self::request('POST', $url, $options); + } + + /** + * Send a PUT request + * + * @param string $url URL of the request + * @param array $options Array of request options + * + * @return \Guzzle\Http\Message\Response + * @see Guzzle::request for a list of available options + */ + public static function put($url, $options = array()) + { + return self::request('PUT', $url, $options); + } + + /** + * Send a PATCH request + * + * @param string $url URL of the request + * @param array $options Array of request options + * + * @return \Guzzle\Http\Message\Response + * @see Guzzle::request for a list of available options + */ + public static function patch($url, $options = array()) + { + return self::request('PATCH', $url, $options); + } + + /** + * Send an OPTIONS request + * + * @param string $url URL of the request + * @param array $options Array of request options + * + * @return \Guzzle\Http\Message\Response + * @see Guzzle::request for a list of available options + */ + public static function options($url, $options = array()) + { + return self::request('OPTIONS', $url, $options); + } +} diff --git a/vendor/guzzle/guzzle/src/Guzzle/Http/Url.php b/vendor/guzzle/guzzle/src/Guzzle/Http/Url.php new file mode 100644 index 0000000..6a4e772 --- /dev/null +++ b/vendor/guzzle/guzzle/src/Guzzle/Http/Url.php @@ -0,0 +1,554 @@ + null, 'host' => null, 'path' => null, 'port' => null, 'query' => null, + 'user' => null, 'pass' => null, 'fragment' => null); + + if (false === ($parts = parse_url($url))) { + throw new InvalidArgumentException('Was unable to parse malformed url: ' . $url); + } + + $parts += $defaults; + + // Convert the query string into a QueryString object + if ($parts['query'] || 0 !== strlen($parts['query'])) { + $parts['query'] = QueryString::fromString($parts['query']); + } + + return new static($parts['scheme'], $parts['host'], $parts['user'], + $parts['pass'], $parts['port'], $parts['path'], $parts['query'], + $parts['fragment']); + } + + /** + * Build a URL from parse_url parts. The generated URL will be a relative URL if a scheme or host are not provided. + * + * @param array $parts Array of parse_url parts + * + * @return string + */ + public static function buildUrl(array $parts) + { + $url = $scheme = ''; + + if (isset($parts['scheme'])) { + $scheme = $parts['scheme']; + $url .= $scheme . ':'; + } + + if (isset($parts['host'])) { + $url .= '//'; + if (isset($parts['user'])) { + $url .= $parts['user']; + if (isset($parts['pass'])) { + $url .= ':' . $parts['pass']; + } + $url .= '@'; + } + + $url .= $parts['host']; + + // Only include the port if it is not the default port of the scheme + if (isset($parts['port']) + && !(($scheme == 'http' && $parts['port'] == 80) || ($scheme == 'https' && $parts['port'] == 443)) + ) { + $url .= ':' . $parts['port']; + } + } + + // Add the path component if present + if (isset($parts['path']) && 0 !== strlen($parts['path'])) { + // Always ensure that the path begins with '/' if set and something is before the path + if ($url && $parts['path'][0] != '/' && substr($url, -1) != '/') { + $url .= '/'; + } + $url .= $parts['path']; + } + + // Add the query string if present + if (isset($parts['query'])) { + $url .= '?' . $parts['query']; + } + + // Ensure that # is only added to the url if fragment contains anything. + if (isset($parts['fragment'])) { + $url .= '#' . $parts['fragment']; + } + + return $url; + } + + /** + * Create a new URL from URL parts + * + * @param string $scheme Scheme of the URL + * @param string $host Host of the URL + * @param string $username Username of the URL + * @param string $password Password of the URL + * @param int $port Port of the URL + * @param string $path Path of the URL + * @param QueryString|array|string $query Query string of the URL + * @param string $fragment Fragment of the URL + */ + public function __construct($scheme, $host, $username = null, $password = null, $port = null, $path = null, QueryString $query = null, $fragment = null) + { + $this->scheme = $scheme; + $this->host = $host; + $this->port = $port; + $this->username = $username; + $this->password = $password; + $this->fragment = $fragment; + if (!$query) { + $this->query = new QueryString(); + } else { + $this->setQuery($query); + } + $this->setPath($path); + } + + /** + * Clone the URL + */ + public function __clone() + { + $this->query = clone $this->query; + } + + /** + * Returns the URL as a URL string + * + * @return string + */ + public function __toString() + { + return self::buildUrl($this->getParts()); + } + + /** + * Get the parts of the URL as an array + * + * @return array + */ + public function getParts() + { + $query = (string) $this->query; + + return array( + 'scheme' => $this->scheme, + 'user' => $this->username, + 'pass' => $this->password, + 'host' => $this->host, + 'port' => $this->port, + 'path' => $this->getPath(), + 'query' => $query !== '' ? $query : null, + 'fragment' => $this->fragment, + ); + } + + /** + * Set the host of the request. + * + * @param string $host Host to set (e.g. www.yahoo.com, yahoo.com) + * + * @return Url + */ + public function setHost($host) + { + if (strpos($host, ':') === false) { + $this->host = $host; + } else { + list($host, $port) = explode(':', $host); + $this->host = $host; + $this->setPort($port); + } + + return $this; + } + + /** + * Get the host part of the URL + * + * @return string + */ + public function getHost() + { + return $this->host; + } + + /** + * Set the scheme part of the URL (http, https, ftp, etc) + * + * @param string $scheme Scheme to set + * + * @return Url + */ + public function setScheme($scheme) + { + if ($this->scheme == 'http' && $this->port == 80) { + $this->port = null; + } elseif ($this->scheme == 'https' && $this->port == 443) { + $this->port = null; + } + + $this->scheme = $scheme; + + return $this; + } + + /** + * Get the scheme part of the URL + * + * @return string + */ + public function getScheme() + { + return $this->scheme; + } + + /** + * Set the port part of the URL + * + * @param int $port Port to set + * + * @return Url + */ + public function setPort($port) + { + $this->port = $port; + + return $this; + } + + /** + * Get the port part of the URl. Will return the default port for a given scheme if no port has been set. + * + * @return int|null + */ + public function getPort() + { + if ($this->port) { + return $this->port; + } elseif ($this->scheme == 'http') { + return 80; + } elseif ($this->scheme == 'https') { + return 443; + } + + return null; + } + + /** + * Set the path part of the URL + * + * @param array|string $path Path string or array of path segments + * + * @return Url + */ + public function setPath($path) + { + static $pathReplace = array(' ' => '%20', '?' => '%3F'); + if (is_array($path)) { + $path = '/' . implode('/', $path); + } + + $this->path = strtr($path, $pathReplace); + + return $this; + } + + /** + * Normalize the URL so that double slashes and relative paths are removed + * + * @return Url + */ + public function normalizePath() + { + if (!$this->path || $this->path == '/' || $this->path == '*') { + return $this; + } + + $results = array(); + $segments = $this->getPathSegments(); + foreach ($segments as $segment) { + if ($segment == '..') { + array_pop($results); + } elseif ($segment != '.' && $segment != '') { + $results[] = $segment; + } + } + + // Combine the normalized parts and add the leading slash if needed + $this->path = ($this->path[0] == '/' ? '/' : '') . implode('/', $results); + + // Add the trailing slash if necessary + if ($this->path != '/' && end($segments) == '') { + $this->path .= '/'; + } + + return $this; + } + + /** + * Add a relative path to the currently set path. + * + * @param string $relativePath Relative path to add + * + * @return Url + */ + public function addPath($relativePath) + { + if ($relativePath != '/' && is_string($relativePath) && strlen($relativePath) > 0) { + // Add a leading slash if needed + if ($relativePath[0] != '/') { + $relativePath = '/' . $relativePath; + } + $this->setPath(str_replace('//', '/', $this->path . $relativePath)); + } + + return $this; + } + + /** + * Get the path part of the URL + * + * @return string + */ + public function getPath() + { + return $this->path; + } + + /** + * Get the path segments of the URL as an array + * + * @return array + */ + public function getPathSegments() + { + return array_slice(explode('/', $this->getPath()), 1); + } + + /** + * Set the password part of the URL + * + * @param string $password Password to set + * + * @return Url + */ + public function setPassword($password) + { + $this->password = $password; + + return $this; + } + + /** + * Get the password part of the URL + * + * @return null|string + */ + public function getPassword() + { + return $this->password; + } + + /** + * Set the username part of the URL + * + * @param string $username Username to set + * + * @return Url + */ + public function setUsername($username) + { + $this->username = $username; + + return $this; + } + + /** + * Get the username part of the URl + * + * @return null|string + */ + public function getUsername() + { + return $this->username; + } + + /** + * Get the query part of the URL as a QueryString object + * + * @return QueryString + */ + public function getQuery() + { + return $this->query; + } + + /** + * Set the query part of the URL + * + * @param QueryString|string|array $query Query to set + * + * @return Url + */ + public function setQuery($query) + { + if (is_string($query)) { + $output = null; + parse_str($query, $output); + $this->query = new QueryString($output); + } elseif (is_array($query)) { + $this->query = new QueryString($query); + } elseif ($query instanceof QueryString) { + $this->query = $query; + } + + return $this; + } + + /** + * Get the fragment part of the URL + * + * @return null|string + */ + public function getFragment() + { + return $this->fragment; + } + + /** + * Set the fragment part of the URL + * + * @param string $fragment Fragment to set + * + * @return Url + */ + public function setFragment($fragment) + { + $this->fragment = $fragment; + + return $this; + } + + /** + * Check if this is an absolute URL + * + * @return bool + */ + public function isAbsolute() + { + return $this->scheme && $this->host; + } + + /** + * Combine the URL with another URL. Follows the rules specific in RFC 3986 section 5.4. + * + * @param string $url Relative URL to combine with + * @param bool $strictRfc3986 Set to true to use strict RFC 3986 compliance when merging paths. When first + * released, Guzzle used an incorrect algorithm for combining relative URL paths. In + * order to not break users, we introduced this flag to allow the merging of URLs based + * on strict RFC 3986 section 5.4.1. This means that "http://a.com/foo/baz" merged with + * "bar" would become "http://a.com/foo/bar". When this value is set to false, it would + * become "http://a.com/foo/baz/bar". + * @return Url + * @throws InvalidArgumentException + * @link http://tools.ietf.org/html/rfc3986#section-5.4 + */ + public function combine($url, $strictRfc3986 = false) + { + $url = self::factory($url); + + // Use the more absolute URL as the base URL + if (!$this->isAbsolute() && $url->isAbsolute()) { + $url = $url->combine($this); + } + + // Passing a URL with a scheme overrides everything + if ($buffer = $url->getScheme()) { + $this->scheme = $buffer; + $this->host = $url->getHost(); + $this->port = $url->getPort(); + $this->username = $url->getUsername(); + $this->password = $url->getPassword(); + $this->path = $url->getPath(); + $this->query = $url->getQuery(); + $this->fragment = $url->getFragment(); + return $this; + } + + // Setting a host overrides the entire rest of the URL + if ($buffer = $url->getHost()) { + $this->host = $buffer; + $this->port = $url->getPort(); + $this->username = $url->getUsername(); + $this->password = $url->getPassword(); + $this->path = $url->getPath(); + $this->query = $url->getQuery(); + $this->fragment = $url->getFragment(); + return $this; + } + + $path = $url->getPath(); + $query = $url->getQuery(); + + if (!$path) { + if (count($query)) { + $this->addQuery($query, $strictRfc3986); + } + } else { + if ($path[0] == '/') { + $this->path = $path; + } elseif ($strictRfc3986) { + $this->path .= '/../' . $path; + } else { + $this->path .= '/' . $path; + } + $this->normalizePath(); + $this->addQuery($query, $strictRfc3986); + } + + $this->fragment = $url->getFragment(); + + return $this; + } + + private function addQuery(QueryString $new, $strictRfc386) + { + if (!$strictRfc386) { + $new->merge($this->query); + } + + $this->query = $new; + } +} diff --git a/vendor/guzzle/guzzle/src/Guzzle/Http/composer.json b/vendor/guzzle/guzzle/src/Guzzle/Http/composer.json new file mode 100644 index 0000000..9384a5b --- /dev/null +++ b/vendor/guzzle/guzzle/src/Guzzle/Http/composer.json @@ -0,0 +1,32 @@ +{ + "name": "guzzle/http", + "description": "HTTP libraries used by Guzzle", + "homepage": "http://guzzlephp.org/", + "keywords": ["http client", "http", "client", "Guzzle", "curl"], + "license": "MIT", + "authors": [ + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + } + ], + "require": { + "php": ">=5.3.2", + "guzzle/common": "self.version", + "guzzle/parser": "self.version", + "guzzle/stream": "self.version" + }, + "suggest": { + "ext-curl": "*" + }, + "autoload": { + "psr-0": { "Guzzle\\Http": "" } + }, + "target-dir": "Guzzle/Http", + "extra": { + "branch-alias": { + "dev-master": "3.7-dev" + } + } +} diff --git a/vendor/guzzle/guzzle/src/Guzzle/Inflection/Inflector.php b/vendor/guzzle/guzzle/src/Guzzle/Inflection/Inflector.php new file mode 100644 index 0000000..c699773 --- /dev/null +++ b/vendor/guzzle/guzzle/src/Guzzle/Inflection/Inflector.php @@ -0,0 +1,38 @@ + array(), + 'camel' => array() + ); + + /** @var int Max entries per cache */ + protected $maxCacheSize; + + /** @var InflectorInterface Decorated inflector */ + protected $decoratedInflector; + + /** + * @param InflectorInterface $inflector Inflector being decorated + * @param int $maxCacheSize Maximum number of cached items to hold per cache + */ + public function __construct(InflectorInterface $inflector, $maxCacheSize = 500) + { + $this->decoratedInflector = $inflector; + $this->maxCacheSize = $maxCacheSize; + } + + public function snake($word) + { + if (!isset($this->cache['snake'][$word])) { + $this->pruneCache('snake'); + $this->cache['snake'][$word] = $this->decoratedInflector->snake($word); + } + + return $this->cache['snake'][$word]; + } + + /** + * Converts strings from snake_case to upper CamelCase + * + * @param string $word Value to convert into upper CamelCase + * + * @return string + */ + public function camel($word) + { + if (!isset($this->cache['camel'][$word])) { + $this->pruneCache('camel'); + $this->cache['camel'][$word] = $this->decoratedInflector->camel($word); + } + + return $this->cache['camel'][$word]; + } + + /** + * Prune one of the named caches by removing 20% of the cache if it is full + * + * @param string $cache Type of cache to prune + */ + protected function pruneCache($cache) + { + if (count($this->cache[$cache]) == $this->maxCacheSize) { + $this->cache[$cache] = array_slice($this->cache[$cache], $this->maxCacheSize * 0.2); + } + } +} diff --git a/vendor/guzzle/guzzle/src/Guzzle/Inflection/PreComputedInflector.php b/vendor/guzzle/guzzle/src/Guzzle/Inflection/PreComputedInflector.php new file mode 100644 index 0000000..db37e4f --- /dev/null +++ b/vendor/guzzle/guzzle/src/Guzzle/Inflection/PreComputedInflector.php @@ -0,0 +1,59 @@ + array(), + 'camel' => array() + ); + + /** @var InflectorInterface Decorated inflector */ + protected $decoratedInflector; + + /** + * @param InflectorInterface $inflector Inflector being decorated + * @param array $snake Hash of pre-computed camel to snake + * @param array $camel Hash of pre-computed snake to camel + * @param bool $mirror Mirror snake and camel reflections + */ + public function __construct(InflectorInterface $inflector, array $snake = array(), array $camel = array(), $mirror = false) + { + if ($mirror) { + $camel = array_merge(array_flip($snake), $camel); + $snake = array_merge(array_flip($camel), $snake); + } + + $this->decoratedInflector = $inflector; + $this->mapping = array( + 'snake' => $snake, + 'camel' => $camel + ); + } + + public function snake($word) + { + return isset($this->mapping['snake'][$word]) + ? $this->mapping['snake'][$word] + : $this->decoratedInflector->snake($word); + } + + /** + * Converts strings from snake_case to upper CamelCase + * + * @param string $word Value to convert into upper CamelCase + * + * @return string + */ + public function camel($word) + { + return isset($this->mapping['camel'][$word]) + ? $this->mapping['camel'][$word] + : $this->decoratedInflector->camel($word); + } +} diff --git a/vendor/guzzle/guzzle/src/Guzzle/Inflection/composer.json b/vendor/guzzle/guzzle/src/Guzzle/Inflection/composer.json new file mode 100644 index 0000000..93f9e7b --- /dev/null +++ b/vendor/guzzle/guzzle/src/Guzzle/Inflection/composer.json @@ -0,0 +1,26 @@ +{ + "name": "guzzle/inflection", + "description": "Guzzle inflection component", + "homepage": "http://guzzlephp.org/", + "keywords": ["inflection", "guzzle"], + "license": "MIT", + "authors": [ + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + } + ], + "require": { + "php": ">=5.3.2" + }, + "autoload": { + "psr-0": { "Guzzle\\Inflection": "" } + }, + "target-dir": "Guzzle/Inflection", + "extra": { + "branch-alias": { + "dev-master": "3.7-dev" + } + } +} diff --git a/vendor/guzzle/guzzle/src/Guzzle/Iterator/AppendIterator.php b/vendor/guzzle/guzzle/src/Guzzle/Iterator/AppendIterator.php new file mode 100644 index 0000000..1b6bd7e --- /dev/null +++ b/vendor/guzzle/guzzle/src/Guzzle/Iterator/AppendIterator.php @@ -0,0 +1,19 @@ +getArrayIterator()->append($iterator); + } +} diff --git a/vendor/guzzle/guzzle/src/Guzzle/Iterator/ChunkedIterator.php b/vendor/guzzle/guzzle/src/Guzzle/Iterator/ChunkedIterator.php new file mode 100644 index 0000000..d76cdd4 --- /dev/null +++ b/vendor/guzzle/guzzle/src/Guzzle/Iterator/ChunkedIterator.php @@ -0,0 +1,56 @@ +chunkSize = $chunkSize; + } + + public function rewind() + { + parent::rewind(); + $this->next(); + } + + public function next() + { + $this->chunk = array(); + for ($i = 0; $i < $this->chunkSize && parent::valid(); $i++) { + $this->chunk[] = parent::current(); + parent::next(); + } + } + + public function current() + { + return $this->chunk; + } + + public function valid() + { + return (bool) $this->chunk; + } +} diff --git a/vendor/guzzle/guzzle/src/Guzzle/Iterator/FilterIterator.php b/vendor/guzzle/guzzle/src/Guzzle/Iterator/FilterIterator.php new file mode 100644 index 0000000..b103367 --- /dev/null +++ b/vendor/guzzle/guzzle/src/Guzzle/Iterator/FilterIterator.php @@ -0,0 +1,36 @@ +callback = $callback; + } + + public function accept() + { + return call_user_func($this->callback, $this->current()); + } +} diff --git a/vendor/guzzle/guzzle/src/Guzzle/Iterator/MapIterator.php b/vendor/guzzle/guzzle/src/Guzzle/Iterator/MapIterator.php new file mode 100644 index 0000000..7e586bd --- /dev/null +++ b/vendor/guzzle/guzzle/src/Guzzle/Iterator/MapIterator.php @@ -0,0 +1,34 @@ +callback = $callback; + } + + public function current() + { + return call_user_func($this->callback, parent::current()); + } +} diff --git a/vendor/guzzle/guzzle/src/Guzzle/Iterator/MethodProxyIterator.php b/vendor/guzzle/guzzle/src/Guzzle/Iterator/MethodProxyIterator.php new file mode 100644 index 0000000..de4ab03 --- /dev/null +++ b/vendor/guzzle/guzzle/src/Guzzle/Iterator/MethodProxyIterator.php @@ -0,0 +1,27 @@ +getInnerIterator(); + while ($i instanceof \OuterIterator) { + $i = $i->getInnerIterator(); + } + + return call_user_func_array(array($i, $name), $args); + } +} diff --git a/vendor/guzzle/guzzle/src/Guzzle/Iterator/README.md b/vendor/guzzle/guzzle/src/Guzzle/Iterator/README.md new file mode 100644 index 0000000..8bb7e08 --- /dev/null +++ b/vendor/guzzle/guzzle/src/Guzzle/Iterator/README.md @@ -0,0 +1,25 @@ +Guzzle Iterator +=============== + +Provides useful Iterators and Iterator decorators + +- ChunkedIterator: Pulls out chunks from an inner iterator and yields the chunks as arrays +- FilterIterator: Used when PHP 5.4's CallbackFilterIterator is not available +- MapIterator: Maps values before yielding +- MethodProxyIterator: Proxies missing method calls to the innermost iterator + +### Installing via Composer + +```bash +# Install Composer +curl -sS https://getcomposer.org/installer | php + +# Add Guzzle as a dependency +php composer.phar require guzzle/iterator:~3.0 +``` + +After installing, you need to require Composer's autoloader: + +```php +require 'vendor/autoload.php'; +``` diff --git a/vendor/guzzle/guzzle/src/Guzzle/Iterator/composer.json b/vendor/guzzle/guzzle/src/Guzzle/Iterator/composer.json new file mode 100644 index 0000000..ee17379 --- /dev/null +++ b/vendor/guzzle/guzzle/src/Guzzle/Iterator/composer.json @@ -0,0 +1,27 @@ +{ + "name": "guzzle/iterator", + "description": "Provides helpful iterators and iterator decorators", + "keywords": ["iterator", "guzzle"], + "homepage": "http://guzzlephp.org/", + "license": "MIT", + "authors": [ + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + } + ], + "require": { + "php": ">=5.3.2", + "guzzle/common": ">=2.8.0" + }, + "autoload": { + "psr-0": { "Guzzle\\Iterator": "/" } + }, + "target-dir": "Guzzle/Iterator", + "extra": { + "branch-alias": { + "dev-master": "3.7-dev" + } + } +} diff --git a/vendor/guzzle/guzzle/src/Guzzle/Log/AbstractLogAdapter.php b/vendor/guzzle/guzzle/src/Guzzle/Log/AbstractLogAdapter.php new file mode 100644 index 0000000..7f6271b --- /dev/null +++ b/vendor/guzzle/guzzle/src/Guzzle/Log/AbstractLogAdapter.php @@ -0,0 +1,16 @@ +log; + } +} diff --git a/vendor/guzzle/guzzle/src/Guzzle/Log/ArrayLogAdapter.php b/vendor/guzzle/guzzle/src/Guzzle/Log/ArrayLogAdapter.php new file mode 100644 index 0000000..a70fc8d --- /dev/null +++ b/vendor/guzzle/guzzle/src/Guzzle/Log/ArrayLogAdapter.php @@ -0,0 +1,34 @@ +logs[] = array('message' => $message, 'priority' => $priority, 'extras' => $extras); + } + + /** + * Get logged entries + * + * @return array + */ + public function getLogs() + { + return $this->logs; + } + + /** + * Clears logged entries + */ + public function clearLogs() + { + $this->logs = array(); + } +} diff --git a/vendor/guzzle/guzzle/src/Guzzle/Log/ClosureLogAdapter.php b/vendor/guzzle/guzzle/src/Guzzle/Log/ClosureLogAdapter.php new file mode 100644 index 0000000..d4bb73f --- /dev/null +++ b/vendor/guzzle/guzzle/src/Guzzle/Log/ClosureLogAdapter.php @@ -0,0 +1,23 @@ +log = $logObject; + } + + public function log($message, $priority = LOG_INFO, $extras = array()) + { + call_user_func($this->log, $message, $priority, $extras); + } +} diff --git a/vendor/guzzle/guzzle/src/Guzzle/Log/LogAdapterInterface.php b/vendor/guzzle/guzzle/src/Guzzle/Log/LogAdapterInterface.php new file mode 100644 index 0000000..d7ac4ea --- /dev/null +++ b/vendor/guzzle/guzzle/src/Guzzle/Log/LogAdapterInterface.php @@ -0,0 +1,18 @@ +>>>>>>>\n{request}\n<<<<<<<<\n{response}\n--------\n{curl_stderr}"; + const SHORT_FORMAT = '[{ts}] "{method} {resource} {protocol}/{version}" {code}'; + + /** + * @var string Template used to format log messages + */ + protected $template; + + /** + * @param string $template Log message template + */ + public function __construct($template = self::DEFAULT_FORMAT) + { + $this->template = $template ?: self::DEFAULT_FORMAT; + } + + /** + * Set the template to use for logging + * + * @param string $template Log message template + * + * @return self + */ + public function setTemplate($template) + { + $this->template = $template; + + return $this; + } + + /** + * Returns a formatted message + * + * @param RequestInterface $request Request that was sent + * @param Response $response Response that was received + * @param CurlHandle $handle Curl handle associated with the message + * @param array $customData Associative array of custom template data + * + * @return string + */ + public function format( + RequestInterface $request, + Response $response = null, + CurlHandle $handle = null, + array $customData = array() + ) { + $cache = $customData; + + return preg_replace_callback( + '/{\s*([A-Za-z_\-\.0-9]+)\s*}/', + function (array $matches) use ($request, $response, $handle, &$cache) { + + if (array_key_exists($matches[1], $cache)) { + return $cache[$matches[1]]; + } + + $result = ''; + switch ($matches[1]) { + case 'request': + $result = (string) $request; + break; + case 'response': + $result = (string) $response; + break; + case 'req_body': + $result = $request instanceof EntityEnclosingRequestInterface + ? (string) $request->getBody() : ''; + break; + case 'res_body': + $result = $response ? $response->getBody(true) : ''; + break; + case 'ts': + $result = gmdate('c'); + break; + case 'method': + $result = $request->getMethod(); + break; + case 'url': + $result = (string) $request->getUrl(); + break; + case 'resource': + $result = $request->getResource(); + break; + case 'protocol': + $result = 'HTTP'; + break; + case 'version': + $result = $request->getProtocolVersion(); + break; + case 'host': + $result = $request->getHost(); + break; + case 'hostname': + $result = gethostname(); + break; + case 'port': + $result = $request->getPort(); + break; + case 'code': + $result = $response ? $response->getStatusCode() : ''; + break; + case 'phrase': + $result = $response ? $response->getReasonPhrase() : ''; + break; + case 'connect_time': + $result = $handle && $handle->getInfo(CURLINFO_CONNECT_TIME) + ? $handle->getInfo(CURLINFO_CONNECT_TIME) + : ($response ? $response->getInfo('connect_time') : ''); + break; + case 'total_time': + $result = $handle && $handle->getInfo(CURLINFO_TOTAL_TIME) + ? $handle->getInfo(CURLINFO_TOTAL_TIME) + : ($response ? $response->getInfo('total_time') : ''); + break; + case 'curl_error': + $result = $handle ? $handle->getError() : ''; + break; + case 'curl_code': + $result = $handle ? $handle->getErrorNo() : ''; + break; + case 'curl_stderr': + $result = $handle ? $handle->getStderr() : ''; + break; + default: + if (strpos($matches[1], 'req_header_') === 0) { + $result = $request->getHeader(substr($matches[1], 11)); + } elseif ($response && strpos($matches[1], 'res_header_') === 0) { + $result = $response->getHeader(substr($matches[1], 11)); + } + } + + $cache[$matches[1]] = $result; + return $result; + }, + $this->template + ); + } +} diff --git a/vendor/guzzle/guzzle/src/Guzzle/Log/MonologLogAdapter.php b/vendor/guzzle/guzzle/src/Guzzle/Log/MonologLogAdapter.php new file mode 100644 index 0000000..6afe7b6 --- /dev/null +++ b/vendor/guzzle/guzzle/src/Guzzle/Log/MonologLogAdapter.php @@ -0,0 +1,34 @@ + Logger::DEBUG, + LOG_INFO => Logger::INFO, + LOG_WARNING => Logger::WARNING, + LOG_ERR => Logger::ERROR, + LOG_CRIT => Logger::CRITICAL, + LOG_ALERT => Logger::ALERT + ); + + public function __construct(Logger $logObject) + { + $this->log = $logObject; + } + + public function log($message, $priority = LOG_INFO, $extras = array()) + { + $this->log->addRecord(self::$mapping[$priority], $message, $extras); + } +} diff --git a/vendor/guzzle/guzzle/src/Guzzle/Log/PsrLogAdapter.php b/vendor/guzzle/guzzle/src/Guzzle/Log/PsrLogAdapter.php new file mode 100644 index 0000000..38a2b60 --- /dev/null +++ b/vendor/guzzle/guzzle/src/Guzzle/Log/PsrLogAdapter.php @@ -0,0 +1,36 @@ + LogLevel::DEBUG, + LOG_INFO => LogLevel::INFO, + LOG_WARNING => LogLevel::WARNING, + LOG_ERR => LogLevel::ERROR, + LOG_CRIT => LogLevel::CRITICAL, + LOG_ALERT => LogLevel::ALERT + ); + + public function __construct(LoggerInterface $logObject) + { + $this->log = $logObject; + } + + public function log($message, $priority = LOG_INFO, $extras = array()) + { + $this->log->log(self::$mapping[$priority], $message, $extras); + } +} diff --git a/vendor/guzzle/guzzle/src/Guzzle/Log/Zf1LogAdapter.php b/vendor/guzzle/guzzle/src/Guzzle/Log/Zf1LogAdapter.php new file mode 100644 index 0000000..0ea8e3b --- /dev/null +++ b/vendor/guzzle/guzzle/src/Guzzle/Log/Zf1LogAdapter.php @@ -0,0 +1,24 @@ +log = $logObject; + Version::warn(__CLASS__ . ' is deprecated'); + } + + public function log($message, $priority = LOG_INFO, $extras = array()) + { + $this->log->log($message, $priority, $extras); + } +} diff --git a/vendor/guzzle/guzzle/src/Guzzle/Log/Zf2LogAdapter.php b/vendor/guzzle/guzzle/src/Guzzle/Log/Zf2LogAdapter.php new file mode 100644 index 0000000..863f6a1 --- /dev/null +++ b/vendor/guzzle/guzzle/src/Guzzle/Log/Zf2LogAdapter.php @@ -0,0 +1,21 @@ +log = $logObject; + } + + public function log($message, $priority = LOG_INFO, $extras = array()) + { + $this->log->log($priority, $message, $extras); + } +} diff --git a/vendor/guzzle/guzzle/src/Guzzle/Log/composer.json b/vendor/guzzle/guzzle/src/Guzzle/Log/composer.json new file mode 100644 index 0000000..a8213e8 --- /dev/null +++ b/vendor/guzzle/guzzle/src/Guzzle/Log/composer.json @@ -0,0 +1,29 @@ +{ + "name": "guzzle/log", + "description": "Guzzle log adapter component", + "homepage": "http://guzzlephp.org/", + "keywords": ["log", "adapter", "guzzle"], + "license": "MIT", + "authors": [ + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + } + ], + "require": { + "php": ">=5.3.2" + }, + "autoload": { + "psr-0": { "Guzzle\\Log": "" } + }, + "suggest": { + "guzzle/http": "self.version" + }, + "target-dir": "Guzzle/Log", + "extra": { + "branch-alias": { + "dev-master": "3.7-dev" + } + } +} diff --git a/vendor/guzzle/guzzle/src/Guzzle/Parser/Cookie/CookieParser.php b/vendor/guzzle/guzzle/src/Guzzle/Parser/Cookie/CookieParser.php new file mode 100644 index 0000000..4349eeb --- /dev/null +++ b/vendor/guzzle/guzzle/src/Guzzle/Parser/Cookie/CookieParser.php @@ -0,0 +1,131 @@ + 'Domain', + 'path' => 'Path', + 'max_age' => 'Max-Age', + 'expires' => 'Expires', + 'version' => 'Version', + 'secure' => 'Secure', + 'port' => 'Port', + 'discard' => 'Discard', + 'comment' => 'Comment', + 'comment_url' => 'Comment-Url', + 'http_only' => 'HttpOnly' + ); + + public function parseCookie($cookie, $host = null, $path = null, $decode = false) + { + // Explode the cookie string using a series of semicolons + $pieces = array_filter(array_map('trim', explode(';', $cookie))); + + // The name of the cookie (first kvp) must include an equal sign. + if (empty($pieces) || !strpos($pieces[0], '=')) { + return false; + } + + // Create the default return array + $data = array_merge(array_fill_keys(array_keys(self::$cookieParts), null), array( + 'cookies' => array(), + 'data' => array(), + 'path' => null, + 'http_only' => false, + 'discard' => false, + 'domain' => $host + )); + $foundNonCookies = 0; + + // Add the cookie pieces into the parsed data array + foreach ($pieces as $part) { + + $cookieParts = explode('=', $part, 2); + $key = trim($cookieParts[0]); + + if (count($cookieParts) == 1) { + // Can be a single value (e.g. secure, httpOnly) + $value = true; + } else { + // Be sure to strip wrapping quotes + $value = trim($cookieParts[1], " \n\r\t\0\x0B\""); + if ($decode) { + $value = urldecode($value); + } + } + + // Only check for non-cookies when cookies have been found + if (!empty($data['cookies'])) { + foreach (self::$cookieParts as $mapValue => $search) { + if (!strcasecmp($search, $key)) { + $data[$mapValue] = $mapValue == 'port' ? array_map('trim', explode(',', $value)) : $value; + $foundNonCookies++; + continue 2; + } + } + } + + // If cookies have not yet been retrieved, or this value was not found in the pieces array, treat it as a + // cookie. IF non-cookies have been parsed, then this isn't a cookie, it's cookie data. Cookies then data. + $data[$foundNonCookies ? 'data' : 'cookies'][$key] = $value; + } + + // Calculate the expires date + if (!$data['expires'] && $data['max_age']) { + $data['expires'] = time() + (int) $data['max_age']; + } + + // Check path attribute according RFC6265 http://tools.ietf.org/search/rfc6265#section-5.2.4 + // "If the attribute-value is empty or if the first character of the + // attribute-value is not %x2F ("/"): + // Let cookie-path be the default-path. + // Otherwise: + // Let cookie-path be the attribute-value." + if (!$data['path'] || substr($data['path'], 0, 1) !== '/') { + $data['path'] = $this->getDefaultPath($path); + } + + return $data; + } + + /** + * Get default cookie path according to RFC 6265 + * http://tools.ietf.org/search/rfc6265#section-5.1.4 Paths and Path-Match + * + * @param string $path Request uri-path + * + * @return string + */ + protected function getDefaultPath($path) { + // "The user agent MUST use an algorithm equivalent to the following algorithm + // to compute the default-path of a cookie:" + + // "2. If the uri-path is empty or if the first character of the uri-path is not + // a %x2F ("/") character, output %x2F ("/") and skip the remaining steps. + if (empty($path) || substr($path, 0, 1) !== '/') { + return '/'; + } + + // "3. If the uri-path contains no more than one %x2F ("/") character, output + // %x2F ("/") and skip the remaining step." + if ($path === "/") { + return $path; + } + + $rightSlashPos = strrpos($path, '/'); + if ($rightSlashPos === 0) { + return "/"; + } + + // "4. Output the characters of the uri-path from the first character up to, + // but not including, the right-most %x2F ("/")." + return substr($path, 0, $rightSlashPos); + + } +} diff --git a/vendor/guzzle/guzzle/src/Guzzle/Parser/Cookie/CookieParserInterface.php b/vendor/guzzle/guzzle/src/Guzzle/Parser/Cookie/CookieParserInterface.php new file mode 100644 index 0000000..d21ffe2 --- /dev/null +++ b/vendor/guzzle/guzzle/src/Guzzle/Parser/Cookie/CookieParserInterface.php @@ -0,0 +1,33 @@ + $requestUrl, + 'scheme' => 'http' + ); + + // Check for the Host header + if (isset($parts['headers']['Host'])) { + $urlParts['host'] = $parts['headers']['Host']; + } elseif (isset($parts['headers']['host'])) { + $urlParts['host'] = $parts['headers']['host']; + } else { + $urlParts['host'] = null; + } + + if (false === strpos($urlParts['host'], ':')) { + $urlParts['port'] = ''; + } else { + $hostParts = explode(':', $urlParts['host']); + $urlParts['host'] = trim($hostParts[0]); + $urlParts['port'] = (int) trim($hostParts[1]); + if ($urlParts['port'] == 443) { + $urlParts['scheme'] = 'https'; + } + } + + // Check if a query is present + $path = $urlParts['path']; + $qpos = strpos($path, '?'); + if ($qpos) { + $urlParts['query'] = substr($path, $qpos + 1); + $urlParts['path'] = substr($path, 0, $qpos); + } else { + $urlParts['query'] = ''; + } + + return $urlParts; + } +} diff --git a/vendor/guzzle/guzzle/src/Guzzle/Parser/Message/MessageParser.php b/vendor/guzzle/guzzle/src/Guzzle/Parser/Message/MessageParser.php new file mode 100644 index 0000000..efc1aa3 --- /dev/null +++ b/vendor/guzzle/guzzle/src/Guzzle/Parser/Message/MessageParser.php @@ -0,0 +1,110 @@ +parseMessage($message); + + // Parse the protocol and protocol version + if (isset($parts['start_line'][2])) { + $startParts = explode('/', $parts['start_line'][2]); + $protocol = strtoupper($startParts[0]); + $version = isset($startParts[1]) ? $startParts[1] : '1.1'; + } else { + $protocol = 'HTTP'; + $version = '1.1'; + } + + $parsed = array( + 'method' => strtoupper($parts['start_line'][0]), + 'protocol' => $protocol, + 'version' => $version, + 'headers' => $parts['headers'], + 'body' => $parts['body'] + ); + + $parsed['request_url'] = $this->getUrlPartsFromMessage(isset($parts['start_line'][1]) ? $parts['start_line'][1] : '' , $parsed); + + return $parsed; + } + + public function parseResponse($message) + { + if (!$message) { + return false; + } + + $parts = $this->parseMessage($message); + list($protocol, $version) = explode('/', trim($parts['start_line'][0])); + + return array( + 'protocol' => $protocol, + 'version' => $version, + 'code' => $parts['start_line'][1], + 'reason_phrase' => isset($parts['start_line'][2]) ? $parts['start_line'][2] : '', + 'headers' => $parts['headers'], + 'body' => $parts['body'] + ); + } + + /** + * Parse a message into parts + * + * @param string $message Message to parse + * + * @return array + */ + protected function parseMessage($message) + { + $startLine = null; + $headers = array(); + $body = ''; + + // Iterate over each line in the message, accounting for line endings + $lines = preg_split('/(\\r?\\n)/', $message, -1, PREG_SPLIT_DELIM_CAPTURE); + for ($i = 0, $totalLines = count($lines); $i < $totalLines; $i += 2) { + + $line = $lines[$i]; + + // If two line breaks were encountered, then this is the end of body + if (empty($line)) { + if ($i < $totalLines - 1) { + $body = implode('', array_slice($lines, $i + 2)); + } + break; + } + + // Parse message headers + if (!$startLine) { + $startLine = explode(' ', $line, 3); + } elseif (strpos($line, ':')) { + $parts = explode(':', $line, 2); + $key = trim($parts[0]); + $value = isset($parts[1]) ? trim($parts[1]) : ''; + if (!isset($headers[$key])) { + $headers[$key] = $value; + } elseif (!is_array($headers[$key])) { + $headers[$key] = array($headers[$key], $value); + } else { + $headers[$key][] = $value; + } + } + } + + return array( + 'start_line' => $startLine, + 'headers' => $headers, + 'body' => $body + ); + } +} diff --git a/vendor/guzzle/guzzle/src/Guzzle/Parser/Message/MessageParserInterface.php b/vendor/guzzle/guzzle/src/Guzzle/Parser/Message/MessageParserInterface.php new file mode 100644 index 0000000..cc44808 --- /dev/null +++ b/vendor/guzzle/guzzle/src/Guzzle/Parser/Message/MessageParserInterface.php @@ -0,0 +1,27 @@ + $parts->requestMethod, + 'protocol' => 'HTTP', + 'version' => number_format($parts->httpVersion, 1), + 'headers' => $parts->headers, + 'body' => $parts->body + ); + + $parsed['request_url'] = $this->getUrlPartsFromMessage($parts->requestUrl, $parsed); + + return $parsed; + } + + public function parseResponse($message) + { + if (!$message) { + return false; + } + + $parts = http_parse_message($message); + + return array( + 'protocol' => 'HTTP', + 'version' => number_format($parts->httpVersion, 1), + 'code' => $parts->responseCode, + 'reason_phrase' => $parts->responseStatus, + 'headers' => $parts->headers, + 'body' => $parts->body + ); + } +} diff --git a/vendor/guzzle/guzzle/src/Guzzle/Parser/ParserRegistry.php b/vendor/guzzle/guzzle/src/Guzzle/Parser/ParserRegistry.php new file mode 100644 index 0000000..f838683 --- /dev/null +++ b/vendor/guzzle/guzzle/src/Guzzle/Parser/ParserRegistry.php @@ -0,0 +1,75 @@ + 'Guzzle\\Parser\\Message\\MessageParser', + 'cookie' => 'Guzzle\\Parser\\Cookie\\CookieParser', + 'url' => 'Guzzle\\Parser\\Url\\UrlParser', + 'uri_template' => 'Guzzle\\Parser\\UriTemplate\\UriTemplate', + ); + + /** + * @return self + * @codeCoverageIgnore + */ + public static function getInstance() + { + if (!self::$instance) { + self::$instance = new static; + } + + return self::$instance; + } + + public function __construct() + { + // Use the PECL URI template parser if available + if (extension_loaded('uri_template')) { + $this->mapping['uri_template'] = 'Guzzle\\Parser\\UriTemplate\\PeclUriTemplate'; + } + } + + /** + * Get a parser by name from an instance + * + * @param string $name Name of the parser to retrieve + * + * @return mixed|null + */ + public function getParser($name) + { + if (!isset($this->instances[$name])) { + if (!isset($this->mapping[$name])) { + return null; + } + $class = $this->mapping[$name]; + $this->instances[$name] = new $class(); + } + + return $this->instances[$name]; + } + + /** + * Register a custom parser by name with the register + * + * @param string $name Name or handle of the parser to register + * @param mixed $parser Instantiated parser to register + */ + public function registerParser($name, $parser) + { + $this->instances[$name] = $parser; + } +} diff --git a/vendor/guzzle/guzzle/src/Guzzle/Parser/UriTemplate/PeclUriTemplate.php b/vendor/guzzle/guzzle/src/Guzzle/Parser/UriTemplate/PeclUriTemplate.php new file mode 100644 index 0000000..b0764e8 --- /dev/null +++ b/vendor/guzzle/guzzle/src/Guzzle/Parser/UriTemplate/PeclUriTemplate.php @@ -0,0 +1,26 @@ + true, '#' => true, '.' => true, '/' => true, ';' => true, '?' => true, '&' => true + ); + + /** @var array Delimiters */ + private static $delims = array( + ':', '/', '?', '#', '[', ']', '@', '!', '$', '&', '\'', '(', ')', '*', '+', ',', ';', '=' + ); + + /** @var array Percent encoded delimiters */ + private static $delimsPct = array( + '%3A', '%2F', '%3F', '%23', '%5B', '%5D', '%40', '%21', '%24', '%26', '%27', '%28', '%29', '%2A', '%2B', '%2C', + '%3B', '%3D' + ); + + public function expand($template, array $variables) + { + if ($this->regex == self::DEFAULT_PATTERN && false === strpos($template, '{')) { + return $template; + } + + $this->template = $template; + $this->variables = $variables; + + return preg_replace_callback($this->regex, array($this, 'expandMatch'), $this->template); + } + + /** + * Set the regex patten used to expand URI templates + * + * @param string $regexPattern + */ + public function setRegex($regexPattern) + { + $this->regex = $regexPattern; + } + + /** + * Parse an expression into parts + * + * @param string $expression Expression to parse + * + * @return array Returns an associative array of parts + */ + private function parseExpression($expression) + { + // Check for URI operators + $operator = ''; + + if (isset(self::$operatorHash[$expression[0]])) { + $operator = $expression[0]; + $expression = substr($expression, 1); + } + + $values = explode(',', $expression); + foreach ($values as &$value) { + $value = trim($value); + $varspec = array(); + $substrPos = strpos($value, ':'); + if ($substrPos) { + $varspec['value'] = substr($value, 0, $substrPos); + $varspec['modifier'] = ':'; + $varspec['position'] = (int) substr($value, $substrPos + 1); + } elseif (substr($value, -1) == '*') { + $varspec['modifier'] = '*'; + $varspec['value'] = substr($value, 0, -1); + } else { + $varspec['value'] = (string) $value; + $varspec['modifier'] = ''; + } + $value = $varspec; + } + + return array( + 'operator' => $operator, + 'values' => $values + ); + } + + /** + * Process an expansion + * + * @param array $matches Matches met in the preg_replace_callback + * + * @return string Returns the replacement string + */ + private function expandMatch(array $matches) + { + static $rfc1738to3986 = array( + '+' => '%20', + '%7e' => '~' + ); + + $parsed = self::parseExpression($matches[1]); + $replacements = array(); + + $prefix = $parsed['operator']; + $joiner = $parsed['operator']; + $useQueryString = false; + if ($parsed['operator'] == '?') { + $joiner = '&'; + $useQueryString = true; + } elseif ($parsed['operator'] == '&') { + $useQueryString = true; + } elseif ($parsed['operator'] == '#') { + $joiner = ','; + } elseif ($parsed['operator'] == ';') { + $useQueryString = true; + } elseif ($parsed['operator'] == '' || $parsed['operator'] == '+') { + $joiner = ','; + $prefix = ''; + } + + foreach ($parsed['values'] as $value) { + + if (!array_key_exists($value['value'], $this->variables) || $this->variables[$value['value']] === null) { + continue; + } + + $variable = $this->variables[$value['value']]; + $actuallyUseQueryString = $useQueryString; + $expanded = ''; + + if (is_array($variable)) { + + $isAssoc = $this->isAssoc($variable); + $kvp = array(); + foreach ($variable as $key => $var) { + + if ($isAssoc) { + $key = rawurlencode($key); + $isNestedArray = is_array($var); + } else { + $isNestedArray = false; + } + + if (!$isNestedArray) { + $var = rawurlencode($var); + if ($parsed['operator'] == '+' || $parsed['operator'] == '#') { + $var = $this->decodeReserved($var); + } + } + + if ($value['modifier'] == '*') { + if ($isAssoc) { + if ($isNestedArray) { + // Nested arrays must allow for deeply nested structures + $var = strtr(http_build_query(array($key => $var)), $rfc1738to3986); + } else { + $var = $key . '=' . $var; + } + } elseif ($key > 0 && $actuallyUseQueryString) { + $var = $value['value'] . '=' . $var; + } + } + + $kvp[$key] = $var; + } + + if (empty($variable)) { + $actuallyUseQueryString = false; + } elseif ($value['modifier'] == '*') { + $expanded = implode($joiner, $kvp); + if ($isAssoc) { + // Don't prepend the value name when using the explode modifier with an associative array + $actuallyUseQueryString = false; + } + } else { + if ($isAssoc) { + // When an associative array is encountered and the explode modifier is not set, then the + // result must be a comma separated list of keys followed by their respective values. + foreach ($kvp as $k => &$v) { + $v = $k . ',' . $v; + } + } + $expanded = implode(',', $kvp); + } + + } else { + if ($value['modifier'] == ':') { + $variable = substr($variable, 0, $value['position']); + } + $expanded = rawurlencode($variable); + if ($parsed['operator'] == '+' || $parsed['operator'] == '#') { + $expanded = $this->decodeReserved($expanded); + } + } + + if ($actuallyUseQueryString) { + if (!$expanded && $joiner != '&') { + $expanded = $value['value']; + } else { + $expanded = $value['value'] . '=' . $expanded; + } + } + + $replacements[] = $expanded; + } + + $ret = implode($joiner, $replacements); + if ($ret && $prefix) { + return $prefix . $ret; + } + + return $ret; + } + + /** + * Determines if an array is associative + * + * @param array $array Array to check + * + * @return bool + */ + private function isAssoc(array $array) + { + return (bool) count(array_filter(array_keys($array), 'is_string')); + } + + /** + * Removes percent encoding on reserved characters (used with + and # modifiers) + * + * @param string $string String to fix + * + * @return string + */ + private function decodeReserved($string) + { + return str_replace(self::$delimsPct, self::$delims, $string); + } +} diff --git a/vendor/guzzle/guzzle/src/Guzzle/Parser/UriTemplate/UriTemplateInterface.php b/vendor/guzzle/guzzle/src/Guzzle/Parser/UriTemplate/UriTemplateInterface.php new file mode 100644 index 0000000..c81d515 --- /dev/null +++ b/vendor/guzzle/guzzle/src/Guzzle/Parser/UriTemplate/UriTemplateInterface.php @@ -0,0 +1,21 @@ +utf8 = $utf8; + } + + public function parseUrl($url) + { + Version::warn(__CLASS__ . ' is deprecated. Just use parse_url()'); + + static $defaults = array('scheme' => null, 'host' => null, 'path' => null, 'port' => null, 'query' => null, + 'user' => null, 'pass' => null, 'fragment' => null); + + $parts = parse_url($url); + + // Need to handle query parsing specially for UTF-8 requirements + if ($this->utf8 && isset($parts['query'])) { + $queryPos = strpos($url, '?'); + if (isset($parts['fragment'])) { + $parts['query'] = substr($url, $queryPos + 1, strpos($url, '#') - $queryPos - 1); + } else { + $parts['query'] = substr($url, $queryPos + 1); + } + } + + return $parts + $defaults; + } +} diff --git a/vendor/guzzle/guzzle/src/Guzzle/Parser/Url/UrlParserInterface.php b/vendor/guzzle/guzzle/src/Guzzle/Parser/Url/UrlParserInterface.php new file mode 100644 index 0000000..89ac4b3 --- /dev/null +++ b/vendor/guzzle/guzzle/src/Guzzle/Parser/Url/UrlParserInterface.php @@ -0,0 +1,19 @@ +=5.3.2" + }, + "autoload": { + "psr-0": { "Guzzle\\Parser": "" } + }, + "target-dir": "Guzzle/Parser", + "extra": { + "branch-alias": { + "dev-master": "3.7-dev" + } + } +} diff --git a/vendor/guzzle/guzzle/src/Guzzle/Plugin/Async/AsyncPlugin.php b/vendor/guzzle/guzzle/src/Guzzle/Plugin/Async/AsyncPlugin.php new file mode 100644 index 0000000..ae59418 --- /dev/null +++ b/vendor/guzzle/guzzle/src/Guzzle/Plugin/Async/AsyncPlugin.php @@ -0,0 +1,84 @@ + 'onBeforeSend', + 'request.exception' => 'onRequestTimeout', + 'request.sent' => 'onRequestSent', + 'curl.callback.progress' => 'onCurlProgress' + ); + } + + /** + * Event used to ensure that progress callback are emitted from the curl handle's request mediator. + * + * @param Event $event + */ + public function onBeforeSend(Event $event) + { + // Ensure that progress callbacks are dispatched + $event['request']->getCurlOptions()->set('progress', true); + } + + /** + * Event emitted when a curl progress function is called. When the amount of data uploaded == the amount of data to + * upload OR any bytes have been downloaded, then time the request out after 1ms because we're done with + * transmitting the request, and tell curl not download a body. + * + * @param Event $event + */ + public function onCurlProgress(Event $event) + { + if ($event['handle'] && + ($event['downloaded'] || (isset($event['uploaded']) && $event['upload_size'] === $event['uploaded'])) + ) { + // Timeout after 1ms + curl_setopt($event['handle'], CURLOPT_TIMEOUT_MS, 1); + // Even if the response is quick, tell curl not to download the body. + // - Note that we can only perform this shortcut if the request transmitted a body so as to ensure that the + // request method is not converted to a HEAD request before the request was sent via curl. + if ($event['uploaded']) { + curl_setopt($event['handle'], CURLOPT_NOBODY, true); + } + } + } + + /** + * Event emitted when a curl exception occurs. Ignore the exception and set a mock response. + * + * @param Event $event + */ + public function onRequestTimeout(Event $event) + { + if ($event['exception'] instanceof CurlException) { + $event['request']->setResponse(new Response(200, array( + 'X-Guzzle-Async' => 'Did not wait for the response' + ))); + } + } + + /** + * Event emitted when a request completes because it took less than 1ms. Add an X-Guzzle-Async header to notify the + * caller that there is no body in the message. + * + * @param Event $event + */ + public function onRequestSent(Event $event) + { + // Let the caller know this was meant to be async + $event['request']->getResponse()->setHeader('X-Guzzle-Async', 'Did not wait for the response'); + } +} diff --git a/vendor/guzzle/guzzle/src/Guzzle/Plugin/Async/composer.json b/vendor/guzzle/guzzle/src/Guzzle/Plugin/Async/composer.json new file mode 100644 index 0000000..dc3fc5b --- /dev/null +++ b/vendor/guzzle/guzzle/src/Guzzle/Plugin/Async/composer.json @@ -0,0 +1,27 @@ +{ + "name": "guzzle/plugin-async", + "description": "Guzzle async request plugin", + "homepage": "http://guzzlephp.org/", + "keywords": ["plugin", "guzzle"], + "license": "MIT", + "authors": [ + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + } + ], + "require": { + "php": ">=5.3.2", + "guzzle/http": "self.version" + }, + "autoload": { + "psr-0": { "Guzzle\\Plugin\\Async": "" } + }, + "target-dir": "Guzzle/Plugin/Async", + "extra": { + "branch-alias": { + "dev-master": "3.7-dev" + } + } +} diff --git a/vendor/guzzle/guzzle/src/Guzzle/Plugin/Backoff/AbstractBackoffStrategy.php b/vendor/guzzle/guzzle/src/Guzzle/Plugin/Backoff/AbstractBackoffStrategy.php new file mode 100644 index 0000000..0a85983 --- /dev/null +++ b/vendor/guzzle/guzzle/src/Guzzle/Plugin/Backoff/AbstractBackoffStrategy.php @@ -0,0 +1,91 @@ +next = $next; + } + + /** + * Get the next backoff strategy in the chain + * + * @return AbstractBackoffStrategy|null + */ + public function getNext() + { + return $this->next; + } + + public function getBackoffPeriod( + $retries, + RequestInterface $request, + Response $response = null, + HttpException $e = null + ) { + $delay = $this->getDelay($retries, $request, $response, $e); + if ($delay === false) { + // The strategy knows that this must not be retried + return false; + } elseif ($delay === null) { + // If the strategy is deferring a decision and the next strategy will not make a decision then return false + return !$this->next || !$this->next->makesDecision() + ? false + : $this->next->getBackoffPeriod($retries, $request, $response, $e); + } elseif ($delay === true) { + // if the strategy knows that it must retry but is deferring to the next to determine the delay + if (!$this->next) { + return 0; + } else { + $next = $this->next; + while ($next->makesDecision() && $next->getNext()) { + $next = $next->getNext(); + } + return !$next->makesDecision() ? $next->getBackoffPeriod($retries, $request, $response, $e) : 0; + } + } else { + return $delay; + } + } + + /** + * Check if the strategy does filtering and makes decisions on whether or not to retry. + * + * Strategies that return false will never retry if all of the previous strategies in a chain defer on a backoff + * decision. + * + * @return bool + */ + abstract public function makesDecision(); + + /** + * Implement the concrete strategy + * + * @param int $retries Number of retries of the request + * @param RequestInterface $request Request that was sent + * @param Response $response Response that was received. Note that there may not be a response + * @param HttpException $e Exception that was encountered if any + * + * @return bool|int|null Returns false to not retry or the number of seconds to delay between retries. Return true + * or null to defer to the next strategy if available, and if not, return 0. + */ + abstract protected function getDelay( + $retries, + RequestInterface $request, + Response $response = null, + HttpException $e = null + ); +} diff --git a/vendor/guzzle/guzzle/src/Guzzle/Plugin/Backoff/AbstractErrorCodeBackoffStrategy.php b/vendor/guzzle/guzzle/src/Guzzle/Plugin/Backoff/AbstractErrorCodeBackoffStrategy.php new file mode 100644 index 0000000..6ebee6c --- /dev/null +++ b/vendor/guzzle/guzzle/src/Guzzle/Plugin/Backoff/AbstractErrorCodeBackoffStrategy.php @@ -0,0 +1,40 @@ +errorCodes = array_fill_keys($codes ?: static::$defaultErrorCodes, 1); + $this->next = $next; + } + + /** + * Get the default failure codes to retry + * + * @return array + */ + public static function getDefaultFailureCodes() + { + return static::$defaultErrorCodes; + } + + public function makesDecision() + { + return true; + } +} diff --git a/vendor/guzzle/guzzle/src/Guzzle/Plugin/Backoff/BackoffLogger.php b/vendor/guzzle/guzzle/src/Guzzle/Plugin/Backoff/BackoffLogger.php new file mode 100644 index 0000000..ec54c28 --- /dev/null +++ b/vendor/guzzle/guzzle/src/Guzzle/Plugin/Backoff/BackoffLogger.php @@ -0,0 +1,76 @@ +logger = $logger; + $this->formatter = $formatter ?: new MessageFormatter(self::DEFAULT_FORMAT); + } + + public static function getSubscribedEvents() + { + return array(BackoffPlugin::RETRY_EVENT => 'onRequestRetry'); + } + + /** + * Set the template to use for logging + * + * @param string $template Log message template + * + * @return self + */ + public function setTemplate($template) + { + $this->formatter->setTemplate($template); + + return $this; + } + + /** + * Called when a request is being retried + * + * @param Event $event Event emitted + */ + public function onRequestRetry(Event $event) + { + $this->logger->log($this->formatter->format( + $event['request'], + $event['response'], + $event['handle'], + array( + 'retries' => $event['retries'], + 'delay' => $event['delay'] + ) + )); + } +} diff --git a/vendor/guzzle/guzzle/src/Guzzle/Plugin/Backoff/BackoffPlugin.php b/vendor/guzzle/guzzle/src/Guzzle/Plugin/Backoff/BackoffPlugin.php new file mode 100644 index 0000000..99ace05 --- /dev/null +++ b/vendor/guzzle/guzzle/src/Guzzle/Plugin/Backoff/BackoffPlugin.php @@ -0,0 +1,126 @@ +strategy = $strategy; + } + + /** + * Retrieve a basic truncated exponential backoff plugin that will retry HTTP errors and cURL errors + * + * @param int $maxRetries Maximum number of retries + * @param array $httpCodes HTTP response codes to retry + * @param array $curlCodes cURL error codes to retry + * + * @return self + */ + public static function getExponentialBackoff( + $maxRetries = 3, + array $httpCodes = null, + array $curlCodes = null + ) { + return new self(new TruncatedBackoffStrategy($maxRetries, + new HttpBackoffStrategy($httpCodes, + new CurlBackoffStrategy($curlCodes, + new ExponentialBackoffStrategy() + ) + ) + )); + } + + public static function getAllEvents() + { + return array(self::RETRY_EVENT); + } + + public static function getSubscribedEvents() + { + return array( + 'request.sent' => 'onRequestSent', + 'request.exception' => 'onRequestSent', + CurlMultiInterface::POLLING_REQUEST => 'onRequestPoll' + ); + } + + /** + * Called when a request has been sent and isn't finished processing + * + * @param Event $event + */ + public function onRequestSent(Event $event) + { + $request = $event['request']; + $response = $event['response']; + $exception = $event['exception']; + + $params = $request->getParams(); + $retries = (int) $params->get(self::RETRY_PARAM); + $delay = $this->strategy->getBackoffPeriod($retries, $request, $response, $exception); + + if ($delay !== false) { + // Calculate how long to wait until the request should be retried + $params->set(self::RETRY_PARAM, ++$retries) + ->set(self::DELAY_PARAM, microtime(true) + $delay); + // Send the request again + $request->setState(RequestInterface::STATE_TRANSFER); + $this->dispatch(self::RETRY_EVENT, array( + 'request' => $request, + 'response' => $response, + 'handle' => ($exception && $exception instanceof CurlException) ? $exception->getCurlHandle() : null, + 'retries' => $retries, + 'delay' => $delay + )); + } + } + + /** + * Called when a request is polling in the curl multi object + * + * @param Event $event + */ + public function onRequestPoll(Event $event) + { + $request = $event['request']; + $delay = $request->getParams()->get(self::DELAY_PARAM); + + // If the duration of the delay has passed, retry the request using the pool + if (null !== $delay && microtime(true) >= $delay) { + // Remove the request from the pool and then add it back again. This is required for cURL to know that we + // want to retry sending the easy handle. + $request->getParams()->remove(self::DELAY_PARAM); + // Rewind the request body if possible + if ($request instanceof EntityEnclosingRequestInterface && $request->getBody()) { + $request->getBody()->seek(0); + } + $multi = $event['curl_multi']; + $multi->remove($request); + $multi->add($request); + } + } +} diff --git a/vendor/guzzle/guzzle/src/Guzzle/Plugin/Backoff/BackoffStrategyInterface.php b/vendor/guzzle/guzzle/src/Guzzle/Plugin/Backoff/BackoffStrategyInterface.php new file mode 100644 index 0000000..4e590db --- /dev/null +++ b/vendor/guzzle/guzzle/src/Guzzle/Plugin/Backoff/BackoffStrategyInterface.php @@ -0,0 +1,30 @@ +callback = $callback; + $this->decision = (bool) $decision; + $this->next = $next; + } + + public function makesDecision() + { + return $this->decision; + } + + protected function getDelay($retries, RequestInterface $request, Response $response = null, HttpException $e = null) + { + return call_user_func($this->callback, $retries, $request, $response, $e); + } +} diff --git a/vendor/guzzle/guzzle/src/Guzzle/Plugin/Backoff/ConstantBackoffStrategy.php b/vendor/guzzle/guzzle/src/Guzzle/Plugin/Backoff/ConstantBackoffStrategy.php new file mode 100644 index 0000000..061d2a4 --- /dev/null +++ b/vendor/guzzle/guzzle/src/Guzzle/Plugin/Backoff/ConstantBackoffStrategy.php @@ -0,0 +1,34 @@ +delay = $delay; + } + + public function makesDecision() + { + return false; + } + + protected function getDelay($retries, RequestInterface $request, Response $response = null, HttpException $e = null) + { + return $this->delay; + } +} diff --git a/vendor/guzzle/guzzle/src/Guzzle/Plugin/Backoff/CurlBackoffStrategy.php b/vendor/guzzle/guzzle/src/Guzzle/Plugin/Backoff/CurlBackoffStrategy.php new file mode 100644 index 0000000..a584ed4 --- /dev/null +++ b/vendor/guzzle/guzzle/src/Guzzle/Plugin/Backoff/CurlBackoffStrategy.php @@ -0,0 +1,28 @@ +errorCodes[$e->getErrorNo()]) ? true : null; + } + } +} diff --git a/vendor/guzzle/guzzle/src/Guzzle/Plugin/Backoff/ExponentialBackoffStrategy.php b/vendor/guzzle/guzzle/src/Guzzle/Plugin/Backoff/ExponentialBackoffStrategy.php new file mode 100644 index 0000000..fb2912d --- /dev/null +++ b/vendor/guzzle/guzzle/src/Guzzle/Plugin/Backoff/ExponentialBackoffStrategy.php @@ -0,0 +1,25 @@ +isSuccessful()) { + return false; + } else { + return isset($this->errorCodes[$response->getStatusCode()]) ? true : null; + } + } + } +} diff --git a/vendor/guzzle/guzzle/src/Guzzle/Plugin/Backoff/LinearBackoffStrategy.php b/vendor/guzzle/guzzle/src/Guzzle/Plugin/Backoff/LinearBackoffStrategy.php new file mode 100644 index 0000000..b35e8a4 --- /dev/null +++ b/vendor/guzzle/guzzle/src/Guzzle/Plugin/Backoff/LinearBackoffStrategy.php @@ -0,0 +1,36 @@ +step = $step; + } + + public function makesDecision() + { + return false; + } + + protected function getDelay($retries, RequestInterface $request, Response $response = null, HttpException $e = null) + { + return $retries * $this->step; + } +} diff --git a/vendor/guzzle/guzzle/src/Guzzle/Plugin/Backoff/ReasonPhraseBackoffStrategy.php b/vendor/guzzle/guzzle/src/Guzzle/Plugin/Backoff/ReasonPhraseBackoffStrategy.php new file mode 100644 index 0000000..4fd73fe --- /dev/null +++ b/vendor/guzzle/guzzle/src/Guzzle/Plugin/Backoff/ReasonPhraseBackoffStrategy.php @@ -0,0 +1,25 @@ +errorCodes[$response->getReasonPhrase()]) ? true : null; + } + } +} diff --git a/vendor/guzzle/guzzle/src/Guzzle/Plugin/Backoff/TruncatedBackoffStrategy.php b/vendor/guzzle/guzzle/src/Guzzle/Plugin/Backoff/TruncatedBackoffStrategy.php new file mode 100644 index 0000000..3608f35 --- /dev/null +++ b/vendor/guzzle/guzzle/src/Guzzle/Plugin/Backoff/TruncatedBackoffStrategy.php @@ -0,0 +1,36 @@ +max = $maxRetries; + $this->next = $next; + } + + public function makesDecision() + { + return true; + } + + protected function getDelay($retries, RequestInterface $request, Response $response = null, HttpException $e = null) + { + return $retries < $this->max ? null : false; + } +} diff --git a/vendor/guzzle/guzzle/src/Guzzle/Plugin/Backoff/composer.json b/vendor/guzzle/guzzle/src/Guzzle/Plugin/Backoff/composer.json new file mode 100644 index 0000000..91c122c --- /dev/null +++ b/vendor/guzzle/guzzle/src/Guzzle/Plugin/Backoff/composer.json @@ -0,0 +1,28 @@ +{ + "name": "guzzle/plugin-backoff", + "description": "Guzzle backoff retry plugins", + "homepage": "http://guzzlephp.org/", + "keywords": ["plugin", "guzzle"], + "license": "MIT", + "authors": [ + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + } + ], + "require": { + "php": ">=5.3.2", + "guzzle/http": "self.version", + "guzzle/log": "self.version" + }, + "autoload": { + "psr-0": { "Guzzle\\Plugin\\Backoff": "" } + }, + "target-dir": "Guzzle/Plugin/Backoff", + "extra": { + "branch-alias": { + "dev-master": "3.7-dev" + } + } +} diff --git a/vendor/guzzle/guzzle/src/Guzzle/Plugin/Cache/CacheKeyProviderInterface.php b/vendor/guzzle/guzzle/src/Guzzle/Plugin/Cache/CacheKeyProviderInterface.php new file mode 100644 index 0000000..7790f88 --- /dev/null +++ b/vendor/guzzle/guzzle/src/Guzzle/Plugin/Cache/CacheKeyProviderInterface.php @@ -0,0 +1,11 @@ + new DefaultCacheStorage($options)); + } elseif ($options instanceof CacheStorageInterface) { + $options = array('storage' => $options); + } elseif ($options) { + $options = array('storage' => new DefaultCacheStorage(CacheAdapterFactory::fromCache($options))); + } elseif (!class_exists('Doctrine\Common\Cache\ArrayCache')) { + // @codeCoverageIgnoreStart + throw new InvalidArgumentException('No cache was provided and Doctrine is not installed'); + // @codeCoverageIgnoreEnd + } + } + + $this->autoPurge = isset($options['auto_purge']) ? $options['auto_purge'] : false; + + // Add a cache storage if a cache adapter was provided + $this->storage = isset($options['storage']) + ? $options['storage'] + : new DefaultCacheStorage(new DoctrineCacheAdapter(new ArrayCache())); + + if (!isset($options['can_cache'])) { + $this->canCache = new DefaultCanCacheStrategy(); + } else { + $this->canCache = is_callable($options['can_cache']) + ? new CallbackCanCacheStrategy($options['can_cache']) + : $options['can_cache']; + } + + // Use the provided revalidation strategy or the default + $this->revalidation = isset($options['revalidation']) + ? $options['revalidation'] + : new DefaultRevalidation($this->storage, $this->canCache); + } + + public static function getSubscribedEvents() + { + return array( + 'request.before_send' => array('onRequestBeforeSend', -255), + 'request.sent' => array('onRequestSent', 255), + 'request.error' => array('onRequestError', 0), + 'request.exception' => array('onRequestException', 0), + ); + } + + /** + * Check if a response in cache will satisfy the request before sending + * + * @param Event $event + */ + public function onRequestBeforeSend(Event $event) + { + $request = $event['request']; + $request->addHeader('Via', sprintf('%s GuzzleCache/%s', $request->getProtocolVersion(), Version::VERSION)); + + if (!$this->canCache->canCacheRequest($request)) { + switch ($request->getMethod()) { + case 'PURGE': + $this->purge($request); + $request->setResponse(new Response(200, array(), 'purged')); + break; + case 'PUT': + case 'POST': + case 'DELETE': + case 'PATCH': + if ($this->autoPurge) { + $this->purge($request); + } + } + return; + } + + if ($response = $this->storage->fetch($request)) { + $params = $request->getParams(); + $params['cache.lookup'] = true; + $response->setHeader( + 'Age', + time() - strtotime($response->getDate() ? : $response->getLastModified() ?: 'now') + ); + // Validate that the response satisfies the request + if ($this->canResponseSatisfyRequest($request, $response)) { + if (!isset($params['cache.hit'])) { + $params['cache.hit'] = true; + } + $request->setResponse($response); + } + } + } + + /** + * If possible, store a response in cache after sending + * + * @param Event $event + */ + public function onRequestSent(Event $event) + { + $request = $event['request']; + $response = $event['response']; + + if ($request->getParams()->get('cache.hit') === null && + $this->canCache->canCacheRequest($request) && + $this->canCache->canCacheResponse($response) + ) { + $this->storage->cache($request, $response); + } + + $this->addResponseHeaders($request, $response); + } + + /** + * If possible, return a cache response on an error + * + * @param Event $event + */ + public function onRequestError(Event $event) + { + $request = $event['request']; + + if (!$this->canCache->canCacheRequest($request)) { + return; + } + + if ($response = $this->storage->fetch($request)) { + $response->setHeader( + 'Age', + time() - strtotime($response->getLastModified() ? : $response->getDate() ?: 'now') + ); + + if ($this->canResponseSatisfyFailedRequest($request, $response)) { + $request->getParams()->set('cache.hit', 'error'); + $this->addResponseHeaders($request, $response); + $event['response'] = $response; + $event->stopPropagation(); + } + } + } + + /** + * If possible, set a cache response on a cURL exception + * + * @param Event $event + * + * @return null + */ + public function onRequestException(Event $event) + { + if (!$event['exception'] instanceof CurlException) { + return; + } + + $request = $event['request']; + if (!$this->canCache->canCacheRequest($request)) { + return; + } + + if ($response = $this->storage->fetch($request)) { + $response->setHeader('Age', time() - strtotime($response->getDate() ? : 'now')); + if (!$this->canResponseSatisfyFailedRequest($request, $response)) { + return; + } + $request->getParams()->set('cache.hit', 'error'); + $request->setResponse($response); + $this->addResponseHeaders($request, $response); + $event->stopPropagation(); + } + } + + /** + * Check if a cache response satisfies a request's caching constraints + * + * @param RequestInterface $request Request to validate + * @param Response $response Response to validate + * + * @return bool + */ + public function canResponseSatisfyRequest(RequestInterface $request, Response $response) + { + $responseAge = $response->calculateAge(); + $reqc = $request->getHeader('Cache-Control'); + $resc = $response->getHeader('Cache-Control'); + + // Check the request's max-age header against the age of the response + if ($reqc && $reqc->hasDirective('max-age') && + $responseAge > $reqc->getDirective('max-age')) { + return false; + } + + // Check the response's max-age header + if ($response->isFresh() === false) { + $maxStale = $reqc ? $reqc->getDirective('max-stale') : null; + if (null !== $maxStale) { + if ($maxStale !== true && $response->getFreshness() < (-1 * $maxStale)) { + return false; + } + } elseif ($resc && $resc->hasDirective('max-age') + && $responseAge > $resc->getDirective('max-age') + ) { + return false; + } + } + + if ($this->revalidation->shouldRevalidate($request, $response)) { + try { + return $this->revalidation->revalidate($request, $response); + } catch (CurlException $e) { + $request->getParams()->set('cache.hit', 'error'); + return $this->canResponseSatisfyFailedRequest($request, $response); + } + } + + return true; + } + + /** + * Check if a cache response satisfies a failed request's caching constraints + * + * @param RequestInterface $request Request to validate + * @param Response $response Response to validate + * + * @return bool + */ + public function canResponseSatisfyFailedRequest(RequestInterface $request, Response $response) + { + $reqc = $request->getHeader('Cache-Control'); + $resc = $response->getHeader('Cache-Control'); + $requestStaleIfError = $reqc ? $reqc->getDirective('stale-if-error') : null; + $responseStaleIfError = $resc ? $resc->getDirective('stale-if-error') : null; + + if (!$requestStaleIfError && !$responseStaleIfError) { + return false; + } + + if (is_numeric($requestStaleIfError) && $response->getAge() - $response->getMaxAge() > $requestStaleIfError) { + return false; + } + + if (is_numeric($responseStaleIfError) && $response->getAge() - $response->getMaxAge() > $responseStaleIfError) { + return false; + } + + return true; + } + + /** + * Purge all cache entries for a given URL + * + * @param string $url URL to purge + */ + public function purge($url) + { + // BC compatibility with previous version that accepted a Request object + $url = $url instanceof RequestInterface ? $url->getUrl() : $url; + $this->storage->purge($url); + } + + /** + * Add the plugin's headers to a response + * + * @param RequestInterface $request Request + * @param Response $response Response to add headers to + */ + protected function addResponseHeaders(RequestInterface $request, Response $response) + { + $params = $request->getParams(); + $response->setHeader('Via', sprintf('%s GuzzleCache/%s', $request->getProtocolVersion(), Version::VERSION)); + + $lookup = ($params['cache.lookup'] === true ? 'HIT' : 'MISS') . ' from GuzzleCache'; + if ($header = $response->getHeader('X-Cache-Lookup')) { + // Don't add duplicates + $values = $header->toArray(); + $values[] = $lookup; + $response->setHeader('X-Cache-Lookup', array_unique($values)); + } else { + $response->setHeader('X-Cache-Lookup', $lookup); + } + + if ($params['cache.hit'] === true) { + $xcache = 'HIT from GuzzleCache'; + } elseif ($params['cache.hit'] == 'error') { + $xcache = 'HIT_ERROR from GuzzleCache'; + } else { + $xcache = 'MISS from GuzzleCache'; + } + + if ($header = $response->getHeader('X-Cache')) { + // Don't add duplicates + $values = $header->toArray(); + $values[] = $xcache; + $response->setHeader('X-Cache', array_unique($values)); + } else { + $response->setHeader('X-Cache', $xcache); + } + + if ($response->isFresh() === false) { + $response->addHeader('Warning', sprintf('110 GuzzleCache/%s "Response is stale"', Version::VERSION)); + if ($params['cache.hit'] === 'error') { + $response->addHeader('Warning', sprintf('111 GuzzleCache/%s "Revalidation failed"', Version::VERSION)); + } + } + } +} diff --git a/vendor/guzzle/guzzle/src/Guzzle/Plugin/Cache/CacheStorageInterface.php b/vendor/guzzle/guzzle/src/Guzzle/Plugin/Cache/CacheStorageInterface.php new file mode 100644 index 0000000..f3d9154 --- /dev/null +++ b/vendor/guzzle/guzzle/src/Guzzle/Plugin/Cache/CacheStorageInterface.php @@ -0,0 +1,43 @@ +requestCallback = $requestCallback; + $this->responseCallback = $responseCallback; + } + + public function canCacheRequest(RequestInterface $request) + { + return $this->requestCallback + ? call_user_func($this->requestCallback, $request) + : parent::canCacheRequest($request); + } + + public function canCacheResponse(Response $response) + { + return $this->responseCallback + ? call_user_func($this->responseCallback, $response) + : parent::canCacheResponse($response); + } +} diff --git a/vendor/guzzle/guzzle/src/Guzzle/Plugin/Cache/CanCacheStrategyInterface.php b/vendor/guzzle/guzzle/src/Guzzle/Plugin/Cache/CanCacheStrategyInterface.php new file mode 100644 index 0000000..6e01a8e --- /dev/null +++ b/vendor/guzzle/guzzle/src/Guzzle/Plugin/Cache/CanCacheStrategyInterface.php @@ -0,0 +1,30 @@ +getParams()->get(self::CACHE_KEY); + + if (!$key) { + + $cloned = clone $request; + $cloned->removeHeader('Cache-Control'); + + // Check to see how and if the key should be filtered + foreach (explode(';', $request->getParams()->get(self::CACHE_KEY_FILTER)) as $part) { + $pieces = array_map('trim', explode('=', $part)); + if (isset($pieces[1])) { + foreach (array_map('trim', explode(',', $pieces[1])) as $remove) { + if ($pieces[0] == 'header') { + $cloned->removeHeader($remove); + } elseif ($pieces[0] == 'query') { + $cloned->getQuery()->remove($remove); + } + } + } + } + + $raw = (string) $cloned; + $key = 'GZ' . md5($raw); + $request->getParams()->set(self::CACHE_KEY, $key)->set(self::CACHE_KEY_RAW, $raw); + } + + return $key; + } +} diff --git a/vendor/guzzle/guzzle/src/Guzzle/Plugin/Cache/DefaultCacheStorage.php b/vendor/guzzle/guzzle/src/Guzzle/Plugin/Cache/DefaultCacheStorage.php new file mode 100644 index 0000000..26d7a8b --- /dev/null +++ b/vendor/guzzle/guzzle/src/Guzzle/Plugin/Cache/DefaultCacheStorage.php @@ -0,0 +1,266 @@ +cache = CacheAdapterFactory::fromCache($cache); + $this->defaultTtl = $defaultTtl; + $this->keyPrefix = $keyPrefix; + } + + public function cache(RequestInterface $request, Response $response) + { + $currentTime = time(); + + $overrideTtl = $request->getParams()->get('cache.override_ttl'); + if ($overrideTtl) { + $ttl = $overrideTtl; + } else { + $maxAge = $response->getMaxAge(); + if ($maxAge !== null) { + $ttl = $maxAge; + } else { + $ttl = $this->defaultTtl; + } + } + + if ($cacheControl = $response->getHeader('Cache-Control')) { + $stale = $cacheControl->getDirective('stale-if-error'); + if ($stale === true) { + $ttl += $ttl; + } else if (is_numeric($stale)) { + $ttl += $stale; + } + } + + // Determine which manifest key should be used + $key = $this->getCacheKey($request); + $persistedRequest = $this->persistHeaders($request); + $entries = array(); + + if ($manifest = $this->cache->fetch($key)) { + // Determine which cache entries should still be in the cache + $vary = $response->getVary(); + foreach (unserialize($manifest) as $entry) { + // Check if the entry is expired + if ($entry[4] < $currentTime) { + continue; + } + $entry[1]['vary'] = isset($entry[1]['vary']) ? $entry[1]['vary'] : ''; + if ($vary != $entry[1]['vary'] || !$this->requestsMatch($vary, $entry[0], $persistedRequest)) { + $entries[] = $entry; + } + } + } + + // Persist the response body if needed + $bodyDigest = null; + if ($response->getBody() && $response->getBody()->getContentLength() > 0) { + $bodyDigest = $this->getBodyKey($request->getUrl(), $response->getBody()); + $this->cache->save($bodyDigest, (string) $response->getBody(), $ttl); + } + + array_unshift($entries, array( + $persistedRequest, + $this->persistHeaders($response), + $response->getStatusCode(), + $bodyDigest, + $currentTime + $ttl + )); + + $this->cache->save($key, serialize($entries)); + } + + public function delete(RequestInterface $request) + { + $key = $this->getCacheKey($request); + if ($entries = $this->cache->fetch($key)) { + // Delete each cached body + foreach (unserialize($entries) as $entry) { + if ($entry[3]) { + $this->cache->delete($entry[3]); + } + } + $this->cache->delete($key); + } + } + + public function purge($url) + { + foreach (array('GET', 'HEAD', 'POST', 'PUT', 'DELETE') as $method) { + $this->delete(new Request($method, $url)); + } + } + + public function fetch(RequestInterface $request) + { + $key = $this->getCacheKey($request); + if (!($entries = $this->cache->fetch($key))) { + return null; + } + + $match = null; + $headers = $this->persistHeaders($request); + $entries = unserialize($entries); + foreach ($entries as $index => $entry) { + if ($this->requestsMatch(isset($entry[1]['vary']) ? $entry[1]['vary'] : '', $headers, $entry[0])) { + $match = $entry; + break; + } + } + + if (!$match) { + return null; + } + + // Ensure that the response is not expired + $response = null; + if ($match[4] < time()) { + $response = -1; + } else { + $response = new Response($match[2], $match[1]); + if ($match[3]) { + if ($body = $this->cache->fetch($match[3])) { + $response->setBody($body); + } else { + // The response is not valid because the body was somehow deleted + $response = -1; + } + } + } + + if ($response === -1) { + // Remove the entry from the metadata and update the cache + unset($entries[$index]); + if ($entries) { + $this->cache->save($key, serialize($entries)); + } else { + $this->cache->delete($key); + } + return null; + } + + return $response; + } + + /** + * Hash a request URL into a string that returns cache metadata + * + * @param RequestInterface $request + * + * @return string + */ + protected function getCacheKey(RequestInterface $request) + { + // Allow cache.key_filter to trim down the URL cache key by removing generate query string values (e.g. auth) + if ($filter = $request->getParams()->get('cache.key_filter')) { + $url = $request->getUrl(true); + foreach (explode(',', $filter) as $remove) { + $url->getQuery()->remove(trim($remove)); + } + } else { + $url = $request->getUrl(); + } + + return $this->keyPrefix . md5($request->getMethod() . ' ' . $url); + } + + /** + * Create a cache key for a response's body + * + * @param string $url URL of the entry + * @param EntityBodyInterface $body Response body + * + * @return string + */ + protected function getBodyKey($url, EntityBodyInterface $body) + { + return $this->keyPrefix . md5($url) . $body->getContentMd5(); + } + + /** + * Determines whether two Request HTTP header sets are non-varying + * + * @param string $vary Response vary header + * @param array $r1 HTTP header array + * @param array $r2 HTTP header array + * + * @return bool + */ + private function requestsMatch($vary, $r1, $r2) + { + if ($vary) { + foreach (explode(',', $vary) as $header) { + $key = trim(strtolower($header)); + $v1 = isset($r1[$key]) ? $r1[$key] : null; + $v2 = isset($r2[$key]) ? $r2[$key] : null; + if ($v1 !== $v2) { + return false; + } + } + } + + return true; + } + + /** + * Creates an array of cacheable and normalized message headers + * + * @param MessageInterface $message + * + * @return array + */ + private function persistHeaders(MessageInterface $message) + { + // Headers are excluded from the caching (see RFC 2616:13.5.1) + static $noCache = array( + 'age' => true, + 'connection' => true, + 'keep-alive' => true, + 'proxy-authenticate' => true, + 'proxy-authorization' => true, + 'te' => true, + 'trailers' => true, + 'transfer-encoding' => true, + 'upgrade' => true, + 'set-cookie' => true, + 'set-cookie2' => true + ); + + // Clone the response to not destroy any necessary headers when caching + $headers = $message->getHeaders()->getAll(); + $headers = array_diff_key($headers, $noCache); + // Cast the headers to a string + $headers = array_map(function ($h) { return (string) $h; }, $headers); + + return $headers; + } +} diff --git a/vendor/guzzle/guzzle/src/Guzzle/Plugin/Cache/DefaultCanCacheStrategy.php b/vendor/guzzle/guzzle/src/Guzzle/Plugin/Cache/DefaultCanCacheStrategy.php new file mode 100644 index 0000000..3ca1fbf --- /dev/null +++ b/vendor/guzzle/guzzle/src/Guzzle/Plugin/Cache/DefaultCanCacheStrategy.php @@ -0,0 +1,32 @@ +getMethod() != RequestInterface::GET && $request->getMethod() != RequestInterface::HEAD) { + return false; + } + + // Never cache requests when using no-store + if ($request->hasHeader('Cache-Control') && $request->getHeader('Cache-Control')->hasDirective('no-store')) { + return false; + } + + return true; + } + + public function canCacheResponse(Response $response) + { + return $response->isSuccessful() && $response->canCache(); + } +} diff --git a/vendor/guzzle/guzzle/src/Guzzle/Plugin/Cache/DefaultRevalidation.php b/vendor/guzzle/guzzle/src/Guzzle/Plugin/Cache/DefaultRevalidation.php new file mode 100644 index 0000000..af33234 --- /dev/null +++ b/vendor/guzzle/guzzle/src/Guzzle/Plugin/Cache/DefaultRevalidation.php @@ -0,0 +1,174 @@ +storage = $cache; + $this->canCache = $canCache ?: new DefaultCanCacheStrategy(); + } + + public function revalidate(RequestInterface $request, Response $response) + { + try { + $revalidate = $this->createRevalidationRequest($request, $response); + $validateResponse = $revalidate->send(); + if ($validateResponse->getStatusCode() == 200) { + return $this->handle200Response($request, $validateResponse); + } elseif ($validateResponse->getStatusCode() == 304) { + return $this->handle304Response($request, $validateResponse, $response); + } + } catch (BadResponseException $e) { + $this->handleBadResponse($e); + } + + // Other exceptions encountered in the revalidation request are ignored + // in hopes that sending a request to the origin server will fix it + return false; + } + + public function shouldRevalidate(RequestInterface $request, Response $response) + { + if ($request->getMethod() != RequestInterface::GET) { + return false; + } + + $reqCache = $request->getHeader('Cache-Control'); + $resCache = $response->getHeader('Cache-Control'); + + $revalidate = $request->getHeader('Pragma') == 'no-cache' || + ($reqCache && ($reqCache->hasDirective('no-cache') || $reqCache->hasDirective('must-revalidate'))) || + ($resCache && ($resCache->hasDirective('no-cache') || $resCache->hasDirective('must-revalidate'))); + + // Use the strong ETag validator if available and the response contains no Cache-Control directive + if (!$revalidate && !$resCache && $response->hasHeader('ETag')) { + $revalidate = true; + } + + return $revalidate; + } + + /** + * Handles a bad response when attempting to revalidate + * + * @param BadResponseException $e Exception encountered + * + * @throws BadResponseException + */ + protected function handleBadResponse(BadResponseException $e) + { + // 404 errors mean the resource no longer exists, so remove from + // cache, and prevent an additional request by throwing the exception + if ($e->getResponse()->getStatusCode() == 404) { + $this->storage->delete($e->getRequest()); + throw $e; + } + } + + /** + * Creates a request to use for revalidation + * + * @param RequestInterface $request Request + * @param Response $response Response to revalidate + * + * @return RequestInterface returns a revalidation request + */ + protected function createRevalidationRequest(RequestInterface $request, Response $response) + { + $revalidate = clone $request; + $revalidate->removeHeader('Pragma')->removeHeader('Cache-Control'); + + if ($response->getLastModified()) { + $revalidate->setHeader('If-Modified-Since', $response->getLastModified()); + } + + if ($response->getEtag()) { + $revalidate->setHeader('If-None-Match', $response->getEtag()); + } + + // Remove any cache plugins that might be on the request to prevent infinite recursive revalidations + $dispatcher = $revalidate->getEventDispatcher(); + foreach ($dispatcher->getListeners() as $eventName => $listeners) { + foreach ($listeners as $listener) { + if (is_array($listener) && $listener[0] instanceof CachePlugin) { + $dispatcher->removeListener($eventName, $listener); + } + } + } + + return $revalidate; + } + + /** + * Handles a 200 response response from revalidating. The server does not support validation, so use this response. + * + * @param RequestInterface $request Request that was sent + * @param Response $validateResponse Response received + * + * @return bool Returns true if valid, false if invalid + */ + protected function handle200Response(RequestInterface $request, Response $validateResponse) + { + $request->setResponse($validateResponse); + if ($this->canCache->canCacheResponse($validateResponse)) { + $this->storage->cache($request, $validateResponse); + } + + return false; + } + + /** + * Handle a 304 response and ensure that it is still valid + * + * @param RequestInterface $request Request that was sent + * @param Response $validateResponse Response received + * @param Response $response Original cached response + * + * @return bool Returns true if valid, false if invalid + */ + protected function handle304Response(RequestInterface $request, Response $validateResponse, Response $response) + { + static $replaceHeaders = array('Date', 'Expires', 'Cache-Control', 'ETag', 'Last-Modified'); + + // Make sure that this response has the same ETag + if ($validateResponse->getEtag() != $response->getEtag()) { + return false; + } + + // Replace cached headers with any of these headers from the + // origin server that might be more up to date + $modified = false; + foreach ($replaceHeaders as $name) { + if ($validateResponse->hasHeader($name)) { + $modified = true; + $response->setHeader($name, $validateResponse->getHeader($name)); + } + } + + // Store the updated response in cache + if ($modified && $this->canCache->canCacheResponse($response)) { + $this->storage->cache($request, $response); + } + + return true; + } +} diff --git a/vendor/guzzle/guzzle/src/Guzzle/Plugin/Cache/DenyRevalidation.php b/vendor/guzzle/guzzle/src/Guzzle/Plugin/Cache/DenyRevalidation.php new file mode 100644 index 0000000..88b86f3 --- /dev/null +++ b/vendor/guzzle/guzzle/src/Guzzle/Plugin/Cache/DenyRevalidation.php @@ -0,0 +1,19 @@ +=5.3.2", + "guzzle/http": "self.version", + "guzzle/cache": "self.version" + }, + "autoload": { + "psr-0": { "Guzzle\\Plugin\\Cache": "" } + }, + "target-dir": "Guzzle/Plugin/Cache", + "extra": { + "branch-alias": { + "dev-master": "3.7-dev" + } + } +} diff --git a/vendor/guzzle/guzzle/src/Guzzle/Plugin/Cookie/Cookie.php b/vendor/guzzle/guzzle/src/Guzzle/Plugin/Cookie/Cookie.php new file mode 100644 index 0000000..5218e5f --- /dev/null +++ b/vendor/guzzle/guzzle/src/Guzzle/Plugin/Cookie/Cookie.php @@ -0,0 +1,538 @@ + '', + 'value' => '', + 'domain' => '', + 'path' => '/', + 'expires' => null, + 'max_age' => 0, + 'comment' => null, + 'comment_url' => null, + 'port' => array(), + 'version' => null, + 'secure' => false, + 'discard' => false, + 'http_only' => false + ); + + $this->data = array_merge($defaults, $data); + // Extract the expires value and turn it into a UNIX timestamp if needed + if (!$this->getExpires() && $this->getMaxAge()) { + // Calculate the expires date + $this->setExpires(time() + (int) $this->getMaxAge()); + } elseif ($this->getExpires() && !is_numeric($this->getExpires())) { + $this->setExpires(strtotime($this->getExpires())); + } + } + + /** + * Get the cookie as an array + * + * @return array + */ + public function toArray() + { + return $this->data; + } + + /** + * Get the cookie name + * + * @return string + */ + public function getName() + { + return $this->data['name']; + } + + /** + * Set the cookie name + * + * @param string $name Cookie name + * + * @return Cookie + */ + public function setName($name) + { + return $this->setData('name', $name); + } + + /** + * Get the cookie value + * + * @return string + */ + public function getValue() + { + return $this->data['value']; + } + + /** + * Set the cookie value + * + * @param string $value Cookie value + * + * @return Cookie + */ + public function setValue($value) + { + return $this->setData('value', $value); + } + + /** + * Get the domain + * + * @return string|null + */ + public function getDomain() + { + return $this->data['domain']; + } + + /** + * Set the domain of the cookie + * + * @param string $domain + * + * @return Cookie + */ + public function setDomain($domain) + { + return $this->setData('domain', $domain); + } + + /** + * Get the path + * + * @return string + */ + public function getPath() + { + return $this->data['path']; + } + + /** + * Set the path of the cookie + * + * @param string $path Path of the cookie + * + * @return Cookie + */ + public function setPath($path) + { + return $this->setData('path', $path); + } + + /** + * Maximum lifetime of the cookie in seconds + * + * @return int|null + */ + public function getMaxAge() + { + return $this->data['max_age']; + } + + /** + * Set the max-age of the cookie + * + * @param int $maxAge Max age of the cookie in seconds + * + * @return Cookie + */ + public function setMaxAge($maxAge) + { + return $this->setData('max_age', $maxAge); + } + + /** + * The UNIX timestamp when the cookie expires + * + * @return mixed + */ + public function getExpires() + { + return $this->data['expires']; + } + + /** + * Set the unix timestamp for which the cookie will expire + * + * @param int $timestamp Unix timestamp + * + * @return Cookie + */ + public function setExpires($timestamp) + { + return $this->setData('expires', $timestamp); + } + + /** + * Version of the cookie specification. RFC 2965 is 1 + * + * @return mixed + */ + public function getVersion() + { + return $this->data['version']; + } + + /** + * Set the cookie version + * + * @param string|int $version Version to set + * + * @return Cookie + */ + public function setVersion($version) + { + return $this->setData('version', $version); + } + + /** + * Get whether or not this is a secure cookie + * + * @return null|bool + */ + public function getSecure() + { + return $this->data['secure']; + } + + /** + * Set whether or not the cookie is secure + * + * @param bool $secure Set to true or false if secure + * + * @return Cookie + */ + public function setSecure($secure) + { + return $this->setData('secure', (bool) $secure); + } + + /** + * Get whether or not this is a session cookie + * + * @return null|bool + */ + public function getDiscard() + { + return $this->data['discard']; + } + + /** + * Set whether or not this is a session cookie + * + * @param bool $discard Set to true or false if this is a session cookie + * + * @return Cookie + */ + public function setDiscard($discard) + { + return $this->setData('discard', $discard); + } + + /** + * Get the comment + * + * @return string|null + */ + public function getComment() + { + return $this->data['comment']; + } + + /** + * Set the comment of the cookie + * + * @param string $comment Cookie comment + * + * @return Cookie + */ + public function setComment($comment) + { + return $this->setData('comment', $comment); + } + + /** + * Get the comment URL of the cookie + * + * @return string|null + */ + public function getCommentUrl() + { + return $this->data['comment_url']; + } + + /** + * Set the comment URL of the cookie + * + * @param string $commentUrl Cookie comment URL for more information + * + * @return Cookie + */ + public function setCommentUrl($commentUrl) + { + return $this->setData('comment_url', $commentUrl); + } + + /** + * Get an array of acceptable ports this cookie can be used with + * + * @return array + */ + public function getPorts() + { + return $this->data['port']; + } + + /** + * Set a list of acceptable ports this cookie can be used with + * + * @param array $ports Array of acceptable ports + * + * @return Cookie + */ + public function setPorts(array $ports) + { + return $this->setData('port', $ports); + } + + /** + * Get whether or not this is an HTTP only cookie + * + * @return bool + */ + public function getHttpOnly() + { + return $this->data['http_only']; + } + + /** + * Set whether or not this is an HTTP only cookie + * + * @param bool $httpOnly Set to true or false if this is HTTP only + * + * @return Cookie + */ + public function setHttpOnly($httpOnly) + { + return $this->setData('http_only', $httpOnly); + } + + /** + * Get an array of extra cookie data + * + * @return array + */ + public function getAttributes() + { + return $this->data['data']; + } + + /** + * Get a specific data point from the extra cookie data + * + * @param string $name Name of the data point to retrieve + * + * @return null|string + */ + public function getAttribute($name) + { + return array_key_exists($name, $this->data['data']) ? $this->data['data'][$name] : null; + } + + /** + * Set a cookie data attribute + * + * @param string $name Name of the attribute to set + * @param string $value Value to set + * + * @return Cookie + */ + public function setAttribute($name, $value) + { + $this->data['data'][$name] = $value; + + return $this; + } + + /** + * Check if the cookie matches a path value + * + * @param string $path Path to check against + * + * @return bool + */ + public function matchesPath($path) + { + // RFC6265 http://tools.ietf.org/search/rfc6265#section-5.1.4 + // A request-path path-matches a given cookie-path if at least one of + // the following conditions holds: + + // o The cookie-path and the request-path are identical. + if ($path == $this->getPath()) { + return true; + } + + $pos = stripos($path, $this->getPath()); + if ($pos === 0) { + // o The cookie-path is a prefix of the request-path, and the last + // character of the cookie-path is %x2F ("/"). + if (substr($this->getPath(), -1, 1) === "/") { + return true; + } + + // o The cookie-path is a prefix of the request-path, and the first + // character of the request-path that is not included in the cookie- + // path is a %x2F ("/") character. + if (substr($path, strlen($this->getPath()), 1) === "/") { + return true; + } + } + + return false; + } + + /** + * Check if the cookie matches a domain value + * + * @param string $domain Domain to check against + * + * @return bool + */ + public function matchesDomain($domain) + { + // Remove the leading '.' as per spec in RFC 6265: http://tools.ietf.org/html/rfc6265#section-5.2.3 + $cookieDomain = ltrim($this->getDomain(), '.'); + + // Domain not set or exact match. + if (!$cookieDomain || !strcasecmp($domain, $cookieDomain)) { + return true; + } + + // Matching the subdomain according to RFC 6265: http://tools.ietf.org/html/rfc6265#section-5.1.3 + if (filter_var($domain, FILTER_VALIDATE_IP)) { + return false; + } + + return (bool) preg_match('/\.' . preg_quote($cookieDomain, '/') . '$/i', $domain); + } + + /** + * Check if the cookie is compatible with a specific port + * + * @param int $port Port to check + * + * @return bool + */ + public function matchesPort($port) + { + return count($this->getPorts()) == 0 || in_array($port, $this->getPorts()); + } + + /** + * Check if the cookie is expired + * + * @return bool + */ + public function isExpired() + { + return $this->getExpires() && time() > $this->getExpires(); + } + + /** + * Check if the cookie is valid according to RFC 6265 + * + * @return bool|string Returns true if valid or an error message if invalid + */ + public function validate() + { + // Names must not be empty, but can be 0 + $name = $this->getName(); + if (empty($name) && !is_numeric($name)) { + return 'The cookie name must not be empty'; + } + + // Check if any of the invalid characters are present in the cookie name + if (strpbrk($name, self::getInvalidCharacters()) !== false) { + return 'The cookie name must not contain invalid characters: ' . $name; + } + + // Value must not be empty, but can be 0 + $value = $this->getValue(); + if (empty($value) && !is_numeric($value)) { + return 'The cookie value must not be empty'; + } + + // Domains must not be empty, but can be 0 + // A "0" is not a valid internet domain, but may be used as server name in a private network + $domain = $this->getDomain(); + if (empty($domain) && !is_numeric($domain)) { + return 'The cookie domain must not be empty'; + } + + return true; + } + + /** + * Set a value and return the cookie object + * + * @param string $key Key to set + * @param string $value Value to set + * + * @return Cookie + */ + private function setData($key, $value) + { + $this->data[$key] = $value; + + return $this; + } +} diff --git a/vendor/guzzle/guzzle/src/Guzzle/Plugin/Cookie/CookieJar/ArrayCookieJar.php b/vendor/guzzle/guzzle/src/Guzzle/Plugin/Cookie/CookieJar/ArrayCookieJar.php new file mode 100644 index 0000000..6b67503 --- /dev/null +++ b/vendor/guzzle/guzzle/src/Guzzle/Plugin/Cookie/CookieJar/ArrayCookieJar.php @@ -0,0 +1,237 @@ +strictMode = $strictMode; + } + + /** + * Enable or disable strict mode on the cookie jar + * + * @param bool $strictMode Set to true to throw exceptions when invalid cookies are added. False to ignore them. + * + * @return self + */ + public function setStrictMode($strictMode) + { + $this->strictMode = $strictMode; + } + + public function remove($domain = null, $path = null, $name = null) + { + $cookies = $this->all($domain, $path, $name, false, false); + $this->cookies = array_filter($this->cookies, function (Cookie $cookie) use ($cookies) { + return !in_array($cookie, $cookies, true); + }); + + return $this; + } + + public function removeTemporary() + { + $this->cookies = array_filter($this->cookies, function (Cookie $cookie) { + return !$cookie->getDiscard() && $cookie->getExpires(); + }); + + return $this; + } + + public function removeExpired() + { + $currentTime = time(); + $this->cookies = array_filter($this->cookies, function (Cookie $cookie) use ($currentTime) { + return !$cookie->getExpires() || $currentTime < $cookie->getExpires(); + }); + + return $this; + } + + public function all($domain = null, $path = null, $name = null, $skipDiscardable = false, $skipExpired = true) + { + return array_values(array_filter($this->cookies, function (Cookie $cookie) use ( + $domain, + $path, + $name, + $skipDiscardable, + $skipExpired + ) { + return false === (($name && $cookie->getName() != $name) || + ($skipExpired && $cookie->isExpired()) || + ($skipDiscardable && ($cookie->getDiscard() || !$cookie->getExpires())) || + ($path && !$cookie->matchesPath($path)) || + ($domain && !$cookie->matchesDomain($domain))); + })); + } + + public function add(Cookie $cookie) + { + // Only allow cookies with set and valid domain, name, value + $result = $cookie->validate(); + if ($result !== true) { + if ($this->strictMode) { + throw new InvalidCookieException($result); + } else { + $this->removeCookieIfEmpty($cookie); + return false; + } + } + + // Resolve conflicts with previously set cookies + foreach ($this->cookies as $i => $c) { + + // Two cookies are identical, when their path, domain, port and name are identical + if ($c->getPath() != $cookie->getPath() || + $c->getDomain() != $cookie->getDomain() || + $c->getPorts() != $cookie->getPorts() || + $c->getName() != $cookie->getName() + ) { + continue; + } + + // The previously set cookie is a discard cookie and this one is not so allow the new cookie to be set + if (!$cookie->getDiscard() && $c->getDiscard()) { + unset($this->cookies[$i]); + continue; + } + + // If the new cookie's expiration is further into the future, then replace the old cookie + if ($cookie->getExpires() > $c->getExpires()) { + unset($this->cookies[$i]); + continue; + } + + // If the value has changed, we better change it + if ($cookie->getValue() !== $c->getValue()) { + unset($this->cookies[$i]); + continue; + } + + // The cookie exists, so no need to continue + return false; + } + + $this->cookies[] = $cookie; + + return true; + } + + /** + * Serializes the cookie cookieJar + * + * @return string + */ + public function serialize() + { + // Only serialize long term cookies and unexpired cookies + return json_encode(array_map(function (Cookie $cookie) { + return $cookie->toArray(); + }, $this->all(null, null, null, true, true))); + } + + /** + * Unserializes the cookie cookieJar + */ + public function unserialize($data) + { + $data = json_decode($data, true); + if (empty($data)) { + $this->cookies = array(); + } else { + $this->cookies = array_map(function (array $cookie) { + return new Cookie($cookie); + }, $data); + } + } + + /** + * Returns the total number of stored cookies + * + * @return int + */ + public function count() + { + return count($this->cookies); + } + + /** + * Returns an iterator + * + * @return \ArrayIterator + */ + public function getIterator() + { + return new \ArrayIterator($this->cookies); + } + + public function addCookiesFromResponse(Response $response, RequestInterface $request = null) + { + if ($cookieHeader = $response->getHeader('Set-Cookie')) { + $parser = ParserRegistry::getInstance()->getParser('cookie'); + foreach ($cookieHeader as $cookie) { + if ($parsed = $request + ? $parser->parseCookie($cookie, $request->getHost(), $request->getPath()) + : $parser->parseCookie($cookie) + ) { + // Break up cookie v2 into multiple cookies + foreach ($parsed['cookies'] as $key => $value) { + $row = $parsed; + $row['name'] = $key; + $row['value'] = $value; + unset($row['cookies']); + $this->add(new Cookie($row)); + } + } + } + } + } + + public function getMatchingCookies(RequestInterface $request) + { + // Find cookies that match this request + $cookies = $this->all($request->getHost(), $request->getPath()); + // Remove ineligible cookies + foreach ($cookies as $index => $cookie) { + if (!$cookie->matchesPort($request->getPort()) || ($cookie->getSecure() && $request->getScheme() != 'https')) { + unset($cookies[$index]); + } + }; + + return $cookies; + } + + /** + * If a cookie already exists and the server asks to set it again with a null value, the + * cookie must be deleted. + * + * @param \Guzzle\Plugin\Cookie\Cookie $cookie + */ + private function removeCookieIfEmpty(Cookie $cookie) + { + $cookieValue = $cookie->getValue(); + if ($cookieValue === null || $cookieValue === '') { + $this->remove($cookie->getDomain(), $cookie->getPath(), $cookie->getName()); + } + } +} diff --git a/vendor/guzzle/guzzle/src/Guzzle/Plugin/Cookie/CookieJar/CookieJarInterface.php b/vendor/guzzle/guzzle/src/Guzzle/Plugin/Cookie/CookieJar/CookieJarInterface.php new file mode 100644 index 0000000..7faa7d2 --- /dev/null +++ b/vendor/guzzle/guzzle/src/Guzzle/Plugin/Cookie/CookieJar/CookieJarInterface.php @@ -0,0 +1,85 @@ +filename = $cookieFile; + $this->load(); + } + + /** + * Saves the file when shutting down + */ + public function __destruct() + { + $this->persist(); + } + + /** + * Save the contents of the data array to the file + * + * @throws RuntimeException if the file cannot be found or created + */ + protected function persist() + { + if (false === file_put_contents($this->filename, $this->serialize())) { + // @codeCoverageIgnoreStart + throw new RuntimeException('Unable to open file ' . $this->filename); + // @codeCoverageIgnoreEnd + } + } + + /** + * Load the contents of the json formatted file into the data array and discard any unsaved state + */ + protected function load() + { + $json = file_get_contents($this->filename); + if (false === $json) { + // @codeCoverageIgnoreStart + throw new RuntimeException('Unable to open file ' . $this->filename); + // @codeCoverageIgnoreEnd + } + + $this->unserialize($json); + $this->cookies = $this->cookies ?: array(); + } +} diff --git a/vendor/guzzle/guzzle/src/Guzzle/Plugin/Cookie/CookiePlugin.php b/vendor/guzzle/guzzle/src/Guzzle/Plugin/Cookie/CookiePlugin.php new file mode 100644 index 0000000..df3210e --- /dev/null +++ b/vendor/guzzle/guzzle/src/Guzzle/Plugin/Cookie/CookiePlugin.php @@ -0,0 +1,70 @@ +cookieJar = $cookieJar ?: new ArrayCookieJar(); + } + + public static function getSubscribedEvents() + { + return array( + 'request.before_send' => array('onRequestBeforeSend', 125), + 'request.sent' => array('onRequestSent', 125) + ); + } + + /** + * Get the cookie cookieJar + * + * @return CookieJarInterface + */ + public function getCookieJar() + { + return $this->cookieJar; + } + + /** + * Add cookies before a request is sent + * + * @param Event $event + */ + public function onRequestBeforeSend(Event $event) + { + $request = $event['request']; + if (!$request->getParams()->get('cookies.disable')) { + $request->removeHeader('Cookie'); + // Find cookies that match this request + foreach ($this->cookieJar->getMatchingCookies($request) as $cookie) { + $request->addCookie($cookie->getName(), $cookie->getValue()); + } + } + } + + /** + * Extract cookies from a sent request + * + * @param Event $event + */ + public function onRequestSent(Event $event) + { + $this->cookieJar->addCookiesFromResponse($event['response'], $event['request']); + } +} diff --git a/vendor/guzzle/guzzle/src/Guzzle/Plugin/Cookie/Exception/InvalidCookieException.php b/vendor/guzzle/guzzle/src/Guzzle/Plugin/Cookie/Exception/InvalidCookieException.php new file mode 100644 index 0000000..b1fa6fd --- /dev/null +++ b/vendor/guzzle/guzzle/src/Guzzle/Plugin/Cookie/Exception/InvalidCookieException.php @@ -0,0 +1,7 @@ +=5.3.2", + "guzzle/http": "self.version" + }, + "autoload": { + "psr-0": { "Guzzle\\Plugin\\Cookie": "" } + }, + "target-dir": "Guzzle/Plugin/Cookie", + "extra": { + "branch-alias": { + "dev-master": "3.7-dev" + } + } +} diff --git a/vendor/guzzle/guzzle/src/Guzzle/Plugin/CurlAuth/CurlAuthPlugin.php b/vendor/guzzle/guzzle/src/Guzzle/Plugin/CurlAuth/CurlAuthPlugin.php new file mode 100644 index 0000000..610e60c --- /dev/null +++ b/vendor/guzzle/guzzle/src/Guzzle/Plugin/CurlAuth/CurlAuthPlugin.php @@ -0,0 +1,46 @@ +getConfig()->setPath('request.options/auth', array('user', 'pass', 'Basic|Digest'); + */ +class CurlAuthPlugin implements EventSubscriberInterface +{ + private $username; + private $password; + private $scheme; + + /** + * @param string $username HTTP basic auth username + * @param string $password Password + * @param int $scheme Curl auth scheme + */ + public function __construct($username, $password, $scheme=CURLAUTH_BASIC) + { + Version::warn(__CLASS__ . " is deprecated. Use \$client->getConfig()->setPath('request.options/auth', array('user', 'pass', 'Basic|Digest');"); + $this->username = $username; + $this->password = $password; + $this->scheme = $scheme; + } + + public static function getSubscribedEvents() + { + return array('client.create_request' => array('onRequestCreate', 255)); + } + + /** + * Add basic auth + * + * @param Event $event + */ + public function onRequestCreate(Event $event) + { + $event['request']->setAuth($this->username, $this->password, $this->scheme); + } +} diff --git a/vendor/guzzle/guzzle/src/Guzzle/Plugin/CurlAuth/composer.json b/vendor/guzzle/guzzle/src/Guzzle/Plugin/CurlAuth/composer.json new file mode 100644 index 0000000..edc8b24 --- /dev/null +++ b/vendor/guzzle/guzzle/src/Guzzle/Plugin/CurlAuth/composer.json @@ -0,0 +1,27 @@ +{ + "name": "guzzle/plugin-curlauth", + "description": "Guzzle cURL authorization plugin", + "homepage": "http://guzzlephp.org/", + "keywords": ["plugin", "curl", "guzzle"], + "license": "MIT", + "authors": [ + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + } + ], + "require": { + "php": ">=5.3.2", + "guzzle/http": "self.version" + }, + "autoload": { + "psr-0": { "Guzzle\\Plugin\\CurlAuth": "" } + }, + "target-dir": "Guzzle/Plugin/CurlAuth", + "extra": { + "branch-alias": { + "dev-master": "3.7-dev" + } + } +} diff --git a/vendor/guzzle/guzzle/src/Guzzle/Plugin/ErrorResponse/ErrorResponseExceptionInterface.php b/vendor/guzzle/guzzle/src/Guzzle/Plugin/ErrorResponse/ErrorResponseExceptionInterface.php new file mode 100644 index 0000000..5dce8bd --- /dev/null +++ b/vendor/guzzle/guzzle/src/Guzzle/Plugin/ErrorResponse/ErrorResponseExceptionInterface.php @@ -0,0 +1,22 @@ + array('onCommandBeforeSend', -1)); + } + + /** + * Adds a listener to requests before they sent from a command + * + * @param Event $event Event emitted + */ + public function onCommandBeforeSend(Event $event) + { + $command = $event['command']; + if ($operation = $command->getOperation()) { + if ($operation->getErrorResponses()) { + $request = $command->getRequest(); + $request->getEventDispatcher() + ->addListener('request.complete', $this->getErrorClosure($request, $command, $operation)); + } + } + } + + /** + * @param RequestInterface $request Request that received an error + * @param CommandInterface $command Command that created the request + * @param Operation $operation Operation that defines the request and errors + * + * @return \Closure Returns a closure + * @throws ErrorResponseException + */ + protected function getErrorClosure(RequestInterface $request, CommandInterface $command, Operation $operation) + { + return function (Event $event) use ($request, $command, $operation) { + $response = $event['response']; + foreach ($operation->getErrorResponses() as $error) { + if (!isset($error['class'])) { + continue; + } + if (isset($error['code']) && $response->getStatusCode() != $error['code']) { + continue; + } + if (isset($error['reason']) && $response->getReasonPhrase() != $error['reason']) { + continue; + } + $className = $error['class']; + $errorClassInterface = __NAMESPACE__ . '\\ErrorResponseExceptionInterface'; + if (!class_exists($className)) { + throw new ErrorResponseException("{$className} does not exist"); + } elseif (!(in_array($errorClassInterface, class_implements($className)))) { + throw new ErrorResponseException("{$className} must implement {$errorClassInterface}"); + } + throw $className::fromCommand($command, $response); + } + }; + } +} diff --git a/vendor/guzzle/guzzle/src/Guzzle/Plugin/ErrorResponse/Exception/ErrorResponseException.php b/vendor/guzzle/guzzle/src/Guzzle/Plugin/ErrorResponse/Exception/ErrorResponseException.php new file mode 100644 index 0000000..1d89e40 --- /dev/null +++ b/vendor/guzzle/guzzle/src/Guzzle/Plugin/ErrorResponse/Exception/ErrorResponseException.php @@ -0,0 +1,7 @@ +=5.3.2", + "guzzle/service": "self.version" + }, + "autoload": { + "psr-0": { "Guzzle\\Plugin\\ErrorResponse": "" } + }, + "target-dir": "Guzzle/Plugin/ErrorResponse", + "extra": { + "branch-alias": { + "dev-master": "3.7-dev" + } + } +} diff --git a/vendor/guzzle/guzzle/src/Guzzle/Plugin/History/HistoryPlugin.php b/vendor/guzzle/guzzle/src/Guzzle/Plugin/History/HistoryPlugin.php new file mode 100644 index 0000000..7375e89 --- /dev/null +++ b/vendor/guzzle/guzzle/src/Guzzle/Plugin/History/HistoryPlugin.php @@ -0,0 +1,163 @@ + array('onRequestSent', 9999)); + } + + /** + * Convert to a string that contains all request and response headers + * + * @return string + */ + public function __toString() + { + $lines = array(); + foreach ($this->transactions as $entry) { + $response = isset($entry['response']) ? $entry['response'] : ''; + $lines[] = '> ' . trim($entry['request']) . "\n\n< " . trim($response) . "\n"; + } + + return implode("\n", $lines); + } + + /** + * Add a request to the history + * + * @param RequestInterface $request Request to add + * @param Response $response Response of the request + * + * @return HistoryPlugin + */ + public function add(RequestInterface $request, Response $response = null) + { + if (!$response && $request->getResponse()) { + $response = $request->getResponse(); + } + + $this->transactions[] = array('request' => $request, 'response' => $response); + if (count($this->transactions) > $this->getlimit()) { + array_shift($this->transactions); + } + + return $this; + } + + /** + * Set the max number of requests to store + * + * @param int $limit Limit + * + * @return HistoryPlugin + */ + public function setLimit($limit) + { + $this->limit = (int) $limit; + + return $this; + } + + /** + * Get the request limit + * + * @return int + */ + public function getLimit() + { + return $this->limit; + } + + /** + * Get all of the raw transactions in the form of an array of associative arrays containing + * 'request' and 'response' keys. + * + * @return array + */ + public function getAll() + { + return $this->transactions; + } + + /** + * Get the requests in the history + * + * @return \ArrayIterator + */ + public function getIterator() + { + // Return an iterator just like the old iteration of the HistoryPlugin for BC compatibility (use getAll()) + return new \ArrayIterator(array_map(function ($entry) { + $entry['request']->getParams()->set('actual_response', $entry['response']); + return $entry['request']; + }, $this->transactions)); + } + + /** + * Get the number of requests in the history + * + * @return int + */ + public function count() + { + return count($this->transactions); + } + + /** + * Get the last request sent + * + * @return RequestInterface + */ + public function getLastRequest() + { + $last = end($this->transactions); + + return $last['request']; + } + + /** + * Get the last response in the history + * + * @return Response|null + */ + public function getLastResponse() + { + $last = end($this->transactions); + + return isset($last['response']) ? $last['response'] : null; + } + + /** + * Clears the history + * + * @return HistoryPlugin + */ + public function clear() + { + $this->transactions = array(); + + return $this; + } + + public function onRequestSent(Event $event) + { + $this->add($event['request'], $event['response']); + } +} diff --git a/vendor/guzzle/guzzle/src/Guzzle/Plugin/History/composer.json b/vendor/guzzle/guzzle/src/Guzzle/Plugin/History/composer.json new file mode 100644 index 0000000..ba0bf2c --- /dev/null +++ b/vendor/guzzle/guzzle/src/Guzzle/Plugin/History/composer.json @@ -0,0 +1,27 @@ +{ + "name": "guzzle/plugin-history", + "description": "Guzzle history plugin", + "homepage": "http://guzzlephp.org/", + "keywords": ["plugin", "guzzle"], + "license": "MIT", + "authors": [ + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + } + ], + "require": { + "php": ">=5.3.2", + "guzzle/http": "self.version" + }, + "autoload": { + "psr-0": { "Guzzle\\Plugin\\History": "" } + }, + "target-dir": "Guzzle/Plugin/History", + "extra": { + "branch-alias": { + "dev-master": "3.7-dev" + } + } +} diff --git a/vendor/guzzle/guzzle/src/Guzzle/Plugin/Log/LogPlugin.php b/vendor/guzzle/guzzle/src/Guzzle/Plugin/Log/LogPlugin.php new file mode 100644 index 0000000..cabdea8 --- /dev/null +++ b/vendor/guzzle/guzzle/src/Guzzle/Plugin/Log/LogPlugin.php @@ -0,0 +1,161 @@ +logAdapter = $logAdapter; + $this->formatter = $formatter instanceof MessageFormatter ? $formatter : new MessageFormatter($formatter); + $this->wireBodies = $wireBodies; + } + + /** + * Get a log plugin that outputs full request, response, and curl error information to stderr + * + * @param bool $wireBodies Set to false to disable request/response body output when they use are not repeatable + * @param resource $stream Stream to write to when logging. Defaults to STDERR when it is available + * + * @return self + */ + public static function getDebugPlugin($wireBodies = true, $stream = null) + { + if ($stream === null) { + if (defined('STDERR')) { + $stream = STDERR; + } else { + $stream = fopen('php://output', 'w'); + } + } + + return new self(new ClosureLogAdapter(function ($m) use ($stream) { + fwrite($stream, $m . PHP_EOL); + }), "# Request:\n{request}\n\n# Response:\n{response}\n\n# Errors: {curl_code} {curl_error}", $wireBodies); + } + + public static function getSubscribedEvents() + { + return array( + 'curl.callback.write' => array('onCurlWrite', 255), + 'curl.callback.read' => array('onCurlRead', 255), + 'request.before_send' => array('onRequestBeforeSend', 255), + 'request.sent' => array('onRequestSent', 255) + ); + } + + /** + * Event triggered when curl data is read from a request + * + * @param Event $event + */ + public function onCurlRead(Event $event) + { + // Stream the request body to the log if the body is not repeatable + if ($wire = $event['request']->getParams()->get('request_wire')) { + $wire->write($event['read']); + } + } + + /** + * Event triggered when curl data is written to a response + * + * @param Event $event + */ + public function onCurlWrite(Event $event) + { + // Stream the response body to the log if the body is not repeatable + if ($wire = $event['request']->getParams()->get('response_wire')) { + $wire->write($event['write']); + } + } + + /** + * Called before a request is sent + * + * @param Event $event + */ + public function onRequestBeforeSend(Event $event) + { + if ($this->wireBodies) { + $request = $event['request']; + // Ensure that curl IO events are emitted + $request->getCurlOptions()->set('emit_io', true); + // We need to make special handling for content wiring and non-repeatable streams. + if ($request instanceof EntityEnclosingRequestInterface && $request->getBody() + && (!$request->getBody()->isSeekable() || !$request->getBody()->isReadable()) + ) { + // The body of the request cannot be recalled so logging the body will require us to buffer it + $request->getParams()->set('request_wire', EntityBody::factory()); + } + if (!$request->getResponseBody()->isRepeatable()) { + // The body of the response cannot be recalled so logging the body will require us to buffer it + $request->getParams()->set('response_wire', EntityBody::factory()); + } + } + } + + /** + * Triggers the actual log write when a request completes + * + * @param Event $event + */ + public function onRequestSent(Event $event) + { + $request = $event['request']; + $response = $event['response']; + $handle = $event['handle']; + + if ($wire = $request->getParams()->get('request_wire')) { + $request = clone $request; + $request->setBody($wire); + } + + if ($wire = $request->getParams()->get('response_wire')) { + $response = clone $response; + $response->setBody($wire); + } + + // Send the log message to the adapter, adding a category and host + $priority = $response && $response->isError() ? LOG_ERR : LOG_DEBUG; + $message = $this->formatter->format($request, $response, $handle); + $this->logAdapter->log($message, $priority, array( + 'request' => $request, + 'response' => $response, + 'handle' => $handle + )); + } +} diff --git a/vendor/guzzle/guzzle/src/Guzzle/Plugin/Log/composer.json b/vendor/guzzle/guzzle/src/Guzzle/Plugin/Log/composer.json new file mode 100644 index 0000000..130e6da --- /dev/null +++ b/vendor/guzzle/guzzle/src/Guzzle/Plugin/Log/composer.json @@ -0,0 +1,28 @@ +{ + "name": "guzzle/plugin-log", + "description": "Guzzle log plugin for over the wire logging", + "homepage": "http://guzzlephp.org/", + "keywords": ["plugin", "log", "guzzle"], + "license": "MIT", + "authors": [ + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + } + ], + "require": { + "php": ">=5.3.2", + "guzzle/http": "self.version", + "guzzle/log": "self.version" + }, + "autoload": { + "psr-0": { "Guzzle\\Plugin\\Log": "" } + }, + "target-dir": "Guzzle/Plugin/Log", + "extra": { + "branch-alias": { + "dev-master": "3.7-dev" + } + } +} diff --git a/vendor/guzzle/guzzle/src/Guzzle/Plugin/Md5/CommandContentMd5Plugin.php b/vendor/guzzle/guzzle/src/Guzzle/Plugin/Md5/CommandContentMd5Plugin.php new file mode 100644 index 0000000..8512424 --- /dev/null +++ b/vendor/guzzle/guzzle/src/Guzzle/Plugin/Md5/CommandContentMd5Plugin.php @@ -0,0 +1,57 @@ +contentMd5Param = $contentMd5Param; + $this->validateMd5Param = $validateMd5Param; + } + + public static function getSubscribedEvents() + { + return array('command.before_send' => array('onCommandBeforeSend', -255)); + } + + public function onCommandBeforeSend(Event $event) + { + $command = $event['command']; + $request = $command->getRequest(); + + // Only add an MD5 is there is a MD5 option on the operation and it has a payload + if ($request instanceof EntityEnclosingRequestInterface && $request->getBody() + && $command->getOperation()->hasParam($this->contentMd5Param)) { + // Check if an MD5 checksum value should be passed along to the request + if ($command[$this->contentMd5Param] === true) { + if (false !== ($md5 = $request->getBody()->getContentMd5(true, true))) { + $request->setHeader('Content-MD5', $md5); + } + } + } + + // Check if MD5 validation should be used with the response + if ($command[$this->validateMd5Param] === true) { + $request->addSubscriber(new Md5ValidatorPlugin(true, false)); + } + } +} diff --git a/vendor/guzzle/guzzle/src/Guzzle/Plugin/Md5/Md5ValidatorPlugin.php b/vendor/guzzle/guzzle/src/Guzzle/Plugin/Md5/Md5ValidatorPlugin.php new file mode 100644 index 0000000..5d7a378 --- /dev/null +++ b/vendor/guzzle/guzzle/src/Guzzle/Plugin/Md5/Md5ValidatorPlugin.php @@ -0,0 +1,88 @@ +contentLengthCutoff = $contentLengthCutoff; + $this->contentEncoded = $contentEncoded; + } + + public static function getSubscribedEvents() + { + return array('request.complete' => array('onRequestComplete', 255)); + } + + /** + * {@inheritdoc} + * @throws UnexpectedValueException + */ + public function onRequestComplete(Event $event) + { + $response = $event['response']; + + if (!$contentMd5 = $response->getContentMd5()) { + return; + } + + $contentEncoding = $response->getContentEncoding(); + if ($contentEncoding && !$this->contentEncoded) { + return false; + } + + // Make sure that the size of the request is under the cutoff size + if ($this->contentLengthCutoff) { + $size = $response->getContentLength() ?: $response->getBody()->getSize(); + if (!$size || $size > $this->contentLengthCutoff) { + return; + } + } + + if (!$contentEncoding) { + $hash = $response->getBody()->getContentMd5(); + } elseif ($contentEncoding == 'gzip') { + $response->getBody()->compress('zlib.deflate'); + $hash = $response->getBody()->getContentMd5(); + $response->getBody()->uncompress(); + } elseif ($contentEncoding == 'compress') { + $response->getBody()->compress('bzip2.compress'); + $hash = $response->getBody()->getContentMd5(); + $response->getBody()->uncompress(); + } else { + return; + } + + if ($contentMd5 !== $hash) { + throw new UnexpectedValueException( + "The response entity body may have been modified over the wire. The Content-MD5 " + . "received ({$contentMd5}) did not match the calculated MD5 hash ({$hash})." + ); + } + } +} diff --git a/vendor/guzzle/guzzle/src/Guzzle/Plugin/Md5/composer.json b/vendor/guzzle/guzzle/src/Guzzle/Plugin/Md5/composer.json new file mode 100644 index 0000000..0602d06 --- /dev/null +++ b/vendor/guzzle/guzzle/src/Guzzle/Plugin/Md5/composer.json @@ -0,0 +1,27 @@ +{ + "name": "guzzle/plugin-md5", + "description": "Guzzle MD5 plugins", + "homepage": "http://guzzlephp.org/", + "keywords": ["plugin", "guzzle"], + "license": "MIT", + "authors": [ + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + } + ], + "require": { + "php": ">=5.3.2", + "guzzle/http": "self.version" + }, + "autoload": { + "psr-0": { "Guzzle\\Plugin\\Md5": "" } + }, + "target-dir": "Guzzle/Plugin/Md5", + "extra": { + "branch-alias": { + "dev-master": "3.7-dev" + } + } +} diff --git a/vendor/guzzle/guzzle/src/Guzzle/Plugin/Mock/MockPlugin.php b/vendor/guzzle/guzzle/src/Guzzle/Plugin/Mock/MockPlugin.php new file mode 100644 index 0000000..2440578 --- /dev/null +++ b/vendor/guzzle/guzzle/src/Guzzle/Plugin/Mock/MockPlugin.php @@ -0,0 +1,245 @@ +readBodies = $readBodies; + $this->temporary = $temporary; + if ($items) { + foreach ($items as $item) { + if ($item instanceof \Exception) { + $this->addException($item); + } else { + $this->addResponse($item); + } + } + } + } + + public static function getSubscribedEvents() + { + // Use a number lower than the CachePlugin + return array('request.before_send' => array('onRequestBeforeSend', -999)); + } + + public static function getAllEvents() + { + return array('mock.request'); + } + + /** + * Get a mock response from a file + * + * @param string $path File to retrieve a mock response from + * + * @return Response + * @throws InvalidArgumentException if the file is not found + */ + public static function getMockFile($path) + { + if (!file_exists($path)) { + throw new InvalidArgumentException('Unable to open mock file: ' . $path); + } + + return Response::fromMessage(file_get_contents($path)); + } + + /** + * Set whether or not to consume the entity body of a request when a mock + * response is used + * + * @param bool $readBodies Set to true to read and consume entity bodies + * + * @return self + */ + public function readBodies($readBodies) + { + $this->readBodies = $readBodies; + + return $this; + } + + /** + * Returns the number of remaining mock responses + * + * @return int + */ + public function count() + { + return count($this->queue); + } + + /** + * Add a response to the end of the queue + * + * @param string|Response $response Response object or path to response file + * + * @return MockPlugin + * @throws InvalidArgumentException if a string or Response is not passed + */ + public function addResponse($response) + { + if (!($response instanceof Response)) { + if (!is_string($response)) { + throw new InvalidArgumentException('Invalid response'); + } + $response = self::getMockFile($response); + } + + $this->queue[] = $response; + + return $this; + } + + /** + * Add an exception to the end of the queue + * + * @param CurlException $e Exception to throw when the request is executed + * + * @return MockPlugin + */ + public function addException(CurlException $e) + { + $this->queue[] = $e; + + return $this; + } + + /** + * Clear the queue + * + * @return MockPlugin + */ + public function clearQueue() + { + $this->queue = array(); + + return $this; + } + + /** + * Returns an array of mock responses remaining in the queue + * + * @return array + */ + public function getQueue() + { + return $this->queue; + } + + /** + * Check if this is a temporary plugin + * + * @return bool + */ + public function isTemporary() + { + return $this->temporary; + } + + /** + * Get a response from the front of the list and add it to a request + * + * @param RequestInterface $request Request to mock + * + * @return self + * @throws CurlException When request.send is called and an exception is queued + */ + public function dequeue(RequestInterface $request) + { + $this->dispatch('mock.request', array('plugin' => $this, 'request' => $request)); + + $item = array_shift($this->queue); + if ($item instanceof Response) { + if ($this->readBodies && $request instanceof EntityEnclosingRequestInterface) { + $request->getEventDispatcher()->addListener('request.sent', $f = function (Event $event) use (&$f) { + while ($data = $event['request']->getBody()->read(8096)); + // Remove the listener after one-time use + $event['request']->getEventDispatcher()->removeListener('request.sent', $f); + }); + } + $request->setResponse($item); + } elseif ($item instanceof CurlException) { + // Emulates exceptions encountered while transferring requests + $item->setRequest($request); + $state = $request->setState(RequestInterface::STATE_ERROR, array('exception' => $item)); + // Only throw if the exception wasn't handled + if ($state == RequestInterface::STATE_ERROR) { + throw $item; + } + } + + return $this; + } + + /** + * Clear the array of received requests + */ + public function flush() + { + $this->received = array(); + } + + /** + * Get an array of requests that were mocked by this plugin + * + * @return array + */ + public function getReceivedRequests() + { + return $this->received; + } + + /** + * Called when a request is about to be sent + * + * @param Event $event + * @throws \OutOfBoundsException When queue is empty + */ + public function onRequestBeforeSend(Event $event) + { + if (!$this->queue) { + throw new \OutOfBoundsException('Mock queue is empty'); + } + + $request = $event['request']; + $this->received[] = $request; + // Detach the filter from the client so it's a one-time use + if ($this->temporary && count($this->queue) == 1 && $request->getClient()) { + $request->getClient()->getEventDispatcher()->removeSubscriber($this); + } + $this->dequeue($request); + } +} diff --git a/vendor/guzzle/guzzle/src/Guzzle/Plugin/Mock/composer.json b/vendor/guzzle/guzzle/src/Guzzle/Plugin/Mock/composer.json new file mode 100644 index 0000000..f8201e3 --- /dev/null +++ b/vendor/guzzle/guzzle/src/Guzzle/Plugin/Mock/composer.json @@ -0,0 +1,27 @@ +{ + "name": "guzzle/plugin-mock", + "description": "Guzzle Mock plugin", + "homepage": "http://guzzlephp.org/", + "keywords": ["mock", "plugin", "guzzle"], + "license": "MIT", + "authors": [ + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + } + ], + "require": { + "php": ">=5.3.2", + "guzzle/http": "self.version" + }, + "autoload": { + "psr-0": { "Guzzle\\Plugin\\Mock": "" } + }, + "target-dir": "Guzzle/Plugin/Mock", + "extra": { + "branch-alias": { + "dev-master": "3.7-dev" + } + } +} diff --git a/vendor/guzzle/guzzle/src/Guzzle/Plugin/Oauth/OauthPlugin.php b/vendor/guzzle/guzzle/src/Guzzle/Plugin/Oauth/OauthPlugin.php new file mode 100644 index 0000000..95e0c3e --- /dev/null +++ b/vendor/guzzle/guzzle/src/Guzzle/Plugin/Oauth/OauthPlugin.php @@ -0,0 +1,306 @@ +config = Collection::fromConfig($config, array( + 'version' => '1.0', + 'request_method' => self::REQUEST_METHOD_HEADER, + 'consumer_key' => 'anonymous', + 'consumer_secret' => 'anonymous', + 'signature_method' => 'HMAC-SHA1', + 'signature_callback' => function($stringToSign, $key) { + return hash_hmac('sha1', $stringToSign, $key, true); + } + ), array( + 'signature_method', 'signature_callback', 'version', + 'consumer_key', 'consumer_secret' + )); + } + + public static function getSubscribedEvents() + { + return array( + 'request.before_send' => array('onRequestBeforeSend', -1000) + ); + } + + /** + * Request before-send event handler + * + * @param Event $event Event received + * @return array + * @throws \InvalidArgumentException + */ + public function onRequestBeforeSend(Event $event) + { + $timestamp = $this->getTimestamp($event); + $request = $event['request']; + $nonce = $this->generateNonce($request); + $authorizationParams = $this->getOauthParams($timestamp, $nonce); + $authorizationParams['oauth_signature'] = $this->getSignature($request, $timestamp, $nonce); + + switch ($this->config['request_method']) { + case self::REQUEST_METHOD_HEADER: + $request->setHeader( + 'Authorization', + $this->buildAuthorizationHeader($authorizationParams) + ); + break; + case self::REQUEST_METHOD_QUERY: + foreach ($authorizationParams as $key => $value) { + $request->getQuery()->set($key, $value); + } + break; + default: + throw new \InvalidArgumentException(sprintf( + 'Invalid consumer method "%s"', + $this->config['request_method'] + )); + } + + return $authorizationParams; + } + + /** + * Builds the Authorization header for a request + * + * @param array $authorizationParams Associative array of authorization parameters + * + * @return string + */ + private function buildAuthorizationHeader($authorizationParams) + { + $authorizationString = 'OAuth '; + foreach ($authorizationParams as $key => $val) { + if ($val) { + $authorizationString .= $key . '="' . urlencode($val) . '", '; + } + } + + return substr($authorizationString, 0, -2); + } + + /** + * Calculate signature for request + * + * @param RequestInterface $request Request to generate a signature for + * @param integer $timestamp Timestamp to use for nonce + * @param string $nonce + * + * @return string + */ + public function getSignature(RequestInterface $request, $timestamp, $nonce) + { + $string = $this->getStringToSign($request, $timestamp, $nonce); + $key = urlencode($this->config['consumer_secret']) . '&' . urlencode($this->config['token_secret']); + + return base64_encode(call_user_func($this->config['signature_callback'], $string, $key)); + } + + /** + * Calculate string to sign + * + * @param RequestInterface $request Request to generate a signature for + * @param int $timestamp Timestamp to use for nonce + * @param string $nonce + * + * @return string + */ + public function getStringToSign(RequestInterface $request, $timestamp, $nonce) + { + $params = $this->getParamsToSign($request, $timestamp, $nonce); + + // Convert booleans to strings. + $params = $this->prepareParameters($params); + + // Build signing string from combined params + $parameterString = clone $request->getQuery(); + $parameterString->replace($params); + + $url = Url::factory($request->getUrl())->setQuery('')->setFragment(null); + + return strtoupper($request->getMethod()) . '&' + . rawurlencode($url) . '&' + . rawurlencode((string) $parameterString); + } + + /** + * Get the oauth parameters as named by the oauth spec + * + * @param $timestamp + * @param $nonce + * @return Collection + */ + protected function getOauthParams($timestamp, $nonce) + { + $params = new Collection(array( + 'oauth_consumer_key' => $this->config['consumer_key'], + 'oauth_nonce' => $nonce, + 'oauth_signature_method' => $this->config['signature_method'], + 'oauth_timestamp' => $timestamp, + )); + + // Optional parameters should not be set if they have not been set in the config as + // the parameter may be considered invalid by the Oauth service. + $optionalParams = array( + 'callback' => 'oauth_callback', + 'token' => 'oauth_token', + 'verifier' => 'oauth_verifier', + 'version' => 'oauth_version' + ); + + foreach ($optionalParams as $optionName => $oauthName) { + if (isset($this->config[$optionName]) == true) { + $params[$oauthName] = $this->config[$optionName]; + } + } + + return $params; + } + + /** + * Get all of the parameters required to sign a request including: + * * The oauth params + * * The request GET params + * * The params passed in the POST body (with a content-type of application/x-www-form-urlencoded) + * + * @param RequestInterface $request Request to generate a signature for + * @param integer $timestamp Timestamp to use for nonce + * @param string $nonce + * + * @return array + */ + public function getParamsToSign(RequestInterface $request, $timestamp, $nonce) + { + $params = $this->getOauthParams($timestamp, $nonce); + + // Add query string parameters + $params->merge($request->getQuery()); + + // Add POST fields to signing string if required + if ($this->shouldPostFieldsBeSigned($request)) + { + $params->merge($request->getPostFields()); + } + + // Sort params + $params = $params->toArray(); + uksort($params, 'strcmp'); + + return $params; + } + + /** + * Decide whether the post fields should be added to the base string that Oauth signs. + * This implementation is correct. Non-conformant APIs may require that this method be + * overwritten e.g. the Flickr API incorrectly adds the post fields when the Content-Type + * is 'application/x-www-form-urlencoded' + * + * @param $request + * @return bool Whether the post fields should be signed or not + */ + public function shouldPostFieldsBeSigned($request) + { + if (!$this->config->get('disable_post_params') && + $request instanceof EntityEnclosingRequestInterface && + false !== strpos($request->getHeader('Content-Type'), 'application/x-www-form-urlencoded')) + { + return true; + } + + return false; + } + + /** + * Returns a Nonce Based on the unique id and URL. This will allow for multiple requests in parallel with the same + * exact timestamp to use separate nonce's. + * + * @param RequestInterface $request Request to generate a nonce for + * + * @return string + */ + public function generateNonce(RequestInterface $request) + { + return sha1(uniqid('', true) . $request->getUrl()); + } + + /** + * Gets timestamp from event or create new timestamp + * + * @param Event $event Event containing contextual information + * + * @return int + */ + public function getTimestamp(Event $event) + { + return $event['timestamp'] ?: time(); + } + + /** + * Convert booleans to strings, removed unset parameters, and sorts the array + * + * @param array $data Data array + * + * @return array + */ + protected function prepareParameters($data) + { + ksort($data); + foreach ($data as $key => &$value) { + switch (gettype($value)) { + case 'NULL': + unset($data[$key]); + break; + case 'array': + $data[$key] = self::prepareParameters($value); + break; + case 'boolean': + $data[$key] = $value ? 'true' : 'false'; + break; + } + } + + return $data; + } +} diff --git a/vendor/guzzle/guzzle/src/Guzzle/Plugin/Oauth/composer.json b/vendor/guzzle/guzzle/src/Guzzle/Plugin/Oauth/composer.json new file mode 100644 index 0000000..c9766ba --- /dev/null +++ b/vendor/guzzle/guzzle/src/Guzzle/Plugin/Oauth/composer.json @@ -0,0 +1,27 @@ +{ + "name": "guzzle/plugin-oauth", + "description": "Guzzle OAuth plugin", + "homepage": "http://guzzlephp.org/", + "keywords": ["oauth", "plugin", "guzzle"], + "license": "MIT", + "authors": [ + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + } + ], + "require": { + "php": ">=5.3.2", + "guzzle/http": "self.version" + }, + "autoload": { + "psr-0": { "Guzzle\\Plugin\\Oauth": "" } + }, + "target-dir": "Guzzle/Plugin/Oauth", + "extra": { + "branch-alias": { + "dev-master": "3.7-dev" + } + } +} diff --git a/vendor/guzzle/guzzle/src/Guzzle/Plugin/composer.json b/vendor/guzzle/guzzle/src/Guzzle/Plugin/composer.json new file mode 100644 index 0000000..2bbe64c --- /dev/null +++ b/vendor/guzzle/guzzle/src/Guzzle/Plugin/composer.json @@ -0,0 +1,44 @@ +{ + "name": "guzzle/plugin", + "description": "Guzzle plugin component containing all Guzzle HTTP plugins", + "homepage": "http://guzzlephp.org/", + "keywords": ["http", "client", "plugin", "extension", "guzzle"], + "license": "MIT", + "authors": [ + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + } + ], + "require": { + "php": ">=5.3.2", + "guzzle/http": "self.version" + }, + "suggest": { + "guzzle/cache": "self.version", + "guzzle/log": "self.version" + }, + "autoload": { + "psr-0": { "Guzzle\\Plugin": "" } + }, + "target-dir": "Guzzle/Plugin", + "replace": { + "guzzle/plugin-async": "self.version", + "guzzle/plugin-backoff": "self.version", + "guzzle/plugin-cache": "self.version", + "guzzle/plugin-cookie": "self.version", + "guzzle/plugin-curlauth": "self.version", + "guzzle/plugin-error-response": "self.version", + "guzzle/plugin-history": "self.version", + "guzzle/plugin-log": "self.version", + "guzzle/plugin-md5": "self.version", + "guzzle/plugin-mock": "self.version", + "guzzle/plugin-oauth": "self.version" + }, + "extra": { + "branch-alias": { + "dev-master": "3.7-dev" + } + } +} diff --git a/vendor/guzzle/guzzle/src/Guzzle/Service/AbstractConfigLoader.php b/vendor/guzzle/guzzle/src/Guzzle/Service/AbstractConfigLoader.php new file mode 100644 index 0000000..cd06f57 --- /dev/null +++ b/vendor/guzzle/guzzle/src/Guzzle/Service/AbstractConfigLoader.php @@ -0,0 +1,177 @@ + 'JSON_ERROR_NONE - No errors', + JSON_ERROR_DEPTH => 'JSON_ERROR_DEPTH - Maximum stack depth exceeded', + JSON_ERROR_STATE_MISMATCH => 'JSON_ERROR_STATE_MISMATCH - Underflow or the modes mismatch', + JSON_ERROR_CTRL_CHAR => 'JSON_ERROR_CTRL_CHAR - Unexpected control character found', + JSON_ERROR_SYNTAX => 'JSON_ERROR_SYNTAX - Syntax error, malformed JSON', + JSON_ERROR_UTF8 => 'JSON_ERROR_UTF8 - Malformed UTF-8 characters, possibly incorrectly encoded' + ); + + public function load($config, array $options = array()) + { + // Reset the array of loaded files because this is a new config + $this->loadedFiles = array(); + + if (is_string($config)) { + $config = $this->loadFile($config); + } elseif (!is_array($config)) { + throw new InvalidArgumentException('Unknown type passed to configuration loader: ' . gettype($config)); + } else { + $this->mergeIncludes($config); + } + + return $this->build($config, $options); + } + + /** + * Add an include alias to the loader + * + * @param string $filename Filename to alias (e.g. _foo) + * @param string $alias Actual file to use (e.g. /path/to/foo.json) + * + * @return self + */ + public function addAlias($filename, $alias) + { + $this->aliases[$filename] = $alias; + + return $this; + } + + /** + * Remove an alias from the loader + * + * @param string $alias Alias to remove + * + * @return self + */ + public function removeAlias($alias) + { + unset($this->aliases[$alias]); + + return $this; + } + + /** + * Perform the parsing of a config file and create the end result + * + * @param array $config Configuration data + * @param array $options Options to use when building + * + * @return mixed + */ + protected abstract function build($config, array $options); + + /** + * Load a configuration file (can load JSON or PHP files that return an array when included) + * + * @param string $filename File to load + * + * @return array + * @throws InvalidArgumentException + * @throws RuntimeException when the JSON cannot be parsed + */ + protected function loadFile($filename) + { + if (isset($this->aliases[$filename])) { + $filename = $this->aliases[$filename]; + } + + switch (pathinfo($filename, PATHINFO_EXTENSION)) { + case 'js': + case 'json': + $level = error_reporting(0); + $json = file_get_contents($filename); + error_reporting($level); + + if ($json === false) { + $err = error_get_last(); + throw new InvalidArgumentException("Unable to open {$filename}: " . $err['message']); + } + + $config = json_decode($json, true); + // Throw an exception if there was an error loading the file + if ($error = json_last_error()) { + $message = isset(self::$jsonErrors[$error]) ? self::$jsonErrors[$error] : 'Unknown error'; + throw new RuntimeException("Error loading JSON data from {$filename}: ({$error}) - {$message}"); + } + break; + case 'php': + if (!is_readable($filename)) { + throw new InvalidArgumentException("Unable to open {$filename} for reading"); + } + $config = require $filename; + if (!is_array($config)) { + throw new InvalidArgumentException('PHP files must return an array of configuration data'); + } + break; + default: + throw new InvalidArgumentException('Unknown file extension: ' . $filename); + } + + // Keep track of this file being loaded to prevent infinite recursion + $this->loadedFiles[$filename] = true; + + // Merge include files into the configuration array + $this->mergeIncludes($config, dirname($filename)); + + return $config; + } + + /** + * Merges in all include files + * + * @param array $config Config data that contains includes + * @param string $basePath Base path to use when a relative path is encountered + * + * @return array Returns the merged and included data + */ + protected function mergeIncludes(&$config, $basePath = null) + { + if (!empty($config['includes'])) { + foreach ($config['includes'] as &$path) { + // Account for relative paths + if ($path[0] != DIRECTORY_SEPARATOR && !isset($this->aliases[$path]) && $basePath) { + $path = "{$basePath}/{$path}"; + } + // Don't load the same files more than once + if (!isset($this->loadedFiles[$path])) { + $this->loadedFiles[$path] = true; + $config = $this->mergeData($this->loadFile($path), $config); + } + } + } + } + + /** + * Default implementation for merging two arrays of data (uses array_merge_recursive) + * + * @param array $a Original data + * @param array $b Data to merge into the original and overwrite existing values + * + * @return array + */ + protected function mergeData(array $a, array $b) + { + return array_merge_recursive($a, $b); + } +} diff --git a/vendor/guzzle/guzzle/src/Guzzle/Service/Builder/ServiceBuilder.php b/vendor/guzzle/guzzle/src/Guzzle/Service/Builder/ServiceBuilder.php new file mode 100644 index 0000000..38150db --- /dev/null +++ b/vendor/guzzle/guzzle/src/Guzzle/Service/Builder/ServiceBuilder.php @@ -0,0 +1,189 @@ +load($config, $globalParameters); + } + + /** + * @param array $serviceBuilderConfig Service configuration settings: + * - name: Name of the service + * - class: Client class to instantiate using a factory method + * - params: array of key value pair configuration settings for the builder + */ + public function __construct(array $serviceBuilderConfig = array()) + { + $this->builderConfig = $serviceBuilderConfig; + } + + public static function getAllEvents() + { + return array('service_builder.create_client'); + } + + public function unserialize($serialized) + { + $this->builderConfig = json_decode($serialized, true); + } + + public function serialize() + { + return json_encode($this->builderConfig); + } + + /** + * Attach a plugin to every client created by the builder + * + * @param EventSubscriberInterface $plugin Plugin to attach to each client + * + * @return self + */ + public function addGlobalPlugin(EventSubscriberInterface $plugin) + { + $this->plugins[] = $plugin; + + return $this; + } + + /** + * Get data from the service builder without triggering the building of a service + * + * @param string $name Name of the service to retrieve + * + * @return array|null + */ + public function getData($name) + { + return isset($this->builderConfig[$name]) ? $this->builderConfig[$name] : null; + } + + public function get($name, $throwAway = false) + { + if (!isset($this->builderConfig[$name])) { + + // Check to see if arbitrary data is being referenced + if (isset($this->clients[$name])) { + return $this->clients[$name]; + } + + // Check aliases and return a match if found + foreach ($this->builderConfig as $actualName => $config) { + if (isset($config['alias']) && $config['alias'] == $name) { + return $this->get($actualName, $throwAway); + } + } + throw new ServiceNotFoundException('No service is registered as ' . $name); + } + + if (!$throwAway && isset($this->clients[$name])) { + return $this->clients[$name]; + } + + $builder =& $this->builderConfig[$name]; + + // Convert references to the actual client + foreach ($builder['params'] as &$v) { + if (is_string($v) && substr($v, 0, 1) == '{' && substr($v, -1) == '}') { + $v = $this->get(trim($v, '{} ')); + } + } + + // Get the configured parameters and merge in any parameters provided for throw-away clients + $config = $builder['params']; + if (is_array($throwAway)) { + $config = $throwAway + $config; + } + + $client = $builder['class']::factory($config); + + if (!$throwAway) { + $this->clients[$name] = $client; + } + + if ($client instanceof ClientInterface) { + foreach ($this->plugins as $plugin) { + $client->addSubscriber($plugin); + } + // Dispatch an event letting listeners know a client was created + $this->dispatch('service_builder.create_client', array('client' => $client)); + } + + return $client; + } + + public function set($key, $service) + { + if (is_array($service) && isset($service['class']) && isset($service['params'])) { + $this->builderConfig[$key] = $service; + } else { + $this->clients[$key] = $service; + } + + return $this; + } + + public function offsetSet($offset, $value) + { + $this->set($offset, $value); + } + + public function offsetUnset($offset) + { + unset($this->builderConfig[$offset]); + unset($this->clients[$offset]); + } + + public function offsetExists($offset) + { + return isset($this->builderConfig[$offset]) || isset($this->clients[$offset]); + } + + public function offsetGet($offset) + { + return $this->get($offset); + } +} diff --git a/vendor/guzzle/guzzle/src/Guzzle/Service/Builder/ServiceBuilderInterface.php b/vendor/guzzle/guzzle/src/Guzzle/Service/Builder/ServiceBuilderInterface.php new file mode 100644 index 0000000..4fc310a --- /dev/null +++ b/vendor/guzzle/guzzle/src/Guzzle/Service/Builder/ServiceBuilderInterface.php @@ -0,0 +1,40 @@ + &$service) { + + $service['params'] = isset($service['params']) ? $service['params'] : array(); + + // Check if this client builder extends another client + if (!empty($service['extends'])) { + + // Make sure that the service it's extending has been defined + if (!isset($services[$service['extends']])) { + throw new ServiceNotFoundException( + "{$name} is trying to extend a non-existent service: {$service['extends']}" + ); + } + + $extended = &$services[$service['extends']]; + + // Use the correct class attribute + if (empty($service['class'])) { + $service['class'] = isset($extended['class']) ? $extended['class'] : ''; + } + if ($extendsParams = isset($extended['params']) ? $extended['params'] : false) { + $service['params'] = $service['params'] + $extendsParams; + } + } + + // Overwrite default values with global parameter values + if (!empty($options)) { + $service['params'] = $options + $service['params']; + } + + $service['class'] = isset($service['class']) ? $service['class'] : ''; + } + + return new $class($services); + } + + protected function mergeData(array $a, array $b) + { + $result = $b + $a; + + // Merge services using a recursive union of arrays + if (isset($a['services']) && $b['services']) { + + // Get a union of the services of the two arrays + $result['services'] = $b['services'] + $a['services']; + + // Merge each service in using a union of the two arrays + foreach ($result['services'] as $name => &$service) { + + // By default, services completely override a previously defined service unless it extends itself + if (isset($a['services'][$name]['extends']) + && isset($b['services'][$name]['extends']) + && $b['services'][$name]['extends'] == $name + ) { + $service += $a['services'][$name]; + // Use the `extends` attribute of the parent + $service['extends'] = $a['services'][$name]['extends']; + // Merge parameters using a union if both have parameters + if (isset($a['services'][$name]['params'])) { + $service['params'] += $a['services'][$name]['params']; + } + } + } + } + + return $result; + } +} diff --git a/vendor/guzzle/guzzle/src/Guzzle/Service/CachingConfigLoader.php b/vendor/guzzle/guzzle/src/Guzzle/Service/CachingConfigLoader.php new file mode 100644 index 0000000..26f8360 --- /dev/null +++ b/vendor/guzzle/guzzle/src/Guzzle/Service/CachingConfigLoader.php @@ -0,0 +1,46 @@ +loader = $loader; + $this->cache = $cache; + } + + public function load($config, array $options = array()) + { + if (!is_string($config)) { + $key = false; + } else { + $key = 'loader_' . crc32($config); + if ($result = $this->cache->fetch($key)) { + return $result; + } + } + + $result = $this->loader->load($config, $options); + if ($key) { + $this->cache->save($key, $result); + } + + return $result; + } +} diff --git a/vendor/guzzle/guzzle/src/Guzzle/Service/Client.php b/vendor/guzzle/guzzle/src/Guzzle/Service/Client.php new file mode 100644 index 0000000..3e5f8e5 --- /dev/null +++ b/vendor/guzzle/guzzle/src/Guzzle/Service/Client.php @@ -0,0 +1,297 @@ +getCommand($method, isset($args[0]) ? $args[0] : array())->getResult(); + } + + public function getCommand($name, array $args = array()) + { + // Add global client options to the command + if ($options = $this->getConfig(self::COMMAND_PARAMS)) { + $args += $options; + } + + if (!($command = $this->getCommandFactory()->factory($name, $args))) { + throw new InvalidArgumentException("Command was not found matching {$name}"); + } + + $command->setClient($this); + $this->dispatch('client.command.create', array('client' => $this, 'command' => $command)); + + return $command; + } + + /** + * Set the command factory used to create commands by name + * + * @param CommandFactoryInterface $factory Command factory + * + * @return self + */ + public function setCommandFactory(CommandFactoryInterface $factory) + { + $this->commandFactory = $factory; + + return $this; + } + + /** + * Set the resource iterator factory associated with the client + * + * @param ResourceIteratorFactoryInterface $factory Resource iterator factory + * + * @return self + */ + public function setResourceIteratorFactory(ResourceIteratorFactoryInterface $factory) + { + $this->resourceIteratorFactory = $factory; + + return $this; + } + + public function getIterator($command, array $commandOptions = null, array $iteratorOptions = array()) + { + if (!($command instanceof CommandInterface)) { + $command = $this->getCommand($command, $commandOptions ?: array()); + } + + return $this->getResourceIteratorFactory()->build($command, $iteratorOptions); + } + + public function execute($command) + { + if ($command instanceof CommandInterface) { + $this->send($this->prepareCommand($command)); + $this->dispatch('command.after_send', array('command' => $command)); + return $command->getResult(); + } elseif (is_array($command) || $command instanceof \Traversable) { + return $this->executeMultiple($command); + } else { + throw new InvalidArgumentException('Command must be a command or array of commands'); + } + } + + public function setDescription(ServiceDescriptionInterface $service) + { + $this->serviceDescription = $service; + + if ($this->getCommandFactory() && $this->getCommandFactory() instanceof CompositeFactory) { + $this->commandFactory->add(new Command\Factory\ServiceDescriptionFactory($service)); + } + + // If a baseUrl was set on the description, then update the client + if ($baseUrl = $service->getBaseUrl()) { + $this->setBaseUrl($baseUrl); + } + + return $this; + } + + public function getDescription() + { + return $this->serviceDescription; + } + + /** + * Set the inflector used with the client + * + * @param InflectorInterface $inflector Inflection object + * + * @return self + */ + public function setInflector(InflectorInterface $inflector) + { + $this->inflector = $inflector; + + return $this; + } + + /** + * Get the inflector used with the client + * + * @return self + */ + public function getInflector() + { + if (!$this->inflector) { + $this->inflector = Inflector::getDefault(); + } + + return $this->inflector; + } + + /** + * Prepare a command for sending and get the RequestInterface object created by the command + * + * @param CommandInterface $command Command to prepare + * + * @return RequestInterface + */ + protected function prepareCommand(CommandInterface $command) + { + // Set the client and prepare the command + $request = $command->setClient($this)->prepare(); + // Set the state to new if the command was previously executed + $request->setState(RequestInterface::STATE_NEW); + $this->dispatch('command.before_send', array('command' => $command)); + + return $request; + } + + /** + * Execute multiple commands in parallel + * + * @param array|Traversable $commands Array of CommandInterface objects to execute + * + * @return array Returns an array of the executed commands + * @throws Exception\CommandTransferException + */ + protected function executeMultiple($commands) + { + $requests = array(); + $commandRequests = new \SplObjectStorage(); + + foreach ($commands as $command) { + $request = $this->prepareCommand($command); + $commandRequests[$request] = $command; + $requests[] = $request; + } + + try { + $this->send($requests); + foreach ($commands as $command) { + $this->dispatch('command.after_send', array('command' => $command)); + } + return $commands; + } catch (MultiTransferException $failureException) { + // Throw a CommandTransferException using the successful and failed commands + $e = CommandTransferException::fromMultiTransferException($failureException); + + // Remove failed requests from the successful requests array and add to the failures array + foreach ($failureException->getFailedRequests() as $request) { + if (isset($commandRequests[$request])) { + $e->addFailedCommand($commandRequests[$request]); + unset($commandRequests[$request]); + } + } + + // Always emit the command after_send events for successful commands + foreach ($commandRequests as $success) { + $e->addSuccessfulCommand($commandRequests[$success]); + $this->dispatch('command.after_send', array('command' => $commandRequests[$success])); + } + + throw $e; + } + } + + protected function getResourceIteratorFactory() + { + if (!$this->resourceIteratorFactory) { + // Build the default resource iterator factory if one is not set + $clientClass = get_class($this); + $prefix = substr($clientClass, 0, strrpos($clientClass, '\\')); + $this->resourceIteratorFactory = new ResourceIteratorClassFactory(array( + "{$prefix}\\Iterator", + "{$prefix}\\Model" + )); + } + + return $this->resourceIteratorFactory; + } + + /** + * Get the command factory associated with the client + * + * @return CommandFactoryInterface + */ + protected function getCommandFactory() + { + if (!$this->commandFactory) { + $this->commandFactory = CompositeFactory::getDefaultChain($this); + } + + return $this->commandFactory; + } + + /** + * @deprecated + * @codeCoverageIgnore + */ + public function enableMagicMethods($isEnabled) + { + Version::warn(__METHOD__ . ' is deprecated'); + } +} diff --git a/vendor/guzzle/guzzle/src/Guzzle/Service/ClientInterface.php b/vendor/guzzle/guzzle/src/Guzzle/Service/ClientInterface.php new file mode 100644 index 0000000..814154f --- /dev/null +++ b/vendor/guzzle/guzzle/src/Guzzle/Service/ClientInterface.php @@ -0,0 +1,68 @@ +operation = $operation ?: $this->createOperation(); + foreach ($this->operation->getParams() as $name => $arg) { + $currentValue = $this[$name]; + $configValue = $arg->getValue($currentValue); + // If default or static values are set, then this should always be updated on the config object + if ($currentValue !== $configValue) { + $this[$name] = $configValue; + } + } + + $headers = $this[self::HEADERS_OPTION]; + if (!$headers instanceof Collection) { + $this[self::HEADERS_OPTION] = new Collection((array) $headers); + } + + // You can set a command.on_complete option in your parameters to set an onComplete callback + if ($onComplete = $this['command.on_complete']) { + unset($this['command.on_complete']); + $this->setOnComplete($onComplete); + } + + // Set the hidden additional parameters + if (!$this[self::HIDDEN_PARAMS]) { + $this[self::HIDDEN_PARAMS] = array( + self::HEADERS_OPTION, + self::RESPONSE_PROCESSING, + self::HIDDEN_PARAMS, + self::REQUEST_OPTIONS + ); + } + + $this->init(); + } + + /** + * Custom clone behavior + */ + public function __clone() + { + $this->request = null; + $this->result = null; + } + + /** + * Execute the command in the same manner as calling a function + * + * @return mixed Returns the result of {@see AbstractCommand::execute} + */ + public function __invoke() + { + return $this->execute(); + } + + public function getName() + { + return $this->operation->getName(); + } + + /** + * Get the API command information about the command + * + * @return OperationInterface + */ + public function getOperation() + { + return $this->operation; + } + + public function setOnComplete($callable) + { + if (!is_callable($callable)) { + throw new InvalidArgumentException('The onComplete function must be callable'); + } + + $this->onComplete = $callable; + + return $this; + } + + public function execute() + { + if (!$this->client) { + throw new CommandException('A client must be associated with the command before it can be executed.'); + } + + return $this->client->execute($this); + } + + public function getClient() + { + return $this->client; + } + + public function setClient(ClientInterface $client) + { + $this->client = $client; + + return $this; + } + + public function getRequest() + { + if (!$this->request) { + throw new CommandException('The command must be prepared before retrieving the request'); + } + + return $this->request; + } + + public function getResponse() + { + if (!$this->isExecuted()) { + $this->execute(); + } + + return $this->request->getResponse(); + } + + public function getResult() + { + if (!$this->isExecuted()) { + $this->execute(); + } + + if (null === $this->result) { + $this->process(); + // Call the onComplete method if one is set + if ($this->onComplete) { + call_user_func($this->onComplete, $this); + } + } + + return $this->result; + } + + public function setResult($result) + { + $this->result = $result; + + return $this; + } + + public function isPrepared() + { + return $this->request !== null; + } + + public function isExecuted() + { + return $this->request !== null && $this->request->getState() == 'complete'; + } + + public function prepare() + { + if (!$this->isPrepared()) { + if (!$this->client) { + throw new CommandException('A client must be associated with the command before it can be prepared.'); + } + + // If no response processing value was specified, then attempt to use the highest level of processing + if (!isset($this[self::RESPONSE_PROCESSING])) { + $this[self::RESPONSE_PROCESSING] = self::TYPE_MODEL; + } + + // Notify subscribers of the client that the command is being prepared + $this->client->dispatch('command.before_prepare', array('command' => $this)); + + // Fail on missing required arguments, and change parameters via filters + $this->validate(); + // Delegate to the subclass that implements the build method + $this->build(); + + // Add custom request headers set on the command + if ($headers = $this[self::HEADERS_OPTION]) { + foreach ($headers as $key => $value) { + $this->request->setHeader($key, $value); + } + } + + // Add any curl options to the request + if ($options = $this[Client::CURL_OPTIONS]) { + $this->request->getCurlOptions()->overwriteWith(CurlHandle::parseCurlConfig($options)); + } + + // Set a custom response body + if ($responseBody = $this[self::RESPONSE_BODY]) { + $this->request->setResponseBody($responseBody); + } + + $this->client->dispatch('command.after_prepare', array('command' => $this)); + } + + return $this->request; + } + + /** + * Set the validator used to validate and prepare command parameters and nested JSON schemas. If no validator is + * set, then the command will validate using the default {@see SchemaValidator}. + * + * @param ValidatorInterface $validator Validator used to prepare and validate properties against a JSON schema + * + * @return self + */ + public function setValidator(ValidatorInterface $validator) + { + $this->validator = $validator; + + return $this; + } + + public function getRequestHeaders() + { + return $this[self::HEADERS_OPTION]; + } + + /** + * Initialize the command (hook that can be implemented in subclasses) + */ + protected function init() {} + + /** + * Create the request object that will carry out the command + */ + abstract protected function build(); + + /** + * Hook used to create an operation for concrete commands that are not associated with a service description + * + * @return OperationInterface + */ + protected function createOperation() + { + return new Operation(array('name' => get_class($this))); + } + + /** + * Create the result of the command after the request has been completed. + * Override this method in subclasses to customize this behavior + */ + protected function process() + { + $this->result = $this[self::RESPONSE_PROCESSING] != self::TYPE_RAW + ? DefaultResponseParser::getInstance()->parse($this) + : $this->request->getResponse(); + } + + /** + * Validate and prepare the command based on the schema and rules defined by the command's Operation object + * + * @throws ValidationException when validation errors occur + */ + protected function validate() + { + // Do not perform request validation/transformation if it is disable + if ($this[self::DISABLE_VALIDATION]) { + return; + } + + $errors = array(); + $validator = $this->getValidator(); + foreach ($this->operation->getParams() as $name => $schema) { + $value = $this[$name]; + if (!$validator->validate($schema, $value)) { + $errors = array_merge($errors, $validator->getErrors()); + } elseif ($value !== $this[$name]) { + // Update the config value if it changed and no validation errors were encountered + $this->data[$name] = $value; + } + } + + // Validate additional parameters + $hidden = $this[self::HIDDEN_PARAMS]; + + if ($properties = $this->operation->getAdditionalParameters()) { + foreach ($this->toArray() as $name => $value) { + // It's only additional if it isn't defined in the schema + if (!$this->operation->hasParam($name) && !in_array($name, $hidden)) { + // Always set the name so that error messages are useful + $properties->setName($name); + if (!$validator->validate($properties, $value)) { + $errors = array_merge($errors, $validator->getErrors()); + } elseif ($value !== $this[$name]) { + $this->data[$name] = $value; + } + } + } + } + + if (!empty($errors)) { + $e = new ValidationException('Validation errors: ' . implode("\n", $errors)); + $e->setErrors($errors); + throw $e; + } + } + + /** + * Get the validator used to prepare and validate properties. If no validator has been set on the command, then + * the default {@see SchemaValidator} will be used. + * + * @return ValidatorInterface + */ + protected function getValidator() + { + if (!$this->validator) { + $this->validator = SchemaValidator::getInstance(); + } + + return $this->validator; + } + + /** + * Get array of any validation errors + * If no validator has been set then return false + */ + public function getValidationErrors() + { + if (!$this->validator) { + return false; + } + + return $this->validator->getErrors(); + } +} diff --git a/vendor/guzzle/guzzle/src/Guzzle/Service/Command/ClosureCommand.php b/vendor/guzzle/guzzle/src/Guzzle/Service/Command/ClosureCommand.php new file mode 100644 index 0000000..cb6ac40 --- /dev/null +++ b/vendor/guzzle/guzzle/src/Guzzle/Service/Command/ClosureCommand.php @@ -0,0 +1,41 @@ +request = $closure($this, $this->operation); + + if (!$this->request || !$this->request instanceof RequestInterface) { + throw new UnexpectedValueException('Closure command did not return a RequestInterface object'); + } + } +} diff --git a/vendor/guzzle/guzzle/src/Guzzle/Service/Command/CommandInterface.php b/vendor/guzzle/guzzle/src/Guzzle/Service/Command/CommandInterface.php new file mode 100644 index 0000000..fbb61d2 --- /dev/null +++ b/vendor/guzzle/guzzle/src/Guzzle/Service/Command/CommandInterface.php @@ -0,0 +1,128 @@ +stopPropagation(); + } + + /** + * Get the created object + * + * @return mixed + */ + public function getResult() + { + return $this['result']; + } +} diff --git a/vendor/guzzle/guzzle/src/Guzzle/Service/Command/DefaultRequestSerializer.php b/vendor/guzzle/guzzle/src/Guzzle/Service/Command/DefaultRequestSerializer.php new file mode 100644 index 0000000..2dc4acd --- /dev/null +++ b/vendor/guzzle/guzzle/src/Guzzle/Service/Command/DefaultRequestSerializer.php @@ -0,0 +1,169 @@ +factory = $factory; + } + + /** + * Add a location visitor to the serializer + * + * @param string $location Location to associate with the visitor + * @param RequestVisitorInterface $visitor Visitor to attach + * + * @return self + */ + public function addVisitor($location, RequestVisitorInterface $visitor) + { + $this->factory->addRequestVisitor($location, $visitor); + + return $this; + } + + public function prepare(CommandInterface $command) + { + $request = $this->createRequest($command); + // Keep an array of visitors found in the operation + $foundVisitors = array(); + $operation = $command->getOperation(); + + // Add arguments to the request using the location attribute + foreach ($operation->getParams() as $name => $arg) { + /** @var $arg \Guzzle\Service\Description\Parameter */ + $location = $arg->getLocation(); + // Skip 'uri' locations because they've already been processed + if ($location && $location != 'uri') { + // Instantiate visitors as they are detected in the properties + if (!isset($foundVisitors[$location])) { + $foundVisitors[$location] = $this->factory->getRequestVisitor($location); + } + // Ensure that a value has been set for this parameter + $value = $command[$name]; + if ($value !== null) { + // Apply the parameter value with the location visitor + $foundVisitors[$location]->visit($command, $request, $arg, $value); + } + } + } + + // Serialize additional parameters + if ($additional = $operation->getAdditionalParameters()) { + if ($visitor = $this->prepareAdditionalParameters($operation, $command, $request, $additional)) { + $foundVisitors[$additional->getLocation()] = $visitor; + } + } + + // Call the after method on each visitor found in the operation + foreach ($foundVisitors as $visitor) { + $visitor->after($command, $request); + } + + return $request; + } + + /** + * Serialize additional parameters + * + * @param OperationInterface $operation Operation that owns the command + * @param CommandInterface $command Command to prepare + * @param RequestInterface $request Request to serialize + * @param Parameter $additional Additional parameters + * + * @return null|RequestVisitorInterface + */ + protected function prepareAdditionalParameters( + OperationInterface $operation, + CommandInterface $command, + RequestInterface $request, + Parameter $additional + ) { + if (!($location = $additional->getLocation())) { + return; + } + + $visitor = $this->factory->getRequestVisitor($location); + $hidden = $command[$command::HIDDEN_PARAMS]; + + foreach ($command->toArray() as $key => $value) { + // Ignore values that are null or built-in command options + if ($value !== null + && !in_array($key, $hidden) + && !$operation->hasParam($key) + ) { + $additional->setName($key); + $visitor->visit($command, $request, $additional, $value); + } + } + + return $visitor; + } + + /** + * Create a request for the command and operation + * + * @param CommandInterface $command Command to create a request for + * + * @return RequestInterface + */ + protected function createRequest(CommandInterface $command) + { + $operation = $command->getOperation(); + $client = $command->getClient(); + $options = $command[AbstractCommand::REQUEST_OPTIONS] ?: array(); + + // If the command does not specify a template, then assume the base URL of the client + if (!($uri = $operation->getUri())) { + return $client->createRequest($operation->getHttpMethod(), $client->getBaseUrl(), null, null, $options); + } + + // Get the path values and use the client config settings + $variables = array(); + foreach ($operation->getParams() as $name => $arg) { + if ($arg->getLocation() == 'uri') { + if (isset($command[$name])) { + $variables[$name] = $arg->filter($command[$name]); + if (!is_array($variables[$name])) { + $variables[$name] = (string) $variables[$name]; + } + } + } + } + + return $client->createRequest($operation->getHttpMethod(), array($uri, $variables), null, null, $options); + } +} diff --git a/vendor/guzzle/guzzle/src/Guzzle/Service/Command/DefaultResponseParser.php b/vendor/guzzle/guzzle/src/Guzzle/Service/Command/DefaultResponseParser.php new file mode 100644 index 0000000..4fe3803 --- /dev/null +++ b/vendor/guzzle/guzzle/src/Guzzle/Service/Command/DefaultResponseParser.php @@ -0,0 +1,55 @@ +getRequest()->getResponse(); + + // Account for hard coded content-type values specified in service descriptions + if ($contentType = $command['command.expects']) { + $response->setHeader('Content-Type', $contentType); + } else { + $contentType = (string) $response->getHeader('Content-Type'); + } + + return $this->handleParsing($command, $response, $contentType); + } + + protected function handleParsing(CommandInterface $command, Response $response, $contentType) + { + $result = $response; + if ($result->getBody()) { + if (stripos($contentType, 'json') !== false) { + $result = $result->json(); + } elseif (stripos($contentType, 'xml') !== false) { + $result = $result->xml(); + } + } + + return $result; + } +} diff --git a/vendor/guzzle/guzzle/src/Guzzle/Service/Command/Factory/AliasFactory.php b/vendor/guzzle/guzzle/src/Guzzle/Service/Command/Factory/AliasFactory.php new file mode 100644 index 0000000..1c5ce07 --- /dev/null +++ b/vendor/guzzle/guzzle/src/Guzzle/Service/Command/Factory/AliasFactory.php @@ -0,0 +1,39 @@ +client = $client; + $this->aliases = $aliases; + } + + public function factory($name, array $args = array()) + { + if (isset($this->aliases[$name])) { + try { + return $this->client->getCommand($this->aliases[$name], $args); + } catch (InvalidArgumentException $e) { + return null; + } + } + } +} diff --git a/vendor/guzzle/guzzle/src/Guzzle/Service/Command/Factory/CompositeFactory.php b/vendor/guzzle/guzzle/src/Guzzle/Service/Command/Factory/CompositeFactory.php new file mode 100644 index 0000000..8c46983 --- /dev/null +++ b/vendor/guzzle/guzzle/src/Guzzle/Service/Command/Factory/CompositeFactory.php @@ -0,0 +1,154 @@ +getDescription()) { + $factories[] = new ServiceDescriptionFactory($description); + } + $factories[] = new ConcreteClassFactory($client); + + return new self($factories); + } + + /** + * @param array $factories Array of command factories + */ + public function __construct(array $factories = array()) + { + $this->factories = $factories; + } + + /** + * Add a command factory to the chain + * + * @param FactoryInterface $factory Factory to add + * @param string|FactoryInterface $before Insert the new command factory before a command factory class or object + * matching a class name. + * @return CompositeFactory + */ + public function add(FactoryInterface $factory, $before = null) + { + $pos = null; + + if ($before) { + foreach ($this->factories as $i => $f) { + if ($before instanceof FactoryInterface) { + if ($f === $before) { + $pos = $i; + break; + } + } elseif (is_string($before)) { + if ($f instanceof $before) { + $pos = $i; + break; + } + } + } + } + + if ($pos === null) { + $this->factories[] = $factory; + } else { + array_splice($this->factories, $i, 0, array($factory)); + } + + return $this; + } + + /** + * Check if the chain contains a specific command factory + * + * @param FactoryInterface|string $factory Factory to check + * + * @return bool + */ + public function has($factory) + { + return (bool) $this->find($factory); + } + + /** + * Remove a specific command factory from the chain + * + * @param string|FactoryInterface $factory Factory to remove by name or instance + * + * @return CompositeFactory + */ + public function remove($factory = null) + { + if (!($factory instanceof FactoryInterface)) { + $factory = $this->find($factory); + } + + $this->factories = array_values(array_filter($this->factories, function($f) use ($factory) { + return $f !== $factory; + })); + + return $this; + } + + /** + * Get a command factory by class name + * + * @param string|FactoryInterface $factory Command factory class or instance + * + * @return null|FactoryInterface + */ + public function find($factory) + { + foreach ($this->factories as $f) { + if ($factory === $f || (is_string($factory) && $f instanceof $factory)) { + return $f; + } + } + } + + /** + * Create a command using the associated command factories + * + * @param string $name Name of the command + * @param array $args Command arguments + * + * @return CommandInterface + */ + public function factory($name, array $args = array()) + { + foreach ($this->factories as $factory) { + $command = $factory->factory($name, $args); + if ($command) { + return $command; + } + } + } + + public function count() + { + return count($this->factories); + } + + public function getIterator() + { + return new \ArrayIterator($this->factories); + } +} diff --git a/vendor/guzzle/guzzle/src/Guzzle/Service/Command/Factory/ConcreteClassFactory.php b/vendor/guzzle/guzzle/src/Guzzle/Service/Command/Factory/ConcreteClassFactory.php new file mode 100644 index 0000000..0e93dea --- /dev/null +++ b/vendor/guzzle/guzzle/src/Guzzle/Service/Command/Factory/ConcreteClassFactory.php @@ -0,0 +1,47 @@ +client = $client; + $this->inflector = $inflector ?: Inflector::getDefault(); + } + + public function factory($name, array $args = array()) + { + // Determine the class to instantiate based on the namespace of the current client and the default directory + $prefix = $this->client->getConfig('command.prefix'); + if (!$prefix) { + // The prefix can be specified in a factory method and is cached + $prefix = implode('\\', array_slice(explode('\\', get_class($this->client)), 0, -1)) . '\\Command\\'; + $this->client->getConfig()->set('command.prefix', $prefix); + } + + $class = $prefix . str_replace(' ', '\\', ucwords(str_replace('.', ' ', $this->inflector->camel($name)))); + + // Create the concrete command if it exists + if (class_exists($class)) { + return new $class($args); + } + } +} diff --git a/vendor/guzzle/guzzle/src/Guzzle/Service/Command/Factory/FactoryInterface.php b/vendor/guzzle/guzzle/src/Guzzle/Service/Command/Factory/FactoryInterface.php new file mode 100644 index 0000000..35c299d --- /dev/null +++ b/vendor/guzzle/guzzle/src/Guzzle/Service/Command/Factory/FactoryInterface.php @@ -0,0 +1,21 @@ +map = $map; + } + + public function factory($name, array $args = array()) + { + if (isset($this->map[$name])) { + $class = $this->map[$name]; + + return new $class($args); + } + } +} diff --git a/vendor/guzzle/guzzle/src/Guzzle/Service/Command/Factory/ServiceDescriptionFactory.php b/vendor/guzzle/guzzle/src/Guzzle/Service/Command/Factory/ServiceDescriptionFactory.php new file mode 100644 index 0000000..b943a5b --- /dev/null +++ b/vendor/guzzle/guzzle/src/Guzzle/Service/Command/Factory/ServiceDescriptionFactory.php @@ -0,0 +1,71 @@ +setServiceDescription($description); + $this->inflector = $inflector; + } + + /** + * Change the service description used with the factory + * + * @param ServiceDescriptionInterface $description Service description to use + * + * @return FactoryInterface + */ + public function setServiceDescription(ServiceDescriptionInterface $description) + { + $this->description = $description; + + return $this; + } + + /** + * Returns the service description + * + * @return ServiceDescriptionInterface + */ + public function getServiceDescription() + { + return $this->description; + } + + public function factory($name, array $args = array()) + { + $command = $this->description->getOperation($name); + + // If a command wasn't found, then try to uppercase the first letter and try again + if (!$command) { + $command = $this->description->getOperation(ucfirst($name)); + // If an inflector was passed, then attempt to get the command using snake_case inflection + if (!$command && $this->inflector) { + $command = $this->description->getOperation($this->inflector->snake($name)); + } + } + + if ($command) { + $class = $command->getClass(); + return new $class($args, $command, $this->description); + } + } +} diff --git a/vendor/guzzle/guzzle/src/Guzzle/Service/Command/LocationVisitor/Request/AbstractRequestVisitor.php b/vendor/guzzle/guzzle/src/Guzzle/Service/Command/LocationVisitor/Request/AbstractRequestVisitor.php new file mode 100644 index 0000000..adcfca1 --- /dev/null +++ b/vendor/guzzle/guzzle/src/Guzzle/Service/Command/LocationVisitor/Request/AbstractRequestVisitor.php @@ -0,0 +1,69 @@ +resolveRecursively($value, $param) + : $param->filter($value); + } + + /** + * Map nested parameters into the location_key based parameters + * + * @param array $value Value to map + * @param Parameter $param Parameter that holds information about the current key + * + * @return array Returns the mapped array + */ + protected function resolveRecursively(array $value, Parameter $param) + { + foreach ($value as $name => &$v) { + switch ($param->getType()) { + case 'object': + if ($subParam = $param->getProperty($name)) { + $key = $subParam->getWireName(); + $value[$key] = $this->prepareValue($v, $subParam); + if ($name != $key) { + unset($value[$name]); + } + } elseif ($param->getAdditionalProperties() instanceof Parameter) { + $v = $this->prepareValue($v, $param->getAdditionalProperties()); + } + break; + case 'array': + if ($items = $param->getItems()) { + $v = $this->prepareValue($v, $items); + } + break; + } + } + + return $param->filter($value); + } +} diff --git a/vendor/guzzle/guzzle/src/Guzzle/Service/Command/LocationVisitor/Request/BodyVisitor.php b/vendor/guzzle/guzzle/src/Guzzle/Service/Command/LocationVisitor/Request/BodyVisitor.php new file mode 100644 index 0000000..168d780 --- /dev/null +++ b/vendor/guzzle/guzzle/src/Guzzle/Service/Command/LocationVisitor/Request/BodyVisitor.php @@ -0,0 +1,58 @@ +filter($value); + $entityBody = EntityBody::factory($value); + $request->setBody($entityBody); + $this->addExpectHeader($request, $entityBody, $param->getData('expect_header')); + // Add the Content-Encoding header if one is set on the EntityBody + if ($encoding = $entityBody->getContentEncoding()) { + $request->setHeader('Content-Encoding', $encoding); + } + } + + /** + * Add the appropriate expect header to a request + * + * @param EntityEnclosingRequestInterface $request Request to update + * @param EntityBodyInterface $body Entity body of the request + * @param string|int $expect Expect header setting + */ + protected function addExpectHeader(EntityEnclosingRequestInterface $request, EntityBodyInterface $body, $expect) + { + // Allow the `expect` data parameter to be set to remove the Expect header from the request + if ($expect === false) { + $request->removeHeader('Expect'); + } elseif ($expect !== true) { + // Default to using a MB as the point in which to start using the expect header + $expect = $expect ?: 1048576; + // If the expect_header value is numeric then only add if the size is greater than the cutoff + if (is_numeric($expect) && $body->getSize()) { + if ($body->getSize() < $expect) { + $request->removeHeader('Expect'); + } else { + $request->setHeader('Expect', '100-Continue'); + } + } + } + } +} diff --git a/vendor/guzzle/guzzle/src/Guzzle/Service/Command/LocationVisitor/Request/HeaderVisitor.php b/vendor/guzzle/guzzle/src/Guzzle/Service/Command/LocationVisitor/Request/HeaderVisitor.php new file mode 100644 index 0000000..2a53754 --- /dev/null +++ b/vendor/guzzle/guzzle/src/Guzzle/Service/Command/LocationVisitor/Request/HeaderVisitor.php @@ -0,0 +1,44 @@ +filter($value); + if ($param->getType() == 'object' && $param->getAdditionalProperties() instanceof Parameter) { + $this->addPrefixedHeaders($request, $param, $value); + } else { + $request->setHeader($param->getWireName(), $value); + } + } + + /** + * Add a prefixed array of headers to the request + * + * @param RequestInterface $request Request to update + * @param Parameter $param Parameter object + * @param array $value Header array to add + * + * @throws InvalidArgumentException + */ + protected function addPrefixedHeaders(RequestInterface $request, Parameter $param, $value) + { + if (!is_array($value)) { + throw new InvalidArgumentException('An array of mapped headers expected, but received a single value'); + } + $prefix = $param->getSentAs(); + foreach ($value as $headerName => $headerValue) { + $request->setHeader($prefix . $headerName, $headerValue); + } + } +} diff --git a/vendor/guzzle/guzzle/src/Guzzle/Service/Command/LocationVisitor/Request/JsonVisitor.php b/vendor/guzzle/guzzle/src/Guzzle/Service/Command/LocationVisitor/Request/JsonVisitor.php new file mode 100644 index 0000000..757e1c5 --- /dev/null +++ b/vendor/guzzle/guzzle/src/Guzzle/Service/Command/LocationVisitor/Request/JsonVisitor.php @@ -0,0 +1,63 @@ +data = new \SplObjectStorage(); + } + + /** + * Set the Content-Type header to add to the request if JSON is added to the body. This visitor does not add a + * Content-Type header unless you specify one here. + * + * @param string $header Header to set when JSON is added (e.g. application/json) + * + * @return self + */ + public function setContentTypeHeader($header = 'application/json') + { + $this->jsonContentType = $header; + + return $this; + } + + public function visit(CommandInterface $command, RequestInterface $request, Parameter $param, $value) + { + if (isset($this->data[$command])) { + $json = $this->data[$command]; + } else { + $json = array(); + } + $json[$param->getWireName()] = $this->prepareValue($value, $param); + $this->data[$command] = $json; + } + + public function after(CommandInterface $command, RequestInterface $request) + { + if (isset($this->data[$command])) { + // Don't overwrite the Content-Type if one is set + if ($this->jsonContentType && !$request->hasHeader('Content-Type')) { + $request->setHeader('Content-Type', $this->jsonContentType); + } + + $request->setBody(json_encode($this->data[$command])); + unset($this->data[$command]); + } + } +} diff --git a/vendor/guzzle/guzzle/src/Guzzle/Service/Command/LocationVisitor/Request/PostFieldVisitor.php b/vendor/guzzle/guzzle/src/Guzzle/Service/Command/LocationVisitor/Request/PostFieldVisitor.php new file mode 100644 index 0000000..975850b --- /dev/null +++ b/vendor/guzzle/guzzle/src/Guzzle/Service/Command/LocationVisitor/Request/PostFieldVisitor.php @@ -0,0 +1,18 @@ +setPostField($param->getWireName(), $this->prepareValue($value, $param)); + } +} diff --git a/vendor/guzzle/guzzle/src/Guzzle/Service/Command/LocationVisitor/Request/PostFileVisitor.php b/vendor/guzzle/guzzle/src/Guzzle/Service/Command/LocationVisitor/Request/PostFileVisitor.php new file mode 100644 index 0000000..0853ebe --- /dev/null +++ b/vendor/guzzle/guzzle/src/Guzzle/Service/Command/LocationVisitor/Request/PostFileVisitor.php @@ -0,0 +1,24 @@ +filter($value); + if ($value instanceof PostFileInterface) { + $request->addPostFile($value); + } else { + $request->addPostFile($param->getWireName(), $value); + } + } +} diff --git a/vendor/guzzle/guzzle/src/Guzzle/Service/Command/LocationVisitor/Request/QueryVisitor.php b/vendor/guzzle/guzzle/src/Guzzle/Service/Command/LocationVisitor/Request/QueryVisitor.php new file mode 100644 index 0000000..315877a --- /dev/null +++ b/vendor/guzzle/guzzle/src/Guzzle/Service/Command/LocationVisitor/Request/QueryVisitor.php @@ -0,0 +1,18 @@ +getQuery()->set($param->getWireName(), $this->prepareValue($value, $param)); + } +} diff --git a/vendor/guzzle/guzzle/src/Guzzle/Service/Command/LocationVisitor/Request/RequestVisitorInterface.php b/vendor/guzzle/guzzle/src/Guzzle/Service/Command/LocationVisitor/Request/RequestVisitorInterface.php new file mode 100644 index 0000000..14e0b2d --- /dev/null +++ b/vendor/guzzle/guzzle/src/Guzzle/Service/Command/LocationVisitor/Request/RequestVisitorInterface.php @@ -0,0 +1,31 @@ +setResponseBody($value); + } +} diff --git a/vendor/guzzle/guzzle/src/Guzzle/Service/Command/LocationVisitor/Request/XmlVisitor.php b/vendor/guzzle/guzzle/src/Guzzle/Service/Command/LocationVisitor/Request/XmlVisitor.php new file mode 100644 index 0000000..5b71487 --- /dev/null +++ b/vendor/guzzle/guzzle/src/Guzzle/Service/Command/LocationVisitor/Request/XmlVisitor.php @@ -0,0 +1,252 @@ +data = new \SplObjectStorage(); + } + + /** + * Change the content-type header that is added when XML is found + * + * @param string $header Header to set when XML is found + * + * @return self + */ + public function setContentTypeHeader($header) + { + $this->contentType = $header; + + return $this; + } + + public function visit(CommandInterface $command, RequestInterface $request, Parameter $param, $value) + { + $xml = isset($this->data[$command]) + ? $this->data[$command] + : $this->createRootElement($param->getParent()); + $this->addXml($xml, $param, $value); + + $this->data[$command] = $xml; + } + + public function after(CommandInterface $command, RequestInterface $request) + { + $xml = null; + + // If data was found that needs to be serialized, then do so + if (isset($this->data[$command])) { + $xml = $this->finishDocument($this->data[$command]); + unset($this->data[$command]); + } else { + // Check if XML should always be sent for the command + $operation = $command->getOperation(); + if ($operation->getData('xmlAllowEmpty')) { + $xmlWriter = $this->createRootElement($operation); + $xml = $this->finishDocument($xmlWriter); + } + } + + if ($xml) { + // Don't overwrite the Content-Type if one is set + if ($this->contentType && !$request->hasHeader('Content-Type')) { + $request->setHeader('Content-Type', $this->contentType); + } + $request->setBody($xml); + } + } + + /** + * Create the root XML element to use with a request + * + * @param Operation $operation Operation object + * + * @return \XMLWriter + */ + protected function createRootElement(Operation $operation) + { + static $defaultRoot = array('name' => 'Request'); + // If no root element was specified, then just wrap the XML in 'Request' + $root = $operation->getData('xmlRoot') ?: $defaultRoot; + // Allow the XML declaration to be customized with xmlEncoding + $encoding = $operation->getData('xmlEncoding'); + + $xmlWriter = $this->startDocument($encoding); + + $xmlWriter->startElement($root['name']); + // Create the wrapping element with no namespaces if no namespaces were present + if (!empty($root['namespaces'])) { + // Create the wrapping element with an array of one or more namespaces + foreach ((array) $root['namespaces'] as $prefix => $uri) { + $nsLabel = 'xmlns'; + if (!is_numeric($prefix)) { + $nsLabel .= ':'.$prefix; + } + $xmlWriter->writeAttribute($nsLabel, $uri); + } + } + return $xmlWriter; + } + + /** + * Recursively build the XML body + * + * @param \XMLWriter $xmlWriter XML to modify + * @param Parameter $param API Parameter + * @param mixed $value Value to add + */ + protected function addXml(\XMLWriter $xmlWriter, Parameter $param, $value) + { + if ($value === null) { + return; + } + + $value = $param->filter($value); + $type = $param->getType(); + $name = $param->getWireName(); + $prefix = null; + $namespace = $param->getData('xmlNamespace'); + if (false !== strpos($name, ':')) { + list($prefix, $name) = explode(':', $name, 2); + } + + if ($type == 'object' || $type == 'array') { + if (!$param->getData('xmlFlattened')) { + $xmlWriter->startElementNS(null, $name, $namespace); + } + if ($param->getType() == 'array') { + $this->addXmlArray($xmlWriter, $param, $value); + } elseif ($param->getType() == 'object') { + $this->addXmlObject($xmlWriter, $param, $value); + } + if (!$param->getData('xmlFlattened')) { + $xmlWriter->endElement(); + } + return; + } + if ($param->getData('xmlAttribute')) { + $this->writeAttribute($xmlWriter, $prefix, $name, $namespace, $value); + } else { + $this->writeElement($xmlWriter, $prefix, $name, $namespace, $value); + } + } + + /** + * Write an attribute with namespace if used + * + * @param \XMLWriter $xmlWriter XMLWriter instance + * @param string $prefix Namespace prefix if any + * @param string $name Attribute name + * @param string $namespace The uri of the namespace + * @param string $value The attribute content + */ + protected function writeAttribute($xmlWriter, $prefix, $name, $namespace, $value) + { + if (empty($namespace)) { + $xmlWriter->writeAttribute($name, $value); + } else { + $xmlWriter->writeAttributeNS($prefix, $name, $namespace, $value); + } + } + + /** + * Write an element with namespace if used + * + * @param \XMLWriter $xmlWriter XML writer resource + * @param string $prefix Namespace prefix if any + * @param string $name Element name + * @param string $namespace The uri of the namespace + * @param string $value The element content + */ + protected function writeElement(\XMLWriter $xmlWriter, $prefix, $name, $namespace, $value) + { + $xmlWriter->startElementNS($prefix, $name, $namespace); + if (strpbrk($value, '<>&')) { + $xmlWriter->writeCData($value); + } else { + $xmlWriter->writeRaw($value); + } + $xmlWriter->endElement(); + } + + /** + * Create a new xml writer and start a document + * + * @param string $encoding document encoding + * + * @return \XMLWriter the writer resource + */ + protected function startDocument($encoding) + { + $xmlWriter = new \XMLWriter(); + $xmlWriter->openMemory(); + $xmlWriter->startDocument('1.0', $encoding); + + return $xmlWriter; + } + + /** + * End the document and return the output + * + * @param \XMLWriter $xmlWriter + * + * @return \string the writer resource + */ + protected function finishDocument($xmlWriter) + { + $xmlWriter->endDocument(); + + return $xmlWriter->outputMemory(); + } + + /** + * Add an array to the XML + */ + protected function addXmlArray(\XMLWriter $xmlWriter, Parameter $param, &$value) + { + if ($items = $param->getItems()) { + foreach ($value as $v) { + $this->addXml($xmlWriter, $items, $v); + } + } + } + + /** + * Add an object to the XML + */ + protected function addXmlObject(\XMLWriter $xmlWriter, Parameter $param, &$value) + { + $noAttributes = array(); + // add values which have attributes + foreach ($value as $name => $v) { + if ($property = $param->getProperty($name)) { + if ($property->getData('xmlAttribute')) { + $this->addXml($xmlWriter, $property, $v); + } else { + $noAttributes[] = array('value' => $v, 'property' => $property); + } + } + } + // now add values with no attributes + foreach ($noAttributes as $element) { + $this->addXml($xmlWriter, $element['property'], $element['value']); + } + } +} diff --git a/vendor/guzzle/guzzle/src/Guzzle/Service/Command/LocationVisitor/Response/AbstractResponseVisitor.php b/vendor/guzzle/guzzle/src/Guzzle/Service/Command/LocationVisitor/Response/AbstractResponseVisitor.php new file mode 100644 index 0000000..d87eeb9 --- /dev/null +++ b/vendor/guzzle/guzzle/src/Guzzle/Service/Command/LocationVisitor/Response/AbstractResponseVisitor.php @@ -0,0 +1,26 @@ +getName()] = $param->filter($response->getBody()); + } +} diff --git a/vendor/guzzle/guzzle/src/Guzzle/Service/Command/LocationVisitor/Response/HeaderVisitor.php b/vendor/guzzle/guzzle/src/Guzzle/Service/Command/LocationVisitor/Response/HeaderVisitor.php new file mode 100644 index 0000000..0f8737c --- /dev/null +++ b/vendor/guzzle/guzzle/src/Guzzle/Service/Command/LocationVisitor/Response/HeaderVisitor.php @@ -0,0 +1,50 @@ +getType() == 'object' && $param->getAdditionalProperties() instanceof Parameter) { + $this->processPrefixedHeaders($response, $param, $value); + } else { + $value[$param->getName()] = $param->filter((string) $response->getHeader($param->getWireName())); + } + } + + /** + * Process a prefixed header array + * + * @param Response $response Response that contains the headers + * @param Parameter $param Parameter object + * @param array $value Value response array to modify + */ + protected function processPrefixedHeaders(Response $response, Parameter $param, &$value) + { + // Grab prefixed headers that should be placed into an array with the prefix stripped + if ($prefix = $param->getSentAs()) { + $container = $param->getName(); + $len = strlen($prefix); + // Find all matching headers and place them into the containing element + foreach ($response->getHeaders()->toArray() as $key => $header) { + if (stripos($key, $prefix) === 0) { + // Account for multi-value headers + $value[$container][substr($key, $len)] = count($header) == 1 ? end($header) : $header; + } + } + } + } +} diff --git a/vendor/guzzle/guzzle/src/Guzzle/Service/Command/LocationVisitor/Response/JsonVisitor.php b/vendor/guzzle/guzzle/src/Guzzle/Service/Command/LocationVisitor/Response/JsonVisitor.php new file mode 100644 index 0000000..a609ebd --- /dev/null +++ b/vendor/guzzle/guzzle/src/Guzzle/Service/Command/LocationVisitor/Response/JsonVisitor.php @@ -0,0 +1,93 @@ +getResponse()->json(); + } + + public function visit( + CommandInterface $command, + Response $response, + Parameter $param, + &$value, + $context = null + ) { + $name = $param->getName(); + $key = $param->getWireName(); + if (isset($value[$key])) { + $this->recursiveProcess($param, $value[$key]); + if ($key != $name) { + $value[$name] = $value[$key]; + unset($value[$key]); + } + } + } + + /** + * Recursively process a parameter while applying filters + * + * @param Parameter $param API parameter being validated + * @param mixed $value Value to validate and process. The value may change during this process. + */ + protected function recursiveProcess(Parameter $param, &$value) + { + if ($value === null) { + return; + } + + if (is_array($value)) { + $type = $param->getType(); + if ($type == 'array') { + foreach ($value as &$item) { + $this->recursiveProcess($param->getItems(), $item); + } + } elseif ($type == 'object' && !isset($value[0])) { + // On the above line, we ensure that the array is associative and not numerically indexed + $knownProperties = array(); + if ($properties = $param->getProperties()) { + foreach ($properties as $property) { + $name = $property->getName(); + $key = $property->getWireName(); + $knownProperties[$name] = 1; + if (isset($value[$key])) { + $this->recursiveProcess($property, $value[$key]); + if ($key != $name) { + $value[$name] = $value[$key]; + unset($value[$key]); + } + } + } + } + + // Remove any unknown and potentially unsafe properties + if ($param->getAdditionalProperties() === false) { + $value = array_intersect_key($value, $knownProperties); + } elseif (($additional = $param->getAdditionalProperties()) !== true) { + // Validate and filter additional properties + foreach ($value as &$v) { + $this->recursiveProcess($additional, $v); + } + } + } + } + + $value = $param->filter($value); + } +} diff --git a/vendor/guzzle/guzzle/src/Guzzle/Service/Command/LocationVisitor/Response/ReasonPhraseVisitor.php b/vendor/guzzle/guzzle/src/Guzzle/Service/Command/LocationVisitor/Response/ReasonPhraseVisitor.php new file mode 100644 index 0000000..1b10ebc --- /dev/null +++ b/vendor/guzzle/guzzle/src/Guzzle/Service/Command/LocationVisitor/Response/ReasonPhraseVisitor.php @@ -0,0 +1,23 @@ +getName()] = $response->getReasonPhrase(); + } +} diff --git a/vendor/guzzle/guzzle/src/Guzzle/Service/Command/LocationVisitor/Response/ResponseVisitorInterface.php b/vendor/guzzle/guzzle/src/Guzzle/Service/Command/LocationVisitor/Response/ResponseVisitorInterface.php new file mode 100644 index 0000000..033f40c --- /dev/null +++ b/vendor/guzzle/guzzle/src/Guzzle/Service/Command/LocationVisitor/Response/ResponseVisitorInterface.php @@ -0,0 +1,46 @@ +getName()] = $response->getStatusCode(); + } +} diff --git a/vendor/guzzle/guzzle/src/Guzzle/Service/Command/LocationVisitor/Response/XmlVisitor.php b/vendor/guzzle/guzzle/src/Guzzle/Service/Command/LocationVisitor/Response/XmlVisitor.php new file mode 100644 index 0000000..bb7124b --- /dev/null +++ b/vendor/guzzle/guzzle/src/Guzzle/Service/Command/LocationVisitor/Response/XmlVisitor.php @@ -0,0 +1,151 @@ +getResponse()->xml()), true); + } + + public function visit( + CommandInterface $command, + Response $response, + Parameter $param, + &$value, + $context = null + ) { + $sentAs = $param->getWireName(); + $name = $param->getName(); + if (isset($value[$sentAs])) { + $this->recursiveProcess($param, $value[$sentAs]); + if ($name != $sentAs) { + $value[$name] = $value[$sentAs]; + unset($value[$sentAs]); + } + } + } + + /** + * Recursively process a parameter while applying filters + * + * @param Parameter $param API parameter being processed + * @param mixed $value Value to validate and process. The value may change during this process. + */ + protected function recursiveProcess(Parameter $param, &$value) + { + $type = $param->getType(); + + if (!is_array($value)) { + if ($type == 'array') { + // Cast to an array if the value was a string, but should be an array + $this->recursiveProcess($param->getItems(), $value); + $value = array($value); + } + } elseif ($type == 'object') { + $this->processObject($param, $value); + } elseif ($type == 'array') { + $this->processArray($param, $value); + } elseif ($type == 'string' && gettype($value) == 'array') { + $value = ''; + } + + if ($value !== null) { + $value = $param->filter($value); + } + } + + /** + * Process an array + * + * @param Parameter $param API parameter being parsed + * @param mixed $value Value to process + */ + protected function processArray(Parameter $param, &$value) + { + // Convert the node if it was meant to be an array + if (!isset($value[0])) { + // Collections fo nodes are sometimes wrapped in an additional array. For example: + // 12 should become: + // array('Items' => array(array('a' => 1), array('a' => 2)) + // Some nodes are not wrapped. For example: 12 + // should become array('Foo' => array(array('a' => 1), array('a' => 2)) + if ($param->getItems() && isset($value[$param->getItems()->getWireName()])) { + // Account for the case of a collection wrapping wrapped nodes: Items => Item[] + $value = $value[$param->getItems()->getWireName()]; + // If the wrapped node only had one value, then make it an array of nodes + if (!isset($value[0]) || !is_array($value)) { + $value = array($value); + } + } elseif (!empty($value)) { + // Account for repeated nodes that must be an array: Foo => Baz, Foo => Baz, but only if the + // value is set and not empty + $value = array($value); + } + } + + foreach ($value as &$item) { + $this->recursiveProcess($param->getItems(), $item); + } + } + + /** + * Process an object + * + * @param Parameter $param API parameter being parsed + * @param mixed $value Value to process + */ + protected function processObject(Parameter $param, &$value) + { + // Ensure that the array is associative and not numerically indexed + if (!isset($value[0]) && ($properties = $param->getProperties())) { + $knownProperties = array(); + foreach ($properties as $property) { + $name = $property->getName(); + $sentAs = $property->getWireName(); + $knownProperties[$name] = 1; + if ($property->getData('xmlAttribute')) { + $this->processXmlAttribute($property, $value); + } elseif (isset($value[$sentAs])) { + $this->recursiveProcess($property, $value[$sentAs]); + if ($name != $sentAs) { + $value[$name] = $value[$sentAs]; + unset($value[$sentAs]); + } + } + } + + // Remove any unknown and potentially unsafe properties + if ($param->getAdditionalProperties() === false) { + $value = array_intersect_key($value, $knownProperties); + } + } + } + + /** + * Process an XML attribute property + * + * @param Parameter $property Property to process + * @param array $value Value to process and update + */ + protected function processXmlAttribute(Parameter $property, array &$value) + { + $sentAs = $property->getWireName(); + if (isset($value['@attributes'][$sentAs])) { + $value[$property->getName()] = $value['@attributes'][$sentAs]; + unset($value['@attributes'][$sentAs]); + if (empty($value['@attributes'])) { + unset($value['@attributes']); + } + } + } +} diff --git a/vendor/guzzle/guzzle/src/Guzzle/Service/Command/LocationVisitor/VisitorFlyweight.php b/vendor/guzzle/guzzle/src/Guzzle/Service/Command/LocationVisitor/VisitorFlyweight.php new file mode 100644 index 0000000..74cb628 --- /dev/null +++ b/vendor/guzzle/guzzle/src/Guzzle/Service/Command/LocationVisitor/VisitorFlyweight.php @@ -0,0 +1,138 @@ + 'Guzzle\Service\Command\LocationVisitor\Request\BodyVisitor', + 'request.header' => 'Guzzle\Service\Command\LocationVisitor\Request\HeaderVisitor', + 'request.json' => 'Guzzle\Service\Command\LocationVisitor\Request\JsonVisitor', + 'request.postField' => 'Guzzle\Service\Command\LocationVisitor\Request\PostFieldVisitor', + 'request.postFile' => 'Guzzle\Service\Command\LocationVisitor\Request\PostFileVisitor', + 'request.query' => 'Guzzle\Service\Command\LocationVisitor\Request\QueryVisitor', + 'request.response_body' => 'Guzzle\Service\Command\LocationVisitor\Request\ResponseBodyVisitor', + 'request.responseBody' => 'Guzzle\Service\Command\LocationVisitor\Request\ResponseBodyVisitor', + 'request.xml' => 'Guzzle\Service\Command\LocationVisitor\Request\XmlVisitor', + 'response.body' => 'Guzzle\Service\Command\LocationVisitor\Response\BodyVisitor', + 'response.header' => 'Guzzle\Service\Command\LocationVisitor\Response\HeaderVisitor', + 'response.json' => 'Guzzle\Service\Command\LocationVisitor\Response\JsonVisitor', + 'response.reasonPhrase' => 'Guzzle\Service\Command\LocationVisitor\Response\ReasonPhraseVisitor', + 'response.statusCode' => 'Guzzle\Service\Command\LocationVisitor\Response\StatusCodeVisitor', + 'response.xml' => 'Guzzle\Service\Command\LocationVisitor\Response\XmlVisitor' + ); + + /** @var array Array of mappings of location names to classes */ + protected $mappings; + + /** @var array Cache of instantiated visitors */ + protected $cache = array(); + + /** + * @return self + * @codeCoverageIgnore + */ + public static function getInstance() + { + if (!self::$instance) { + self::$instance = new self(); + } + + return self::$instance; + } + + /** + * @param array $mappings Array mapping request.name and response.name to location visitor classes. Leave null to + * use the default values. + */ + public function __construct(array $mappings = null) + { + $this->mappings = $mappings === null ? self::$defaultMappings : $mappings; + } + + /** + * Get an instance of a request visitor by location name + * + * @param string $visitor Visitor name + * + * @return RequestVisitorInterface + */ + public function getRequestVisitor($visitor) + { + return $this->getKey('request.' . $visitor); + } + + /** + * Get an instance of a response visitor by location name + * + * @param string $visitor Visitor name + * + * @return ResponseVisitorInterface + */ + public function getResponseVisitor($visitor) + { + return $this->getKey('response.' . $visitor); + } + + /** + * Add a response visitor to the factory by name + * + * @param string $name Name of the visitor + * @param RequestVisitorInterface $visitor Visitor to add + * + * @return self + */ + public function addRequestVisitor($name, RequestVisitorInterface $visitor) + { + $this->cache['request.' . $name] = $visitor; + + return $this; + } + + /** + * Add a response visitor to the factory by name + * + * @param string $name Name of the visitor + * @param ResponseVisitorInterface $visitor Visitor to add + * + * @return self + */ + public function addResponseVisitor($name, ResponseVisitorInterface $visitor) + { + $this->cache['response.' . $name] = $visitor; + + return $this; + } + + /** + * Get a visitor by key value name + * + * @param string $key Key name to retrieve + * + * @return mixed + * @throws InvalidArgumentException + */ + private function getKey($key) + { + if (!isset($this->cache[$key])) { + if (!isset($this->mappings[$key])) { + list($type, $name) = explode('.', $key); + throw new InvalidArgumentException("No {$type} visitor has been mapped for {$name}"); + } + $this->cache[$key] = new $this->mappings[$key]; + } + + return $this->cache[$key]; + } +} diff --git a/vendor/guzzle/guzzle/src/Guzzle/Service/Command/OperationCommand.php b/vendor/guzzle/guzzle/src/Guzzle/Service/Command/OperationCommand.php new file mode 100644 index 0000000..0748b5a --- /dev/null +++ b/vendor/guzzle/guzzle/src/Guzzle/Service/Command/OperationCommand.php @@ -0,0 +1,89 @@ +responseParser = $parser; + + return $this; + } + + /** + * Set the request serializer used with the command + * + * @param RequestSerializerInterface $serializer Request serializer + * + * @return self + */ + public function setRequestSerializer(RequestSerializerInterface $serializer) + { + $this->requestSerializer = $serializer; + + return $this; + } + + /** + * Get the request serializer used with the command + * + * @return RequestSerializerInterface + */ + public function getRequestSerializer() + { + if (!$this->requestSerializer) { + // Use the default request serializer if none was found + $this->requestSerializer = DefaultRequestSerializer::getInstance(); + } + + return $this->requestSerializer; + } + + /** + * Get the response parser used for the operation + * + * @return ResponseParserInterface + */ + public function getResponseParser() + { + if (!$this->responseParser) { + // Use the default response parser if none was found + $this->responseParser = OperationResponseParser::getInstance(); + } + + return $this->responseParser; + } + + protected function build() + { + // Prepare and serialize the request + $this->request = $this->getRequestSerializer()->prepare($this); + } + + protected function process() + { + // Do not process the response if 'command.response_processing' is set to 'raw' + $this->result = $this[self::RESPONSE_PROCESSING] == self::TYPE_RAW + ? $this->request->getResponse() + : $this->getResponseParser()->parse($this); + } +} diff --git a/vendor/guzzle/guzzle/src/Guzzle/Service/Command/OperationResponseParser.php b/vendor/guzzle/guzzle/src/Guzzle/Service/Command/OperationResponseParser.php new file mode 100644 index 0000000..ca00bc0 --- /dev/null +++ b/vendor/guzzle/guzzle/src/Guzzle/Service/Command/OperationResponseParser.php @@ -0,0 +1,195 @@ +factory = $factory; + $this->schemaInModels = $schemaInModels; + } + + /** + * Add a location visitor to the command + * + * @param string $location Location to associate with the visitor + * @param ResponseVisitorInterface $visitor Visitor to attach + * + * @return self + */ + public function addVisitor($location, ResponseVisitorInterface $visitor) + { + $this->factory->addResponseVisitor($location, $visitor); + + return $this; + } + + protected function handleParsing(CommandInterface $command, Response $response, $contentType) + { + $operation = $command->getOperation(); + $type = $operation->getResponseType(); + $model = null; + + if ($type == OperationInterface::TYPE_MODEL) { + $model = $operation->getServiceDescription()->getModel($operation->getResponseClass()); + } elseif ($type == OperationInterface::TYPE_CLASS) { + return $this->parseClass($command); + } + + if (!$model) { + // Return basic processing if the responseType is not model or the model cannot be found + return parent::handleParsing($command, $response, $contentType); + } elseif ($command[AbstractCommand::RESPONSE_PROCESSING] != AbstractCommand::TYPE_MODEL) { + // Returns a model with no visiting if the command response processing is not model + return new Model(parent::handleParsing($command, $response, $contentType)); + } else { + // Only inject the schema into the model if "schemaInModel" is true + return new Model($this->visitResult($model, $command, $response), $this->schemaInModels ? $model : null); + } + } + + /** + * Parse a class object + * + * @param CommandInterface $command Command to parse into an object + * + * @return mixed + * @throws ResponseClassException + */ + protected function parseClass(CommandInterface $command) + { + // Emit the operation.parse_class event. If a listener injects a 'result' property, then that will be the result + $event = new CreateResponseClassEvent(array('command' => $command)); + $command->getClient()->getEventDispatcher()->dispatch('command.parse_response', $event); + if ($result = $event->getResult()) { + return $result; + } + + $className = $command->getOperation()->getResponseClass(); + if (!method_exists($className, 'fromCommand')) { + throw new ResponseClassException("{$className} must exist and implement a static fromCommand() method"); + } + + return $className::fromCommand($command); + } + + /** + * Perform transformations on the result array + * + * @param Parameter $model Model that defines the structure + * @param CommandInterface $command Command that performed the operation + * @param Response $response Response received + * + * @return array Returns the array of result data + */ + protected function visitResult(Parameter $model, CommandInterface $command, Response $response) + { + $foundVisitors = $result = $knownProps = array(); + $props = $model->getProperties(); + + foreach ($props as $schema) { + if ($location = $schema->getLocation()) { + // Trigger the before method on the first found visitor of this type + if (!isset($foundVisitors[$location])) { + $foundVisitors[$location] = $this->factory->getResponseVisitor($location); + $foundVisitors[$location]->before($command, $result); + } + } + } + + // Visit additional properties when it is an actual schema + if (($additional = $model->getAdditionalProperties()) instanceof Parameter) { + $this->visitAdditionalProperties($model, $command, $response, $additional, $result, $foundVisitors); + } + + // Apply the parameter value with the location visitor + foreach ($props as $schema) { + $knownProps[$schema->getName()] = 1; + if ($location = $schema->getLocation()) { + $foundVisitors[$location]->visit($command, $response, $schema, $result); + } + } + + // Remove any unknown and potentially unsafe top-level properties + if ($additional === false) { + $result = array_intersect_key($result, $knownProps); + } + + // Call the after() method of each found visitor + foreach ($foundVisitors as $visitor) { + $visitor->after($command); + } + + return $result; + } + + protected function visitAdditionalProperties( + Parameter $model, + CommandInterface $command, + Response $response, + Parameter $additional, + &$result, + array &$foundVisitors + ) { + // Only visit when a location is specified + if ($location = $additional->getLocation()) { + if (!isset($foundVisitors[$location])) { + $foundVisitors[$location] = $this->factory->getResponseVisitor($location); + $foundVisitors[$location]->before($command, $result); + } + // Only traverse if an array was parsed from the before() visitors + if (is_array($result)) { + // Find each additional property + foreach (array_keys($result) as $key) { + // Check if the model actually knows this property. If so, then it is not additional + if (!$model->getProperty($key)) { + // Set the name to the key so that we can parse it with each visitor + $additional->setName($key); + $foundVisitors[$location]->visit($command, $response, $additional, $result); + } + } + // Reset the additionalProperties name to null + $additional->setName(null); + } + } + } +} diff --git a/vendor/guzzle/guzzle/src/Guzzle/Service/Command/RequestSerializerInterface.php b/vendor/guzzle/guzzle/src/Guzzle/Service/Command/RequestSerializerInterface.php new file mode 100644 index 0000000..60b9334 --- /dev/null +++ b/vendor/guzzle/guzzle/src/Guzzle/Service/Command/RequestSerializerInterface.php @@ -0,0 +1,21 @@ + true, 'httpMethod' => true, 'uri' => true, 'class' => true, 'responseClass' => true, + 'responseType' => true, 'responseNotes' => true, 'notes' => true, 'summary' => true, 'documentationUrl' => true, + 'deprecated' => true, 'data' => true, 'parameters' => true, 'additionalParameters' => true, + 'errorResponses' => true + ); + + /** @var array Parameters */ + protected $parameters = array(); + + /** @var Parameter Additional parameters schema */ + protected $additionalParameters; + + /** @var string Name of the command */ + protected $name; + + /** @var string HTTP method */ + protected $httpMethod; + + /** @var string This is a short summary of what the operation does */ + protected $summary; + + /** @var string A longer text field to explain the behavior of the operation. */ + protected $notes; + + /** @var string Reference URL providing more information about the operation */ + protected $documentationUrl; + + /** @var string HTTP URI of the command */ + protected $uri; + + /** @var string Class of the command object */ + protected $class; + + /** @var string This is what is returned from the method */ + protected $responseClass; + + /** @var string Type information about the response */ + protected $responseType; + + /** @var string Information about the response returned by the operation */ + protected $responseNotes; + + /** @var bool Whether or not the command is deprecated */ + protected $deprecated; + + /** @var array Array of errors that could occur when running the command */ + protected $errorResponses; + + /** @var ServiceDescriptionInterface */ + protected $description; + + /** @var array Extra operation information */ + protected $data; + + /** + * Builds an Operation object using an array of configuration data: + * - name: (string) Name of the command + * - httpMethod: (string) HTTP method of the operation + * - uri: (string) URI template that can create a relative or absolute URL + * - class: (string) Concrete class that implements this command + * - parameters: (array) Associative array of parameters for the command. {@see Parameter} for information. + * - summary: (string) This is a short summary of what the operation does + * - notes: (string) A longer text field to explain the behavior of the operation. + * - documentationUrl: (string) Reference URL providing more information about the operation + * - responseClass: (string) This is what is returned from the method. Can be a primitive, PSR-0 compliant + * class name, or model. + * - responseNotes: (string) Information about the response returned by the operation + * - responseType: (string) One of 'primitive', 'class', 'model', or 'documentation'. If not specified, this + * value will be automatically inferred based on whether or not there is a model matching the + * name, if a matching PSR-0 compliant class name is found, or set to 'primitive' by default. + * - deprecated: (bool) Set to true if this is a deprecated command + * - errorResponses: (array) Errors that could occur when executing the command. Array of hashes, each with a + * 'code' (the HTTP response code), 'reason' (response reason phrase or description of the + * error), and 'class' (a custom exception class that would be thrown if the error is + * encountered). + * - data: (array) Any extra data that might be used to help build or serialize the operation + * - additionalParameters: (null|array) Parameter schema to use when an option is passed to the operation that is + * not in the schema + * + * @param array $config Array of configuration data + * @param ServiceDescriptionInterface $description Service description used to resolve models if $ref tags are found + */ + public function __construct(array $config = array(), ServiceDescriptionInterface $description = null) + { + $this->description = $description; + + // Get the intersection of the available properties and properties set on the operation + foreach (array_intersect_key($config, self::$properties) as $key => $value) { + $this->{$key} = $value; + } + + $this->class = $this->class ?: self::DEFAULT_COMMAND_CLASS; + $this->deprecated = (bool) $this->deprecated; + $this->errorResponses = $this->errorResponses ?: array(); + $this->data = $this->data ?: array(); + + if (!$this->responseClass) { + $this->responseClass = 'array'; + $this->responseType = 'primitive'; + } elseif ($this->responseType) { + // Set the response type to perform validation + $this->setResponseType($this->responseType); + } else { + // A response class was set and no response type was set, so guess what the type is + $this->inferResponseType(); + } + + // Parameters need special handling when adding + if ($this->parameters) { + foreach ($this->parameters as $name => $param) { + if ($param instanceof Parameter) { + $param->setName($name)->setParent($this); + } elseif (is_array($param)) { + $param['name'] = $name; + $this->addParam(new Parameter($param, $this->description)); + } + } + } + + if ($this->additionalParameters) { + if ($this->additionalParameters instanceof Parameter) { + $this->additionalParameters->setParent($this); + } elseif (is_array($this->additionalParameters)) { + $this->setadditionalParameters(new Parameter($this->additionalParameters, $this->description)); + } + } + } + + public function toArray() + { + $result = array(); + // Grab valid properties and filter out values that weren't set + foreach (array_keys(self::$properties) as $check) { + if ($value = $this->{$check}) { + $result[$check] = $value; + } + } + // Remove the name property + unset($result['name']); + // Parameters need to be converted to arrays + $result['parameters'] = array(); + foreach ($this->parameters as $key => $param) { + $result['parameters'][$key] = $param->toArray(); + } + // Additional parameters need to be cast to an array + if ($this->additionalParameters instanceof Parameter) { + $result['additionalParameters'] = $this->additionalParameters->toArray(); + } + + return $result; + } + + public function getServiceDescription() + { + return $this->description; + } + + public function setServiceDescription(ServiceDescriptionInterface $description) + { + $this->description = $description; + + return $this; + } + + public function getParams() + { + return $this->parameters; + } + + public function getParamNames() + { + return array_keys($this->parameters); + } + + public function hasParam($name) + { + return isset($this->parameters[$name]); + } + + public function getParam($param) + { + return isset($this->parameters[$param]) ? $this->parameters[$param] : null; + } + + /** + * Add a parameter to the command + * + * @param Parameter $param Parameter to add + * + * @return self + */ + public function addParam(Parameter $param) + { + $this->parameters[$param->getName()] = $param; + $param->setParent($this); + + return $this; + } + + /** + * Remove a parameter from the command + * + * @param string $name Name of the parameter to remove + * + * @return self + */ + public function removeParam($name) + { + unset($this->parameters[$name]); + + return $this; + } + + public function getHttpMethod() + { + return $this->httpMethod; + } + + /** + * Set the HTTP method of the command + * + * @param string $httpMethod Method to set + * + * @return self + */ + public function setHttpMethod($httpMethod) + { + $this->httpMethod = $httpMethod; + + return $this; + } + + public function getClass() + { + return $this->class; + } + + /** + * Set the concrete class of the command + * + * @param string $className Concrete class name + * + * @return self + */ + public function setClass($className) + { + $this->class = $className; + + return $this; + } + + public function getName() + { + return $this->name; + } + + /** + * Set the name of the command + * + * @param string $name Name of the command + * + * @return self + */ + public function setName($name) + { + $this->name = $name; + + return $this; + } + + public function getSummary() + { + return $this->summary; + } + + /** + * Set a short summary of what the operation does + * + * @param string $summary Short summary of the operation + * + * @return self + */ + public function setSummary($summary) + { + $this->summary = $summary; + + return $this; + } + + public function getNotes() + { + return $this->notes; + } + + /** + * Set a longer text field to explain the behavior of the operation. + * + * @param string $notes Notes on the operation + * + * @return self + */ + public function setNotes($notes) + { + $this->notes = $notes; + + return $this; + } + + public function getDocumentationUrl() + { + return $this->documentationUrl; + } + + /** + * Set the URL pointing to additional documentation on the command + * + * @param string $docUrl Documentation URL + * + * @return self + */ + public function setDocumentationUrl($docUrl) + { + $this->documentationUrl = $docUrl; + + return $this; + } + + public function getResponseClass() + { + return $this->responseClass; + } + + /** + * Set what is returned from the method. Can be a primitive, class name, or model. For example: 'array', + * 'Guzzle\\Foo\\Baz', or 'MyModelName' (to reference a model by ID). + * + * @param string $responseClass Type of response + * + * @return self + */ + public function setResponseClass($responseClass) + { + $this->responseClass = $responseClass; + $this->inferResponseType(); + + return $this; + } + + public function getResponseType() + { + return $this->responseType; + } + + /** + * Set qualifying information about the responseClass. One of 'primitive', 'class', 'model', or 'documentation' + * + * @param string $responseType Response type information + * + * @return self + * @throws InvalidArgumentException + */ + public function setResponseType($responseType) + { + static $types = array( + self::TYPE_PRIMITIVE => true, + self::TYPE_CLASS => true, + self::TYPE_MODEL => true, + self::TYPE_DOCUMENTATION => true + ); + if (!isset($types[$responseType])) { + throw new InvalidArgumentException('responseType must be one of ' . implode(', ', array_keys($types))); + } + + $this->responseType = $responseType; + + return $this; + } + + public function getResponseNotes() + { + return $this->responseNotes; + } + + /** + * Set notes about the response of the operation + * + * @param string $notes Response notes + * + * @return self + */ + public function setResponseNotes($notes) + { + $this->responseNotes = $notes; + + return $this; + } + + public function getDeprecated() + { + return $this->deprecated; + } + + /** + * Set whether or not the command is deprecated + * + * @param bool $isDeprecated Set to true to mark as deprecated + * + * @return self + */ + public function setDeprecated($isDeprecated) + { + $this->deprecated = $isDeprecated; + + return $this; + } + + public function getUri() + { + return $this->uri; + } + + /** + * Set the URI template of the command + * + * @param string $uri URI template to set + * + * @return self + */ + public function setUri($uri) + { + $this->uri = $uri; + + return $this; + } + + public function getErrorResponses() + { + return $this->errorResponses; + } + + /** + * Add an error to the command + * + * @param string $code HTTP response code + * @param string $reason HTTP response reason phrase or information about the error + * @param string $class Exception class associated with the error + * + * @return self + */ + public function addErrorResponse($code, $reason, $class) + { + $this->errorResponses[] = array('code' => $code, 'reason' => $reason, 'class' => $class); + + return $this; + } + + /** + * Set all of the error responses of the operation + * + * @param array $errorResponses Hash of error name to a hash containing a code, reason, class + * + * @return self + */ + public function setErrorResponses(array $errorResponses) + { + $this->errorResponses = $errorResponses; + + return $this; + } + + public function getData($name) + { + return isset($this->data[$name]) ? $this->data[$name] : null; + } + + /** + * Set a particular data point on the operation + * + * @param string $name Name of the data value + * @param mixed $value Value to set + * + * @return self + */ + public function setData($name, $value) + { + $this->data[$name] = $value; + + return $this; + } + + /** + * Get the additionalParameters of the operation + * + * @return Parameter|null + */ + public function getAdditionalParameters() + { + return $this->additionalParameters; + } + + /** + * Set the additionalParameters of the operation + * + * @param Parameter|null $parameter Parameter to set + * + * @return self + */ + public function setAdditionalParameters($parameter) + { + if ($this->additionalParameters = $parameter) { + $this->additionalParameters->setParent($this); + } + + return $this; + } + + /** + * Infer the response type from the responseClass value + */ + protected function inferResponseType() + { + static $primitives = array('array' => 1, 'boolean' => 1, 'string' => 1, 'integer' => 1, '' => 1); + if (isset($primitives[$this->responseClass])) { + $this->responseType = self::TYPE_PRIMITIVE; + } elseif ($this->description && $this->description->hasModel($this->responseClass)) { + $this->responseType = self::TYPE_MODEL; + } else { + $this->responseType = self::TYPE_CLASS; + } + } +} diff --git a/vendor/guzzle/guzzle/src/Guzzle/Service/Description/OperationInterface.php b/vendor/guzzle/guzzle/src/Guzzle/Service/Description/OperationInterface.php new file mode 100644 index 0000000..4de41bd --- /dev/null +++ b/vendor/guzzle/guzzle/src/Guzzle/Service/Description/OperationInterface.php @@ -0,0 +1,159 @@ +getModel($data['$ref'])) { + $data = $model->toArray() + $data; + } + } elseif (isset($data['extends'])) { + // If this parameter extends from another parameter then start with the actual data + // union in the parent's data (e.g. actual supersedes parent) + if ($extends = $description->getModel($data['extends'])) { + $data += $extends->toArray(); + } + } + } + + // Pull configuration data into the parameter + foreach ($data as $key => $value) { + $this->{$key} = $value; + } + + $this->serviceDescription = $description; + $this->required = (bool) $this->required; + $this->data = (array) $this->data; + + if ($this->filters) { + $this->setFilters((array) $this->filters); + } + + if ($this->type == 'object' && $this->additionalProperties === null) { + $this->additionalProperties = true; + } + } + + /** + * Convert the object to an array + * + * @return array + */ + public function toArray() + { + static $checks = array('required', 'description', 'static', 'type', 'format', 'instanceOf', 'location', 'sentAs', + 'pattern', 'minimum', 'maximum', 'minItems', 'maxItems', 'minLength', 'maxLength', 'data', 'enum', + 'filters'); + + $result = array(); + + // Anything that is in the `Items` attribute of an array *must* include it's name if available + if ($this->parent instanceof self && $this->parent->getType() == 'array' && isset($this->name)) { + $result['name'] = $this->name; + } + + foreach ($checks as $c) { + if ($value = $this->{$c}) { + $result[$c] = $value; + } + } + + if ($this->default !== null) { + $result['default'] = $this->default; + } + + if ($this->items !== null) { + $result['items'] = $this->getItems()->toArray(); + } + + if ($this->additionalProperties !== null) { + $result['additionalProperties'] = $this->getAdditionalProperties(); + if ($result['additionalProperties'] instanceof self) { + $result['additionalProperties'] = $result['additionalProperties']->toArray(); + } + } + + if ($this->type == 'object' && $this->properties) { + $result['properties'] = array(); + foreach ($this->getProperties() as $name => $property) { + $result['properties'][$name] = $property->toArray(); + } + } + + return $result; + } + + /** + * Get the default or static value of the command based on a value + * + * @param string $value Value that is currently set + * + * @return mixed Returns the value, a static value if one is present, or a default value + */ + public function getValue($value) + { + if ($this->static || ($this->default !== null && $value === null)) { + return $this->default; + } + + return $value; + } + + /** + * Run a value through the filters OR format attribute associated with the parameter + * + * @param mixed $value Value to filter + * + * @return mixed Returns the filtered value + */ + public function filter($value) + { + // Formats are applied exclusively and supersed filters + if ($this->format) { + return SchemaFormatter::format($this->format, $value); + } + + // Convert Boolean values + if ($this->type == 'boolean' && !is_bool($value)) { + $value = filter_var($value, FILTER_VALIDATE_BOOLEAN); + } + + // Apply filters to the value + if ($this->filters) { + foreach ($this->filters as $filter) { + if (is_array($filter)) { + // Convert complex filters that hold value place holders + foreach ($filter['args'] as &$data) { + if ($data == '@value') { + $data = $value; + } elseif ($data == '@api') { + $data = $this; + } + } + $value = call_user_func_array($filter['method'], $filter['args']); + } else { + $value = call_user_func($filter, $value); + } + } + } + + return $value; + } + + /** + * Get the name of the parameter + * + * @return string + */ + public function getName() + { + return $this->name; + } + + /** + * Get the key of the parameter, where sentAs will supersede name if it is set + * + * @return string + */ + public function getWireName() + { + return $this->sentAs ?: $this->name; + } + + /** + * Set the name of the parameter + * + * @param string $name Name to set + * + * @return self + */ + public function setName($name) + { + $this->name = $name; + + return $this; + } + + /** + * Get the type(s) of the parameter + * + * @return string|array + */ + public function getType() + { + return $this->type; + } + + /** + * Set the type(s) of the parameter + * + * @param string|array $type Type of parameter or array of simple types used in a union + * + * @return self + */ + public function setType($type) + { + $this->type = $type; + + return $this; + } + + /** + * Get if the parameter is required + * + * @return bool + */ + public function getRequired() + { + return $this->required; + } + + /** + * Set if the parameter is required + * + * @param bool $isRequired Whether or not the parameter is required + * + * @return self + */ + public function setRequired($isRequired) + { + $this->required = (bool) $isRequired; + + return $this; + } + + /** + * Get the default value of the parameter + * + * @return string|null + */ + public function getDefault() + { + return $this->default; + } + + /** + * Set the default value of the parameter + * + * @param string|null $default Default value to set + * + * @return self + */ + public function setDefault($default) + { + $this->default = $default; + + return $this; + } + + /** + * Get the description of the parameter + * + * @return string|null + */ + public function getDescription() + { + return $this->description; + } + + /** + * Set the description of the parameter + * + * @param string $description Description + * + * @return self + */ + public function setDescription($description) + { + $this->description = $description; + + return $this; + } + + /** + * Get the minimum acceptable value for an integer + * + * @return int|null + */ + public function getMinimum() + { + return $this->minimum; + } + + /** + * Set the minimum acceptable value for an integer + * + * @param int|null $min Minimum + * + * @return self + */ + public function setMinimum($min) + { + $this->minimum = $min; + + return $this; + } + + /** + * Get the maximum acceptable value for an integer + * + * @return int|null + */ + public function getMaximum() + { + return $this->maximum; + } + + /** + * Set the maximum acceptable value for an integer + * + * @param int $max Maximum + * + * @return self + */ + public function setMaximum($max) + { + $this->maximum = $max; + + return $this; + } + + /** + * Get the minimum allowed length of a string value + * + * @return int + */ + public function getMinLength() + { + return $this->minLength; + } + + /** + * Set the minimum allowed length of a string value + * + * @param int|null $min Minimum + * + * @return self + */ + public function setMinLength($min) + { + $this->minLength = $min; + + return $this; + } + + /** + * Get the maximum allowed length of a string value + * + * @return int|null + */ + public function getMaxLength() + { + return $this->maxLength; + } + + /** + * Set the maximum allowed length of a string value + * + * @param int $max Maximum length + * + * @return self + */ + public function setMaxLength($max) + { + $this->maxLength = $max; + + return $this; + } + + /** + * Get the maximum allowed number of items in an array value + * + * @return int|null + */ + public function getMaxItems() + { + return $this->maxItems; + } + + /** + * Set the maximum allowed number of items in an array value + * + * @param int $max Maximum + * + * @return self + */ + public function setMaxItems($max) + { + $this->maxItems = $max; + + return $this; + } + + /** + * Get the minimum allowed number of items in an array value + * + * @return int + */ + public function getMinItems() + { + return $this->minItems; + } + + /** + * Set the minimum allowed number of items in an array value + * + * @param int|null $min Minimum + * + * @return self + */ + public function setMinItems($min) + { + $this->minItems = $min; + + return $this; + } + + /** + * Get the location of the parameter + * + * @return string|null + */ + public function getLocation() + { + return $this->location; + } + + /** + * Set the location of the parameter + * + * @param string|null $location Location of the parameter + * + * @return self + */ + public function setLocation($location) + { + $this->location = $location; + + return $this; + } + + /** + * Get the sentAs attribute of the parameter that used with locations to sentAs an attribute when it is being + * applied to a location. + * + * @return string|null + */ + public function getSentAs() + { + return $this->sentAs; + } + + /** + * Set the sentAs attribute + * + * @param string|null $name Name of the value as it is sent over the wire + * + * @return self + */ + public function setSentAs($name) + { + $this->sentAs = $name; + + return $this; + } + + /** + * Retrieve a known property from the parameter by name or a data property by name. When not specific name value + * is specified, all data properties will be returned. + * + * @param string|null $name Specify a particular property name to retrieve + * + * @return array|mixed|null + */ + public function getData($name = null) + { + if (!$name) { + return $this->data; + } + + if (isset($this->data[$name])) { + return $this->data[$name]; + } elseif (isset($this->{$name})) { + return $this->{$name}; + } + + return null; + } + + /** + * Set the extra data properties of the parameter or set a specific extra property + * + * @param string|array|null $nameOrData The name of a specific extra to set or an array of extras to set + * @param mixed|null $data When setting a specific extra property, specify the data to set for it + * + * @return self + */ + public function setData($nameOrData, $data = null) + { + if (is_array($nameOrData)) { + $this->data = $nameOrData; + } else { + $this->data[$nameOrData] = $data; + } + + return $this; + } + + /** + * Get whether or not the default value can be changed + * + * @return mixed|null + */ + public function getStatic() + { + return $this->static; + } + + /** + * Set to true if the default value cannot be changed + * + * @param bool $static True or false + * + * @return self + */ + public function setStatic($static) + { + $this->static = (bool) $static; + + return $this; + } + + /** + * Get an array of filters used by the parameter + * + * @return array + */ + public function getFilters() + { + return $this->filters ?: array(); + } + + /** + * Set the array of filters used by the parameter + * + * @param array $filters Array of functions to use as filters + * + * @return self + */ + public function setFilters(array $filters) + { + $this->filters = array(); + foreach ($filters as $filter) { + $this->addFilter($filter); + } + + return $this; + } + + /** + * Add a filter to the parameter + * + * @param string|array $filter Method to filter the value through + * + * @return self + * @throws InvalidArgumentException + */ + public function addFilter($filter) + { + if (is_array($filter)) { + if (!isset($filter['method'])) { + throw new InvalidArgumentException('A [method] value must be specified for each complex filter'); + } + } + + if (!$this->filters) { + $this->filters = array($filter); + } else { + $this->filters[] = $filter; + } + + return $this; + } + + /** + * Get the parent object (an {@see OperationInterface} or {@see Parameter} + * + * @return OperationInterface|Parameter|null + */ + public function getParent() + { + return $this->parent; + } + + /** + * Set the parent object of the parameter + * + * @param OperationInterface|Parameter|null $parent Parent container of the parameter + * + * @return self + */ + public function setParent($parent) + { + $this->parent = $parent; + + return $this; + } + + /** + * Get the properties of the parameter + * + * @return array + */ + public function getProperties() + { + if (!$this->propertiesCache) { + $this->propertiesCache = array(); + foreach (array_keys($this->properties) as $name) { + $this->propertiesCache[$name] = $this->getProperty($name); + } + } + + return $this->propertiesCache; + } + + /** + * Get a specific property from the parameter + * + * @param string $name Name of the property to retrieve + * + * @return null|Parameter + */ + public function getProperty($name) + { + if (!isset($this->properties[$name])) { + return null; + } + + if (!($this->properties[$name] instanceof self)) { + $this->properties[$name]['name'] = $name; + $this->properties[$name] = new static($this->properties[$name], $this->serviceDescription); + $this->properties[$name]->setParent($this); + } + + return $this->properties[$name]; + } + + /** + * Remove a property from the parameter + * + * @param string $name Name of the property to remove + * + * @return self + */ + public function removeProperty($name) + { + unset($this->properties[$name]); + $this->propertiesCache = null; + + return $this; + } + + /** + * Add a property to the parameter + * + * @param Parameter $property Properties to set + * + * @return self + */ + public function addProperty(Parameter $property) + { + $this->properties[$property->getName()] = $property; + $property->setParent($this); + $this->propertiesCache = null; + + return $this; + } + + /** + * Get the additionalProperties value of the parameter + * + * @return bool|Parameter|null + */ + public function getAdditionalProperties() + { + if (is_array($this->additionalProperties)) { + $this->additionalProperties = new static($this->additionalProperties, $this->serviceDescription); + $this->additionalProperties->setParent($this); + } + + return $this->additionalProperties; + } + + /** + * Set the additionalProperties value of the parameter + * + * @param bool|Parameter|null $additional Boolean to allow any, an Parameter to specify a schema, or false to disallow + * + * @return self + */ + public function setAdditionalProperties($additional) + { + $this->additionalProperties = $additional; + + return $this; + } + + /** + * Set the items data of the parameter + * + * @param Parameter|null $items Items to set + * + * @return self + */ + public function setItems(Parameter $items = null) + { + if ($this->items = $items) { + $this->items->setParent($this); + } + + return $this; + } + + /** + * Get the item data of the parameter + * + * @return Parameter|null + */ + public function getItems() + { + if (is_array($this->items)) { + $this->items = new static($this->items, $this->serviceDescription); + $this->items->setParent($this); + } + + return $this->items; + } + + /** + * Get the class that the parameter must implement + * + * @return null|string + */ + public function getInstanceOf() + { + return $this->instanceOf; + } + + /** + * Set the class that the parameter must be an instance of + * + * @param string|null $instanceOf Class or interface name + * + * @return self + */ + public function setInstanceOf($instanceOf) + { + $this->instanceOf = $instanceOf; + + return $this; + } + + /** + * Get the enum of strings that are valid for the parameter + * + * @return array|null + */ + public function getEnum() + { + return $this->enum; + } + + /** + * Set the enum of strings that are valid for the parameter + * + * @param array|null $enum Array of strings or null + * + * @return self + */ + public function setEnum(array $enum = null) + { + $this->enum = $enum; + + return $this; + } + + /** + * Get the regex pattern that must match a value when the value is a string + * + * @return string + */ + public function getPattern() + { + return $this->pattern; + } + + /** + * Set the regex pattern that must match a value when the value is a string + * + * @param string $pattern Regex pattern + * + * @return self + */ + public function setPattern($pattern) + { + $this->pattern = $pattern; + + return $this; + } + + /** + * Get the format attribute of the schema + * + * @return string + */ + public function getFormat() + { + return $this->format; + } + + /** + * Set the format attribute of the schema + * + * @param string $format Format to set (e.g. date, date-time, timestamp, time, date-time-http) + * + * @return self + */ + public function setFormat($format) + { + $this->format = $format; + + return $this; + } +} diff --git a/vendor/guzzle/guzzle/src/Guzzle/Service/Description/SchemaFormatter.php b/vendor/guzzle/guzzle/src/Guzzle/Service/Description/SchemaFormatter.php new file mode 100644 index 0000000..7f47fc9 --- /dev/null +++ b/vendor/guzzle/guzzle/src/Guzzle/Service/Description/SchemaFormatter.php @@ -0,0 +1,156 @@ +setTimezone(self::getUtcTimeZone())->format($format); + } + + throw new InvalidArgumentException('Date/Time values must be either a string, integer, or DateTime object'); + } +} diff --git a/vendor/guzzle/guzzle/src/Guzzle/Service/Description/SchemaValidator.php b/vendor/guzzle/guzzle/src/Guzzle/Service/Description/SchemaValidator.php new file mode 100644 index 0000000..b045422 --- /dev/null +++ b/vendor/guzzle/guzzle/src/Guzzle/Service/Description/SchemaValidator.php @@ -0,0 +1,291 @@ +castIntegerToStringType = $castIntegerToStringType; + } + + public function validate(Parameter $param, &$value) + { + $this->errors = array(); + $this->recursiveProcess($param, $value); + + if (empty($this->errors)) { + return true; + } else { + sort($this->errors); + return false; + } + } + + /** + * Get the errors encountered while validating + * + * @return array + */ + public function getErrors() + { + return $this->errors ?: array(); + } + + /** + * Recursively validate a parameter + * + * @param Parameter $param API parameter being validated + * @param mixed $value Value to validate and validate. The value may change during this validate. + * @param string $path Current validation path (used for error reporting) + * @param int $depth Current depth in the validation validate + * + * @return bool Returns true if valid, or false if invalid + */ + protected function recursiveProcess(Parameter $param, &$value, $path = '', $depth = 0) + { + // Update the value by adding default or static values + $value = $param->getValue($value); + + $required = $param->getRequired(); + // if the value is null and the parameter is not required or is static, then skip any further recursion + if ((null === $value && !$required) || $param->getStatic()) { + return true; + } + + $type = $param->getType(); + // Attempt to limit the number of times is_array is called by tracking if the value is an array + $valueIsArray = is_array($value); + // If a name is set then update the path so that validation messages are more helpful + if ($name = $param->getName()) { + $path .= "[{$name}]"; + } + + if ($type == 'object') { + + // Objects are either associative arrays, ToArrayInterface, or some other object + if ($param->getInstanceOf()) { + $instance = $param->getInstanceOf(); + if (!($value instanceof $instance)) { + $this->errors[] = "{$path} must be an instance of {$instance}"; + return false; + } + } + + // Determine whether or not this "value" has properties and should be traversed + $traverse = $temporaryValue = false; + + // Convert the value to an array + if (!$valueIsArray && $value instanceof ToArrayInterface) { + $value = $value->toArray(); + } + + if ($valueIsArray) { + // Ensure that the array is associative and not numerically indexed + if (isset($value[0])) { + $this->errors[] = "{$path} must be an array of properties. Got a numerically indexed array."; + return false; + } + $traverse = true; + } elseif ($value === null) { + // Attempt to let the contents be built up by default values if possible + $value = array(); + $temporaryValue = $valueIsArray = $traverse = true; + } + + if ($traverse) { + + if ($properties = $param->getProperties()) { + // if properties were found, the validate each property of the value + foreach ($properties as $property) { + $name = $property->getName(); + if (isset($value[$name])) { + $this->recursiveProcess($property, $value[$name], $path, $depth + 1); + } else { + $current = null; + $this->recursiveProcess($property, $current, $path, $depth + 1); + // Only set the value if it was populated with something + if (null !== $current) { + $value[$name] = $current; + } + } + } + } + + $additional = $param->getAdditionalProperties(); + if ($additional !== true) { + // If additional properties were found, then validate each against the additionalProperties attr. + $keys = array_keys($value); + // Determine the keys that were specified that were not listed in the properties of the schema + $diff = array_diff($keys, array_keys($properties)); + if (!empty($diff)) { + // Determine which keys are not in the properties + if ($additional instanceOf Parameter) { + foreach ($diff as $key) { + $this->recursiveProcess($additional, $value[$key], "{$path}[{$key}]", $depth); + } + } else { + // if additionalProperties is set to false and there are additionalProperties in the values, then fail + foreach ($diff as $prop) { + $this->errors[] = sprintf('%s[%s] is not an allowed property', $path, $prop); + } + } + } + } + + // A temporary value will be used to traverse elements that have no corresponding input value. + // This allows nested required parameters with default values to bubble up into the input. + // Here we check if we used a temp value and nothing bubbled up, then we need to remote the value. + if ($temporaryValue && empty($value)) { + $value = null; + $valueIsArray = false; + } + } + + } elseif ($type == 'array' && $valueIsArray && $param->getItems()) { + foreach ($value as $i => &$item) { + // Validate each item in an array against the items attribute of the schema + $this->recursiveProcess($param->getItems(), $item, $path . "[{$i}]", $depth + 1); + } + } + + // If the value is required and the type is not null, then there is an error if the value is not set + if ($required && $value === null && $type != 'null') { + $message = "{$path} is " . ($param->getType() ? ('a required ' . implode(' or ', (array) $param->getType())) : 'required'); + if ($param->getDescription()) { + $message .= ': ' . $param->getDescription(); + } + $this->errors[] = $message; + return false; + } + + // Validate that the type is correct. If the type is string but an integer was passed, the class can be + // instructed to cast the integer to a string to pass validation. This is the default behavior. + if ($type && (!$type = $this->determineType($type, $value))) { + if ($this->castIntegerToStringType && $param->getType() == 'string' && is_integer($value)) { + $value = (string) $value; + } else { + $this->errors[] = "{$path} must be of type " . implode(' or ', (array) $param->getType()); + } + } + + // Perform type specific validation for strings, arrays, and integers + if ($type == 'string') { + + // Strings can have enums which are a list of predefined values + if (($enum = $param->getEnum()) && !in_array($value, $enum)) { + $this->errors[] = "{$path} must be one of " . implode(' or ', array_map(function ($s) { + return '"' . addslashes($s) . '"'; + }, $enum)); + } + // Strings can have a regex pattern that the value must match + if (($pattern = $param->getPattern()) && !preg_match($pattern, $value)) { + $this->errors[] = "{$path} must match the following regular expression: {$pattern}"; + } + + $strLen = null; + if ($min = $param->getMinLength()) { + $strLen = strlen($value); + if ($strLen < $min) { + $this->errors[] = "{$path} length must be greater than or equal to {$min}"; + } + } + if ($max = $param->getMaxLength()) { + if (($strLen ?: strlen($value)) > $max) { + $this->errors[] = "{$path} length must be less than or equal to {$max}"; + } + } + + } elseif ($type == 'array') { + + $size = null; + if ($min = $param->getMinItems()) { + $size = count($value); + if ($size < $min) { + $this->errors[] = "{$path} must contain {$min} or more elements"; + } + } + if ($max = $param->getMaxItems()) { + if (($size ?: count($value)) > $max) { + $this->errors[] = "{$path} must contain {$max} or fewer elements"; + } + } + + } elseif ($type == 'integer' || $type == 'number' || $type == 'numeric') { + if (($min = $param->getMinimum()) && $value < $min) { + $this->errors[] = "{$path} must be greater than or equal to {$min}"; + } + if (($max = $param->getMaximum()) && $value > $max) { + $this->errors[] = "{$path} must be less than or equal to {$max}"; + } + } + + return empty($this->errors); + } + + /** + * From the allowable types, determine the type that the variable matches + * + * @param string $type Parameter type + * @param mixed $value Value to determine the type + * + * @return string|bool Returns the matching type on + */ + protected function determineType($type, $value) + { + foreach ((array) $type as $t) { + if ($t == 'string' && (is_string($value) || (is_object($value) && method_exists($value, '__toString')))) { + return 'string'; + } elseif ($t == 'object' && (is_array($value) || is_object($value))) { + return 'object'; + } elseif ($t == 'array' && is_array($value)) { + return 'array'; + } elseif ($t == 'integer' && is_integer($value)) { + return 'integer'; + } elseif ($t == 'boolean' && is_bool($value)) { + return 'boolean'; + } elseif ($t == 'number' && is_numeric($value)) { + return 'number'; + } elseif ($t == 'numeric' && is_numeric($value)) { + return 'numeric'; + } elseif ($t == 'null' && !$value) { + return 'null'; + } elseif ($t == 'any') { + return 'any'; + } + } + + return false; + } +} diff --git a/vendor/guzzle/guzzle/src/Guzzle/Service/Description/ServiceDescription.php b/vendor/guzzle/guzzle/src/Guzzle/Service/Description/ServiceDescription.php new file mode 100644 index 0000000..286e65e --- /dev/null +++ b/vendor/guzzle/guzzle/src/Guzzle/Service/Description/ServiceDescription.php @@ -0,0 +1,271 @@ +load($config, $options); + } + + /** + * @param array $config Array of configuration data + */ + public function __construct(array $config = array()) + { + $this->fromArray($config); + } + + public function serialize() + { + return json_encode($this->toArray()); + } + + public function unserialize($json) + { + $this->operations = array(); + $this->fromArray(json_decode($json, true)); + } + + public function toArray() + { + $result = array( + 'name' => $this->name, + 'apiVersion' => $this->apiVersion, + 'baseUrl' => $this->baseUrl, + 'description' => $this->description + ) + $this->extraData; + $result['operations'] = array(); + foreach ($this->getOperations() as $name => $operation) { + $result['operations'][$operation->getName() ?: $name] = $operation->toArray(); + } + if (!empty($this->models)) { + $result['models'] = array(); + foreach ($this->models as $id => $model) { + $result['models'][$id] = $model instanceof Parameter ? $model->toArray(): $model; + } + } + + return array_filter($result); + } + + public function getBaseUrl() + { + return $this->baseUrl; + } + + /** + * Set the baseUrl of the description + * + * @param string $baseUrl Base URL of each operation + * + * @return self + */ + public function setBaseUrl($baseUrl) + { + $this->baseUrl = $baseUrl; + + return $this; + } + + public function getOperations() + { + foreach (array_keys($this->operations) as $name) { + $this->getOperation($name); + } + + return $this->operations; + } + + public function hasOperation($name) + { + return isset($this->operations[$name]); + } + + public function getOperation($name) + { + // Lazily retrieve and build operations + if (!isset($this->operations[$name])) { + return null; + } + + if (!($this->operations[$name] instanceof Operation)) { + $this->operations[$name] = new Operation($this->operations[$name], $this); + } + + return $this->operations[$name]; + } + + /** + * Add a operation to the service description + * + * @param OperationInterface $operation Operation to add + * + * @return self + */ + public function addOperation(OperationInterface $operation) + { + $this->operations[$operation->getName()] = $operation->setServiceDescription($this); + + return $this; + } + + public function getModel($id) + { + if (!isset($this->models[$id])) { + return null; + } + + if (!($this->models[$id] instanceof Parameter)) { + $this->models[$id] = new Parameter($this->models[$id] + array('name' => $id), $this); + } + + return $this->models[$id]; + } + + public function getModels() + { + // Ensure all models are converted into parameter objects + foreach (array_keys($this->models) as $id) { + $this->getModel($id); + } + + return $this->models; + } + + public function hasModel($id) + { + return isset($this->models[$id]); + } + + /** + * Add a model to the service description + * + * @param Parameter $model Model to add + * + * @return self + */ + public function addModel(Parameter $model) + { + $this->models[$model->getName()] = $model; + + return $this; + } + + public function getApiVersion() + { + return $this->apiVersion; + } + + public function getName() + { + return $this->name; + } + + public function getDescription() + { + return $this->description; + } + + public function getData($key) + { + return isset($this->extraData[$key]) ? $this->extraData[$key] : null; + } + + public function setData($key, $value) + { + $this->extraData[$key] = $value; + + return $this; + } + + /** + * Initialize the state from an array + * + * @param array $config Configuration data + * @throws InvalidArgumentException + */ + protected function fromArray(array $config) + { + // Keep a list of default keys used in service descriptions that is later used to determine extra data keys + static $defaultKeys = array('name', 'models', 'apiVersion', 'baseUrl', 'description'); + // Pull in the default configuration values + foreach ($defaultKeys as $key) { + if (isset($config[$key])) { + $this->{$key} = $config[$key]; + } + } + + // Account for the Swagger name for Guzzle's baseUrl + if (isset($config['basePath'])) { + $this->baseUrl = $config['basePath']; + } + + // Ensure that the models and operations properties are always arrays + $this->models = (array) $this->models; + $this->operations = (array) $this->operations; + + // We want to add operations differently than adding the other properties + $defaultKeys[] = 'operations'; + + // Create operations for each operation + if (isset($config['operations'])) { + foreach ($config['operations'] as $name => $operation) { + if (!($operation instanceof Operation) && !is_array($operation)) { + throw new InvalidArgumentException('Invalid operation in service description: ' + . gettype($operation)); + } + $this->operations[$name] = $operation; + } + } + + // Get all of the additional properties of the service description and store them in a data array + foreach (array_diff(array_keys($config), $defaultKeys) as $key) { + $this->extraData[$key] = $config[$key]; + } + } +} diff --git a/vendor/guzzle/guzzle/src/Guzzle/Service/Description/ServiceDescriptionInterface.php b/vendor/guzzle/guzzle/src/Guzzle/Service/Description/ServiceDescriptionInterface.php new file mode 100644 index 0000000..5983e58 --- /dev/null +++ b/vendor/guzzle/guzzle/src/Guzzle/Service/Description/ServiceDescriptionInterface.php @@ -0,0 +1,106 @@ + $op) { + $name = $op['name'] = isset($op['name']) ? $op['name'] : $name; + // Extend other operations + if (!empty($op['extends'])) { + $this->resolveExtension($name, $op, $operations); + } + $op['parameters'] = isset($op['parameters']) ? $op['parameters'] : array(); + $operations[$name] = $op; + } + } + + return new ServiceDescription(array( + 'apiVersion' => isset($config['apiVersion']) ? $config['apiVersion'] : null, + 'baseUrl' => isset($config['baseUrl']) ? $config['baseUrl'] : null, + 'description' => isset($config['description']) ? $config['description'] : null, + 'operations' => $operations, + 'models' => isset($config['models']) ? $config['models'] : null + ) + $config); + } + + /** + * @param string $name Name of the operation + * @param array $op Operation value array + * @param array $operations Currently loaded operations + * @throws DescriptionBuilderException when extending a non-existent operation + */ + protected function resolveExtension($name, array &$op, array &$operations) + { + $resolved = array(); + $original = empty($op['parameters']) ? false: $op['parameters']; + $hasClass = !empty($op['class']); + foreach ((array) $op['extends'] as $extendedCommand) { + if (empty($operations[$extendedCommand])) { + throw new DescriptionBuilderException("{$name} extends missing operation {$extendedCommand}"); + } + $toArray = $operations[$extendedCommand]; + $resolved = empty($resolved) + ? $toArray['parameters'] + : array_merge($resolved, $toArray['parameters']); + + $op = $op + $toArray; + if (!$hasClass && isset($toArray['class'])) { + $op['class'] = $toArray['class']; + } + } + $op['parameters'] = $original ? array_merge($resolved, $original) : $resolved; + } +} diff --git a/vendor/guzzle/guzzle/src/Guzzle/Service/Description/ValidatorInterface.php b/vendor/guzzle/guzzle/src/Guzzle/Service/Description/ValidatorInterface.php new file mode 100644 index 0000000..94ca77d --- /dev/null +++ b/vendor/guzzle/guzzle/src/Guzzle/Service/Description/ValidatorInterface.php @@ -0,0 +1,28 @@ +getMessage(), $e->getCode(), $e->getPrevious()); + $ce->setSuccessfulRequests($e->getSuccessfulRequests()); + + $alreadyAddedExceptions = array(); + foreach ($e->getFailedRequests() as $request) { + if ($re = $e->getExceptionForFailedRequest($request)) { + $alreadyAddedExceptions[] = $re; + $ce->addFailedRequestWithException($request, $re); + } else { + $ce->addFailedRequest($request); + } + } + + // Add any exceptions that did not map to a request + if (count($alreadyAddedExceptions) < count($e)) { + foreach ($e as $ex) { + if (!in_array($ex, $alreadyAddedExceptions)) { + $ce->add($ex); + } + } + } + + return $ce; + } + + /** + * Get all of the commands in the transfer + * + * @return array + */ + public function getAllCommands() + { + return array_merge($this->successfulCommands, $this->failedCommands); + } + + /** + * Add to the array of successful commands + * + * @param CommandInterface $command Successful command + * + * @return self + */ + public function addSuccessfulCommand(CommandInterface $command) + { + $this->successfulCommands[] = $command; + + return $this; + } + + /** + * Add to the array of failed commands + * + * @param CommandInterface $command Failed command + * + * @return self + */ + public function addFailedCommand(CommandInterface $command) + { + $this->failedCommands[] = $command; + + return $this; + } + + /** + * Get an array of successful commands + * + * @return array + */ + public function getSuccessfulCommands() + { + return $this->successfulCommands; + } + + /** + * Get an array of failed commands + * + * @return array + */ + public function getFailedCommands() + { + return $this->failedCommands; + } + + /** + * Get the Exception that caused the given $command to fail + * + * @param CommandInterface $command Failed command + * + * @return \Exception|null + */ + public function getExceptionForFailedCommand(CommandInterface $command) + { + return $this->getExceptionForFailedRequest($command->getRequest()); + } +} diff --git a/vendor/guzzle/guzzle/src/Guzzle/Service/Exception/DescriptionBuilderException.php b/vendor/guzzle/guzzle/src/Guzzle/Service/Exception/DescriptionBuilderException.php new file mode 100644 index 0000000..1407e56 --- /dev/null +++ b/vendor/guzzle/guzzle/src/Guzzle/Service/Exception/DescriptionBuilderException.php @@ -0,0 +1,7 @@ +invalidCommands = $commands; + parent::__construct( + 'Encountered commands in a batch transfer that use inconsistent clients. The batching ' . + 'strategy you use with a command transfer must divide command batches by client.' + ); + } + + /** + * Get the invalid commands + * + * @return array + */ + public function getCommands() + { + return $this->invalidCommands; + } +} diff --git a/vendor/guzzle/guzzle/src/Guzzle/Service/Exception/ResponseClassException.php b/vendor/guzzle/guzzle/src/Guzzle/Service/Exception/ResponseClassException.php new file mode 100644 index 0000000..d59ff21 --- /dev/null +++ b/vendor/guzzle/guzzle/src/Guzzle/Service/Exception/ResponseClassException.php @@ -0,0 +1,9 @@ +errors = $errors; + } + + /** + * Get any validation errors + * + * @return array + */ + public function getErrors() + { + return $this->errors; + } +} diff --git a/vendor/guzzle/guzzle/src/Guzzle/Service/Resource/AbstractResourceIteratorFactory.php b/vendor/guzzle/guzzle/src/Guzzle/Service/Resource/AbstractResourceIteratorFactory.php new file mode 100644 index 0000000..21140e7 --- /dev/null +++ b/vendor/guzzle/guzzle/src/Guzzle/Service/Resource/AbstractResourceIteratorFactory.php @@ -0,0 +1,37 @@ +canBuild($command)) { + throw new InvalidArgumentException('Iterator was not found for ' . $command->getName()); + } + + $className = $this->getClassName($command); + + return new $className($command, $options); + } + + public function canBuild(CommandInterface $command) + { + return (bool) $this->getClassName($command); + } + + /** + * Get the name of the class to instantiate for the command + * + * @param CommandInterface $command Command that is associated with the iterator + * + * @return string + */ + abstract protected function getClassName(CommandInterface $command); +} diff --git a/vendor/guzzle/guzzle/src/Guzzle/Service/Resource/CompositeResourceIteratorFactory.php b/vendor/guzzle/guzzle/src/Guzzle/Service/Resource/CompositeResourceIteratorFactory.php new file mode 100644 index 0000000..2efc133 --- /dev/null +++ b/vendor/guzzle/guzzle/src/Guzzle/Service/Resource/CompositeResourceIteratorFactory.php @@ -0,0 +1,67 @@ +factories = $factories; + } + + public function build(CommandInterface $command, array $options = array()) + { + if (!($factory = $this->getFactory($command))) { + throw new InvalidArgumentException('Iterator was not found for ' . $command->getName()); + } + + return $factory->build($command, $options); + } + + public function canBuild(CommandInterface $command) + { + return $this->getFactory($command) !== false; + } + + /** + * Add a factory to the composite factory + * + * @param ResourceIteratorFactoryInterface $factory Factory to add + * + * @return self + */ + public function addFactory(ResourceIteratorFactoryInterface $factory) + { + $this->factories[] = $factory; + + return $this; + } + + /** + * Get the factory that matches the command object + * + * @param CommandInterface $command Command retrieving the iterator for + * + * @return ResourceIteratorFactoryInterface|bool + */ + protected function getFactory(CommandInterface $command) + { + foreach ($this->factories as $factory) { + if ($factory->canBuild($command)) { + return $factory; + } + } + + return false; + } +} diff --git a/vendor/guzzle/guzzle/src/Guzzle/Service/Resource/MapResourceIteratorFactory.php b/vendor/guzzle/guzzle/src/Guzzle/Service/Resource/MapResourceIteratorFactory.php new file mode 100644 index 0000000..c71ca9d --- /dev/null +++ b/vendor/guzzle/guzzle/src/Guzzle/Service/Resource/MapResourceIteratorFactory.php @@ -0,0 +1,34 @@ +map = $map; + } + + public function getClassName(CommandInterface $command) + { + $className = $command->getName(); + + if (isset($this->map[$className])) { + return $this->map[$className]; + } elseif (isset($this->map['*'])) { + // If a wildcard was added, then always use that + return $this->map['*']; + } + + return null; + } +} diff --git a/vendor/guzzle/guzzle/src/Guzzle/Service/Resource/Model.php b/vendor/guzzle/guzzle/src/Guzzle/Service/Resource/Model.php new file mode 100644 index 0000000..2322434 --- /dev/null +++ b/vendor/guzzle/guzzle/src/Guzzle/Service/Resource/Model.php @@ -0,0 +1,64 @@ +data = $data; + $this->structure = $structure; + } + + /** + * Get the structure of the model + * + * @return Parameter + */ + public function getStructure() + { + return $this->structure ?: new Parameter(); + } + + /** + * Provides debug information about the model object + * + * @return string + */ + public function __toString() + { + $output = 'Debug output of '; + if ($this->structure) { + $output .= $this->structure->getName() . ' '; + } + $output .= 'model'; + $output = str_repeat('=', strlen($output)) . "\n" . $output . "\n" . str_repeat('=', strlen($output)) . "\n\n"; + $output .= "Model data\n-----------\n\n"; + $output .= "This data can be retrieved from the model object using the get() method of the model " + . "(e.g. \$model->get(\$key)) or accessing the model like an associative array (e.g. \$model['key']).\n\n"; + $lines = array_slice(explode("\n", trim(print_r($this->toArray(), true))), 2, -1); + $output .= implode("\n", $lines); + + if ($this->structure) { + $output .= "\n\nModel structure\n---------------\n\n"; + $output .= "The following JSON document defines how the model was parsed from an HTTP response into the " + . "associative array structure you see above.\n\n"; + $output .= ' ' . json_encode($this->structure->toArray()) . "\n\n"; + } + + return $output . "\n"; + } +} diff --git a/vendor/guzzle/guzzle/src/Guzzle/Service/Resource/ResourceIterator.php b/vendor/guzzle/guzzle/src/Guzzle/Service/Resource/ResourceIterator.php new file mode 100644 index 0000000..e141524 --- /dev/null +++ b/vendor/guzzle/guzzle/src/Guzzle/Service/Resource/ResourceIterator.php @@ -0,0 +1,254 @@ +originalCommand = $command; + + // Parse options from the array of options + $this->data = $data; + $this->limit = array_key_exists('limit', $data) ? $data['limit'] : 0; + $this->pageSize = array_key_exists('page_size', $data) ? $data['page_size'] : false; + } + + /** + * Get all of the resources as an array (Warning: this could issue a large number of requests) + * + * @return array + */ + public function toArray() + { + return iterator_to_array($this, false); + } + + public function setLimit($limit) + { + $this->limit = $limit; + $this->resetState(); + + return $this; + } + + public function setPageSize($pageSize) + { + $this->pageSize = $pageSize; + $this->resetState(); + + return $this; + } + + /** + * Get an option from the iterator + * + * @param string $key Key of the option to retrieve + * + * @return mixed|null Returns NULL if not set or the value if set + */ + public function get($key) + { + return array_key_exists($key, $this->data) ? $this->data[$key] : null; + } + + /** + * Set an option on the iterator + * + * @param string $key Key of the option to set + * @param mixed $value Value to set for the option + * + * @return ResourceIterator + */ + public function set($key, $value) + { + $this->data[$key] = $value; + + return $this; + } + + public function current() + { + return $this->resources ? current($this->resources) : false; + } + + public function key() + { + return max(0, $this->iteratedCount - 1); + } + + public function count() + { + return $this->retrievedCount; + } + + /** + * Get the total number of requests sent + * + * @return int + */ + public function getRequestCount() + { + return $this->requestCount; + } + + /** + * Rewind the Iterator to the first element and send the original command + */ + public function rewind() + { + // Use the original command + $this->command = clone $this->originalCommand; + $this->resetState(); + $this->next(); + } + + public function valid() + { + return !$this->invalid && (!$this->resources || $this->current() || $this->nextToken) + && (!$this->limit || $this->iteratedCount < $this->limit + 1); + } + + public function next() + { + $this->iteratedCount++; + + // Check if a new set of resources needs to be retrieved + $sendRequest = false; + if (!$this->resources) { + $sendRequest = true; + } else { + // iterate over the internal array + $current = next($this->resources); + $sendRequest = $current === false && $this->nextToken && (!$this->limit || $this->iteratedCount < $this->limit + 1); + } + + if ($sendRequest) { + + $this->dispatch('resource_iterator.before_send', array( + 'iterator' => $this, + 'resources' => $this->resources + )); + + // Get a new command object from the original command + $this->command = clone $this->originalCommand; + // Send a request and retrieve the newly loaded resources + $this->resources = $this->sendRequest(); + $this->requestCount++; + + // If no resources were found, then the last request was not needed + // and iteration must stop + if (empty($this->resources)) { + $this->invalid = true; + } else { + // Add to the number of retrieved resources + $this->retrievedCount += count($this->resources); + // Ensure that we rewind to the beginning of the array + reset($this->resources); + } + + $this->dispatch('resource_iterator.after_send', array( + 'iterator' => $this, + 'resources' => $this->resources + )); + } + } + + /** + * Retrieve the NextToken that can be used in other iterators. + * + * @return string Returns a NextToken + */ + public function getNextToken() + { + return $this->nextToken; + } + + /** + * Returns the value that should be specified for the page size for a request that will maintain any hard limits, + * but still honor the specified pageSize if the number of items retrieved + pageSize < hard limit + * + * @return int Returns the page size of the next request. + */ + protected function calculatePageSize() + { + if ($this->limit && $this->iteratedCount + $this->pageSize > $this->limit) { + return 1 + ($this->limit - $this->iteratedCount); + } + + return (int) $this->pageSize; + } + + /** + * Reset the internal state of the iterator without triggering a rewind() + */ + protected function resetState() + { + $this->iteratedCount = 0; + $this->retrievedCount = 0; + $this->nextToken = false; + $this->resources = null; + $this->invalid = false; + } + + /** + * Send a request to retrieve the next page of results. Hook for subclasses to implement. + * + * @return array Returns the newly loaded resources + */ + abstract protected function sendRequest(); +} diff --git a/vendor/guzzle/guzzle/src/Guzzle/Service/Resource/ResourceIteratorApplyBatched.php b/vendor/guzzle/guzzle/src/Guzzle/Service/Resource/ResourceIteratorApplyBatched.php new file mode 100644 index 0000000..6aa3615 --- /dev/null +++ b/vendor/guzzle/guzzle/src/Guzzle/Service/Resource/ResourceIteratorApplyBatched.php @@ -0,0 +1,111 @@ +iterator = $iterator; + $this->callback = $callback; + Version::warn(__CLASS__ . ' is deprecated'); + } + + /** + * Apply the callback to the contents of the resource iterator + * + * @param int $perBatch The number of records to group per batch transfer + * + * @return int Returns the number of iterated resources + */ + public function apply($perBatch = 50) + { + $this->iterated = $this->batches = $batches = 0; + $that = $this; + $it = $this->iterator; + $callback = $this->callback; + + $batch = BatchBuilder::factory() + ->createBatchesWith(new BatchSizeDivisor($perBatch)) + ->transferWith(new BatchClosureTransfer(function (array $batch) use ($that, $callback, &$batches, $it) { + $batches++; + $that->dispatch('iterator_batch.before_batch', array('iterator' => $it, 'batch' => $batch)); + call_user_func_array($callback, array($it, $batch)); + $that->dispatch('iterator_batch.after_batch', array('iterator' => $it, 'batch' => $batch)); + })) + ->autoFlushAt($perBatch) + ->build(); + + $this->dispatch('iterator_batch.created_batch', array('batch' => $batch)); + + foreach ($this->iterator as $resource) { + $this->iterated++; + $batch->add($resource); + } + + $batch->flush(); + $this->batches = $batches; + + return $this->iterated; + } + + /** + * Get the total number of batches sent + * + * @return int + */ + public function getBatchCount() + { + return $this->batches; + } + + /** + * Get the total number of iterated resources + * + * @return int + */ + public function getIteratedCount() + { + return $this->iterated; + } +} diff --git a/vendor/guzzle/guzzle/src/Guzzle/Service/Resource/ResourceIteratorClassFactory.php b/vendor/guzzle/guzzle/src/Guzzle/Service/Resource/ResourceIteratorClassFactory.php new file mode 100644 index 0000000..2fd9980 --- /dev/null +++ b/vendor/guzzle/guzzle/src/Guzzle/Service/Resource/ResourceIteratorClassFactory.php @@ -0,0 +1,60 @@ + AbcFoo). + */ +class ResourceIteratorClassFactory extends AbstractResourceIteratorFactory +{ + /** @var array List of namespaces used to look for classes */ + protected $namespaces; + + /** @var InflectorInterface Inflector used to determine class names */ + protected $inflector; + + /** + * @param string|array $namespaces List of namespaces for iterator objects + * @param InflectorInterface $inflector Inflector used to resolve class names + */ + public function __construct($namespaces = array(), InflectorInterface $inflector = null) + { + $this->namespaces = (array) $namespaces; + $this->inflector = $inflector ?: Inflector::getDefault(); + } + + /** + * Registers a namespace to check for Iterators + * + * @param string $namespace Namespace which contains Iterator classes + * + * @return self + */ + public function registerNamespace($namespace) + { + array_unshift($this->namespaces, $namespace); + + return $this; + } + + protected function getClassName(CommandInterface $command) + { + $iteratorName = $this->inflector->camel($command->getName()) . 'Iterator'; + + // Determine the name of the class to load + foreach ($this->namespaces as $namespace) { + $potentialClassName = $namespace . '\\' . $iteratorName; + if (class_exists($potentialClassName)) { + return $potentialClassName; + } + } + + return false; + } +} diff --git a/vendor/guzzle/guzzle/src/Guzzle/Service/Resource/ResourceIteratorFactoryInterface.php b/vendor/guzzle/guzzle/src/Guzzle/Service/Resource/ResourceIteratorFactoryInterface.php new file mode 100644 index 0000000..8b4e8db --- /dev/null +++ b/vendor/guzzle/guzzle/src/Guzzle/Service/Resource/ResourceIteratorFactoryInterface.php @@ -0,0 +1,30 @@ +=5.3.2", + "guzzle/cache": "self.version", + "guzzle/http": "self.version", + "guzzle/inflection": "self.version" + }, + "autoload": { + "psr-0": { "Guzzle\\Service": "" } + }, + "target-dir": "Guzzle/Service", + "extra": { + "branch-alias": { + "dev-master": "3.7-dev" + } + } +} diff --git a/vendor/guzzle/guzzle/src/Guzzle/Stream/PhpStreamRequestFactory.php b/vendor/guzzle/guzzle/src/Guzzle/Stream/PhpStreamRequestFactory.php new file mode 100644 index 0000000..d115fd8 --- /dev/null +++ b/vendor/guzzle/guzzle/src/Guzzle/Stream/PhpStreamRequestFactory.php @@ -0,0 +1,284 @@ +contextOptions = stream_context_get_options($context); + $this->context = $context; + } elseif (is_array($context) || !$context) { + $this->contextOptions = $context; + $this->createContext($params); + } elseif ($context) { + throw new InvalidArgumentException('$context must be an array or resource'); + } + + // Dispatch the before send event + $request->dispatch('request.before_send', array( + 'request' => $request, + 'context' => $this->context, + 'context_options' => $this->contextOptions + )); + + $this->setUrl($request); + $this->addDefaultContextOptions($request); + $this->addSslOptions($request); + $this->addBodyOptions($request); + $this->addProxyOptions($request); + + // Create the file handle but silence errors + return $this->createStream($params) + ->setCustomData('request', $request) + ->setCustomData('response_headers', $this->getLastResponseHeaders()); + } + + /** + * Set an option on the context and the internal options array + * + * @param string $wrapper Stream wrapper name of http + * @param string $name Context name + * @param mixed $value Context value + * @param bool $overwrite Set to true to overwrite an existing value + */ + protected function setContextValue($wrapper, $name, $value, $overwrite = false) + { + if (!isset($this->contextOptions[$wrapper])) { + $this->contextOptions[$wrapper] = array($name => $value); + } elseif (!$overwrite && isset($this->contextOptions[$wrapper][$name])) { + return; + } + $this->contextOptions[$wrapper][$name] = $value; + stream_context_set_option($this->context, $wrapper, $name, $value); + } + + /** + * Create a stream context + * + * @param array $params Parameter array + */ + protected function createContext(array $params) + { + $options = $this->contextOptions; + $this->context = $this->createResource(function () use ($params, $options) { + return stream_context_create($options, $params); + }); + } + + /** + * Get the last response headers received by the HTTP request + * + * @return array + */ + public function getLastResponseHeaders() + { + return $this->lastResponseHeaders; + } + + /** + * Adds the default context options to the stream context options + * + * @param RequestInterface $request Request + */ + protected function addDefaultContextOptions(RequestInterface $request) + { + $this->setContextValue('http', 'method', $request->getMethod()); + $headers = $request->getHeaderLines(); + + // "Connection: close" is required to get streams to work in HTTP 1.1 + if (!$request->hasHeader('Connection')) { + $headers[] = 'Connection: close'; + } + + $this->setContextValue('http', 'header', $headers); + $this->setContextValue('http', 'protocol_version', $request->getProtocolVersion()); + $this->setContextValue('http', 'ignore_errors', true); + } + + /** + * Set the URL to use with the factory + * + * @param RequestInterface $request Request that owns the URL + */ + protected function setUrl(RequestInterface $request) + { + $this->url = $request->getUrl(true); + + // Check for basic Auth username + if ($request->getUsername()) { + $this->url->setUsername($request->getUsername()); + } + + // Check for basic Auth password + if ($request->getPassword()) { + $this->url->setPassword($request->getPassword()); + } + } + + /** + * Add SSL options to the stream context + * + * @param RequestInterface $request Request + */ + protected function addSslOptions(RequestInterface $request) + { + if ($request->getCurlOptions()->get(CURLOPT_SSL_VERIFYPEER)) { + $this->setContextValue('ssl', 'verify_peer', true, true); + if ($cafile = $request->getCurlOptions()->get(CURLOPT_CAINFO)) { + $this->setContextValue('ssl', 'cafile', $cafile, true); + } + } else { + $this->setContextValue('ssl', 'verify_peer', false, true); + } + } + + /** + * Add body (content) specific options to the context options + * + * @param RequestInterface $request + */ + protected function addBodyOptions(RequestInterface $request) + { + // Add the content for the request if needed + if (!($request instanceof EntityEnclosingRequestInterface)) { + return; + } + + if (count($request->getPostFields())) { + $this->setContextValue('http', 'content', (string) $request->getPostFields(), true); + } elseif ($request->getBody()) { + $this->setContextValue('http', 'content', (string) $request->getBody(), true); + } + + // Always ensure a content-length header is sent + if (isset($this->contextOptions['http']['content'])) { + $headers = isset($this->contextOptions['http']['header']) ? $this->contextOptions['http']['header'] : array(); + $headers[] = 'Content-Length: ' . strlen($this->contextOptions['http']['content']); + $this->setContextValue('http', 'header', $headers, true); + } + } + + /** + * Add proxy parameters to the context if needed + * + * @param RequestInterface $request Request + */ + protected function addProxyOptions(RequestInterface $request) + { + if ($proxy = $request->getCurlOptions()->get(CURLOPT_PROXY)) { + $this->setContextValue('http', 'proxy', $proxy); + } + } + + /** + * Create the stream for the request with the context options + * + * @param array $params Parameters of the stream + * + * @return StreamInterface + */ + protected function createStream(array $params) + { + $http_response_header = null; + $url = $this->url; + $context = $this->context; + $fp = $this->createResource(function () use ($context, $url, &$http_response_header) { + return fopen((string) $url, 'r', false, $context); + }); + + // Determine the class to instantiate + $className = isset($params['stream_class']) ? $params['stream_class'] : __NAMESPACE__ . '\\Stream'; + + /** @var $stream StreamInterface */ + $stream = new $className($fp); + + // Track the response headers of the request + if (isset($http_response_header)) { + $this->lastResponseHeaders = $http_response_header; + $this->processResponseHeaders($stream); + } + + return $stream; + } + + /** + * Process response headers + * + * @param StreamInterface $stream + */ + protected function processResponseHeaders(StreamInterface $stream) + { + // Set the size on the stream if it was returned in the response + foreach ($this->lastResponseHeaders as $header) { + if ((stripos($header, 'Content-Length:')) === 0) { + $stream->setSize(trim(substr($header, 15))); + } + } + } + + /** + * Create a resource and check to ensure it was created successfully + * + * @param callable $callback Closure to invoke that must return a valid resource + * + * @return resource + * @throws RuntimeException on error + */ + protected function createResource($callback) + { + $errors = null; + set_error_handler(function ($_, $msg, $file, $line) use (&$errors) { + $errors[] = array( + 'message' => $msg, + 'file' => $file, + 'line' => $line + ); + return true; + }); + $resource = call_user_func($callback); + restore_error_handler(); + + if (!$resource) { + $message = 'Error creating resource. '; + foreach ($errors as $err) { + foreach ($err as $key => $value) { + $message .= "[$key] $value" . PHP_EOL; + } + } + throw new RuntimeException(trim($message)); + } + + return $resource; + } +} diff --git a/vendor/guzzle/guzzle/src/Guzzle/Stream/Stream.php b/vendor/guzzle/guzzle/src/Guzzle/Stream/Stream.php new file mode 100644 index 0000000..12bed26 --- /dev/null +++ b/vendor/guzzle/guzzle/src/Guzzle/Stream/Stream.php @@ -0,0 +1,289 @@ + array( + 'r' => true, 'w+' => true, 'r+' => true, 'x+' => true, 'c+' => true, + 'rb' => true, 'w+b' => true, 'r+b' => true, 'x+b' => true, 'c+b' => true, + 'rt' => true, 'w+t' => true, 'r+t' => true, 'x+t' => true, 'c+t' => true, 'a+' => true + ), + 'write' => array( + 'w' => true, 'w+' => true, 'rw' => true, 'r+' => true, 'x+' => true, 'c+' => true, + 'wb' => true, 'w+b' => true, 'r+b' => true, 'x+b' => true, 'c+b' => true, + 'w+t' => true, 'r+t' => true, 'x+t' => true, 'c+t' => true, 'a' => true, 'a+' => true + ) + ); + + /** + * @param resource $stream Stream resource to wrap + * @param int $size Size of the stream in bytes. Only pass if the size cannot be obtained from the stream. + * + * @throws InvalidArgumentException if the stream is not a stream resource + */ + public function __construct($stream, $size = null) + { + $this->setStream($stream, $size); + } + + /** + * Closes the stream when the helper is destructed + */ + public function __destruct() + { + $this->close(); + } + + public function __toString() + { + if (!$this->isReadable() || (!$this->isSeekable() && $this->isConsumed())) { + return ''; + } + + $originalPos = $this->ftell(); + $body = stream_get_contents($this->stream, -1, 0); + $this->seek($originalPos); + + return $body; + } + + public function close() + { + if (is_resource($this->stream)) { + fclose($this->stream); + } + $this->cache[self::IS_READABLE] = false; + $this->cache[self::IS_WRITABLE] = false; + } + + /** + * Calculate a hash of a Stream + * + * @param StreamInterface $stream Stream to calculate the hash for + * @param string $algo Hash algorithm (e.g. md5, crc32, etc) + * @param bool $rawOutput Whether or not to use raw output + * + * @return bool|string Returns false on failure or a hash string on success + */ + public static function getHash(StreamInterface $stream, $algo, $rawOutput = false) + { + $pos = $stream->ftell(); + if (!$stream->seek(0)) { + return false; + } + + $ctx = hash_init($algo); + while (!$stream->feof()) { + hash_update($ctx, $stream->read(8192)); + } + + $out = hash_final($ctx, (bool) $rawOutput); + $stream->seek($pos); + + return $out; + } + + public function getMetaData($key = null) + { + $meta = stream_get_meta_data($this->stream); + + return !$key ? $meta : (array_key_exists($key, $meta) ? $meta[$key] : null); + } + + public function getStream() + { + return $this->stream; + } + + public function setStream($stream, $size = null) + { + if (!is_resource($stream)) { + throw new InvalidArgumentException('Stream must be a resource'); + } + + $this->size = $size; + $this->stream = $stream; + $this->rebuildCache(); + + return $this; + } + + public function detachStream() + { + $this->stream = null; + + return $this; + } + + public function getWrapper() + { + return $this->cache[self::WRAPPER_TYPE]; + } + + public function getWrapperData() + { + return $this->getMetaData('wrapper_data') ?: array(); + } + + public function getStreamType() + { + return $this->cache[self::STREAM_TYPE]; + } + + public function getUri() + { + return $this->cache['uri']; + } + + public function getSize() + { + if ($this->size !== null) { + return $this->size; + } + + // If the stream is a file based stream and local, then use fstat + clearstatcache(true, $this->cache['uri']); + $stats = fstat($this->stream); + if (isset($stats['size'])) { + $this->size = $stats['size']; + return $this->size; + } elseif ($this->cache[self::IS_READABLE] && $this->cache[self::SEEKABLE]) { + // Only get the size based on the content if the the stream is readable and seekable + $pos = $this->ftell(); + $this->size = strlen((string) $this); + $this->seek($pos); + return $this->size; + } + + return false; + } + + public function isReadable() + { + return $this->cache[self::IS_READABLE]; + } + + public function isRepeatable() + { + return $this->cache[self::IS_READABLE] && $this->cache[self::SEEKABLE]; + } + + public function isWritable() + { + return $this->cache[self::IS_WRITABLE]; + } + + public function isConsumed() + { + return feof($this->stream); + } + + public function feof() + { + return $this->isConsumed(); + } + + public function isLocal() + { + return $this->cache[self::IS_LOCAL]; + } + + public function isSeekable() + { + return $this->cache[self::SEEKABLE]; + } + + public function setSize($size) + { + $this->size = $size; + + return $this; + } + + public function seek($offset, $whence = SEEK_SET) + { + return $this->cache[self::SEEKABLE] ? fseek($this->stream, $offset, $whence) === 0 : false; + } + + public function read($length) + { + return fread($this->stream, $length); + } + + public function write($string) + { + // We can't know the size after writing anything + $this->size = null; + + return fwrite($this->stream, $string); + } + + public function ftell() + { + return ftell($this->stream); + } + + public function rewind() + { + return $this->seek(0); + } + + public function readLine($maxLength = null) + { + if (!$this->cache[self::IS_READABLE]) { + return false; + } else { + return $maxLength ? fgets($this->getStream(), $maxLength) : fgets($this->getStream()); + } + } + + public function setCustomData($key, $value) + { + $this->customData[$key] = $value; + + return $this; + } + + public function getCustomData($key) + { + return isset($this->customData[$key]) ? $this->customData[$key] : null; + } + + /** + * Reprocess stream metadata + */ + protected function rebuildCache() + { + $this->cache = stream_get_meta_data($this->stream); + $this->cache[self::IS_LOCAL] = stream_is_local($this->stream); + $this->cache[self::IS_READABLE] = isset(self::$readWriteHash['read'][$this->cache['mode']]); + $this->cache[self::IS_WRITABLE] = isset(self::$readWriteHash['write'][$this->cache['mode']]); + } +} diff --git a/vendor/guzzle/guzzle/src/Guzzle/Stream/StreamInterface.php b/vendor/guzzle/guzzle/src/Guzzle/Stream/StreamInterface.php new file mode 100644 index 0000000..6d7dc37 --- /dev/null +++ b/vendor/guzzle/guzzle/src/Guzzle/Stream/StreamInterface.php @@ -0,0 +1,218 @@ +=5.3.2", + "guzzle/common": "self.version" + }, + "suggest": { + "guzzle/http": "To convert Guzzle request objects to PHP streams" + }, + "autoload": { + "psr-0": { "Guzzle\\Stream": "" } + }, + "target-dir": "Guzzle/Stream", + "extra": { + "branch-alias": { + "dev-master": "3.7-dev" + } + } +} diff --git a/vendor/guzzle/guzzle/tests/Guzzle/Tests/Batch/AbstractBatchDecoratorTest.php b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Batch/AbstractBatchDecoratorTest.php new file mode 100644 index 0000000..951738d --- /dev/null +++ b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Batch/AbstractBatchDecoratorTest.php @@ -0,0 +1,33 @@ +getMock('Guzzle\Batch\BatchTransferInterface'), + $this->getMock('Guzzle\Batch\BatchDivisorInterface') + ); + + $decoratorA = $this->getMockBuilder('Guzzle\Batch\AbstractBatchDecorator') + ->setConstructorArgs(array($batch)) + ->getMockForAbstractClass(); + + $decoratorB = $this->getMockBuilder('Guzzle\Batch\AbstractBatchDecorator') + ->setConstructorArgs(array($decoratorA)) + ->getMockForAbstractClass(); + + $decoratorA->add('foo'); + $this->assertFalse($decoratorB->isEmpty()); + $this->assertFalse($batch->isEmpty()); + $this->assertEquals(array($decoratorB, $decoratorA), $decoratorB->getDecorators()); + $this->assertEquals(array(), $decoratorB->flush()); + } +} diff --git a/vendor/guzzle/guzzle/tests/Guzzle/Tests/Batch/BatchBuilderTest.php b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Batch/BatchBuilderTest.php new file mode 100644 index 0000000..4da09d3 --- /dev/null +++ b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Batch/BatchBuilderTest.php @@ -0,0 +1,86 @@ +getMock('Guzzle\Batch\BatchTransferInterface'); + } + + private function getMockDivisor() + { + return $this->getMock('Guzzle\Batch\BatchDivisorInterface'); + } + + private function getMockBatchBuilder() + { + return BatchBuilder::factory() + ->transferWith($this->getMockTransfer()) + ->createBatchesWith($this->getMockDivisor()); + } + + public function testFactoryCreatesInstance() + { + $builder = BatchBuilder::factory(); + $this->assertInstanceOf('Guzzle\Batch\BatchBuilder', $builder); + } + + public function testAddsAutoFlush() + { + $batch = $this->getMockBatchBuilder()->autoFlushAt(10)->build(); + $this->assertInstanceOf('Guzzle\Batch\FlushingBatch', $batch); + } + + public function testAddsExceptionBuffering() + { + $batch = $this->getMockBatchBuilder()->bufferExceptions()->build(); + $this->assertInstanceOf('Guzzle\Batch\ExceptionBufferingBatch', $batch); + } + + public function testAddHistory() + { + $batch = $this->getMockBatchBuilder()->keepHistory()->build(); + $this->assertInstanceOf('Guzzle\Batch\HistoryBatch', $batch); + } + + public function testAddsNotify() + { + $batch = $this->getMockBatchBuilder()->notify(function() {})->build(); + $this->assertInstanceOf('Guzzle\Batch\NotifyingBatch', $batch); + } + + /** + * @expectedException Guzzle\Common\Exception\RuntimeException + */ + public function testTransferStrategyMustBeSet() + { + $batch = BatchBuilder::factory()->createBatchesWith($this->getMockDivisor())->build(); + } + + /** + * @expectedException Guzzle\Common\Exception\RuntimeException + */ + public function testDivisorStrategyMustBeSet() + { + $batch = BatchBuilder::factory()->transferWith($this->getMockTransfer())->build(); + } + + public function testTransfersRequests() + { + $batch = BatchBuilder::factory()->transferRequests(10)->build(); + $this->assertInstanceOf('Guzzle\Batch\BatchRequestTransfer', $this->readAttribute($batch, 'transferStrategy')); + } + + public function testTransfersCommands() + { + $batch = BatchBuilder::factory()->transferCommands(10)->build(); + $this->assertInstanceOf('Guzzle\Batch\BatchCommandTransfer', $this->readAttribute($batch, 'transferStrategy')); + } +} diff --git a/vendor/guzzle/guzzle/tests/Guzzle/Tests/Batch/BatchClosureDivisorTest.php b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Batch/BatchClosureDivisorTest.php new file mode 100644 index 0000000..753db7d --- /dev/null +++ b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Batch/BatchClosureDivisorTest.php @@ -0,0 +1,36 @@ +createBatches($queue); + $this->assertEquals(array(array('foo'), array('baz')), $batches); + } +} diff --git a/vendor/guzzle/guzzle/tests/Guzzle/Tests/Batch/BatchClosureTransferTest.php b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Batch/BatchClosureTransferTest.php new file mode 100644 index 0000000..6ba7ae0 --- /dev/null +++ b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Batch/BatchClosureTransferTest.php @@ -0,0 +1,52 @@ +itemsTransferred = null; + $itemsTransferred =& $this->itemsTransferred; + + $this->transferStrategy = new BatchClosureTransfer(function (array $batch) use (&$itemsTransferred) { + $itemsTransferred = $batch; + return; + }); + } + + public function testTransfersBatch() + { + $batchedItems = array('foo', 'bar', 'baz'); + $this->transferStrategy->transfer($batchedItems); + + $this->assertEquals($batchedItems, $this->itemsTransferred); + } + + public function testTransferBailsOnEmptyBatch() + { + $batchedItems = array(); + $this->transferStrategy->transfer($batchedItems); + + $this->assertNull($this->itemsTransferred); + } + + /** + * @expectedException Guzzle\Common\Exception\InvalidArgumentException + */ + public function testEnsuresCallableIsCallable() + { + $foo = new BatchClosureTransfer('uh oh!'); + } +} diff --git a/vendor/guzzle/guzzle/tests/Guzzle/Tests/Batch/BatchCommandTransferTest.php b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Batch/BatchCommandTransferTest.php new file mode 100644 index 0000000..a04efab --- /dev/null +++ b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Batch/BatchCommandTransferTest.php @@ -0,0 +1,83 @@ + $command) { + if ($i % 2) { + $command->setClient($client1); + } else { + $command->setClient($client2); + } + $queue[] = $command; + } + + $batch = new BatchCommandTransfer(2); + $this->assertEquals(array( + array($commands[0], $commands[2]), + array($commands[4]), + array($commands[1], $commands[3]) + ), $batch->createBatches($queue)); + } + + /** + * @expectedException Guzzle\Common\Exception\InvalidArgumentException + */ + public function testEnsuresAllItemsAreCommands() + { + $queue = new \SplQueue(); + $queue[] = 'foo'; + $batch = new BatchCommandTransfer(2); + $batch->createBatches($queue); + } + + public function testTransfersBatches() + { + $client = $this->getMockBuilder('Guzzle\Service\Client') + ->setMethods(array('send')) + ->getMock(); + $client->expects($this->once()) + ->method('send'); + $command = new Mc(); + $command->setClient($client); + $batch = new BatchCommandTransfer(2); + $batch->transfer(array($command)); + } + + public function testDoesNotTransfersEmptyBatches() + { + $batch = new BatchCommandTransfer(2); + $batch->transfer(array()); + } + + /** + * @expectedException Guzzle\Service\Exception\InconsistentClientTransferException + */ + public function testEnsuresAllCommandsUseTheSameClient() + { + $batch = new BatchCommandTransfer(2); + $client1 = new Client('http://www.example.com'); + $client2 = new Client('http://www.example.com'); + $command1 = new Mc(); + $command1->setClient($client1); + $command2 = new Mc(); + $command2->setClient($client2); + $batch->transfer(array($command1, $command2)); + } +} diff --git a/vendor/guzzle/guzzle/tests/Guzzle/Tests/Batch/BatchRequestTransferTest.php b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Batch/BatchRequestTransferTest.php new file mode 100644 index 0000000..dec7bd5 --- /dev/null +++ b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Batch/BatchRequestTransferTest.php @@ -0,0 +1,80 @@ +setCurlMulti(new CurlMulti()); + + $client2 = new Client('http://www.example.com'); + $client2->setCurlMulti(new CurlMulti()); + + $request1 = $client1->get(); + $request2 = $client2->get(); + $request3 = $client1->get(); + $request4 = $client2->get(); + $request5 = $client1->get(); + + $queue = new \SplQueue(); + $queue[] = $request1; + $queue[] = $request2; + $queue[] = $request3; + $queue[] = $request4; + $queue[] = $request5; + + $batch = new BatchRequestTransfer(2); + $this->assertEquals(array( + array($request1, $request3), + array($request3), + array($request2, $request4) + ), $batch->createBatches($queue)); + } + + /** + * @expectedException \Guzzle\Common\Exception\InvalidArgumentException + */ + public function testEnsuresAllItemsAreRequests() + { + $queue = new \SplQueue(); + $queue[] = 'foo'; + $batch = new BatchRequestTransfer(2); + $batch->createBatches($queue); + } + + public function testTransfersBatches() + { + $client = new Client('http://127.0.0.1:123'); + $request = $client->get(); + // For some reason... PHP unit clones the request, which emits a request.clone event. This causes the + // 'sorted' property of the event dispatcher to contain an array in the cloned request that is not present in + // the original. + $request->dispatch('request.clone'); + + $multi = $this->getMock('Guzzle\Http\Curl\CurlMultiInterface'); + $client->setCurlMulti($multi); + $multi->expects($this->once()) + ->method('add') + ->with($request); + $multi->expects($this->once()) + ->method('send'); + + $batch = new BatchRequestTransfer(2); + $batch->transfer(array($request)); + } + + public function testDoesNotTransfersEmptyBatches() + { + $batch = new BatchRequestTransfer(2); + $batch->transfer(array()); + } +} diff --git a/vendor/guzzle/guzzle/tests/Guzzle/Tests/Batch/BatchSizeDivisorTest.php b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Batch/BatchSizeDivisorTest.php new file mode 100644 index 0000000..5542228 --- /dev/null +++ b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Batch/BatchSizeDivisorTest.php @@ -0,0 +1,24 @@ +assertEquals(3, $d->getSize()); + $d->setSize(2); + $batches = $d->createBatches($queue); + $this->assertEquals(array(array('foo', 'baz'), array('bar')), $batches); + } +} diff --git a/vendor/guzzle/guzzle/tests/Guzzle/Tests/Batch/BatchTest.php b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Batch/BatchTest.php new file mode 100644 index 0000000..296f57a --- /dev/null +++ b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Batch/BatchTest.php @@ -0,0 +1,91 @@ +getMock('Guzzle\Batch\BatchTransferInterface'); + } + + private function getMockDivisor() + { + return $this->getMock('Guzzle\Batch\BatchDivisorInterface'); + } + + public function testAddsItemsToQueue() + { + $batch = new Batch($this->getMockTransfer(), $this->getMockDivisor()); + $this->assertSame($batch, $batch->add('foo')); + $this->assertEquals(1, count($batch)); + } + + public function testFlushReturnsItems() + { + $transfer = $this->getMockTransfer(); + $transfer->expects($this->exactly(2)) + ->method('transfer'); + + $divisor = $this->getMockDivisor(); + $divisor->expects($this->once()) + ->method('createBatches') + ->will($this->returnValue(array(array('foo', 'baz'), array('bar')))); + + $batch = new Batch($transfer, $divisor); + + $batch->add('foo')->add('baz')->add('bar'); + $items = $batch->flush(); + + $this->assertEquals(array('foo', 'baz', 'bar'), $items); + } + + public function testThrowsExceptionContainingTheFailedBatch() + { + $called = 0; + $originalException = new \Exception('Foo!'); + + $transfer = $this->getMockTransfer(); + $transfer->expects($this->exactly(2)) + ->method('transfer') + ->will($this->returnCallback(function () use (&$called, $originalException) { + if (++$called == 2) { + throw $originalException; + } + })); + + $divisor = $this->getMockDivisor(); + $batch = new Batch($transfer, $divisor); + + // PHPunit clones objects before passing them to a callback. + // Horrible hack to get around this! + $queue = $this->readAttribute($batch, 'queue'); + + $divisor->expects($this->once()) + ->method('createBatches') + ->will($this->returnCallback(function ($batch) use ($queue) { + foreach ($queue as $item) { + $items[] = $item; + } + return array_chunk($items, 2); + })); + + $batch->add('foo')->add('baz')->add('bar')->add('bee')->add('boo'); + $this->assertFalse($batch->isEmpty()); + + try { + $items = $batch->flush(); + $this->fail('Expected exception'); + } catch (BatchTransferException $e) { + $this->assertEquals($originalException, $e->getPrevious()); + $this->assertEquals(array('bar', 'bee'), array_values($e->getBatch())); + $this->assertEquals(1, count($batch)); + } + } +} diff --git a/vendor/guzzle/guzzle/tests/Guzzle/Tests/Batch/ExceptionBufferingBatchTest.php b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Batch/ExceptionBufferingBatchTest.php new file mode 100644 index 0000000..fd810b1 --- /dev/null +++ b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Batch/ExceptionBufferingBatchTest.php @@ -0,0 +1,45 @@ +getMockBuilder('Guzzle\Batch\BatchTransferInterface') + ->setMethods(array('transfer')) + ->getMock(); + + $d = new BatchSizeDivisor(1); + $batch = new Batch($t, $d); + + $called = 0; + $t->expects($this->exactly(3)) + ->method('transfer') + ->will($this->returnCallback(function ($batch) use (&$called) { + if (++$called === 2) { + throw new \Exception('Foo'); + } + })); + + $decorator = new ExceptionBufferingBatch($batch); + $decorator->add('foo')->add('baz')->add('bar'); + $result = $decorator->flush(); + + $e = $decorator->getExceptions(); + $this->assertEquals(1, count($e)); + $this->assertEquals(array('baz'), $e[0]->getBatch()); + + $decorator->clearExceptions(); + $this->assertEquals(0, count($decorator->getExceptions())); + + $this->assertEquals(array('foo', 'bar'), $result); + } +} diff --git a/vendor/guzzle/guzzle/tests/Guzzle/Tests/Batch/FlushingBatchTest.php b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Batch/FlushingBatchTest.php new file mode 100644 index 0000000..9b37a48 --- /dev/null +++ b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Batch/FlushingBatchTest.php @@ -0,0 +1,40 @@ +getMock('Guzzle\Batch\BatchTransferInterface', array('transfer')); + $d = $this->getMock('Guzzle\Batch\BatchDivisorInterface', array('createBatches')); + + $batch = new Batch($t, $d); + $queue = $this->readAttribute($batch, 'queue'); + + $d->expects($this->exactly(2)) + ->method('createBatches') + ->will($this->returnCallback(function () use ($queue) { + $items = array(); + foreach ($queue as $item) { + $items[] = $item; + } + return array($items); + })); + + $t->expects($this->exactly(2)) + ->method('transfer'); + + $flush = new FlushingBatch($batch, 3); + $this->assertEquals(3, $flush->getThreshold()); + $flush->setThreshold(2); + $flush->add('foo')->add('baz')->add('bar')->add('bee')->add('boo'); + $this->assertEquals(1, count($flush)); + } +} diff --git a/vendor/guzzle/guzzle/tests/Guzzle/Tests/Batch/HistoryBatchTest.php b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Batch/HistoryBatchTest.php new file mode 100644 index 0000000..60d6f95 --- /dev/null +++ b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Batch/HistoryBatchTest.php @@ -0,0 +1,26 @@ +getMock('Guzzle\Batch\BatchTransferInterface'), + $this->getMock('Guzzle\Batch\BatchDivisorInterface') + ); + + $history = new HistoryBatch($batch); + $history->add('foo')->add('baz'); + $this->assertEquals(array('foo', 'baz'), $history->getHistory()); + $history->clearHistory(); + $this->assertEquals(array(), $history->getHistory()); + } +} diff --git a/vendor/guzzle/guzzle/tests/Guzzle/Tests/Batch/NotifyingBatchTest.php b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Batch/NotifyingBatchTest.php new file mode 100644 index 0000000..69a8900 --- /dev/null +++ b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Batch/NotifyingBatchTest.php @@ -0,0 +1,45 @@ +getMock('Guzzle\Batch\Batch', array('flush'), array( + $this->getMock('Guzzle\Batch\BatchTransferInterface'), + $this->getMock('Guzzle\Batch\BatchDivisorInterface') + )); + + $batch->expects($this->once()) + ->method('flush') + ->will($this->returnValue(array('foo', 'baz'))); + + $data = array(); + $decorator = new NotifyingBatch($batch, function ($batch) use (&$data) { + $data[] = $batch; + }); + + $decorator->add('foo')->add('baz'); + $decorator->flush(); + $this->assertEquals(array(array('foo', 'baz')), $data); + } + + /** + * @expectedException Guzzle\Common\Exception\InvalidArgumentException + */ + public function testEnsuresCallableIsValid() + { + $batch = new Batch( + $this->getMock('Guzzle\Batch\BatchTransferInterface'), + $this->getMock('Guzzle\Batch\BatchDivisorInterface') + ); + $decorator = new NotifyingBatch($batch, 'foo'); + } +} diff --git a/vendor/guzzle/guzzle/tests/Guzzle/Tests/Cache/CacheAdapterFactoryTest.php b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Cache/CacheAdapterFactoryTest.php new file mode 100644 index 0000000..c4140a9 --- /dev/null +++ b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Cache/CacheAdapterFactoryTest.php @@ -0,0 +1,64 @@ +cache = new ArrayCache(); + $this->adapter = new DoctrineCacheAdapter($this->cache); + } + + /** + * @expectedException \InvalidArgumentException + */ + public function testEnsuresConfigIsObject() + { + CacheAdapterFactory::fromCache(array()); + } + + /** + * @expectedException \InvalidArgumentException + */ + public function testEnsuresKnownType() + { + CacheAdapterFactory::fromCache(new \stdClass()); + } + + public function cacheProvider() + { + return array( + array(new DoctrineCacheAdapter(new ArrayCache()), 'Guzzle\Cache\DoctrineCacheAdapter'), + array(new ArrayCache(), 'Guzzle\Cache\DoctrineCacheAdapter'), + array(StorageFactory::factory(array('adapter' => 'memory')), 'Guzzle\Cache\Zf2CacheAdapter'), + ); + } + + /** + * @dataProvider cacheProvider + */ + public function testCreatesNullCacheAdapterByDefault($cache, $type) + { + $adapter = CacheAdapterFactory::fromCache($cache); + $this->assertInstanceOf($type, $adapter); + } +} diff --git a/vendor/guzzle/guzzle/tests/Guzzle/Tests/Cache/CacheAdapterTest.php b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Cache/CacheAdapterTest.php new file mode 100644 index 0000000..3e30ddd --- /dev/null +++ b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Cache/CacheAdapterTest.php @@ -0,0 +1,68 @@ +cache = new ArrayCache(); + $this->adapter = new DoctrineCacheAdapter($this->cache); + } + + /** + * Cleans up the environment after running a test. + */ + protected function tearDown() + { + $this->adapter = null; + $this->cache = null; + parent::tearDown(); + } + + public function testGetCacheObject() + { + $this->assertEquals($this->cache, $this->adapter->getCacheObject()); + } + + public function testSave() + { + $this->assertTrue($this->adapter->save('test', 'data', 1000)); + } + + public function testFetch() + { + $this->assertTrue($this->adapter->save('test', 'data', 1000)); + $this->assertEquals('data', $this->adapter->fetch('test')); + } + + public function testContains() + { + $this->assertTrue($this->adapter->save('test', 'data', 1000)); + $this->assertTrue($this->adapter->contains('test')); + } + + public function testDelete() + { + $this->assertTrue($this->adapter->save('test', 'data', 1000)); + $this->assertTrue($this->adapter->delete('test')); + $this->assertFalse($this->adapter->contains('test')); + } +} diff --git a/vendor/guzzle/guzzle/tests/Guzzle/Tests/Cache/ClosureCacheAdapterTest.php b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Cache/ClosureCacheAdapterTest.php new file mode 100644 index 0000000..12de65b --- /dev/null +++ b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Cache/ClosureCacheAdapterTest.php @@ -0,0 +1,94 @@ +callables = array( + 'contains' => function($id, $options = array()) use ($that) { + return array_key_exists($id, $that->data); + }, + 'delete' => function($id, $options = array()) use ($that) { + unset($that->data[$id]); + return true; + }, + 'fetch' => function($id, $options = array()) use ($that) { + return array_key_exists($id, $that->data) ? $that->data[$id] : null; + }, + 'save' => function($id, $data, $lifeTime, $options = array()) use ($that) { + $that->data[$id] = $data; + return true; + } + ); + + $this->adapter = new ClosureCacheAdapter($this->callables); + } + + /** + * Cleans up the environment after running a test. + */ + protected function tearDown() + { + $this->cache = null; + $this->callables = null; + parent::tearDown(); + } + + /** + * @expectedException InvalidArgumentException + */ + public function testEnsuresCallablesArePresent() + { + $callables = $this->callables; + unset($callables['delete']); + $cache = new ClosureCacheAdapter($callables); + } + + public function testAllCallablesMustBePresent() + { + $cache = new ClosureCacheAdapter($this->callables); + } + + public function testCachesDataUsingCallables() + { + $this->assertTrue($this->adapter->save('test', 'data', 1000)); + $this->assertEquals('data', $this->adapter->fetch('test')); + } + + public function testChecksIfCacheContainsKeys() + { + $this->adapter->save('test', 'data', 1000); + $this->assertTrue($this->adapter->contains('test')); + $this->assertFalse($this->adapter->contains('foo')); + } + + public function testDeletesFromCacheByKey() + { + $this->adapter->save('test', 'data', 1000); + $this->assertTrue($this->adapter->contains('test')); + $this->adapter->delete('test'); + $this->assertFalse($this->adapter->contains('test')); + } +} diff --git a/vendor/guzzle/guzzle/tests/Guzzle/Tests/Cache/NullCacheAdapterTest.php b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Cache/NullCacheAdapterTest.php new file mode 100644 index 0000000..e05df3f --- /dev/null +++ b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Cache/NullCacheAdapterTest.php @@ -0,0 +1,20 @@ +assertEquals(false, $c->contains('foo')); + $this->assertEquals(true, $c->delete('foo')); + $this->assertEquals(false, $c->fetch('foo')); + $this->assertEquals(true, $c->save('foo', 'bar')); + } +} diff --git a/vendor/guzzle/guzzle/tests/Guzzle/Tests/Cache/Zf2CacheAdapterTest.php b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Cache/Zf2CacheAdapterTest.php new file mode 100644 index 0000000..9077c12 --- /dev/null +++ b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Cache/Zf2CacheAdapterTest.php @@ -0,0 +1,58 @@ +cache = StorageFactory::factory(array( + 'adapter' => 'memory' + )); + $this->adapter = new Zf2CacheAdapter($this->cache); + } + + /** + * Cleans up the environment after running a test. + */ + protected function tearDown() + { + $this->adapter = null; + $this->cache = null; + parent::tearDown(); + } + + public function testCachesDataUsingCallables() + { + $this->assertTrue($this->adapter->save('test', 'data', 1000)); + $this->assertEquals('data', $this->adapter->fetch('test')); + } + + public function testChecksIfCacheContainsKeys() + { + $this->adapter->save('test', 'data', 1000); + $this->assertTrue($this->adapter->contains('test')); + $this->assertFalse($this->adapter->contains('foo')); + } + + public function testDeletesFromCacheByKey() + { + $this->adapter->save('test', 'data', 1000); + $this->assertTrue($this->adapter->contains('test')); + $this->adapter->delete('test'); + $this->assertFalse($this->adapter->contains('test')); + } +} diff --git a/vendor/guzzle/guzzle/tests/Guzzle/Tests/Common/AbstractHasDispatcherTest.php b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Common/AbstractHasDispatcherTest.php new file mode 100644 index 0000000..19d12e6 --- /dev/null +++ b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Common/AbstractHasDispatcherTest.php @@ -0,0 +1,63 @@ +assertEquals(array(), AbstractHasDispatcher::getAllEvents()); + } + + public function testAllowsDispatcherToBeInjected() + { + $d = new EventDispatcher(); + $mock = $this->getMockForAbstractClass('Guzzle\Common\AbstractHasDispatcher'); + $this->assertSame($mock, $mock->setEventDispatcher($d)); + $this->assertSame($d, $mock->getEventDispatcher()); + } + + public function testCreatesDefaultEventDispatcherIfNeeded() + { + $mock = $this->getMockForAbstractClass('Guzzle\Common\AbstractHasDispatcher'); + $this->assertInstanceOf('Symfony\Component\EventDispatcher\EventDispatcher', $mock->getEventDispatcher()); + } + + public function testHelperDispatchesEvents() + { + $data = array(); + $mock = $this->getMockForAbstractClass('Guzzle\Common\AbstractHasDispatcher'); + $mock->getEventDispatcher()->addListener('test', function(Event $e) use (&$data) { + $data = $e->getIterator()->getArrayCopy(); + }); + $mock->dispatch('test', array( + 'param' => 'abc' + )); + $this->assertEquals(array( + 'param' => 'abc', + ), $data); + } + + public function testHelperAttachesSubscribers() + { + $mock = $this->getMockForAbstractClass('Guzzle\Common\AbstractHasDispatcher'); + $subscriber = $this->getMockForAbstractClass('Symfony\Component\EventDispatcher\EventSubscriberInterface'); + + $dispatcher = $this->getMockBuilder('Symfony\Component\EventDispatcher\EventDispatcher') + ->setMethods(array('addSubscriber')) + ->getMock(); + + $dispatcher->expects($this->once()) + ->method('addSubscriber'); + + $mock->setEventDispatcher($dispatcher); + $mock->addSubscriber($subscriber); + } +} diff --git a/vendor/guzzle/guzzle/tests/Guzzle/Tests/Common/CollectionTest.php b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Common/CollectionTest.php new file mode 100644 index 0000000..0648a02 --- /dev/null +++ b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Common/CollectionTest.php @@ -0,0 +1,529 @@ +coll = new Collection(); + } + + public function testConstructorCanBeCalledWithNoParams() + { + $this->coll = new Collection(); + $p = $this->coll->getAll(); + $this->assertEmpty($p, '-> Collection must be empty when no data is passed'); + } + + public function testConstructorCanBeCalledWithParams() + { + $testData = array( + 'test' => 'value', + 'test_2' => 'value2' + ); + $this->coll = new Collection($testData); + $this->assertEquals($this->coll->getAll(), $testData, '-> getAll() must return the data passed in the constructor'); + $this->assertEquals($this->coll->getAll(), $this->coll->toArray()); + } + + public function testImplementsIteratorAggregate() + { + $this->coll->set('key', 'value'); + $this->assertInstanceOf('ArrayIterator', $this->coll->getIterator()); + $this->assertEquals(1, count($this->coll)); + $total = 0; + foreach ($this->coll as $key => $value) { + $this->assertEquals('key', $key); + $this->assertEquals('value', $value); + $total++; + } + $this->assertEquals(1, $total); + } + + public function testCanAddValuesToExistingKeysByUsingArray() + { + $this->coll->add('test', 'value1'); + $this->assertEquals($this->coll->getAll(), array('test' => 'value1')); + $this->coll->add('test', 'value2'); + $this->assertEquals($this->coll->getAll(), array('test' => array('value1', 'value2'))); + $this->coll->add('test', 'value3'); + $this->assertEquals($this->coll->getAll(), array('test' => array('value1', 'value2', 'value3'))); + } + + public function testHandlesMergingInDisparateDataSources() + { + $params = array( + 'test' => 'value1', + 'test2' => 'value2', + 'test3' => array('value3', 'value4') + ); + $this->coll->merge($params); + $this->assertEquals($this->coll->getAll(), $params); + + // Pass the same object to itself + $this->assertEquals($this->coll->merge($this->coll), $this->coll); + } + + public function testCanClearAllDataOrSpecificKeys() + { + $this->coll->merge(array( + 'test' => 'value1', + 'test2' => 'value2' + )); + + // Clear a specific parameter by name + $this->coll->remove('test'); + + $this->assertEquals($this->coll->getAll(), array( + 'test2' => 'value2' + )); + + // Clear all parameters + $this->coll->clear(); + + $this->assertEquals($this->coll->getAll(), array()); + } + + public function testGetsValuesByKey() + { + $this->assertNull($this->coll->get('test')); + $this->coll->add('test', 'value'); + $this->assertEquals('value', $this->coll->get('test')); + $this->coll->set('test2', 'v2'); + $this->coll->set('test3', 'v3'); + $this->assertEquals(array( + 'test' => 'value', + 'test2' => 'v2' + ), $this->coll->getAll(array('test', 'test2'))); + } + + public function testProvidesKeys() + { + $this->assertEquals(array(), $this->coll->getKeys()); + $this->coll->merge(array( + 'test1' => 'value1', + 'test2' => 'value2' + )); + $this->assertEquals(array('test1', 'test2'), $this->coll->getKeys()); + // Returns the cached array previously returned + $this->assertEquals(array('test1', 'test2'), $this->coll->getKeys()); + $this->coll->remove('test1'); + $this->assertEquals(array('test2'), $this->coll->getKeys()); + $this->coll->add('test3', 'value3'); + $this->assertEquals(array('test2', 'test3'), $this->coll->getKeys()); + } + + public function testChecksIfHasKey() + { + $this->assertFalse($this->coll->hasKey('test')); + $this->coll->add('test', 'value'); + $this->assertEquals(true, $this->coll->hasKey('test')); + $this->coll->add('test2', 'value2'); + $this->assertEquals(true, $this->coll->hasKey('test')); + $this->assertEquals(true, $this->coll->hasKey('test2')); + $this->assertFalse($this->coll->hasKey('testing')); + $this->assertEquals(false, $this->coll->hasKey('AB-C', 'junk')); + } + + public function testChecksIfHasValue() + { + $this->assertFalse($this->coll->hasValue('value')); + $this->coll->add('test', 'value'); + $this->assertEquals('test', $this->coll->hasValue('value')); + $this->coll->add('test2', 'value2'); + $this->assertEquals('test', $this->coll->hasValue('value')); + $this->assertEquals('test2', $this->coll->hasValue('value2')); + $this->assertFalse($this->coll->hasValue('val')); + } + + public function testCanGetAllValuesByArray() + { + $this->coll->add('foo', 'bar'); + $this->coll->add('tEsT', 'value'); + $this->coll->add('tesTing', 'v2'); + $this->coll->add('key', 'v3'); + $this->assertNull($this->coll->get('test')); + $this->assertEquals(array( + 'foo' => 'bar', + 'tEsT' => 'value', + 'tesTing' => 'v2' + ), $this->coll->getAll(array( + 'foo', 'tesTing', 'tEsT' + ))); + } + + public function testImplementsCount() + { + $data = new Collection(); + $this->assertEquals(0, $data->count()); + $data->add('key', 'value'); + $this->assertEquals(1, count($data)); + $data->add('key', 'value2'); + $this->assertEquals(1, count($data)); + $data->add('key_2', 'value3'); + $this->assertEquals(2, count($data)); + } + + public function testAddParamsByMerging() + { + $params = array( + 'test' => 'value1', + 'test2' => 'value2', + 'test3' => array('value3', 'value4') + ); + + // Add some parameters + $this->coll->merge($params); + + // Add more parameters by merging them in + $this->coll->merge(array( + 'test' => 'another', + 'different_key' => 'new value' + )); + + $this->assertEquals(array( + 'test' => array('value1', 'another'), + 'test2' => 'value2', + 'test3' => array('value3', 'value4'), + 'different_key' => 'new value' + ), $this->coll->getAll()); + } + + public function testAllowsFunctionalFilter() + { + $this->coll->merge(array( + 'fruit' => 'apple', + 'number' => 'ten', + 'prepositions' => array('about', 'above', 'across', 'after'), + 'same_number' => 'ten' + )); + + $filtered = $this->coll->filter(function($key, $value) { + return $value == 'ten'; + }); + + $this->assertNotEquals($filtered, $this->coll); + + $this->assertEquals(array( + 'number' => 'ten', + 'same_number' => 'ten' + ), $filtered->getAll()); + } + + public function testAllowsFunctionalMapping() + { + $this->coll->merge(array( + 'number_1' => 1, + 'number_2' => 2, + 'number_3' => 3 + )); + + $mapped = $this->coll->map(function($key, $value) { + return $value * $value; + }); + + $this->assertNotEquals($mapped, $this->coll); + + $this->assertEquals(array( + 'number_1' => 1, + 'number_2' => 4, + 'number_3' => 9 + ), $mapped->getAll()); + } + + public function testImplementsArrayAccess() + { + $this->coll->merge(array( + 'k1' => 'v1', + 'k2' => 'v2' + )); + + $this->assertTrue($this->coll->offsetExists('k1')); + $this->assertFalse($this->coll->offsetExists('Krull')); + + $this->coll->offsetSet('k3', 'v3'); + $this->assertEquals('v3', $this->coll->offsetGet('k3')); + $this->assertEquals('v3', $this->coll->get('k3')); + + $this->coll->offsetUnset('k1'); + $this->assertFalse($this->coll->offsetExists('k1')); + } + + public function testUsesStaticWhenCreatingNew() + { + $qs = new QueryString(array( + 'a' => 'b', + 'c' => 'd' + )); + + $this->assertInstanceOf('Guzzle\\Http\\QueryString', $qs->map(function($a, $b) {})); + $this->assertInstanceOf('Guzzle\\Common\\Collection', $qs->map(function($a, $b) {}, array(), false)); + + $this->assertInstanceOf('Guzzle\\Http\\QueryString', $qs->filter(function($a, $b) {})); + $this->assertInstanceOf('Guzzle\\Common\\Collection', $qs->filter(function($a, $b) {}, false)); + } + + public function testCanReplaceAllData() + { + $this->assertSame($this->coll, $this->coll->replace(array( + 'a' => '123' + ))); + + $this->assertEquals(array( + 'a' => '123' + ), $this->coll->getAll()); + } + + public function dataProvider() + { + return array( + array('this_is_a_test', '{a}_is_a_{b}', array( + 'a' => 'this', + 'b' => 'test' + )), + array('this_is_a_test', '{abc}_is_a_{0}', array( + 'abc' => 'this', + 0 => 'test' + )), + array('this_is_a_test', '{abc}_is_a_{0}', array( + 'abc' => 'this', + 0 => 'test' + )), + array('this_is_a_test', 'this_is_a_test', array( + 'abc' => 'this' + )), + array('{abc}_is_{not_found}a_{0}', '{abc}_is_{not_found}a_{0}', array()) + ); + } + + /** + * @dataProvider dataProvider + */ + public function testInjectsConfigData($output, $input, $config) + { + $collection = new Collection($config); + $this->assertEquals($output, $collection->inject($input)); + } + + public function testCanSearchByKey() + { + $collection = new Collection(array( + 'foo' => 'bar', + 'BaZ' => 'pho' + )); + + $this->assertEquals('foo', $collection->keySearch('FOO')); + $this->assertEquals('BaZ', $collection->keySearch('baz')); + $this->assertEquals(false, $collection->keySearch('Bar')); + } + + public function testPreparesFromConfig() + { + $c = Collection::fromConfig(array( + 'a' => '123', + 'base_url' => 'http://www.test.com/' + ), array( + 'a' => 'xyz', + 'b' => 'lol' + ), array('a')); + + $this->assertInstanceOf('Guzzle\Common\Collection', $c); + $this->assertEquals(array( + 'a' => '123', + 'b' => 'lol', + 'base_url' => 'http://www.test.com/' + ), $c->getAll()); + + try { + $c = Collection::fromConfig(array(), array(), array('a')); + $this->fail('Exception not throw when missing config'); + } catch (InvalidArgumentException $e) { + } + } + + function falseyDataProvider() + { + return array( + array(false, false), + array(null, null), + array('', ''), + array(array(), array()), + array(0, 0), + ); + } + + /** + * @dataProvider falseyDataProvider + */ + public function testReturnsCorrectData($a, $b) + { + $c = new Collection(array('value' => $a)); + $this->assertSame($b, $c->get('value')); + } + + public function testRetrievesNestedKeysUsingPath() + { + $data = array( + 'foo' => 'bar', + 'baz' => array( + 'mesa' => array( + 'jar' => 'jar' + ) + ) + ); + $collection = new Collection($data); + $this->assertEquals('bar', $collection->getPath('foo')); + $this->assertEquals('jar', $collection->getPath('baz/mesa/jar')); + $this->assertNull($collection->getPath('wewewf')); + $this->assertNull($collection->getPath('baz/mesa/jar/jar')); + } + + public function testFalseyKeysStillDescend() + { + $collection = new Collection(array( + '0' => array( + 'a' => 'jar' + ), + 1 => 'other' + )); + $this->assertEquals('jar', $collection->getPath('0/a')); + $this->assertEquals('other', $collection->getPath('1')); + } + + public function getPathProvider() + { + $data = array( + 'foo' => 'bar', + 'baz' => array( + 'mesa' => array( + 'jar' => 'jar', + 'array' => array('a', 'b', 'c') + ), + 'bar' => array( + 'baz' => 'bam', + 'array' => array('d', 'e', 'f') + ) + ), + 'bam' => array( + array('foo' => 1), + array('foo' => 2), + array('array' => array('h', 'i')) + ) + ); + $c = new Collection($data); + + return array( + // Simple path selectors + array($c, 'foo', 'bar'), + array($c, 'baz', $data['baz']), + array($c, 'bam', $data['bam']), + array($c, 'baz/mesa', $data['baz']['mesa']), + array($c, 'baz/mesa/jar', 'jar'), + // Merge everything two levels under baz + array($c, 'baz/*', array( + 'jar' => 'jar', + 'array' => array_merge($data['baz']['mesa']['array'], $data['baz']['bar']['array']), + 'baz' => 'bam' + )), + // Does not barf on missing keys + array($c, 'fefwfw', null), + // Does not barf when a wildcard does not resolve correctly + array($c, '*/*/*/*/*/wefwfe', array()), + // Allows custom separator + array($c, '*|mesa', $data['baz']['mesa'], '|'), + // Merge all 'array' keys two levels under baz (the trailing * does not hurt the results) + array($c, 'baz/*/array/*', array_merge($data['baz']['mesa']['array'], $data['baz']['bar']['array'])), + // Merge all 'array' keys two levels under baz + array($c, 'baz/*/array', array_merge($data['baz']['mesa']['array'], $data['baz']['bar']['array'])), + array($c, 'baz/mesa/array', $data['baz']['mesa']['array']), + // Having a trailing * does not hurt the results + array($c, 'baz/mesa/array/*', $data['baz']['mesa']['array']), + // Merge of anything one level deep + array($c, '*', array_merge(array('bar'), $data['baz'], $data['bam'])), + // Funky merge of anything two levels deep + array($c, '*/*', array( + 'jar' => 'jar', + 'array' => array('a', 'b', 'c', 'd', 'e', 'f', 'h', 'i'), + 'baz' => 'bam', + 'foo' => array(1, 2) + )), + // Funky merge of all 'array' keys that are two levels deep + array($c, '*/*/array', array('a', 'b', 'c', 'd', 'e', 'f', 'h', 'i')) + ); + } + + /** + * @dataProvider getPathProvider + */ + public function testGetPath(Collection $c, $path, $expected, $separator = '/') + { + $this->assertEquals($expected, $c->getPath($path, $separator)); + } + + public function testOverridesSettings() + { + $c = new Collection(array('foo' => 1, 'baz' => 2, 'bar' => 3)); + $c->overwriteWith(array('foo' => 10, 'bar' => 300)); + $this->assertEquals(array('foo' => 10, 'baz' => 2, 'bar' => 300), $c->getAll()); + } + + public function testOverwriteWithCollection() + { + $c = new Collection(array('foo' => 1, 'baz' => 2, 'bar' => 3)); + $b = new Collection(array('foo' => 10, 'bar' => 300)); + $c->overwriteWith($b); + $this->assertEquals(array('foo' => 10, 'baz' => 2, 'bar' => 300), $c->getAll()); + } + + public function testOverwriteWithTraversable() + { + $c = new Collection(array('foo' => 1, 'baz' => 2, 'bar' => 3)); + $b = new Collection(array('foo' => 10, 'bar' => 300)); + $c->overwriteWith($b->getIterator()); + $this->assertEquals(array('foo' => 10, 'baz' => 2, 'bar' => 300), $c->getAll()); + } + + public function testCanSetNestedPathValueThatDoesNotExist() + { + $c = new Collection(array()); + $c->setPath('foo/bar/baz/123', 'hi'); + $this->assertEquals('hi', $c['foo']['bar']['baz']['123']); + } + + public function testCanSetNestedPathValueThatExists() + { + $c = new Collection(array('foo' => array('bar' => 'test'))); + $c->setPath('foo/bar', 'hi'); + $this->assertEquals('hi', $c['foo']['bar']); + } + + /** + * @expectedException \Guzzle\Common\Exception\RuntimeException + */ + public function testVerifiesNestedPathIsValidAtExactLevel() + { + $c = new Collection(array('foo' => 'bar')); + $c->setPath('foo/bar', 'hi'); + $this->assertEquals('hi', $c['foo']['bar']); + } + + /** + * @expectedException \Guzzle\Common\Exception\RuntimeException + */ + public function testVerifiesThatNestedPathIsValidAtAnyLevel() + { + $c = new Collection(array('foo' => 'bar')); + $c->setPath('foo/bar/baz', 'test'); + } +} diff --git a/vendor/guzzle/guzzle/tests/Guzzle/Tests/Common/EventTest.php b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Common/EventTest.php new file mode 100644 index 0000000..5484e14 --- /dev/null +++ b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Common/EventTest.php @@ -0,0 +1,62 @@ + '123', + 'other' => '456', + 'event' => 'test.notify' + )); + } + + public function testAllowsParameterInjection() + { + $event = new Event(array( + 'test' => '123' + )); + $this->assertEquals('123', $event['test']); + } + + public function testImplementsArrayAccess() + { + $event = $this->getEvent(); + $this->assertEquals('123', $event['test']); + $this->assertNull($event['foobar']); + + $this->assertTrue($event->offsetExists('test')); + $this->assertFalse($event->offsetExists('foobar')); + + unset($event['test']); + $this->assertFalse($event->offsetExists('test')); + + $event['test'] = 'new'; + $this->assertEquals('new', $event['test']); + } + + public function testImplementsIteratorAggregate() + { + $event = $this->getEvent(); + $this->assertInstanceOf('ArrayIterator', $event->getIterator()); + } + + public function testConvertsToArray() + { + $this->assertEquals(array( + 'test' => '123', + 'other' => '456', + 'event' => 'test.notify' + ), $this->getEvent()->toArray()); + } +} diff --git a/vendor/guzzle/guzzle/tests/Guzzle/Tests/Common/Exception/BatchTransferExceptionTest.php b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Common/Exception/BatchTransferExceptionTest.php new file mode 100644 index 0000000..c72a2a6 --- /dev/null +++ b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Common/Exception/BatchTransferExceptionTest.php @@ -0,0 +1,21 @@ +getMock('Guzzle\Batch\BatchTransferInterface'); + $d = $this->getMock('Guzzle\Batch\BatchDivisorInterface'); + $transferException = new BatchTransferException(array('foo'), array(1, 2), $e, $t, $d); + $this->assertEquals(array('foo'), $transferException->getBatch()); + $this->assertSame($t, $transferException->getTransferStrategy()); + $this->assertSame($d, $transferException->getDivisorStrategy()); + $this->assertSame($e, $transferException->getPrevious()); + $this->assertEquals(array(1, 2), $transferException->getTransferredItems()); + } +} diff --git a/vendor/guzzle/guzzle/tests/Guzzle/Tests/Common/Exception/ExceptionCollectionTest.php b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Common/Exception/ExceptionCollectionTest.php new file mode 100644 index 0000000..2aecf2a --- /dev/null +++ b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Common/Exception/ExceptionCollectionTest.php @@ -0,0 +1,66 @@ +getExceptions(); + $e->add($exceptions[0]); + $e->add($exceptions[1]); + $this->assertContains("(Exception) ./tests/Guzzle/Tests/Common/Exception/ExceptionCollectionTest.php line ", $e->getMessage()); + $this->assertContains(" Test\n\n #0 ./", $e->getMessage()); + $this->assertSame($exceptions[0], $e->getFirst()); + } + + public function testCanSetExceptions() + { + $ex = new \Exception('foo'); + $e = new ExceptionCollection(); + $e->setExceptions(array($ex)); + $this->assertSame($ex, $e->getFirst()); + } + + public function testActsAsArray() + { + $e = new ExceptionCollection(); + $exceptions = $this->getExceptions(); + $e->add($exceptions[0]); + $e->add($exceptions[1]); + $this->assertEquals(2, count($e)); + $this->assertEquals($exceptions, $e->getIterator()->getArrayCopy()); + } + + public function testCanAddSelf() + { + $e1 = new ExceptionCollection(); + $e1->add(new \Exception("Test")); + $e2 = new ExceptionCollection('Meta description!'); + $e2->add(new \Exception("Test 2")); + $e3 = new ExceptionCollection(); + $e3->add(new \Exception('Baz')); + $e2->add($e3); + $e1->add($e2); + $message = $e1->getMessage(); + $this->assertContains("(Exception) ./tests/Guzzle/Tests/Common/Exception/ExceptionCollectionTest.php line ", $message); + $this->assertContains("\n Test\n\n #0 ", $message); + $this->assertContains("\n\n(Guzzle\\Common\\Exception\\ExceptionCollection) ./tests/Guzzle/Tests/Common/Exception/ExceptionCollectionTest.php line ", $message); + $this->assertContains("\n\n Meta description!\n\n", $message); + $this->assertContains(" (Exception) ./tests/Guzzle/Tests/Common/Exception/ExceptionCollectionTest.php line ", $message); + $this->assertContains("\n Test 2\n\n #0 ", $message); + $this->assertContains(" (Exception) ./tests/Guzzle/Tests/Common/Exception/ExceptionCollectionTest.php line ", $message); + $this->assertContains(" Baz\n\n #0", $message); + } +} diff --git a/vendor/guzzle/guzzle/tests/Guzzle/Tests/Common/VersionTest.php b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Common/VersionTest.php new file mode 100644 index 0000000..c3a81d1 --- /dev/null +++ b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Common/VersionTest.php @@ -0,0 +1,27 @@ +isRunning()) { + self::$server->flush(); + } else { + self::$server->start(); + } + } + + return self::$server; + } + + /** + * Set the service builder to use for tests + * + * @param ServiceBuilderInterface $builder Service builder + */ + public static function setServiceBuilder(ServiceBuilderInterface $builder) + { + self::$serviceBuilder = $builder; + } + + /** + * Get a service builder object that can be used throughout the service tests + * + * @return ServiceBuilder + */ + public static function getServiceBuilder() + { + if (!self::$serviceBuilder) { + throw new RuntimeException('No service builder has been set via setServiceBuilder()'); + } + + return self::$serviceBuilder; + } + + /** + * Check if an event dispatcher has a subscriber + * + * @param HasDispatcherInterface $dispatcher + * @param EventSubscriberInterface $subscriber + * + * @return bool + */ + protected function hasSubscriber(HasDispatcherInterface $dispatcher, EventSubscriberInterface $subscriber) + { + $class = get_class($subscriber); + $all = array_keys(call_user_func(array($class, 'getSubscribedEvents'))); + + foreach ($all as $i => $event) { + foreach ($dispatcher->getEventDispatcher()->getListeners($event) as $e) { + if ($e[0] === $subscriber) { + unset($all[$i]); + break; + } + } + } + + return count($all) == 0; + } + + /** + * Get a wildcard observer for an event dispatcher + * + * @param HasDispatcherInterface $hasDispatcher + * + * @return MockObserver + */ + public function getWildcardObserver(HasDispatcherInterface $hasDispatcher) + { + $class = get_class($hasDispatcher); + $o = new MockObserver(); + $events = call_user_func(array($class, 'getAllEvents')); + foreach ($events as $event) { + $hasDispatcher->getEventDispatcher()->addListener($event, array($o, 'update')); + } + + return $o; + } + + /** + * Set the mock response base path + * + * @param string $path Path to mock response folder + * + * @return GuzzleTestCase + */ + public static function setMockBasePath($path) + { + self::$mockBasePath = $path; + } + + /** + * Mark a request as being mocked + * + * @param RequestInterface $request + * + * @return self + */ + public function addMockedRequest(RequestInterface $request) + { + $this->requests[] = $request; + + return $this; + } + + /** + * Get all of the mocked requests + * + * @return array + */ + public function getMockedRequests() + { + return $this->requests; + } + + /** + * Get a mock response for a client by mock file name + * + * @param string $path Relative path to the mock response file + * + * @return Response + */ + public function getMockResponse($path) + { + return $path instanceof Response + ? $path + : MockPlugin::getMockFile(self::$mockBasePath . DIRECTORY_SEPARATOR . $path); + } + + /** + * Set a mock response from a mock file on the next client request. + * + * This method assumes that mock response files are located under the + * Command/Mock/ directory of the Service being tested + * (e.g. Unfuddle/Command/Mock/). A mock response is added to the next + * request sent by the client. + * + * @param Client $client Client object to modify + * @param string $paths Path to files within the Mock folder of the service + * + * @return MockPlugin returns the created mock plugin + */ + public function setMockResponse(Client $client, $paths) + { + $this->requests = array(); + $that = $this; + $mock = new MockPlugin(null, true); + $client->getEventDispatcher()->removeSubscriber($mock); + $mock->getEventDispatcher()->addListener('mock.request', function(Event $event) use ($that) { + $that->addMockedRequest($event['request']); + }); + + if ($paths instanceof Response) { + // A single response instance has been specified, create an array with that instance + // as the only element for the following loop to work as expected + $paths = array($paths); + } + + foreach ((array) $paths as $path) { + $mock->addResponse($this->getMockResponse($path)); + } + + $client->getEventDispatcher()->addSubscriber($mock); + + return $mock; + } + + /** + * Compare HTTP headers and use special markup to filter values + * A header prefixed with '!' means it must not exist + * A header prefixed with '_' means it must be ignored + * A header value of '*' means anything after the * will be ignored + * + * @param array $filteredHeaders Array of special headers + * @param array $actualHeaders Array of headers to check against + * + * @return array|bool Returns an array of the differences or FALSE if none + */ + public function compareHeaders($filteredHeaders, $actualHeaders) + { + $comparison = new HeaderComparison(); + + return $comparison->compare($filteredHeaders, $actualHeaders); + } + + /** + * Case insensitive assertContains + * + * @param string $needle Search string + * @param string $haystack Search this + * @param string $message Optional failure message + */ + public function assertContainsIns($needle, $haystack, $message = null) + { + $this->assertContains(strtolower($needle), strtolower($haystack), $message); + } +} diff --git a/vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/AbstractEntityBodyDecoratorTest.php b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/AbstractEntityBodyDecoratorTest.php new file mode 100644 index 0000000..20feaa8 --- /dev/null +++ b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/AbstractEntityBodyDecoratorTest.php @@ -0,0 +1,34 @@ +getMockForAbstractClass('Guzzle\Http\AbstractEntityBodyDecorator', array($e)); + + $this->assertSame($e->getStream(), $mock->getStream()); + $this->assertSame($e->getContentLength(), $mock->getContentLength()); + $this->assertSame($e->getSize(), $mock->getSize()); + $this->assertSame($e->getContentMd5(), $mock->getContentMd5()); + $this->assertSame($e->getContentType(), $mock->getContentType()); + $this->assertSame($e->__toString(), $mock->__toString()); + $this->assertSame($e->getUri(), $mock->getUri()); + $this->assertSame($e->getStreamType(), $mock->getStreamType()); + $this->assertSame($e->getWrapper(), $mock->getWrapper()); + $this->assertSame($e->getWrapperData(), $mock->getWrapperData()); + $this->assertSame($e->isReadable(), $mock->isReadable()); + $this->assertSame($e->isWritable(), $mock->isWritable()); + $this->assertSame($e->isConsumed(), $mock->isConsumed()); + $this->assertSame($e->isLocal(), $mock->isLocal()); + $this->assertSame($e->isSeekable(), $mock->isSeekable()); + $this->assertSame($e->getContentEncoding(), $mock->getContentEncoding()); + } +} diff --git a/vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/CachingEntityBodyTest.php b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/CachingEntityBodyTest.php new file mode 100644 index 0000000..e6e6cdb --- /dev/null +++ b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/CachingEntityBodyTest.php @@ -0,0 +1,249 @@ +decorated = EntityBody::factory('testing'); + $this->body = new CachingEntityBody($this->decorated); + } + + public function testUsesRemoteSizeIfPossible() + { + $body = EntityBody::factory('test'); + $caching = new CachingEntityBody($body); + $this->assertEquals(4, $caching->getSize()); + $this->assertEquals(4, $caching->getContentLength()); + } + + /** + * @expectedException \Guzzle\Common\Exception\RuntimeException + * @expectedExceptionMessage does not support custom stream rewind + */ + public function testDoesNotAllowRewindFunction() + { + $this->body->setRewindFunction(true); + } + + /** + * @expectedException \Guzzle\Common\Exception\RuntimeException + * @expectedExceptionMessage Cannot seek to byte 10 + */ + public function testCannotSeekPastWhatHasBeenRead() + { + $this->body->seek(10); + } + + /** + * @expectedException \Guzzle\Common\Exception\RuntimeException + * @expectedExceptionMessage supports only SEEK_SET and SEEK_CUR + */ + public function testCannotUseSeekEnd() + { + $this->body->seek(2, SEEK_END); + } + + public function testChangingUnderlyingStreamUpdatesSizeAndStream() + { + $size = filesize(__FILE__); + $s = fopen(__FILE__, 'r'); + $this->body->setStream($s, $size); + $this->assertEquals($size, $this->body->getSize()); + $this->assertEquals($size, $this->decorated->getSize()); + $this->assertSame($s, $this->body->getStream()); + $this->assertSame($s, $this->decorated->getStream()); + } + + public function testRewindUsesSeek() + { + $a = EntityBody::factory('foo'); + $d = $this->getMockBuilder('Guzzle\Http\CachingEntityBody') + ->setMethods(array('seek')) + ->setConstructorArgs(array($a)) + ->getMock(); + $d->expects($this->once()) + ->method('seek') + ->with(0) + ->will($this->returnValue(true)); + $d->rewind(); + } + + public function testCanSeekToReadBytes() + { + $this->assertEquals('te', $this->body->read(2)); + $this->body->seek(0); + $this->assertEquals('test', $this->body->read(4)); + $this->assertEquals(4, $this->body->ftell()); + $this->body->seek(2); + $this->assertEquals(2, $this->body->ftell()); + $this->body->seek(2, SEEK_CUR); + $this->assertEquals(4, $this->body->ftell()); + $this->assertEquals('ing', $this->body->read(3)); + } + + public function testWritesToBufferStream() + { + $this->body->read(2); + $this->body->write('hi'); + $this->body->rewind(); + $this->assertEquals('tehiing', (string) $this->body); + } + + public function testReadLinesFromBothStreams() + { + $this->body->seek($this->body->ftell()); + $this->body->write("test\n123\nhello\n1234567890\n"); + $this->body->rewind(); + $this->assertEquals("test\n", $this->body->readLine(7)); + $this->assertEquals("123\n", $this->body->readLine(7)); + $this->assertEquals("hello\n", $this->body->readLine(7)); + $this->assertEquals("123456", $this->body->readLine(7)); + $this->assertEquals("7890\n", $this->body->readLine(7)); + // We overwrote the decorated stream, so no more data + $this->assertEquals('', $this->body->readLine(7)); + } + + public function testSkipsOverwrittenBytes() + { + $decorated = EntityBody::factory( + implode("\n", array_map(function ($n) { + return str_pad($n, 4, '0', STR_PAD_LEFT); + }, range(0, 25))) + ); + + $body = new CachingEntityBody($decorated); + + $this->assertEquals("0000\n", $body->readLine()); + $this->assertEquals("0001\n", $body->readLine()); + // Write over part of the body yet to be read, so skip some bytes + $this->assertEquals(5, $body->write("TEST\n")); + $this->assertEquals(5, $this->readAttribute($body, 'skipReadBytes')); + // Read, which skips bytes, then reads + $this->assertEquals("0003\n", $body->readLine()); + $this->assertEquals(0, $this->readAttribute($body, 'skipReadBytes')); + $this->assertEquals("0004\n", $body->readLine()); + $this->assertEquals("0005\n", $body->readLine()); + + // Overwrite part of the cached body (so don't skip any bytes) + $body->seek(5); + $this->assertEquals(5, $body->write("ABCD\n")); + $this->assertEquals(0, $this->readAttribute($body, 'skipReadBytes')); + $this->assertEquals("TEST\n", $body->readLine()); + $this->assertEquals("0003\n", $body->readLine()); + $this->assertEquals("0004\n", $body->readLine()); + $this->assertEquals("0005\n", $body->readLine()); + $this->assertEquals("0006\n", $body->readLine()); + $this->assertEquals(5, $body->write("1234\n")); + $this->assertEquals(5, $this->readAttribute($body, 'skipReadBytes')); + + // Seek to 0 and ensure the overwritten bit is replaced + $body->rewind(); + $this->assertEquals("0000\nABCD\nTEST\n0003\n0004\n0005\n0006\n1234\n0008\n0009\n", $body->read(50)); + + // Ensure that casting it to a string does not include the bit that was overwritten + $this->assertContains("0000\nABCD\nTEST\n0003\n0004\n0005\n0006\n1234\n0008\n0009\n", (string) $body); + } + + public function testWrapsContentType() + { + $a = $this->getMockBuilder('Guzzle\Http\EntityBody') + ->setMethods(array('getContentType')) + ->setConstructorArgs(array(fopen(__FILE__, 'r'))) + ->getMock(); + $a->expects($this->once()) + ->method('getContentType') + ->will($this->returnValue('foo')); + $d = new CachingEntityBody($a); + $this->assertEquals('foo', $d->getContentType()); + } + + public function testWrapsContentEncoding() + { + $a = $this->getMockBuilder('Guzzle\Http\EntityBody') + ->setMethods(array('getContentEncoding')) + ->setConstructorArgs(array(fopen(__FILE__, 'r'))) + ->getMock(); + $a->expects($this->once()) + ->method('getContentEncoding') + ->will($this->returnValue('foo')); + $d = new CachingEntityBody($a); + $this->assertEquals('foo', $d->getContentEncoding()); + } + + public function testWrapsMetadata() + { + $a = $this->getMockBuilder('Guzzle\Http\EntityBody') + ->setMethods(array('getMetadata', 'getWrapper', 'getWrapperData', 'getStreamType', 'getUri')) + ->setConstructorArgs(array(fopen(__FILE__, 'r'))) + ->getMock(); + + $a->expects($this->once()) + ->method('getMetadata') + ->will($this->returnValue(array())); + // Called twice for getWrapper and getWrapperData + $a->expects($this->exactly(1)) + ->method('getWrapper') + ->will($this->returnValue('wrapper')); + $a->expects($this->once()) + ->method('getWrapperData') + ->will($this->returnValue(array())); + $a->expects($this->once()) + ->method('getStreamType') + ->will($this->returnValue('baz')); + $a->expects($this->once()) + ->method('getUri') + ->will($this->returnValue('path/to/foo')); + + $d = new CachingEntityBody($a); + $this->assertEquals(array(), $d->getMetaData()); + $this->assertEquals('wrapper', $d->getWrapper()); + $this->assertEquals(array(), $d->getWrapperData()); + $this->assertEquals('baz', $d->getStreamType()); + $this->assertEquals('path/to/foo', $d->getUri()); + } + + public function testWrapsCustomData() + { + $a = $this->getMockBuilder('Guzzle\Http\EntityBody') + ->setMethods(array('getCustomData', 'setCustomData')) + ->setConstructorArgs(array(fopen(__FILE__, 'r'))) + ->getMock(); + + $a->expects($this->exactly(1)) + ->method('getCustomData') + ->with('foo') + ->will($this->returnValue('bar')); + + $a->expects($this->exactly(1)) + ->method('setCustomData') + ->with('foo', 'bar') + ->will($this->returnSelf()); + + $d = new CachingEntityBody($a); + $this->assertSame($d, $d->setCustomData('foo', 'bar')); + $this->assertEquals('bar', $d->getCustomData('foo')); + } + + public function testClosesBothStreams() + { + $s = fopen('php://temp', 'r'); + $a = EntityBody::factory($s); + $d = new CachingEntityBody($a); + $d->close(); + $this->assertFalse(is_resource($s)); + } +} diff --git a/vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/ClientTest.php b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/ClientTest.php new file mode 100644 index 0000000..4a91a18 --- /dev/null +++ b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/ClientTest.php @@ -0,0 +1,601 @@ +assertEquals('http://www.google.com/', $client->getBaseUrl()); + $this->assertSame($client, $client->setConfig(array( + 'test' => '123' + ))); + $this->assertEquals(array('test' => '123'), $client->getConfig()->getAll()); + $this->assertEquals('123', $client->getConfig('test')); + $this->assertSame($client, $client->setBaseUrl('http://www.test.com/{test}')); + $this->assertEquals('http://www.test.com/123', $client->getBaseUrl()); + $this->assertEquals('http://www.test.com/{test}', $client->getBaseUrl(false)); + + try { + $client->setConfig(false); + } catch (\InvalidArgumentException $e) { + } + } + + public function testDescribesEvents() + { + $this->assertEquals(array('client.create_request'), Client::getAllEvents()); + } + + public function testConstructorCanAcceptConfig() + { + $client = new Client('http://www.test.com/', array( + 'data' => '123' + )); + $this->assertEquals('123', $client->getConfig('data')); + } + + public function testCanUseCollectionAsConfig() + { + $client = new Client('http://www.google.com/'); + $client->setConfig(new Collection(array( + 'api' => 'v1', + 'key' => 'value', + 'base_url' => 'http://www.google.com/' + ))); + $this->assertEquals('v1', $client->getConfig('api')); + } + + public function testExpandsUriTemplatesUsingConfig() + { + $client = new Client('http://www.google.com/'); + $client->setConfig(array('api' => 'v1', 'key' => 'value', 'foo' => 'bar')); + $ref = new \ReflectionMethod($client, 'expandTemplate'); + $ref->setAccessible(true); + $this->assertEquals('Testing...api/v1/key/value', $ref->invoke($client, 'Testing...api/{api}/key/{key}')); + } + + public function testClientAttachersObserversToRequests() + { + $this->getServer()->flush(); + $this->getServer()->enqueue("HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n"); + + $client = new Client($this->getServer()->getUrl()); + $logPlugin = $this->getLogPlugin(); + $client->getEventDispatcher()->addSubscriber($logPlugin); + + // Get a request from the client and ensure the the observer was + // attached to the new request + $request = $client->createRequest(); + $this->assertTrue($this->hasSubscriber($request, $logPlugin)); + } + + public function testClientReturnsValidBaseUrls() + { + $client = new Client('http://www.{foo}.{data}/', array( + 'data' => '123', + 'foo' => 'bar' + )); + $this->assertEquals('http://www.bar.123/', $client->getBaseUrl()); + $client->setBaseUrl('http://www.google.com/'); + $this->assertEquals('http://www.google.com/', $client->getBaseUrl()); + } + + public function testClientAddsCurlOptionsToRequests() + { + $client = new Client('http://www.test.com/', array( + 'api' => 'v1', + // Adds the option using the curl values + 'curl.options' => array( + 'CURLOPT_HTTPAUTH' => 'CURLAUTH_DIGEST', + 'abc' => 'foo', + 'blacklist' => 'abc', + 'debug' => true + ) + )); + + $request = $client->createRequest(); + $options = $request->getCurlOptions(); + $this->assertEquals(CURLAUTH_DIGEST, $options->get(CURLOPT_HTTPAUTH)); + $this->assertEquals('foo', $options->get('abc')); + $this->assertEquals('abc', $options->get('blacklist')); + } + + public function testClientAllowsFineGrainedSslControlButIsSecureByDefault() + { + $client = new Client('https://www.secure.com/'); + + // secure by default + $request = $client->createRequest(); + $options = $request->getCurlOptions(); + $this->assertTrue($options->get(CURLOPT_SSL_VERIFYPEER)); + + // set a capath if you prefer + $client = new Client('https://www.secure.com/'); + $client->setSslVerification(__DIR__); + $request = $client->createRequest(); + $options = $request->getCurlOptions(); + $this->assertSame(__DIR__, $options->get(CURLOPT_CAPATH)); + } + + public function testConfigSettingsControlSslConfiguration() + { + // Use the default ca certs on the system + $client = new Client('https://www.secure.com/', array('ssl.certificate_authority' => 'system')); + $this->assertNull($client->getConfig('curl.options')); + // Can set the cacert value as well + $client = new Client('https://www.secure.com/', array('ssl.certificate_authority' => false)); + $options = $client->getConfig('curl.options'); + $this->assertArrayNotHasKey(CURLOPT_CAINFO, $options); + $this->assertSame(false, $options[CURLOPT_SSL_VERIFYPEER]); + $this->assertSame(0, $options[CURLOPT_SSL_VERIFYHOST]); + } + + public function testClientAllowsUnsafeOperationIfRequested() + { + // be really unsafe if you insist + $client = new Client('https://www.secure.com/', array( + 'api' => 'v1' + )); + + $client->setSslVerification(false); + $request = $client->createRequest(); + $options = $request->getCurlOptions(); + $this->assertFalse($options->get(CURLOPT_SSL_VERIFYPEER)); + $this->assertNull($options->get(CURLOPT_CAINFO)); + } + + /** + * @expectedException \Guzzle\Common\Exception\RuntimeException + */ + public function testThrowsExceptionForInvalidCertificate() + { + $client = new Client('https://www.secure.com/'); + $client->setSslVerification('/path/to/missing/file'); + } + + public function testClientAllowsSettingSpecificSslCaInfo() + { + // set a file other than the provided cacert.pem + $client = new Client('https://www.secure.com/', array( + 'api' => 'v1' + )); + + $client->setSslVerification(__FILE__); + $request = $client->createRequest(); + $options = $request->getCurlOptions(); + $this->assertSame(__FILE__, $options->get(CURLOPT_CAINFO)); + } + + /** + * @expectedException Guzzle\Common\Exception\InvalidArgumentException + */ + public function testClientPreventsInadvertentInsecureVerifyHostSetting() + { + // set a file other than the provided cacert.pem + $client = new Client('https://www.secure.com/', array( + 'api' => 'v1' + )); + $client->setSslVerification(__FILE__, true, true); + } + + /** + * @expectedException Guzzle\Common\Exception\InvalidArgumentException + */ + public function testClientPreventsInvalidVerifyPeerSetting() + { + // set a file other than the provided cacert.pem + $client = new Client('https://www.secure.com/', array( + 'api' => 'v1' + )); + $client->setSslVerification(__FILE__, 'yes'); + } + + public function testClientAddsParamsToRequests() + { + Version::$emitWarnings = false; + $client = new Client('http://www.example.com', array( + 'api' => 'v1', + 'request.params' => array( + 'foo' => 'bar', + 'baz' => 'jar' + ) + )); + $request = $client->createRequest(); + $this->assertEquals('bar', $request->getParams()->get('foo')); + $this->assertEquals('jar', $request->getParams()->get('baz')); + Version::$emitWarnings = true; + } + + public function urlProvider() + { + $u = $this->getServer()->getUrl() . 'base/'; + $u2 = $this->getServer()->getUrl() . 'base?z=1'; + return array( + array($u, '', $u), + array($u, 'relative/path/to/resource', $u . 'relative/path/to/resource'), + array($u, 'relative/path/to/resource?a=b&c=d', $u . 'relative/path/to/resource?a=b&c=d'), + array($u, '/absolute/path/to/resource', $this->getServer()->getUrl() . 'absolute/path/to/resource'), + array($u, '/absolute/path/to/resource?a=b&c=d', $this->getServer()->getUrl() . 'absolute/path/to/resource?a=b&c=d'), + array($u2, '/absolute/path/to/resource?a=b&c=d', $this->getServer()->getUrl() . 'absolute/path/to/resource?a=b&c=d&z=1'), + array($u2, 'relative/path/to/resource', $this->getServer()->getUrl() . 'base/relative/path/to/resource?z=1'), + array($u2, 'relative/path/to/resource?another=query', $this->getServer()->getUrl() . 'base/relative/path/to/resource?another=query&z=1') + ); + } + + /** + * @dataProvider urlProvider + */ + public function testBuildsRelativeUrls($baseUrl, $url, $result) + { + $client = new Client($baseUrl); + $this->assertEquals($result, $client->get($url)->getUrl()); + } + + public function testAllowsConfigsToBeChangedAndInjectedInBaseUrl() + { + $client = new Client('http://{a}/{b}'); + $this->assertEquals('http:///', $client->getBaseUrl()); + $this->assertEquals('http://{a}/{b}', $client->getBaseUrl(false)); + $client->setConfig(array( + 'a' => 'test.com', + 'b' => 'index.html' + )); + $this->assertEquals('http://test.com/index.html', $client->getBaseUrl()); + } + + public function testCreatesRequestsWithDefaultValues() + { + $client = new Client($this->getServer()->getUrl() . 'base'); + + // Create a GET request + $request = $client->createRequest(); + $this->assertEquals('GET', $request->getMethod()); + $this->assertEquals($client->getBaseUrl(), $request->getUrl()); + + // Create a DELETE request + $request = $client->createRequest('DELETE'); + $this->assertEquals('DELETE', $request->getMethod()); + $this->assertEquals($client->getBaseUrl(), $request->getUrl()); + + // Create a HEAD request with custom headers + $request = $client->createRequest('HEAD', 'http://www.test.com/'); + $this->assertEquals('HEAD', $request->getMethod()); + $this->assertEquals('http://www.test.com/', $request->getUrl()); + + // Create a PUT request + $request = $client->createRequest('PUT'); + $this->assertEquals('PUT', $request->getMethod()); + + // Create a PUT request with injected config + $client->getConfig()->set('a', 1)->set('b', 2); + $request = $client->createRequest('PUT', '/path/{a}?q={b}'); + $this->assertEquals($request->getUrl(), $this->getServer()->getUrl() . 'path/1?q=2'); + } + + public function testClientHasHelperMethodsForCreatingRequests() + { + $url = $this->getServer()->getUrl(); + $client = new Client($url . 'base'); + $this->assertEquals('GET', $client->get()->getMethod()); + $this->assertEquals('PUT', $client->put()->getMethod()); + $this->assertEquals('POST', $client->post()->getMethod()); + $this->assertEquals('HEAD', $client->head()->getMethod()); + $this->assertEquals('DELETE', $client->delete()->getMethod()); + $this->assertEquals('OPTIONS', $client->options()->getMethod()); + $this->assertEquals('PATCH', $client->patch()->getMethod()); + $this->assertEquals($url . 'base/abc', $client->get('abc')->getUrl()); + $this->assertEquals($url . 'zxy', $client->put('/zxy')->getUrl()); + $this->assertEquals($url . 'zxy?a=b', $client->post('/zxy?a=b')->getUrl()); + $this->assertEquals($url . 'base?a=b', $client->head('?a=b')->getUrl()); + $this->assertEquals($url . 'base?a=b', $client->delete('/base?a=b')->getUrl()); + } + + public function testClientInjectsConfigsIntoUrls() + { + $client = new Client('http://www.test.com/api/v1', array( + 'test' => '123' + )); + $request = $client->get('relative/{test}'); + $this->assertEquals('http://www.test.com/api/v1/relative/123', $request->getUrl()); + } + + public function testAllowsEmptyBaseUrl() + { + $client = new Client(); + $request = $client->get('http://www.google.com/'); + $this->assertEquals('http://www.google.com/', $request->getUrl()); + $request->setResponse(new Response(200), true); + $request->send(); + } + + public function testAllowsCustomCurlMultiObjects() + { + $mock = $this->getMock('Guzzle\\Http\\Curl\\CurlMulti', array('add', 'send')); + $mock->expects($this->once()) + ->method('add') + ->will($this->returnSelf()); + $mock->expects($this->once()) + ->method('send') + ->will($this->returnSelf()); + + $client = new Client(); + $client->setCurlMulti($mock); + + $request = $client->get(); + $request->setResponse(new Response(200), true); + $client->send($request); + } + + public function testClientSendsMultipleRequests() + { + $client = new Client($this->getServer()->getUrl()); + $mock = new MockPlugin(); + + $responses = array( + new Response(200), + new Response(201), + new Response(202) + ); + + $mock->addResponse($responses[0]); + $mock->addResponse($responses[1]); + $mock->addResponse($responses[2]); + + $client->getEventDispatcher()->addSubscriber($mock); + + $requests = array( + $client->get(), + $client->head(), + $client->put('/', null, 'test') + ); + + $this->assertEquals(array( + $responses[0], + $responses[1], + $responses[2] + ), $client->send($requests)); + } + + public function testClientSendsSingleRequest() + { + $client = new Client($this->getServer()->getUrl()); + $mock = new MockPlugin(); + $response = new Response(200); + $mock->addResponse($response); + $client->getEventDispatcher()->addSubscriber($mock); + $this->assertEquals($response, $client->send($client->get())); + } + + /** + * @expectedException \Guzzle\Http\Exception\BadResponseException + */ + public function testClientThrowsExceptionForSingleRequest() + { + $client = new Client($this->getServer()->getUrl()); + $mock = new MockPlugin(); + $response = new Response(404); + $mock->addResponse($response); + $client->getEventDispatcher()->addSubscriber($mock); + $client->send($client->get()); + } + + /** + * @expectedException \Guzzle\Common\Exception\ExceptionCollection + */ + public function testClientThrowsExceptionForMultipleRequests() + { + $client = new Client($this->getServer()->getUrl()); + $mock = new MockPlugin(); + $mock->addResponse(new Response(200)); + $mock->addResponse(new Response(404)); + $client->getEventDispatcher()->addSubscriber($mock); + $client->send(array($client->get(), $client->head())); + } + + public function testQueryStringsAreNotDoubleEncoded() + { + $client = new Client('http://test.com', array( + 'path' => array('foo', 'bar'), + 'query' => 'hi there', + 'data' => array( + 'test' => 'a&b' + ) + )); + + $request = $client->get('{/path*}{?query,data*}'); + $this->assertEquals('http://test.com/foo/bar?query=hi%20there&test=a%26b', $request->getUrl()); + $this->assertEquals('hi there', $request->getQuery()->get('query')); + $this->assertEquals('a&b', $request->getQuery()->get('test')); + } + + public function testQueryStringsAreNotDoubleEncodedUsingAbsolutePaths() + { + $client = new Client('http://test.com', array( + 'path' => array('foo', 'bar'), + 'query' => 'hi there', + )); + $request = $client->get('http://test.com{?query}'); + $this->assertEquals('http://test.com?query=hi%20there', $request->getUrl()); + $this->assertEquals('hi there', $request->getQuery()->get('query')); + } + + public function testAllowsUriTemplateInjection() + { + $client = new Client('http://test.com'); + $ref = new \ReflectionMethod($client, 'getUriTemplate'); + $ref->setAccessible(true); + $a = $ref->invoke($client); + $this->assertSame($a, $ref->invoke($client)); + $client->setUriTemplate(new UriTemplate()); + $this->assertNotSame($a, $ref->invoke($client)); + } + + public function testAllowsCustomVariablesWhenExpandingTemplates() + { + $client = new Client('http://test.com', array('test' => 'hi')); + $ref = new \ReflectionMethod($client, 'expandTemplate'); + $ref->setAccessible(true); + $uri = $ref->invoke($client, 'http://{test}{?query*}', array('query' => array('han' => 'solo'))); + $this->assertEquals('http://hi?han=solo', $uri); + } + + public function testUriArrayAllowsCustomTemplateVariables() + { + $client = new Client(); + $vars = array( + 'var' => 'hi' + ); + $this->assertEquals('/hi', (string) $client->createRequest('GET', array('/{var}', $vars))->getUrl()); + $this->assertEquals('/hi', (string) $client->get(array('/{var}', $vars))->getUrl()); + $this->assertEquals('/hi', (string) $client->put(array('/{var}', $vars))->getUrl()); + $this->assertEquals('/hi', (string) $client->post(array('/{var}', $vars))->getUrl()); + $this->assertEquals('/hi', (string) $client->head(array('/{var}', $vars))->getUrl()); + $this->assertEquals('/hi', (string) $client->options(array('/{var}', $vars))->getUrl()); + } + + public function testAllowsDefaultHeaders() + { + Version::$emitWarnings = false; + $default = array('X-Test' => 'Hi!'); + $other = array('X-Other' => 'Foo'); + + $client = new Client(); + $client->setDefaultHeaders($default); + $this->assertEquals($default, $client->getDefaultHeaders()->getAll()); + $client->setDefaultHeaders(new Collection($default)); + $this->assertEquals($default, $client->getDefaultHeaders()->getAll()); + + $request = $client->createRequest('GET', null, $other); + $this->assertEquals('Hi!', $request->getHeader('X-Test')); + $this->assertEquals('Foo', $request->getHeader('X-Other')); + + $request = $client->createRequest('GET', null, new Collection($other)); + $this->assertEquals('Hi!', $request->getHeader('X-Test')); + $this->assertEquals('Foo', $request->getHeader('X-Other')); + + $request = $client->createRequest('GET'); + $this->assertEquals('Hi!', $request->getHeader('X-Test')); + Version::$emitWarnings = true; + } + + public function testDontReuseCurlMulti() + { + $client1 = new Client(); + $client2 = new Client(); + $this->assertNotSame($client1->getCurlMulti(), $client2->getCurlMulti()); + } + + public function testGetDefaultUserAgent() + { + $client = new Client(); + $agent = $this->readAttribute($client, 'userAgent'); + $version = curl_version(); + $testAgent = sprintf('Guzzle/%s curl/%s PHP/%s', Version::VERSION, $version['version'], PHP_VERSION); + $this->assertEquals($agent, $testAgent); + + $client->setUserAgent('foo'); + $this->assertEquals('foo', $this->readAttribute($client, 'userAgent')); + } + + public function testOverwritesUserAgent() + { + $client = new Client(); + $request = $client->createRequest('GET', 'http://www.foo.com', array('User-agent' => 'foo')); + $this->assertEquals('foo', (string) $request->getHeader('User-Agent')); + } + + public function testUsesDefaultUserAgent() + { + $client = new Client(); + $request = $client->createRequest('GET', 'http://www.foo.com'); + $this->assertContains('Guzzle/', (string) $request->getHeader('User-Agent')); + } + + public function testCanSetDefaultRequestOptions() + { + $client = new Client(); + $client->getConfig()->set('request.options', array( + 'query' => array('test' => '123', 'other' => 'abc'), + 'headers' => array('Foo' => 'Bar', 'Baz' => 'Bam') + )); + $request = $client->createRequest('GET', 'http://www.foo.com?test=hello', array('Foo' => 'Test')); + // Explicit options on a request should overrule default options + $this->assertEquals('Test', (string) $request->getHeader('Foo')); + $this->assertEquals('hello', $request->getQuery()->get('test')); + // Default options should still be set + $this->assertEquals('abc', $request->getQuery()->get('other')); + $this->assertEquals('Bam', (string) $request->getHeader('Baz')); + } + + public function testCanSetSetOptionsOnRequests() + { + $client = new Client(); + $request = $client->createRequest('GET', 'http://www.foo.com?test=hello', array('Foo' => 'Test'), null, array( + 'cookies' => array('michael' => 'test') + )); + $this->assertEquals('test', $request->getCookie('michael')); + } + + public function testHasDefaultOptionsHelperMethods() + { + $client = new Client(); + // With path + $client->setDefaultOption('headers/foo', 'bar'); + $this->assertEquals('bar', $client->getDefaultOption('headers/foo')); + // With simple key + $client->setDefaultOption('allow_redirects', false); + $this->assertFalse($client->getDefaultOption('allow_redirects')); + + $this->assertEquals(array( + 'headers' => array('foo' => 'bar'), + 'allow_redirects' => false + ), $client->getConfig('request.options')); + + $request = $client->get('/'); + $this->assertEquals('bar', $request->getHeader('foo')); + } + + public function testHeadCanUseOptions() + { + $client = new Client(); + $head = $client->head('http://www.foo.com', array(), array('query' => array('foo' => 'bar'))); + $this->assertEquals('bar', $head->getQuery()->get('foo')); + } + + public function testCanSetRelativeUrlStartingWithHttp() + { + $client = new Client('http://www.foo.com'); + $this->assertEquals( + 'http://www.foo.com/httpfoo', + $client->createRequest('GET', 'httpfoo')->getUrl() + ); + } +} diff --git a/vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/Curl/CurlHandleTest.php b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/Curl/CurlHandleTest.php new file mode 100644 index 0000000..5bf28de --- /dev/null +++ b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/Curl/CurlHandleTest.php @@ -0,0 +1,947 @@ +getEventDispatcher()->addListener('request.sent', function (Event $e) use ($that) { + $that->requestHandle = $e['handle']; + }); + + return $request; + } + + public function setUp() + { + $this->requestHandle = null; + } + + /** + * @expectedException \InvalidArgumentException + */ + public function testConstructorExpectsCurlResource() + { + $h = new CurlHandle(false, array()); + } + + public function testConstructorExpectsProperOptions() + { + $h = curl_init($this->getServer()->getUrl()); + try { + $ha = new CurlHandle($h, false); + $this->fail('Expected InvalidArgumentException'); + } catch (\InvalidArgumentException $e) { + } + + $ha = new CurlHandle($h, array( + CURLOPT_URL => $this->getServer()->getUrl() + )); + $this->assertEquals($this->getServer()->getUrl(), $ha->getOptions()->get(CURLOPT_URL)); + + $ha = new CurlHandle($h, new Collection(array( + CURLOPT_URL => $this->getServer()->getUrl() + ))); + $this->assertEquals($this->getServer()->getUrl(), $ha->getOptions()->get(CURLOPT_URL)); + } + + public function testConstructorInitializesObject() + { + $handle = curl_init($this->getServer()->getUrl()); + $h = new CurlHandle($handle, array( + CURLOPT_URL => $this->getServer()->getUrl() + )); + $this->assertSame($handle, $h->getHandle()); + $this->assertInstanceOf('Guzzle\\Http\\Url', $h->getUrl()); + $this->assertEquals($this->getServer()->getUrl(), (string) $h->getUrl()); + $this->assertEquals($this->getServer()->getUrl(), $h->getOptions()->get(CURLOPT_URL)); + } + + public function testStoresStdErr() + { + $request = RequestFactory::getInstance()->create('GET', 'http://test.com'); + $request->getCurlOptions()->set('debug', true); + $h = CurlHandle::factory($request); + $this->assertEquals($h->getStderr(true), $h->getOptions()->get(CURLOPT_STDERR)); + $this->assertInternalType('resource', $h->getStderr(true)); + $this->assertInternalType('string', $h->getStderr(false)); + $r = $h->getStderr(true); + fwrite($r, 'test'); + $this->assertEquals('test', $h->getStderr(false)); + } + + public function testStoresCurlErrorNumber() + { + $h = new CurlHandle(curl_init('http://test.com'), array(CURLOPT_URL => 'http://test.com')); + $this->assertEquals(CURLE_OK, $h->getErrorNo()); + $h->setErrorNo(CURLE_OPERATION_TIMEOUTED); + $this->assertEquals(CURLE_OPERATION_TIMEOUTED, $h->getErrorNo()); + } + + public function testAccountsForMissingStdErr() + { + $handle = curl_init('http://www.test.com/'); + $h = new CurlHandle($handle, array( + CURLOPT_URL => 'http://www.test.com/' + )); + $this->assertNull($h->getStderr(false)); + } + + public function testDeterminesIfResourceIsAvailable() + { + $handle = curl_init($this->getServer()->getUrl()); + $h = new CurlHandle($handle, array()); + $this->assertTrue($h->isAvailable()); + + // Mess it up by closing the handle + curl_close($handle); + $this->assertFalse($h->isAvailable()); + + // Mess it up by unsetting the handle + $handle = null; + $this->assertFalse($h->isAvailable()); + } + + public function testWrapsErrorsAndInfo() + { + if (!defined('CURLOPT_TIMEOUT_MS')) { + $this->markTestSkipped('Update curl'); + } + + $settings = array( + CURLOPT_PORT => 123, + CURLOPT_CONNECTTIMEOUT_MS => 1, + CURLOPT_TIMEOUT_MS => 1 + ); + + $handle = curl_init($this->getServer()->getUrl()); + curl_setopt_array($handle, $settings); + $h = new CurlHandle($handle, $settings); + @curl_exec($handle); + + $errors = array( + "couldn't connect to host", + 'timeout was reached', + 'connection time-out', + 'connect() timed out!', + 'failed connect to 127.0.0.1:123; connection refused', + 'failed to connect to 127.0.0.1 port 123: connection refused' + ); + $this->assertTrue(in_array(strtolower($h->getError()), $errors), $h->getError() . ' was not the error'); + + $this->assertTrue($h->getErrorNo() > 0); + + $this->assertEquals($this->getServer()->getUrl(), $h->getInfo(CURLINFO_EFFECTIVE_URL)); + $this->assertInternalType('array', $h->getInfo()); + + curl_close($handle); + $this->assertEquals(null, $h->getInfo('url')); + } + + public function testGetInfoWithoutDebugMode() + { + $this->getServer()->enqueue("HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n"); + $client = new Client($this->getServer()->getUrl()); + $request = $client->get($this->getServer()->getUrl()); + $response = $request->send(); + + $info = $response->getInfo(); + $this->assertFalse(empty($info)); + $this->assertEquals($this->getServer()->getUrl(), $info['url']); + } + + public function testWrapsCurlOptions() + { + $handle = curl_init($this->getServer()->getUrl()); + $h = new CurlHandle($handle, array( + CURLOPT_AUTOREFERER => true, + CURLOPT_BUFFERSIZE => 1024 + )); + + $this->assertEquals(true, $h->getOptions()->get(CURLOPT_AUTOREFERER)); + $this->assertEquals(1024, $h->getOptions()->get(CURLOPT_BUFFERSIZE)); + } + + /** + * Data provider for factory tests + * + * @return array + */ + public function dataProvider() + { + $testFile = __DIR__ . '/../../../../../phpunit.xml.dist'; + + $postBody = new QueryString(array('file' => '@' . $testFile)); + $qs = new QueryString(array( + 'x' => 'y', + 'z' => 'a' + )); + + $client = new Client(); + $userAgent = $client->getDefaultUserAgent(); + $auth = base64_encode('michael:123'); + $testFileSize = filesize($testFile); + + $tests = array( + // Send a regular GET + array('GET', 'http://www.google.com/', null, null, array( + CURLOPT_RETURNTRANSFER => 0, + CURLOPT_HEADER => 0, + CURLOPT_CONNECTTIMEOUT => 150, + CURLOPT_WRITEFUNCTION => 'callback', + CURLOPT_HEADERFUNCTION => 'callback', + CURLOPT_HTTPHEADER => array('Accept:', 'Host: www.google.com', 'User-Agent: ' . $userAgent), + )), + // Test that custom request methods can be used + array('TRACE', 'http://www.google.com/', null, null, array( + CURLOPT_CUSTOMREQUEST => 'TRACE' + )), + // Send a GET using a port + array('GET', 'http://127.0.0.1:8080', null, null, array( + CURLOPT_RETURNTRANSFER => 0, + CURLOPT_HEADER => 0, + CURLOPT_CONNECTTIMEOUT => 150, + CURLOPT_WRITEFUNCTION => 'callback', + CURLOPT_HEADERFUNCTION => 'callback', + CURLOPT_PORT => 8080, + CURLOPT_HTTPHEADER => array('Accept:', 'Host: 127.0.0.1:8080', 'User-Agent: ' . $userAgent), + )), + // Send a HEAD request + array('HEAD', 'http://www.google.com/', null, null, array( + CURLOPT_RETURNTRANSFER => 0, + CURLOPT_HEADER => 0, + CURLOPT_CONNECTTIMEOUT => 150, + CURLOPT_HEADERFUNCTION => 'callback', + CURLOPT_HTTPHEADER => array('Accept:', 'Host: www.google.com', 'User-Agent: ' . $userAgent), + CURLOPT_NOBODY => 1 + )), + // Send a GET using basic auth + array('GET', 'https://michael:123@127.0.0.1/index.html?q=2', null, null, array( + CURLOPT_RETURNTRANSFER => 0, + CURLOPT_HEADER => 0, + CURLOPT_CONNECTTIMEOUT => 150, + CURLOPT_WRITEFUNCTION => 'callback', + CURLOPT_HEADERFUNCTION => 'callback', + CURLOPT_HTTPHEADER => array( + 'Accept:', + 'Host: 127.0.0.1', + 'Authorization: Basic ' . $auth, + 'User-Agent: ' . $userAgent + ), + CURLOPT_PORT => 443 + )), + // Send a GET request with custom headers + array('GET', 'http://127.0.0.1:8124/', array( + 'x-test-data' => 'Guzzle' + ), null, array( + CURLOPT_PORT => 8124, + CURLOPT_HTTPHEADER => array( + 'Accept:', + 'Host: 127.0.0.1:8124', + 'x-test-data: Guzzle', + 'User-Agent: ' . $userAgent + ) + ), array( + 'Host' => '*', + 'User-Agent' => '*', + 'x-test-data' => 'Guzzle' + )), + // Send a POST using a query string + array('POST', 'http://127.0.0.1:8124/post.php', null, $qs, array( + CURLOPT_RETURNTRANSFER => 0, + CURLOPT_HEADER => 0, + CURLOPT_CONNECTTIMEOUT => 150, + CURLOPT_WRITEFUNCTION => 'callback', + CURLOPT_HEADERFUNCTION => 'callback', + CURLOPT_POSTFIELDS => 'x=y&z=a', + CURLOPT_HTTPHEADER => array ( + 'Expect:', + 'Accept:', + 'Host: 127.0.0.1:8124', + 'Content-Type: application/x-www-form-urlencoded; charset=utf-8', + 'User-Agent: ' . $userAgent + ) + ), array( + 'Host' => '*', + 'User-Agent' => '*', + 'Content-Length' => '7', + '!Expect' => null, + 'Content-Type' => 'application/x-www-form-urlencoded; charset=utf-8', + '!Transfer-Encoding' => null + )), + // Send a PUT using raw data + array('PUT', 'http://127.0.0.1:8124/put.php', null, EntityBody::factory(fopen($testFile, 'r+')), array( + CURLOPT_RETURNTRANSFER => 0, + CURLOPT_HEADER => 0, + CURLOPT_CONNECTTIMEOUT => 150, + CURLOPT_WRITEFUNCTION => 'callback', + CURLOPT_HEADERFUNCTION => 'callback', + CURLOPT_READFUNCTION => 'callback', + CURLOPT_INFILESIZE => filesize($testFile), + CURLOPT_HTTPHEADER => array ( + 'Expect:', + 'Accept:', + 'Host: 127.0.0.1:8124', + 'User-Agent: ' . $userAgent + ) + ), array( + 'Host' => '*', + 'User-Agent' => '*', + '!Expect' => null, + 'Content-Length' => $testFileSize, + '!Transfer-Encoding' => null + )), + // Send a POST request using an array of fields + array('POST', 'http://127.0.0.1:8124/post.php', null, array( + 'x' => 'y', + 'a' => 'b' + ), array( + CURLOPT_RETURNTRANSFER => 0, + CURLOPT_HEADER => 0, + CURLOPT_CONNECTTIMEOUT => 150, + CURLOPT_WRITEFUNCTION => 'callback', + CURLOPT_HEADERFUNCTION => 'callback', + CURLOPT_POST => 1, + CURLOPT_POSTFIELDS => 'x=y&a=b', + CURLOPT_HTTPHEADER => array ( + 'Expect:', + 'Accept:', + 'Host: 127.0.0.1:8124', + 'Content-Type: application/x-www-form-urlencoded; charset=utf-8', + 'User-Agent: ' . $userAgent + ) + ), array( + 'Host' => '*', + 'User-Agent' => '*', + 'Content-Length' => '7', + '!Expect' => null, + 'Content-Type' => 'application/x-www-form-urlencoded; charset=utf-8', + '!Transfer-Encoding' => null + )), + // Send a POST request with raw POST data and a custom content-type + array('POST', 'http://127.0.0.1:8124/post.php', array( + 'Content-Type' => 'application/json' + ), '{"hi":"there"}', array( + CURLOPT_RETURNTRANSFER => 0, + CURLOPT_HEADER => 0, + CURLOPT_CONNECTTIMEOUT => 150, + CURLOPT_WRITEFUNCTION => 'callback', + CURLOPT_HEADERFUNCTION => 'callback', + CURLOPT_CUSTOMREQUEST => 'POST', + CURLOPT_UPLOAD => true, + CURLOPT_INFILESIZE => 14, + CURLOPT_HTTPHEADER => array ( + 'Expect:', + 'Accept:', + 'Host: 127.0.0.1:8124', + 'Content-Type: application/json', + 'User-Agent: ' . $userAgent + ), + ), array( + 'Host' => '*', + 'User-Agent' => '*', + 'Content-Type' => 'application/json', + '!Expect' => null, + 'Content-Length' => '14', + '!Transfer-Encoding' => null + )), + // Send a POST request with raw POST data, a custom content-type, and use chunked encoding + array('POST', 'http://127.0.0.1:8124/post.php', array( + 'Content-Type' => 'application/json', + 'Transfer-Encoding' => 'chunked' + ), '{"hi":"there"}', array( + CURLOPT_RETURNTRANSFER => 0, + CURLOPT_HEADER => 0, + CURLOPT_CONNECTTIMEOUT => 150, + CURLOPT_WRITEFUNCTION => 'callback', + CURLOPT_HEADERFUNCTION => 'callback', + CURLOPT_CUSTOMREQUEST => 'POST', + CURLOPT_UPLOAD => true, + CURLOPT_HTTPHEADER => array ( + 'Expect:', + 'Accept:', + 'Host: 127.0.0.1:8124', + 'Transfer-Encoding: chunked', + 'Content-Type: application/json', + 'User-Agent: ' . $userAgent + ), + ), array( + 'Host' => '*', + 'User-Agent' => '*', + 'Content-Type' => 'application/json', + '!Expect' => null, + 'Transfer-Encoding' => 'chunked', + '!Content-Length' => '' + )), + // Send a POST request with no body + array('POST', 'http://127.0.0.1:8124/post.php', null, '', array( + CURLOPT_CUSTOMREQUEST => 'POST', + CURLOPT_HTTPHEADER => array ( + 'Expect:', + 'Accept:', + 'Host: 127.0.0.1:8124', + 'User-Agent: ' . $userAgent + ) + ), array( + 'Host' => '*', + 'User-Agent' => '*', + 'Content-Length' => '0', + '!Transfer-Encoding' => null + )), + // Send a POST request with empty post fields + array('POST', 'http://127.0.0.1:8124/post.php', null, array(), array( + CURLOPT_CUSTOMREQUEST => 'POST', + CURLOPT_HTTPHEADER => array ( + 'Expect:', + 'Accept:', + 'Host: 127.0.0.1:8124', + 'User-Agent: ' . $userAgent + ) + ), array( + 'Host' => '*', + 'User-Agent' => '*', + 'Content-Length' => '0', + '!Transfer-Encoding' => null + )), + // Send a PATCH request + array('PATCH', 'http://127.0.0.1:8124/patch.php', null, 'body', array( + CURLOPT_INFILESIZE => 4, + CURLOPT_HTTPHEADER => array ( + 'Expect:', + 'Accept:', + 'Host: 127.0.0.1:8124', + 'User-Agent: ' . $userAgent + ) + )), + // Send a DELETE request with a body + array('DELETE', 'http://127.0.0.1:8124/delete.php', null, 'body', array( + CURLOPT_CUSTOMREQUEST => 'DELETE', + CURLOPT_INFILESIZE => 4, + CURLOPT_HTTPHEADER => array ( + 'Expect:', + 'Accept:', + 'Host: 127.0.0.1:8124', + 'User-Agent: ' . $userAgent + ) + ), array( + 'Host' => '*', + 'User-Agent' => '*', + 'Content-Length' => '4', + '!Expect' => null, + '!Transfer-Encoding' => null + )), + + /** + * Send a request with empty path and a fragment - the fragment must be + * stripped out before sending it to curl + * + * @issue 453 + * @link https://github.com/guzzle/guzzle/issues/453 + */ + array('GET', 'http://www.google.com#head', null, null, array( + CURLOPT_RETURNTRANSFER => 0, + CURLOPT_HEADER => 0, + CURLOPT_CONNECTTIMEOUT => 150, + CURLOPT_WRITEFUNCTION => 'callback', + CURLOPT_HEADERFUNCTION => 'callback', + CURLOPT_HTTPHEADER => array('Accept:', 'Host: www.google.com', 'User-Agent: ' . $userAgent), + )), + ); + + $postTest = array('POST', 'http://127.0.0.1:8124/post.php', null, $postBody, array( + CURLOPT_RETURNTRANSFER => 0, + CURLOPT_HEADER => 0, + CURLOPT_CONNECTTIMEOUT => 150, + CURLOPT_WRITEFUNCTION => 'callback', + CURLOPT_HEADERFUNCTION => 'callback', + CURLOPT_POST => 1, + CURLOPT_POSTFIELDS => array( + 'file' => '@' . $testFile . ';filename=phpunit.xml.dist;type=application/octet-stream' + ), + CURLOPT_HTTPHEADER => array ( + 'Accept:', + 'Host: 127.0.0.1:8124', + 'Content-Type: multipart/form-data', + 'Expect: 100-Continue', + 'User-Agent: ' . $userAgent + ) + ), array( + 'Host' => '*', + 'User-Agent' => '*', + 'Content-Length' => '*', + 'Expect' => '100-Continue', + 'Content-Type' => 'multipart/form-data; boundary=*', + '!Transfer-Encoding' => null + )); + + if (version_compare(phpversion(), '5.5.0', '>=')) { + $postTest[4][CURLOPT_POSTFIELDS] = array( + 'file' => new \CurlFile($testFile, 'application/octet-stream', 'phpunit.xml.dist') + ); + } + + $tests[] = $postTest; + + return $tests; + } + + /** + * @dataProvider dataProvider + */ + public function testFactoryCreatesCurlBasedOnRequest($method, $url, $headers, $body, $options, $expectedHeaders = null) + { + $client = new Client(); + $request = $client->createRequest($method, $url, $headers, $body); + $request->getCurlOptions()->set('debug', true); + + $originalRequest = clone $request; + $curlTest = clone $request; + $handle = CurlHandle::factory($curlTest); + + $this->assertInstanceOf('Guzzle\\Http\\Curl\\CurlHandle', $handle); + $o = $handle->getOptions()->getAll(); + + // Headers are case-insensitive + if (isset($o[CURLOPT_HTTPHEADER])) { + $o[CURLOPT_HTTPHEADER] = array_map('strtolower', $o[CURLOPT_HTTPHEADER]); + } + if (isset($options[CURLOPT_HTTPHEADER])) { + $options[CURLOPT_HTTPHEADER] = array_map('strtolower', $options[CURLOPT_HTTPHEADER]); + } + + $check = 0; + foreach ($options as $key => $value) { + $check++; + $this->assertArrayHasKey($key, $o, '-> Check number ' . $check); + if ($key != CURLOPT_HTTPHEADER && $key != CURLOPT_POSTFIELDS && (is_array($o[$key])) || $o[$key] instanceof \Closure) { + $this->assertEquals('callback', $value, '-> Check number ' . $check); + } else { + $this->assertTrue($value == $o[$key], '-> Check number ' . $check . ' - ' . var_export($value, true) . ' != ' . var_export($o[$key], true)); + } + } + + // If we are testing the actual sent headers + if ($expectedHeaders) { + + // Send the request to the test server + $client = new Client($this->getServer()->getUrl()); + $request->setClient($client); + $this->getServer()->flush(); + $this->getServer()->enqueue("HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n"); + $request->send(); + + // Get the request that was sent and create a request that we expected + $requests = $this->getServer()->getReceivedRequests(true); + $this->assertEquals($method, $requests[0]->getMethod()); + + $test = $this->compareHeaders($expectedHeaders, $requests[0]->getHeaders()); + $this->assertFalse($test, $test . "\nSent: \n" . $request . "\n\n" . $requests[0]); + + // Ensure only one Content-Length header is sent + if ($request->getHeader('Content-Length')) { + $this->assertEquals((string) $request->getHeader('Content-Length'), (string) $requests[0]->getHeader('Content-Length')); + } + } + } + + public function testFactoryUsesSpecifiedProtocol() + { + $request = RequestFactory::getInstance()->create('GET', 'http://127.0.0.1:8124/'); + $request->setProtocolVersion('1.1'); + $handle = CurlHandle::factory($request); + $options = $handle->getOptions(); + $this->assertEquals(CURL_HTTP_VERSION_1_1, $options[CURLOPT_HTTP_VERSION]); + } + + public function testUploadsPutData() + { + $this->getServer()->flush(); + $this->getServer()->enqueue("HTTP/1.1 200 OK\r\nContent-Length: 2\r\n\r\nhi"); + + $client = new Client($this->getServer()->getUrl()); + $request = $client->put('/'); + $request->getCurlOptions()->set('debug', true); + $request->setBody(EntityBody::factory('test'), 'text/plain', false); + $request->getCurlOptions()->set('progress', true); + + $o = $this->getWildcardObserver($request); + $request->send(); + + // Make sure that the events were dispatched + $this->assertTrue($o->has('curl.callback.progress')); + + // Ensure that the request was received exactly as intended + $r = $this->getServer()->getReceivedRequests(true); + $this->assertFalse($r[0]->hasHeader('Transfer-Encoding')); + $this->assertEquals(4, (string) $r[0]->getHeader('Content-Length')); + $sent = strtolower($r[0]); + $this->assertContains('put / http/1.1', $sent); + $this->assertContains('host: 127.0.0.1', $sent); + $this->assertContains('user-agent:', $sent); + $this->assertContains('content-type: text/plain', $sent); + } + + public function testUploadsPutDataUsingChunkedEncodingWhenLengthCannotBeDetermined() + { + $this->getServer()->flush(); + $this->getServer()->enqueue(array( + "HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n", + "HTTP/1.1 200 OK\r\nContent-Length: 2\r\n\r\nhi" + )); + $client = new Client($this->getServer()->getUrl()); + $request = $client->put('/'); + $request->setBody(EntityBody::factory(fopen($this->getServer()->getUrl(), 'r')), 'text/plain'); + $request->send(); + + $r = $this->getServer()->getReceivedRequests(true); + $this->assertEquals('chunked', $r[1]->getHeader('Transfer-Encoding')); + $this->assertFalse($r[1]->hasHeader('Content-Length')); + } + + public function testUploadsPutDataUsingChunkedEncodingWhenForced() + { + $this->getServer()->flush(); + $this->getServer()->enqueue("HTTP/1.1 200 OK\r\nContent-Length: 2\r\n\r\nhi"); + + $client = new Client($this->getServer()->getUrl()); + $request = $client->put('/', array('Transfer-Encoding' => 'chunked'), 'hi!'); + $request->send(); + + $r = $this->getServer()->getReceivedRequests(true); + $this->assertEquals('chunked', $r[0]->getHeader('Transfer-Encoding')); + $this->assertFalse($r[0]->hasHeader('Content-Length')); + $this->assertEquals('hi!', $r[0]->getBody(true)); + } + + public function testSendsPostRequestsWithFields() + { + $this->getServer()->flush(); + $this->getServer()->enqueue("HTTP/1.1 200 OK\r\nContent-Length: 2\r\n\r\nhi"); + + $request = RequestFactory::getInstance()->create('POST', $this->getServer()->getUrl()); + $request->getCurlOptions()->set('debug', true); + $request->setClient(new Client()); + $request->addPostFields(array( + 'a' => 'b', + 'c' => 'ay! ~This is a test, isn\'t it?' + )); + $request->send(); + + // Make sure that the request was sent correctly + $r = $this->getServer()->getReceivedRequests(true); + $this->assertEquals('a=b&c=ay%21%20~This%20is%20a%20test%2C%20isn%27t%20it%3F', (string) $r[0]->getBody()); + $this->assertFalse($r[0]->hasHeader('Transfer-Encoding')); + $this->assertEquals(56, (string) $r[0]->getHeader('Content-Length')); + $sent = strtolower($r[0]); + $this->assertContains('post / http/1.1', $sent); + $this->assertContains('content-type: application/x-www-form-urlencoded; charset=utf-8', $sent); + } + + public function testSendsPostRequestsWithFiles() + { + $this->getServer()->flush(); + $this->getServer()->enqueue("HTTP/1.1 200 OK\r\nContent-Length: 2\r\n\r\nhi"); + + $request = RequestFactory::getInstance()->create('POST', $this->getServer()->getUrl()); + $request->getCurlOptions()->set('debug', true); + $request->setClient(new Client()); + $request->addPostFiles(array( + 'foo' => __FILE__, + )); + $request->addPostFields(array( + 'bar' => 'baz', + 'arr' => array('a' => 1, 'b' => 2), + )); + $this->updateForHandle($request); + $request->send(); + + // Ensure the CURLOPT_POSTFIELDS option was set properly + $options = $this->requestHandle->getOptions()->getAll(); + if (version_compare(phpversion(), '5.5.0', '<')) { + $this->assertContains('@' . __FILE__ . ';filename=CurlHandleTest.php;type=text/x-', $options[CURLOPT_POSTFIELDS]['foo']); + } else{ + $this->assertInstanceOf('CURLFile', $options[CURLOPT_POSTFIELDS]['foo']); + } + $this->assertEquals('baz', $options[CURLOPT_POSTFIELDS]['bar']); + $this->assertEquals('1', $options[CURLOPT_POSTFIELDS]['arr[a]']); + $this->assertEquals('2', $options[CURLOPT_POSTFIELDS]['arr[b]']); + // Ensure that a Content-Length header was sent by cURL + $this->assertTrue($request->hasHeader('Content-Length')); + } + + public function testCurlConfigurationOptionsAreSet() + { + $request = RequestFactory::getInstance()->create('PUT', $this->getServer()->getUrl()); + $request->setClient(new Client('http://www.example.com')); + $request->getCurlOptions()->set(CURLOPT_CONNECTTIMEOUT, 99); + $request->getCurlOptions()->set('curl.fake_opt', 99); + $request->getCurlOptions()->set(CURLOPT_PORT, 8181); + $handle = CurlHandle::factory($request); + $this->assertEquals(99, $handle->getOptions()->get(CURLOPT_CONNECTTIMEOUT)); + $this->assertEquals(8181, $handle->getOptions()->get(CURLOPT_PORT)); + $this->assertNull($handle->getOptions()->get('curl.fake_opt')); + $this->assertNull($handle->getOptions()->get('fake_opt')); + } + + public function testEnsuresRequestsHaveResponsesWhenUpdatingFromTransfer() + { + $request = RequestFactory::getInstance()->create('PUT', $this->getServer()->getUrl()); + $handle = CurlHandle::factory($request); + $handle->updateRequestFromTransfer($request); + } + + public function testCanSendBodyAsString() + { + $this->getServer()->flush(); + $this->getServer()->enqueue("HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n"); + $client = new Client($this->getServer()->getUrl()); + $request = $client->put('/', null, 'foo'); + $request->getCurlOptions()->set('body_as_string', true); + $request->send(); + $requests = $this->getServer()->getReceivedRequests(false); + $this->assertContains('PUT /', $requests[0]); + $this->assertContains("\nfoo", $requests[0]); + $this->assertContains('content-length: 3', $requests[0]); + $this->assertNotContains('content-type', $requests[0]); + } + + public function testCanSendPostBodyAsString() + { + $this->getServer()->flush(); + $this->getServer()->enqueue("HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n"); + $client = new Client($this->getServer()->getUrl()); + $request = $client->post('/', null, 'foo'); + $request->getCurlOptions()->set('body_as_string', true); + $request->send(); + $requests = $this->getServer()->getReceivedRequests(false); + $this->assertContains('POST /', $requests[0]); + $this->assertContains("\nfoo", $requests[0]); + $this->assertContains('content-length: 3', $requests[0]); + $this->assertNotContains('content-type', $requests[0]); + } + + public function testAllowsWireTransferInfoToBeEnabled() + { + $request = RequestFactory::getInstance()->create('PUT', $this->getServer()->getUrl()); + $request->getCurlOptions()->set('debug', true); + $handle = CurlHandle::factory($request); + $this->assertNotNull($handle->getOptions()->get(CURLOPT_STDERR)); + $this->assertNotNull($handle->getOptions()->get(CURLOPT_VERBOSE)); + } + + public function testAddsCustomCurlOptions() + { + $request = RequestFactory::getInstance()->create('PUT', $this->getServer()->getUrl()); + $request->getCurlOptions()->set(CURLOPT_TIMEOUT, 200); + $handle = CurlHandle::factory($request); + $this->assertEquals(200, $handle->getOptions()->get(CURLOPT_TIMEOUT)); + } + + public function testSendsPostUploadsWithContentDispositionHeaders() + { + $this->getServer()->flush(); + $this->getServer()->enqueue("HTTP/1.1 200 OK\r\n\r\nContent-Length: 0\r\n\r\n"); + + $fileToUpload = dirname(dirname(__DIR__)) . DIRECTORY_SEPARATOR . 'TestData' . DIRECTORY_SEPARATOR . 'test_service.json'; + + $client = new Client($this->getServer()->getUrl()); + $request = $client->post(); + $request->addPostFile('foo', $fileToUpload, 'application/json'); + $request->addPostFile('foo', __FILE__); + + $request->send(); + $requests = $this->getServer()->getReceivedRequests(true); + $body = (string) $requests[0]->getBody(); + + $this->assertContains('Content-Disposition: form-data; name="foo[0]"; filename="', $body); + $this->assertContains('Content-Type: application/json', $body); + $this->assertContains('Content-Type: text/x-', $body); + $this->assertContains('Content-Disposition: form-data; name="foo[1]"; filename="', $body); + } + + public function requestMethodProvider() + { + return array(array('POST'), array('PUT'), array('PATCH')); + } + + /** + * @dataProvider requestMethodProvider + */ + public function testSendsRequestsWithNoBodyUsingContentLengthZero($method) + { + $this->getServer()->flush(); + $this->getServer()->enqueue("HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n"); + $client = new Client($this->getServer()->getUrl()); + $client->createRequest($method)->send(); + $requests = $this->getServer()->getReceivedRequests(true); + $this->assertFalse($requests[0]->hasHeader('Transfer-Encoding')); + $this->assertTrue($requests[0]->hasHeader('Content-Length')); + $this->assertEquals('0', (string) $requests[0]->getHeader('Content-Length')); + } + + /** + * @dataProvider provideCurlConfig + */ + public function testParseCurlConfigConvertsStringKeysToConstantKeys($options, $expected) + { + $actual = CurlHandle::parseCurlConfig($options); + $this->assertEquals($expected, $actual); + } + + /** + * Data provider for curl configurations + * + * @return array + */ + public function provideCurlConfig() + { + return array( + // Conversion of option name to constant value + array( + array( + 'CURLOPT_PORT' => 10, + 'CURLOPT_TIMEOUT' => 99 + ), + array( + CURLOPT_PORT => 10, + CURLOPT_TIMEOUT => 99 + ) + ), + // Keeps non constant options + array( + array('debug' => true), + array('debug' => true) + ), + // Conversion of constant names to constant values + array( + array('debug' => 'CURLPROXY_HTTP'), + array('debug' => CURLPROXY_HTTP) + ) + ); + } + + public function testSeeksToBeginningOfStreamWhenSending() + { + $this->getServer()->flush(); + $this->getServer()->enqueue(array( + "HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n", + "HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n" + )); + + $client = new Client($this->getServer()->getUrl()); + $request = $client->put('/', null, 'test'); + $request->send(); + $request->send(); + + $received = $this->getServer()->getReceivedRequests(true); + $this->assertEquals(2, count($received)); + $this->assertEquals('test', (string) $received[0]->getBody()); + $this->assertEquals('test', (string) $received[1]->getBody()); + } + + public function testAllowsCurloptEncodingToBeSet() + { + $this->getServer()->flush(); + $this->getServer()->enqueue("HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n"); + + $client = new Client($this->getServer()->getUrl()); + $request = $client->get('/', null); + $request->getCurlOptions()->set(CURLOPT_ENCODING, ''); + $this->updateForHandle($request); + $request->send(); + $options = $this->requestHandle->getOptions()->getAll(); + $this->assertSame('', $options[CURLOPT_ENCODING]); + $received = $this->getServer()->getReceivedRequests(false); + $this->assertContainsIns('accept: */*', $received[0]); + $this->assertContainsIns('accept-encoding: ', $received[0]); + } + + public function testSendsExpectHeaderWhenSizeIsGreaterThanCutoff() + { + $this->getServer()->flush(); + $this->getServer()->enqueue("HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n"); + $client = new Client($this->getServer()->getUrl()); + $request = $client->put('/', null, 'test'); + // Start sending the expect header to 2 bytes + $this->updateForHandle($request); + $request->setExpectHeaderCutoff(2)->send(); + $options = $this->requestHandle->getOptions()->getAll(); + $this->assertContains('Expect: 100-Continue', $options[CURLOPT_HTTPHEADER]); + $received = $this->getServer()->getReceivedRequests(false); + $this->assertContainsIns('expect: 100-continue', $received[0]); + } + + public function testSetsCurloptEncodingWhenAcceptEncodingHeaderIsSet() + { + $this->getServer()->flush(); + $this->getServer()->enqueue("HTTP/1.1 200 OK\r\nContent-Length: 4\r\n\r\ndata"); + $client = new Client($this->getServer()->getUrl()); + $request = $client->get('/', array( + 'Accept' => 'application/json', + 'Accept-Encoding' => 'gzip, deflate', + )); + $this->updateForHandle($request); + $request->send(); + $options = $this->requestHandle->getOptions()->getAll(); + $this->assertSame('gzip, deflate', $options[CURLOPT_ENCODING]); + $received = $this->getServer()->getReceivedRequests(false); + $this->assertContainsIns('accept: application/json', $received[0]); + $this->assertContainsIns('accept-encoding: gzip, deflate', $received[0]); + } + + public function testSendsPostFieldsForNonPostRequests() + { + $this->getServer()->flush(); + $this->getServer()->enqueue("HTTP/1.1 200 OK\r\n\r\nContent-Length: 0\r\n\r\n"); + + $client = new Client(); + $request = $client->put($this->getServer()->getUrl(), null, array( + 'foo' => 'baz', + 'baz' => 'bar' + )); + + $request->send(); + $requests = $this->getServer()->getReceivedRequests(true); + $this->assertEquals('PUT', $requests[0]->getMethod()); + $this->assertEquals( + 'application/x-www-form-urlencoded; charset=utf-8', + (string) $requests[0]->getHeader('Content-Type') + ); + $this->assertEquals(15, (string) $requests[0]->getHeader('Content-Length')); + $this->assertEquals('foo=baz&baz=bar', (string) $requests[0]->getBody()); + } + + public function testSendsPostFilesForNonPostRequests() + { + $this->getServer()->flush(); + $this->getServer()->enqueue("HTTP/1.1 200 OK\r\n\r\nContent-Length: 0\r\n\r\n"); + + $client = new Client(); + $request = $client->put($this->getServer()->getUrl(), null, array( + 'foo' => '@' . __FILE__ + )); + + $request->send(); + $requests = $this->getServer()->getReceivedRequests(true); + $this->assertEquals('PUT', $requests[0]->getMethod()); + $this->assertContains('multipart/form-data', (string) $requests[0]->getHeader('Content-Type')); + $this->assertContains('testSendsPostFilesForNonPostRequests', (string) $requests[0]->getBody()); + } +} diff --git a/vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/Curl/CurlMultiProxyTest.php b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/Curl/CurlMultiProxyTest.php new file mode 100644 index 0000000..e04141c --- /dev/null +++ b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/Curl/CurlMultiProxyTest.php @@ -0,0 +1,110 @@ +multi = new CurlMultiProxy(self::MAX_HANDLES, self::SELECT_TIMEOUT); + } + + public function tearDown() + { + unset($this->multi); + } + + public function testConstructorSetsMaxHandles() + { + $m = new CurlMultiProxy(self::MAX_HANDLES, self::SELECT_TIMEOUT); + $this->assertEquals(self::MAX_HANDLES, $this->readAttribute($m, 'maxHandles')); + } + + public function testConstructorSetsSelectTimeout() + { + $m = new CurlMultiProxy(self::MAX_HANDLES, self::SELECT_TIMEOUT); + $this->assertEquals(self::SELECT_TIMEOUT, $this->readAttribute($m, 'selectTimeout')); + } + + public function testAddingRequestsAddsToQueue() + { + $r = new Request('GET', 'http://www.foo.com'); + $this->assertSame($this->multi, $this->multi->add($r)); + $this->assertEquals(1, count($this->multi)); + $this->assertEquals(array($r), $this->multi->all()); + + $this->assertTrue($this->multi->remove($r)); + $this->assertFalse($this->multi->remove($r)); + $this->assertEquals(0, count($this->multi)); + } + + public function testResetClearsState() + { + $r = new Request('GET', 'http://www.foo.com'); + $this->multi->add($r); + $this->multi->reset(); + $this->assertEquals(0, count($this->multi)); + } + + public function testSendWillSendQueuedRequestsFirst() + { + $this->getServer()->flush(); + $this->getServer()->enqueue(array( + "HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n", + "HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n" + )); + $client = new Client($this->getServer()->getUrl()); + $events = array(); + $client->getCurlMulti()->getEventDispatcher()->addListener( + CurlMultiProxy::ADD_REQUEST, + function ($e) use (&$events) { + $events[] = $e; + } + ); + $request = $client->get(); + $request->getEventDispatcher()->addListener('request.complete', function () use ($client) { + $client->get('/foo')->send(); + }); + $request->send(); + $received = $this->getServer()->getReceivedRequests(true); + $this->assertEquals(2, count($received)); + $this->assertEquals($this->getServer()->getUrl(), $received[0]->getUrl()); + $this->assertEquals($this->getServer()->getUrl() . 'foo', $received[1]->getUrl()); + $this->assertEquals(2, count($events)); + } + + public function testTrimsDownMaxHandleCount() + { + $this->getServer()->flush(); + $this->getServer()->enqueue(array( + "HTTP/1.1 307 OK\r\nLocation: /foo\r\nContent-Length: 0\r\n\r\n", + "HTTP/1.1 307 OK\r\nLocation: /foo\r\nContent-Length: 0\r\n\r\n", + "HTTP/1.1 307 OK\r\nLocation: /foo\r\nContent-Length: 0\r\n\r\n", + "HTTP/1.1 307 OK\r\nLocation: /foo\r\nContent-Length: 0\r\n\r\n", + "HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n" + )); + $client = new Client($this->getServer()->getUrl()); + $client->setCurlMulti(new CurlMultiProxy(self::MAX_HANDLES, self::SELECT_TIMEOUT)); + $request = $client->get(); + $request->send(); + $this->assertEquals(200, $request->getResponse()->getStatusCode()); + $handles = $this->readAttribute($client->getCurlMulti(), 'handles'); + $this->assertEquals(2, count($handles)); + } +} diff --git a/vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/Curl/CurlMultiTest.php b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/Curl/CurlMultiTest.php new file mode 100644 index 0000000..1272281 --- /dev/null +++ b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/Curl/CurlMultiTest.php @@ -0,0 +1,455 @@ +multi = new MockMulti(); + } + + public function tearDown() + { + unset($this->multi); + } + + public function testConstructorCreateMultiHandle() + { + $this->assertInternalType('resource', $this->multi->getHandle()); + $this->assertEquals('curl_multi', get_resource_type($this->multi->getHandle())); + } + + public function testDestructorClosesMultiHandle() + { + $handle = $this->multi->getHandle(); + $this->multi->__destruct(); + $this->assertFalse(is_resource($handle)); + } + + public function testRequestsCanBeAddedAndCounted() + { + $multi = new CurlMulti(); + $request1 = new Request('GET', 'http://www.google.com/'); + $multi->add($request1); + $this->assertEquals(array($request1), $multi->all()); + $request2 = new Request('POST', 'http://www.google.com/'); + $multi->add($request2); + $this->assertEquals(array($request1, $request2), $multi->all()); + $this->assertEquals(2, count($multi)); + } + + public function testRequestsCanBeRemoved() + { + $request1 = new Request('GET', 'http://www.google.com/'); + $this->multi->add($request1); + $request2 = new Request('PUT', 'http://www.google.com/'); + $this->multi->add($request2); + $this->assertEquals(array($request1, $request2), $this->multi->all()); + $this->assertTrue($this->multi->remove($request1)); + $this->assertFalse($this->multi->remove($request1)); + $this->assertEquals(array($request2), $this->multi->all()); + } + + public function testsResetRemovesRequestsAndResetsState() + { + $this->multi->add(new Request('GET', 'http://www.google.com/')); + $this->multi->reset(); + $this->assertEquals(array(), $this->multi->all()); + } + + public function testSendsRequestsThroughCurl() + { + $this->getServer()->enqueue(array( + "HTTP/1.1 204 No content\r\n" . + "Content-Length: 0\r\n" . + "Server: Jetty(6.1.3)\r\n\r\n", + "HTTP/1.1 200 OK\r\n" . + "Content-Type: text/html; charset=utf-8\r\n" . + "Content-Length: 4\r\n" . + "Server: Jetty(6.1.3)\r\n\r\n" . + "data" + )); + + $request1 = new Request('GET', $this->getServer()->getUrl()); + $request2 = new Request('GET', $this->getServer()->getUrl()); + $this->multi->add($request1); + $this->multi->add($request2); + $this->multi->send(); + + $response1 = $request1->getResponse(); + $response2 = $request2->getResponse(); + $this->assertInstanceOf('Guzzle\\Http\\Message\\Response', $response1); + $this->assertInstanceOf('Guzzle\\Http\\Message\\Response', $response2); + + $this->assertTrue($response1->getBody(true) == 'data' || $response2->getBody(true) == 'data'); + $this->assertTrue($response1->getBody(true) == '' || $response2->getBody(true) == ''); + $this->assertTrue($response1->getStatusCode() == '204' || $response2->getStatusCode() == '204'); + $this->assertNotEquals((string) $response1, (string) $response2); + } + + public function testSendsThroughCurlAndAggregatesRequestExceptions() + { + $this->getServer()->enqueue(array( + "HTTP/1.1 200 OK\r\n" . + "Content-Type: text/html; charset=utf-8\r\n" . + "Content-Length: 4\r\n" . + "Server: Jetty(6.1.3)\r\n" . + "\r\n" . + "data", + "HTTP/1.1 204 No content\r\n" . + "Content-Length: 0\r\n" . + "Server: Jetty(6.1.3)\r\n" . + "\r\n", + "HTTP/1.1 404 Not Found\r\n" . + "Content-Length: 0\r\n" . + "\r\n" + )); + + $request1 = new Request('GET', $this->getServer()->getUrl()); + $request2 = new Request('HEAD', $this->getServer()->getUrl()); + $request3 = new Request('GET', $this->getServer()->getUrl()); + $this->multi->add($request1); + $this->multi->add($request2); + $this->multi->add($request3); + + try { + $this->multi->send(); + $this->fail('MultiTransferException not thrown when aggregating request exceptions'); + } catch (MultiTransferException $e) { + + $this->assertTrue($e->containsRequest($request1)); + $this->assertTrue($e->containsRequest($request2)); + $this->assertTrue($e->containsRequest($request3)); + $this->assertInstanceOf('ArrayIterator', $e->getIterator()); + $this->assertEquals(1, count($e)); + $exceptions = $e->getIterator(); + + $response1 = $request1->getResponse(); + $response2 = $request2->getResponse(); + $response3 = $request3->getResponse(); + + $this->assertNotEquals((string) $response1, (string) $response2); + $this->assertNotEquals((string) $response3, (string) $response1); + $this->assertInstanceOf('Guzzle\\Http\\Message\\Response', $response1); + $this->assertInstanceOf('Guzzle\\Http\\Message\\Response', $response2); + $this->assertInstanceOf('Guzzle\\Http\\Message\\Response', $response3); + + $failed = $exceptions[0]->getResponse(); + $this->assertEquals(404, $failed->getStatusCode()); + $this->assertEquals(1, count($e)); + + // Test the IteratorAggregate functionality + foreach ($e as $except) { + $this->assertEquals($failed, $except->getResponse()); + } + + $this->assertEquals(1, count($e->getFailedRequests())); + $this->assertEquals(2, count($e->getSuccessfulRequests())); + $this->assertEquals(3, count($e->getAllRequests())); + } + } + + public function testCurlErrorsAreCaught() + { + $this->getServer()->enqueue("HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n"); + try { + $request = RequestFactory::getInstance()->create('GET', 'http://127.0.0.1:9876/'); + $request->setClient(new Client()); + $request->getCurlOptions()->set(CURLOPT_FRESH_CONNECT, true); + $request->getCurlOptions()->set(CURLOPT_FORBID_REUSE, true); + $request->getCurlOptions()->set(CURLOPT_CONNECTTIMEOUT_MS, 5); + $request->send(); + $this->fail('CurlException not thrown'); + } catch (CurlException $e) { + $m = $e->getMessage(); + $this->assertContains('[curl] ', $m); + $this->assertContains('[url] http://127.0.0.1:9876/', $m); + $this->assertInternalType('array', $e->getCurlInfo()); + } + } + + public function testRemovesQueuedRequests() + { + $request = RequestFactory::getInstance()->create('GET', 'http://127.0.0.1:9876/'); + $r = new Response(200); + $request->setClient(new Client()); + $request->setResponse($r, true); + $this->multi->add($request); + $this->multi->send(); + $this->assertSame($r, $request->getResponse()); + } + + public function testRemovesQueuedRequestsAddedInTransit() + { + $this->getServer()->flush(); + $this->getServer()->enqueue(array("HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n")); + $client = new Client($this->getServer()->getUrl()); + $r = $client->get(); + $r->getEventDispatcher()->addListener('request.receive.status_line', function (Event $event) use ($client) { + // Create a request using a queued response + $request = $client->get()->setResponse(new Response(200), true); + $request->send(); + }); + $r->send(); + $this->assertEquals(1, count($this->getServer()->getReceivedRequests(false))); + } + + public function testCatchesExceptionsBeforeSendingSingleRequest() + { + $client = new Client($this->getServer()->getUrl()); + $multi = new CurlMulti(); + $client->setCurlMulti($multi); + $request = $client->get(); + $request->getEventDispatcher()->addListener('request.before_send', function() { + throw new \RuntimeException('Testing!'); + }); + try { + $request->send(); + $this->fail('Did not throw'); + } catch (\RuntimeException $e) { + // Ensure it was removed + $this->assertEquals(0, count($multi)); + } + } + + /** + * @expectedException \Guzzle\Common\Exception\ExceptionCollection + * @expectedExceptionMessage Thrown before sending! + */ + public function testCatchesExceptionsBeforeSendingMultipleRequests() + { + $client = new Client($this->getServer()->getUrl()); + $request = $client->get(); + $request->getEventDispatcher()->addListener('request.before_send', function() { + throw new \RuntimeException('Thrown before sending!'); + }); + $client->send(array($request)); + } + + public function testCatchesExceptionsWhenRemovingQueuedRequests() + { + $this->getServer()->enqueue("HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n"); + $client = new Client($this->getServer()->getUrl()); + $r = $client->get(); + $r->getEventDispatcher()->addListener('request.sent', function() use ($client) { + // Create a request using a queued response + $client->get()->setResponse(new Response(404), true)->send(); + }); + try { + $r->send(); + $this->fail('Did not throw'); + } catch (BadResponseException $e) { + $this->assertCount(0, $client->getCurlMulti()); + } + } + + public function testCatchesExceptionsWhenRemovingQueuedRequestsBeforeSending() + { + $this->getServer()->enqueue("HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n"); + $client = new Client($this->getServer()->getUrl()); + $r = $client->get(); + $r->getEventDispatcher()->addListener('request.before_send', function() use ($client) { + // Create a request using a queued response + $client->get()->setResponse(new Response(404), true)->send(); + }); + try { + $r->send(); + $this->fail('Did not throw'); + } catch (BadResponseException $e) { + $this->assertCount(0, $client->getCurlMulti()); + } + } + + /** + * @expectedException \RuntimeException + * @expectedExceptionMessage test + */ + public function testDoesNotCatchRandomExceptionsThrownDuringPerform() + { + $client = new Client($this->getServer()->getUrl()); + $multi = $this->getMock('Guzzle\\Http\\Curl\\CurlMulti', array('perform')); + $multi->expects($this->once()) + ->method('perform') + ->will($this->throwException(new \RuntimeException('test'))); + $multi->add($client->get()); + $multi->send(); + } + + public function testDoesNotSendRequestsDecliningToBeSent() + { + if (!defined('CURLOPT_TIMEOUT_MS')) { + $this->markTestSkipped('Update curl'); + } + + // Create a client that is bound to fail connecting + $client = new Client('http://127.0.0.1:123', array( + 'curl.CURLOPT_PORT' => 123, + 'curl.CURLOPT_CONNECTTIMEOUT_MS' => 1, + )); + + $request = $client->get(); + $multi = new CurlMulti(); + $multi->add($request); + + // Listen for request exceptions, and when they occur, first change the + // state of the request back to transferring, and then just allow it to + // exception out + $request->getEventDispatcher()->addListener('request.exception', function(Event $event) use ($multi) { + $retries = $event['request']->getParams()->get('retries'); + // Allow the first failure to retry + if ($retries == 0) { + $event['request']->setState('transfer'); + $event['request']->getParams()->set('retries', 1); + // Remove the request to try again + $multi->remove($event['request']); + $multi->add($event['request']); + } + }); + + try { + $multi->send(); + $this->fail('Did not throw an exception at all!?!'); + } catch (\Exception $e) { + $this->assertEquals(1, $request->getParams()->get('retries')); + } + } + + public function testDoesNotThrowExceptionsWhenRequestsRecoverWithRetry() + { + $this->getServer()->flush(); + $client = new Client($this->getServer()->getUrl()); + $request = $client->get(); + $request->getEventDispatcher()->addListener('request.before_send', function(Event $event) { + $event['request']->setResponse(new Response(200)); + }); + + $multi = new CurlMulti(); + $multi->add($request); + $multi->send(); + $this->assertEquals(0, count($this->getServer()->getReceivedRequests(false))); + } + + public function testDoesNotThrowExceptionsWhenRequestsRecoverWithSuccess() + { + // Attempt a port that 99.9% is not listening + $client = new Client('http://127.0.0.1:123'); + $request = $client->get(); + // Ensure it times out quickly if needed + $request->getCurlOptions()->set(CURLOPT_TIMEOUT_MS, 1)->set(CURLOPT_CONNECTTIMEOUT_MS, 1); + + $request->getEventDispatcher()->addListener('request.exception', function(Event $event) use (&$count) { + $event['request']->setResponse(new Response(200)); + }); + + $multi = new CurlMulti(); + $multi->add($request); + $multi->send(); + + // Ensure that the exception was caught, and the response was set manually + $this->assertEquals(200, $request->getResponse()->getStatusCode()); + } + + public function testHardResetReopensMultiHandle() + { + $this->getServer()->enqueue(array( + "HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n", + "HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n" + )); + + $stream = fopen('php://temp', 'w+'); + $client = new Client($this->getServer()->getUrl()); + $client->getConfig()->set('curl.CURLOPT_VERBOSE', true)->set('curl.CURLOPT_STDERR', $stream); + + $request = $client->get(); + $multi = new CurlMulti(); + $multi->add($request); + $multi->send(); + $multi->reset(true); + $multi->add($request); + $multi->send(); + + rewind($stream); + $this->assertNotContains('Re-using existing connection', stream_get_contents($stream)); + } + + public function testThrowsMeaningfulExceptionsForCurlMultiErrors() + { + $multi = new CurlMulti(); + + // Set the state of the multi object to sending to trigger the exception + $reflector = new \ReflectionMethod('Guzzle\Http\Curl\CurlMulti', 'checkCurlResult'); + $reflector->setAccessible(true); + + // Successful + $reflector->invoke($multi, 0); + + // Known error + try { + $reflector->invoke($multi, CURLM_BAD_HANDLE); + $this->fail('Expected an exception here'); + } catch (CurlException $e) { + $this->assertContains('The passed-in handle is not a valid CURLM handle.', $e->getMessage()); + $this->assertContains('CURLM_BAD_HANDLE', $e->getMessage()); + $this->assertContains(strval(CURLM_BAD_HANDLE), $e->getMessage()); + } + + // Unknown error + try { + $reflector->invoke($multi, 255); + $this->fail('Expected an exception here'); + } catch (CurlException $e) { + $this->assertEquals('Unexpected cURL error: 255', $e->getMessage()); + } + } + + public function testRequestBeforeSendIncludesContentLengthHeaderIfEmptyBody() + { + $this->getServer()->enqueue("HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n"); + $request = new Request('PUT', $this->getServer()->getUrl()); + $that = $this; + $request->getEventDispatcher()->addListener('request.before_send', function ($event) use ($that) { + $that->assertEquals(0, $event['request']->getHeader('Content-Length')); + }); + $this->multi->add($request); + $this->multi->send(); + } + + public function testRemovesConflictingTransferEncodingHeader() + { + $this->getServer()->flush(); + $this->getServer()->enqueue(array( + "HTTP/1.1 200 OK\r\nContent-Length: 4\r\n\r\ntest", + "HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n" + )); + $client = new Client($this->getServer()->getUrl()); + $request = $client->put('/', null, fopen($this->getServer()->getUrl(), 'r')); + $request->setHeader('Content-Length', 4); + $request->send(); + $received = $this->getServer()->getReceivedRequests(true); + $this->assertFalse($received[1]->hasHeader('Transfer-Encoding')); + $this->assertEquals(4, (string) $received[1]->getHeader('Content-Length')); + } +} diff --git a/vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/Curl/CurlVersionTest.php b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/Curl/CurlVersionTest.php new file mode 100644 index 0000000..c7b5ee6 --- /dev/null +++ b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/Curl/CurlVersionTest.php @@ -0,0 +1,39 @@ +getProperty('version'); + $refProperty->setAccessible(true); + $refProperty->setValue($instance, array()); + + $this->assertEquals($info, $instance->getAll()); + $this->assertEquals($info, $instance->getAll()); + + $this->assertEquals($info['version'], $instance->get('version')); + $this->assertFalse($instance->get('foo')); + } + + public function testIsSingleton() + { + $refObject = new \ReflectionClass('Guzzle\Http\Curl\CurlVersion'); + $refProperty = $refObject->getProperty('instance'); + $refProperty->setAccessible(true); + $refProperty->setValue(null, null); + + $this->assertInstanceOf('Guzzle\Http\Curl\CurlVersion', CurlVersion::getInstance()); + } +} diff --git a/vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/Curl/RequestMediatorTest.php b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/Curl/RequestMediatorTest.php new file mode 100644 index 0000000..c69e0c9 --- /dev/null +++ b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/Curl/RequestMediatorTest.php @@ -0,0 +1,67 @@ +events[] = $event; + } + + public function testEmitsEvents() + { + $request = new EntityEnclosingRequest('PUT', 'http://www.example.com'); + $request->setBody('foo'); + $request->setResponse(new Response(200)); + + // Ensure that IO events are emitted + $request->getCurlOptions()->set('emit_io', true); + + // Attach listeners for each event type + $request->getEventDispatcher()->addListener('curl.callback.progress', array($this, 'event')); + $request->getEventDispatcher()->addListener('curl.callback.read', array($this, 'event')); + $request->getEventDispatcher()->addListener('curl.callback.write', array($this, 'event')); + + $mediator = new RequestMediator($request, true); + + $mediator->progress('a', 'b', 'c', 'd'); + $this->assertEquals(1, count($this->events)); + $this->assertEquals('curl.callback.progress', $this->events[0]->getName()); + + $this->assertEquals(3, $mediator->writeResponseBody('foo', 'bar')); + $this->assertEquals(2, count($this->events)); + $this->assertEquals('curl.callback.write', $this->events[1]->getName()); + $this->assertEquals('bar', $this->events[1]['write']); + $this->assertSame($request, $this->events[1]['request']); + + $this->assertEquals('foo', $mediator->readRequestBody('a', 'b', 3)); + $this->assertEquals(3, count($this->events)); + $this->assertEquals('curl.callback.read', $this->events[2]->getName()); + $this->assertEquals('foo', $this->events[2]['read']); + $this->assertSame($request, $this->events[2]['request']); + } + + public function testDoesNotUseRequestResponseBodyWhenNotCustom() + { + $this->getServer()->flush(); + $this->getServer()->enqueue(array( + "HTTP/1.1 307 Foo\r\nLocation: /foo\r\nContent-Length: 2\r\n\r\nHI", + "HTTP/1.1 301 Foo\r\nLocation: /foo\r\nContent-Length: 2\r\n\r\nFI", + "HTTP/1.1 200 OK\r\nContent-Length: 4\r\n\r\ntest", + )); + $client = new Client($this->getServer()->getUrl()); + $response = $client->get()->send(); + $this->assertEquals('test', $response->getBody(true)); + } +} diff --git a/vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/EntityBodyTest.php b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/EntityBodyTest.php new file mode 100644 index 0000000..124a44d --- /dev/null +++ b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/EntityBodyTest.php @@ -0,0 +1,182 @@ +assertEquals('data', (string) $body); + $this->assertEquals(4, $body->getContentLength()); + $this->assertEquals('PHP', $body->getWrapper()); + $this->assertEquals('TEMP', $body->getStreamType()); + + $handle = fopen(__DIR__ . '/../../../../phpunit.xml.dist', 'r'); + if (!$handle) { + $this->fail('Could not open test file'); + } + $body = EntityBody::factory($handle); + $this->assertEquals(__DIR__ . '/../../../../phpunit.xml.dist', $body->getUri()); + $this->assertTrue($body->isLocal()); + $this->assertEquals(__DIR__ . '/../../../../phpunit.xml.dist', $body->getUri()); + $this->assertEquals(filesize(__DIR__ . '/../../../../phpunit.xml.dist'), $body->getContentLength()); + + // make sure that a body will return as the same object + $this->assertTrue($body === EntityBody::factory($body)); + } + + public function testFactoryCreatesTempStreamByDefault() + { + $body = EntityBody::factory(''); + $this->assertEquals('PHP', $body->getWrapper()); + $this->assertEquals('TEMP', $body->getStreamType()); + $body = EntityBody::factory(); + $this->assertEquals('PHP', $body->getWrapper()); + $this->assertEquals('TEMP', $body->getStreamType()); + } + + public function testFactoryCanCreateFromObject() + { + $body = EntityBody::factory(new QueryString(array('foo' => 'bar'))); + $this->assertEquals('foo=bar', (string) $body); + } + + /** + * @expectedException \Guzzle\Common\Exception\InvalidArgumentException + */ + public function testFactoryEnsuresObjectsHaveToStringMethod() + { + EntityBody::factory(new \stdClass('a')); + } + + public function testHandlesCompression() + { + $body = EntityBody::factory('testing 123...testing 123'); + $this->assertFalse($body->getContentEncoding(), '-> getContentEncoding() must initially return FALSE'); + $size = $body->getContentLength(); + $body->compress(); + $this->assertEquals('gzip', $body->getContentEncoding(), '-> getContentEncoding() must return the correct encoding after compressing'); + $this->assertEquals(gzdeflate('testing 123...testing 123'), (string) $body); + $this->assertTrue($body->getContentLength() < $size); + $this->assertTrue($body->uncompress()); + $this->assertEquals('testing 123...testing 123', (string) $body); + $this->assertFalse($body->getContentEncoding(), '-> getContentEncoding() must reset to FALSE'); + + if (in_array('bzip2.*', stream_get_filters())) { + $this->assertTrue($body->compress('bzip2.compress')); + $this->assertEquals('compress', $body->getContentEncoding(), '-> compress() must set \'compress\' as the Content-Encoding'); + } + + $this->assertFalse($body->compress('non-existent'), '-> compress() must return false when a non-existent stream filter is used'); + + // Release the body + unset($body); + + // Use gzip compression on the initial content. This will include a + // gzip header which will need to be stripped when deflating the stream + $body = EntityBody::factory(gzencode('test')); + $this->assertSame($body, $body->setStreamFilterContentEncoding('zlib.deflate')); + $this->assertTrue($body->uncompress('zlib.inflate')); + $this->assertEquals('test', (string) $body); + unset($body); + + // Test using a very long string + $largeString = ''; + for ($i = 0; $i < 25000; $i++) { + $largeString .= chr(rand(33, 126)); + } + $body = EntityBody::factory($largeString); + $this->assertEquals($largeString, (string) $body); + $this->assertTrue($body->compress()); + $this->assertNotEquals($largeString, (string) $body); + $compressed = (string) $body; + $this->assertTrue($body->uncompress()); + $this->assertEquals($largeString, (string) $body); + $this->assertEquals($compressed, gzdeflate($largeString)); + + $body = EntityBody::factory(fopen(__DIR__ . '/../TestData/compress_test', 'w')); + $this->assertFalse($body->compress()); + unset($body); + + unlink(__DIR__ . '/../TestData/compress_test'); + } + + public function testDeterminesContentType() + { + // Test using a string/temp stream + $body = EntityBody::factory('testing 123...testing 123'); + $this->assertNull($body->getContentType()); + + // Use a local file + $body = EntityBody::factory(fopen(__FILE__, 'r')); + $this->assertContains('text/x-', $body->getContentType()); + } + + public function testCreatesMd5Checksum() + { + $body = EntityBody::factory('testing 123...testing 123'); + $this->assertEquals(md5('testing 123...testing 123'), $body->getContentMd5()); + + $server = $this->getServer()->enqueue( + "HTTP/1.1 200 OK" . "\r\n" . + "Content-Length: 3" . "\r\n\r\n" . + "abc" + ); + + $body = EntityBody::factory(fopen($this->getServer()->getUrl(), 'r')); + $this->assertFalse($body->getContentMd5()); + } + + public function testSeeksToOriginalPosAfterMd5() + { + $body = EntityBody::factory('testing 123'); + $body->seek(4); + $this->assertEquals(md5('testing 123'), $body->getContentMd5()); + $this->assertEquals(4, $body->ftell()); + $this->assertEquals('ing 123', $body->read(1000)); + } + + public function testGetTypeFormBodyFactoring() + { + $body = EntityBody::factory(array('key1' => 'val1', 'key2' => 'val2')); + $this->assertEquals('key1=val1&key2=val2', (string) $body); + } + + public function testAllowsCustomRewind() + { + $body = EntityBody::factory('foo'); + $rewound = false; + $body->setRewindFunction(function ($body) use (&$rewound) { + $rewound = true; + return $body->seek(0); + }); + $body->seek(2); + $this->assertTrue($body->rewind()); + $this->assertTrue($rewound); + } + + /** + * @expectedException \Guzzle\Common\Exception\InvalidArgumentException + */ + public function testCustomRewindFunctionMustBeCallable() + { + $body = EntityBody::factory(); + $body->setRewindFunction('foo'); + } +} diff --git a/vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/Exception/CurlExceptionTest.php b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/Exception/CurlExceptionTest.php new file mode 100644 index 0000000..df3e4b7 --- /dev/null +++ b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/Exception/CurlExceptionTest.php @@ -0,0 +1,27 @@ +assertNull($e->getError()); + $this->assertNull($e->getErrorNo()); + $this->assertSame($e, $e->setError('test', 12)); + $this->assertEquals('test', $e->getError()); + $this->assertEquals(12, $e->getErrorNo()); + + $handle = new CurlHandle(curl_init(), array()); + $e->setCurlHandle($handle); + $this->assertSame($handle, $e->getCurlHandle()); + $handle->close(); + } +} diff --git a/vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/Exception/ExceptionTest.php b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/Exception/ExceptionTest.php new file mode 100644 index 0000000..12cfd36 --- /dev/null +++ b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/Exception/ExceptionTest.php @@ -0,0 +1,66 @@ +setRequest($request); + $this->assertEquals($request, $e->getRequest()); + } + + /** + * @covers Guzzle\Http\Exception\BadResponseException + */ + public function testBadResponseException() + { + $e = new BadResponseException('Message'); + $response = new Response(200); + $e->setResponse($response); + $this->assertEquals($response, $e->getResponse()); + } + + /** + * @covers Guzzle\Http\Exception\BadResponseException::factory + */ + public function testCreatesGenericErrorExceptionOnError() + { + $request = new Request('GET', 'http://www.example.com'); + $response = new Response(307); + $e = BadResponseException::factory($request, $response); + $this->assertInstanceOf('Guzzle\Http\Exception\BadResponseException', $e); + } + + /** + * @covers Guzzle\Http\Exception\BadResponseException::factory + */ + public function testCreatesClientErrorExceptionOnClientError() + { + $request = new Request('GET', 'http://www.example.com'); + $response = new Response(404); + $e = BadResponseException::factory($request, $response); + $this->assertInstanceOf('Guzzle\Http\Exception\ClientErrorResponseException', $e); + } + + /** + * @covers Guzzle\Http\Exception\BadResponseException::factory + */ + public function testCreatesServerErrorExceptionOnServerError() + { + $request = new Request('GET', 'http://www.example.com'); + $response = new Response(503); + $e = BadResponseException::factory($request, $response); + $this->assertInstanceOf('Guzzle\Http\Exception\ServerErrorResponseException', $e); + } +} diff --git a/vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/Exception/MultiTransferExceptionTest.php b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/Exception/MultiTransferExceptionTest.php new file mode 100644 index 0000000..fa4ec26 --- /dev/null +++ b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/Exception/MultiTransferExceptionTest.php @@ -0,0 +1,51 @@ +addSuccessfulRequest($r1); + $e->addFailedRequest($r2); + $this->assertEquals(array($r1), $e->getSuccessfulRequests()); + $this->assertEquals(array($r2), $e->getSuccessfulRequests()); + $this->assertEquals(array($r1, $r2), $e->getAllRequests()); + $this->assertTrue($e->containsRequest($r1)); + $this->assertTrue($e->containsRequest($r2)); + $this->assertFalse($e->containsRequest(new Request('POST', '/foo'))); + } + + public function testCanSetRequests() + { + $s = array($r1 = new Request('GET', 'http://www.foo.com')); + $f = array($r2 = new Request('GET', 'http://www.foo.com')); + $e = new MultiTransferException(); + $e->setSuccessfulRequests($s); + $e->setFailedRequests($f); + $this->assertEquals(array($r1), $e->getSuccessfulRequests()); + $this->assertEquals(array($r2), $e->getSuccessfulRequests()); + } + + public function testAssociatesExceptionsWithRequests() + { + $r1 = new Request('GET', 'http://www.foo.com'); + $re1 = new \Exception('foo'); + $re2 = new \Exception('bar'); + $e = new MultiTransferException(); + $e->add($re2); + $e->addFailedRequestWithException($r1, $re1); + $this->assertSame($re1, $e->getExceptionForFailedRequest($r1)); + $this->assertNull($e->getExceptionForFailedRequest(new Request('POST', '/foo'))); + } +} diff --git a/vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/IoEmittingEntityBodyTest.php b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/IoEmittingEntityBodyTest.php new file mode 100644 index 0000000..cd6355f --- /dev/null +++ b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/IoEmittingEntityBodyTest.php @@ -0,0 +1,47 @@ +decorated = EntityBody::factory('hello'); + $this->body = new IoEmittingEntityBody($this->decorated); + } + + public function testEmitsReadEvents() + { + $e = null; + $this->body->getEventDispatcher()->addListener('body.read', function ($event) use (&$e) { + $e = $event; + }); + $this->assertEquals('hel', $this->body->read(3)); + $this->assertEquals('hel', $e['read']); + $this->assertEquals(3, $e['length']); + $this->assertSame($this->body, $e['body']); + } + + public function testEmitsWriteEvents() + { + $e = null; + $this->body->getEventDispatcher()->addListener('body.write', function ($event) use (&$e) { + $e = $event; + }); + $this->body->seek(0, SEEK_END); + $this->assertEquals(5, $this->body->write('there')); + $this->assertEquals('there', $e['write']); + $this->assertEquals(5, $e['result']); + $this->assertSame($this->body, $e['body']); + $this->assertEquals('hellothere', (string) $this->body); + } +} diff --git a/vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/Message/AbstractMessageTest.php b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/Message/AbstractMessageTest.php new file mode 100644 index 0000000..9447d8c --- /dev/null +++ b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/Message/AbstractMessageTest.php @@ -0,0 +1,136 @@ +mock = $this->getMockForAbstractClass('Guzzle\Http\Message\AbstractMessage'); + } + + public function tearDown() + { + $this->mock = $this->request = null; + } + + public function testGetParams() + { + $request = new Request('GET', 'http://example.com'); + $this->assertInstanceOf('Guzzle\\Common\\Collection', $request->getParams()); + } + + public function testAddHeaders() + { + $this->mock->setHeader('A', 'B'); + + $this->assertEquals($this->mock, $this->mock->addHeaders(array( + 'X-Data' => '123' + ))); + + $this->assertTrue($this->mock->hasHeader('X-Data') !== false); + $this->assertTrue($this->mock->hasHeader('A') !== false); + } + + public function testAllowsHeaderToSetAsHeader() + { + $h = new Header('A', 'B'); + $this->mock->setHeader('A', $h); + $this->assertSame($h, $this->mock->getHeader('A')); + } + + public function testGetHeader() + { + $this->mock->setHeader('Test', '123'); + $this->assertEquals('123', $this->mock->getHeader('Test')); + } + + public function testGetHeaders() + { + $this->assertSame($this->mock, $this->mock->setHeaders(array('a' => 'b', 'c' => 'd'))); + $h = $this->mock->getHeaders(); + $this->assertArrayHasKey('a', $h->toArray()); + $this->assertArrayHasKey('c', $h->toArray()); + $this->assertInstanceOf('Guzzle\Http\Message\Header\HeaderInterface', $h->get('a')); + $this->assertInstanceOf('Guzzle\Http\Message\Header\HeaderInterface', $h->get('c')); + } + + public function testGetHeaderLinesUsesGlue() + { + $this->mock->setHeaders(array('a' => 'b', 'c' => 'd')); + $this->mock->addHeader('a', 'e'); + $this->mock->getHeader('a')->setGlue('!'); + $this->assertEquals(array( + 'a: b! e', + 'c: d' + ), $this->mock->getHeaderLines()); + } + + public function testHasHeader() + { + $this->assertFalse($this->mock->hasHeader('Foo')); + $this->mock->setHeader('Foo', 'Bar'); + $this->assertEquals(true, $this->mock->hasHeader('Foo')); + $this->mock->setHeader('foo', 'yoo'); + $this->assertEquals(true, $this->mock->hasHeader('Foo')); + $this->assertEquals(true, $this->mock->hasHeader('foo')); + $this->assertEquals(false, $this->mock->hasHeader('bar')); + } + + public function testRemoveHeader() + { + $this->mock->setHeader('Foo', 'Bar'); + $this->assertEquals(true, $this->mock->hasHeader('Foo')); + $this->mock->removeHeader('Foo'); + $this->assertFalse($this->mock->hasHeader('Foo')); + } + + public function testReturnsNullWhenHeaderIsNotFound() + { + $this->assertNull($this->mock->getHeader('foo')); + } + + public function testAddingHeadersPreservesOriginalHeaderCase() + { + $this->mock->addHeaders(array( + 'test' => '123', + 'Test' => 'abc' + )); + $this->mock->addHeader('test', '456'); + $this->mock->addHeader('test', '789'); + + $header = $this->mock->getHeader('test'); + $this->assertContains('123', $header->toArray()); + $this->assertContains('456', $header->toArray()); + $this->assertContains('789', $header->toArray()); + $this->assertContains('abc', $header->toArray()); + } + + public function testCanStoreEmptyHeaders() + { + $this->mock->setHeader('Content-Length', 0); + $this->assertTrue($this->mock->hasHeader('Content-Length')); + $this->assertEquals(0, (string) $this->mock->getHeader('Content-Length')); + } + + public function testCanSetCustomHeaderFactory() + { + $f = new Header\HeaderFactory(); + $this->mock->setHeaderFactory($f); + $this->assertSame($f, $this->readAttribute($this->mock, 'headerFactory')); + } +} diff --git a/vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/Message/EntityEnclosingRequestTest.php b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/Message/EntityEnclosingRequestTest.php new file mode 100644 index 0000000..191b022 --- /dev/null +++ b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/Message/EntityEnclosingRequestTest.php @@ -0,0 +1,434 @@ +client = new Client(); + } + + public function tearDown() + { + $this->client = null; + } + + public function testConstructorConfiguresRequest() + { + $request = new EntityEnclosingRequest('PUT', 'http://test.com', array( + 'X-Test' => '123' + )); + $request->setBody('Test'); + $this->assertEquals('123', $request->getHeader('X-Test')); + $this->assertNull($request->getHeader('Expect')); + } + + public function testCanSetBodyWithoutOverridingContentType() + { + $request = new EntityEnclosingRequest('PUT', 'http://test.com', array('Content-Type' => 'foooooo')); + $request->setBody('{"a":"b"}'); + $this->assertEquals('foooooo', $request->getHeader('Content-Type')); + } + + public function testRequestIncludesBodyInMessage() + { + + $request = RequestFactory::getInstance()->create('PUT', 'http://www.guzzle-project.com/', null, 'data'); + $this->assertEquals("PUT / HTTP/1.1\r\n" + . "Host: www.guzzle-project.com\r\n" + . "Content-Length: 4\r\n\r\n" + . "data", (string) $request); + } + + public function testRequestIncludesPostBodyInMessageOnlyWhenNoPostFiles() + { + $request = RequestFactory::getInstance()->create('POST', 'http://www.guzzle-project.com/', null, array( + 'foo' => 'bar' + )); + $this->assertEquals("POST / HTTP/1.1\r\n" + . "Host: www.guzzle-project.com\r\n" + . "Content-Type: application/x-www-form-urlencoded; charset=utf-8\r\n\r\n" + . "foo=bar", (string) $request); + + $request = RequestFactory::getInstance()->create('POST', 'http://www.guzzle-project.com/', null, array( + 'foo' => '@' . __FILE__ + )); + $this->assertEquals("POST / HTTP/1.1\r\n" + . "Host: www.guzzle-project.com\r\n" + . "Content-Type: multipart/form-data\r\n" + . "Expect: 100-Continue\r\n\r\n", (string) $request); + } + + public function testAddsPostFieldsAndSetsContentLength() + { + $request = RequestFactory::getInstance()->create('POST', 'http://www.guzzle-project.com/', null, array( + 'data' => '123' + )); + $this->assertEquals("POST / HTTP/1.1\r\n" + . "Host: www.guzzle-project.com\r\n" + . "Content-Type: application/x-www-form-urlencoded; charset=utf-8\r\n\r\n" + . "data=123", (string) $request); + } + + public function testAddsPostFilesAndSetsContentType() + { + $request = RequestFactory::getInstance()->create('POST', 'http://www.test.com/') + ->addPostFiles(array( + 'file' => __FILE__ + ))->addPostFields(array( + 'a' => 'b' + )); + $message = (string) $request; + $this->assertEquals('multipart/form-data', $request->getHeader('Content-Type')); + $this->assertEquals('100-Continue', $request->getHeader('Expect')); + } + + public function testRequestBodyContainsPostFiles() + { + $request = RequestFactory::getInstance()->create('POST', 'http://www.test.com/'); + $request->addPostFields(array( + 'test' => '123' + )); + $this->assertContains("\r\n\r\ntest=123", (string) $request); + } + + public function testRequestBodyAddsContentLength() + { + $request = RequestFactory::getInstance()->create('PUT', 'http://www.test.com/'); + $request->setBody(EntityBody::factory('test')); + $this->assertEquals(4, (string) $request->getHeader('Content-Length')); + $this->assertFalse($request->hasHeader('Transfer-Encoding')); + } + + public function testRequestBodyDoesNotUseContentLengthWhenChunked() + { + $request = RequestFactory::getInstance()->create('PUT', 'http://www.test.com/', array( + 'Transfer-Encoding' => 'chunked' + ), 'test'); + $this->assertNull($request->getHeader('Content-Length')); + $this->assertTrue($request->hasHeader('Transfer-Encoding')); + } + + public function testRequestHasMutableBody() + { + $request = RequestFactory::getInstance()->create('PUT', 'http://www.guzzle-project.com/', null, 'data'); + $body = $request->getBody(); + $this->assertInstanceOf('Guzzle\\Http\\EntityBody', $body); + $this->assertSame($body, $request->getBody()); + + $newBody = EntityBody::factory('foobar'); + $request->setBody($newBody); + $this->assertEquals('foobar', (string) $request->getBody()); + $this->assertSame($newBody, $request->getBody()); + } + + public function testSetPostFields() + { + $request = RequestFactory::getInstance()->create('POST', 'http://www.guzzle-project.com/'); + $this->assertInstanceOf('Guzzle\\Http\\QueryString', $request->getPostFields()); + + $fields = new QueryString(array( + 'a' => 'b' + )); + $request->addPostFields($fields); + $this->assertEquals($fields->getAll(), $request->getPostFields()->getAll()); + $this->assertEquals(array(), $request->getPostFiles()); + } + + public function testSetPostFiles() + { + $request = RequestFactory::getInstance()->create('POST', $this->getServer()->getUrl()) + ->setClient(new Client()) + ->addPostFiles(array(__FILE__)) + ->addPostFields(array( + 'test' => 'abc' + )); + + $request->getCurlOptions()->set('debug', true); + + $this->assertEquals(array( + 'test' => 'abc' + ), $request->getPostFields()->getAll()); + + $files = $request->getPostFiles(); + $post = $files['file'][0]; + $this->assertEquals('file', $post->getFieldName()); + $this->assertContains('text/x-', $post->getContentType()); + $this->assertEquals(__FILE__, $post->getFilename()); + + $this->getServer()->enqueue("HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n"); + $request->send(); + + $this->assertNotNull($request->getHeader('Content-Length')); + $this->assertContains('multipart/form-data; boundary=', (string) $request->getHeader('Content-Type'), '-> cURL must add the boundary'); + } + + /** + * @expectedException Guzzle\Common\Exception\InvalidArgumentException + */ + public function testSetPostFilesThrowsExceptionWhenFileIsNotFound() + { + $request = RequestFactory::getInstance()->create('POST', 'http://www.guzzle-project.com/') + ->addPostFiles(array( + 'file' => 'filenotfound.ini' + )); + } + + /** + * @expectedException Guzzle\Http\Exception\RequestException + */ + public function testThrowsExceptionWhenNonStringsAreAddedToPost() + { + $request = RequestFactory::getInstance()->create('POST', 'http://www.guzzle-project.com/') + ->addPostFile('foo', new \stdClass()); + } + + public function testAllowsContentTypeInPostUploads() + { + $request = RequestFactory::getInstance()->create('POST', 'http://www.guzzle-project.com/') + ->addPostFile('foo', __FILE__, 'text/plain'); + + $this->assertEquals(array( + new PostFile('foo', __FILE__, 'text/plain') + ), $request->getPostFile('foo')); + } + + public function testGuessesContentTypeOfPostUpload() + { + $request = RequestFactory::getInstance()->create('POST', 'http://www.guzzle-project.com/') + ->addPostFile('foo', __FILE__); + $file = $request->getPostFile('foo'); + $this->assertContains('text/x-', $file[0]->getContentType()); + } + + public function testAllowsContentDispositionFieldsInPostUploadsWhenSettingInBulk() + { + $postFile = new PostFile('foo', __FILE__, 'text/x-php'); + $request = RequestFactory::getInstance()->create('POST', 'http://www.guzzle-project.com/') + ->addPostFiles(array('foo' => $postFile)); + + $this->assertEquals(array($postFile), $request->getPostFile('foo')); + } + + public function testPostRequestsUseApplicationXwwwForUrlEncodedForArrays() + { + $request = RequestFactory::getInstance()->create('POST', 'http://www.guzzle-project.com/'); + $request->setPostField('a', 'b'); + $this->assertContains("\r\n\r\na=b", (string) $request); + $this->assertEquals('application/x-www-form-urlencoded; charset=utf-8', $request->getHeader('Content-Type')); + } + + public function testProcessMethodAddsContentType() + { + $request = RequestFactory::getInstance()->create('POST', 'http://www.guzzle-project.com/'); + $request->setPostField('a', 'b'); + $this->assertEquals('application/x-www-form-urlencoded; charset=utf-8', $request->getHeader('Content-Type')); + } + + public function testPostRequestsUseMultipartFormDataWithFiles() + { + $request = RequestFactory::getInstance()->create('POST', 'http://www.guzzle-project.com/'); + $request->addPostFiles(array('file' => __FILE__)); + $this->assertEquals('multipart/form-data', $request->getHeader('Content-Type')); + } + + public function testCanSendMultipleRequestsUsingASingleRequestObject() + { + $this->getServer()->flush(); + $this->getServer()->enqueue(array( + "HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n", + "HTTP/1.1 201 Created\r\nContent-Length: 0\r\n\r\n", + )); + + // Send the first request + $request = RequestFactory::getInstance()->create('PUT', $this->getServer()->getUrl()) + ->setBody('test') + ->setClient(new Client()); + $request->send(); + $this->assertEquals(200, $request->getResponse()->getStatusCode()); + + // Send the second request + $request->setBody('abcdefg', 'application/json', false); + $request->send(); + $this->assertEquals(201, $request->getResponse()->getStatusCode()); + + // Ensure that the same request was sent twice with different bodies + $requests = $this->getServer()->getReceivedRequests(true); + $this->assertEquals(2, count($requests)); + $this->assertEquals(4, (string) $requests[0]->getHeader('Content-Length')); + $this->assertEquals(7, (string) $requests[1]->getHeader('Content-Length')); + } + + public function testRemovingPostFieldRebuildsPostFields() + { + $request = new EntityEnclosingRequest('POST', 'http://test.com'); + $request->setPostField('test', 'value'); + $request->removePostField('test'); + $this->assertNull($request->getPostField('test')); + } + + public function testUsesChunkedTransferWhenBodyLengthCannotBeDetermined() + { + $this->getServer()->enqueue("HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n"); + $request = new EntityEnclosingRequest('PUT', 'http://test.com/'); + $request->setBody(fopen($this->getServer()->getUrl(), 'r')); + $this->assertEquals('chunked', $request->getHeader('Transfer-Encoding')); + $this->assertFalse($request->hasHeader('Content-Length')); + } + + /** + * @expectedException \Guzzle\Http\Exception\RequestException + */ + public function testThrowsExceptionWhenContentLengthCannotBeDeterminedAndUsingHttp1() + { + $request = new EntityEnclosingRequest('PUT', 'http://test.com/'); + $this->getServer()->enqueue("HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n"); + $request->setProtocolVersion('1.0'); + $request->setBody(fopen($this->getServer()->getUrl(), 'r')); + } + + public function testAllowsNestedPostData() + { + $request = new EntityEnclosingRequest('POST', 'http://test.com/'); + $request->addPostFields(array( + 'a' => array('b', 'c') + )); + $this->assertEquals(array( + 'a' => array('b', 'c') + ), $request->getPostFields()->getAll()); + } + + public function testAllowsEmptyFields() + { + $request = new EntityEnclosingRequest('POST', 'http://test.com/'); + $request->addPostFields(array( + 'a' => '' + )); + $this->assertEquals(array( + 'a' => '' + ), $request->getPostFields()->getAll()); + } + + /** + * @expectedException \Guzzle\Http\Exception\RequestException + */ + public function testFailsOnInvalidFiles() + { + $request = new EntityEnclosingRequest('POST', 'http://test.com/'); + $request->addPostFiles(array( + 'a' => new \stdClass() + )); + } + + public function testHandlesEmptyStrings() + { + $request = new EntityEnclosingRequest('POST', 'http://test.com/'); + $request->addPostFields(array( + 'a' => '', + 'b' => null, + 'c' => 'Foo' + )); + $this->assertEquals(array( + 'a' => '', + 'b' => null, + 'c' => 'Foo' + ), $request->getPostFields()->getAll()); + } + + public function testHoldsPostFiles() + { + $request = new EntityEnclosingRequest('POST', 'http://test.com/'); + $request->addPostFile('foo', __FILE__); + $request->addPostFile(new PostFile('foo', __FILE__)); + + $this->assertArrayHasKey('foo', $request->getPostFiles()); + $foo = $request->getPostFile('foo'); + $this->assertEquals(2, count($foo)); + $this->assertEquals(__FILE__, $foo[0]->getFilename()); + $this->assertEquals(__FILE__, $foo[1]->getFilename()); + + $request->removePostFile('foo'); + $this->assertEquals(array(), $request->getPostFiles()); + } + + public function testAllowsAtPrefixWhenAddingPostFiles() + { + $request = new EntityEnclosingRequest('POST', 'http://test.com/'); + $request->addPostFiles(array( + 'foo' => '@' . __FILE__ + )); + $foo = $request->getPostFile('foo'); + $this->assertEquals(__FILE__, $foo[0]->getFilename()); + } + + public function testSetStateToTransferWithEmptyBodySetsContentLengthToZero() + { + $request = new EntityEnclosingRequest('POST', 'http://test.com/'); + $request->setState($request::STATE_TRANSFER); + $this->assertEquals('0', (string) $request->getHeader('Content-Length')); + } + + public function testSettingExpectHeaderCutoffChangesRequest() + { + $request = new EntityEnclosingRequest('PUT', 'http://test.com/'); + $request->setHeader('Expect', '100-Continue'); + $request->setExpectHeaderCutoff(false); + $this->assertNull($request->getHeader('Expect')); + // There is not body, so remove the expect header + $request->setHeader('Expect', '100-Continue'); + $request->setExpectHeaderCutoff(10); + $this->assertNull($request->getHeader('Expect')); + // The size is less than the cutoff + $request->setBody('foo'); + $this->assertNull($request->getHeader('Expect')); + // The size is greater than the cutoff + $request->setBody('foobazbarbamboo'); + $this->assertNotNull($request->getHeader('Expect')); + } + + public function testStrictRedirectsCanBeSpecifiedOnEntityEnclosingRequests() + { + $request = new EntityEnclosingRequest('PUT', 'http://test.com/'); + $request->configureRedirects(true); + $this->assertTrue($request->getParams()->get(RedirectPlugin::STRICT_REDIRECTS)); + } + + public function testCanDisableRedirects() + { + $request = new EntityEnclosingRequest('PUT', 'http://test.com/'); + $request->configureRedirects(false, false); + $this->assertTrue($request->getParams()->get(RedirectPlugin::DISABLE)); + } + + public function testSetsContentTypeWhenSettingBodyByGuessingFromEntityBody() + { + $request = new EntityEnclosingRequest('PUT', 'http://test.com/foo'); + $request->setBody(EntityBody::factory(fopen(__FILE__, 'r'))); + $this->assertEquals('text/x-php', (string) $request->getHeader('Content-Type')); + } + + public function testDoesNotCloneBody() + { + $request = new EntityEnclosingRequest('PUT', 'http://test.com/foo'); + $request->setBody('test'); + $newRequest = clone $request; + $newRequest->setBody('foo'); + $this->assertInternalType('string', (string) $request->getBody()); + } +} diff --git a/vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/Message/Header/HeaderFactoryTest.php b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/Message/Header/HeaderFactoryTest.php new file mode 100644 index 0000000..62ca555 --- /dev/null +++ b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/Message/Header/HeaderFactoryTest.php @@ -0,0 +1,29 @@ +createHeader('Foo', 'Bar'); + $this->assertInstanceOf('Guzzle\Http\Message\Header', $h); + $this->assertEquals('Foo', $h->getName()); + $this->assertEquals('Bar', (string) $h); + } + + public function testCreatesSpecificHeaders() + { + $f = new HeaderFactory(); + $h = $f->createHeader('Link', '; rel="test"'); + $this->assertInstanceOf('Guzzle\Http\Message\Header\Link', $h); + $this->assertEquals('Link', $h->getName()); + $this->assertEquals('; rel="test"', (string) $h); + } +} diff --git a/vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/Message/Header/LinkTest.php b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/Message/Header/LinkTest.php new file mode 100644 index 0000000..c834d10 --- /dev/null +++ b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/Message/Header/LinkTest.php @@ -0,0 +1,63 @@ +; rel=front; type="image/jpeg", ; rel=back; type="image/jpeg", ; rel=side; type="image/jpeg"'); + $links = $link->getLinks(); + $this->assertEquals(array( + array( + 'rel' => 'front', + 'type' => 'image/jpeg', + 'url' => 'http:/.../front.jpeg', + ), + array( + 'rel' => 'back', + 'type' => 'image/jpeg', + 'url' => 'http://.../back.jpeg', + ), + array( + 'rel' => 'side', + 'type' => 'image/jpeg', + 'url' => 'http://.../side.jpeg?test=1' + ) + ), $links); + + $this->assertEquals(array( + 'rel' => 'back', + 'type' => 'image/jpeg', + 'url' => 'http://.../back.jpeg', + ), $link->getLink('back')); + + $this->assertTrue($link->hasLink('front')); + $this->assertFalse($link->hasLink('foo')); + } + + public function testCanAddLink() + { + $link = new Link('Link', '; rel=a; type="image/jpeg"'); + $link->addLink('http://test.com', 'test', array('foo' => 'bar')); + $this->assertEquals( + '; rel=a; type="image/jpeg", ; rel="test"; foo="bar"', + (string) $link + ); + } + + public function testCanParseLinksWithCommas() + { + $link = new Link('Link', '; rel="previous"; title="start, index"'); + $this->assertEquals(array( + array( + 'rel' => 'previous', + 'title' => 'start, index', + 'url' => 'http://example.com/TheBook/chapter1', + ) + ), $link->getLinks()); + } +} diff --git a/vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/Message/HeaderComparison.php b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/Message/HeaderComparison.php new file mode 100644 index 0000000..a3f511b --- /dev/null +++ b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/Message/HeaderComparison.php @@ -0,0 +1,135 @@ +toArray(); + } + + foreach ($filteredHeaders as $k => $v) { + if ($k[0] == '_') { + // This header should be ignored + $ignore[] = str_replace('_', '', $k); + } elseif ($k[0] == '!') { + // This header must not be present + $absent[] = str_replace('!', '', $k); + } else { + $expected[$k] = $v; + } + } + + return $this->compareArray($expected, $actualHeaders, $ignore, $absent); + } + + /** + * Check if an array of HTTP headers matches another array of HTTP headers while taking * into account as a wildcard + * + * @param array $expected Expected HTTP headers (allows wildcard values) + * @param array|Collection $actual Actual HTTP header array + * @param array $ignore Headers to ignore from the comparison + * @param array $absent Array of headers that must not be present + * + * @return array|bool Returns an array of the differences or FALSE if none + */ + public function compareArray(array $expected, $actual, array $ignore = array(), array $absent = array()) + { + $differences = array(); + + // Add information about headers that were present but weren't supposed to be + foreach ($absent as $header) { + if ($this->hasKey($header, $actual)) { + $differences["++ {$header}"] = $actual[$header]; + unset($actual[$header]); + } + } + + // Check if expected headers are missing + foreach ($expected as $header => $value) { + if (!$this->hasKey($header, $actual)) { + $differences["- {$header}"] = $value; + } + } + + // Flip the ignore array so it works with the case insensitive helper + $ignore = array_flip($ignore); + // Allow case-insensitive comparisons in wildcards + $expected = array_change_key_case($expected); + + // Compare the expected and actual HTTP headers in no particular order + foreach ($actual as $key => $value) { + + // If this is to be ignored, the skip it + if ($this->hasKey($key, $ignore)) { + continue; + } + + // If the header was not expected + if (!$this->hasKey($key, $expected)) { + $differences["+ {$key}"] = $value; + continue; + } + + // Check values and take wildcards into account + $lkey = strtolower($key); + $pos = is_string($expected[$lkey]) ? strpos($expected[$lkey], '*') : false; + + foreach ((array) $actual[$key] as $v) { + if (($pos === false && $v != $expected[$lkey]) || $pos > 0 && substr($v, 0, $pos) != substr($expected[$lkey], 0, $pos)) { + $differences[$key] = "{$value} != {$expected[$lkey]}"; + } + } + } + + return empty($differences) ? false : $differences; + } + + /** + * Case insensitive check if an array have a key + * + * @param string $key Key to check + * @param array $array Array to check + * + * @return bool + */ + protected function hasKey($key, $array) + { + if ($array instanceof Collection) { + $keys = $array->getKeys(); + } else { + $keys = array_keys($array); + } + + foreach ($keys as $k) { + if (!strcasecmp($k, $key)) { + return true; + } + } + + return false; + } +} diff --git a/vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/Message/HeaderComparisonTest.php b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/Message/HeaderComparisonTest.php new file mode 100644 index 0000000..86c4fe8 --- /dev/null +++ b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/Message/HeaderComparisonTest.php @@ -0,0 +1,115 @@ + 'Foo' + ), array( + 'Content-Length' => 'Foo' + ), false), + + // Missing header + array(array( + 'X-Foo' => 'Bar' + ), array(), array( + '- X-Foo' => 'Bar' + )), + + // Extra headers is present + array(array( + 'X-Foo' => 'Bar' + ), array( + 'X-Foo' => 'Bar', + 'X-Baz' => 'Jar' + ), array( + '+ X-Baz' => 'Jar' + )), + + // Header is present but must be absent + array(array( + '!X-Foo' => '*' + ), array( + 'X-Foo' => 'Bar' + ), array( + '++ X-Foo' => 'Bar' + )), + + // Different values + array(array( + 'X-Foo' => 'Bar' + ), array( + 'X-Foo' => 'Baz' + ), array( + 'X-Foo' => 'Baz != Bar' + )), + + // Wildcard search passes + array(array( + 'X-Foo' => '*' + ), array( + 'X-Foo' => 'Bar' + ), false), + + // Wildcard search fails + array(array( + 'X-Foo' => '*' + ), array(), array( + '- X-Foo' => '*' + )), + + // Ignore extra header if present + array(array( + 'X-Foo' => '*', + '_X-Bar' => '*', + ), array( + 'X-Foo' => 'Baz', + 'X-Bar' => 'Jar' + ), false), + + // Ignore extra header if present and is not + array(array( + 'X-Foo' => '*', + '_X-Bar' => '*', + ), array( + 'X-Foo' => 'Baz' + ), false), + + // Case insensitive + array(array( + 'X-Foo' => '*', + '_X-Bar' => '*', + ), array( + 'x-foo' => 'Baz', + 'x-BAR' => 'baz' + ), false), + + // Case insensitive with collection + array(array( + 'X-Foo' => '*', + '_X-Bar' => '*', + ), new Collection(array( + 'x-foo' => 'Baz', + 'x-BAR' => 'baz' + )), false), + ); + } + + /** + * @dataProvider filterProvider + */ + public function testComparesHeaders($filters, $headers, $result) + { + $compare = new HeaderComparison(); + $this->assertEquals($result, $compare->compare($filters, $headers)); + } +} diff --git a/vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/Message/HeaderTest.php b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/Message/HeaderTest.php new file mode 100644 index 0000000..c750234 --- /dev/null +++ b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/Message/HeaderTest.php @@ -0,0 +1,162 @@ + array('foo', 'Foo'), + 'Zoo' => 'bar', + ); + + public function testStoresHeaderName() + { + $i = new Header('Zoo', $this->test); + $this->assertEquals('Zoo', $i->getName()); + } + + public function testConvertsToString() + { + $i = new Header('Zoo', $this->test); + $this->assertEquals('foo, Foo, bar', (string) $i); + $i->setGlue(';'); + $this->assertEquals('foo; Foo; bar', (string) $i); + } + + public function testNormalizesGluedHeaders() + { + $h = new Header('Zoo', array('foo, Faz', 'bar')); + $result = $h->normalize(true)->toArray(); + natsort($result); + $this->assertEquals(array('bar', 'foo', 'Faz'), $result); + } + + public function testCanSearchForValues() + { + $h = new Header('Zoo', $this->test); + $this->assertTrue($h->hasValue('foo')); + $this->assertTrue($h->hasValue('Foo')); + $this->assertTrue($h->hasValue('bar')); + $this->assertFalse($h->hasValue('moo')); + $this->assertFalse($h->hasValue('FoO')); + } + + public function testIsCountable() + { + $h = new Header('Zoo', $this->test); + $this->assertEquals(3, count($h)); + } + + public function testCanBeIterated() + { + $h = new Header('Zoo', $this->test); + $results = array(); + foreach ($h as $key => $value) { + $results[$key] = $value; + } + $this->assertEquals(array( + 'foo', 'Foo', 'bar' + ), $results); + } + + public function testAllowsFalseyValues() + { + // Allows 0 + $h = new Header('Foo', 0, ';'); + $this->assertEquals('0', (string) $h); + $this->assertEquals(1, count($h)); + $this->assertEquals(';', $h->getGlue()); + + // Does not add a null header by default + $h = new Header('Foo'); + $this->assertEquals('', (string) $h); + $this->assertEquals(0, count($h)); + + // Allows null array for a single null header + $h = new Header('Foo', array(null)); + $this->assertEquals('', (string) $h); + + // Allows empty string + $h = new Header('Foo', ''); + $this->assertEquals('', (string) $h); + $this->assertEquals(1, count($h)); + $this->assertEquals(1, count($h->normalize()->toArray())); + } + + public function testCanRemoveValues() + { + $h = new Header('Foo', array('Foo', 'baz', 'bar')); + $h->removeValue('bar'); + $this->assertTrue($h->hasValue('Foo')); + $this->assertFalse($h->hasValue('bar')); + $this->assertTrue($h->hasValue('baz')); + } + + public function testAllowsArrayInConstructor() + { + $h = new Header('Foo', array('Testing', '123', 'Foo=baz')); + $this->assertEquals(array('Testing', '123', 'Foo=baz'), $h->toArray()); + } + + public function parseParamsProvider() + { + $res1 = array( + array( + '' => '', + 'rel' => 'front', + 'type' => 'image/jpeg', + ), + array( + '' => '', + 'rel' => 'back', + 'type' => 'image/jpeg', + ), + ); + + return array( + array( + '; rel="front"; type="image/jpeg", ; rel=back; type="image/jpeg"', + $res1 + ), + array( + '; rel="front"; type="image/jpeg",; rel=back; type="image/jpeg"', + $res1 + ), + array( + 'foo="baz"; bar=123, boo, test="123", foobar="foo;bar"', + array( + array('foo' => 'baz', 'bar' => '123'), + array('boo' => ''), + array('test' => '123'), + array('foobar' => 'foo;bar') + ) + ), + array( + '; rel="side"; type="image/jpeg",; rel=side; type="image/jpeg"', + array( + array('' => '', 'rel' => 'side', 'type' => 'image/jpeg'), + array('' => '', 'rel' => 'side', 'type' => 'image/jpeg') + ) + ), + array( + '', + array() + ) + ); + } + + /** + * @dataProvider parseParamsProvider + */ + public function testParseParams($header, $result) + { + $response = new Response(200, array('Link' => $header)); + $this->assertEquals($result, $response->getHeader('Link')->parseParams()); + } +} diff --git a/vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/Message/PostFileTest.php b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/Message/PostFileTest.php new file mode 100644 index 0000000..be048cb --- /dev/null +++ b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/Message/PostFileTest.php @@ -0,0 +1,88 @@ +assertEquals('foo', $file->getFieldName()); + $this->assertEquals(__FILE__, $file->getFilename()); + $this->assertEquals('boo', $file->getPostName()); + $this->assertEquals('x-foo', $file->getContentType()); + } + + public function testRemovesLeadingAtSymbolFromPath() + { + $file = new PostFile('foo', '@' . __FILE__); + $this->assertEquals(__FILE__, $file->getFilename()); + } + + /** + * @expectedException Guzzle\Common\Exception\InvalidArgumentException + */ + public function testEnsuresFileIsReadable() + { + $file = new PostFile('foo', '/foo/baz/bar'); + } + + public function testCanChangeContentType() + { + $file = new PostFile('foo', '@' . __FILE__); + $file->setContentType('Boo'); + $this->assertEquals('Boo', $file->getContentType()); + } + + public function testCanChangeFieldName() + { + $file = new PostFile('foo', '@' . __FILE__); + $file->setFieldName('Boo'); + $this->assertEquals('Boo', $file->getFieldName()); + } + + public function testReturnsCurlValueString() + { + $file = new PostFile('foo', __FILE__); + if (version_compare(phpversion(), '5.5.0', '<')) { + $this->assertContains('@' . __FILE__ . ';filename=PostFileTest.php;type=text/x-', $file->getCurlValue()); + } else { + $c = $file->getCurlValue(); + $this->assertEquals(__FILE__, $c->getFilename()); + $this->assertEquals('PostFileTest.php', $c->getPostFilename()); + $this->assertContains('text/x-', $c->getMimeType()); + } + } + + public function testReturnsCurlValueStringAndPostname() + { + $file = new PostFile('foo', __FILE__, null, 'NewPostFileTest.php'); + if (version_compare(phpversion(), '5.5.0', '<')) { + $this->assertContains('@' . __FILE__ . ';filename=NewPostFileTest.php;type=text/x-', $file->getCurlValue()); + } else { + $c = $file->getCurlValue(); + $this->assertEquals(__FILE__, $c->getFilename()); + $this->assertEquals('NewPostFileTest.php', $c->getPostFilename()); + $this->assertContains('text/x-', $c->getMimeType()); + } + } + + public function testContentDispositionFilePathIsStripped() + { + $this->getServer()->flush(); + $client = new Client($this->getServer()->getUrl()); + $this->getServer()->enqueue("HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n"); + $request = $client->post()->addPostFile('file', __FILE__); + $request->send(); + $requests = $this->getServer()->getReceivedRequests(false); + $this->assertContains('POST / HTTP/1.1', $requests[0]); + $this->assertContains('Content-Disposition: form-data; name="file"; filename="PostFileTest.php"', $requests[0]); + } +} diff --git a/vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/Message/RequestFactoryTest.php b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/Message/RequestFactoryTest.php new file mode 100644 index 0000000..80b8d54 --- /dev/null +++ b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/Message/RequestFactoryTest.php @@ -0,0 +1,616 @@ +assertSame($factory, RequestFactory::getInstance()); + } + + public function testCreatesNewGetRequests() + { + $request = RequestFactory::getInstance()->create('GET', 'http://www.google.com/'); + $this->assertInstanceOf('Guzzle\\Http\\Message\\MessageInterface', $request); + $this->assertInstanceOf('Guzzle\\Http\\Message\\RequestInterface', $request); + $this->assertInstanceOf('Guzzle\\Http\\Message\\Request', $request); + $this->assertEquals('GET', $request->getMethod()); + $this->assertEquals('http', $request->getScheme()); + $this->assertEquals('http://www.google.com/', $request->getUrl()); + $this->assertEquals('www.google.com', $request->getHost()); + $this->assertEquals('/', $request->getPath()); + $this->assertEquals('/', $request->getResource()); + + // Create a GET request with a custom receiving body + $this->getServer()->enqueue("HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n"); + $b = EntityBody::factory(); + $request = RequestFactory::getInstance()->create('GET', $this->getServer()->getUrl(), null, $b); + $request->setClient(new Client()); + $response = $request->send(); + $this->assertSame($b, $response->getBody()); + } + + public function testCreatesPutRequests() + { + // Test using a string + $request = RequestFactory::getInstance()->create('PUT', 'http://www.google.com/path?q=1&v=2', null, 'Data'); + $this->assertInstanceOf('Guzzle\\Http\\Message\\EntityEnclosingRequest', $request); + $this->assertEquals('PUT', $request->getMethod()); + $this->assertEquals('http', $request->getScheme()); + $this->assertEquals('http://www.google.com/path?q=1&v=2', $request->getUrl()); + $this->assertEquals('www.google.com', $request->getHost()); + $this->assertEquals('/path', $request->getPath()); + $this->assertEquals('/path?q=1&v=2', $request->getResource()); + $this->assertInstanceOf('Guzzle\\Http\\EntityBody', $request->getBody()); + $this->assertEquals('Data', (string) $request->getBody()); + unset($request); + + // Test using an EntityBody + $request = RequestFactory::getInstance()->create('PUT', 'http://www.google.com/path?q=1&v=2', null, EntityBody::factory('Data')); + $this->assertInstanceOf('Guzzle\\Http\\Message\\EntityEnclosingRequest', $request); + $this->assertEquals('Data', (string) $request->getBody()); + + // Test using a resource + $resource = fopen('php://temp', 'w+'); + fwrite($resource, 'Data'); + $request = RequestFactory::getInstance()->create('PUT', 'http://www.google.com/path?q=1&v=2', null, $resource); + $this->assertInstanceOf('Guzzle\\Http\\Message\\EntityEnclosingRequest', $request); + $this->assertEquals('Data', (string) $request->getBody()); + + // Test using an object that can be cast as a string + $request = RequestFactory::getInstance()->create('PUT', 'http://www.google.com/path?q=1&v=2', null, Url::factory('http://www.example.com/')); + $this->assertInstanceOf('Guzzle\\Http\\Message\\EntityEnclosingRequest', $request); + $this->assertEquals('http://www.example.com/', (string) $request->getBody()); + } + + public function testCreatesHeadAndDeleteRequests() + { + $request = RequestFactory::getInstance()->create('DELETE', 'http://www.test.com/'); + $this->assertEquals('DELETE', $request->getMethod()); + $request = RequestFactory::getInstance()->create('HEAD', 'http://www.test.com/'); + $this->assertEquals('HEAD', $request->getMethod()); + } + + public function testCreatesOptionsRequests() + { + $request = RequestFactory::getInstance()->create('OPTIONS', 'http://www.example.com/'); + $this->assertEquals('OPTIONS', $request->getMethod()); + $this->assertInstanceOf('Guzzle\\Http\\Message\\EntityEnclosingRequest', $request); + } + + public function testCreatesNewPutRequestWithBody() + { + $request = RequestFactory::getInstance()->create('PUT', 'http://www.google.com/path?q=1&v=2', null, 'Data'); + $this->assertEquals('Data', (string) $request->getBody()); + } + + public function testCreatesNewPostRequestWithFields() + { + // Use an array + $request = RequestFactory::getInstance()->create('POST', 'http://www.google.com/path?q=1&v=2', null, array( + 'a' => 'b' + )); + $this->assertEquals(array('a' => 'b'), $request->getPostFields()->getAll()); + unset($request); + + // Use a collection + $request = RequestFactory::getInstance()->create('POST', 'http://www.google.com/path?q=1&v=2', null, new Collection(array( + 'a' => 'b' + ))); + $this->assertEquals(array('a' => 'b'), $request->getPostFields()->getAll()); + + // Use a QueryString + $request = RequestFactory::getInstance()->create('POST', 'http://www.google.com/path?q=1&v=2', null, new QueryString(array( + 'a' => 'b' + ))); + $this->assertEquals(array('a' => 'b'), $request->getPostFields()->getAll()); + + $request = RequestFactory::getInstance()->create('POST', 'http://www.test.com/', null, array( + 'a' => 'b', + 'file' => '@' . __FILE__ + )); + + $this->assertEquals(array( + 'a' => 'b' + ), $request->getPostFields()->getAll()); + + $files = $request->getPostFiles(); + $this->assertInstanceOf('Guzzle\Http\Message\PostFile', $files['file'][0]); + } + + public function testCreatesFromParts() + { + $parts = parse_url('http://michael:123@www.google.com:8080/path?q=1&v=2'); + + $request = RequestFactory::getInstance()->fromParts('PUT', $parts, null, 'Data'); + $this->assertInstanceOf('Guzzle\\Http\\Message\\EntityEnclosingRequest', $request); + $this->assertEquals('PUT', $request->getMethod()); + $this->assertEquals('http', $request->getScheme()); + $this->assertEquals('http://www.google.com:8080/path?q=1&v=2', $request->getUrl()); + $this->assertEquals('www.google.com', $request->getHost()); + $this->assertEquals('www.google.com:8080', $request->getHeader('Host')); + $this->assertEquals('/path', $request->getPath()); + $this->assertEquals('/path?q=1&v=2', $request->getResource()); + $this->assertInstanceOf('Guzzle\\Http\\EntityBody', $request->getBody()); + $this->assertEquals('Data', (string) $request->getBody()); + $this->assertEquals('michael', $request->getUsername()); + $this->assertEquals('123', $request->getPassword()); + $this->assertEquals('8080', $request->getPort()); + $this->assertEquals(array( + 'scheme' => 'http', + 'host' => 'www.google.com', + 'port' => 8080, + 'path' => '/path', + 'query' => 'q=1&v=2', + ), parse_url($request->getUrl())); + } + + public function testCreatesFromMessage() + { + $auth = base64_encode('michael:123'); + $message = "PUT /path?q=1&v=2 HTTP/1.1\r\nHost: www.google.com:8080\r\nContent-Length: 4\r\nAuthorization: Basic {$auth}\r\n\r\nData"; + $request = RequestFactory::getInstance()->fromMessage($message); + $this->assertInstanceOf('Guzzle\\Http\\Message\\EntityEnclosingRequest', $request); + $this->assertEquals('PUT', $request->getMethod()); + $this->assertEquals('http', $request->getScheme()); + $this->assertEquals('http://www.google.com:8080/path?q=1&v=2', $request->getUrl()); + $this->assertEquals('www.google.com', $request->getHost()); + $this->assertEquals('www.google.com:8080', $request->getHeader('Host')); + $this->assertEquals('/path', $request->getPath()); + $this->assertEquals('/path?q=1&v=2', $request->getResource()); + $this->assertInstanceOf('Guzzle\\Http\\EntityBody', $request->getBody()); + $this->assertEquals('Data', (string) $request->getBody()); + $this->assertEquals("Basic {$auth}", (string) $request->getHeader('Authorization')); + $this->assertEquals('8080', $request->getPort()); + + // Test passing a blank message returns false + $this->assertFalse($request = RequestFactory::getInstance()->fromMessage('')); + + // Test passing a url with no port + $message = "PUT /path?q=1&v=2 HTTP/1.1\r\nHost: www.google.com\r\nContent-Length: 4\r\nAuthorization: Basic {$auth}\r\n\r\nData"; + $request = RequestFactory::getInstance()->fromMessage($message); + $this->assertInstanceOf('Guzzle\\Http\\Message\\EntityEnclosingRequest', $request); + $this->assertEquals('PUT', $request->getMethod()); + $this->assertEquals('http', $request->getScheme()); + $this->assertEquals('http://www.google.com/path?q=1&v=2', $request->getUrl()); + $this->assertEquals('www.google.com', $request->getHost()); + $this->assertEquals('/path', $request->getPath()); + $this->assertEquals('/path?q=1&v=2', $request->getResource()); + $this->assertInstanceOf('Guzzle\\Http\\EntityBody', $request->getBody()); + $this->assertEquals('Data', (string) $request->getBody()); + $this->assertEquals("Basic {$auth}", (string) $request->getHeader('Authorization')); + $this->assertEquals(80, $request->getPort()); + } + + public function testCreatesNewTraceRequest() + { + $request = RequestFactory::getInstance()->create('TRACE', 'http://www.google.com/'); + $this->assertFalse($request instanceof \Guzzle\Http\Message\EntityEnclosingRequest); + $this->assertEquals('TRACE', $request->getMethod()); + } + + public function testCreatesProperTransferEncodingRequests() + { + $request = RequestFactory::getInstance()->create('PUT', 'http://www.google.com/', array( + 'Transfer-Encoding' => 'chunked' + ), 'hello'); + $this->assertEquals('chunked', $request->getHeader('Transfer-Encoding')); + $this->assertFalse($request->hasHeader('Content-Length')); + } + + public function testProperlyDealsWithDuplicateHeaders() + { + $parser = new MessageParser(); + + $message = "POST / http/1.1\r\n" + . "DATE:Mon, 09 Sep 2011 23:36:00 GMT\r\n" + . "host:host.foo.com\r\n" + . "ZOO:abc\r\n" + . "ZOO:123\r\n" + . "ZOO:HI\r\n" + . "zoo:456\r\n\r\n"; + + $parts = $parser->parseRequest($message); + $this->assertEquals(array ( + 'DATE' => 'Mon, 09 Sep 2011 23:36:00 GMT', + 'host' => 'host.foo.com', + 'ZOO' => array('abc', '123', 'HI'), + 'zoo' => '456', + ), $parts['headers']); + + $request = RequestFactory::getInstance()->fromMessage($message); + + $this->assertEquals(array( + 'abc', '123', 'HI', '456' + ), $request->getHeader('zoo')->toArray()); + } + + public function testCreatesHttpMessagesWithBodiesAndNormalizesLineEndings() + { + $message = "POST / http/1.1\r\n" + . "Content-Type:application/x-www-form-urlencoded; charset=utf8\r\n" + . "Date:Mon, 09 Sep 2011 23:36:00 GMT\r\n" + . "Host:host.foo.com\r\n\r\n" + . "foo=bar"; + + $request = RequestFactory::getInstance()->fromMessage($message); + $this->assertEquals('application/x-www-form-urlencoded; charset=utf8', (string) $request->getHeader('Content-Type')); + $this->assertEquals('foo=bar', (string) $request->getBody()); + + $message = "POST / http/1.1\n" + . "Content-Type:application/x-www-form-urlencoded; charset=utf8\n" + . "Date:Mon, 09 Sep 2011 23:36:00 GMT\n" + . "Host:host.foo.com\n\n" + . "foo=bar"; + $request = RequestFactory::getInstance()->fromMessage($message); + $this->assertEquals('foo=bar', (string) $request->getBody()); + + $message = "PUT / HTTP/1.1\r\nContent-Length: 0\r\n\r\n"; + $request = RequestFactory::getInstance()->fromMessage($message); + $this->assertTrue($request->hasHeader('Content-Length')); + $this->assertEquals(0, (string) $request->getHeader('Content-Length')); + } + + public function testBugPathIncorrectlyHandled() + { + $message = "POST /foo\r\n\r\nBODY"; + $request = RequestFactory::getInstance()->fromMessage($message); + $this->assertSame('POST', $request->getMethod()); + $this->assertSame('/foo', $request->getPath()); + $this->assertSame('BODY', (string) $request->getBody()); + } + + public function testHandlesChunkedTransferEncoding() + { + $request = RequestFactory::getInstance()->create('PUT', 'http://www.foo.com/', array( + 'Transfer-Encoding' => 'chunked' + ), 'Test'); + $this->assertFalse($request->hasHeader('Content-Length')); + $this->assertEquals('chunked', $request->getHeader('Transfer-Encoding')); + + $request = RequestFactory::getInstance()->create('POST', 'http://www.foo.com/', array( + 'transfer-encoding' => 'chunked' + ), array( + 'foo' => 'bar' + )); + + $this->assertFalse($request->hasHeader('Content-Length')); + $this->assertEquals('chunked', $request->getHeader('Transfer-Encoding')); + } + + public function testClonesRequestsWithMethodWithoutClient() + { + $f = RequestFactory::getInstance(); + $request = $f->create('GET', 'http://www.test.com', array('X-Foo' => 'Bar')); + $request->getParams()->replace(array('test' => '123')); + $request->getCurlOptions()->set('foo', 'bar'); + $cloned = $f->cloneRequestWithMethod($request, 'PUT'); + $this->assertEquals('PUT', $cloned->getMethod()); + $this->assertEquals('Bar', (string) $cloned->getHeader('X-Foo')); + $this->assertEquals('http://www.test.com', $cloned->getUrl()); + // Ensure params are cloned and cleaned up + $this->assertEquals(1, count($cloned->getParams()->getAll())); + $this->assertEquals('123', $cloned->getParams()->get('test')); + // Ensure curl options are cloned + $this->assertEquals('bar', $cloned->getCurlOptions()->get('foo')); + // Ensure event dispatcher is cloned + $this->assertNotSame($request->getEventDispatcher(), $cloned->getEventDispatcher()); + } + + public function testClonesRequestsWithMethodWithClient() + { + $f = RequestFactory::getInstance(); + $client = new Client(); + $request = $client->put('http://www.test.com', array('Content-Length' => 4), 'test'); + $cloned = $f->cloneRequestWithMethod($request, 'GET'); + $this->assertEquals('GET', $cloned->getMethod()); + $this->assertNull($cloned->getHeader('Content-Length')); + $this->assertEquals('http://www.test.com', $cloned->getUrl()); + $this->assertSame($request->getClient(), $cloned->getClient()); + } + + public function testClonesRequestsWithMethodWithClientWithEntityEnclosingChange() + { + $f = RequestFactory::getInstance(); + $client = new Client(); + $request = $client->put('http://www.test.com', array('Content-Length' => 4), 'test'); + $cloned = $f->cloneRequestWithMethod($request, 'POST'); + $this->assertEquals('POST', $cloned->getMethod()); + $this->assertEquals('test', (string) $cloned->getBody()); + } + + public function testCanDisableRedirects() + { + $this->getServer()->enqueue(array( + "HTTP/1.1 307\r\nLocation: " . $this->getServer()->getUrl() . "\r\nContent-Length: 0\r\n\r\n" + )); + $client = new Client($this->getServer()->getUrl()); + $response = $client->get('/', array(), array('allow_redirects' => false))->send(); + $this->assertEquals(307, $response->getStatusCode()); + } + + public function testCanAddCookies() + { + $client = new Client($this->getServer()->getUrl()); + $request = $client->get('/', array(), array('cookies' => array('Foo' => 'Bar'))); + $this->assertEquals('Bar', $request->getCookie('Foo')); + } + + public function testCanAddQueryString() + { + $request = RequestFactory::getInstance()->create('GET', 'http://foo.com', array(), null, array( + 'query' => array('Foo' => 'Bar') + )); + $this->assertEquals('Bar', $request->getQuery()->get('Foo')); + } + + public function testCanSetDefaultQueryString() + { + $request = new Request('GET', 'http://www.foo.com?test=abc'); + RequestFactory::getInstance()->applyOptions($request, array( + 'query' => array('test' => '123', 'other' => 't123') + ), RequestFactory::OPTIONS_AS_DEFAULTS); + $this->assertEquals('abc', $request->getQuery()->get('test')); + $this->assertEquals('t123', $request->getQuery()->get('other')); + } + + public function testCanAddBasicAuth() + { + $request = RequestFactory::getInstance()->create('GET', 'http://foo.com', array(), null, array( + 'auth' => array('michael', 'test') + )); + $this->assertEquals('michael', $request->getUsername()); + $this->assertEquals('test', $request->getPassword()); + } + + public function testCanAddDigestAuth() + { + $request = RequestFactory::getInstance()->create('GET', 'http://foo.com', array(), null, array( + 'auth' => array('michael', 'test', 'digest') + )); + $this->assertEquals(CURLAUTH_DIGEST, $request->getCurlOptions()->get(CURLOPT_HTTPAUTH)); + $this->assertEquals('michael', $request->getUsername()); + $this->assertEquals('test', $request->getPassword()); + } + + public function testCanAddEvents() + { + $foo = null; + $client = new Client(); + $client->addSubscriber(new MockPlugin(array(new Response(200)))); + $request = $client->get($this->getServer()->getUrl(), array(), array( + 'events' => array( + 'request.before_send' => function () use (&$foo) { $foo = true; } + ) + )); + $request->send(); + $this->assertTrue($foo); + } + + public function testCanAddEventsWithPriority() + { + $foo = null; + $client = new Client(); + $client->addSubscriber(new MockPlugin(array(new Response(200)))); + $request = $client->get($this->getServer()->getUrl(), array(), array( + 'events' => array( + 'request.before_send' => array(function () use (&$foo) { $foo = true; }, 100) + ) + )); + $request->send(); + $this->assertTrue($foo); + } + + public function testCanAddPlugins() + { + $mock = new MockPlugin(array( + new Response(200), + new Response(200) + )); + $client = new Client(); + $client->addSubscriber($mock); + $request = $client->get('/', array(), array( + 'plugins' => array($mock) + )); + $request->send(); + } + + public function testCanDisableExceptions() + { + $client = new Client(); + $request = $client->get('/', array(), array( + 'plugins' => array(new MockPlugin(array(new Response(500)))), + 'exceptions' => false + )); + $this->assertEquals(500, $request->send()->getStatusCode()); + } + + public function testCanDisableExceptionsWithErrorListener() + { + $client = new Client(); + $client->getEventDispatcher()->addListener('request.error', function () {}); + $request = $client->get('/', array(), array( + 'plugins' => array(new MockPlugin(array(new Response(500)))), + 'exceptions' => false + )); + $this->assertEquals(500, $request->send()->getStatusCode()); + } + + public function testCanChangeSaveToLocation() + { + $r = EntityBody::factory(); + $client = new Client(); + $request = $client->get('/', array(), array( + 'plugins' => array(new MockPlugin(array(new Response(200, array(), 'testing')))), + 'save_to' => $r + )); + $request->send(); + $this->assertEquals('testing', (string) $r); + } + + public function testCanSetProxy() + { + $client = new Client(); + $request = $client->get('/', array(), array('proxy' => '192.168.16.121')); + $this->assertEquals('192.168.16.121', $request->getCurlOptions()->get(CURLOPT_PROXY)); + } + + public function testCanSetHeadersOption() + { + $client = new Client(); + $request = $client->get('/', array(), array('headers' => array('Foo' => 'Bar'))); + $this->assertEquals('Bar', (string) $request->getHeader('Foo')); + } + + public function testCanSetDefaultHeadersOptions() + { + $request = new Request('GET', 'http://www.foo.com', array('Foo' => 'Bar')); + RequestFactory::getInstance()->applyOptions($request, array( + 'headers' => array('Foo' => 'Baz', 'Bam' => 't123') + ), RequestFactory::OPTIONS_AS_DEFAULTS); + $this->assertEquals('Bar', (string) $request->getHeader('Foo')); + $this->assertEquals('t123', (string) $request->getHeader('Bam')); + } + + public function testCanSetBodyOption() + { + $client = new Client(); + $request = $client->put('/', array(), null, array('body' => 'test')); + $this->assertEquals('test', (string) $request->getBody()); + } + + /** + * @expectedException \InvalidArgumentException + */ + public function testValidatesBodyOption() + { + $client = new Client(); + $client->get('/', array(), array('body' => 'test')); + } + + public function testCanSetTimeoutOption() + { + $client = new Client(); + $request = $client->get('/', array(), array('timeout' => 1.5)); + $this->assertEquals(1500, $request->getCurlOptions()->get(CURLOPT_TIMEOUT_MS)); + } + + public function testCanSetConnectTimeoutOption() + { + $client = new Client(); + $request = $client->get('/', array(), array('connect_timeout' => 1.5)); + $this->assertEquals(1500, $request->getCurlOptions()->get(CURLOPT_CONNECTTIMEOUT_MS)); + } + + public function testCanSetDebug() + { + $client = new Client(); + $request = $client->get('/', array(), array('debug' => true)); + $this->assertTrue($request->getCurlOptions()->get(CURLOPT_VERBOSE)); + } + + public function testCanSetVerifyToOff() + { + $client = new Client(); + $request = $client->get('/', array(), array('verify' => false)); + $this->assertNull($request->getCurlOptions()->get(CURLOPT_CAINFO)); + $this->assertSame(0, $request->getCurlOptions()->get(CURLOPT_SSL_VERIFYHOST)); + $this->assertFalse($request->getCurlOptions()->get(CURLOPT_SSL_VERIFYPEER)); + } + + public function testCanSetVerifyToOn() + { + $client = new Client(); + $request = $client->get('/', array(), array('verify' => true)); + $this->assertNotNull($request->getCurlOptions()->get(CURLOPT_CAINFO)); + $this->assertSame(2, $request->getCurlOptions()->get(CURLOPT_SSL_VERIFYHOST)); + $this->assertTrue($request->getCurlOptions()->get(CURLOPT_SSL_VERIFYPEER)); + } + + public function testCanSetVerifyToPath() + { + $client = new Client(); + $request = $client->get('/', array(), array('verify' => '/foo.pem')); + $this->assertEquals('/foo.pem', $request->getCurlOptions()->get(CURLOPT_CAINFO)); + $this->assertSame(2, $request->getCurlOptions()->get(CURLOPT_SSL_VERIFYHOST)); + $this->assertTrue($request->getCurlOptions()->get(CURLOPT_SSL_VERIFYPEER)); + } + + public function inputValidation() + { + return array_map(function ($option) { return array($option); }, array( + 'headers', 'query', 'cookies', 'auth', 'events', 'plugins', 'params' + )); + } + + /** + * @dataProvider inputValidation + * @expectedException \Guzzle\Common\Exception\InvalidArgumentException + */ + public function testValidatesInput($option) + { + $client = new Client(); + $client->get('/', array(), array($option => 'foo')); + } + + public function testCanAddRequestParams() + { + $client = new Client(); + $request = $client->put('/', array(), null, array('params' => array('foo' => 'test'))); + $this->assertEquals('test', $request->getParams()->get('foo')); + } + + public function testCanAddSslKey() + { + $client = new Client(); + $request = $client->get('/', array(), array('ssl_key' => '/foo.pem')); + $this->assertEquals('/foo.pem', $request->getCurlOptions()->get(CURLOPT_SSLKEY)); + } + + public function testCanAddSslKeyPassword() + { + $client = new Client(); + $request = $client->get('/', array(), array('ssl_key' => array('/foo.pem', 'bar'))); + $this->assertEquals('/foo.pem', $request->getCurlOptions()->get(CURLOPT_SSLKEY)); + $this->assertEquals('bar', $request->getCurlOptions()->get(CURLOPT_SSLKEYPASSWD)); + } + + public function testCanAddSslCert() + { + $client = new Client(); + $request = $client->get('/', array(), array('cert' => '/foo.pem')); + $this->assertEquals('/foo.pem', $request->getCurlOptions()->get(CURLOPT_SSLCERT)); + } + + public function testCanAddSslCertPassword() + { + $client = new Client(); + $request = $client->get('/', array(), array('cert' => array('/foo.pem', 'bar'))); + $this->assertEquals('/foo.pem', $request->getCurlOptions()->get(CURLOPT_SSLCERT)); + $this->assertEquals('bar', $request->getCurlOptions()->get(CURLOPT_SSLCERTPASSWD)); + } + + public function testCreatesBodyWithoutZeroString() + { + $request = RequestFactory::getInstance()->create('PUT', 'http://test.com', array(), '0'); + $this->assertSame('0', (string) $request->getBody()); + } +} diff --git a/vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/Message/RequestTest.php b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/Message/RequestTest.php new file mode 100644 index 0000000..5bf6248 --- /dev/null +++ b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/Message/RequestTest.php @@ -0,0 +1,639 @@ +client = new Client($this->getServer()->getUrl()); + $this->request = $this->client->get(); + } + + public function tearDown() + { + unset($this->request); + unset($this->client); + } + + public function testConstructorBuildsRequestWithArrayHeaders() + { + // Test passing an array of headers + $request = new Request('GET', 'http://www.guzzle-project.com/', array( + 'foo' => 'bar' + )); + + $this->assertEquals('GET', $request->getMethod()); + $this->assertEquals('http://www.guzzle-project.com/', $request->getUrl()); + $this->assertEquals('bar', $request->getHeader('foo')); + } + + public function testDescribesEvents() + { + $this->assertInternalType('array', Request::getAllEvents()); + } + + public function testConstructorBuildsRequestWithCollectionHeaders() + { + $request = new Request('GET', 'http://www.guzzle-project.com/', new Collection(array( + 'foo' => 'bar' + ))); + $this->assertEquals('bar', $request->getHeader('foo')); + } + + public function testConstructorBuildsRequestWithNoHeaders() + { + $request = new Request('GET', 'http://www.guzzle-project.com/', null); + $this->assertFalse($request->hasHeader('foo')); + } + + public function testConstructorHandlesNonBasicAuth() + { + $request = new Request('GET', 'http://www.guzzle-project.com/', array( + 'Authorization' => 'Foo bar' + )); + $this->assertNull($request->getUserName()); + $this->assertNull($request->getPassword()); + $this->assertEquals('Foo bar', (string) $request->getHeader('Authorization')); + } + + public function testRequestsCanBeConvertedToRawMessageStrings() + { + $auth = base64_encode('michael:123'); + $message = "PUT /path?q=1&v=2 HTTP/1.1\r\n" + . "Host: www.google.com\r\n" + . "Authorization: Basic {$auth}\r\n" + . "Content-Length: 4\r\n\r\nData"; + + $request = RequestFactory::getInstance()->create('PUT', 'http://www.google.com/path?q=1&v=2', array( + 'Authorization' => 'Basic ' . $auth + ), 'Data'); + + $this->assertEquals($message, $request->__toString()); + } + + /** + * Add authorization after the fact and see that it was put in the message + */ + public function testRequestStringsIncludeAuth() + { + $auth = base64_encode('michael:123'); + $this->getServer()->enqueue("HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n"); + $request = RequestFactory::getInstance()->create('PUT', $this->getServer()->getUrl(), null, 'Data') + ->setClient($this->client) + ->setAuth('michael', '123', CURLAUTH_BASIC); + $request->send(); + + $this->assertContains('Authorization: Basic ' . $auth, (string) $request); + } + + public function testGetEventDispatcher() + { + $d = $this->request->getEventDispatcher(); + $this->assertInstanceOf('Symfony\\Component\\EventDispatcher\\EventDispatcherInterface', $d); + $this->assertEquals($d, $this->request->getEventDispatcher()); + } + + public function testRequestsManageClients() + { + $request = new Request('GET', 'http://test.com'); + $this->assertNull($request->getClient()); + $request->setClient($this->client); + $this->assertSame($this->client, $request->getClient()); + } + + /** + * @expectedException \RuntimeException + * @expectedExceptionMessage A client must be set on the request + */ + public function testRequestsRequireClients() + { + $request = new Request('GET', 'http://test.com'); + $request->send(); + } + + public function testSend() + { + $response = new Response(200, array( + 'Content-Length' => 3 + ), 'abc'); + $this->request->setResponse($response, true); + $r = $this->request->send(); + + $this->assertSame($response, $r); + $this->assertInstanceOf('Guzzle\\Http\\Message\\Response', $this->request->getResponse()); + $this->assertSame($r, $this->request->getResponse()); + $this->assertEquals('complete', $this->request->getState()); + } + + public function testGetResponse() + { + $this->assertNull($this->request->getResponse()); + $response = new Response(200, array('Content-Length' => 3), 'abc'); + + $this->request->setResponse($response); + $this->assertEquals($response, $this->request->getResponse()); + + $client = new Client('http://www.google.com'); + $request = $client->get('http://www.google.com/'); + $request->setResponse($response, true); + $request->send(); + $requestResponse = $request->getResponse(); + $this->assertSame($response, $requestResponse); + + // Try again, making sure it's still the same response + $this->assertSame($requestResponse, $request->getResponse()); + + $response = new Response(204); + $request = $client->get(); + $request->setResponse($response, true); + $request->send(); + $requestResponse = $request->getResponse(); + $this->assertSame($response, $requestResponse); + $this->assertInstanceOf('Guzzle\\Http\\EntityBody', $response->getBody()); + } + + public function testRequestThrowsExceptionOnBadResponse() + { + try { + $this->request->setResponse(new Response(404, array('Content-Length' => 3), 'abc'), true); + $this->request->send(); + $this->fail('Expected exception not thrown'); + } catch (BadResponseException $e) { + $this->assertInstanceOf('Guzzle\\Http\\Message\\RequestInterface', $e->getRequest()); + $this->assertInstanceOf('Guzzle\\Http\\Message\\Response', $e->getResponse()); + $this->assertContains('Client error response', $e->getMessage()); + } + } + + public function testManagesQuery() + { + $this->assertInstanceOf('Guzzle\\Http\\QueryString', $this->request->getQuery()); + $this->request->getQuery()->set('test', '123'); + $this->assertEquals('test=123', $this->request->getQuery(true)); + } + + public function testRequestHasMethod() + { + $this->assertEquals('GET', $this->request->getMethod()); + } + + public function testRequestHasScheme() + { + $this->assertEquals('http', $this->request->getScheme()); + $this->assertEquals($this->request, $this->request->setScheme('https')); + $this->assertEquals('https', $this->request->getScheme()); + } + + public function testRequestHasHost() + { + $this->assertEquals('127.0.0.1', $this->request->getHost()); + $this->assertEquals('127.0.0.1:8124', (string) $this->request->getHeader('Host')); + + $this->assertSame($this->request, $this->request->setHost('www2.google.com')); + $this->assertEquals('www2.google.com', $this->request->getHost()); + $this->assertEquals('www2.google.com:8124', (string) $this->request->getHeader('Host')); + + $this->assertSame($this->request, $this->request->setHost('www.test.com:8081')); + $this->assertEquals('www.test.com', $this->request->getHost()); + $this->assertEquals(8081, $this->request->getPort()); + } + + public function testRequestHasProtocol() + { + $this->assertEquals('1.1', $this->request->getProtocolVersion()); + $this->assertEquals($this->request, $this->request->setProtocolVersion('1.1')); + $this->assertEquals('1.1', $this->request->getProtocolVersion()); + $this->assertEquals($this->request, $this->request->setProtocolVersion('1.0')); + $this->assertEquals('1.0', $this->request->getProtocolVersion()); + } + + public function testRequestHasPath() + { + $this->assertEquals('/', $this->request->getPath()); + $this->assertEquals($this->request, $this->request->setPath('/index.html')); + $this->assertEquals('/index.html', $this->request->getPath()); + $this->assertEquals($this->request, $this->request->setPath('index.html')); + $this->assertEquals('/index.html', $this->request->getPath()); + } + + public function testPermitsFalsyComponents() + { + $request = new Request('GET', 'http://0/0?0'); + $this->assertSame('0', $request->getHost()); + $this->assertSame('/0', $request->getPath()); + $this->assertSame('0', $request->getQuery(true)); + + $request = new Request('GET', '0'); + $this->assertEquals('/0', $request->getPath()); + } + + public function testRequestHasPort() + { + $this->assertEquals(8124, $this->request->getPort()); + $this->assertEquals('127.0.0.1:8124', $this->request->getHeader('Host')); + + $this->assertEquals($this->request, $this->request->setPort('8080')); + $this->assertEquals('8080', $this->request->getPort()); + $this->assertEquals('127.0.0.1:8080', $this->request->getHeader('Host')); + + $this->request->setPort(80); + $this->assertEquals('127.0.0.1', $this->request->getHeader('Host')); + } + + public function testRequestHandlesAuthorization() + { + // Uninitialized auth + $this->assertEquals(null, $this->request->getUsername()); + $this->assertEquals(null, $this->request->getPassword()); + + // Set an auth + $this->assertSame($this->request, $this->request->setAuth('michael', '123')); + $this->assertEquals('michael', $this->request->getUsername()); + $this->assertEquals('123', $this->request->getPassword()); + + // Set an auth with blank password + $this->assertSame($this->request, $this->request->setAuth('michael', '')); + $this->assertEquals('michael', $this->request->getUsername()); + $this->assertEquals('', $this->request->getPassword()); + + // Remove the auth + $this->request->setAuth(false); + $this->assertEquals(null, $this->request->getUsername()); + $this->assertEquals(null, $this->request->getPassword()); + + // Make sure that the cURL based auth works too + $request = new Request('GET', $this->getServer()->getUrl()); + $request->setAuth('michael', 'password', CURLAUTH_DIGEST); + $this->assertEquals('michael:password', $request->getCurlOptions()->get(CURLOPT_USERPWD)); + $this->assertEquals(CURLAUTH_DIGEST, $request->getCurlOptions()->get(CURLOPT_HTTPAUTH)); + } + + /** + * @expectedException \Guzzle\Common\Exception\InvalidArgumentException + */ + public function testValidatesAuth() + { + $this->request->setAuth('foo', 'bar', 'bam'); + } + + public function testGetResourceUri() + { + $this->assertEquals('/', $this->request->getResource()); + $this->request->setPath('/index.html'); + $this->assertEquals('/index.html', $this->request->getResource()); + $this->request->getQuery()->add('v', '1'); + $this->assertEquals('/index.html?v=1', $this->request->getResource()); + } + + public function testRequestHasMutableUrl() + { + $url = 'http://www.test.com:8081/path?q=123#fragment'; + $u = Url::factory($url); + $this->assertSame($this->request, $this->request->setUrl($url)); + $this->assertEquals($url, $this->request->getUrl()); + + $this->assertSame($this->request, $this->request->setUrl($u)); + $this->assertEquals($url, $this->request->getUrl()); + } + + public function testRequestHasState() + { + $this->assertEquals(RequestInterface::STATE_NEW, $this->request->getState()); + $this->request->setState(RequestInterface::STATE_TRANSFER); + $this->assertEquals(RequestInterface::STATE_TRANSFER, $this->request->getState()); + } + + public function testSetManualResponse() + { + $response = new Response(200, array( + 'Date' => 'Sat, 16 Oct 2010 17:27:14 GMT', + 'Expires' => '-1', + 'Cache-Control' => 'private, max-age=0', + 'Content-Type' => 'text/html; charset=ISO-8859-1', + ), 'response body'); + + $this->assertSame($this->request, $this->request->setResponse($response), '-> setResponse() must use a fluent interface'); + $this->assertEquals('complete', $this->request->getState(), '-> setResponse() must change the state of the request to complete'); + $this->assertSame($response, $this->request->getResponse(), '-> setResponse() must set the exact same response that was passed in to it'); + } + + public function testRequestCanHaveManuallySetResponseBody() + { + $file = __DIR__ . '/../../TestData/temp.out'; + if (file_exists($file)) { + unlink($file); + } + + $this->getServer()->enqueue("HTTP/1.1 200 OK\r\nContent-Length: 4\r\n\r\ndata"); + $request = RequestFactory::getInstance()->create('GET', $this->getServer()->getUrl()); + $request->setClient($this->client); + $entityBody = EntityBody::factory(fopen($file, 'w+')); + $request->setResponseBody($entityBody); + $response = $request->send(); + $this->assertSame($entityBody, $response->getBody()); + + $this->assertTrue(file_exists($file)); + $this->assertEquals('data', file_get_contents($file)); + unlink($file); + + $this->assertEquals('data', $response->getBody(true)); + } + + public function testHoldsCookies() + { + $this->assertNull($this->request->getCookie('test')); + + // Set a cookie + $this->assertSame($this->request, $this->request->addCookie('test', 'abc')); + $this->assertEquals('abc', $this->request->getCookie('test')); + + // Multiple cookies by setting the Cookie header + $this->request->setHeader('Cookie', '__utma=1.638370270.1344367610.1374365610.1944450276.2; __utmz=1.1346368610.1.1.utmcsr=(direct)|utmccn=(direct)|utmcmd=(none); hl=de; PHPSESSID=ak93pqashi5uubuoq8fjv60897'); + $this->assertEquals('1.638370270.1344367610.1374365610.1944450276.2', $this->request->getCookie('__utma')); + $this->assertEquals('1.1346368610.1.1.utmcsr=(direct)|utmccn=(direct)|utmcmd=(none)', $this->request->getCookie('__utmz')); + $this->assertEquals('de', $this->request->getCookie('hl')); + $this->assertEquals('ak93pqashi5uubuoq8fjv60897', $this->request->getCookie('PHPSESSID')); + + // Unset the cookies by setting the Cookie header to null + $this->request->setHeader('Cookie', null); + $this->assertNull($this->request->getCookie('test')); + $this->request->removeHeader('Cookie'); + + // Set and remove a cookie + $this->assertSame($this->request, $this->request->addCookie('test', 'abc')); + $this->assertEquals('abc', $this->request->getCookie('test')); + $this->assertSame($this->request, $this->request->removeCookie('test')); + $this->assertNull($this->request->getCookie('test')); + + // Remove the cookie header + $this->assertSame($this->request, $this->request->addCookie('test', 'abc')); + $this->request->removeHeader('Cookie'); + $this->assertEquals('', (string) $this->request->getHeader('Cookie')); + + // Remove a cookie value + $this->request->addCookie('foo', 'bar')->addCookie('baz', 'boo'); + $this->request->removeCookie('foo'); + $this->assertEquals(array( + 'baz' => 'boo' + ), $this->request->getCookies()); + + $this->request->addCookie('foo', 'bar'); + $this->assertEquals('baz=boo; foo=bar', (string) $this->request->getHeader('Cookie')); + } + + /** + * @expectedException \Guzzle\Http\Exception\RequestException + * @expectedExceptionMessage Error completing request + */ + public function testRequestThrowsExceptionWhenSetToCompleteWithNoResponse() + { + $this->request->setState(RequestInterface::STATE_COMPLETE); + } + + public function testClonedRequestsUseNewInternalState() + { + $p = new AsyncPlugin(); + $this->request->getEventDispatcher()->addSubscriber($p); + $h = $this->request->getHeader('Host'); + + $r = clone $this->request; + $this->assertEquals(RequestInterface::STATE_NEW, $r->getState()); + $this->assertNotSame($r->getQuery(), $this->request->getQuery()); + $this->assertNotSame($r->getCurlOptions(), $this->request->getCurlOptions()); + $this->assertNotSame($r->getEventDispatcher(), $this->request->getEventDispatcher()); + $this->assertEquals($r->getHeaders(), $this->request->getHeaders()); + $this->assertNotSame($h, $r->getHeader('Host')); + $this->assertNotSame($r->getParams(), $this->request->getParams()); + $this->assertTrue($this->request->getEventDispatcher()->hasListeners('request.sent')); + } + + public function testRecognizesBasicAuthCredentialsInUrls() + { + $this->request->setUrl('http://michael:test@test.com/'); + $this->assertEquals('michael', $this->request->getUsername()); + $this->assertEquals('test', $this->request->getPassword()); + } + + public function testRequestCanBeSentUsingCurl() + { + $this->getServer()->flush(); + $this->getServer()->enqueue(array( + "HTTP/1.1 200 OK\r\nContent-Length: 4\r\nExpires: Thu, 01 Dec 1994 16:00:00 GMT\r\nConnection: close\r\n\r\ndata", + "HTTP/1.1 200 OK\r\nContent-Length: 4\r\nExpires: Thu, 01 Dec 1994 16:00:00 GMT\r\nConnection: close\r\n\r\ndata", + "HTTP/1.1 404 Not Found\r\nContent-Encoding: application/xml\r\nContent-Length: 48\r\n\r\nFile not found" + )); + + $request = RequestFactory::getInstance()->create('GET', $this->getServer()->getUrl()); + $request->setClient($this->client); + $response = $request->send(); + + $this->assertEquals('data', $response->getBody(true)); + $this->assertEquals(200, (int) $response->getStatusCode()); + $this->assertEquals('OK', $response->getReasonPhrase()); + $this->assertEquals(4, $response->getContentLength()); + $this->assertEquals('Thu, 01 Dec 1994 16:00:00 GMT', $response->getExpires()); + + // Test that the same handle can be sent twice without setting state to new + $response2 = $request->send(); + $this->assertNotSame($response, $response2); + + try { + $request = RequestFactory::getInstance()->create('GET', $this->getServer()->getUrl() . 'index.html'); + $request->setClient($this->client); + $response = $request->send(); + $this->fail('Request did not receive a 404 response'); + } catch (BadResponseException $e) { + } + + $requests = $this->getServer()->getReceivedRequests(true); + $messages = $this->getServer()->getReceivedRequests(false); + $port = $this->getServer()->getPort(); + + $userAgent = $this->client->getDefaultUserAgent(); + + $this->assertEquals('127.0.0.1:' . $port, $requests[0]->getHeader('Host')); + $this->assertEquals('127.0.0.1:' . $port, $requests[1]->getHeader('Host')); + $this->assertEquals('127.0.0.1:' . $port, $requests[2]->getHeader('Host')); + + $this->assertEquals('/', $requests[0]->getPath()); + $this->assertEquals('/', $requests[1]->getPath()); + $this->assertEquals('/index.html', $requests[2]->getPath()); + + $parts = explode("\r\n", $messages[0]); + $this->assertEquals('GET / HTTP/1.1', $parts[0]); + + $parts = explode("\r\n", $messages[1]); + $this->assertEquals('GET / HTTP/1.1', $parts[0]); + + $parts = explode("\r\n", $messages[2]); + $this->assertEquals('GET /index.html HTTP/1.1', $parts[0]); + } + + public function testThrowsExceptionsWhenUnsuccessfulResponseIsReceivedByDefault() + { + $this->getServer()->flush(); + $this->getServer()->enqueue("HTTP/1.1 404 Not found\r\nContent-Length: 0\r\n\r\n"); + + try { + $request = $this->client->get('/index.html'); + $response = $request->send(); + $this->fail('Request did not receive a 404 response'); + } catch (BadResponseException $e) { + $this->assertContains('Client error response', $e->getMessage()); + $this->assertContains('[status code] 404', $e->getMessage()); + $this->assertContains('[reason phrase] Not found', $e->getMessage()); + } + } + + public function testCanShortCircuitErrorHandling() + { + $request = $this->request; + $response = new Response(404); + $request->setResponse($response, true); + $out = ''; + $that = $this; + $request->getEventDispatcher()->addListener('request.error', function($event) use (&$out, $that) { + $out .= $event['request'] . "\n" . $event['response'] . "\n"; + $event->stopPropagation(); + }); + $request->send(); + $this->assertContains((string) $request, $out); + $this->assertContains((string) $request->getResponse(), $out); + $this->assertSame($response, $request->getResponse()); + } + + public function testCanOverrideUnsuccessfulResponses() + { + $this->getServer()->flush(); + $this->getServer()->enqueue(array( + "HTTP/1.1 404 NOT FOUND\r\n" . + "Content-Length: 0\r\n" . + "\r\n", + "HTTP/1.1 200 OK\r\n" . + "Content-Length: 0\r\n" . + "\r\n" + )); + + $newResponse = null; + + $request = $this->request; + $request->getEventDispatcher()->addListener('request.error', function($event) use (&$newResponse) { + if ($event['response']->getStatusCode() == 404) { + $newRequest = clone $event['request']; + $newResponse = $newRequest->send(); + // Override the original response and bypass additional response processing + $event['response'] = $newResponse; + // Call $event['request']->setResponse($newResponse); to re-apply events + $event->stopPropagation(); + } + }); + + $request->send(); + + $this->assertEquals(200, $request->getResponse()->getStatusCode()); + $this->assertSame($newResponse, $request->getResponse()); + $this->assertEquals(2, count($this->getServer()->getReceivedRequests())); + } + + public function testCanRetrieveUrlObject() + { + $request = new Request('GET', 'http://www.example.com/foo?abc=d'); + $this->assertInstanceOf('Guzzle\Http\Url', $request->getUrl(true)); + $this->assertEquals('http://www.example.com/foo?abc=d', $request->getUrl()); + $this->assertEquals('http://www.example.com/foo?abc=d', (string) $request->getUrl(true)); + } + + public function testUnresolvedRedirectsReturnResponse() + { + $this->getServer()->flush(); + $this->getServer()->enqueue(array( + "HTTP/1.1 303 SEE OTHER\r\nContent-Length: 0\r\n\r\n", + "HTTP/1.1 301 Foo\r\nLocation: /foo\r\nContent-Length: 0\r\n\r\n" + )); + $request = $this->request; + $this->assertEquals(303, $request->send()->getStatusCode()); + $request->getParams()->set(RedirectPlugin::DISABLE, true); + $this->assertEquals(301, $request->send()->getStatusCode()); + } + + public function testCanSendCustomRequests() + { + $this->getServer()->flush(); + $this->getServer()->enqueue("HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n"); + $request = $this->client->createRequest('PROPFIND', $this->getServer()->getUrl(), array( + 'Content-Type' => 'text/plain' + ), 'foo'); + $response = $request->send(); + $requests = $this->getServer()->getReceivedRequests(true); + $this->assertEquals('PROPFIND', $requests[0]->getMethod()); + $this->assertEquals(3, (string) $requests[0]->getHeader('Content-Length')); + $this->assertEquals('foo', (string) $requests[0]->getBody()); + } + + /** + * @expectedException \PHPUnit_Framework_Error_Warning + */ + public function testEnsuresFileCanBeCreated() + { + $this->getServer()->flush(); + $this->getServer()->enqueue("HTTP/1.1 200 OK\r\nContent-Length: 4\r\n\r\ntest"); + $this->client->get('/')->setResponseBody('/wefwefefefefwewefwe/wefwefwefefwe/wefwefewfw.txt')->send(); + } + + public function testAllowsFilenameForDownloadingContent() + { + $this->getServer()->flush(); + $this->getServer()->enqueue("HTTP/1.1 200 OK\r\nContent-Length: 4\r\n\r\ntest"); + $name = sys_get_temp_dir() . '/foo.txt'; + $this->client->get('/')->setResponseBody($name)->send(); + $this->assertEquals('test', file_get_contents($name)); + unlink($name); + } + + public function testUsesCustomResponseBodyWhenItIsCustom() + { + $en = EntityBody::factory(); + $request = $this->client->get(); + $request->setResponseBody($en); + $request->setResponse(new Response(200, array(), 'foo')); + $this->assertEquals('foo', (string) $en); + } + + public function testCanChangePortThroughScheme() + { + $request = new Request('GET', 'http://foo.com'); + $request->setScheme('https'); + $this->assertEquals('https://foo.com', (string) $request->getUrl()); + $this->assertEquals('foo.com', $request->getHost()); + $request->setScheme('http'); + $this->assertEquals('http://foo.com', (string) $request->getUrl()); + $this->assertEquals('foo.com', $request->getHost()); + $request->setPort(null); + $this->assertEquals('http://foo.com', (string) $request->getUrl()); + $this->assertEquals('foo.com', $request->getHost()); + } +} diff --git a/vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/Message/ResponseTest.php b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/Message/ResponseTest.php new file mode 100644 index 0000000..08b4df8 --- /dev/null +++ b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/Message/ResponseTest.php @@ -0,0 +1,677 @@ +response = new Response(200, new Collection(array( + 'Accept-Ranges' => 'bytes', + 'Age' => '12', + 'Allow' => 'GET, HEAD', + 'Cache-Control' => 'no-cache', + 'Content-Encoding' => 'gzip', + 'Content-Language' => 'da', + 'Content-Length' => '348', + 'Content-Location' => '/index.htm', + 'Content-Disposition' => 'attachment; filename=fname.ext', + 'Content-MD5' => 'Q2hlY2sgSW50ZWdyaXR5IQ==', + 'Content-Range' => 'bytes 21010-47021/47022', + 'Content-Type' => 'text/html; charset=utf-8', + 'Date' => 'Tue, 15 Nov 1994 08:12:31 GMT', + 'ETag' => '737060cd8c284d8af7ad3082f209582d', + 'Expires' => 'Thu, 01 Dec 1994 16:00:00 GMT', + 'Last-Modified' => 'Tue, 15 Nov 1994 12:45:26 GMT', + 'Location' => 'http://www.w3.org/pub/WWW/People.html', + 'Pragma' => 'no-cache', + 'Proxy-Authenticate' => 'Basic', + 'Retry-After' => '120', + 'Server' => 'Apache/1.3.27 (Unix) (Red-Hat/Linux)', + 'Set-Cookie' => 'UserID=JohnDoe; Max-Age=3600; Version=1', + 'Trailer' => 'Max-Forwards', + 'Transfer-Encoding' => 'chunked', + 'Vary' => '*', + 'Via' => '1.0 fred, 1.1 nowhere.com (Apache/1.1)', + 'Warning' => '199 Miscellaneous warning', + 'WWW-Authenticate' => 'Basic' + )), 'body'); + } + + public function tearDown() + { + unset($this->response); + } + + public function testConstructor() + { + $params = new Collection(); + $body = EntityBody::factory(''); + $response = new Response(200, $params, $body); + $this->assertEquals(200, $response->getStatusCode()); + $this->assertEquals($body, $response->getBody()); + $this->assertEquals('OK', $response->getReasonPhrase()); + $this->assertEquals("HTTP/1.1 200 OK\r\n\r\n", $response->getRawHeaders()); + + // Make sure Content-Length is set automatically + $response = new Response(200, $params); + $this->assertEquals("HTTP/1.1 200 OK\r\n\r\n", $response->getRawHeaders()); + + // Pass bodies to the response + $response = new Response(200, null, 'data'); + $this->assertInstanceOf('Guzzle\\Http\\EntityBody', $response->getBody()); + $response = new Response(200, null, EntityBody::factory('data')); + $this->assertInstanceOf('Guzzle\\Http\\EntityBody', $response->getBody()); + $this->assertEquals('data', $response->getBody(true)); + $response = new Response(200, null, '0'); + $this->assertSame('0', $response->getBody(true), 'getBody(true) should return "0" if response body is "0".'); + + // Make sure the proper exception is thrown + try { + //$response = new Response(200, null, array('foo' => 'bar')); + //$this->fail('Response did not throw exception when passing invalid body'); + } catch (HttpException $e) { + } + + // Ensure custom codes can be set + $response = new Response(2); + $this->assertEquals(2, $response->getStatusCode()); + $this->assertEquals('', $response->getReasonPhrase()); + + // Make sure the proper exception is thrown when sending invalid headers + try { + $response = new Response(200, 'adidas'); + $this->fail('Response did not throw exception when passing invalid $headers'); + } catch (BadResponseException $e) { + } + } + + public function test__toString() + { + $response = new Response(200); + $this->assertEquals("HTTP/1.1 200 OK\r\n\r\n", (string) $response); + + // Add another header + $response = new Response(200, array( + 'X-Test' => 'Guzzle' + )); + $this->assertEquals("HTTP/1.1 200 OK\r\nX-Test: Guzzle\r\n\r\n", (string) $response); + + $response = new Response(200, array( + 'Content-Length' => 4 + ), 'test'); + $this->assertEquals("HTTP/1.1 200 OK\r\nContent-Length: 4\r\n\r\ntest", (string) $response); + } + + public function testFactory() + { + $response = Response::fromMessage("HTTP/1.1 200 OK\r\nContent-Length: 4\r\n\r\ntest"); + $this->assertEquals(200, $response->getStatusCode()); + $this->assertEquals('OK', $response->getReasonPhrase()); + $this->assertEquals(4, (string) $response->getContentLength()); + $this->assertEquals('test', $response->getBody(true)); + + // Make sure that automatic Content-Length works + $response = Response::fromMessage("HTTP/1.1 200 OK\r\nContent-Length: 4\r\n\r\ntest"); + $this->assertEquals(4, (string) $response->getContentLength()); + $this->assertEquals('test', $response->getBody(true)); + } + + public function testFactoryCanCreateHeadResponses() + { + $response = Response::fromMessage("HTTP/1.1 200 OK\r\nContent-Length: 4\r\n\r\n"); + $this->assertEquals(200, $response->getStatusCode()); + $this->assertEquals('OK', $response->getReasonPhrase()); + $this->assertEquals(4, (string) $response->getContentLength()); + $this->assertEquals('', $response->getBody(true)); + } + + public function testFactoryRequiresMessage() + { + $this->assertFalse(Response::fromMessage('')); + } + + public function testGetBody() + { + $body = EntityBody::factory(''); + $response = new Response(403, new Collection(), $body); + $this->assertEquals($body, $response->getBody()); + $response->setBody('foo'); + $this->assertEquals('foo', $response->getBody(true)); + } + + public function testManagesStatusCode() + { + $response = new Response(403); + $this->assertEquals(403, $response->getStatusCode()); + } + + public function testGetMessage() + { + $response = new Response(200, new Collection(array( + 'Content-Length' => 4 + )), 'body'); + + $this->assertEquals("HTTP/1.1 200 OK\r\nContent-Length: 4\r\n\r\nbody", $response->getMessage()); + } + + public function testGetRawHeaders() + { + $response = new Response(200, new Collection(array( + 'Keep-Alive' => 155, + 'User-Agent' => 'Guzzle', + 'Content-Length' => 4 + )), 'body'); + + $this->assertEquals("HTTP/1.1 200 OK\r\nKeep-Alive: 155\r\nUser-Agent: Guzzle\r\nContent-Length: 4\r\n\r\n", $response->getRawHeaders()); + } + + public function testHandlesStatusAndStatusCodes() + { + $response = new Response(200, new Collection(), 'body'); + $this->assertEquals('OK', $response->getReasonPhrase()); + + $this->assertSame($response, $response->setStatus(204)); + $this->assertEquals('No Content', $response->getReasonPhrase()); + $this->assertEquals(204, $response->getStatusCode()); + + $this->assertSame($response, $response->setStatus(204, 'Testing!')); + $this->assertEquals('Testing!', $response->getReasonPhrase()); + $this->assertEquals(204, $response->getStatusCode()); + + $response->setStatus(2000); + $this->assertEquals(2000, $response->getStatusCode()); + $this->assertEquals('', $response->getReasonPhrase()); + + $response->setStatus(200, 'Foo'); + $this->assertEquals(200, $response->getStatusCode()); + $this->assertEquals('Foo', $response->getReasonPhrase()); + } + + public function testIsClientError() + { + $response = new Response(403); + $this->assertTrue($response->isClientError()); + $response = new Response(200); + $this->assertFalse($response->isClientError()); + } + + public function testIsError() + { + $response = new Response(403); + $this->assertTrue($response->isError()); + $response = new Response(200); + $this->assertFalse($response->isError()); + $response = new Response(500); + $this->assertTrue($response->isError()); + } + + public function testIsInformational() + { + $response = new Response(100); + $this->assertTrue($response->isInformational()); + $response = new Response(200); + $this->assertFalse($response->isInformational()); + } + + public function testIsRedirect() + { + $response = new Response(301); + $this->assertTrue($response->isRedirect()); + $response = new Response(200); + $this->assertFalse($response->isRedirect()); + } + + public function testIsServerError() + { + $response = new Response(500); + $this->assertTrue($response->isServerError()); + $response = new Response(400); + $this->assertFalse($response->isServerError()); + } + + public function testIsSuccessful() + { + $response = new Response(200); + $this->assertTrue($response->isSuccessful()); + $response = new Response(403); + $this->assertFalse($response->isSuccessful()); + } + + public function testGetAcceptRanges() + { + $this->assertEquals('bytes', $this->response->getAcceptRanges()); + } + + public function testCalculatesAge() + { + $this->assertEquals(12, $this->response->calculateAge()); + + $this->response->removeHeader('Age'); + $this->response->removeHeader('Date'); + $this->assertNull($this->response->calculateAge()); + + $this->response->setHeader('Date', gmdate(ClientInterface::HTTP_DATE, strtotime('-1 minute'))); + // If the test runs slowly, still pass with a +5 second allowance + $this->assertTrue($this->response->getAge() - 60 <= 5); + } + + public function testGetAllow() + { + $this->assertEquals('GET, HEAD', $this->response->getAllow()); + } + + public function testGetCacheControl() + { + $this->assertEquals('no-cache', $this->response->getCacheControl()); + } + + public function testGetContentEncoding() + { + $this->assertEquals('gzip', $this->response->getContentEncoding()); + } + + public function testGetContentLanguage() + { + $this->assertEquals('da', $this->response->getContentLanguage()); + } + + public function testGetContentLength() + { + $this->assertEquals('348', $this->response->getContentLength()); + } + + public function testGetContentLocation() + { + $this->assertEquals('/index.htm', $this->response->getContentLocation()); + } + + public function testGetContentDisposition() + { + $this->assertEquals('attachment; filename=fname.ext', $this->response->getContentDisposition()); + } + + public function testGetContentMd5() + { + $this->assertEquals('Q2hlY2sgSW50ZWdyaXR5IQ==', $this->response->getContentMd5()); + } + + public function testGetContentRange() + { + $this->assertEquals('bytes 21010-47021/47022', $this->response->getContentRange()); + } + + public function testGetContentType() + { + $this->assertEquals('text/html; charset=utf-8', $this->response->getContentType()); + } + + public function testGetDate() + { + $this->assertEquals('Tue, 15 Nov 1994 08:12:31 GMT', $this->response->getDate()); + } + + public function testGetEtag() + { + $this->assertEquals('737060cd8c284d8af7ad3082f209582d', $this->response->getEtag()); + } + + public function testGetExpires() + { + $this->assertEquals('Thu, 01 Dec 1994 16:00:00 GMT', $this->response->getExpires()); + } + + public function testGetLastModified() + { + $this->assertEquals('Tue, 15 Nov 1994 12:45:26 GMT', $this->response->getLastModified()); + } + + public function testGetLocation() + { + $this->assertEquals('http://www.w3.org/pub/WWW/People.html', $this->response->getLocation()); + } + + public function testGetPragma() + { + $this->assertEquals('no-cache', $this->response->getPragma()); + } + + public function testGetProxyAuthenticate() + { + $this->assertEquals('Basic', $this->response->getProxyAuthenticate()); + } + + public function testGetServer() + { + $this->assertEquals('Apache/1.3.27 (Unix) (Red-Hat/Linux)', $this->response->getServer()); + } + + public function testGetSetCookie() + { + $this->assertEquals('UserID=JohnDoe; Max-Age=3600; Version=1', $this->response->getSetCookie()); + } + + public function testGetMultipleSetCookie() + { + $this->response->addHeader('Set-Cookie', 'UserID=Mike; Max-Age=200'); + $this->assertEquals(array( + 'UserID=JohnDoe; Max-Age=3600; Version=1', + 'UserID=Mike; Max-Age=200', + ), $this->response->getHeader('Set-Cookie')->toArray()); + } + + public function testGetSetCookieNormalizesHeaders() + { + $this->response->addHeaders(array( + 'Set-Cooke' => 'boo', + 'set-cookie' => 'foo' + )); + + $this->assertEquals(array( + 'UserID=JohnDoe; Max-Age=3600; Version=1', + 'foo' + ), $this->response->getHeader('Set-Cookie')->toArray()); + + $this->response->addHeaders(array( + 'set-cookie' => 'fubu' + )); + $this->assertEquals( + array('UserID=JohnDoe; Max-Age=3600; Version=1', 'foo', 'fubu'), + $this->response->getHeader('Set-Cookie')->toArray() + ); + } + + public function testGetTrailer() + { + $this->assertEquals('Max-Forwards', $this->response->getTrailer()); + } + + public function testGetTransferEncoding() + { + $this->assertEquals('chunked', $this->response->getTransferEncoding()); + } + + public function testGetVary() + { + $this->assertEquals('*', $this->response->getVary()); + } + + public function testReturnsViaHeader() + { + $this->assertEquals('1.0 fred, 1.1 nowhere.com (Apache/1.1)', $this->response->getVia()); + } + public function testGetWarning() + { + $this->assertEquals('199 Miscellaneous warning', $this->response->getWarning()); + } + + public function testReturnsWwwAuthenticateHeader() + { + $this->assertEquals('Basic', $this->response->getWwwAuthenticate()); + } + + public function testReturnsConnectionHeader() + { + $this->assertEquals(null, $this->response->getConnection()); + $this->response->setHeader('Connection', 'close'); + $this->assertEquals('close', $this->response->getConnection()); + } + + public function testReturnsHeaders() + { + $this->assertEquals('Basic', $this->response->getHeader('WWW-Authenticate', null, true)); + $this->assertEquals('chunked', $this->response->getHeader('Transfer-Encoding', null, false)); + } + + public function testHasTransferInfo() + { + $stats = array ( + 'url' => 'http://www.google.com/', + 'content_type' => 'text/html; charset=ISO-8859-1', + 'http_code' => 200, + 'header_size' => 606, + 'request_size' => 53, + 'filetime' => -1, + 'ssl_verify_result' => 0, + 'redirect_count' => 0, + 'total_time' => 0.093284, + 'namelookup_time' => 0.001349, + 'connect_time' => 0.01635, + 'pretransfer_time' => 0.016358, + 'size_upload' => 0, + 'size_download' => 10330, + 'speed_download' => 110737, + 'speed_upload' => 0, + 'download_content_length' => -1, + 'upload_content_length' => 0, + 'starttransfer_time' => 0.07066, + 'redirect_time' => 0, + ); + + // Uninitialized state + $this->assertNull($this->response->getInfo('url')); + $this->assertEquals(array(), $this->response->getInfo()); + + // Set the stats + $this->response->setInfo($stats); + $this->assertEquals($stats, $this->response->getInfo()); + $this->assertEquals(606, $this->response->getInfo('header_size')); + $this->assertNull($this->response->getInfo('does_not_exist')); + } + + /** + * @return Response + */ + private function getResponse($code, array $headers = null, EntityBody $body = null) + { + return new Response($code, $headers, $body); + } + + public function testDeterminesIfItCanBeCached() + { + $this->assertTrue($this->getResponse(200)->canCache()); + $this->assertTrue($this->getResponse(410)->canCache()); + $this->assertFalse($this->getResponse(404)->canCache()); + $this->assertTrue($this->getResponse(200, array( + 'Cache-Control' => 'public' + ))->canCache()); + + // This has the no-store directive + $this->assertFalse($this->getResponse(200, array( + 'Cache-Control' => 'private, no-store' + ))->canCache()); + + // The body cannot be read, so it cannot be cached + $tmp = tempnam('/tmp', 'not-readable'); + $resource = fopen($tmp, 'w'); + $this->assertFalse($this->getResponse(200, array( + 'Transfer-Encoding' => 'chunked' + ), EntityBody::factory($resource, 10))->canCache()); + unlink($tmp); + + // The body is 0 length, cannot be read, so it can be cached + $tmp = tempnam('/tmp', 'not-readable'); + $resource = fopen($tmp, 'w'); + $this->assertTrue($this->getResponse(200, array(array( + 'Content-Length' => 0 + )), EntityBody::factory($resource, 0))->canCache()); + unlink($tmp); + } + + public function testDeterminesResponseMaxAge() + { + $this->assertEquals(null, $this->getResponse(200)->getMaxAge()); + + // Uses the response's s-maxage + $this->assertEquals(140, $this->getResponse(200, array( + 'Cache-Control' => 's-maxage=140' + ))->getMaxAge()); + + // Uses the response's max-age + $this->assertEquals(120, $this->getResponse(200, array( + 'Cache-Control' => 'max-age=120' + ))->getMaxAge()); + + // Uses the response's max-age + $this->assertEquals(120, $this->getResponse(200, array( + 'Cache-Control' => 'max-age=120', + 'Expires' => gmdate(ClientInterface::HTTP_DATE, strtotime('+1 day')) + ))->getMaxAge()); + + // Uses the Expires date + $this->assertGreaterThanOrEqual(82400, $this->getResponse(200, array( + 'Expires' => gmdate(ClientInterface::HTTP_DATE, strtotime('+1 day')) + ))->getMaxAge()); + + // Uses the Expires date + $this->assertGreaterThanOrEqual(82400, $this->getResponse(200, array( + 'Expires' => gmdate(ClientInterface::HTTP_DATE, strtotime('+1 day')) + ))->getMaxAge()); + } + + public function testDeterminesIfItCanValidate() + { + $response = new Response(200); + $this->assertFalse($response->canValidate()); + $response->setHeader('ETag', '123'); + $this->assertTrue($response->canValidate()); + $response->removeHeader('ETag'); + $this->assertFalse($response->canValidate()); + $response->setHeader('Last-Modified', '123'); + $this->assertTrue($response->canValidate()); + } + + public function testCalculatesFreshness() + { + $response = new Response(200); + $this->assertNull($response->isFresh()); + $this->assertNull($response->getFreshness()); + + $response->setHeader('Cache-Control', 'max-age=120'); + $response->setHeader('Age', 100); + $this->assertEquals(20, $response->getFreshness()); + $this->assertTrue($response->isFresh()); + + $response->setHeader('Age', 120); + $this->assertEquals(0, $response->getFreshness()); + $this->assertTrue($response->isFresh()); + + $response->setHeader('Age', 150); + $this->assertEquals(-30, $response->getFreshness()); + $this->assertFalse($response->isFresh()); + } + + public function testHandlesProtocols() + { + $this->assertSame($this->response, $this->response->setProtocol('HTTP', '1.0')); + $this->assertEquals('HTTP', $this->response->getProtocol()); + $this->assertEquals('1.0', $this->response->getProtocolVersion()); + } + + public function testComparesContentType() + { + $response = new Response(200, array( + 'Content-Type' => 'text/html; charset=ISO-8859-4' + )); + + $this->assertTrue($response->isContentType('text/html')); + $this->assertTrue($response->isContentType('TExT/html')); + $this->assertTrue($response->isContentType('charset=ISO-8859-4')); + $this->assertFalse($response->isContentType('application/xml')); + } + + public function testResponseDeterminesIfMethodIsAllowedBaseOnAllowHeader() + { + $response = new Response(200, array( + 'Allow' => 'OPTIONS, POST, deletE,GET' + )); + + $this->assertTrue($response->isMethodAllowed('get')); + $this->assertTrue($response->isMethodAllowed('GET')); + $this->assertTrue($response->isMethodAllowed('options')); + $this->assertTrue($response->isMethodAllowed('post')); + $this->assertTrue($response->isMethodAllowed('Delete')); + $this->assertFalse($response->isMethodAllowed('put')); + $this->assertFalse($response->isMethodAllowed('PUT')); + + $response = new Response(200); + $this->assertFalse($response->isMethodAllowed('get')); + } + + public function testParsesJsonResponses() + { + $response = new Response(200, array(), '{"foo": "bar"}'); + $this->assertEquals(array('foo' => 'bar'), $response->json()); + // Return array when null is a service response + $response = new Response(200); + $this->assertEquals(array(), $response->json()); + } + + /** + * @expectedException \Guzzle\Common\Exception\RuntimeException + * @expectedExceptionMessage Unable to parse response body into JSON: 4 + */ + public function testThrowsExceptionWhenFailsToParseJsonResponse() + { + $response = new Response(200, array(), '{"foo": "'); + $response->json(); + } + + public function testParsesXmlResponses() + { + $response = new Response(200, array(), 'bar'); + $this->assertEquals('bar', (string) $response->xml()->foo); + // Always return a SimpleXMLElement from the xml method + $response = new Response(200); + $this->assertEmpty((string) $response->xml()->foo); + } + + /** + * @expectedException \Guzzle\Common\Exception\RuntimeException + * @expectedExceptionMessage Unable to parse response body into XML: String could not be parsed as XML + */ + public function testThrowsExceptionWhenFailsToParseXmlResponse() + { + $response = new Response(200, array(), 'xml(); + } + + public function testResponseIsSerializable() + { + $response = new Response(200, array('Foo' => 'bar'), 'test'); + $r = unserialize(serialize($response)); + $this->assertEquals(200, $r->getStatusCode()); + $this->assertEquals('bar', (string) $r->getHeader('Foo')); + $this->assertEquals('test', (string) $r->getBody()); + } + + public function testPreventsComplexExternalEntities() + { + $xml = ']>&test;'; + $response = new Response(200, array(), $xml); + + $oldCwd = getcwd(); + chdir(__DIR__); + try { + $xml = $response->xml(); + chdir($oldCwd); + $this->markTestIncomplete('Did not throw the expected exception! XML resolved as: ' . $xml->asXML()); + } catch (\Exception $e) { + chdir($oldCwd); + } + } +} diff --git a/vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/MimetypesTest.php b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/MimetypesTest.php new file mode 100644 index 0000000..7228453 --- /dev/null +++ b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/MimetypesTest.php @@ -0,0 +1,31 @@ +assertEquals('text/x-php', Mimetypes::getInstance()->fromExtension('php')); + } + + public function testGetsFromFilename() + { + $this->assertEquals('text/x-php', Mimetypes::getInstance()->fromFilename(__FILE__)); + } + + public function testGetsFromCaseInsensitiveFilename() + { + $this->assertEquals('text/x-php', Mimetypes::getInstance()->fromFilename(strtoupper(__FILE__))); + } + + public function testReturnsNullWhenNoMatchFound() + { + $this->assertNull(Mimetypes::getInstance()->fromExtension('foobar')); + } +} diff --git a/vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/QueryAggregator/CommaAggregatorTest.php b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/QueryAggregator/CommaAggregatorTest.php new file mode 100644 index 0000000..549d3ed --- /dev/null +++ b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/QueryAggregator/CommaAggregatorTest.php @@ -0,0 +1,30 @@ +aggregate($key, $value, $query); + $this->assertEquals(array('test%20123' => 'foo%20123,baz,bar'), $result); + } + + public function testEncodes() + { + $query = new QueryString(); + $query->useUrlEncoding(false); + $a = new Ag(); + $key = 'test 123'; + $value = array('foo 123', 'baz', 'bar'); + $result = $a->aggregate($key, $value, $query); + $this->assertEquals(array('test 123' => 'foo 123,baz,bar'), $result); + } +} diff --git a/vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/QueryAggregator/DuplicateAggregatorTest.php b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/QueryAggregator/DuplicateAggregatorTest.php new file mode 100644 index 0000000..6a4d9d9 --- /dev/null +++ b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/QueryAggregator/DuplicateAggregatorTest.php @@ -0,0 +1,30 @@ +aggregate($key, $value, $query); + $this->assertEquals(array('facet%201' => array('size%20a', 'width%20b')), $result); + } + + public function testEncodes() + { + $query = new QueryString(); + $query->useUrlEncoding(false); + $a = new Ag(); + $key = 'facet 1'; + $value = array('size a', 'width b'); + $result = $a->aggregate($key, $value, $query); + $this->assertEquals(array('facet 1' => array('size a', 'width b')), $result); + } +} diff --git a/vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/QueryAggregator/PhpAggregatorTest.php b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/QueryAggregator/PhpAggregatorTest.php new file mode 100644 index 0000000..1e7f0c2 --- /dev/null +++ b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/QueryAggregator/PhpAggregatorTest.php @@ -0,0 +1,32 @@ +useUrlEncoding(false); + $a = new Ag(); + $key = 't'; + $value = array( + 'v1' => 'a', + 'v2' => 'b', + 'v3' => array( + 'v4' => 'c', + 'v5' => 'd', + ) + ); + $result = $a->aggregate($key, $value, $query); + $this->assertEquals(array( + 't[v1]' => 'a', + 't[v2]' => 'b', + 't[v3][v4]' => 'c', + 't[v3][v5]' => 'd', + ), $result); + } +} diff --git a/vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/QueryStringTest.php b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/QueryStringTest.php new file mode 100644 index 0000000..948db44 --- /dev/null +++ b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/QueryStringTest.php @@ -0,0 +1,233 @@ +q = new QueryString(); + } + + public function testGetFieldSeparator() + { + $this->assertEquals('&', $this->q->getFieldSeparator()); + } + + public function testGetValueSeparator() + { + $this->assertEquals('=', $this->q->getValueSeparator()); + } + + public function testIsUrlEncoding() + { + $this->assertEquals('RFC 3986', $this->q->getUrlEncoding()); + $this->assertTrue($this->q->isUrlEncoding()); + $this->assertEquals('foo%20bar', $this->q->encodeValue('foo bar')); + + $this->q->useUrlEncoding(QueryString::FORM_URLENCODED); + $this->assertTrue($this->q->isUrlEncoding()); + $this->assertEquals(QueryString::FORM_URLENCODED, $this->q->getUrlEncoding()); + $this->assertEquals('foo+bar', $this->q->encodeValue('foo bar')); + + $this->assertSame($this->q, $this->q->useUrlEncoding(false)); + $this->assertFalse($this->q->isUrlEncoding()); + $this->assertFalse($this->q->isUrlEncoding()); + } + + public function testSetFieldSeparator() + { + $this->assertEquals($this->q, $this->q->setFieldSeparator('/')); + $this->assertEquals('/', $this->q->getFieldSeparator()); + } + + public function testSetValueSeparator() + { + $this->assertEquals($this->q, $this->q->setValueSeparator('/')); + $this->assertEquals('/', $this->q->getValueSeparator()); + } + + public function testUrlEncode() + { + $params = array( + 'test' => 'value', + 'test 2' => 'this is a test?', + 'test3' => array('v1', 'v2', 'v3'), + 'ሴ' => 'bar' + ); + $encoded = array( + 'test' => 'value', + 'test%202' => rawurlencode('this is a test?'), + 'test3%5B0%5D' => 'v1', + 'test3%5B1%5D' => 'v2', + 'test3%5B2%5D' => 'v3', + '%E1%88%B4' => 'bar' + ); + $this->q->replace($params); + $this->assertEquals($encoded, $this->q->urlEncode()); + + // Disable encoding + $testData = array('test 2' => 'this is a test'); + $this->q->replace($testData); + $this->q->useUrlEncoding(false); + $this->assertEquals($testData, $this->q->urlEncode()); + } + + public function testToString() + { + // Check with no parameters + $this->assertEquals('', $this->q->__toString()); + + $params = array( + 'test' => 'value', + 'test 2' => 'this is a test?', + 'test3' => array('v1', 'v2', 'v3'), + 'test4' => null, + ); + $this->q->replace($params); + $this->assertEquals('test=value&test%202=this%20is%20a%20test%3F&test3%5B0%5D=v1&test3%5B1%5D=v2&test3%5B2%5D=v3&test4', $this->q->__toString()); + $this->q->useUrlEncoding(false); + $this->assertEquals('test=value&test 2=this is a test?&test3[0]=v1&test3[1]=v2&test3[2]=v3&test4', $this->q->__toString()); + + // Use an alternative aggregator + $this->q->setAggregator(new CommaAggregator()); + $this->assertEquals('test=value&test 2=this is a test?&test3=v1,v2,v3&test4', $this->q->__toString()); + } + + public function testAllowsMultipleValuesPerKey() + { + $q = new QueryString(); + $q->add('facet', 'size'); + $q->add('facet', 'width'); + $q->add('facet.field', 'foo'); + // Use the duplicate aggregator + $q->setAggregator(new DuplicateAggregator()); + $this->assertEquals('facet=size&facet=width&facet.field=foo', $q->__toString()); + } + + public function testAllowsNestedQueryData() + { + $this->q->replace(array( + 'test' => 'value', + 't' => array( + 'v1' => 'a', + 'v2' => 'b', + 'v3' => array( + 'v4' => 'c', + 'v5' => 'd', + ) + ) + )); + + $this->q->useUrlEncoding(false); + $this->assertEquals('test=value&t[v1]=a&t[v2]=b&t[v3][v4]=c&t[v3][v5]=d', $this->q->__toString()); + } + + public function parseQueryProvider() + { + return array( + // Ensure that multiple query string values are allowed per value + array('q=a&q=b', array('q' => array('a', 'b'))), + // Ensure that PHP array style query string values are parsed + array('q[]=a&q[]=b', array('q' => array('a', 'b'))), + // Ensure that a single PHP array style query string value is parsed into an array + array('q[]=a', array('q' => array('a'))), + // Ensure that decimals are allowed in query strings + array('q.a=a&q.b=b', array( + 'q.a' => 'a', + 'q.b' => 'b' + )), + // Ensure that query string values are percent decoded + array('q%20a=a%20b', array('q a' => 'a b')), + // Ensure null values can be added + array('q&a', array('q' => false, 'a' => false)), + ); + } + + /** + * @dataProvider parseQueryProvider + */ + public function testParsesQueryStrings($query, $data) + { + $query = QueryString::fromString($query); + $this->assertEquals($data, $query->getAll()); + } + + public function testProperlyDealsWithDuplicateQueryStringValues() + { + $query = QueryString::fromString('foo=a&foo=b&?µ=c'); + $this->assertEquals(array('a', 'b'), $query->get('foo')); + $this->assertEquals('c', $query->get('?µ')); + } + + public function testAllowsBlankQueryStringValues() + { + $query = QueryString::fromString('foo'); + $this->assertEquals('foo', (string) $query); + $query->set('foo', QueryString::BLANK); + $this->assertEquals('foo', (string) $query); + } + + public function testAllowsFalsyQueryStringValues() + { + $query = QueryString::fromString('0'); + $this->assertEquals('0', (string) $query); + $query->set('0', QueryString::BLANK); + $this->assertSame('0', (string) $query); + } + + public function testFromStringIgnoresQuestionMark() + { + $query = QueryString::fromString('foo=baz&bar=boo'); + $this->assertEquals('foo=baz&bar=boo', (string) $query); + } + + public function testConvertsPlusSymbolsToSpaces() + { + $query = QueryString::fromString('var=foo+bar'); + $this->assertEquals('foo bar', $query->get('var')); + } + + public function testFromStringDoesntMangleZeroes() + { + $query = QueryString::fromString('var=0'); + $this->assertSame('0', $query->get('var')); + } + + public function testAllowsZeroValues() + { + $query = new QueryString(array( + 'foo' => 0, + 'baz' => '0', + 'bar' => null, + 'boo' => false, + 'bam' => '' + )); + $this->assertEquals('foo=0&baz=0&bar&boo&bam=', (string) $query); + } + + public function testFromStringDoesntStripTrailingEquals() + { + $query = QueryString::fromString('data=mF0b3IiLCJUZWFtIERldiJdfX0='); + $this->assertEquals('mF0b3IiLCJUZWFtIERldiJdfX0=', $query->get('data')); + } + + public function testGuessesIfDuplicateAggregatorShouldBeUsed() + { + $query = QueryString::fromString('test=a&test=b'); + $this->assertEquals('test=a&test=b', (string) $query); + } + + public function testGuessesIfDuplicateAggregatorShouldBeUsedAndChecksForPhpStyle() + { + $query = QueryString::fromString('test[]=a&test[]=b'); + $this->assertEquals('test%5B0%5D=a&test%5B1%5D=b', (string) $query); + } +} diff --git a/vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/ReadLimitEntityBodyTest.php b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/ReadLimitEntityBodyTest.php new file mode 100644 index 0000000..6bb3fed --- /dev/null +++ b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/ReadLimitEntityBodyTest.php @@ -0,0 +1,81 @@ +decorated = EntityBody::factory(fopen(__FILE__, 'r')); + $this->body = new ReadLimitEntityBody($this->decorated, 10, 3); + } + + public function testReturnsSubsetWhenCastToString() + { + $body = EntityBody::factory('foo_baz_bar'); + $limited = new ReadLimitEntityBody($body, 3, 4); + $this->assertEquals('baz', (string) $limited); + } + + public function testReturnsSubsetOfEmptyBodyWhenCastToString() + { + $body = EntityBody::factory(''); + $limited = new ReadLimitEntityBody($body, 0, 10); + $this->assertEquals('', (string) $limited); + } + + public function testSeeksWhenConstructed() + { + $this->assertEquals(3, $this->body->ftell()); + } + + public function testAllowsBoundedSeek() + { + $this->body->seek(100); + $this->assertEquals(13, $this->body->ftell()); + $this->body->seek(0); + $this->assertEquals(3, $this->body->ftell()); + $this->assertEquals(false, $this->body->seek(1000, SEEK_END)); + } + + public function testReadsOnlySubsetOfData() + { + $data = $this->body->read(100); + $this->assertEquals(10, strlen($data)); + $this->assertFalse($this->body->read(1000)); + + $this->body->setOffset(10); + $newData = $this->body->read(100); + $this->assertEquals(10, strlen($newData)); + $this->assertNotSame($data, $newData); + } + + public function testClaimsConsumedWhenReadLimitIsReached() + { + $this->assertFalse($this->body->isConsumed()); + $this->body->read(1000); + $this->assertTrue($this->body->isConsumed()); + } + + public function testContentLengthIsBounded() + { + $this->assertEquals(10, $this->body->getContentLength()); + } + + public function testContentMd5IsBasedOnSubsection() + { + $this->assertNotSame($this->body->getContentMd5(), $this->decorated->getContentMd5()); + } +} diff --git a/vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/RedirectPluginTest.php b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/RedirectPluginTest.php new file mode 100755 index 0000000..886236d --- /dev/null +++ b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/RedirectPluginTest.php @@ -0,0 +1,277 @@ +getServer()->flush(); + $this->getServer()->enqueue(array( + "HTTP/1.1 301 Moved Permanently\r\nLocation: /redirect1\r\nContent-Length: 0\r\n\r\n", + "HTTP/1.1 301 Moved Permanently\r\nLocation: /redirect2\r\nContent-Length: 0\r\n\r\n", + "HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n", + )); + + // Create a client that uses the default redirect behavior + $client = new Client($this->getServer()->getUrl()); + $history = new HistoryPlugin(); + $client->addSubscriber($history); + + $request = $client->get('/foo'); + $response = $request->send(); + $this->assertEquals(200, $response->getStatusCode()); + $this->assertContains('/redirect2', $response->getEffectiveUrl()); + + // Ensure that two requests were sent + $requests = $this->getServer()->getReceivedRequests(true); + $this->assertEquals('/foo', $requests[0]->getResource()); + $this->assertEquals('GET', $requests[0]->getMethod()); + $this->assertEquals('/redirect1', $requests[1]->getResource()); + $this->assertEquals('GET', $requests[1]->getMethod()); + $this->assertEquals('/redirect2', $requests[2]->getResource()); + $this->assertEquals('GET', $requests[2]->getMethod()); + + // Ensure that the redirect count was incremented + $this->assertEquals(2, $request->getParams()->get(RedirectPlugin::REDIRECT_COUNT)); + $this->assertCount(3, $history); + $requestHistory = $history->getAll(); + + $this->assertEquals(301, $requestHistory[0]['response']->getStatusCode()); + $this->assertEquals('/redirect1', (string) $requestHistory[0]['response']->getHeader('Location')); + $this->assertEquals(301, $requestHistory[1]['response']->getStatusCode()); + $this->assertEquals('/redirect2', (string) $requestHistory[1]['response']->getHeader('Location')); + $this->assertEquals(200, $requestHistory[2]['response']->getStatusCode()); + } + + public function testCanLimitNumberOfRedirects() + { + // Flush the server and queue up a redirect followed by a successful response + $this->getServer()->flush(); + $this->getServer()->enqueue(array( + "HTTP/1.1 301 Moved Permanently\r\nLocation: /redirect1\r\nContent-Length: 0\r\n\r\n", + "HTTP/1.1 301 Moved Permanently\r\nLocation: /redirect2\r\nContent-Length: 0\r\n\r\n", + "HTTP/1.1 301 Moved Permanently\r\nLocation: /redirect3\r\nContent-Length: 0\r\n\r\n", + "HTTP/1.1 301 Moved Permanently\r\nLocation: /redirect4\r\nContent-Length: 0\r\n\r\n", + "HTTP/1.1 301 Moved Permanently\r\nLocation: /redirect5\r\nContent-Length: 0\r\n\r\n", + "HTTP/1.1 301 Moved Permanently\r\nLocation: /redirect6\r\nContent-Length: 0\r\n\r\n" + )); + + try { + $client = new Client($this->getServer()->getUrl()); + $client->get('/foo')->send(); + $this->fail('Did not throw expected exception'); + } catch (TooManyRedirectsException $e) { + $this->assertContains( + "5 redirects were issued for this request:\nGET /foo HTTP/1.1\r\n", + $e->getMessage() + ); + } + } + + public function testDefaultBehaviorIsToRedirectWithGetForEntityEnclosingRequests() + { + $this->getServer()->flush(); + $this->getServer()->enqueue(array( + "HTTP/1.1 301 Moved Permanently\r\nLocation: /redirect\r\nContent-Length: 0\r\n\r\n", + "HTTP/1.1 301 Moved Permanently\r\nLocation: /redirect\r\nContent-Length: 0\r\n\r\n", + "HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n", + )); + + $client = new Client($this->getServer()->getUrl()); + $client->post('/foo', array('X-Baz' => 'bar'), 'testing')->send(); + + $requests = $this->getServer()->getReceivedRequests(true); + $this->assertEquals('POST', $requests[0]->getMethod()); + $this->assertEquals('GET', $requests[1]->getMethod()); + $this->assertEquals('bar', (string) $requests[1]->getHeader('X-Baz')); + $this->assertEquals('GET', $requests[2]->getMethod()); + } + + public function testCanRedirectWithStrictRfcCompliance() + { + $this->getServer()->flush(); + $this->getServer()->enqueue(array( + "HTTP/1.1 301 Moved Permanently\r\nLocation: /redirect\r\nContent-Length: 0\r\n\r\n", + "HTTP/1.1 301 Moved Permanently\r\nLocation: /redirect\r\nContent-Length: 0\r\n\r\n", + "HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n", + )); + + $client = new Client($this->getServer()->getUrl()); + $request = $client->post('/foo', array('X-Baz' => 'bar'), 'testing'); + $request->getParams()->set(RedirectPlugin::STRICT_REDIRECTS, true); + $request->send(); + + $requests = $this->getServer()->getReceivedRequests(true); + $this->assertEquals('POST', $requests[0]->getMethod()); + $this->assertEquals('POST', $requests[1]->getMethod()); + $this->assertEquals('bar', (string) $requests[1]->getHeader('X-Baz')); + $this->assertEquals('POST', $requests[2]->getMethod()); + } + + public function testRedirect303WithGet() + { + $this->getServer()->flush(); + $this->getServer()->enqueue(array( + "HTTP/1.1 303 Moved Permanently\r\nLocation: /redirect\r\nContent-Length: 0\r\n\r\n", + "HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n", + )); + + $client = new Client($this->getServer()->getUrl()); + $request = $client->post('/foo'); + $request->send(); + + $requests = $this->getServer()->getReceivedRequests(true); + $this->assertEquals('POST', $requests[0]->getMethod()); + $this->assertEquals('GET', $requests[1]->getMethod()); + } + + public function testRedirect303WithGetWithStrictRfcCompliance() + { + $this->getServer()->flush(); + $this->getServer()->enqueue(array( + "HTTP/1.1 303 Moved Permanently\r\nLocation: /redirect\r\nContent-Length: 0\r\n\r\n", + "HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n", + )); + + $client = new Client($this->getServer()->getUrl()); + $request = $client->post('/foo'); + $request->getParams()->set(RedirectPlugin::STRICT_REDIRECTS, true); + $request->send(); + + $requests = $this->getServer()->getReceivedRequests(true); + $this->assertEquals('POST', $requests[0]->getMethod()); + $this->assertEquals('GET', $requests[1]->getMethod()); + } + + public function testRewindsStreamWhenRedirectingIfNeeded() + { + $this->getServer()->flush(); + $this->getServer()->enqueue(array( + "HTTP/1.1 301 Moved Permanently\r\nLocation: /redirect\r\nContent-Length: 0\r\n\r\n", + "HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n", + )); + + $client = new Client($this->getServer()->getUrl()); + $request = $client->put(); + $request->configureRedirects(true); + $body = EntityBody::factory('foo'); + $body->read(1); + $request->setBody($body); + $request->send(); + $requests = $this->getServer()->getReceivedRequests(true); + $this->assertEquals('foo', (string) $requests[0]->getBody()); + } + + /** + * @expectedException \Guzzle\Http\Exception\CouldNotRewindStreamException + */ + public function testThrowsExceptionWhenStreamCannotBeRewound() + { + $this->getServer()->flush(); + $this->getServer()->enqueue(array( + "HTTP/1.1 200 OK\r\nContent-Length: 2\r\n\r\nhi", + "HTTP/1.1 301 Moved Permanently\r\nLocation: /redirect\r\nContent-Length: 0\r\n\r\n" + )); + + $client = new Client($this->getServer()->getUrl()); + $request = $client->put(); + $request->configureRedirects(true); + $body = EntityBody::factory(fopen($this->getServer()->getUrl(), 'r')); + $body->read(1); + $request->setBody($body)->send(); + } + + public function testRedirectsCanBeDisabledPerRequest() + { + $this->getServer()->flush(); + $this->getServer()->enqueue(array("HTTP/1.1 301 Foo\r\nLocation: /foo\r\nContent-Length: 0\r\n\r\n")); + $client = new Client($this->getServer()->getUrl()); + $request = $client->put(); + $request->configureRedirects(false, 0); + $this->assertEquals(301, $request->send()->getStatusCode()); + } + + public function testCanRedirectWithNoLeadingSlashAndQuery() + { + $this->getServer()->flush(); + $this->getServer()->enqueue(array( + "HTTP/1.1 301 Moved Permanently\r\nLocation: redirect?foo=bar\r\nContent-Length: 0\r\n\r\n", + "HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n", + )); + $client = new Client($this->getServer()->getUrl()); + $request = $client->get('?foo=bar'); + $request->send(); + $requests = $this->getServer()->getReceivedRequests(true); + $this->assertEquals($this->getServer()->getUrl() . '?foo=bar', $requests[0]->getUrl()); + $this->assertEquals($this->getServer()->getUrl() . 'redirect?foo=bar', $requests[1]->getUrl()); + // Ensure that the history on the actual request is correct + $this->assertEquals($this->getServer()->getUrl() . '?foo=bar', $request->getUrl()); + } + + public function testRedirectWithStrictRfc386Compliance() + { + // Flush the server and queue up a redirect followed by a successful response + $this->getServer()->flush(); + $this->getServer()->enqueue(array( + "HTTP/1.1 301 Moved Permanently\r\nLocation: redirect\r\nContent-Length: 0\r\n\r\n", + "HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n" + )); + $client = new Client($this->getServer()->getUrl()); + $request = $client->get('/foo'); + $request->send(); + $requests = $this->getServer()->getReceivedRequests(true); + $this->assertEquals('/redirect', $requests[1]->getResource()); + } + + public function testResetsHistoryEachSend() + { + // Flush the server and queue up a redirect followed by a successful response + $this->getServer()->flush(); + $this->getServer()->enqueue(array( + "HTTP/1.1 301 Moved Permanently\r\nLocation: /redirect1\r\nContent-Length: 0\r\n\r\n", + "HTTP/1.1 301 Moved Permanently\r\nLocation: /redirect2\r\nContent-Length: 0\r\n\r\n", + "HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n", + "HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n" + )); + + // Create a client that uses the default redirect behavior + $client = new Client($this->getServer()->getUrl()); + $history = new HistoryPlugin(); + $client->addSubscriber($history); + + $request = $client->get('/foo'); + $response = $request->send(); + $this->assertEquals(3, count($history)); + $this->assertTrue($request->getParams()->hasKey('redirect.count')); + $this->assertContains('/redirect2', $response->getEffectiveUrl()); + + $request->send(); + $this->assertFalse($request->getParams()->hasKey('redirect.count')); + } + + public function testHandlesRedirectsWithSpacesProperly() + { + // Flush the server and queue up a redirect followed by a successful response + $this->getServer()->flush(); + $this->getServer()->enqueue(array( + "HTTP/1.1 301 Moved Permanently\r\nLocation: /redirect 1\r\nContent-Length: 0\r\n\r\n", + "HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n" + )); + $client = new Client($this->getServer()->getUrl()); + $request = $client->get('/foo'); + $request->send(); + $reqs = $this->getServer()->getReceivedRequests(true); + $this->assertEquals('/redirect%201', $reqs[1]->getResource()); + } +} diff --git a/vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/Server.php b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/Server.php new file mode 100644 index 0000000..94eb59a --- /dev/null +++ b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/Server.php @@ -0,0 +1,191 @@ +port = $port ?: self::DEFAULT_PORT; + $this->client = new Client($this->getUrl()); + register_shutdown_function(array($this, 'stop')); + } + + /** + * Flush the received requests from the server + * @throws RuntimeException + */ + public function flush() + { + $this->client->delete('guzzle-server/requests')->send(); + } + + /** + * Queue an array of responses or a single response on the server. + * + * Any currently queued responses will be overwritten. Subsequent requests + * on the server will return queued responses in FIFO order. + * + * @param array|Response $responses A single or array of Responses to queue + * @throws BadResponseException + */ + public function enqueue($responses) + { + $data = array(); + foreach ((array) $responses as $response) { + + // Create the response object from a string + if (is_string($response)) { + $response = Response::fromMessage($response); + } elseif (!($response instanceof Response)) { + throw new BadResponseException('Responses must be strings or implement Response'); + } + + $data[] = array( + 'statusCode' => $response->getStatusCode(), + 'reasonPhrase' => $response->getReasonPhrase(), + 'headers' => $response->getHeaders()->toArray(), + 'body' => $response->getBody(true) + ); + } + + $request = $this->client->put('guzzle-server/responses', null, json_encode($data)); + $request->send(); + } + + /** + * Check if the server is running + * + * @return bool + */ + public function isRunning() + { + if ($this->running) { + return true; + } + + try { + $this->client->get('guzzle-server/perf', array(), array('timeout' => 5))->send(); + $this->running = true; + return true; + } catch (\Exception $e) { + return false; + } + } + + /** + * Get the URL to the server + * + * @return string + */ + public function getUrl() + { + return 'http://127.0.0.1:' . $this->getPort() . '/'; + } + + /** + * Get the port that the server is listening on + * + * @return int + */ + public function getPort() + { + return $this->port; + } + + /** + * Get all of the received requests + * + * @param bool $hydrate Set to TRUE to turn the messages into + * actual {@see RequestInterface} objects. If $hydrate is FALSE, + * requests will be returned as strings. + * + * @return array + * @throws RuntimeException + */ + public function getReceivedRequests($hydrate = false) + { + $response = $this->client->get('guzzle-server/requests')->send(); + $data = array_filter(explode(self::REQUEST_DELIMITER, $response->getBody(true))); + if ($hydrate) { + $data = array_map(function($message) { + return RequestFactory::getInstance()->fromMessage($message); + }, $data); + } + + return $data; + } + + /** + * Start running the node.js server in the background + */ + public function start() + { + if (!$this->isRunning()) { + exec('node ' . __DIR__ . \DIRECTORY_SEPARATOR + . 'server.js ' . $this->port + . ' >> /tmp/server.log 2>&1 &'); + // Wait at most 5 seconds for the server the setup before + // proceeding. + $start = time(); + while (!$this->isRunning() && time() - $start < 5); + if (!$this->running) { + throw new RuntimeException( + 'Unable to contact server.js. Have you installed node.js v0.5.0+? node must be in your path.' + ); + } + } + } + + /** + * Stop running the node.js server + */ + public function stop() + { + if (!$this->isRunning()) { + return false; + } + + $this->running = false; + $this->client->delete('guzzle-server')->send(); + } +} diff --git a/vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/StaticClientTest.php b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/StaticClientTest.php new file mode 100644 index 0000000..091314b --- /dev/null +++ b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/StaticClientTest.php @@ -0,0 +1,67 @@ +assertTrue(class_exists('FooBazBar')); + $this->assertSame($client, $this->readAttribute('Guzzle\Http\StaticClient', 'client')); + } + + public function requestProvider() + { + return array_map( + function ($m) { return array($m); }, + array('GET', 'POST', 'PUT', 'DELETE', 'PATCH', 'HEAD', 'OPTIONS') + ); + } + + /** + * @dataProvider requestProvider + */ + public function testSendsRequests($method) + { + $mock = new MockPlugin(array(new Response(200))); + call_user_func('Guzzle\Http\StaticClient::' . $method, 'http://foo.com', array( + 'plugins' => array($mock) + )); + $requests = $mock->getReceivedRequests(); + $this->assertCount(1, $requests); + $this->assertEquals($method, $requests[0]->getMethod()); + } + + public function testCanCreateStreamsUsingDefaultFactory() + { + $this->getServer()->enqueue(array("HTTP/1.1 200 OK\r\nContent-Length: 4\r\n\r\ntest")); + $stream = StaticClient::get($this->getServer()->getUrl(), array('stream' => true)); + $this->assertInstanceOf('Guzzle\Stream\StreamInterface', $stream); + $this->assertEquals('test', (string) $stream); + } + + public function testCanCreateStreamsUsingCustomFactory() + { + $stream = $this->getMockBuilder('Guzzle\Stream\StreamRequestFactoryInterface') + ->setMethods(array('fromRequest')) + ->getMockForAbstractClass(); + $resource = new Stream(fopen('php://temp', 'r+')); + $stream->expects($this->once()) + ->method('fromRequest') + ->will($this->returnValue($resource)); + $this->getServer()->enqueue(array("HTTP/1.1 200 OK\r\nContent-Length: 4\r\n\r\ntest")); + $result = StaticClient::get($this->getServer()->getUrl(), array('stream' => $stream)); + $this->assertSame($resource, $result); + } +} diff --git a/vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/UrlTest.php b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/UrlTest.php new file mode 100644 index 0000000..28f2671 --- /dev/null +++ b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/UrlTest.php @@ -0,0 +1,303 @@ +assertEquals('', (string) $url); + } + + public function testPortIsDeterminedFromScheme() + { + $this->assertEquals(80, Url::factory('http://www.test.com/')->getPort()); + $this->assertEquals(443, Url::factory('https://www.test.com/')->getPort()); + $this->assertEquals(null, Url::factory('ftp://www.test.com/')->getPort()); + $this->assertEquals(8192, Url::factory('http://www.test.com:8192/')->getPort()); + } + + public function testCloneCreatesNewInternalObjects() + { + $u1 = Url::factory('http://www.test.com/'); + $u2 = clone $u1; + $this->assertNotSame($u1->getQuery(), $u2->getQuery()); + } + + public function testValidatesUrlPartsInFactory() + { + $url = Url::factory('/index.php'); + $this->assertEquals('/index.php', (string) $url); + $this->assertFalse($url->isAbsolute()); + + $url = 'http://michael:test@test.com:80/path/123?q=abc#test'; + $u = Url::factory($url); + $this->assertEquals('http://michael:test@test.com/path/123?q=abc#test', (string) $u); + $this->assertTrue($u->isAbsolute()); + } + + public function testAllowsFalsyUrlParts() + { + $url = Url::factory('http://0:50/0?0#0'); + $this->assertSame('0', $url->getHost()); + $this->assertEquals(50, $url->getPort()); + $this->assertSame('/0', $url->getPath()); + $this->assertEquals('0', (string) $url->getQuery()); + $this->assertSame('0', $url->getFragment()); + $this->assertEquals('http://0:50/0?0#0', (string) $url); + + $url = Url::factory(''); + $this->assertSame('', (string) $url); + + $url = Url::factory('0'); + $this->assertSame('0', (string) $url); + } + + public function testBuildsRelativeUrlsWithFalsyParts() + { + $url = Url::buildUrl(array( + 'host' => '0', + 'path' => '0', + )); + + $this->assertSame('//0/0', $url); + + $url = Url::buildUrl(array( + 'path' => '0', + )); + $this->assertSame('0', $url); + } + + public function testUrlStoresParts() + { + $url = Url::factory('http://test:pass@www.test.com:8081/path/path2/?a=1&b=2#fragment'); + $this->assertEquals('http', $url->getScheme()); + $this->assertEquals('test', $url->getUsername()); + $this->assertEquals('pass', $url->getPassword()); + $this->assertEquals('www.test.com', $url->getHost()); + $this->assertEquals(8081, $url->getPort()); + $this->assertEquals('/path/path2/', $url->getPath()); + $this->assertEquals('fragment', $url->getFragment()); + $this->assertEquals('a=1&b=2', (string) $url->getQuery()); + + $this->assertEquals(array( + 'fragment' => 'fragment', + 'host' => 'www.test.com', + 'pass' => 'pass', + 'path' => '/path/path2/', + 'port' => 8081, + 'query' => 'a=1&b=2', + 'scheme' => 'http', + 'user' => 'test' + ), $url->getParts()); + } + + public function testHandlesPathsCorrectly() + { + $url = Url::factory('http://www.test.com'); + $this->assertEquals('', $url->getPath()); + $url->setPath('test'); + $this->assertEquals('test', $url->getPath()); + + $url->setPath('/test/123/abc'); + $this->assertEquals(array('test', '123', 'abc'), $url->getPathSegments()); + + $parts = parse_url('http://www.test.com/test'); + $parts['path'] = ''; + $this->assertEquals('http://www.test.com', Url::buildUrl($parts)); + $parts['path'] = 'test'; + $this->assertEquals('http://www.test.com/test', Url::buildUrl($parts)); + } + + public function testAddsQueryStringIfPresent() + { + $this->assertEquals('?foo=bar', Url::buildUrl(array( + 'query' => 'foo=bar' + ))); + } + + public function testAddsToPath() + { + // Does nothing here + $this->assertEquals('http://e.com/base?a=1', (string) Url::factory('http://e.com/base?a=1')->addPath(false)); + $this->assertEquals('http://e.com/base?a=1', (string) Url::factory('http://e.com/base?a=1')->addPath(null)); + $this->assertEquals('http://e.com/base?a=1', (string) Url::factory('http://e.com/base?a=1')->addPath(array())); + $this->assertEquals('http://e.com/base?a=1', (string) Url::factory('http://e.com/base?a=1')->addPath(new \stdClass())); + $this->assertEquals('http://e.com/base?a=1', (string) Url::factory('http://e.com/base?a=1')->addPath('')); + $this->assertEquals('http://e.com/base?a=1', (string) Url::factory('http://e.com/base?a=1')->addPath('/')); + $this->assertEquals('http://e.com/baz/foo', (string) Url::factory('http://e.com/baz/')->addPath('foo')); + $this->assertEquals('http://e.com/base/relative?a=1', (string) Url::factory('http://e.com/base?a=1')->addPath('relative')); + $this->assertEquals('http://e.com/base/relative?a=1', (string) Url::factory('http://e.com/base?a=1')->addPath('/relative')); + $this->assertEquals('http://e.com/base/0', (string) Url::factory('http://e.com/base')->addPath('0')); + $this->assertEquals('http://e.com/base/0/1', (string) Url::factory('http://e.com/base')->addPath('0')->addPath('1')); + } + + /** + * URL combination data provider + * + * @return array + */ + public function urlCombineDataProvider() + { + return array( + array('http://www.example.com/', 'http://www.example.com/', 'http://www.example.com/'), + array('http://www.example.com/path', '/absolute', 'http://www.example.com/absolute'), + array('http://www.example.com/path', '/absolute?q=2', 'http://www.example.com/absolute?q=2'), + array('http://www.example.com/path', 'more', 'http://www.example.com/path/more'), + array('http://www.example.com/path', 'more?q=1', 'http://www.example.com/path/more?q=1'), + array('http://www.example.com/', '?q=1', 'http://www.example.com/?q=1'), + array('http://www.example.com/path', 'http://test.com', 'http://test.com'), + array('http://www.example.com:8080/path', 'http://test.com', 'http://test.com'), + array('http://www.example.com:8080/path', '?q=2#abc', 'http://www.example.com:8080/path?q=2#abc'), + array('http://u:a@www.example.com/path', 'test', 'http://u:a@www.example.com/path/test'), + array('http://www.example.com/path', 'http://u:a@www.example.com/', 'http://u:a@www.example.com/'), + array('/path?q=2', 'http://www.test.com/', 'http://www.test.com/path?q=2'), + array('http://api.flickr.com/services/', 'http://www.flickr.com/services/oauth/access_token', 'http://www.flickr.com/services/oauth/access_token'), + array('http://www.example.com/?foo=bar', 'some/path', 'http://www.example.com/some/path?foo=bar'), + array('http://www.example.com/?foo=bar', 'some/path?boo=moo', 'http://www.example.com/some/path?boo=moo&foo=bar'), + array('http://www.example.com/some/', 'path?foo=bar&foo=baz', 'http://www.example.com/some/path?foo=bar&foo=baz'), + ); + } + + /** + * @dataProvider urlCombineDataProvider + */ + public function testCombinesUrls($a, $b, $c) + { + $this->assertEquals($c, (string) Url::factory($a)->combine($b)); + } + + public function testHasGettersAndSetters() + { + $url = Url::factory('http://www.test.com/'); + $this->assertEquals('example.com', $url->setHost('example.com')->getHost()); + $this->assertEquals('8080', $url->setPort(8080)->getPort()); + $this->assertEquals('/foo/bar', $url->setPath(array('foo', 'bar'))->getPath()); + $this->assertEquals('a', $url->setPassword('a')->getPassword()); + $this->assertEquals('b', $url->setUsername('b')->getUsername()); + $this->assertEquals('abc', $url->setFragment('abc')->getFragment()); + $this->assertEquals('https', $url->setScheme('https')->getScheme()); + $this->assertEquals('a=123', (string) $url->setQuery('a=123')->getQuery()); + $this->assertEquals('https://b:a@example.com:8080/foo/bar?a=123#abc', (string) $url); + $this->assertEquals('b=boo', (string) $url->setQuery(new QueryString(array( + 'b' => 'boo' + )))->getQuery()); + $this->assertEquals('https://b:a@example.com:8080/foo/bar?b=boo#abc', (string) $url); + } + + public function testSetQueryAcceptsArray() + { + $url = Url::factory('http://www.test.com'); + $url->setQuery(array('a' => 'b')); + $this->assertEquals('http://www.test.com?a=b', (string) $url); + } + + public function urlProvider() + { + return array( + array('/foo/..', '/'), + array('//foo//..', '/'), + array('/foo/../..', '/'), + array('/foo/../.', '/'), + array('/./foo/..', '/'), + array('/./foo', '/foo'), + array('/./foo/', '/foo/'), + array('/./foo/bar/baz/pho/../..', '/foo/bar'), + array('*', '*'), + array('/foo', '/foo'), + array('/abc/123/../foo/', '/abc/foo/'), + array('/a/b/c/./../../g', '/a/g'), + array('/b/c/./../../g', '/g'), + array('/b/c/./../../g', '/g'), + array('/c/./../../g', '/g'), + array('/./../../g', '/g'), + ); + } + + /** + * @dataProvider urlProvider + */ + public function testNormalizesPaths($path, $result) + { + $url = Url::factory('http://www.example.com/'); + $url->setPath($path)->normalizePath(); + $this->assertEquals($result, $url->getPath()); + } + + public function testSettingHostWithPortModifiesPort() + { + $url = Url::factory('http://www.example.com'); + $url->setHost('foo:8983'); + $this->assertEquals('foo', $url->getHost()); + $this->assertEquals(8983, $url->getPort()); + } + + /** + * @expectedException \Guzzle\Common\Exception\InvalidArgumentException + */ + public function testValidatesUrlCanBeParsed() + { + Url::factory('foo:////'); + } + + public function testConvertsSpecialCharsInPathWhenCastingToString() + { + $url = Url::factory('http://foo.com/baz bar?a=b'); + $url->addPath('?'); + $this->assertEquals('http://foo.com/baz%20bar/%3F?a=b', (string) $url); + } + + /** + * @link http://tools.ietf.org/html/rfc3986#section-5.4.1 + */ + public function rfc3986UrlProvider() + { + $result = array( + array('g', 'http://a/b/c/g'), + array('./g', 'http://a/b/c/g'), + array('g/', 'http://a/b/c/g/'), + array('/g', 'http://a/g'), + array('?y', 'http://a/b/c/d;p?y'), + array('g?y', 'http://a/b/c/g?y'), + array('#s', 'http://a/b/c/d;p?q#s'), + array('g#s', 'http://a/b/c/g#s'), + array('g?y#s', 'http://a/b/c/g?y#s'), + array(';x', 'http://a/b/c/;x'), + array('g;x', 'http://a/b/c/g;x'), + array('g;x?y#s', 'http://a/b/c/g;x?y#s'), + array('', 'http://a/b/c/d;p?q'), + array('.', 'http://a/b/c'), + array('./', 'http://a/b/c/'), + array('..', 'http://a/b'), + array('../', 'http://a/b/'), + array('../g', 'http://a/b/g'), + array('../..', 'http://a/'), + array('../../', 'http://a/'), + array('../../g', 'http://a/g') + ); + + // This support was added in PHP 5.4.7: https://bugs.php.net/bug.php?id=62844 + if (version_compare(PHP_VERSION, '5.4.7', '>=')) { + $result[] = array('//g', 'http://g'); + } + + return $result; + } + + /** + * @dataProvider rfc3986UrlProvider + */ + public function testCombinesUrlsUsingRfc3986($relative, $result) + { + $a = Url::factory('http://a/b/c/d;p?q'); + $b = Url::factory($relative); + $this->assertEquals($result, trim((string) $a->combine($b, true), '=')); + } +} diff --git a/vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/server.js b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/server.js new file mode 100644 index 0000000..4156f1a --- /dev/null +++ b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/server.js @@ -0,0 +1,146 @@ +/** + * Guzzle node.js test server to return queued responses to HTTP requests and + * expose a RESTful API for enqueueing responses and retrieving the requests + * that have been received. + * + * - Delete all requests that have been received: + * DELETE /guzzle-server/requests + * Host: 127.0.0.1:8124 + * + * - Enqueue responses + * PUT /guzzle-server/responses + * Host: 127.0.0.1:8124 + * + * [{ "statusCode": 200, "reasonPhrase": "OK", "headers": {}, "body": "" }] + * + * - Get the received requests + * GET /guzzle-server/requests + * Host: 127.0.0.1:8124 + * + * - Shutdown the server + * DELETE /guzzle-server + * Host: 127.0.0.1:8124 + * + * @package Guzzle PHP + * @license See the LICENSE file that was distributed with this source code. + */ + +var http = require("http"); + +/** + * Guzzle node.js server + * @class + */ +var GuzzleServer = function(port, log) { + + this.port = port; + this.log = log; + this.responses = []; + this.requests = []; + var that = this; + + var controlRequest = function(request, req, res) { + if (req.url == '/guzzle-server/perf') { + res.writeHead(200, "OK", {"Content-Length": 16}); + res.end("Body of response"); + } else if (req.method == "DELETE") { + if (req.url == "/guzzle-server/requests") { + // Clear the received requests + that.requests = []; + res.writeHead(200, "OK", { "Content-Length": 0 }); + res.end(); + if (this.log) { + console.log("Flushing requests"); + } + } else if (req.url == "/guzzle-server") { + // Shutdown the server + res.writeHead(200, "OK", { "Content-Length": 0, "Connection": "close" }); + res.end(); + if (this.log) { + console.log("Shutting down"); + } + that.server.close(); + } + } else if (req.method == "GET") { + if (req.url === "/guzzle-server/requests") { + // Get received requests + var data = that.requests.join("\n----[request]\n"); + res.writeHead(200, "OK", { "Content-Length": data.length }); + res.end(data); + if (that.log) { + console.log("Sending receiving requests"); + } + } + } else if (req.method == "PUT") { + if (req.url == "/guzzle-server/responses") { + if (that.log) { + console.log("Adding responses..."); + } + // Received response to queue + var data = request.split("\r\n\r\n")[1]; + if (!data) { + if (that.log) { + console.log("No response data was provided"); + } + res.writeHead(400, "NO RESPONSES IN REQUEST", { "Content-Length": 0 }); + } else { + that.responses = eval("(" + data + ")"); + if (that.log) { + console.log(that.responses); + } + res.writeHead(200, "OK", { "Content-Length": 0 }); + } + res.end(); + } + } + }; + + var receivedRequest = function(request, req, res) { + if (req.url.indexOf("/guzzle-server") === 0) { + controlRequest(request, req, res); + } else if (req.url.indexOf("/guzzle-server") == -1 && !that.responses.length) { + res.writeHead(500); + res.end("No responses in queue"); + } else { + var response = that.responses.shift(); + res.writeHead(response.statusCode, response.reasonPhrase, response.headers); + res.end(response.body); + that.requests.push(request); + } + }; + + this.start = function() { + + that.server = http.createServer(function(req, res) { + + var request = req.method + " " + req.url + " HTTP/" + req.httpVersion + "\r\n"; + for (var i in req.headers) { + request += i + ": " + req.headers[i] + "\r\n"; + } + request += "\r\n"; + + // Receive each chunk of the request body + req.addListener("data", function(chunk) { + request += chunk; + }); + + // Called when the request completes + req.addListener("end", function() { + receivedRequest(request, req, res); + }); + }); + that.server.listen(port, "127.0.0.1"); + + if (this.log) { + console.log("Server running at http://127.0.0.1:8124/"); + } + }; +}; + +// Get the port from the arguments +port = process.argv.length >= 3 ? process.argv[2] : 8124; +log = process.argv.length >= 4 ? process.argv[3] : false; + +// Start the server +server = new GuzzleServer(port, log); +server.start(); diff --git a/vendor/guzzle/guzzle/tests/Guzzle/Tests/Inflection/InflectorTest.php b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Inflection/InflectorTest.php new file mode 100644 index 0000000..990c0af --- /dev/null +++ b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Inflection/InflectorTest.php @@ -0,0 +1,37 @@ +assertSame(Inflector::getDefault(), Inflector::getDefault()); + } + + public function testSnake() + { + $this->assertEquals('camel_case', Inflector::getDefault()->snake('camelCase')); + $this->assertEquals('camel_case', Inflector::getDefault()->snake('CamelCase')); + $this->assertEquals('camel_case_words', Inflector::getDefault()->snake('CamelCaseWords')); + $this->assertEquals('camel_case_words', Inflector::getDefault()->snake('CamelCase_words')); + $this->assertEquals('test', Inflector::getDefault()->snake('test')); + $this->assertEquals('test', Inflector::getDefault()->snake('test')); + $this->assertEquals('expect100_continue', Inflector::getDefault()->snake('Expect100Continue')); + } + + public function testCamel() + { + $this->assertEquals('CamelCase', Inflector::getDefault()->camel('camel_case')); + $this->assertEquals('CamelCaseWords', Inflector::getDefault()->camel('camel_case_words')); + $this->assertEquals('Test', Inflector::getDefault()->camel('test')); + $this->assertEquals('Expect100Continue', ucfirst(Inflector::getDefault()->camel('expect100_continue'))); + // Get from cache + $this->assertEquals('Test', Inflector::getDefault()->camel('test', false)); + } +} diff --git a/vendor/guzzle/guzzle/tests/Guzzle/Tests/Inflection/MemoizingInflectorTest.php b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Inflection/MemoizingInflectorTest.php new file mode 100644 index 0000000..f00b7fa --- /dev/null +++ b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Inflection/MemoizingInflectorTest.php @@ -0,0 +1,46 @@ +getMock('Guzzle\Inflection\Inflector', array('snake', 'camel')); + $mock->expects($this->once())->method('snake')->will($this->returnValue('foo_bar')); + $mock->expects($this->once())->method('camel')->will($this->returnValue('FooBar')); + + $inflector = new MemoizingInflector($mock); + $this->assertEquals('foo_bar', $inflector->snake('FooBar')); + $this->assertEquals('foo_bar', $inflector->snake('FooBar')); + $this->assertEquals('FooBar', $inflector->camel('foo_bar')); + $this->assertEquals('FooBar', $inflector->camel('foo_bar')); + } + + public function testProtectsAgainstCacheOverflow() + { + $inflector = new MemoizingInflector(new Inflector(), 10); + for ($i = 1; $i < 11; $i++) { + $inflector->camel('foo_' . $i); + $inflector->snake('Foo' . $i); + } + + $cache = $this->readAttribute($inflector, 'cache'); + $this->assertEquals(10, count($cache['snake'])); + $this->assertEquals(10, count($cache['camel'])); + + $inflector->camel('baz!'); + $inflector->snake('baz!'); + + // Now ensure that 20% of the cache was removed (2), then the item was added + $cache = $this->readAttribute($inflector, 'cache'); + $this->assertEquals(9, count($cache['snake'])); + $this->assertEquals(9, count($cache['camel'])); + } +} diff --git a/vendor/guzzle/guzzle/tests/Guzzle/Tests/Inflection/PreComputedInflectorTest.php b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Inflection/PreComputedInflectorTest.php new file mode 100644 index 0000000..ff2654c --- /dev/null +++ b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Inflection/PreComputedInflectorTest.php @@ -0,0 +1,45 @@ +getMock('Guzzle\Inflection\Inflector', array('snake', 'camel')); + $mock->expects($this->once())->method('snake')->with('Test')->will($this->returnValue('test')); + $mock->expects($this->once())->method('camel')->with('Test')->will($this->returnValue('Test')); + $inflector = new PreComputedInflector($mock, array('FooBar' => 'foo_bar'), array('foo_bar' => 'FooBar')); + $this->assertEquals('FooBar', $inflector->camel('foo_bar')); + $this->assertEquals('foo_bar', $inflector->snake('FooBar')); + $this->assertEquals('Test', $inflector->camel('Test')); + $this->assertEquals('test', $inflector->snake('Test')); + } + + public function testMirrorsPrecomputedValues() + { + $mock = $this->getMock('Guzzle\Inflection\Inflector', array('snake', 'camel')); + $mock->expects($this->never())->method('snake'); + $mock->expects($this->never())->method('camel'); + $inflector = new PreComputedInflector($mock, array('Zeep' => 'zeep'), array(), true); + $this->assertEquals('Zeep', $inflector->camel('zeep')); + $this->assertEquals('zeep', $inflector->snake('Zeep')); + } + + public function testMirrorsPrecomputedValuesByMerging() + { + $mock = $this->getMock('Guzzle\Inflection\Inflector', array('snake', 'camel')); + $mock->expects($this->never())->method('snake'); + $mock->expects($this->never())->method('camel'); + $inflector = new PreComputedInflector($mock, array('Zeep' => 'zeep'), array('foo' => 'Foo'), true); + $this->assertEquals('Zeep', $inflector->camel('zeep')); + $this->assertEquals('zeep', $inflector->snake('Zeep')); + $this->assertEquals('Foo', $inflector->camel('foo')); + $this->assertEquals('foo', $inflector->snake('Foo')); + } +} diff --git a/vendor/guzzle/guzzle/tests/Guzzle/Tests/Iterator/AppendIteratorTest.php b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Iterator/AppendIteratorTest.php new file mode 100644 index 0000000..8d6ae84 --- /dev/null +++ b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Iterator/AppendIteratorTest.php @@ -0,0 +1,29 @@ + 1, + 'b' => 2 + )); + $b = new \ArrayIterator(array()); + $c = new \ArrayIterator(array( + 'c' => 3, + 'd' => 4 + )); + $i = new AppendIterator(); + $i->append($a); + $i->append($b); + $i->append($c); + $this->assertEquals(array(1, 2, 3, 4), iterator_to_array($i, false)); + } +} diff --git a/vendor/guzzle/guzzle/tests/Guzzle/Tests/Iterator/ChunkedIteratorTest.php b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Iterator/ChunkedIteratorTest.php new file mode 100644 index 0000000..ec4c129 --- /dev/null +++ b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Iterator/ChunkedIteratorTest.php @@ -0,0 +1,52 @@ +assertEquals(11, count($chunks)); + foreach ($chunks as $j => $chunk) { + $this->assertEquals(range($j * 10, min(100, $j * 10 + 9)), $chunk); + } + } + + public function testChunksIteratorWithOddValues() + { + $chunked = new ChunkedIterator(new \ArrayIterator(array(1, 2, 3, 4, 5)), 2); + $chunks = iterator_to_array($chunked, false); + $this->assertEquals(3, count($chunks)); + $this->assertEquals(array(1, 2), $chunks[0]); + $this->assertEquals(array(3, 4), $chunks[1]); + $this->assertEquals(array(5), $chunks[2]); + } + + public function testMustNotTerminateWithTraversable() + { + $traversable = simplexml_load_string('')->foo; + $chunked = new ChunkedIterator($traversable, 2); + $actual = iterator_to_array($chunked, false); + $this->assertCount(2, $actual); + } + + public function testSizeOfZeroMakesIteratorInvalid() { + $chunked = new ChunkedIterator(new \ArrayIterator(range(1, 5)), 0); + $chunked->rewind(); + $this->assertFalse($chunked->valid()); + } + + /** + * @expectedException \InvalidArgumentException + */ + public function testSizeLowerZeroThrowsException() { + new ChunkedIterator(new \ArrayIterator(range(1, 5)), -1); + } +} diff --git a/vendor/guzzle/guzzle/tests/Guzzle/Tests/Iterator/FilterIteratorTest.php b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Iterator/FilterIteratorTest.php new file mode 100644 index 0000000..73b4f69 --- /dev/null +++ b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Iterator/FilterIteratorTest.php @@ -0,0 +1,28 @@ +assertEquals(range(1, 99, 2), iterator_to_array($i, false)); + } + + /** + * @expectedException \InvalidArgumentException + */ + public function testValidatesCallable() + { + $i = new FilterIterator(new \ArrayIterator(), new \stdClass()); + } +} diff --git a/vendor/guzzle/guzzle/tests/Guzzle/Tests/Iterator/MapIteratorTest.php b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Iterator/MapIteratorTest.php new file mode 100644 index 0000000..4de4a6b --- /dev/null +++ b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Iterator/MapIteratorTest.php @@ -0,0 +1,28 @@ +assertEquals(range(0, 1000, 10), iterator_to_array($i, false)); + } + + /** + * @expectedException \InvalidArgumentException + */ + public function testValidatesCallable() + { + $i = new MapIterator(new \ArrayIterator(), new \stdClass()); + } +} diff --git a/vendor/guzzle/guzzle/tests/Guzzle/Tests/Iterator/MethodProxyIteratorTest.php b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Iterator/MethodProxyIteratorTest.php new file mode 100644 index 0000000..5bcf06f --- /dev/null +++ b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Iterator/MethodProxyIteratorTest.php @@ -0,0 +1,28 @@ +append('a'); + $proxy->append('b'); + $this->assertEquals(array('a', 'b'), $i->getArrayCopy()); + $this->assertEquals(array('a', 'b'), $proxy->getArrayCopy()); + } + + public function testUsesInnerIterator() + { + $i = new MethodProxyIterator(new ChunkedIterator(new \ArrayIterator(array(1, 2, 3, 4, 5)), 2)); + $this->assertEquals(3, count(iterator_to_array($i, false))); + } +} diff --git a/vendor/guzzle/guzzle/tests/Guzzle/Tests/Log/ArrayLogAdapterTest.php b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Log/ArrayLogAdapterTest.php new file mode 100644 index 0000000..a66882f --- /dev/null +++ b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Log/ArrayLogAdapterTest.php @@ -0,0 +1,23 @@ +log('test', \LOG_NOTICE, '127.0.0.1'); + $this->assertEquals(array(array('message' => 'test', 'priority' => \LOG_NOTICE, 'extras' => '127.0.0.1')), $adapter->getLogs()); + } + + public function testClearLog() + { + $adapter = new ArrayLogAdapter(); + $adapter->log('test', \LOG_NOTICE, '127.0.0.1'); + $adapter->clearLogs(); + $this->assertEquals(array(), $adapter->getLogs()); + } +} diff --git a/vendor/guzzle/guzzle/tests/Guzzle/Tests/Log/ClosureLogAdapterTest.php b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Log/ClosureLogAdapterTest.php new file mode 100644 index 0000000..0177dc0 --- /dev/null +++ b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Log/ClosureLogAdapterTest.php @@ -0,0 +1,30 @@ +adapter = new ClosureLogAdapter(function($message, $priority, $extras = null) use ($that, &$modified) { + $modified = array($message, $priority, $extras); + }); + $this->adapter->log('test', LOG_NOTICE, '127.0.0.1'); + $this->assertEquals(array('test', LOG_NOTICE, '127.0.0.1'), $modified); + } + + /** + * @expectedException InvalidArgumentException + */ + public function testThrowsExceptionWhenNotCallable() + { + $this->adapter = new ClosureLogAdapter(123); + } +} diff --git a/vendor/guzzle/guzzle/tests/Guzzle/Tests/Log/MessageFormatterTest.php b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Log/MessageFormatterTest.php new file mode 100644 index 0000000..3ff4b07 --- /dev/null +++ b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Log/MessageFormatterTest.php @@ -0,0 +1,143 @@ +request = new EntityEnclosingRequest('POST', 'http://foo.com?q=test', array( + 'X-Foo' => 'bar', + 'Authorization' => 'Baz' + )); + $this->request->setBody(EntityBody::factory('Hello')); + + $this->response = new Response(200, array( + 'X-Test' => 'Abc' + ), 'Foo'); + + $this->handle = $this->getMockBuilder('Guzzle\Http\Curl\CurlHandle') + ->disableOriginalConstructor() + ->setMethods(array('getError', 'getErrorNo', 'getStderr', 'getInfo')) + ->getMock(); + + $this->handle->expects($this->any()) + ->method('getError') + ->will($this->returnValue('e')); + + $this->handle->expects($this->any()) + ->method('getErrorNo') + ->will($this->returnValue('123')); + + $this->handle->expects($this->any()) + ->method('getStderr') + ->will($this->returnValue('testing')); + + $this->handle->expects($this->any()) + ->method('getInfo') + ->will($this->returnValueMap(array( + array(CURLINFO_CONNECT_TIME, '123'), + array(CURLINFO_TOTAL_TIME, '456') + ))); + } + + public function logProvider() + { + return array( + // Uses the cache for the second time + array('{method} - {method}', 'POST - POST'), + array('{url}', 'http://foo.com?q=test'), + array('{port}', '80'), + array('{resource}', '/?q=test'), + array('{host}', 'foo.com'), + array('{hostname}', gethostname()), + array('{protocol}/{version}', 'HTTP/1.1'), + array('{code} {phrase}', '200 OK'), + array('{req_header_Foo}', ''), + array('{req_header_X-Foo}', 'bar'), + array('{req_header_Authorization}', 'Baz'), + array('{res_header_foo}', ''), + array('{res_header_X-Test}', 'Abc'), + array('{req_body}', 'Hello'), + array('{res_body}', 'Foo'), + array('{curl_stderr}', 'testing'), + array('{curl_error}', 'e'), + array('{curl_code}', '123'), + array('{connect_time}', '123'), + array('{total_time}', '456') + ); + } + + /** + * @dataProvider logProvider + */ + public function testFormatsMessages($template, $output) + { + $formatter = new MessageFormatter($template); + $this->assertEquals($output, $formatter->format($this->request, $this->response, $this->handle)); + } + + public function testFormatsRequestsAndResponses() + { + $formatter = new MessageFormatter(); + $formatter->setTemplate('{request}{response}'); + $this->assertEquals($this->request . $this->response, $formatter->format($this->request, $this->response)); + } + + public function testAddsTimestamp() + { + $formatter = new MessageFormatter('{ts}'); + $this->assertNotEmpty($formatter->format($this->request, $this->response)); + } + + public function testUsesResponseWhenNoHandleAndGettingCurlInformation() + { + $formatter = new MessageFormatter('{connect_time}/{total_time}'); + $response = $this->getMockBuilder('Guzzle\Http\Message\Response') + ->setConstructorArgs(array(200)) + ->setMethods(array('getInfo')) + ->getMock(); + $response->expects($this->exactly(2)) + ->method('getInfo') + ->will($this->returnValueMap(array( + array('connect_time', '1'), + array('total_time', '2'), + ))); + $this->assertEquals('1/2', $formatter->format($this->request, $response)); + } + + public function testUsesEmptyStringWhenNoHandleAndNoResponse() + { + $formatter = new MessageFormatter('{connect_time}/{total_time}'); + $this->assertEquals('/', $formatter->format($this->request)); + } + + public function testInjectsTotalTime() + { + $out = ''; + $formatter = new MessageFormatter('{connect_time}/{total_time}'); + $adapter = new ClosureLogAdapter(function ($m) use (&$out) { $out .= $m; }); + $log = new LogPlugin($adapter, $formatter); + $this->getServer()->enqueue("HTTP/1.1 200 OK\r\nContent-Length: 2\r\n\r\nHI"); + $client = new Client($this->getServer()->getUrl()); + $client->addSubscriber($log); + $client->get('/')->send(); + $this->assertNotEquals('/', $out); + } +} diff --git a/vendor/guzzle/guzzle/tests/Guzzle/Tests/Log/PsrLogAdapterTest.php b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Log/PsrLogAdapterTest.php new file mode 100644 index 0000000..7b72dd6 --- /dev/null +++ b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Log/PsrLogAdapterTest.php @@ -0,0 +1,25 @@ +pushHandler($handler); + $adapter = new PsrLogAdapter($log); + $adapter->log('test!', LOG_INFO); + $this->assertTrue($handler->hasInfoRecords()); + $this->assertSame($log, $adapter->getLogObject()); + } +} diff --git a/vendor/guzzle/guzzle/tests/Guzzle/Tests/Log/Zf2LogAdapterTest.php b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Log/Zf2LogAdapterTest.php new file mode 100644 index 0000000..1b61283 --- /dev/null +++ b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Log/Zf2LogAdapterTest.php @@ -0,0 +1,51 @@ +stream = fopen('php://temp', 'r+'); + $this->log = new Logger(); + $this->log->addWriter(new Stream($this->stream)); + $this->adapter = new Zf2LogAdapter($this->log); + + } + + public function testLogsMessagesToAdaptedObject() + { + // Test without a priority + $this->adapter->log('Zend_Test!', \LOG_NOTICE); + rewind($this->stream); + $contents = stream_get_contents($this->stream); + $this->assertEquals(1, substr_count($contents, 'Zend_Test!')); + + // Test with a priority + $this->adapter->log('Zend_Test!', \LOG_ALERT); + rewind($this->stream); + $contents = stream_get_contents($this->stream); + $this->assertEquals(2, substr_count($contents, 'Zend_Test!')); + } + + public function testExposesAdaptedLogObject() + { + $this->assertEquals($this->log, $this->adapter->getLogObject()); + } +} diff --git a/vendor/guzzle/guzzle/tests/Guzzle/Tests/Mock/CustomResponseModel.php b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Mock/CustomResponseModel.php new file mode 100644 index 0000000..3fb6527 --- /dev/null +++ b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Mock/CustomResponseModel.php @@ -0,0 +1,21 @@ +command = $command; + } +} diff --git a/vendor/guzzle/guzzle/tests/Guzzle/Tests/Mock/ErrorResponseMock.php b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Mock/ErrorResponseMock.php new file mode 100644 index 0000000..aabb15f --- /dev/null +++ b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Mock/ErrorResponseMock.php @@ -0,0 +1,25 @@ +command = $command; + $this->response = $response; + $this->message = 'Error from ' . $response; + } +} diff --git a/vendor/guzzle/guzzle/tests/Guzzle/Tests/Mock/ExceptionMock.php b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Mock/ExceptionMock.php new file mode 100644 index 0000000..97a1974 --- /dev/null +++ b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Mock/ExceptionMock.php @@ -0,0 +1,11 @@ +multiHandle; + } +} diff --git a/vendor/guzzle/guzzle/tests/Guzzle/Tests/Mock/MockObserver.php b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Mock/MockObserver.php new file mode 100644 index 0000000..11e22eb --- /dev/null +++ b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Mock/MockObserver.php @@ -0,0 +1,65 @@ +events as $event) { + if ($event->getName() == $eventName) { + return true; + } + } + + return false; + } + + public function getLastEvent() + { + return end($this->events); + } + + public function count() + { + return count($this->events); + } + + public function getGrouped() + { + $events = array(); + foreach ($this->events as $event) { + if (!isset($events[$event->getName()])) { + $events[$event->getName()] = array(); + } + $events[$event->getName()][] = $event; + } + + return $events; + } + + public function getData($event, $key, $occurrence = 0) + { + $grouped = $this->getGrouped(); + if (isset($grouped[$event])) { + return $grouped[$event][$occurrence][$key]; + } + + return null; + } + + public function update(Event $event) + { + $this->events[] = $event; + } +} diff --git a/vendor/guzzle/guzzle/tests/Guzzle/Tests/Mock/MockSubject.php b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Mock/MockSubject.php new file mode 100644 index 0000000..e011959 --- /dev/null +++ b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Mock/MockSubject.php @@ -0,0 +1,7 @@ + 'allseeing-i.com', + 'path' => '/', + 'data' => array( + 'PHPSESSID' => '6c951590e7a9359bcedde25cda73e43c' + ), + 'max_age' => NULL, + 'expires' => 'Sat, 26-Jul-2008 17:00:42 GMT', + 'version' => NULL, + 'secure' => NULL, + 'discard' => NULL, + 'port' => NULL, + 'cookies' => array( + 'ASIHTTPRequestTestCookie' => 'This+is+the+value' + ), + 'comment' => null, + 'comment_url' => null, + 'http_only' => false + ) + ), + array('', false), + array('foo', false), + // Test setting a blank value for a cookie + array(array( + 'foo=', 'foo =', 'foo =;', 'foo= ;', 'foo =', 'foo= '), + array( + 'cookies' => array( + 'foo' => '' + ), + 'data' => array(), + 'discard' => null, + 'domain' => null, + 'expires' => null, + 'max_age' => null, + 'path' => '/', + 'port' => null, + 'secure' => null, + 'version' => null, + 'comment' => null, + 'comment_url' => null, + 'http_only' => false + ) + ), + // Test setting a value and removing quotes + array(array( + 'foo=1', 'foo =1', 'foo =1;', 'foo=1 ;', 'foo =1', 'foo= 1', 'foo = 1 ;', 'foo="1"', 'foo="1";', 'foo= "1";'), + array( + 'cookies' => array( + 'foo' => '1' + ), + 'data' => array(), + 'discard' => null, + 'domain' => null, + 'expires' => null, + 'max_age' => null, + 'path' => '/', + 'port' => null, + 'secure' => null, + 'version' => null, + 'comment' => null, + 'comment_url' => null, + 'http_only' => false + ) + ), + // Test setting multiple values + array(array( + 'foo=1; bar=2;', 'foo =1; bar = "2"', 'foo=1; bar=2'), + array( + 'cookies' => array( + 'foo' => '1', + 'bar' => '2', + ), + 'data' => array(), + 'discard' => null, + 'domain' => null, + 'expires' => null, + 'max_age' => null, + 'path' => '/', + 'port' => null, + 'secure' => null, + 'version' => null, + 'comment' => null, + 'comment_url' => null, + 'http_only' => false + ) + ), + // Tests getting the domain and path from a reference request + array(array( + 'foo=1; port="80,8081"; httponly', 'foo=1; port="80,8081"; domain=www.test.com; HttpOnly;', 'foo=1; ; domain=www.test.com; path=/path; port="80,8081"; HttpOnly;'), + array( + 'cookies' => array( + 'foo' => 1 + ), + 'data' => array(), + 'discard' => null, + 'domain' => 'www.test.com', + 'expires' => null, + 'max_age' => null, + 'path' => '/path', + 'port' => array('80', '8081'), + 'secure' => null, + 'version' => null, + 'comment' => null, + 'comment_url' => null, + 'http_only' => true + ), + 'http://www.test.com/path/' + ), + // Some of the following tests are based on http://framework.zend.com/svn/framework/standard/trunk/tests/Zend/Http/CookieTest.php + array( + 'justacookie=foo; domain=example.com', + array( + 'cookies' => array( + 'justacookie' => 'foo' + ), + 'domain' => 'example.com', + 'data' => array(), + 'discard' => null, + 'expires' => null, + 'max_age' => null, + 'path' => '/', + 'port' => null, + 'secure' => null, + 'version' => null, + 'comment' => null, + 'comment_url' => null, + 'http_only' => false + ) + ), + array( + 'expires=tomorrow; secure; path=/Space Out/; expires=Tue, 21-Nov-2006 08:33:44 GMT; domain=.example.com', + array( + 'cookies' => array( + 'expires' => 'tomorrow' + ), + 'domain' => '.example.com', + 'path' => '/Space Out/', + 'expires' => 'Tue, 21-Nov-2006 08:33:44 GMT', + 'data' => array(), + 'discard' => null, + 'port' => null, + 'secure' => true, + 'version' => null, + 'max_age' => null, + 'comment' => null, + 'comment_url' => null, + 'http_only' => false + ) + ), + array( + 'domain=unittests; expires=Tue, 21-Nov-2006 08:33:44 GMT; domain=example.com; path=/some value/', + array( + 'cookies' => array( + 'domain' => 'unittests' + ), + 'domain' => 'example.com', + 'path' => '/some value/', + 'expires' => 'Tue, 21-Nov-2006 08:33:44 GMT', + 'secure' => false, + 'data' => array(), + 'discard' => null, + 'max_age' => null, + 'port' => null, + 'version' => null, + 'comment' => null, + 'comment_url' => null, + 'http_only' => false + ) + ), + array( + 'path=indexAction; path=/; domain=.foo.com; expires=Tue, 21-Nov-2006 08:33:44 GMT', + array( + 'cookies' => array( + 'path' => 'indexAction' + ), + 'domain' => '.foo.com', + 'path' => '/', + 'expires' => 'Tue, 21-Nov-2006 08:33:44 GMT', + 'secure' => false, + 'data' => array(), + 'discard' => null, + 'max_age' => null, + 'port' => null, + 'version' => null, + 'comment' => null, + 'comment_url' => null, + 'http_only' => false + ) + ), + array( + 'secure=sha1; secure; SECURE; domain=some.really.deep.domain.com; version=1; Max-Age=86400', + array( + 'cookies' => array( + 'secure' => 'sha1' + ), + 'domain' => 'some.really.deep.domain.com', + 'path' => '/', + 'secure' => true, + 'data' => array(), + 'discard' => null, + 'expires' => time() + 86400, + 'max_age' => 86400, + 'port' => null, + 'version' => 1, + 'comment' => null, + 'comment_url' => null, + 'http_only' => false + ) + ), + array( + 'PHPSESSID=123456789+abcd%2Cef; secure; discard; domain=.localdomain; path=/foo/baz; expires=Tue, 21-Nov-2006 08:33:44 GMT;', + array( + 'cookies' => array( + 'PHPSESSID' => '123456789+abcd%2Cef' + ), + 'domain' => '.localdomain', + 'path' => '/foo/baz', + 'expires' => 'Tue, 21-Nov-2006 08:33:44 GMT', + 'secure' => true, + 'data' => array(), + 'discard' => true, + 'max_age' => null, + 'port' => null, + 'version' => null, + 'comment' => null, + 'comment_url' => null, + 'http_only' => false + ) + ), + // rfc6265#section-5.1.4 + array( + 'cookie=value', + array( + 'cookies' => array( + 'cookie' => 'value' + ), + 'domain' => 'example.com', + 'data' => array(), + 'discard' => null, + 'expires' => null, + 'max_age' => null, + 'path' => '/some/path', + 'port' => null, + 'secure' => null, + 'version' => null, + 'comment' => null, + 'comment_url' => null, + 'http_only' => false + ), + 'http://example.com/some/path/test.html' + ), + array( + 'empty=path', + array( + 'cookies' => array( + 'empty' => 'path' + ), + 'domain' => 'example.com', + 'data' => array(), + 'discard' => null, + 'expires' => null, + 'max_age' => null, + 'path' => '/', + 'port' => null, + 'secure' => null, + 'version' => null, + 'comment' => null, + 'comment_url' => null, + 'http_only' => false + ), + 'http://example.com/test.html' + ), + array( + 'baz=qux', + array( + 'cookies' => array( + 'baz' => 'qux' + ), + 'domain' => 'example.com', + 'data' => array(), + 'discard' => null, + 'expires' => null, + 'max_age' => null, + 'path' => '/', + 'port' => null, + 'secure' => null, + 'version' => null, + 'comment' => null, + 'comment_url' => null, + 'http_only' => false + ), + 'http://example.com?query=here' + ), + array( + 'test=noSlashPath; path=someString', + array( + 'cookies' => array( + 'test' => 'noSlashPath' + ), + 'domain' => 'example.com', + 'data' => array(), + 'discard' => null, + 'expires' => null, + 'max_age' => null, + 'path' => '/real/path', + 'port' => null, + 'secure' => null, + 'version' => null, + 'comment' => null, + 'comment_url' => null, + 'http_only' => false + ), + 'http://example.com/real/path/' + ), + ); + } + + /** + * @dataProvider cookieParserDataProvider + */ + public function testParseCookie($cookie, $parsed, $url = null) + { + $c = $this->cookieParserClass; + $parser = new $c(); + + $request = null; + if ($url) { + $url = Url::factory($url); + $host = $url->getHost(); + $path = $url->getPath(); + } else { + $host = ''; + $path = ''; + } + + foreach ((array) $cookie as $c) { + $p = $parser->parseCookie($c, $host, $path); + + // Remove expires values from the assertion if they are relatively equal by allowing a 5 minute difference + if ($p['expires'] != $parsed['expires']) { + if (abs($p['expires'] - $parsed['expires']) < 300) { + unset($p['expires']); + unset($parsed['expires']); + } + } + + if (is_array($parsed)) { + foreach ($parsed as $key => $value) { + $this->assertEquals($parsed[$key], $p[$key], 'Comparing ' . $key . ' ' . var_export($value, true) . ' : ' . var_export($parsed, true) . ' | ' . var_export($p, true)); + } + + foreach ($p as $key => $value) { + $this->assertEquals($p[$key], $parsed[$key], 'Comparing ' . $key . ' ' . var_export($value, true) . ' : ' . var_export($parsed, true) . ' | ' . var_export($p, true)); + } + } else { + $this->assertEquals($parsed, $p); + } + } + } +} diff --git a/vendor/guzzle/guzzle/tests/Guzzle/Tests/Parser/Cookie/CookieParserTest.php b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Parser/Cookie/CookieParserTest.php new file mode 100644 index 0000000..75d336f --- /dev/null +++ b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Parser/Cookie/CookieParserTest.php @@ -0,0 +1,22 @@ +parseCookie('foo=baz+bar', null, null, true); + $this->assertEquals(array( + 'foo' => 'baz bar' + ), $result['cookies']); + } +} diff --git a/vendor/guzzle/guzzle/tests/Guzzle/Tests/Parser/Message/MessageParserProvider.php b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Parser/Message/MessageParserProvider.php new file mode 100644 index 0000000..da58bb4 --- /dev/null +++ b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Parser/Message/MessageParserProvider.php @@ -0,0 +1,225 @@ + 'GET', + 'protocol' => 'HTTP', + 'version' => '1.1', + 'request_url' => array( + 'scheme' => 'http', + 'host' => '', + 'port' => '', + 'path' => '/', + 'query' => '' + ), + 'headers' => array(), + 'body' => '' + )), + // Path and query string, multiple header values per header and case sensitive storage + array("HEAD /path?query=foo HTTP/1.0\r\nHost: example.com\r\nX-Foo: foo\r\nx-foo: Bar\r\nX-Foo: foo\r\nX-Foo: Baz\r\n\r\n", array( + 'method' => 'HEAD', + 'protocol' => 'HTTP', + 'version' => '1.0', + 'request_url' => array( + 'scheme' => 'http', + 'host' => 'example.com', + 'port' => '', + 'path' => '/path', + 'query' => 'query=foo' + ), + 'headers' => array( + 'Host' => 'example.com', + 'X-Foo' => array('foo', 'foo', 'Baz'), + 'x-foo' => 'Bar' + ), + 'body' => '' + )), + // Includes a body + array("PUT / HTTP/1.0\r\nhost: example.com:443\r\nContent-Length: 4\r\n\r\ntest", array( + 'method' => 'PUT', + 'protocol' => 'HTTP', + 'version' => '1.0', + 'request_url' => array( + 'scheme' => 'https', + 'host' => 'example.com', + 'port' => '443', + 'path' => '/', + 'query' => '' + ), + 'headers' => array( + 'host' => 'example.com:443', + 'Content-Length' => '4' + ), + 'body' => 'test' + )), + // Includes Authorization headers + array("GET / HTTP/1.1\r\nHost: example.com:8080\r\nAuthorization: Basic {$auth}\r\n\r\n", array( + 'method' => 'GET', + 'protocol' => 'HTTP', + 'version' => '1.1', + 'request_url' => array( + 'scheme' => 'http', + 'host' => 'example.com', + 'port' => '8080', + 'path' => '/', + 'query' => '' + ), + 'headers' => array( + 'Host' => 'example.com:8080', + 'Authorization' => "Basic {$auth}" + ), + 'body' => '' + )), + // Include authorization header + array("GET / HTTP/1.1\r\nHost: example.com:8080\r\nauthorization: Basic {$auth}\r\n\r\n", array( + 'method' => 'GET', + 'protocol' => 'HTTP', + 'version' => '1.1', + 'request_url' => array( + 'scheme' => 'http', + 'host' => 'example.com', + 'port' => '8080', + 'path' => '/', + 'query' => '' + ), + 'headers' => array( + 'Host' => 'example.com:8080', + 'authorization' => "Basic {$auth}" + ), + 'body' => '' + )), + ); + } + + public function responseProvider() + { + return array( + // Empty request + array('', false), + + array("HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n", array( + 'protocol' => 'HTTP', + 'version' => '1.1', + 'code' => '200', + 'reason_phrase' => 'OK', + 'headers' => array( + 'Content-Length' => 0 + ), + 'body' => '' + )), + array("HTTP/1.0 400 Bad Request\r\nContent-Length: 0\r\n\r\n", array( + 'protocol' => 'HTTP', + 'version' => '1.0', + 'code' => '400', + 'reason_phrase' => 'Bad Request', + 'headers' => array( + 'Content-Length' => 0 + ), + 'body' => '' + )), + array("HTTP/1.0 100 Continue\r\n\r\n", array( + 'protocol' => 'HTTP', + 'version' => '1.0', + 'code' => '100', + 'reason_phrase' => 'Continue', + 'headers' => array(), + 'body' => '' + )), + array("HTTP/1.1 204 No Content\r\nX-Foo: foo\r\nx-foo: Bar\r\nX-Foo: foo\r\n\r\n", array( + 'protocol' => 'HTTP', + 'version' => '1.1', + 'code' => '204', + 'reason_phrase' => 'No Content', + 'headers' => array( + 'X-Foo' => array('foo', 'foo'), + 'x-foo' => 'Bar' + ), + 'body' => '' + )), + array("HTTP/1.1 200 Ok that is great!\r\nContent-Length: 4\r\n\r\nTest", array( + 'protocol' => 'HTTP', + 'version' => '1.1', + 'code' => '200', + 'reason_phrase' => 'Ok that is great!', + 'headers' => array( + 'Content-Length' => 4 + ), + 'body' => 'Test' + )), + ); + } + + public function compareRequestResults($result, $expected) + { + if (!$result) { + $this->assertFalse($expected); + return; + } + + $this->assertEquals($result['method'], $expected['method']); + $this->assertEquals($result['protocol'], $expected['protocol']); + $this->assertEquals($result['version'], $expected['version']); + $this->assertEquals($result['request_url'], $expected['request_url']); + $this->assertEquals($result['body'], $expected['body']); + $this->compareHttpHeaders($result['headers'], $expected['headers']); + } + + public function compareResponseResults($result, $expected) + { + if (!$result) { + $this->assertFalse($expected); + return; + } + + $this->assertEquals($result['protocol'], $expected['protocol']); + $this->assertEquals($result['version'], $expected['version']); + $this->assertEquals($result['code'], $expected['code']); + $this->assertEquals($result['reason_phrase'], $expected['reason_phrase']); + $this->assertEquals($result['body'], $expected['body']); + $this->compareHttpHeaders($result['headers'], $expected['headers']); + } + + protected function normalizeHeaders($headers) + { + $normalized = array(); + foreach ($headers as $key => $value) { + $key = strtolower($key); + if (!isset($normalized[$key])) { + $normalized[$key] = $value; + } elseif (!is_array($normalized[$key])) { + $normalized[$key] = array($value); + } else { + $normalized[$key][] = $value; + } + } + + foreach ($normalized as $key => &$value) { + if (is_array($value)) { + sort($value); + } + } + + return $normalized; + } + + public function compareHttpHeaders($result, $expected) + { + // Aggregate all headers case-insensitively + $result = $this->normalizeHeaders($result); + $expected = $this->normalizeHeaders($expected); + $this->assertEquals($result, $expected); + } +} diff --git a/vendor/guzzle/guzzle/tests/Guzzle/Tests/Parser/Message/MessageParserTest.php b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Parser/Message/MessageParserTest.php new file mode 100644 index 0000000..2f52228 --- /dev/null +++ b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Parser/Message/MessageParserTest.php @@ -0,0 +1,58 @@ +compareRequestResults($parts, $parser->parseRequest($message)); + } + + /** + * @dataProvider responseProvider + */ + public function testParsesResponses($message, $parts) + { + $parser = new MessageParser(); + $this->compareResponseResults($parts, $parser->parseResponse($message)); + } + + public function testParsesRequestsWithMissingProtocol() + { + $parser = new MessageParser(); + $parts = $parser->parseRequest("GET /\r\nHost: Foo.com\r\n\r\n"); + $this->assertEquals('GET', $parts['method']); + $this->assertEquals('HTTP', $parts['protocol']); + $this->assertEquals('1.1', $parts['version']); + } + + public function testParsesRequestsWithMissingVersion() + { + $parser = new MessageParser(); + $parts = $parser->parseRequest("GET / HTTP\r\nHost: Foo.com\r\n\r\n"); + $this->assertEquals('GET', $parts['method']); + $this->assertEquals('HTTP', $parts['protocol']); + $this->assertEquals('1.1', $parts['version']); + } + + public function testParsesResponsesWithMissingReasonPhrase() + { + $parser = new MessageParser(); + $parts = $parser->parseResponse("HTTP/1.1 200\r\n\r\n"); + $this->assertEquals('200', $parts['code']); + $this->assertEquals('', $parts['reason_phrase']); + $this->assertEquals('HTTP', $parts['protocol']); + $this->assertEquals('1.1', $parts['version']); + } +} diff --git a/vendor/guzzle/guzzle/tests/Guzzle/Tests/Parser/Message/PeclHttpMessageParserTest.php b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Parser/Message/PeclHttpMessageParserTest.php new file mode 100644 index 0000000..6706e20 --- /dev/null +++ b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Parser/Message/PeclHttpMessageParserTest.php @@ -0,0 +1,36 @@ +markTestSkipped('pecl_http is not available.'); + } + } + + /** + * @dataProvider requestProvider + */ + public function testParsesRequests($message, $parts) + { + $parser = new PeclHttpMessageParser(); + $this->compareRequestResults($parts, $parser->parseRequest($message)); + } + + /** + * @dataProvider responseProvider + */ + public function testParsesResponses($message, $parts) + { + $parser = new PeclHttpMessageParser(); + $this->compareResponseResults($parts, $parser->parseResponse($message)); + } +} diff --git a/vendor/guzzle/guzzle/tests/Guzzle/Tests/Parser/ParserRegistryTest.php b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Parser/ParserRegistryTest.php new file mode 100644 index 0000000..7675efb --- /dev/null +++ b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Parser/ParserRegistryTest.php @@ -0,0 +1,33 @@ +registerParser('foo', $c); + $this->assertSame($c, $r->getParser('foo')); + } + + public function testReturnsNullWhenNotFound() + { + $r = new ParserRegistry(); + $this->assertNull($r->getParser('FOO')); + } + + public function testReturnsLazyLoadedDefault() + { + $r = new ParserRegistry(); + $c = $r->getParser('cookie'); + $this->assertInstanceOf('Guzzle\Parser\Cookie\CookieParser', $c); + $this->assertSame($c, $r->getParser('cookie')); + } +} diff --git a/vendor/guzzle/guzzle/tests/Guzzle/Tests/Parser/UriTemplate/AbstractUriTemplateTest.php b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Parser/UriTemplate/AbstractUriTemplateTest.php new file mode 100644 index 0000000..a05fc2e --- /dev/null +++ b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Parser/UriTemplate/AbstractUriTemplateTest.php @@ -0,0 +1,113 @@ + 'value', + 'hello' => 'Hello World!', + 'empty' => '', + 'path' => '/foo/bar', + 'x' => '1024', + 'y' => '768', + 'null' => null, + 'list' => array('red', 'green', 'blue'), + 'keys' => array( + "semi" => ';', + "dot" => '.', + "comma" => ',' + ), + 'empty_keys' => array(), + ); + + return array_map(function($t) use ($params) { + $t[] = $params; + return $t; + }, array( + array('foo', 'foo'), + array('{var}', 'value'), + array('{hello}', 'Hello%20World%21'), + array('{+var}', 'value'), + array('{+hello}', 'Hello%20World!'), + array('{+path}/here', '/foo/bar/here'), + array('here?ref={+path}', 'here?ref=/foo/bar'), + array('X{#var}', 'X#value'), + array('X{#hello}', 'X#Hello%20World!'), + array('map?{x,y}', 'map?1024,768'), + array('{x,hello,y}', '1024,Hello%20World%21,768'), + array('{+x,hello,y}', '1024,Hello%20World!,768'), + array('{+path,x}/here', '/foo/bar,1024/here'), + array('{#x,hello,y}', '#1024,Hello%20World!,768'), + array('{#path,x}/here', '#/foo/bar,1024/here'), + array('X{.var}', 'X.value'), + array('X{.x,y}', 'X.1024.768'), + array('{/var}', '/value'), + array('{/var,x}/here', '/value/1024/here'), + array('{;x,y}', ';x=1024;y=768'), + array('{;x,y,empty}', ';x=1024;y=768;empty'), + array('{?x,y}', '?x=1024&y=768'), + array('{?x,y,empty}', '?x=1024&y=768&empty='), + array('?fixed=yes{&x}', '?fixed=yes&x=1024'), + array('{&x,y,empty}', '&x=1024&y=768&empty='), + array('{var:3}', 'val'), + array('{var:30}', 'value'), + array('{list}', 'red,green,blue'), + array('{list*}', 'red,green,blue'), + array('{keys}', 'semi,%3B,dot,.,comma,%2C'), + array('{keys*}', 'semi=%3B,dot=.,comma=%2C'), + array('{+path:6}/here', '/foo/b/here'), + array('{+list}', 'red,green,blue'), + array('{+list*}', 'red,green,blue'), + array('{+keys}', 'semi,;,dot,.,comma,,'), + array('{+keys*}', 'semi=;,dot=.,comma=,'), + array('{#path:6}/here', '#/foo/b/here'), + array('{#list}', '#red,green,blue'), + array('{#list*}', '#red,green,blue'), + array('{#keys}', '#semi,;,dot,.,comma,,'), + array('{#keys*}', '#semi=;,dot=.,comma=,'), + array('X{.var:3}', 'X.val'), + array('X{.list}', 'X.red,green,blue'), + array('X{.list*}', 'X.red.green.blue'), + array('X{.keys}', 'X.semi,%3B,dot,.,comma,%2C'), + array('X{.keys*}', 'X.semi=%3B.dot=..comma=%2C'), + array('{/var:1,var}', '/v/value'), + array('{/list}', '/red,green,blue'), + array('{/list*}', '/red/green/blue'), + array('{/list*,path:4}', '/red/green/blue/%2Ffoo'), + array('{/keys}', '/semi,%3B,dot,.,comma,%2C'), + array('{/keys*}', '/semi=%3B/dot=./comma=%2C'), + array('{;hello:5}', ';hello=Hello'), + array('{;list}', ';list=red,green,blue'), + array('{;list*}', ';list=red;list=green;list=blue'), + array('{;keys}', ';keys=semi,%3B,dot,.,comma,%2C'), + array('{;keys*}', ';semi=%3B;dot=.;comma=%2C'), + array('{?var:3}', '?var=val'), + array('{?list}', '?list=red,green,blue'), + array('{?list*}', '?list=red&list=green&list=blue'), + array('{?keys}', '?keys=semi,%3B,dot,.,comma,%2C'), + array('{?keys*}', '?semi=%3B&dot=.&comma=%2C'), + array('{&var:3}', '&var=val'), + array('{&list}', '&list=red,green,blue'), + array('{&list*}', '&list=red&list=green&list=blue'), + array('{&keys}', '&keys=semi,%3B,dot,.,comma,%2C'), + array('{&keys*}', '&semi=%3B&dot=.&comma=%2C'), + array('{.null}', ''), + array('{.null,var}', '.value'), + array('X{.empty_keys*}', 'X'), + array('X{.empty_keys}', 'X'), + // Test that missing expansions are skipped + array('test{&missing*}', 'test'), + // Test that multiple expansions can be set + array('http://{var}/{var:2}{?keys*}', 'http://value/va?semi=%3B&dot=.&comma=%2C'), + // Test more complex query string stuff + array('http://www.test.com{+path}{?var,keys*}', 'http://www.test.com/foo/bar?var=value&semi=%3B&dot=.&comma=%2C') + )); + } +} diff --git a/vendor/guzzle/guzzle/tests/Guzzle/Tests/Parser/UriTemplate/PeclUriTemplateTest.php b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Parser/UriTemplate/PeclUriTemplateTest.php new file mode 100644 index 0000000..633c5d5 --- /dev/null +++ b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Parser/UriTemplate/PeclUriTemplateTest.php @@ -0,0 +1,27 @@ +markTestSkipped('uri_template PECL extension must be installed to test PeclUriTemplate'); + } + } + + /** + * @dataProvider templateProvider + */ + public function testExpandsUriTemplates($template, $expansion, $params) + { + $uri = new PeclUriTemplate($template); + $this->assertEquals($expansion, $uri->expand($template, $params)); + } +} diff --git a/vendor/guzzle/guzzle/tests/Guzzle/Tests/Parser/UriTemplate/UriTemplateTest.php b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Parser/UriTemplate/UriTemplateTest.php new file mode 100644 index 0000000..5130d6f --- /dev/null +++ b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Parser/UriTemplate/UriTemplateTest.php @@ -0,0 +1,106 @@ +assertEquals($expansion, $uri->expand($template, $params)); + } + + public function expressionProvider() + { + return array( + array( + '{+var*}', array( + 'operator' => '+', + 'values' => array( + array('value' => 'var', 'modifier' => '*') + ) + ), + ), + array( + '{?keys,var,val}', array( + 'operator' => '?', + 'values' => array( + array('value' => 'keys', 'modifier' => ''), + array('value' => 'var', 'modifier' => ''), + array('value' => 'val', 'modifier' => '') + ) + ), + ), + array( + '{+x,hello,y}', array( + 'operator' => '+', + 'values' => array( + array('value' => 'x', 'modifier' => ''), + array('value' => 'hello', 'modifier' => ''), + array('value' => 'y', 'modifier' => '') + ) + ) + ) + ); + } + + /** + * @dataProvider expressionProvider + */ + public function testParsesExpressions($exp, $data) + { + $template = new UriTemplate($exp); + + // Access the config object + $class = new \ReflectionClass($template); + $method = $class->getMethod('parseExpression'); + $method->setAccessible(true); + + $exp = substr($exp, 1, -1); + $this->assertEquals($data, $method->invokeArgs($template, array($exp))); + } + + /** + * @ticket https://github.com/guzzle/guzzle/issues/90 + */ + public function testAllowsNestedArrayExpansion() + { + $template = new UriTemplate(); + + $result = $template->expand('http://example.com{+path}{/segments}{?query,data*,foo*}', array( + 'path' => '/foo/bar', + 'segments' => array('one', 'two'), + 'query' => 'test', + 'data' => array( + 'more' => array('fun', 'ice cream') + ), + 'foo' => array( + 'baz' => array( + 'bar' => 'fizz', + 'test' => 'buzz' + ), + 'bam' => 'boo' + ) + )); + + $this->assertEquals('http://example.com/foo/bar/one,two?query=test&more%5B0%5D=fun&more%5B1%5D=ice%20cream&baz%5Bbar%5D=fizz&baz%5Btest%5D=buzz&bam=boo', $result); + } + + /** + * @ticket https://github.com/guzzle/guzzle/issues/426 + */ + public function testSetRegex() + { + $template = new UriTemplate(); + $template->setRegex('/\<\$(.+)\>/'); + $this->assertSame('/foo', $template->expand('/<$a>', array('a' => 'foo'))); + } +} diff --git a/vendor/guzzle/guzzle/tests/Guzzle/Tests/Plugin/Async/AsyncPluginTest.php b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Plugin/Async/AsyncPluginTest.php new file mode 100644 index 0000000..16990a5 --- /dev/null +++ b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Plugin/Async/AsyncPluginTest.php @@ -0,0 +1,93 @@ +assertArrayHasKey('request.before_send', $events); + $this->assertArrayHasKey('request.exception', $events); + $this->assertArrayHasKey('curl.callback.progress', $events); + } + + public function testEnablesProgressCallbacks() + { + $p = new AsyncPlugin(); + $request = RequestFactory::getInstance()->create('PUT', 'http://www.example.com'); + $event = new Event(array( + 'request' => $request + )); + $p->onBeforeSend($event); + $this->assertEquals(true, $request->getCurlOptions()->get('progress')); + } + + public function testAddsTimesOutAfterSending() + { + $p = new AsyncPlugin(); + $request = RequestFactory::getInstance()->create('PUT', 'http://www.example.com'); + $handle = CurlHandle::factory($request); + $event = new Event(array( + 'request' => $request, + 'handle' => $handle->getHandle(), + 'uploaded' => 10, + 'upload_size' => 10, + 'downloaded' => 0 + )); + $p->onCurlProgress($event); + } + + public function testEnsuresRequestIsSet() + { + $p = new AsyncPlugin(); + $event = new Event(array( + 'uploaded' => 10, + 'upload_size' => 10, + 'downloaded' => 0 + )); + $p->onCurlProgress($event); + } + + public function testMasksCurlExceptions() + { + $p = new AsyncPlugin(); + $request = RequestFactory::getInstance()->create('PUT', 'http://www.example.com'); + $e = new CurlException('Error'); + $event = new Event(array( + 'request' => $request, + 'exception' => $e + )); + $p->onRequestTimeout($event); + $this->assertEquals(RequestInterface::STATE_COMPLETE, $request->getState()); + $this->assertEquals(200, $request->getResponse()->getStatusCode()); + $this->assertTrue($request->getResponse()->hasHeader('X-Guzzle-Async')); + } + + public function testEnsuresIntegration() + { + $this->getServer()->flush(); + $this->getServer()->enqueue("HTTP/1.1 204 FOO\r\nContent-Length: 4\r\n\r\ntest"); + $client = new Client($this->getServer()->getUrl()); + $request = $client->post('/', null, array( + 'foo' => 'bar' + )); + $request->getEventDispatcher()->addSubscriber(new AsyncPlugin()); + $request->send(); + $this->assertEquals('', $request->getResponse()->getBody(true)); + $this->assertTrue($request->getResponse()->hasHeader('X-Guzzle-Async')); + $received = $this->getServer()->getReceivedRequests(true); + $this->assertEquals('POST', $received[0]->getMethod()); + } +} diff --git a/vendor/guzzle/guzzle/tests/Guzzle/Tests/Plugin/Backoff/AbstractBackoffStrategyTest.php b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Plugin/Backoff/AbstractBackoffStrategyTest.php new file mode 100644 index 0000000..72af263 --- /dev/null +++ b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Plugin/Backoff/AbstractBackoffStrategyTest.php @@ -0,0 +1,86 @@ +getMockBuilder('Guzzle\Plugin\Backoff\AbstractBackoffStrategy') + ->setMethods(array('getDelay', 'makesDecision')) + ->getMockForAbstractClass(); + } + + public function testReturnsZeroWhenNoNextAndGotNull() + { + $request = new Request('GET', 'http://www.foo.com'); + $mock = $this->getMockStrategy(); + $mock->expects($this->atLeastOnce())->method('getDelay')->will($this->returnValue(null)); + $this->assertEquals(0, $mock->getBackoffPeriod(0, $request)); + } + + public function testReturnsFalse() + { + $request = new Request('GET', 'http://www.foo.com'); + $mock = $this->getMockStrategy(); + $mock->expects($this->atLeastOnce())->method('getDelay')->will($this->returnValue(false)); + $this->assertEquals(false, $mock->getBackoffPeriod(0, $request)); + } + + public function testReturnsNextValueWhenNullOrTrue() + { + $request = new Request('GET', 'http://www.foo.com'); + $mock = $this->getMockStrategy(); + $mock->expects($this->atLeastOnce())->method('getDelay')->will($this->returnValue(null)); + $mock->expects($this->any())->method('makesDecision')->will($this->returnValue(false)); + + $mock2 = $this->getMockStrategy(); + $mock2->expects($this->atLeastOnce())->method('getDelay')->will($this->returnValue(10)); + $mock2->expects($this->atLeastOnce())->method('makesDecision')->will($this->returnValue(true)); + $mock->setNext($mock2); + + $this->assertEquals(10, $mock->getBackoffPeriod(0, $request)); + } + + public function testReturnsFalseWhenNullAndNoNext() + { + $request = new Request('GET', 'http://www.foo.com'); + $s = new TruncatedBackoffStrategy(2); + $this->assertFalse($s->getBackoffPeriod(0, $request)); + } + + public function testHasNext() + { + $a = new TruncatedBackoffStrategy(2); + $b = new TruncatedBackoffStrategy(2); + $a->setNext($b); + $this->assertSame($b, $a->getNext()); + } + + public function testSkipsOtherDecisionsInChainWhenOneReturnsTrue() + { + $a = new CallbackBackoffStrategy(function () { return null; }, true); + $b = new CallbackBackoffStrategy(function () { return true; }, true); + $c = new CallbackBackoffStrategy(function () { return null; }, true); + $d = new CallbackBackoffStrategy(function () { return 10; }, false); + $a->setNext($b); + $b->setNext($c); + $c->setNext($d); + $this->assertEquals(10, $a->getBackoffPeriod(2, new Request('GET', 'http://www.foo.com'))); + } + + public function testReturnsZeroWhenDecisionMakerReturnsTrueButNoFurtherStrategiesAreInTheChain() + { + $a = new CallbackBackoffStrategy(function () { return null; }, true); + $b = new CallbackBackoffStrategy(function () { return true; }, true); + $a->setNext($b); + $this->assertSame(0, $a->getBackoffPeriod(2, new Request('GET', 'http://www.foo.com'))); + } +} diff --git a/vendor/guzzle/guzzle/tests/Guzzle/Tests/Plugin/Backoff/BackoffLoggerTest.php b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Plugin/Backoff/BackoffLoggerTest.php new file mode 100644 index 0000000..a64dd82 --- /dev/null +++ b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Plugin/Backoff/BackoffLoggerTest.php @@ -0,0 +1,110 @@ +message = ''; + } + + public function testHasEventList() + { + $this->assertEquals(1, count(BackoffLogger::getSubscribedEvents())); + } + + public function testLogsEvents() + { + list($logPlugin, $request, $response) = $this->getMocks(); + + $response = $this->getMockBuilder('Guzzle\Http\Message\Response') + ->setConstructorArgs(array(503)) + ->setMethods(array('getInfo')) + ->getMock(); + + $response->expects($this->any()) + ->method('getInfo') + ->will($this->returnValue(2)); + + $handle = $this->getMockHandle(); + + $event = new Event(array( + 'request' => $request, + 'response' => $response, + 'retries' => 1, + 'delay' => 3, + 'handle' => $handle + )); + + $logPlugin->onRequestRetry($event); + $this->assertContains( + '] PUT http://www.example.com - 503 Service Unavailable - Retries: 1, Delay: 3, Time: 2, 2, cURL: 30 Foo', + $this->message + ); + } + + public function testCanSetTemplate() + { + $l = new BackoffLogger(new ClosureLogAdapter(function () {})); + $l->setTemplate('foo'); + $t = $this->readAttribute($l, 'formatter'); + $this->assertEquals('foo', $this->readAttribute($t, 'template')); + } + + /** + * @return array + */ + protected function getMocks() + { + $that = $this; + $logger = new ClosureLogAdapter(function ($message) use ($that) { + $that->message .= $message . "\n"; + }); + $logPlugin = new BackoffLogger($logger); + $response = new Response(503); + $request = RequestFactory::getInstance()->create('PUT', 'http://www.example.com', array( + 'Content-Length' => 3, + 'Foo' => 'Bar' + )); + + return array($logPlugin, $request, $response); + } + + /** + * @return CurlHandle + */ + protected function getMockHandle() + { + $handle = $this->getMockBuilder('Guzzle\Http\Curl\CurlHandle') + ->disableOriginalConstructor() + ->setMethods(array('getError', 'getErrorNo', 'getInfo')) + ->getMock(); + + $handle->expects($this->once()) + ->method('getError') + ->will($this->returnValue('Foo')); + + $handle->expects($this->once()) + ->method('getErrorNo') + ->will($this->returnValue(30)); + + $handle->expects($this->any()) + ->method('getInfo') + ->will($this->returnValue(2)); + + return $handle; + } +} diff --git a/vendor/guzzle/guzzle/tests/Guzzle/Tests/Plugin/Backoff/BackoffPluginTest.php b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Plugin/Backoff/BackoffPluginTest.php new file mode 100644 index 0000000..496e49e --- /dev/null +++ b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Plugin/Backoff/BackoffPluginTest.php @@ -0,0 +1,297 @@ +retried = false; + } + + public static function getSubscribedEvents() + { + return array(BackoffPlugin::RETRY_EVENT => 'onRequestRetry'); + } + + public function onRequestRetry(Event $event) + { + $this->retried = $event; + } + + public function testHasEventList() + { + $this->assertEquals(1, count(BackoffPlugin::getAllEvents())); + } + + public function testCreatesDefaultExponentialBackoffPlugin() + { + $plugin = BackoffPlugin::getExponentialBackoff(3, array(204), array(10)); + $this->assertInstanceOf('Guzzle\Plugin\Backoff\BackoffPlugin', $plugin); + $strategy = $this->readAttribute($plugin, 'strategy'); + $this->assertInstanceOf('Guzzle\Plugin\Backoff\TruncatedBackoffStrategy', $strategy); + $this->assertEquals(3, $this->readAttribute($strategy, 'max')); + $strategy = $this->readAttribute($strategy, 'next'); + $this->assertInstanceOf('Guzzle\Plugin\Backoff\HttpBackoffStrategy', $strategy); + $this->assertEquals(array(204 => true), $this->readAttribute($strategy, 'errorCodes')); + $strategy = $this->readAttribute($strategy, 'next'); + $this->assertInstanceOf('Guzzle\Plugin\Backoff\CurlBackoffStrategy', $strategy); + $this->assertEquals(array(10 => true), $this->readAttribute($strategy, 'errorCodes')); + $strategy = $this->readAttribute($strategy, 'next'); + $this->assertInstanceOf('Guzzle\Plugin\Backoff\ExponentialBackoffStrategy', $strategy); + } + + public function testDoesNotRetryUnlessStrategyReturnsNumber() + { + $request = new Request('GET', 'http://www.example.com'); + $request->setState('transfer'); + + $mock = $this->getMockBuilder('Guzzle\Plugin\Backoff\BackoffStrategyInterface') + ->setMethods(array('getBackoffPeriod')) + ->getMockForAbstractClass(); + + $mock->expects($this->once()) + ->method('getBackoffPeriod') + ->will($this->returnValue(false)); + + $plugin = new BackoffPlugin($mock); + $plugin->addSubscriber($this); + $plugin->onRequestSent(new Event(array('request' => $request))); + $this->assertFalse($this->retried); + } + + public function testUpdatesRequestForRetry() + { + $request = new Request('GET', 'http://www.example.com'); + $request->setState('transfer'); + $response = new Response(500); + $handle = $this->getMockBuilder('Guzzle\Http\Curl\CurlHandle')->disableOriginalConstructor()->getMock(); + $e = new CurlException(); + $e->setCurlHandle($handle); + + $plugin = new BackoffPlugin(new ConstantBackoffStrategy(10)); + $plugin->addSubscriber($this); + + $event = new Event(array( + 'request' => $request, + 'response' => $response, + 'exception' => $e + )); + + $plugin->onRequestSent($event); + $this->assertEquals(array( + 'request' => $request, + 'response' => $response, + 'handle' => $handle, + 'retries' => 1, + 'delay' => 10 + ), $this->readAttribute($this->retried, 'context')); + + $plugin->onRequestSent($event); + $this->assertEquals(array( + 'request' => $request, + 'response' => $response, + 'handle' => $handle, + 'retries' => 2, + 'delay' => 10 + ), $this->readAttribute($this->retried, 'context')); + } + + public function testDoesNothingWhenNotRetryingAndPollingRequest() + { + $request = new Request('GET', 'http://www.foo.com'); + $plugin = new BackoffPlugin(new ConstantBackoffStrategy(10)); + $plugin->onRequestPoll(new Event(array('request' => $request))); + } + + public function testRetriesRequests() + { + // Create a script to return several 500 and 503 response codes + $this->getServer()->flush(); + $this->getServer()->enqueue(array( + "HTTP/1.1 500 Internal Server Error\r\nContent-Length: 0\r\n\r\n", + "HTTP/1.1 500 Internal Server Error\r\nContent-Length: 0\r\n\r\n", + "HTTP/1.1 200 OK\r\nContent-Length: 4\r\n\r\ndata" + )); + + $plugin = new BackoffPlugin( + new TruncatedBackoffStrategy(3, + new HttpBackoffStrategy(null, + new CurlBackoffStrategy(null, + new ConstantBackoffStrategy(0.05) + ) + ) + ) + ); + + $client = new Client($this->getServer()->getUrl()); + $client->getEventDispatcher()->addSubscriber($plugin); + $request = $client->get(); + $request->send(); + + // Make sure it eventually completed successfully + $this->assertEquals(200, $request->getResponse()->getStatusCode()); + $this->assertEquals('data', $request->getResponse()->getBody(true)); + + // Check that three requests were made to retry this request + $this->assertEquals(3, count($this->getServer()->getReceivedRequests(false))); + $this->assertEquals(2, $request->getParams()->get(BackoffPlugin::RETRY_PARAM)); + } + + /** + * @expectedException \Guzzle\Http\Exception\ServerErrorResponseException + */ + public function testFailsOnTruncation() + { + $this->getServer()->flush(); + $this->getServer()->enqueue(array( + "HTTP/1.1 500 Internal Server Error\r\nContent-Length: 0\r\n\r\n", + "HTTP/1.1 500 Internal Server Error\r\nContent-Length: 0\r\n\r\n" + )); + + $plugin = new BackoffPlugin( + new TruncatedBackoffStrategy(2, + new HttpBackoffStrategy(null, + new ConstantBackoffStrategy(0.05) + ) + ) + ); + + $client = new Client($this->getServer()->getUrl()); + $client->addSubscriber($plugin); + $client->get()->send(); + } + + public function testRetriesRequestsWhenInParallel() + { + // Create a script to return several 500 and 503 response codes + $this->getServer()->flush(); + $this->getServer()->enqueue(array( + "HTTP/1.1 500 Internal Server Error\r\nContent-Length: 0\r\n\r\n", + "HTTP/1.1 500 Internal Server Error\r\nContent-Length: 0\r\n\r\n", + "HTTP/1.1 500 Internal Server Error\r\nContent-Length: 0\r\n\r\n", + "HTTP/1.1 500 Internal Server Error\r\nContent-Length: 0\r\n\r\n", + "HTTP/1.1 500 Internal Server Error\r\nContent-Length: 0\r\n\r\n", + "HTTP/1.1 500 Internal Server Error\r\nContent-Length: 0\r\n\r\n", + "HTTP/1.1 500 Internal Server Error\r\nContent-Length: 0\r\n\r\n", + "HTTP/1.1 500 Internal Server Error\r\nContent-Length: 0\r\n\r\n", + "HTTP/1.1 500 Internal Server Error\r\nContent-Length: 0\r\n\r\n", + "HTTP/1.1 500 Internal Server Error\r\nContent-Length: 0\r\n\r\n", + "HTTP/1.1 200 OK\r\nContent-Length: 4\r\n\r\ndata", + "HTTP/1.1 200 OK\r\nContent-Length: 4\r\n\r\ndata", + "HTTP/1.1 200 OK\r\nContent-Length: 4\r\n\r\ndata", + "HTTP/1.1 200 OK\r\nContent-Length: 4\r\n\r\ndata", + "HTTP/1.1 200 OK\r\nContent-Length: 4\r\n\r\ndata" + )); + + $plugin = new BackoffPlugin( + new HttpBackoffStrategy(null, + new TruncatedBackoffStrategy(3, + new CurlBackoffStrategy(null, + new ConstantBackoffStrategy(0.1) + ) + ) + ) + ); + $client = new Client($this->getServer()->getUrl()); + $client->getEventDispatcher()->addSubscriber($plugin); + $requests = array(); + for ($i = 0; $i < 5; $i++) { + $requests[] = $client->get(); + } + $client->send($requests); + + $this->assertEquals(15, count($this->getServer()->getReceivedRequests(false))); + } + + /** + * @covers Guzzle\Plugin\Backoff\BackoffPlugin + * @covers Guzzle\Http\Curl\CurlMulti + */ + public function testRetriesPooledRequestsUsingDelayAndPollingEvent() + { + $this->getServer()->flush(); + $this->getServer()->enqueue(array( + "HTTP/1.1 500 Internal Server Error\r\nContent-Length: 0\r\n\r\n", + "HTTP/1.1 200 OK\r\nContent-Length: 4\r\n\r\ndata" + )); + // Need to sleep for some time ensure that the polling works correctly in the observer + $plugin = new BackoffPlugin(new HttpBackoffStrategy(null, + new TruncatedBackoffStrategy(1, + new ConstantBackoffStrategy(0.5)))); + + $client = new Client($this->getServer()->getUrl()); + $client->getEventDispatcher()->addSubscriber($plugin); + $request = $client->get(); + $request->send(); + // Make sure it eventually completed successfully + $this->assertEquals('data', $request->getResponse()->getBody(true)); + // Check that two requests were made to retry this request + $this->assertEquals(2, count($this->getServer()->getReceivedRequests(false))); + } + + public function testSeeksToBeginningOfRequestBodyWhenRetrying() + { + // Create a request with a body + $request = new EntityEnclosingRequest('PUT', 'http://www.example.com'); + $request->setBody('abc'); + // Set the retry time to be something that will be retried always + $request->getParams()->set(BackoffPlugin::DELAY_PARAM, 2); + // Seek to the end of the stream + $request->getBody()->seek(3); + $this->assertEquals('', $request->getBody()->read(1)); + // Create a plugin that does not delay when retrying + $plugin = new BackoffPlugin(new ConstantBackoffStrategy(0)); + $plugin->onRequestPoll($this->getMockEvent($request)); + // Ensure that the stream was seeked to 0 + $this->assertEquals('a', $request->getBody()->read(1)); + } + + public function testDoesNotSeekOnRequestsWithNoBodyWhenRetrying() + { + // Create a request with a body + $request = new EntityEnclosingRequest('PUT', 'http://www.example.com'); + $request->getParams()->set(BackoffPlugin::DELAY_PARAM, 2); + $plugin = new BackoffPlugin(new ConstantBackoffStrategy(0)); + $plugin->onRequestPoll($this->getMockEvent($request)); + } + + protected function getMockEvent(RequestInterface $request) + { + // Create a mock curl multi object + $multi = $this->getMockBuilder('Guzzle\Http\Curl\CurlMulti') + ->setMethods(array('remove', 'add')) + ->getMock(); + + // Create an event that is expected for the Poll event + $event = new Event(array( + 'request' => $request, + 'curl_multi' => $multi + )); + $event->setName(CurlMultiInterface::POLLING_REQUEST); + + return $event; + } +} diff --git a/vendor/guzzle/guzzle/tests/Guzzle/Tests/Plugin/Backoff/CallbackBackoffStrategyTest.php b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Plugin/Backoff/CallbackBackoffStrategyTest.php new file mode 100644 index 0000000..c0ce10d --- /dev/null +++ b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Plugin/Backoff/CallbackBackoffStrategyTest.php @@ -0,0 +1,31 @@ +getMock('Guzzle\Http\Message\Request', array(), array(), '', false); + $strategy = new CallbackBackoffStrategy(function () { return 10; }, true); + $this->assertTrue($strategy->makesDecision()); + $this->assertEquals(10, $strategy->getBackoffPeriod(0, $request)); + // Ensure it chains correctly when null is returned + $strategy = new CallbackBackoffStrategy(function () { return null; }, false); + $this->assertFalse($strategy->makesDecision()); + $this->assertFalse($strategy->getBackoffPeriod(0, $request)); + } +} diff --git a/vendor/guzzle/guzzle/tests/Guzzle/Tests/Plugin/Backoff/ConstantBackoffStrategyTest.php b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Plugin/Backoff/ConstantBackoffStrategyTest.php new file mode 100644 index 0000000..703eb4a --- /dev/null +++ b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Plugin/Backoff/ConstantBackoffStrategyTest.php @@ -0,0 +1,20 @@ +assertFalse($strategy->makesDecision()); + $request = $this->getMock('Guzzle\Http\Message\Request', array(), array(), '', false); + $this->assertEquals(3.5, $strategy->getBackoffPeriod(0, $request)); + $this->assertEquals(3.5, $strategy->getBackoffPeriod(1, $request)); + } +} diff --git a/vendor/guzzle/guzzle/tests/Guzzle/Tests/Plugin/Backoff/CurlBackoffStrategyTest.php b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Plugin/Backoff/CurlBackoffStrategyTest.php new file mode 100644 index 0000000..0a5c3e2 --- /dev/null +++ b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Plugin/Backoff/CurlBackoffStrategyTest.php @@ -0,0 +1,36 @@ +assertNotEmpty(CurlBackoffStrategy::getDefaultFailureCodes()); + $strategy = new CurlBackoffStrategy(); + $this->assertTrue($strategy->makesDecision()); + $request = $this->getMock('Guzzle\Http\Message\Request', array(), array(), '', false); + $e = new CurlException(); + $e->setError('foo', CURLE_BAD_CALLING_ORDER); + $this->assertEquals(false, $strategy->getBackoffPeriod(0, $request, null, $e)); + + foreach (CurlBackoffStrategy::getDefaultFailureCodes() as $code) { + $this->assertEquals(0, $strategy->getBackoffPeriod(0, $request, null, $e->setError('foo', $code))); + } + } + + public function testIgnoresNonErrors() + { + $strategy = new CurlBackoffStrategy(); + $request = $this->getMock('Guzzle\Http\Message\Request', array(), array(), '', false); + $this->assertEquals(false, $strategy->getBackoffPeriod(0, $request, new Response(200))); + } +} diff --git a/vendor/guzzle/guzzle/tests/Guzzle/Tests/Plugin/Backoff/ExponentialBackoffStrategyTest.php b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Plugin/Backoff/ExponentialBackoffStrategyTest.php new file mode 100644 index 0000000..09965bc --- /dev/null +++ b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Plugin/Backoff/ExponentialBackoffStrategyTest.php @@ -0,0 +1,23 @@ +assertFalse($strategy->makesDecision()); + $request = $this->getMock('Guzzle\Http\Message\Request', array(), array(), '', false); + $this->assertEquals(1, $strategy->getBackoffPeriod(0, $request)); + $this->assertEquals(2, $strategy->getBackoffPeriod(1, $request)); + $this->assertEquals(4, $strategy->getBackoffPeriod(2, $request)); + $this->assertEquals(8, $strategy->getBackoffPeriod(3, $request)); + $this->assertEquals(16, $strategy->getBackoffPeriod(4, $request)); + } +} diff --git a/vendor/guzzle/guzzle/tests/Guzzle/Tests/Plugin/Backoff/HttpBackoffStrategyTest.php b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Plugin/Backoff/HttpBackoffStrategyTest.php new file mode 100644 index 0000000..ae68a4e --- /dev/null +++ b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Plugin/Backoff/HttpBackoffStrategyTest.php @@ -0,0 +1,47 @@ +assertNotEmpty(HttpBackoffStrategy::getDefaultFailureCodes()); + $strategy = new HttpBackoffStrategy(); + $this->assertTrue($strategy->makesDecision()); + $request = $this->getMock('Guzzle\Http\Message\Request', array(), array(), '', false); + + $response = new Response(200); + $this->assertEquals(false, $strategy->getBackoffPeriod(0, $request, $response)); + $response->setStatus(400); + $this->assertEquals(false, $strategy->getBackoffPeriod(0, $request, $response)); + + foreach (HttpBackoffStrategy::getDefaultFailureCodes() as $code) { + $this->assertEquals(0, $strategy->getBackoffPeriod(0, $request, $response->setStatus($code))); + } + } + + public function testAllowsCustomCodes() + { + $strategy = new HttpBackoffStrategy(array(204)); + $request = $this->getMock('Guzzle\Http\Message\Request', array(), array(), '', false); + $response = new Response(204); + $this->assertEquals(0, $strategy->getBackoffPeriod(0, $request, $response)); + $response->setStatus(500); + $this->assertEquals(false, $strategy->getBackoffPeriod(0, $request, $response)); + } + + public function testIgnoresNonErrors() + { + $strategy = new HttpBackoffStrategy(); + $request = $this->getMock('Guzzle\Http\Message\Request', array(), array(), '', false); + $this->assertEquals(false, $strategy->getBackoffPeriod(0, $request)); + } +} diff --git a/vendor/guzzle/guzzle/tests/Guzzle/Tests/Plugin/Backoff/LinearBackoffStrategyTest.php b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Plugin/Backoff/LinearBackoffStrategyTest.php new file mode 100644 index 0000000..b4ce8e4 --- /dev/null +++ b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Plugin/Backoff/LinearBackoffStrategyTest.php @@ -0,0 +1,21 @@ +assertFalse($strategy->makesDecision()); + $request = $this->getMock('Guzzle\Http\Message\Request', array(), array(), '', false); + $this->assertEquals(0, $strategy->getBackoffPeriod(0, $request)); + $this->assertEquals(5, $strategy->getBackoffPeriod(1, $request)); + $this->assertEquals(10, $strategy->getBackoffPeriod(2, $request)); + } +} diff --git a/vendor/guzzle/guzzle/tests/Guzzle/Tests/Plugin/Backoff/ReasonPhraseBackoffStrategyTest.php b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Plugin/Backoff/ReasonPhraseBackoffStrategyTest.php new file mode 100644 index 0000000..dea5a68 --- /dev/null +++ b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Plugin/Backoff/ReasonPhraseBackoffStrategyTest.php @@ -0,0 +1,32 @@ +assertEmpty(ReasonPhraseBackoffStrategy::getDefaultFailureCodes()); + $strategy = new ReasonPhraseBackoffStrategy(array('Foo', 'Internal Server Error')); + $this->assertTrue($strategy->makesDecision()); + $request = $this->getMock('Guzzle\Http\Message\Request', array(), array(), '', false); + $response = new Response(200); + $this->assertEquals(false, $strategy->getBackoffPeriod(0, $request, $response)); + $response->setStatus(200, 'Foo'); + $this->assertEquals(0, $strategy->getBackoffPeriod(0, $request, $response)); + } + + public function testIgnoresNonErrors() + { + $strategy = new ReasonPhraseBackoffStrategy(); + $request = $this->getMock('Guzzle\Http\Message\Request', array(), array(), '', false); + $this->assertEquals(false, $strategy->getBackoffPeriod(0, $request)); + } +} diff --git a/vendor/guzzle/guzzle/tests/Guzzle/Tests/Plugin/Backoff/TruncatedBackoffStrategyTest.php b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Plugin/Backoff/TruncatedBackoffStrategyTest.php new file mode 100644 index 0000000..5590dfb --- /dev/null +++ b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Plugin/Backoff/TruncatedBackoffStrategyTest.php @@ -0,0 +1,30 @@ +assertTrue($strategy->makesDecision()); + $request = $this->getMock('Guzzle\Http\Message\Request', array(), array(), '', false); + $this->assertFalse($strategy->getBackoffPeriod(0, $request)); + $this->assertFalse($strategy->getBackoffPeriod(1, $request)); + $this->assertFalse($strategy->getBackoffPeriod(2, $request)); + + $response = new Response(500); + $strategy->setNext(new HttpBackoffStrategy(null, new ConstantBackoffStrategy(10))); + $this->assertEquals(10, $strategy->getBackoffPeriod(0, $request, $response)); + $this->assertEquals(10, $strategy->getBackoffPeriod(1, $request, $response)); + $this->assertFalse($strategy->getBackoffPeriod(2, $request, $response)); + } +} diff --git a/vendor/guzzle/guzzle/tests/Guzzle/Tests/Plugin/Cache/CachePluginTest.php b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Plugin/Cache/CachePluginTest.php new file mode 100644 index 0000000..69da60a --- /dev/null +++ b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Plugin/Cache/CachePluginTest.php @@ -0,0 +1,441 @@ +assertInstanceOf('Guzzle\Plugin\Cache\CacheStorageInterface', $this->readAttribute($plugin, 'storage')); + } + + public function testAddsDefaultCollaborators() + { + $this->assertNotEmpty(CachePlugin::getSubscribedEvents()); + $plugin = new CachePlugin(array( + 'storage' => $this->getMockBuilder('Guzzle\Plugin\Cache\CacheStorageInterface')->getMockForAbstractClass() + )); + $this->assertInstanceOf('Guzzle\Plugin\Cache\CacheStorageInterface', $this->readAttribute($plugin, 'storage')); + $this->assertInstanceOf( + 'Guzzle\Plugin\Cache\CanCacheStrategyInterface', + $this->readAttribute($plugin, 'canCache') + ); + $this->assertInstanceOf( + 'Guzzle\Plugin\Cache\RevalidationInterface', + $this->readAttribute($plugin, 'revalidation') + ); + } + + public function testAddsCallbackCollaborators() + { + $this->assertNotEmpty(CachePlugin::getSubscribedEvents()); + $plugin = new CachePlugin(array('can_cache' => function () {})); + $this->assertInstanceOf( + 'Guzzle\Plugin\Cache\CallbackCanCacheStrategy', + $this->readAttribute($plugin, 'canCache') + ); + } + + public function testCanPassCacheAsOnlyArgumentToConstructor() + { + $p = new CachePlugin(new DoctrineCacheAdapter(new ArrayCache())); + $p = new CachePlugin(new DefaultCacheStorage(new DoctrineCacheAdapter(new ArrayCache()))); + } + + public function testUsesCreatedCacheStorage() + { + $plugin = new CachePlugin(array( + 'adapter' => $this->getMockBuilder('Guzzle\Cache\CacheAdapterInterface')->getMockForAbstractClass() + )); + $this->assertInstanceOf('Guzzle\Plugin\Cache\CacheStorageInterface', $this->readAttribute($plugin, 'storage')); + } + + public function testUsesProvidedOptions() + { + $can = $this->getMockBuilder('Guzzle\Plugin\Cache\CanCacheStrategyInterface')->getMockForAbstractClass(); + $revalidate = $this->getMockBuilder('Guzzle\Plugin\Cache\RevalidationInterface')->getMockForAbstractClass(); + $plugin = new CachePlugin(array( + 'storage' => $this->getMockBuilder('Guzzle\Plugin\Cache\CacheStorageInterface')->getMockForAbstractClass(), + 'can_cache' => $can, + 'revalidation' => $revalidate + )); + $this->assertSame($can, $this->readAttribute($plugin, 'canCache')); + $this->assertSame($revalidate, $this->readAttribute($plugin, 'revalidation')); + } + + public function satisfyProvider() + { + $req1 = new Request('GET', 'http://foo.com', array('Cache-Control' => 'no-cache')); + + return array( + // The response is too old to satisfy the request + array(new Request('GET', 'http://foo.com', array('Cache-Control' => 'max-age=20')), new Response(200, array('Age' => 100)), false, false), + // The response cannot satisfy the request because it is stale + array(new Request('GET', 'http://foo.com'), new Response(200, array('Cache-Control' => 'max-age=10', 'Age' => 100)), false, false), + // Allows the expired response to satisfy the request because of the max-stale + array(new Request('GET', 'http://foo.com', array('Cache-Control' => 'max-stale=15')), new Response(200, array('Cache-Control' => 'max-age=90', 'Age' => 100)), true, false), + // Max stale is > than the allowed staleness + array(new Request('GET', 'http://foo.com', array('Cache-Control' => 'max-stale=5')), new Response(200, array('Cache-Control' => 'max-age=90', 'Age' => 100)), false, false), + // Performs cache revalidation + array($req1, new Response(200), true, true), + // Performs revalidation due to ETag on the response and no cache-control on the request + array(new Request('GET', 'http://foo.com'), new Response(200, array( + 'ETag' => 'ABC', + 'Expires' => date('c', strtotime('+1 year')) + )), true, true), + ); + } + + /** + * @dataProvider satisfyProvider + */ + public function testChecksIfResponseCanSatisfyRequest($request, $response, $can, $revalidates) + { + $didRevalidate = false; + $storage = $this->getMockBuilder('Guzzle\Plugin\Cache\CacheStorageInterface')->getMockForAbstractClass(); + $revalidate = $this->getMockBuilder('Guzzle\Plugin\Cache\DefaultRevalidation') + ->setMethods(array('revalidate')) + ->setConstructorArgs(array($storage)) + ->getMockForAbstractClass(); + + $revalidate->expects($this->any()) + ->method('revalidate') + ->will($this->returnCallback(function () use (&$didRevalidate) { + $didRevalidate = true; + return true; + })); + + $plugin = new CachePlugin(array( + 'storage' => $storage, + 'revalidation' => $revalidate + )); + + $this->assertEquals($can, $plugin->canResponseSatisfyRequest($request, $response)); + $this->assertEquals($didRevalidate, $revalidates); + } + + public function satisfyFailedProvider() + { + return array( + // Neither has stale-if-error + array(new Request('GET', 'http://foo.com', array()), new Response(200, array('Age' => 100)), false), + // Request has stale-if-error + array(new Request('GET', 'http://foo.com', array('Cache-Control' => 'stale-if-error')), new Response(200, array('Age' => 100, 'Cache-Control' => 'max-age=50')), true), + // Request has valid stale-if-error + array(new Request('GET', 'http://foo.com', array('Cache-Control' => 'stale-if-error=50')), new Response(200, array('Age' => 100, 'Cache-Control' => 'max-age=50')), true), + // Request has expired stale-if-error + array(new Request('GET', 'http://foo.com', array('Cache-Control' => 'stale-if-error=20')), new Response(200, array('Age' => 100, 'Cache-Control' => 'max-age=50')), false), + // Response has permanent stale-if-error + array(new Request('GET', 'http://foo.com', array()), new Response(200, array('Age' => 100, 'Cache-Control' => 'max-age=50, stale-if-error', )), true), + // Response has valid stale-if-error + array(new Request('GET', 'http://foo.com', array()), new Response(200, array('Age' => 100, 'Cache-Control' => 'max-age=50, stale-if-error=50')), true), + // Response has expired stale-if-error + array(new Request('GET', 'http://foo.com', array()), new Response(200, array('Age' => 100, 'Cache-Control' => 'max-age=50, stale-if-error=20')), false), + // Request has valid stale-if-error but response does not + array(new Request('GET', 'http://foo.com', array('Cache-Control' => 'stale-if-error=50')), new Response(200, array('Age' => 100, 'Cache-Control' => 'max-age=50, stale-if-error=20')), false), + // Response has valid stale-if-error but request does not + array(new Request('GET', 'http://foo.com', array('Cache-Control' => 'stale-if-error=20')), new Response(200, array('Age' => 100, 'Cache-Control' => 'max-age=50, stale-if-error=50')), false), + ); + } + + /** + * @dataProvider satisfyFailedProvider + */ + public function testChecksIfResponseCanSatisfyFailedRequest($request, $response, $can) + { + $plugin = new CachePlugin(); + + $this->assertEquals($can, $plugin->canResponseSatisfyFailedRequest($request, $response)); + } + + public function testDoesNothingWhenRequestIsNotCacheable() + { + $storage = $this->getMockBuilder('Guzzle\Plugin\Cache\CacheStorageInterface') + ->setMethods(array('fetch')) + ->getMockForAbstractClass(); + $storage->expects($this->never())->method('fetch'); + + $plugin = new CachePlugin(array( + 'storage' => $storage, + 'can_cache' => new CallbackCanCacheStrategy(function () { return false; }) + )); + + $plugin->onRequestBeforeSend(new Event(array( + 'request' => new Request('GET', 'http://foo.com') + ))); + } + + public function satisfiableProvider() + { + $date = new \DateTime('-10 seconds'); + + return array( + // Fresh response + array(new Response(200, array(), 'foo')), + // Stale response + array(new Response(200, array('Date' => $date->format('c'), 'Cache-Control' => 'max-age=5'), 'foo')) + ); + } + + /** + * @dataProvider satisfiableProvider + */ + public function testInjectsSatisfiableResponses($response) + { + $storage = $this->getMockBuilder('Guzzle\Plugin\Cache\CacheStorageInterface') + ->setMethods(array('fetch')) + ->getMockForAbstractClass(); + + $storage->expects($this->once())->method('fetch')->will($this->returnValue($response)); + $plugin = new CachePlugin(array('storage' => $storage)); + $request = new Request('GET', 'http://foo.com', array('Cache-Control' => 'max-stale')); + $plugin->onRequestBeforeSend(new Event(array('request' => $request))); + $plugin->onRequestSent(new Event(array('request' => $request, 'response' => $request->getResponse()))); + $this->assertEquals($response->getStatusCode(), $request->getResponse()->getStatusCode()); + $this->assertEquals((string) $response->getBody(), (string) $request->getResponse()->getBody()); + $this->assertTrue($request->getResponse()->hasHeader('Age')); + if ($request->getResponse()->isFresh() === false) { + $this->assertContains('110', (string) $request->getResponse()->getHeader('Warning')); + } + $this->assertSame( + sprintf('%s GuzzleCache/%s', $request->getProtocolVersion(), Version::VERSION), + (string) $request->getHeader('Via') + ); + $this->assertSame( + sprintf('%s GuzzleCache/%s',$request->getProtocolVersion(), Version::VERSION), + (string) $request->getResponse()->getHeader('Via') + ); + $this->assertTrue($request->getParams()->get('cache.lookup')); + $this->assertTrue($request->getParams()->get('cache.hit')); + $this->assertTrue($request->getResponse()->hasHeader('X-Cache-Lookup')); + $this->assertTrue($request->getResponse()->hasHeader('X-Cache')); + $this->assertEquals('HIT from GuzzleCache', (string) $request->getResponse()->getHeader('X-Cache')); + $this->assertEquals('HIT from GuzzleCache', (string) $request->getResponse()->getHeader('X-Cache-Lookup')); + } + + public function satisfiableOnErrorProvider() + { + $date = new \DateTime('-10 seconds'); + return array( + array( + new Response(200, array( + 'Date' => $date->format('c'), + 'Cache-Control' => 'max-age=5, stale-if-error' + ), 'foo'), + ) + ); + } + + /** + * @dataProvider satisfiableOnErrorProvider + */ + public function testInjectsSatisfiableResponsesOnError($cacheResponse) + { + $storage = $this->getMockBuilder('Guzzle\Plugin\Cache\CacheStorageInterface') + ->setMethods(array('fetch')) + ->getMockForAbstractClass(); + $storage->expects($this->exactly(2))->method('fetch')->will($this->returnValue($cacheResponse)); + $plugin = new CachePlugin(array('storage' => $storage)); + $request = new Request('GET', 'http://foo.com', array('Cache-Control' => 'max-stale')); + $plugin->onRequestBeforeSend(new Event(array('request' => $request))); + $plugin->onRequestError( + $event = new Event(array( + 'request' => $request, + 'response' => $request->getResponse(), + )) + ); + $response = $event['response']; + $this->assertEquals($cacheResponse->getStatusCode(), $response->getStatusCode()); + $this->assertEquals((string) $cacheResponse->getBody(), (string) $response->getBody()); + $this->assertTrue($response->hasHeader('Age')); + if ($response->isFresh() === false) { + $this->assertContains('110', (string) $response->getHeader('Warning')); + } + $this->assertSame(sprintf('%s GuzzleCache/%s', $request->getProtocolVersion(), Version::VERSION), (string) $request->getHeader('Via')); + $this->assertSame(sprintf('%s GuzzleCache/%s', $request->getProtocolVersion(), Version::VERSION), (string) $response->getHeader('Via')); + $this->assertTrue($request->getParams()->get('cache.lookup')); + $this->assertSame('error', $request->getParams()->get('cache.hit')); + $this->assertTrue($response->hasHeader('X-Cache-Lookup')); + $this->assertTrue($response->hasHeader('X-Cache')); + $this->assertEquals('HIT from GuzzleCache', (string) $response->getHeader('X-Cache-Lookup')); + $this->assertEquals('HIT_ERROR from GuzzleCache', (string) $response->getHeader('X-Cache')); + } + + /** + * @dataProvider satisfiableOnErrorProvider + */ + public function testInjectsSatisfiableResponsesOnException($cacheResponse) + { + $storage = $this->getMockBuilder('Guzzle\Plugin\Cache\CacheStorageInterface') + ->setMethods(array('fetch')) + ->getMockForAbstractClass(); + $storage->expects($this->exactly(2))->method('fetch')->will($this->returnValue($cacheResponse)); + $plugin = new CachePlugin(array('storage' => $storage)); + $request = new Request('GET', 'http://foo.com', array('Cache-Control' => 'max-stale')); + $plugin->onRequestBeforeSend(new Event(array( + 'request' => $request + ))); + $plugin->onRequestException( + new Event(array( + 'request' => $request, + 'response' => $request->getResponse(), + 'exception' => $this->getMock('Guzzle\Http\Exception\CurlException'), + )) + ); + $plugin->onRequestSent( + new Event(array( + 'request' => $request, + 'response' => $response = $request->getResponse(), + )) + ); + $this->assertEquals($cacheResponse->getStatusCode(), $response->getStatusCode()); + $this->assertEquals((string) $cacheResponse->getBody(), (string) $response->getBody()); + $this->assertTrue($response->hasHeader('Age')); + if ($response->isFresh() === false) { + $this->assertContains('110', (string) $response->getHeader('Warning')); + } + $this->assertSame(sprintf('%s GuzzleCache/%s', $request->getProtocolVersion(), Version::VERSION), (string) $request->getHeader('Via')); + $this->assertSame(sprintf('%s GuzzleCache/%s', $request->getProtocolVersion(), Version::VERSION), (string) $response->getHeader('Via')); + $this->assertTrue($request->getParams()->get('cache.lookup')); + $this->assertSame('error', $request->getParams()->get('cache.hit')); + $this->assertTrue($response->hasHeader('X-Cache-Lookup')); + $this->assertTrue($response->hasHeader('X-Cache')); + $this->assertEquals('HIT from GuzzleCache', (string) $response->getHeader('X-Cache-Lookup')); + $this->assertEquals('HIT_ERROR from GuzzleCache', (string) $response->getHeader('X-Cache')); + } + + public function unsatisfiableOnErrorProvider() + { + $date = new \DateTime('-10 seconds'); + + return array( + // no-store on request + array( + false, + array('Cache-Control' => 'no-store'), + new Response(200, array('Date' => $date->format('D, d M Y H:i:s T'), 'Cache-Control' => 'max-age=5, stale-if-error'), 'foo'), + ), + // request expired + array( + true, + array('Cache-Control' => 'stale-if-error=4'), + new Response(200, array('Date' => $date->format('D, d M Y H:i:s T'), 'Cache-Control' => 'max-age=5, stale-if-error'), 'foo'), + ), + // response expired + array( + true, + array('Cache-Control' => 'stale-if-error'), + new Response(200, array('Date' => $date->format('D, d M Y H:i:s T'), 'Cache-Control' => 'max-age=5, stale-if-error=4'), 'foo'), + ), + ); + } + + /** + * @dataProvider unsatisfiableOnErrorProvider + */ + public function testDoesNotInjectUnsatisfiableResponsesOnError($requestCanCache, $requestHeaders, $cacheResponse) + { + $storage = $this->getMockBuilder('Guzzle\Plugin\Cache\CacheStorageInterface') + ->setMethods(array('fetch')) + ->getMockForAbstractClass(); + $storage->expects($this->exactly($requestCanCache ? 2 : 0))->method('fetch')->will($this->returnValue($cacheResponse)); + $plugin = new CachePlugin(array('storage' => $storage)); + $request = new Request('GET', 'http://foo.com', $requestHeaders); + $plugin->onRequestBeforeSend(new Event(array( + 'request' => $request + ))); + $plugin->onRequestError( + $event = new Event(array( + 'request' => $request, + 'response' => $response = $request->getResponse(), + )) + ); + + $this->assertSame($response, $event['response']); + } + + /** + * @dataProvider unsatisfiableOnErrorProvider + */ + public function testDoesNotInjectUnsatisfiableResponsesOnException($requestCanCache, $requestHeaders, $responseParts) + { + $storage = $this->getMockBuilder('Guzzle\Plugin\Cache\CacheStorageInterface') + ->setMethods(array('fetch')) + ->getMockForAbstractClass(); + $storage->expects($this->exactly($requestCanCache ? 2 : 0))->method('fetch')->will($this->returnValue($responseParts)); + $plugin = new CachePlugin(array('storage' => $storage)); + $request = new Request('GET', 'http://foo.com', $requestHeaders); + $plugin->onRequestBeforeSend(new Event(array( + 'request' => $request + ))); + $plugin->onRequestException( + $event = new Event(array( + 'request' => $request, + 'response' => $response = $request->getResponse(), + 'exception' => $this->getMock('Guzzle\Http\Exception\CurlException'), + )) + ); + + $this->assertSame($response, $request->getResponse()); + } + + public function testCachesResponsesWhenCacheable() + { + $cache = new ArrayCache(); + $plugin = new CachePlugin($cache); + + $request = new Request('GET', 'http://foo.com'); + $response = new Response(200, array(), 'Foo'); + $plugin->onRequestBeforeSend(new Event(array( + 'request' => $request + ))); + $plugin->onRequestSent(new Event(array( + 'request' => $request, + 'response' => $response + ))); + $data = $this->readAttribute($cache, 'data'); + $this->assertNotEmpty($data); + } + + public function testPurgesRequests() + { + $storage = $this->getMockBuilder('Guzzle\Plugin\Cache\CacheStorageInterface') + ->setMethods(array('purge')) + ->getMockForAbstractClass(); + $storage->expects($this->atLeastOnce())->method('purge'); + $plugin = new CachePlugin(array('storage' => $storage)); + $request = new Request('GET', 'http://foo.com', array('X-Foo' => 'Bar')); + $plugin->purge($request); + } + + public function testAutoPurgesRequests() + { + $storage = $this->getMockBuilder('Guzzle\Plugin\Cache\CacheStorageInterface') + ->setMethods(array('purge')) + ->getMockForAbstractClass(); + $storage->expects($this->atLeastOnce())->method('purge'); + $plugin = new CachePlugin(array('storage' => $storage, 'auto_purge' => true)); + $client = new Client(); + $request = $client->put('http://foo.com', array('X-Foo' => 'Bar')); + $request->addSubscriber($plugin); + $request->setResponse(new Response(200), true); + $request->send(); + } +} diff --git a/vendor/guzzle/guzzle/tests/Guzzle/Tests/Plugin/Cache/CallbackCanCacheStrategyTest.php b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Plugin/Cache/CallbackCanCacheStrategyTest.php new file mode 100644 index 0000000..f3d9baf --- /dev/null +++ b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Plugin/Cache/CallbackCanCacheStrategyTest.php @@ -0,0 +1,72 @@ +assertTrue($c->canCacheRequest(new Request('DELETE', 'http://www.foo.com'))); + } + + /** + * The following is a bit of an integration test to ensure that the CachePlugin honors a + * custom can cache strategy. + */ + public function testIntegrationWithCachePlugin() + { + $c = new CallbackCanCacheStrategy( + function ($request) { return true; }, + function ($response) { return true; } + ); + + // Make a request and response that have no business being cached + $request = new Request('DELETE', 'http://www.foo.com'); + $response = Response::fromMessage( + "HTTP/1.1 200 OK\r\n" + . "Expires: Mon, 26 Jul 1997 05:00:00 GMT\r\n" + . "Last-Modified: Wed, 09 Jan 2013 08:48:53 GMT\r\n" + . "Content-Length: 2\r\n" + . "Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0\r\n\r\n" + . "hi" + ); + + $this->assertTrue($c->canCacheRequest($request)); + $this->assertTrue($c->canCacheResponse($response)); + + $s = $this->getMockBuilder('Guzzle\Plugin\Cache\DefaultCacheStorage') + ->setConstructorArgs(array(new DoctrineCacheAdapter(new ArrayCache()))) + ->setMethods(array('fetch')) + ->getMockForAbstractClass(); + + $s->expects($this->once()) + ->method('fetch') + ->will($this->returnValue($response)); + + $plugin = new CachePlugin(array('can_cache' => $c, 'storage' => $s)); + $plugin->onRequestBeforeSend(new Event(array('request' => $request))); + + $this->assertEquals(200, $request->getResponse()->getStatusCode()); + $this->assertEquals('hi', $request->getResponse()->getBody(true)); + } +} diff --git a/vendor/guzzle/guzzle/tests/Guzzle/Tests/Plugin/Cache/DefaultCacheStorageTest.php b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Plugin/Cache/DefaultCacheStorageTest.php new file mode 100644 index 0000000..701a015 --- /dev/null +++ b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Plugin/Cache/DefaultCacheStorageTest.php @@ -0,0 +1,193 @@ + 'application/json')); + $response = new Response(200, array( + 'Content-Type' => 'application/json', + 'Connection' => 'close', + 'X-Foo' => 'Bar', + 'Vary' => 'Accept' + ), 'test'); + $s->cache($request, $response); + $data = $this->readAttribute($a, 'data'); + + return array( + 'cache' => $a, + 'adapter' => $c, + 'storage' => $s, + 'request' => $request, + 'response' => $response, + 'serialized' => end($data) + ); + } + + public function testReturnsNullForCacheMiss() + { + $cache = $this->getCache(); + $this->assertNull($cache['storage']->fetch(new Request('GET', 'http://test.com'))); + } + + public function testCachesRequests() + { + $cache = $this->getCache(); + $foundRequest = $foundBody = $bodyKey = false; + foreach ($this->readAttribute($cache['cache'], 'data') as $key => $v) { + if (strpos($v, 'foo.com')) { + $foundRequest = true; + $data = unserialize($v); + $bodyKey = $data[0][3]; + $this->assertInternalType('integer', $data[0][4]); + $this->assertFalse(isset($data[0][0]['connection'])); + $this->assertEquals('foo.com', $data[0][0]['host']); + } elseif ($v == 'test') { + $foundBody = $key; + } + } + $this->assertContains($bodyKey, $foundBody); + $this->assertTrue($foundRequest); + } + + public function testFetchesResponse() + { + $cache = $this->getCache(); + $response = $cache['storage']->fetch($cache['request']); + $this->assertEquals(200, $response->getStatusCode()); + $this->assertFalse($response->hasHeader('Connection')); + $this->assertEquals('Bar', (string) $response->getHeader('X-Foo')); + $this->assertEquals('test', (string) $response->getBody()); + $this->assertTrue(in_array($cache['serialized'], $this->readAttribute($cache['cache'], 'data'))); + } + + public function testDeletesRequestItemsAndBody() + { + $cache = $this->getCache(); + $cache['storage']->delete($cache['request']); + $this->assertFalse(in_array('test', $this->readAttribute($cache['cache'], 'data'))); + $this->assertFalse(in_array($cache['serialized'], $this->readAttribute($cache['cache'], 'data'))); + } + + public function testCachesMultipleRequestsWithVary() + { + $cache = $this->getCache(); + $cache['request']->setHeader('Accept', 'application/xml'); + $response = $cache['response']->setHeader('Content-Type', 'application/xml'); + $response->setBody('123'); + $cache['storage']->cache($cache['request'], $response); + $data = $this->readAttribute($cache['cache'], 'data'); + foreach ($data as $v) { + if (strpos($v, 'foo.com')) { + $u = unserialize($v); + $this->assertEquals(2, count($u)); + $this->assertEquals($u[0][0]['accept'], 'application/xml'); + $this->assertEquals($u[0][1]['content-type'], 'application/xml'); + $this->assertEquals($u[1][0]['accept'], 'application/json'); + $this->assertEquals($u[1][1]['content-type'], 'application/json'); + $this->assertNotSame($u[0][3], $u[1][3]); + break; + } + } + } + + public function testPurgeRemovesAllMethodCaches() + { + $cache = $this->getCache(); + foreach (array('HEAD', 'POST', 'PUT', 'DELETE') as $method) { + $request = RequestFactory::getInstance()->cloneRequestWithMethod($cache['request'], $method); + $cache['storage']->cache($request, $cache['response']); + } + $cache['storage']->purge('http://foo.com'); + $this->assertFalse(in_array('test', $this->readAttribute($cache['cache'], 'data'))); + $this->assertFalse(in_array($cache['serialized'], $this->readAttribute($cache['cache'], 'data'))); + $this->assertEquals( + array('DoctrineNamespaceCacheKey[]'), + array_keys($this->readAttribute($cache['cache'], 'data')) + ); + } + + public function testRemovesExpiredResponses() + { + $cache = $this->getCache(); + $request = new Request('GET', 'http://xyz.com'); + $response = new Response(200, array('Age' => 1000, 'Cache-Control' => 'max-age=-10000')); + $cache['storage']->cache($request, $response); + $this->assertNull($cache['storage']->fetch($request)); + $data = $this->readAttribute($cache['cache'], 'data'); + $this->assertFalse(in_array('xyz.com', $data)); + $this->assertTrue(in_array($cache['serialized'], $data)); + } + + public function testUsesVaryToDetermineResult() + { + $cache = $this->getCache(); + $this->assertInstanceOf('Guzzle\Http\Message\Response', $cache['storage']->fetch($cache['request'])); + $request = new Request('GET', 'http://foo.com', array('Accept' => 'application/xml')); + $this->assertNull($cache['storage']->fetch($request)); + } + + public function testEnsuresResponseIsStillPresent() + { + $cache = $this->getCache(); + $data = $this->readAttribute($cache['cache'], 'data'); + $key = array_search('test', $data); + $cache['cache']->delete(substr($key, 1, -4)); + $this->assertNull($cache['storage']->fetch($cache['request'])); + } + + public function staleProvider() + { + return array( + array( + new Request('GET', 'http://foo.com', array('Accept' => 'foo')), + new Response(200, array('Cache-Control' => 'stale-if-error=100', 'Vary' => 'Accept')) + ), + array( + new Request('GET', 'http://foo.com', array('Accept' => 'foo')), + new Response(200, array('Cache-Control' => 'stale-if-error', 'Vary' => 'Accept')) + ) + ); + } + + /** + * @dataProvider staleProvider + */ + public function testUsesStaleTimeDirectiveForTtd($request, $response) + { + $cache = $this->getCache(); + $cache['storage']->cache($request, $response); + $data = $this->readAttribute($cache['cache'], 'data'); + foreach ($data as $v) { + if (strpos($v, 'foo.com')) { + $u = unserialize($v); + $this->assertGreaterThan($u[1][4], $u[0][4]); + break; + } + } + } + + public function testCanFilterCacheKeys() + { + $cache = $this->getCache(); + $cache['request']->getQuery()->set('auth', 'foo'); + $this->assertNull($cache['storage']->fetch($cache['request'])); + $cache['request']->getParams()->set('cache.key_filter', 'auth'); + $this->assertNotNull($cache['storage']->fetch($cache['request'])); + } +} diff --git a/vendor/guzzle/guzzle/tests/Guzzle/Tests/Plugin/Cache/DefaultCanCacheStrategyTest.php b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Plugin/Cache/DefaultCanCacheStrategyTest.php new file mode 100644 index 0000000..de4d182 --- /dev/null +++ b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Plugin/Cache/DefaultCanCacheStrategyTest.php @@ -0,0 +1,40 @@ +assertTrue($strategy->canCacheRequest($request)); + } + + public function testDoesNotCacheNoStore() + { + $strategy = new DefaultCanCacheStrategy(); + $request = new Request('GET', 'http://foo.com', array('cache-control' => 'no-store')); + $this->assertFalse($strategy->canCacheRequest($request)); + } + + public function testCanCacheResponse() + { + $response = $this->getMockBuilder('Guzzle\Http\Message\Response') + ->setMethods(array('canCache')) + ->setConstructorArgs(array(200)) + ->getMock(); + $response->expects($this->once()) + ->method('canCache') + ->will($this->returnValue(true)); + $strategy = new DefaultCanCacheStrategy(); + $this->assertTrue($strategy->canCacheResponse($response)); + } +} diff --git a/vendor/guzzle/guzzle/tests/Guzzle/Tests/Plugin/Cache/DefaultRevalidationTest.php b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Plugin/Cache/DefaultRevalidationTest.php new file mode 100644 index 0000000..0699cb2 --- /dev/null +++ b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Plugin/Cache/DefaultRevalidationTest.php @@ -0,0 +1,248 @@ +getHttpDate('-100 hours') . "\r\nContent-Length: 4\r\n\r\nData", + "HTTP/1.1 304 NOT MODIFIED\r\nCache-Control: max-age=2000000\r\nContent-Length: 0\r\n\r\n", + ), + // Forces revalidation that overwrites what is in cache + array( + false, + "\r\n", + "HTTP/1.1 200 OK\r\nCache-Control: must-revalidate, no-cache\r\nDate: " . $this->getHttpDate('-10 hours') . "\r\nContent-Length: 4\r\n\r\nData", + "HTTP/1.1 200 OK\r\nContent-Length: 5\r\n\r\nDatas", + "HTTP/1.1 200 OK\r\nContent-Length: 5\r\nDate: " . $this->getHttpDate('now') . "\r\n\r\nDatas" + ), + // Throws an exception during revalidation + array( + false, + "\r\n", + "HTTP/1.1 200 OK\r\nCache-Control: no-cache\r\nDate: " . $this->getHttpDate('-3 hours') . "\r\n\r\nData", + "HTTP/1.1 500 INTERNAL SERVER ERROR\r\nContent-Length: 0\r\n\r\n" + ), + // ETag mismatch + array( + false, + "\r\n", + "HTTP/1.1 200 OK\r\nCache-Control: no-cache\r\nETag: \"123\"\r\nDate: " . $this->getHttpDate('-10 hours') . "\r\n\r\nData", + "HTTP/1.1 304 NOT MODIFIED\r\nETag: \"123456\"\r\n\r\n", + ), + ); + } + + /** + * @dataProvider cacheRevalidationDataProvider + */ + public function testRevalidatesResponsesAgainstOriginServer($can, $request, $response, $validate = null, $result = null) + { + // Send some responses to the test server for cache validation + $server = $this->getServer(); + $server->flush(); + + if ($validate) { + $server->enqueue($validate); + } + + $request = RequestFactory::getInstance()->fromMessage("GET / HTTP/1.1\r\nHost: 127.0.0.1:" . $server->getPort() . "\r\n" . $request); + $response = Response::fromMessage($response); + $request->setClient(new Client()); + + $plugin = new CachePlugin(new DoctrineCacheAdapter(new ArrayCache())); + $this->assertEquals( + $can, + $plugin->canResponseSatisfyRequest($request, $response), + '-> ' . $request . "\n" . $response + ); + + if ($result) { + $result = Response::fromMessage($result); + $result->removeHeader('Date'); + $request->getResponse()->removeHeader('Date'); + $request->getResponse()->removeHeader('Connection'); + // Get rid of dates + $this->assertEquals((string) $result, (string) $request->getResponse()); + } + + if ($validate) { + $this->assertEquals(1, count($server->getReceivedRequests())); + } + } + + public function testHandles404RevalidationResponses() + { + $request = new Request('GET', 'http://foo.com'); + $request->setClient(new Client()); + $badResponse = new Response(404, array(), 'Oh no!'); + $badRequest = clone $request; + $badRequest->setResponse($badResponse, true); + $response = new Response(200, array(), 'foo'); + + // Seed the cache + $s = new DefaultCacheStorage(new DoctrineCacheAdapter(new ArrayCache())); + $s->cache($request, $response); + $this->assertNotNull($s->fetch($request)); + + $rev = $this->getMockBuilder('Guzzle\Plugin\Cache\DefaultRevalidation') + ->setConstructorArgs(array($s)) + ->setMethods(array('createRevalidationRequest')) + ->getMock(); + + $rev->expects($this->once()) + ->method('createRevalidationRequest') + ->will($this->returnValue($badRequest)); + + try { + $rev->revalidate($request, $response); + $this->fail('Should have thrown an exception'); + } catch (BadResponseException $e) { + $this->assertSame($badResponse, $e->getResponse()); + $this->assertNull($s->fetch($request)); + } + } + + public function testCanRevalidateWithPlugin() + { + $this->getServer()->flush(); + $this->getServer()->enqueue(array( + "HTTP/1.1 200 OK\r\n" . + "Date: Mon, 12 Nov 2012 03:06:37 GMT\r\n" . + "Cache-Control: private, s-maxage=0, max-age=0, must-revalidate\r\n" . + "Last-Modified: Mon, 12 Nov 2012 02:53:38 GMT\r\n" . + "Content-Length: 2\r\n\r\nhi", + "HTTP/1.0 304 Not Modified\r\n" . + "Date: Mon, 12 Nov 2012 03:06:38 GMT\r\n" . + "Content-Type: text/html; charset=UTF-8\r\n" . + "Last-Modified: Mon, 12 Nov 2012 02:53:38 GMT\r\n" . + "Age: 6302\r\n\r\n", + "HTTP/1.0 304 Not Modified\r\n" . + "Date: Mon, 12 Nov 2012 03:06:38 GMT\r\n" . + "Content-Type: text/html; charset=UTF-8\r\n" . + "Last-Modified: Mon, 12 Nov 2012 02:53:38 GMT\r\n" . + "Age: 6302\r\n\r\n", + )); + $client = new Client($this->getServer()->getUrl()); + $client->addSubscriber(new CachePlugin()); + $this->assertEquals(200, $client->get()->send()->getStatusCode()); + $this->assertEquals(200, $client->get()->send()->getStatusCode()); + $this->assertEquals(200, $client->get()->send()->getStatusCode()); + $this->assertEquals(3, count($this->getServer()->getReceivedRequests())); + } + + public function testCanHandleRevalidationFailures() + { + $client = new Client($this->getServer()->getUrl()); + $lm = gmdate('c', time() - 60); + $mock = new MockPlugin(array( + new Response(200, array( + 'Date' => $lm, + 'Cache-Control' => 'max-age=100, must-revalidate, stale-if-error=9999', + 'Last-Modified' => $lm, + 'Content-Length' => 2 + ), 'hi'), + new CurlException('Bleh'), + new CurlException('Bleh') + )); + $client->addSubscriber(new CachePlugin()); + $client->addSubscriber($mock); + $client->get()->send(); + $response = $client->get()->send(); + $this->assertEquals(200, $response->getStatusCode()); + $this->assertEquals('hi', $response->getBody(true)); + $this->assertEquals(3, count($mock->getReceivedRequests())); + $this->assertEquals(0, count($mock->getQueue())); + } + + public function testCanHandleStaleIfErrorWhenRevalidating() + { + $lm = gmdate('c', time() - 60); + $mock = new MockPlugin(array( + new Response(200, array( + 'Date' => $lm, + 'Cache-Control' => 'must-revalidate, max-age=0, stale-if-error=1200', + 'Last-Modified' => $lm, + 'Content-Length' => 2 + ), 'hi'), + new CurlException('Oh no!'), + new CurlException('Oh no!') + )); + $cache = new CachePlugin(); + $client = new Client('http://www.example.com'); + $client->addSubscriber($cache); + $client->addSubscriber($mock); + $this->assertEquals(200, $client->get()->send()->getStatusCode()); + $response = $client->get()->send(); + $this->assertEquals(200, $response->getStatusCode()); + $this->assertCount(0, $mock); + $this->assertEquals('HIT from GuzzleCache', (string) $response->getHeader('X-Cache-Lookup')); + $this->assertEquals('HIT_ERROR from GuzzleCache', (string) $response->getHeader('X-Cache')); + } + + /** + * @group issue-437 + */ + public function testDoesNotTouchClosureListeners() + { + $this->getServer()->flush(); + $this->getServer()->enqueue(array( + "HTTP/1.1 200 OK\r\n" . + "Date: Mon, 12 Nov 2012 03:06:37 GMT\r\n" . + "Cache-Control: private, s-maxage=0, max-age=0, must-revalidate\r\n" . + "Last-Modified: Mon, 12 Nov 2012 02:53:38 GMT\r\n" . + "Content-Length: 2\r\n\r\nhi", + "HTTP/1.0 304 Not Modified\r\n" . + "Date: Mon, 12 Nov 2012 03:06:38 GMT\r\n" . + "Content-Type: text/html; charset=UTF-8\r\n" . + "Last-Modified: Mon, 12 Nov 2012 02:53:38 GMT\r\n" . + "Age: 6302\r\n\r\n", + "HTTP/1.0 304 Not Modified\r\n" . + "Date: Mon, 12 Nov 2012 03:06:38 GMT\r\n" . + "Content-Type: text/html; charset=UTF-8\r\n" . + "Last-Modified: Mon, 12 Nov 2012 02:53:38 GMT\r\n" . + "Age: 6302\r\n\r\n", + )); + $client = new Client($this->getServer()->getUrl()); + $client->addSubscriber(new CachePlugin()); + $client->getEventDispatcher()->addListener('command.after_send', function(){}); + $this->assertEquals(200, $client->get()->send()->getStatusCode()); + $this->assertEquals(200, $client->get()->send()->getStatusCode()); + $this->assertEquals(200, $client->get()->send()->getStatusCode()); + } + +} diff --git a/vendor/guzzle/guzzle/tests/Guzzle/Tests/Plugin/Cache/DenyRevalidationTest.php b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Plugin/Cache/DenyRevalidationTest.php new file mode 100644 index 0000000..9af80f2 --- /dev/null +++ b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Plugin/Cache/DenyRevalidationTest.php @@ -0,0 +1,19 @@ +assertFalse($deny->revalidate(new Request('GET', 'http://foo.com'), new Response(200))); + } +} diff --git a/vendor/guzzle/guzzle/tests/Guzzle/Tests/Plugin/Cache/SkipRevalidationTest.php b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Plugin/Cache/SkipRevalidationTest.php new file mode 100644 index 0000000..4bcc04b --- /dev/null +++ b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Plugin/Cache/SkipRevalidationTest.php @@ -0,0 +1,19 @@ +assertTrue($skip->revalidate(new Request('GET', 'http://foo.com'), new Response(200))); + } +} diff --git a/vendor/guzzle/guzzle/tests/Guzzle/Tests/Plugin/Cookie/CookieJar/ArrayCookieJarTest.php b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Plugin/Cookie/CookieJar/ArrayCookieJarTest.php new file mode 100644 index 0000000..5d0f668 --- /dev/null +++ b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Plugin/Cookie/CookieJar/ArrayCookieJarTest.php @@ -0,0 +1,385 @@ +jar = new ArrayCookieJar(); + } + + protected function getTestCookies() + { + return array( + new Cookie(array('name' => 'foo', 'value' => 'bar', 'domain' => 'foo.com', 'path' => '/', 'discard' => true)), + new Cookie(array('name' => 'test', 'value' => '123', 'domain' => 'baz.com', 'path' => '/foo', 'expires' => 2)), + new Cookie(array('name' => 'you', 'value' => '123', 'domain' => 'bar.com', 'path' => '/boo', 'expires' => time() + 1000)) + ); + } + + /** + * Provides test data for cookie cookieJar retrieval + */ + public function getCookiesDataProvider() + { + return array( + array(array('foo', 'baz', 'test', 'muppet', 'googoo'), '', '', '', false), + array(array('foo', 'baz', 'muppet', 'googoo'), '', '', '', true), + array(array('googoo'), 'www.example.com', '', '', false), + array(array('muppet', 'googoo'), 'test.y.example.com', '', '', false), + array(array('foo', 'baz'), 'example.com', '', '', false), + array(array('muppet'), 'x.y.example.com', '/acme/', '', false), + array(array('muppet'), 'x.y.example.com', '/acme/test/', '', false), + array(array('googoo'), 'x.y.example.com', '/test/acme/test/', '', false), + array(array('foo', 'baz'), 'example.com', '', '', false), + array(array('baz'), 'example.com', '', 'baz', false), + ); + } + + public function testStoresAndRetrievesCookies() + { + $cookies = $this->getTestCookies(); + foreach ($cookies as $cookie) { + $this->assertTrue($this->jar->add($cookie)); + } + + $this->assertEquals(3, count($this->jar)); + $this->assertEquals(3, count($this->jar->getIterator())); + $this->assertEquals($cookies, $this->jar->all(null, null, null, false, false)); + } + + public function testRemovesExpiredCookies() + { + $cookies = $this->getTestCookies(); + foreach ($this->getTestCookies() as $cookie) { + $this->jar->add($cookie); + } + $this->jar->removeExpired(); + $this->assertEquals(array($cookies[0], $cookies[2]), $this->jar->all()); + } + + public function testRemovesTemporaryCookies() + { + $cookies = $this->getTestCookies(); + foreach ($this->getTestCookies() as $cookie) { + $this->jar->add($cookie); + } + $this->jar->removeTemporary(); + $this->assertEquals(array($cookies[2]), $this->jar->all()); + } + + public function testIsSerializable() + { + $this->assertEquals('[]', $this->jar->serialize()); + $this->jar->unserialize('[]'); + $this->assertEquals(array(), $this->jar->all()); + + $cookies = $this->getTestCookies(); + foreach ($this->getTestCookies() as $cookie) { + $this->jar->add($cookie); + } + + // Remove discard and expired cookies + $serialized = $this->jar->serialize(); + $data = json_decode($serialized, true); + $this->assertEquals(1, count($data)); + + $a = new ArrayCookieJar(); + $a->unserialize($serialized); + $this->assertEquals(1, count($a)); + } + + public function testRemovesSelectively() + { + $cookies = $this->getTestCookies(); + foreach ($this->getTestCookies() as $cookie) { + $this->jar->add($cookie); + } + + // Remove foo.com cookies + $this->jar->remove('foo.com'); + $this->assertEquals(2, count($this->jar)); + // Try again, removing no further cookies + $this->jar->remove('foo.com'); + $this->assertEquals(2, count($this->jar)); + + // Remove bar.com cookies with path of /boo + $this->jar->remove('bar.com', '/boo'); + $this->assertEquals(1, count($this->jar)); + + // Remove cookie by name + $this->jar->remove(null, null, 'test'); + $this->assertEquals(0, count($this->jar)); + } + + public function testDoesNotAddIncompleteCookies() + { + $this->assertEquals(false, $this->jar->add(new Cookie())); + $this->assertFalse($this->jar->add(new Cookie(array( + 'name' => 'foo' + )))); + $this->assertFalse($this->jar->add(new Cookie(array( + 'name' => false + )))); + $this->assertFalse($this->jar->add(new Cookie(array( + 'name' => true + )))); + $this->assertFalse($this->jar->add(new Cookie(array( + 'name' => 'foo', + 'domain' => 'foo.com' + )))); + } + + public function testDoesAddValidCookies() + { + $this->assertTrue($this->jar->add(new Cookie(array( + 'name' => 'foo', + 'domain' => 'foo.com', + 'value' => 0 + )))); + $this->assertTrue($this->jar->add(new Cookie(array( + 'name' => 'foo', + 'domain' => 'foo.com', + 'value' => 0.0 + )))); + $this->assertTrue($this->jar->add(new Cookie(array( + 'name' => 'foo', + 'domain' => 'foo.com', + 'value' => '0' + )))); + } + + public function testOverwritesCookiesThatAreOlderOrDiscardable() + { + $t = time() + 1000; + $data = array( + 'name' => 'foo', + 'value' => 'bar', + 'domain' => '.example.com', + 'path' => '/', + 'max_age' => '86400', + 'port' => array(80, 8080), + 'version' => '1', + 'secure' => true, + 'discard' => true, + 'expires' => $t + ); + + // Make sure that the discard cookie is overridden with the non-discard + $this->assertTrue($this->jar->add(new Cookie($data))); + + unset($data['discard']); + $this->assertTrue($this->jar->add(new Cookie($data))); + $this->assertEquals(1, count($this->jar)); + + $c = $this->jar->all(); + $this->assertEquals(false, $c[0]->getDiscard()); + + // Make sure it doesn't duplicate the cookie + $this->jar->add(new Cookie($data)); + $this->assertEquals(1, count($this->jar)); + + // Make sure the more future-ful expiration date supersede the other + $data['expires'] = time() + 2000; + $this->assertTrue($this->jar->add(new Cookie($data))); + $this->assertEquals(1, count($this->jar)); + $c = $this->jar->all(); + $this->assertNotEquals($t, $c[0]->getExpires()); + } + + public function testOverwritesCookiesThatHaveChanged() + { + $t = time() + 1000; + $data = array( + 'name' => 'foo', + 'value' => 'bar', + 'domain' => '.example.com', + 'path' => '/', + 'max_age' => '86400', + 'port' => array(80, 8080), + 'version' => '1', + 'secure' => true, + 'discard' => true, + 'expires' => $t + ); + + // Make sure that the discard cookie is overridden with the non-discard + $this->assertTrue($this->jar->add(new Cookie($data))); + + $data['value'] = 'boo'; + $this->assertTrue($this->jar->add(new Cookie($data))); + $this->assertEquals(1, count($this->jar)); + + // Changing the value plus a parameter also must overwrite the existing one + $data['value'] = 'zoo'; + $data['secure'] = false; + $this->assertTrue($this->jar->add(new Cookie($data))); + $this->assertEquals(1, count($this->jar)); + + $c = $this->jar->all(); + $this->assertEquals('zoo', $c[0]->getValue()); + } + + public function testAddsCookiesFromResponseWithNoRequest() + { + $response = new Response(200, array( + 'Set-Cookie' => array( + "fpc=d=.Hm.yh4.1XmJWjJfs4orLQzKzPImxklQoxXSHOZATHUSEFciRueW_7704iYUtsXNEXq0M92Px2glMdWypmJ7HIQl6XIUvrZimWjQ3vIdeuRbI.FNQMAfcxu_XN1zSx7l.AcPdKL6guHc2V7hIQFhnjRW0rxm2oHY1P4bGQxFNz7f.tHm12ZD3DbdMDiDy7TBXsuP4DM-&v=2; expires=Fri, 02-Mar-2019 02:17:40 GMT; path=/; domain=127.0.0.1", + "FPCK3=AgBNbvoQAGpGEABZLRAAbFsQAF1tEABkDhAAeO0=; expires=Sat, 02-Apr-2019 02:17:40 GMT; path=/; domain=127.0.0.1", + "CH=deleted; expires=Wed, 03-Mar-2010 02:17:39 GMT; path=/; domain=127.0.0.1", + "CH=AgBNbvoQAAEcEAApuhAAMJcQADQvEAAvGxAALe0QAD6uEAATwhAAC1AQAC8t; expires=Sat, 02-Apr-2019 02:17:40 GMT; path=/; domain=127.0.0.1" + ) + )); + + $this->jar->addCookiesFromResponse($response); + $this->assertEquals(3, count($this->jar)); + $this->assertEquals(1, count($this->jar->all(null, null, 'fpc'))); + $this->assertEquals(1, count($this->jar->all(null, null, 'FPCK3'))); + $this->assertEquals(1, count($this->jar->all(null, null, 'CH'))); + } + + public function testAddsCookiesFromResponseWithRequest() + { + $response = new Response(200, array( + 'Set-Cookie' => "fpc=d=.Hm.yh4.1XmJWjJfs4orLQzKzPImxklQoxXSHOZATHUSEFciRueW_7704iYUtsXNEXq0M92Px2glMdWypmJ7HIQl6XIUvrZimWjQ3vIdeuRbI.FNQMAfcxu_XN1zSx7l.AcPdKL6guHc2V7hIQFhnjRW0rxm2oHY1P4bGQxFNz7f.tHm12ZD3DbdMDiDy7TBXsuP4DM-&v=2; expires=Fri, 02-Mar-2019 02:17:40 GMT;" + )); + $request = new Request('GET', 'http://www.example.com'); + $this->jar->addCookiesFromResponse($response, $request); + $this->assertEquals(1, count($this->jar)); + } + + public function getMatchingCookiesDataProvider() + { + return array( + array('https://example.com', array(0)), + array('http://example.com', array()), + array('https://example.com:8912', array()), + array('https://foo.example.com', array(0)), + array('http://foo.example.com/test/acme/', array(4)) + ); + } + + /** + * @dataProvider getMatchingCookiesDataProvider + */ + public function testReturnsCookiesMatchingRequests($url, $cookies) + { + $bag = array( + new Cookie(array( + 'name' => 'foo', + 'value' => 'bar', + 'domain' => 'example.com', + 'path' => '/', + 'max_age' => '86400', + 'port' => array(443, 8080), + 'version' => '1', + 'secure' => true + )), + new Cookie(array( + 'name' => 'baz', + 'value' => 'foobar', + 'domain' => 'example.com', + 'path' => '/', + 'max_age' => '86400', + 'port' => array(80, 8080), + 'version' => '1', + 'secure' => true + )), + new Cookie(array( + 'name' => 'test', + 'value' => '123', + 'domain' => 'www.foobar.com', + 'path' => '/path/', + 'discard' => true + )), + new Cookie(array( + 'name' => 'muppet', + 'value' => 'cookie_monster', + 'domain' => '.y.example.com', + 'path' => '/acme/', + 'comment' => 'Comment goes here...', + 'expires' => time() + 86400 + )), + new Cookie(array( + 'name' => 'googoo', + 'value' => 'gaga', + 'domain' => '.example.com', + 'path' => '/test/acme/', + 'max_age' => 1500, + 'version' => 2 + )) + ); + + foreach ($bag as $cookie) { + $this->jar->add($cookie); + } + + $request = new Request('GET', $url); + $results = $this->jar->getMatchingCookies($request); + $this->assertEquals(count($cookies), count($results)); + foreach ($cookies as $i) { + $this->assertContains($bag[$i], $results); + } + } + + /** + * @expectedException \Guzzle\Plugin\Cookie\Exception\InvalidCookieException + * @expectedExceptionMessage The cookie name must not contain invalid characters: abc:@123 + */ + public function testThrowsExceptionWithStrictMode() + { + $a = new ArrayCookieJar(); + $a->setStrictMode(true); + $a->add(new Cookie(array( + 'name' => 'abc:@123', + 'value' => 'foo', + 'domain' => 'bar' + ))); + } + + public function testRemoveExistingCookieIfEmpty() + { + // Add a cookie that should not be affected + $a = new Cookie(array( + 'name' => 'foo', + 'value' => 'nope', + 'domain' => 'foo.com', + 'path' => '/abc' + )); + $this->jar->add($a); + + $data = array( + 'name' => 'foo', + 'value' => 'bar', + 'domain' => 'foo.com', + 'path' => '/' + ); + + $b = new Cookie($data); + $this->assertTrue($this->jar->add($b)); + $this->assertEquals(2, count($this->jar)); + + // Try to re-set the same cookie with no value: assert that cookie is not added + $data['value'] = null; + $this->assertFalse($this->jar->add(new Cookie($data))); + // assert that original cookie has been deleted + $cookies = $this->jar->all('foo.com'); + $this->assertTrue(in_array($a, $cookies, true)); + $this->assertFalse(in_array($b, $cookies, true)); + $this->assertEquals(1, count($this->jar)); + } +} diff --git a/vendor/guzzle/guzzle/tests/Guzzle/Tests/Plugin/Cookie/CookieJar/FileCookieJarTest.php b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Plugin/Cookie/CookieJar/FileCookieJarTest.php new file mode 100644 index 0000000..ac9471f --- /dev/null +++ b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Plugin/Cookie/CookieJar/FileCookieJarTest.php @@ -0,0 +1,63 @@ +file = tempnam('/tmp', 'file-cookies'); + } + + public function testLoadsFromFileFile() + { + $jar = new FileCookieJar($this->file); + $this->assertEquals(array(), $jar->all()); + unlink($this->file); + } + + public function testPersistsToFileFile() + { + $jar = new FileCookieJar($this->file); + $jar->add(new Cookie(array( + 'name' => 'foo', + 'value' => 'bar', + 'domain' => 'foo.com', + 'expires' => time() + 1000 + ))); + $jar->add(new Cookie(array( + 'name' => 'baz', + 'value' => 'bar', + 'domain' => 'foo.com', + 'expires' => time() + 1000 + ))); + $jar->add(new Cookie(array( + 'name' => 'boo', + 'value' => 'bar', + 'domain' => 'foo.com', + ))); + + $this->assertEquals(3, count($jar)); + unset($jar); + + // Make sure it wrote to the file + $contents = file_get_contents($this->file); + $this->assertNotEmpty($contents); + + // Load the cookieJar from the file + $jar = new FileCookieJar($this->file); + + // Weeds out temporary and session cookies + $this->assertEquals(2, count($jar)); + unset($jar); + unlink($this->file); + } +} diff --git a/vendor/guzzle/guzzle/tests/Guzzle/Tests/Plugin/Cookie/CookiePluginTest.php b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Plugin/Cookie/CookiePluginTest.php new file mode 100644 index 0000000..f8c175c --- /dev/null +++ b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Plugin/Cookie/CookiePluginTest.php @@ -0,0 +1,134 @@ +getMockBuilder('Guzzle\Plugin\Cookie\CookieJar\ArrayCookieJar') + ->setMethods(array('addCookiesFromResponse')) + ->getMock(); + + $mock->expects($this->exactly(1)) + ->method('addCookiesFromResponse') + ->with($response); + + $plugin = new CookiePlugin($mock); + $plugin->onRequestSent(new Event(array( + 'response' => $response + ))); + } + + public function testAddsCookiesToRequests() + { + $cookie = new Cookie(array( + 'name' => 'foo', + 'value' => 'bar' + )); + + $mock = $this->getMockBuilder('Guzzle\Plugin\Cookie\CookieJar\ArrayCookieJar') + ->setMethods(array('getMatchingCookies')) + ->getMock(); + + $mock->expects($this->once()) + ->method('getMatchingCookies') + ->will($this->returnValue(array($cookie))); + + $plugin = new CookiePlugin($mock); + + $client = new Client(); + $client->getEventDispatcher()->addSubscriber($plugin); + + $request = $client->get('http://www.example.com'); + $plugin->onRequestBeforeSend(new Event(array( + 'request' => $request + ))); + + $this->assertEquals('bar', $request->getCookie('foo')); + } + + public function testCookiesAreExtractedFromRedirectResponses() + { + $plugin = new CookiePlugin(new ArrayCookieJar()); + $this->getServer()->flush(); + $this->getServer()->enqueue(array( + "HTTP/1.1 302 Moved Temporarily\r\n" . + "Set-Cookie: test=583551; expires=Wednesday, 23-Mar-2050 19:49:45 GMT; path=/\r\n" . + "Location: /redirect\r\n\r\n", + "HTTP/1.1 200 OK\r\n" . + "Content-Length: 0\r\n\r\n", + "HTTP/1.1 200 OK\r\n" . + "Content-Length: 0\r\n\r\n" + )); + + $client = new Client($this->getServer()->getUrl()); + $client->getEventDispatcher()->addSubscriber($plugin); + + $client->get()->send(); + $request = $client->get(); + $request->send(); + $this->assertEquals('test=583551', $request->getHeader('Cookie')); + + $requests = $this->getServer()->getReceivedRequests(true); + // Confirm subsequent requests have the cookie. + $this->assertEquals('test=583551', $requests[2]->getHeader('Cookie')); + // Confirm the redirected request has the cookie. + $this->assertEquals('test=583551', $requests[1]->getHeader('Cookie')); + } + + public function testCookiesAreNotAddedWhenParamIsSet() + { + $jar = new ArrayCookieJar(); + $plugin = new CookiePlugin($jar); + + $jar->add(new Cookie(array( + 'domain' => 'example.com', + 'path' => '/', + 'name' => 'test', + 'value' => 'hi', + 'expires' => time() + 3600 + ))); + + $client = new Client('http://example.com'); + $client->getEventDispatcher()->addSubscriber($plugin); + + // Ensure that it is normally added + $request = $client->get(); + $request->setResponse(new Response(200), true); + $request->send(); + $this->assertEquals('hi', $request->getCookie('test')); + + // Now ensure that it is not added + $request = $client->get(); + $request->getParams()->set('cookies.disable', true); + $request->setResponse(new Response(200), true); + $request->send(); + $this->assertNull($request->getCookie('test')); + } + + public function testProvidesCookieJar() + { + $jar = new ArrayCookieJar(); + $plugin = new CookiePlugin($jar); + $this->assertSame($jar, $plugin->getCookieJar()); + } + + public function testEscapesCookieDomains() + { + $cookie = new Cookie(array('domain' => '/foo/^$[A-Z]+/')); + $this->assertFalse($cookie->matchesDomain('foo')); + } +} diff --git a/vendor/guzzle/guzzle/tests/Guzzle/Tests/Plugin/Cookie/CookieTest.php b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Plugin/Cookie/CookieTest.php new file mode 100644 index 0000000..9fb0b43 --- /dev/null +++ b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Plugin/Cookie/CookieTest.php @@ -0,0 +1,223 @@ +assertEquals('/', $cookie->getPath()); + $this->assertEquals(array(), $cookie->getPorts()); + } + + public function testConvertsDateTimeMaxAgeToUnixTimestamp() + { + $cookie = new Cookie(array( + 'expires' => 'November 20, 1984' + )); + $this->assertTrue(is_numeric($cookie->getExpires())); + } + + public function testAddsExpiresBasedOnMaxAge() + { + $t = time(); + $cookie = new Cookie(array( + 'max_age' => 100 + )); + $this->assertEquals($t + 100, $cookie->getExpires()); + } + + public function testHoldsValues() + { + $t = time(); + $data = array( + 'name' => 'foo', + 'value' => 'baz', + 'path' => '/bar', + 'domain' => 'baz.com', + 'expires' => $t, + 'max_age' => 100, + 'comment' => 'Hi', + 'comment_url' => 'foo.com', + 'port' => array(1, 2), + 'version' => 2, + 'secure' => true, + 'discard' => true, + 'http_only' => true, + 'data' => array( + 'foo' => 'baz', + 'bar' => 'bam' + ) + ); + + $cookie = new Cookie($data); + $this->assertEquals($data, $cookie->toArray()); + + $this->assertEquals('foo', $cookie->getName()); + $this->assertEquals('baz', $cookie->getValue()); + $this->assertEquals('baz.com', $cookie->getDomain()); + $this->assertEquals('/bar', $cookie->getPath()); + $this->assertEquals($t, $cookie->getExpires()); + $this->assertEquals(100, $cookie->getMaxAge()); + $this->assertEquals('Hi', $cookie->getComment()); + $this->assertEquals('foo.com', $cookie->getCommentUrl()); + $this->assertEquals(array(1, 2), $cookie->getPorts()); + $this->assertEquals(2, $cookie->getVersion()); + $this->assertTrue($cookie->getSecure()); + $this->assertTrue($cookie->getDiscard()); + $this->assertTrue($cookie->getHttpOnly()); + $this->assertEquals('baz', $cookie->getAttribute('foo')); + $this->assertEquals('bam', $cookie->getAttribute('bar')); + $this->assertEquals(array( + 'foo' => 'baz', + 'bar' => 'bam' + ), $cookie->getAttributes()); + + $cookie->setName('a') + ->setValue('b') + ->setPath('c') + ->setDomain('bar.com') + ->setExpires(10) + ->setMaxAge(200) + ->setComment('e') + ->setCommentUrl('f') + ->setPorts(array(80)) + ->setVersion(3) + ->setSecure(false) + ->setHttpOnly(false) + ->setDiscard(false) + ->setAttribute('snoop', 'dog'); + + $this->assertEquals('a', $cookie->getName()); + $this->assertEquals('b', $cookie->getValue()); + $this->assertEquals('c', $cookie->getPath()); + $this->assertEquals('bar.com', $cookie->getDomain()); + $this->assertEquals(10, $cookie->getExpires()); + $this->assertEquals(200, $cookie->getMaxAge()); + $this->assertEquals('e', $cookie->getComment()); + $this->assertEquals('f', $cookie->getCommentUrl()); + $this->assertEquals(array(80), $cookie->getPorts()); + $this->assertEquals(3, $cookie->getVersion()); + $this->assertFalse($cookie->getSecure()); + $this->assertFalse($cookie->getDiscard()); + $this->assertFalse($cookie->getHttpOnly()); + $this->assertEquals('dog', $cookie->getAttribute('snoop')); + } + + public function testDeterminesIfExpired() + { + $c = new Cookie(); + $c->setExpires(10); + $this->assertTrue($c->isExpired()); + $c->setExpires(time() + 10000); + $this->assertFalse($c->isExpired()); + } + + public function testMatchesPorts() + { + $cookie = new Cookie(); + // Always matches when nothing is set + $this->assertTrue($cookie->matchesPort(2)); + + $cookie->setPorts(array(1, 2)); + $this->assertTrue($cookie->matchesPort(2)); + $this->assertFalse($cookie->matchesPort(100)); + } + + public function testMatchesDomain() + { + $cookie = new Cookie(); + $this->assertTrue($cookie->matchesDomain('baz.com')); + + $cookie->setDomain('baz.com'); + $this->assertTrue($cookie->matchesDomain('baz.com')); + $this->assertFalse($cookie->matchesDomain('bar.com')); + + $cookie->setDomain('.baz.com'); + $this->assertTrue($cookie->matchesDomain('.baz.com')); + $this->assertTrue($cookie->matchesDomain('foo.baz.com')); + $this->assertFalse($cookie->matchesDomain('baz.bar.com')); + $this->assertTrue($cookie->matchesDomain('baz.com')); + + $cookie->setDomain('.127.0.0.1'); + $this->assertTrue($cookie->matchesDomain('127.0.0.1')); + + $cookie->setDomain('127.0.0.1'); + $this->assertTrue($cookie->matchesDomain('127.0.0.1')); + + $cookie->setDomain('.com.'); + $this->assertFalse($cookie->matchesDomain('baz.com')); + + $cookie->setDomain('.local'); + $this->assertTrue($cookie->matchesDomain('example.local')); + } + + public function testMatchesPath() + { + $cookie = new Cookie(); + $this->assertTrue($cookie->matchesPath('/foo')); + + $cookie->setPath('/foo'); + + // o The cookie-path and the request-path are identical. + $this->assertTrue($cookie->matchesPath('/foo')); + $this->assertFalse($cookie->matchesPath('/bar')); + + // o The cookie-path is a prefix of the request-path, and the first + // character of the request-path that is not included in the cookie- + // path is a %x2F ("/") character. + $this->assertTrue($cookie->matchesPath('/foo/bar')); + $this->assertFalse($cookie->matchesPath('/fooBar')); + + // o The cookie-path is a prefix of the request-path, and the last + // character of the cookie-path is %x2F ("/"). + $cookie->setPath('/foo/'); + $this->assertTrue($cookie->matchesPath('/foo/bar')); + $this->assertFalse($cookie->matchesPath('/fooBaz')); + $this->assertFalse($cookie->matchesPath('/foo')); + + } + + public function cookieValidateProvider() + { + return array( + array('foo', 'baz', 'bar', true), + array('0', '0', '0', true), + array('', 'baz', 'bar', 'The cookie name must not be empty'), + array('foo', '', 'bar', 'The cookie value must not be empty'), + array('foo', 'baz', '', 'The cookie domain must not be empty'), + array('foo\\', 'baz', '0', 'The cookie name must not contain invalid characters: foo\\'), + ); + } + + /** + * @dataProvider cookieValidateProvider + */ + public function testValidatesCookies($name, $value, $domain, $result) + { + $cookie = new Cookie(array( + 'name' => $name, + 'value' => $value, + 'domain' => $domain + )); + $this->assertSame($result, $cookie->validate()); + } + + public function testCreatesInvalidCharacterString() + { + $m = new \ReflectionMethod('Guzzle\Plugin\Cookie\Cookie', 'getInvalidCharacters'); + $m->setAccessible(true); + $p = new \ReflectionProperty('Guzzle\Plugin\Cookie\Cookie', 'invalidCharString'); + $p->setAccessible(true); + $p->setValue(''); + // Expects a string containing 51 invalid characters + $this->assertEquals(51, strlen($m->invoke($m))); + $this->assertContains('@', $m->invoke($m)); + } +} diff --git a/vendor/guzzle/guzzle/tests/Guzzle/Tests/Plugin/CurlAuth/CurlAuthPluginTest.php b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Plugin/CurlAuth/CurlAuthPluginTest.php new file mode 100644 index 0000000..2a4b49e --- /dev/null +++ b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Plugin/CurlAuth/CurlAuthPluginTest.php @@ -0,0 +1,39 @@ +getEventDispatcher()->addSubscriber($plugin); + $request = $client->get('/'); + $this->assertEquals('michael', $request->getUsername()); + $this->assertEquals('test', $request->getPassword()); + Version::$emitWarnings = true; + } + + public function testAddsDigestAuthentication() + { + Version::$emitWarnings = false; + $plugin = new CurlAuthPlugin('julian', 'test', CURLAUTH_DIGEST); + $client = new Client('http://www.test.com/'); + $client->getEventDispatcher()->addSubscriber($plugin); + $request = $client->get('/'); + $this->assertEquals('julian', $request->getUsername()); + $this->assertEquals('test', $request->getPassword()); + $this->assertEquals('julian:test', $request->getCurlOptions()->get(CURLOPT_USERPWD)); + $this->assertEquals(CURLAUTH_DIGEST, $request->getCurlOptions()->get(CURLOPT_HTTPAUTH)); + Version::$emitWarnings = true; + } +} diff --git a/vendor/guzzle/guzzle/tests/Guzzle/Tests/Plugin/ErrorResponse/ErrorResponsePluginTest.php b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Plugin/ErrorResponse/ErrorResponsePluginTest.php new file mode 100644 index 0000000..6f94186 --- /dev/null +++ b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Plugin/ErrorResponse/ErrorResponsePluginTest.php @@ -0,0 +1,137 @@ +flush(); + } + + public function setUp() + { + $mockError = 'Guzzle\Tests\Mock\ErrorResponseMock'; + $description = ServiceDescription::factory(array( + 'operations' => array( + 'works' => array( + 'httpMethod' => 'GET', + 'errorResponses' => array( + array('code' => 500, 'class' => $mockError), + array('code' => 503, 'reason' => 'foo', 'class' => $mockError), + array('code' => 200, 'reason' => 'Error!', 'class' => $mockError) + ) + ), + 'bad_class' => array( + 'httpMethod' => 'GET', + 'errorResponses' => array( + array('code' => 500, 'class' => 'Does\\Not\\Exist') + ) + ), + 'does_not_implement' => array( + 'httpMethod' => 'GET', + 'errorResponses' => array( + array('code' => 500, 'class' => __CLASS__) + ) + ), + 'no_errors' => array('httpMethod' => 'GET'), + 'no_class' => array( + 'httpMethod' => 'GET', + 'errorResponses' => array( + array('code' => 500) + ) + ), + ) + )); + $this->client = new Client($this->getServer()->getUrl()); + $this->client->setDescription($description); + } + + /** + * @expectedException \Guzzle\Http\Exception\ServerErrorResponseException + */ + public function testSkipsWhenErrorResponsesIsNotSet() + { + $this->getServer()->enqueue("HTTP/1.1 500 Foo\r\nContent-Length: 0\r\n\r\n"); + $this->client->addSubscriber(new ErrorResponsePlugin()); + $this->client->getCommand('no_errors')->execute(); + } + + public function testSkipsWhenErrorResponsesIsNotSetAndAllowsSuccess() + { + $this->getServer()->enqueue("HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n"); + $this->client->addSubscriber(new ErrorResponsePlugin()); + $this->client->getCommand('no_errors')->execute(); + } + + /** + * @expectedException \Guzzle\Plugin\ErrorResponse\Exception\ErrorResponseException + * @expectedExceptionMessage Does\Not\Exist does not exist + */ + public function testEnsuresErrorResponseExists() + { + $this->getServer()->enqueue("HTTP/1.1 500 Foo\r\nContent-Length: 0\r\n\r\n"); + $this->client->addSubscriber(new ErrorResponsePlugin()); + $this->client->getCommand('bad_class')->execute(); + } + + /** + * @expectedException \Guzzle\Plugin\ErrorResponse\Exception\ErrorResponseException + * @expectedExceptionMessage must implement Guzzle\Plugin\ErrorResponse\ErrorResponseExceptionInterface + */ + public function testEnsuresErrorResponseImplementsInterface() + { + $this->getServer()->enqueue("HTTP/1.1 500 Foo\r\nContent-Length: 0\r\n\r\n"); + $this->client->addSubscriber(new ErrorResponsePlugin()); + $this->client->getCommand('does_not_implement')->execute(); + } + + public function testThrowsSpecificErrorResponseOnMatch() + { + try { + $this->getServer()->enqueue("HTTP/1.1 500 Foo\r\nContent-Length: 0\r\n\r\n"); + $this->client->addSubscriber(new ErrorResponsePlugin()); + $command = $this->client->getCommand('works'); + $command->execute(); + $this->fail('Exception not thrown'); + } catch (ErrorResponseMock $e) { + $this->assertSame($command, $e->command); + $this->assertEquals(500, $e->response->getStatusCode()); + } + } + + /** + * @expectedException \Guzzle\Tests\Mock\ErrorResponseMock + */ + public function testThrowsWhenCodeAndPhraseMatch() + { + $this->getServer()->enqueue("HTTP/1.1 200 Error!\r\nContent-Length: 0\r\n\r\n"); + $this->client->addSubscriber(new ErrorResponsePlugin()); + $this->client->getCommand('works')->execute(); + } + + public function testSkipsWhenReasonDoesNotMatch() + { + $this->getServer()->enqueue("HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n"); + $this->client->addSubscriber(new ErrorResponsePlugin()); + $this->client->getCommand('works')->execute(); + } + + public function testSkipsWhenNoClassIsSet() + { + $this->getServer()->enqueue("HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n"); + $this->client->addSubscriber(new ErrorResponsePlugin()); + $this->client->getCommand('no_class')->execute(); + } +} diff --git a/vendor/guzzle/guzzle/tests/Guzzle/Tests/Plugin/History/HistoryPluginTest.php b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Plugin/History/HistoryPluginTest.php new file mode 100644 index 0000000..41aa673 --- /dev/null +++ b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Plugin/History/HistoryPluginTest.php @@ -0,0 +1,140 @@ +get(); + $requests[$i]->setResponse(new Response(200), true); + $requests[$i]->send(); + $h->add($requests[$i]); + } + + return $requests; + } + + public function testDescribesSubscribedEvents() + { + $this->assertInternalType('array', HistoryPlugin::getSubscribedEvents()); + } + + public function testMaintainsLimitValue() + { + $h = new HistoryPlugin(); + $this->assertSame($h, $h->setLimit(10)); + $this->assertEquals(10, $h->getLimit()); + } + + public function testAddsRequests() + { + $h = new HistoryPlugin(); + $requests = $this->addRequests($h, 1); + $this->assertEquals(1, count($h)); + $i = $h->getIterator(); + $this->assertEquals(1, count($i)); + $this->assertEquals($requests[0], $i[0]); + } + + /** + * @depends testAddsRequests + */ + public function testMaintainsLimit() + { + $h = new HistoryPlugin(); + $h->setLimit(2); + $requests = $this->addRequests($h, 3); + $this->assertEquals(2, count($h)); + $i = 0; + foreach ($h as $request) { + if ($i > 0) { + $this->assertSame($requests[$i], $request); + } + } + } + + public function testReturnsLastRequest() + { + $h = new HistoryPlugin(); + $requests = $this->addRequests($h, 5); + $this->assertSame(end($requests), $h->getLastRequest()); + } + + public function testReturnsLastResponse() + { + $h = new HistoryPlugin(); + $requests = $this->addRequests($h, 5); + $this->assertSame(end($requests)->getResponse(), $h->getLastResponse()); + } + + public function testClearsHistory() + { + $h = new HistoryPlugin(); + $requests = $this->addRequests($h, 5); + $this->assertEquals(5, count($h)); + $h->clear(); + $this->assertEquals(0, count($h)); + } + + /** + * @depends testAddsRequests + */ + public function testUpdatesAddRequests() + { + $h = new HistoryPlugin(); + $client = new Client('http://127.0.0.1/'); + $client->getEventDispatcher()->addSubscriber($h); + + $request = $client->get(); + $request->setResponse(new Response(200), true); + $request->send(); + + $this->assertSame($request, $h->getLastRequest()); + } + + public function testCanCastToString() + { + $client = new Client('http://127.0.0.1/'); + $h = new HistoryPlugin(); + $client->getEventDispatcher()->addSubscriber($h); + + $mock = new MockPlugin(array( + new Response(301, array('Location' => '/redirect1', 'Content-Length' => 0)), + new Response(307, array('Location' => '/redirect2', 'Content-Length' => 0)), + new Response(200, array('Content-Length' => '2'), 'HI') + )); + + $client->getEventDispatcher()->addSubscriber($mock); + $request = $client->get(); + $request->send(); + $this->assertEquals(3, count($h)); + $this->assertEquals(3, count($mock->getReceivedRequests())); + + $h = str_replace("\r", '', $h); + $this->assertContains("> GET / HTTP/1.1\nHost: 127.0.0.1\nUser-Agent:", $h); + $this->assertContains("< HTTP/1.1 301 Moved Permanently\nLocation: /redirect1", $h); + $this->assertContains("< HTTP/1.1 307 Temporary Redirect\nLocation: /redirect2", $h); + $this->assertContains("< HTTP/1.1 200 OK\nContent-Length: 2\n\nHI", $h); + } +} diff --git a/vendor/guzzle/guzzle/tests/Guzzle/Tests/Plugin/Log/LogPluginTest.php b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Plugin/Log/LogPluginTest.php new file mode 100644 index 0000000..ad663a5 --- /dev/null +++ b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Plugin/Log/LogPluginTest.php @@ -0,0 +1,95 @@ +adapter = new ClosureLogAdapter(function ($message) { + echo $message; + }); + } + + public function testIgnoresCurlEventsWhenNotWiringBodies() + { + $p = new LogPlugin($this->adapter); + $this->assertNotEmpty($p->getSubscribedEvents()); + $event = new Event(array('request' => new Request('GET', 'http://foo.com'))); + $p->onCurlRead($event); + $p->onCurlWrite($event); + $p->onRequestBeforeSend($event); + } + + public function testLogsWhenComplete() + { + $output = ''; + $p = new LogPlugin(new ClosureLogAdapter(function ($message) use (&$output) { + $output = $message; + }), '{method} {resource} | {code} {res_body}'); + + $p->onRequestSent(new Event(array( + 'request' => new Request('GET', 'http://foo.com'), + 'response' => new Response(200, array(), 'Foo') + ))); + + $this->assertEquals('GET / | 200 Foo', $output); + } + + public function testWiresBodiesWhenNeeded() + { + $client = new Client($this->getServer()->getUrl()); + $plugin = new LogPlugin($this->adapter, '{req_body} | {res_body}', true); + $client->getEventDispatcher()->addSubscriber($plugin); + $request = $client->put(); + + // Send the response from the dummy server as the request body + $this->getServer()->enqueue("HTTP/1.1 200 OK\r\nContent-Length: 4\r\n\r\nsend"); + $stream = fopen($this->getServer()->getUrl(), 'r'); + $request->setBody(EntityBody::factory($stream, 4)); + + $tmpFile = tempnam(sys_get_temp_dir(), 'non_repeatable'); + $request->setResponseBody(EntityBody::factory(fopen($tmpFile, 'w'))); + + $this->getServer()->enqueue("HTTP/1.1 200 OK\r\nContent-Length: 8\r\n\r\nresponse"); + + ob_start(); + $request->send(); + $message = ob_get_clean(); + + unlink($tmpFile); + $this->assertContains("send", $message); + $this->assertContains("response", $message); + } + + public function testHasHelpfulStaticFactoryMethod() + { + $s = fopen('php://temp', 'r+'); + $client = new Client(); + $client->addSubscriber(LogPlugin::getDebugPlugin(true, $s)); + $request = $client->put('http://foo.com', array('Content-Type' => 'Foo'), 'Bar'); + $request->setresponse(new Response(200), true); + $request->send(); + rewind($s); + $contents = stream_get_contents($s); + $this->assertContains('# Request:', $contents); + $this->assertContainsIns('PUT / HTTP/1.1', $contents); + $this->assertContains('# Response:', $contents); + $this->assertContainsIns('HTTP/1.1 200 OK', $contents); + $this->assertContains('# Errors:', $contents); + } +} diff --git a/vendor/guzzle/guzzle/tests/Guzzle/Tests/Plugin/Md5/CommandContentMd5PluginTest.php b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Plugin/Md5/CommandContentMd5PluginTest.php new file mode 100644 index 0000000..4bd4111 --- /dev/null +++ b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Plugin/Md5/CommandContentMd5PluginTest.php @@ -0,0 +1,97 @@ + array( + 'test' => array( + 'httpMethod' => 'PUT', + 'parameters' => array( + 'ContentMD5' => array(), + 'Body' => array( + 'location' => 'body' + ) + ) + ) + ) + )); + + $client = new Client(); + $client->setDescription($description); + + return $client; + } + + public function testHasEvents() + { + $this->assertNotEmpty(CommandContentMd5Plugin::getSubscribedEvents()); + } + + public function testValidatesMd5WhenParamExists() + { + $client = $this->getClient(); + $command = $client->getCommand('test', array( + 'Body' => 'Foo', + 'ContentMD5' => true + )); + $event = new Event(array('command' => $command)); + $request = $command->prepare(); + $plugin = new CommandContentMd5Plugin(); + $plugin->onCommandBeforeSend($event); + $this->assertEquals('E1bGfXrRY42Ba/uCLdLCXQ==', (string) $request->getHeader('Content-MD5')); + } + + public function testDoesNothingWhenNoPayloadExists() + { + $client = $this->getClient(); + $client->getDescription()->getOperation('test')->setHttpMethod('GET'); + $command = $client->getCommand('test'); + $event = new Event(array('command' => $command)); + $request = $command->prepare(); + $plugin = new CommandContentMd5Plugin(); + $plugin->onCommandBeforeSend($event); + $this->assertNull($request->getHeader('Content-MD5')); + } + + public function testAddsValidationToResponsesOfContentMd5() + { + $client = $this->getClient(); + $client->getDescription()->getOperation('test')->setHttpMethod('GET'); + $command = $client->getCommand('test', array( + 'ValidateMD5' => true + )); + $event = new Event(array('command' => $command)); + $request = $command->prepare(); + $plugin = new CommandContentMd5Plugin(); + $plugin->onCommandBeforeSend($event); + $listeners = $request->getEventDispatcher()->getListeners('request.complete'); + $this->assertNotEmpty($listeners); + } + + public function testIgnoresValidationWhenDisabled() + { + $client = $this->getClient(); + $client->getDescription()->getOperation('test')->setHttpMethod('GET'); + $command = $client->getCommand('test', array( + 'ValidateMD5' => false + )); + $event = new Event(array('command' => $command)); + $request = $command->prepare(); + $plugin = new CommandContentMd5Plugin(); + $plugin->onCommandBeforeSend($event); + $listeners = $request->getEventDispatcher()->getListeners('request.complete'); + $this->assertEmpty($listeners); + } +} diff --git a/vendor/guzzle/guzzle/tests/Guzzle/Tests/Plugin/Md5/Md5ValidatorPluginTest.php b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Plugin/Md5/Md5ValidatorPluginTest.php new file mode 100644 index 0000000..482e92b --- /dev/null +++ b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Plugin/Md5/Md5ValidatorPluginTest.php @@ -0,0 +1,120 @@ +create('GET', 'http://www.test.com/'); + $request->getEventDispatcher()->addSubscriber($plugin); + + $body = 'abc'; + $hash = md5($body); + $response = new Response(200, array( + 'Content-MD5' => $hash, + 'Content-Length' => 3 + ), 'abc'); + + $request->dispatch('request.complete', array( + 'response' => $response + )); + + // Try again with no Content-MD5 + $response->removeHeader('Content-MD5'); + $request->dispatch('request.complete', array( + 'response' => $response + )); + } + + /** + * @expectedException UnexpectedValueException + */ + public function testThrowsExceptionOnInvalidMd5() + { + $plugin = new Md5ValidatorPlugin(); + $request = RequestFactory::getInstance()->create('GET', 'http://www.test.com/'); + $request->getEventDispatcher()->addSubscriber($plugin); + + $request->dispatch('request.complete', array( + 'response' => new Response(200, array( + 'Content-MD5' => 'foobar', + 'Content-Length' => 3 + ), 'abc') + )); + } + + public function testSkipsWhenContentLengthIsTooLarge() + { + $plugin = new Md5ValidatorPlugin(false, 1); + $request = RequestFactory::getInstance()->create('GET', 'http://www.test.com/'); + $request->getEventDispatcher()->addSubscriber($plugin); + + $request->dispatch('request.complete', array( + 'response' => new Response(200, array( + 'Content-MD5' => 'foobar', + 'Content-Length' => 3 + ), 'abc') + )); + } + + public function testProperlyValidatesWhenUsingContentEncoding() + { + $plugin = new Md5ValidatorPlugin(true); + $request = RequestFactory::getInstance()->create('GET', 'http://www.test.com/'); + $request->getEventDispatcher()->addSubscriber($plugin); + + // Content-MD5 is the MD5 hash of the canonical content after all + // content-encoding has been applied. Because cURL will automatically + // decompress entity bodies, we need to re-compress it to calculate. + $body = EntityBody::factory('abc'); + $body->compress(); + $hash = $body->getContentMd5(); + $body->uncompress(); + + $response = new Response(200, array( + 'Content-MD5' => $hash, + 'Content-Encoding' => 'gzip' + ), 'abc'); + $request->dispatch('request.complete', array( + 'response' => $response + )); + $this->assertEquals('abc', $response->getBody(true)); + + // Try again with an unknown encoding + $response = new Response(200, array( + 'Content-MD5' => $hash, + 'Content-Encoding' => 'foobar' + ), 'abc'); + $request->dispatch('request.complete', array( + 'response' => $response + )); + + // Try again with compress + $body->compress('bzip2.compress'); + $response = new Response(200, array( + 'Content-MD5' => $body->getContentMd5(), + 'Content-Encoding' => 'compress' + ), 'abc'); + $request->dispatch('request.complete', array( + 'response' => $response + )); + + // Try again with encoding and disabled content-encoding checks + $request->getEventDispatcher()->removeSubscriber($plugin); + $plugin = new Md5ValidatorPlugin(false); + $request->getEventDispatcher()->addSubscriber($plugin); + $request->dispatch('request.complete', array( + 'response' => $response + )); + } +} diff --git a/vendor/guzzle/guzzle/tests/Guzzle/Tests/Plugin/Mock/MockPluginTest.php b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Plugin/Mock/MockPluginTest.php new file mode 100644 index 0000000..3af8fef --- /dev/null +++ b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Plugin/Mock/MockPluginTest.php @@ -0,0 +1,199 @@ +assertInternalType('array', MockPlugin::getSubscribedEvents()); + } + + public function testDescribesEvents() + { + $this->assertInternalType('array', MockPlugin::getAllEvents()); + } + + public function testCanBeTemporary() + { + $plugin = new MockPlugin(); + $this->assertFalse($plugin->isTemporary()); + $plugin = new MockPlugin(null, true); + $this->assertTrue($plugin->isTemporary()); + } + + public function testIsCountable() + { + $plugin = new MockPlugin(); + $plugin->addResponse(Response::fromMessage("HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n")); + $this->assertEquals(1, count($plugin)); + } + + /** + * @depends testIsCountable + */ + public function testCanClearQueue() + { + $plugin = new MockPlugin(); + $plugin->addResponse(Response::fromMessage("HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n")); + $plugin->clearQueue(); + $this->assertEquals(0, count($plugin)); + } + + public function testCanInspectQueue() + { + $plugin = new MockPlugin(); + $this->assertInternalType('array', $plugin->getQueue()); + $plugin->addResponse(Response::fromMessage("HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n")); + $queue = $plugin->getQueue(); + $this->assertInternalType('array', $queue); + $this->assertEquals(1, count($queue)); + } + + public function testRetrievesResponsesFromFiles() + { + $response = MockPlugin::getMockFile(__DIR__ . '/../../TestData/mock_response'); + $this->assertInstanceOf('Guzzle\\Http\\Message\\Response', $response); + $this->assertEquals(200, $response->getStatusCode()); + } + + /** + * @expectedException InvalidArgumentException + */ + public function testThrowsExceptionWhenResponseFileIsNotFound() + { + MockPlugin::getMockFile('missing/filename'); + } + + /** + * @expectedException InvalidArgumentException + */ + public function testInvalidResponsesThrowAnException() + { + $p = new MockPlugin(); + $p->addResponse($this); + } + + public function testAddsResponseObjectsToQueue() + { + $p = new MockPlugin(); + $response = Response::fromMessage("HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n"); + $p->addResponse($response); + $this->assertEquals(array($response), $p->getQueue()); + } + + public function testAddsResponseFilesToQueue() + { + $p = new MockPlugin(); + $p->addResponse(__DIR__ . '/../../TestData/mock_response'); + $this->assertEquals(1, count($p)); + } + + /** + * @depends testAddsResponseFilesToQueue + */ + public function testAddsMockResponseToRequestFromClient() + { + $p = new MockPlugin(); + $response = MockPlugin::getMockFile(__DIR__ . '/../../TestData/mock_response'); + $p->addResponse($response); + + $client = new Client('http://127.0.0.1:123/'); + $client->getEventDispatcher()->addSubscriber($p, 9999); + $request = $client->get(); + $request->send(); + + $this->assertSame($response, $request->getResponse()); + $this->assertEquals(0, count($p)); + } + + /** + * @depends testAddsResponseFilesToQueue + * @expectedException \OutOfBoundsException + */ + public function testUpdateThrowsExceptionWhenEmpty() + { + $p = new MockPlugin(); + $p->onRequestBeforeSend(new Event()); + } + + /** + * @depends testAddsMockResponseToRequestFromClient + */ + public function testDetachesTemporaryWhenEmpty() + { + $p = new MockPlugin(null, true); + $p->addResponse(MockPlugin::getMockFile(__DIR__ . '/../../TestData/mock_response')); + $client = new Client('http://127.0.0.1:123/'); + $client->getEventDispatcher()->addSubscriber($p, 9999); + $request = $client->get(); + $request->send(); + + $this->assertFalse($this->hasSubscriber($client, $p)); + } + + public function testLoadsResponsesFromConstructor() + { + $p = new MockPlugin(array(new Response(200))); + $this->assertEquals(1, $p->count()); + } + + public function testStoresMockedRequests() + { + $p = new MockPlugin(array(new Response(200), new Response(200))); + $client = new Client('http://127.0.0.1:123/'); + $client->getEventDispatcher()->addSubscriber($p, 9999); + + $request1 = $client->get(); + $request1->send(); + $this->assertEquals(array($request1), $p->getReceivedRequests()); + + $request2 = $client->get(); + $request2->send(); + $this->assertEquals(array($request1, $request2), $p->getReceivedRequests()); + + $p->flush(); + $this->assertEquals(array(), $p->getReceivedRequests()); + } + + public function testReadsBodiesFromMockedRequests() + { + $p = new MockPlugin(array(new Response(200))); + $p->readBodies(true); + $client = new Client('http://127.0.0.1:123/'); + $client->getEventDispatcher()->addSubscriber($p, 9999); + + $body = EntityBody::factory('foo'); + $request = $client->put(); + $request->setBody($body); + $request->send(); + $this->assertEquals(3, $body->ftell()); + } + + public function testCanMockBadRequestExceptions() + { + $client = new Client('http://127.0.0.1:123/'); + $ex = new CurlException('Foo'); + $mock = new MockPlugin(array($ex)); + $client->addSubscriber($mock); + $request = $client->get('foo'); + + try { + $request->send(); + $this->fail('Did not dequeue an exception'); + } catch (CurlException $e) { + $this->assertSame($e, $ex); + $this->assertSame($request, $ex->getRequest()); + } + } +} diff --git a/vendor/guzzle/guzzle/tests/Guzzle/Tests/Plugin/Oauth/OauthPluginTest.php b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Plugin/Oauth/OauthPluginTest.php new file mode 100644 index 0000000..3892fb6 --- /dev/null +++ b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Plugin/Oauth/OauthPluginTest.php @@ -0,0 +1,345 @@ + 'foo', + 'consumer_secret' => 'bar', + 'token' => 'count', + 'token_secret' => 'dracula' + ); + + protected function getRequest() + { + return RequestFactory::getInstance()->create('POST', 'http://www.test.com/path?a=b&c=d', null, array( + 'e' => 'f' + )); + } + + public function testSubscribesToEvents() + { + $events = OauthPlugin::getSubscribedEvents(); + $this->assertArrayHasKey('request.before_send', $events); + } + + public function testAcceptsConfigurationData() + { + $p = new OauthPlugin($this->config); + + // Access the config object + $class = new \ReflectionClass($p); + $property = $class->getProperty('config'); + $property->setAccessible(true); + $config = $property->getValue($p); + + $this->assertEquals('foo', $config['consumer_key']); + $this->assertEquals('bar', $config['consumer_secret']); + $this->assertEquals('count', $config['token']); + $this->assertEquals('dracula', $config['token_secret']); + $this->assertEquals('1.0', $config['version']); + $this->assertEquals('HMAC-SHA1', $config['signature_method']); + $this->assertEquals('header', $config['request_method']); + } + + public function testCreatesStringToSignFromPostRequest() + { + $p = new OauthPlugin($this->config); + $request = $this->getRequest(); + $signString = $p->getStringToSign($request, self::TIMESTAMP, self::NONCE); + + $this->assertContains('&e=f', rawurldecode($signString)); + + $expectedSignString = + // Method and URL + 'POST&http%3A%2F%2Fwww.test.com%2Fpath' . + // Sorted parameters from query string and body + '&a%3Db%26c%3Dd%26e%3Df%26oauth_consumer_key%3Dfoo' . + '%26oauth_nonce%3De7aa11195ca58349bec8b5ebe351d3497eb9e603%26' . + 'oauth_signature_method%3DHMAC-SHA1' . + '%26oauth_timestamp%3D' . self::TIMESTAMP . '%26oauth_token%3Dcount%26oauth_version%3D1.0'; + + $this->assertEquals($expectedSignString, $signString); + } + + public function testCreatesStringToSignIgnoringPostFields() + { + $config = $this->config; + $config['disable_post_params'] = true; + $p = new OauthPlugin($config); + $request = $this->getRequest(); + $sts = rawurldecode($p->getStringToSign($request, self::TIMESTAMP, self::NONCE)); + $this->assertNotContains('&e=f', $sts); + } + + public function testCreatesStringToSignFromPostRequestWithCustomContentType() + { + $p = new OauthPlugin($this->config); + $request = $this->getRequest(); + $request->setHeader('Content-Type', 'Foo'); + $this->assertEquals( + // Method and URL + 'POST&http%3A%2F%2Fwww.test.com%2Fpath' . + // Sorted parameters from query string and body + '&a%3Db%26c%3Dd%26oauth_consumer_key%3Dfoo' . + '%26oauth_nonce%3D'. self::NONCE .'%26' . + 'oauth_signature_method%3DHMAC-SHA1' . + '%26oauth_timestamp%3D' . self::TIMESTAMP . '%26oauth_token%3Dcount%26oauth_version%3D1.0', + $p->getStringToSign($request, self::TIMESTAMP, self::NONCE) + ); + } + + /** + * @depends testCreatesStringToSignFromPostRequest + */ + public function testConvertsBooleansToStrings() + { + $p = new OauthPlugin($this->config); + $request = $this->getRequest(); + $request->getQuery()->set('a', true); + $request->getQuery()->set('c', false); + $this->assertContains('&a%3Dtrue%26c%3Dfalse', $p->getStringToSign($request, self::TIMESTAMP, self::NONCE)); + } + + public function testCreatesStringToSignFromPostRequestWithNullValues() + { + $config = array( + 'consumer_key' => 'foo', + 'consumer_secret' => 'bar', + 'token' => null, + 'token_secret' => 'dracula' + ); + + $p = new OauthPlugin($config); + $request = $this->getRequest(); + $signString = $p->getStringToSign($request, self::TIMESTAMP, self::NONCE); + + $this->assertContains('&e=f', rawurldecode($signString)); + + $expectedSignString = // Method and URL + 'POST&http%3A%2F%2Fwww.test.com%2Fpath' . + // Sorted parameters from query string and body + '&a%3Db%26c%3Dd%26e%3Df%26oauth_consumer_key%3Dfoo' . + '%26oauth_nonce%3De7aa11195ca58349bec8b5ebe351d3497eb9e603%26' . + 'oauth_signature_method%3DHMAC-SHA1' . + '%26oauth_timestamp%3D' . self::TIMESTAMP . '%26oauth_version%3D1.0'; + + $this->assertEquals($expectedSignString, $signString); + } + + /** + * @depends testCreatesStringToSignFromPostRequest + */ + public function testMultiDimensionalArray() + { + $p = new OauthPlugin($this->config); + $request = $this->getRequest(); + $request->getQuery()->set('a', array('b' => array('e' => 'f', 'c' => 'd'))); + $this->assertContains('a%255Bb%255D%255Bc%255D%3Dd%26a%255Bb%255D%255Be%255D%3Df%26c%3Dd%26e%3Df%26', $p->getStringToSign($request, self::TIMESTAMP, self::NONCE)); + } + + /** + * @depends testMultiDimensionalArray + */ + public function testMultiDimensionalArrayWithNonDefaultQueryAggregator() + { + $p = new OauthPlugin($this->config); + $request = $this->getRequest(); + $aggregator = new CommaAggregator(); + $query = $request->getQuery()->setAggregator($aggregator) + ->set('g', array('h', 'i', 'j')) + ->set('k', array('l')) + ->set('m', array('n', 'o')); + $this->assertContains('a%3Db%26c%3Dd%26e%3Df%26g%3Dh%2Ci%2Cj%26k%3Dl%26m%3Dn%2Co', $p->getStringToSign($request, self::TIMESTAMP, self::NONCE)); + } + + /** + * @depends testCreatesStringToSignFromPostRequest + */ + public function testSignsStrings() + { + $p = new OauthPlugin(array_merge($this->config, array( + 'signature_callback' => function($string, $key) { + return "_{$string}|{$key}_"; + } + ))); + $request = $this->getRequest(); + $sig = $p->getSignature($request, self::TIMESTAMP, self::NONCE); + $this->assertEquals( + '_POST&http%3A%2F%2Fwww.test.com%2Fpath&a%3Db%26c%3Dd%26e%3Df%26oauth_consumer_key%3Dfoo' . + '%26oauth_nonce%3D'. self::NONCE .'%26oauth_signature_method%3DHMAC-SHA1' . + '%26oauth_timestamp%3D' . self::TIMESTAMP . '%26oauth_token%3Dcount%26oauth_version%3D1.0|' . + 'bar&dracula_', + base64_decode($sig) + ); + } + + /** + * Test that the Oauth is signed correctly and that extra strings haven't been added + * to the authorization header. + */ + public function testSignsOauthRequests() + { + $p = new OauthPlugin($this->config); + $event = new Event(array( + 'request' => $this->getRequest(), + 'timestamp' => self::TIMESTAMP + )); + $params = $p->onRequestBeforeSend($event); + + $this->assertTrue($event['request']->hasHeader('Authorization')); + + $authorizationHeader = (string)$event['request']->getHeader('Authorization'); + + $this->assertStringStartsWith('OAuth ', $authorizationHeader); + + $stringsToCheck = array( + 'oauth_consumer_key="foo"', + 'oauth_nonce="'.urlencode($params['oauth_nonce']).'"', + 'oauth_signature="'.urlencode($params['oauth_signature']).'"', + 'oauth_signature_method="HMAC-SHA1"', + 'oauth_timestamp="' . self::TIMESTAMP . '"', + 'oauth_token="count"', + 'oauth_version="1.0"', + ); + + $totalLength = strlen('OAuth '); + + //Separator is not used before first parameter. + $separator = ''; + + foreach ($stringsToCheck as $stringToCheck) { + $this->assertContains($stringToCheck, $authorizationHeader); + $totalLength += strlen($separator); + $totalLength += strlen($stringToCheck); + $separator = ', '; + } + + // Technically this test is not universally valid. It would be allowable to have extra \n characters + // in the Authorization header. However Guzzle does not do this, so we just perform a simple check + // on length to validate the Authorization header is composed of only the strings above. + $this->assertEquals($totalLength, strlen($authorizationHeader), 'Authorization has extra characters i.e. contains extra elements compared to stringsToCheck.'); + } + + public function testSignsOauthQueryStringRequest() + { + $config = array_merge( + $this->config, + array('request_method' => OauthPlugin::REQUEST_METHOD_QUERY) + ); + + $p = new OauthPlugin($config); + $event = new Event(array( + 'request' => $this->getRequest(), + 'timestamp' => self::TIMESTAMP + )); + $params = $p->onRequestBeforeSend($event); + + $this->assertFalse($event['request']->hasHeader('Authorization')); + + $stringsToCheck = array( + 'a=b', + 'c=d', + 'oauth_consumer_key=foo', + 'oauth_nonce='.urlencode($params['oauth_nonce']), + 'oauth_signature='.urlencode($params['oauth_signature']), + 'oauth_signature_method=HMAC-SHA1', + 'oauth_timestamp='.self::TIMESTAMP, + 'oauth_token=count', + 'oauth_version=1.0', + ); + + $queryString = (string) $event['request']->getQuery(); + + $totalLength = strlen('?'); + + //Separator is not used before first parameter. + $separator = ''; + + foreach ($stringsToCheck as $stringToCheck) { + $this->assertContains($stringToCheck, $queryString); + $totalLength += strlen($separator); + $totalLength += strlen($stringToCheck); + $separator = '&'; + } + + // Removes the last query string separator '&' + $totalLength -= 1; + + $this->assertEquals($totalLength, strlen($queryString), 'Query string has extra characters i.e. contains extra elements compared to stringsToCheck.'); + } + + /** + * @expectedException \InvalidArgumentException + */ + public function testInvalidArgumentExceptionOnMethodError() + { + $config = array_merge( + $this->config, + array('request_method' => 'FakeMethod') + ); + + $p = new OauthPlugin($config); + $event = new Event(array( + 'request' => $this->getRequest(), + 'timestamp' => self::TIMESTAMP + )); + + $p->onRequestBeforeSend($event); + } + + public function testDoesNotAddFalseyValuesToAuthorization() + { + unset($this->config['token']); + $p = new OauthPlugin($this->config); + $event = new Event(array('request' => $this->getRequest(), 'timestamp' => self::TIMESTAMP)); + $p->onRequestBeforeSend($event); + $this->assertTrue($event['request']->hasHeader('Authorization')); + $this->assertNotContains('oauth_token=', (string) $event['request']->getHeader('Authorization')); + } + + public function testOptionalOauthParametersAreNotAutomaticallyAdded() + { + // The only required Oauth parameters are the consumer key and secret. That is enough credentials + // for signing oauth requests. + $config = array( + 'consumer_key' => 'foo', + 'consumer_secret' => 'bar', + ); + + $plugin = new OauthPlugin($config); + $event = new Event(array( + 'request' => $this->getRequest(), + 'timestamp' => self::TIMESTAMP + )); + + $timestamp = $plugin->getTimestamp($event); + $request = $event['request']; + $nonce = $plugin->generateNonce($request); + + $paramsToSign = $plugin->getParamsToSign($request, $timestamp, $nonce); + + $optionalParams = array( + 'callback' => 'oauth_callback', + 'token' => 'oauth_token', + 'verifier' => 'oauth_verifier', + 'token_secret' => 'token_secret' + ); + + foreach ($optionalParams as $optionName => $oauthName) { + $this->assertArrayNotHasKey($oauthName, $paramsToSign, "Optional Oauth param '$oauthName' was not set via config variable '$optionName', but it is listed in getParamsToSign()."); + } + } +} diff --git a/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/AbstractConfigLoaderTest.php b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/AbstractConfigLoaderTest.php new file mode 100644 index 0000000..8b42fb8 --- /dev/null +++ b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/AbstractConfigLoaderTest.php @@ -0,0 +1,149 @@ +loader = $this->getMockBuilder('Guzzle\Service\AbstractConfigLoader') + ->setMethods(array('build')) + ->getMockForAbstractClass(); + } + + public function tearDown() + { + foreach ($this->cleanup as $file) { + unlink($file); + } + } + + /** + * @expectedException \Guzzle\Common\Exception\InvalidArgumentException + */ + public function testOnlyLoadsSupportedTypes() + { + $this->loader->load(new \stdClass()); + } + + /** + * @expectedException \Guzzle\Common\Exception\InvalidArgumentException + * @expectedExceptionMessage Unable to open fooooooo.json + */ + public function testFileMustBeReadable() + { + $this->loader->load('fooooooo.json'); + } + + /** + * @expectedException \Guzzle\Common\Exception\InvalidArgumentException + * @expectedExceptionMessage Unknown file extension + */ + public function testMustBeSupportedExtension() + { + $this->loader->load(dirname(__DIR__) . '/TestData/FileBody.txt'); + } + + /** + * @expectedException \Guzzle\Common\Exception\RuntimeException + * @expectedExceptionMessage Error loading JSON data from + */ + public function testJsonMustBeValue() + { + $filename = tempnam(sys_get_temp_dir(), 'json') . '.json'; + file_put_contents($filename, '{/{./{}foo'); + $this->cleanup[] = $filename; + $this->loader->load($filename); + } + + /** + * @expectedException \Guzzle\Common\Exception\InvalidArgumentException + * @expectedExceptionMessage PHP files must return an array + */ + public function testPhpFilesMustReturnAnArray() + { + $filename = tempnam(sys_get_temp_dir(), 'php') . '.php'; + file_put_contents($filename, 'cleanup[] = $filename; + $this->loader->load($filename); + } + + public function testLoadsPhpFileIncludes() + { + $filename = tempnam(sys_get_temp_dir(), 'php') . '.php'; + file_put_contents($filename, ' "bar");'); + $this->cleanup[] = $filename; + $this->loader->expects($this->exactly(1))->method('build')->will($this->returnArgument(0)); + $config = $this->loader->load($filename); + $this->assertEquals(array('foo' => 'bar'), $config); + } + + public function testCanCreateFromJson() + { + $file = dirname(__DIR__) . '/TestData/services/json1.json'; + // The build method will just return the config data + $this->loader->expects($this->exactly(1))->method('build')->will($this->returnArgument(0)); + $data = $this->loader->load($file); + // Ensure that the config files were merged using the includes directives + $this->assertArrayHasKey('includes', $data); + $this->assertArrayHasKey('services', $data); + $this->assertInternalType('array', $data['services']['foo']); + $this->assertInternalType('array', $data['services']['abstract']); + $this->assertInternalType('array', $data['services']['mock']); + $this->assertEquals('bar', $data['services']['foo']['params']['baz']); + } + + public function testUsesAliases() + { + $file = dirname(__DIR__) . '/TestData/services/json1.json'; + $this->loader->addAlias('foo', $file); + // The build method will just return the config data + $this->loader->expects($this->exactly(1))->method('build')->will($this->returnArgument(0)); + $data = $this->loader->load('foo'); + $this->assertEquals('bar', $data['services']['foo']['params']['baz']); + } + + /** + * @expectedException \Guzzle\Common\Exception\InvalidArgumentException + * @expectedExceptionMessage Unable to open foo.json + */ + public function testCanRemoveAliases() + { + $file = dirname(__DIR__) . '/TestData/services/json1.json'; + $this->loader->addAlias('foo.json', $file); + $this->loader->removeAlias('foo.json'); + $this->loader->load('foo.json'); + } + + public function testCanLoadArraysWithIncludes() + { + $file = dirname(__DIR__) . '/TestData/services/json1.json'; + $config = array('includes' => array($file)); + // The build method will just return the config data + $this->loader->expects($this->exactly(1))->method('build')->will($this->returnArgument(0)); + $data = $this->loader->load($config); + $this->assertEquals('bar', $data['services']['foo']['params']['baz']); + } + + public function testDoesNotEnterInfiniteLoop() + { + $prefix = $file = dirname(__DIR__) . '/TestData/description'; + $this->loader->load("{$prefix}/baz.json"); + $this->assertCount(4, $this->readAttribute($this->loader, 'loadedFiles')); + // Ensure that the internal list of loaded files is reset + $this->loader->load("{$prefix}/../test_service2.json"); + $this->assertCount(1, $this->readAttribute($this->loader, 'loadedFiles')); + // Ensure that previously loaded files will be reloaded when starting fresh + $this->loader->load("{$prefix}/baz.json"); + $this->assertCount(4, $this->readAttribute($this->loader, 'loadedFiles')); + } +} diff --git a/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Builder/ServiceBuilderLoaderTest.php b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Builder/ServiceBuilderLoaderTest.php new file mode 100644 index 0000000..f63070e --- /dev/null +++ b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Builder/ServiceBuilderLoaderTest.php @@ -0,0 +1,177 @@ + array( + 'abstract' => array( + 'params' => array( + 'access_key' => 'xyz', + 'secret' => 'abc', + ), + ), + 'foo' => array( + 'extends' => 'abstract', + 'params' => array( + 'baz' => 'bar', + ), + ), + 'mock' => array( + 'extends' => 'abstract', + 'params' => array( + 'username' => 'foo', + 'password' => 'baz', + 'subdomain' => 'bar', + ) + ) + ) + ); + + $builder = $arrayFactory->load($data); + + // Ensure that services were parsed + $this->assertTrue(isset($builder['mock'])); + $this->assertTrue(isset($builder['abstract'])); + $this->assertTrue(isset($builder['foo'])); + $this->assertFalse(isset($builder['jimmy'])); + } + + /** + * @expectedException Guzzle\Service\Exception\ServiceNotFoundException + * @expectedExceptionMessage foo is trying to extend a non-existent service: abstract + */ + public function testThrowsExceptionWhenExtendingNonExistentService() + { + $arrayFactory = new ServiceBuilderLoader(); + + $data = array( + 'services' => array( + 'foo' => array( + 'extends' => 'abstract' + ) + ) + ); + + $builder = $arrayFactory->load($data); + } + + public function testAllowsGlobalParameterOverrides() + { + $arrayFactory = new ServiceBuilderLoader(); + + $data = array( + 'services' => array( + 'foo' => array( + 'params' => array( + 'foo' => 'baz', + 'bar' => 'boo' + ) + ) + ) + ); + + $builder = $arrayFactory->load($data, array( + 'bar' => 'jar', + 'far' => 'car' + )); + + $compiled = json_decode($builder->serialize(), true); + $this->assertEquals(array( + 'foo' => 'baz', + 'bar' => 'jar', + 'far' => 'car' + ), $compiled['foo']['params']); + } + + public function tstDoesNotErrorOnCircularReferences() + { + $arrayFactory = new ServiceBuilderLoader(); + $arrayFactory->load(array( + 'services' => array( + 'too' => array('extends' => 'ball'), + 'ball' => array('extends' => 'too'), + ) + )); + } + + public function configProvider() + { + $foo = array( + 'extends' => 'bar', + 'class' => 'stdClass', + 'params' => array('a' => 'test', 'b' => '456') + ); + + return array( + array( + // Does not extend the existing `foo` service but overwrites it + array( + 'services' => array( + 'foo' => $foo, + 'bar' => array('params' => array('baz' => '123')) + ) + ), + array( + 'services' => array( + 'foo' => array('class' => 'Baz') + ) + ), + array( + 'services' => array( + 'foo' => array('class' => 'Baz'), + 'bar' => array('params' => array('baz' => '123')) + ) + ) + ), + array( + // Extends the existing `foo` service + array( + 'services' => array( + 'foo' => $foo, + 'bar' => array('params' => array('baz' => '123')) + ) + ), + array( + 'services' => array( + 'foo' => array( + 'extends' => 'foo', + 'params' => array('b' => '123', 'c' => 'def') + ) + ) + ), + array( + 'services' => array( + 'foo' => array( + 'extends' => 'bar', + 'class' => 'stdClass', + 'params' => array('a' => 'test', 'b' => '123', 'c' => 'def') + ), + 'bar' => array('params' => array('baz' => '123')) + ) + ) + ) + ); + } + + /** + * @dataProvider configProvider + */ + public function testCombinesConfigs($a, $b, $c) + { + $l = new ServiceBuilderLoader(); + $m = new \ReflectionMethod($l, 'mergeData'); + $m->setAccessible(true); + $this->assertEquals($c, $m->invoke($l, $a, $b)); + } +} diff --git a/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Builder/ServiceBuilderTest.php b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Builder/ServiceBuilderTest.php new file mode 100644 index 0000000..e1b3a1d --- /dev/null +++ b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Builder/ServiceBuilderTest.php @@ -0,0 +1,317 @@ + array( + 'class' => 'Guzzle\Tests\Service\Mock\MockClient', + 'params' => array( + 'username' => 'michael', + 'password' => 'testing123', + 'subdomain' => 'michael', + ), + ), + 'billy.mock' => array( + 'alias' => 'Hello!', + 'class' => 'Guzzle\Tests\Service\Mock\MockClient', + 'params' => array( + 'username' => 'billy', + 'password' => 'passw0rd', + 'subdomain' => 'billy', + ), + ), + 'billy.testing' => array( + 'extends' => 'billy.mock', + 'params' => array( + 'subdomain' => 'test.billy', + ), + ), + 'missing_params' => array( + 'extends' => 'billy.mock' + ) + ); + + public function testAllowsSerialization() + { + $builder = ServiceBuilder::factory($this->arrayData); + $cached = unserialize(serialize($builder)); + $this->assertEquals($cached, $builder); + } + + public function testDelegatesFactoryMethodToAbstractFactory() + { + $builder = ServiceBuilder::factory($this->arrayData); + $c = $builder->get('michael.mock'); + $this->assertInstanceOf('Guzzle\Tests\Service\Mock\MockClient', $c); + } + + /** + * @expectedException Guzzle\Service\Exception\ServiceNotFoundException + * @expectedExceptionMessage No service is registered as foobar + */ + public function testThrowsExceptionWhenGettingInvalidClient() + { + ServiceBuilder::factory($this->arrayData)->get('foobar'); + } + + public function testStoresClientCopy() + { + $builder = ServiceBuilder::factory($this->arrayData); + $client = $builder->get('michael.mock'); + $this->assertInstanceOf('Guzzle\Tests\Service\Mock\MockClient', $client); + $this->assertEquals('http://127.0.0.1:8124/v1/michael', $client->getBaseUrl()); + $this->assertEquals($client, $builder->get('michael.mock')); + + // Get another client but throw this one away + $client2 = $builder->get('billy.mock', true); + $this->assertInstanceOf('Guzzle\Tests\Service\Mock\MockClient', $client2); + $this->assertEquals('http://127.0.0.1:8124/v1/billy', $client2->getBaseUrl()); + + // Make sure the original client is still there and set + $this->assertTrue($client === $builder->get('michael.mock')); + + // Create a new billy.mock client that is stored + $client3 = $builder->get('billy.mock'); + + // Make sure that the stored billy.mock client is equal to the other stored client + $this->assertTrue($client3 === $builder->get('billy.mock')); + + // Make sure that this client is not equal to the previous throwaway client + $this->assertFalse($client2 === $builder->get('billy.mock')); + } + + public function testBuildersPassOptionsThroughToClients() + { + $s = new ServiceBuilder(array( + 'michael.mock' => array( + 'class' => 'Guzzle\Tests\Service\Mock\MockClient', + 'params' => array( + 'base_url' => 'http://www.test.com/', + 'subdomain' => 'michael', + 'password' => 'test', + 'username' => 'michael', + 'curl.curlopt_proxyport' => 8080 + ) + ) + )); + + $c = $s->get('michael.mock'); + $this->assertEquals(8080, $c->getConfig('curl.curlopt_proxyport')); + } + + public function testUsesTheDefaultBuilderWhenNoBuilderIsSpecified() + { + $s = new ServiceBuilder(array( + 'michael.mock' => array( + 'class' => 'Guzzle\Tests\Service\Mock\MockClient', + 'params' => array( + 'base_url' => 'http://www.test.com/', + 'subdomain' => 'michael', + 'password' => 'test', + 'username' => 'michael', + 'curl.curlopt_proxyport' => 8080 + ) + ) + )); + + $c = $s->get('michael.mock'); + $this->assertInstanceOf('Guzzle\Tests\Service\Mock\MockClient', $c); + } + + public function testUsedAsArray() + { + $b = ServiceBuilder::factory($this->arrayData); + $this->assertTrue($b->offsetExists('michael.mock')); + $this->assertFalse($b->offsetExists('not_there')); + $this->assertInstanceOf('Guzzle\Service\Client', $b['michael.mock']); + + unset($b['michael.mock']); + $this->assertFalse($b->offsetExists('michael.mock')); + + $b['michael.mock'] = new Client('http://www.test.com/'); + $this->assertInstanceOf('Guzzle\Service\Client', $b['michael.mock']); + } + + public function testFactoryCanCreateFromJson() + { + $tmp = sys_get_temp_dir() . '/test.js'; + file_put_contents($tmp, json_encode($this->arrayData)); + $b = ServiceBuilder::factory($tmp); + unlink($tmp); + $s = $b->get('billy.testing'); + $this->assertEquals('test.billy', $s->getConfig('subdomain')); + $this->assertEquals('billy', $s->getConfig('username')); + } + + public function testFactoryCanCreateFromArray() + { + $b = ServiceBuilder::factory($this->arrayData); + $s = $b->get('billy.testing'); + $this->assertEquals('test.billy', $s->getConfig('subdomain')); + $this->assertEquals('billy', $s->getConfig('username')); + } + + public function testFactoryDoesNotRequireParams() + { + $b = ServiceBuilder::factory($this->arrayData); + $s = $b->get('missing_params'); + $this->assertEquals('billy', $s->getConfig('username')); + } + + public function testBuilderAllowsReferencesBetweenClients() + { + $builder = ServiceBuilder::factory(array( + 'a' => array( + 'class' => 'Guzzle\Tests\Service\Mock\MockClient', + 'params' => array( + 'other_client' => '{b}', + 'username' => 'x', + 'password' => 'y', + 'subdomain' => 'z' + ) + ), + 'b' => array( + 'class' => 'Guzzle\Tests\Service\Mock\MockClient', + 'params' => array( + 'username' => '1', + 'password' => '2', + 'subdomain' => '3' + ) + ) + )); + + $client = $builder['a']; + $this->assertEquals('x', $client->getConfig('username')); + $this->assertSame($builder['b'], $client->getConfig('other_client')); + $this->assertEquals('1', $builder['b']->getConfig('username')); + } + + public function testEmitsEventsWhenClientsAreCreated() + { + // Ensure that the client signals that it emits an event + $this->assertEquals(array('service_builder.create_client'), ServiceBuilder::getAllEvents()); + + // Create a test service builder + $builder = ServiceBuilder::factory(array( + 'a' => array( + 'class' => 'Guzzle\Tests\Service\Mock\MockClient', + 'params' => array( + 'username' => 'test', + 'password' => '123', + 'subdomain' => 'z' + ) + ) + )); + + // Add an event listener to pick up client creation events + $emits = 0; + $builder->getEventDispatcher()->addListener('service_builder.create_client', function($event) use (&$emits) { + $emits++; + }); + + // Get the 'a' client by name + $client = $builder->get('a'); + + // Ensure that the event was emitted once, and that the client was present + $this->assertEquals(1, $emits); + $this->assertInstanceOf('Guzzle\Tests\Service\Mock\MockClient', $client); + } + + public function testCanAddGlobalParametersToServicesOnLoad() + { + $builder = ServiceBuilder::factory($this->arrayData, array( + 'username' => 'fred', + 'new_value' => 'test' + )); + + $data = json_decode($builder->serialize(), true); + + foreach ($data as $service) { + $this->assertEquals('fred', $service['params']['username']); + $this->assertEquals('test', $service['params']['new_value']); + } + } + + public function testAddsGlobalPlugins() + { + $b = new ServiceBuilder($this->arrayData); + $b->addGlobalPlugin(new HistoryPlugin()); + $s = $b->get('michael.mock'); + $this->assertTrue($s->getEventDispatcher()->hasListeners('request.sent')); + } + + public function testCanGetData() + { + $b = new ServiceBuilder($this->arrayData); + $this->assertEquals($this->arrayData['michael.mock'], $b->getData('michael.mock')); + $this->assertNull($b->getData('ewofweoweofe')); + } + + public function testCanGetByAlias() + { + $b = new ServiceBuilder($this->arrayData); + $this->assertSame($b->get('billy.mock'), $b->get('Hello!')); + } + + public function testCanOverwriteParametersForThrowawayClients() + { + $b = new ServiceBuilder($this->arrayData); + + $c1 = $b->get('michael.mock'); + $this->assertEquals('michael', $c1->getConfig('username')); + + $c2 = $b->get('michael.mock', array('username' => 'jeremy')); + $this->assertEquals('jeremy', $c2->getConfig('username')); + } + + public function testGettingAThrowawayClientWithParametersDoesNotAffectGettingOtherClients() + { + $b = new ServiceBuilder($this->arrayData); + + $c1 = $b->get('michael.mock', array('username' => 'jeremy')); + $this->assertEquals('jeremy', $c1->getConfig('username')); + + $c2 = $b->get('michael.mock'); + $this->assertEquals('michael', $c2->getConfig('username')); + } + + public function testCanUseArbitraryData() + { + $b = new ServiceBuilder(); + $b['a'] = 'foo'; + $this->assertTrue(isset($b['a'])); + $this->assertEquals('foo', $b['a']); + unset($b['a']); + $this->assertFalse(isset($b['a'])); + } + + public function testCanRegisterServiceData() + { + $b = new ServiceBuilder(); + $b['a'] = array( + 'class' => 'Guzzle\Tests\Service\Mock\MockClient', + 'params' => array( + 'username' => 'billy', + 'password' => 'passw0rd', + 'subdomain' => 'billy', + ) + ); + $this->assertTrue(isset($b['a'])); + $this->assertInstanceOf('Guzzle\Tests\Service\Mock\MockClient', $b['a']); + $client = $b['a']; + unset($b['a']); + $this->assertFalse(isset($b['a'])); + // Ensure that instantiated clients can be registered + $b['mock'] = $client; + $this->assertSame($client, $b['mock']); + } +} diff --git a/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/CachingConfigLoaderTest.php b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/CachingConfigLoaderTest.php new file mode 100644 index 0000000..b8245ad --- /dev/null +++ b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/CachingConfigLoaderTest.php @@ -0,0 +1,43 @@ +getMockBuilder('Guzzle\Service\ConfigLoaderInterface') + ->setMethods(array('load')) + ->getMockForAbstractClass(); + $data = array('foo' => 'bar'); + $loader->expects($this->once()) + ->method('load') + ->will($this->returnValue($data)); + $cache = new CachingConfigLoader($loader, $cache); + $this->assertEquals($data, $cache->load('foo')); + $this->assertEquals($data, $cache->load('foo')); + } + + public function testDoesNotCacheArrays() + { + $cache = new DoctrineCacheAdapter(new ArrayCache()); + $loader = $this->getMockBuilder('Guzzle\Service\ConfigLoaderInterface') + ->setMethods(array('load')) + ->getMockForAbstractClass(); + $data = array('foo' => 'bar'); + $loader->expects($this->exactly(2)) + ->method('load') + ->will($this->returnValue($data)); + $cache = new CachingConfigLoader($loader, $cache); + $this->assertEquals($data, $cache->load(array())); + $this->assertEquals($data, $cache->load(array())); + } +} diff --git a/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/ClientTest.php b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/ClientTest.php new file mode 100644 index 0000000..aee29ed --- /dev/null +++ b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/ClientTest.php @@ -0,0 +1,320 @@ +serviceTest = new ServiceDescription(array( + 'test_command' => new Operation(array( + 'doc' => 'documentationForCommand', + 'method' => 'DELETE', + 'class' => 'Guzzle\\Tests\\Service\\Mock\\Command\\MockCommand', + 'args' => array( + 'bucket' => array( + 'required' => true + ), + 'key' => array( + 'required' => true + ) + ) + )) + )); + + $this->service = ServiceDescription::factory(__DIR__ . '/../TestData/test_service.json'); + } + + public function testAllowsCustomClientParameters() + { + $client = new Mock\MockClient(null, array( + Client::COMMAND_PARAMS => array(AbstractCommand::RESPONSE_PROCESSING => 'foo') + )); + $command = $client->getCommand('mock_command'); + $this->assertEquals('foo', $command->get(AbstractCommand::RESPONSE_PROCESSING)); + } + + public function testFactoryCreatesClient() + { + $client = Client::factory(array( + 'base_url' => 'http://www.test.com/', + 'test' => '123' + )); + + $this->assertEquals('http://www.test.com/', $client->getBaseUrl()); + $this->assertEquals('123', $client->getConfig('test')); + } + + public function testFactoryDoesNotRequireBaseUrl() + { + $client = Client::factory(); + } + + public function testDescribesEvents() + { + $this->assertInternalType('array', Client::getAllEvents()); + } + + public function testExecutesCommands() + { + $this->getServer()->flush(); + $this->getServer()->enqueue("HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n"); + + $client = new Client($this->getServer()->getUrl()); + $cmd = new MockCommand(); + $client->execute($cmd); + + $this->assertInstanceOf('Guzzle\\Http\\Message\\Response', $cmd->getResponse()); + $this->assertInstanceOf('Guzzle\\Http\\Message\\Response', $cmd->getResult()); + $this->assertEquals(1, count($this->getServer()->getReceivedRequests(false))); + } + + public function testExecutesCommandsWithArray() + { + $client = new Client('http://www.test.com/'); + $client->getEventDispatcher()->addSubscriber(new MockPlugin(array( + new Response(200), + new Response(200) + ))); + + // Create a command set and a command + $set = array(new MockCommand(), new MockCommand()); + $client->execute($set); + + // Make sure it sent + $this->assertTrue($set[0]->isExecuted()); + $this->assertTrue($set[1]->isExecuted()); + } + + /** + * @expectedException Guzzle\Common\Exception\InvalidArgumentException + */ + public function testThrowsExceptionWhenInvalidCommandIsExecuted() + { + $client = new Client(); + $client->execute(new \stdClass()); + } + + /** + * @expectedException InvalidArgumentException + */ + public function testThrowsExceptionWhenMissingCommand() + { + $client = new Client(); + + $mock = $this->getMock('Guzzle\\Service\\Command\\Factory\\FactoryInterface'); + $mock->expects($this->any()) + ->method('factory') + ->with($this->equalTo('test')) + ->will($this->returnValue(null)); + + $client->setCommandFactory($mock); + $client->getCommand('test'); + } + + public function testCreatesCommandsUsingCommandFactory() + { + $mockCommand = new MockCommand(); + + $client = new Mock\MockClient(); + $mock = $this->getMock('Guzzle\\Service\\Command\\Factory\\FactoryInterface'); + $mock->expects($this->any()) + ->method('factory') + ->with($this->equalTo('foo')) + ->will($this->returnValue($mockCommand)); + + $client->setCommandFactory($mock); + + $command = $client->getCommand('foo', array('acl' => '123')); + $this->assertSame($mockCommand, $command); + $command = $client->getCommand('foo', array('acl' => '123')); + $this->assertSame($mockCommand, $command); + $this->assertSame($client, $command->getClient()); + } + + public function testOwnsServiceDescription() + { + $client = new Mock\MockClient(); + $this->assertNull($client->getDescription()); + + $description = $this->getMock('Guzzle\\Service\\Description\\ServiceDescription'); + $this->assertSame($client, $client->setDescription($description)); + $this->assertSame($description, $client->getDescription()); + } + + public function testOwnsResourceIteratorFactory() + { + $client = new Mock\MockClient(); + + $method = new \ReflectionMethod($client, 'getResourceIteratorFactory'); + $method->setAccessible(TRUE); + $rf1 = $method->invoke($client); + + $rf = $this->readAttribute($client, 'resourceIteratorFactory'); + $this->assertInstanceOf('Guzzle\\Service\\Resource\\ResourceIteratorClassFactory', $rf); + $this->assertSame($rf1, $rf); + + $rf = new ResourceIteratorClassFactory('Guzzle\Tests\Service\Mock'); + $client->setResourceIteratorFactory($rf); + $this->assertNotSame($rf1, $rf); + } + + public function testClientResetsRequestsBeforeExecutingCommands() + { + $this->getServer()->flush(); + $this->getServer()->enqueue(array( + "HTTP/1.1 200 OK\r\nContent-Length: 2\r\n\r\nHi", + "HTTP/1.1 200 OK\r\nContent-Length: 1\r\n\r\nI" + )); + + $client = new Mock\MockClient($this->getServer()->getUrl()); + + $command = $client->getCommand('mock_command'); + $client->execute($command); + $client->execute($command); + $this->assertEquals('I', $command->getResponse()->getBody(true)); + } + + public function testClientCreatesIterators() + { + $client = new Mock\MockClient(); + + $iterator = $client->getIterator('mock_command', array( + 'foo' => 'bar' + ), array( + 'limit' => 10 + )); + + $this->assertInstanceOf('Guzzle\Tests\Service\Mock\Model\MockCommandIterator', $iterator); + $this->assertEquals(10, $this->readAttribute($iterator, 'limit')); + + $command = $this->readAttribute($iterator, 'originalCommand'); + $this->assertEquals('bar', $command->get('foo')); + } + + public function testClientCreatesIteratorsWithNoOptions() + { + $client = new Mock\MockClient(); + $iterator = $client->getIterator('mock_command'); + $this->assertInstanceOf('Guzzle\Tests\Service\Mock\Model\MockCommandIterator', $iterator); + } + + public function testClientCreatesIteratorsWithCommands() + { + $client = new Mock\MockClient(); + $command = new MockCommand(); + $iterator = $client->getIterator($command); + $this->assertInstanceOf('Guzzle\Tests\Service\Mock\Model\MockCommandIterator', $iterator); + $iteratorCommand = $this->readAttribute($iterator, 'originalCommand'); + $this->assertSame($command, $iteratorCommand); + } + + public function testClientHoldsInflector() + { + $client = new Mock\MockClient(); + $this->assertInstanceOf('Guzzle\Inflection\MemoizingInflector', $client->getInflector()); + + $inflector = new Inflector(); + $client->setInflector($inflector); + $this->assertSame($inflector, $client->getInflector()); + } + + public function testClientAddsGlobalCommandOptions() + { + $client = new Mock\MockClient('http://www.foo.com', array( + Client::COMMAND_PARAMS => array( + 'mesa' => 'bar' + ) + )); + $command = $client->getCommand('mock_command'); + $this->assertEquals('bar', $command->get('mesa')); + } + + public function testSupportsServiceDescriptionBaseUrls() + { + $description = new ServiceDescription(array('baseUrl' => 'http://foo.com')); + $client = new Client(); + $client->setDescription($description); + $this->assertEquals('http://foo.com', $client->getBaseUrl()); + } + + public function testMergesDefaultCommandParamsCorrectly() + { + $client = new Mock\MockClient('http://www.foo.com', array( + Client::COMMAND_PARAMS => array( + 'mesa' => 'bar', + 'jar' => 'jar' + ) + )); + $command = $client->getCommand('mock_command', array('jar' => 'test')); + $this->assertEquals('bar', $command->get('mesa')); + $this->assertEquals('test', $command->get('jar')); + } + + /** + * @expectedException \Guzzle\Http\Exception\BadResponseException + */ + public function testWrapsSingleCommandExceptions() + { + $client = new Mock\MockClient('http://foobaz.com'); + $mock = new MockPlugin(array(new Response(401))); + $client->addSubscriber($mock); + $client->execute(new MockCommand()); + } + + public function testWrapsMultipleCommandExceptions() + { + $client = new Mock\MockClient('http://foobaz.com'); + $mock = new MockPlugin(array(new Response(200), new Response(200), new Response(404), new Response(500))); + $client->addSubscriber($mock); + + $cmds = array(new MockCommand(), new MockCommand(), new MockCommand(), new MockCommand()); + try { + $client->execute($cmds); + } catch (CommandTransferException $e) { + $this->assertEquals(2, count($e->getFailedRequests())); + $this->assertEquals(2, count($e->getSuccessfulRequests())); + $this->assertEquals(2, count($e->getFailedCommands())); + $this->assertEquals(2, count($e->getSuccessfulCommands())); + + foreach ($e->getSuccessfulCommands() as $c) { + $this->assertTrue($c->getResponse()->isSuccessful()); + } + + foreach ($e->getFailedCommands() as $c) { + $this->assertFalse($c->getRequest()->getResponse()->isSuccessful()); + } + } + } + + public function testGetCommandAfterTwoSetDescriptions() + { + $service1 = ServiceDescription::factory(__DIR__ . '/../TestData/test_service.json'); + $service2 = ServiceDescription::factory(__DIR__ . '/../TestData/test_service_3.json'); + + $client = new Mock\MockClient(); + + $client->setDescription($service1); + $client->getCommand('foo_bar'); + $client->setDescription($service2); + $client->getCommand('baz_qux'); + } +} diff --git a/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Command/AbstractCommandTest.php b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Command/AbstractCommandTest.php new file mode 100644 index 0000000..1004fae --- /dev/null +++ b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Command/AbstractCommandTest.php @@ -0,0 +1,16 @@ +setDescription(ServiceDescription::factory(__DIR__ . '/../../TestData/test_service.json')); + } +} diff --git a/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Command/ClosureCommandTest.php b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Command/ClosureCommandTest.php new file mode 100644 index 0000000..d762246 --- /dev/null +++ b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Command/ClosureCommandTest.php @@ -0,0 +1,54 @@ + function($command, $api) { + $command->set('testing', '123'); + $request = RequestFactory::getInstance()->create('GET', 'http://www.test.com/'); + return $request; + } + )); + + $client = $this->getServiceBuilder()->get('mock'); + $c->setClient($client)->prepare(); + $this->assertEquals('123', $c->get('testing')); + $this->assertEquals('http://www.test.com/', $c->getRequest()->getUrl()); + } + + /** + * @expectedException UnexpectedValueException + * @expectedExceptionMessage Closure command did not return a RequestInterface object + */ + public function testMustReturnRequest() + { + $c = new ClosureCommand(array( + 'closure' => function($command, $api) { + return false; + } + )); + + $client = $this->getServiceBuilder()->get('mock'); + $c->setClient($client)->prepare(); + } +} diff --git a/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Command/CommandTest.php b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Command/CommandTest.php new file mode 100644 index 0000000..b7173d4 --- /dev/null +++ b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Command/CommandTest.php @@ -0,0 +1,445 @@ +assertEquals('123', $command->get('test')); + $this->assertFalse($command->isPrepared()); + $this->assertFalse($command->isExecuted()); + } + + public function testDeterminesShortName() + { + $api = new Operation(array('name' => 'foobar')); + $command = new MockCommand(array(), $api); + $this->assertEquals('foobar', $command->getName()); + + $command = new MockCommand(); + $this->assertEquals('mock_command', $command->getName()); + + $command = new Sub(); + $this->assertEquals('sub.sub', $command->getName()); + } + + /** + * @expectedException RuntimeException + */ + public function testGetRequestThrowsExceptionBeforePreparation() + { + $command = new MockCommand(); + $command->getRequest(); + } + + public function testGetResponseExecutesCommandsWhenNeeded() + { + $response = new Response(200); + $client = $this->getClient(); + $this->setMockResponse($client, array($response)); + $command = new MockCommand(); + $command->setClient($client); + $this->assertSame($response, $command->getResponse()); + $this->assertSame($response, $command->getResponse()); + } + + public function testGetResultExecutesCommandsWhenNeeded() + { + $response = new Response(200); + $client = $this->getClient(); + $this->setMockResponse($client, array($response)); + $command = new MockCommand(); + $command->setClient($client); + $this->assertSame($response, $command->getResult()); + $this->assertSame($response, $command->getResult()); + } + + public function testSetClient() + { + $command = new MockCommand(); + $client = $this->getClient(); + + $command->setClient($client); + $this->assertEquals($client, $command->getClient()); + + unset($client); + unset($command); + + $command = new MockCommand(); + $client = $this->getClient(); + + $command->setClient($client)->prepare(); + $this->assertEquals($client, $command->getClient()); + $this->assertTrue($command->isPrepared()); + } + + public function testExecute() + { + $client = $this->getClient(); + $response = new Response(200, array( + 'Content-Type' => 'application/xml' + ), '123'); + $this->setMockResponse($client, array($response)); + $command = new MockCommand(); + $this->assertSame($command, $command->setClient($client)); + + // Returns the result of the command + $this->assertInstanceOf('SimpleXMLElement', $command->execute()); + + $this->assertTrue($command->isPrepared()); + $this->assertTrue($command->isExecuted()); + $this->assertSame($response, $command->getResponse()); + $this->assertInstanceOf('Guzzle\\Http\\Message\\Request', $command->getRequest()); + // Make sure that the result was automatically set to a SimpleXMLElement + $this->assertInstanceOf('SimpleXMLElement', $command->getResult()); + $this->assertEquals('123', (string) $command->getResult()->data); + } + + public function testConvertsJsonResponsesToArray() + { + $client = $this->getClient(); + $this->setMockResponse($client, array( + new \Guzzle\Http\Message\Response(200, array( + 'Content-Type' => 'application/json' + ), '{ "key": "Hi!" }' + ) + )); + $command = new MockCommand(); + $command->setClient($client); + $command->execute(); + $this->assertEquals(array( + 'key' => 'Hi!' + ), $command->getResult()); + } + + /** + * @expectedException \Guzzle\Common\Exception\RuntimeException + */ + public function testConvertsInvalidJsonResponsesToArray() + { + $json = '{ "key": "Hi!" }invalid'; + // Some implementations of php-json extension are not strict enough + // and allow to parse invalid json ignoring invalid parts + // See https://github.com/remicollet/pecl-json-c/issues/5 + if (json_decode($json) && JSON_ERROR_NONE === json_last_error()) { + $this->markTestSkipped('php-pecl-json library regression issues'); + } + + $client = $this->getClient(); + $this->setMockResponse($client, array( + new \Guzzle\Http\Message\Response(200, array( + 'Content-Type' => 'application/json' + ), $json + ) + )); + $command = new MockCommand(); + $command->setClient($client); + $command->execute(); + } + + public function testProcessResponseIsNotXml() + { + $client = $this->getClient(); + $this->setMockResponse($client, array( + new Response(200, array( + 'Content-Type' => 'application/octet-stream' + ), 'abc,def,ghi') + )); + $command = new MockCommand(); + $client->execute($command); + + // Make sure that the result was not converted to XML + $this->assertFalse($command->getResult() instanceof \SimpleXMLElement); + } + + /** + * @expectedException RuntimeException + */ + public function testExecuteThrowsExceptionWhenNoClientIsSet() + { + $command = new MockCommand(); + $command->execute(); + } + + /** + * @expectedException RuntimeException + */ + public function testPrepareThrowsExceptionWhenNoClientIsSet() + { + $command = new MockCommand(); + $command->prepare(); + } + + public function testCommandsAllowsCustomRequestHeaders() + { + $command = new MockCommand(); + $command->getRequestHeaders()->set('test', '123'); + $this->assertInstanceOf('Guzzle\Common\Collection', $command->getRequestHeaders()); + $this->assertEquals('123', $command->getRequestHeaders()->get('test')); + + $command->setClient($this->getClient())->prepare(); + $this->assertEquals('123', (string) $command->getRequest()->getHeader('test')); + } + + public function testCommandsAllowsCustomRequestHeadersAsArray() + { + $command = new MockCommand(array(AbstractCommand::HEADERS_OPTION => array('Foo' => 'Bar'))); + $this->assertInstanceOf('Guzzle\Common\Collection', $command->getRequestHeaders()); + $this->assertEquals('Bar', $command->getRequestHeaders()->get('Foo')); + } + + private function getOperation() + { + return new Operation(array( + 'name' => 'foobar', + 'httpMethod' => 'POST', + 'class' => 'Guzzle\\Tests\\Service\\Mock\\Command\\MockCommand', + 'parameters' => array( + 'test' => array( + 'default' => '123', + 'type' => 'string' + ) + ))); + } + + public function testCommandsUsesOperation() + { + $api = $this->getOperation(); + $command = new MockCommand(array(), $api); + $this->assertSame($api, $command->getOperation()); + $command->setClient($this->getClient())->prepare(); + $this->assertEquals('123', $command->get('test')); + $this->assertSame($api, $command->getOperation($api)); + } + + public function testCloneMakesNewRequest() + { + $client = $this->getClient(); + $command = new MockCommand(array(), $this->getOperation()); + $command->setClient($client); + + $command->prepare(); + $this->assertTrue($command->isPrepared()); + + $command2 = clone $command; + $this->assertFalse($command2->isPrepared()); + } + + public function testHasOnCompleteMethod() + { + $that = $this; + $called = 0; + + $testFunction = function($command) use (&$called, $that) { + $called++; + $that->assertInstanceOf('Guzzle\Service\Command\CommandInterface', $command); + }; + + $client = $this->getClient(); + $command = new MockCommand(array( + 'command.on_complete' => $testFunction + ), $this->getOperation()); + $command->setClient($client); + + $command->prepare()->setResponse(new Response(200), true); + $command->execute(); + $this->assertEquals(1, $called); + } + + /** + * @expectedException \Guzzle\Common\Exception\InvalidArgumentException + */ + public function testOnCompleteMustBeCallable() + { + $client = $this->getClient(); + $command = new MockCommand(); + $command->setOnComplete('foo'); + } + + public function testCanSetResultManually() + { + $client = $this->getClient(); + $client->getEventDispatcher()->addSubscriber(new MockPlugin(array( + new Response(200) + ))); + $command = new MockCommand(); + $client->execute($command); + $command->setResult('foo!'); + $this->assertEquals('foo!', $command->getResult()); + } + + public function testCanInitConfig() + { + $command = $this->getMockBuilder('Guzzle\\Service\\Command\\AbstractCommand') + ->setConstructorArgs(array(array( + 'foo' => 'bar' + ), new Operation(array( + 'parameters' => array( + 'baz' => new Parameter(array( + 'default' => 'baaar' + )) + ) + )))) + ->getMockForAbstractClass(); + + $this->assertEquals('bar', $command['foo']); + $this->assertEquals('baaar', $command['baz']); + } + + public function testAddsCurlOptionsToRequestsWhenPreparing() + { + $command = new MockCommand(array( + 'foo' => 'bar', + 'curl.options' => array('CURLOPT_PROXYPORT' => 8080) + )); + $client = new Client(); + $command->setClient($client); + $request = $command->prepare(); + $this->assertEquals(8080, $request->getCurlOptions()->get(CURLOPT_PROXYPORT)); + } + + public function testIsInvokable() + { + $client = $this->getClient(); + $response = new Response(200); + $this->setMockResponse($client, array($response)); + $command = new MockCommand(); + $command->setClient($client); + // Returns the result of the command + $this->assertSame($response, $command()); + } + + public function testCreatesDefaultOperation() + { + $command = $this->getMockBuilder('Guzzle\Service\Command\AbstractCommand')->getMockForAbstractClass(); + $this->assertInstanceOf('Guzzle\Service\Description\Operation', $command->getOperation()); + } + + public function testAllowsValidatorToBeInjected() + { + $command = $this->getMockBuilder('Guzzle\Service\Command\AbstractCommand')->getMockForAbstractClass(); + $v = new SchemaValidator(); + $command->setValidator($v); + $this->assertSame($v, $this->readAttribute($command, 'validator')); + } + + public function testCanDisableValidation() + { + $command = new MockCommand(); + $command->setClient(new \Guzzle\Service\Client()); + $v = $this->getMockBuilder('Guzzle\Service\Description\SchemaValidator') + ->setMethods(array('validate')) + ->getMock(); + $v->expects($this->never())->method('validate'); + $command->setValidator($v); + $command->set(AbstractCommand::DISABLE_VALIDATION, true); + $command->prepare(); + } + + public function testValidatorDoesNotUpdateNonDefaultValues() + { + $command = new MockCommand(array('test' => 123, 'foo' => 'bar')); + $command->setClient(new \Guzzle\Service\Client()); + $command->prepare(); + $this->assertEquals(123, $command->get('test')); + $this->assertEquals('bar', $command->get('foo')); + } + + public function testValidatorUpdatesDefaultValues() + { + $command = new MockCommand(); + $command->setClient(new \Guzzle\Service\Client()); + $command->prepare(); + $this->assertEquals(123, $command->get('test')); + $this->assertEquals('abc', $command->get('_internal')); + } + + /** + * @expectedException \Guzzle\Service\Exception\ValidationException + * @expectedExceptionMessage [Foo] Baz + */ + public function testValidatesCommandBeforeSending() + { + $command = new MockCommand(); + $command->setClient(new \Guzzle\Service\Client()); + $v = $this->getMockBuilder('Guzzle\Service\Description\SchemaValidator') + ->setMethods(array('validate', 'getErrors')) + ->getMock(); + $v->expects($this->any())->method('validate')->will($this->returnValue(false)); + $v->expects($this->any())->method('getErrors')->will($this->returnValue(array('[Foo] Baz', '[Bar] Boo'))); + $command->setValidator($v); + $command->prepare(); + } + + /** + * @expectedException \Guzzle\Service\Exception\ValidationException + * @expectedExceptionMessage Validation errors: [abc] must be of type string + */ + public function testValidatesAdditionalParameters() + { + $description = ServiceDescription::factory(array( + 'operations' => array( + 'foo' => array( + 'parameters' => array( + 'baz' => array('type' => 'integer') + ), + 'additionalParameters' => array( + 'type' => 'string' + ) + ) + ) + )); + + $client = new Client(); + $client->setDescription($description); + $command = $client->getCommand('foo', array( + 'abc' => false, + 'command.headers' => array('foo' => 'bar') + )); + $command->prepare(); + } + + public function testCanAccessValidationErrorsFromCommand() + { + $validationErrors = array('[Foo] Baz', '[Bar] Boo'); + $command = new MockCommand(); + $command->setClient(new \Guzzle\Service\Client()); + + $this->assertFalse($command->getValidationErrors()); + + $v = $this->getMockBuilder('Guzzle\Service\Description\SchemaValidator') + ->setMethods(array('validate', 'getErrors')) + ->getMock(); + $v->expects($this->any())->method('getErrors')->will($this->returnValue($validationErrors)); + $command->setValidator($v); + + $this->assertEquals($validationErrors, $command->getValidationErrors()); + } + + public function testCanChangeResponseBody() + { + $body = EntityBody::factory(); + $command = new MockCommand(); + $command->setClient(new \Guzzle\Service\Client()); + $command->set(AbstractCommand::RESPONSE_BODY, $body); + $request = $command->prepare(); + $this->assertSame($body, $this->readAttribute($request, 'responseBody')); + } +} diff --git a/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Command/DefaultRequestSerializerTest.php b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Command/DefaultRequestSerializerTest.php new file mode 100644 index 0000000..b7a4682 --- /dev/null +++ b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Command/DefaultRequestSerializerTest.php @@ -0,0 +1,122 @@ +serializer = DefaultRequestSerializer::getInstance(); + $this->client = new Client('http://foo.com/baz'); + $this->operation = new Operation(array('httpMethod' => 'POST')); + $this->command = $this->getMockBuilder('Guzzle\Service\Command\AbstractCommand') + ->setConstructorArgs(array(array(), $this->operation)) + ->getMockForAbstractClass(); + $this->command->setClient($this->client); + } + + public function testAllowsCustomVisitor() + { + $this->serializer->addVisitor('custom', new HeaderVisitor()); + $this->command['test'] = '123'; + $this->operation->addParam(new Parameter(array('name' => 'test', 'location' => 'custom'))); + $request = $this->serializer->prepare($this->command); + $this->assertEquals('123', (string) $request->getHeader('test')); + } + + public function testUsesRelativePath() + { + $this->operation->setUri('bar'); + $request = $this->serializer->prepare($this->command); + $this->assertEquals('http://foo.com/baz/bar', (string) $request->getUrl()); + } + + public function testUsesRelativePathWithUriLocations() + { + $this->command['test'] = '123'; + $this->operation->setUri('bar/{test}'); + $this->operation->addParam(new Parameter(array('name' => 'test', 'location' => 'uri'))); + $request = $this->serializer->prepare($this->command); + $this->assertEquals('http://foo.com/baz/bar/123', (string) $request->getUrl()); + } + + public function testAllowsCustomFactory() + { + $f = new VisitorFlyweight(); + $serializer = new DefaultRequestSerializer($f); + $this->assertSame($f, $this->readAttribute($serializer, 'factory')); + } + + public function testMixedParams() + { + $this->operation->setUri('bar{?limit,fields}'); + $this->operation->addParam(new Parameter(array( + 'name' => 'limit', + 'location' => 'uri', + 'required' => false, + ))); + $this->operation->addParam(new Parameter(array( + 'name' => 'fields', + 'location' => 'uri', + 'required' => true, + ))); + + $this->command['fields'] = array('id', 'name'); + + $request = $this->serializer->prepare($this->command); + $this->assertEquals('http://foo.com/baz/bar?fields='.urlencode('id,name'), (string) $request->getUrl()); + } + + public function testValidatesAdditionalParameters() + { + $description = ServiceDescription::factory(array( + 'operations' => array( + 'foo' => array( + 'httpMethod' => 'PUT', + 'parameters' => array( + 'bar' => array('location' => 'header') + ), + 'additionalParameters' => array( + 'location' => 'json' + ) + ) + ) + )); + + $client = new Client(); + $client->setDescription($description); + $command = $client->getCommand('foo'); + $command['bar'] = 'test'; + $command['hello'] = 'abc'; + $request = $command->prepare(); + $this->assertEquals('test', (string) $request->getHeader('bar')); + $this->assertEquals('{"hello":"abc"}', (string) $request->getBody()); + } +} diff --git a/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Command/DefaultResponseParserTest.php b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Command/DefaultResponseParserTest.php new file mode 100644 index 0000000..a6a02f9 --- /dev/null +++ b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Command/DefaultResponseParserTest.php @@ -0,0 +1,59 @@ +setClient(new Client()); + $request = $op->prepare(); + $request->setResponse(new Response(200, array( + 'Content-Type' => 'application/xml' + ), 'Bar'), true); + $this->assertInstanceOf('SimpleXMLElement', $op->execute()); + } + + public function testParsesJsonResponses() + { + $op = new OperationCommand(array(), new Operation()); + $op->setClient(new Client()); + $request = $op->prepare(); + $request->setResponse(new Response(200, array( + 'Content-Type' => 'application/json' + ), '{"Baz":"Bar"}'), true); + $this->assertEquals(array('Baz' => 'Bar'), $op->execute()); + } + + /** + * @expectedException \Guzzle\Common\Exception\RuntimeException + */ + public function testThrowsExceptionWhenParsingJsonFails() + { + $op = new OperationCommand(array(), new Operation()); + $op->setClient(new Client()); + $request = $op->prepare(); + $request->setResponse(new Response(200, array('Content-Type' => 'application/json'), '{"Baz":ddw}'), true); + $op->execute(); + } + + public function testAddsContentTypeWhenExpectsIsSetOnCommand() + { + $op = new OperationCommand(array(), new Operation()); + $op['command.expects'] = 'application/json'; + $op->setClient(new Client()); + $request = $op->prepare(); + $request->setResponse(new Response(200, null, '{"Baz":"Bar"}'), true); + $this->assertEquals(array('Baz' => 'Bar'), $op->execute()); + } +} diff --git a/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Command/Factory/AliasFactoryTest.php b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Command/Factory/AliasFactoryTest.php new file mode 100644 index 0000000..ab1041a --- /dev/null +++ b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Command/Factory/AliasFactoryTest.php @@ -0,0 +1,76 @@ +client = new Client(); + + $map = new MapFactory(array( + 'test' => 'Guzzle\Tests\Service\Mock\Command\MockCommand', + 'test1' => 'Guzzle\Tests\Service\Mock\Command\OtherCommand' + )); + + $this->factory = new AliasFactory($this->client, array( + 'foo' => 'test', + 'bar' => 'sub', + 'sub' => 'test1', + 'krull' => 'test3', + 'krull_2' => 'krull', + 'sub_2' => 'bar', + 'bad_link' => 'jarjar' + )); + + $map2 = new MapFactory(array( + 'test3' => 'Guzzle\Tests\Service\Mock\Command\Sub\Sub' + )); + + $this->client->setCommandFactory(new CompositeFactory(array($map, $this->factory, $map2))); + } + + public function aliasProvider() + { + return array( + array('foo', 'Guzzle\Tests\Service\Mock\Command\MockCommand', false), + array('bar', 'Guzzle\Tests\Service\Mock\Command\OtherCommand', false), + array('sub', 'Guzzle\Tests\Service\Mock\Command\OtherCommand', false), + array('sub_2', 'Guzzle\Tests\Service\Mock\Command\OtherCommand', false), + array('krull', 'Guzzle\Tests\Service\Mock\Command\Sub\Sub', false), + array('krull_2', 'Guzzle\Tests\Service\Mock\Command\Sub\Sub', false), + array('missing', null, true), + array('bad_link', null, true) + ); + } + + /** + * @dataProvider aliasProvider + */ + public function testAliasesCommands($key, $result, $exception) + { + try { + $command = $this->client->getCommand($key); + if (is_null($result)) { + $this->assertNull($command); + } else { + $this->assertInstanceof($result, $command); + } + } catch (\Exception $e) { + if (!$exception) { + $this->fail('Got exception when it was not expected'); + } + } + } +} diff --git a/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Command/Factory/CompositeFactoryTest.php b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Command/Factory/CompositeFactoryTest.php new file mode 100644 index 0000000..b896dcf --- /dev/null +++ b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Command/Factory/CompositeFactoryTest.php @@ -0,0 +1,124 @@ +getMockBuilder($class) + ->disableOriginalConstructor() + ->getMock(); + } + + public function testIsIterable() + { + $factory = new CompositeFactory(array($this->getFactory(), $this->getFactory())); + $this->assertEquals(2, count($factory)); + $this->assertEquals(2, count(iterator_to_array($factory->getIterator()))); + } + + public function testFindsFactories() + { + $f1 = $this->getFactory(); + $f2 = $this->getFactory('Guzzle\\Service\\Command\\Factory\\CompositeFactory'); + $factory = new CompositeFactory(array($f1, $f2)); + $this->assertNull($factory->find('foo')); + $this->assertNull($factory->find($this->getFactory())); + $this->assertSame($f1, $factory->find('Guzzle\\Service\\Command\\Factory\\MapFactory')); + $this->assertSame($f2, $factory->find('Guzzle\\Service\\Command\\Factory\\CompositeFactory')); + $this->assertSame($f1, $factory->find($f1)); + $this->assertSame($f2, $factory->find($f2)); + + $this->assertFalse($factory->has('foo')); + $this->assertTrue($factory->has('Guzzle\\Service\\Command\\Factory\\MapFactory')); + $this->assertTrue($factory->has('Guzzle\\Service\\Command\\Factory\\CompositeFactory')); + } + + public function testCreatesCommands() + { + $factory = new CompositeFactory(); + $this->assertNull($factory->factory('foo')); + + $f1 = $this->getFactory(); + $mockCommand1 = $this->getMockForAbstractClass('Guzzle\\Service\\Command\\AbstractCommand'); + + $f1->expects($this->once()) + ->method('factory') + ->with($this->equalTo('foo')) + ->will($this->returnValue($mockCommand1)); + + $factory = new CompositeFactory(array($f1)); + $this->assertSame($mockCommand1, $factory->factory('foo')); + } + + public function testAllowsRemovalOfFactories() + { + $f1 = $this->getFactory(); + $f2 = $this->getFactory(); + $f3 = $this->getFactory('Guzzle\\Service\\Command\\Factory\\CompositeFactory'); + $factories = array($f1, $f2, $f3); + $factory = new CompositeFactory($factories); + + $factory->remove('foo'); + $this->assertEquals($factories, $factory->getIterator()->getArrayCopy()); + + $factory->remove($f1); + $this->assertEquals(array($f2, $f3), $factory->getIterator()->getArrayCopy()); + + $factory->remove('Guzzle\\Service\\Command\\Factory\\MapFactory'); + $this->assertEquals(array($f3), $factory->getIterator()->getArrayCopy()); + + $factory->remove('Guzzle\\Service\\Command\\Factory\\CompositeFactory'); + $this->assertEquals(array(), $factory->getIterator()->getArrayCopy()); + + $factory->remove('foo'); + $this->assertEquals(array(), $factory->getIterator()->getArrayCopy()); + } + + public function testAddsFactoriesBeforeAndAtEnd() + { + $f1 = $this->getFactory(); + $f2 = $this->getFactory(); + $f3 = $this->getFactory('Guzzle\\Service\\Command\\Factory\\CompositeFactory'); + $f4 = $this->getFactory(); + + $factory = new CompositeFactory(); + + $factory->add($f1); + $this->assertEquals(array($f1), $factory->getIterator()->getArrayCopy()); + + $factory->add($f2); + $this->assertEquals(array($f1, $f2), $factory->getIterator()->getArrayCopy()); + + $factory->add($f3, $f2); + $this->assertEquals(array($f1, $f3, $f2), $factory->getIterator()->getArrayCopy()); + + $factory->add($f4, 'Guzzle\\Service\\Command\\Factory\\CompositeFactory'); + $this->assertEquals(array($f1, $f4, $f3, $f2), $factory->getIterator()->getArrayCopy()); + } + + public function testProvidesDefaultChainForClients() + { + $client = $this->getMock('Guzzle\\Service\\Client'); + $chain = CompositeFactory::getDefaultChain($client); + $a = $chain->getIterator()->getArrayCopy(); + $this->assertEquals(1, count($a)); + $this->assertInstanceOf('Guzzle\\Service\\Command\\Factory\\ConcreteClassFactory', $a[0]); + + $description = $this->getMock('Guzzle\\Service\\Description\\ServiceDescription'); + $client->expects($this->once()) + ->method('getDescription') + ->will($this->returnValue($description)); + $chain = CompositeFactory::getDefaultChain($client); + $a = $chain->getIterator()->getArrayCopy(); + $this->assertEquals(2, count($a)); + $this->assertInstanceOf('Guzzle\\Service\\Command\\Factory\\ServiceDescriptionFactory', $a[0]); + $this->assertInstanceOf('Guzzle\\Service\\Command\\Factory\\ConcreteClassFactory', $a[1]); + } +} diff --git a/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Command/Factory/ConcreteClassFactoryTest.php b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Command/Factory/ConcreteClassFactoryTest.php new file mode 100644 index 0000000..7664718 --- /dev/null +++ b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Command/Factory/ConcreteClassFactoryTest.php @@ -0,0 +1,49 @@ + $prefix + )); + } + + $factory = new ConcreteClassFactory($client); + + if (is_null($result)) { + $this->assertNull($factory->factory($key)); + } else { + $this->assertInstanceof($result, $factory->factory($key)); + } + } +} diff --git a/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Command/Factory/MapFactoryTest.php b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Command/Factory/MapFactoryTest.php new file mode 100644 index 0000000..ee720d1 --- /dev/null +++ b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Command/Factory/MapFactoryTest.php @@ -0,0 +1,37 @@ + 'Guzzle\Tests\Service\Mock\Command\MockCommand', + 'test1' => 'Guzzle\Tests\Service\Mock\Command\OtherCommand' + )); + + if (is_null($result)) { + $this->assertNull($factory->factory($key)); + } else { + $this->assertInstanceof($result, $factory->factory($key)); + } + } +} diff --git a/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Command/Factory/ServiceDescriptionFactoryTest.php b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Command/Factory/ServiceDescriptionFactoryTest.php new file mode 100644 index 0000000..3372634 --- /dev/null +++ b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Command/Factory/ServiceDescriptionFactoryTest.php @@ -0,0 +1,68 @@ +getDescription(); + + $factory = new ServiceDescriptionFactory($d); + $this->assertSame($d, $factory->getServiceDescription()); + + if (is_null($result)) { + $this->assertNull($factory->factory($key)); + } else { + $this->assertInstanceof($result, $factory->factory($key)); + } + } + + public function testUsesUcFirstIfNoExactMatch() + { + $d = $this->getDescription(); + $factory = new ServiceDescriptionFactory($d, new Inflector()); + $this->assertInstanceof('Guzzle\Tests\Service\Mock\Command\OtherCommand', $factory->factory('Test')); + $this->assertInstanceof('Guzzle\Tests\Service\Mock\Command\OtherCommand', $factory->factory('test')); + } + + public function testUsesInflectionIfNoExactMatch() + { + $d = $this->getDescription(); + $factory = new ServiceDescriptionFactory($d, new Inflector()); + $this->assertInstanceof('Guzzle\Tests\Service\Mock\Command\OtherCommand', $factory->factory('Binks')); + $this->assertInstanceof('Guzzle\Tests\Service\Mock\Command\OtherCommand', $factory->factory('binks')); + $this->assertInstanceof('Guzzle\Tests\Service\Mock\Command\MockCommand', $factory->factory('JarJar')); + $this->assertInstanceof('Guzzle\Tests\Service\Mock\Command\MockCommand', $factory->factory('jar_jar')); + } + + protected function getDescription() + { + return ServiceDescription::factory(array( + 'operations' => array( + 'jar_jar' => array('class' => 'Guzzle\Tests\Service\Mock\Command\MockCommand'), + 'binks' => array('class' => 'Guzzle\Tests\Service\Mock\Command\OtherCommand'), + 'Test' => array('class' => 'Guzzle\Tests\Service\Mock\Command\OtherCommand') + ) + )); + } +} diff --git a/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Command/LocationVisitor/Request/AbstractVisitorTestCase.php b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Command/LocationVisitor/Request/AbstractVisitorTestCase.php new file mode 100644 index 0000000..46b472e --- /dev/null +++ b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Command/LocationVisitor/Request/AbstractVisitorTestCase.php @@ -0,0 +1,110 @@ +command = new MockCommand(); + $this->request = new EntityEnclosingRequest('POST', 'http://www.test.com/some/path.php'); + $this->validator = new SchemaValidator(); + } + + protected function getCommand($location) + { + $command = new OperationCommand(array(), $this->getNestedCommand($location)); + $command->setClient(new MockClient()); + + return $command; + } + + protected function getNestedCommand($location) + { + return new Operation(array( + 'httpMethod' => 'POST', + 'parameters' => array( + 'foo' => new Parameter(array( + 'type' => 'object', + 'location' => $location, + 'sentAs' => 'Foo', + 'required' => true, + 'properties' => array( + 'test' => array( + 'type' => 'object', + 'required' => true, + 'properties' => array( + 'baz' => array( + 'type' => 'boolean', + 'default' => true + ), + 'jenga' => array( + 'type' => 'string', + 'default' => 'hello', + 'sentAs' => 'Jenga_Yall!', + 'filters' => array('strtoupper') + ) + ) + ), + 'bar' => array('default' => 123) + ), + 'additionalProperties' => array( + 'type' => 'string', + 'filters' => array('strtoupper'), + 'location' => $location + ) + )), + 'arr' => new Parameter(array( + 'type' => 'array', + 'location' => $location, + 'items' => array( + 'type' => 'string', + 'filters' => array('strtoupper') + ) + )), + ) + )); + } + + protected function getCommandWithArrayParamAndFilters() + { + $operation = new Operation(array( + 'httpMethod' => 'POST', + 'parameters' => array( + 'foo' => new Parameter(array( + 'type' => 'string', + 'location' => 'query', + 'sentAs' => 'Foo', + 'required' => true, + 'default' => 'bar', + 'filters' => array('strtoupper') + )), + 'arr' => new Parameter(array( + 'type' => 'array', + 'location' => 'query', + 'sentAs' => 'Arr', + 'required' => true, + 'default' => array(123, 456, 789), + 'filters' => array(array('method' => 'implode', 'args' => array(',', '@value'))) + )) + ) + )); + $command = new OperationCommand(array(), $operation); + $command->setClient(new MockClient()); + + return $command; + } +} diff --git a/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Command/LocationVisitor/Request/BodyVisitorTest.php b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Command/LocationVisitor/Request/BodyVisitorTest.php new file mode 100644 index 0000000..2a95c45 --- /dev/null +++ b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Command/LocationVisitor/Request/BodyVisitorTest.php @@ -0,0 +1,63 @@ +getNestedCommand('body')->getParam('foo')->setSentAs('Foo'); + $visitor->visit($this->command, $this->request, $param, '123'); + $this->assertEquals('123', (string) $this->request->getBody()); + $this->assertNull($this->request->getHeader('Expect')); + } + + public function testAddsExpectHeaderWhenSetToTrue() + { + $visitor = new Visitor(); + $param = $this->getNestedCommand('body')->getParam('foo')->setSentAs('Foo'); + $param->setData('expect_header', true); + $visitor->visit($this->command, $this->request, $param, '123'); + $this->assertEquals('123', (string) $this->request->getBody()); + } + + public function testCanDisableExpectHeader() + { + $visitor = new Visitor(); + $param = $this->getNestedCommand('body')->getParam('foo')->setSentAs('Foo'); + $param->setData('expect_header', false); + $visitor->visit($this->command, $this->request, $param, '123'); + $this->assertNull($this->request->getHeader('Expect')); + } + + public function testCanSetExpectHeaderBasedOnSize() + { + $visitor = new Visitor(); + $param = $this->getNestedCommand('body')->getParam('foo')->setSentAs('Foo'); + // The body is less than the cutoff + $param->setData('expect_header', 5); + $visitor->visit($this->command, $this->request, $param, '123'); + $this->assertNull($this->request->getHeader('Expect')); + // Now check when the body is greater than the cutoff + $param->setData('expect_header', 2); + $visitor->visit($this->command, $this->request, $param, '123'); + $this->assertEquals('100-Continue', (string) $this->request->getHeader('Expect')); + } + + public function testAddsContentEncodingWhenSetOnBody() + { + $visitor = new Visitor(); + $param = $this->getNestedCommand('body')->getParam('foo')->setSentAs('Foo'); + $body = EntityBody::factory('foo'); + $body->compress(); + $visitor->visit($this->command, $this->request, $param, $body); + $this->assertEquals('gzip', (string) $this->request->getHeader('Content-Encoding')); + } +} diff --git a/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Command/LocationVisitor/Request/HeaderVisitorTest.php b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Command/LocationVisitor/Request/HeaderVisitorTest.php new file mode 100644 index 0000000..7ea1ae9 --- /dev/null +++ b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Command/LocationVisitor/Request/HeaderVisitorTest.php @@ -0,0 +1,48 @@ +getNestedCommand('header')->getParam('foo')->setSentAs('test'); + $param->setAdditionalProperties(new Parameter(array())); + $visitor->visit($this->command, $this->request, $param, 'test'); + } + + public function testVisitsLocation() + { + $visitor = new Visitor(); + $param = $this->getNestedCommand('header')->getParam('foo')->setSentAs('test'); + $param->setAdditionalProperties(false); + $visitor->visit($this->command, $this->request, $param, '123'); + $this->assertEquals('123', (string) $this->request->getHeader('test')); + } + + public function testVisitsMappedPrefixHeaders() + { + $visitor = new Visitor(); + $param = $this->getNestedCommand('header')->getParam('foo')->setSentAs('test'); + $param->setSentAs('x-foo-'); + $param->setAdditionalProperties(new Parameter(array( + 'type' => 'string' + ))); + $visitor->visit($this->command, $this->request, $param, array( + 'bar' => 'test', + 'baz' => '123' + )); + $this->assertEquals('test', (string) $this->request->getHeader('x-foo-bar')); + $this->assertEquals('123', (string) $this->request->getHeader('x-foo-baz')); + } +} diff --git a/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Command/LocationVisitor/Request/JsonVisitorTest.php b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Command/LocationVisitor/Request/JsonVisitorTest.php new file mode 100644 index 0000000..ea6782f --- /dev/null +++ b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Command/LocationVisitor/Request/JsonVisitorTest.php @@ -0,0 +1,60 @@ +after($this->command, $this->request); + + $param = $this->getNestedCommand('json')->getParam('foo'); + $visitor->visit($this->command, $this->request, $param->setSentAs('test'), '123'); + $visitor->visit($this->command, $this->request, $param->setSentAs('test2'), 'abc'); + $visitor->after($this->command, $this->request); + $this->assertEquals('{"test":"123","test2":"abc"}', (string) $this->request->getBody()); + } + + public function testAddsJsonHeader() + { + $visitor = new Visitor(); + $visitor->setContentTypeHeader('application/json-foo'); + $param = $this->getNestedCommand('json')->getParam('foo'); + $visitor->visit($this->command, $this->request, $param->setSentAs('test'), '123'); + $visitor->after($this->command, $this->request); + $this->assertEquals('application/json-foo', (string) $this->request->getHeader('Content-Type')); + } + + public function testRecursivelyBuildsJsonBodies() + { + $command = $this->getCommand('json'); + $request = $command->prepare(); + $this->assertEquals('{"Foo":{"test":{"baz":true,"Jenga_Yall!":"HELLO"},"bar":123}}', (string) $request->getBody()); + } + + public function testAppliesFiltersToAdditionalProperties() + { + $command = $this->getCommand('json'); + $command->set('foo', array('not_set' => 'abc')); + $request = $command->prepare(); + $result = json_decode($request->getBody(), true); + $this->assertEquals('ABC', $result['Foo']['not_set']); + } + + public function testAppliesFiltersToArrayItemValues() + { + $command = $this->getCommand('json'); + $command->set('arr', array('a', 'b')); + $request = $command->prepare(); + $result = json_decode($request->getBody(), true); + $this->assertEquals(array('A', 'B'), $result['arr']); + } +} diff --git a/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Command/LocationVisitor/Request/PostFieldVisitorTest.php b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Command/LocationVisitor/Request/PostFieldVisitorTest.php new file mode 100644 index 0000000..540b410 --- /dev/null +++ b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Command/LocationVisitor/Request/PostFieldVisitorTest.php @@ -0,0 +1,33 @@ +getNestedCommand('postField')->getParam('foo'); + $visitor->visit($this->command, $this->request, $param->setSentAs('test'), '123'); + $this->assertEquals('123', (string) $this->request->getPostField('test')); + } + + public function testRecursivelyBuildsPostFields() + { + $command = $this->getCommand('postField'); + $request = $command->prepare(); + $visitor = new Visitor(); + $param = $command->getOperation()->getParam('foo'); + $visitor->visit($command, $request, $param, $command['foo']); + $visitor->after($command, $request); + $this->assertEquals( + 'Foo[test][baz]=1&Foo[test][Jenga_Yall!]=HELLO&Foo[bar]=123', + rawurldecode((string) $request->getPostFields()) + ); + } +} diff --git a/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Command/LocationVisitor/Request/PostFileVisitorTest.php b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Command/LocationVisitor/Request/PostFileVisitorTest.php new file mode 100644 index 0000000..21e3cec --- /dev/null +++ b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Command/LocationVisitor/Request/PostFileVisitorTest.php @@ -0,0 +1,54 @@ +getNestedCommand('postFile')->getParam('foo'); + + // Test using a path to a file + $visitor->visit($this->command, $this->request, $param->setSentAs('test_3'), __FILE__); + $this->assertInternalType('array', $this->request->getPostFile('test_3')); + + // Test with a PostFile + $visitor->visit($this->command, $this->request, $param->setSentAs(null), new PostFile('baz', __FILE__)); + $this->assertInternalType('array', $this->request->getPostFile('baz')); + } + + public function testVisitsLocationWithMultipleFiles() + { + $description = ServiceDescription::factory(array( + 'operations' => array( + 'DoPost' => array( + 'httpMethod' => 'POST', + 'parameters' => array( + 'foo' => array( + 'location' => 'postFile', + 'type' => array('string', 'array') + ) + ) + ) + ) + )); + $this->getServer()->flush(); + $this->getServer()->enqueue(array("HTTP/1.1 200 OK\r\nContent-Length:0\r\n\r\n")); + $client = new Client($this->getServer()->getUrl()); + $client->setDescription($description); + $command = $client->getCommand('DoPost', array('foo' => array(__FILE__, __FILE__))); + $command->execute(); + $received = $this->getServer()->getReceivedRequests(); + $this->assertContains('name="foo[0]";', $received[0]); + $this->assertContains('name="foo[1]";', $received[0]); + } +} diff --git a/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Command/LocationVisitor/Request/QueryVisitorTest.php b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Command/LocationVisitor/Request/QueryVisitorTest.php new file mode 100644 index 0000000..607af76 --- /dev/null +++ b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Command/LocationVisitor/Request/QueryVisitorTest.php @@ -0,0 +1,48 @@ +getNestedCommand('query')->getParam('foo')->setSentAs('test'); + $visitor->visit($this->command, $this->request, $param, '123'); + $this->assertEquals('123', $this->request->getQuery()->get('test')); + } + + /** + * @covers Guzzle\Service\Command\LocationVisitor\Request\QueryVisitor + * @covers Guzzle\Service\Command\LocationVisitor\Request\AbstractRequestVisitor::resolveRecursively + */ + public function testRecursivelyBuildsQueryStrings() + { + $command = $this->getCommand('query'); + $command->getOperation()->getParam('foo')->setSentAs('Foo'); + $request = $command->prepare(); + $this->assertEquals( + 'Foo[test][baz]=1&Foo[test][Jenga_Yall!]=HELLO&Foo[bar]=123', + rawurldecode($request->getQuery()) + ); + } + + /** + * @covers Guzzle\Service\Command\LocationVisitor\Request\AbstractRequestVisitor::resolveRecursively + */ + public function testFiltersAreAppliedToArrayParamType() + { + $command = $this->getCommandWithArrayParamAndFilters(); + $request = $command->prepare(); + $query = $request->getQuery(); + // param type 'string' + $this->assertEquals('BAR', $query->get('Foo')); + // param type 'array' + $this->assertEquals('123,456,789', $query->get('Arr')); + } +} diff --git a/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Command/LocationVisitor/Request/ResponseBodyVisitorTest.php b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Command/LocationVisitor/Request/ResponseBodyVisitorTest.php new file mode 100644 index 0000000..ff8cec5 --- /dev/null +++ b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Command/LocationVisitor/Request/ResponseBodyVisitorTest.php @@ -0,0 +1,20 @@ +getNestedCommand('response_body')->getParam('foo'); + $visitor->visit($this->command, $this->request, $param, sys_get_temp_dir() . '/foo.txt'); + $body = $this->readAttribute($this->request, 'responseBody'); + $this->assertContains('/foo.txt', $body->getUri()); + } +} diff --git a/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Command/LocationVisitor/Request/XmlVisitorTest.php b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Command/LocationVisitor/Request/XmlVisitorTest.php new file mode 100644 index 0000000..beb58b0 --- /dev/null +++ b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Command/LocationVisitor/Request/XmlVisitorTest.php @@ -0,0 +1,558 @@ + array( + 'xmlRoot' => array( + 'name' => 'test', + 'namespaces' => 'http://foo.com' + ) + ), + 'parameters' => array( + 'Foo' => array('location' => 'xml', 'type' => 'string'), + 'Baz' => array('location' => 'xml', 'type' => 'string') + ) + ), + array('Foo' => 'test', 'Baz' => 'bar'), + 'testbar' + ), + // Ensure that the content-type is not added + array(array('parameters' => array('Foo' => array('location' => 'xml', 'type' => 'string'))), array(), ''), + // Test with adding attributes and no namespace + array( + array( + 'data' => array( + 'xmlRoot' => array( + 'name' => 'test' + ) + ), + 'parameters' => array( + 'Foo' => array('location' => 'xml', 'type' => 'string', 'data' => array('xmlAttribute' => true)) + ) + ), + array('Foo' => 'test', 'Baz' => 'bar'), + '' + ), + // Test adding with an array + array( + array( + 'parameters' => array( + 'Foo' => array('location' => 'xml', 'type' => 'string'), + 'Baz' => array( + 'type' => 'array', + 'location' => 'xml', + 'items' => array( + 'type' => 'numeric', + 'sentAs' => 'Bar' + ) + ) + ) + ), + array('Foo' => 'test', 'Baz' => array(1, 2)), + 'test12' + ), + // Test adding an object + array( + array( + 'parameters' => array( + 'Foo' => array('location' => 'xml', 'type' => 'string'), + 'Baz' => array( + 'type' => 'object', + 'location' => 'xml', + 'properties' => array( + 'Bar' => array('type' => 'string'), + 'Bam' => array() + ) + ) + ) + ), + array('Foo' => 'test', 'Baz' => array('Bar' => 'abc', 'Bam' => 'foo')), + 'testabcfoo' + ), + // Add an array that contains an object + array( + array( + 'parameters' => array( + 'Baz' => array( + 'type' => 'array', + 'location' => 'xml', + 'items' => array( + 'type' => 'object', + 'sentAs' => 'Bar', + 'properties' => array('A' => array(), 'B' => array()) + ) + ) + ) + ), + array('Baz' => array( + array('A' => '1', 'B' => '2'), + array('A' => '3', 'B' => '4') + )), + '1234' + ), + // Add an object of attributes + array( + array( + 'parameters' => array( + 'Foo' => array('location' => 'xml', 'type' => 'string'), + 'Baz' => array( + 'type' => 'object', + 'location' => 'xml', + 'properties' => array( + 'Bar' => array('type' => 'string', 'data' => array('xmlAttribute' => true)), + 'Bam' => array() + ) + ) + ) + ), + array('Foo' => 'test', 'Baz' => array('Bar' => 'abc', 'Bam' => 'foo')), + 'testfoo' + ), + // Check order doesn't matter + array( + array( + 'parameters' => array( + 'Foo' => array('location' => 'xml', 'type' => 'string'), + 'Baz' => array( + 'type' => 'object', + 'location' => 'xml', + 'properties' => array( + 'Bar' => array('type' => 'string', 'data' => array('xmlAttribute' => true)), + 'Bam' => array() + ) + ) + ) + ), + array('Foo' => 'test', 'Baz' => array('Bam' => 'foo', 'Bar' => 'abc')), + 'testfoo' + ), + // Add values with custom namespaces + array( + array( + 'parameters' => array( + 'Foo' => array( + 'location' => 'xml', + 'type' => 'string', + 'data' => array( + 'xmlNamespace' => 'http://foo.com' + ) + ) + ) + ), + array('Foo' => 'test'), + 'test' + ), + // Add attributes with custom namespace prefix + array( + array( + 'parameters' => array( + 'Wrap' => array( + 'type' => 'object', + 'location' => 'xml', + 'properties' => array( + 'Foo' => array( + 'type' => 'string', + 'sentAs' => 'xsi:baz', + 'data' => array( + 'xmlNamespace' => 'http://foo.com', + 'xmlAttribute' => true + ) + ) + ) + ), + ) + ), + array('Wrap' => array( + 'Foo' => 'test' + )), + '' + ), + // Add nodes with custom namespace prefix + array( + array( + 'parameters' => array( + 'Wrap' => array( + 'type' => 'object', + 'location' => 'xml', + 'properties' => array( + 'Foo' => array( + 'type' => 'string', + 'sentAs' => 'xsi:Foo', + 'data' => array( + 'xmlNamespace' => 'http://foobar.com' + ) + ) + ) + ), + ) + ), + array('Wrap' => array( + 'Foo' => 'test' + )), + 'test' + ), + array( + array( + 'parameters' => array( + 'Foo' => array( + 'location' => 'xml', + 'type' => 'string', + 'data' => array( + 'xmlNamespace' => 'http://foo.com' + ) + ) + ) + ), + array('Foo' => '

    This is a title

    '), + 'This is a title]]>' + ), + // Flat array at top level + array( + array( + 'parameters' => array( + 'Bars' => array( + 'type' => 'array', + 'data' => array('xmlFlattened' => true), + 'location' => 'xml', + 'items' => array( + 'type' => 'object', + 'sentAs' => 'Bar', + 'properties' => array( + 'A' => array(), + 'B' => array() + ) + ) + ), + 'Boos' => array( + 'type' => 'array', + 'data' => array('xmlFlattened' => true), + 'location' => 'xml', + 'items' => array( + 'sentAs' => 'Boo', + 'type' => 'string' + ) + ) + ) + ), + array( + 'Bars' => array( + array('A' => '1', 'B' => '2'), + array('A' => '3', 'B' => '4') + ), + 'Boos' => array('test', '123') + ), + '1234test123' + ), + // Nested flat arrays + array( + array( + 'parameters' => array( + 'Delete' => array( + 'type' => 'object', + 'location' => 'xml', + 'properties' => array( + 'Items' => array( + 'type' => 'array', + 'data' => array('xmlFlattened' => true), + 'items' => array( + 'type' => 'object', + 'sentAs' => 'Item', + 'properties' => array( + 'A' => array(), + 'B' => array() + ) + ) + ) + ) + ) + ) + ), + array( + 'Delete' => array( + 'Items' => array( + array('A' => '1', 'B' => '2'), + array('A' => '3', 'B' => '4') + ) + ) + ), + '1234' + ) + ); + } + + /** + * @dataProvider xmlProvider + */ + public function testSerializesXml(array $operation, array $input, $xml) + { + $operation = new Operation($operation); + $command = $this->getMockBuilder('Guzzle\Service\Command\OperationCommand') + ->setConstructorArgs(array($input, $operation)) + ->getMockForAbstractClass(); + $command->setClient(new Client('http://www.test.com/some/path.php')); + $request = $command->prepare(); + if (!empty($input)) { + $this->assertEquals('application/xml', (string) $request->getHeader('Content-Type')); + } else { + $this->assertNull($request->getHeader('Content-Type')); + } + $body = str_replace(array("\n", ""), '', (string) $request->getBody()); + $this->assertEquals($xml, $body); + } + + public function testAddsContentTypeAndTopLevelValues() + { + $operation = new Operation(array( + 'data' => array( + 'xmlRoot' => array( + 'name' => 'test', + 'namespaces' => array( + 'xsi' => 'http://foo.com' + ) + ) + ), + 'parameters' => array( + 'Foo' => array('location' => 'xml', 'type' => 'string'), + 'Baz' => array('location' => 'xml', 'type' => 'string') + ) + )); + + $command = $this->getMockBuilder('Guzzle\Service\Command\OperationCommand') + ->setConstructorArgs(array(array( + 'Foo' => 'test', + 'Baz' => 'bar' + ), $operation)) + ->getMockForAbstractClass(); + + $command->setClient(new Client()); + $request = $command->prepare(); + $this->assertEquals('application/xml', (string) $request->getHeader('Content-Type')); + $this->assertEquals( + '' . "\n" + . 'testbar' . "\n", + (string) $request->getBody() + ); + } + + public function testCanChangeContentType() + { + $visitor = new XmlVisitor(); + $visitor->setContentTypeHeader('application/foo'); + $this->assertEquals('application/foo', $this->readAttribute($visitor, 'contentType')); + } + + public function testCanAddArrayOfSimpleTypes() + { + $request = new EntityEnclosingRequest('POST', 'http://foo.com'); + $visitor = new XmlVisitor(); + $param = new Parameter(array( + 'type' => 'object', + 'location' => 'xml', + 'name' => 'Out', + 'properties' => array( + 'Nodes' => array( + 'required' => true, + 'type' => 'array', + 'min' => 1, + 'items' => array('type' => 'string', 'sentAs' => 'Node') + ) + ) + )); + + $param->setParent(new Operation(array( + 'data' => array( + 'xmlRoot' => array( + 'name' => 'Test', + 'namespaces' => array( + 'https://foo/' + ) + ) + ) + ))); + + $value = array('Nodes' => array('foo', 'baz')); + $this->assertTrue($this->validator->validate($param, $value)); + $visitor->visit($this->command, $request, $param, $value); + $visitor->after($this->command, $request); + + $this->assertEquals( + "\n" + . "foobaz\n", + (string) $request->getBody() + ); + } + + public function testCanAddMultipleNamespacesToRoot() + { + $operation = new Operation(array( + 'data' => array( + 'xmlRoot' => array( + 'name' => 'Hi', + 'namespaces' => array( + 'xsi' => 'http://foo.com', + 'foo' => 'http://foobar.com' + ) + ) + ), + 'parameters' => array( + 'Foo' => array('location' => 'xml', 'type' => 'string') + ) + )); + + $command = $this->getMockBuilder('Guzzle\Service\Command\OperationCommand') + ->setConstructorArgs(array(array( + 'Foo' => 'test' + ), $operation)) + ->getMockForAbstractClass(); + + $command->setClient(new Client()); + $request = $command->prepare(); + $this->assertEquals('application/xml', (string) $request->getHeader('Content-Type')); + $this->assertEquals( + '' . "\n" + . 'test' . "\n", + (string) $request->getBody() + ); + } + + public function testValuesAreFiltered() + { + $operation = new Operation(array( + 'parameters' => array( + 'Foo' => array( + 'location' => 'xml', + 'type' => 'string', + 'filters' => array('strtoupper') + ), + 'Bar' => array( + 'location' => 'xml', + 'type' => 'object', + 'properties' => array( + 'Baz' => array( + 'filters' => array('strtoupper') + ) + ) + ) + ) + )); + + $command = $this->getMockBuilder('Guzzle\Service\Command\OperationCommand') + ->setConstructorArgs(array(array( + 'Foo' => 'test', + 'Bar' => array( + 'Baz' => 'abc' + ) + ), $operation)) + ->getMockForAbstractClass(); + + $command->setClient(new Client()); + $request = $command->prepare(); + $this->assertEquals( + '' . "\n" + . 'TESTABC' . "\n", + (string) $request->getBody() + ); + } + + public function testSkipsNullValues() + { + $operation = new Operation(array( + 'parameters' => array( + 'Foo' => array( + 'location' => 'xml', + 'type' => 'string' + ), + 'Bar' => array( + 'location' => 'xml', + 'type' => 'object', + 'properties' => array( + 'Baz' => array(), + 'Bam' => array(), + ) + ), + 'Arr' => array( + 'type' => 'array', + 'items' => array( + 'type' => 'string' + ) + ) + ) + )); + + $command = $this->getMockBuilder('Guzzle\Service\Command\OperationCommand') + ->setConstructorArgs(array(array( + 'Foo' => null, + 'Bar' => array( + 'Bar' => null, + 'Bam' => 'test' + ), + 'Arr' => array(null) + ), $operation)) + ->getMockForAbstractClass(); + + $command->setClient(new Client()); + $request = $command->prepare(); + $this->assertEquals( + '' . "\n" + . 'test' . "\n", + (string) $request->getBody() + ); + } + + public function testAllowsXmlEncoding() + { + $operation = new Operation(array( + 'data' => array( + 'xmlEncoding' => 'UTF-8' + ), + 'parameters' => array( + 'Foo' => array('location' => 'xml') + ) + )); + $command = $this->getMockBuilder('Guzzle\Service\Command\OperationCommand') + ->setConstructorArgs(array(array('Foo' => 'test'), $operation)) + ->getMockForAbstractClass(); + $command->setClient(new Client()); + $request = $command->prepare(); + $this->assertEquals( + '' . "\n" + . 'test' . "\n", + (string) $request->getBody() + ); + } + + public function testAllowsSendingXmlPayloadIfNoXmlParamsWereSet() + { + $operation = new Operation(array( + 'httpMethod' => 'POST', + 'data' => array('xmlAllowEmpty' => true), + 'parameters' => array('Foo' => array('location' => 'xml')) + )); + $command = $this->getMockBuilder('Guzzle\Service\Command\OperationCommand') + ->setConstructorArgs(array(array(), $operation)) + ->getMockForAbstractClass(); + $command->setClient(new Client('http://foo.com')); + $request = $command->prepare(); + $this->assertEquals( + '' . "\n" + . '' . "\n", + (string) $request->getBody() + ); + } +} diff --git a/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Command/LocationVisitor/Response/AbstractResponseVisitorTest.php b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Command/LocationVisitor/Response/AbstractResponseVisitorTest.php new file mode 100644 index 0000000..7b86003 --- /dev/null +++ b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Command/LocationVisitor/Response/AbstractResponseVisitorTest.php @@ -0,0 +1,29 @@ +value = array(); + $this->command = new MockCommand(); + $this->response = new Response(200, array( + 'X-Foo' => 'bar', + 'Content-Length' => 3, + 'Content-Type' => 'text/plain' + ), 'Foo'); + } +} diff --git a/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Command/LocationVisitor/Response/BodyVisitorTest.php b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Command/LocationVisitor/Response/BodyVisitorTest.php new file mode 100644 index 0000000..932e39b --- /dev/null +++ b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Command/LocationVisitor/Response/BodyVisitorTest.php @@ -0,0 +1,21 @@ + 'body', 'name' => 'foo')); + $visitor->visit($this->command, $this->response, $param, $this->value); + $this->assertEquals('Foo', (string) $this->value['foo']); + } +} diff --git a/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Command/LocationVisitor/Response/HeaderVisitorTest.php b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Command/LocationVisitor/Response/HeaderVisitorTest.php new file mode 100644 index 0000000..db54b1a --- /dev/null +++ b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Command/LocationVisitor/Response/HeaderVisitorTest.php @@ -0,0 +1,98 @@ + 'header', + 'name' => 'ContentType', + 'sentAs' => 'Content-Type' + )); + $visitor->visit($this->command, $this->response, $param, $this->value); + $this->assertEquals('text/plain', $this->value['ContentType']); + } + + public function testVisitsLocationWithFilters() + { + $visitor = new Visitor(); + $param = new Parameter(array( + 'location' => 'header', + 'name' => 'Content-Type', + 'filters' => array('strtoupper') + )); + $visitor->visit($this->command, $this->response, $param, $this->value); + $this->assertEquals('TEXT/PLAIN', $this->value['Content-Type']); + } + + public function testVisitsMappedPrefixHeaders() + { + $visitor = new Visitor(); + $param = new Parameter(array( + 'location' => 'header', + 'name' => 'Metadata', + 'sentAs' => 'X-Baz-', + 'type' => 'object', + 'additionalProperties' => array( + 'type' => 'string' + ) + )); + $response = new Response(200, array( + 'X-Baz-Test' => 'ABC', + 'X-Baz-Bar' => array('123', '456'), + 'Content-Length' => 3 + ), 'Foo'); + $visitor->visit($this->command, $response, $param, $this->value); + $this->assertEquals(array( + 'Metadata' => array( + 'Test' => 'ABC', + 'Bar' => array('123', '456') + ) + ), $this->value); + } + + /** + * @group issue-399 + * @link https://github.com/guzzle/guzzle/issues/399 + */ + public function testDiscardingUnknownHeaders() + { + $visitor = new Visitor(); + $param = new Parameter(array( + 'location' => 'header', + 'name' => 'Content-Type', + 'additionalParameters' => false + )); + $visitor->visit($this->command, $this->response, $param, $this->value); + $this->assertEquals('text/plain', $this->value['Content-Type']); + $this->assertArrayNotHasKey('X-Foo', $this->value); + } + + /** + * @group issue-399 + * @link https://github.com/guzzle/guzzle/issues/399 + */ + public function testDiscardingUnknownPropertiesWithAliasing() + { + $visitor = new Visitor(); + $param = new Parameter(array( + 'location' => 'header', + 'name' => 'ContentType', + 'sentAs' => 'Content-Type', + 'additionalParameters' => false + )); + $visitor->visit($this->command, $this->response, $param, $this->value); + $this->assertEquals('text/plain', $this->value['ContentType']); + $this->assertArrayNotHasKey('X-Foo', $this->value); + } +} diff --git a/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Command/LocationVisitor/Response/JsonVisitorTest.php b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Command/LocationVisitor/Response/JsonVisitorTest.php new file mode 100644 index 0000000..4f8d30b --- /dev/null +++ b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Command/LocationVisitor/Response/JsonVisitorTest.php @@ -0,0 +1,157 @@ +getMockBuilder('Guzzle\Service\Command\AbstractCommand') + ->setMethods(array('getResponse')) + ->getMockForAbstractClass(); + $command->expects($this->once()) + ->method('getResponse') + ->will($this->returnValue(new Response(200, null, '{"foo":"bar"}'))); + $result = array(); + $visitor->before($command, $result); + $this->assertEquals(array('foo' => 'bar'), $result); + } + + public function testVisitsLocation() + { + $visitor = new Visitor(); + $param = new Parameter(array( + 'name' => 'foo', + 'type' => 'array', + 'items' => array( + 'filters' => 'strtoupper', + 'type' => 'string' + ) + )); + $this->value = array('foo' => array('a', 'b', 'c')); + $visitor->visit($this->command, $this->response, $param, $this->value); + $this->assertEquals(array('A', 'B', 'C'), $this->value['foo']); + } + + public function testRenamesTopLevelValues() + { + $visitor = new Visitor(); + $param = new Parameter(array( + 'name' => 'foo', + 'sentAs' => 'Baz', + 'type' => 'string', + )); + $this->value = array('Baz' => 'test'); + $visitor->visit($this->command, $this->response, $param, $this->value); + $this->assertEquals(array('foo' => 'test'), $this->value); + } + + public function testRenamesDoesNotFailForNonExistentKey() + { + $visitor = new Visitor(); + $param = new Parameter(array( + 'name' => 'foo', + 'type' => 'object', + 'properties' => array( + 'bar' => array( + 'name' => 'bar', + 'sentAs' => 'baz', + ), + ), + )); + $this->value = array('foo' => array('unknown' => 'Unknown')); + $visitor->visit($this->command, $this->response, $param, $this->value); + $this->assertEquals(array('foo' => array('unknown' => 'Unknown')), $this->value); + } + + public function testTraversesObjectsAndAppliesFilters() + { + $visitor = new Visitor(); + $param = new Parameter(array( + 'name' => 'foo', + 'type' => 'object', + 'properties' => array( + 'foo' => array('filters' => 'strtoupper'), + 'bar' => array('filters' => 'strtolower') + ) + )); + $this->value = array('foo' => array('foo' => 'hello', 'bar' => 'THERE')); + $visitor->visit($this->command, $this->response, $param, $this->value); + $this->assertEquals(array('foo' => 'HELLO', 'bar' => 'there'), $this->value['foo']); + } + + /** + * @group issue-399 + * @link https://github.com/guzzle/guzzle/issues/399 + */ + public function testDiscardingUnknownProperties() + { + $visitor = new Visitor(); + $param = new Parameter(array( + 'name' => 'foo', + 'type' => 'object', + 'additionalProperties' => false, + 'properties' => array( + 'bar' => array( + 'type' => 'string', + 'name' => 'bar', + ), + ), + )); + $this->value = array('foo' => array('bar' => 15, 'unknown' => 'Unknown')); + $visitor->visit($this->command, $this->response, $param, $this->value); + $this->assertEquals(array('foo' => array('bar' => 15)), $this->value); + } + + /** + * @group issue-399 + * @link https://github.com/guzzle/guzzle/issues/399 + */ + public function testDiscardingUnknownPropertiesWithAliasing() + { + $visitor = new Visitor(); + $param = new Parameter(array( + 'name' => 'foo', + 'type' => 'object', + 'additionalProperties' => false, + 'properties' => array( + 'bar' => array( + 'name' => 'bar', + 'sentAs' => 'baz', + ), + ), + )); + $this->value = array('foo' => array('baz' => 15, 'unknown' => 'Unknown')); + $visitor->visit($this->command, $this->response, $param, $this->value); + $this->assertEquals(array('foo' => array('bar' => 15)), $this->value); + } + + public function testWalksAdditionalProperties() + { + $visitor = new Visitor(); + $param = new Parameter(array( + 'name' => 'foo', + 'type' => 'object', + 'additionalProperties' => array( + 'type' => 'object', + 'properties' => array( + 'bar' => array( + 'type' => 'string', + 'filters' => array('base64_decode') + ) + ), + ), + )); + $this->value = array('foo' => array('baz' => array('bar' => 'Zm9v'))); + $visitor->visit($this->command, $this->response, $param, $this->value); + $this->assertEquals('foo', $this->value['foo']['baz']['bar']); + } +} diff --git a/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Command/LocationVisitor/Response/ReasonPhraseVisitorTest.php b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Command/LocationVisitor/Response/ReasonPhraseVisitorTest.php new file mode 100644 index 0000000..23cd40f --- /dev/null +++ b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Command/LocationVisitor/Response/ReasonPhraseVisitorTest.php @@ -0,0 +1,21 @@ + 'reasonPhrase', 'name' => 'phrase')); + $visitor->visit($this->command, $this->response, $param, $this->value); + $this->assertEquals('OK', $this->value['phrase']); + } +} diff --git a/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Command/LocationVisitor/Response/StatusCodeVisitorTest.php b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Command/LocationVisitor/Response/StatusCodeVisitorTest.php new file mode 100644 index 0000000..7211a58 --- /dev/null +++ b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Command/LocationVisitor/Response/StatusCodeVisitorTest.php @@ -0,0 +1,21 @@ + 'statusCode', 'name' => 'code')); + $visitor->visit($this->command, $this->response, $param, $this->value); + $this->assertEquals(200, $this->value['code']); + } +} diff --git a/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Command/LocationVisitor/Response/XmlVisitorTest.php b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Command/LocationVisitor/Response/XmlVisitorTest.php new file mode 100644 index 0000000..f87cec7 --- /dev/null +++ b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Command/LocationVisitor/Response/XmlVisitorTest.php @@ -0,0 +1,431 @@ +getMockBuilder('Guzzle\Service\Command\AbstractCommand') + ->setMethods(array('getResponse')) + ->getMockForAbstractClass(); + $command->expects($this->once()) + ->method('getResponse') + ->will($this->returnValue(new Response(200, null, 'test'))); + $result = array(); + $visitor->before($command, $result); + $this->assertEquals(array('Bar' => 'test'), $result); + } + + public function testBeforeMethodParsesXmlWithNamespace() + { + $this->markTestSkipped("Response/XmlVisitor cannot accept 'xmlns' in response, see #368 (http://git.io/USa1mA)."); + + $visitor = new Visitor(); + $command = $this->getMockBuilder('Guzzle\Service\Command\AbstractCommand') + ->setMethods(array('getResponse')) + ->getMockForAbstractClass(); + $command->expects($this->once()) + ->method('getResponse') + ->will($this->returnValue(new Response(200, null, 'test'))); + $result = array(); + $visitor->before($command, $result); + $this->assertEquals(array('Bar' => 'test'), $result); + } + + public function testBeforeMethodParsesNestedXml() + { + $visitor = new Visitor(); + $command = $this->getMockBuilder('Guzzle\Service\Command\AbstractCommand') + ->setMethods(array('getResponse')) + ->getMockForAbstractClass(); + $command->expects($this->once()) + ->method('getResponse') + ->will($this->returnValue(new Response(200, null, 'test'))); + $result = array(); + $visitor->before($command, $result); + $this->assertEquals(array('Items' => array('Bar' => 'test')), $result); + } + + public function testCanExtractAndRenameTopLevelXmlValues() + { + $visitor = new Visitor(); + $param = new Parameter(array( + 'location' => 'xml', + 'name' => 'foo', + 'sentAs' => 'Bar' + )); + $value = array('Bar' => 'test'); + $visitor->visit($this->command, $this->response, $param, $value); + $this->assertArrayHasKey('foo', $value); + $this->assertEquals('test', $value['foo']); + } + + public function testEnsuresRepeatedArraysAreInCorrectLocations() + { + $visitor = new Visitor(); + $param = new Parameter(array( + 'location' => 'xml', + 'name' => 'foo', + 'sentAs' => 'Foo', + 'type' => 'array', + 'items' => array( + 'type' => 'object', + 'properties' => array( + 'Bar' => array('type' => 'string'), + 'Baz' => array('type' => 'string'), + 'Bam' => array('type' => 'string') + ) + ) + )); + + $xml = new \SimpleXMLElement('12'); + $value = json_decode(json_encode($xml), true); + $visitor->visit($this->command, $this->response, $param, $value); + $this->assertEquals(array( + 'foo' => array( + array ( + 'Bar' => '1', + 'Baz' => '2' + ) + ) + ), $value); + } + + public function testEnsuresFlatArraysAreFlat() + { + $visitor = new Visitor(); + $param = new Parameter(array( + 'location' => 'xml', + 'name' => 'foo', + 'type' => 'array', + 'items' => array('type' => 'string') + )); + + $value = array('foo' => array('bar', 'baz')); + $visitor->visit($this->command, $this->response, $param, $value); + $this->assertEquals(array('foo' => array('bar', 'baz')), $value); + + $value = array('foo' => 'bar'); + $visitor->visit($this->command, $this->response, $param, $value); + $this->assertEquals(array('foo' => array('bar')), $value); + } + + public function xmlDataProvider() + { + $param = new Parameter(array( + 'location' => 'xml', + 'name' => 'Items', + 'type' => 'array', + 'items' => array( + 'type' => 'object', + 'name' => 'Item', + 'properties' => array( + 'Bar' => array('type' => 'string'), + 'Baz' => array('type' => 'string') + ) + ) + )); + + return array( + array($param, '12', array( + 'Items' => array( + array('Bar' => 1), + array('Bar' => 2) + ) + )), + array($param, '1', array( + 'Items' => array( + array('Bar' => 1) + ) + )), + array($param, '', array( + 'Items' => array() + )) + ); + } + + /** + * @dataProvider xmlDataProvider + */ + public function testEnsuresWrappedArraysAreInCorrectLocations($param, $xml, $result) + { + $visitor = new Visitor(); + $xml = new \SimpleXMLElement($xml); + $value = json_decode(json_encode($xml), true); + $visitor->visit($this->command, $this->response, $param, $value); + $this->assertEquals($result, $value); + } + + public function testCanRenameValues() + { + $visitor = new Visitor(); + $param = new Parameter(array( + 'name' => 'TerminatingInstances', + 'type' => 'array', + 'location' => 'xml', + 'sentAs' => 'instancesSet', + 'items' => array( + 'name' => 'item', + 'type' => 'object', + 'sentAs' => 'item', + 'properties' => array( + 'InstanceId' => array( + 'type' => 'string', + 'sentAs' => 'instanceId', + ), + 'CurrentState' => array( + 'type' => 'object', + 'sentAs' => 'currentState', + 'properties' => array( + 'Code' => array( + 'type' => 'numeric', + 'sentAs' => 'code', + ), + 'Name' => array( + 'type' => 'string', + 'sentAs' => 'name', + ), + ), + ), + 'PreviousState' => array( + 'type' => 'object', + 'sentAs' => 'previousState', + 'properties' => array( + 'Code' => array( + 'type' => 'numeric', + 'sentAs' => 'code', + ), + 'Name' => array( + 'type' => 'string', + 'sentAs' => 'name', + ), + ), + ), + ), + ) + )); + + $value = array( + 'instancesSet' => array ( + 'item' => array ( + 'instanceId' => 'i-3ea74257', + 'currentState' => array( + 'code' => '32', + 'name' => 'shutting-down', + ), + 'previousState' => array( + 'code' => '16', + 'name' => 'running', + ), + ), + ) + ); + + $visitor->visit($this->command, $this->response, $param, $value); + + $this->assertEquals(array( + 'TerminatingInstances' => array( + array( + 'InstanceId' => 'i-3ea74257', + 'CurrentState' => array( + 'Code' => '32', + 'Name' => 'shutting-down', + ), + 'PreviousState' => array( + 'Code' => '16', + 'Name' => 'running', + ) + ) + ) + ), $value); + } + + public function testCanRenameAttributes() + { + $visitor = new Visitor(); + $param = new Parameter(array( + 'name' => 'RunningQueues', + 'type' => 'array', + 'location' => 'xml', + 'items' => array( + 'type' => 'object', + 'sentAs' => 'item', + 'properties' => array( + 'QueueId' => array( + 'type' => 'string', + 'sentAs' => 'queue_id', + 'data' => array( + 'xmlAttribute' => true, + ), + ), + 'CurrentState' => array( + 'type' => 'object', + 'properties' => array( + 'Code' => array( + 'type' => 'numeric', + 'sentAs' => 'code', + 'data' => array( + 'xmlAttribute' => true, + ), + ), + 'Name' => array( + 'sentAs' => 'name', + 'data' => array( + 'xmlAttribute' => true, + ), + ), + ), + ), + 'PreviousState' => array( + 'type' => 'object', + 'properties' => array( + 'Code' => array( + 'type' => 'numeric', + 'sentAs' => 'code', + 'data' => array( + 'xmlAttribute' => true, + ), + ), + 'Name' => array( + 'sentAs' => 'name', + 'data' => array( + 'xmlAttribute' => true, + ), + ), + ), + ), + ), + ) + )); + + $xml = ''; + $value = json_decode(json_encode(new \SimpleXMLElement($xml)), true); + $visitor->visit($this->command, $this->response, $param, $value); + + $this->assertEquals(array( + 'RunningQueues' => array( + array( + 'QueueId' => 'q-3ea74257', + 'CurrentState' => array( + 'Code' => '32', + 'Name' => 'processing', + ), + 'PreviousState' => array( + 'Code' => '16', + 'Name' => 'wait', + ), + ), + ) + ), $value); + } + + public function testAddsEmptyArraysWhenValueIsMissing() + { + $visitor = new Visitor(); + $param = new Parameter(array( + 'name' => 'Foo', + 'type' => 'array', + 'location' => 'xml', + 'items' => array( + 'type' => 'object', + 'properties' => array( + 'Baz' => array('type' => 'array'), + 'Bar' => array( + 'type' => 'object', + 'properties' => array( + 'Baz' => array('type' => 'array'), + ) + ) + ) + ) + )); + + $value = array(); + $visitor->visit($this->command, $this->response, $param, $value); + + $value = array( + 'Foo' => array( + 'Bar' => array() + ) + ); + $visitor->visit($this->command, $this->response, $param, $value); + $this->assertEquals(array( + 'Foo' => array( + array( + 'Bar' => array() + ) + ) + ), $value); + } + + /** + * @group issue-399 + * @link https://github.com/guzzle/guzzle/issues/399 + */ + public function testDiscardingUnknownProperties() + { + $visitor = new Visitor(); + $param = new Parameter(array( + 'name' => 'foo', + 'type' => 'object', + 'additionalProperties' => false, + 'properties' => array( + 'bar' => array( + 'type' => 'string', + 'name' => 'bar', + ), + ), + )); + $this->value = array('foo' => array('bar' => 15, 'unknown' => 'Unknown')); + $visitor->visit($this->command, $this->response, $param, $this->value); + $this->assertEquals(array('foo' => array('bar' => 15)), $this->value); + } + + /** + * @group issue-399 + * @link https://github.com/guzzle/guzzle/issues/399 + */ + public function testDiscardingUnknownPropertiesWithAliasing() + { + $visitor = new Visitor(); + $param = new Parameter(array( + 'name' => 'foo', + 'type' => 'object', + 'additionalProperties' => false, + 'properties' => array( + 'bar' => array( + 'name' => 'bar', + 'sentAs' => 'baz', + ), + ), + )); + $this->value = array('foo' => array('baz' => 15, 'unknown' => 'Unknown')); + $visitor->visit($this->command, $this->response, $param, $this->value); + $this->assertEquals(array('foo' => array('bar' => 15)), $this->value); + } + + public function testProperlyHandlesEmptyStringValues() + { + $visitor = new Visitor(); + $param = new Parameter(array( + 'name' => 'foo', + 'type' => 'object', + 'properties' => array( + 'bar' => array('type' => 'string') + ), + )); + $xml = ''; + $value = json_decode(json_encode(new \SimpleXMLElement($xml)), true); + $visitor->visit($this->command, $this->response, $param, $value); + $this->assertEquals(array('foo' => array('bar' => '')), $value); + } +} diff --git a/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Command/LocationVisitor/VisitorFlyweightTest.php b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Command/LocationVisitor/VisitorFlyweightTest.php new file mode 100644 index 0000000..a252ffe --- /dev/null +++ b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Command/LocationVisitor/VisitorFlyweightTest.php @@ -0,0 +1,53 @@ +assertInstanceOf('Guzzle\Service\Command\LocationVisitor\Request\JsonVisitor', $f->getRequestVisitor('json')); + $this->assertInstanceOf('Guzzle\Service\Command\LocationVisitor\Response\JsonVisitor', $f->getResponseVisitor('json')); + } + + public function testCanUseCustomMappings() + { + $f = new VisitorFlyweight(array()); + $this->assertEquals(array(), $this->readAttribute($f, 'mappings')); + } + + /** + * @expectedException \InvalidArgumentException + * @expectedExceptionMessage No request visitor has been mapped for foo + */ + public function testThrowsExceptionWhenRetrievingUnknownVisitor() + { + VisitorFlyweight::getInstance()->getRequestVisitor('foo'); + } + + public function testCachesVisitors() + { + $f = new VisitorFlyweight(); + $v1 = $f->getRequestVisitor('json'); + $this->assertSame($v1, $f->getRequestVisitor('json')); + } + + public function testAllowsAddingVisitors() + { + $f = new VisitorFlyweight(); + $j1 = new JsonRequestVisitor(); + $j2 = new JsonResponseVisitor(); + $f->addRequestVisitor('json', $j1); + $f->addResponseVisitor('json', $j2); + $this->assertSame($j1, $f->getRequestVisitor('json')); + $this->assertSame($j2, $f->getResponseVisitor('json')); + } +} diff --git a/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Command/OperationCommandTest.php b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Command/OperationCommandTest.php new file mode 100644 index 0000000..95fb533 --- /dev/null +++ b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Command/OperationCommandTest.php @@ -0,0 +1,102 @@ +getRequestSerializer(); + $b = new DefaultRequestSerializer(VisitorFlyweight::getInstance()); + $operation->setRequestSerializer($b); + $this->assertNotSame($a, $operation->getRequestSerializer()); + } + + public function testPreparesRequestUsingSerializer() + { + $op = new OperationCommand(array(), new Operation()); + $op->setClient(new Client()); + $s = $this->getMockBuilder('Guzzle\Service\Command\RequestSerializerInterface') + ->setMethods(array('prepare')) + ->getMockForAbstractClass(); + $s->expects($this->once()) + ->method('prepare') + ->will($this->returnValue(new EntityEnclosingRequest('POST', 'http://foo.com'))); + $op->setRequestSerializer($s); + $op->prepare(); + } + + public function testParsesResponsesWithResponseParser() + { + $op = new OperationCommand(array(), new Operation()); + $p = $this->getMockBuilder('Guzzle\Service\Command\ResponseParserInterface') + ->setMethods(array('parse')) + ->getMockForAbstractClass(); + $p->expects($this->once()) + ->method('parse') + ->will($this->returnValue(array('foo' => 'bar'))); + $op->setResponseParser($p); + $op->setClient(new Client()); + $request = $op->prepare(); + $request->setResponse(new Response(200), true); + $this->assertEquals(array('foo' => 'bar'), $op->execute()); + } + + public function testParsesResponsesUsingModelParserWhenMatchingModelIsFound() + { + $description = ServiceDescription::factory(array( + 'operations' => array( + 'foo' => array('responseClass' => 'bar', 'responseType' => 'model') + ), + 'models' => array( + 'bar' => array( + 'type' => 'object', + 'properties' => array( + 'Baz' => array('type' => 'string', 'location' => 'xml') + ) + ) + ) + )); + + $op = new OperationCommand(array(), $description->getOperation('foo')); + $op->setClient(new Client()); + $request = $op->prepare(); + $request->setResponse(new Response(200, array( + 'Content-Type' => 'application/xml' + ), 'Bar'), true); + $result = $op->execute(); + $this->assertEquals(new Model(array('Baz' => 'Bar')), $result); + } + + public function testAllowsRawResponses() + { + $description = new ServiceDescription(array( + 'operations' => array('foo' => array('responseClass' => 'bar', 'responseType' => 'model')), + 'models' => array('bar' => array()) + )); + $op = new OperationCommand(array( + OperationCommand::RESPONSE_PROCESSING => OperationCommand::TYPE_RAW + ), $description->getOperation('foo')); + $op->setClient(new Client()); + $request = $op->prepare(); + $response = new Response(200, array( + 'Content-Type' => 'application/xml' + ), 'Bar'); + $request->setResponse($response, true); + $this->assertSame($response, $op->execute()); + } +} diff --git a/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Command/OperationResponseParserTest.php b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Command/OperationResponseParserTest.php new file mode 100644 index 0000000..69ba1fc --- /dev/null +++ b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Command/OperationResponseParserTest.php @@ -0,0 +1,335 @@ +addVisitor('foo', $visitor); + $this->assertSame($visitor, $this->readAttribute($p, 'factory')->getResponseVisitor('foo')); + } + + public function testUsesParentParser() + { + $p = new OperationResponseParser(new VisitorFlyweight()); + $operation = new Operation(); + $operation->setServiceDescription(new ServiceDescription()); + $op = new OperationCommand(array(), $operation); + $op->setResponseParser($p)->setClient(new Client()); + $op->prepare()->setResponse(new Response(200, array('Content-Type' => 'application/xml'), 'C'), true); + $this->assertInstanceOf('SimpleXMLElement', $op->execute()); + } + + public function testVisitsLocations() + { + $parser = new OperationResponseParser(new VisitorFlyweight(array())); + $parser->addVisitor('statusCode', new StatusCodeVisitor()); + $parser->addVisitor('reasonPhrase', new ReasonPhraseVisitor()); + $parser->addVisitor('json', new JsonVisitor()); + $op = new OperationCommand(array(), $this->getDescription()->getOperation('test')); + $op->setResponseParser($parser)->setClient(new Client()); + $op->prepare()->setResponse(new Response(201), true); + $result = $op->execute(); + $this->assertEquals(201, $result['code']); + $this->assertEquals('Created', $result['phrase']); + } + + public function testVisitsLocationsForJsonResponse() + { + $parser = OperationResponseParser::getInstance(); + $operation = $this->getDescription()->getOperation('test'); + $op = new OperationCommand(array(), $operation); + $op->setResponseParser($parser)->setClient(new Client()); + $op->prepare()->setResponse(new Response(200, array( + 'Content-Type' => 'application/json' + ), '{"baz":"bar","enigma":"123"}'), true); + $result = $op->execute(); + $this->assertEquals(array( + 'baz' => 'bar', + 'enigma' => '123', + 'code' => 200, + 'phrase' => 'OK' + ), $result->toArray()); + } + + public function testSkipsUnkownModels() + { + $parser = OperationResponseParser::getInstance(); + $operation = $this->getDescription()->getOperation('test'); + $operation->setResponseClass('Baz')->setResponseType('model'); + $op = new OperationCommand(array(), $operation); + $op->setResponseParser($parser)->setClient(new Client()); + $op->prepare()->setResponse(new Response(201), true); + $this->assertInstanceOf('Guzzle\Http\Message\Response', $op->execute()); + } + + public function testAllowsModelProcessingToBeDisabled() + { + $parser = OperationResponseParser::getInstance(); + $operation = $this->getDescription()->getOperation('test'); + $op = new OperationCommand(array('command.response_processing' => 'native'), $operation); + $op->setResponseParser($parser)->setClient(new Client()); + $op->prepare()->setResponse(new Response(200, array( + 'Content-Type' => 'application/json' + ), '{"baz":"bar","enigma":"123"}'), true); + $result = $op->execute(); + $this->assertInstanceOf('Guzzle\Service\Resource\Model', $result); + $this->assertEquals(array( + 'baz' => 'bar', + 'enigma' => '123' + ), $result->toArray()); + } + + public function testCanInjectModelSchemaIntoModels() + { + $parser = new OperationResponseParser(VisitorFlyweight::getInstance(), true); + $desc = $this->getDescription(); + $operation = $desc->getOperation('test'); + $op = new OperationCommand(array(), $operation); + $op->setResponseParser($parser)->setClient(new Client()); + $op->prepare()->setResponse(new Response(200, array( + 'Content-Type' => 'application/json' + ), '{"baz":"bar","enigma":"123"}'), true); + $result = $op->execute(); + $this->assertSame($result->getStructure(), $desc->getModel('Foo')); + } + + public function testDoesNotParseXmlWhenNotUsingXmlVisitor() + { + $parser = OperationResponseParser::getInstance(); + $description = ServiceDescription::factory(array( + 'operations' => array('test' => array('responseClass' => 'Foo')), + 'models' => array( + 'Foo' => array( + 'type' => 'object', + 'properties' => array('baz' => array('location' => 'body')) + ) + ) + )); + $operation = $description->getOperation('test'); + $op = new OperationCommand(array(), $operation); + $op->setResponseParser($parser)->setClient(new Client()); + $brokenXml = '<><><>>>>'; + $op->prepare()->setResponse(new Response(200, array( + 'Content-Type' => 'application/xml' + ), $brokenXml), true); + $result = $op->execute(); + $this->assertEquals(array('baz'), $result->getKeys()); + $this->assertEquals($brokenXml, (string) $result['baz']); + } + + public function testVisitsAdditionalProperties() + { + $parser = OperationResponseParser::getInstance(); + $description = ServiceDescription::factory(array( + 'operations' => array('test' => array('responseClass' => 'Foo')), + 'models' => array( + 'Foo' => array( + 'type' => 'object', + 'properties' => array( + 'code' => array('location' => 'statusCode') + ), + 'additionalProperties' => array( + 'location' => 'json', + 'type' => 'object', + 'properties' => array( + 'a' => array( + 'type' => 'string', + 'filters' => 'strtoupper' + ) + ) + ) + ) + ) + )); + + $operation = $description->getOperation('test'); + $op = new OperationCommand(array(), $operation); + $op->setResponseParser($parser)->setClient(new Client()); + $json = '[{"a":"test"},{"a":"baz"}]'; + $op->prepare()->setResponse(new Response(200, array('Content-Type' => 'application/json'), $json), true); + $result = $op->execute()->toArray(); + $this->assertEquals(array( + 'code' => 200, + array('a' => 'TEST'), + array('a' => 'BAZ') + ), $result); + } + + /** + * @group issue-399 + * @link https://github.com/guzzle/guzzle/issues/399 + */ + public function testAdditionalPropertiesDisabledDiscardsData() + { + $parser = OperationResponseParser::getInstance(); + $description = ServiceDescription::factory(array( + 'operations' => array('test' => array('responseClass' => 'Foo')), + 'models' => array( + 'Foo' => array( + 'type' => 'object', + 'additionalProperties' => false, + 'properties' => array( + 'name' => array( + 'location' => 'json', + 'type' => 'string', + ), + 'nested' => array( + 'location' => 'json', + 'type' => 'object', + 'additionalProperties' => false, + 'properties' => array( + 'width' => array( + 'type' => 'integer' + ) + ), + ), + 'code' => array('location' => 'statusCode') + ), + + ) + ) + )); + + $operation = $description->getOperation('test'); + $op = new OperationCommand(array(), $operation); + $op->setResponseParser($parser)->setClient(new Client()); + $json = '{"name":"test", "volume":2.0, "nested":{"width":10,"bogus":1}}'; + $op->prepare()->setResponse(new Response(200, array('Content-Type' => 'application/json'), $json), true); + $result = $op->execute()->toArray(); + $this->assertEquals(array( + 'name' => 'test', + 'nested' => array( + 'width' => 10, + ), + 'code' => 200 + ), $result); + } + + public function testCreatesCustomResponseClassInterface() + { + $parser = OperationResponseParser::getInstance(); + $description = ServiceDescription::factory(array( + 'operations' => array('test' => array('responseClass' => 'Guzzle\Tests\Mock\CustomResponseModel')) + )); + $operation = $description->getOperation('test'); + $op = new OperationCommand(array(), $operation); + $op->setResponseParser($parser)->setClient(new Client()); + $op->prepare()->setResponse(new Response(200, array('Content-Type' => 'application/json'), 'hi!'), true); + $result = $op->execute(); + $this->assertInstanceOf('Guzzle\Tests\Mock\CustomResponseModel', $result); + $this->assertSame($op, $result->command); + } + + /** + * @expectedException \Guzzle\Service\Exception\ResponseClassException + * @expectedExceptionMessage must exist + */ + public function testEnsuresResponseClassExists() + { + $parser = OperationResponseParser::getInstance(); + $description = ServiceDescription::factory(array( + 'operations' => array('test' => array('responseClass' => 'Foo\Baz\Bar')) + )); + $operation = $description->getOperation('test'); + $op = new OperationCommand(array(), $operation); + $op->setResponseParser($parser)->setClient(new Client()); + $op->prepare()->setResponse(new Response(200, array('Content-Type' => 'application/json'), 'hi!'), true); + $op->execute(); + } + + /** + * @expectedException \Guzzle\Service\Exception\ResponseClassException + * @expectedExceptionMessage and implement + */ + public function testEnsuresResponseClassImplementsResponseClassInterface() + { + $parser = OperationResponseParser::getInstance(); + $description = ServiceDescription::factory(array( + 'operations' => array('test' => array('responseClass' => __CLASS__)) + )); + $operation = $description->getOperation('test'); + $op = new OperationCommand(array(), $operation); + $op->setResponseParser($parser)->setClient(new Client()); + $op->prepare()->setResponse(new Response(200, array('Content-Type' => 'application/json'), 'hi!'), true); + $op->execute(); + } + + protected function getDescription() + { + return ServiceDescription::factory(array( + 'operations' => array('test' => array('responseClass' => 'Foo')), + 'models' => array( + 'Foo' => array( + 'type' => 'object', + 'properties' => array( + 'baz' => array('type' => 'string', 'location' => 'json'), + 'code' => array('location' => 'statusCode'), + 'phrase' => array('location' => 'reasonPhrase'), + ) + ) + ) + )); + } + + public function testCanAddListenerToParseDomainObjects() + { + $client = new Client(); + $client->setDescription(ServiceDescription::factory(array( + 'operations' => array('test' => array('responseClass' => 'FooBazBar')) + ))); + $foo = new \stdClass(); + $client->getEventDispatcher()->addListener('command.parse_response', function ($e) use ($foo) { + $e['result'] = $foo; + }); + $command = $client->getCommand('test'); + $command->prepare()->setResponse(new Response(200), true); + $result = $command->execute(); + $this->assertSame($result, $foo); + } + + /** + * @group issue-399 + * @link https://github.com/guzzle/guzzle/issues/501 + */ + public function testAdditionalPropertiesWithRefAreResolved() + { + $parser = OperationResponseParser::getInstance(); + $description = ServiceDescription::factory(array( + 'operations' => array('test' => array('responseClass' => 'Foo')), + 'models' => array( + 'Baz' => array('type' => 'string'), + 'Foo' => array( + 'type' => 'object', + 'additionalProperties' => array('$ref' => 'Baz', 'location' => 'json') + ) + ) + )); + $operation = $description->getOperation('test'); + $op = new OperationCommand(array(), $operation); + $op->setResponseParser($parser)->setClient(new Client()); + $json = '{"a":"a","b":"b","c":"c"}'; + $op->prepare()->setResponse(new Response(200, array('Content-Type' => 'application/json'), $json), true); + $result = $op->execute()->toArray(); + $this->assertEquals(array('a' => 'a', 'b' => 'b', 'c' => 'c'), $result); + } +} diff --git a/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Description/OperationTest.php b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Description/OperationTest.php new file mode 100644 index 0000000..ae33b69 --- /dev/null +++ b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Description/OperationTest.php @@ -0,0 +1,308 @@ + 'test', + 'summary' => 'doc', + 'notes' => 'notes', + 'documentationUrl' => 'http://www.example.com', + 'httpMethod' => 'POST', + 'uri' => '/api/v1', + 'responseClass' => 'array', + 'responseNotes' => 'returns the json_decoded response', + 'deprecated' => true, + 'parameters' => array( + 'key' => array( + 'required' => true, + 'type' => 'string', + 'maxLength' => 10 + ), + 'key_2' => array( + 'required' => true, + 'type' => 'integer', + 'default' => 10 + ) + ) + )); + + $this->assertEquals('test', $c->getName()); + $this->assertEquals('doc', $c->getSummary()); + $this->assertEquals('http://www.example.com', $c->getDocumentationUrl()); + $this->assertEquals('POST', $c->getHttpMethod()); + $this->assertEquals('/api/v1', $c->getUri()); + $this->assertEquals('array', $c->getResponseClass()); + $this->assertEquals('returns the json_decoded response', $c->getResponseNotes()); + $this->assertTrue($c->getDeprecated()); + $this->assertEquals('Guzzle\\Service\\Command\\OperationCommand', $c->getClass()); + $this->assertEquals(array( + 'key' => new Parameter(array( + 'name' => 'key', + 'required' => true, + 'type' => 'string', + 'maxLength' => 10, + 'parent' => $c + )), + 'key_2' => new Parameter(array( + 'name' => 'key_2', + 'required' => true, + 'type' => 'integer', + 'default' => 10, + 'parent' => $c + )) + ), $c->getParams()); + + $this->assertEquals(new Parameter(array( + 'name' => 'key_2', + 'required' => true, + 'type' => 'integer', + 'default' => 10, + 'parent' => $c + )), $c->getParam('key_2')); + + $this->assertNull($c->getParam('afefwef')); + $this->assertArrayNotHasKey('parent', $c->getParam('key_2')->toArray()); + } + + public function testAllowsConcreteCommands() + { + $c = new Operation(array( + 'name' => 'test', + 'class' => 'Guzzle\\Service\\Command\ClosureCommand', + 'parameters' => array( + 'p' => new Parameter(array( + 'name' => 'foo' + )) + ) + )); + $this->assertEquals('Guzzle\\Service\\Command\ClosureCommand', $c->getClass()); + } + + public function testConvertsToArray() + { + $data = array( + 'name' => 'test', + 'class' => 'Guzzle\\Service\\Command\ClosureCommand', + 'summary' => 'test', + 'documentationUrl' => 'http://www.example.com', + 'httpMethod' => 'PUT', + 'uri' => '/', + 'parameters' => array('p' => array('name' => 'foo')) + ); + $c = new Operation($data); + $toArray = $c->toArray(); + unset($data['name']); + $this->assertArrayHasKey('parameters', $toArray); + $this->assertInternalType('array', $toArray['parameters']); + + // Normalize the array + unset($data['parameters']); + unset($toArray['parameters']); + + $data['responseType'] = 'primitive'; + $data['responseClass'] = 'array'; + $this->assertEquals($data, $toArray); + } + + public function testDeterminesIfHasParam() + { + $command = $this->getTestCommand(); + $this->assertTrue($command->hasParam('data')); + $this->assertFalse($command->hasParam('baz')); + } + + public function testReturnsParamNames() + { + $command = $this->getTestCommand(); + $this->assertEquals(array('data'), $command->getParamNames()); + } + + protected function getTestCommand() + { + return new Operation(array( + 'parameters' => array( + 'data' => new Parameter(array( + 'type' => 'string' + )) + ) + )); + } + + public function testCanBuildUpCommands() + { + $c = new Operation(array()); + $c->setName('foo') + ->setClass('Baz') + ->setDeprecated(false) + ->setSummary('summary') + ->setDocumentationUrl('http://www.foo.com') + ->setHttpMethod('PUT') + ->setResponseNotes('oh') + ->setResponseClass('string') + ->setUri('/foo/bar') + ->addParam(new Parameter(array( + 'name' => 'test' + ))); + + $this->assertEquals('foo', $c->getName()); + $this->assertEquals('Baz', $c->getClass()); + $this->assertEquals(false, $c->getDeprecated()); + $this->assertEquals('summary', $c->getSummary()); + $this->assertEquals('http://www.foo.com', $c->getDocumentationUrl()); + $this->assertEquals('PUT', $c->getHttpMethod()); + $this->assertEquals('oh', $c->getResponseNotes()); + $this->assertEquals('string', $c->getResponseClass()); + $this->assertEquals('/foo/bar', $c->getUri()); + $this->assertEquals(array('test'), $c->getParamNames()); + } + + public function testCanRemoveParams() + { + $c = new Operation(array()); + $c->addParam(new Parameter(array('name' => 'foo'))); + $this->assertTrue($c->hasParam('foo')); + $c->removeParam('foo'); + $this->assertFalse($c->hasParam('foo')); + } + + public function testAddsNameToParametersIfNeeded() + { + $command = new Operation(array('parameters' => array('foo' => new Parameter(array())))); + $this->assertEquals('foo', $command->getParam('foo')->getName()); + } + + public function testContainsApiErrorInformation() + { + $command = $this->getOperation(); + $this->assertEquals(1, count($command->getErrorResponses())); + $arr = $command->toArray(); + $this->assertEquals(1, count($arr['errorResponses'])); + $command->addErrorResponse(400, 'Foo', 'Baz\\Bar'); + $this->assertEquals(2, count($command->getErrorResponses())); + $command->setErrorResponses(array()); + $this->assertEquals(0, count($command->getErrorResponses())); + } + + public function testHasNotes() + { + $o = new Operation(array('notes' => 'foo')); + $this->assertEquals('foo', $o->getNotes()); + $o->setNotes('bar'); + $this->assertEquals('bar', $o->getNotes()); + } + + public function testHasData() + { + $o = new Operation(array('data' => array('foo' => 'baz', 'bar' => 123))); + $o->setData('test', false); + $this->assertEquals('baz', $o->getData('foo')); + $this->assertEquals(123, $o->getData('bar')); + $this->assertNull($o->getData('wfefwe')); + $this->assertEquals(array( + 'parameters' => array(), + 'class' => 'Guzzle\Service\Command\OperationCommand', + 'data' => array('foo' => 'baz', 'bar' => 123, 'test' => false), + 'responseClass' => 'array', + 'responseType' => 'primitive' + ), $o->toArray()); + } + + public function testHasServiceDescription() + { + $s = new ServiceDescription(); + $o = new Operation(array(), $s); + $this->assertSame($s, $o->getServiceDescription()); + } + + /** + * @expectedException Guzzle\Common\Exception\InvalidArgumentException + */ + public function testValidatesResponseType() + { + $o = new Operation(array('responseClass' => 'array', 'responseType' => 'foo')); + } + + public function testInfersResponseType() + { + $o = $this->getOperation(); + $o->setServiceDescription(new ServiceDescription(array('models' => array('Foo' => array())))); + $this->assertEquals('primitive', $o->getResponseType()); + $this->assertEquals('primitive', $o->setResponseClass('boolean')->getResponseType()); + $this->assertEquals('primitive', $o->setResponseClass('array')->getResponseType()); + $this->assertEquals('primitive', $o->setResponseClass('integer')->getResponseType()); + $this->assertEquals('primitive', $o->setResponseClass('string')->getResponseType()); + $this->assertEquals('class', $o->setResponseClass('foo')->getResponseType()); + $this->assertEquals('class', $o->setResponseClass(__CLASS__)->getResponseType()); + $this->assertEquals('model', $o->setResponseClass('Foo')->getResponseType()); + } + + public function testHasResponseType() + { + // infers in the constructor + $o = new Operation(array('responseClass' => 'array')); + $this->assertEquals('primitive', $o->getResponseType()); + // Infers when set + $o = new Operation(); + $this->assertEquals('primitive', $o->getResponseType()); + $this->assertEquals('model', $o->setResponseType('model')->getResponseType()); + } + + public function testHasAdditionalParameters() + { + $o = new Operation(array( + 'additionalParameters' => array( + 'type' => 'string', 'name' => 'binks' + ), + 'parameters' => array( + 'foo' => array('type' => 'integer') + ) + )); + $this->assertEquals('string', $o->getAdditionalParameters()->getType()); + $arr = $o->toArray(); + $this->assertEquals(array( + 'type' => 'string' + ), $arr['additionalParameters']); + } + + /** + * @return Operation + */ + protected function getOperation() + { + return new Operation(array( + 'name' => 'OperationTest', + 'class' => get_class($this), + 'parameters' => array( + 'test' => array('type' => 'object'), + 'bool_1' => array('default' => true, 'type' => 'boolean'), + 'bool_2' => array('default' => false), + 'float' => array('type' => 'numeric'), + 'int' => array('type' => 'integer'), + 'date' => array('type' => 'string'), + 'timestamp' => array('type' => 'string'), + 'string' => array('type' => 'string'), + 'username' => array('type' => 'string', 'required' => true, 'filters' => 'strtolower'), + 'test_function' => array('type' => 'string', 'filters' => __CLASS__ . '::strtoupper') + ), + 'errorResponses' => array( + array('code' => 503, 'reason' => 'InsufficientCapacity', 'class' => 'Guzzle\\Exception\\RuntimeException') + ) + )); + } +} diff --git a/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Description/ParameterTest.php b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Description/ParameterTest.php new file mode 100644 index 0000000..b9c162a --- /dev/null +++ b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Description/ParameterTest.php @@ -0,0 +1,411 @@ + 'foo', + 'type' => 'bar', + 'required' => true, + 'default' => '123', + 'description' => '456', + 'minLength' => 2, + 'maxLength' => 5, + 'location' => 'body', + 'static' => 'static!', + 'filters' => array('trim', 'json_encode') + ); + + public function testCreatesParamFromArray() + { + $p = new Parameter($this->data); + $this->assertEquals('foo', $p->getName()); + $this->assertEquals('bar', $p->getType()); + $this->assertEquals(true, $p->getRequired()); + $this->assertEquals('123', $p->getDefault()); + $this->assertEquals('456', $p->getDescription()); + $this->assertEquals(2, $p->getMinLength()); + $this->assertEquals(5, $p->getMaxLength()); + $this->assertEquals('body', $p->getLocation()); + $this->assertEquals('static!', $p->getStatic()); + $this->assertEquals(array('trim', 'json_encode'), $p->getFilters()); + } + + public function testCanConvertToArray() + { + $p = new Parameter($this->data); + unset($this->data['name']); + $this->assertEquals($this->data, $p->toArray()); + } + + public function testUsesStatic() + { + $d = $this->data; + $d['default'] = 'booboo'; + $d['static'] = true; + $p = new Parameter($d); + $this->assertEquals('booboo', $p->getValue('bar')); + } + + public function testUsesDefault() + { + $d = $this->data; + $d['default'] = 'foo'; + $d['static'] = null; + $p = new Parameter($d); + $this->assertEquals('foo', $p->getValue(null)); + } + + public function testReturnsYourValue() + { + $d = $this->data; + $d['static'] = null; + $p = new Parameter($d); + $this->assertEquals('foo', $p->getValue('foo')); + } + + public function testZeroValueDoesNotCauseDefaultToBeReturned() + { + $d = $this->data; + $d['default'] = '1'; + $d['static'] = null; + $p = new Parameter($d); + $this->assertEquals('0', $p->getValue('0')); + } + + public function testFiltersValues() + { + $d = $this->data; + $d['static'] = null; + $d['filters'] = 'strtoupper'; + $p = new Parameter($d); + $this->assertEquals('FOO', $p->filter('foo')); + } + + public function testConvertsBooleans() + { + $p = new Parameter(array('type' => 'boolean')); + $this->assertEquals(true, $p->filter('true')); + $this->assertEquals(false, $p->filter('false')); + } + + public function testUsesArrayByDefaultForFilters() + { + $d = $this->data; + $d['filters'] = null; + $p = new Parameter($d); + $this->assertEquals(array(), $p->getFilters()); + } + + public function testAllowsSimpleLocationValue() + { + $p = new Parameter(array('name' => 'myname', 'location' => 'foo', 'sentAs' => 'Hello')); + $this->assertEquals('foo', $p->getLocation()); + $this->assertEquals('Hello', $p->getSentAs()); + } + + public function testParsesTypeValues() + { + $p = new Parameter(array('type' => 'foo')); + $this->assertEquals('foo', $p->getType()); + } + + /** + * @expectedException InvalidArgumentException + * @expectedExceptionMessage A [method] value must be specified for each complex filter + */ + public function testValidatesComplexFilters() + { + $p = new Parameter(array('filters' => array(array('args' => 'foo')))); + } + + public function testCanBuildUpParams() + { + $p = new Parameter(array()); + $p->setName('foo') + ->setDescription('c') + ->setFilters(array('d')) + ->setLocation('e') + ->setSentAs('f') + ->setMaxLength(1) + ->setMinLength(1) + ->setMinimum(2) + ->setMaximum(2) + ->setMinItems(3) + ->setMaxItems(3) + ->setRequired(true) + ->setStatic(true) + ->setDefault('h') + ->setType('i'); + + $p->addFilter('foo'); + + $this->assertEquals('foo', $p->getName()); + $this->assertEquals('h', $p->getDefault()); + $this->assertEquals('c', $p->getDescription()); + $this->assertEquals(array('d', 'foo'), $p->getFilters()); + $this->assertEquals('e', $p->getLocation()); + $this->assertEquals('f', $p->getSentAs()); + $this->assertEquals(1, $p->getMaxLength()); + $this->assertEquals(1, $p->getMinLength()); + $this->assertEquals(2, $p->getMaximum()); + $this->assertEquals(2, $p->getMinimum()); + $this->assertEquals(3, $p->getMaxItems()); + $this->assertEquals(3, $p->getMinItems()); + $this->assertEquals(true, $p->getRequired()); + $this->assertEquals(true, $p->getStatic()); + $this->assertEquals('i', $p->getType()); + } + + public function testAllowsNestedShape() + { + $command = $this->getServiceBuilder()->get('mock')->getCommand('mock_command')->getOperation(); + $param = new Parameter(array( + 'parent' => $command, + 'name' => 'foo', + 'type' => 'object', + 'location' => 'query', + 'properties' => array( + 'foo' => array( + 'type' => 'object', + 'required' => true, + 'properties' => array( + 'baz' => array( + 'name' => 'baz', + 'type' => 'bool', + ) + ) + ), + 'bar' => array( + 'name' => 'bar', + 'default' => '123' + ) + ) + )); + + $this->assertSame($command, $param->getParent()); + $this->assertNotEmpty($param->getProperties()); + $this->assertInstanceOf('Guzzle\Service\Description\Parameter', $param->getProperty('foo')); + $this->assertSame($param, $param->getProperty('foo')->getParent()); + $this->assertSame($param->getProperty('foo'), $param->getProperty('foo')->getProperty('baz')->getParent()); + $this->assertInstanceOf('Guzzle\Service\Description\Parameter', $param->getProperty('bar')); + $this->assertSame($param, $param->getProperty('bar')->getParent()); + + $array = $param->toArray(); + $this->assertInternalType('array', $array['properties']); + $this->assertArrayHasKey('foo', $array['properties']); + $this->assertArrayHasKey('bar', $array['properties']); + } + + public function testAllowsComplexFilters() + { + $that = $this; + $param = new Parameter(array()); + $param->setFilters(array(array('method' => function ($a, $b, $c, $d) use ($that, $param) { + $that->assertEquals('test', $a); + $that->assertEquals('my_value!', $b); + $that->assertEquals('bar', $c); + $that->assertSame($param, $d); + return 'abc' . $b; + }, 'args' => array('test', '@value', 'bar', '@api')))); + $this->assertEquals('abcmy_value!', $param->filter('my_value!')); + } + + public function testCanChangeParentOfNestedParameter() + { + $param1 = new Parameter(array('name' => 'parent')); + $param2 = new Parameter(array('name' => 'child')); + $param2->setParent($param1); + $this->assertSame($param1, $param2->getParent()); + } + + public function testCanRemoveFromNestedStructure() + { + $param1 = new Parameter(array('name' => 'parent')); + $param2 = new Parameter(array('name' => 'child')); + $param1->addProperty($param2); + $this->assertSame($param1, $param2->getParent()); + $this->assertSame($param2, $param1->getProperty('child')); + + // Remove a single child from the structure + $param1->removeProperty('child'); + $this->assertNull($param1->getProperty('child')); + // Remove the entire structure + $param1->addProperty($param2); + $param1->removeProperty('child'); + $this->assertNull($param1->getProperty('child')); + } + + public function testAddsAdditionalProperties() + { + $p = new Parameter(array( + 'type' => 'object', + 'additionalProperties' => array('type' => 'string') + )); + $this->assertInstanceOf('Guzzle\Service\Description\Parameter', $p->getAdditionalProperties()); + $this->assertNull($p->getAdditionalProperties()->getAdditionalProperties()); + $p = new Parameter(array('type' => 'object')); + $this->assertTrue($p->getAdditionalProperties()); + } + + public function testAddsItems() + { + $p = new Parameter(array( + 'type' => 'array', + 'items' => array('type' => 'string') + )); + $this->assertInstanceOf('Guzzle\Service\Description\Parameter', $p->getItems()); + $out = $p->toArray(); + $this->assertEquals('array', $out['type']); + $this->assertInternalType('array', $out['items']); + } + + public function testHasExtraProperties() + { + $p = new Parameter(); + $this->assertEquals(array(), $p->getData()); + $p->setData(array('foo' => 'bar')); + $this->assertEquals('bar', $p->getData('foo')); + $p->setData('baz', 'boo'); + $this->assertEquals(array('foo' => 'bar', 'baz' => 'boo'), $p->getData()); + } + + public function testCanRetrieveKnownPropertiesUsingDataMethod() + { + $p = new Parameter(); + $this->assertEquals(null, $p->getData('foo')); + $p->setName('test'); + $this->assertEquals('test', $p->getData('name')); + } + + public function testHasInstanceOf() + { + $p = new Parameter(); + $this->assertNull($p->getInstanceOf()); + $p->setInstanceOf('Foo'); + $this->assertEquals('Foo', $p->getInstanceOf()); + } + + public function testHasPattern() + { + $p = new Parameter(); + $this->assertNull($p->getPattern()); + $p->setPattern('/[0-9]+/'); + $this->assertEquals('/[0-9]+/', $p->getPattern()); + } + + public function testHasEnum() + { + $p = new Parameter(); + $this->assertNull($p->getEnum()); + $p->setEnum(array('foo', 'bar')); + $this->assertEquals(array('foo', 'bar'), $p->getEnum()); + } + + public function testSerializesItems() + { + $p = new Parameter(array( + 'type' => 'object', + 'additionalProperties' => array('type' => 'string') + )); + $this->assertEquals(array( + 'type' => 'object', + 'additionalProperties' => array('type' => 'string') + ), $p->toArray()); + } + + public function testResolvesRefKeysRecursively() + { + $description = new ServiceDescription(array( + 'models' => array( + 'JarJar' => array('type' => 'string', 'default' => 'Mesa address tha senate!'), + 'Anakin' => array('type' => 'array', 'items' => array('$ref' => 'JarJar')) + ) + )); + $p = new Parameter(array('$ref' => 'Anakin', 'description' => 'added'), $description); + $this->assertEquals(array( + 'type' => 'array', + 'items' => array('type' => 'string', 'default' => 'Mesa address tha senate!'), + 'description' => 'added' + ), $p->toArray()); + } + + public function testResolvesExtendsRecursively() + { + $jarJar = array('type' => 'string', 'default' => 'Mesa address tha senate!', 'description' => 'a'); + $anakin = array('type' => 'array', 'items' => array('extends' => 'JarJar', 'description' => 'b')); + $description = new ServiceDescription(array( + 'models' => array('JarJar' => $jarJar, 'Anakin' => $anakin) + )); + // Description attribute will be updated, and format added + $p = new Parameter(array('extends' => 'Anakin', 'format' => 'date'), $description); + $this->assertEquals(array( + 'type' => 'array', + 'format' => 'date', + 'items' => array( + 'type' => 'string', + 'default' => 'Mesa address tha senate!', + 'description' => 'b' + ) + ), $p->toArray()); + } + + public function testHasKeyMethod() + { + $p = new Parameter(array('name' => 'foo', 'sentAs' => 'bar')); + $this->assertEquals('bar', $p->getWireName()); + $p->setSentAs(null); + $this->assertEquals('foo', $p->getWireName()); + } + + public function testIncludesNameInToArrayWhenItemsAttributeHasName() + { + $p = new Parameter(array( + 'type' => 'array', + 'name' => 'Abc', + 'items' => array( + 'name' => 'Foo', + 'type' => 'object' + ) + )); + $result = $p->toArray(); + $this->assertEquals(array( + 'type' => 'array', + 'items' => array( + 'name' => 'Foo', + 'type' => 'object', + 'additionalProperties' => true + ) + ), $result); + } + + public function dateTimeProvider() + { + $d = 'October 13, 2012 16:15:46 UTC'; + + return array( + array($d, 'date-time', '2012-10-13T16:15:46Z'), + array($d, 'date', '2012-10-13'), + array($d, 'timestamp', strtotime($d)), + array(new \DateTime($d), 'timestamp', strtotime($d)) + ); + } + + /** + * @dataProvider dateTimeProvider + */ + public function testAppliesFormat($d, $format, $result) + { + $p = new Parameter(); + $p->setFormat($format); + $this->assertEquals($format, $p->getFormat()); + $this->assertEquals($result, $p->filter($d)); + } +} diff --git a/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Description/SchemaFormatterTest.php b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Description/SchemaFormatterTest.php new file mode 100644 index 0000000..eb3619b --- /dev/null +++ b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Description/SchemaFormatterTest.php @@ -0,0 +1,61 @@ +assertEquals($result, SchemaFormatter::format($format, $value)); + } + + /** + * @expectedException \Guzzle\Common\Exception\InvalidArgumentException + */ + public function testValidatesDateTimeInput() + { + SchemaFormatter::format('date-time', false); + } + + public function testEnsuresTimestampsAreIntegers() + { + $t = time(); + $result = SchemaFormatter::format('timestamp', $t); + $this->assertSame($t, $result); + $this->assertInternalType('int', $result); + } +} diff --git a/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Description/SchemaValidatorTest.php b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Description/SchemaValidatorTest.php new file mode 100644 index 0000000..4d6cc87 --- /dev/null +++ b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Description/SchemaValidatorTest.php @@ -0,0 +1,326 @@ +validator = new SchemaValidator(); + } + + public function testValidatesArrayListsAreNumericallyIndexed() + { + $value = array(array(1)); + $this->assertFalse($this->validator->validate($this->getComplexParam(), $value)); + $this->assertEquals( + array('[Foo][0] must be an array of properties. Got a numerically indexed array.'), + $this->validator->getErrors() + ); + } + + public function testValidatesArrayListsContainProperItems() + { + $value = array(true); + $this->assertFalse($this->validator->validate($this->getComplexParam(), $value)); + $this->assertEquals( + array('[Foo][0] must be of type object'), + $this->validator->getErrors() + ); + } + + public function testAddsDefaultValuesInLists() + { + $value = array(array()); + $this->assertTrue($this->validator->validate($this->getComplexParam(), $value)); + $this->assertEquals(array(array('Bar' => true)), $value); + } + + public function testMergesDefaultValuesInLists() + { + $value = array( + array('Baz' => 'hello!'), + array('Bar' => false) + ); + $this->assertTrue($this->validator->validate($this->getComplexParam(), $value)); + $this->assertEquals(array( + array( + 'Baz' => 'hello!', + 'Bar' => true + ), + array('Bar' => false) + ), $value); + } + + public function testCorrectlyConvertsParametersToArrayWhenArraysArePresent() + { + $param = $this->getComplexParam(); + $result = $param->toArray(); + $this->assertInternalType('array', $result['items']); + $this->assertEquals('array', $result['type']); + $this->assertInstanceOf('Guzzle\Service\Description\Parameter', $param->getItems()); + } + + public function testAllowsInstanceOf() + { + $p = new Parameter(array( + 'name' => 'foo', + 'type' => 'object', + 'instanceOf' => get_class($this) + )); + $this->assertTrue($this->validator->validate($p, $this)); + $this->assertFalse($this->validator->validate($p, $p)); + $this->assertEquals(array('[foo] must be an instance of ' . __CLASS__), $this->validator->getErrors()); + } + + public function testEnforcesInstanceOfOnlyWhenObject() + { + $p = new Parameter(array( + 'name' => 'foo', + 'type' => array('object', 'string'), + 'instanceOf' => get_class($this) + )); + $this->assertTrue($this->validator->validate($p, $this)); + $s = 'test'; + $this->assertTrue($this->validator->validate($p, $s)); + } + + public function testConvertsObjectsToArraysWhenToArrayInterface() + { + $o = $this->getMockBuilder('Guzzle\Common\ToArrayInterface') + ->setMethods(array('toArray')) + ->getMockForAbstractClass(); + $o->expects($this->once()) + ->method('toArray') + ->will($this->returnValue(array( + 'foo' => 'bar' + ))); + $p = new Parameter(array( + 'name' => 'test', + 'type' => 'object', + 'properties' => array( + 'foo' => array('required' => 'true') + ) + )); + $this->assertTrue($this->validator->validate($p, $o)); + } + + public function testMergesValidationErrorsInPropertiesWithParent() + { + $p = new Parameter(array( + 'name' => 'foo', + 'type' => 'object', + 'properties' => array( + 'bar' => array('type' => 'string', 'required' => true, 'description' => 'This is what it does'), + 'test' => array('type' => 'string', 'minLength' => 2, 'maxLength' => 5), + 'test2' => array('type' => 'string', 'minLength' => 2, 'maxLength' => 2), + 'test3' => array('type' => 'integer', 'minimum' => 100), + 'test4' => array('type' => 'integer', 'maximum' => 10), + 'test5' => array('type' => 'array', 'maxItems' => 2), + 'test6' => array('type' => 'string', 'enum' => array('a', 'bc')), + 'test7' => array('type' => 'string', 'pattern' => '/[0-9]+/'), + 'test8' => array('type' => 'number'), + 'baz' => array( + 'type' => 'array', + 'minItems' => 2, + 'required' => true, + "items" => array("type" => "string") + ) + ) + )); + + $value = array( + 'test' => 'a', + 'test2' => 'abc', + 'baz' => array(false), + 'test3' => 10, + 'test4' => 100, + 'test5' => array(1, 3, 4), + 'test6' => 'Foo', + 'test7' => 'abc', + 'test8' => 'abc' + ); + + $this->assertFalse($this->validator->validate($p, $value)); + $this->assertEquals(array ( + '[foo][bar] is a required string: This is what it does', + '[foo][baz] must contain 2 or more elements', + '[foo][baz][0] must be of type string', + '[foo][test2] length must be less than or equal to 2', + '[foo][test3] must be greater than or equal to 100', + '[foo][test4] must be less than or equal to 10', + '[foo][test5] must contain 2 or fewer elements', + '[foo][test6] must be one of "a" or "bc"', + '[foo][test7] must match the following regular expression: /[0-9]+/', + '[foo][test8] must be of type number', + '[foo][test] length must be greater than or equal to 2', + ), $this->validator->getErrors()); + } + + public function testHandlesNullValuesInArraysWithDefaults() + { + $p = new Parameter(array( + 'name' => 'foo', + 'type' => 'object', + 'required' => true, + 'properties' => array( + 'bar' => array( + 'type' => 'object', + 'required' => true, + 'properties' => array( + 'foo' => array('default' => 'hi') + ) + ) + ) + )); + $value = array(); + $this->assertTrue($this->validator->validate($p, $value)); + $this->assertEquals(array('bar' => array('foo' => 'hi')), $value); + } + + public function testFailsWhenNullValuesInArraysWithNoDefaults() + { + $p = new Parameter(array( + 'name' => 'foo', + 'type' => 'object', + 'required' => true, + 'properties' => array( + 'bar' => array( + 'type' => 'object', + 'required' => true, + 'properties' => array('foo' => array('type' => 'string')) + ) + ) + )); + $value = array(); + $this->assertFalse($this->validator->validate($p, $value)); + $this->assertEquals(array('[foo][bar] is a required object'), $this->validator->getErrors()); + } + + public function testChecksTypes() + { + $p = new SchemaValidator(); + $r = new \ReflectionMethod($p, 'determineType'); + $r->setAccessible(true); + $this->assertEquals('any', $r->invoke($p, 'any', 'hello')); + $this->assertEquals(false, $r->invoke($p, 'foo', 'foo')); + $this->assertEquals('string', $r->invoke($p, 'string', 'hello')); + $this->assertEquals(false, $r->invoke($p, 'string', false)); + $this->assertEquals('integer', $r->invoke($p, 'integer', 1)); + $this->assertEquals(false, $r->invoke($p, 'integer', 'abc')); + $this->assertEquals('numeric', $r->invoke($p, 'numeric', 1)); + $this->assertEquals('numeric', $r->invoke($p, 'numeric', '1')); + $this->assertEquals('number', $r->invoke($p, 'number', 1)); + $this->assertEquals('number', $r->invoke($p, 'number', '1')); + $this->assertEquals(false, $r->invoke($p, 'numeric', 'a')); + $this->assertEquals('boolean', $r->invoke($p, 'boolean', true)); + $this->assertEquals('boolean', $r->invoke($p, 'boolean', false)); + $this->assertEquals(false, $r->invoke($p, 'boolean', 'false')); + $this->assertEquals('null', $r->invoke($p, 'null', null)); + $this->assertEquals(false, $r->invoke($p, 'null', 'abc')); + $this->assertEquals('array', $r->invoke($p, 'array', array())); + $this->assertEquals(false, $r->invoke($p, 'array', 'foo')); + } + + public function testValidatesFalseAdditionalProperties() + { + $param = new Parameter(array( + 'name' => 'foo', + 'type' => 'object', + 'properties' => array('bar' => array('type' => 'string')), + 'additionalProperties' => false + )); + $value = array('test' => '123'); + $this->assertFalse($this->validator->validate($param, $value)); + $this->assertEquals(array('[foo][test] is not an allowed property'), $this->validator->getErrors()); + $value = array('bar' => '123'); + $this->assertTrue($this->validator->validate($param, $value)); + } + + public function testAllowsUndefinedAdditionalProperties() + { + $param = new Parameter(array( + 'name' => 'foo', + 'type' => 'object', + 'properties' => array('bar' => array('type' => 'string')) + )); + $value = array('test' => '123'); + $this->assertTrue($this->validator->validate($param, $value)); + } + + public function testValidatesAdditionalProperties() + { + $param = new Parameter(array( + 'name' => 'foo', + 'type' => 'object', + 'properties' => array('bar' => array('type' => 'string')), + 'additionalProperties' => array('type' => 'integer') + )); + $value = array('test' => 'foo'); + $this->assertFalse($this->validator->validate($param, $value)); + $this->assertEquals(array('[foo][test] must be of type integer'), $this->validator->getErrors()); + } + + public function testValidatesAdditionalPropertiesThatArrayArrays() + { + $param = new Parameter(array( + 'name' => 'foo', + 'type' => 'object', + 'additionalProperties' => array( + 'type' => 'array', + 'items' => array('type' => 'string') + ) + )); + $value = array('test' => array(true)); + $this->assertFalse($this->validator->validate($param, $value)); + $this->assertEquals(array('[foo][test][0] must be of type string'), $this->validator->getErrors()); + } + + public function testIntegersCastToStringWhenTypeMismatch() + { + $param = new Parameter(array('name' => 'test', 'type' => 'string')); + $value = 12; + $this->assertTrue($this->validator->validate($param, $value)); + $this->assertEquals('12', $value); + } + + public function testRequiredMessageIncludesType() + { + $param = new Parameter(array('name' => 'test', 'type' => array('string', 'boolean'), 'required' => true)); + $value = null; + $this->assertFalse($this->validator->validate($param, $value)); + $this->assertEquals(array('[test] is a required string or boolean'), $this->validator->getErrors()); + } + + protected function getComplexParam() + { + return new Parameter(array( + 'name' => 'Foo', + 'type' => 'array', + 'required' => true, + 'min' => 1, + 'items' => array( + 'type' => 'object', + 'properties' => array( + 'Baz' => array( + 'type' => 'string', + ), + 'Bar' => array( + 'required' => true, + 'type' => 'boolean', + 'default' => true + ) + ) + ) + )); + } +} diff --git a/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Description/ServiceDescriptionLoaderTest.php b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Description/ServiceDescriptionLoaderTest.php new file mode 100644 index 0000000..bbfd1d6 --- /dev/null +++ b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Description/ServiceDescriptionLoaderTest.php @@ -0,0 +1,177 @@ + true, + 'baz' => array('bar'), + 'apiVersion' => '123', + 'operations' => array() + )); + + $this->assertEquals(true, $d->getData('foo')); + $this->assertEquals(array('bar'), $d->getData('baz')); + $this->assertEquals('123', $d->getApiVersion()); + } + + public function testAllowsDeepNestedInheritance() + { + $d = ServiceDescription::factory(array( + 'operations' => array( + 'abstract' => array( + 'httpMethod' => 'HEAD', + 'parameters' => array( + 'test' => array('type' => 'string', 'required' => true) + ) + ), + 'abstract2' => array('uri' => '/test', 'extends' => 'abstract'), + 'concrete' => array('extends' => 'abstract2'), + 'override' => array('extends' => 'abstract', 'httpMethod' => 'PUT'), + 'override2' => array('extends' => 'override', 'httpMethod' => 'POST', 'uri' => '/') + ) + )); + + $c = $d->getOperation('concrete'); + $this->assertEquals('/test', $c->getUri()); + $this->assertEquals('HEAD', $c->getHttpMethod()); + $params = $c->getParams(); + $param = $params['test']; + $this->assertEquals('string', $param->getType()); + $this->assertTrue($param->getRequired()); + + // Ensure that merging HTTP method does not make an array + $this->assertEquals('PUT', $d->getOperation('override')->getHttpMethod()); + $this->assertEquals('POST', $d->getOperation('override2')->getHttpMethod()); + $this->assertEquals('/', $d->getOperation('override2')->getUri()); + } + + /** + * @expectedException RuntimeException + */ + public function testThrowsExceptionWhenExtendingMissingCommand() + { + ServiceDescription::factory(array( + 'operations' => array( + 'concrete' => array( + 'extends' => 'missing' + ) + ) + )); + } + + public function testAllowsMultipleInheritance() + { + $description = ServiceDescription::factory(array( + 'operations' => array( + 'a' => array( + 'httpMethod' => 'GET', + 'parameters' => array( + 'a1' => array( + 'default' => 'foo', + 'required' => true, + 'prepend' => 'hi' + ) + ) + ), + 'b' => array( + 'extends' => 'a', + 'parameters' => array( + 'b2' => array() + ) + ), + 'c' => array( + 'parameters' => array( + 'a1' => array( + 'default' => 'bar', + 'required' => true, + 'description' => 'test' + ), + 'c3' => array() + ) + ), + 'd' => array( + 'httpMethod' => 'DELETE', + 'extends' => array('b', 'c'), + 'parameters' => array( + 'test' => array() + ) + ) + ) + )); + + $command = $description->getOperation('d'); + $this->assertEquals('DELETE', $command->getHttpMethod()); + $this->assertContains('a1', $command->getParamNames()); + $this->assertContains('b2', $command->getParamNames()); + $this->assertContains('c3', $command->getParamNames()); + $this->assertContains('test', $command->getParamNames()); + + $this->assertTrue($command->getParam('a1')->getRequired()); + $this->assertEquals('bar', $command->getParam('a1')->getDefault()); + $this->assertEquals('test', $command->getParam('a1')->getDescription()); + } + + public function testAddsOtherFields() + { + $description = ServiceDescription::factory(array( + 'operations' => array(), + 'description' => 'Foo', + 'apiVersion' => 'bar' + )); + $this->assertEquals('Foo', $description->getDescription()); + $this->assertEquals('bar', $description->getApiVersion()); + } + + public function testCanLoadNestedExtends() + { + $description = ServiceDescription::factory(array( + 'operations' => array( + 'root' => array( + 'class' => 'foo' + ), + 'foo' => array( + 'extends' => 'root', + 'parameters' => array( + 'baz' => array('type' => 'string') + ) + ), + 'foo_2' => array( + 'extends' => 'foo', + 'parameters' => array( + 'bar' => array('type' => 'string') + ) + ), + 'foo_3' => array( + 'class' => 'bar', + 'parameters' => array( + 'bar2' => array('type' => 'string') + ) + ), + 'foo_4' => array( + 'extends' => array('foo_2', 'foo_3'), + 'parameters' => array( + 'bar3' => array('type' => 'string') + ) + ) + ) + )); + + $this->assertTrue($description->hasOperation('foo_4')); + $foo4 = $description->getOperation('foo_4'); + $this->assertTrue($foo4->hasParam('baz')); + $this->assertTrue($foo4->hasParam('bar')); + $this->assertTrue($foo4->hasParam('bar2')); + $this->assertTrue($foo4->hasParam('bar3')); + $this->assertEquals('bar', $foo4->getClass()); + } +} diff --git a/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Description/ServiceDescriptionTest.php b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Description/ServiceDescriptionTest.php new file mode 100644 index 0000000..ff25452 --- /dev/null +++ b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Description/ServiceDescriptionTest.php @@ -0,0 +1,240 @@ +serviceData = array( + 'test_command' => new Operation(array( + 'name' => 'test_command', + 'description' => 'documentationForCommand', + 'httpMethod' => 'DELETE', + 'class' => 'Guzzle\\Tests\\Service\\Mock\\Command\\MockCommand', + 'parameters' => array( + 'bucket' => array('required' => true), + 'key' => array('required' => true) + ) + )) + ); + } + + /** + * @covers Guzzle\Service\Description\ServiceDescription::factory + * @covers Guzzle\Service\Description\ServiceDescriptionLoader::build + */ + public function testFactoryDelegatesToConcreteFactories() + { + $jsonFile = __DIR__ . '/../../TestData/test_service.json'; + $this->assertInstanceOf('Guzzle\Service\Description\ServiceDescription', ServiceDescription::factory($jsonFile)); + } + + public function testConstructor() + { + $service = new ServiceDescription(array('operations' => $this->serviceData)); + $this->assertEquals(1, count($service->getOperations())); + $this->assertFalse($service->hasOperation('foobar')); + $this->assertTrue($service->hasOperation('test_command')); + } + + public function testIsSerializable() + { + $service = new ServiceDescription(array('operations' => $this->serviceData)); + $data = serialize($service); + $d2 = unserialize($data); + $this->assertEquals(serialize($service), serialize($d2)); + } + + public function testSerializesParameters() + { + $service = new ServiceDescription(array( + 'operations' => array( + 'foo' => new Operation(array('parameters' => array('foo' => array('type' => 'string')))) + ) + )); + $serialized = serialize($service); + $this->assertContains('"parameters":{"foo":', $serialized); + $service = unserialize($serialized); + $this->assertTrue($service->getOperation('foo')->hasParam('foo')); + } + + public function testAllowsForJsonBasedArrayParamsFunctionalTest() + { + $description = new ServiceDescription(array( + 'operations' => array( + 'test' => new Operation(array( + 'httpMethod' => 'PUT', + 'parameters' => array( + 'data' => array( + 'required' => true, + 'filters' => 'json_encode', + 'location' => 'body' + ) + ) + )) + ) + )); + $client = new Client(); + $client->setDescription($description); + $command = $client->getCommand('test', array( + 'data' => array( + 'foo' => 'bar' + ) + )); + + $request = $command->prepare(); + $this->assertEquals('{"foo":"bar"}', (string) $request->getBody()); + } + + public function testContainsModels() + { + $d = new ServiceDescription(array( + 'operations' => array('foo' => array()), + 'models' => array( + 'Tag' => array('type' => 'object'), + 'Person' => array('type' => 'object') + ) + )); + $this->assertTrue($d->hasModel('Tag')); + $this->assertTrue($d->hasModel('Person')); + $this->assertFalse($d->hasModel('Foo')); + $this->assertInstanceOf('Guzzle\Service\Description\Parameter', $d->getModel('Tag')); + $this->assertNull($d->getModel('Foo')); + $this->assertContains('"models":{', serialize($d)); + $this->assertEquals(array('Tag', 'Person'), array_keys($d->getModels())); + } + + public function testCanAddModels() + { + $d = new ServiceDescription(array()); + $this->assertFalse($d->hasModel('Foo')); + $d->addModel(new Parameter(array('name' => 'Foo'))); + $this->assertTrue($d->hasModel('Foo')); + } + + public function testHasAttributes() + { + $d = new ServiceDescription(array( + 'operations' => array(), + 'name' => 'Name', + 'description' => 'Description', + 'apiVersion' => '1.24' + )); + + $this->assertEquals('Name', $d->getName()); + $this->assertEquals('Description', $d->getDescription()); + $this->assertEquals('1.24', $d->getApiVersion()); + + $s = serialize($d); + $this->assertContains('"name":"Name"', $s); + $this->assertContains('"description":"Description"', $s); + $this->assertContains('"apiVersion":"1.24"', $s); + + $d = unserialize($s); + $this->assertEquals('Name', $d->getName()); + $this->assertEquals('Description', $d->getDescription()); + $this->assertEquals('1.24', $d->getApiVersion()); + } + + public function testPersistsCustomAttributes() + { + $data = array( + 'operations' => array('foo' => array('class' => 'foo', 'parameters' => array())), + 'name' => 'Name', + 'description' => 'Test', + 'apiVersion' => '1.24', + 'auth' => 'foo', + 'keyParam' => 'bar' + ); + $d = new ServiceDescription($data); + $d->setData('hello', 'baz'); + $this->assertEquals('foo', $d->getData('auth')); + $this->assertEquals('baz', $d->getData('hello')); + $this->assertEquals('bar', $d->getData('keyParam')); + // responseClass and responseType are added by default + $data['operations']['foo']['responseClass'] = 'array'; + $data['operations']['foo']['responseType'] = 'primitive'; + $this->assertEquals($data + array('hello' => 'baz'), json_decode($d->serialize(), true)); + } + + public function testHasToArray() + { + $data = array( + 'operations' => array(), + 'name' => 'Name', + 'description' => 'Test' + ); + $d = new ServiceDescription($data); + $arr = $d->toArray(); + $this->assertEquals('Name', $arr['name']); + $this->assertEquals('Test', $arr['description']); + } + + public function testReturnsNullWhenRetrievingMissingOperation() + { + $s = new ServiceDescription(array()); + $this->assertNull($s->getOperation('foo')); + } + + public function testCanAddOperations() + { + $s = new ServiceDescription(array()); + $this->assertFalse($s->hasOperation('Foo')); + $s->addOperation(new Operation(array('name' => 'Foo'))); + $this->assertTrue($s->hasOperation('Foo')); + } + + /** + * @expectedException Guzzle\Common\Exception\InvalidArgumentException + */ + public function testValidatesOperationTypes() + { + $s = new ServiceDescription(array( + 'operations' => array('foo' => new \stdClass()) + )); + } + + public function testHasBaseUrl() + { + $description = new ServiceDescription(array('baseUrl' => 'http://foo.com')); + $this->assertEquals('http://foo.com', $description->getBaseUrl()); + $description->setBaseUrl('http://foobar.com'); + $this->assertEquals('http://foobar.com', $description->getBaseUrl()); + } + + public function testCanUseBasePath() + { + $description = new ServiceDescription(array('basePath' => 'http://foo.com')); + $this->assertEquals('http://foo.com', $description->getBaseUrl()); + } + + public function testModelsHaveNames() + { + $desc = array( + 'models' => array( + 'date' => array('type' => 'string'), + 'user'=> array( + 'type' => 'object', + 'properties' => array( + 'dob' => array('$ref' => 'date') + ) + ) + ) + ); + + $s = ServiceDescription::factory($desc); + $this->assertEquals('date', $s->getModel('date')->getName()); + $this->assertEquals('dob', $s->getModel('user')->getProperty('dob')->getName()); + } +} diff --git a/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Exception/CommandTransferExceptionTest.php b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Exception/CommandTransferExceptionTest.php new file mode 100644 index 0000000..be0d4ac --- /dev/null +++ b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Exception/CommandTransferExceptionTest.php @@ -0,0 +1,66 @@ +addSuccessfulCommand($c1)->addFailedCommand($c2); + $this->assertSame(array($c1), $e->getSuccessfulCommands()); + $this->assertSame(array($c2), $e->getFailedCommands()); + $this->assertSame(array($c1, $c2), $e->getAllCommands()); + } + + public function testConvertsMultiExceptionIntoCommandTransfer() + { + $r1 = new Request('GET', 'http://foo.com'); + $r2 = new Request('GET', 'http://foobaz.com'); + $e = new MultiTransferException('Test', 123); + $e->addSuccessfulRequest($r1)->addFailedRequest($r2); + $ce = CommandTransferException::fromMultiTransferException($e); + + $this->assertInstanceOf('Guzzle\Service\Exception\CommandTransferException', $ce); + $this->assertEquals('Test', $ce->getMessage()); + $this->assertEquals(123, $ce->getCode()); + $this->assertSame(array($r1), $ce->getSuccessfulRequests()); + $this->assertSame(array($r2), $ce->getFailedRequests()); + } + + public function testCanRetrieveExceptionForCommand() + { + $r1 = new Request('GET', 'http://foo.com'); + $e1 = new \Exception('foo'); + $c1 = $this->getMockBuilder('Guzzle\Tests\Service\Mock\Command\MockCommand') + ->setMethods(array('getRequest')) + ->getMock(); + $c1->expects($this->once())->method('getRequest')->will($this->returnValue($r1)); + + $e = new MultiTransferException('Test', 123); + $e->addFailedRequestWithException($r1, $e1); + $ce = CommandTransferException::fromMultiTransferException($e); + $ce->addFailedCommand($c1); + + $this->assertSame($e1, $ce->getExceptionForFailedCommand($c1)); + } + + public function testAddsNonRequestExceptions() + { + $e = new MultiTransferException(); + $e->add(new \Exception('bar')); + $e->addFailedRequestWithException(new Request('GET', 'http://www.foo.com'), new \Exception('foo')); + $ce = CommandTransferException::fromMultiTransferException($e); + $this->assertEquals(2, count($ce)); + } +} diff --git a/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Exception/InconsistentClientTransferExceptionTest.php b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Exception/InconsistentClientTransferExceptionTest.php new file mode 100644 index 0000000..6455295 --- /dev/null +++ b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Exception/InconsistentClientTransferExceptionTest.php @@ -0,0 +1,15 @@ +assertEquals($items, $e->getCommands()); + } +} diff --git a/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Exception/ValidationExceptionTest.php b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Exception/ValidationExceptionTest.php new file mode 100644 index 0000000..ef789d8 --- /dev/null +++ b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Exception/ValidationExceptionTest.php @@ -0,0 +1,17 @@ +setErrors($errors); + $this->assertEquals($errors, $e->getErrors()); + } +} diff --git a/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Mock/Command/IterableCommand.php b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Mock/Command/IterableCommand.php new file mode 100644 index 0000000..4ab423e --- /dev/null +++ b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Mock/Command/IterableCommand.php @@ -0,0 +1,31 @@ + 'iterable_command', + 'parameters' => array( + 'page_size' => array('type' => 'integer'), + 'next_token' => array('type' => 'string') + ) + )); + } + + protected function build() + { + $this->request = $this->client->createRequest('GET'); + + // Add the next token and page size query string values + $this->request->getQuery()->set('next_token', $this->get('next_token')); + + if ($this->get('page_size')) { + $this->request->getQuery()->set('page_size', $this->get('page_size')); + } + } +} diff --git a/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Mock/Command/MockCommand.php b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Mock/Command/MockCommand.php new file mode 100644 index 0000000..831a7e7 --- /dev/null +++ b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Mock/Command/MockCommand.php @@ -0,0 +1,32 @@ + get_called_class() == __CLASS__ ? 'mock_command' : 'sub.sub', + 'httpMethod' => 'POST', + 'parameters' => array( + 'test' => array( + 'default' => 123, + 'required' => true, + 'doc' => 'Test argument' + ), + '_internal' => array( + 'default' => 'abc' + ), + 'foo' => array('filters' => array('strtoupper')) + ) + )); + } + + protected function build() + { + $this->request = $this->client->createRequest(); + } +} diff --git a/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Mock/Command/OtherCommand.php b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Mock/Command/OtherCommand.php new file mode 100644 index 0000000..72ae1f6 --- /dev/null +++ b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Mock/Command/OtherCommand.php @@ -0,0 +1,30 @@ + 'other_command', + 'parameters' => array( + 'test' => array( + 'default' => '123', + 'required' => true, + 'doc' => 'Test argument' + ), + 'other' => array(), + 'arg' => array('type' => 'string'), + 'static' => array('static' => true, 'default' => 'this is static') + ) + )); + } + + protected function build() + { + $this->request = $this->client->getRequest('HEAD'); + } +} diff --git a/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Mock/Command/Sub/Sub.php b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Mock/Command/Sub/Sub.php new file mode 100644 index 0000000..d348480 --- /dev/null +++ b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Mock/Command/Sub/Sub.php @@ -0,0 +1,7 @@ + '{scheme}://127.0.0.1:8124/{api_version}/{subdomain}', + 'scheme' => 'http', + 'api_version' => 'v1' + ), array('username', 'password', 'subdomain')); + + return new self($config->get('base_url'), $config); + } +} diff --git a/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Mock/Model/MockCommandIterator.php b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Mock/Model/MockCommandIterator.php new file mode 100644 index 0000000..8faf412 --- /dev/null +++ b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Mock/Model/MockCommandIterator.php @@ -0,0 +1,42 @@ +nextToken) { + $this->command->set('next_token', $this->nextToken); + } + + $this->command->set('page_size', (int) $this->calculatePageSize()); + $this->command->execute(); + + $data = json_decode($this->command->getResponse()->getBody(true), true); + + $this->nextToken = $data['next_token']; + + return $data['resources']; + } + + public function next() + { + $this->calledNext++; + parent::next(); + } + + public function getResources() + { + return $this->resources; + } + + public function getIteratedCount() + { + return $this->iteratedCount; + } +} diff --git a/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Resource/CompositeResourceIteratorFactoryTest.php b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Resource/CompositeResourceIteratorFactoryTest.php new file mode 100644 index 0000000..41c2073 --- /dev/null +++ b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Resource/CompositeResourceIteratorFactoryTest.php @@ -0,0 +1,37 @@ +assertFalse($factory->canBuild($cmd)); + $factory->build($cmd); + } + + public function testBuildsResourceIterators() + { + $f1 = new ResourceIteratorClassFactory('Guzzle\Tests\Service\Mock\Model'); + $factory = new CompositeResourceIteratorFactory(array()); + $factory->addFactory($f1); + $command = new MockCommand(); + $iterator = $factory->build($command, array('client.namespace' => 'Guzzle\Tests\Service\Mock')); + $this->assertInstanceOf('Guzzle\Tests\Service\Mock\Model\MockCommandIterator', $iterator); + } +} diff --git a/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Resource/MapResourceIteratorFactoryTest.php b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Resource/MapResourceIteratorFactoryTest.php new file mode 100644 index 0000000..d166e92 --- /dev/null +++ b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Resource/MapResourceIteratorFactoryTest.php @@ -0,0 +1,40 @@ +build(new MockCommand()); + } + + public function testBuildsResourceIterators() + { + $factory = new MapResourceIteratorFactory(array( + 'mock_command' => 'Guzzle\Tests\Service\Mock\Model\MockCommandIterator' + )); + $iterator = $factory->build(new MockCommand()); + $this->assertInstanceOf('Guzzle\Tests\Service\Mock\Model\MockCommandIterator', $iterator); + } + + public function testUsesWildcardMappings() + { + $factory = new MapResourceIteratorFactory(array( + '*' => 'Guzzle\Tests\Service\Mock\Model\MockCommandIterator' + )); + $iterator = $factory->build(new MockCommand()); + $this->assertInstanceOf('Guzzle\Tests\Service\Mock\Model\MockCommandIterator', $iterator); + } +} diff --git a/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Resource/ModelTest.php b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Resource/ModelTest.php new file mode 100644 index 0000000..7214133 --- /dev/null +++ b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Resource/ModelTest.php @@ -0,0 +1,65 @@ + 'object')); + $model = new Model(array('foo' => 'bar'), $param); + $this->assertSame($param, $model->getStructure()); + $this->assertEquals('bar', $model->get('foo')); + $this->assertEquals('bar', $model['foo']); + } + + public function testCanBeUsedWithoutStructure() + { + $model = new Model(array( + 'Foo' => 'baz', + 'Bar' => array( + 'Boo' => 'Bam' + ) + )); + $transform = function ($key, $value) { + return ($value && is_array($value)) ? new Collection($value) : $value; + }; + $model = $model->map($transform); + $this->assertInstanceOf('Guzzle\Common\Collection', $model->getPath('Bar')); + } + + public function testAllowsFiltering() + { + $model = new Model(array( + 'Foo' => 'baz', + 'Bar' => 'a' + )); + $model = $model->filter(function ($i, $v) { + return $v[0] == 'a'; + }); + $this->assertEquals(array('Bar' => 'a'), $model->toArray()); + } + + public function testDoesNotIncludeEmptyStructureInString() + { + $model = new Model(array('Foo' => 'baz')); + $str = (string) $model; + $this->assertContains('Debug output of model', $str); + $this->assertNotContains('Model structure', $str); + } + + public function testDoesIncludeModelStructureInString() + { + $model = new Model(array('Foo' => 'baz'), new Parameter(array('name' => 'Foo'))); + $str = (string) $model; + $this->assertContains('Debug output of Foo model', $str); + $this->assertContains('Model structure', $str); + } +} diff --git a/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Resource/ResourceIteratorClassFactoryTest.php b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Resource/ResourceIteratorClassFactoryTest.php new file mode 100644 index 0000000..7b061b5 --- /dev/null +++ b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Resource/ResourceIteratorClassFactoryTest.php @@ -0,0 +1,41 @@ +registerNamespace('Baz'); + $command = new MockCommand(); + $factory->build($command); + } + + public function testBuildsResourceIterators() + { + $factory = new ResourceIteratorClassFactory('Guzzle\Tests\Service\Mock\Model'); + $command = new MockCommand(); + $iterator = $factory->build($command, array('client.namespace' => 'Guzzle\Tests\Service\Mock')); + $this->assertInstanceOf('Guzzle\Tests\Service\Mock\Model\MockCommandIterator', $iterator); + } + + public function testChecksIfCanBuild() + { + $factory = new ResourceIteratorClassFactory('Guzzle\Tests\Service'); + $this->assertFalse($factory->canBuild(new MockCommand())); + $factory = new ResourceIteratorClassFactory('Guzzle\Tests\Service\Mock\Model'); + $this->assertTrue($factory->canBuild(new MockCommand())); + } +} diff --git a/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Resource/ResourceIteratorTest.php b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Resource/ResourceIteratorTest.php new file mode 100644 index 0000000..573fb6d --- /dev/null +++ b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Resource/ResourceIteratorTest.php @@ -0,0 +1,184 @@ +assertInternalType('array', ResourceIterator::getAllEvents()); + } + + public function testConstructorConfiguresDefaults() + { + $ri = $this->getMockForAbstractClass('Guzzle\\Service\\Resource\\ResourceIterator', array( + $this->getServiceBuilder()->get('mock')->getCommand('iterable_command'), + array( + 'limit' => 10, + 'page_size' => 3 + ) + ), 'MockIterator'); + + $this->assertEquals(false, $ri->getNextToken()); + $this->assertEquals(false, $ri->current()); + } + + public function testSendsRequestsForNextSetOfResources() + { + // Queue up an array of responses for iterating + $this->getServer()->flush(); + $this->getServer()->enqueue(array( + "HTTP/1.1 200 OK\r\nContent-Length: 52\r\n\r\n{ \"next_token\": \"g\", \"resources\": [\"d\", \"e\", \"f\"] }", + "HTTP/1.1 200 OK\r\nContent-Length: 52\r\n\r\n{ \"next_token\": \"j\", \"resources\": [\"g\", \"h\", \"i\"] }", + "HTTP/1.1 200 OK\r\nContent-Length: 41\r\n\r\n{ \"next_token\": \"\", \"resources\": [\"j\"] }" + )); + + // Create a new resource iterator using the IterableCommand mock + $ri = new MockCommandIterator($this->getServiceBuilder()->get('mock')->getCommand('iterable_command'), array( + 'page_size' => 3 + )); + + // Ensure that no requests have been sent yet + $this->assertEquals(0, count($this->getServer()->getReceivedRequests(false))); + + //$this->assertEquals(array('d', 'e', 'f', 'g', 'h', 'i', 'j'), $ri->toArray()); + $ri->toArray(); + $requests = $this->getServer()->getReceivedRequests(true); + $this->assertEquals(3, count($requests)); + + $this->assertEquals(3, $requests[0]->getQuery()->get('page_size')); + $this->assertEquals(3, $requests[1]->getQuery()->get('page_size')); + $this->assertEquals(3, $requests[2]->getQuery()->get('page_size')); + + // Reset and resend + $this->getServer()->flush(); + $this->getServer()->enqueue(array( + "HTTP/1.1 200 OK\r\nContent-Length: 52\r\n\r\n{ \"next_token\": \"g\", \"resources\": [\"d\", \"e\", \"f\"] }", + "HTTP/1.1 200 OK\r\nContent-Length: 52\r\n\r\n{ \"next_token\": \"j\", \"resources\": [\"g\", \"h\", \"i\"] }", + "HTTP/1.1 200 OK\r\nContent-Length: 41\r\n\r\n{ \"next_token\": \"\", \"resources\": [\"j\"] }", + )); + + $d = array(); + foreach ($ri as $data) { + $d[] = $data; + } + $this->assertEquals(array('d', 'e', 'f', 'g', 'h', 'i', 'j'), $d); + } + + public function testCalculatesPageSize() + { + $this->getServer()->flush(); + $this->getServer()->enqueue(array( + "HTTP/1.1 200 OK\r\nContent-Length: 52\r\n\r\n{ \"next_token\": \"g\", \"resources\": [\"d\", \"e\", \"f\"] }", + "HTTP/1.1 200 OK\r\nContent-Length: 52\r\n\r\n{ \"next_token\": \"j\", \"resources\": [\"g\", \"h\", \"i\"] }", + "HTTP/1.1 200 OK\r\nContent-Length: 52\r\n\r\n{ \"next_token\": \"j\", \"resources\": [\"j\", \"k\"] }" + )); + + $ri = new MockCommandIterator($this->getServiceBuilder()->get('mock')->getCommand('iterable_command'), array( + 'page_size' => 3, + 'limit' => 7 + )); + + $this->assertEquals(array('d', 'e', 'f', 'g', 'h', 'i', 'j'), $ri->toArray()); + $requests = $this->getServer()->getReceivedRequests(true); + $this->assertEquals(3, count($requests)); + $this->assertEquals(3, $requests[0]->getQuery()->get('page_size')); + $this->assertEquals(3, $requests[1]->getQuery()->get('page_size')); + $this->assertEquals(1, $requests[2]->getQuery()->get('page_size')); + } + + public function testUseAsArray() + { + $this->getServer()->flush(); + $this->getServer()->enqueue(array( + "HTTP/1.1 200 OK\r\nContent-Length: 52\r\n\r\n{ \"next_token\": \"g\", \"resources\": [\"d\", \"e\", \"f\"] }", + "HTTP/1.1 200 OK\r\nContent-Length: 52\r\n\r\n{ \"next_token\": \"\", \"resources\": [\"g\", \"h\", \"i\"] }" + )); + + $ri = new MockCommandIterator($this->getServiceBuilder()->get('mock')->getCommand('iterable_command')); + + // Ensure that the key is never < 0 + $this->assertEquals(0, $ri->key()); + $this->assertEquals(0, count($ri)); + + // Ensure that the iterator can be used as KVP array + $data = array(); + foreach ($ri as $key => $value) { + $data[$key] = $value; + } + + // Ensure that the iterate is countable + $this->assertEquals(6, count($ri)); + $this->assertEquals(array('d', 'e', 'f', 'g', 'h', 'i'), $data); + } + + public function testBailsWhenSendReturnsNoResults() + { + $this->getServer()->flush(); + $this->getServer()->enqueue(array( + "HTTP/1.1 200 OK\r\n\r\n{ \"next_token\": \"g\", \"resources\": [\"d\", \"e\", \"f\"] }", + "HTTP/1.1 200 OK\r\n\r\n{ \"next_token\": \"\", \"resources\": [] }" + )); + + $ri = new MockCommandIterator($this->getServiceBuilder()->get('mock')->getCommand('iterable_command')); + + // Ensure that the iterator can be used as KVP array + $data = $ri->toArray(); + + // Ensure that the iterate is countable + $this->assertEquals(3, count($ri)); + $this->assertEquals(array('d', 'e', 'f'), $data); + + $this->assertEquals(2, $ri->getRequestCount()); + } + + public function testHoldsDataOptions() + { + $ri = new MockCommandIterator($this->getServiceBuilder()->get('mock')->getCommand('iterable_command')); + $this->assertNull($ri->get('foo')); + $this->assertSame($ri, $ri->set('foo', 'bar')); + $this->assertEquals('bar', $ri->get('foo')); + } + + public function testSettingLimitOrPageSizeClearsData() + { + $this->getServer()->flush(); + $this->getServer()->enqueue(array( + "HTTP/1.1 200 OK\r\n\r\n{ \"next_token\": \"\", \"resources\": [\"d\", \"e\", \"f\"] }", + "HTTP/1.1 200 OK\r\n\r\n{ \"next_token\": \"\", \"resources\": [\"d\", \"e\", \"f\"] }", + "HTTP/1.1 200 OK\r\n\r\n{ \"next_token\": \"\", \"resources\": [\"d\", \"e\", \"f\"] }" + )); + + $ri = new MockCommandIterator($this->getServiceBuilder()->get('mock')->getCommand('iterable_command')); + $ri->toArray(); + $this->assertNotEmpty($this->readAttribute($ri, 'resources')); + + $ri->setLimit(10); + $this->assertEmpty($this->readAttribute($ri, 'resources')); + + $ri->toArray(); + $this->assertNotEmpty($this->readAttribute($ri, 'resources')); + $ri->setPageSize(10); + $this->assertEmpty($this->readAttribute($ri, 'resources')); + } + + public function testWorksWithCustomAppendIterator() + { + $this->getServer()->flush(); + $this->getServer()->enqueue(array( + "HTTP/1.1 200 OK\r\n\r\n{ \"next_token\": \"\", \"resources\": [\"d\", \"e\", \"f\"] }" + )); + $ri = new MockCommandIterator($this->getServiceBuilder()->get('mock')->getCommand('iterable_command')); + $a = new \Guzzle\Iterator\AppendIterator(); + $a->append($ri); + $results = iterator_to_array($a, false); + $this->assertEquals(4, $ri->calledNext); + } +} diff --git a/vendor/guzzle/guzzle/tests/Guzzle/Tests/Stream/PhpStreamRequestFactoryTest.php b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Stream/PhpStreamRequestFactoryTest.php new file mode 100644 index 0000000..083aaa0 --- /dev/null +++ b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Stream/PhpStreamRequestFactoryTest.php @@ -0,0 +1,172 @@ +client = new Client($this->getServer()->getUrl()); + $this->factory = new PhpStreamRequestFactory(); + } + + public function testOpensValidStreamByCreatingContext() + { + $this->getServer()->enqueue("HTTP/1.1 200 OK\r\nContent-Length: 2\r\n\r\nhi"); + $request = $this->client->get('/'); + $stream = $this->factory->fromRequest($request); + $this->assertEquals('hi', (string) $stream); + $headers = $this->factory->getLastResponseHeaders(); + $this->assertContains('HTTP/1.1 200 OK', $headers); + $this->assertContains('Content-Length: 2', $headers); + $this->assertSame($headers, $stream->getCustomData('response_headers')); + $this->assertEquals(2, $stream->getSize()); + } + + public function testOpensValidStreamByPassingContextAndMerging() + { + $request = $this->client->get('/'); + $this->factory = $this->getMockBuilder('Guzzle\Stream\PhpStreamRequestFactory') + ->setMethods(array('createContext', 'createStream')) + ->getMock(); + $this->factory->expects($this->never()) + ->method('createContext'); + $this->factory->expects($this->once()) + ->method('createStream') + ->will($this->returnValue(new Stream(fopen('php://temp', 'r')))); + + $context = array('http' => array('method' => 'HEAD', 'ignore_errors' => false)); + $this->factory->fromRequest($request, stream_context_create($context)); + $options = stream_context_get_options($this->readAttribute($this->factory, 'context')); + $this->assertEquals('HEAD', $options['http']['method']); + $this->assertFalse($options['http']['ignore_errors']); + $this->assertEquals('1.1', $options['http']['protocol_version']); + } + + public function testAppliesProxySettings() + { + $request = $this->client->get('/'); + $request->getCurlOptions()->set(CURLOPT_PROXY, 'tcp://foo.com'); + $this->factory = $this->getMockBuilder('Guzzle\Stream\PhpStreamRequestFactory') + ->setMethods(array('createStream')) + ->getMock(); + $this->factory->expects($this->once()) + ->method('createStream') + ->will($this->returnValue(new Stream(fopen('php://temp', 'r')))); + $this->factory->fromRequest($request); + $options = stream_context_get_options($this->readAttribute($this->factory, 'context')); + $this->assertEquals('tcp://foo.com', $options['http']['proxy']); + } + + public function testAddsPostFields() + { + $this->getServer()->flush(); + $this->getServer()->enqueue("HTTP/1.1 200 OK\r\nContent-Length: 2\r\n\r\nhi"); + $request = $this->client->post('/', array('Foo' => 'Bar'), array('foo' => 'baz bar')); + $stream = $this->factory->fromRequest($request); + $this->assertEquals('hi', (string) $stream); + + $headers = $this->factory->getLastResponseHeaders(); + $this->assertContains('HTTP/1.1 200 OK', $headers); + $this->assertContains('Content-Length: 2', $headers); + $this->assertSame($headers, $stream->getCustomData('response_headers')); + + $received = $this->getServer()->getReceivedRequests(); + $this->assertEquals(1, count($received)); + $this->assertContains('POST / HTTP/1.1', $received[0]); + $this->assertContains('host: ', $received[0]); + $this->assertContains('user-agent: Guzzle/', $received[0]); + $this->assertContains('foo: Bar', $received[0]); + $this->assertContains('content-length: 13', $received[0]); + $this->assertContains('foo=baz%20bar', $received[0]); + } + + public function testAddsBody() + { + $this->getServer()->flush(); + $this->getServer()->enqueue("HTTP/1.1 200 OK\r\nContent-Length: 2\r\n\r\nhi"); + $request = $this->client->put('/', array('Foo' => 'Bar'), 'Testing...123'); + $stream = $this->factory->fromRequest($request); + $this->assertEquals('hi', (string) $stream); + + $headers = $this->factory->getLastResponseHeaders(); + $this->assertContains('HTTP/1.1 200 OK', $headers); + $this->assertContains('Content-Length: 2', $headers); + $this->assertSame($headers, $stream->getCustomData('response_headers')); + + $received = $this->getServer()->getReceivedRequests(); + $this->assertEquals(1, count($received)); + $this->assertContains('PUT / HTTP/1.1', $received[0]); + $this->assertContains('host: ', $received[0]); + $this->assertContains('user-agent: Guzzle/', $received[0]); + $this->assertContains('foo: Bar', $received[0]); + $this->assertContains('content-length: 13', $received[0]); + $this->assertContains('Testing...123', $received[0]); + } + + public function testCanDisableSslValidation() + { + $request = $this->client->get('/'); + $request->getCurlOptions()->set(CURLOPT_SSL_VERIFYPEER, false); + $this->factory = $this->getMockBuilder('Guzzle\Stream\PhpStreamRequestFactory') + ->setMethods(array('createStream')) + ->getMock(); + $this->factory->expects($this->once()) + ->method('createStream') + ->will($this->returnValue(new Stream(fopen('php://temp', 'r')))); + $this->factory->fromRequest($request); + $options = stream_context_get_options($this->readAttribute($this->factory, 'context')); + $this->assertFalse($options['ssl']['verify_peer']); + } + + public function testUsesSslValidationByDefault() + { + $request = $this->client->get('/'); + $this->factory = $this->getMockBuilder('Guzzle\Stream\PhpStreamRequestFactory') + ->setMethods(array('createStream')) + ->getMock(); + $this->factory->expects($this->once()) + ->method('createStream') + ->will($this->returnValue(new Stream(fopen('php://temp', 'r')))); + $this->factory->fromRequest($request); + $options = stream_context_get_options($this->readAttribute($this->factory, 'context')); + $this->assertTrue($options['ssl']['verify_peer']); + $this->assertSame($request->getCurlOptions()->get(CURLOPT_CAINFO), $options['ssl']['cafile']); + } + + public function testBasicAuthAddsUserAndPassToUrl() + { + $request = $this->client->get('/'); + $request->setAuth('Foo', 'Bar'); + $this->factory = $this->getMockBuilder('Guzzle\Stream\PhpStreamRequestFactory') + ->setMethods(array('createStream')) + ->getMock(); + $this->factory->expects($this->once()) + ->method('createStream') + ->will($this->returnValue(new Stream(fopen('php://temp', 'r')))); + $this->factory->fromRequest($request); + $this->assertContains('Foo:Bar@', (string) $this->readAttribute($this->factory, 'url')); + } + + public function testCanCreateCustomStreamClass() + { + $this->getServer()->enqueue("HTTP/1.1 200 OK\r\nContent-Length: 2\r\n\r\nhi"); + $request = $this->client->get('/'); + $stream = $this->factory->fromRequest($request, array(), array('stream_class' => 'Guzzle\Http\EntityBody')); + $this->assertInstanceOf('Guzzle\Http\EntityBody', $stream); + } +} diff --git a/vendor/guzzle/guzzle/tests/Guzzle/Tests/Stream/StreamTest.php b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Stream/StreamTest.php new file mode 100644 index 0000000..4973f25 --- /dev/null +++ b/vendor/guzzle/guzzle/tests/Guzzle/Tests/Stream/StreamTest.php @@ -0,0 +1,189 @@ +assertEquals($handle, $stream->getStream()); + $this->assertTrue($stream->isReadable()); + $this->assertTrue($stream->isWritable()); + $this->assertTrue($stream->isLocal()); + $this->assertTrue($stream->isSeekable()); + $this->assertEquals('PHP', $stream->getWrapper()); + $this->assertEquals('TEMP', $stream->getStreamType()); + $this->assertEquals(4, $stream->getSize()); + $this->assertEquals('php://temp', $stream->getUri()); + $this->assertEquals(array(), $stream->getWrapperData()); + $this->assertFalse($stream->isConsumed()); + unset($stream); + } + + public function testCanModifyStream() + { + $handle1 = fopen('php://temp', 'r+'); + $handle2 = fopen('php://temp', 'r+'); + $stream = new Stream($handle1); + $this->assertSame($handle1, $stream->getStream()); + $stream->setStream($handle2, 10); + $this->assertEquals(10, $stream->getSize()); + $this->assertSame($handle2, $stream->getStream()); + } + + public function testStreamClosesHandleOnDestruct() + { + $handle = fopen('php://temp', 'r'); + $stream = new Stream($handle); + unset($stream); + $this->assertFalse(is_resource($handle)); + } + + public function testConvertsToString() + { + $handle = fopen('php://temp', 'w+'); + fwrite($handle, 'data'); + $stream = new Stream($handle); + $this->assertEquals('data', (string) $stream); + unset($stream); + + $handle = fopen(__DIR__ . '/../TestData/FileBody.txt', 'r'); + $stream = new Stream($handle); + $this->assertEquals('', (string) $stream); + unset($stream); + } + + public function testConvertsToStringAndRestoresCursorPos() + { + $handle = fopen('php://temp', 'w+'); + $stream = new Stream($handle); + $stream->write('foobazbar'); + $stream->seek(3); + $this->assertEquals('foobazbar', (string) $stream); + $this->assertEquals(3, $stream->ftell()); + } + + public function testIsConsumed() + { + $handle = fopen('php://temp', 'w+'); + fwrite($handle, 'data'); + $stream = new Stream($handle); + $this->assertFalse($stream->isConsumed()); + $stream->read(4); + $this->assertTrue($stream->isConsumed()); + } + + public function testAllowsSettingManualSize() + { + $handle = fopen('php://temp', 'w+'); + fwrite($handle, 'data'); + $stream = new Stream($handle); + $stream->setSize(10); + $this->assertEquals(10, $stream->getSize()); + unset($stream); + } + + public function testWrapsStream() + { + $handle = fopen('php://temp', 'w+'); + fwrite($handle, 'data'); + $stream = new Stream($handle); + $this->assertTrue($stream->isSeekable()); + $this->assertTrue($stream->isReadable()); + $this->assertTrue($stream->seek(0)); + $this->assertEquals('da', $stream->read(2)); + $this->assertEquals('ta', $stream->read(2)); + $this->assertTrue($stream->seek(0)); + $this->assertEquals('data', $stream->read(4)); + $stream->write('_appended'); + $stream->seek(0); + $this->assertEquals('data_appended', $stream->read(13)); + } + + public function testGetSize() + { + $size = filesize(__DIR__ . '/../../../bootstrap.php'); + $handle = fopen(__DIR__ . '/../../../bootstrap.php', 'r'); + $stream = new Stream($handle); + $this->assertEquals($handle, $stream->getStream()); + $this->assertEquals($size, $stream->getSize()); + $this->assertEquals($size, $stream->getSize()); + unset($stream); + + // Make sure that false is returned when the size cannot be determined + $this->getServer()->enqueue("HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n"); + $handle = fopen('http://127.0.0.1:' . $this->getServer()->getPort(), 'r'); + $stream = new Stream($handle); + $this->assertEquals(false, $stream->getSize()); + unset($stream); + } + + public function testEnsuresSizeIsConsistent() + { + $h = fopen('php://temp', 'r+'); + fwrite($h, 'foo'); + $stream = new Stream($h); + $this->assertEquals(3, $stream->getSize()); + $stream->write('test'); + $this->assertEquals(7, $stream->getSize()); + fclose($h); + } + + public function testAbstractsMetaData() + { + $handle = fopen(__DIR__ . '/../../../bootstrap.php', 'r'); + $stream = new Stream($handle); + $this->assertEquals('plainfile', $stream->getMetaData('wrapper_type')); + $this->assertEquals(null, $stream->getMetaData('wrapper_data')); + $this->assertInternalType('array', $stream->getMetaData()); + } + + public function testDoesNotAttemptToWriteToReadonlyStream() + { + $handle = fopen(__DIR__ . '/../../../bootstrap.php', 'r'); + $stream = new Stream($handle); + $this->assertEquals(0, $stream->write('foo')); + } + + public function testProvidesStreamPosition() + { + $handle = fopen(__DIR__ . '/../../../bootstrap.php', 'r'); + $stream = new Stream($handle); + $stream->read(2); + $this->assertSame(ftell($handle), $stream->ftell()); + $this->assertEquals(2, $stream->ftell()); + } + + public function testRewindIsSeekZero() + { + $stream = new Stream(fopen('php://temp', 'w+')); + $stream->write('foobazbar'); + $this->assertTrue($stream->rewind()); + $this->assertEquals('foobazbar', $stream->read(9)); + } + + public function testCanDetachStream() + { + $r = fopen('php://temp', 'w+'); + $stream = new Stream($r); + $stream->detachStream(); + $this->assertNull($stream->getStream()); + } +} diff --git a/vendor/guzzle/guzzle/tests/Guzzle/Tests/TestData/FileBody.txt b/vendor/guzzle/guzzle/tests/Guzzle/Tests/TestData/FileBody.txt new file mode 100644 index 0000000..e69de29 diff --git a/vendor/guzzle/guzzle/tests/Guzzle/Tests/TestData/description/bar.json b/vendor/guzzle/guzzle/tests/Guzzle/Tests/TestData/description/bar.json new file mode 100644 index 0000000..c354ed7 --- /dev/null +++ b/vendor/guzzle/guzzle/tests/Guzzle/Tests/TestData/description/bar.json @@ -0,0 +1,3 @@ +{ + "includes": ["foo.json"] +} diff --git a/vendor/guzzle/guzzle/tests/Guzzle/Tests/TestData/description/baz.json b/vendor/guzzle/guzzle/tests/Guzzle/Tests/TestData/description/baz.json new file mode 100644 index 0000000..765237b --- /dev/null +++ b/vendor/guzzle/guzzle/tests/Guzzle/Tests/TestData/description/baz.json @@ -0,0 +1,3 @@ +{ + "includes": ["foo.json", "bar.json"] +} diff --git a/vendor/guzzle/guzzle/tests/Guzzle/Tests/TestData/description/foo.json b/vendor/guzzle/guzzle/tests/Guzzle/Tests/TestData/description/foo.json new file mode 100644 index 0000000..cee5005 --- /dev/null +++ b/vendor/guzzle/guzzle/tests/Guzzle/Tests/TestData/description/foo.json @@ -0,0 +1,8 @@ +{ + "includes": ["recursive.json"], + "operations": { + "abstract": { + "httpMethod": "POST" + } + } +} diff --git a/vendor/guzzle/guzzle/tests/Guzzle/Tests/TestData/description/recursive.json b/vendor/guzzle/guzzle/tests/Guzzle/Tests/TestData/description/recursive.json new file mode 100644 index 0000000..c354ed7 --- /dev/null +++ b/vendor/guzzle/guzzle/tests/Guzzle/Tests/TestData/description/recursive.json @@ -0,0 +1,3 @@ +{ + "includes": ["foo.json"] +} diff --git a/vendor/guzzle/guzzle/tests/Guzzle/Tests/TestData/mock_response b/vendor/guzzle/guzzle/tests/Guzzle/Tests/TestData/mock_response new file mode 100644 index 0000000..b6938a2 --- /dev/null +++ b/vendor/guzzle/guzzle/tests/Guzzle/Tests/TestData/mock_response @@ -0,0 +1,3 @@ +HTTP/1.1 200 OK +Content-Length: 0 + diff --git a/vendor/guzzle/guzzle/tests/Guzzle/Tests/TestData/services/json1.json b/vendor/guzzle/guzzle/tests/Guzzle/Tests/TestData/services/json1.json new file mode 100644 index 0000000..7b2a9da --- /dev/null +++ b/vendor/guzzle/guzzle/tests/Guzzle/Tests/TestData/services/json1.json @@ -0,0 +1,18 @@ +{ + "includes": [ "json2.json" ], + "services": { + "abstract": { + "access_key": "xyz", + "secret": "abc" + }, + "mock": { + "class": "Guzzle\\Tests\\Service\\Mock\\MockClient", + "extends": "abstract", + "params": { + "username": "foo", + "password": "baz", + "subdomain": "bar" + } + } + } +} diff --git a/vendor/guzzle/guzzle/tests/Guzzle/Tests/TestData/services/json2.json b/vendor/guzzle/guzzle/tests/Guzzle/Tests/TestData/services/json2.json new file mode 100644 index 0000000..08e5566 --- /dev/null +++ b/vendor/guzzle/guzzle/tests/Guzzle/Tests/TestData/services/json2.json @@ -0,0 +1,11 @@ +{ + "services": { + "foo": { + "class": "Guzzle\\Tests\\Service\\Mock\\MockClient", + "extends": "abstract", + "params": { + "baz": "bar" + } + } + } +} diff --git a/vendor/guzzle/guzzle/tests/Guzzle/Tests/TestData/services/services.json b/vendor/guzzle/guzzle/tests/Guzzle/Tests/TestData/services/services.json new file mode 100644 index 0000000..25452e4 --- /dev/null +++ b/vendor/guzzle/guzzle/tests/Guzzle/Tests/TestData/services/services.json @@ -0,0 +1,71 @@ +{ + "abstract": { + "access_key": "xyz", + "secret": "abc" + }, + "mock": { + "class": "Guzzle\\Tests\\Service\\Mock\\MockClient", + "extends": "abstract", + "params": { + "username": "foo", + "password": "baz", + "subdomain": "bar" + } + }, + + "test.abstract.aws": { + "params": { + "access_key": "12345", + "secret_key": "abcd" + } + }, + + "test.s3": { + "class": "Guzzle\\Service\\Aws\\S3Client", + "extends": "test.abstract.aws", + "params": { + "devpay_product_token": "", + "devpay_user_token": "" + } + }, + + "test.simple_db": { + "class": "Guzzle\\Service\\Aws\\SimpleDb\\SimpleDbClient", + "extends": "test.abstract.aws" + }, + + "test.sqs": { + "class": "Guzzle\\Service\\Aws\\Sqs\\SqsClient", + "extends": "test.abstract.aws" + }, + + "test.centinel": { + "class": "Guzzle\\Service\\CardinalCommerce\\Centinel.CentinelClient", + "params": { + "password": "test", + "processor_id": "123", + "merchant_id": "456" + } + }, + + "test.mws": { + "class": "Guzzle\\Service\\Mws\\MwsClient", + "extends": "test.abstract.aws", + "params": { + "merchant_id": "ABCDE", + "marketplace_id": "FGHIJ", + "application_name": "GuzzleTest", + "application_version": "0.1", + "base_url": "https://mws.amazonservices.com" + } + }, + + "mock": { + "class": "Guzzle\\Tests\\Service\\Mock\\MockClient", + "params": { + "username": "test_user", + "password": "****", + "subdomain": "test" + } + } +} diff --git a/vendor/guzzle/guzzle/tests/Guzzle/Tests/TestData/test_service.json b/vendor/guzzle/guzzle/tests/Guzzle/Tests/TestData/test_service.json new file mode 100644 index 0000000..01557ca --- /dev/null +++ b/vendor/guzzle/guzzle/tests/Guzzle/Tests/TestData/test_service.json @@ -0,0 +1,40 @@ +{ + "includes": [ "test_service2.json" ], + "operations": { + "test": { + "uri": "/path" + }, + "concrete": { + "extends": "abstract" + }, + "foo_bar": { + "uri": "/testing", + "parameters": { + "other": { + "location": "json", + "location_key": "Other" + }, + "test": { + "type": "object", + "location": "json", + "properties": { + "baz": { + "type": "boolean", + "default": true + }, + "bar": { + "type": "string", + "filters": [ + { + "method": "strtolower", + "args": ["test", "@value"] + }, + "strtoupper" + ] + } + } + } + } + } + } +} diff --git a/vendor/guzzle/guzzle/tests/Guzzle/Tests/TestData/test_service2.json b/vendor/guzzle/guzzle/tests/Guzzle/Tests/TestData/test_service2.json new file mode 100644 index 0000000..66dd9ef --- /dev/null +++ b/vendor/guzzle/guzzle/tests/Guzzle/Tests/TestData/test_service2.json @@ -0,0 +1,7 @@ +{ + "operations": { + "abstract": { + "uri": "/abstract" + } + } +} diff --git a/vendor/guzzle/guzzle/tests/Guzzle/Tests/TestData/test_service_3.json b/vendor/guzzle/guzzle/tests/Guzzle/Tests/TestData/test_service_3.json new file mode 100644 index 0000000..ae2ae0b --- /dev/null +++ b/vendor/guzzle/guzzle/tests/Guzzle/Tests/TestData/test_service_3.json @@ -0,0 +1,40 @@ +{ + "includes": [ "test_service2.json" ], + "operations": { + "test": { + "uri": "/path" + }, + "concrete": { + "extends": "abstract" + }, + "baz_qux": { + "uri": "/testing", + "parameters": { + "other": { + "location": "json", + "location_key": "Other" + }, + "test": { + "type": "object", + "location": "json", + "properties": { + "baz": { + "type": "boolean", + "default": true + }, + "bar": { + "type": "string", + "filters": [ + { + "method": "strtolower", + "args": ["test", "@value"] + }, + "strtoupper" + ] + } + } + } + } + } + } +} diff --git a/vendor/guzzle/guzzle/tests/bootstrap.php b/vendor/guzzle/guzzle/tests/bootstrap.php new file mode 100644 index 0000000..28908d3 --- /dev/null +++ b/vendor/guzzle/guzzle/tests/bootstrap.php @@ -0,0 +1,10 @@ +setChannel('#test') + ->setIconEmoji(':ghost:') + ->setUsername('slack-php'); + +$slack->notify($message); +``` + +### With attachments + +```php +require __DIR__ . '/vendor/autoload.php'; + +$client = new Slack\Client('your_team', 'your_token'); +$slack = new Slack\Notifier($client); + +$message = new Slack\Message\Message('Hello world'); +$attachment = new Slack\Message\MessageAttachment(); +$field = new Slack\Message\MessageField(); +$field + ->setTitle('foo') + ->setValue('bar'); + +$attachment->addField($field); +$message->addAttachment($attachment); + +$message->setChannel('#test') + ->setIconEmoji(':ghost:') + ->setUsername('slack-php'); + +$slack->notify($message); +``` + +### Message + +If your message contain @username and you want him to be notified, add `$message->enableLinkNames(true)` diff --git a/vendor/poweredbycoffee/slack-notifier/bin/slack b/vendor/poweredbycoffee/slack-notifier/bin/slack new file mode 100755 index 0000000..d53f880 --- /dev/null +++ b/vendor/poweredbycoffee/slack-notifier/bin/slack @@ -0,0 +1,27 @@ +#!/usr/bin/env php +add(new NotifierCommand()); +$application->run(); diff --git a/vendor/poweredbycoffee/slack-notifier/composer.json b/vendor/poweredbycoffee/slack-notifier/composer.json new file mode 100644 index 0000000..2a977ae --- /dev/null +++ b/vendor/poweredbycoffee/slack-notifier/composer.json @@ -0,0 +1,23 @@ +{ + "name": "polem/slack-notifier", + "description": "A simple slack wrapper", + "require": { + "guzzle/guzzle": "~3", + "symfony/serializer": "~2.4", + "symfony/console": "~2.4" + }, + "authors": [ + { + "name": "Paul-Emile MINY", + "email": "paulemile.miny@gmail.com" + } + ], + "autoload": { + "psr-0": {"Slack\\": "src/"} + }, + "require-dev": { + "phpunit/phpunit": "~3" + }, + "bin": ["bin/slack"], + "license": "MIT" +} diff --git a/vendor/poweredbycoffee/slack-notifier/phpunit.xml.dist b/vendor/poweredbycoffee/slack-notifier/phpunit.xml.dist new file mode 100644 index 0000000..ec964c4 --- /dev/null +++ b/vendor/poweredbycoffee/slack-notifier/phpunit.xml.dist @@ -0,0 +1,26 @@ + + + + + + + + + + + + ./tests/Slack/ + + + + diff --git a/vendor/poweredbycoffee/slack-notifier/src/Slack/Client.php b/vendor/poweredbycoffee/slack-notifier/src/Slack/Client.php new file mode 100644 index 0000000..4ff49b7 --- /dev/null +++ b/vendor/poweredbycoffee/slack-notifier/src/Slack/Client.php @@ -0,0 +1,15 @@ +setDefaultOption('query', array('token' => $token)); + } +} diff --git a/vendor/poweredbycoffee/slack-notifier/src/Slack/Command/NotifierCommand.php b/vendor/poweredbycoffee/slack-notifier/src/Slack/Command/NotifierCommand.php new file mode 100644 index 0000000..2bca7a1 --- /dev/null +++ b/vendor/poweredbycoffee/slack-notifier/src/Slack/Command/NotifierCommand.php @@ -0,0 +1,81 @@ +setName('notify') + ->setDescription('send a simple message to Slack') + ->addOption( + 'team', + null, + InputOption::VALUE_REQUIRED, + 'Your slack team/organization name', + null + ) + ->addOption( + 'token', + null, + InputOption::VALUE_REQUIRED, + 'Your slack auth token', null + ) + + ->addOption( + 'emoji', + null, + InputOption::VALUE_OPTIONAL, + 'icon_emoji used in Slack' + ) + + ->addOption( + 'username', + null, + InputOption::VALUE_REQUIRED, + 'username used in Slack', 'slack-notifier' + ) + + ->addArgument( + 'channel', + InputArgument::REQUIRED, + 'your message will be posted on this channel' + ) + + ->addArgument( + 'message', + InputArgument::REQUIRED, + 'message that will be posted' + ); + + } + /** + * [execute description] + * @param InputInterface $input [description] + * @param OutputInterface $output [description] + * @return [type] [description] + */ + protected function execute(InputInterface $input, OutputInterface $output) + { + + $client = new \Slack\Client($input->getOption('team'),$input->getOption('token')); + $slack = new \Slack\Notifier($client); + $message = new \Slack\Message\Message($input->getArgument('message')); + + $message->setChannel($input->getArgument('channel')) + ->setUsername($input->getOption('username')); + + if ( $input->getOption('emoji') ) { + + $message->setIconEmoji($input->getOption('emoji')); + } + $slack->notify($message); + $output->writeln("Sent!"); + } +} diff --git a/vendor/poweredbycoffee/slack-notifier/src/Slack/Message/Message.php b/vendor/poweredbycoffee/slack-notifier/src/Slack/Message/Message.php new file mode 100644 index 0000000..c5c03c4 --- /dev/null +++ b/vendor/poweredbycoffee/slack-notifier/src/Slack/Message/Message.php @@ -0,0 +1,194 @@ +text = $text; + } + + /** + * Get text. + * + * @return text. + */ + public function getText() + { + return $this->text; + } + + /** + * Set text. + * + * @param string $text the value to set. + * @return MessageInterface + */ + public function setText($text) + { + $this->text = $text; + + return $this; + } + + /** + * Get channel. + * + * @return channel. + */ + public function getChannel() + { + return $this->channel; + } + + /** + * Set channel. + * + * @param channel the value to set. + */ + public function setChannel($channel) + { + $this->channel = $channel; + + return $this; + } + + /** + * Get username. + * + * @return username. + */ + public function getUsername() + { + return $this->username; + } + + /** + * Set username. + * + * @param username the value to set. + */ + public function setUsername($username) + { + $this->username = $username; + + return $this; + } + + /** + * Get icon_emoji. + * + * @return icon_emoji. + */ + public function getIconEmoji() + { + return $this->icon_emoji; + } + + /** + * Set icon_emoji. + * + * @param icon_emoji the value to set. + */ + public function setIconEmoji($icon_emoji) + { + $this->icon_emoji = $icon_emoji; + + return $this; + } + + /** + * Get icon_url. + * + * @return icon_url. + */ + public function getIconUrl() + { + return $this->icon_url; + } + + /** + * Set icon_url. + * + * @param icon_url the value to set. + */ + public function setIconUrl($icon_url) + { + $this->icon_url = $icon_url; + + return $this; + } + + /** + * Get link_names. + * + * @return link_names. + */ + public function getLinkNames() + { + return $this->link_names; + } + + /** + * Set link_names. + * + * @param link_names the value to set. + */ + public function enableLinkNames($link_names) + { + $this->link_names = $link_names; + + return $this; + } + + /** + * addAttachment + * + * @param MessageAttachment $attachment + */ + public function addAttachment(MessageAttachment $attachment) + { + $this->attachments[] = $attachment; + } + + /** + * Get attachments. + * + * @return attachments. + */ + public function getAttachments() + { + return $this->attachments; + } + + /** + * Set attachments. + * + * @param attachments the value to set. + */ + public function setAttachments($attachments) + { + $this->attachments = $attachments; + + return $this; + } +} diff --git a/vendor/poweredbycoffee/slack-notifier/src/Slack/Message/MessageAttachment.php b/vendor/poweredbycoffee/slack-notifier/src/Slack/Message/MessageAttachment.php new file mode 100644 index 0000000..8cf7716 --- /dev/null +++ b/vendor/poweredbycoffee/slack-notifier/src/Slack/Message/MessageAttachment.php @@ -0,0 +1,139 @@ +fields[] = $field; + + return $this; + } + + /** + * Get fields. + * + * @return fields. + */ + public function getFields() + { + return $this->fields; + } + + /** + * Set fields. + * + * @param fields the value to set. + */ + public function setFields($fields) + { + $this->fields = $fields; + + return $this; + } + + /** + * Get fallback. + * + * @return fallback. + */ + public function getFallback() + { + return $this->fallback; + } + + /** + * Set fallback. + * + * @param fallback the value to set. + */ + public function setFallback($fallback) + { + $this->fallback = $fallback; + + return $this; + } + + /** + * Get text. + * + * @return text. + */ + public function getText() + { + return $this->text; + } + + /** + * Set text. + * + * @param text the value to set. + */ + public function setText($text) + { + $this->text = $text; + + return $this; + } + + /** + * Get pretext. + * + * @return pretext. + */ + public function getPretext() + { + return $this->pretext; + } + + /** + * Set pretext. + * + * @param pretext the value to set. + */ + public function setPretext($pretext) + { + $this->pretext = $pretext; + + return $this; + } + + /** + * Get color. + * + * @return color. + */ + public function getColor() + { + return $this->color; + } + + /** + * Set color. + * + * @param color the value to set. + */ + public function setColor($color) + { + $this->color = $color; + + return $this; + } +} diff --git a/vendor/poweredbycoffee/slack-notifier/src/Slack/Message/MessageField.php b/vendor/poweredbycoffee/slack-notifier/src/Slack/Message/MessageField.php new file mode 100644 index 0000000..769500e --- /dev/null +++ b/vendor/poweredbycoffee/slack-notifier/src/Slack/Message/MessageField.php @@ -0,0 +1,76 @@ +title; + } + + /** + * Set title. + * + * @param title the value to set. + */ + public function setTitle($title) + { + $this->title = $title; + + return $this; + } + + /** + * Get value. + * + * @return value. + */ + public function getValue() + { + return $this->value; + } + + /** + * Set value. + * + * @param value the value to set. + */ + public function setValue($value) + { + $this->value = $value; + + return $this; + } + + /** + * Get short. + * + * @return short. + */ + public function getShort() + { + return $this->short; + } + + /** + * Set short. + * + * @param short the value to set. + */ + public function setShort($short) + { + $this->short = $short; + + return $this; + } +} diff --git a/vendor/poweredbycoffee/slack-notifier/src/Slack/Message/MessageInterface.php b/vendor/poweredbycoffee/slack-notifier/src/Slack/Message/MessageInterface.php new file mode 100644 index 0000000..ffde9cf --- /dev/null +++ b/vendor/poweredbycoffee/slack-notifier/src/Slack/Message/MessageInterface.php @@ -0,0 +1,7 @@ +setCamelizedAttributes(array('icon_emoji', 'icon_url')); + + $serializer = new Serializer( + array($normalizer), + array(new JsonEncoder()) + ); + } + + $this->client = $client; + $this->serializer = $serializer; + } + + /** + * notify + * + * @param MessageInterface $message + * @param boolean $debug + */ + public function notify(MessageInterface $message, $debug = false) + { + $payload = $this->serializer->serialize($message, 'json'); + + $request = $this->client->post( + '/services/hooks/incoming-webhook', + array(), + $payload, + array('debug' => $debug) + ); + + $request->send(); + } +} diff --git a/vendor/poweredbycoffee/slack-notifier/src/Slack/Serializer/Normalizer/GetSetMethodNormalizer.php b/vendor/poweredbycoffee/slack-notifier/src/Slack/Serializer/Normalizer/GetSetMethodNormalizer.php new file mode 100644 index 0000000..e16bf74 --- /dev/null +++ b/vendor/poweredbycoffee/slack-notifier/src/Slack/Serializer/Normalizer/GetSetMethodNormalizer.php @@ -0,0 +1,43 @@ + $value) { + if (!isset($value)) { + continue; + } + $attributes[$this->fromCamelCase($name)] = $value; + } + + return $attributes; + } + + /** + * fromCamelCase + * + * @param string $str + */ + protected function fromCamelCase($str) + { + $str[0] = strtolower($str[0]); + $func = create_function('$c', 'return "_" . strtolower($c[1]);'); + + return preg_replace_callback('/([A-Z])/', $func, $str); + } +} diff --git a/vendor/poweredbycoffee/slack-notifier/tests/Slack/Test/Command/NotifierCommandTest.php b/vendor/poweredbycoffee/slack-notifier/tests/Slack/Test/Command/NotifierCommandTest.php new file mode 100644 index 0000000..f829366 --- /dev/null +++ b/vendor/poweredbycoffee/slack-notifier/tests/Slack/Test/Command/NotifierCommandTest.php @@ -0,0 +1,33 @@ +add(new NotifierCommand()); + + $command = $application->find('notify'); + $commandTester = new CommandTester($command); + try { + $commandTester->execute(array('command' => $command->getName(), 'message'=>'test','channel'=>'test')); + $this->failed(''); + + } catch (\Guzzle\Http\Exception\CurlException $expected) { + return; + } + + } +} diff --git a/vendor/poweredbycoffee/slack-notifier/tests/Slack/Test/NotifierTest.php b/vendor/poweredbycoffee/slack-notifier/tests/Slack/Test/NotifierTest.php new file mode 100644 index 0000000..ddb18ab --- /dev/null +++ b/vendor/poweredbycoffee/slack-notifier/tests/Slack/Test/NotifierTest.php @@ -0,0 +1,95 @@ +getMockBuilder('\Slack\Client') + ->disableOriginalConstructor() + ->getMock(array('post')); + + $request = $this->getMockBuilder('\Guzzle\Http\Message\Request') + ->disableOriginalConstructor() + ->getMock(array('send')); + + $message = new Message('Hello world'); + + $message->setChannel('#test') + ->setIconEmoji(':ghost:') + ->setUsername('slack-php'); + + $attachment = new \Slack\Message\MessageAttachment(); + $field = new \Slack\Message\MessageField(); + $field + ->setTitle('foo') + ->setValue('bar') + ->setShort(false); + + $attachment->addField($field); + $message->addAttachment($attachment); + + + $expectedDatas = json_encode( + array( + 'text' => $message->getText(), + 'channel' => $message->getChannel(), + 'username' => 'slack-php', + 'icon_emoji' => ':ghost:', + 'attachments' => array( + array( + 'fields' => array( + array( + 'title' => 'foo', + 'value' => 'bar', + 'short' => false + ) + ) + ) + ) + ) + ); + + $client->expects($this->once()) + ->method('post') + ->with( + $this->equalTo('/services/hooks/incoming-webhook'), + $this->anything(), + $this->equalTo($expectedDatas), + $this->anything() + ) + ->will($this->returnValue($request)); + + $notifier = new Notifier($client); + + $notifier->notify($message); + } +} diff --git a/vendor/poweredbycoffee/slack-notifier/tests/bootstrap.php b/vendor/poweredbycoffee/slack-notifier/tests/bootstrap.php new file mode 100644 index 0000000..a131000 --- /dev/null +++ b/vendor/poweredbycoffee/slack-notifier/tests/bootstrap.php @@ -0,0 +1,5 @@ +add('Slack\Test', __DIR__); + diff --git a/vendor/symfony/console/.gitignore b/vendor/symfony/console/.gitignore new file mode 100644 index 0000000..c49a5d8 --- /dev/null +++ b/vendor/symfony/console/.gitignore @@ -0,0 +1,3 @@ +vendor/ +composer.lock +phpunit.xml diff --git a/vendor/symfony/console/Application.php b/vendor/symfony/console/Application.php new file mode 100644 index 0000000..c816f01 --- /dev/null +++ b/vendor/symfony/console/Application.php @@ -0,0 +1,1177 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console; + +use Symfony\Component\Console\Descriptor\TextDescriptor; +use Symfony\Component\Console\Descriptor\XmlDescriptor; +use Symfony\Component\Console\Helper\DebugFormatterHelper; +use Symfony\Component\Console\Helper\ProcessHelper; +use Symfony\Component\Console\Helper\QuestionHelper; +use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Input\ArgvInput; +use Symfony\Component\Console\Input\ArrayInput; +use Symfony\Component\Console\Input\InputDefinition; +use Symfony\Component\Console\Input\InputOption; +use Symfony\Component\Console\Input\InputArgument; +use Symfony\Component\Console\Input\InputAwareInterface; +use Symfony\Component\Console\Output\BufferedOutput; +use Symfony\Component\Console\Output\OutputInterface; +use Symfony\Component\Console\Output\ConsoleOutput; +use Symfony\Component\Console\Output\ConsoleOutputInterface; +use Symfony\Component\Console\Command\Command; +use Symfony\Component\Console\Command\HelpCommand; +use Symfony\Component\Console\Command\ListCommand; +use Symfony\Component\Console\Helper\HelperSet; +use Symfony\Component\Console\Helper\FormatterHelper; +use Symfony\Component\Console\Helper\DialogHelper; +use Symfony\Component\Console\Helper\ProgressHelper; +use Symfony\Component\Console\Helper\TableHelper; +use Symfony\Component\Console\Event\ConsoleCommandEvent; +use Symfony\Component\Console\Event\ConsoleExceptionEvent; +use Symfony\Component\Console\Event\ConsoleTerminateEvent; +use Symfony\Component\EventDispatcher\EventDispatcherInterface; + +/** + * An Application is the container for a collection of commands. + * + * It is the main entry point of a Console application. + * + * This class is optimized for a standard CLI environment. + * + * Usage: + * + * $app = new Application('myapp', '1.0 (stable)'); + * $app->add(new SimpleCommand()); + * $app->run(); + * + * @author Fabien Potencier + * + * @api + */ +class Application +{ + private $commands = array(); + private $wantHelps = false; + private $runningCommand; + private $name; + private $version; + private $catchExceptions = true; + private $autoExit = true; + private $definition; + private $helperSet; + private $dispatcher; + private $terminalDimensions; + private $defaultCommand; + + /** + * Constructor. + * + * @param string $name The name of the application + * @param string $version The version of the application + * + * @api + */ + public function __construct($name = 'UNKNOWN', $version = 'UNKNOWN') + { + $this->name = $name; + $this->version = $version; + $this->defaultCommand = 'list'; + $this->helperSet = $this->getDefaultHelperSet(); + $this->definition = $this->getDefaultInputDefinition(); + + foreach ($this->getDefaultCommands() as $command) { + $this->add($command); + } + } + + public function setDispatcher(EventDispatcherInterface $dispatcher) + { + $this->dispatcher = $dispatcher; + } + + /** + * Runs the current application. + * + * @param InputInterface $input An Input instance + * @param OutputInterface $output An Output instance + * + * @return int 0 if everything went fine, or an error code + * + * @throws \Exception When doRun returns Exception + * + * @api + */ + public function run(InputInterface $input = null, OutputInterface $output = null) + { + if (null === $input) { + $input = new ArgvInput(); + } + + if (null === $output) { + $output = new ConsoleOutput(); + } + + $this->configureIO($input, $output); + + try { + $exitCode = $this->doRun($input, $output); + } catch (\Exception $e) { + if (!$this->catchExceptions) { + throw $e; + } + + if ($output instanceof ConsoleOutputInterface) { + $this->renderException($e, $output->getErrorOutput()); + } else { + $this->renderException($e, $output); + } + + $exitCode = $e->getCode(); + if (is_numeric($exitCode)) { + $exitCode = (int) $exitCode; + if (0 === $exitCode) { + $exitCode = 1; + } + } else { + $exitCode = 1; + } + } + + if ($this->autoExit) { + if ($exitCode > 255) { + $exitCode = 255; + } + + exit($exitCode); + } + + return $exitCode; + } + + /** + * Runs the current application. + * + * @param InputInterface $input An Input instance + * @param OutputInterface $output An Output instance + * + * @return int 0 if everything went fine, or an error code + */ + public function doRun(InputInterface $input, OutputInterface $output) + { + if (true === $input->hasParameterOption(array('--version', '-V'))) { + $output->writeln($this->getLongVersion()); + + return 0; + } + + $name = $this->getCommandName($input); + if (true === $input->hasParameterOption(array('--help', '-h'))) { + if (!$name) { + $name = 'help'; + $input = new ArrayInput(array('command' => 'help')); + } else { + $this->wantHelps = true; + } + } + + if (!$name) { + $name = $this->defaultCommand; + $input = new ArrayInput(array('command' => $this->defaultCommand)); + } + + // the command name MUST be the first element of the input + $command = $this->find($name); + + $this->runningCommand = $command; + $exitCode = $this->doRunCommand($command, $input, $output); + $this->runningCommand = null; + + return $exitCode; + } + + /** + * Set a helper set to be used with the command. + * + * @param HelperSet $helperSet The helper set + * + * @api + */ + public function setHelperSet(HelperSet $helperSet) + { + $this->helperSet = $helperSet; + } + + /** + * Get the helper set associated with the command. + * + * @return HelperSet The HelperSet instance associated with this command + * + * @api + */ + public function getHelperSet() + { + return $this->helperSet; + } + + /** + * Set an input definition set to be used with this application. + * + * @param InputDefinition $definition The input definition + * + * @api + */ + public function setDefinition(InputDefinition $definition) + { + $this->definition = $definition; + } + + /** + * Gets the InputDefinition related to this Application. + * + * @return InputDefinition The InputDefinition instance + */ + public function getDefinition() + { + return $this->definition; + } + + /** + * Gets the help message. + * + * @return string A help message. + */ + public function getHelp() + { + return $this->getLongVersion(); + } + + /** + * Sets whether to catch exceptions or not during commands execution. + * + * @param bool $boolean Whether to catch exceptions or not during commands execution + * + * @api + */ + public function setCatchExceptions($boolean) + { + $this->catchExceptions = (bool) $boolean; + } + + /** + * Sets whether to automatically exit after a command execution or not. + * + * @param bool $boolean Whether to automatically exit after a command execution or not + * + * @api + */ + public function setAutoExit($boolean) + { + $this->autoExit = (bool) $boolean; + } + + /** + * Gets the name of the application. + * + * @return string The application name + * + * @api + */ + public function getName() + { + return $this->name; + } + + /** + * Sets the application name. + * + * @param string $name The application name + * + * @api + */ + public function setName($name) + { + $this->name = $name; + } + + /** + * Gets the application version. + * + * @return string The application version + * + * @api + */ + public function getVersion() + { + return $this->version; + } + + /** + * Sets the application version. + * + * @param string $version The application version + * + * @api + */ + public function setVersion($version) + { + $this->version = $version; + } + + /** + * Returns the long version of the application. + * + * @return string The long application version + * + * @api + */ + public function getLongVersion() + { + if ('UNKNOWN' !== $this->getName() && 'UNKNOWN' !== $this->getVersion()) { + return sprintf('%s version %s', $this->getName(), $this->getVersion()); + } + + return 'Console Tool'; + } + + /** + * Registers a new command. + * + * @param string $name The command name + * + * @return Command The newly created command + * + * @api + */ + public function register($name) + { + return $this->add(new Command($name)); + } + + /** + * Adds an array of command objects. + * + * @param Command[] $commands An array of commands + * + * @api + */ + public function addCommands(array $commands) + { + foreach ($commands as $command) { + $this->add($command); + } + } + + /** + * Adds a command object. + * + * If a command with the same name already exists, it will be overridden. + * + * @param Command $command A Command object + * + * @return Command The registered command + * + * @api + */ + public function add(Command $command) + { + $command->setApplication($this); + + if (!$command->isEnabled()) { + $command->setApplication(null); + + return; + } + + if (null === $command->getDefinition()) { + throw new \LogicException(sprintf('Command class "%s" is not correctly initialized. You probably forgot to call the parent constructor.', get_class($command))); + } + + $this->commands[$command->getName()] = $command; + + foreach ($command->getAliases() as $alias) { + $this->commands[$alias] = $command; + } + + return $command; + } + + /** + * Returns a registered command by name or alias. + * + * @param string $name The command name or alias + * + * @return Command A Command object + * + * @throws \InvalidArgumentException When command name given does not exist + * + * @api + */ + public function get($name) + { + if (!isset($this->commands[$name])) { + throw new \InvalidArgumentException(sprintf('The command "%s" does not exist.', $name)); + } + + $command = $this->commands[$name]; + + if ($this->wantHelps) { + $this->wantHelps = false; + + $helpCommand = $this->get('help'); + $helpCommand->setCommand($command); + + return $helpCommand; + } + + return $command; + } + + /** + * Returns true if the command exists, false otherwise. + * + * @param string $name The command name or alias + * + * @return bool true if the command exists, false otherwise + * + * @api + */ + public function has($name) + { + return isset($this->commands[$name]); + } + + /** + * Returns an array of all unique namespaces used by currently registered commands. + * + * It does not returns the global namespace which always exists. + * + * @return array An array of namespaces + */ + public function getNamespaces() + { + $namespaces = array(); + foreach ($this->commands as $command) { + $namespaces = array_merge($namespaces, $this->extractAllNamespaces($command->getName())); + + foreach ($command->getAliases() as $alias) { + $namespaces = array_merge($namespaces, $this->extractAllNamespaces($alias)); + } + } + + return array_values(array_unique(array_filter($namespaces))); + } + + /** + * Finds a registered namespace by a name or an abbreviation. + * + * @param string $namespace A namespace or abbreviation to search for + * + * @return string A registered namespace + * + * @throws \InvalidArgumentException When namespace is incorrect or ambiguous + */ + public function findNamespace($namespace) + { + $allNamespaces = $this->getNamespaces(); + $expr = preg_replace_callback('{([^:]+|)}', function ($matches) { return preg_quote($matches[1]).'[^:]*'; }, $namespace); + $namespaces = preg_grep('{^'.$expr.'}', $allNamespaces); + + if (empty($namespaces)) { + $message = sprintf('There are no commands defined in the "%s" namespace.', $namespace); + + if ($alternatives = $this->findAlternatives($namespace, $allNamespaces)) { + if (1 == count($alternatives)) { + $message .= "\n\nDid you mean this?\n "; + } else { + $message .= "\n\nDid you mean one of these?\n "; + } + + $message .= implode("\n ", $alternatives); + } + + throw new \InvalidArgumentException($message); + } + + $exact = in_array($namespace, $namespaces, true); + if (count($namespaces) > 1 && !$exact) { + throw new \InvalidArgumentException(sprintf('The namespace "%s" is ambiguous (%s).', $namespace, $this->getAbbreviationSuggestions(array_values($namespaces)))); + } + + return $exact ? $namespace : reset($namespaces); + } + + /** + * Finds a command by name or alias. + * + * Contrary to get, this command tries to find the best + * match if you give it an abbreviation of a name or alias. + * + * @param string $name A command name or a command alias + * + * @return Command A Command instance + * + * @throws \InvalidArgumentException When command name is incorrect or ambiguous + * + * @api + */ + public function find($name) + { + $allCommands = array_keys($this->commands); + $expr = preg_replace_callback('{([^:]+|)}', function ($matches) { return preg_quote($matches[1]).'[^:]*'; }, $name); + $commands = preg_grep('{^'.$expr.'}', $allCommands); + + if (empty($commands) || count(preg_grep('{^'.$expr.'$}', $commands)) < 1) { + if (false !== $pos = strrpos($name, ':')) { + // check if a namespace exists and contains commands + $this->findNamespace(substr($name, 0, $pos)); + } + + $message = sprintf('Command "%s" is not defined.', $name); + + if ($alternatives = $this->findAlternatives($name, $allCommands)) { + if (1 == count($alternatives)) { + $message .= "\n\nDid you mean this?\n "; + } else { + $message .= "\n\nDid you mean one of these?\n "; + } + $message .= implode("\n ", $alternatives); + } + + throw new \InvalidArgumentException($message); + } + + // filter out aliases for commands which are already on the list + if (count($commands) > 1) { + $commandList = $this->commands; + $commands = array_filter($commands, function ($nameOrAlias) use ($commandList, $commands) { + $commandName = $commandList[$nameOrAlias]->getName(); + + return $commandName === $nameOrAlias || !in_array($commandName, $commands); + }); + } + + $exact = in_array($name, $commands, true); + if (count($commands) > 1 && !$exact) { + $suggestions = $this->getAbbreviationSuggestions(array_values($commands)); + + throw new \InvalidArgumentException(sprintf('Command "%s" is ambiguous (%s).', $name, $suggestions)); + } + + return $this->get($exact ? $name : reset($commands)); + } + + /** + * Gets the commands (registered in the given namespace if provided). + * + * The array keys are the full names and the values the command instances. + * + * @param string $namespace A namespace name + * + * @return Command[] An array of Command instances + * + * @api + */ + public function all($namespace = null) + { + if (null === $namespace) { + return $this->commands; + } + + $commands = array(); + foreach ($this->commands as $name => $command) { + if ($namespace === $this->extractNamespace($name, substr_count($namespace, ':') + 1)) { + $commands[$name] = $command; + } + } + + return $commands; + } + + /** + * Returns an array of possible abbreviations given a set of names. + * + * @param array $names An array of names + * + * @return array An array of abbreviations + */ + public static function getAbbreviations($names) + { + $abbrevs = array(); + foreach ($names as $name) { + for ($len = strlen($name); $len > 0; --$len) { + $abbrev = substr($name, 0, $len); + $abbrevs[$abbrev][] = $name; + } + } + + return $abbrevs; + } + + /** + * Returns a text representation of the Application. + * + * @param string $namespace An optional namespace name + * @param bool $raw Whether to return raw command list + * + * @return string A string representing the Application + * + * @deprecated since version 2.3, to be removed in 3.0. + */ + public function asText($namespace = null, $raw = false) + { + @trigger_error('The '.__METHOD__.' method is deprecated since version 2.3 and will be removed in 3.0.', E_USER_DEPRECATED); + + $descriptor = new TextDescriptor(); + $output = new BufferedOutput(BufferedOutput::VERBOSITY_NORMAL, !$raw); + $descriptor->describe($output, $this, array('namespace' => $namespace, 'raw_output' => true)); + + return $output->fetch(); + } + + /** + * Returns an XML representation of the Application. + * + * @param string $namespace An optional namespace name + * @param bool $asDom Whether to return a DOM or an XML string + * + * @return string|\DOMDocument An XML string representing the Application + * + * @deprecated since version 2.3, to be removed in 3.0. + */ + public function asXml($namespace = null, $asDom = false) + { + @trigger_error('The '.__METHOD__.' method is deprecated since version 2.3 and will be removed in 3.0.', E_USER_DEPRECATED); + + $descriptor = new XmlDescriptor(); + + if ($asDom) { + return $descriptor->getApplicationDocument($this, $namespace); + } + + $output = new BufferedOutput(); + $descriptor->describe($output, $this, array('namespace' => $namespace)); + + return $output->fetch(); + } + + /** + * Renders a caught exception. + * + * @param \Exception $e An exception instance + * @param OutputInterface $output An OutputInterface instance + */ + public function renderException($e, $output) + { + do { + $title = sprintf(' [%s] ', get_class($e)); + + $len = $this->stringWidth($title); + + $width = $this->getTerminalWidth() ? $this->getTerminalWidth() - 1 : PHP_INT_MAX; + // HHVM only accepts 32 bits integer in str_split, even when PHP_INT_MAX is a 64 bit integer: https://github.com/facebook/hhvm/issues/1327 + if (defined('HHVM_VERSION') && $width > 1 << 31) { + $width = 1 << 31; + } + $formatter = $output->getFormatter(); + $lines = array(); + foreach (preg_split('/\r?\n/', $e->getMessage()) as $line) { + foreach ($this->splitStringByWidth($line, $width - 4) as $line) { + // pre-format lines to get the right string length + $lineLength = $this->stringWidth(preg_replace('/\[[^m]*m/', '', $formatter->format($line))) + 4; + $lines[] = array($line, $lineLength); + + $len = max($lineLength, $len); + } + } + + $messages = array('', ''); + $messages[] = $emptyLine = $formatter->format(sprintf('%s', str_repeat(' ', $len))); + $messages[] = $formatter->format(sprintf('%s%s', $title, str_repeat(' ', max(0, $len - $this->stringWidth($title))))); + foreach ($lines as $line) { + $messages[] = $formatter->format(sprintf(' %s %s', $line[0], str_repeat(' ', $len - $line[1]))); + } + $messages[] = $emptyLine; + $messages[] = ''; + $messages[] = ''; + + $output->writeln($messages, OutputInterface::OUTPUT_RAW); + + if (OutputInterface::VERBOSITY_VERBOSE <= $output->getVerbosity()) { + $output->writeln('Exception trace:'); + + // exception related properties + $trace = $e->getTrace(); + array_unshift($trace, array( + 'function' => '', + 'file' => $e->getFile() !== null ? $e->getFile() : 'n/a', + 'line' => $e->getLine() !== null ? $e->getLine() : 'n/a', + 'args' => array(), + )); + + for ($i = 0, $count = count($trace); $i < $count; ++$i) { + $class = isset($trace[$i]['class']) ? $trace[$i]['class'] : ''; + $type = isset($trace[$i]['type']) ? $trace[$i]['type'] : ''; + $function = $trace[$i]['function']; + $file = isset($trace[$i]['file']) ? $trace[$i]['file'] : 'n/a'; + $line = isset($trace[$i]['line']) ? $trace[$i]['line'] : 'n/a'; + + $output->writeln(sprintf(' %s%s%s() at %s:%s', $class, $type, $function, $file, $line)); + } + + $output->writeln(''); + $output->writeln(''); + } + } while ($e = $e->getPrevious()); + + if (null !== $this->runningCommand) { + $output->writeln(sprintf('%s', sprintf($this->runningCommand->getSynopsis(), $this->getName()))); + $output->writeln(''); + $output->writeln(''); + } + } + + /** + * Tries to figure out the terminal width in which this application runs. + * + * @return int|null + */ + protected function getTerminalWidth() + { + $dimensions = $this->getTerminalDimensions(); + + return $dimensions[0]; + } + + /** + * Tries to figure out the terminal height in which this application runs. + * + * @return int|null + */ + protected function getTerminalHeight() + { + $dimensions = $this->getTerminalDimensions(); + + return $dimensions[1]; + } + + /** + * Tries to figure out the terminal dimensions based on the current environment. + * + * @return array Array containing width and height + */ + public function getTerminalDimensions() + { + if ($this->terminalDimensions) { + return $this->terminalDimensions; + } + + if ('\\' === DIRECTORY_SEPARATOR) { + // extract [w, H] from "wxh (WxH)" + if (preg_match('/^(\d+)x\d+ \(\d+x(\d+)\)$/', trim(getenv('ANSICON')), $matches)) { + return array((int) $matches[1], (int) $matches[2]); + } + // extract [w, h] from "wxh" + if (preg_match('/^(\d+)x(\d+)$/', $this->getConsoleMode(), $matches)) { + return array((int) $matches[1], (int) $matches[2]); + } + } + + if ($sttyString = $this->getSttyColumns()) { + // extract [w, h] from "rows h; columns w;" + if (preg_match('/rows.(\d+);.columns.(\d+);/i', $sttyString, $matches)) { + return array((int) $matches[2], (int) $matches[1]); + } + // extract [w, h] from "; h rows; w columns" + if (preg_match('/;.(\d+).rows;.(\d+).columns/i', $sttyString, $matches)) { + return array((int) $matches[2], (int) $matches[1]); + } + } + + return array(null, null); + } + + /** + * Sets terminal dimensions. + * + * Can be useful to force terminal dimensions for functional tests. + * + * @param int $width The width + * @param int $height The height + * + * @return Application The current application + */ + public function setTerminalDimensions($width, $height) + { + $this->terminalDimensions = array($width, $height); + + return $this; + } + + /** + * Configures the input and output instances based on the user arguments and options. + * + * @param InputInterface $input An InputInterface instance + * @param OutputInterface $output An OutputInterface instance + */ + protected function configureIO(InputInterface $input, OutputInterface $output) + { + if (true === $input->hasParameterOption(array('--ansi'))) { + $output->setDecorated(true); + } elseif (true === $input->hasParameterOption(array('--no-ansi'))) { + $output->setDecorated(false); + } + + if (true === $input->hasParameterOption(array('--no-interaction', '-n'))) { + $input->setInteractive(false); + } elseif (function_exists('posix_isatty') && $this->getHelperSet()->has('question')) { + $inputStream = $this->getHelperSet()->get('question')->getInputStream(); + if (!@posix_isatty($inputStream) && false === getenv('SHELL_INTERACTIVE')) { + $input->setInteractive(false); + } + } + + if (true === $input->hasParameterOption(array('--quiet', '-q'))) { + $output->setVerbosity(OutputInterface::VERBOSITY_QUIET); + } else { + if ($input->hasParameterOption('-vvv') || $input->hasParameterOption('--verbose=3') || $input->getParameterOption('--verbose') === 3) { + $output->setVerbosity(OutputInterface::VERBOSITY_DEBUG); + } elseif ($input->hasParameterOption('-vv') || $input->hasParameterOption('--verbose=2') || $input->getParameterOption('--verbose') === 2) { + $output->setVerbosity(OutputInterface::VERBOSITY_VERY_VERBOSE); + } elseif ($input->hasParameterOption('-v') || $input->hasParameterOption('--verbose=1') || $input->hasParameterOption('--verbose') || $input->getParameterOption('--verbose')) { + $output->setVerbosity(OutputInterface::VERBOSITY_VERBOSE); + } + } + } + + /** + * Runs the current command. + * + * If an event dispatcher has been attached to the application, + * events are also dispatched during the life-cycle of the command. + * + * @param Command $command A Command instance + * @param InputInterface $input An Input instance + * @param OutputInterface $output An Output instance + * + * @return int 0 if everything went fine, or an error code + * + * @throws \Exception when the command being run threw an exception + */ + protected function doRunCommand(Command $command, InputInterface $input, OutputInterface $output) + { + foreach ($command->getHelperSet() as $helper) { + if ($helper instanceof InputAwareInterface) { + $helper->setInput($input); + } + } + + if (null === $this->dispatcher) { + return $command->run($input, $output); + } + + $event = new ConsoleCommandEvent($command, $input, $output); + $this->dispatcher->dispatch(ConsoleEvents::COMMAND, $event); + + if ($event->commandShouldRun()) { + try { + $exitCode = $command->run($input, $output); + } catch (\Exception $e) { + $event = new ConsoleTerminateEvent($command, $input, $output, $e->getCode()); + $this->dispatcher->dispatch(ConsoleEvents::TERMINATE, $event); + + $event = new ConsoleExceptionEvent($command, $input, $output, $e, $event->getExitCode()); + $this->dispatcher->dispatch(ConsoleEvents::EXCEPTION, $event); + + throw $event->getException(); + } + } else { + $exitCode = ConsoleCommandEvent::RETURN_CODE_DISABLED; + } + + $event = new ConsoleTerminateEvent($command, $input, $output, $exitCode); + $this->dispatcher->dispatch(ConsoleEvents::TERMINATE, $event); + + return $event->getExitCode(); + } + + /** + * Gets the name of the command based on input. + * + * @param InputInterface $input The input interface + * + * @return string The command name + */ + protected function getCommandName(InputInterface $input) + { + return $input->getFirstArgument(); + } + + /** + * Gets the default input definition. + * + * @return InputDefinition An InputDefinition instance + */ + protected function getDefaultInputDefinition() + { + return new InputDefinition(array( + new InputArgument('command', InputArgument::REQUIRED, 'The command to execute'), + + new InputOption('--help', '-h', InputOption::VALUE_NONE, 'Display this help message'), + new InputOption('--quiet', '-q', InputOption::VALUE_NONE, 'Do not output any message'), + new InputOption('--verbose', '-v|vv|vvv', InputOption::VALUE_NONE, 'Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug'), + new InputOption('--version', '-V', InputOption::VALUE_NONE, 'Display this application version'), + new InputOption('--ansi', '', InputOption::VALUE_NONE, 'Force ANSI output'), + new InputOption('--no-ansi', '', InputOption::VALUE_NONE, 'Disable ANSI output'), + new InputOption('--no-interaction', '-n', InputOption::VALUE_NONE, 'Do not ask any interactive question'), + )); + } + + /** + * Gets the default commands that should always be available. + * + * @return Command[] An array of default Command instances + */ + protected function getDefaultCommands() + { + return array(new HelpCommand(), new ListCommand()); + } + + /** + * Gets the default helper set with the helpers that should always be available. + * + * @return HelperSet A HelperSet instance + */ + protected function getDefaultHelperSet() + { + return new HelperSet(array( + new FormatterHelper(), + new DialogHelper(false), + new ProgressHelper(false), + new TableHelper(false), + new DebugFormatterHelper(), + new ProcessHelper(), + new QuestionHelper(), + )); + } + + /** + * Runs and parses stty -a if it's available, suppressing any error output. + * + * @return string + */ + private function getSttyColumns() + { + if (!function_exists('proc_open')) { + return; + } + + $descriptorspec = array(1 => array('pipe', 'w'), 2 => array('pipe', 'w')); + $process = proc_open('stty -a | grep columns', $descriptorspec, $pipes, null, null, array('suppress_errors' => true)); + if (is_resource($process)) { + $info = stream_get_contents($pipes[1]); + fclose($pipes[1]); + fclose($pipes[2]); + proc_close($process); + + return $info; + } + } + + /** + * Runs and parses mode CON if it's available, suppressing any error output. + * + * @return string x or null if it could not be parsed + */ + private function getConsoleMode() + { + if (!function_exists('proc_open')) { + return; + } + + $descriptorspec = array(1 => array('pipe', 'w'), 2 => array('pipe', 'w')); + $process = proc_open('mode CON', $descriptorspec, $pipes, null, null, array('suppress_errors' => true)); + if (is_resource($process)) { + $info = stream_get_contents($pipes[1]); + fclose($pipes[1]); + fclose($pipes[2]); + proc_close($process); + + if (preg_match('/--------+\r?\n.+?(\d+)\r?\n.+?(\d+)\r?\n/', $info, $matches)) { + return $matches[2].'x'.$matches[1]; + } + } + } + + /** + * Returns abbreviated suggestions in string format. + * + * @param array $abbrevs Abbreviated suggestions to convert + * + * @return string A formatted string of abbreviated suggestions + */ + private function getAbbreviationSuggestions($abbrevs) + { + return sprintf('%s, %s%s', $abbrevs[0], $abbrevs[1], count($abbrevs) > 2 ? sprintf(' and %d more', count($abbrevs) - 2) : ''); + } + + /** + * Returns the namespace part of the command name. + * + * This method is not part of public API and should not be used directly. + * + * @param string $name The full name of the command + * @param string $limit The maximum number of parts of the namespace + * + * @return string The namespace of the command + */ + public function extractNamespace($name, $limit = null) + { + $parts = explode(':', $name); + array_pop($parts); + + return implode(':', null === $limit ? $parts : array_slice($parts, 0, $limit)); + } + + /** + * Finds alternative of $name among $collection, + * if nothing is found in $collection, try in $abbrevs. + * + * @param string $name The string + * @param array|\Traversable $collection The collection + * + * @return array A sorted array of similar string + */ + private function findAlternatives($name, $collection) + { + $threshold = 1e3; + $alternatives = array(); + + $collectionParts = array(); + foreach ($collection as $item) { + $collectionParts[$item] = explode(':', $item); + } + + foreach (explode(':', $name) as $i => $subname) { + foreach ($collectionParts as $collectionName => $parts) { + $exists = isset($alternatives[$collectionName]); + if (!isset($parts[$i]) && $exists) { + $alternatives[$collectionName] += $threshold; + continue; + } elseif (!isset($parts[$i])) { + continue; + } + + $lev = levenshtein($subname, $parts[$i]); + if ($lev <= strlen($subname) / 3 || '' !== $subname && false !== strpos($parts[$i], $subname)) { + $alternatives[$collectionName] = $exists ? $alternatives[$collectionName] + $lev : $lev; + } elseif ($exists) { + $alternatives[$collectionName] += $threshold; + } + } + } + + foreach ($collection as $item) { + $lev = levenshtein($name, $item); + if ($lev <= strlen($name) / 3 || false !== strpos($item, $name)) { + $alternatives[$item] = isset($alternatives[$item]) ? $alternatives[$item] - $lev : $lev; + } + } + + $alternatives = array_filter($alternatives, function ($lev) use ($threshold) { return $lev < 2 * $threshold; }); + asort($alternatives); + + return array_keys($alternatives); + } + + /** + * Sets the default Command name. + * + * @param string $commandName The Command name + */ + public function setDefaultCommand($commandName) + { + $this->defaultCommand = $commandName; + } + + private function stringWidth($string) + { + if (!function_exists('mb_strwidth')) { + return strlen($string); + } + + if (false === $encoding = mb_detect_encoding($string)) { + return strlen($string); + } + + return mb_strwidth($string, $encoding); + } + + private function splitStringByWidth($string, $width) + { + // str_split is not suitable for multi-byte characters, we should use preg_split to get char array properly. + // additionally, array_slice() is not enough as some character has doubled width. + // we need a function to split string not by character count but by string width + + if (!function_exists('mb_strwidth')) { + return str_split($string, $width); + } + + if (false === $encoding = mb_detect_encoding($string)) { + return str_split($string, $width); + } + + $utf8String = mb_convert_encoding($string, 'utf8', $encoding); + $lines = array(); + $line = ''; + foreach (preg_split('//u', $utf8String) as $char) { + // test if $char could be appended to current line + if (mb_strwidth($line.$char, 'utf8') <= $width) { + $line .= $char; + continue; + } + // if not, push current line to array and make new line + $lines[] = str_pad($line, $width); + $line = $char; + } + if ('' !== $line) { + $lines[] = count($lines) ? str_pad($line, $width) : $line; + } + + mb_convert_variables($encoding, 'utf8', $lines); + + return $lines; + } + + /** + * Returns all namespaces of the command name. + * + * @param string $name The full name of the command + * + * @return array The namespaces of the command + */ + private function extractAllNamespaces($name) + { + // -1 as third argument is needed to skip the command short name when exploding + $parts = explode(':', $name, -1); + $namespaces = array(); + + foreach ($parts as $part) { + if (count($namespaces)) { + $namespaces[] = end($namespaces).':'.$part; + } else { + $namespaces[] = $part; + } + } + + return $namespaces; + } +} diff --git a/vendor/symfony/console/CHANGELOG.md b/vendor/symfony/console/CHANGELOG.md new file mode 100644 index 0000000..07254c6 --- /dev/null +++ b/vendor/symfony/console/CHANGELOG.md @@ -0,0 +1,62 @@ +CHANGELOG +========= + +2.6.0 +----- + + * added a Process helper + * added a DebugFormatter helper + +2.5.0 +----- + + * deprecated the dialog helper (use the question helper instead) + * deprecated TableHelper in favor of Table + * deprecated ProgressHelper in favor of ProgressBar + * added ConsoleLogger + * added a question helper + * added a way to set the process name of a command + * added a way to set a default command instead of `ListCommand` + +2.4.0 +----- + + * added a way to force terminal dimensions + * added a convenient method to detect verbosity level + * [BC BREAK] made descriptors use output instead of returning a string + +2.3.0 +----- + + * added multiselect support to the select dialog helper + * added Table Helper for tabular data rendering + * added support for events in `Application` + * added a way to normalize EOLs in `ApplicationTester::getDisplay()` and `CommandTester::getDisplay()` + * added a way to set the progress bar progress via the `setCurrent` method + * added support for multiple InputOption shortcuts, written as `'-a|-b|-c'` + * added two additional verbosity levels, VERBOSITY_VERY_VERBOSE and VERBOSITY_DEBUG + +2.2.0 +----- + + * added support for colorization on Windows via ConEmu + * add a method to Dialog Helper to ask for a question and hide the response + * added support for interactive selections in console (DialogHelper::select()) + * added support for autocompletion as you type in Dialog Helper + +2.1.0 +----- + + * added ConsoleOutputInterface + * added the possibility to disable a command (Command::isEnabled()) + * added suggestions when a command does not exist + * added a --raw option to the list command + * added support for STDERR in the console output class (errors are now sent + to STDERR) + * made the defaults (helper set, commands, input definition) in Application + more easily customizable + * added support for the shell even if readline is not available + * added support for process isolation in Symfony shell via + `--process-isolation` switch + * added support for `--`, which disables options parsing after that point + (tokens will be parsed as arguments) diff --git a/vendor/symfony/console/Command/Command.php b/vendor/symfony/console/Command/Command.php new file mode 100644 index 0000000..519778c --- /dev/null +++ b/vendor/symfony/console/Command/Command.php @@ -0,0 +1,697 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Command; + +use Symfony\Component\Console\Descriptor\TextDescriptor; +use Symfony\Component\Console\Descriptor\XmlDescriptor; +use Symfony\Component\Console\Input\InputDefinition; +use Symfony\Component\Console\Input\InputOption; +use Symfony\Component\Console\Input\InputArgument; +use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Output\BufferedOutput; +use Symfony\Component\Console\Output\OutputInterface; +use Symfony\Component\Console\Application; +use Symfony\Component\Console\Helper\HelperSet; + +/** + * Base class for all commands. + * + * @author Fabien Potencier + * + * @api + */ +class Command +{ + private $application; + private $name; + private $processTitle; + private $aliases = array(); + private $definition; + private $help; + private $description; + private $ignoreValidationErrors = false; + private $applicationDefinitionMerged = false; + private $applicationDefinitionMergedWithArgs = false; + private $code; + private $synopsis = array(); + private $usages = array(); + private $helperSet; + + /** + * Constructor. + * + * @param string|null $name The name of the command; passing null means it must be set in configure() + * + * @throws \LogicException When the command name is empty + * + * @api + */ + public function __construct($name = null) + { + $this->definition = new InputDefinition(); + + if (null !== $name) { + $this->setName($name); + } + + $this->configure(); + + if (!$this->name) { + throw new \LogicException(sprintf('The command defined in "%s" cannot have an empty name.', get_class($this))); + } + } + + /** + * Ignores validation errors. + * + * This is mainly useful for the help command. + */ + public function ignoreValidationErrors() + { + $this->ignoreValidationErrors = true; + } + + /** + * Sets the application instance for this command. + * + * @param Application $application An Application instance + * + * @api + */ + public function setApplication(Application $application = null) + { + $this->application = $application; + if ($application) { + $this->setHelperSet($application->getHelperSet()); + } else { + $this->helperSet = null; + } + } + + /** + * Sets the helper set. + * + * @param HelperSet $helperSet A HelperSet instance + */ + public function setHelperSet(HelperSet $helperSet) + { + $this->helperSet = $helperSet; + } + + /** + * Gets the helper set. + * + * @return HelperSet A HelperSet instance + */ + public function getHelperSet() + { + return $this->helperSet; + } + + /** + * Gets the application instance for this command. + * + * @return Application An Application instance + * + * @api + */ + public function getApplication() + { + return $this->application; + } + + /** + * Checks whether the command is enabled or not in the current environment. + * + * Override this to check for x or y and return false if the command can not + * run properly under the current conditions. + * + * @return bool + */ + public function isEnabled() + { + return true; + } + + /** + * Configures the current command. + */ + protected function configure() + { + } + + /** + * Executes the current command. + * + * This method is not abstract because you can use this class + * as a concrete class. In this case, instead of defining the + * execute() method, you set the code to execute by passing + * a Closure to the setCode() method. + * + * @param InputInterface $input An InputInterface instance + * @param OutputInterface $output An OutputInterface instance + * + * @return null|int null or 0 if everything went fine, or an error code + * + * @throws \LogicException When this abstract method is not implemented + * + * @see setCode() + */ + protected function execute(InputInterface $input, OutputInterface $output) + { + throw new \LogicException('You must override the execute() method in the concrete command class.'); + } + + /** + * Interacts with the user. + * + * This method is executed before the InputDefinition is validated. + * This means that this is the only place where the command can + * interactively ask for values of missing required arguments. + * + * @param InputInterface $input An InputInterface instance + * @param OutputInterface $output An OutputInterface instance + */ + protected function interact(InputInterface $input, OutputInterface $output) + { + } + + /** + * Initializes the command just after the input has been validated. + * + * This is mainly useful when a lot of commands extends one main command + * where some things need to be initialized based on the input arguments and options. + * + * @param InputInterface $input An InputInterface instance + * @param OutputInterface $output An OutputInterface instance + */ + protected function initialize(InputInterface $input, OutputInterface $output) + { + } + + /** + * Runs the command. + * + * The code to execute is either defined directly with the + * setCode() method or by overriding the execute() method + * in a sub-class. + * + * @param InputInterface $input An InputInterface instance + * @param OutputInterface $output An OutputInterface instance + * + * @return int The command exit code + * + * @throws \Exception + * + * @see setCode() + * @see execute() + * + * @api + */ + public function run(InputInterface $input, OutputInterface $output) + { + // force the creation of the synopsis before the merge with the app definition + $this->getSynopsis(true); + $this->getSynopsis(false); + + // add the application arguments and options + $this->mergeApplicationDefinition(); + + // bind the input against the command specific arguments/options + try { + $input->bind($this->definition); + } catch (\Exception $e) { + if (!$this->ignoreValidationErrors) { + throw $e; + } + } + + $this->initialize($input, $output); + + if (null !== $this->processTitle) { + if (function_exists('cli_set_process_title')) { + cli_set_process_title($this->processTitle); + } elseif (function_exists('setproctitle')) { + setproctitle($this->processTitle); + } elseif (OutputInterface::VERBOSITY_VERY_VERBOSE === $output->getVerbosity()) { + $output->writeln('Install the proctitle PECL to be able to change the process title.'); + } + } + + if ($input->isInteractive()) { + $this->interact($input, $output); + } + + $input->validate(); + + if ($this->code) { + $statusCode = call_user_func($this->code, $input, $output); + } else { + $statusCode = $this->execute($input, $output); + } + + return is_numeric($statusCode) ? (int) $statusCode : 0; + } + + /** + * Sets the code to execute when running this command. + * + * If this method is used, it overrides the code defined + * in the execute() method. + * + * @param callable $code A callable(InputInterface $input, OutputInterface $output) + * + * @return Command The current instance + * + * @throws \InvalidArgumentException + * + * @see execute() + * + * @api + */ + public function setCode($code) + { + if (!is_callable($code)) { + throw new \InvalidArgumentException('Invalid callable provided to Command::setCode.'); + } + + $this->code = $code; + + return $this; + } + + /** + * Merges the application definition with the command definition. + * + * This method is not part of public API and should not be used directly. + * + * @param bool $mergeArgs Whether to merge or not the Application definition arguments to Command definition arguments + */ + public function mergeApplicationDefinition($mergeArgs = true) + { + if (null === $this->application || (true === $this->applicationDefinitionMerged && ($this->applicationDefinitionMergedWithArgs || !$mergeArgs))) { + return; + } + + if ($mergeArgs) { + $currentArguments = $this->definition->getArguments(); + $this->definition->setArguments($this->application->getDefinition()->getArguments()); + $this->definition->addArguments($currentArguments); + } + + $this->definition->addOptions($this->application->getDefinition()->getOptions()); + + $this->applicationDefinitionMerged = true; + if ($mergeArgs) { + $this->applicationDefinitionMergedWithArgs = true; + } + } + + /** + * Sets an array of argument and option instances. + * + * @param array|InputDefinition $definition An array of argument and option instances or a definition instance + * + * @return Command The current instance + * + * @api + */ + public function setDefinition($definition) + { + if ($definition instanceof InputDefinition) { + $this->definition = $definition; + } else { + $this->definition->setDefinition($definition); + } + + $this->applicationDefinitionMerged = false; + + return $this; + } + + /** + * Gets the InputDefinition attached to this Command. + * + * @return InputDefinition An InputDefinition instance + * + * @api + */ + public function getDefinition() + { + return $this->definition; + } + + /** + * Gets the InputDefinition to be used to create XML and Text representations of this Command. + * + * Can be overridden to provide the original command representation when it would otherwise + * be changed by merging with the application InputDefinition. + * + * This method is not part of public API and should not be used directly. + * + * @return InputDefinition An InputDefinition instance + */ + public function getNativeDefinition() + { + return $this->getDefinition(); + } + + /** + * Adds an argument. + * + * @param string $name The argument name + * @param int $mode The argument mode: InputArgument::REQUIRED or InputArgument::OPTIONAL + * @param string $description A description text + * @param mixed $default The default value (for InputArgument::OPTIONAL mode only) + * + * @return Command The current instance + * + * @api + */ + public function addArgument($name, $mode = null, $description = '', $default = null) + { + $this->definition->addArgument(new InputArgument($name, $mode, $description, $default)); + + return $this; + } + + /** + * Adds an option. + * + * @param string $name The option name + * @param string $shortcut The shortcut (can be null) + * @param int $mode The option mode: One of the InputOption::VALUE_* constants + * @param string $description A description text + * @param mixed $default The default value (must be null for InputOption::VALUE_REQUIRED or InputOption::VALUE_NONE) + * + * @return Command The current instance + * + * @api + */ + public function addOption($name, $shortcut = null, $mode = null, $description = '', $default = null) + { + $this->definition->addOption(new InputOption($name, $shortcut, $mode, $description, $default)); + + return $this; + } + + /** + * Sets the name of the command. + * + * This method can set both the namespace and the name if + * you separate them by a colon (:) + * + * $command->setName('foo:bar'); + * + * @param string $name The command name + * + * @return Command The current instance + * + * @throws \InvalidArgumentException When the name is invalid + * + * @api + */ + public function setName($name) + { + $this->validateName($name); + + $this->name = $name; + + return $this; + } + + /** + * Sets the process title of the command. + * + * This feature should be used only when creating a long process command, + * like a daemon. + * + * PHP 5.5+ or the proctitle PECL library is required + * + * @param string $title The process title + * + * @return Command The current instance + */ + public function setProcessTitle($title) + { + $this->processTitle = $title; + + return $this; + } + + /** + * Returns the command name. + * + * @return string The command name + * + * @api + */ + public function getName() + { + return $this->name; + } + + /** + * Sets the description for the command. + * + * @param string $description The description for the command + * + * @return Command The current instance + * + * @api + */ + public function setDescription($description) + { + $this->description = $description; + + return $this; + } + + /** + * Returns the description for the command. + * + * @return string The description for the command + * + * @api + */ + public function getDescription() + { + return $this->description; + } + + /** + * Sets the help for the command. + * + * @param string $help The help for the command + * + * @return Command The current instance + * + * @api + */ + public function setHelp($help) + { + $this->help = $help; + + return $this; + } + + /** + * Returns the help for the command. + * + * @return string The help for the command + * + * @api + */ + public function getHelp() + { + return $this->help ?: $this->description; + } + + /** + * Returns the processed help for the command replacing the %command.name% and + * %command.full_name% patterns with the real values dynamically. + * + * @return string The processed help for the command + */ + public function getProcessedHelp() + { + $name = $this->name; + + $placeholders = array( + '%command.name%', + '%command.full_name%', + ); + $replacements = array( + $name, + $_SERVER['PHP_SELF'].' '.$name, + ); + + return str_replace($placeholders, $replacements, $this->getHelp()); + } + + /** + * Sets the aliases for the command. + * + * @param string[] $aliases An array of aliases for the command + * + * @return Command The current instance + * + * @throws \InvalidArgumentException When an alias is invalid + * + * @api + */ + public function setAliases($aliases) + { + if (!is_array($aliases) && !$aliases instanceof \Traversable) { + throw new \InvalidArgumentException('$aliases must be an array or an instance of \Traversable'); + } + + foreach ($aliases as $alias) { + $this->validateName($alias); + } + + $this->aliases = $aliases; + + return $this; + } + + /** + * Returns the aliases for the command. + * + * @return array An array of aliases for the command + * + * @api + */ + public function getAliases() + { + return $this->aliases; + } + + /** + * Returns the synopsis for the command. + * + * @param bool $short Whether to show the short version of the synopsis (with options folded) or not + * + * @return string The synopsis + */ + public function getSynopsis($short = false) + { + $key = $short ? 'short' : 'long'; + + if (!isset($this->synopsis[$key])) { + $this->synopsis[$key] = trim(sprintf('%s %s', $this->name, $this->definition->getSynopsis($short))); + } + + return $this->synopsis[$key]; + } + + /** + * Add a command usage example. + * + * @param string $usage The usage, it'll be prefixed with the command name + */ + public function addUsage($usage) + { + if (0 !== strpos($usage, $this->name)) { + $usage = sprintf('%s %s', $this->name, $usage); + } + + $this->usages[] = $usage; + + return $this; + } + + /** + * Returns alternative usages of the command. + * + * @return array + */ + public function getUsages() + { + return $this->usages; + } + + /** + * Gets a helper instance by name. + * + * @param string $name The helper name + * + * @return mixed The helper value + * + * @throws \InvalidArgumentException if the helper is not defined + * + * @api + */ + public function getHelper($name) + { + return $this->helperSet->get($name); + } + + /** + * Returns a text representation of the command. + * + * @return string A string representing the command + * + * @deprecated since version 2.3, to be removed in 3.0. + */ + public function asText() + { + @trigger_error('The '.__METHOD__.' method is deprecated since version 2.3 and will be removed in 3.0.', E_USER_DEPRECATED); + + $descriptor = new TextDescriptor(); + $output = new BufferedOutput(BufferedOutput::VERBOSITY_NORMAL, true); + $descriptor->describe($output, $this, array('raw_output' => true)); + + return $output->fetch(); + } + + /** + * Returns an XML representation of the command. + * + * @param bool $asDom Whether to return a DOM or an XML string + * + * @return string|\DOMDocument An XML string representing the command + * + * @deprecated since version 2.3, to be removed in 3.0. + */ + public function asXml($asDom = false) + { + @trigger_error('The '.__METHOD__.' method is deprecated since version 2.3 and will be removed in 3.0.', E_USER_DEPRECATED); + + $descriptor = new XmlDescriptor(); + + if ($asDom) { + return $descriptor->getCommandDocument($this); + } + + $output = new BufferedOutput(); + $descriptor->describe($output, $this); + + return $output->fetch(); + } + + /** + * Validates a command name. + * + * It must be non-empty and parts can optionally be separated by ":". + * + * @param string $name + * + * @throws \InvalidArgumentException When the name is invalid + */ + private function validateName($name) + { + if (!preg_match('/^[^\:]++(\:[^\:]++)*$/', $name)) { + throw new \InvalidArgumentException(sprintf('Command name "%s" is invalid.', $name)); + } + } +} diff --git a/vendor/symfony/console/Command/HelpCommand.php b/vendor/symfony/console/Command/HelpCommand.php new file mode 100644 index 0000000..8c20b57 --- /dev/null +++ b/vendor/symfony/console/Command/HelpCommand.php @@ -0,0 +1,93 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Command; + +use Symfony\Component\Console\Helper\DescriptorHelper; +use Symfony\Component\Console\Input\InputArgument; +use Symfony\Component\Console\Input\InputOption; +use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Output\OutputInterface; + +/** + * HelpCommand displays the help for a given command. + * + * @author Fabien Potencier + */ +class HelpCommand extends Command +{ + private $command; + + /** + * {@inheritdoc} + */ + protected function configure() + { + $this->ignoreValidationErrors(); + + $this + ->setName('help') + ->setDefinition(array( + new InputArgument('command_name', InputArgument::OPTIONAL, 'The command name', 'help'), + new InputOption('xml', null, InputOption::VALUE_NONE, 'To output help as XML'), + new InputOption('format', null, InputOption::VALUE_REQUIRED, 'The output format (txt, xml, json, or md)', 'txt'), + new InputOption('raw', null, InputOption::VALUE_NONE, 'To output raw command help'), + )) + ->setDescription('Displays help for a command') + ->setHelp(<<%command.name% command displays help for a given command: + + php %command.full_name% list + +You can also output the help in other formats by using the --format option: + + php %command.full_name% --format=xml list + +To display the list of available commands, please use the list command. +EOF + ) + ; + } + + /** + * Sets the command. + * + * @param Command $command The command to set + */ + public function setCommand(Command $command) + { + $this->command = $command; + } + + /** + * {@inheritdoc} + */ + protected function execute(InputInterface $input, OutputInterface $output) + { + if (null === $this->command) { + $this->command = $this->getApplication()->find($input->getArgument('command_name')); + } + + if ($input->getOption('xml')) { + @trigger_error('The --xml option was deprecated in version 2.7 and will be removed in version 3.0. Use the --format option instead.', E_USER_DEPRECATED); + + $input->setOption('format', 'xml'); + } + + $helper = new DescriptorHelper(); + $helper->describe($output, $this->command, array( + 'format' => $input->getOption('format'), + 'raw_text' => $input->getOption('raw'), + )); + + $this->command = null; + } +} diff --git a/vendor/symfony/console/Command/ListCommand.php b/vendor/symfony/console/Command/ListCommand.php new file mode 100644 index 0000000..5f970e8 --- /dev/null +++ b/vendor/symfony/console/Command/ListCommand.php @@ -0,0 +1,97 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Command; + +use Symfony\Component\Console\Helper\DescriptorHelper; +use Symfony\Component\Console\Input\InputArgument; +use Symfony\Component\Console\Input\InputOption; +use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Output\OutputInterface; +use Symfony\Component\Console\Input\InputDefinition; + +/** + * ListCommand displays the list of all available commands for the application. + * + * @author Fabien Potencier + */ +class ListCommand extends Command +{ + /** + * {@inheritdoc} + */ + protected function configure() + { + $this + ->setName('list') + ->setDefinition($this->createDefinition()) + ->setDescription('Lists commands') + ->setHelp(<<%command.name% command lists all commands: + + php %command.full_name% + +You can also display the commands for a specific namespace: + + php %command.full_name% test + +You can also output the information in other formats by using the --format option: + + php %command.full_name% --format=xml + +It's also possible to get raw list of commands (useful for embedding command runner): + + php %command.full_name% --raw +EOF + ) + ; + } + + /** + * {@inheritdoc} + */ + public function getNativeDefinition() + { + return $this->createDefinition(); + } + + /** + * {@inheritdoc} + */ + protected function execute(InputInterface $input, OutputInterface $output) + { + if ($input->getOption('xml')) { + @trigger_error('The --xml option was deprecated in version 2.7 and will be removed in version 3.0. Use the --format option instead.', E_USER_DEPRECATED); + + $input->setOption('format', 'xml'); + } + + $helper = new DescriptorHelper(); + $helper->describe($output, $this->getApplication(), array( + 'format' => $input->getOption('format'), + 'raw_text' => $input->getOption('raw'), + 'namespace' => $input->getArgument('namespace'), + )); + } + + /** + * {@inheritdoc} + */ + private function createDefinition() + { + return new InputDefinition(array( + new InputArgument('namespace', InputArgument::OPTIONAL, 'The namespace name'), + new InputOption('xml', null, InputOption::VALUE_NONE, 'To output list as XML'), + new InputOption('raw', null, InputOption::VALUE_NONE, 'To output raw command list'), + new InputOption('format', null, InputOption::VALUE_REQUIRED, 'The output format (txt, xml, json, or md)', 'txt'), + )); + } +} diff --git a/vendor/symfony/console/ConsoleEvents.php b/vendor/symfony/console/ConsoleEvents.php new file mode 100644 index 0000000..1ed41b7 --- /dev/null +++ b/vendor/symfony/console/ConsoleEvents.php @@ -0,0 +1,61 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console; + +/** + * Contains all events dispatched by an Application. + * + * @author Francesco Levorato + */ +final class ConsoleEvents +{ + /** + * The COMMAND event allows you to attach listeners before any command is + * executed by the console. It also allows you to modify the command, input and output + * before they are handled to the command. + * + * The event listener method receives a Symfony\Component\Console\Event\ConsoleCommandEvent + * instance. + * + * @Event + * + * @var string + */ + const COMMAND = 'console.command'; + + /** + * The TERMINATE event allows you to attach listeners after a command is + * executed by the console. + * + * The event listener method receives a Symfony\Component\Console\Event\ConsoleTerminateEvent + * instance. + * + * @Event + * + * @var string + */ + const TERMINATE = 'console.terminate'; + + /** + * The EXCEPTION event occurs when an uncaught exception appears. + * + * This event allows you to deal with the exception or + * to modify the thrown exception. The event listener method receives + * a Symfony\Component\Console\Event\ConsoleExceptionEvent + * instance. + * + * @Event + * + * @var string + */ + const EXCEPTION = 'console.exception'; +} diff --git a/vendor/symfony/console/Descriptor/ApplicationDescription.php b/vendor/symfony/console/Descriptor/ApplicationDescription.php new file mode 100644 index 0000000..c481be4 --- /dev/null +++ b/vendor/symfony/console/Descriptor/ApplicationDescription.php @@ -0,0 +1,157 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Descriptor; + +use Symfony\Component\Console\Application; +use Symfony\Component\Console\Command\Command; + +/** + * @author Jean-François Simon + * + * @internal + */ +class ApplicationDescription +{ + const GLOBAL_NAMESPACE = '_global'; + + /** + * @var Application + */ + private $application; + + /** + * @var null|string + */ + private $namespace; + + /** + * @var array + */ + private $namespaces; + + /** + * @var Command[] + */ + private $commands; + + /** + * @var Command[] + */ + private $aliases; + + /** + * Constructor. + * + * @param Application $application + * @param string|null $namespace + */ + public function __construct(Application $application, $namespace = null) + { + $this->application = $application; + $this->namespace = $namespace; + } + + /** + * @return array + */ + public function getNamespaces() + { + if (null === $this->namespaces) { + $this->inspectApplication(); + } + + return $this->namespaces; + } + + /** + * @return Command[] + */ + public function getCommands() + { + if (null === $this->commands) { + $this->inspectApplication(); + } + + return $this->commands; + } + + /** + * @param string $name + * + * @return Command + * + * @throws \InvalidArgumentException + */ + public function getCommand($name) + { + if (!isset($this->commands[$name]) && !isset($this->aliases[$name])) { + throw new \InvalidArgumentException(sprintf('Command %s does not exist.', $name)); + } + + return isset($this->commands[$name]) ? $this->commands[$name] : $this->aliases[$name]; + } + + private function inspectApplication() + { + $this->commands = array(); + $this->namespaces = array(); + + $all = $this->application->all($this->namespace ? $this->application->findNamespace($this->namespace) : null); + foreach ($this->sortCommands($all) as $namespace => $commands) { + $names = array(); + + /** @var Command $command */ + foreach ($commands as $name => $command) { + if (!$command->getName()) { + continue; + } + + if ($command->getName() === $name) { + $this->commands[$name] = $command; + } else { + $this->aliases[$name] = $command; + } + + $names[] = $name; + } + + $this->namespaces[$namespace] = array('id' => $namespace, 'commands' => $names); + } + } + + /** + * @param array $commands + * + * @return array + */ + private function sortCommands(array $commands) + { + $namespacedCommands = array(); + foreach ($commands as $name => $command) { + $key = $this->application->extractNamespace($name, 1); + if (!$key) { + $key = '_global'; + } + + $namespacedCommands[$key][$name] = $command; + } + ksort($namespacedCommands); + + foreach ($namespacedCommands as &$commandsSet) { + ksort($commandsSet); + } + // unset reference to keep scope clear + unset($commandsSet); + + return $namespacedCommands; + } +} diff --git a/vendor/symfony/console/Descriptor/Descriptor.php b/vendor/symfony/console/Descriptor/Descriptor.php new file mode 100644 index 0000000..49e2193 --- /dev/null +++ b/vendor/symfony/console/Descriptor/Descriptor.php @@ -0,0 +1,121 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Descriptor; + +use Symfony\Component\Console\Application; +use Symfony\Component\Console\Command\Command; +use Symfony\Component\Console\Input\InputArgument; +use Symfony\Component\Console\Input\InputDefinition; +use Symfony\Component\Console\Input\InputOption; +use Symfony\Component\Console\Output\OutputInterface; + +/** + * @author Jean-François Simon + * + * @internal + */ +abstract class Descriptor implements DescriptorInterface +{ + /** + * @var OutputInterface + */ + private $output; + + /** + * {@inheritdoc} + */ + public function describe(OutputInterface $output, $object, array $options = array()) + { + $this->output = $output; + + switch (true) { + case $object instanceof InputArgument: + $this->describeInputArgument($object, $options); + break; + case $object instanceof InputOption: + $this->describeInputOption($object, $options); + break; + case $object instanceof InputDefinition: + $this->describeInputDefinition($object, $options); + break; + case $object instanceof Command: + $this->describeCommand($object, $options); + break; + case $object instanceof Application: + $this->describeApplication($object, $options); + break; + default: + throw new \InvalidArgumentException(sprintf('Object of type "%s" is not describable.', get_class($object))); + } + } + + /** + * Writes content to output. + * + * @param string $content + * @param bool $decorated + */ + protected function write($content, $decorated = false) + { + $this->output->write($content, false, $decorated ? OutputInterface::OUTPUT_NORMAL : OutputInterface::OUTPUT_RAW); + } + + /** + * Describes an InputArgument instance. + * + * @param InputArgument $argument + * @param array $options + * + * @return string|mixed + */ + abstract protected function describeInputArgument(InputArgument $argument, array $options = array()); + + /** + * Describes an InputOption instance. + * + * @param InputOption $option + * @param array $options + * + * @return string|mixed + */ + abstract protected function describeInputOption(InputOption $option, array $options = array()); + + /** + * Describes an InputDefinition instance. + * + * @param InputDefinition $definition + * @param array $options + * + * @return string|mixed + */ + abstract protected function describeInputDefinition(InputDefinition $definition, array $options = array()); + + /** + * Describes a Command instance. + * + * @param Command $command + * @param array $options + * + * @return string|mixed + */ + abstract protected function describeCommand(Command $command, array $options = array()); + + /** + * Describes an Application instance. + * + * @param Application $application + * @param array $options + * + * @return string|mixed + */ + abstract protected function describeApplication(Application $application, array $options = array()); +} diff --git a/vendor/symfony/console/Descriptor/DescriptorInterface.php b/vendor/symfony/console/Descriptor/DescriptorInterface.php new file mode 100644 index 0000000..3929b6d --- /dev/null +++ b/vendor/symfony/console/Descriptor/DescriptorInterface.php @@ -0,0 +1,31 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Descriptor; + +use Symfony\Component\Console\Output\OutputInterface; + +/** + * Descriptor interface. + * + * @author Jean-François Simon + */ +interface DescriptorInterface +{ + /** + * Describes an InputArgument instance. + * + * @param OutputInterface $output + * @param object $object + * @param array $options + */ + public function describe(OutputInterface $output, $object, array $options = array()); +} diff --git a/vendor/symfony/console/Descriptor/JsonDescriptor.php b/vendor/symfony/console/Descriptor/JsonDescriptor.php new file mode 100644 index 0000000..87e38fd --- /dev/null +++ b/vendor/symfony/console/Descriptor/JsonDescriptor.php @@ -0,0 +1,166 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Descriptor; + +use Symfony\Component\Console\Application; +use Symfony\Component\Console\Command\Command; +use Symfony\Component\Console\Input\InputArgument; +use Symfony\Component\Console\Input\InputDefinition; +use Symfony\Component\Console\Input\InputOption; + +/** + * JSON descriptor. + * + * @author Jean-François Simon + * + * @internal + */ +class JsonDescriptor extends Descriptor +{ + /** + * {@inheritdoc} + */ + protected function describeInputArgument(InputArgument $argument, array $options = array()) + { + $this->writeData($this->getInputArgumentData($argument), $options); + } + + /** + * {@inheritdoc} + */ + protected function describeInputOption(InputOption $option, array $options = array()) + { + $this->writeData($this->getInputOptionData($option), $options); + } + + /** + * {@inheritdoc} + */ + protected function describeInputDefinition(InputDefinition $definition, array $options = array()) + { + $this->writeData($this->getInputDefinitionData($definition), $options); + } + + /** + * {@inheritdoc} + */ + protected function describeCommand(Command $command, array $options = array()) + { + $this->writeData($this->getCommandData($command), $options); + } + + /** + * {@inheritdoc} + */ + protected function describeApplication(Application $application, array $options = array()) + { + $describedNamespace = isset($options['namespace']) ? $options['namespace'] : null; + $description = new ApplicationDescription($application, $describedNamespace); + $commands = array(); + + foreach ($description->getCommands() as $command) { + $commands[] = $this->getCommandData($command); + } + + $data = $describedNamespace + ? array('commands' => $commands, 'namespace' => $describedNamespace) + : array('commands' => $commands, 'namespaces' => array_values($description->getNamespaces())); + + $this->writeData($data, $options); + } + + /** + * Writes data as json. + * + * @param array $data + * @param array $options + * + * @return array|string + */ + private function writeData(array $data, array $options) + { + $this->write(json_encode($data, isset($options['json_encoding']) ? $options['json_encoding'] : 0)); + } + + /** + * @param InputArgument $argument + * + * @return array + */ + private function getInputArgumentData(InputArgument $argument) + { + return array( + 'name' => $argument->getName(), + 'is_required' => $argument->isRequired(), + 'is_array' => $argument->isArray(), + 'description' => preg_replace('/\s*[\r\n]\s*/', ' ', $argument->getDescription()), + 'default' => $argument->getDefault(), + ); + } + + /** + * @param InputOption $option + * + * @return array + */ + private function getInputOptionData(InputOption $option) + { + return array( + 'name' => '--'.$option->getName(), + 'shortcut' => $option->getShortcut() ? '-'.implode('|-', explode('|', $option->getShortcut())) : '', + 'accept_value' => $option->acceptValue(), + 'is_value_required' => $option->isValueRequired(), + 'is_multiple' => $option->isArray(), + 'description' => preg_replace('/\s*[\r\n]\s*/', ' ', $option->getDescription()), + 'default' => $option->getDefault(), + ); + } + + /** + * @param InputDefinition $definition + * + * @return array + */ + private function getInputDefinitionData(InputDefinition $definition) + { + $inputArguments = array(); + foreach ($definition->getArguments() as $name => $argument) { + $inputArguments[$name] = $this->getInputArgumentData($argument); + } + + $inputOptions = array(); + foreach ($definition->getOptions() as $name => $option) { + $inputOptions[$name] = $this->getInputOptionData($option); + } + + return array('arguments' => $inputArguments, 'options' => $inputOptions); + } + + /** + * @param Command $command + * + * @return array + */ + private function getCommandData(Command $command) + { + $command->getSynopsis(); + $command->mergeApplicationDefinition(false); + + return array( + 'name' => $command->getName(), + 'usage' => array_merge(array($command->getSynopsis()), $command->getUsages(), $command->getAliases()), + 'description' => $command->getDescription(), + 'help' => $command->getProcessedHelp(), + 'definition' => $this->getInputDefinitionData($command->getNativeDefinition()), + ); + } +} diff --git a/vendor/symfony/console/Descriptor/MarkdownDescriptor.php b/vendor/symfony/console/Descriptor/MarkdownDescriptor.php new file mode 100644 index 0000000..d3d76a4 --- /dev/null +++ b/vendor/symfony/console/Descriptor/MarkdownDescriptor.php @@ -0,0 +1,143 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Descriptor; + +use Symfony\Component\Console\Application; +use Symfony\Component\Console\Command\Command; +use Symfony\Component\Console\Input\InputArgument; +use Symfony\Component\Console\Input\InputDefinition; +use Symfony\Component\Console\Input\InputOption; + +/** + * Markdown descriptor. + * + * @author Jean-François Simon + * + * @internal + */ +class MarkdownDescriptor extends Descriptor +{ + /** + * {@inheritdoc} + */ + protected function describeInputArgument(InputArgument $argument, array $options = array()) + { + $this->write( + '**'.$argument->getName().':**'."\n\n" + .'* Name: '.($argument->getName() ?: '')."\n" + .'* Is required: '.($argument->isRequired() ? 'yes' : 'no')."\n" + .'* Is array: '.($argument->isArray() ? 'yes' : 'no')."\n" + .'* Description: '.preg_replace('/\s*[\r\n]\s*/', "\n ", $argument->getDescription() ?: '')."\n" + .'* Default: `'.str_replace("\n", '', var_export($argument->getDefault(), true)).'`' + ); + } + + /** + * {@inheritdoc} + */ + protected function describeInputOption(InputOption $option, array $options = array()) + { + $this->write( + '**'.$option->getName().':**'."\n\n" + .'* Name: `--'.$option->getName().'`'."\n" + .'* Shortcut: '.($option->getShortcut() ? '`-'.implode('|-', explode('|', $option->getShortcut())).'`' : '')."\n" + .'* Accept value: '.($option->acceptValue() ? 'yes' : 'no')."\n" + .'* Is value required: '.($option->isValueRequired() ? 'yes' : 'no')."\n" + .'* Is multiple: '.($option->isArray() ? 'yes' : 'no')."\n" + .'* Description: '.preg_replace('/\s*[\r\n]\s*/', "\n ", $option->getDescription() ?: '')."\n" + .'* Default: `'.str_replace("\n", '', var_export($option->getDefault(), true)).'`' + ); + } + + /** + * {@inheritdoc} + */ + protected function describeInputDefinition(InputDefinition $definition, array $options = array()) + { + if ($showArguments = count($definition->getArguments()) > 0) { + $this->write('### Arguments:'); + foreach ($definition->getArguments() as $argument) { + $this->write("\n\n"); + $this->write($this->describeInputArgument($argument)); + } + } + + if (count($definition->getOptions()) > 0) { + if ($showArguments) { + $this->write("\n\n"); + } + + $this->write('### Options:'); + foreach ($definition->getOptions() as $option) { + $this->write("\n\n"); + $this->write($this->describeInputOption($option)); + } + } + } + + /** + * {@inheritdoc} + */ + protected function describeCommand(Command $command, array $options = array()) + { + $command->getSynopsis(); + $command->mergeApplicationDefinition(false); + + $this->write( + $command->getName()."\n" + .str_repeat('-', strlen($command->getName()))."\n\n" + .'* Description: '.($command->getDescription() ?: '')."\n" + .'* Usage:'."\n\n" + .array_reduce(array_merge(array($command->getSynopsis()), $command->getAliases(), $command->getUsages()), function ($carry, $usage) { + return $carry .= ' * `'.$usage.'`'."\n"; + }) + ); + + if ($help = $command->getProcessedHelp()) { + $this->write("\n"); + $this->write($help); + } + + if ($command->getNativeDefinition()) { + $this->write("\n\n"); + $this->describeInputDefinition($command->getNativeDefinition()); + } + } + + /** + * {@inheritdoc} + */ + protected function describeApplication(Application $application, array $options = array()) + { + $describedNamespace = isset($options['namespace']) ? $options['namespace'] : null; + $description = new ApplicationDescription($application, $describedNamespace); + + $this->write($application->getName()."\n".str_repeat('=', strlen($application->getName()))); + + foreach ($description->getNamespaces() as $namespace) { + if (ApplicationDescription::GLOBAL_NAMESPACE !== $namespace['id']) { + $this->write("\n\n"); + $this->write('**'.$namespace['id'].':**'); + } + + $this->write("\n\n"); + $this->write(implode("\n", array_map(function ($commandName) { + return '* '.$commandName; + }, $namespace['commands']))); + } + + foreach ($description->getCommands() as $command) { + $this->write("\n\n"); + $this->write($this->describeCommand($command)); + } + } +} diff --git a/vendor/symfony/console/Descriptor/TextDescriptor.php b/vendor/symfony/console/Descriptor/TextDescriptor.php new file mode 100644 index 0000000..57e09e4 --- /dev/null +++ b/vendor/symfony/console/Descriptor/TextDescriptor.php @@ -0,0 +1,287 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Descriptor; + +use Symfony\Component\Console\Application; +use Symfony\Component\Console\Command\Command; +use Symfony\Component\Console\Input\InputArgument; +use Symfony\Component\Console\Input\InputDefinition; +use Symfony\Component\Console\Input\InputOption; + +/** + * Text descriptor. + * + * @author Jean-François Simon + * + * @internal + */ +class TextDescriptor extends Descriptor +{ + /** + * {@inheritdoc} + */ + protected function describeInputArgument(InputArgument $argument, array $options = array()) + { + if (null !== $argument->getDefault() && (!is_array($argument->getDefault()) || count($argument->getDefault()))) { + $default = sprintf(' [default: %s]', $this->formatDefaultValue($argument->getDefault())); + } else { + $default = ''; + } + + $totalWidth = isset($options['total_width']) ? $options['total_width'] : strlen($argument->getName()); + $spacingWidth = $totalWidth - strlen($argument->getName()) + 2; + + $this->writeText(sprintf(' %s%s%s%s', + $argument->getName(), + str_repeat(' ', $spacingWidth), + // + 17 = 2 spaces + + + 2 spaces + preg_replace('/\s*[\r\n]\s*/', "\n".str_repeat(' ', $totalWidth + 17), $argument->getDescription()), + $default + ), $options); + } + + /** + * {@inheritdoc} + */ + protected function describeInputOption(InputOption $option, array $options = array()) + { + if ($option->acceptValue() && null !== $option->getDefault() && (!is_array($option->getDefault()) || count($option->getDefault()))) { + $default = sprintf(' [default: %s]', $this->formatDefaultValue($option->getDefault())); + } else { + $default = ''; + } + + $value = ''; + if ($option->acceptValue()) { + $value = '='.strtoupper($option->getName()); + + if ($option->isValueOptional()) { + $value = '['.$value.']'; + } + } + + $totalWidth = isset($options['total_width']) ? $options['total_width'] : $this->calculateTotalWidthForOptions(array($option)); + $synopsis = sprintf('%s%s', + $option->getShortcut() ? sprintf('-%s, ', $option->getShortcut()) : ' ', + sprintf('--%s%s', $option->getName(), $value) + ); + + $spacingWidth = $totalWidth - strlen($synopsis) + 2; + + $this->writeText(sprintf(' %s%s%s%s%s', + $synopsis, + str_repeat(' ', $spacingWidth), + // + 17 = 2 spaces + + + 2 spaces + preg_replace('/\s*[\r\n]\s*/', "\n".str_repeat(' ', $totalWidth + 17), $option->getDescription()), + $default, + $option->isArray() ? ' (multiple values allowed)' : '' + ), $options); + } + + /** + * {@inheritdoc} + */ + protected function describeInputDefinition(InputDefinition $definition, array $options = array()) + { + $totalWidth = $this->calculateTotalWidthForOptions($definition->getOptions()); + foreach ($definition->getArguments() as $argument) { + $totalWidth = max($totalWidth, strlen($argument->getName())); + } + + if ($definition->getArguments()) { + $this->writeText('Arguments:', $options); + $this->writeText("\n"); + foreach ($definition->getArguments() as $argument) { + $this->describeInputArgument($argument, array_merge($options, array('total_width' => $totalWidth))); + $this->writeText("\n"); + } + } + + if ($definition->getArguments() && $definition->getOptions()) { + $this->writeText("\n"); + } + + if ($definition->getOptions()) { + $laterOptions = array(); + + $this->writeText('Options:', $options); + foreach ($definition->getOptions() as $option) { + if (strlen($option->getShortcut()) > 1) { + $laterOptions[] = $option; + continue; + } + $this->writeText("\n"); + $this->describeInputOption($option, array_merge($options, array('total_width' => $totalWidth))); + } + foreach ($laterOptions as $option) { + $this->writeText("\n"); + $this->describeInputOption($option, array_merge($options, array('total_width' => $totalWidth))); + } + } + } + + /** + * {@inheritdoc} + */ + protected function describeCommand(Command $command, array $options = array()) + { + $command->getSynopsis(true); + $command->getSynopsis(false); + $command->mergeApplicationDefinition(false); + + $this->writeText('Usage:', $options); + foreach (array_merge(array($command->getSynopsis(true)), $command->getAliases(), $command->getUsages()) as $usage) { + $this->writeText("\n"); + $this->writeText(' '.$usage, $options); + } + $this->writeText("\n"); + + $definition = $command->getNativeDefinition(); + if ($definition->getOptions() || $definition->getArguments()) { + $this->writeText("\n"); + $this->describeInputDefinition($definition, $options); + $this->writeText("\n"); + } + + if ($help = $command->getProcessedHelp()) { + $this->writeText("\n"); + $this->writeText('Help:', $options); + $this->writeText("\n"); + $this->writeText(' '.str_replace("\n", "\n ", $help), $options); + $this->writeText("\n"); + } + } + + /** + * {@inheritdoc} + */ + protected function describeApplication(Application $application, array $options = array()) + { + $describedNamespace = isset($options['namespace']) ? $options['namespace'] : null; + $description = new ApplicationDescription($application, $describedNamespace); + + if (isset($options['raw_text']) && $options['raw_text']) { + $width = $this->getColumnWidth($description->getCommands()); + + foreach ($description->getCommands() as $command) { + $this->writeText(sprintf("%-${width}s %s", $command->getName(), $command->getDescription()), $options); + $this->writeText("\n"); + } + } else { + if ('' != $help = $application->getHelp()) { + $this->writeText("$help\n\n", $options); + } + + $this->writeText("Usage:\n", $options); + $this->writeText(" command [options] [arguments]\n\n", $options); + + $this->describeInputDefinition(new InputDefinition($application->getDefinition()->getOptions()), $options); + + $this->writeText("\n"); + $this->writeText("\n"); + + $width = $this->getColumnWidth($description->getCommands()); + + if ($describedNamespace) { + $this->writeText(sprintf('Available commands for the "%s" namespace:', $describedNamespace), $options); + } else { + $this->writeText('Available commands:', $options); + } + + // add commands by namespace + foreach ($description->getNamespaces() as $namespace) { + if (!$describedNamespace && ApplicationDescription::GLOBAL_NAMESPACE !== $namespace['id']) { + $this->writeText("\n"); + $this->writeText(' '.$namespace['id'].'', $options); + } + + foreach ($namespace['commands'] as $name) { + $this->writeText("\n"); + $spacingWidth = $width - strlen($name); + $this->writeText(sprintf(' %s%s%s', $name, str_repeat(' ', $spacingWidth), $description->getCommand($name)->getDescription()), $options); + } + } + + $this->writeText("\n"); + } + } + + /** + * {@inheritdoc} + */ + private function writeText($content, array $options = array()) + { + $this->write( + isset($options['raw_text']) && $options['raw_text'] ? strip_tags($content) : $content, + isset($options['raw_output']) ? !$options['raw_output'] : true + ); + } + + /** + * Formats input option/argument default value. + * + * @param mixed $default + * + * @return string + */ + private function formatDefaultValue($default) + { + if (PHP_VERSION_ID < 50400) { + return str_replace('\/', '/', json_encode($default)); + } + + return json_encode($default, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE); + } + + /** + * @param Command[] $commands + * + * @return int + */ + private function getColumnWidth(array $commands) + { + $widths = array(); + + foreach ($commands as $command) { + $widths[] = strlen($command->getName()); + foreach ($command->getAliases() as $alias) { + $widths[] = strlen($alias); + } + } + + return max($widths) + 2; + } + + /** + * @param InputOption[] $options + * + * @return int + */ + private function calculateTotalWidthForOptions($options) + { + $totalWidth = 0; + foreach ($options as $option) { + // "-" + shortcut + ", --" + name + $nameLength = 1 + max(strlen($option->getShortcut()), 1) + 4 + strlen($option->getName()); + + if ($option->acceptValue()) { + $valueLength = 1 + strlen($option->getName()); // = + value + $valueLength += $option->isValueOptional() ? 2 : 0; // [ + ] + + $nameLength += $valueLength; + } + $totalWidth = max($totalWidth, $nameLength); + } + + return $totalWidth; + } +} diff --git a/vendor/symfony/console/Descriptor/XmlDescriptor.php b/vendor/symfony/console/Descriptor/XmlDescriptor.php new file mode 100644 index 0000000..b5676be --- /dev/null +++ b/vendor/symfony/console/Descriptor/XmlDescriptor.php @@ -0,0 +1,263 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Descriptor; + +use Symfony\Component\Console\Application; +use Symfony\Component\Console\Command\Command; +use Symfony\Component\Console\Input\InputArgument; +use Symfony\Component\Console\Input\InputDefinition; +use Symfony\Component\Console\Input\InputOption; + +/** + * XML descriptor. + * + * @author Jean-François Simon + * + * @internal + */ +class XmlDescriptor extends Descriptor +{ + /** + * @param InputDefinition $definition + * + * @return \DOMDocument + */ + public function getInputDefinitionDocument(InputDefinition $definition) + { + $dom = new \DOMDocument('1.0', 'UTF-8'); + $dom->appendChild($definitionXML = $dom->createElement('definition')); + + $definitionXML->appendChild($argumentsXML = $dom->createElement('arguments')); + foreach ($definition->getArguments() as $argument) { + $this->appendDocument($argumentsXML, $this->getInputArgumentDocument($argument)); + } + + $definitionXML->appendChild($optionsXML = $dom->createElement('options')); + foreach ($definition->getOptions() as $option) { + $this->appendDocument($optionsXML, $this->getInputOptionDocument($option)); + } + + return $dom; + } + + /** + * @param Command $command + * + * @return \DOMDocument + */ + public function getCommandDocument(Command $command) + { + $dom = new \DOMDocument('1.0', 'UTF-8'); + $dom->appendChild($commandXML = $dom->createElement('command')); + + $command->getSynopsis(); + $command->mergeApplicationDefinition(false); + + $commandXML->setAttribute('id', $command->getName()); + $commandXML->setAttribute('name', $command->getName()); + + $commandXML->appendChild($usagesXML = $dom->createElement('usages')); + + foreach (array_merge(array($command->getSynopsis()), $command->getAliases(), $command->getUsages()) as $usage) { + $usagesXML->appendChild($dom->createElement('usage', $usage)); + } + + $commandXML->appendChild($descriptionXML = $dom->createElement('description')); + $descriptionXML->appendChild($dom->createTextNode(str_replace("\n", "\n ", $command->getDescription()))); + + $commandXML->appendChild($helpXML = $dom->createElement('help')); + $helpXML->appendChild($dom->createTextNode(str_replace("\n", "\n ", $command->getProcessedHelp()))); + + $definitionXML = $this->getInputDefinitionDocument($command->getNativeDefinition()); + $this->appendDocument($commandXML, $definitionXML->getElementsByTagName('definition')->item(0)); + + return $dom; + } + + /** + * @param Application $application + * @param string|null $namespace + * + * @return \DOMDocument + */ + public function getApplicationDocument(Application $application, $namespace = null) + { + $dom = new \DOMDocument('1.0', 'UTF-8'); + $dom->appendChild($rootXml = $dom->createElement('symfony')); + + if ($application->getName() !== 'UNKNOWN') { + $rootXml->setAttribute('name', $application->getName()); + if ($application->getVersion() !== 'UNKNOWN') { + $rootXml->setAttribute('version', $application->getVersion()); + } + } + + $rootXml->appendChild($commandsXML = $dom->createElement('commands')); + + $description = new ApplicationDescription($application, $namespace); + + if ($namespace) { + $commandsXML->setAttribute('namespace', $namespace); + } + + foreach ($description->getCommands() as $command) { + $this->appendDocument($commandsXML, $this->getCommandDocument($command)); + } + + if (!$namespace) { + $rootXml->appendChild($namespacesXML = $dom->createElement('namespaces')); + + foreach ($description->getNamespaces() as $namespaceDescription) { + $namespacesXML->appendChild($namespaceArrayXML = $dom->createElement('namespace')); + $namespaceArrayXML->setAttribute('id', $namespaceDescription['id']); + + foreach ($namespaceDescription['commands'] as $name) { + $namespaceArrayXML->appendChild($commandXML = $dom->createElement('command')); + $commandXML->appendChild($dom->createTextNode($name)); + } + } + } + + return $dom; + } + + /** + * {@inheritdoc} + */ + protected function describeInputArgument(InputArgument $argument, array $options = array()) + { + $this->writeDocument($this->getInputArgumentDocument($argument)); + } + + /** + * {@inheritdoc} + */ + protected function describeInputOption(InputOption $option, array $options = array()) + { + $this->writeDocument($this->getInputOptionDocument($option)); + } + + /** + * {@inheritdoc} + */ + protected function describeInputDefinition(InputDefinition $definition, array $options = array()) + { + $this->writeDocument($this->getInputDefinitionDocument($definition)); + } + + /** + * {@inheritdoc} + */ + protected function describeCommand(Command $command, array $options = array()) + { + $this->writeDocument($this->getCommandDocument($command)); + } + + /** + * {@inheritdoc} + */ + protected function describeApplication(Application $application, array $options = array()) + { + $this->writeDocument($this->getApplicationDocument($application, isset($options['namespace']) ? $options['namespace'] : null)); + } + + /** + * Appends document children to parent node. + * + * @param \DOMNode $parentNode + * @param \DOMNode $importedParent + */ + private function appendDocument(\DOMNode $parentNode, \DOMNode $importedParent) + { + foreach ($importedParent->childNodes as $childNode) { + $parentNode->appendChild($parentNode->ownerDocument->importNode($childNode, true)); + } + } + + /** + * Writes DOM document. + * + * @param \DOMDocument $dom + * + * @return \DOMDocument|string + */ + private function writeDocument(\DOMDocument $dom) + { + $dom->formatOutput = true; + $this->write($dom->saveXML()); + } + + /** + * @param InputArgument $argument + * + * @return \DOMDocument + */ + private function getInputArgumentDocument(InputArgument $argument) + { + $dom = new \DOMDocument('1.0', 'UTF-8'); + + $dom->appendChild($objectXML = $dom->createElement('argument')); + $objectXML->setAttribute('name', $argument->getName()); + $objectXML->setAttribute('is_required', $argument->isRequired() ? 1 : 0); + $objectXML->setAttribute('is_array', $argument->isArray() ? 1 : 0); + $objectXML->appendChild($descriptionXML = $dom->createElement('description')); + $descriptionXML->appendChild($dom->createTextNode($argument->getDescription())); + + $objectXML->appendChild($defaultsXML = $dom->createElement('defaults')); + $defaults = is_array($argument->getDefault()) ? $argument->getDefault() : (is_bool($argument->getDefault()) ? array(var_export($argument->getDefault(), true)) : ($argument->getDefault() ? array($argument->getDefault()) : array())); + foreach ($defaults as $default) { + $defaultsXML->appendChild($defaultXML = $dom->createElement('default')); + $defaultXML->appendChild($dom->createTextNode($default)); + } + + return $dom; + } + + /** + * @param InputOption $option + * + * @return \DOMDocument + */ + private function getInputOptionDocument(InputOption $option) + { + $dom = new \DOMDocument('1.0', 'UTF-8'); + + $dom->appendChild($objectXML = $dom->createElement('option')); + $objectXML->setAttribute('name', '--'.$option->getName()); + $pos = strpos($option->getShortcut(), '|'); + if (false !== $pos) { + $objectXML->setAttribute('shortcut', '-'.substr($option->getShortcut(), 0, $pos)); + $objectXML->setAttribute('shortcuts', '-'.implode('|-', explode('|', $option->getShortcut()))); + } else { + $objectXML->setAttribute('shortcut', $option->getShortcut() ? '-'.$option->getShortcut() : ''); + } + $objectXML->setAttribute('accept_value', $option->acceptValue() ? 1 : 0); + $objectXML->setAttribute('is_value_required', $option->isValueRequired() ? 1 : 0); + $objectXML->setAttribute('is_multiple', $option->isArray() ? 1 : 0); + $objectXML->appendChild($descriptionXML = $dom->createElement('description')); + $descriptionXML->appendChild($dom->createTextNode($option->getDescription())); + + if ($option->acceptValue()) { + $defaults = is_array($option->getDefault()) ? $option->getDefault() : (is_bool($option->getDefault()) ? array(var_export($option->getDefault(), true)) : ($option->getDefault() ? array($option->getDefault()) : array())); + $objectXML->appendChild($defaultsXML = $dom->createElement('defaults')); + + if (!empty($defaults)) { + foreach ($defaults as $default) { + $defaultsXML->appendChild($defaultXML = $dom->createElement('default')); + $defaultXML->appendChild($dom->createTextNode($default)); + } + } + } + + return $dom; + } +} diff --git a/vendor/symfony/console/Event/ConsoleCommandEvent.php b/vendor/symfony/console/Event/ConsoleCommandEvent.php new file mode 100644 index 0000000..92adf1e --- /dev/null +++ b/vendor/symfony/console/Event/ConsoleCommandEvent.php @@ -0,0 +1,62 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Event; + +/** + * Allows to do things before the command is executed, like skipping the command or changing the input. + * + * @author Fabien Potencier + */ +class ConsoleCommandEvent extends ConsoleEvent +{ + /** + * The return code for skipped commands, this will also be passed into the terminate event. + */ + const RETURN_CODE_DISABLED = 113; + + /** + * Indicates if the command should be run or skipped. + * + * @var bool + */ + private $commandShouldRun = true; + + /** + * Disables the command, so it won't be run. + * + * @return bool + */ + public function disableCommand() + { + return $this->commandShouldRun = false; + } + + /** + * Enables the command. + * + * @return bool + */ + public function enableCommand() + { + return $this->commandShouldRun = true; + } + + /** + * Returns true if the command is runnable, false otherwise. + * + * @return bool + */ + public function commandShouldRun() + { + return $this->commandShouldRun; + } +} diff --git a/vendor/symfony/console/Event/ConsoleEvent.php b/vendor/symfony/console/Event/ConsoleEvent.php new file mode 100644 index 0000000..ab620c4 --- /dev/null +++ b/vendor/symfony/console/Event/ConsoleEvent.php @@ -0,0 +1,67 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Event; + +use Symfony\Component\Console\Command\Command; +use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Output\OutputInterface; +use Symfony\Component\EventDispatcher\Event; + +/** + * Allows to inspect input and output of a command. + * + * @author Francesco Levorato + */ +class ConsoleEvent extends Event +{ + protected $command; + + private $input; + private $output; + + public function __construct(Command $command, InputInterface $input, OutputInterface $output) + { + $this->command = $command; + $this->input = $input; + $this->output = $output; + } + + /** + * Gets the command that is executed. + * + * @return Command A Command instance + */ + public function getCommand() + { + return $this->command; + } + + /** + * Gets the input instance. + * + * @return InputInterface An InputInterface instance + */ + public function getInput() + { + return $this->input; + } + + /** + * Gets the output instance. + * + * @return OutputInterface An OutputInterface instance + */ + public function getOutput() + { + return $this->output; + } +} diff --git a/vendor/symfony/console/Event/ConsoleExceptionEvent.php b/vendor/symfony/console/Event/ConsoleExceptionEvent.php new file mode 100644 index 0000000..603b7ee --- /dev/null +++ b/vendor/symfony/console/Event/ConsoleExceptionEvent.php @@ -0,0 +1,67 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Event; + +use Symfony\Component\Console\Command\Command; +use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Output\OutputInterface; + +/** + * Allows to handle exception thrown in a command. + * + * @author Fabien Potencier + */ +class ConsoleExceptionEvent extends ConsoleEvent +{ + private $exception; + private $exitCode; + + public function __construct(Command $command, InputInterface $input, OutputInterface $output, \Exception $exception, $exitCode) + { + parent::__construct($command, $input, $output); + + $this->setException($exception); + $this->exitCode = (int) $exitCode; + } + + /** + * Returns the thrown exception. + * + * @return \Exception The thrown exception + */ + public function getException() + { + return $this->exception; + } + + /** + * Replaces the thrown exception. + * + * This exception will be thrown if no response is set in the event. + * + * @param \Exception $exception The thrown exception + */ + public function setException(\Exception $exception) + { + $this->exception = $exception; + } + + /** + * Gets the exit code. + * + * @return int The command exit code + */ + public function getExitCode() + { + return $this->exitCode; + } +} diff --git a/vendor/symfony/console/Event/ConsoleTerminateEvent.php b/vendor/symfony/console/Event/ConsoleTerminateEvent.php new file mode 100644 index 0000000..b6a5d7c --- /dev/null +++ b/vendor/symfony/console/Event/ConsoleTerminateEvent.php @@ -0,0 +1,58 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Event; + +use Symfony\Component\Console\Command\Command; +use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Output\OutputInterface; + +/** + * Allows to manipulate the exit code of a command after its execution. + * + * @author Francesco Levorato + */ +class ConsoleTerminateEvent extends ConsoleEvent +{ + /** + * The exit code of the command. + * + * @var int + */ + private $exitCode; + + public function __construct(Command $command, InputInterface $input, OutputInterface $output, $exitCode) + { + parent::__construct($command, $input, $output); + + $this->setExitCode($exitCode); + } + + /** + * Sets the exit code. + * + * @param int $exitCode The command exit code + */ + public function setExitCode($exitCode) + { + $this->exitCode = (int) $exitCode; + } + + /** + * Gets the exit code. + * + * @return int The command exit code + */ + public function getExitCode() + { + return $this->exitCode; + } +} diff --git a/vendor/symfony/console/Formatter/OutputFormatter.php b/vendor/symfony/console/Formatter/OutputFormatter.php new file mode 100644 index 0000000..331b204 --- /dev/null +++ b/vendor/symfony/console/Formatter/OutputFormatter.php @@ -0,0 +1,242 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Formatter; + +/** + * Formatter class for console output. + * + * @author Konstantin Kudryashov + * + * @api + */ +class OutputFormatter implements OutputFormatterInterface +{ + private $decorated; + private $styles = array(); + private $styleStack; + + /** + * Escapes "<" special char in given text. + * + * @param string $text Text to escape + * + * @return string Escaped text + */ + public static function escape($text) + { + return preg_replace('/([^\\\\]?) FormatterStyle" instances + * + * @api + */ + public function __construct($decorated = false, array $styles = array()) + { + $this->decorated = (bool) $decorated; + + $this->setStyle('error', new OutputFormatterStyle('white', 'red')); + $this->setStyle('info', new OutputFormatterStyle('green')); + $this->setStyle('comment', new OutputFormatterStyle('yellow')); + $this->setStyle('question', new OutputFormatterStyle('black', 'cyan')); + + foreach ($styles as $name => $style) { + $this->setStyle($name, $style); + } + + $this->styleStack = new OutputFormatterStyleStack(); + } + + /** + * Sets the decorated flag. + * + * @param bool $decorated Whether to decorate the messages or not + * + * @api + */ + public function setDecorated($decorated) + { + $this->decorated = (bool) $decorated; + } + + /** + * Gets the decorated flag. + * + * @return bool true if the output will decorate messages, false otherwise + * + * @api + */ + public function isDecorated() + { + return $this->decorated; + } + + /** + * Sets a new style. + * + * @param string $name The style name + * @param OutputFormatterStyleInterface $style The style instance + * + * @api + */ + public function setStyle($name, OutputFormatterStyleInterface $style) + { + $this->styles[strtolower($name)] = $style; + } + + /** + * Checks if output formatter has style with specified name. + * + * @param string $name + * + * @return bool + * + * @api + */ + public function hasStyle($name) + { + return isset($this->styles[strtolower($name)]); + } + + /** + * Gets style options from style with specified name. + * + * @param string $name + * + * @return OutputFormatterStyleInterface + * + * @throws \InvalidArgumentException When style isn't defined + * + * @api + */ + public function getStyle($name) + { + if (!$this->hasStyle($name)) { + throw new \InvalidArgumentException(sprintf('Undefined style: %s', $name)); + } + + return $this->styles[strtolower($name)]; + } + + /** + * Formats a message according to the given styles. + * + * @param string $message The message to style + * + * @return string The styled message + * + * @api + */ + public function format($message) + { + $message = (string) $message; + $offset = 0; + $output = ''; + $tagRegex = '[a-z][a-z0-9_=;-]*'; + preg_match_all("#<(($tagRegex) | /($tagRegex)?)>#ix", $message, $matches, PREG_OFFSET_CAPTURE); + foreach ($matches[0] as $i => $match) { + $pos = $match[1]; + $text = $match[0]; + + if (0 != $pos && '\\' == $message[$pos - 1]) { + continue; + } + + // add the text up to the next tag + $output .= $this->applyCurrentStyle(substr($message, $offset, $pos - $offset)); + $offset = $pos + strlen($text); + + // opening tag? + if ($open = '/' != $text[1]) { + $tag = $matches[1][$i][0]; + } else { + $tag = isset($matches[3][$i][0]) ? $matches[3][$i][0] : ''; + } + + if (!$open && !$tag) { + // + $this->styleStack->pop(); + } elseif (false === $style = $this->createStyleFromString(strtolower($tag))) { + $output .= $this->applyCurrentStyle($text); + } elseif ($open) { + $this->styleStack->push($style); + } else { + $this->styleStack->pop($style); + } + } + + $output .= $this->applyCurrentStyle(substr($message, $offset)); + + return str_replace('\\<', '<', $output); + } + + /** + * @return OutputFormatterStyleStack + */ + public function getStyleStack() + { + return $this->styleStack; + } + + /** + * Tries to create new style instance from string. + * + * @param string $string + * + * @return OutputFormatterStyle|bool false if string is not format string + */ + private function createStyleFromString($string) + { + if (isset($this->styles[$string])) { + return $this->styles[$string]; + } + + if (!preg_match_all('/([^=]+)=([^;]+)(;|$)/', strtolower($string), $matches, PREG_SET_ORDER)) { + return false; + } + + $style = new OutputFormatterStyle(); + foreach ($matches as $match) { + array_shift($match); + + if ('fg' == $match[0]) { + $style->setForeground($match[1]); + } elseif ('bg' == $match[0]) { + $style->setBackground($match[1]); + } else { + try { + $style->setOption($match[1]); + } catch (\InvalidArgumentException $e) { + return false; + } + } + } + + return $style; + } + + /** + * Applies current style from stack to text, if must be applied. + * + * @param string $text Input text + * + * @return string Styled text + */ + private function applyCurrentStyle($text) + { + return $this->isDecorated() && strlen($text) > 0 ? $this->styleStack->getCurrent()->apply($text) : $text; + } +} diff --git a/vendor/symfony/console/Formatter/OutputFormatterInterface.php b/vendor/symfony/console/Formatter/OutputFormatterInterface.php new file mode 100644 index 0000000..52efa31 --- /dev/null +++ b/vendor/symfony/console/Formatter/OutputFormatterInterface.php @@ -0,0 +1,83 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Formatter; + +/** + * Formatter interface for console output. + * + * @author Konstantin Kudryashov + * + * @api + */ +interface OutputFormatterInterface +{ + /** + * Sets the decorated flag. + * + * @param bool $decorated Whether to decorate the messages or not + * + * @api + */ + public function setDecorated($decorated); + + /** + * Gets the decorated flag. + * + * @return bool true if the output will decorate messages, false otherwise + * + * @api + */ + public function isDecorated(); + + /** + * Sets a new style. + * + * @param string $name The style name + * @param OutputFormatterStyleInterface $style The style instance + * + * @api + */ + public function setStyle($name, OutputFormatterStyleInterface $style); + + /** + * Checks if output formatter has style with specified name. + * + * @param string $name + * + * @return bool + * + * @api + */ + public function hasStyle($name); + + /** + * Gets style options from style with specified name. + * + * @param string $name + * + * @return OutputFormatterStyleInterface + * + * @api + */ + public function getStyle($name); + + /** + * Formats a message according to the given styles. + * + * @param string $message The message to style + * + * @return string The styled message + * + * @api + */ + public function format($message); +} diff --git a/vendor/symfony/console/Formatter/OutputFormatterStyle.php b/vendor/symfony/console/Formatter/OutputFormatterStyle.php new file mode 100644 index 0000000..ee62cdb --- /dev/null +++ b/vendor/symfony/console/Formatter/OutputFormatterStyle.php @@ -0,0 +1,229 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Formatter; + +/** + * Formatter style class for defining styles. + * + * @author Konstantin Kudryashov + * + * @api + */ +class OutputFormatterStyle implements OutputFormatterStyleInterface +{ + private static $availableForegroundColors = array( + 'black' => array('set' => 30, 'unset' => 39), + 'red' => array('set' => 31, 'unset' => 39), + 'green' => array('set' => 32, 'unset' => 39), + 'yellow' => array('set' => 33, 'unset' => 39), + 'blue' => array('set' => 34, 'unset' => 39), + 'magenta' => array('set' => 35, 'unset' => 39), + 'cyan' => array('set' => 36, 'unset' => 39), + 'white' => array('set' => 37, 'unset' => 39), + 'default' => array('set' => 39, 'unset' => 39), + ); + private static $availableBackgroundColors = array( + 'black' => array('set' => 40, 'unset' => 49), + 'red' => array('set' => 41, 'unset' => 49), + 'green' => array('set' => 42, 'unset' => 49), + 'yellow' => array('set' => 43, 'unset' => 49), + 'blue' => array('set' => 44, 'unset' => 49), + 'magenta' => array('set' => 45, 'unset' => 49), + 'cyan' => array('set' => 46, 'unset' => 49), + 'white' => array('set' => 47, 'unset' => 49), + 'default' => array('set' => 49, 'unset' => 49), + ); + private static $availableOptions = array( + 'bold' => array('set' => 1, 'unset' => 22), + 'underscore' => array('set' => 4, 'unset' => 24), + 'blink' => array('set' => 5, 'unset' => 25), + 'reverse' => array('set' => 7, 'unset' => 27), + 'conceal' => array('set' => 8, 'unset' => 28), + ); + + private $foreground; + private $background; + private $options = array(); + + /** + * Initializes output formatter style. + * + * @param string|null $foreground The style foreground color name + * @param string|null $background The style background color name + * @param array $options The style options + * + * @api + */ + public function __construct($foreground = null, $background = null, array $options = array()) + { + if (null !== $foreground) { + $this->setForeground($foreground); + } + if (null !== $background) { + $this->setBackground($background); + } + if (count($options)) { + $this->setOptions($options); + } + } + + /** + * Sets style foreground color. + * + * @param string|null $color The color name + * + * @throws \InvalidArgumentException When the color name isn't defined + * + * @api + */ + public function setForeground($color = null) + { + if (null === $color) { + $this->foreground = null; + + return; + } + + if (!isset(static::$availableForegroundColors[$color])) { + throw new \InvalidArgumentException(sprintf( + 'Invalid foreground color specified: "%s". Expected one of (%s)', + $color, + implode(', ', array_keys(static::$availableForegroundColors)) + )); + } + + $this->foreground = static::$availableForegroundColors[$color]; + } + + /** + * Sets style background color. + * + * @param string|null $color The color name + * + * @throws \InvalidArgumentException When the color name isn't defined + * + * @api + */ + public function setBackground($color = null) + { + if (null === $color) { + $this->background = null; + + return; + } + + if (!isset(static::$availableBackgroundColors[$color])) { + throw new \InvalidArgumentException(sprintf( + 'Invalid background color specified: "%s". Expected one of (%s)', + $color, + implode(', ', array_keys(static::$availableBackgroundColors)) + )); + } + + $this->background = static::$availableBackgroundColors[$color]; + } + + /** + * Sets some specific style option. + * + * @param string $option The option name + * + * @throws \InvalidArgumentException When the option name isn't defined + * + * @api + */ + public function setOption($option) + { + if (!isset(static::$availableOptions[$option])) { + throw new \InvalidArgumentException(sprintf( + 'Invalid option specified: "%s". Expected one of (%s)', + $option, + implode(', ', array_keys(static::$availableOptions)) + )); + } + + if (!in_array(static::$availableOptions[$option], $this->options)) { + $this->options[] = static::$availableOptions[$option]; + } + } + + /** + * Unsets some specific style option. + * + * @param string $option The option name + * + * @throws \InvalidArgumentException When the option name isn't defined + */ + public function unsetOption($option) + { + if (!isset(static::$availableOptions[$option])) { + throw new \InvalidArgumentException(sprintf( + 'Invalid option specified: "%s". Expected one of (%s)', + $option, + implode(', ', array_keys(static::$availableOptions)) + )); + } + + $pos = array_search(static::$availableOptions[$option], $this->options); + if (false !== $pos) { + unset($this->options[$pos]); + } + } + + /** + * Sets multiple style options at once. + * + * @param array $options + */ + public function setOptions(array $options) + { + $this->options = array(); + + foreach ($options as $option) { + $this->setOption($option); + } + } + + /** + * Applies the style to a given text. + * + * @param string $text The text to style + * + * @return string + */ + public function apply($text) + { + $setCodes = array(); + $unsetCodes = array(); + + if (null !== $this->foreground) { + $setCodes[] = $this->foreground['set']; + $unsetCodes[] = $this->foreground['unset']; + } + if (null !== $this->background) { + $setCodes[] = $this->background['set']; + $unsetCodes[] = $this->background['unset']; + } + if (count($this->options)) { + foreach ($this->options as $option) { + $setCodes[] = $option['set']; + $unsetCodes[] = $option['unset']; + } + } + + if (0 === count($setCodes)) { + return $text; + } + + return sprintf("\033[%sm%s\033[%sm", implode(';', $setCodes), $text, implode(';', $unsetCodes)); + } +} diff --git a/vendor/symfony/console/Formatter/OutputFormatterStyleInterface.php b/vendor/symfony/console/Formatter/OutputFormatterStyleInterface.php new file mode 100644 index 0000000..e8642b3 --- /dev/null +++ b/vendor/symfony/console/Formatter/OutputFormatterStyleInterface.php @@ -0,0 +1,72 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Formatter; + +/** + * Formatter style interface for defining styles. + * + * @author Konstantin Kudryashov + * + * @api + */ +interface OutputFormatterStyleInterface +{ + /** + * Sets style foreground color. + * + * @param string $color The color name + * + * @api + */ + public function setForeground($color = null); + + /** + * Sets style background color. + * + * @param string $color The color name + * + * @api + */ + public function setBackground($color = null); + + /** + * Sets some specific style option. + * + * @param string $option The option name + * + * @api + */ + public function setOption($option); + + /** + * Unsets some specific style option. + * + * @param string $option The option name + */ + public function unsetOption($option); + + /** + * Sets multiple style options at once. + * + * @param array $options + */ + public function setOptions(array $options); + + /** + * Applies the style to a given text. + * + * @param string $text The text to style + * + * @return string + */ + public function apply($text); +} diff --git a/vendor/symfony/console/Formatter/OutputFormatterStyleStack.php b/vendor/symfony/console/Formatter/OutputFormatterStyleStack.php new file mode 100644 index 0000000..b64c87f --- /dev/null +++ b/vendor/symfony/console/Formatter/OutputFormatterStyleStack.php @@ -0,0 +1,121 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Formatter; + +/** + * @author Jean-François Simon + */ +class OutputFormatterStyleStack +{ + /** + * @var OutputFormatterStyleInterface[] + */ + private $styles; + + /** + * @var OutputFormatterStyleInterface + */ + private $emptyStyle; + + /** + * Constructor. + * + * @param OutputFormatterStyleInterface|null $emptyStyle + */ + public function __construct(OutputFormatterStyleInterface $emptyStyle = null) + { + $this->emptyStyle = $emptyStyle ?: new OutputFormatterStyle(); + $this->reset(); + } + + /** + * Resets stack (ie. empty internal arrays). + */ + public function reset() + { + $this->styles = array(); + } + + /** + * Pushes a style in the stack. + * + * @param OutputFormatterStyleInterface $style + */ + public function push(OutputFormatterStyleInterface $style) + { + $this->styles[] = $style; + } + + /** + * Pops a style from the stack. + * + * @param OutputFormatterStyleInterface|null $style + * + * @return OutputFormatterStyleInterface + * + * @throws \InvalidArgumentException When style tags incorrectly nested + */ + public function pop(OutputFormatterStyleInterface $style = null) + { + if (empty($this->styles)) { + return $this->emptyStyle; + } + + if (null === $style) { + return array_pop($this->styles); + } + + foreach (array_reverse($this->styles, true) as $index => $stackedStyle) { + if ($style->apply('') === $stackedStyle->apply('')) { + $this->styles = array_slice($this->styles, 0, $index); + + return $stackedStyle; + } + } + + throw new \InvalidArgumentException('Incorrectly nested style tag found.'); + } + + /** + * Computes current style with stacks top codes. + * + * @return OutputFormatterStyle + */ + public function getCurrent() + { + if (empty($this->styles)) { + return $this->emptyStyle; + } + + return $this->styles[count($this->styles) - 1]; + } + + /** + * @param OutputFormatterStyleInterface $emptyStyle + * + * @return OutputFormatterStyleStack + */ + public function setEmptyStyle(OutputFormatterStyleInterface $emptyStyle) + { + $this->emptyStyle = $emptyStyle; + + return $this; + } + + /** + * @return OutputFormatterStyleInterface + */ + public function getEmptyStyle() + { + return $this->emptyStyle; + } +} diff --git a/vendor/symfony/console/Helper/DebugFormatterHelper.php b/vendor/symfony/console/Helper/DebugFormatterHelper.php new file mode 100644 index 0000000..1119b79 --- /dev/null +++ b/vendor/symfony/console/Helper/DebugFormatterHelper.php @@ -0,0 +1,127 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Helper; + +/** + * Helps outputting debug information when running an external program from a command. + * + * An external program can be a Process, an HTTP request, or anything else. + * + * @author Fabien Potencier + */ +class DebugFormatterHelper extends Helper +{ + private $colors = array('black', 'red', 'green', 'yellow', 'blue', 'magenta', 'cyan', 'white', 'default'); + private $started = array(); + private $count = -1; + + /** + * Starts a debug formatting session. + * + * @param string $id The id of the formatting session + * @param string $message The message to display + * @param string $prefix The prefix to use + * + * @return string + */ + public function start($id, $message, $prefix = 'RUN') + { + $this->started[$id] = array('border' => ++$this->count % count($this->colors)); + + return sprintf("%s %s %s\n", $this->getBorder($id), $prefix, $message); + } + + /** + * Adds progress to a formatting session. + * + * @param string $id The id of the formatting session + * @param string $buffer The message to display + * @param bool $error Whether to consider the buffer as error + * @param string $prefix The prefix for output + * @param string $errorPrefix The prefix for error output + * + * @return string + */ + public function progress($id, $buffer, $error = false, $prefix = 'OUT', $errorPrefix = 'ERR') + { + $message = ''; + + if ($error) { + if (isset($this->started[$id]['out'])) { + $message .= "\n"; + unset($this->started[$id]['out']); + } + if (!isset($this->started[$id]['err'])) { + $message .= sprintf('%s %s ', $this->getBorder($id), $errorPrefix); + $this->started[$id]['err'] = true; + } + + $message .= str_replace("\n", sprintf("\n%s %s ", $this->getBorder($id), $errorPrefix), $buffer); + } else { + if (isset($this->started[$id]['err'])) { + $message .= "\n"; + unset($this->started[$id]['err']); + } + if (!isset($this->started[$id]['out'])) { + $message .= sprintf('%s %s ', $this->getBorder($id), $prefix); + $this->started[$id]['out'] = true; + } + + $message .= str_replace("\n", sprintf("\n%s %s ", $this->getBorder($id), $prefix), $buffer); + } + + return $message; + } + + /** + * Stops a formatting session. + * + * @param string $id The id of the formatting session + * @param string $message The message to display + * @param bool $successful Whether to consider the result as success + * @param string $prefix The prefix for the end output + * + * @return string + */ + public function stop($id, $message, $successful, $prefix = 'RES') + { + $trailingEOL = isset($this->started[$id]['out']) || isset($this->started[$id]['err']) ? "\n" : ''; + + if ($successful) { + return sprintf("%s%s %s %s\n", $trailingEOL, $this->getBorder($id), $prefix, $message); + } + + $message = sprintf("%s%s %s %s\n", $trailingEOL, $this->getBorder($id), $prefix, $message); + + unset($this->started[$id]['out'], $this->started[$id]['err']); + + return $message; + } + + /** + * @param string $id The id of the formatting session + * + * @return string + */ + private function getBorder($id) + { + return sprintf(' ', $this->colors[$this->started[$id]['border']]); + } + + /** + * {@inheritdoc} + */ + public function getName() + { + return 'debug_formatter'; + } +} diff --git a/vendor/symfony/console/Helper/DescriptorHelper.php b/vendor/symfony/console/Helper/DescriptorHelper.php new file mode 100644 index 0000000..c324c99 --- /dev/null +++ b/vendor/symfony/console/Helper/DescriptorHelper.php @@ -0,0 +1,96 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Helper; + +use Symfony\Component\Console\Descriptor\DescriptorInterface; +use Symfony\Component\Console\Descriptor\JsonDescriptor; +use Symfony\Component\Console\Descriptor\MarkdownDescriptor; +use Symfony\Component\Console\Descriptor\TextDescriptor; +use Symfony\Component\Console\Descriptor\XmlDescriptor; +use Symfony\Component\Console\Output\OutputInterface; + +/** + * This class adds helper method to describe objects in various formats. + * + * @author Jean-François Simon + */ +class DescriptorHelper extends Helper +{ + /** + * @var DescriptorInterface[] + */ + private $descriptors = array(); + + /** + * Constructor. + */ + public function __construct() + { + $this + ->register('txt', new TextDescriptor()) + ->register('xml', new XmlDescriptor()) + ->register('json', new JsonDescriptor()) + ->register('md', new MarkdownDescriptor()) + ; + } + + /** + * Describes an object if supported. + * + * Available options are: + * * format: string, the output format name + * * raw_text: boolean, sets output type as raw + * + * @param OutputInterface $output + * @param object $object + * @param array $options + * + * @throws \InvalidArgumentException when the given format is not supported + */ + public function describe(OutputInterface $output, $object, array $options = array()) + { + $options = array_merge(array( + 'raw_text' => false, + 'format' => 'txt', + ), $options); + + if (!isset($this->descriptors[$options['format']])) { + throw new \InvalidArgumentException(sprintf('Unsupported format "%s".', $options['format'])); + } + + $descriptor = $this->descriptors[$options['format']]; + $descriptor->describe($output, $object, $options); + } + + /** + * Registers a descriptor. + * + * @param string $format + * @param DescriptorInterface $descriptor + * + * @return DescriptorHelper + */ + public function register($format, DescriptorInterface $descriptor) + { + $this->descriptors[$format] = $descriptor; + + return $this; + } + + /** + * {@inheritdoc} + */ + public function getName() + { + return 'descriptor'; + } +} diff --git a/vendor/symfony/console/Helper/DialogHelper.php b/vendor/symfony/console/Helper/DialogHelper.php new file mode 100644 index 0000000..a280b49 --- /dev/null +++ b/vendor/symfony/console/Helper/DialogHelper.php @@ -0,0 +1,483 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Helper; + +use Symfony\Component\Console\Output\OutputInterface; +use Symfony\Component\Console\Formatter\OutputFormatterStyle; + +/** + * The Dialog class provides helpers to interact with the user. + * + * @author Fabien Potencier + * + * @deprecated since version 2.5, to be removed in 3.0. + * Use {@link \Symfony\Component\Console\Helper\QuestionHelper} instead. + */ +class DialogHelper extends InputAwareHelper +{ + private $inputStream; + private static $shell; + private static $stty; + + public function __construct($triggerDeprecationError = true) + { + if ($triggerDeprecationError) { + @trigger_error('"Symfony\Component\Console\Helper\DialogHelper" is deprecated since version 2.5 and will be removed in 3.0. Use "Symfony\Component\Console\Helper\QuestionHelper" instead.', E_USER_DEPRECATED); + } + } + + /** + * Asks the user to select a value. + * + * @param OutputInterface $output An Output instance + * @param string|array $question The question to ask + * @param array $choices List of choices to pick from + * @param bool|string $default The default answer if the user enters nothing + * @param bool|int $attempts Max number of times to ask before giving up (false by default, which means infinite) + * @param string $errorMessage Message which will be shown if invalid value from choice list would be picked + * @param bool $multiselect Select more than one value separated by comma + * + * @return int|string|array The selected value or values (the key of the choices array) + * + * @throws \InvalidArgumentException + */ + public function select(OutputInterface $output, $question, $choices, $default = null, $attempts = false, $errorMessage = 'Value "%s" is invalid', $multiselect = false) + { + $width = max(array_map('strlen', array_keys($choices))); + + $messages = (array) $question; + foreach ($choices as $key => $value) { + $messages[] = sprintf(" [%-${width}s] %s", $key, $value); + } + + $output->writeln($messages); + + $result = $this->askAndValidate($output, '> ', function ($picked) use ($choices, $errorMessage, $multiselect) { + // Collapse all spaces. + $selectedChoices = str_replace(' ', '', $picked); + + if ($multiselect) { + // Check for a separated comma values + if (!preg_match('/^[a-zA-Z0-9_-]+(?:,[a-zA-Z0-9_-]+)*$/', $selectedChoices, $matches)) { + throw new \InvalidArgumentException(sprintf($errorMessage, $picked)); + } + $selectedChoices = explode(',', $selectedChoices); + } else { + $selectedChoices = array($picked); + } + + $multiselectChoices = array(); + + foreach ($selectedChoices as $value) { + if (empty($choices[$value])) { + throw new \InvalidArgumentException(sprintf($errorMessage, $value)); + } + $multiselectChoices[] = $value; + } + + if ($multiselect) { + return $multiselectChoices; + } + + return $picked; + }, $attempts, $default); + + return $result; + } + + /** + * Asks a question to the user. + * + * @param OutputInterface $output An Output instance + * @param string|array $question The question to ask + * @param string $default The default answer if none is given by the user + * @param array $autocomplete List of values to autocomplete + * + * @return string The user answer + * + * @throws \RuntimeException If there is no data to read in the input stream + */ + public function ask(OutputInterface $output, $question, $default = null, array $autocomplete = null) + { + if ($this->input && !$this->input->isInteractive()) { + return $default; + } + + $output->write($question); + + $inputStream = $this->inputStream ?: STDIN; + + if (null === $autocomplete || !$this->hasSttyAvailable()) { + $ret = fgets($inputStream, 4096); + if (false === $ret) { + throw new \RuntimeException('Aborted'); + } + $ret = trim($ret); + } else { + $ret = ''; + + $i = 0; + $ofs = -1; + $matches = $autocomplete; + $numMatches = count($matches); + + $sttyMode = shell_exec('stty -g'); + + // Disable icanon (so we can fread each keypress) and echo (we'll do echoing here instead) + shell_exec('stty -icanon -echo'); + + // Add highlighted text style + $output->getFormatter()->setStyle('hl', new OutputFormatterStyle('black', 'white')); + + // Read a keypress + while (!feof($inputStream)) { + $c = fread($inputStream, 1); + + // Backspace Character + if ("\177" === $c) { + if (0 === $numMatches && 0 !== $i) { + --$i; + // Move cursor backwards + $output->write("\033[1D"); + } + + if ($i === 0) { + $ofs = -1; + $matches = $autocomplete; + $numMatches = count($matches); + } else { + $numMatches = 0; + } + + // Pop the last character off the end of our string + $ret = substr($ret, 0, $i); + } elseif ("\033" === $c) { + // Did we read an escape sequence? + $c .= fread($inputStream, 2); + + // A = Up Arrow. B = Down Arrow + if (isset($c[2]) && ('A' === $c[2] || 'B' === $c[2])) { + if ('A' === $c[2] && -1 === $ofs) { + $ofs = 0; + } + + if (0 === $numMatches) { + continue; + } + + $ofs += ('A' === $c[2]) ? -1 : 1; + $ofs = ($numMatches + $ofs) % $numMatches; + } + } elseif (ord($c) < 32) { + if ("\t" === $c || "\n" === $c) { + if ($numMatches > 0 && -1 !== $ofs) { + $ret = $matches[$ofs]; + // Echo out remaining chars for current match + $output->write(substr($ret, $i)); + $i = strlen($ret); + } + + if ("\n" === $c) { + $output->write($c); + break; + } + + $numMatches = 0; + } + + continue; + } else { + $output->write($c); + $ret .= $c; + ++$i; + + $numMatches = 0; + $ofs = 0; + + foreach ($autocomplete as $value) { + // If typed characters match the beginning chunk of value (e.g. [AcmeDe]moBundle) + if (0 === strpos($value, $ret) && $i !== strlen($value)) { + $matches[$numMatches++] = $value; + } + } + } + + // Erase characters from cursor to end of line + $output->write("\033[K"); + + if ($numMatches > 0 && -1 !== $ofs) { + // Save cursor position + $output->write("\0337"); + // Write highlighted text + $output->write(''.substr($matches[$ofs], $i).''); + // Restore cursor position + $output->write("\0338"); + } + } + + // Reset stty so it behaves normally again + shell_exec(sprintf('stty %s', $sttyMode)); + } + + return strlen($ret) > 0 ? $ret : $default; + } + + /** + * Asks a confirmation to the user. + * + * The question will be asked until the user answers by nothing, yes, or no. + * + * @param OutputInterface $output An Output instance + * @param string|array $question The question to ask + * @param bool $default The default answer if the user enters nothing + * + * @return bool true if the user has confirmed, false otherwise + */ + public function askConfirmation(OutputInterface $output, $question, $default = true) + { + $answer = 'z'; + while ($answer && !in_array(strtolower($answer[0]), array('y', 'n'))) { + $answer = $this->ask($output, $question); + } + + if (false === $default) { + return $answer && 'y' == strtolower($answer[0]); + } + + return !$answer || 'y' == strtolower($answer[0]); + } + + /** + * Asks a question to the user, the response is hidden. + * + * @param OutputInterface $output An Output instance + * @param string|array $question The question + * @param bool $fallback In case the response can not be hidden, whether to fallback on non-hidden question or not + * + * @return string The answer + * + * @throws \RuntimeException In case the fallback is deactivated and the response can not be hidden + */ + public function askHiddenResponse(OutputInterface $output, $question, $fallback = true) + { + if ('\\' === DIRECTORY_SEPARATOR) { + $exe = __DIR__.'/../Resources/bin/hiddeninput.exe'; + + // handle code running from a phar + if ('phar:' === substr(__FILE__, 0, 5)) { + $tmpExe = sys_get_temp_dir().'/hiddeninput.exe'; + copy($exe, $tmpExe); + $exe = $tmpExe; + } + + $output->write($question); + $value = rtrim(shell_exec($exe)); + $output->writeln(''); + + if (isset($tmpExe)) { + unlink($tmpExe); + } + + return $value; + } + + if ($this->hasSttyAvailable()) { + $output->write($question); + + $sttyMode = shell_exec('stty -g'); + + shell_exec('stty -echo'); + $value = fgets($this->inputStream ?: STDIN, 4096); + shell_exec(sprintf('stty %s', $sttyMode)); + + if (false === $value) { + throw new \RuntimeException('Aborted'); + } + + $value = trim($value); + $output->writeln(''); + + return $value; + } + + if (false !== $shell = $this->getShell()) { + $output->write($question); + $readCmd = $shell === 'csh' ? 'set mypassword = $<' : 'read -r mypassword'; + $command = sprintf("/usr/bin/env %s -c 'stty -echo; %s; stty echo; echo \$mypassword'", $shell, $readCmd); + $value = rtrim(shell_exec($command)); + $output->writeln(''); + + return $value; + } + + if ($fallback) { + return $this->ask($output, $question); + } + + throw new \RuntimeException('Unable to hide the response'); + } + + /** + * Asks for a value and validates the response. + * + * The validator receives the data to validate. It must return the + * validated data when the data is valid and throw an exception + * otherwise. + * + * @param OutputInterface $output An Output instance + * @param string|array $question The question to ask + * @param callable $validator A PHP callback + * @param int|false $attempts Max number of times to ask before giving up (false by default, which means infinite) + * @param string $default The default answer if none is given by the user + * @param array $autocomplete List of values to autocomplete + * + * @return mixed + * + * @throws \Exception When any of the validators return an error + */ + public function askAndValidate(OutputInterface $output, $question, $validator, $attempts = false, $default = null, array $autocomplete = null) + { + $that = $this; + + $interviewer = function () use ($output, $question, $default, $autocomplete, $that) { + return $that->ask($output, $question, $default, $autocomplete); + }; + + return $this->validateAttempts($interviewer, $output, $validator, $attempts); + } + + /** + * Asks for a value, hide and validates the response. + * + * The validator receives the data to validate. It must return the + * validated data when the data is valid and throw an exception + * otherwise. + * + * @param OutputInterface $output An Output instance + * @param string|array $question The question to ask + * @param callable $validator A PHP callback + * @param int|false $attempts Max number of times to ask before giving up (false by default, which means infinite) + * @param bool $fallback In case the response can not be hidden, whether to fallback on non-hidden question or not + * + * @return string The response + * + * @throws \Exception When any of the validators return an error + * @throws \RuntimeException In case the fallback is deactivated and the response can not be hidden + */ + public function askHiddenResponseAndValidate(OutputInterface $output, $question, $validator, $attempts = false, $fallback = true) + { + $that = $this; + + $interviewer = function () use ($output, $question, $fallback, $that) { + return $that->askHiddenResponse($output, $question, $fallback); + }; + + return $this->validateAttempts($interviewer, $output, $validator, $attempts); + } + + /** + * Sets the input stream to read from when interacting with the user. + * + * This is mainly useful for testing purpose. + * + * @param resource $stream The input stream + */ + public function setInputStream($stream) + { + $this->inputStream = $stream; + } + + /** + * Returns the helper's input stream. + * + * @return string + */ + public function getInputStream() + { + return $this->inputStream; + } + + /** + * {@inheritdoc} + */ + public function getName() + { + return 'dialog'; + } + + /** + * Return a valid Unix shell. + * + * @return string|bool The valid shell name, false in case no valid shell is found + */ + private function getShell() + { + if (null !== self::$shell) { + return self::$shell; + } + + self::$shell = false; + + if (file_exists('/usr/bin/env')) { + // handle other OSs with bash/zsh/ksh/csh if available to hide the answer + $test = "/usr/bin/env %s -c 'echo OK' 2> /dev/null"; + foreach (array('bash', 'zsh', 'ksh', 'csh') as $sh) { + if ('OK' === rtrim(shell_exec(sprintf($test, $sh)))) { + self::$shell = $sh; + break; + } + } + } + + return self::$shell; + } + + private function hasSttyAvailable() + { + if (null !== self::$stty) { + return self::$stty; + } + + exec('stty 2>&1', $output, $exitcode); + + return self::$stty = $exitcode === 0; + } + + /** + * Validate an attempt. + * + * @param callable $interviewer A callable that will ask for a question and return the result + * @param OutputInterface $output An Output instance + * @param callable $validator A PHP callback + * @param int|false $attempts Max number of times to ask before giving up ; false will ask infinitely + * + * @return string The validated response + * + * @throws \Exception In case the max number of attempts has been reached and no valid response has been given + */ + private function validateAttempts($interviewer, OutputInterface $output, $validator, $attempts) + { + $e = null; + while (false === $attempts || $attempts--) { + if (null !== $e) { + $output->writeln($this->getHelperSet()->get('formatter')->formatBlock($e->getMessage(), 'error')); + } + + try { + return call_user_func($validator, $interviewer()); + } catch (\Exception $e) { + } + } + + throw $e; + } +} diff --git a/vendor/symfony/console/Helper/FormatterHelper.php b/vendor/symfony/console/Helper/FormatterHelper.php new file mode 100644 index 0000000..ac736f9 --- /dev/null +++ b/vendor/symfony/console/Helper/FormatterHelper.php @@ -0,0 +1,82 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Helper; + +use Symfony\Component\Console\Formatter\OutputFormatter; + +/** + * The Formatter class provides helpers to format messages. + * + * @author Fabien Potencier + */ +class FormatterHelper extends Helper +{ + /** + * Formats a message within a section. + * + * @param string $section The section name + * @param string $message The message + * @param string $style The style to apply to the section + * + * @return string The format section + */ + public function formatSection($section, $message, $style = 'info') + { + return sprintf('<%s>[%s] %s', $style, $section, $style, $message); + } + + /** + * Formats a message as a block of text. + * + * @param string|array $messages The message to write in the block + * @param string $style The style to apply to the whole block + * @param bool $large Whether to return a large block + * + * @return string The formatter message + */ + public function formatBlock($messages, $style, $large = false) + { + if (!is_array($messages)) { + $messages = array($messages); + } + + $len = 0; + $lines = array(); + foreach ($messages as $message) { + $message = OutputFormatter::escape($message); + $lines[] = sprintf($large ? ' %s ' : ' %s ', $message); + $len = max($this->strlen($message) + ($large ? 4 : 2), $len); + } + + $messages = $large ? array(str_repeat(' ', $len)) : array(); + for ($i = 0; isset($lines[$i]); ++$i) { + $messages[] = $lines[$i].str_repeat(' ', $len - $this->strlen($lines[$i])); + } + if ($large) { + $messages[] = str_repeat(' ', $len); + } + + for ($i = 0; isset($messages[$i]); ++$i) { + $messages[$i] = sprintf('<%s>%s', $style, $messages[$i], $style); + } + + return implode("\n", $messages); + } + + /** + * {@inheritdoc} + */ + public function getName() + { + return 'formatter'; + } +} diff --git a/vendor/symfony/console/Helper/Helper.php b/vendor/symfony/console/Helper/Helper.php new file mode 100644 index 0000000..b288d44 --- /dev/null +++ b/vendor/symfony/console/Helper/Helper.php @@ -0,0 +1,121 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Helper; + +use Symfony\Component\Console\Formatter\OutputFormatterInterface; + +/** + * Helper is the base class for all helper classes. + * + * @author Fabien Potencier + */ +abstract class Helper implements HelperInterface +{ + protected $helperSet = null; + + /** + * Sets the helper set associated with this helper. + * + * @param HelperSet $helperSet A HelperSet instance + */ + public function setHelperSet(HelperSet $helperSet = null) + { + $this->helperSet = $helperSet; + } + + /** + * Gets the helper set associated with this helper. + * + * @return HelperSet A HelperSet instance + */ + public function getHelperSet() + { + return $this->helperSet; + } + + /** + * Returns the length of a string, using mb_strwidth if it is available. + * + * @param string $string The string to check its length + * + * @return int The length of the string + */ + public static function strlen($string) + { + if (!function_exists('mb_strwidth')) { + return strlen($string); + } + + if (false === $encoding = mb_detect_encoding($string)) { + return strlen($string); + } + + return mb_strwidth($string, $encoding); + } + + public static function formatTime($secs) + { + static $timeFormats = array( + array(0, '< 1 sec'), + array(2, '1 sec'), + array(59, 'secs', 1), + array(60, '1 min'), + array(3600, 'mins', 60), + array(5400, '1 hr'), + array(86400, 'hrs', 3600), + array(129600, '1 day'), + array(604800, 'days', 86400), + ); + + foreach ($timeFormats as $format) { + if ($secs >= $format[0]) { + continue; + } + + if (2 == count($format)) { + return $format[1]; + } + + return ceil($secs / $format[2]).' '.$format[1]; + } + } + + public static function formatMemory($memory) + { + if ($memory >= 1024 * 1024 * 1024) { + return sprintf('%.1f GiB', $memory / 1024 / 1024 / 1024); + } + + if ($memory >= 1024 * 1024) { + return sprintf('%.1f MiB', $memory / 1024 / 1024); + } + + if ($memory >= 1024) { + return sprintf('%d KiB', $memory / 1024); + } + + return sprintf('%d B', $memory); + } + + public static function strlenWithoutDecoration(OutputFormatterInterface $formatter, $string) + { + $isDecorated = $formatter->isDecorated(); + $formatter->setDecorated(false); + // remove <...> formatting + $string = $formatter->format($string); + // remove already formatted characters + $string = preg_replace("/\033\[[^m]*m/", '', $string); + $formatter->setDecorated($isDecorated); + + return self::strlen($string); + } +} diff --git a/vendor/symfony/console/Helper/HelperInterface.php b/vendor/symfony/console/Helper/HelperInterface.php new file mode 100644 index 0000000..6d39449 --- /dev/null +++ b/vendor/symfony/console/Helper/HelperInterface.php @@ -0,0 +1,49 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Helper; + +/** + * HelperInterface is the interface all helpers must implement. + * + * @author Fabien Potencier + * + * @api + */ +interface HelperInterface +{ + /** + * Sets the helper set associated with this helper. + * + * @param HelperSet $helperSet A HelperSet instance + * + * @api + */ + public function setHelperSet(HelperSet $helperSet = null); + + /** + * Gets the helper set associated with this helper. + * + * @return HelperSet A HelperSet instance + * + * @api + */ + public function getHelperSet(); + + /** + * Returns the canonical name of this helper. + * + * @return string The canonical name + * + * @api + */ + public function getName(); +} diff --git a/vendor/symfony/console/Helper/HelperSet.php b/vendor/symfony/console/Helper/HelperSet.php new file mode 100644 index 0000000..00354dd --- /dev/null +++ b/vendor/symfony/console/Helper/HelperSet.php @@ -0,0 +1,116 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Helper; + +use Symfony\Component\Console\Command\Command; + +/** + * HelperSet represents a set of helpers to be used with a command. + * + * @author Fabien Potencier + */ +class HelperSet implements \IteratorAggregate +{ + private $helpers = array(); + private $command; + + /** + * Constructor. + * + * @param Helper[] $helpers An array of helper. + */ + public function __construct(array $helpers = array()) + { + foreach ($helpers as $alias => $helper) { + $this->set($helper, is_int($alias) ? null : $alias); + } + } + + /** + * Sets a helper. + * + * @param HelperInterface $helper The helper instance + * @param string $alias An alias + */ + public function set(HelperInterface $helper, $alias = null) + { + $this->helpers[$helper->getName()] = $helper; + if (null !== $alias) { + $this->helpers[$alias] = $helper; + } + + $helper->setHelperSet($this); + } + + /** + * Returns true if the helper if defined. + * + * @param string $name The helper name + * + * @return bool true if the helper is defined, false otherwise + */ + public function has($name) + { + return isset($this->helpers[$name]); + } + + /** + * Gets a helper value. + * + * @param string $name The helper name + * + * @return HelperInterface The helper instance + * + * @throws \InvalidArgumentException if the helper is not defined + */ + public function get($name) + { + if (!$this->has($name)) { + throw new \InvalidArgumentException(sprintf('The helper "%s" is not defined.', $name)); + } + + if ('dialog' === $name && $this->helpers[$name] instanceof DialogHelper) { + @trigger_error('"Symfony\Component\Console\Helper\DialogHelper" is deprecated since version 2.5 and will be removed in 3.0. Use "Symfony\Component\Console\Helper\QuestionHelper" instead.', E_USER_DEPRECATED); + } elseif ('progress' === $name && $this->helpers[$name] instanceof ProgressHelper) { + @trigger_error('"Symfony\Component\Console\Helper\ProgressHelper" is deprecated since version 2.5 and will be removed in 3.0. Use "Symfony\Component\Console\Helper\ProgressBar" instead.', E_USER_DEPRECATED); + } elseif ('table' === $name && $this->helpers[$name] instanceof TableHelper) { + @trigger_error('"Symfony\Component\Console\Helper\TableHelper" is deprecated since version 2.5 and will be removed in 3.0. Use "Symfony\Component\Console\Helper\Table" instead.', E_USER_DEPRECATED); + } + + return $this->helpers[$name]; + } + + /** + * Sets the command associated with this helper set. + * + * @param Command $command A Command instance + */ + public function setCommand(Command $command = null) + { + $this->command = $command; + } + + /** + * Gets the command associated with this helper set. + * + * @return Command A Command instance + */ + public function getCommand() + { + return $this->command; + } + + public function getIterator() + { + return new \ArrayIterator($this->helpers); + } +} diff --git a/vendor/symfony/console/Helper/InputAwareHelper.php b/vendor/symfony/console/Helper/InputAwareHelper.php new file mode 100644 index 0000000..4261767 --- /dev/null +++ b/vendor/symfony/console/Helper/InputAwareHelper.php @@ -0,0 +1,33 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Helper; + +use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Input\InputAwareInterface; + +/** + * An implementation of InputAwareInterface for Helpers. + * + * @author Wouter J + */ +abstract class InputAwareHelper extends Helper implements InputAwareInterface +{ + protected $input; + + /** + * {@inheritdoc} + */ + public function setInput(InputInterface $input) + { + $this->input = $input; + } +} diff --git a/vendor/symfony/console/Helper/ProcessHelper.php b/vendor/symfony/console/Helper/ProcessHelper.php new file mode 100644 index 0000000..0c9da73 --- /dev/null +++ b/vendor/symfony/console/Helper/ProcessHelper.php @@ -0,0 +1,142 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Helper; + +use Symfony\Component\Console\Output\OutputInterface; +use Symfony\Component\Process\Exception\ProcessFailedException; +use Symfony\Component\Process\Process; +use Symfony\Component\Process\ProcessBuilder; + +/** + * The ProcessHelper class provides helpers to run external processes. + * + * @author Fabien Potencier + */ +class ProcessHelper extends Helper +{ + /** + * Runs an external process. + * + * @param OutputInterface $output An OutputInterface instance + * @param string|array|Process $cmd An instance of Process or an array of arguments to escape and run or a command to run + * @param string|null $error An error message that must be displayed if something went wrong + * @param callable|null $callback A PHP callback to run whenever there is some + * output available on STDOUT or STDERR + * @param int $verbosity The threshold for verbosity + * + * @return Process The process that ran + */ + public function run(OutputInterface $output, $cmd, $error = null, $callback = null, $verbosity = OutputInterface::VERBOSITY_VERY_VERBOSE) + { + $formatter = $this->getHelperSet()->get('debug_formatter'); + + if (is_array($cmd)) { + $process = ProcessBuilder::create($cmd)->getProcess(); + } elseif ($cmd instanceof Process) { + $process = $cmd; + } else { + $process = new Process($cmd); + } + + if ($verbosity <= $output->getVerbosity()) { + $output->write($formatter->start(spl_object_hash($process), $this->escapeString($process->getCommandLine()))); + } + + if ($output->isDebug()) { + $callback = $this->wrapCallback($output, $process, $callback); + } + + $process->run($callback); + + if ($verbosity <= $output->getVerbosity()) { + $message = $process->isSuccessful() ? 'Command ran successfully' : sprintf('%s Command did not run successfully', $process->getExitCode()); + $output->write($formatter->stop(spl_object_hash($process), $message, $process->isSuccessful())); + } + + if (!$process->isSuccessful() && null !== $error) { + $output->writeln(sprintf('%s', $this->escapeString($error))); + } + + return $process; + } + + /** + * Runs the process. + * + * This is identical to run() except that an exception is thrown if the process + * exits with a non-zero exit code. + * + * @param OutputInterface $output An OutputInterface instance + * @param string|Process $cmd An instance of Process or a command to run + * @param string|null $error An error message that must be displayed if something went wrong + * @param callable|null $callback A PHP callback to run whenever there is some + * output available on STDOUT or STDERR + * + * @return Process The process that ran + * + * @throws ProcessFailedException + * + * @see run() + */ + public function mustRun(OutputInterface $output, $cmd, $error = null, $callback = null) + { + $process = $this->run($output, $cmd, $error, $callback); + + if (!$process->isSuccessful()) { + throw new ProcessFailedException($process); + } + + return $process; + } + + /** + * Wraps a Process callback to add debugging output. + * + * @param OutputInterface $output An OutputInterface interface + * @param Process $process The Process + * @param callable|null $callback A PHP callable + * + * @return callable + */ + public function wrapCallback(OutputInterface $output, Process $process, $callback = null) + { + $formatter = $this->getHelperSet()->get('debug_formatter'); + + $that = $this; + + return function ($type, $buffer) use ($output, $process, $callback, $formatter, $that) { + $output->write($formatter->progress(spl_object_hash($process), $that->escapeString($buffer), Process::ERR === $type)); + + if (null !== $callback) { + call_user_func($callback, $type, $buffer); + } + }; + } + + /** + * This method is public for PHP 5.3 compatibility, it should be private. + * + * @internal + */ + public function escapeString($str) + { + return str_replace('<', '\\<', $str); + } + + /** + * {@inheritdoc} + */ + public function getName() + { + return 'process'; + } +} diff --git a/vendor/symfony/console/Helper/ProgressBar.php b/vendor/symfony/console/Helper/ProgressBar.php new file mode 100644 index 0000000..e5ba927 --- /dev/null +++ b/vendor/symfony/console/Helper/ProgressBar.php @@ -0,0 +1,615 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Helper; + +use Symfony\Component\Console\Output\OutputInterface; + +/** + * The ProgressBar provides helpers to display progress output. + * + * @author Fabien Potencier + * @author Chris Jones + */ +class ProgressBar +{ + // options + private $barWidth = 28; + private $barChar; + private $emptyBarChar = '-'; + private $progressChar = '>'; + private $format = null; + private $redrawFreq = 1; + + /** + * @var OutputInterface + */ + private $output; + private $step = 0; + private $max; + private $startTime; + private $stepWidth; + private $percent = 0.0; + private $lastMessagesLength = 0; + private $formatLineCount; + private $messages; + private $overwrite = true; + + private static $formatters; + private static $formats; + + /** + * Constructor. + * + * @param OutputInterface $output An OutputInterface instance + * @param int $max Maximum steps (0 if unknown) + */ + public function __construct(OutputInterface $output, $max = 0) + { + $this->output = $output; + $this->setMaxSteps($max); + + if (!$this->output->isDecorated()) { + // disable overwrite when output does not support ANSI codes. + $this->overwrite = false; + + if ($this->max > 10) { + // set a reasonable redraw frequency so output isn't flooded + $this->setRedrawFrequency($max / 10); + } + } + + $this->setFormat($this->determineBestFormat()); + + $this->startTime = time(); + } + + /** + * Sets a placeholder formatter for a given name. + * + * This method also allow you to override an existing placeholder. + * + * @param string $name The placeholder name (including the delimiter char like %) + * @param callable $callable A PHP callable + */ + public static function setPlaceholderFormatterDefinition($name, $callable) + { + if (!self::$formatters) { + self::$formatters = self::initPlaceholderFormatters(); + } + + self::$formatters[$name] = $callable; + } + + /** + * Gets the placeholder formatter for a given name. + * + * @param string $name The placeholder name (including the delimiter char like %) + * + * @return callable|null A PHP callable + */ + public static function getPlaceholderFormatterDefinition($name) + { + if (!self::$formatters) { + self::$formatters = self::initPlaceholderFormatters(); + } + + return isset(self::$formatters[$name]) ? self::$formatters[$name] : null; + } + + /** + * Sets a format for a given name. + * + * This method also allow you to override an existing format. + * + * @param string $name The format name + * @param string $format A format string + */ + public static function setFormatDefinition($name, $format) + { + if (!self::$formats) { + self::$formats = self::initFormats(); + } + + self::$formats[$name] = $format; + } + + /** + * Gets the format for a given name. + * + * @param string $name The format name + * + * @return string|null A format string + */ + public static function getFormatDefinition($name) + { + if (!self::$formats) { + self::$formats = self::initFormats(); + } + + return isset(self::$formats[$name]) ? self::$formats[$name] : null; + } + + public function setMessage($message, $name = 'message') + { + $this->messages[$name] = $message; + } + + public function getMessage($name = 'message') + { + return $this->messages[$name]; + } + + /** + * Gets the progress bar start time. + * + * @return int The progress bar start time + */ + public function getStartTime() + { + return $this->startTime; + } + + /** + * Gets the progress bar maximal steps. + * + * @return int The progress bar max steps + */ + public function getMaxSteps() + { + return $this->max; + } + + /** + * Gets the progress bar step. + * + * @deprecated since version 2.6, to be removed in 3.0. Use {@link getProgress()} instead. + * + * @return int The progress bar step + */ + public function getStep() + { + @trigger_error('The '.__METHOD__.' method is deprecated since version 2.6 and will be removed in 3.0. Use the getProgress() method instead.', E_USER_DEPRECATED); + + return $this->getProgress(); + } + + /** + * Gets the current step position. + * + * @return int The progress bar step + */ + public function getProgress() + { + return $this->step; + } + + /** + * Gets the progress bar step width. + * + * @internal This method is public for PHP 5.3 compatibility, it should not be used. + * + * @return int The progress bar step width + */ + public function getStepWidth() + { + return $this->stepWidth; + } + + /** + * Gets the current progress bar percent. + * + * @return float The current progress bar percent + */ + public function getProgressPercent() + { + return $this->percent; + } + + /** + * Sets the progress bar width. + * + * @param int $size The progress bar size + */ + public function setBarWidth($size) + { + $this->barWidth = (int) $size; + } + + /** + * Gets the progress bar width. + * + * @return int The progress bar size + */ + public function getBarWidth() + { + return $this->barWidth; + } + + /** + * Sets the bar character. + * + * @param string $char A character + */ + public function setBarCharacter($char) + { + $this->barChar = $char; + } + + /** + * Gets the bar character. + * + * @return string A character + */ + public function getBarCharacter() + { + if (null === $this->barChar) { + return $this->max ? '=' : $this->emptyBarChar; + } + + return $this->barChar; + } + + /** + * Sets the empty bar character. + * + * @param string $char A character + */ + public function setEmptyBarCharacter($char) + { + $this->emptyBarChar = $char; + } + + /** + * Gets the empty bar character. + * + * @return string A character + */ + public function getEmptyBarCharacter() + { + return $this->emptyBarChar; + } + + /** + * Sets the progress bar character. + * + * @param string $char A character + */ + public function setProgressCharacter($char) + { + $this->progressChar = $char; + } + + /** + * Gets the progress bar character. + * + * @return string A character + */ + public function getProgressCharacter() + { + return $this->progressChar; + } + + /** + * Sets the progress bar format. + * + * @param string $format The format + */ + public function setFormat($format) + { + // try to use the _nomax variant if available + if (!$this->max && null !== self::getFormatDefinition($format.'_nomax')) { + $this->format = self::getFormatDefinition($format.'_nomax'); + } elseif (null !== self::getFormatDefinition($format)) { + $this->format = self::getFormatDefinition($format); + } else { + $this->format = $format; + } + + $this->formatLineCount = substr_count($this->format, "\n"); + } + + /** + * Sets the redraw frequency. + * + * @param int $freq The frequency in steps + */ + public function setRedrawFrequency($freq) + { + $this->redrawFreq = (int) $freq; + } + + /** + * Starts the progress output. + * + * @param int|null $max Number of steps to complete the bar (0 if indeterminate), null to leave unchanged + */ + public function start($max = null) + { + $this->startTime = time(); + $this->step = 0; + $this->percent = 0.0; + + if (null !== $max) { + $this->setMaxSteps($max); + } + + $this->display(); + } + + /** + * Advances the progress output X steps. + * + * @param int $step Number of steps to advance + * + * @throws \LogicException + */ + public function advance($step = 1) + { + $this->setProgress($this->step + $step); + } + + /** + * Sets the current progress. + * + * @deprecated since version 2.6, to be removed in 3.0. Use {@link setProgress()} instead. + * + * @param int $step The current progress + * + * @throws \LogicException + */ + public function setCurrent($step) + { + @trigger_error('The '.__METHOD__.' method is deprecated since version 2.6 and will be removed in 3.0. Use the setProgress() method instead.', E_USER_DEPRECATED); + + $this->setProgress($step); + } + + /** + * Sets whether to overwrite the progressbar, false for new line. + * + * @param bool $overwrite + */ + public function setOverwrite($overwrite) + { + $this->overwrite = (bool) $overwrite; + } + + /** + * Sets the current progress. + * + * @param int $step The current progress + * + * @throws \LogicException + */ + public function setProgress($step) + { + $step = (int) $step; + if ($step < $this->step) { + throw new \LogicException('You can\'t regress the progress bar.'); + } + + if ($this->max && $step > $this->max) { + $this->max = $step; + } + + $prevPeriod = (int) ($this->step / $this->redrawFreq); + $currPeriod = (int) ($step / $this->redrawFreq); + $this->step = $step; + $this->percent = $this->max ? (float) $this->step / $this->max : 0; + if ($prevPeriod !== $currPeriod || $this->max === $step) { + $this->display(); + } + } + + /** + * Finishes the progress output. + */ + public function finish() + { + if (!$this->max) { + $this->max = $this->step; + } + + if ($this->step === $this->max && !$this->overwrite) { + // prevent double 100% output + return; + } + + $this->setProgress($this->max); + } + + /** + * Outputs the current progress string. + */ + public function display() + { + if (OutputInterface::VERBOSITY_QUIET === $this->output->getVerbosity()) { + return; + } + + // these 3 variables can be removed in favor of using $this in the closure when support for PHP 5.3 will be dropped. + $self = $this; + $output = $this->output; + $messages = $this->messages; + $this->overwrite(preg_replace_callback("{%([a-z\-_]+)(?:\:([^%]+))?%}i", function ($matches) use ($self, $output, $messages) { + if ($formatter = $self::getPlaceholderFormatterDefinition($matches[1])) { + $text = call_user_func($formatter, $self, $output); + } elseif (isset($messages[$matches[1]])) { + $text = $messages[$matches[1]]; + } else { + return $matches[0]; + } + + if (isset($matches[2])) { + $text = sprintf('%'.$matches[2], $text); + } + + return $text; + }, $this->format)); + } + + /** + * Removes the progress bar from the current line. + * + * This is useful if you wish to write some output + * while a progress bar is running. + * Call display() to show the progress bar again. + */ + public function clear() + { + if (!$this->overwrite) { + return; + } + + $this->overwrite(str_repeat("\n", $this->formatLineCount)); + } + + /** + * Sets the progress bar maximal steps. + * + * @param int The progress bar max steps + */ + private function setMaxSteps($max) + { + $this->max = max(0, (int) $max); + $this->stepWidth = $this->max ? Helper::strlen($this->max) : 4; + } + + /** + * Overwrites a previous message to the output. + * + * @param string $message The message + */ + private function overwrite($message) + { + $lines = explode("\n", $message); + + // append whitespace to match the line's length + if (null !== $this->lastMessagesLength) { + foreach ($lines as $i => $line) { + if ($this->lastMessagesLength > Helper::strlenWithoutDecoration($this->output->getFormatter(), $line)) { + $lines[$i] = str_pad($line, $this->lastMessagesLength, "\x20", STR_PAD_RIGHT); + } + } + } + + if ($this->overwrite) { + // move back to the beginning of the progress bar before redrawing it + $this->output->write("\x0D"); + } elseif ($this->step > 0) { + // move to new line + $this->output->writeln(''); + } + + if ($this->formatLineCount) { + $this->output->write(sprintf("\033[%dA", $this->formatLineCount)); + } + $this->output->write(implode("\n", $lines)); + + $this->lastMessagesLength = 0; + foreach ($lines as $line) { + $len = Helper::strlenWithoutDecoration($this->output->getFormatter(), $line); + if ($len > $this->lastMessagesLength) { + $this->lastMessagesLength = $len; + } + } + } + + private function determineBestFormat() + { + switch ($this->output->getVerbosity()) { + // OutputInterface::VERBOSITY_QUIET: display is disabled anyway + case OutputInterface::VERBOSITY_VERBOSE: + return $this->max ? 'verbose' : 'verbose_nomax'; + case OutputInterface::VERBOSITY_VERY_VERBOSE: + return $this->max ? 'very_verbose' : 'very_verbose_nomax'; + case OutputInterface::VERBOSITY_DEBUG: + return $this->max ? 'debug' : 'debug_nomax'; + default: + return $this->max ? 'normal' : 'normal_nomax'; + } + } + + private static function initPlaceholderFormatters() + { + return array( + 'bar' => function (ProgressBar $bar, OutputInterface $output) { + $completeBars = floor($bar->getMaxSteps() > 0 ? $bar->getProgressPercent() * $bar->getBarWidth() : $bar->getProgress() % $bar->getBarWidth()); + $display = str_repeat($bar->getBarCharacter(), $completeBars); + if ($completeBars < $bar->getBarWidth()) { + $emptyBars = $bar->getBarWidth() - $completeBars - Helper::strlenWithoutDecoration($output->getFormatter(), $bar->getProgressCharacter()); + $display .= $bar->getProgressCharacter().str_repeat($bar->getEmptyBarCharacter(), $emptyBars); + } + + return $display; + }, + 'elapsed' => function (ProgressBar $bar) { + return Helper::formatTime(time() - $bar->getStartTime()); + }, + 'remaining' => function (ProgressBar $bar) { + if (!$bar->getMaxSteps()) { + throw new \LogicException('Unable to display the remaining time if the maximum number of steps is not set.'); + } + + if (!$bar->getProgress()) { + $remaining = 0; + } else { + $remaining = round((time() - $bar->getStartTime()) / $bar->getProgress() * ($bar->getMaxSteps() - $bar->getProgress())); + } + + return Helper::formatTime($remaining); + }, + 'estimated' => function (ProgressBar $bar) { + if (!$bar->getMaxSteps()) { + throw new \LogicException('Unable to display the estimated time if the maximum number of steps is not set.'); + } + + if (!$bar->getProgress()) { + $estimated = 0; + } else { + $estimated = round((time() - $bar->getStartTime()) / $bar->getProgress() * $bar->getMaxSteps()); + } + + return Helper::formatTime($estimated); + }, + 'memory' => function (ProgressBar $bar) { + return Helper::formatMemory(memory_get_usage(true)); + }, + 'current' => function (ProgressBar $bar) { + return str_pad($bar->getProgress(), $bar->getStepWidth(), ' ', STR_PAD_LEFT); + }, + 'max' => function (ProgressBar $bar) { + return $bar->getMaxSteps(); + }, + 'percent' => function (ProgressBar $bar) { + return floor($bar->getProgressPercent() * 100); + }, + ); + } + + private static function initFormats() + { + return array( + 'normal' => ' %current%/%max% [%bar%] %percent:3s%%', + 'normal_nomax' => ' %current% [%bar%]', + + 'verbose' => ' %current%/%max% [%bar%] %percent:3s%% %elapsed:6s%', + 'verbose_nomax' => ' %current% [%bar%] %elapsed:6s%', + + 'very_verbose' => ' %current%/%max% [%bar%] %percent:3s%% %elapsed:6s%/%estimated:-6s%', + 'very_verbose_nomax' => ' %current% [%bar%] %elapsed:6s%', + + 'debug' => ' %current%/%max% [%bar%] %percent:3s%% %elapsed:6s%/%estimated:-6s% %memory:6s%', + 'debug_nomax' => ' %current% [%bar%] %elapsed:6s% %memory:6s%', + ); + } +} diff --git a/vendor/symfony/console/Helper/ProgressHelper.php b/vendor/symfony/console/Helper/ProgressHelper.php new file mode 100644 index 0000000..bd88566 --- /dev/null +++ b/vendor/symfony/console/Helper/ProgressHelper.php @@ -0,0 +1,465 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Helper; + +use Symfony\Component\Console\Output\NullOutput; +use Symfony\Component\Console\Output\OutputInterface; + +/** + * The Progress class provides helpers to display progress output. + * + * @author Chris Jones + * @author Fabien Potencier + * + * @deprecated since version 2.5, to be removed in 3.0 + * Use {@link ProgressBar} instead. + */ +class ProgressHelper extends Helper +{ + const FORMAT_QUIET = ' %percent%%'; + const FORMAT_NORMAL = ' %current%/%max% [%bar%] %percent%%'; + const FORMAT_VERBOSE = ' %current%/%max% [%bar%] %percent%% Elapsed: %elapsed%'; + const FORMAT_QUIET_NOMAX = ' %current%'; + const FORMAT_NORMAL_NOMAX = ' %current% [%bar%]'; + const FORMAT_VERBOSE_NOMAX = ' %current% [%bar%] Elapsed: %elapsed%'; + + // options + private $barWidth = 28; + private $barChar = '='; + private $emptyBarChar = '-'; + private $progressChar = '>'; + private $format = null; + private $redrawFreq = 1; + + private $lastMessagesLength; + private $barCharOriginal; + + /** + * @var OutputInterface + */ + private $output; + + /** + * Current step. + * + * @var int + */ + private $current; + + /** + * Maximum number of steps. + * + * @var int + */ + private $max; + + /** + * Start time of the progress bar. + * + * @var int + */ + private $startTime; + + /** + * List of formatting variables. + * + * @var array + */ + private $defaultFormatVars = array( + 'current', + 'max', + 'bar', + 'percent', + 'elapsed', + ); + + /** + * Available formatting variables. + * + * @var array + */ + private $formatVars; + + /** + * Stored format part widths (used for padding). + * + * @var array + */ + private $widths = array( + 'current' => 4, + 'max' => 4, + 'percent' => 3, + 'elapsed' => 6, + ); + + /** + * Various time formats. + * + * @var array + */ + private $timeFormats = array( + array(0, '???'), + array(2, '1 sec'), + array(59, 'secs', 1), + array(60, '1 min'), + array(3600, 'mins', 60), + array(5400, '1 hr'), + array(86400, 'hrs', 3600), + array(129600, '1 day'), + array(604800, 'days', 86400), + ); + + public function __construct($triggerDeprecationError = true) + { + if ($triggerDeprecationError) { + @trigger_error('The '.__CLASS__.' class is deprecated since version 2.5 and will be removed in 3.0. Use the Symfony\Component\Console\Helper\ProgressBar class instead.', E_USER_DEPRECATED); + } + } + + /** + * Sets the progress bar width. + * + * @param int $size The progress bar size + */ + public function setBarWidth($size) + { + $this->barWidth = (int) $size; + } + + /** + * Sets the bar character. + * + * @param string $char A character + */ + public function setBarCharacter($char) + { + $this->barChar = $char; + } + + /** + * Sets the empty bar character. + * + * @param string $char A character + */ + public function setEmptyBarCharacter($char) + { + $this->emptyBarChar = $char; + } + + /** + * Sets the progress bar character. + * + * @param string $char A character + */ + public function setProgressCharacter($char) + { + $this->progressChar = $char; + } + + /** + * Sets the progress bar format. + * + * @param string $format The format + */ + public function setFormat($format) + { + $this->format = $format; + } + + /** + * Sets the redraw frequency. + * + * @param int $freq The frequency in steps + */ + public function setRedrawFrequency($freq) + { + $this->redrawFreq = (int) $freq; + } + + /** + * Starts the progress output. + * + * @param OutputInterface $output An Output instance + * @param int|null $max Maximum steps + */ + public function start(OutputInterface $output, $max = null) + { + $this->startTime = time(); + $this->current = 0; + $this->max = (int) $max; + + // Disabling output when it does not support ANSI codes as it would result in a broken display anyway. + $this->output = $output->isDecorated() ? $output : new NullOutput(); + $this->lastMessagesLength = 0; + $this->barCharOriginal = ''; + + if (null === $this->format) { + switch ($output->getVerbosity()) { + case OutputInterface::VERBOSITY_QUIET: + $this->format = self::FORMAT_QUIET_NOMAX; + if ($this->max > 0) { + $this->format = self::FORMAT_QUIET; + } + break; + case OutputInterface::VERBOSITY_VERBOSE: + case OutputInterface::VERBOSITY_VERY_VERBOSE: + case OutputInterface::VERBOSITY_DEBUG: + $this->format = self::FORMAT_VERBOSE_NOMAX; + if ($this->max > 0) { + $this->format = self::FORMAT_VERBOSE; + } + break; + default: + $this->format = self::FORMAT_NORMAL_NOMAX; + if ($this->max > 0) { + $this->format = self::FORMAT_NORMAL; + } + break; + } + } + + $this->initialize(); + } + + /** + * Advances the progress output X steps. + * + * @param int $step Number of steps to advance + * @param bool $redraw Whether to redraw or not + * + * @throws \LogicException + */ + public function advance($step = 1, $redraw = false) + { + $this->setCurrent($this->current + $step, $redraw); + } + + /** + * Sets the current progress. + * + * @param int $current The current progress + * @param bool $redraw Whether to redraw or not + * + * @throws \LogicException + */ + public function setCurrent($current, $redraw = false) + { + if (null === $this->startTime) { + throw new \LogicException('You must start the progress bar before calling setCurrent().'); + } + + $current = (int) $current; + + if ($current < $this->current) { + throw new \LogicException('You can\'t regress the progress bar'); + } + + if (0 === $this->current) { + $redraw = true; + } + + $prevPeriod = (int) ($this->current / $this->redrawFreq); + + $this->current = $current; + + $currPeriod = (int) ($this->current / $this->redrawFreq); + if ($redraw || $prevPeriod !== $currPeriod || $this->max === $this->current) { + $this->display(); + } + } + + /** + * Outputs the current progress string. + * + * @param bool $finish Forces the end result + * + * @throws \LogicException + */ + public function display($finish = false) + { + if (null === $this->startTime) { + throw new \LogicException('You must start the progress bar before calling display().'); + } + + $message = $this->format; + foreach ($this->generate($finish) as $name => $value) { + $message = str_replace("%{$name}%", $value, $message); + } + $this->overwrite($this->output, $message); + } + + /** + * Removes the progress bar from the current line. + * + * This is useful if you wish to write some output + * while a progress bar is running. + * Call display() to show the progress bar again. + */ + public function clear() + { + $this->overwrite($this->output, ''); + } + + /** + * Finishes the progress output. + */ + public function finish() + { + if (null === $this->startTime) { + throw new \LogicException('You must start the progress bar before calling finish().'); + } + + if (null !== $this->startTime) { + if (!$this->max) { + $this->barChar = $this->barCharOriginal; + $this->display(true); + } + $this->startTime = null; + $this->output->writeln(''); + $this->output = null; + } + } + + /** + * Initializes the progress helper. + */ + private function initialize() + { + $this->formatVars = array(); + foreach ($this->defaultFormatVars as $var) { + if (false !== strpos($this->format, "%{$var}%")) { + $this->formatVars[$var] = true; + } + } + + if ($this->max > 0) { + $this->widths['max'] = $this->strlen($this->max); + $this->widths['current'] = $this->widths['max']; + } else { + $this->barCharOriginal = $this->barChar; + $this->barChar = $this->emptyBarChar; + } + } + + /** + * Generates the array map of format variables to values. + * + * @param bool $finish Forces the end result + * + * @return array Array of format vars and values + */ + private function generate($finish = false) + { + $vars = array(); + $percent = 0; + if ($this->max > 0) { + $percent = (float) $this->current / $this->max; + } + + if (isset($this->formatVars['bar'])) { + $completeBars = 0; + + if ($this->max > 0) { + $completeBars = floor($percent * $this->barWidth); + } else { + if (!$finish) { + $completeBars = floor($this->current % $this->barWidth); + } else { + $completeBars = $this->barWidth; + } + } + + $emptyBars = $this->barWidth - $completeBars - $this->strlen($this->progressChar); + $bar = str_repeat($this->barChar, $completeBars); + if ($completeBars < $this->barWidth) { + $bar .= $this->progressChar; + $bar .= str_repeat($this->emptyBarChar, $emptyBars); + } + + $vars['bar'] = $bar; + } + + if (isset($this->formatVars['elapsed'])) { + $elapsed = time() - $this->startTime; + $vars['elapsed'] = str_pad($this->humaneTime($elapsed), $this->widths['elapsed'], ' ', STR_PAD_LEFT); + } + + if (isset($this->formatVars['current'])) { + $vars['current'] = str_pad($this->current, $this->widths['current'], ' ', STR_PAD_LEFT); + } + + if (isset($this->formatVars['max'])) { + $vars['max'] = $this->max; + } + + if (isset($this->formatVars['percent'])) { + $vars['percent'] = str_pad(floor($percent * 100), $this->widths['percent'], ' ', STR_PAD_LEFT); + } + + return $vars; + } + + /** + * Converts seconds into human-readable format. + * + * @param int $secs Number of seconds + * + * @return string Time in readable format + */ + private function humaneTime($secs) + { + $text = ''; + foreach ($this->timeFormats as $format) { + if ($secs < $format[0]) { + if (count($format) == 2) { + $text = $format[1]; + break; + } else { + $text = ceil($secs / $format[2]).' '.$format[1]; + break; + } + } + } + + return $text; + } + + /** + * Overwrites a previous message to the output. + * + * @param OutputInterface $output An Output instance + * @param string $message The message + */ + private function overwrite(OutputInterface $output, $message) + { + $length = $this->strlen($message); + + // append whitespace to match the last line's length + if (null !== $this->lastMessagesLength && $this->lastMessagesLength > $length) { + $message = str_pad($message, $this->lastMessagesLength, "\x20", STR_PAD_RIGHT); + } + + // carriage return + $output->write("\x0D"); + $output->write($message); + + $this->lastMessagesLength = $this->strlen($message); + } + + /** + * {@inheritdoc} + */ + public function getName() + { + return 'progress'; + } +} diff --git a/vendor/symfony/console/Helper/QuestionHelper.php b/vendor/symfony/console/Helper/QuestionHelper.php new file mode 100644 index 0000000..6584377 --- /dev/null +++ b/vendor/symfony/console/Helper/QuestionHelper.php @@ -0,0 +1,441 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Helper; + +use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Output\OutputInterface; +use Symfony\Component\Console\Formatter\OutputFormatterStyle; +use Symfony\Component\Console\Question\Question; +use Symfony\Component\Console\Question\ChoiceQuestion; + +/** + * The QuestionHelper class provides helpers to interact with the user. + * + * @author Fabien Potencier + */ +class QuestionHelper extends Helper +{ + private $inputStream; + private static $shell; + private static $stty; + + /** + * Asks a question to the user. + * + * @param InputInterface $input An InputInterface instance + * @param OutputInterface $output An OutputInterface instance + * @param Question $question The question to ask + * + * @return string The user answer + * + * @throws \RuntimeException If there is no data to read in the input stream + */ + public function ask(InputInterface $input, OutputInterface $output, Question $question) + { + if (!$input->isInteractive()) { + return $question->getDefault(); + } + + if (!$question->getValidator()) { + return $this->doAsk($output, $question); + } + + $that = $this; + + $interviewer = function () use ($output, $question, $that) { + return $that->doAsk($output, $question); + }; + + return $this->validateAttempts($interviewer, $output, $question); + } + + /** + * Sets the input stream to read from when interacting with the user. + * + * This is mainly useful for testing purpose. + * + * @param resource $stream The input stream + * + * @throws \InvalidArgumentException In case the stream is not a resource + */ + public function setInputStream($stream) + { + if (!is_resource($stream)) { + throw new \InvalidArgumentException('Input stream must be a valid resource.'); + } + + $this->inputStream = $stream; + } + + /** + * Returns the helper's input stream. + * + * @return resource + */ + public function getInputStream() + { + return $this->inputStream; + } + + /** + * {@inheritdoc} + */ + public function getName() + { + return 'question'; + } + + /** + * Asks the question to the user. + * + * This method is public for PHP 5.3 compatibility, it should be private. + * + * @param OutputInterface $output + * @param Question $question + * + * @return bool|mixed|null|string + * + * @throws \Exception + * @throws \RuntimeException + */ + public function doAsk(OutputInterface $output, Question $question) + { + $this->writePrompt($output, $question); + + $inputStream = $this->inputStream ?: STDIN; + $autocomplete = $question->getAutocompleterValues(); + + if (null === $autocomplete || !$this->hasSttyAvailable()) { + $ret = false; + if ($question->isHidden()) { + try { + $ret = trim($this->getHiddenResponse($output, $inputStream)); + } catch (\RuntimeException $e) { + if (!$question->isHiddenFallback()) { + throw $e; + } + } + } + + if (false === $ret) { + $ret = fgets($inputStream, 4096); + if (false === $ret) { + throw new \RuntimeException('Aborted'); + } + $ret = trim($ret); + } + } else { + $ret = trim($this->autocomplete($output, $question, $inputStream)); + } + + $ret = strlen($ret) > 0 ? $ret : $question->getDefault(); + + if ($normalizer = $question->getNormalizer()) { + return $normalizer($ret); + } + + return $ret; + } + + /** + * Outputs the question prompt. + * + * @param OutputInterface $output + * @param Question $question + */ + protected function writePrompt(OutputInterface $output, Question $question) + { + $message = $question->getQuestion(); + + if ($question instanceof ChoiceQuestion) { + $width = max(array_map('strlen', array_keys($question->getChoices()))); + + $messages = (array) $question->getQuestion(); + foreach ($question->getChoices() as $key => $value) { + $messages[] = sprintf(" [%-${width}s] %s", $key, $value); + } + + $output->writeln($messages); + + $message = $question->getPrompt(); + } + + $output->write($message); + } + + /** + * Outputs an error message. + * + * @param OutputInterface $output + * @param \Exception $error + */ + protected function writeError(OutputInterface $output, \Exception $error) + { + if (null !== $this->getHelperSet() && $this->getHelperSet()->has('formatter')) { + $message = $this->getHelperSet()->get('formatter')->formatBlock($error->getMessage(), 'error'); + } else { + $message = ''.$error->getMessage().''; + } + + $output->writeln($message); + } + + /** + * Autocompletes a question. + * + * @param OutputInterface $output + * @param Question $question + * + * @return string + */ + private function autocomplete(OutputInterface $output, Question $question, $inputStream) + { + $autocomplete = $question->getAutocompleterValues(); + $ret = ''; + + $i = 0; + $ofs = -1; + $matches = $autocomplete; + $numMatches = count($matches); + + $sttyMode = shell_exec('stty -g'); + + // Disable icanon (so we can fread each keypress) and echo (we'll do echoing here instead) + shell_exec('stty -icanon -echo'); + + // Add highlighted text style + $output->getFormatter()->setStyle('hl', new OutputFormatterStyle('black', 'white')); + + // Read a keypress + while (!feof($inputStream)) { + $c = fread($inputStream, 1); + + // Backspace Character + if ("\177" === $c) { + if (0 === $numMatches && 0 !== $i) { + --$i; + // Move cursor backwards + $output->write("\033[1D"); + } + + if ($i === 0) { + $ofs = -1; + $matches = $autocomplete; + $numMatches = count($matches); + } else { + $numMatches = 0; + } + + // Pop the last character off the end of our string + $ret = substr($ret, 0, $i); + } elseif ("\033" === $c) { + // Did we read an escape sequence? + $c .= fread($inputStream, 2); + + // A = Up Arrow. B = Down Arrow + if (isset($c[2]) && ('A' === $c[2] || 'B' === $c[2])) { + if ('A' === $c[2] && -1 === $ofs) { + $ofs = 0; + } + + if (0 === $numMatches) { + continue; + } + + $ofs += ('A' === $c[2]) ? -1 : 1; + $ofs = ($numMatches + $ofs) % $numMatches; + } + } elseif (ord($c) < 32) { + if ("\t" === $c || "\n" === $c) { + if ($numMatches > 0 && -1 !== $ofs) { + $ret = $matches[$ofs]; + // Echo out remaining chars for current match + $output->write(substr($ret, $i)); + $i = strlen($ret); + } + + if ("\n" === $c) { + $output->write($c); + break; + } + + $numMatches = 0; + } + + continue; + } else { + $output->write($c); + $ret .= $c; + ++$i; + + $numMatches = 0; + $ofs = 0; + + foreach ($autocomplete as $value) { + // If typed characters match the beginning chunk of value (e.g. [AcmeDe]moBundle) + if (0 === strpos($value, $ret) && $i !== strlen($value)) { + $matches[$numMatches++] = $value; + } + } + } + + // Erase characters from cursor to end of line + $output->write("\033[K"); + + if ($numMatches > 0 && -1 !== $ofs) { + // Save cursor position + $output->write("\0337"); + // Write highlighted text + $output->write(''.substr($matches[$ofs], $i).''); + // Restore cursor position + $output->write("\0338"); + } + } + + // Reset stty so it behaves normally again + shell_exec(sprintf('stty %s', $sttyMode)); + + return $ret; + } + + /** + * Gets a hidden response from user. + * + * @param OutputInterface $output An Output instance + * + * @return string The answer + * + * @throws \RuntimeException In case the fallback is deactivated and the response cannot be hidden + */ + private function getHiddenResponse(OutputInterface $output, $inputStream) + { + if ('\\' === DIRECTORY_SEPARATOR) { + $exe = __DIR__.'/../Resources/bin/hiddeninput.exe'; + + // handle code running from a phar + if ('phar:' === substr(__FILE__, 0, 5)) { + $tmpExe = sys_get_temp_dir().'/hiddeninput.exe'; + copy($exe, $tmpExe); + $exe = $tmpExe; + } + + $value = rtrim(shell_exec($exe)); + $output->writeln(''); + + if (isset($tmpExe)) { + unlink($tmpExe); + } + + return $value; + } + + if ($this->hasSttyAvailable()) { + $sttyMode = shell_exec('stty -g'); + + shell_exec('stty -echo'); + $value = fgets($inputStream, 4096); + shell_exec(sprintf('stty %s', $sttyMode)); + + if (false === $value) { + throw new \RuntimeException('Aborted'); + } + + $value = trim($value); + $output->writeln(''); + + return $value; + } + + if (false !== $shell = $this->getShell()) { + $readCmd = $shell === 'csh' ? 'set mypassword = $<' : 'read -r mypassword'; + $command = sprintf("/usr/bin/env %s -c 'stty -echo; %s; stty echo; echo \$mypassword'", $shell, $readCmd); + $value = rtrim(shell_exec($command)); + $output->writeln(''); + + return $value; + } + + throw new \RuntimeException('Unable to hide the response.'); + } + + /** + * Validates an attempt. + * + * @param callable $interviewer A callable that will ask for a question and return the result + * @param OutputInterface $output An Output instance + * @param Question $question A Question instance + * + * @return string The validated response + * + * @throws \Exception In case the max number of attempts has been reached and no valid response has been given + */ + private function validateAttempts($interviewer, OutputInterface $output, Question $question) + { + $error = null; + $attempts = $question->getMaxAttempts(); + while (null === $attempts || $attempts--) { + if (null !== $error) { + $this->writeError($output, $error); + } + + try { + return call_user_func($question->getValidator(), $interviewer()); + } catch (\Exception $error) { + } + } + + throw $error; + } + + /** + * Returns a valid unix shell. + * + * @return string|bool The valid shell name, false in case no valid shell is found + */ + private function getShell() + { + if (null !== self::$shell) { + return self::$shell; + } + + self::$shell = false; + + if (file_exists('/usr/bin/env')) { + // handle other OSs with bash/zsh/ksh/csh if available to hide the answer + $test = "/usr/bin/env %s -c 'echo OK' 2> /dev/null"; + foreach (array('bash', 'zsh', 'ksh', 'csh') as $sh) { + if ('OK' === rtrim(shell_exec(sprintf($test, $sh)))) { + self::$shell = $sh; + break; + } + } + } + + return self::$shell; + } + + /** + * Returns whether Stty is available or not. + * + * @return bool + */ + private function hasSttyAvailable() + { + if (null !== self::$stty) { + return self::$stty; + } + + exec('stty 2>&1', $output, $exitcode); + + return self::$stty = $exitcode === 0; + } +} diff --git a/vendor/symfony/console/Helper/SymfonyQuestionHelper.php b/vendor/symfony/console/Helper/SymfonyQuestionHelper.php new file mode 100644 index 0000000..77130f9 --- /dev/null +++ b/vendor/symfony/console/Helper/SymfonyQuestionHelper.php @@ -0,0 +1,106 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Helper; + +use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Output\OutputInterface; +use Symfony\Component\Console\Question\ChoiceQuestion; +use Symfony\Component\Console\Question\ConfirmationQuestion; +use Symfony\Component\Console\Question\Question; +use Symfony\Component\Console\Style\SymfonyStyle; + +/** + * Symfony Style Guide compliant question helper. + * + * @author Kevin Bond + */ +class SymfonyQuestionHelper extends QuestionHelper +{ + /** + * {@inheritdoc} + */ + public function ask(InputInterface $input, OutputInterface $output, Question $question) + { + $validator = $question->getValidator(); + $question->setValidator(function ($value) use ($validator) { + if (null !== $validator && is_callable($validator)) { + $value = $validator($value); + } + + // make required + if (!is_array($value) && !is_bool($value) && 0 === strlen($value)) { + throw new \Exception('A value is required.'); + } + + return $value; + }); + + return parent::ask($input, $output, $question); + } + + /** + * {@inheritdoc} + */ + protected function writePrompt(OutputInterface $output, Question $question) + { + $text = $question->getQuestion(); + $default = $question->getDefault(); + + switch (true) { + case null === $default: + $text = sprintf(' %s:', $text); + + break; + + case $question instanceof ConfirmationQuestion: + $text = sprintf(' %s (yes/no) [%s]:', $text, $default ? 'yes' : 'no'); + + break; + + case $question instanceof ChoiceQuestion: + $choices = $question->getChoices(); + $text = sprintf(' %s [%s]:', $text, $choices[$default]); + + break; + + default: + $text = sprintf(' %s [%s]:', $text, $default); + } + + $output->writeln($text); + + if ($question instanceof ChoiceQuestion) { + $width = max(array_map('strlen', array_keys($question->getChoices()))); + + foreach ($question->getChoices() as $key => $value) { + $output->writeln(sprintf(" [%-${width}s] %s", $key, $value)); + } + } + + $output->write(' > '); + } + + /** + * {@inheritdoc} + */ + protected function writeError(OutputInterface $output, \Exception $error) + { + if ($output instanceof SymfonyStyle) { + $output->newLine(); + $output->error($error->getMessage()); + + return; + } + + parent::writeError($output, $error); + } +} diff --git a/vendor/symfony/console/Helper/Table.php b/vendor/symfony/console/Helper/Table.php new file mode 100644 index 0000000..6da4b7d --- /dev/null +++ b/vendor/symfony/console/Helper/Table.php @@ -0,0 +1,606 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Helper; + +use Symfony\Component\Console\Output\OutputInterface; + +/** + * Provides helpers to display a table. + * + * @author Fabien Potencier + * @author Саша Стаменковић + * @author Abdellatif Ait boudad + */ +class Table +{ + /** + * Table headers. + * + * @var array + */ + private $headers = array(); + + /** + * Table rows. + * + * @var array + */ + private $rows = array(); + + /** + * Column widths cache. + * + * @var array + */ + private $columnWidths = array(); + + /** + * Number of columns cache. + * + * @var array + */ + private $numberOfColumns; + + /** + * @var OutputInterface + */ + private $output; + + /** + * @var TableStyle + */ + private $style; + + private static $styles; + + public function __construct(OutputInterface $output) + { + $this->output = $output; + + if (!self::$styles) { + self::$styles = self::initStyles(); + } + + $this->setStyle('default'); + } + + /** + * Sets a style definition. + * + * @param string $name The style name + * @param TableStyle $style A TableStyle instance + */ + public static function setStyleDefinition($name, TableStyle $style) + { + if (!self::$styles) { + self::$styles = self::initStyles(); + } + + self::$styles[$name] = $style; + } + + /** + * Gets a style definition by name. + * + * @param string $name The style name + * + * @return TableStyle A TableStyle instance + */ + public static function getStyleDefinition($name) + { + if (!self::$styles) { + self::$styles = self::initStyles(); + } + + if (!self::$styles[$name]) { + throw new \InvalidArgumentException(sprintf('Style "%s" is not defined.', $name)); + } + + return self::$styles[$name]; + } + + /** + * Sets table style. + * + * @param TableStyle|string $name The style name or a TableStyle instance + * + * @return Table + */ + public function setStyle($name) + { + if ($name instanceof TableStyle) { + $this->style = $name; + } elseif (isset(self::$styles[$name])) { + $this->style = self::$styles[$name]; + } else { + throw new \InvalidArgumentException(sprintf('Style "%s" is not defined.', $name)); + } + + return $this; + } + + /** + * Gets the current table style. + * + * @return TableStyle + */ + public function getStyle() + { + return $this->style; + } + + public function setHeaders(array $headers) + { + $headers = array_values($headers); + if (!empty($headers) && !is_array($headers[0])) { + $headers = array($headers); + } + + $this->headers = $headers; + + return $this; + } + + public function setRows(array $rows) + { + $this->rows = array(); + + return $this->addRows($rows); + } + + public function addRows(array $rows) + { + foreach ($rows as $row) { + $this->addRow($row); + } + + return $this; + } + + public function addRow($row) + { + if ($row instanceof TableSeparator) { + $this->rows[] = $row; + + return $this; + } + + if (!is_array($row)) { + throw new \InvalidArgumentException('A row must be an array or a TableSeparator instance.'); + } + + $this->rows[] = array_values($row); + + return $this; + } + + public function setRow($column, array $row) + { + $this->rows[$column] = $row; + + return $this; + } + + /** + * Renders table to output. + * + * Example: + * +---------------+-----------------------+------------------+ + * | ISBN | Title | Author | + * +---------------+-----------------------+------------------+ + * | 99921-58-10-7 | Divine Comedy | Dante Alighieri | + * | 9971-5-0210-0 | A Tale of Two Cities | Charles Dickens | + * | 960-425-059-0 | The Lord of the Rings | J. R. R. Tolkien | + * +---------------+-----------------------+------------------+ + */ + public function render() + { + $this->calculateNumberOfColumns(); + $this->rows = $this->buildTableRows($this->rows); + $this->headers = $this->buildTableRows($this->headers); + + $this->renderRowSeparator(); + if (!empty($this->headers)) { + foreach ($this->headers as $header) { + $this->renderRow($header, $this->style->getCellHeaderFormat()); + $this->renderRowSeparator(); + } + } + foreach ($this->rows as $row) { + if ($row instanceof TableSeparator) { + $this->renderRowSeparator(); + } else { + $this->renderRow($row, $this->style->getCellRowFormat()); + } + } + if (!empty($this->rows)) { + $this->renderRowSeparator(); + } + + $this->cleanup(); + } + + /** + * Renders horizontal header separator. + * + * Example: +-----+-----------+-------+ + */ + private function renderRowSeparator() + { + if (0 === $count = $this->numberOfColumns) { + return; + } + + if (!$this->style->getHorizontalBorderChar() && !$this->style->getCrossingChar()) { + return; + } + + $markup = $this->style->getCrossingChar(); + for ($column = 0; $column < $count; ++$column) { + $markup .= str_repeat($this->style->getHorizontalBorderChar(), $this->getColumnWidth($column)).$this->style->getCrossingChar(); + } + + $this->output->writeln(sprintf($this->style->getBorderFormat(), $markup)); + } + + /** + * Renders vertical column separator. + */ + private function renderColumnSeparator() + { + $this->output->write(sprintf($this->style->getBorderFormat(), $this->style->getVerticalBorderChar())); + } + + /** + * Renders table row. + * + * Example: | 9971-5-0210-0 | A Tale of Two Cities | Charles Dickens | + * + * @param array $row + * @param string $cellFormat + */ + private function renderRow(array $row, $cellFormat) + { + if (empty($row)) { + return; + } + + $this->renderColumnSeparator(); + foreach ($this->getRowColumns($row) as $column) { + $this->renderCell($row, $column, $cellFormat); + $this->renderColumnSeparator(); + } + $this->output->writeln(''); + } + + /** + * Renders table cell with padding. + * + * @param array $row + * @param int $column + * @param string $cellFormat + */ + private function renderCell(array $row, $column, $cellFormat) + { + $cell = isset($row[$column]) ? $row[$column] : ''; + $width = $this->getColumnWidth($column); + if ($cell instanceof TableCell && $cell->getColspan() > 1) { + // add the width of the following columns(numbers of colspan). + foreach (range($column + 1, $column + $cell->getColspan() - 1) as $nextColumn) { + $width += $this->getColumnSeparatorWidth() + $this->getColumnWidth($nextColumn); + } + } + + // str_pad won't work properly with multi-byte strings, we need to fix the padding + if (function_exists('mb_strwidth') && false !== $encoding = mb_detect_encoding($cell)) { + $width += strlen($cell) - mb_strwidth($cell, $encoding); + } + + if ($cell instanceof TableSeparator) { + $this->output->write(sprintf($this->style->getBorderFormat(), str_repeat($this->style->getHorizontalBorderChar(), $width))); + } else { + $width += Helper::strlen($cell) - Helper::strlenWithoutDecoration($this->output->getFormatter(), $cell); + $content = sprintf($this->style->getCellRowContentFormat(), $cell); + $this->output->write(sprintf($cellFormat, str_pad($content, $width, $this->style->getPaddingChar(), $this->style->getPadType()))); + } + } + + /** + * Calculate number of columns for this table. + */ + private function calculateNumberOfColumns() + { + if (null !== $this->numberOfColumns) { + return; + } + + $columns = array(0); + foreach (array_merge($this->headers, $this->rows) as $row) { + if ($row instanceof TableSeparator) { + continue; + } + + $columns[] = $this->getNumberOfColumns($row); + } + + return $this->numberOfColumns = max($columns); + } + + private function buildTableRows($rows) + { + $unmergedRows = array(); + for ($rowKey = 0; $rowKey < count($rows); ++$rowKey) { + $rows = $this->fillNextRows($rows, $rowKey); + + // Remove any new line breaks and replace it with a new line + foreach ($rows[$rowKey] as $column => $cell) { + $rows[$rowKey] = $this->fillCells($rows[$rowKey], $column); + if (!strstr($cell, "\n")) { + continue; + } + $lines = explode("\n", $cell); + foreach ($lines as $lineKey => $line) { + if ($cell instanceof TableCell) { + $line = new TableCell($line, array('colspan' => $cell->getColspan())); + } + if (0 === $lineKey) { + $rows[$rowKey][$column] = $line; + } else { + $unmergedRows[$rowKey][$lineKey][$column] = $line; + } + } + } + } + + $tableRows = array(); + foreach ($rows as $rowKey => $row) { + $tableRows[] = $row; + if (isset($unmergedRows[$rowKey])) { + $tableRows = array_merge($tableRows, $unmergedRows[$rowKey]); + } + } + + return $tableRows; + } + + /** + * fill rows that contains rowspan > 1. + * + * @param array $rows + * @param array $line + * + * @return array + */ + private function fillNextRows($rows, $line) + { + $unmergedRows = array(); + foreach ($rows[$line] as $column => $cell) { + if ($cell instanceof TableCell && $cell->getRowspan() > 1) { + $nbLines = $cell->getRowspan() - 1; + $lines = array($cell); + if (strstr($cell, "\n")) { + $lines = explode("\n", $cell); + $nbLines = count($lines) > $nbLines ? substr_count($cell, "\n") : $nbLines; + + $rows[$line][$column] = new TableCell($lines[0], array('colspan' => $cell->getColspan())); + unset($lines[0]); + } + + // create a two dimensional array (rowspan x colspan) + $unmergedRows = array_replace_recursive(array_fill($line + 1, $nbLines, ''), $unmergedRows); + foreach ($unmergedRows as $unmergedRowKey => $unmergedRow) { + $value = isset($lines[$unmergedRowKey - $line]) ? $lines[$unmergedRowKey - $line] : ''; + $unmergedRows[$unmergedRowKey][$column] = new TableCell($value, array('colspan' => $cell->getColspan())); + } + } + } + + foreach ($unmergedRows as $unmergedRowKey => $unmergedRow) { + // we need to know if $unmergedRow will be merged or inserted into $rows + if (isset($rows[$unmergedRowKey]) && is_array($rows[$unmergedRowKey]) && ($this->getNumberOfColumns($rows[$unmergedRowKey]) + $this->getNumberOfColumns($unmergedRows[$unmergedRowKey]) <= $this->numberOfColumns)) { + foreach ($unmergedRow as $cellKey => $cell) { + // insert cell into row at cellKey position + array_splice($rows[$unmergedRowKey], $cellKey, 0, array($cell)); + } + } else { + $row = $this->copyRow($rows, $unmergedRowKey - 1); + foreach ($unmergedRow as $column => $cell) { + if (!empty($cell)) { + $row[$column] = $unmergedRow[$column]; + } + } + array_splice($rows, $unmergedRowKey, 0, array($row)); + } + } + + return $rows; + } + + /** + * fill cells for a row that contains colspan > 1. + * + * @param array $row + * @param array $column + * + * @return array + */ + private function fillCells($row, $column) + { + $cell = $row[$column]; + if ($cell instanceof TableCell && $cell->getColspan() > 1) { + foreach (range($column + 1, $column + $cell->getColspan() - 1) as $position) { + // insert empty value into rows at column position + array_splice($row, $position, 0, ''); + } + } + + return $row; + } + + /** + * @param array $rows + * @param int $line + * + * @return array + */ + private function copyRow($rows, $line) + { + $row = $rows[$line]; + foreach ($row as $cellKey => $cellValue) { + $row[$cellKey] = ''; + if ($cellValue instanceof TableCell) { + $row[$cellKey] = new TableCell('', array('colspan' => $cellValue->getColspan())); + } + } + + return $row; + } + + /** + * Gets number of columns by row. + * + * @param array $row + * + * @return int + */ + private function getNumberOfColumns(array $row) + { + $columns = count($row); + foreach ($row as $column) { + $columns += $column instanceof TableCell ? ($column->getColspan() - 1) : 0; + } + + return $columns; + } + + /** + * Gets list of columns for the given row. + * + * @param array $row + * + * @return array() + */ + private function getRowColumns($row) + { + $columns = range(0, $this->numberOfColumns - 1); + foreach ($row as $cellKey => $cell) { + if ($cell instanceof TableCell && $cell->getColspan() > 1) { + // exclude grouped columns. + $columns = array_diff($columns, range($cellKey + 1, $cellKey + $cell->getColspan() - 1)); + } + } + + return $columns; + } + + /** + * Gets column width. + * + * @param int $column + * + * @return int + */ + private function getColumnWidth($column) + { + if (isset($this->columnWidths[$column])) { + return $this->columnWidths[$column]; + } + + foreach (array_merge($this->headers, $this->rows) as $row) { + if ($row instanceof TableSeparator) { + continue; + } + + $lengths[] = $this->getCellWidth($row, $column); + } + + return $this->columnWidths[$column] = max($lengths) + strlen($this->style->getCellRowContentFormat()) - 2; + } + + /** + * Gets column width. + * + * @param int $column + * + * @return int + */ + private function getColumnSeparatorWidth() + { + return strlen(sprintf($this->style->getBorderFormat(), $this->style->getVerticalBorderChar())); + } + + /** + * Gets cell width. + * + * @param array $row + * @param int $column + * + * @return int + */ + private function getCellWidth(array $row, $column) + { + if (isset($row[$column])) { + $cell = $row[$column]; + $cellWidth = Helper::strlenWithoutDecoration($this->output->getFormatter(), $cell); + if ($cell instanceof TableCell && $cell->getColspan() > 1) { + // we assume that cell value will be across more than one column. + $cellWidth = $cellWidth / $cell->getColspan(); + } + + return $cellWidth; + } + + return 0; + } + + /** + * Called after rendering to cleanup cache data. + */ + private function cleanup() + { + $this->columnWidths = array(); + $this->numberOfColumns = null; + } + + private static function initStyles() + { + $borderless = new TableStyle(); + $borderless + ->setHorizontalBorderChar('=') + ->setVerticalBorderChar(' ') + ->setCrossingChar(' ') + ; + + $compact = new TableStyle(); + $compact + ->setHorizontalBorderChar('') + ->setVerticalBorderChar(' ') + ->setCrossingChar('') + ->setCellRowContentFormat('%s') + ; + + $styleGuide = new TableStyle(); + $styleGuide + ->setHorizontalBorderChar('-') + ->setVerticalBorderChar(' ') + ->setCrossingChar(' ') + ->setCellHeaderFormat('%s') + ; + + return array( + 'default' => new TableStyle(), + 'borderless' => $borderless, + 'compact' => $compact, + 'symfony-style-guide' => $styleGuide, + ); + } +} diff --git a/vendor/symfony/console/Helper/TableCell.php b/vendor/symfony/console/Helper/TableCell.php new file mode 100644 index 0000000..aa0d318 --- /dev/null +++ b/vendor/symfony/console/Helper/TableCell.php @@ -0,0 +1,77 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Helper; + +/** + * @author Abdellatif Ait boudad + */ +class TableCell +{ + /** + * @var string + */ + private $value; + + /** + * @var array + */ + private $options = array( + 'rowspan' => 1, + 'colspan' => 1, + ); + + /** + * @param string $value + * @param array $options + */ + public function __construct($value = '', array $options = array()) + { + $this->value = $value; + + // check option names + if ($diff = array_diff(array_keys($options), array_keys($this->options))) { + throw new \InvalidArgumentException(sprintf('The TableCell does not support the following options: \'%s\'.', implode('\', \'', $diff))); + } + + $this->options = array_merge($this->options, $options); + } + + /** + * Returns the cell value. + * + * @return string + */ + public function __toString() + { + return $this->value; + } + + /** + * Gets number of colspan. + * + * @return int + */ + public function getColspan() + { + return (int) $this->options['colspan']; + } + + /** + * Gets number of rowspan. + * + * @return int + */ + public function getRowspan() + { + return (int) $this->options['rowspan']; + } +} diff --git a/vendor/symfony/console/Helper/TableHelper.php b/vendor/symfony/console/Helper/TableHelper.php new file mode 100644 index 0000000..2953522 --- /dev/null +++ b/vendor/symfony/console/Helper/TableHelper.php @@ -0,0 +1,268 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Helper; + +use Symfony\Component\Console\Output\OutputInterface; +use Symfony\Component\Console\Output\NullOutput; + +/** + * Provides helpers to display table output. + * + * @author Саша Стаменковић + * @author Fabien Potencier + * + * @deprecated since version 2.5, to be removed in 3.0 + * Use {@link Table} instead. + */ +class TableHelper extends Helper +{ + const LAYOUT_DEFAULT = 0; + const LAYOUT_BORDERLESS = 1; + const LAYOUT_COMPACT = 2; + + /** + * @var Table + */ + private $table; + + public function __construct($triggerDeprecationError = true) + { + if ($triggerDeprecationError) { + @trigger_error('The '.__CLASS__.' class is deprecated since version 2.5 and will be removed in 3.0. Use the Symfony\Component\Console\Helper\Table class instead.', E_USER_DEPRECATED); + } + + $this->table = new Table(new NullOutput()); + } + + /** + * Sets table layout type. + * + * @param int $layout self::LAYOUT_* + * + * @return TableHelper + * + * @throws \InvalidArgumentException when the table layout is not known + */ + public function setLayout($layout) + { + switch ($layout) { + case self::LAYOUT_BORDERLESS: + $this->table->setStyle('borderless'); + break; + + case self::LAYOUT_COMPACT: + $this->table->setStyle('compact'); + break; + + case self::LAYOUT_DEFAULT: + $this->table->setStyle('default'); + break; + + default: + throw new \InvalidArgumentException(sprintf('Invalid table layout "%s".', $layout)); + }; + + return $this; + } + + public function setHeaders(array $headers) + { + $this->table->setHeaders($headers); + + return $this; + } + + public function setRows(array $rows) + { + $this->table->setRows($rows); + + return $this; + } + + public function addRows(array $rows) + { + $this->table->addRows($rows); + + return $this; + } + + public function addRow(array $row) + { + $this->table->addRow($row); + + return $this; + } + + public function setRow($column, array $row) + { + $this->table->setRow($column, $row); + + return $this; + } + + /** + * Sets padding character, used for cell padding. + * + * @param string $paddingChar + * + * @return TableHelper + */ + public function setPaddingChar($paddingChar) + { + $this->table->getStyle()->setPaddingChar($paddingChar); + + return $this; + } + + /** + * Sets horizontal border character. + * + * @param string $horizontalBorderChar + * + * @return TableHelper + */ + public function setHorizontalBorderChar($horizontalBorderChar) + { + $this->table->getStyle()->setHorizontalBorderChar($horizontalBorderChar); + + return $this; + } + + /** + * Sets vertical border character. + * + * @param string $verticalBorderChar + * + * @return TableHelper + */ + public function setVerticalBorderChar($verticalBorderChar) + { + $this->table->getStyle()->setVerticalBorderChar($verticalBorderChar); + + return $this; + } + + /** + * Sets crossing character. + * + * @param string $crossingChar + * + * @return TableHelper + */ + public function setCrossingChar($crossingChar) + { + $this->table->getStyle()->setCrossingChar($crossingChar); + + return $this; + } + + /** + * Sets header cell format. + * + * @param string $cellHeaderFormat + * + * @return TableHelper + */ + public function setCellHeaderFormat($cellHeaderFormat) + { + $this->table->getStyle()->setCellHeaderFormat($cellHeaderFormat); + + return $this; + } + + /** + * Sets row cell format. + * + * @param string $cellRowFormat + * + * @return TableHelper + */ + public function setCellRowFormat($cellRowFormat) + { + $this->table->getStyle()->setCellHeaderFormat($cellRowFormat); + + return $this; + } + + /** + * Sets row cell content format. + * + * @param string $cellRowContentFormat + * + * @return TableHelper + */ + public function setCellRowContentFormat($cellRowContentFormat) + { + $this->table->getStyle()->setCellRowContentFormat($cellRowContentFormat); + + return $this; + } + + /** + * Sets table border format. + * + * @param string $borderFormat + * + * @return TableHelper + */ + public function setBorderFormat($borderFormat) + { + $this->table->getStyle()->setBorderFormat($borderFormat); + + return $this; + } + + /** + * Sets cell padding type. + * + * @param int $padType STR_PAD_* + * + * @return TableHelper + */ + public function setPadType($padType) + { + $this->table->getStyle()->setPadType($padType); + + return $this; + } + + /** + * Renders table to output. + * + * Example: + * +---------------+-----------------------+------------------+ + * | ISBN | Title | Author | + * +---------------+-----------------------+------------------+ + * | 99921-58-10-7 | Divine Comedy | Dante Alighieri | + * | 9971-5-0210-0 | A Tale of Two Cities | Charles Dickens | + * | 960-425-059-0 | The Lord of the Rings | J. R. R. Tolkien | + * +---------------+-----------------------+------------------+ + * + * @param OutputInterface $output + */ + public function render(OutputInterface $output) + { + $p = new \ReflectionProperty($this->table, 'output'); + $p->setAccessible(true); + $p->setValue($this->table, $output); + + $this->table->render(); + } + + /** + * {@inheritdoc} + */ + public function getName() + { + return 'table'; + } +} diff --git a/vendor/symfony/console/Helper/TableSeparator.php b/vendor/symfony/console/Helper/TableSeparator.php new file mode 100644 index 0000000..8cbbc66 --- /dev/null +++ b/vendor/symfony/console/Helper/TableSeparator.php @@ -0,0 +1,29 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Helper; + +/** + * Marks a row as being a separator. + * + * @author Fabien Potencier + */ +class TableSeparator extends TableCell +{ + /** + * @param string $value + * @param array $options + */ + public function __construct(array $options = array()) + { + parent::__construct('', $options); + } +} diff --git a/vendor/symfony/console/Helper/TableStyle.php b/vendor/symfony/console/Helper/TableStyle.php new file mode 100644 index 0000000..f0f46c7 --- /dev/null +++ b/vendor/symfony/console/Helper/TableStyle.php @@ -0,0 +1,255 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Helper; + +/** + * Defines the styles for a Table. + * + * @author Fabien Potencier + * @author Саша Стаменковић + */ +class TableStyle +{ + private $paddingChar = ' '; + private $horizontalBorderChar = '-'; + private $verticalBorderChar = '|'; + private $crossingChar = '+'; + private $cellHeaderFormat = '%s'; + private $cellRowFormat = '%s'; + private $cellRowContentFormat = ' %s '; + private $borderFormat = '%s'; + private $padType = STR_PAD_RIGHT; + + /** + * Sets padding character, used for cell padding. + * + * @param string $paddingChar + * + * @return TableStyle + */ + public function setPaddingChar($paddingChar) + { + if (!$paddingChar) { + throw new \LogicException('The padding char must not be empty'); + } + + $this->paddingChar = $paddingChar; + + return $this; + } + + /** + * Gets padding character, used for cell padding. + * + * @return string + */ + public function getPaddingChar() + { + return $this->paddingChar; + } + + /** + * Sets horizontal border character. + * + * @param string $horizontalBorderChar + * + * @return TableStyle + */ + public function setHorizontalBorderChar($horizontalBorderChar) + { + $this->horizontalBorderChar = $horizontalBorderChar; + + return $this; + } + + /** + * Gets horizontal border character. + * + * @return string + */ + public function getHorizontalBorderChar() + { + return $this->horizontalBorderChar; + } + + /** + * Sets vertical border character. + * + * @param string $verticalBorderChar + * + * @return TableStyle + */ + public function setVerticalBorderChar($verticalBorderChar) + { + $this->verticalBorderChar = $verticalBorderChar; + + return $this; + } + + /** + * Gets vertical border character. + * + * @return string + */ + public function getVerticalBorderChar() + { + return $this->verticalBorderChar; + } + + /** + * Sets crossing character. + * + * @param string $crossingChar + * + * @return TableStyle + */ + public function setCrossingChar($crossingChar) + { + $this->crossingChar = $crossingChar; + + return $this; + } + + /** + * Gets crossing character. + * + * @return string $crossingChar + */ + public function getCrossingChar() + { + return $this->crossingChar; + } + + /** + * Sets header cell format. + * + * @param string $cellHeaderFormat + * + * @return TableStyle + */ + public function setCellHeaderFormat($cellHeaderFormat) + { + $this->cellHeaderFormat = $cellHeaderFormat; + + return $this; + } + + /** + * Gets header cell format. + * + * @return string + */ + public function getCellHeaderFormat() + { + return $this->cellHeaderFormat; + } + + /** + * Sets row cell format. + * + * @param string $cellRowFormat + * + * @return TableStyle + */ + public function setCellRowFormat($cellRowFormat) + { + $this->cellRowFormat = $cellRowFormat; + + return $this; + } + + /** + * Gets row cell format. + * + * @return string + */ + public function getCellRowFormat() + { + return $this->cellRowFormat; + } + + /** + * Sets row cell content format. + * + * @param string $cellRowContentFormat + * + * @return TableStyle + */ + public function setCellRowContentFormat($cellRowContentFormat) + { + $this->cellRowContentFormat = $cellRowContentFormat; + + return $this; + } + + /** + * Gets row cell content format. + * + * @return string + */ + public function getCellRowContentFormat() + { + return $this->cellRowContentFormat; + } + + /** + * Sets table border format. + * + * @param string $borderFormat + * + * @return TableStyle + */ + public function setBorderFormat($borderFormat) + { + $this->borderFormat = $borderFormat; + + return $this; + } + + /** + * Gets table border format. + * + * @return string + */ + public function getBorderFormat() + { + return $this->borderFormat; + } + + /** + * Sets cell padding type. + * + * @param int $padType STR_PAD_* + * + * @return TableStyle + */ + public function setPadType($padType) + { + if (!in_array($padType, array(STR_PAD_LEFT, STR_PAD_RIGHT, STR_PAD_BOTH), true)) { + throw new \InvalidArgumentException('Invalid padding type. Expected one of (STR_PAD_LEFT, STR_PAD_RIGHT, STR_PAD_BOTH).'); + } + + $this->padType = $padType; + + return $this; + } + + /** + * Gets cell padding type. + * + * @return int + */ + public function getPadType() + { + return $this->padType; + } +} diff --git a/vendor/symfony/console/Input/ArgvInput.php b/vendor/symfony/console/Input/ArgvInput.php new file mode 100644 index 0000000..a6c2132 --- /dev/null +++ b/vendor/symfony/console/Input/ArgvInput.php @@ -0,0 +1,353 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Input; + +/** + * ArgvInput represents an input coming from the CLI arguments. + * + * Usage: + * + * $input = new ArgvInput(); + * + * By default, the `$_SERVER['argv']` array is used for the input values. + * + * This can be overridden by explicitly passing the input values in the constructor: + * + * $input = new ArgvInput($_SERVER['argv']); + * + * If you pass it yourself, don't forget that the first element of the array + * is the name of the running application. + * + * When passing an argument to the constructor, be sure that it respects + * the same rules as the argv one. It's almost always better to use the + * `StringInput` when you want to provide your own input. + * + * @author Fabien Potencier + * + * @see http://www.gnu.org/software/libc/manual/html_node/Argument-Syntax.html + * @see http://www.opengroup.org/onlinepubs/009695399/basedefs/xbd_chap12.html#tag_12_02 + * + * @api + */ +class ArgvInput extends Input +{ + private $tokens; + private $parsed; + + /** + * Constructor. + * + * @param array $argv An array of parameters from the CLI (in the argv format) + * @param InputDefinition $definition A InputDefinition instance + * + * @api + */ + public function __construct(array $argv = null, InputDefinition $definition = null) + { + if (null === $argv) { + $argv = $_SERVER['argv']; + } + + // strip the application name + array_shift($argv); + + $this->tokens = $argv; + + parent::__construct($definition); + } + + protected function setTokens(array $tokens) + { + $this->tokens = $tokens; + } + + /** + * Processes command line arguments. + */ + protected function parse() + { + $parseOptions = true; + $this->parsed = $this->tokens; + while (null !== $token = array_shift($this->parsed)) { + if ($parseOptions && '' == $token) { + $this->parseArgument($token); + } elseif ($parseOptions && '--' == $token) { + $parseOptions = false; + } elseif ($parseOptions && 0 === strpos($token, '--')) { + $this->parseLongOption($token); + } elseif ($parseOptions && '-' === $token[0] && '-' !== $token) { + $this->parseShortOption($token); + } else { + $this->parseArgument($token); + } + } + } + + /** + * Parses a short option. + * + * @param string $token The current token. + */ + private function parseShortOption($token) + { + $name = substr($token, 1); + + if (strlen($name) > 1) { + if ($this->definition->hasShortcut($name[0]) && $this->definition->getOptionForShortcut($name[0])->acceptValue()) { + // an option with a value (with no space) + $this->addShortOption($name[0], substr($name, 1)); + } else { + $this->parseShortOptionSet($name); + } + } else { + $this->addShortOption($name, null); + } + } + + /** + * Parses a short option set. + * + * @param string $name The current token + * + * @throws \RuntimeException When option given doesn't exist + */ + private function parseShortOptionSet($name) + { + $len = strlen($name); + for ($i = 0; $i < $len; ++$i) { + if (!$this->definition->hasShortcut($name[$i])) { + throw new \RuntimeException(sprintf('The "-%s" option does not exist.', $name[$i])); + } + + $option = $this->definition->getOptionForShortcut($name[$i]); + if ($option->acceptValue()) { + $this->addLongOption($option->getName(), $i === $len - 1 ? null : substr($name, $i + 1)); + + break; + } else { + $this->addLongOption($option->getName(), null); + } + } + } + + /** + * Parses a long option. + * + * @param string $token The current token + */ + private function parseLongOption($token) + { + $name = substr($token, 2); + + if (false !== $pos = strpos($name, '=')) { + $this->addLongOption(substr($name, 0, $pos), substr($name, $pos + 1)); + } else { + $this->addLongOption($name, null); + } + } + + /** + * Parses an argument. + * + * @param string $token The current token + * + * @throws \RuntimeException When too many arguments are given + */ + private function parseArgument($token) + { + $c = count($this->arguments); + + // if input is expecting another argument, add it + if ($this->definition->hasArgument($c)) { + $arg = $this->definition->getArgument($c); + $this->arguments[$arg->getName()] = $arg->isArray() ? array($token) : $token; + + // if last argument isArray(), append token to last argument + } elseif ($this->definition->hasArgument($c - 1) && $this->definition->getArgument($c - 1)->isArray()) { + $arg = $this->definition->getArgument($c - 1); + $this->arguments[$arg->getName()][] = $token; + + // unexpected argument + } else { + throw new \RuntimeException('Too many arguments.'); + } + } + + /** + * Adds a short option value. + * + * @param string $shortcut The short option key + * @param mixed $value The value for the option + * + * @throws \RuntimeException When option given doesn't exist + */ + private function addShortOption($shortcut, $value) + { + if (!$this->definition->hasShortcut($shortcut)) { + throw new \RuntimeException(sprintf('The "-%s" option does not exist.', $shortcut)); + } + + $this->addLongOption($this->definition->getOptionForShortcut($shortcut)->getName(), $value); + } + + /** + * Adds a long option value. + * + * @param string $name The long option key + * @param mixed $value The value for the option + * + * @throws \RuntimeException When option given doesn't exist + */ + private function addLongOption($name, $value) + { + if (!$this->definition->hasOption($name)) { + throw new \RuntimeException(sprintf('The "--%s" option does not exist.', $name)); + } + + $option = $this->definition->getOption($name); + + // Convert empty values to null + if (!isset($value[0])) { + $value = null; + } + + if (null !== $value && !$option->acceptValue()) { + throw new \RuntimeException(sprintf('The "--%s" option does not accept a value.', $name)); + } + + if (null === $value && $option->acceptValue() && count($this->parsed)) { + // if option accepts an optional or mandatory argument + // let's see if there is one provided + $next = array_shift($this->parsed); + if (isset($next[0]) && '-' !== $next[0]) { + $value = $next; + } elseif (empty($next)) { + $value = ''; + } else { + array_unshift($this->parsed, $next); + } + } + + if (null === $value) { + if ($option->isValueRequired()) { + throw new \RuntimeException(sprintf('The "--%s" option requires a value.', $name)); + } + + if (!$option->isArray()) { + $value = $option->isValueOptional() ? $option->getDefault() : true; + } + } + + if ($option->isArray()) { + $this->options[$name][] = $value; + } else { + $this->options[$name] = $value; + } + } + + /** + * Returns the first argument from the raw parameters (not parsed). + * + * @return string The value of the first argument or null otherwise + */ + public function getFirstArgument() + { + foreach ($this->tokens as $token) { + if ($token && '-' === $token[0]) { + continue; + } + + return $token; + } + } + + /** + * Returns true if the raw parameters (not parsed) contain a value. + * + * This method is to be used to introspect the input parameters + * before they have been validated. It must be used carefully. + * + * @param string|array $values The value(s) to look for in the raw parameters (can be an array) + * + * @return bool true if the value is contained in the raw parameters + */ + public function hasParameterOption($values) + { + $values = (array) $values; + + foreach ($this->tokens as $token) { + foreach ($values as $value) { + if ($token === $value || 0 === strpos($token, $value.'=')) { + return true; + } + } + } + + return false; + } + + /** + * Returns the value of a raw option (not parsed). + * + * This method is to be used to introspect the input parameters + * before they have been validated. It must be used carefully. + * + * @param string|array $values The value(s) to look for in the raw parameters (can be an array) + * @param mixed $default The default value to return if no result is found + * + * @return mixed The option value + */ + public function getParameterOption($values, $default = false) + { + $values = (array) $values; + $tokens = $this->tokens; + + while (0 < count($tokens)) { + $token = array_shift($tokens); + + foreach ($values as $value) { + if ($token === $value || 0 === strpos($token, $value.'=')) { + if (false !== $pos = strpos($token, '=')) { + return substr($token, $pos + 1); + } + + return array_shift($tokens); + } + } + } + + return $default; + } + + /** + * Returns a stringified representation of the args passed to the command. + * + * @return string + */ + public function __toString() + { + $self = $this; + $tokens = array_map(function ($token) use ($self) { + if (preg_match('{^(-[^=]+=)(.+)}', $token, $match)) { + return $match[1].$self->escapeToken($match[2]); + } + + if ($token && $token[0] !== '-') { + return $self->escapeToken($token); + } + + return $token; + }, $this->tokens); + + return implode(' ', $tokens); + } +} diff --git a/vendor/symfony/console/Input/ArrayInput.php b/vendor/symfony/console/Input/ArrayInput.php new file mode 100644 index 0000000..5743bb8 --- /dev/null +++ b/vendor/symfony/console/Input/ArrayInput.php @@ -0,0 +1,211 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Input; + +/** + * ArrayInput represents an input provided as an array. + * + * Usage: + * + * $input = new ArrayInput(array('name' => 'foo', '--bar' => 'foobar')); + * + * @author Fabien Potencier + * + * @api + */ +class ArrayInput extends Input +{ + private $parameters; + + /** + * Constructor. + * + * @param array $parameters An array of parameters + * @param InputDefinition $definition A InputDefinition instance + * + * @api + */ + public function __construct(array $parameters, InputDefinition $definition = null) + { + $this->parameters = $parameters; + + parent::__construct($definition); + } + + /** + * Returns the first argument from the raw parameters (not parsed). + * + * @return string The value of the first argument or null otherwise + */ + public function getFirstArgument() + { + foreach ($this->parameters as $key => $value) { + if ($key && '-' === $key[0]) { + continue; + } + + return $value; + } + } + + /** + * Returns true if the raw parameters (not parsed) contain a value. + * + * This method is to be used to introspect the input parameters + * before they have been validated. It must be used carefully. + * + * @param string|array $values The values to look for in the raw parameters (can be an array) + * + * @return bool true if the value is contained in the raw parameters + */ + public function hasParameterOption($values) + { + $values = (array) $values; + + foreach ($this->parameters as $k => $v) { + if (!is_int($k)) { + $v = $k; + } + + if (in_array($v, $values)) { + return true; + } + } + + return false; + } + + /** + * Returns the value of a raw option (not parsed). + * + * This method is to be used to introspect the input parameters + * before they have been validated. It must be used carefully. + * + * @param string|array $values The value(s) to look for in the raw parameters (can be an array) + * @param mixed $default The default value to return if no result is found + * + * @return mixed The option value + */ + public function getParameterOption($values, $default = false) + { + $values = (array) $values; + + foreach ($this->parameters as $k => $v) { + if (is_int($k)) { + if (in_array($v, $values)) { + return true; + } + } elseif (in_array($k, $values)) { + return $v; + } + } + + return $default; + } + + /** + * Returns a stringified representation of the args passed to the command. + * + * @return string + */ + public function __toString() + { + $params = array(); + foreach ($this->parameters as $param => $val) { + if ($param && '-' === $param[0]) { + $params[] = $param.('' != $val ? '='.$this->escapeToken($val) : ''); + } else { + $params[] = $this->escapeToken($val); + } + } + + return implode(' ', $params); + } + + /** + * Processes command line arguments. + */ + protected function parse() + { + foreach ($this->parameters as $key => $value) { + if (0 === strpos($key, '--')) { + $this->addLongOption(substr($key, 2), $value); + } elseif ('-' === $key[0]) { + $this->addShortOption(substr($key, 1), $value); + } else { + $this->addArgument($key, $value); + } + } + } + + /** + * Adds a short option value. + * + * @param string $shortcut The short option key + * @param mixed $value The value for the option + * + * @throws \InvalidArgumentException When option given doesn't exist + */ + private function addShortOption($shortcut, $value) + { + if (!$this->definition->hasShortcut($shortcut)) { + throw new \InvalidArgumentException(sprintf('The "-%s" option does not exist.', $shortcut)); + } + + $this->addLongOption($this->definition->getOptionForShortcut($shortcut)->getName(), $value); + } + + /** + * Adds a long option value. + * + * @param string $name The long option key + * @param mixed $value The value for the option + * + * @throws \InvalidArgumentException When option given doesn't exist + * @throws \InvalidArgumentException When a required value is missing + */ + private function addLongOption($name, $value) + { + if (!$this->definition->hasOption($name)) { + throw new \InvalidArgumentException(sprintf('The "--%s" option does not exist.', $name)); + } + + $option = $this->definition->getOption($name); + + if (null === $value) { + if ($option->isValueRequired()) { + throw new \InvalidArgumentException(sprintf('The "--%s" option requires a value.', $name)); + } + + $value = $option->isValueOptional() ? $option->getDefault() : true; + } + + $this->options[$name] = $value; + } + + /** + * Adds an argument value. + * + * @param string $name The argument name + * @param mixed $value The value for the argument + * + * @throws \InvalidArgumentException When argument given doesn't exist + */ + private function addArgument($name, $value) + { + if (!$this->definition->hasArgument($name)) { + throw new \InvalidArgumentException(sprintf('The "%s" argument does not exist.', $name)); + } + + $this->arguments[$name] = $value; + } +} diff --git a/vendor/symfony/console/Input/Input.php b/vendor/symfony/console/Input/Input.php new file mode 100644 index 0000000..5e7c140 --- /dev/null +++ b/vendor/symfony/console/Input/Input.php @@ -0,0 +1,226 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Input; + +/** + * Input is the base class for all concrete Input classes. + * + * Three concrete classes are provided by default: + * + * * `ArgvInput`: The input comes from the CLI arguments (argv) + * * `StringInput`: The input is provided as a string + * * `ArrayInput`: The input is provided as an array + * + * @author Fabien Potencier + */ +abstract class Input implements InputInterface +{ + /** + * @var InputDefinition + */ + protected $definition; + protected $options = array(); + protected $arguments = array(); + protected $interactive = true; + + /** + * Constructor. + * + * @param InputDefinition $definition A InputDefinition instance + */ + public function __construct(InputDefinition $definition = null) + { + if (null === $definition) { + $this->definition = new InputDefinition(); + } else { + $this->bind($definition); + $this->validate(); + } + } + + /** + * Binds the current Input instance with the given arguments and options. + * + * @param InputDefinition $definition A InputDefinition instance + */ + public function bind(InputDefinition $definition) + { + $this->arguments = array(); + $this->options = array(); + $this->definition = $definition; + + $this->parse(); + } + + /** + * Processes command line arguments. + */ + abstract protected function parse(); + + /** + * Validates the input. + * + * @throws \RuntimeException When not enough arguments are given + */ + public function validate() + { + if (count($this->arguments) < $this->definition->getArgumentRequiredCount()) { + throw new \RuntimeException('Not enough arguments.'); + } + } + + /** + * Checks if the input is interactive. + * + * @return bool Returns true if the input is interactive + */ + public function isInteractive() + { + return $this->interactive; + } + + /** + * Sets the input interactivity. + * + * @param bool $interactive If the input should be interactive + */ + public function setInteractive($interactive) + { + $this->interactive = (bool) $interactive; + } + + /** + * Returns the argument values. + * + * @return array An array of argument values + */ + public function getArguments() + { + return array_merge($this->definition->getArgumentDefaults(), $this->arguments); + } + + /** + * Returns the argument value for a given argument name. + * + * @param string $name The argument name + * + * @return mixed The argument value + * + * @throws \InvalidArgumentException When argument given doesn't exist + */ + public function getArgument($name) + { + if (!$this->definition->hasArgument($name)) { + throw new \InvalidArgumentException(sprintf('The "%s" argument does not exist.', $name)); + } + + return isset($this->arguments[$name]) ? $this->arguments[$name] : $this->definition->getArgument($name)->getDefault(); + } + + /** + * Sets an argument value by name. + * + * @param string $name The argument name + * @param string $value The argument value + * + * @throws \InvalidArgumentException When argument given doesn't exist + */ + public function setArgument($name, $value) + { + if (!$this->definition->hasArgument($name)) { + throw new \InvalidArgumentException(sprintf('The "%s" argument does not exist.', $name)); + } + + $this->arguments[$name] = $value; + } + + /** + * Returns true if an InputArgument object exists by name or position. + * + * @param string|int $name The InputArgument name or position + * + * @return bool true if the InputArgument object exists, false otherwise + */ + public function hasArgument($name) + { + return $this->definition->hasArgument($name); + } + + /** + * Returns the options values. + * + * @return array An array of option values + */ + public function getOptions() + { + return array_merge($this->definition->getOptionDefaults(), $this->options); + } + + /** + * Returns the option value for a given option name. + * + * @param string $name The option name + * + * @return mixed The option value + * + * @throws \InvalidArgumentException When option given doesn't exist + */ + public function getOption($name) + { + if (!$this->definition->hasOption($name)) { + throw new \InvalidArgumentException(sprintf('The "%s" option does not exist.', $name)); + } + + return isset($this->options[$name]) ? $this->options[$name] : $this->definition->getOption($name)->getDefault(); + } + + /** + * Sets an option value by name. + * + * @param string $name The option name + * @param string|bool $value The option value + * + * @throws \InvalidArgumentException When option given doesn't exist + */ + public function setOption($name, $value) + { + if (!$this->definition->hasOption($name)) { + throw new \InvalidArgumentException(sprintf('The "%s" option does not exist.', $name)); + } + + $this->options[$name] = $value; + } + + /** + * Returns true if an InputOption object exists by name. + * + * @param string $name The InputOption name + * + * @return bool true if the InputOption object exists, false otherwise + */ + public function hasOption($name) + { + return $this->definition->hasOption($name); + } + + /** + * Escapes a token through escapeshellarg if it contains unsafe chars. + * + * @param string $token + * + * @return string + */ + public function escapeToken($token) + { + return preg_match('{^[\w-]+$}', $token) ? $token : escapeshellarg($token); + } +} diff --git a/vendor/symfony/console/Input/InputArgument.php b/vendor/symfony/console/Input/InputArgument.php new file mode 100644 index 0000000..1167da9 --- /dev/null +++ b/vendor/symfony/console/Input/InputArgument.php @@ -0,0 +1,132 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Input; + +/** + * Represents a command line argument. + * + * @author Fabien Potencier + * + * @api + */ +class InputArgument +{ + const REQUIRED = 1; + const OPTIONAL = 2; + const IS_ARRAY = 4; + + private $name; + private $mode; + private $default; + private $description; + + /** + * Constructor. + * + * @param string $name The argument name + * @param int $mode The argument mode: self::REQUIRED or self::OPTIONAL + * @param string $description A description text + * @param mixed $default The default value (for self::OPTIONAL mode only) + * + * @throws \InvalidArgumentException When argument mode is not valid + * + * @api + */ + public function __construct($name, $mode = null, $description = '', $default = null) + { + if (null === $mode) { + $mode = self::OPTIONAL; + } elseif (!is_int($mode) || $mode > 7 || $mode < 1) { + throw new \InvalidArgumentException(sprintf('Argument mode "%s" is not valid.', $mode)); + } + + $this->name = $name; + $this->mode = $mode; + $this->description = $description; + + $this->setDefault($default); + } + + /** + * Returns the argument name. + * + * @return string The argument name + */ + public function getName() + { + return $this->name; + } + + /** + * Returns true if the argument is required. + * + * @return bool true if parameter mode is self::REQUIRED, false otherwise + */ + public function isRequired() + { + return self::REQUIRED === (self::REQUIRED & $this->mode); + } + + /** + * Returns true if the argument can take multiple values. + * + * @return bool true if mode is self::IS_ARRAY, false otherwise + */ + public function isArray() + { + return self::IS_ARRAY === (self::IS_ARRAY & $this->mode); + } + + /** + * Sets the default value. + * + * @param mixed $default The default value + * + * @throws \LogicException When incorrect default value is given + */ + public function setDefault($default = null) + { + if (self::REQUIRED === $this->mode && null !== $default) { + throw new \LogicException('Cannot set a default value except for InputArgument::OPTIONAL mode.'); + } + + if ($this->isArray()) { + if (null === $default) { + $default = array(); + } elseif (!is_array($default)) { + throw new \LogicException('A default value for an array argument must be an array.'); + } + } + + $this->default = $default; + } + + /** + * Returns the default value. + * + * @return mixed The default value + */ + public function getDefault() + { + return $this->default; + } + + /** + * Returns the description text. + * + * @return string The description text + */ + public function getDescription() + { + return $this->description; + } +} diff --git a/vendor/symfony/console/Input/InputAwareInterface.php b/vendor/symfony/console/Input/InputAwareInterface.php new file mode 100644 index 0000000..d0f11e9 --- /dev/null +++ b/vendor/symfony/console/Input/InputAwareInterface.php @@ -0,0 +1,28 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Input; + +/** + * InputAwareInterface should be implemented by classes that depends on the + * Console Input. + * + * @author Wouter J + */ +interface InputAwareInterface +{ + /** + * Sets the Console Input. + * + * @param InputInterface + */ + public function setInput(InputInterface $input); +} diff --git a/vendor/symfony/console/Input/InputDefinition.php b/vendor/symfony/console/Input/InputDefinition.php new file mode 100644 index 0000000..21ac832 --- /dev/null +++ b/vendor/symfony/console/Input/InputDefinition.php @@ -0,0 +1,485 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Input; + +use Symfony\Component\Console\Descriptor\TextDescriptor; +use Symfony\Component\Console\Descriptor\XmlDescriptor; +use Symfony\Component\Console\Output\BufferedOutput; + +/** + * A InputDefinition represents a set of valid command line arguments and options. + * + * Usage: + * + * $definition = new InputDefinition(array( + * new InputArgument('name', InputArgument::REQUIRED), + * new InputOption('foo', 'f', InputOption::VALUE_REQUIRED), + * )); + * + * @author Fabien Potencier + * + * @api + */ +class InputDefinition +{ + private $arguments; + private $requiredCount; + private $hasAnArrayArgument = false; + private $hasOptional; + private $options; + private $shortcuts; + + /** + * Constructor. + * + * @param array $definition An array of InputArgument and InputOption instance + * + * @api + */ + public function __construct(array $definition = array()) + { + $this->setDefinition($definition); + } + + /** + * Sets the definition of the input. + * + * @param array $definition The definition array + * + * @api + */ + public function setDefinition(array $definition) + { + $arguments = array(); + $options = array(); + foreach ($definition as $item) { + if ($item instanceof InputOption) { + $options[] = $item; + } else { + $arguments[] = $item; + } + } + + $this->setArguments($arguments); + $this->setOptions($options); + } + + /** + * Sets the InputArgument objects. + * + * @param InputArgument[] $arguments An array of InputArgument objects + * + * @api + */ + public function setArguments($arguments = array()) + { + $this->arguments = array(); + $this->requiredCount = 0; + $this->hasOptional = false; + $this->hasAnArrayArgument = false; + $this->addArguments($arguments); + } + + /** + * Adds an array of InputArgument objects. + * + * @param InputArgument[] $arguments An array of InputArgument objects + * + * @api + */ + public function addArguments($arguments = array()) + { + if (null !== $arguments) { + foreach ($arguments as $argument) { + $this->addArgument($argument); + } + } + } + + /** + * Adds an InputArgument object. + * + * @param InputArgument $argument An InputArgument object + * + * @throws \LogicException When incorrect argument is given + * + * @api + */ + public function addArgument(InputArgument $argument) + { + if (isset($this->arguments[$argument->getName()])) { + throw new \LogicException(sprintf('An argument with name "%s" already exists.', $argument->getName())); + } + + if ($this->hasAnArrayArgument) { + throw new \LogicException('Cannot add an argument after an array argument.'); + } + + if ($argument->isRequired() && $this->hasOptional) { + throw new \LogicException('Cannot add a required argument after an optional one.'); + } + + if ($argument->isArray()) { + $this->hasAnArrayArgument = true; + } + + if ($argument->isRequired()) { + ++$this->requiredCount; + } else { + $this->hasOptional = true; + } + + $this->arguments[$argument->getName()] = $argument; + } + + /** + * Returns an InputArgument by name or by position. + * + * @param string|int $name The InputArgument name or position + * + * @return InputArgument An InputArgument object + * + * @throws \InvalidArgumentException When argument given doesn't exist + * + * @api + */ + public function getArgument($name) + { + if (!$this->hasArgument($name)) { + throw new \InvalidArgumentException(sprintf('The "%s" argument does not exist.', $name)); + } + + $arguments = is_int($name) ? array_values($this->arguments) : $this->arguments; + + return $arguments[$name]; + } + + /** + * Returns true if an InputArgument object exists by name or position. + * + * @param string|int $name The InputArgument name or position + * + * @return bool true if the InputArgument object exists, false otherwise + * + * @api + */ + public function hasArgument($name) + { + $arguments = is_int($name) ? array_values($this->arguments) : $this->arguments; + + return isset($arguments[$name]); + } + + /** + * Gets the array of InputArgument objects. + * + * @return InputArgument[] An array of InputArgument objects + * + * @api + */ + public function getArguments() + { + return $this->arguments; + } + + /** + * Returns the number of InputArguments. + * + * @return int The number of InputArguments + */ + public function getArgumentCount() + { + return $this->hasAnArrayArgument ? PHP_INT_MAX : count($this->arguments); + } + + /** + * Returns the number of required InputArguments. + * + * @return int The number of required InputArguments + */ + public function getArgumentRequiredCount() + { + return $this->requiredCount; + } + + /** + * Gets the default values. + * + * @return array An array of default values + */ + public function getArgumentDefaults() + { + $values = array(); + foreach ($this->arguments as $argument) { + $values[$argument->getName()] = $argument->getDefault(); + } + + return $values; + } + + /** + * Sets the InputOption objects. + * + * @param InputOption[] $options An array of InputOption objects + * + * @api + */ + public function setOptions($options = array()) + { + $this->options = array(); + $this->shortcuts = array(); + $this->addOptions($options); + } + + /** + * Adds an array of InputOption objects. + * + * @param InputOption[] $options An array of InputOption objects + * + * @api + */ + public function addOptions($options = array()) + { + foreach ($options as $option) { + $this->addOption($option); + } + } + + /** + * Adds an InputOption object. + * + * @param InputOption $option An InputOption object + * + * @throws \LogicException When option given already exist + * + * @api + */ + public function addOption(InputOption $option) + { + if (isset($this->options[$option->getName()]) && !$option->equals($this->options[$option->getName()])) { + throw new \LogicException(sprintf('An option named "%s" already exists.', $option->getName())); + } + + if ($option->getShortcut()) { + foreach (explode('|', $option->getShortcut()) as $shortcut) { + if (isset($this->shortcuts[$shortcut]) && !$option->equals($this->options[$this->shortcuts[$shortcut]])) { + throw new \LogicException(sprintf('An option with shortcut "%s" already exists.', $shortcut)); + } + } + } + + $this->options[$option->getName()] = $option; + if ($option->getShortcut()) { + foreach (explode('|', $option->getShortcut()) as $shortcut) { + $this->shortcuts[$shortcut] = $option->getName(); + } + } + } + + /** + * Returns an InputOption by name. + * + * @param string $name The InputOption name + * + * @return InputOption A InputOption object + * + * @throws \InvalidArgumentException When option given doesn't exist + * + * @api + */ + public function getOption($name) + { + if (!$this->hasOption($name)) { + throw new \InvalidArgumentException(sprintf('The "--%s" option does not exist.', $name)); + } + + return $this->options[$name]; + } + + /** + * Returns true if an InputOption object exists by name. + * + * @param string $name The InputOption name + * + * @return bool true if the InputOption object exists, false otherwise + * + * @api + */ + public function hasOption($name) + { + return isset($this->options[$name]); + } + + /** + * Gets the array of InputOption objects. + * + * @return InputOption[] An array of InputOption objects + * + * @api + */ + public function getOptions() + { + return $this->options; + } + + /** + * Returns true if an InputOption object exists by shortcut. + * + * @param string $name The InputOption shortcut + * + * @return bool true if the InputOption object exists, false otherwise + */ + public function hasShortcut($name) + { + return isset($this->shortcuts[$name]); + } + + /** + * Gets an InputOption by shortcut. + * + * @param string $shortcut the Shortcut name + * + * @return InputOption An InputOption object + */ + public function getOptionForShortcut($shortcut) + { + return $this->getOption($this->shortcutToName($shortcut)); + } + + /** + * Gets an array of default values. + * + * @return array An array of all default values + */ + public function getOptionDefaults() + { + $values = array(); + foreach ($this->options as $option) { + $values[$option->getName()] = $option->getDefault(); + } + + return $values; + } + + /** + * Returns the InputOption name given a shortcut. + * + * @param string $shortcut The shortcut + * + * @return string The InputOption name + * + * @throws \InvalidArgumentException When option given does not exist + */ + private function shortcutToName($shortcut) + { + if (!isset($this->shortcuts[$shortcut])) { + throw new \InvalidArgumentException(sprintf('The "-%s" option does not exist.', $shortcut)); + } + + return $this->shortcuts[$shortcut]; + } + + /** + * Gets the synopsis. + * + * @param bool $short Whether to return the short version (with options folded) or not + * + * @return string The synopsis + */ + public function getSynopsis($short = false) + { + $elements = array(); + + if ($short && $this->getOptions()) { + $elements[] = '[options]'; + } elseif (!$short) { + foreach ($this->getOptions() as $option) { + $value = ''; + if ($option->acceptValue()) { + $value = sprintf( + ' %s%s%s', + $option->isValueOptional() ? '[' : '', + strtoupper($option->getName()), + $option->isValueOptional() ? ']' : '' + ); + } + + $shortcut = $option->getShortcut() ? sprintf('-%s|', $option->getShortcut()) : ''; + $elements[] = sprintf('[%s--%s%s]', $shortcut, $option->getName(), $value); + } + } + + if (count($elements) && $this->getArguments()) { + $elements[] = '[--]'; + } + + foreach ($this->getArguments() as $argument) { + $element = '<'.$argument->getName().'>'; + if (!$argument->isRequired()) { + $element = '['.$element.']'; + } elseif ($argument->isArray()) { + $element = $element.' ('.$element.')'; + } + + if ($argument->isArray()) { + $element .= '...'; + } + + $elements[] = $element; + } + + return implode(' ', $elements); + } + + /** + * Returns a textual representation of the InputDefinition. + * + * @return string A string representing the InputDefinition + * + * @deprecated since version 2.3, to be removed in 3.0. + */ + public function asText() + { + @trigger_error('The '.__METHOD__.' method is deprecated since version 2.3 and will be removed in 3.0.', E_USER_DEPRECATED); + + $descriptor = new TextDescriptor(); + $output = new BufferedOutput(BufferedOutput::VERBOSITY_NORMAL, true); + $descriptor->describe($output, $this, array('raw_output' => true)); + + return $output->fetch(); + } + + /** + * Returns an XML representation of the InputDefinition. + * + * @param bool $asDom Whether to return a DOM or an XML string + * + * @return string|\DOMDocument An XML string representing the InputDefinition + * + * @deprecated since version 2.3, to be removed in 3.0. + */ + public function asXml($asDom = false) + { + @trigger_error('The '.__METHOD__.' method is deprecated since version 2.3 and will be removed in 3.0.', E_USER_DEPRECATED); + + $descriptor = new XmlDescriptor(); + + if ($asDom) { + return $descriptor->getInputDefinitionDocument($this); + } + + $output = new BufferedOutput(); + $descriptor->describe($output, $this); + + return $output->fetch(); + } +} diff --git a/vendor/symfony/console/Input/InputInterface.php b/vendor/symfony/console/Input/InputInterface.php new file mode 100644 index 0000000..6ef2f26 --- /dev/null +++ b/vendor/symfony/console/Input/InputInterface.php @@ -0,0 +1,152 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Input; + +/** + * InputInterface is the interface implemented by all input classes. + * + * @author Fabien Potencier + */ +interface InputInterface +{ + /** + * Returns the first argument from the raw parameters (not parsed). + * + * @return string The value of the first argument or null otherwise + */ + public function getFirstArgument(); + + /** + * Returns true if the raw parameters (not parsed) contain a value. + * + * This method is to be used to introspect the input parameters + * before they have been validated. It must be used carefully. + * + * @param string|array $values The values to look for in the raw parameters (can be an array) + * + * @return bool true if the value is contained in the raw parameters + */ + public function hasParameterOption($values); + + /** + * Returns the value of a raw option (not parsed). + * + * This method is to be used to introspect the input parameters + * before they have been validated. It must be used carefully. + * + * @param string|array $values The value(s) to look for in the raw parameters (can be an array) + * @param mixed $default The default value to return if no result is found + * + * @return mixed The option value + */ + public function getParameterOption($values, $default = false); + + /** + * Binds the current Input instance with the given arguments and options. + * + * @param InputDefinition $definition A InputDefinition instance + */ + public function bind(InputDefinition $definition); + + /** + * Validates if arguments given are correct. + * + * Throws an exception when not enough arguments are given. + * + * @throws \RuntimeException + */ + public function validate(); + + /** + * Returns all the given arguments merged with the default values. + * + * @return array + */ + public function getArguments(); + + /** + * Gets argument by name. + * + * @param string $name The name of the argument + * + * @return mixed + */ + public function getArgument($name); + + /** + * Sets an argument value by name. + * + * @param string $name The argument name + * @param string $value The argument value + * + * @throws \InvalidArgumentException When argument given doesn't exist + */ + public function setArgument($name, $value); + + /** + * Returns true if an InputArgument object exists by name or position. + * + * @param string|int $name The InputArgument name or position + * + * @return bool true if the InputArgument object exists, false otherwise + */ + public function hasArgument($name); + + /** + * Returns all the given options merged with the default values. + * + * @return array + */ + public function getOptions(); + + /** + * Gets an option by name. + * + * @param string $name The name of the option + * + * @return mixed + */ + public function getOption($name); + + /** + * Sets an option value by name. + * + * @param string $name The option name + * @param string|bool $value The option value + * + * @throws \InvalidArgumentException When option given doesn't exist + */ + public function setOption($name, $value); + + /** + * Returns true if an InputOption object exists by name. + * + * @param string $name The InputOption name + * + * @return bool true if the InputOption object exists, false otherwise + */ + public function hasOption($name); + + /** + * Is this input means interactive? + * + * @return bool + */ + public function isInteractive(); + + /** + * Sets the input interactivity. + * + * @param bool $interactive If the input should be interactive + */ + public function setInteractive($interactive); +} diff --git a/vendor/symfony/console/Input/InputOption.php b/vendor/symfony/console/Input/InputOption.php new file mode 100644 index 0000000..3a48ca3 --- /dev/null +++ b/vendor/symfony/console/Input/InputOption.php @@ -0,0 +1,213 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Input; + +/** + * Represents a command line option. + * + * @author Fabien Potencier + * + * @api + */ +class InputOption +{ + const VALUE_NONE = 1; + const VALUE_REQUIRED = 2; + const VALUE_OPTIONAL = 4; + const VALUE_IS_ARRAY = 8; + + private $name; + private $shortcut; + private $mode; + private $default; + private $description; + + /** + * Constructor. + * + * @param string $name The option name + * @param string|array $shortcut The shortcuts, can be null, a string of shortcuts delimited by | or an array of shortcuts + * @param int $mode The option mode: One of the VALUE_* constants + * @param string $description A description text + * @param mixed $default The default value (must be null for self::VALUE_REQUIRED or self::VALUE_NONE) + * + * @throws \InvalidArgumentException If option mode is invalid or incompatible + * + * @api + */ + public function __construct($name, $shortcut = null, $mode = null, $description = '', $default = null) + { + if (0 === strpos($name, '--')) { + $name = substr($name, 2); + } + + if (empty($name)) { + throw new \InvalidArgumentException('An option name cannot be empty.'); + } + + if (empty($shortcut)) { + $shortcut = null; + } + + if (null !== $shortcut) { + if (is_array($shortcut)) { + $shortcut = implode('|', $shortcut); + } + $shortcuts = preg_split('{(\|)-?}', ltrim($shortcut, '-')); + $shortcuts = array_filter($shortcuts); + $shortcut = implode('|', $shortcuts); + + if (empty($shortcut)) { + throw new \InvalidArgumentException('An option shortcut cannot be empty.'); + } + } + + if (null === $mode) { + $mode = self::VALUE_NONE; + } elseif (!is_int($mode) || $mode > 15 || $mode < 1) { + throw new \InvalidArgumentException(sprintf('Option mode "%s" is not valid.', $mode)); + } + + $this->name = $name; + $this->shortcut = $shortcut; + $this->mode = $mode; + $this->description = $description; + + if ($this->isArray() && !$this->acceptValue()) { + throw new \InvalidArgumentException('Impossible to have an option mode VALUE_IS_ARRAY if the option does not accept a value.'); + } + + $this->setDefault($default); + } + + /** + * Returns the option shortcut. + * + * @return string The shortcut + */ + public function getShortcut() + { + return $this->shortcut; + } + + /** + * Returns the option name. + * + * @return string The name + */ + public function getName() + { + return $this->name; + } + + /** + * Returns true if the option accepts a value. + * + * @return bool true if value mode is not self::VALUE_NONE, false otherwise + */ + public function acceptValue() + { + return $this->isValueRequired() || $this->isValueOptional(); + } + + /** + * Returns true if the option requires a value. + * + * @return bool true if value mode is self::VALUE_REQUIRED, false otherwise + */ + public function isValueRequired() + { + return self::VALUE_REQUIRED === (self::VALUE_REQUIRED & $this->mode); + } + + /** + * Returns true if the option takes an optional value. + * + * @return bool true if value mode is self::VALUE_OPTIONAL, false otherwise + */ + public function isValueOptional() + { + return self::VALUE_OPTIONAL === (self::VALUE_OPTIONAL & $this->mode); + } + + /** + * Returns true if the option can take multiple values. + * + * @return bool true if mode is self::VALUE_IS_ARRAY, false otherwise + */ + public function isArray() + { + return self::VALUE_IS_ARRAY === (self::VALUE_IS_ARRAY & $this->mode); + } + + /** + * Sets the default value. + * + * @param mixed $default The default value + * + * @throws \LogicException When incorrect default value is given + */ + public function setDefault($default = null) + { + if (self::VALUE_NONE === (self::VALUE_NONE & $this->mode) && null !== $default) { + throw new \LogicException('Cannot set a default value when using InputOption::VALUE_NONE mode.'); + } + + if ($this->isArray()) { + if (null === $default) { + $default = array(); + } elseif (!is_array($default)) { + throw new \LogicException('A default value for an array option must be an array.'); + } + } + + $this->default = $this->acceptValue() ? $default : false; + } + + /** + * Returns the default value. + * + * @return mixed The default value + */ + public function getDefault() + { + return $this->default; + } + + /** + * Returns the description text. + * + * @return string The description text + */ + public function getDescription() + { + return $this->description; + } + + /** + * Checks whether the given option equals this one. + * + * @param InputOption $option option to compare + * + * @return bool + */ + public function equals(InputOption $option) + { + return $option->getName() === $this->getName() + && $option->getShortcut() === $this->getShortcut() + && $option->getDefault() === $this->getDefault() + && $option->isArray() === $this->isArray() + && $option->isValueRequired() === $this->isValueRequired() + && $option->isValueOptional() === $this->isValueOptional() + ; + } +} diff --git a/vendor/symfony/console/Input/StringInput.php b/vendor/symfony/console/Input/StringInput.php new file mode 100644 index 0000000..40d1dfb --- /dev/null +++ b/vendor/symfony/console/Input/StringInput.php @@ -0,0 +1,87 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Input; + +/** + * StringInput represents an input provided as a string. + * + * Usage: + * + * $input = new StringInput('foo --bar="foobar"'); + * + * @author Fabien Potencier + * + * @api + */ +class StringInput extends ArgvInput +{ + const REGEX_STRING = '([^\s]+?)(?:\s|(?setTokens($this->tokenize($input)); + + if (null !== $definition) { + $this->bind($definition); + } + } + + /** + * Tokenizes a string. + * + * @param string $input The input to tokenize + * + * @return array An array of tokens + * + * @throws \InvalidArgumentException When unable to parse input (should never happen) + */ + private function tokenize($input) + { + $tokens = array(); + $length = strlen($input); + $cursor = 0; + while ($cursor < $length) { + if (preg_match('/\s+/A', $input, $match, null, $cursor)) { + } elseif (preg_match('/([^="\'\s]+?)(=?)('.self::REGEX_QUOTED_STRING.'+)/A', $input, $match, null, $cursor)) { + $tokens[] = $match[1].$match[2].stripcslashes(str_replace(array('"\'', '\'"', '\'\'', '""'), '', substr($match[3], 1, strlen($match[3]) - 2))); + } elseif (preg_match('/'.self::REGEX_QUOTED_STRING.'/A', $input, $match, null, $cursor)) { + $tokens[] = stripcslashes(substr($match[0], 1, strlen($match[0]) - 2)); + } elseif (preg_match('/'.self::REGEX_STRING.'/A', $input, $match, null, $cursor)) { + $tokens[] = stripcslashes($match[1]); + } else { + // should never happen + throw new \InvalidArgumentException(sprintf('Unable to parse input near "... %s ..."', substr($input, $cursor, 10))); + } + + $cursor += strlen($match[0]); + } + + return $tokens; + } +} diff --git a/vendor/symfony/console/LICENSE b/vendor/symfony/console/LICENSE new file mode 100644 index 0000000..43028bc --- /dev/null +++ b/vendor/symfony/console/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2004-2015 Fabien Potencier + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is furnished +to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/vendor/symfony/console/Logger/ConsoleLogger.php b/vendor/symfony/console/Logger/ConsoleLogger.php new file mode 100644 index 0000000..1f7417e --- /dev/null +++ b/vendor/symfony/console/Logger/ConsoleLogger.php @@ -0,0 +1,119 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Logger; + +use Psr\Log\AbstractLogger; +use Psr\Log\InvalidArgumentException; +use Psr\Log\LogLevel; +use Symfony\Component\Console\Output\OutputInterface; +use Symfony\Component\Console\Output\ConsoleOutputInterface; + +/** + * PSR-3 compliant console logger. + * + * @author Kévin Dunglas + * + * @link http://www.php-fig.org/psr/psr-3/ + */ +class ConsoleLogger extends AbstractLogger +{ + const INFO = 'info'; + const ERROR = 'error'; + + /** + * @var OutputInterface + */ + private $output; + /** + * @var array + */ + private $verbosityLevelMap = array( + LogLevel::EMERGENCY => OutputInterface::VERBOSITY_NORMAL, + LogLevel::ALERT => OutputInterface::VERBOSITY_NORMAL, + LogLevel::CRITICAL => OutputInterface::VERBOSITY_NORMAL, + LogLevel::ERROR => OutputInterface::VERBOSITY_NORMAL, + LogLevel::WARNING => OutputInterface::VERBOSITY_NORMAL, + LogLevel::NOTICE => OutputInterface::VERBOSITY_VERBOSE, + LogLevel::INFO => OutputInterface::VERBOSITY_VERY_VERBOSE, + LogLevel::DEBUG => OutputInterface::VERBOSITY_DEBUG, + ); + /** + * @var array + */ + private $formatLevelMap = array( + LogLevel::EMERGENCY => self::ERROR, + LogLevel::ALERT => self::ERROR, + LogLevel::CRITICAL => self::ERROR, + LogLevel::ERROR => self::ERROR, + LogLevel::WARNING => self::INFO, + LogLevel::NOTICE => self::INFO, + LogLevel::INFO => self::INFO, + LogLevel::DEBUG => self::INFO, + ); + + /** + * @param OutputInterface $output + * @param array $verbosityLevelMap + * @param array $formatLevelMap + */ + public function __construct(OutputInterface $output, array $verbosityLevelMap = array(), array $formatLevelMap = array()) + { + $this->output = $output; + $this->verbosityLevelMap = $verbosityLevelMap + $this->verbosityLevelMap; + $this->formatLevelMap = $formatLevelMap + $this->formatLevelMap; + } + + /** + * {@inheritdoc} + */ + public function log($level, $message, array $context = array()) + { + if (!isset($this->verbosityLevelMap[$level])) { + throw new InvalidArgumentException(sprintf('The log level "%s" does not exist.', $level)); + } + + // Write to the error output if necessary and available + if ($this->formatLevelMap[$level] === self::ERROR && $this->output instanceof ConsoleOutputInterface) { + $output = $this->output->getErrorOutput(); + } else { + $output = $this->output; + } + + if ($output->getVerbosity() >= $this->verbosityLevelMap[$level]) { + $output->writeln(sprintf('<%1$s>[%2$s] %3$s', $this->formatLevelMap[$level], $level, $this->interpolate($message, $context))); + } + } + + /** + * Interpolates context values into the message placeholders. + * + * @author PHP Framework Interoperability Group + * + * @param string $message + * @param array $context + * + * @return string + */ + private function interpolate($message, array $context) + { + // build a replacement array with braces around the context keys + $replace = array(); + foreach ($context as $key => $val) { + if (!is_array($val) && (!is_object($val) || method_exists($val, '__toString'))) { + $replace[sprintf('{%s}', $key)] = $val; + } + } + + // interpolate replacement values into the message and return + return strtr($message, $replace); + } +} diff --git a/vendor/symfony/console/Output/BufferedOutput.php b/vendor/symfony/console/Output/BufferedOutput.php new file mode 100644 index 0000000..5682fc2 --- /dev/null +++ b/vendor/symfony/console/Output/BufferedOutput.php @@ -0,0 +1,48 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Output; + +/** + * @author Jean-François Simon + */ +class BufferedOutput extends Output +{ + /** + * @var string + */ + private $buffer = ''; + + /** + * Empties buffer and returns its content. + * + * @return string + */ + public function fetch() + { + $content = $this->buffer; + $this->buffer = ''; + + return $content; + } + + /** + * {@inheritdoc} + */ + protected function doWrite($message, $newline) + { + $this->buffer .= $message; + + if ($newline) { + $this->buffer .= "\n"; + } + } +} diff --git a/vendor/symfony/console/Output/ConsoleOutput.php b/vendor/symfony/console/Output/ConsoleOutput.php new file mode 100644 index 0000000..50ef4df --- /dev/null +++ b/vendor/symfony/console/Output/ConsoleOutput.php @@ -0,0 +1,149 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Output; + +use Symfony\Component\Console\Formatter\OutputFormatterInterface; + +/** + * ConsoleOutput is the default class for all CLI output. It uses STDOUT. + * + * This class is a convenient wrapper around `StreamOutput`. + * + * $output = new ConsoleOutput(); + * + * This is equivalent to: + * + * $output = new StreamOutput(fopen('php://stdout', 'w')); + * + * @author Fabien Potencier + * + * @api + */ +class ConsoleOutput extends StreamOutput implements ConsoleOutputInterface +{ + /** + * @var StreamOutput + */ + private $stderr; + + /** + * Constructor. + * + * @param int $verbosity The verbosity level (one of the VERBOSITY constants in OutputInterface) + * @param bool|null $decorated Whether to decorate messages (null for auto-guessing) + * @param OutputFormatterInterface|null $formatter Output formatter instance (null to use default OutputFormatter) + * + * @api + */ + public function __construct($verbosity = self::VERBOSITY_NORMAL, $decorated = null, OutputFormatterInterface $formatter = null) + { + parent::__construct($this->openOutputStream(), $verbosity, $decorated, $formatter); + + $this->stderr = new StreamOutput($this->openErrorStream(), $verbosity, $decorated, $this->getFormatter()); + } + + /** + * {@inheritdoc} + */ + public function setDecorated($decorated) + { + parent::setDecorated($decorated); + $this->stderr->setDecorated($decorated); + } + + /** + * {@inheritdoc} + */ + public function setFormatter(OutputFormatterInterface $formatter) + { + parent::setFormatter($formatter); + $this->stderr->setFormatter($formatter); + } + + /** + * {@inheritdoc} + */ + public function setVerbosity($level) + { + parent::setVerbosity($level); + $this->stderr->setVerbosity($level); + } + + /** + * {@inheritdoc} + */ + public function getErrorOutput() + { + return $this->stderr; + } + + /** + * {@inheritdoc} + */ + public function setErrorOutput(OutputInterface $error) + { + $this->stderr = $error; + } + + /** + * Returns true if current environment supports writing console output to + * STDOUT. + * + * @return bool + */ + protected function hasStdoutSupport() + { + return false === $this->isRunningOS400(); + } + + /** + * Returns true if current environment supports writing console output to + * STDERR. + * + * @return bool + */ + protected function hasStderrSupport() + { + return false === $this->isRunningOS400(); + } + + /** + * Checks if current executing environment is IBM iSeries (OS400), which + * doesn't properly convert character-encodings between ASCII to EBCDIC. + * + * @return bool + */ + private function isRunningOS400() + { + return 'OS400' === php_uname('s'); + } + + /** + * @return resource + */ + private function openOutputStream() + { + $outputStream = $this->hasStdoutSupport() ? 'php://stdout' : 'php://output'; + + return @fopen($outputStream, 'w') ?: fopen('php://output', 'w'); + } + + /** + * @return resource + */ + private function openErrorStream() + { + $errorStream = $this->hasStderrSupport() ? 'php://stderr' : 'php://output'; + + return fopen($errorStream, 'w'); + } +} diff --git a/vendor/symfony/console/Output/ConsoleOutputInterface.php b/vendor/symfony/console/Output/ConsoleOutputInterface.php new file mode 100644 index 0000000..5eb4fc7 --- /dev/null +++ b/vendor/symfony/console/Output/ConsoleOutputInterface.php @@ -0,0 +1,35 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Output; + +/** + * ConsoleOutputInterface is the interface implemented by ConsoleOutput class. + * This adds information about stderr output stream. + * + * @author Dariusz Górecki + */ +interface ConsoleOutputInterface extends OutputInterface +{ + /** + * Gets the OutputInterface for errors. + * + * @return OutputInterface + */ + public function getErrorOutput(); + + /** + * Sets the OutputInterface used for errors. + * + * @param OutputInterface $error + */ + public function setErrorOutput(OutputInterface $error); +} diff --git a/vendor/symfony/console/Output/NullOutput.php b/vendor/symfony/console/Output/NullOutput.php new file mode 100644 index 0000000..557f8af --- /dev/null +++ b/vendor/symfony/console/Output/NullOutput.php @@ -0,0 +1,113 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Output; + +use Symfony\Component\Console\Formatter\OutputFormatter; +use Symfony\Component\Console\Formatter\OutputFormatterInterface; + +/** + * NullOutput suppresses all output. + * + * $output = new NullOutput(); + * + * @author Fabien Potencier + * @author Tobias Schultze + * + * @api + */ +class NullOutput implements OutputInterface +{ + /** + * {@inheritdoc} + */ + public function setFormatter(OutputFormatterInterface $formatter) + { + // do nothing + } + + /** + * {@inheritdoc} + */ + public function getFormatter() + { + // to comply with the interface we must return a OutputFormatterInterface + return new OutputFormatter(); + } + + /** + * {@inheritdoc} + */ + public function setDecorated($decorated) + { + // do nothing + } + + /** + * {@inheritdoc} + */ + public function isDecorated() + { + return false; + } + + /** + * {@inheritdoc} + */ + public function setVerbosity($level) + { + // do nothing + } + + /** + * {@inheritdoc} + */ + public function getVerbosity() + { + return self::VERBOSITY_QUIET; + } + + public function isQuiet() + { + return true; + } + + public function isVerbose() + { + return false; + } + + public function isVeryVerbose() + { + return false; + } + + public function isDebug() + { + return false; + } + + /** + * {@inheritdoc} + */ + public function writeln($messages, $type = self::OUTPUT_NORMAL) + { + // do nothing + } + + /** + * {@inheritdoc} + */ + public function write($messages, $newline = false, $type = self::OUTPUT_NORMAL) + { + // do nothing + } +} diff --git a/vendor/symfony/console/Output/Output.php b/vendor/symfony/console/Output/Output.php new file mode 100644 index 0000000..cb0e40d --- /dev/null +++ b/vendor/symfony/console/Output/Output.php @@ -0,0 +1,165 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Output; + +use Symfony\Component\Console\Formatter\OutputFormatterInterface; +use Symfony\Component\Console\Formatter\OutputFormatter; + +/** + * Base class for output classes. + * + * There are five levels of verbosity: + * + * * normal: no option passed (normal output) + * * verbose: -v (more output) + * * very verbose: -vv (highly extended output) + * * debug: -vvv (all debug output) + * * quiet: -q (no output) + * + * @author Fabien Potencier + * + * @api + */ +abstract class Output implements OutputInterface +{ + private $verbosity; + private $formatter; + + /** + * Constructor. + * + * @param int $verbosity The verbosity level (one of the VERBOSITY constants in OutputInterface) + * @param bool $decorated Whether to decorate messages + * @param OutputFormatterInterface|null $formatter Output formatter instance (null to use default OutputFormatter) + * + * @api + */ + public function __construct($verbosity = self::VERBOSITY_NORMAL, $decorated = false, OutputFormatterInterface $formatter = null) + { + $this->verbosity = null === $verbosity ? self::VERBOSITY_NORMAL : $verbosity; + $this->formatter = $formatter ?: new OutputFormatter(); + $this->formatter->setDecorated($decorated); + } + + /** + * {@inheritdoc} + */ + public function setFormatter(OutputFormatterInterface $formatter) + { + $this->formatter = $formatter; + } + + /** + * {@inheritdoc} + */ + public function getFormatter() + { + return $this->formatter; + } + + /** + * {@inheritdoc} + */ + public function setDecorated($decorated) + { + $this->formatter->setDecorated($decorated); + } + + /** + * {@inheritdoc} + */ + public function isDecorated() + { + return $this->formatter->isDecorated(); + } + + /** + * {@inheritdoc} + */ + public function setVerbosity($level) + { + $this->verbosity = (int) $level; + } + + /** + * {@inheritdoc} + */ + public function getVerbosity() + { + return $this->verbosity; + } + + public function isQuiet() + { + return self::VERBOSITY_QUIET === $this->verbosity; + } + + public function isVerbose() + { + return self::VERBOSITY_VERBOSE <= $this->verbosity; + } + + public function isVeryVerbose() + { + return self::VERBOSITY_VERY_VERBOSE <= $this->verbosity; + } + + public function isDebug() + { + return self::VERBOSITY_DEBUG <= $this->verbosity; + } + + /** + * {@inheritdoc} + */ + public function writeln($messages, $type = self::OUTPUT_NORMAL) + { + $this->write($messages, true, $type); + } + + /** + * {@inheritdoc} + */ + public function write($messages, $newline = false, $type = self::OUTPUT_NORMAL) + { + if (self::VERBOSITY_QUIET === $this->verbosity) { + return; + } + + $messages = (array) $messages; + + foreach ($messages as $message) { + switch ($type) { + case OutputInterface::OUTPUT_NORMAL: + $message = $this->formatter->format($message); + break; + case OutputInterface::OUTPUT_RAW: + break; + case OutputInterface::OUTPUT_PLAIN: + $message = strip_tags($this->formatter->format($message)); + break; + default: + throw new \InvalidArgumentException(sprintf('Unknown output type given (%s)', $type)); + } + + $this->doWrite($message, $newline); + } + } + + /** + * Writes a message to the output. + * + * @param string $message A message to write to the output + * @param bool $newline Whether to add a newline or not + */ + abstract protected function doWrite($message, $newline); +} diff --git a/vendor/symfony/console/Output/OutputInterface.php b/vendor/symfony/console/Output/OutputInterface.php new file mode 100644 index 0000000..f7f3063 --- /dev/null +++ b/vendor/symfony/console/Output/OutputInterface.php @@ -0,0 +1,113 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Output; + +use Symfony\Component\Console\Formatter\OutputFormatterInterface; + +/** + * OutputInterface is the interface implemented by all Output classes. + * + * @author Fabien Potencier + * + * @api + */ +interface OutputInterface +{ + const VERBOSITY_QUIET = 0; + const VERBOSITY_NORMAL = 1; + const VERBOSITY_VERBOSE = 2; + const VERBOSITY_VERY_VERBOSE = 3; + const VERBOSITY_DEBUG = 4; + + const OUTPUT_NORMAL = 0; + const OUTPUT_RAW = 1; + const OUTPUT_PLAIN = 2; + + /** + * Writes a message to the output. + * + * @param string|array $messages The message as an array of lines or a single string + * @param bool $newline Whether to add a newline + * @param int $type The type of output (one of the OUTPUT constants) + * + * @throws \InvalidArgumentException When unknown output type is given + * + * @api + */ + public function write($messages, $newline = false, $type = self::OUTPUT_NORMAL); + + /** + * Writes a message to the output and adds a newline at the end. + * + * @param string|array $messages The message as an array of lines of a single string + * @param int $type The type of output (one of the OUTPUT constants) + * + * @throws \InvalidArgumentException When unknown output type is given + * + * @api + */ + public function writeln($messages, $type = self::OUTPUT_NORMAL); + + /** + * Sets the verbosity of the output. + * + * @param int $level The level of verbosity (one of the VERBOSITY constants) + * + * @api + */ + public function setVerbosity($level); + + /** + * Gets the current verbosity of the output. + * + * @return int The current level of verbosity (one of the VERBOSITY constants) + * + * @api + */ + public function getVerbosity(); + + /** + * Sets the decorated flag. + * + * @param bool $decorated Whether to decorate the messages + * + * @api + */ + public function setDecorated($decorated); + + /** + * Gets the decorated flag. + * + * @return bool true if the output will decorate messages, false otherwise + * + * @api + */ + public function isDecorated(); + + /** + * Sets output formatter. + * + * @param OutputFormatterInterface $formatter + * + * @api + */ + public function setFormatter(OutputFormatterInterface $formatter); + + /** + * Returns current output formatter instance. + * + * @return OutputFormatterInterface + * + * @api + */ + public function getFormatter(); +} diff --git a/vendor/symfony/console/Output/StreamOutput.php b/vendor/symfony/console/Output/StreamOutput.php new file mode 100644 index 0000000..494cded --- /dev/null +++ b/vendor/symfony/console/Output/StreamOutput.php @@ -0,0 +1,103 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Output; + +use Symfony\Component\Console\Formatter\OutputFormatterInterface; + +/** + * StreamOutput writes the output to a given stream. + * + * Usage: + * + * $output = new StreamOutput(fopen('php://stdout', 'w')); + * + * As `StreamOutput` can use any stream, you can also use a file: + * + * $output = new StreamOutput(fopen('/path/to/output.log', 'a', false)); + * + * @author Fabien Potencier + * + * @api + */ +class StreamOutput extends Output +{ + private $stream; + + /** + * Constructor. + * + * @param mixed $stream A stream resource + * @param int $verbosity The verbosity level (one of the VERBOSITY constants in OutputInterface) + * @param bool|null $decorated Whether to decorate messages (null for auto-guessing) + * @param OutputFormatterInterface|null $formatter Output formatter instance (null to use default OutputFormatter) + * + * @throws \InvalidArgumentException When first argument is not a real stream + * + * @api + */ + public function __construct($stream, $verbosity = self::VERBOSITY_NORMAL, $decorated = null, OutputFormatterInterface $formatter = null) + { + if (!is_resource($stream) || 'stream' !== get_resource_type($stream)) { + throw new \InvalidArgumentException('The StreamOutput class needs a stream as its first argument.'); + } + + $this->stream = $stream; + + if (null === $decorated) { + $decorated = $this->hasColorSupport(); + } + + parent::__construct($verbosity, $decorated, $formatter); + } + + /** + * Gets the stream attached to this StreamOutput instance. + * + * @return resource A stream resource + */ + public function getStream() + { + return $this->stream; + } + + /** + * {@inheritdoc} + */ + protected function doWrite($message, $newline) + { + if (false === @fwrite($this->stream, $message.($newline ? PHP_EOL : ''))) { + // should never happen + throw new \RuntimeException('Unable to write output.'); + } + + fflush($this->stream); + } + + /** + * Returns true if the stream supports colorization. + * + * Colorization is disabled if not supported by the stream: + * + * - Windows without Ansicon and ConEmu + * - non tty consoles + * + * @return bool true if the stream supports colorization, false otherwise + */ + protected function hasColorSupport() + { + if (DIRECTORY_SEPARATOR === '\\') { + return false !== getenv('ANSICON') || 'ON' === getenv('ConEmuANSI'); + } + + return function_exists('posix_isatty') && @posix_isatty($this->stream); + } +} diff --git a/vendor/symfony/console/Question/ChoiceQuestion.php b/vendor/symfony/console/Question/ChoiceQuestion.php new file mode 100644 index 0000000..a36c739 --- /dev/null +++ b/vendor/symfony/console/Question/ChoiceQuestion.php @@ -0,0 +1,175 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Question; + +/** + * Represents a choice question. + * + * @author Fabien Potencier + */ +class ChoiceQuestion extends Question +{ + private $choices; + private $multiselect = false; + private $prompt = ' > '; + private $errorMessage = 'Value "%s" is invalid'; + + /** + * Constructor. + * + * @param string $question The question to ask to the user + * @param array $choices The list of available choices + * @param mixed $default The default answer to return + */ + public function __construct($question, array $choices, $default = null) + { + parent::__construct($question, $default); + + $this->choices = $choices; + $this->setValidator($this->getDefaultValidator()); + $this->setAutocompleterValues($choices); + } + + /** + * Returns available choices. + * + * @return array + */ + public function getChoices() + { + return $this->choices; + } + + /** + * Sets multiselect option. + * + * When multiselect is set to true, multiple choices can be answered. + * + * @param bool $multiselect + * + * @return ChoiceQuestion The current instance + */ + public function setMultiselect($multiselect) + { + $this->multiselect = $multiselect; + $this->setValidator($this->getDefaultValidator()); + + return $this; + } + + /** + * Gets the prompt for choices. + * + * @return string + */ + public function getPrompt() + { + return $this->prompt; + } + + /** + * Sets the prompt for choices. + * + * @param string $prompt + * + * @return ChoiceQuestion The current instance + */ + public function setPrompt($prompt) + { + $this->prompt = $prompt; + + return $this; + } + + /** + * Sets the error message for invalid values. + * + * The error message has a string placeholder (%s) for the invalid value. + * + * @param string $errorMessage + * + * @return ChoiceQuestion The current instance + */ + public function setErrorMessage($errorMessage) + { + $this->errorMessage = $errorMessage; + $this->setValidator($this->getDefaultValidator()); + + return $this; + } + + /** + * Returns the default answer validator. + * + * @return callable + */ + private function getDefaultValidator() + { + $choices = $this->choices; + $errorMessage = $this->errorMessage; + $multiselect = $this->multiselect; + $isAssoc = $this->isAssoc($choices); + + return function ($selected) use ($choices, $errorMessage, $multiselect, $isAssoc) { + // Collapse all spaces. + $selectedChoices = str_replace(' ', '', $selected); + + if ($multiselect) { + // Check for a separated comma values + if (!preg_match('/^[a-zA-Z0-9_-]+(?:,[a-zA-Z0-9_-]+)*$/', $selectedChoices, $matches)) { + throw new \InvalidArgumentException(sprintf($errorMessage, $selected)); + } + $selectedChoices = explode(',', $selectedChoices); + } else { + $selectedChoices = array($selected); + } + + $multiselectChoices = array(); + foreach ($selectedChoices as $value) { + $results = array(); + foreach ($choices as $key => $choice) { + if ($choice === $value) { + $results[] = $key; + } + } + + if (count($results) > 1) { + throw new \InvalidArgumentException(sprintf('The provided answer is ambiguous. Value should be one of %s.', implode(' or ', $results))); + } + + $result = array_search($value, $choices); + + if (!$isAssoc) { + if (false !== $result) { + $result = $choices[$result]; + } elseif (isset($choices[$value])) { + $result = $choices[$value]; + } + } elseif (false === $result && isset($choices[$value])) { + $result = $value; + } + + if (false === $result) { + throw new \InvalidArgumentException(sprintf($errorMessage, $value)); + } + + $multiselectChoices[] = (string) $result; + } + + if ($multiselect) { + return $multiselectChoices; + } + + return current($multiselectChoices); + }; + } +} diff --git a/vendor/symfony/console/Question/ConfirmationQuestion.php b/vendor/symfony/console/Question/ConfirmationQuestion.php new file mode 100644 index 0000000..29d9887 --- /dev/null +++ b/vendor/symfony/console/Question/ConfirmationQuestion.php @@ -0,0 +1,61 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Question; + +/** + * Represents a yes/no question. + * + * @author Fabien Potencier + */ +class ConfirmationQuestion extends Question +{ + private $trueAnswerRegex; + + /** + * Constructor. + * + * @param string $question The question to ask to the user + * @param bool $default The default answer to return, true or false + * @param string $trueAnswerRegex A regex to match the "yes" answer + */ + public function __construct($question, $default = true, $trueAnswerRegex = '/^y/i') + { + parent::__construct($question, (bool) $default); + + $this->trueAnswerRegex = $trueAnswerRegex; + $this->setNormalizer($this->getDefaultNormalizer()); + } + + /** + * Returns the default answer normalizer. + * + * @return callable + */ + private function getDefaultNormalizer() + { + $default = $this->getDefault(); + $regex = $this->trueAnswerRegex; + + return function ($answer) use ($default, $regex) { + if (is_bool($answer)) { + return $answer; + } + + $answerIsTrue = (bool) preg_match($regex, $answer); + if (false === $default) { + return $answer && $answerIsTrue; + } + + return !$answer || $answerIsTrue; + }; + } +} diff --git a/vendor/symfony/console/Question/Question.php b/vendor/symfony/console/Question/Question.php new file mode 100644 index 0000000..01702b2 --- /dev/null +++ b/vendor/symfony/console/Question/Question.php @@ -0,0 +1,247 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Question; + +/** + * Represents a Question. + * + * @author Fabien Potencier + */ +class Question +{ + private $question; + private $attempts; + private $hidden = false; + private $hiddenFallback = true; + private $autocompleterValues; + private $validator; + private $default; + private $normalizer; + + /** + * Constructor. + * + * @param string $question The question to ask to the user + * @param mixed $default The default answer to return if the user enters nothing + */ + public function __construct($question, $default = null) + { + $this->question = $question; + $this->default = $default; + } + + /** + * Returns the question. + * + * @return string + */ + public function getQuestion() + { + return $this->question; + } + + /** + * Returns the default answer. + * + * @return mixed + */ + public function getDefault() + { + return $this->default; + } + + /** + * Returns whether the user response must be hidden. + * + * @return bool + */ + public function isHidden() + { + return $this->hidden; + } + + /** + * Sets whether the user response must be hidden or not. + * + * @param bool $hidden + * + * @return Question The current instance + * + * @throws \LogicException In case the autocompleter is also used + */ + public function setHidden($hidden) + { + if ($this->autocompleterValues) { + throw new \LogicException('A hidden question cannot use the autocompleter.'); + } + + $this->hidden = (bool) $hidden; + + return $this; + } + + /** + * In case the response can not be hidden, whether to fallback on non-hidden question or not. + * + * @return bool + */ + public function isHiddenFallback() + { + return $this->hiddenFallback; + } + + /** + * Sets whether to fallback on non-hidden question if the response can not be hidden. + * + * @param bool $fallback + * + * @return Question The current instance + */ + public function setHiddenFallback($fallback) + { + $this->hiddenFallback = (bool) $fallback; + + return $this; + } + + /** + * Gets values for the autocompleter. + * + * @return null|array|\Traversable + */ + public function getAutocompleterValues() + { + return $this->autocompleterValues; + } + + /** + * Sets values for the autocompleter. + * + * @param null|array|\Traversable $values + * + * @return Question The current instance + * + * @throws \InvalidArgumentException + * @throws \LogicException + */ + public function setAutocompleterValues($values) + { + if (is_array($values) && $this->isAssoc($values)) { + $values = array_merge(array_keys($values), array_values($values)); + } + + if (null !== $values && !is_array($values)) { + if (!$values instanceof \Traversable || $values instanceof \Countable) { + throw new \InvalidArgumentException('Autocompleter values can be either an array, `null` or an object implementing both `Countable` and `Traversable` interfaces.'); + } + } + + if ($this->hidden) { + throw new \LogicException('A hidden question cannot use the autocompleter.'); + } + + $this->autocompleterValues = $values; + + return $this; + } + + /** + * Sets a validator for the question. + * + * @param null|callable $validator + * + * @return Question The current instance + */ + public function setValidator($validator) + { + $this->validator = $validator; + + return $this; + } + + /** + * Gets the validator for the question. + * + * @return null|callable + */ + public function getValidator() + { + return $this->validator; + } + + /** + * Sets the maximum number of attempts. + * + * Null means an unlimited number of attempts. + * + * @param null|int $attempts + * + * @return Question The current instance + * + * @throws \InvalidArgumentException In case the number of attempts is invalid. + */ + public function setMaxAttempts($attempts) + { + if (null !== $attempts && $attempts < 1) { + throw new \InvalidArgumentException('Maximum number of attempts must be a positive value.'); + } + + $this->attempts = $attempts; + + return $this; + } + + /** + * Gets the maximum number of attempts. + * + * Null means an unlimited number of attempts. + * + * @return null|int + */ + public function getMaxAttempts() + { + return $this->attempts; + } + + /** + * Sets a normalizer for the response. + * + * The normalizer can be a callable (a string), a closure or a class implementing __invoke. + * + * @param string|\Closure $normalizer + * + * @return Question The current instance + */ + public function setNormalizer($normalizer) + { + $this->normalizer = $normalizer; + + return $this; + } + + /** + * Gets the normalizer for the response. + * + * The normalizer can ba a callable (a string), a closure or a class implementing __invoke. + * + * @return string|\Closure + */ + public function getNormalizer() + { + return $this->normalizer; + } + + protected function isAssoc($array) + { + return (bool) count(array_filter(array_keys($array), 'is_string')); + } +} diff --git a/vendor/symfony/console/README.md b/vendor/symfony/console/README.md new file mode 100644 index 0000000..25f700c --- /dev/null +++ b/vendor/symfony/console/README.md @@ -0,0 +1,67 @@ +Console Component +================= + +Console eases the creation of beautiful and testable command line interfaces. + +The Application object manages the CLI application: + +```php +use Symfony\Component\Console\Application; + +$console = new Application(); +$console->run(); +``` + +The ``run()`` method parses the arguments and options passed on the command +line and executes the right command. + +Registering a new command can easily be done via the ``register()`` method, +which returns a ``Command`` instance: + +```php +use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Input\InputArgument; +use Symfony\Component\Console\Input\InputOption; +use Symfony\Component\Console\Output\OutputInterface; + +$console + ->register('ls') + ->setDefinition(array( + new InputArgument('dir', InputArgument::REQUIRED, 'Directory name'), + )) + ->setDescription('Displays the files in the given directory') + ->setCode(function (InputInterface $input, OutputInterface $output) { + $dir = $input->getArgument('dir'); + + $output->writeln(sprintf('Dir listing for %s', $dir)); + }) +; +``` + +You can also register new commands via classes. + +The component provides a lot of features like output coloring, input and +output abstractions (so that you can easily unit-test your commands), +validation, automatic help messages, ... + +Tests +----- + +You can run the unit tests with the following command: + + $ cd path/to/Symfony/Component/Console/ + $ composer install + $ phpunit + +Third Party +----------- + +`Resources/bin/hiddeninput.exe` is a third party binary provided within this +component. Find sources and license at https://github.com/Seldaek/hidden-input. + +Resources +--------- + +[The Console Component](https://symfony.com/doc/current/components/console.html) + +[How to create a Console Command](https://symfony.com/doc/current/cookbook/console/console_command.html) diff --git a/vendor/symfony/console/Resources/bin/hiddeninput.exe b/vendor/symfony/console/Resources/bin/hiddeninput.exe new file mode 100644 index 0000000000000000000000000000000000000000..c8cf65e8d819e6e525121cf6b21f1c2429746038 GIT binary patch literal 9216 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 J0sQ~1{4brj`U(I5 literal 0 HcmV?d00001 diff --git a/vendor/symfony/console/Shell.php b/vendor/symfony/console/Shell.php new file mode 100644 index 0000000..eaaadfd --- /dev/null +++ b/vendor/symfony/console/Shell.php @@ -0,0 +1,228 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console; + +use Symfony\Component\Console\Input\StringInput; +use Symfony\Component\Console\Output\ConsoleOutput; +use Symfony\Component\Process\ProcessBuilder; +use Symfony\Component\Process\PhpExecutableFinder; + +/** + * A Shell wraps an Application to add shell capabilities to it. + * + * Support for history and completion only works with a PHP compiled + * with readline support (either --with-readline or --with-libedit) + * + * @author Fabien Potencier + * @author Martin Hasoň + */ +class Shell +{ + private $application; + private $history; + private $output; + private $hasReadline; + private $processIsolation = false; + + /** + * Constructor. + * + * If there is no readline support for the current PHP executable + * a \RuntimeException exception is thrown. + * + * @param Application $application An application instance + */ + public function __construct(Application $application) + { + $this->hasReadline = function_exists('readline'); + $this->application = $application; + $this->history = getenv('HOME').'/.history_'.$application->getName(); + $this->output = new ConsoleOutput(); + } + + /** + * Runs the shell. + */ + public function run() + { + $this->application->setAutoExit(false); + $this->application->setCatchExceptions(true); + + if ($this->hasReadline) { + readline_read_history($this->history); + readline_completion_function(array($this, 'autocompleter')); + } + + $this->output->writeln($this->getHeader()); + $php = null; + if ($this->processIsolation) { + $finder = new PhpExecutableFinder(); + $php = $finder->find(); + $this->output->writeln(<<Running with process isolation, you should consider this: + * each command is executed as separate process, + * commands don't support interactivity, all params must be passed explicitly, + * commands output is not colorized. + +EOF + ); + } + + while (true) { + $command = $this->readline(); + + if (false === $command) { + $this->output->writeln("\n"); + + break; + } + + if ($this->hasReadline) { + readline_add_history($command); + readline_write_history($this->history); + } + + if ($this->processIsolation) { + $pb = new ProcessBuilder(); + + $process = $pb + ->add($php) + ->add($_SERVER['argv'][0]) + ->add($command) + ->inheritEnvironmentVariables(true) + ->getProcess() + ; + + $output = $this->output; + $process->run(function ($type, $data) use ($output) { + $output->writeln($data); + }); + + $ret = $process->getExitCode(); + } else { + $ret = $this->application->run(new StringInput($command), $this->output); + } + + if (0 !== $ret) { + $this->output->writeln(sprintf('The command terminated with an error status (%s)', $ret)); + } + } + } + + /** + * Returns the shell header. + * + * @return string The header string + */ + protected function getHeader() + { + return <<{$this->application->getName()} shell ({$this->application->getVersion()}). + +At the prompt, type help for some help, +or list to get a list of available commands. + +To exit the shell, type ^D. + +EOF; + } + + /** + * Renders a prompt. + * + * @return string The prompt + */ + protected function getPrompt() + { + // using the formatter here is required when using readline + return $this->output->getFormatter()->format($this->application->getName().' > '); + } + + protected function getOutput() + { + return $this->output; + } + + protected function getApplication() + { + return $this->application; + } + + /** + * Tries to return autocompletion for the current entered text. + * + * @param string $text The last segment of the entered text + * + * @return bool|array A list of guessed strings or true + */ + private function autocompleter($text) + { + $info = readline_info(); + $text = substr($info['line_buffer'], 0, $info['end']); + + if ($info['point'] !== $info['end']) { + return true; + } + + // task name? + if (false === strpos($text, ' ') || !$text) { + return array_keys($this->application->all()); + } + + // options and arguments? + try { + $command = $this->application->find(substr($text, 0, strpos($text, ' '))); + } catch (\Exception $e) { + return true; + } + + $list = array('--help'); + foreach ($command->getDefinition()->getOptions() as $option) { + $list[] = '--'.$option->getName(); + } + + return $list; + } + + /** + * Reads a single line from standard input. + * + * @return string The single line from standard input + */ + private function readline() + { + if ($this->hasReadline) { + $line = readline($this->getPrompt()); + } else { + $this->output->write($this->getPrompt()); + $line = fgets(STDIN, 1024); + $line = (false === $line || '' === $line) ? false : rtrim($line); + } + + return $line; + } + + public function getProcessIsolation() + { + return $this->processIsolation; + } + + public function setProcessIsolation($processIsolation) + { + $this->processIsolation = (bool) $processIsolation; + + if ($this->processIsolation && !class_exists('Symfony\\Component\\Process\\Process')) { + throw new \RuntimeException('Unable to isolate processes as the Symfony Process Component is not installed.'); + } + } +} diff --git a/vendor/symfony/console/Style/OutputStyle.php b/vendor/symfony/console/Style/OutputStyle.php new file mode 100644 index 0000000..8371bb5 --- /dev/null +++ b/vendor/symfony/console/Style/OutputStyle.php @@ -0,0 +1,116 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Style; + +use Symfony\Component\Console\Formatter\OutputFormatterInterface; +use Symfony\Component\Console\Helper\ProgressBar; +use Symfony\Component\Console\Output\OutputInterface; + +/** + * Decorates output to add console style guide helpers. + * + * @author Kevin Bond + */ +abstract class OutputStyle implements OutputInterface, StyleInterface +{ + private $output; + + /** + * @param OutputInterface $output + */ + public function __construct(OutputInterface $output) + { + $this->output = $output; + } + + /** + * {@inheritdoc} + */ + public function newLine($count = 1) + { + $this->output->write(str_repeat(PHP_EOL, $count)); + } + + /** + * @param int $max + * + * @return ProgressBar + */ + public function createProgressBar($max = 0) + { + return new ProgressBar($this->output, $max); + } + + /** + * {@inheritdoc} + */ + public function write($messages, $newline = false, $type = self::OUTPUT_NORMAL) + { + $this->output->write($messages, $newline, $type); + } + + /** + * {@inheritdoc} + */ + public function writeln($messages, $type = self::OUTPUT_NORMAL) + { + $this->output->writeln($messages, $type); + } + + /** + * {@inheritdoc} + */ + public function setVerbosity($level) + { + $this->output->setVerbosity($level); + } + + /** + * {@inheritdoc} + */ + public function getVerbosity() + { + return $this->output->getVerbosity(); + } + + /** + * {@inheritdoc} + */ + public function setDecorated($decorated) + { + $this->output->setDecorated($decorated); + } + + /** + * {@inheritdoc} + */ + public function isDecorated() + { + return $this->output->isDecorated(); + } + + /** + * {@inheritdoc} + */ + public function setFormatter(OutputFormatterInterface $formatter) + { + $this->output->setFormatter($formatter); + } + + /** + * {@inheritdoc} + */ + public function getFormatter() + { + return $this->output->getFormatter(); + } +} diff --git a/vendor/symfony/console/Style/StyleInterface.php b/vendor/symfony/console/Style/StyleInterface.php new file mode 100644 index 0000000..2448547 --- /dev/null +++ b/vendor/symfony/console/Style/StyleInterface.php @@ -0,0 +1,159 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Style; + +/** + * Output style helpers. + * + * @author Kevin Bond + */ +interface StyleInterface +{ + /** + * Formats a command title. + * + * @param string $message + */ + public function title($message); + + /** + * Formats a section title. + * + * @param string $message + */ + public function section($message); + + /** + * Formats a list. + * + * @param array $elements + */ + public function listing(array $elements); + + /** + * Formats informational text. + * + * @param string|array $message + */ + public function text($message); + + /** + * Formats a success result bar. + * + * @param string|array $message + */ + public function success($message); + + /** + * Formats an error result bar. + * + * @param string|array $message + */ + public function error($message); + + /** + * Formats an warning result bar. + * + * @param string|array $message + */ + public function warning($message); + + /** + * Formats a note admonition. + * + * @param string|array $message + */ + public function note($message); + + /** + * Formats a caution admonition. + * + * @param string|array $message + */ + public function caution($message); + + /** + * Formats a table. + * + * @param array $headers + * @param array $rows + */ + public function table(array $headers, array $rows); + + /** + * Asks a question. + * + * @param string $question + * @param string|null $default + * @param callable|null $validator + * + * @return string + */ + public function ask($question, $default = null, $validator = null); + + /** + * Asks a question with the user input hidden. + * + * @param string $question + * @param callable|null $validator + * + * @return string + */ + public function askHidden($question, $validator = null); + + /** + * Asks for confirmation. + * + * @param string $question + * @param bool $default + * + * @return bool + */ + public function confirm($question, $default = true); + + /** + * Asks a choice question. + * + * @param string $question + * @param array $choices + * @param string|int|null $default + * + * @return string + */ + public function choice($question, array $choices, $default = null); + + /** + * Add newline(s). + * + * @param int $count The number of newlines + */ + public function newLine($count = 1); + + /** + * Starts the progress output. + * + * @param int $max Maximum steps (0 if unknown) + */ + public function progressStart($max = 0); + + /** + * Advances the progress output X steps. + * + * @param int $step Number of steps to advance + */ + public function progressAdvance($step = 1); + + /** + * Finishes the progress output. + */ + public function progressFinish(); +} diff --git a/vendor/symfony/console/Style/SymfonyStyle.php b/vendor/symfony/console/Style/SymfonyStyle.php new file mode 100644 index 0000000..0d366c7 --- /dev/null +++ b/vendor/symfony/console/Style/SymfonyStyle.php @@ -0,0 +1,406 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Style; + +use Symfony\Component\Console\Application; +use Symfony\Component\Console\Formatter\OutputFormatter; +use Symfony\Component\Console\Helper\Helper; +use Symfony\Component\Console\Helper\ProgressBar; +use Symfony\Component\Console\Helper\SymfonyQuestionHelper; +use Symfony\Component\Console\Helper\Table; +use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Output\BufferedOutput; +use Symfony\Component\Console\Output\OutputInterface; +use Symfony\Component\Console\Question\ChoiceQuestion; +use Symfony\Component\Console\Question\ConfirmationQuestion; +use Symfony\Component\Console\Question\Question; + +/** + * Output decorator helpers for the Symfony Style Guide. + * + * @author Kevin Bond + */ +class SymfonyStyle extends OutputStyle +{ + const MAX_LINE_LENGTH = 120; + + private $input; + private $questionHelper; + private $progressBar; + private $lineLength; + private $bufferedOutput; + + /** + * @param InputInterface $input + * @param OutputInterface $output + */ + public function __construct(InputInterface $input, OutputInterface $output) + { + $this->input = $input; + $this->bufferedOutput = new BufferedOutput($output->getVerbosity(), false, clone $output->getFormatter()); + // Windows cmd wraps lines as soon as the terminal width is reached, whether there are following chars or not. + $this->lineLength = min($this->getTerminalWidth() - (int) (DIRECTORY_SEPARATOR === '\\'), self::MAX_LINE_LENGTH); + + parent::__construct($output); + } + + /** + * Formats a message as a block of text. + * + * @param string|array $messages The message to write in the block + * @param string|null $type The block type (added in [] on first line) + * @param string|null $style The style to apply to the whole block + * @param string $prefix The prefix for the block + * @param bool $padding Whether to add vertical padding + */ + public function block($messages, $type = null, $style = null, $prefix = ' ', $padding = false) + { + $this->autoPrependBlock(); + $messages = is_array($messages) ? array_values($messages) : array($messages); + $lines = array(); + + // add type + if (null !== $type) { + $messages[0] = sprintf('[%s] %s', $type, $messages[0]); + } + + // wrap and add newlines for each element + foreach ($messages as $key => $message) { + $message = OutputFormatter::escape($message); + $lines = array_merge($lines, explode(PHP_EOL, wordwrap($message, $this->lineLength - Helper::strlen($prefix), PHP_EOL, true))); + + if (count($messages) > 1 && $key < count($messages) - 1) { + $lines[] = ''; + } + } + + if ($padding && $this->isDecorated()) { + array_unshift($lines, ''); + $lines[] = ''; + } + + foreach ($lines as &$line) { + $line = sprintf('%s%s', $prefix, $line); + $line .= str_repeat(' ', $this->lineLength - Helper::strlenWithoutDecoration($this->getFormatter(), $line)); + + if ($style) { + $line = sprintf('<%s>%s', $style, $line); + } + } + + $this->writeln($lines); + $this->newLine(); + } + + /** + * {@inheritdoc} + */ + public function title($message) + { + $this->autoPrependBlock(); + $this->writeln(array( + sprintf('%s', $message), + sprintf('%s', str_repeat('=', strlen($message))), + )); + $this->newLine(); + } + + /** + * {@inheritdoc} + */ + public function section($message) + { + $this->autoPrependBlock(); + $this->writeln(array( + sprintf('%s', $message), + sprintf('%s', str_repeat('-', strlen($message))), + )); + $this->newLine(); + } + + /** + * {@inheritdoc} + */ + public function listing(array $elements) + { + $this->autoPrependText(); + $elements = array_map(function ($element) { + return sprintf(' * %s', $element); + }, $elements); + + $this->writeln($elements); + $this->newLine(); + } + + /** + * {@inheritdoc} + */ + public function text($message) + { + $this->autoPrependText(); + + if (!is_array($message)) { + $this->writeln(sprintf(' // %s', $message)); + + return; + } + + foreach ($message as $element) { + $this->text($element); + } + } + + /** + * {@inheritdoc} + */ + public function success($message) + { + $this->block($message, 'OK', 'fg=white;bg=green', ' ', true); + } + + /** + * {@inheritdoc} + */ + public function error($message) + { + $this->block($message, 'ERROR', 'fg=white;bg=red', ' ', true); + } + + /** + * {@inheritdoc} + */ + public function warning($message) + { + $this->block($message, 'WARNING', 'fg=white;bg=red', ' ', true); + } + + /** + * {@inheritdoc} + */ + public function note($message) + { + $this->block($message, 'NOTE', 'fg=yellow', ' ! '); + } + + /** + * {@inheritdoc} + */ + public function caution($message) + { + $this->block($message, 'CAUTION', 'fg=white;bg=red', ' ! ', true); + } + + /** + * {@inheritdoc} + */ + public function table(array $headers, array $rows) + { + $headers = array_map(function ($value) { return sprintf('%s', $value); }, $headers); + + $table = new Table($this); + $table->setHeaders($headers); + $table->setRows($rows); + $table->setStyle('symfony-style-guide'); + + $table->render(); + $this->newLine(); + } + + /** + * {@inheritdoc} + */ + public function ask($question, $default = null, $validator = null) + { + $question = new Question($question, $default); + $question->setValidator($validator); + + return $this->askQuestion($question); + } + + /** + * {@inheritdoc} + */ + public function askHidden($question, $validator = null) + { + $question = new Question($question); + + $question->setHidden(true); + $question->setValidator($validator); + + return $this->askQuestion($question); + } + + /** + * {@inheritdoc} + */ + public function confirm($question, $default = true) + { + return $this->askQuestion(new ConfirmationQuestion($question, $default)); + } + + /** + * {@inheritdoc} + */ + public function choice($question, array $choices, $default = null) + { + if (null !== $default) { + $values = array_flip($choices); + $default = $values[$default]; + } + + return $this->askQuestion(new ChoiceQuestion($question, $choices, $default)); + } + + /** + * {@inheritdoc} + */ + public function progressStart($max = 0) + { + $this->progressBar = $this->createProgressBar($max); + $this->progressBar->start(); + } + + /** + * {@inheritdoc} + */ + public function progressAdvance($step = 1) + { + $this->getProgressBar()->advance($step); + } + + /** + * {@inheritdoc} + */ + public function progressFinish() + { + $this->getProgressBar()->finish(); + $this->newLine(2); + $this->progressBar = null; + } + + /** + * {@inheritdoc} + */ + public function createProgressBar($max = 0) + { + $progressBar = parent::createProgressBar($max); + + if ('\\' === DIRECTORY_SEPARATOR) { + $progressBar->setEmptyBarCharacter('░'); // light shade character \u2591 + $progressBar->setProgressCharacter(''); + $progressBar->setBarCharacter('▓'); // dark shade character \u2593 + } + + return $progressBar; + } + + /** + * @param Question $question + * + * @return string + */ + public function askQuestion(Question $question) + { + if ($this->input->isInteractive()) { + $this->autoPrependBlock(); + } + + if (!$this->questionHelper) { + $this->questionHelper = new SymfonyQuestionHelper(); + } + + $answer = $this->questionHelper->ask($this->input, $this, $question); + + if ($this->input->isInteractive()) { + $this->newLine(); + $this->bufferedOutput->write("\n"); + } + + return $answer; + } + + /** + * {@inheritdoc} + */ + public function writeln($messages, $type = self::OUTPUT_NORMAL) + { + parent::writeln($messages, $type); + $this->bufferedOutput->writeln($this->reduceBuffer($messages), $type); + } + + /** + * {@inheritdoc} + */ + public function write($messages, $newline = false, $type = self::OUTPUT_NORMAL) + { + parent::write($messages, $newline, $type); + $this->bufferedOutput->write($this->reduceBuffer($messages), $newline, $type); + } + + /** + * {@inheritdoc} + */ + public function newLine($count = 1) + { + parent::newLine($count); + $this->bufferedOutput->write(str_repeat("\n", $count)); + } + + /** + * @return ProgressBar + */ + private function getProgressBar() + { + if (!$this->progressBar) { + throw new \RuntimeException('The ProgressBar is not started.'); + } + + return $this->progressBar; + } + + private function getTerminalWidth() + { + $application = new Application(); + $dimensions = $application->getTerminalDimensions(); + + return $dimensions[0] ?: self::MAX_LINE_LENGTH; + } + + private function autoPrependBlock() + { + $chars = substr(str_replace(PHP_EOL, "\n", $this->bufferedOutput->fetch()), -2); + + if (!isset($chars[0])) { + return $this->newLine(); //empty history, so we should start with a new line. + } + //Prepend new line for each non LF chars (This means no blank line was output before) + $this->newLine(2 - substr_count($chars, "\n")); + } + + private function autoPrependText() + { + $fetched = $this->bufferedOutput->fetch(); + //Prepend new line if last char isn't EOL: + if ("\n" !== substr($fetched, -1)) { + $this->newLine(); + } + } + + private function reduceBuffer($messages) + { + // We need to know if the two last chars are PHP_EOL + // Preserve the last 4 chars inserted (PHP_EOL on windows is two chars) in the history buffer + return array_map(function ($value) { + return substr($value, -4); + }, array_merge(array($this->bufferedOutput->fetch()), (array) $messages)); + } +} diff --git a/vendor/symfony/console/Tester/ApplicationTester.php b/vendor/symfony/console/Tester/ApplicationTester.php new file mode 100644 index 0000000..da8a19c --- /dev/null +++ b/vendor/symfony/console/Tester/ApplicationTester.php @@ -0,0 +1,128 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Tester; + +use Symfony\Component\Console\Application; +use Symfony\Component\Console\Input\ArrayInput; +use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Output\OutputInterface; +use Symfony\Component\Console\Output\StreamOutput; + +/** + * Eases the testing of console applications. + * + * When testing an application, don't forget to disable the auto exit flag: + * + * $application = new Application(); + * $application->setAutoExit(false); + * + * @author Fabien Potencier + */ +class ApplicationTester +{ + private $application; + private $input; + private $output; + private $statusCode; + + /** + * Constructor. + * + * @param Application $application An Application instance to test. + */ + public function __construct(Application $application) + { + $this->application = $application; + } + + /** + * Executes the application. + * + * Available options: + * + * * interactive: Sets the input interactive flag + * * decorated: Sets the output decorated flag + * * verbosity: Sets the output verbosity flag + * + * @param array $input An array of arguments and options + * @param array $options An array of options + * + * @return int The command exit code + */ + public function run(array $input, $options = array()) + { + $this->input = new ArrayInput($input); + if (isset($options['interactive'])) { + $this->input->setInteractive($options['interactive']); + } + + $this->output = new StreamOutput(fopen('php://memory', 'w', false)); + if (isset($options['decorated'])) { + $this->output->setDecorated($options['decorated']); + } + if (isset($options['verbosity'])) { + $this->output->setVerbosity($options['verbosity']); + } + + return $this->statusCode = $this->application->run($this->input, $this->output); + } + + /** + * Gets the display returned by the last execution of the application. + * + * @param bool $normalize Whether to normalize end of lines to \n or not + * + * @return string The display + */ + public function getDisplay($normalize = false) + { + rewind($this->output->getStream()); + + $display = stream_get_contents($this->output->getStream()); + + if ($normalize) { + $display = str_replace(PHP_EOL, "\n", $display); + } + + return $display; + } + + /** + * Gets the input instance used by the last execution of the application. + * + * @return InputInterface The current input instance + */ + public function getInput() + { + return $this->input; + } + + /** + * Gets the output instance used by the last execution of the application. + * + * @return OutputInterface The current output instance + */ + public function getOutput() + { + return $this->output; + } + + /** + * Gets the status code returned by the last execution of the application. + * + * @return int The status code + */ + public function getStatusCode() + { + return $this->statusCode; + } +} diff --git a/vendor/symfony/console/Tester/CommandTester.php b/vendor/symfony/console/Tester/CommandTester.php new file mode 100644 index 0000000..8d6486e --- /dev/null +++ b/vendor/symfony/console/Tester/CommandTester.php @@ -0,0 +1,132 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Tester; + +use Symfony\Component\Console\Command\Command; +use Symfony\Component\Console\Input\ArrayInput; +use Symfony\Component\Console\Output\StreamOutput; +use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Output\OutputInterface; + +/** + * Eases the testing of console commands. + * + * @author Fabien Potencier + */ +class CommandTester +{ + private $command; + private $input; + private $output; + private $statusCode; + + /** + * Constructor. + * + * @param Command $command A Command instance to test. + */ + public function __construct(Command $command) + { + $this->command = $command; + } + + /** + * Executes the command. + * + * Available execution options: + * + * * interactive: Sets the input interactive flag + * * decorated: Sets the output decorated flag + * * verbosity: Sets the output verbosity flag + * + * @param array $input An array of command arguments and options + * @param array $options An array of execution options + * + * @return int The command exit code + */ + public function execute(array $input, array $options = array()) + { + // set the command name automatically if the application requires + // this argument and no command name was passed + if (!isset($input['command']) + && (null !== $application = $this->command->getApplication()) + && $application->getDefinition()->hasArgument('command') + ) { + $input = array_merge(array('command' => $this->command->getName()), $input); + } + + $this->input = new ArrayInput($input); + if (isset($options['interactive'])) { + $this->input->setInteractive($options['interactive']); + } + + $this->output = new StreamOutput(fopen('php://memory', 'w', false)); + if (isset($options['decorated'])) { + $this->output->setDecorated($options['decorated']); + } + if (isset($options['verbosity'])) { + $this->output->setVerbosity($options['verbosity']); + } + + return $this->statusCode = $this->command->run($this->input, $this->output); + } + + /** + * Gets the display returned by the last execution of the command. + * + * @param bool $normalize Whether to normalize end of lines to \n or not + * + * @return string The display + */ + public function getDisplay($normalize = false) + { + rewind($this->output->getStream()); + + $display = stream_get_contents($this->output->getStream()); + + if ($normalize) { + $display = str_replace(PHP_EOL, "\n", $display); + } + + return $display; + } + + /** + * Gets the input instance used by the last execution of the command. + * + * @return InputInterface The current input instance + */ + public function getInput() + { + return $this->input; + } + + /** + * Gets the output instance used by the last execution of the command. + * + * @return OutputInterface The current output instance + */ + public function getOutput() + { + return $this->output; + } + + /** + * Gets the status code returned by the last execution of the application. + * + * @return int The status code + */ + public function getStatusCode() + { + return $this->statusCode; + } +} diff --git a/vendor/symfony/console/Tests/ApplicationTest.php b/vendor/symfony/console/Tests/ApplicationTest.php new file mode 100644 index 0000000..45242cf --- /dev/null +++ b/vendor/symfony/console/Tests/ApplicationTest.php @@ -0,0 +1,1060 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Tests; + +use Symfony\Component\Console\Application; +use Symfony\Component\Console\Helper\HelperSet; +use Symfony\Component\Console\Helper\FormatterHelper; +use Symfony\Component\Console\Input\ArgvInput; +use Symfony\Component\Console\Input\ArrayInput; +use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Input\InputArgument; +use Symfony\Component\Console\Input\InputDefinition; +use Symfony\Component\Console\Input\InputOption; +use Symfony\Component\Console\Output\NullOutput; +use Symfony\Component\Console\Output\Output; +use Symfony\Component\Console\Output\OutputInterface; +use Symfony\Component\Console\Output\StreamOutput; +use Symfony\Component\Console\Tester\ApplicationTester; +use Symfony\Component\Console\Event\ConsoleCommandEvent; +use Symfony\Component\Console\Event\ConsoleExceptionEvent; +use Symfony\Component\Console\Event\ConsoleTerminateEvent; +use Symfony\Component\EventDispatcher\EventDispatcher; + +class ApplicationTest extends \PHPUnit_Framework_TestCase +{ + protected static $fixturesPath; + + public static function setUpBeforeClass() + { + self::$fixturesPath = realpath(__DIR__.'/Fixtures/'); + require_once self::$fixturesPath.'/FooCommand.php'; + require_once self::$fixturesPath.'/Foo1Command.php'; + require_once self::$fixturesPath.'/Foo2Command.php'; + require_once self::$fixturesPath.'/Foo3Command.php'; + require_once self::$fixturesPath.'/Foo4Command.php'; + require_once self::$fixturesPath.'/Foo5Command.php'; + require_once self::$fixturesPath.'/FoobarCommand.php'; + require_once self::$fixturesPath.'/BarBucCommand.php'; + require_once self::$fixturesPath.'/FooSubnamespaced1Command.php'; + require_once self::$fixturesPath.'/FooSubnamespaced2Command.php'; + } + + protected function normalizeLineBreaks($text) + { + return str_replace(PHP_EOL, "\n", $text); + } + + /** + * Replaces the dynamic placeholders of the command help text with a static version. + * The placeholder %command.full_name% includes the script path that is not predictable + * and can not be tested against. + */ + protected function ensureStaticCommandHelp(Application $application) + { + foreach ($application->all() as $command) { + $command->setHelp(str_replace('%command.full_name%', 'app/console %command.name%', $command->getHelp())); + } + } + + public function testConstructor() + { + $application = new Application('foo', 'bar'); + $this->assertEquals('foo', $application->getName(), '__construct() takes the application name as its first argument'); + $this->assertEquals('bar', $application->getVersion(), '__construct() takes the application version as its second argument'); + $this->assertEquals(array('help', 'list'), array_keys($application->all()), '__construct() registered the help and list commands by default'); + } + + public function testSetGetName() + { + $application = new Application(); + $application->setName('foo'); + $this->assertEquals('foo', $application->getName(), '->setName() sets the name of the application'); + } + + public function testSetGetVersion() + { + $application = new Application(); + $application->setVersion('bar'); + $this->assertEquals('bar', $application->getVersion(), '->setVersion() sets the version of the application'); + } + + public function testGetLongVersion() + { + $application = new Application('foo', 'bar'); + $this->assertEquals('foo version bar', $application->getLongVersion(), '->getLongVersion() returns the long version of the application'); + } + + public function testHelp() + { + $application = new Application(); + $this->assertStringEqualsFile(self::$fixturesPath.'/application_gethelp.txt', $this->normalizeLineBreaks($application->getHelp()), '->getHelp() returns a help message'); + } + + public function testAll() + { + $application = new Application(); + $commands = $application->all(); + $this->assertInstanceOf('Symfony\\Component\\Console\\Command\\HelpCommand', $commands['help'], '->all() returns the registered commands'); + + $application->add(new \FooCommand()); + $commands = $application->all('foo'); + $this->assertCount(1, $commands, '->all() takes a namespace as its first argument'); + } + + public function testRegister() + { + $application = new Application(); + $command = $application->register('foo'); + $this->assertEquals('foo', $command->getName(), '->register() registers a new command'); + } + + public function testAdd() + { + $application = new Application(); + $application->add($foo = new \FooCommand()); + $commands = $application->all(); + $this->assertEquals($foo, $commands['foo:bar'], '->add() registers a command'); + + $application = new Application(); + $application->addCommands(array($foo = new \FooCommand(), $foo1 = new \Foo1Command())); + $commands = $application->all(); + $this->assertEquals(array($foo, $foo1), array($commands['foo:bar'], $commands['foo:bar1']), '->addCommands() registers an array of commands'); + } + + /** + * @expectedException \LogicException + * @expectedExceptionMessage Command class "Foo5Command" is not correctly initialized. You probably forgot to call the parent constructor. + */ + public function testAddCommandWithEmptyConstructor() + { + $application = new Application(); + $application->add(new \Foo5Command()); + } + + public function testHasGet() + { + $application = new Application(); + $this->assertTrue($application->has('list'), '->has() returns true if a named command is registered'); + $this->assertFalse($application->has('afoobar'), '->has() returns false if a named command is not registered'); + + $application->add($foo = new \FooCommand()); + $this->assertTrue($application->has('afoobar'), '->has() returns true if an alias is registered'); + $this->assertEquals($foo, $application->get('foo:bar'), '->get() returns a command by name'); + $this->assertEquals($foo, $application->get('afoobar'), '->get() returns a command by alias'); + + $application = new Application(); + $application->add($foo = new \FooCommand()); + // simulate --help + $r = new \ReflectionObject($application); + $p = $r->getProperty('wantHelps'); + $p->setAccessible(true); + $p->setValue($application, true); + $command = $application->get('foo:bar'); + $this->assertInstanceOf('Symfony\Component\Console\Command\HelpCommand', $command, '->get() returns the help command if --help is provided as the input'); + } + + public function testSilentHelp() + { + $application = new Application(); + $application->setAutoExit(false); + $application->setCatchExceptions(false); + + $tester = new ApplicationTester($application); + $tester->run(array('-h' => true, '-q' => true), array('decorated' => false)); + + $this->assertEmpty($tester->getDisplay(true)); + } + + /** + * @expectedException \InvalidArgumentException + * @expectedExceptionMessage The command "foofoo" does not exist. + */ + public function testGetInvalidCommand() + { + $application = new Application(); + $application->get('foofoo'); + } + + public function testGetNamespaces() + { + $application = new Application(); + $application->add(new \FooCommand()); + $application->add(new \Foo1Command()); + $this->assertEquals(array('foo'), $application->getNamespaces(), '->getNamespaces() returns an array of unique used namespaces'); + } + + public function testFindNamespace() + { + $application = new Application(); + $application->add(new \FooCommand()); + $this->assertEquals('foo', $application->findNamespace('foo'), '->findNamespace() returns the given namespace if it exists'); + $this->assertEquals('foo', $application->findNamespace('f'), '->findNamespace() finds a namespace given an abbreviation'); + $application->add(new \Foo2Command()); + $this->assertEquals('foo', $application->findNamespace('foo'), '->findNamespace() returns the given namespace if it exists'); + } + + public function testFindNamespaceWithSubnamespaces() + { + $application = new Application(); + $application->add(new \FooSubnamespaced1Command()); + $application->add(new \FooSubnamespaced2Command()); + $this->assertEquals('foo', $application->findNamespace('foo'), '->findNamespace() returns commands even if the commands are only contained in subnamespaces'); + } + + /** + * @expectedException \InvalidArgumentException + * @expectedExceptionMessage The namespace "f" is ambiguous (foo, foo1). + */ + public function testFindAmbiguousNamespace() + { + $application = new Application(); + $application->add(new \BarBucCommand()); + $application->add(new \FooCommand()); + $application->add(new \Foo2Command()); + $application->findNamespace('f'); + } + + /** + * @expectedException \InvalidArgumentException + * @expectedExceptionMessage There are no commands defined in the "bar" namespace. + */ + public function testFindInvalidNamespace() + { + $application = new Application(); + $application->findNamespace('bar'); + } + + /** + * @expectedException \InvalidArgumentException + * @expectedExceptionMessage Command "foo1" is not defined + */ + public function testFindUniqueNameButNamespaceName() + { + $application = new Application(); + $application->add(new \FooCommand()); + $application->add(new \Foo1Command()); + $application->add(new \Foo2Command()); + + $application->find($commandName = 'foo1'); + } + + public function testFind() + { + $application = new Application(); + $application->add(new \FooCommand()); + + $this->assertInstanceOf('FooCommand', $application->find('foo:bar'), '->find() returns a command if its name exists'); + $this->assertInstanceOf('Symfony\Component\Console\Command\HelpCommand', $application->find('h'), '->find() returns a command if its name exists'); + $this->assertInstanceOf('FooCommand', $application->find('f:bar'), '->find() returns a command if the abbreviation for the namespace exists'); + $this->assertInstanceOf('FooCommand', $application->find('f:b'), '->find() returns a command if the abbreviation for the namespace and the command name exist'); + $this->assertInstanceOf('FooCommand', $application->find('a'), '->find() returns a command if the abbreviation exists for an alias'); + } + + /** + * @dataProvider provideAmbiguousAbbreviations + */ + public function testFindWithAmbiguousAbbreviations($abbreviation, $expectedExceptionMessage) + { + $this->setExpectedException('InvalidArgumentException', $expectedExceptionMessage); + + $application = new Application(); + $application->add(new \FooCommand()); + $application->add(new \Foo1Command()); + $application->add(new \Foo2Command()); + + $application->find($abbreviation); + } + + public function provideAmbiguousAbbreviations() + { + return array( + array('f', 'Command "f" is not defined.'), + array('a', 'Command "a" is ambiguous (afoobar, afoobar1 and 1 more).'), + array('foo:b', 'Command "foo:b" is ambiguous (foo:bar, foo:bar1 and 1 more).'), + ); + } + + public function testFindCommandEqualNamespace() + { + $application = new Application(); + $application->add(new \Foo3Command()); + $application->add(new \Foo4Command()); + + $this->assertInstanceOf('Foo3Command', $application->find('foo3:bar'), '->find() returns the good command even if a namespace has same name'); + $this->assertInstanceOf('Foo4Command', $application->find('foo3:bar:toh'), '->find() returns a command even if its namespace equals another command name'); + } + + public function testFindCommandWithAmbiguousNamespacesButUniqueName() + { + $application = new Application(); + $application->add(new \FooCommand()); + $application->add(new \FoobarCommand()); + + $this->assertInstanceOf('FoobarCommand', $application->find('f:f')); + } + + public function testFindCommandWithMissingNamespace() + { + $application = new Application(); + $application->add(new \Foo4Command()); + + $this->assertInstanceOf('Foo4Command', $application->find('f::t')); + } + + /** + * @dataProvider provideInvalidCommandNamesSingle + * @expectedException \InvalidArgumentException + * @expectedExceptionMessage Did you mean this + */ + public function testFindAlternativeExceptionMessageSingle($name) + { + $application = new Application(); + $application->add(new \Foo3Command()); + $application->find($name); + } + + public function provideInvalidCommandNamesSingle() + { + return array( + array('foo3:baR'), + array('foO3:bar'), + ); + } + + public function testFindAlternativeExceptionMessageMultiple() + { + $application = new Application(); + $application->add(new \FooCommand()); + $application->add(new \Foo1Command()); + $application->add(new \Foo2Command()); + + // Command + plural + try { + $application->find('foo:baR'); + $this->fail('->find() throws an \InvalidArgumentException if command does not exist, with alternatives'); + } catch (\Exception $e) { + $this->assertInstanceOf('\InvalidArgumentException', $e, '->find() throws an \InvalidArgumentException if command does not exist, with alternatives'); + $this->assertRegExp('/Did you mean one of these/', $e->getMessage(), '->find() throws an \InvalidArgumentException if command does not exist, with alternatives'); + $this->assertRegExp('/foo1:bar/', $e->getMessage()); + $this->assertRegExp('/foo:bar/', $e->getMessage()); + } + + // Namespace + plural + try { + $application->find('foo2:bar'); + $this->fail('->find() throws an \InvalidArgumentException if command does not exist, with alternatives'); + } catch (\Exception $e) { + $this->assertInstanceOf('\InvalidArgumentException', $e, '->find() throws an \InvalidArgumentException if command does not exist, with alternatives'); + $this->assertRegExp('/Did you mean one of these/', $e->getMessage(), '->find() throws an \InvalidArgumentException if command does not exist, with alternatives'); + $this->assertRegExp('/foo1/', $e->getMessage()); + } + + $application->add(new \Foo3Command()); + $application->add(new \Foo4Command()); + + // Subnamespace + plural + try { + $a = $application->find('foo3:'); + $this->fail('->find() should throw an \InvalidArgumentException if a command is ambiguous because of a subnamespace, with alternatives'); + } catch (\Exception $e) { + $this->assertInstanceOf('\InvalidArgumentException', $e); + $this->assertRegExp('/foo3:bar/', $e->getMessage()); + $this->assertRegExp('/foo3:bar:toh/', $e->getMessage()); + } + } + + public function testFindAlternativeCommands() + { + $application = new Application(); + + $application->add(new \FooCommand()); + $application->add(new \Foo1Command()); + $application->add(new \Foo2Command()); + + try { + $application->find($commandName = 'Unknown command'); + $this->fail('->find() throws an \InvalidArgumentException if command does not exist'); + } catch (\Exception $e) { + $this->assertInstanceOf('\InvalidArgumentException', $e, '->find() throws an \InvalidArgumentException if command does not exist'); + $this->assertEquals(sprintf('Command "%s" is not defined.', $commandName), $e->getMessage(), '->find() throws an \InvalidArgumentException if command does not exist, without alternatives'); + } + + // Test if "bar1" command throw an "\InvalidArgumentException" and does not contain + // "foo:bar" as alternative because "bar1" is too far from "foo:bar" + try { + $application->find($commandName = 'bar1'); + $this->fail('->find() throws an \InvalidArgumentException if command does not exist'); + } catch (\Exception $e) { + $this->assertInstanceOf('\InvalidArgumentException', $e, '->find() throws an \InvalidArgumentException if command does not exist'); + $this->assertRegExp(sprintf('/Command "%s" is not defined./', $commandName), $e->getMessage(), '->find() throws an \InvalidArgumentException if command does not exist, with alternatives'); + $this->assertRegExp('/afoobar1/', $e->getMessage(), '->find() throws an \InvalidArgumentException if command does not exist, with alternative : "afoobar1"'); + $this->assertRegExp('/foo:bar1/', $e->getMessage(), '->find() throws an \InvalidArgumentException if command does not exist, with alternative : "foo:bar1"'); + $this->assertNotRegExp('/foo:bar(?>!1)/', $e->getMessage(), '->find() throws an \InvalidArgumentException if command does not exist, without "foo:bar" alternative'); + } + } + + public function testFindAlternativeCommandsWithAnAlias() + { + $fooCommand = new \FooCommand(); + $fooCommand->setAliases(array('foo2')); + + $application = new Application(); + $application->add($fooCommand); + + $result = $application->find('foo'); + + $this->assertSame($fooCommand, $result); + } + + public function testFindAlternativeNamespace() + { + $application = new Application(); + + $application->add(new \FooCommand()); + $application->add(new \Foo1Command()); + $application->add(new \Foo2Command()); + $application->add(new \foo3Command()); + + try { + $application->find('Unknown-namespace:Unknown-command'); + $this->fail('->find() throws an \InvalidArgumentException if namespace does not exist'); + } catch (\Exception $e) { + $this->assertInstanceOf('\InvalidArgumentException', $e, '->find() throws an \InvalidArgumentException if namespace does not exist'); + $this->assertEquals('There are no commands defined in the "Unknown-namespace" namespace.', $e->getMessage(), '->find() throws an \InvalidArgumentException if namespace does not exist, without alternatives'); + } + + try { + $application->find('foo2:command'); + $this->fail('->find() throws an \InvalidArgumentException if namespace does not exist'); + } catch (\Exception $e) { + $this->assertInstanceOf('\InvalidArgumentException', $e, '->find() throws an \InvalidArgumentException if namespace does not exist'); + $this->assertRegExp('/There are no commands defined in the "foo2" namespace./', $e->getMessage(), '->find() throws an \InvalidArgumentException if namespace does not exist, with alternative'); + $this->assertRegExp('/foo/', $e->getMessage(), '->find() throws an \InvalidArgumentException if namespace does not exist, with alternative : "foo"'); + $this->assertRegExp('/foo1/', $e->getMessage(), '->find() throws an \InvalidArgumentException if namespace does not exist, with alternative : "foo1"'); + $this->assertRegExp('/foo3/', $e->getMessage(), '->find() throws an \InvalidArgumentException if namespace does not exist, with alternative : "foo3"'); + } + } + + public function testFindNamespaceDoesNotFailOnDeepSimilarNamespaces() + { + $application = $this->getMock('Symfony\Component\Console\Application', array('getNamespaces')); + $application->expects($this->once()) + ->method('getNamespaces') + ->will($this->returnValue(array('foo:sublong', 'bar:sub'))); + + $this->assertEquals('foo:sublong', $application->findNamespace('f:sub')); + } + + /** + * @expectedException \InvalidArgumentException + * @expectedExceptionMessage Command "foo::bar" is not defined. + */ + public function testFindWithDoubleColonInNameThrowsException() + { + $application = new Application(); + $application->add(new \FooCommand()); + $application->add(new \Foo4Command()); + $application->find('foo::bar'); + } + + public function testSetCatchExceptions() + { + $application = $this->getMock('Symfony\Component\Console\Application', array('getTerminalWidth')); + $application->setAutoExit(false); + $application->expects($this->any()) + ->method('getTerminalWidth') + ->will($this->returnValue(120)); + $tester = new ApplicationTester($application); + + $application->setCatchExceptions(true); + $tester->run(array('command' => 'foo'), array('decorated' => false)); + $this->assertStringEqualsFile(self::$fixturesPath.'/application_renderexception1.txt', $tester->getDisplay(true), '->setCatchExceptions() sets the catch exception flag'); + + $application->setCatchExceptions(false); + try { + $tester->run(array('command' => 'foo'), array('decorated' => false)); + $this->fail('->setCatchExceptions() sets the catch exception flag'); + } catch (\Exception $e) { + $this->assertInstanceOf('\Exception', $e, '->setCatchExceptions() sets the catch exception flag'); + $this->assertEquals('Command "foo" is not defined.', $e->getMessage(), '->setCatchExceptions() sets the catch exception flag'); + } + } + + /** + * @group legacy + */ + public function testLegacyAsText() + { + $application = new Application(); + $application->add(new \FooCommand()); + $this->ensureStaticCommandHelp($application); + $this->assertStringEqualsFile(self::$fixturesPath.'/application_astext1.txt', $this->normalizeLineBreaks($application->asText()), '->asText() returns a text representation of the application'); + $this->assertStringEqualsFile(self::$fixturesPath.'/application_astext2.txt', $this->normalizeLineBreaks($application->asText('foo')), '->asText() returns a text representation of the application'); + } + + /** + * @group legacy + */ + public function testLegacyAsXml() + { + $application = new Application(); + $application->add(new \FooCommand()); + $this->ensureStaticCommandHelp($application); + $this->assertXmlStringEqualsXmlFile(self::$fixturesPath.'/application_asxml1.txt', $application->asXml(), '->asXml() returns an XML representation of the application'); + $this->assertXmlStringEqualsXmlFile(self::$fixturesPath.'/application_asxml2.txt', $application->asXml('foo'), '->asXml() returns an XML representation of the application'); + } + + public function testRenderException() + { + $application = $this->getMock('Symfony\Component\Console\Application', array('getTerminalWidth')); + $application->setAutoExit(false); + $application->expects($this->any()) + ->method('getTerminalWidth') + ->will($this->returnValue(120)); + $tester = new ApplicationTester($application); + + $tester->run(array('command' => 'foo'), array('decorated' => false)); + $this->assertStringEqualsFile(self::$fixturesPath.'/application_renderexception1.txt', $tester->getDisplay(true), '->renderException() renders a pretty exception'); + + $tester->run(array('command' => 'foo'), array('decorated' => false, 'verbosity' => Output::VERBOSITY_VERBOSE)); + $this->assertContains('Exception trace', $tester->getDisplay(), '->renderException() renders a pretty exception with a stack trace when verbosity is verbose'); + + $tester->run(array('command' => 'list', '--foo' => true), array('decorated' => false)); + $this->assertStringEqualsFile(self::$fixturesPath.'/application_renderexception2.txt', $tester->getDisplay(true), '->renderException() renders the command synopsis when an exception occurs in the context of a command'); + + $application->add(new \Foo3Command()); + $tester = new ApplicationTester($application); + $tester->run(array('command' => 'foo3:bar'), array('decorated' => false)); + $this->assertStringEqualsFile(self::$fixturesPath.'/application_renderexception3.txt', $tester->getDisplay(true), '->renderException() renders a pretty exceptions with previous exceptions'); + + $tester->run(array('command' => 'foo3:bar'), array('decorated' => true)); + $this->assertStringEqualsFile(self::$fixturesPath.'/application_renderexception3decorated.txt', $tester->getDisplay(true), '->renderException() renders a pretty exceptions with previous exceptions'); + + $application = $this->getMock('Symfony\Component\Console\Application', array('getTerminalWidth')); + $application->setAutoExit(false); + $application->expects($this->any()) + ->method('getTerminalWidth') + ->will($this->returnValue(32)); + $tester = new ApplicationTester($application); + + $tester->run(array('command' => 'foo'), array('decorated' => false)); + $this->assertStringEqualsFile(self::$fixturesPath.'/application_renderexception4.txt', $tester->getDisplay(true), '->renderException() wraps messages when they are bigger than the terminal'); + } + + public function testRenderExceptionWithDoubleWidthCharacters() + { + if (!function_exists('mb_strwidth')) { + $this->markTestSkipped('The "mb_strwidth" function is not available'); + } + + $application = $this->getMock('Symfony\Component\Console\Application', array('getTerminalWidth')); + $application->setAutoExit(false); + $application->expects($this->any()) + ->method('getTerminalWidth') + ->will($this->returnValue(120)); + $application->register('foo')->setCode(function () { + throw new \Exception('エラーメッセージ'); + }); + $tester = new ApplicationTester($application); + + $tester->run(array('command' => 'foo'), array('decorated' => false)); + $this->assertStringEqualsFile(self::$fixturesPath.'/application_renderexception_doublewidth1.txt', $tester->getDisplay(true), '->renderException() renders a pretty exceptions with previous exceptions'); + + $tester->run(array('command' => 'foo'), array('decorated' => true)); + $this->assertStringEqualsFile(self::$fixturesPath.'/application_renderexception_doublewidth1decorated.txt', $tester->getDisplay(true), '->renderException() renders a pretty exceptions with previous exceptions'); + + $application = $this->getMock('Symfony\Component\Console\Application', array('getTerminalWidth')); + $application->setAutoExit(false); + $application->expects($this->any()) + ->method('getTerminalWidth') + ->will($this->returnValue(32)); + $application->register('foo')->setCode(function () { + throw new \Exception('コマンドの実行中にエラーが発生しました。'); + }); + $tester = new ApplicationTester($application); + $tester->run(array('command' => 'foo'), array('decorated' => false)); + $this->assertStringEqualsFile(self::$fixturesPath.'/application_renderexception_doublewidth2.txt', $tester->getDisplay(true), '->renderException() wraps messages when they are bigger than the terminal'); + } + + public function testRun() + { + $application = new Application(); + $application->setAutoExit(false); + $application->setCatchExceptions(false); + $application->add($command = new \Foo1Command()); + $_SERVER['argv'] = array('cli.php', 'foo:bar1'); + + ob_start(); + $application->run(); + ob_end_clean(); + + $this->assertInstanceOf('Symfony\Component\Console\Input\ArgvInput', $command->input, '->run() creates an ArgvInput by default if none is given'); + $this->assertInstanceOf('Symfony\Component\Console\Output\ConsoleOutput', $command->output, '->run() creates a ConsoleOutput by default if none is given'); + + $application = new Application(); + $application->setAutoExit(false); + $application->setCatchExceptions(false); + + $this->ensureStaticCommandHelp($application); + $tester = new ApplicationTester($application); + + $tester->run(array(), array('decorated' => false)); + $this->assertStringEqualsFile(self::$fixturesPath.'/application_run1.txt', $tester->getDisplay(true), '->run() runs the list command if no argument is passed'); + + $tester->run(array('--help' => true), array('decorated' => false)); + $this->assertStringEqualsFile(self::$fixturesPath.'/application_run2.txt', $tester->getDisplay(true), '->run() runs the help command if --help is passed'); + + $tester->run(array('-h' => true), array('decorated' => false)); + $this->assertStringEqualsFile(self::$fixturesPath.'/application_run2.txt', $tester->getDisplay(true), '->run() runs the help command if -h is passed'); + + $tester->run(array('command' => 'list', '--help' => true), array('decorated' => false)); + $this->assertStringEqualsFile(self::$fixturesPath.'/application_run3.txt', $tester->getDisplay(true), '->run() displays the help if --help is passed'); + + $tester->run(array('command' => 'list', '-h' => true), array('decorated' => false)); + $this->assertStringEqualsFile(self::$fixturesPath.'/application_run3.txt', $tester->getDisplay(true), '->run() displays the help if -h is passed'); + + $tester->run(array('--ansi' => true)); + $this->assertTrue($tester->getOutput()->isDecorated(), '->run() forces color output if --ansi is passed'); + + $tester->run(array('--no-ansi' => true)); + $this->assertFalse($tester->getOutput()->isDecorated(), '->run() forces color output to be disabled if --no-ansi is passed'); + + $tester->run(array('--version' => true), array('decorated' => false)); + $this->assertStringEqualsFile(self::$fixturesPath.'/application_run4.txt', $tester->getDisplay(true), '->run() displays the program version if --version is passed'); + + $tester->run(array('-V' => true), array('decorated' => false)); + $this->assertStringEqualsFile(self::$fixturesPath.'/application_run4.txt', $tester->getDisplay(true), '->run() displays the program version if -v is passed'); + + $tester->run(array('command' => 'list', '--quiet' => true)); + $this->assertSame('', $tester->getDisplay(), '->run() removes all output if --quiet is passed'); + + $tester->run(array('command' => 'list', '-q' => true)); + $this->assertSame('', $tester->getDisplay(), '->run() removes all output if -q is passed'); + + $tester->run(array('command' => 'list', '--verbose' => true)); + $this->assertSame(Output::VERBOSITY_VERBOSE, $tester->getOutput()->getVerbosity(), '->run() sets the output to verbose if --verbose is passed'); + + $tester->run(array('command' => 'list', '--verbose' => 1)); + $this->assertSame(Output::VERBOSITY_VERBOSE, $tester->getOutput()->getVerbosity(), '->run() sets the output to verbose if --verbose=1 is passed'); + + $tester->run(array('command' => 'list', '--verbose' => 2)); + $this->assertSame(Output::VERBOSITY_VERY_VERBOSE, $tester->getOutput()->getVerbosity(), '->run() sets the output to very verbose if --verbose=2 is passed'); + + $tester->run(array('command' => 'list', '--verbose' => 3)); + $this->assertSame(Output::VERBOSITY_DEBUG, $tester->getOutput()->getVerbosity(), '->run() sets the output to debug if --verbose=3 is passed'); + + $tester->run(array('command' => 'list', '--verbose' => 4)); + $this->assertSame(Output::VERBOSITY_VERBOSE, $tester->getOutput()->getVerbosity(), '->run() sets the output to verbose if unknown --verbose level is passed'); + + $tester->run(array('command' => 'list', '-v' => true)); + $this->assertSame(Output::VERBOSITY_VERBOSE, $tester->getOutput()->getVerbosity(), '->run() sets the output to verbose if -v is passed'); + + $tester->run(array('command' => 'list', '-vv' => true)); + $this->assertSame(Output::VERBOSITY_VERY_VERBOSE, $tester->getOutput()->getVerbosity(), '->run() sets the output to verbose if -v is passed'); + + $tester->run(array('command' => 'list', '-vvv' => true)); + $this->assertSame(Output::VERBOSITY_DEBUG, $tester->getOutput()->getVerbosity(), '->run() sets the output to verbose if -v is passed'); + + $application = new Application(); + $application->setAutoExit(false); + $application->setCatchExceptions(false); + $application->add(new \FooCommand()); + $tester = new ApplicationTester($application); + + $tester->run(array('command' => 'foo:bar', '--no-interaction' => true), array('decorated' => false)); + $this->assertSame('called'.PHP_EOL, $tester->getDisplay(), '->run() does not call interact() if --no-interaction is passed'); + + $tester->run(array('command' => 'foo:bar', '-n' => true), array('decorated' => false)); + $this->assertSame('called'.PHP_EOL, $tester->getDisplay(), '->run() does not call interact() if -n is passed'); + } + + /** + * Issue #9285. + * + * If the "verbose" option is just before an argument in ArgvInput, + * an argument value should not be treated as verbosity value. + * This test will fail with "Not enough arguments." if broken + */ + public function testVerboseValueNotBreakArguments() + { + $application = new Application(); + $application->setAutoExit(false); + $application->setCatchExceptions(false); + $application->add(new \FooCommand()); + + $output = new StreamOutput(fopen('php://memory', 'w', false)); + + $input = new ArgvInput(array('cli.php', '-v', 'foo:bar')); + $application->run($input, $output); + + $input = new ArgvInput(array('cli.php', '--verbose', 'foo:bar')); + $application->run($input, $output); + } + + public function testRunReturnsIntegerExitCode() + { + $exception = new \Exception('', 4); + + $application = $this->getMock('Symfony\Component\Console\Application', array('doRun')); + $application->setAutoExit(false); + $application->expects($this->once()) + ->method('doRun') + ->will($this->throwException($exception)); + + $exitCode = $application->run(new ArrayInput(array()), new NullOutput()); + + $this->assertSame(4, $exitCode, '->run() returns integer exit code extracted from raised exception'); + } + + public function testRunReturnsExitCodeOneForExceptionCodeZero() + { + $exception = new \Exception('', 0); + + $application = $this->getMock('Symfony\Component\Console\Application', array('doRun')); + $application->setAutoExit(false); + $application->expects($this->once()) + ->method('doRun') + ->will($this->throwException($exception)); + + $exitCode = $application->run(new ArrayInput(array()), new NullOutput()); + + $this->assertSame(1, $exitCode, '->run() returns exit code 1 when exception code is 0'); + } + + /** + * @expectedException \LogicException + * @dataProvider getAddingAlreadySetDefinitionElementData + */ + public function testAddingAlreadySetDefinitionElementData($def) + { + $application = new Application(); + $application->setAutoExit(false); + $application->setCatchExceptions(false); + $application + ->register('foo') + ->setDefinition(array($def)) + ->setCode(function (InputInterface $input, OutputInterface $output) {}) + ; + + $input = new ArrayInput(array('command' => 'foo')); + $output = new NullOutput(); + $application->run($input, $output); + } + + public function getAddingAlreadySetDefinitionElementData() + { + return array( + array(new InputArgument('command', InputArgument::REQUIRED)), + array(new InputOption('quiet', '', InputOption::VALUE_NONE)), + array(new InputOption('query', 'q', InputOption::VALUE_NONE)), + ); + } + + public function testGetDefaultHelperSetReturnsDefaultValues() + { + $application = new Application(); + $application->setAutoExit(false); + $application->setCatchExceptions(false); + + $helperSet = $application->getHelperSet(); + + $this->assertTrue($helperSet->has('formatter')); + $this->assertTrue($helperSet->has('dialog')); + $this->assertTrue($helperSet->has('progress')); + } + + public function testAddingSingleHelperSetOverwritesDefaultValues() + { + $application = new Application(); + $application->setAutoExit(false); + $application->setCatchExceptions(false); + + $application->setHelperSet(new HelperSet(array(new FormatterHelper()))); + + $helperSet = $application->getHelperSet(); + + $this->assertTrue($helperSet->has('formatter')); + + // no other default helper set should be returned + $this->assertFalse($helperSet->has('dialog')); + $this->assertFalse($helperSet->has('progress')); + } + + public function testOverwritingDefaultHelperSetOverwritesDefaultValues() + { + $application = new CustomApplication(); + $application->setAutoExit(false); + $application->setCatchExceptions(false); + + $application->setHelperSet(new HelperSet(array(new FormatterHelper()))); + + $helperSet = $application->getHelperSet(); + + $this->assertTrue($helperSet->has('formatter')); + + // no other default helper set should be returned + $this->assertFalse($helperSet->has('dialog')); + $this->assertFalse($helperSet->has('progress')); + } + + public function testGetDefaultInputDefinitionReturnsDefaultValues() + { + $application = new Application(); + $application->setAutoExit(false); + $application->setCatchExceptions(false); + + $inputDefinition = $application->getDefinition(); + + $this->assertTrue($inputDefinition->hasArgument('command')); + + $this->assertTrue($inputDefinition->hasOption('help')); + $this->assertTrue($inputDefinition->hasOption('quiet')); + $this->assertTrue($inputDefinition->hasOption('verbose')); + $this->assertTrue($inputDefinition->hasOption('version')); + $this->assertTrue($inputDefinition->hasOption('ansi')); + $this->assertTrue($inputDefinition->hasOption('no-ansi')); + $this->assertTrue($inputDefinition->hasOption('no-interaction')); + } + + public function testOverwritingDefaultInputDefinitionOverwritesDefaultValues() + { + $application = new CustomApplication(); + $application->setAutoExit(false); + $application->setCatchExceptions(false); + + $inputDefinition = $application->getDefinition(); + + // check whether the default arguments and options are not returned any more + $this->assertFalse($inputDefinition->hasArgument('command')); + + $this->assertFalse($inputDefinition->hasOption('help')); + $this->assertFalse($inputDefinition->hasOption('quiet')); + $this->assertFalse($inputDefinition->hasOption('verbose')); + $this->assertFalse($inputDefinition->hasOption('version')); + $this->assertFalse($inputDefinition->hasOption('ansi')); + $this->assertFalse($inputDefinition->hasOption('no-ansi')); + $this->assertFalse($inputDefinition->hasOption('no-interaction')); + + $this->assertTrue($inputDefinition->hasOption('custom')); + } + + public function testSettingCustomInputDefinitionOverwritesDefaultValues() + { + $application = new Application(); + $application->setAutoExit(false); + $application->setCatchExceptions(false); + + $application->setDefinition(new InputDefinition(array(new InputOption('--custom', '-c', InputOption::VALUE_NONE, 'Set the custom input definition.')))); + + $inputDefinition = $application->getDefinition(); + + // check whether the default arguments and options are not returned any more + $this->assertFalse($inputDefinition->hasArgument('command')); + + $this->assertFalse($inputDefinition->hasOption('help')); + $this->assertFalse($inputDefinition->hasOption('quiet')); + $this->assertFalse($inputDefinition->hasOption('verbose')); + $this->assertFalse($inputDefinition->hasOption('version')); + $this->assertFalse($inputDefinition->hasOption('ansi')); + $this->assertFalse($inputDefinition->hasOption('no-ansi')); + $this->assertFalse($inputDefinition->hasOption('no-interaction')); + + $this->assertTrue($inputDefinition->hasOption('custom')); + } + + public function testRunWithDispatcher() + { + $application = new Application(); + $application->setAutoExit(false); + $application->setDispatcher($this->getDispatcher()); + + $application->register('foo')->setCode(function (InputInterface $input, OutputInterface $output) { + $output->write('foo.'); + }); + + $tester = new ApplicationTester($application); + $tester->run(array('command' => 'foo')); + $this->assertEquals('before.foo.after.', $tester->getDisplay()); + } + + /** + * @expectedException \LogicException + * @expectedExceptionMessage caught + */ + public function testRunWithExceptionAndDispatcher() + { + $application = new Application(); + $application->setDispatcher($this->getDispatcher()); + $application->setAutoExit(false); + $application->setCatchExceptions(false); + + $application->register('foo')->setCode(function (InputInterface $input, OutputInterface $output) { + throw new \RuntimeException('foo'); + }); + + $tester = new ApplicationTester($application); + $tester->run(array('command' => 'foo')); + } + + public function testRunDispatchesAllEventsWithException() + { + $application = new Application(); + $application->setDispatcher($this->getDispatcher()); + $application->setAutoExit(false); + + $application->register('foo')->setCode(function (InputInterface $input, OutputInterface $output) { + $output->write('foo.'); + + throw new \RuntimeException('foo'); + }); + + $tester = new ApplicationTester($application); + $tester->run(array('command' => 'foo')); + $this->assertContains('before.foo.after.caught.', $tester->getDisplay()); + } + + public function testRunWithDispatcherSkippingCommand() + { + $application = new Application(); + $application->setDispatcher($this->getDispatcher(true)); + $application->setAutoExit(false); + + $application->register('foo')->setCode(function (InputInterface $input, OutputInterface $output) { + $output->write('foo.'); + }); + + $tester = new ApplicationTester($application); + $exitCode = $tester->run(array('command' => 'foo')); + $this->assertContains('before.after.', $tester->getDisplay()); + $this->assertEquals(ConsoleCommandEvent::RETURN_CODE_DISABLED, $exitCode); + } + + public function testTerminalDimensions() + { + $application = new Application(); + $originalDimensions = $application->getTerminalDimensions(); + $this->assertCount(2, $originalDimensions); + + $width = 80; + if ($originalDimensions[0] == $width) { + $width = 100; + } + + $application->setTerminalDimensions($width, 80); + $this->assertSame(array($width, 80), $application->getTerminalDimensions()); + } + + protected function getDispatcher($skipCommand = false) + { + $dispatcher = new EventDispatcher(); + $dispatcher->addListener('console.command', function (ConsoleCommandEvent $event) use ($skipCommand) { + $event->getOutput()->write('before.'); + + if ($skipCommand) { + $event->disableCommand(); + } + }); + $dispatcher->addListener('console.terminate', function (ConsoleTerminateEvent $event) use ($skipCommand) { + $event->getOutput()->write('after.'); + + if (!$skipCommand) { + $event->setExitCode(113); + } + }); + $dispatcher->addListener('console.exception', function (ConsoleExceptionEvent $event) { + $event->getOutput()->writeln('caught.'); + + $event->setException(new \LogicException('caught.', $event->getExitCode(), $event->getException())); + }); + + return $dispatcher; + } + + public function testSetRunCustomDefaultCommand() + { + $command = new \FooCommand(); + + $application = new Application(); + $application->setAutoExit(false); + $application->add($command); + $application->setDefaultCommand($command->getName()); + + $tester = new ApplicationTester($application); + $tester->run(array()); + $this->assertEquals('interact called'.PHP_EOL.'called'.PHP_EOL, $tester->getDisplay(), 'Application runs the default set command if different from \'list\' command'); + + $application = new CustomDefaultCommandApplication(); + $application->setAutoExit(false); + + $tester = new ApplicationTester($application); + $tester->run(array()); + + $this->assertEquals('interact called'.PHP_EOL.'called'.PHP_EOL, $tester->getDisplay(), 'Application runs the default set command if different from \'list\' command'); + } + + public function testCanCheckIfTerminalIsInteractive() + { + if (!function_exists('posix_isatty')) { + $this->markTestSkipped('posix_isatty function is required'); + } + + $application = new CustomDefaultCommandApplication(); + $application->setAutoExit(false); + + $tester = new ApplicationTester($application); + $tester->run(array('command' => 'help')); + + $this->assertFalse($tester->getInput()->hasParameterOption(array('--no-interaction', '-n'))); + + $inputStream = $application->getHelperSet()->get('question')->getInputStream(); + $this->assertEquals($tester->getInput()->isInteractive(), @posix_isatty($inputStream)); + } +} + +class CustomApplication extends Application +{ + /** + * Overwrites the default input definition. + * + * @return InputDefinition An InputDefinition instance + */ + protected function getDefaultInputDefinition() + { + return new InputDefinition(array(new InputOption('--custom', '-c', InputOption::VALUE_NONE, 'Set the custom input definition.'))); + } + + /** + * Gets the default helper set with the helpers that should always be available. + * + * @return HelperSet A HelperSet instance + */ + protected function getDefaultHelperSet() + { + return new HelperSet(array(new FormatterHelper())); + } +} + +class CustomDefaultCommandApplication extends Application +{ + /** + * Overwrites the constructor in order to set a different default command. + */ + public function __construct() + { + parent::__construct(); + + $command = new \FooCommand(); + $this->add($command); + $this->setDefaultCommand($command->getName()); + } +} diff --git a/vendor/symfony/console/Tests/Command/CommandTest.php b/vendor/symfony/console/Tests/Command/CommandTest.php new file mode 100644 index 0000000..7ab993b --- /dev/null +++ b/vendor/symfony/console/Tests/Command/CommandTest.php @@ -0,0 +1,337 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Tests\Command; + +use Symfony\Component\Console\Command\Command; +use Symfony\Component\Console\Helper\FormatterHelper; +use Symfony\Component\Console\Application; +use Symfony\Component\Console\Input\InputDefinition; +use Symfony\Component\Console\Input\InputArgument; +use Symfony\Component\Console\Input\InputOption; +use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Input\StringInput; +use Symfony\Component\Console\Output\OutputInterface; +use Symfony\Component\Console\Output\NullOutput; +use Symfony\Component\Console\Tester\CommandTester; + +class CommandTest extends \PHPUnit_Framework_TestCase +{ + protected static $fixturesPath; + + public static function setUpBeforeClass() + { + self::$fixturesPath = __DIR__.'/../Fixtures/'; + require_once self::$fixturesPath.'/TestCommand.php'; + } + + public function testConstructor() + { + $command = new Command('foo:bar'); + $this->assertEquals('foo:bar', $command->getName(), '__construct() takes the command name as its first argument'); + } + + /** + * @expectedException \LogicException + * @expectedExceptionMessage The command defined in "Symfony\Component\Console\Command\Command" cannot have an empty name. + */ + public function testCommandNameCannotBeEmpty() + { + new Command(); + } + + public function testSetApplication() + { + $application = new Application(); + $command = new \TestCommand(); + $command->setApplication($application); + $this->assertEquals($application, $command->getApplication(), '->setApplication() sets the current application'); + } + + public function testSetGetDefinition() + { + $command = new \TestCommand(); + $ret = $command->setDefinition($definition = new InputDefinition()); + $this->assertEquals($command, $ret, '->setDefinition() implements a fluent interface'); + $this->assertEquals($definition, $command->getDefinition(), '->setDefinition() sets the current InputDefinition instance'); + $command->setDefinition(array(new InputArgument('foo'), new InputOption('bar'))); + $this->assertTrue($command->getDefinition()->hasArgument('foo'), '->setDefinition() also takes an array of InputArguments and InputOptions as an argument'); + $this->assertTrue($command->getDefinition()->hasOption('bar'), '->setDefinition() also takes an array of InputArguments and InputOptions as an argument'); + $command->setDefinition(new InputDefinition()); + } + + public function testAddArgument() + { + $command = new \TestCommand(); + $ret = $command->addArgument('foo'); + $this->assertEquals($command, $ret, '->addArgument() implements a fluent interface'); + $this->assertTrue($command->getDefinition()->hasArgument('foo'), '->addArgument() adds an argument to the command'); + } + + public function testAddOption() + { + $command = new \TestCommand(); + $ret = $command->addOption('foo'); + $this->assertEquals($command, $ret, '->addOption() implements a fluent interface'); + $this->assertTrue($command->getDefinition()->hasOption('foo'), '->addOption() adds an option to the command'); + } + + public function testGetNamespaceGetNameSetName() + { + $command = new \TestCommand(); + $this->assertEquals('namespace:name', $command->getName(), '->getName() returns the command name'); + $command->setName('foo'); + $this->assertEquals('foo', $command->getName(), '->setName() sets the command name'); + + $ret = $command->setName('foobar:bar'); + $this->assertEquals($command, $ret, '->setName() implements a fluent interface'); + $this->assertEquals('foobar:bar', $command->getName(), '->setName() sets the command name'); + } + + /** + * @dataProvider provideInvalidCommandNames + */ + public function testInvalidCommandNames($name) + { + $this->setExpectedException('InvalidArgumentException', sprintf('Command name "%s" is invalid.', $name)); + + $command = new \TestCommand(); + $command->setName($name); + } + + public function provideInvalidCommandNames() + { + return array( + array(''), + array('foo:'), + ); + } + + public function testGetSetDescription() + { + $command = new \TestCommand(); + $this->assertEquals('description', $command->getDescription(), '->getDescription() returns the description'); + $ret = $command->setDescription('description1'); + $this->assertEquals($command, $ret, '->setDescription() implements a fluent interface'); + $this->assertEquals('description1', $command->getDescription(), '->setDescription() sets the description'); + } + + public function testGetSetHelp() + { + $command = new \TestCommand(); + $this->assertEquals('help', $command->getHelp(), '->getHelp() returns the help'); + $ret = $command->setHelp('help1'); + $this->assertEquals($command, $ret, '->setHelp() implements a fluent interface'); + $this->assertEquals('help1', $command->getHelp(), '->setHelp() sets the help'); + $command->setHelp(''); + $this->assertEquals('description', $command->getHelp(), '->getHelp() fallback to the description'); + } + + public function testGetProcessedHelp() + { + $command = new \TestCommand(); + $command->setHelp('The %command.name% command does... Example: php %command.full_name%.'); + $this->assertContains('The namespace:name command does...', $command->getProcessedHelp(), '->getProcessedHelp() replaces %command.name% correctly'); + $this->assertNotContains('%command.full_name%', $command->getProcessedHelp(), '->getProcessedHelp() replaces %command.full_name%'); + } + + public function testGetSetAliases() + { + $command = new \TestCommand(); + $this->assertEquals(array('name'), $command->getAliases(), '->getAliases() returns the aliases'); + $ret = $command->setAliases(array('name1')); + $this->assertEquals($command, $ret, '->setAliases() implements a fluent interface'); + $this->assertEquals(array('name1'), $command->getAliases(), '->setAliases() sets the aliases'); + } + + public function testGetSynopsis() + { + $command = new \TestCommand(); + $command->addOption('foo'); + $command->addArgument('bar'); + $this->assertEquals('namespace:name [--foo] [--] []', $command->getSynopsis(), '->getSynopsis() returns the synopsis'); + } + + public function testGetHelper() + { + $application = new Application(); + $command = new \TestCommand(); + $command->setApplication($application); + $formatterHelper = new FormatterHelper(); + $this->assertEquals($formatterHelper->getName(), $command->getHelper('formatter')->getName(), '->getHelper() returns the correct helper'); + } + + public function testMergeApplicationDefinition() + { + $application1 = new Application(); + $application1->getDefinition()->addArguments(array(new InputArgument('foo'))); + $application1->getDefinition()->addOptions(array(new InputOption('bar'))); + $command = new \TestCommand(); + $command->setApplication($application1); + $command->setDefinition($definition = new InputDefinition(array(new InputArgument('bar'), new InputOption('foo')))); + + $r = new \ReflectionObject($command); + $m = $r->getMethod('mergeApplicationDefinition'); + $m->setAccessible(true); + $m->invoke($command); + $this->assertTrue($command->getDefinition()->hasArgument('foo'), '->mergeApplicationDefinition() merges the application arguments and the command arguments'); + $this->assertTrue($command->getDefinition()->hasArgument('bar'), '->mergeApplicationDefinition() merges the application arguments and the command arguments'); + $this->assertTrue($command->getDefinition()->hasOption('foo'), '->mergeApplicationDefinition() merges the application options and the command options'); + $this->assertTrue($command->getDefinition()->hasOption('bar'), '->mergeApplicationDefinition() merges the application options and the command options'); + + $m->invoke($command); + $this->assertEquals(3, $command->getDefinition()->getArgumentCount(), '->mergeApplicationDefinition() does not try to merge twice the application arguments and options'); + } + + public function testMergeApplicationDefinitionWithoutArgsThenWithArgsAddsArgs() + { + $application1 = new Application(); + $application1->getDefinition()->addArguments(array(new InputArgument('foo'))); + $application1->getDefinition()->addOptions(array(new InputOption('bar'))); + $command = new \TestCommand(); + $command->setApplication($application1); + $command->setDefinition($definition = new InputDefinition(array())); + + $r = new \ReflectionObject($command); + $m = $r->getMethod('mergeApplicationDefinition'); + $m->setAccessible(true); + $m->invoke($command, false); + $this->assertTrue($command->getDefinition()->hasOption('bar'), '->mergeApplicationDefinition(false) merges the application and the command options'); + $this->assertFalse($command->getDefinition()->hasArgument('foo'), '->mergeApplicationDefinition(false) does not merge the application arguments'); + + $m->invoke($command, true); + $this->assertTrue($command->getDefinition()->hasArgument('foo'), '->mergeApplicationDefinition(true) merges the application arguments and the command arguments'); + + $m->invoke($command); + $this->assertEquals(2, $command->getDefinition()->getArgumentCount(), '->mergeApplicationDefinition() does not try to merge twice the application arguments'); + } + + public function testRunInteractive() + { + $tester = new CommandTester(new \TestCommand()); + + $tester->execute(array(), array('interactive' => true)); + + $this->assertEquals('interact called'.PHP_EOL.'execute called'.PHP_EOL, $tester->getDisplay(), '->run() calls the interact() method if the input is interactive'); + } + + public function testRunNonInteractive() + { + $tester = new CommandTester(new \TestCommand()); + + $tester->execute(array(), array('interactive' => false)); + + $this->assertEquals('execute called'.PHP_EOL, $tester->getDisplay(), '->run() does not call the interact() method if the input is not interactive'); + } + + /** + * @expectedException \LogicException + * @expectedExceptionMessage You must override the execute() method in the concrete command class. + */ + public function testExecuteMethodNeedsToBeOverridden() + { + $command = new Command('foo'); + $command->run(new StringInput(''), new NullOutput()); + } + + /** + * @expectedException \InvalidArgumentException + * @expectedExceptionMessage The "--bar" option does not exist. + */ + public function testRunWithInvalidOption() + { + $command = new \TestCommand(); + $tester = new CommandTester($command); + $tester->execute(array('--bar' => true)); + } + + public function testRunReturnsIntegerExitCode() + { + $command = new \TestCommand(); + $exitCode = $command->run(new StringInput(''), new NullOutput()); + $this->assertSame(0, $exitCode, '->run() returns integer exit code (treats null as 0)'); + + $command = $this->getMock('TestCommand', array('execute')); + $command->expects($this->once()) + ->method('execute') + ->will($this->returnValue('2.3')); + $exitCode = $command->run(new StringInput(''), new NullOutput()); + $this->assertSame(2, $exitCode, '->run() returns integer exit code (casts numeric to int)'); + } + + public function testRunReturnsAlwaysInteger() + { + $command = new \TestCommand(); + + $this->assertSame(0, $command->run(new StringInput(''), new NullOutput())); + } + + public function testSetCode() + { + $command = new \TestCommand(); + $ret = $command->setCode(function (InputInterface $input, OutputInterface $output) { + $output->writeln('from the code...'); + }); + $this->assertEquals($command, $ret, '->setCode() implements a fluent interface'); + $tester = new CommandTester($command); + $tester->execute(array()); + $this->assertEquals('interact called'.PHP_EOL.'from the code...'.PHP_EOL, $tester->getDisplay()); + } + + public function testSetCodeWithNonClosureCallable() + { + $command = new \TestCommand(); + $ret = $command->setCode(array($this, 'callableMethodCommand')); + $this->assertEquals($command, $ret, '->setCode() implements a fluent interface'); + $tester = new CommandTester($command); + $tester->execute(array()); + $this->assertEquals('interact called'.PHP_EOL.'from the code...'.PHP_EOL, $tester->getDisplay()); + } + + /** + * @expectedException \InvalidArgumentException + * @expectedExceptionMessage Invalid callable provided to Command::setCode. + */ + public function testSetCodeWithNonCallable() + { + $command = new \TestCommand(); + $command->setCode(array($this, 'nonExistentMethod')); + } + + public function callableMethodCommand(InputInterface $input, OutputInterface $output) + { + $output->writeln('from the code...'); + } + + /** + * @group legacy + */ + public function testLegacyAsText() + { + $command = new \TestCommand(); + $command->setApplication(new Application()); + $tester = new CommandTester($command); + $tester->execute(array('command' => $command->getName())); + $this->assertStringEqualsFile(self::$fixturesPath.'/command_astext.txt', $command->asText(), '->asText() returns a text representation of the command'); + } + + /** + * @group legacy + */ + public function testLegacyAsXml() + { + $command = new \TestCommand(); + $command->setApplication(new Application()); + $tester = new CommandTester($command); + $tester->execute(array('command' => $command->getName())); + $this->assertXmlStringEqualsXmlFile(self::$fixturesPath.'/command_asxml.txt', $command->asXml(), '->asXml() returns an XML representation of the command'); + } +} diff --git a/vendor/symfony/console/Tests/Command/HelpCommandTest.php b/vendor/symfony/console/Tests/Command/HelpCommandTest.php new file mode 100644 index 0000000..9e06858 --- /dev/null +++ b/vendor/symfony/console/Tests/Command/HelpCommandTest.php @@ -0,0 +1,70 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Tests\Command; + +use Symfony\Component\Console\Tester\CommandTester; +use Symfony\Component\Console\Command\HelpCommand; +use Symfony\Component\Console\Command\ListCommand; +use Symfony\Component\Console\Application; + +class HelpCommandTest extends \PHPUnit_Framework_TestCase +{ + public function testExecuteForCommandAlias() + { + $command = new HelpCommand(); + $command->setApplication(new Application()); + $commandTester = new CommandTester($command); + $commandTester->execute(array('command_name' => 'li'), array('decorated' => false)); + $this->assertContains('list [options] [--] []', $commandTester->getDisplay(), '->execute() returns a text help for the given command alias'); + $this->assertContains('format=FORMAT', $commandTester->getDisplay(), '->execute() returns a text help for the given command alias'); + $this->assertContains('raw', $commandTester->getDisplay(), '->execute() returns a text help for the given command alias'); + } + + public function testExecuteForCommand() + { + $command = new HelpCommand(); + $commandTester = new CommandTester($command); + $command->setCommand(new ListCommand()); + $commandTester->execute(array(), array('decorated' => false)); + $this->assertContains('list [options] [--] []', $commandTester->getDisplay(), '->execute() returns a text help for the given command'); + $this->assertContains('format=FORMAT', $commandTester->getDisplay(), '->execute() returns a text help for the given command'); + $this->assertContains('raw', $commandTester->getDisplay(), '->execute() returns a text help for the given command'); + } + + public function testExecuteForCommandWithXmlOption() + { + $command = new HelpCommand(); + $commandTester = new CommandTester($command); + $command->setCommand(new ListCommand()); + $commandTester->execute(array('--format' => 'xml')); + $this->assertContains('getDisplay(), '->execute() returns an XML help text if --xml is passed'); + } + + public function testExecuteForApplicationCommand() + { + $application = new Application(); + $commandTester = new CommandTester($application->get('help')); + $commandTester->execute(array('command_name' => 'list')); + $this->assertContains('list [options] [--] []', $commandTester->getDisplay(), '->execute() returns a text help for the given command'); + $this->assertContains('format=FORMAT', $commandTester->getDisplay(), '->execute() returns a text help for the given command'); + $this->assertContains('raw', $commandTester->getDisplay(), '->execute() returns a text help for the given command'); + } + + public function testExecuteForApplicationCommandWithXmlOption() + { + $application = new Application(); + $commandTester = new CommandTester($application->get('help')); + $commandTester->execute(array('command_name' => 'list', '--format' => 'xml')); + $this->assertContains('list [--xml] [--raw] [--format FORMAT] [--] [<namespace>]', $commandTester->getDisplay(), '->execute() returns a text help for the given command'); + $this->assertContains('getDisplay(), '->execute() returns an XML help text if --format=xml is passed'); + } +} diff --git a/vendor/symfony/console/Tests/Command/ListCommandTest.php b/vendor/symfony/console/Tests/Command/ListCommandTest.php new file mode 100644 index 0000000..3578d48 --- /dev/null +++ b/vendor/symfony/console/Tests/Command/ListCommandTest.php @@ -0,0 +1,64 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Tests\Command; + +use Symfony\Component\Console\Tester\CommandTester; +use Symfony\Component\Console\Application; + +class ListCommandTest extends \PHPUnit_Framework_TestCase +{ + public function testExecuteListsCommands() + { + $application = new Application(); + $commandTester = new CommandTester($command = $application->get('list')); + $commandTester->execute(array('command' => $command->getName()), array('decorated' => false)); + + $this->assertRegExp('/help\s{2,}Displays help for a command/', $commandTester->getDisplay(), '->execute() returns a list of available commands'); + } + + public function testExecuteListsCommandsWithXmlOption() + { + $application = new Application(); + $commandTester = new CommandTester($command = $application->get('list')); + $commandTester->execute(array('command' => $command->getName(), '--format' => 'xml')); + $this->assertRegExp('//', $commandTester->getDisplay(), '->execute() returns a list of available commands in XML if --xml is passed'); + } + + public function testExecuteListsCommandsWithRawOption() + { + $application = new Application(); + $commandTester = new CommandTester($command = $application->get('list')); + $commandTester->execute(array('command' => $command->getName(), '--raw' => true)); + $output = <<assertEquals($output, $commandTester->getDisplay(true)); + } + + public function testExecuteListsCommandsWithNamespaceArgument() + { + require_once realpath(__DIR__.'/../Fixtures/FooCommand.php'); + $application = new Application(); + $application->add(new \FooCommand()); + $commandTester = new CommandTester($command = $application->get('list')); + $commandTester->execute(array('command' => $command->getName(), 'namespace' => 'foo', '--raw' => true)); + $output = <<assertEquals($output, $commandTester->getDisplay(true)); + } +} diff --git a/vendor/symfony/console/Tests/Descriptor/AbstractDescriptorTest.php b/vendor/symfony/console/Tests/Descriptor/AbstractDescriptorTest.php new file mode 100644 index 0000000..f582e7f --- /dev/null +++ b/vendor/symfony/console/Tests/Descriptor/AbstractDescriptorTest.php @@ -0,0 +1,105 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Tests\Descriptor; + +use Symfony\Component\Console\Application; +use Symfony\Component\Console\Command\Command; +use Symfony\Component\Console\Input\InputArgument; +use Symfony\Component\Console\Input\InputDefinition; +use Symfony\Component\Console\Input\InputOption; +use Symfony\Component\Console\Output\BufferedOutput; + +abstract class AbstractDescriptorTest extends \PHPUnit_Framework_TestCase +{ + /** @dataProvider getDescribeInputArgumentTestData */ + public function testDescribeInputArgument(InputArgument $argument, $expectedDescription) + { + $this->assertDescription($expectedDescription, $argument); + } + + /** @dataProvider getDescribeInputOptionTestData */ + public function testDescribeInputOption(InputOption $option, $expectedDescription) + { + $this->assertDescription($expectedDescription, $option); + } + + /** @dataProvider getDescribeInputDefinitionTestData */ + public function testDescribeInputDefinition(InputDefinition $definition, $expectedDescription) + { + $this->assertDescription($expectedDescription, $definition); + } + + /** @dataProvider getDescribeCommandTestData */ + public function testDescribeCommand(Command $command, $expectedDescription) + { + $this->assertDescription($expectedDescription, $command); + } + + /** @dataProvider getDescribeApplicationTestData */ + public function testDescribeApplication(Application $application, $expectedDescription) + { + // Replaces the dynamic placeholders of the command help text with a static version. + // The placeholder %command.full_name% includes the script path that is not predictable + // and can not be tested against. + foreach ($application->all() as $command) { + $command->setHelp(str_replace('%command.full_name%', 'app/console %command.name%', $command->getHelp())); + } + + $this->assertDescription($expectedDescription, $application); + } + + public function getDescribeInputArgumentTestData() + { + return $this->getDescriptionTestData(ObjectsProvider::getInputArguments()); + } + + public function getDescribeInputOptionTestData() + { + return $this->getDescriptionTestData(ObjectsProvider::getInputOptions()); + } + + public function getDescribeInputDefinitionTestData() + { + return $this->getDescriptionTestData(ObjectsProvider::getInputDefinitions()); + } + + public function getDescribeCommandTestData() + { + return $this->getDescriptionTestData(ObjectsProvider::getCommands()); + } + + public function getDescribeApplicationTestData() + { + return $this->getDescriptionTestData(ObjectsProvider::getApplications()); + } + + abstract protected function getDescriptor(); + abstract protected function getFormat(); + + private function getDescriptionTestData(array $objects) + { + $data = array(); + foreach ($objects as $name => $object) { + $description = file_get_contents(sprintf('%s/../Fixtures/%s.%s', __DIR__, $name, $this->getFormat())); + $data[] = array($object, $description); + } + + return $data; + } + + protected function assertDescription($expectedDescription, $describedObject) + { + $output = new BufferedOutput(BufferedOutput::VERBOSITY_NORMAL, true); + $this->getDescriptor()->describe($output, $describedObject, array('raw_output' => true)); + $this->assertEquals(trim($expectedDescription), trim(str_replace(PHP_EOL, "\n", $output->fetch()))); + } +} diff --git a/vendor/symfony/console/Tests/Descriptor/JsonDescriptorTest.php b/vendor/symfony/console/Tests/Descriptor/JsonDescriptorTest.php new file mode 100644 index 0000000..f9a1561 --- /dev/null +++ b/vendor/symfony/console/Tests/Descriptor/JsonDescriptorTest.php @@ -0,0 +1,35 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Tests\Descriptor; + +use Symfony\Component\Console\Descriptor\JsonDescriptor; +use Symfony\Component\Console\Output\BufferedOutput; + +class JsonDescriptorTest extends AbstractDescriptorTest +{ + protected function getDescriptor() + { + return new JsonDescriptor(); + } + + protected function getFormat() + { + return 'json'; + } + + protected function assertDescription($expectedDescription, $describedObject) + { + $output = new BufferedOutput(BufferedOutput::VERBOSITY_NORMAL, true); + $this->getDescriptor()->describe($output, $describedObject, array('raw_output' => true)); + $this->assertEquals(json_decode(trim($expectedDescription), true), json_decode(trim(str_replace(PHP_EOL, "\n", $output->fetch())), true)); + } +} diff --git a/vendor/symfony/console/Tests/Descriptor/MarkdownDescriptorTest.php b/vendor/symfony/console/Tests/Descriptor/MarkdownDescriptorTest.php new file mode 100644 index 0000000..c85e8a5 --- /dev/null +++ b/vendor/symfony/console/Tests/Descriptor/MarkdownDescriptorTest.php @@ -0,0 +1,27 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Tests\Descriptor; + +use Symfony\Component\Console\Descriptor\MarkdownDescriptor; + +class MarkdownDescriptorTest extends AbstractDescriptorTest +{ + protected function getDescriptor() + { + return new MarkdownDescriptor(); + } + + protected function getFormat() + { + return 'md'; + } +} diff --git a/vendor/symfony/console/Tests/Descriptor/ObjectsProvider.php b/vendor/symfony/console/Tests/Descriptor/ObjectsProvider.php new file mode 100644 index 0000000..45b3b2f --- /dev/null +++ b/vendor/symfony/console/Tests/Descriptor/ObjectsProvider.php @@ -0,0 +1,77 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Tests\Descriptor; + +use Symfony\Component\Console\Input\InputArgument; +use Symfony\Component\Console\Input\InputDefinition; +use Symfony\Component\Console\Input\InputOption; +use Symfony\Component\Console\Tests\Fixtures\DescriptorApplication1; +use Symfony\Component\Console\Tests\Fixtures\DescriptorApplication2; +use Symfony\Component\Console\Tests\Fixtures\DescriptorCommand1; +use Symfony\Component\Console\Tests\Fixtures\DescriptorCommand2; + +/** + * @author Jean-François Simon + */ +class ObjectsProvider +{ + public static function getInputArguments() + { + return array( + 'input_argument_1' => new InputArgument('argument_name', InputArgument::REQUIRED), + 'input_argument_2' => new InputArgument('argument_name', InputArgument::IS_ARRAY, 'argument description'), + 'input_argument_3' => new InputArgument('argument_name', InputArgument::OPTIONAL, 'argument description', 'default_value'), + 'input_argument_4' => new InputArgument('argument_name', InputArgument::REQUIRED, "multiline\nargument description"), + ); + } + + public static function getInputOptions() + { + return array( + 'input_option_1' => new InputOption('option_name', 'o', InputOption::VALUE_NONE), + 'input_option_2' => new InputOption('option_name', 'o', InputOption::VALUE_OPTIONAL, 'option description', 'default_value'), + 'input_option_3' => new InputOption('option_name', 'o', InputOption::VALUE_REQUIRED, 'option description'), + 'input_option_4' => new InputOption('option_name', 'o', InputOption::VALUE_IS_ARRAY | InputOption::VALUE_OPTIONAL, 'option description', array()), + 'input_option_5' => new InputOption('option_name', 'o', InputOption::VALUE_REQUIRED, "multiline\noption description"), + 'input_option_6' => new InputOption('option_name', array('o', 'O'), InputOption::VALUE_REQUIRED, 'option with multiple shortcuts'), + ); + } + + public static function getInputDefinitions() + { + return array( + 'input_definition_1' => new InputDefinition(), + 'input_definition_2' => new InputDefinition(array(new InputArgument('argument_name', InputArgument::REQUIRED))), + 'input_definition_3' => new InputDefinition(array(new InputOption('option_name', 'o', InputOption::VALUE_NONE))), + 'input_definition_4' => new InputDefinition(array( + new InputArgument('argument_name', InputArgument::REQUIRED), + new InputOption('option_name', 'o', InputOption::VALUE_NONE), + )), + ); + } + + public static function getCommands() + { + return array( + 'command_1' => new DescriptorCommand1(), + 'command_2' => new DescriptorCommand2(), + ); + } + + public static function getApplications() + { + return array( + 'application_1' => new DescriptorApplication1(), + 'application_2' => new DescriptorApplication2(), + ); + } +} diff --git a/vendor/symfony/console/Tests/Descriptor/TextDescriptorTest.php b/vendor/symfony/console/Tests/Descriptor/TextDescriptorTest.php new file mode 100644 index 0000000..350b679 --- /dev/null +++ b/vendor/symfony/console/Tests/Descriptor/TextDescriptorTest.php @@ -0,0 +1,27 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Tests\Descriptor; + +use Symfony\Component\Console\Descriptor\TextDescriptor; + +class TextDescriptorTest extends AbstractDescriptorTest +{ + protected function getDescriptor() + { + return new TextDescriptor(); + } + + protected function getFormat() + { + return 'txt'; + } +} diff --git a/vendor/symfony/console/Tests/Descriptor/XmlDescriptorTest.php b/vendor/symfony/console/Tests/Descriptor/XmlDescriptorTest.php new file mode 100644 index 0000000..59a5d1e --- /dev/null +++ b/vendor/symfony/console/Tests/Descriptor/XmlDescriptorTest.php @@ -0,0 +1,27 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Tests\Descriptor; + +use Symfony\Component\Console\Descriptor\XmlDescriptor; + +class XmlDescriptorTest extends AbstractDescriptorTest +{ + protected function getDescriptor() + { + return new XmlDescriptor(); + } + + protected function getFormat() + { + return 'xml'; + } +} diff --git a/vendor/symfony/console/Tests/Fixtures/BarBucCommand.php b/vendor/symfony/console/Tests/Fixtures/BarBucCommand.php new file mode 100644 index 0000000..52b619e --- /dev/null +++ b/vendor/symfony/console/Tests/Fixtures/BarBucCommand.php @@ -0,0 +1,11 @@ +setName('bar:buc'); + } +} diff --git a/vendor/symfony/console/Tests/Fixtures/DescriptorApplication1.php b/vendor/symfony/console/Tests/Fixtures/DescriptorApplication1.php new file mode 100644 index 0000000..132b6d5 --- /dev/null +++ b/vendor/symfony/console/Tests/Fixtures/DescriptorApplication1.php @@ -0,0 +1,18 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Tests\Fixtures; + +use Symfony\Component\Console\Application; + +class DescriptorApplication1 extends Application +{ +} diff --git a/vendor/symfony/console/Tests/Fixtures/DescriptorApplication2.php b/vendor/symfony/console/Tests/Fixtures/DescriptorApplication2.php new file mode 100644 index 0000000..ff55135 --- /dev/null +++ b/vendor/symfony/console/Tests/Fixtures/DescriptorApplication2.php @@ -0,0 +1,24 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Tests\Fixtures; + +use Symfony\Component\Console\Application; + +class DescriptorApplication2 extends Application +{ + public function __construct() + { + parent::__construct('My Symfony application', 'v1.0'); + $this->add(new DescriptorCommand1()); + $this->add(new DescriptorCommand2()); + } +} diff --git a/vendor/symfony/console/Tests/Fixtures/DescriptorCommand1.php b/vendor/symfony/console/Tests/Fixtures/DescriptorCommand1.php new file mode 100644 index 0000000..ede05d7 --- /dev/null +++ b/vendor/symfony/console/Tests/Fixtures/DescriptorCommand1.php @@ -0,0 +1,27 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Tests\Fixtures; + +use Symfony\Component\Console\Command\Command; + +class DescriptorCommand1 extends Command +{ + protected function configure() + { + $this + ->setName('descriptor:command1') + ->setAliases(array('alias1', 'alias2')) + ->setDescription('command 1 description') + ->setHelp('command 1 help') + ; + } +} diff --git a/vendor/symfony/console/Tests/Fixtures/DescriptorCommand2.php b/vendor/symfony/console/Tests/Fixtures/DescriptorCommand2.php new file mode 100644 index 0000000..51106b9 --- /dev/null +++ b/vendor/symfony/console/Tests/Fixtures/DescriptorCommand2.php @@ -0,0 +1,32 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Tests\Fixtures; + +use Symfony\Component\Console\Command\Command; +use Symfony\Component\Console\Input\InputArgument; +use Symfony\Component\Console\Input\InputOption; + +class DescriptorCommand2 extends Command +{ + protected function configure() + { + $this + ->setName('descriptor:command2') + ->setDescription('command 2 description') + ->setHelp('command 2 help') + ->addUsage('-o|--option_name ') + ->addUsage('') + ->addArgument('argument_name', InputArgument::REQUIRED) + ->addOption('option_name', 'o', InputOption::VALUE_NONE) + ; + } +} diff --git a/vendor/symfony/console/Tests/Fixtures/DummyOutput.php b/vendor/symfony/console/Tests/Fixtures/DummyOutput.php new file mode 100644 index 0000000..0070c0a --- /dev/null +++ b/vendor/symfony/console/Tests/Fixtures/DummyOutput.php @@ -0,0 +1,36 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Tests\Fixtures; + +use Symfony\Component\Console\Output\BufferedOutput; + +/** + * Dummy output. + * + * @author Kévin Dunglas + */ +class DummyOutput extends BufferedOutput +{ + /** + * @return array + */ + public function getLogs() + { + $logs = array(); + foreach (explode("\n", trim($this->fetch())) as $message) { + preg_match('/^\[(.*)\] (.*)/', $message, $matches); + $logs[] = sprintf('%s %s', $matches[1], $matches[2]); + } + + return $logs; + } +} diff --git a/vendor/symfony/console/Tests/Fixtures/Foo1Command.php b/vendor/symfony/console/Tests/Fixtures/Foo1Command.php new file mode 100644 index 0000000..254162f --- /dev/null +++ b/vendor/symfony/console/Tests/Fixtures/Foo1Command.php @@ -0,0 +1,26 @@ +setName('foo:bar1') + ->setDescription('The foo:bar1 command') + ->setAliases(array('afoobar1')) + ; + } + + protected function execute(InputInterface $input, OutputInterface $output) + { + $this->input = $input; + $this->output = $output; + } +} diff --git a/vendor/symfony/console/Tests/Fixtures/Foo2Command.php b/vendor/symfony/console/Tests/Fixtures/Foo2Command.php new file mode 100644 index 0000000..8071dc8 --- /dev/null +++ b/vendor/symfony/console/Tests/Fixtures/Foo2Command.php @@ -0,0 +1,21 @@ +setName('foo1:bar') + ->setDescription('The foo1:bar command') + ->setAliases(array('afoobar2')) + ; + } + + protected function execute(InputInterface $input, OutputInterface $output) + { + } +} diff --git a/vendor/symfony/console/Tests/Fixtures/Foo3Command.php b/vendor/symfony/console/Tests/Fixtures/Foo3Command.php new file mode 100644 index 0000000..6c890fa --- /dev/null +++ b/vendor/symfony/console/Tests/Fixtures/Foo3Command.php @@ -0,0 +1,29 @@ +setName('foo3:bar') + ->setDescription('The foo3:bar command') + ; + } + + protected function execute(InputInterface $input, OutputInterface $output) + { + try { + try { + throw new \Exception('First exception

    this is html

    '); + } catch (\Exception $e) { + throw new \Exception('Second exception comment', 0, $e); + } + } catch (\Exception $e) { + throw new \Exception('Third exception comment', 0, $e); + } + } +} diff --git a/vendor/symfony/console/Tests/Fixtures/Foo4Command.php b/vendor/symfony/console/Tests/Fixtures/Foo4Command.php new file mode 100644 index 0000000..1c54639 --- /dev/null +++ b/vendor/symfony/console/Tests/Fixtures/Foo4Command.php @@ -0,0 +1,11 @@ +setName('foo3:bar:toh'); + } +} diff --git a/vendor/symfony/console/Tests/Fixtures/Foo5Command.php b/vendor/symfony/console/Tests/Fixtures/Foo5Command.php new file mode 100644 index 0000000..a1c6082 --- /dev/null +++ b/vendor/symfony/console/Tests/Fixtures/Foo5Command.php @@ -0,0 +1,10 @@ +setName('foo:bar') + ->setDescription('The foo:bar command') + ->setAliases(array('afoobar')) + ; + } + + protected function interact(InputInterface $input, OutputInterface $output) + { + $output->writeln('interact called'); + } + + protected function execute(InputInterface $input, OutputInterface $output) + { + $this->input = $input; + $this->output = $output; + + $output->writeln('called'); + } +} diff --git a/vendor/symfony/console/Tests/Fixtures/FooSubnamespaced1Command.php b/vendor/symfony/console/Tests/Fixtures/FooSubnamespaced1Command.php new file mode 100644 index 0000000..fc50c72 --- /dev/null +++ b/vendor/symfony/console/Tests/Fixtures/FooSubnamespaced1Command.php @@ -0,0 +1,26 @@ +setName('foo:bar:baz') + ->setDescription('The foo:bar:baz command') + ->setAliases(array('foobarbaz')) + ; + } + + protected function execute(InputInterface $input, OutputInterface $output) + { + $this->input = $input; + $this->output = $output; + } +} diff --git a/vendor/symfony/console/Tests/Fixtures/FooSubnamespaced2Command.php b/vendor/symfony/console/Tests/Fixtures/FooSubnamespaced2Command.php new file mode 100644 index 0000000..1cf31ff --- /dev/null +++ b/vendor/symfony/console/Tests/Fixtures/FooSubnamespaced2Command.php @@ -0,0 +1,26 @@ +setName('foo:go:bret') + ->setDescription('The foo:bar:go command') + ->setAliases(array('foobargo')) + ; + } + + protected function execute(InputInterface $input, OutputInterface $output) + { + $this->input = $input; + $this->output = $output; + } +} diff --git a/vendor/symfony/console/Tests/Fixtures/FoobarCommand.php b/vendor/symfony/console/Tests/Fixtures/FoobarCommand.php new file mode 100644 index 0000000..9681628 --- /dev/null +++ b/vendor/symfony/console/Tests/Fixtures/FoobarCommand.php @@ -0,0 +1,25 @@ +setName('foobar:foo') + ->setDescription('The foobar:foo command') + ; + } + + protected function execute(InputInterface $input, OutputInterface $output) + { + $this->input = $input; + $this->output = $output; + } +} diff --git a/vendor/symfony/console/Tests/Fixtures/Style/SymfonyStyle/command/command_0.php b/vendor/symfony/console/Tests/Fixtures/Style/SymfonyStyle/command/command_0.php new file mode 100644 index 0000000..8fe7c07 --- /dev/null +++ b/vendor/symfony/console/Tests/Fixtures/Style/SymfonyStyle/command/command_0.php @@ -0,0 +1,11 @@ +caution('Lorem ipsum dolor sit amet'); +}; diff --git a/vendor/symfony/console/Tests/Fixtures/Style/SymfonyStyle/command/command_1.php b/vendor/symfony/console/Tests/Fixtures/Style/SymfonyStyle/command/command_1.php new file mode 100644 index 0000000..e5c700d --- /dev/null +++ b/vendor/symfony/console/Tests/Fixtures/Style/SymfonyStyle/command/command_1.php @@ -0,0 +1,13 @@ +title('Title'); + $output->warning('Lorem ipsum dolor sit amet'); + $output->title('Title'); +}; diff --git a/vendor/symfony/console/Tests/Fixtures/Style/SymfonyStyle/command/command_2.php b/vendor/symfony/console/Tests/Fixtures/Style/SymfonyStyle/command/command_2.php new file mode 100644 index 0000000..791b626 --- /dev/null +++ b/vendor/symfony/console/Tests/Fixtures/Style/SymfonyStyle/command/command_2.php @@ -0,0 +1,16 @@ +warning('Warning'); + $output->caution('Caution'); + $output->error('Error'); + $output->success('Success'); + $output->note('Note'); + $output->block('Custom block', 'CUSTOM', 'fg=white;bg=green', 'X ', true); +}; diff --git a/vendor/symfony/console/Tests/Fixtures/Style/SymfonyStyle/command/command_3.php b/vendor/symfony/console/Tests/Fixtures/Style/SymfonyStyle/command/command_3.php new file mode 100644 index 0000000..99253a6 --- /dev/null +++ b/vendor/symfony/console/Tests/Fixtures/Style/SymfonyStyle/command/command_3.php @@ -0,0 +1,12 @@ +title('First title'); + $output->title('Second title'); +}; diff --git a/vendor/symfony/console/Tests/Fixtures/Style/SymfonyStyle/command/command_4.php b/vendor/symfony/console/Tests/Fixtures/Style/SymfonyStyle/command/command_4.php new file mode 100644 index 0000000..0c5d3fb --- /dev/null +++ b/vendor/symfony/console/Tests/Fixtures/Style/SymfonyStyle/command/command_4.php @@ -0,0 +1,34 @@ +write('Lorem ipsum dolor sit amet'); + $output->title('First title'); + + $output->writeln('Lorem ipsum dolor sit amet'); + $output->title('Second title'); + + $output->write('Lorem ipsum dolor sit amet'); + $output->write(''); + $output->title('Third title'); + + //Ensure edge case by appending empty strings to history: + $output->write('Lorem ipsum dolor sit amet'); + $output->write(array('', '', '')); + $output->title('Fourth title'); + + //Ensure have manual control over number of blank lines: + $output->writeln('Lorem ipsum dolor sit amet'); + $output->writeln(array('', '')); //Should append an extra blank line + $output->title('Fifth title'); + + $output->writeln('Lorem ipsum dolor sit amet'); + $output->newLine(2); //Should append an extra blank line + $output->title('Fifth title'); +}; diff --git a/vendor/symfony/console/Tests/Fixtures/Style/SymfonyStyle/command/command_5.php b/vendor/symfony/console/Tests/Fixtures/Style/SymfonyStyle/command/command_5.php new file mode 100644 index 0000000..4543ad8 --- /dev/null +++ b/vendor/symfony/console/Tests/Fixtures/Style/SymfonyStyle/command/command_5.php @@ -0,0 +1,29 @@ +writeln('Lorem ipsum dolor sit amet'); + $output->listing(array( + 'Lorem ipsum dolor sit amet', + 'consectetur adipiscing elit', + )); + + //Even using write: + $output->write('Lorem ipsum dolor sit amet'); + $output->listing(array( + 'Lorem ipsum dolor sit amet', + 'consectetur adipiscing elit', + )); + + $output->write('Lorem ipsum dolor sit amet'); + $output->text(array( + 'Lorem ipsum dolor sit amet', + 'consectetur adipiscing elit', + )); +}; diff --git a/vendor/symfony/console/Tests/Fixtures/Style/SymfonyStyle/command/command_6.php b/vendor/symfony/console/Tests/Fixtures/Style/SymfonyStyle/command/command_6.php new file mode 100644 index 0000000..8031ec9 --- /dev/null +++ b/vendor/symfony/console/Tests/Fixtures/Style/SymfonyStyle/command/command_6.php @@ -0,0 +1,16 @@ +listing(array( + 'Lorem ipsum dolor sit amet', + 'consectetur adipiscing elit', + )); + $output->success('Lorem ipsum dolor sit amet'); +}; diff --git a/vendor/symfony/console/Tests/Fixtures/Style/SymfonyStyle/command/command_7.php b/vendor/symfony/console/Tests/Fixtures/Style/SymfonyStyle/command/command_7.php new file mode 100644 index 0000000..203eb5b --- /dev/null +++ b/vendor/symfony/console/Tests/Fixtures/Style/SymfonyStyle/command/command_7.php @@ -0,0 +1,15 @@ +title('Title'); + $output->askHidden('Hidden question'); + $output->choice('Choice question with default', array('choice1', 'choice2'), 'choice1'); + $output->confirm('Confirmation with yes default', true); + $output->text('Duis aute irure dolor in reprehenderit in voluptate velit esse'); +}; diff --git a/vendor/symfony/console/Tests/Fixtures/Style/SymfonyStyle/output/output_0.txt b/vendor/symfony/console/Tests/Fixtures/Style/SymfonyStyle/output/output_0.txt new file mode 100644 index 0000000..a42e0f7 --- /dev/null +++ b/vendor/symfony/console/Tests/Fixtures/Style/SymfonyStyle/output/output_0.txt @@ -0,0 +1,3 @@ + + ! [CAUTION] Lorem ipsum dolor sit amet + diff --git a/vendor/symfony/console/Tests/Fixtures/Style/SymfonyStyle/output/output_1.txt b/vendor/symfony/console/Tests/Fixtures/Style/SymfonyStyle/output/output_1.txt new file mode 100644 index 0000000..334875f --- /dev/null +++ b/vendor/symfony/console/Tests/Fixtures/Style/SymfonyStyle/output/output_1.txt @@ -0,0 +1,9 @@ + +Title +===== + + [WARNING] Lorem ipsum dolor sit amet + +Title +===== + diff --git a/vendor/symfony/console/Tests/Fixtures/Style/SymfonyStyle/output/output_2.txt b/vendor/symfony/console/Tests/Fixtures/Style/SymfonyStyle/output/output_2.txt new file mode 100644 index 0000000..ca60976 --- /dev/null +++ b/vendor/symfony/console/Tests/Fixtures/Style/SymfonyStyle/output/output_2.txt @@ -0,0 +1,13 @@ + + [WARNING] Warning + + ! [CAUTION] Caution + + [ERROR] Error + + [OK] Success + + ! [NOTE] Note + +X [CUSTOM] Custom block + diff --git a/vendor/symfony/console/Tests/Fixtures/Style/SymfonyStyle/output/output_3.txt b/vendor/symfony/console/Tests/Fixtures/Style/SymfonyStyle/output/output_3.txt new file mode 100644 index 0000000..f4b6d58 --- /dev/null +++ b/vendor/symfony/console/Tests/Fixtures/Style/SymfonyStyle/output/output_3.txt @@ -0,0 +1,7 @@ + +First title +=========== + +Second title +============ + diff --git a/vendor/symfony/console/Tests/Fixtures/Style/SymfonyStyle/output/output_4.txt b/vendor/symfony/console/Tests/Fixtures/Style/SymfonyStyle/output/output_4.txt new file mode 100644 index 0000000..2646d85 --- /dev/null +++ b/vendor/symfony/console/Tests/Fixtures/Style/SymfonyStyle/output/output_4.txt @@ -0,0 +1,32 @@ +Lorem ipsum dolor sit amet + +First title +=========== + +Lorem ipsum dolor sit amet + +Second title +============ + +Lorem ipsum dolor sit amet + +Third title +=========== + +Lorem ipsum dolor sit amet + +Fourth title +============ + +Lorem ipsum dolor sit amet + + +Fifth title +=========== + +Lorem ipsum dolor sit amet + + +Fifth title +=========== + diff --git a/vendor/symfony/console/Tests/Fixtures/Style/SymfonyStyle/output/output_5.txt b/vendor/symfony/console/Tests/Fixtures/Style/SymfonyStyle/output/output_5.txt new file mode 100644 index 0000000..910240f --- /dev/null +++ b/vendor/symfony/console/Tests/Fixtures/Style/SymfonyStyle/output/output_5.txt @@ -0,0 +1,11 @@ +Lorem ipsum dolor sit amet + * Lorem ipsum dolor sit amet + * consectetur adipiscing elit + +Lorem ipsum dolor sit amet + * Lorem ipsum dolor sit amet + * consectetur adipiscing elit + +Lorem ipsum dolor sit amet + // Lorem ipsum dolor sit amet + // consectetur adipiscing elit diff --git a/vendor/symfony/console/Tests/Fixtures/Style/SymfonyStyle/output/output_6.txt b/vendor/symfony/console/Tests/Fixtures/Style/SymfonyStyle/output/output_6.txt new file mode 100644 index 0000000..5f2d33c --- /dev/null +++ b/vendor/symfony/console/Tests/Fixtures/Style/SymfonyStyle/output/output_6.txt @@ -0,0 +1,6 @@ + + * Lorem ipsum dolor sit amet + * consectetur adipiscing elit + + [OK] Lorem ipsum dolor sit amet + diff --git a/vendor/symfony/console/Tests/Fixtures/Style/SymfonyStyle/output/output_7.txt b/vendor/symfony/console/Tests/Fixtures/Style/SymfonyStyle/output/output_7.txt new file mode 100644 index 0000000..ab18e5d --- /dev/null +++ b/vendor/symfony/console/Tests/Fixtures/Style/SymfonyStyle/output/output_7.txt @@ -0,0 +1,5 @@ + +Title +===== + + // Duis aute irure dolor in reprehenderit in voluptate velit esse diff --git a/vendor/symfony/console/Tests/Fixtures/TestCommand.php b/vendor/symfony/console/Tests/Fixtures/TestCommand.php new file mode 100644 index 0000000..dcd3273 --- /dev/null +++ b/vendor/symfony/console/Tests/Fixtures/TestCommand.php @@ -0,0 +1,28 @@ +setName('namespace:name') + ->setAliases(array('name')) + ->setDescription('description') + ->setHelp('help') + ; + } + + protected function execute(InputInterface $input, OutputInterface $output) + { + $output->writeln('execute called'); + } + + protected function interact(InputInterface $input, OutputInterface $output) + { + $output->writeln('interact called'); + } +} diff --git a/vendor/symfony/console/Tests/Fixtures/application_1.json b/vendor/symfony/console/Tests/Fixtures/application_1.json new file mode 100644 index 0000000..b17b38d --- /dev/null +++ b/vendor/symfony/console/Tests/Fixtures/application_1.json @@ -0,0 +1 @@ +{"commands":[{"name":"help","usage":["help [--xml] [--format FORMAT] [--raw] [--] []"],"description":"Displays help for a command","help":"The help<\/info> command displays help for a given command:\n\n php app\/console help list<\/info>\n\nYou can also output the help in other formats by using the --format<\/comment> option:\n\n php app\/console help --format=xml list<\/info>\n\nTo display the list of available commands, please use the list<\/info> command.","definition":{"arguments":{"command_name":{"name":"command_name","is_required":false,"is_array":false,"description":"The command name","default":"help"}},"options":{"xml":{"name":"--xml","shortcut":"","accept_value":false,"is_value_required":false,"is_multiple":false,"description":"To output help as XML","default":false},"format":{"name":"--format","shortcut":"","accept_value":true,"is_value_required":true,"is_multiple":false,"description":"The output format (txt, xml, json, or md)","default":"txt"},"raw":{"name":"--raw","shortcut":"","accept_value":false,"is_value_required":false,"is_multiple":false,"description":"To output raw command help","default":false},"help":{"name":"--help","shortcut":"-h","accept_value":false,"is_value_required":false,"is_multiple":false,"description":"Display this help message","default":false},"quiet":{"name":"--quiet","shortcut":"-q","accept_value":false,"is_value_required":false,"is_multiple":false,"description":"Do not output any message","default":false},"verbose":{"name":"--verbose","shortcut":"-v|-vv|-vvv","accept_value":false,"is_value_required":false,"is_multiple":false,"description":"Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug","default":false},"version":{"name":"--version","shortcut":"-V","accept_value":false,"is_value_required":false,"is_multiple":false,"description":"Display this application version","default":false},"ansi":{"name":"--ansi","shortcut":"","accept_value":false,"is_value_required":false,"is_multiple":false,"description":"Force ANSI output","default":false},"no-ansi":{"name":"--no-ansi","shortcut":"","accept_value":false,"is_value_required":false,"is_multiple":false,"description":"Disable ANSI output","default":false},"no-interaction":{"name":"--no-interaction","shortcut":"-n","accept_value":false,"is_value_required":false,"is_multiple":false,"description":"Do not ask any interactive question","default":false}}}},{"name":"list","usage":["list [--xml] [--raw] [--format FORMAT] [--] []"],"description":"Lists commands","help":"The list<\/info> command lists all commands:\n\n php app\/console list<\/info>\n\nYou can also display the commands for a specific namespace:\n\n php app\/console list test<\/info>\n\nYou can also output the information in other formats by using the --format<\/comment> option:\n\n php app\/console list --format=xml<\/info>\n\nIt's also possible to get raw list of commands (useful for embedding command runner):\n\n php app\/console list --raw<\/info>","definition":{"arguments":{"namespace":{"name":"namespace","is_required":false,"is_array":false,"description":"The namespace name","default":null}},"options":{"xml":{"name":"--xml","shortcut":"","accept_value":false,"is_value_required":false,"is_multiple":false,"description":"To output list as XML","default":false},"raw":{"name":"--raw","shortcut":"","accept_value":false,"is_value_required":false,"is_multiple":false,"description":"To output raw command list","default":false},"format":{"name":"--format","shortcut":"","accept_value":true,"is_value_required":true,"is_multiple":false,"description":"The output format (txt, xml, json, or md)","default":"txt"}}}}],"namespaces":[{"id":"_global","commands":["help","list"]}]} diff --git a/vendor/symfony/console/Tests/Fixtures/application_1.md b/vendor/symfony/console/Tests/Fixtures/application_1.md new file mode 100644 index 0000000..82a605d --- /dev/null +++ b/vendor/symfony/console/Tests/Fixtures/application_1.md @@ -0,0 +1,201 @@ +UNKNOWN +======= + +* help +* list + +help +---- + +* Description: Displays help for a command +* Usage: + + * `help [--xml] [--format FORMAT] [--raw] [--] []` + +The help command displays help for a given command: + + php app/console help list + +You can also output the help in other formats by using the --format option: + + php app/console help --format=xml list + +To display the list of available commands, please use the list command. + +### Arguments: + +**command_name:** + +* Name: command_name +* Is required: no +* Is array: no +* Description: The command name +* Default: `'help'` + +### Options: + +**xml:** + +* Name: `--xml` +* Shortcut: +* Accept value: no +* Is value required: no +* Is multiple: no +* Description: To output help as XML +* Default: `false` + +**format:** + +* Name: `--format` +* Shortcut: +* Accept value: yes +* Is value required: yes +* Is multiple: no +* Description: The output format (txt, xml, json, or md) +* Default: `'txt'` + +**raw:** + +* Name: `--raw` +* Shortcut: +* Accept value: no +* Is value required: no +* Is multiple: no +* Description: To output raw command help +* Default: `false` + +**help:** + +* Name: `--help` +* Shortcut: `-h` +* Accept value: no +* Is value required: no +* Is multiple: no +* Description: Display this help message +* Default: `false` + +**quiet:** + +* Name: `--quiet` +* Shortcut: `-q` +* Accept value: no +* Is value required: no +* Is multiple: no +* Description: Do not output any message +* Default: `false` + +**verbose:** + +* Name: `--verbose` +* Shortcut: `-v|-vv|-vvv` +* Accept value: no +* Is value required: no +* Is multiple: no +* Description: Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug +* Default: `false` + +**version:** + +* Name: `--version` +* Shortcut: `-V` +* Accept value: no +* Is value required: no +* Is multiple: no +* Description: Display this application version +* Default: `false` + +**ansi:** + +* Name: `--ansi` +* Shortcut: +* Accept value: no +* Is value required: no +* Is multiple: no +* Description: Force ANSI output +* Default: `false` + +**no-ansi:** + +* Name: `--no-ansi` +* Shortcut: +* Accept value: no +* Is value required: no +* Is multiple: no +* Description: Disable ANSI output +* Default: `false` + +**no-interaction:** + +* Name: `--no-interaction` +* Shortcut: `-n` +* Accept value: no +* Is value required: no +* Is multiple: no +* Description: Do not ask any interactive question +* Default: `false` + +list +---- + +* Description: Lists commands +* Usage: + + * `list [--xml] [--raw] [--format FORMAT] [--] []` + +The list command lists all commands: + + php app/console list + +You can also display the commands for a specific namespace: + + php app/console list test + +You can also output the information in other formats by using the --format option: + + php app/console list --format=xml + +It's also possible to get raw list of commands (useful for embedding command runner): + + php app/console list --raw + +### Arguments: + +**namespace:** + +* Name: namespace +* Is required: no +* Is array: no +* Description: The namespace name +* Default: `NULL` + +### Options: + +**xml:** + +* Name: `--xml` +* Shortcut: +* Accept value: no +* Is value required: no +* Is multiple: no +* Description: To output list as XML +* Default: `false` + +**raw:** + +* Name: `--raw` +* Shortcut: +* Accept value: no +* Is value required: no +* Is multiple: no +* Description: To output raw command list +* Default: `false` + +**format:** + +* Name: `--format` +* Shortcut: +* Accept value: yes +* Is value required: yes +* Is multiple: no +* Description: The output format (txt, xml, json, or md) +* Default: `'txt'` diff --git a/vendor/symfony/console/Tests/Fixtures/application_1.txt b/vendor/symfony/console/Tests/Fixtures/application_1.txt new file mode 100644 index 0000000..c4cf8f2 --- /dev/null +++ b/vendor/symfony/console/Tests/Fixtures/application_1.txt @@ -0,0 +1,17 @@ +Console Tool + +Usage: + command [options] [arguments] + +Options: + -h, --help Display this help message + -q, --quiet Do not output any message + -V, --version Display this application version + --ansi Force ANSI output + --no-ansi Disable ANSI output + -n, --no-interaction Do not ask any interactive question + -v|vv|vvv, --verbose Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug + +Available commands: + help Displays help for a command + list Lists commands diff --git a/vendor/symfony/console/Tests/Fixtures/application_1.xml b/vendor/symfony/console/Tests/Fixtures/application_1.xml new file mode 100644 index 0000000..35d1db4 --- /dev/null +++ b/vendor/symfony/console/Tests/Fixtures/application_1.xml @@ -0,0 +1,110 @@ + + + + + + help [--xml] [--format FORMAT] [--raw] [--] [<command_name>] + + Displays help for a command + The <info>help</info> command displays help for a given command: + + <info>php app/console help list</info> + + You can also output the help in other formats by using the <comment>--format</comment> option: + + <info>php app/console help --format=xml list</info> + + To display the list of available commands, please use the <info>list</info> command. + + + The command name + + help + + + + + + + + + + + + + + + + + + + list [--xml] [--raw] [--format FORMAT] [--] [<namespace>] + + Lists commands + The <info>list</info> command lists all commands: + + <info>php app/console list</info> + + You can also display the commands for a specific namespace: + + <info>php app/console list test</info> + + You can also output the information in other formats by using the <comment>--format</comment> option: + + <info>php app/console list --format=xml</info> + + It's also possible to get raw list of commands (useful for embedding command runner): + + <info>php app/console list --raw</info> + + + The namespace name + + + + + + + + + + + + + help + list + + + diff --git a/vendor/symfony/console/Tests/Fixtures/application_2.json b/vendor/symfony/console/Tests/Fixtures/application_2.json new file mode 100644 index 0000000..e47a7a9 --- /dev/null +++ b/vendor/symfony/console/Tests/Fixtures/application_2.json @@ -0,0 +1 @@ +{"commands":[{"name":"help","usage":["help [--xml] [--format FORMAT] [--raw] [--] []"],"description":"Displays help for a command","help":"The help<\/info> command displays help for a given command:\n\n php app\/console help list<\/info>\n\nYou can also output the help in other formats by using the --format<\/comment> option:\n\n php app\/console help --format=xml list<\/info>\n\nTo display the list of available commands, please use the list<\/info> command.","definition":{"arguments":{"command_name":{"name":"command_name","is_required":false,"is_array":false,"description":"The command name","default":"help"}},"options":{"xml":{"name":"--xml","shortcut":"","accept_value":false,"is_value_required":false,"is_multiple":false,"description":"To output help as XML","default":false},"format":{"name":"--format","shortcut":"","accept_value":true,"is_value_required":true,"is_multiple":false,"description":"The output format (txt, xml, json, or md)","default":"txt"},"raw":{"name":"--raw","shortcut":"","accept_value":false,"is_value_required":false,"is_multiple":false,"description":"To output raw command help","default":false},"help":{"name":"--help","shortcut":"-h","accept_value":false,"is_value_required":false,"is_multiple":false,"description":"Display this help message","default":false},"quiet":{"name":"--quiet","shortcut":"-q","accept_value":false,"is_value_required":false,"is_multiple":false,"description":"Do not output any message","default":false},"verbose":{"name":"--verbose","shortcut":"-v|-vv|-vvv","accept_value":false,"is_value_required":false,"is_multiple":false,"description":"Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug","default":false},"version":{"name":"--version","shortcut":"-V","accept_value":false,"is_value_required":false,"is_multiple":false,"description":"Display this application version","default":false},"ansi":{"name":"--ansi","shortcut":"","accept_value":false,"is_value_required":false,"is_multiple":false,"description":"Force ANSI output","default":false},"no-ansi":{"name":"--no-ansi","shortcut":"","accept_value":false,"is_value_required":false,"is_multiple":false,"description":"Disable ANSI output","default":false},"no-interaction":{"name":"--no-interaction","shortcut":"-n","accept_value":false,"is_value_required":false,"is_multiple":false,"description":"Do not ask any interactive question","default":false}}}},{"name":"list","usage":["list [--xml] [--raw] [--format FORMAT] [--] []"],"description":"Lists commands","help":"The list<\/info> command lists all commands:\n\n php app\/console list<\/info>\n\nYou can also display the commands for a specific namespace:\n\n php app\/console list test<\/info>\n\nYou can also output the information in other formats by using the --format<\/comment> option:\n\n php app\/console list --format=xml<\/info>\n\nIt's also possible to get raw list of commands (useful for embedding command runner):\n\n php app\/console list --raw<\/info>","definition":{"arguments":{"namespace":{"name":"namespace","is_required":false,"is_array":false,"description":"The namespace name","default":null}},"options":{"xml":{"name":"--xml","shortcut":"","accept_value":false,"is_value_required":false,"is_multiple":false,"description":"To output list as XML","default":false},"raw":{"name":"--raw","shortcut":"","accept_value":false,"is_value_required":false,"is_multiple":false,"description":"To output raw command list","default":false},"format":{"name":"--format","shortcut":"","accept_value":true,"is_value_required":true,"is_multiple":false,"description":"The output format (txt, xml, json, or md)","default":"txt"}}}},{"name":"descriptor:command1","usage":["descriptor:command1", "alias1", "alias2"],"description":"command 1 description","help":"command 1 help","definition":{"arguments":[],"options":{"help":{"name":"--help","shortcut":"-h","accept_value":false,"is_value_required":false,"is_multiple":false,"description":"Display this help message","default":false},"quiet":{"name":"--quiet","shortcut":"-q","accept_value":false,"is_value_required":false,"is_multiple":false,"description":"Do not output any message","default":false},"verbose":{"name":"--verbose","shortcut":"-v|-vv|-vvv","accept_value":false,"is_value_required":false,"is_multiple":false,"description":"Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug","default":false},"version":{"name":"--version","shortcut":"-V","accept_value":false,"is_value_required":false,"is_multiple":false,"description":"Display this application version","default":false},"ansi":{"name":"--ansi","shortcut":"","accept_value":false,"is_value_required":false,"is_multiple":false,"description":"Force ANSI output","default":false},"no-ansi":{"name":"--no-ansi","shortcut":"","accept_value":false,"is_value_required":false,"is_multiple":false,"description":"Disable ANSI output","default":false},"no-interaction":{"name":"--no-interaction","shortcut":"-n","accept_value":false,"is_value_required":false,"is_multiple":false,"description":"Do not ask any interactive question","default":false}}}},{"name":"descriptor:command2","usage":["descriptor:command2 [-o|--option_name] [--] ", "descriptor:command2 -o|--option_name ", "descriptor:command2 "],"description":"command 2 description","help":"command 2 help","definition":{"arguments":{"argument_name":{"name":"argument_name","is_required":true,"is_array":false,"description":"","default":null}},"options":{"option_name":{"name":"--option_name","shortcut":"-o","accept_value":false,"is_value_required":false,"is_multiple":false,"description":"","default":false},"help":{"name":"--help","shortcut":"-h","accept_value":false,"is_value_required":false,"is_multiple":false,"description":"Display this help message","default":false},"quiet":{"name":"--quiet","shortcut":"-q","accept_value":false,"is_value_required":false,"is_multiple":false,"description":"Do not output any message","default":false},"verbose":{"name":"--verbose","shortcut":"-v|-vv|-vvv","accept_value":false,"is_value_required":false,"is_multiple":false,"description":"Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug","default":false},"version":{"name":"--version","shortcut":"-V","accept_value":false,"is_value_required":false,"is_multiple":false,"description":"Display this application version","default":false},"ansi":{"name":"--ansi","shortcut":"","accept_value":false,"is_value_required":false,"is_multiple":false,"description":"Force ANSI output","default":false},"no-ansi":{"name":"--no-ansi","shortcut":"","accept_value":false,"is_value_required":false,"is_multiple":false,"description":"Disable ANSI output","default":false},"no-interaction":{"name":"--no-interaction","shortcut":"-n","accept_value":false,"is_value_required":false,"is_multiple":false,"description":"Do not ask any interactive question","default":false}}}}],"namespaces":[{"id":"_global","commands":["alias1","alias2","help","list"]},{"id":"descriptor","commands":["descriptor:command1","descriptor:command2"]}]} \ No newline at end of file diff --git a/vendor/symfony/console/Tests/Fixtures/application_2.md b/vendor/symfony/console/Tests/Fixtures/application_2.md new file mode 100644 index 0000000..f031c9e --- /dev/null +++ b/vendor/symfony/console/Tests/Fixtures/application_2.md @@ -0,0 +1,396 @@ +My Symfony application +====================== + +* alias1 +* alias2 +* help +* list + +**descriptor:** + +* descriptor:command1 +* descriptor:command2 + +help +---- + +* Description: Displays help for a command +* Usage: + + * `help [--xml] [--format FORMAT] [--raw] [--] []` + +The help command displays help for a given command: + + php app/console help list + +You can also output the help in other formats by using the --format option: + + php app/console help --format=xml list + +To display the list of available commands, please use the list command. + +### Arguments: + +**command_name:** + +* Name: command_name +* Is required: no +* Is array: no +* Description: The command name +* Default: `'help'` + +### Options: + +**xml:** + +* Name: `--xml` +* Shortcut: +* Accept value: no +* Is value required: no +* Is multiple: no +* Description: To output help as XML +* Default: `false` + +**format:** + +* Name: `--format` +* Shortcut: +* Accept value: yes +* Is value required: yes +* Is multiple: no +* Description: The output format (txt, xml, json, or md) +* Default: `'txt'` + +**raw:** + +* Name: `--raw` +* Shortcut: +* Accept value: no +* Is value required: no +* Is multiple: no +* Description: To output raw command help +* Default: `false` + +**help:** + +* Name: `--help` +* Shortcut: `-h` +* Accept value: no +* Is value required: no +* Is multiple: no +* Description: Display this help message +* Default: `false` + +**quiet:** + +* Name: `--quiet` +* Shortcut: `-q` +* Accept value: no +* Is value required: no +* Is multiple: no +* Description: Do not output any message +* Default: `false` + +**verbose:** + +* Name: `--verbose` +* Shortcut: `-v|-vv|-vvv` +* Accept value: no +* Is value required: no +* Is multiple: no +* Description: Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug +* Default: `false` + +**version:** + +* Name: `--version` +* Shortcut: `-V` +* Accept value: no +* Is value required: no +* Is multiple: no +* Description: Display this application version +* Default: `false` + +**ansi:** + +* Name: `--ansi` +* Shortcut: +* Accept value: no +* Is value required: no +* Is multiple: no +* Description: Force ANSI output +* Default: `false` + +**no-ansi:** + +* Name: `--no-ansi` +* Shortcut: +* Accept value: no +* Is value required: no +* Is multiple: no +* Description: Disable ANSI output +* Default: `false` + +**no-interaction:** + +* Name: `--no-interaction` +* Shortcut: `-n` +* Accept value: no +* Is value required: no +* Is multiple: no +* Description: Do not ask any interactive question +* Default: `false` + +list +---- + +* Description: Lists commands +* Usage: + + * `list [--xml] [--raw] [--format FORMAT] [--] []` + +The list command lists all commands: + + php app/console list + +You can also display the commands for a specific namespace: + + php app/console list test + +You can also output the information in other formats by using the --format option: + + php app/console list --format=xml + +It's also possible to get raw list of commands (useful for embedding command runner): + + php app/console list --raw + +### Arguments: + +**namespace:** + +* Name: namespace +* Is required: no +* Is array: no +* Description: The namespace name +* Default: `NULL` + +### Options: + +**xml:** + +* Name: `--xml` +* Shortcut: +* Accept value: no +* Is value required: no +* Is multiple: no +* Description: To output list as XML +* Default: `false` + +**raw:** + +* Name: `--raw` +* Shortcut: +* Accept value: no +* Is value required: no +* Is multiple: no +* Description: To output raw command list +* Default: `false` + +**format:** + +* Name: `--format` +* Shortcut: +* Accept value: yes +* Is value required: yes +* Is multiple: no +* Description: The output format (txt, xml, json, or md) +* Default: `'txt'` + +descriptor:command1 +------------------- + +* Description: command 1 description +* Usage: + + * `descriptor:command1` + * `alias1` + * `alias2` + +command 1 help + +### Options: + +**help:** + +* Name: `--help` +* Shortcut: `-h` +* Accept value: no +* Is value required: no +* Is multiple: no +* Description: Display this help message +* Default: `false` + +**quiet:** + +* Name: `--quiet` +* Shortcut: `-q` +* Accept value: no +* Is value required: no +* Is multiple: no +* Description: Do not output any message +* Default: `false` + +**verbose:** + +* Name: `--verbose` +* Shortcut: `-v|-vv|-vvv` +* Accept value: no +* Is value required: no +* Is multiple: no +* Description: Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug +* Default: `false` + +**version:** + +* Name: `--version` +* Shortcut: `-V` +* Accept value: no +* Is value required: no +* Is multiple: no +* Description: Display this application version +* Default: `false` + +**ansi:** + +* Name: `--ansi` +* Shortcut: +* Accept value: no +* Is value required: no +* Is multiple: no +* Description: Force ANSI output +* Default: `false` + +**no-ansi:** + +* Name: `--no-ansi` +* Shortcut: +* Accept value: no +* Is value required: no +* Is multiple: no +* Description: Disable ANSI output +* Default: `false` + +**no-interaction:** + +* Name: `--no-interaction` +* Shortcut: `-n` +* Accept value: no +* Is value required: no +* Is multiple: no +* Description: Do not ask any interactive question +* Default: `false` + +descriptor:command2 +------------------- + +* Description: command 2 description +* Usage: + + * `descriptor:command2 [-o|--option_name] [--] ` + * `descriptor:command2 -o|--option_name ` + * `descriptor:command2 ` + +command 2 help + +### Arguments: + +**argument_name:** + +* Name: argument_name +* Is required: yes +* Is array: no +* Description: +* Default: `NULL` + +### Options: + +**option_name:** + +* Name: `--option_name` +* Shortcut: `-o` +* Accept value: no +* Is value required: no +* Is multiple: no +* Description: +* Default: `false` + +**help:** + +* Name: `--help` +* Shortcut: `-h` +* Accept value: no +* Is value required: no +* Is multiple: no +* Description: Display this help message +* Default: `false` + +**quiet:** + +* Name: `--quiet` +* Shortcut: `-q` +* Accept value: no +* Is value required: no +* Is multiple: no +* Description: Do not output any message +* Default: `false` + +**verbose:** + +* Name: `--verbose` +* Shortcut: `-v|-vv|-vvv` +* Accept value: no +* Is value required: no +* Is multiple: no +* Description: Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug +* Default: `false` + +**version:** + +* Name: `--version` +* Shortcut: `-V` +* Accept value: no +* Is value required: no +* Is multiple: no +* Description: Display this application version +* Default: `false` + +**ansi:** + +* Name: `--ansi` +* Shortcut: +* Accept value: no +* Is value required: no +* Is multiple: no +* Description: Force ANSI output +* Default: `false` + +**no-ansi:** + +* Name: `--no-ansi` +* Shortcut: +* Accept value: no +* Is value required: no +* Is multiple: no +* Description: Disable ANSI output +* Default: `false` + +**no-interaction:** + +* Name: `--no-interaction` +* Shortcut: `-n` +* Accept value: no +* Is value required: no +* Is multiple: no +* Description: Do not ask any interactive question +* Default: `false` diff --git a/vendor/symfony/console/Tests/Fixtures/application_2.txt b/vendor/symfony/console/Tests/Fixtures/application_2.txt new file mode 100644 index 0000000..292aa82 --- /dev/null +++ b/vendor/symfony/console/Tests/Fixtures/application_2.txt @@ -0,0 +1,22 @@ +My Symfony application version v1.0 + +Usage: + command [options] [arguments] + +Options: + -h, --help Display this help message + -q, --quiet Do not output any message + -V, --version Display this application version + --ansi Force ANSI output + --no-ansi Disable ANSI output + -n, --no-interaction Do not ask any interactive question + -v|vv|vvv, --verbose Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug + +Available commands: + alias1 command 1 description + alias2 command 1 description + help Displays help for a command + list Lists commands + descriptor + descriptor:command1 command 1 description + descriptor:command2 command 2 description diff --git a/vendor/symfony/console/Tests/Fixtures/application_2.xml b/vendor/symfony/console/Tests/Fixtures/application_2.xml new file mode 100644 index 0000000..bc8ab21 --- /dev/null +++ b/vendor/symfony/console/Tests/Fixtures/application_2.xml @@ -0,0 +1,190 @@ + + + + + + help [--xml] [--format FORMAT] [--raw] [--] [<command_name>] + + Displays help for a command + The <info>help</info> command displays help for a given command: + + <info>php app/console help list</info> + + You can also output the help in other formats by using the <comment>--format</comment> option: + + <info>php app/console help --format=xml list</info> + + To display the list of available commands, please use the <info>list</info> command. + + + The command name + + help + + + + + + + + + + + + + + + + + + + list [--xml] [--raw] [--format FORMAT] [--] [<namespace>] + + Lists commands + The <info>list</info> command lists all commands: + + <info>php app/console list</info> + + You can also display the commands for a specific namespace: + + <info>php app/console list test</info> + + You can also output the information in other formats by using the <comment>--format</comment> option: + + <info>php app/console list --format=xml</info> + + It's also possible to get raw list of commands (useful for embedding command runner): + + <info>php app/console list --raw</info> + + + The namespace name + + + + + + + + + + + + descriptor:command1 + alias1 + alias2 + + command 1 description + command 1 help + + + + + + + + + + + + + + descriptor:command2 [-o|--option_name] [--] <argument_name> + descriptor:command2 -o|--option_name <argument_name> + descriptor:command2 <argument_name> + + command 2 description + command 2 help + + + + + + + + + + + + + + + + + + + + + alias1 + alias2 + help + list + + + descriptor:command1 + descriptor:command2 + + + diff --git a/vendor/symfony/console/Tests/Fixtures/application_astext1.txt b/vendor/symfony/console/Tests/Fixtures/application_astext1.txt new file mode 100644 index 0000000..19dacb2 --- /dev/null +++ b/vendor/symfony/console/Tests/Fixtures/application_astext1.txt @@ -0,0 +1,20 @@ +Console Tool + +Usage: + command [options] [arguments] + +Options: + -h, --help Display this help message + -q, --quiet Do not output any message + -V, --version Display this application version + --ansi Force ANSI output + --no-ansi Disable ANSI output + -n, --no-interaction Do not ask any interactive question + -v|vv|vvv, --verbose Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug + +Available commands: + afoobar The foo:bar command + help Displays help for a command + list Lists commands + foo + foo:bar The foo:bar command diff --git a/vendor/symfony/console/Tests/Fixtures/application_astext2.txt b/vendor/symfony/console/Tests/Fixtures/application_astext2.txt new file mode 100644 index 0000000..c99ccdd --- /dev/null +++ b/vendor/symfony/console/Tests/Fixtures/application_astext2.txt @@ -0,0 +1,16 @@ +Console Tool + +Usage: + command [options] [arguments] + +Options: + -h, --help Display this help message + -q, --quiet Do not output any message + -V, --version Display this application version + --ansi Force ANSI output + --no-ansi Disable ANSI output + -n, --no-interaction Do not ask any interactive question + -v|vv|vvv, --verbose Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug + +Available commands for the "foo" namespace: + foo:bar The foo:bar command diff --git a/vendor/symfony/console/Tests/Fixtures/application_asxml1.txt b/vendor/symfony/console/Tests/Fixtures/application_asxml1.txt new file mode 100644 index 0000000..4c7f550 --- /dev/null +++ b/vendor/symfony/console/Tests/Fixtures/application_asxml1.txt @@ -0,0 +1,146 @@ + + + + + + help [--xml] [--format FORMAT] [--raw] [--] [<command_name>] + + Displays help for a command + The <info>help</info> command displays help for a given command: + + <info>php app/console help list</info> + + You can also output the help in other formats by using the <comment>--format</comment> option: + + <info>php app/console help --format=xml list</info> + + To display the list of available commands, please use the <info>list</info> command. + + + The command name + + help + + + + + + + + + + + + + + + + + + + list [--xml] [--raw] [--format FORMAT] [--] [<namespace>] + + Lists commands + The <info>list</info> command lists all commands: + + <info>php app/console list</info> + + You can also display the commands for a specific namespace: + + <info>php app/console list test</info> + + You can also output the information in other formats by using the <comment>--format</comment> option: + + <info>php app/console list --format=xml</info> + + It's also possible to get raw list of commands (useful for embedding command runner): + + <info>php app/console list --raw</info> + + + The namespace name + + + + + + + + + + + + foo:bar + afoobar + + The foo:bar command + The foo:bar command + + + + + + + + + + + + + + + afoobar + help + list + + + foo:bar + + + diff --git a/vendor/symfony/console/Tests/Fixtures/application_asxml2.txt b/vendor/symfony/console/Tests/Fixtures/application_asxml2.txt new file mode 100644 index 0000000..89d1310 --- /dev/null +++ b/vendor/symfony/console/Tests/Fixtures/application_asxml2.txt @@ -0,0 +1,37 @@ + + + + + + foo:bar + afoobar + + The foo:bar command + The foo:bar command + + + + + + + + + + + + + diff --git a/vendor/symfony/console/Tests/Fixtures/application_gethelp.txt b/vendor/symfony/console/Tests/Fixtures/application_gethelp.txt new file mode 100644 index 0000000..0c16e3c --- /dev/null +++ b/vendor/symfony/console/Tests/Fixtures/application_gethelp.txt @@ -0,0 +1 @@ +Console Tool \ No newline at end of file diff --git a/vendor/symfony/console/Tests/Fixtures/application_renderexception1.txt b/vendor/symfony/console/Tests/Fixtures/application_renderexception1.txt new file mode 100644 index 0000000..4629345 --- /dev/null +++ b/vendor/symfony/console/Tests/Fixtures/application_renderexception1.txt @@ -0,0 +1,8 @@ + + + + [InvalidArgumentException] + Command "foo" is not defined. + + + diff --git a/vendor/symfony/console/Tests/Fixtures/application_renderexception2.txt b/vendor/symfony/console/Tests/Fixtures/application_renderexception2.txt new file mode 100644 index 0000000..3d9d363 --- /dev/null +++ b/vendor/symfony/console/Tests/Fixtures/application_renderexception2.txt @@ -0,0 +1,11 @@ + + + + [InvalidArgumentException] + The "--foo" option does not exist. + + + +list [--xml] [--raw] [--format FORMAT] [--] [] + + diff --git a/vendor/symfony/console/Tests/Fixtures/application_renderexception3.txt b/vendor/symfony/console/Tests/Fixtures/application_renderexception3.txt new file mode 100644 index 0000000..72a7286 --- /dev/null +++ b/vendor/symfony/console/Tests/Fixtures/application_renderexception3.txt @@ -0,0 +1,27 @@ + + + + [Exception] + Third exception comment + + + + + + + [Exception] + Second exception comment + + + + + + + [Exception] + First exception

    this is html

    + + + +foo3:bar + + diff --git a/vendor/symfony/console/Tests/Fixtures/application_renderexception3decorated.txt b/vendor/symfony/console/Tests/Fixtures/application_renderexception3decorated.txt new file mode 100644 index 0000000..b44d50b --- /dev/null +++ b/vendor/symfony/console/Tests/Fixtures/application_renderexception3decorated.txt @@ -0,0 +1,27 @@ + + +  + [Exception]  + Third exception comment  +  + + + + +  + [Exception]  + Second exception comment  +  + + + + +  + [Exception]  + First exception 

    this is html

      +  + + +foo3:bar + + diff --git a/vendor/symfony/console/Tests/Fixtures/application_renderexception4.txt b/vendor/symfony/console/Tests/Fixtures/application_renderexception4.txt new file mode 100644 index 0000000..19f893b --- /dev/null +++ b/vendor/symfony/console/Tests/Fixtures/application_renderexception4.txt @@ -0,0 +1,9 @@ + + + + [InvalidArgumentException] + Command "foo" is not define + d. + + + diff --git a/vendor/symfony/console/Tests/Fixtures/application_renderexception_doublewidth1.txt b/vendor/symfony/console/Tests/Fixtures/application_renderexception_doublewidth1.txt new file mode 100644 index 0000000..6a98660 --- /dev/null +++ b/vendor/symfony/console/Tests/Fixtures/application_renderexception_doublewidth1.txt @@ -0,0 +1,11 @@ + + + + [Exception] + エラーメッセージ + + + +foo + + diff --git a/vendor/symfony/console/Tests/Fixtures/application_renderexception_doublewidth1decorated.txt b/vendor/symfony/console/Tests/Fixtures/application_renderexception_doublewidth1decorated.txt new file mode 100644 index 0000000..8c8801b --- /dev/null +++ b/vendor/symfony/console/Tests/Fixtures/application_renderexception_doublewidth1decorated.txt @@ -0,0 +1,11 @@ + + +  + [Exception]  + エラーメッセージ  +  + + +foo + + diff --git a/vendor/symfony/console/Tests/Fixtures/application_renderexception_doublewidth2.txt b/vendor/symfony/console/Tests/Fixtures/application_renderexception_doublewidth2.txt new file mode 100644 index 0000000..545cd7b --- /dev/null +++ b/vendor/symfony/console/Tests/Fixtures/application_renderexception_doublewidth2.txt @@ -0,0 +1,12 @@ + + + + [Exception] + コマンドの実行中にエラーが + 発生しました。 + + + +foo + + diff --git a/vendor/symfony/console/Tests/Fixtures/application_run1.txt b/vendor/symfony/console/Tests/Fixtures/application_run1.txt new file mode 100644 index 0000000..0dc2730 --- /dev/null +++ b/vendor/symfony/console/Tests/Fixtures/application_run1.txt @@ -0,0 +1,17 @@ +Console Tool + +Usage: + command [options] [arguments] + +Options: + -h, --help Display this help message + -q, --quiet Do not output any message + -V, --version Display this application version + --ansi Force ANSI output + --no-ansi Disable ANSI output + -n, --no-interaction Do not ask any interactive question + -v|vv|vvv, --verbose Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug + +Available commands: + help Displays help for a command + list Lists commands diff --git a/vendor/symfony/console/Tests/Fixtures/application_run2.txt b/vendor/symfony/console/Tests/Fixtures/application_run2.txt new file mode 100644 index 0000000..d28b928 --- /dev/null +++ b/vendor/symfony/console/Tests/Fixtures/application_run2.txt @@ -0,0 +1,29 @@ +Usage: + help [options] [--] [] + +Arguments: + command The command to execute + command_name The command name [default: "help"] + +Options: + --xml To output help as XML + --format=FORMAT The output format (txt, xml, json, or md) [default: "txt"] + --raw To output raw command help + -h, --help Display this help message + -q, --quiet Do not output any message + -V, --version Display this application version + --ansi Force ANSI output + --no-ansi Disable ANSI output + -n, --no-interaction Do not ask any interactive question + -v|vv|vvv, --verbose Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug + +Help: + The help command displays help for a given command: + + php app/console help list + + You can also output the help in other formats by using the --format option: + + php app/console help --format=xml list + + To display the list of available commands, please use the list command. diff --git a/vendor/symfony/console/Tests/Fixtures/application_run3.txt b/vendor/symfony/console/Tests/Fixtures/application_run3.txt new file mode 100644 index 0000000..bc51995 --- /dev/null +++ b/vendor/symfony/console/Tests/Fixtures/application_run3.txt @@ -0,0 +1,27 @@ +Usage: + list [options] [--] [] + +Arguments: + namespace The namespace name + +Options: + --xml To output list as XML + --raw To output raw command list + --format=FORMAT The output format (txt, xml, json, or md) [default: "txt"] + +Help: + The list command lists all commands: + + php app/console list + + You can also display the commands for a specific namespace: + + php app/console list test + + You can also output the information in other formats by using the --format option: + + php app/console list --format=xml + + It's also possible to get raw list of commands (useful for embedding command runner): + + php app/console list --raw diff --git a/vendor/symfony/console/Tests/Fixtures/application_run4.txt b/vendor/symfony/console/Tests/Fixtures/application_run4.txt new file mode 100644 index 0000000..47187fc --- /dev/null +++ b/vendor/symfony/console/Tests/Fixtures/application_run4.txt @@ -0,0 +1 @@ +Console Tool diff --git a/vendor/symfony/console/Tests/Fixtures/command_1.json b/vendor/symfony/console/Tests/Fixtures/command_1.json new file mode 100644 index 0000000..20f310b --- /dev/null +++ b/vendor/symfony/console/Tests/Fixtures/command_1.json @@ -0,0 +1 @@ +{"name":"descriptor:command1","usage":["descriptor:command1", "alias1", "alias2"],"description":"command 1 description","help":"command 1 help","definition":{"arguments":[],"options":[]}} diff --git a/vendor/symfony/console/Tests/Fixtures/command_1.md b/vendor/symfony/console/Tests/Fixtures/command_1.md new file mode 100644 index 0000000..34ed3ea --- /dev/null +++ b/vendor/symfony/console/Tests/Fixtures/command_1.md @@ -0,0 +1,11 @@ +descriptor:command1 +------------------- + +* Description: command 1 description +* Usage: + + * `descriptor:command1` + * `alias1` + * `alias2` + +command 1 help diff --git a/vendor/symfony/console/Tests/Fixtures/command_1.txt b/vendor/symfony/console/Tests/Fixtures/command_1.txt new file mode 100644 index 0000000..28e14a0 --- /dev/null +++ b/vendor/symfony/console/Tests/Fixtures/command_1.txt @@ -0,0 +1,7 @@ +Usage: + descriptor:command1 + alias1 + alias2 + +Help: + command 1 help diff --git a/vendor/symfony/console/Tests/Fixtures/command_1.xml b/vendor/symfony/console/Tests/Fixtures/command_1.xml new file mode 100644 index 0000000..838b9bd --- /dev/null +++ b/vendor/symfony/console/Tests/Fixtures/command_1.xml @@ -0,0 +1,12 @@ + + + + descriptor:command1 + alias1 + alias2 + + command 1 description + command 1 help + + + diff --git a/vendor/symfony/console/Tests/Fixtures/command_2.json b/vendor/symfony/console/Tests/Fixtures/command_2.json new file mode 100644 index 0000000..38edd1e --- /dev/null +++ b/vendor/symfony/console/Tests/Fixtures/command_2.json @@ -0,0 +1 @@ +{"name":"descriptor:command2","usage":["descriptor:command2 [-o|--option_name] [--] ", "descriptor:command2 -o|--option_name ", "descriptor:command2 "],"description":"command 2 description","help":"command 2 help","definition":{"arguments":{"argument_name":{"name":"argument_name","is_required":true,"is_array":false,"description":"","default":null}},"options":{"option_name":{"name":"--option_name","shortcut":"-o","accept_value":false,"is_value_required":false,"is_multiple":false,"description":"","default":false}}}} diff --git a/vendor/symfony/console/Tests/Fixtures/command_2.md b/vendor/symfony/console/Tests/Fixtures/command_2.md new file mode 100644 index 0000000..6f538b6 --- /dev/null +++ b/vendor/symfony/console/Tests/Fixtures/command_2.md @@ -0,0 +1,33 @@ +descriptor:command2 +------------------- + +* Description: command 2 description +* Usage: + + * `descriptor:command2 [-o|--option_name] [--] ` + * `descriptor:command2 -o|--option_name ` + * `descriptor:command2 ` + +command 2 help + +### Arguments: + +**argument_name:** + +* Name: argument_name +* Is required: yes +* Is array: no +* Description: +* Default: `NULL` + +### Options: + +**option_name:** + +* Name: `--option_name` +* Shortcut: `-o` +* Accept value: no +* Is value required: no +* Is multiple: no +* Description: +* Default: `false` diff --git a/vendor/symfony/console/Tests/Fixtures/command_2.txt b/vendor/symfony/console/Tests/Fixtures/command_2.txt new file mode 100644 index 0000000..72f7ce0 --- /dev/null +++ b/vendor/symfony/console/Tests/Fixtures/command_2.txt @@ -0,0 +1,13 @@ +Usage: + descriptor:command2 [options] [--] + descriptor:command2 -o|--option_name + descriptor:command2 + +Arguments: + argument_name + +Options: + -o, --option_name + +Help: + command 2 help diff --git a/vendor/symfony/console/Tests/Fixtures/command_2.xml b/vendor/symfony/console/Tests/Fixtures/command_2.xml new file mode 100644 index 0000000..67364ca --- /dev/null +++ b/vendor/symfony/console/Tests/Fixtures/command_2.xml @@ -0,0 +1,21 @@ + + + + descriptor:command2 [-o|--option_name] [--] <argument_name> + descriptor:command2 -o|--option_name <argument_name> + descriptor:command2 <argument_name> + + command 2 description + command 2 help + + + + + + + + + + diff --git a/vendor/symfony/console/Tests/Fixtures/command_astext.txt b/vendor/symfony/console/Tests/Fixtures/command_astext.txt new file mode 100644 index 0000000..7e20638 --- /dev/null +++ b/vendor/symfony/console/Tests/Fixtures/command_astext.txt @@ -0,0 +1,18 @@ +Usage: + namespace:name + name + +Arguments: + command The command to execute + +Options: + -h, --help Display this help message + -q, --quiet Do not output any message + -V, --version Display this application version + --ansi Force ANSI output + --no-ansi Disable ANSI output + -n, --no-interaction Do not ask any interactive question + -v|vv|vvv, --verbose Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug + +Help: + help diff --git a/vendor/symfony/console/Tests/Fixtures/command_asxml.txt b/vendor/symfony/console/Tests/Fixtures/command_asxml.txt new file mode 100644 index 0000000..5e77623 --- /dev/null +++ b/vendor/symfony/console/Tests/Fixtures/command_asxml.txt @@ -0,0 +1,38 @@ + + + + namespace:name + name + + description + help + + + The command to execute + + + + + + + + + + + + + diff --git a/vendor/symfony/console/Tests/Fixtures/definition_astext.txt b/vendor/symfony/console/Tests/Fixtures/definition_astext.txt new file mode 100644 index 0000000..0431c07 --- /dev/null +++ b/vendor/symfony/console/Tests/Fixtures/definition_astext.txt @@ -0,0 +1,11 @@ +Arguments: + foo The foo argument + baz The baz argument [default: true] + bar The bar argument [default: ["http://foo.com/"]] + +Options: + -f, --foo=FOO The foo option + --baz[=BAZ] The baz option [default: false] + -b, --bar[=BAR] The bar option [default: "bar"] + --qux[=QUX] The qux option [default: ["http://foo.com/","bar"]] (multiple values allowed) + --qux2[=QUX2] The qux2 option [default: {"foo":"bar"}] (multiple values allowed) \ No newline at end of file diff --git a/vendor/symfony/console/Tests/Fixtures/definition_asxml.txt b/vendor/symfony/console/Tests/Fixtures/definition_asxml.txt new file mode 100644 index 0000000..eec8c07 --- /dev/null +++ b/vendor/symfony/console/Tests/Fixtures/definition_asxml.txt @@ -0,0 +1,39 @@ + + + + + The foo argument + + + + The baz argument + + true + + + + The bar argument + + bar + + + + + + + + + diff --git a/vendor/symfony/console/Tests/Fixtures/input_argument_1.json b/vendor/symfony/console/Tests/Fixtures/input_argument_1.json new file mode 100644 index 0000000..b8173b6 --- /dev/null +++ b/vendor/symfony/console/Tests/Fixtures/input_argument_1.json @@ -0,0 +1 @@ +{"name":"argument_name","is_required":true,"is_array":false,"description":"","default":null} diff --git a/vendor/symfony/console/Tests/Fixtures/input_argument_1.md b/vendor/symfony/console/Tests/Fixtures/input_argument_1.md new file mode 100644 index 0000000..88f311a --- /dev/null +++ b/vendor/symfony/console/Tests/Fixtures/input_argument_1.md @@ -0,0 +1,7 @@ +**argument_name:** + +* Name: argument_name +* Is required: yes +* Is array: no +* Description: +* Default: `NULL` diff --git a/vendor/symfony/console/Tests/Fixtures/input_argument_1.txt b/vendor/symfony/console/Tests/Fixtures/input_argument_1.txt new file mode 100644 index 0000000..5503518 --- /dev/null +++ b/vendor/symfony/console/Tests/Fixtures/input_argument_1.txt @@ -0,0 +1 @@ + argument_name diff --git a/vendor/symfony/console/Tests/Fixtures/input_argument_1.xml b/vendor/symfony/console/Tests/Fixtures/input_argument_1.xml new file mode 100644 index 0000000..cb37f81 --- /dev/null +++ b/vendor/symfony/console/Tests/Fixtures/input_argument_1.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/vendor/symfony/console/Tests/Fixtures/input_argument_2.json b/vendor/symfony/console/Tests/Fixtures/input_argument_2.json new file mode 100644 index 0000000..ef06b09 --- /dev/null +++ b/vendor/symfony/console/Tests/Fixtures/input_argument_2.json @@ -0,0 +1 @@ +{"name":"argument_name","is_required":false,"is_array":true,"description":"argument description","default":[]} diff --git a/vendor/symfony/console/Tests/Fixtures/input_argument_2.md b/vendor/symfony/console/Tests/Fixtures/input_argument_2.md new file mode 100644 index 0000000..3cdb00c --- /dev/null +++ b/vendor/symfony/console/Tests/Fixtures/input_argument_2.md @@ -0,0 +1,7 @@ +**argument_name:** + +* Name: argument_name +* Is required: no +* Is array: yes +* Description: argument description +* Default: `array ()` diff --git a/vendor/symfony/console/Tests/Fixtures/input_argument_2.txt b/vendor/symfony/console/Tests/Fixtures/input_argument_2.txt new file mode 100644 index 0000000..e713660 --- /dev/null +++ b/vendor/symfony/console/Tests/Fixtures/input_argument_2.txt @@ -0,0 +1 @@ + argument_name argument description diff --git a/vendor/symfony/console/Tests/Fixtures/input_argument_2.xml b/vendor/symfony/console/Tests/Fixtures/input_argument_2.xml new file mode 100644 index 0000000..629da5a --- /dev/null +++ b/vendor/symfony/console/Tests/Fixtures/input_argument_2.xml @@ -0,0 +1,5 @@ + + + argument description + + diff --git a/vendor/symfony/console/Tests/Fixtures/input_argument_3.json b/vendor/symfony/console/Tests/Fixtures/input_argument_3.json new file mode 100644 index 0000000..de8484e --- /dev/null +++ b/vendor/symfony/console/Tests/Fixtures/input_argument_3.json @@ -0,0 +1 @@ +{"name":"argument_name","is_required":false,"is_array":false,"description":"argument description","default":"default_value"} diff --git a/vendor/symfony/console/Tests/Fixtures/input_argument_3.md b/vendor/symfony/console/Tests/Fixtures/input_argument_3.md new file mode 100644 index 0000000..be1c443 --- /dev/null +++ b/vendor/symfony/console/Tests/Fixtures/input_argument_3.md @@ -0,0 +1,7 @@ +**argument_name:** + +* Name: argument_name +* Is required: no +* Is array: no +* Description: argument description +* Default: `'default_value'` diff --git a/vendor/symfony/console/Tests/Fixtures/input_argument_3.txt b/vendor/symfony/console/Tests/Fixtures/input_argument_3.txt new file mode 100644 index 0000000..6b76639 --- /dev/null +++ b/vendor/symfony/console/Tests/Fixtures/input_argument_3.txt @@ -0,0 +1 @@ + argument_name argument description [default: "default_value"] diff --git a/vendor/symfony/console/Tests/Fixtures/input_argument_3.xml b/vendor/symfony/console/Tests/Fixtures/input_argument_3.xml new file mode 100644 index 0000000..399a5c8 --- /dev/null +++ b/vendor/symfony/console/Tests/Fixtures/input_argument_3.xml @@ -0,0 +1,7 @@ + + + argument description + + default_value + + diff --git a/vendor/symfony/console/Tests/Fixtures/input_argument_4.json b/vendor/symfony/console/Tests/Fixtures/input_argument_4.json new file mode 100644 index 0000000..8067a4d --- /dev/null +++ b/vendor/symfony/console/Tests/Fixtures/input_argument_4.json @@ -0,0 +1 @@ +{"name":"argument_name","is_required":true,"is_array":false,"description":"multiline argument description","default":null} diff --git a/vendor/symfony/console/Tests/Fixtures/input_argument_4.md b/vendor/symfony/console/Tests/Fixtures/input_argument_4.md new file mode 100644 index 0000000..f026ab3 --- /dev/null +++ b/vendor/symfony/console/Tests/Fixtures/input_argument_4.md @@ -0,0 +1,8 @@ +**argument_name:** + +* Name: argument_name +* Is required: yes +* Is array: no +* Description: multiline + argument description +* Default: `NULL` diff --git a/vendor/symfony/console/Tests/Fixtures/input_argument_4.txt b/vendor/symfony/console/Tests/Fixtures/input_argument_4.txt new file mode 100644 index 0000000..aa74e8c --- /dev/null +++ b/vendor/symfony/console/Tests/Fixtures/input_argument_4.txt @@ -0,0 +1,2 @@ + argument_name multiline + argument description diff --git a/vendor/symfony/console/Tests/Fixtures/input_argument_4.xml b/vendor/symfony/console/Tests/Fixtures/input_argument_4.xml new file mode 100644 index 0000000..5ca135e --- /dev/null +++ b/vendor/symfony/console/Tests/Fixtures/input_argument_4.xml @@ -0,0 +1,6 @@ + + + multiline +argument description + + diff --git a/vendor/symfony/console/Tests/Fixtures/input_definition_1.json b/vendor/symfony/console/Tests/Fixtures/input_definition_1.json new file mode 100644 index 0000000..c7a7d83 --- /dev/null +++ b/vendor/symfony/console/Tests/Fixtures/input_definition_1.json @@ -0,0 +1 @@ +{"arguments":[],"options":[]} diff --git a/vendor/symfony/console/Tests/Fixtures/input_definition_1.md b/vendor/symfony/console/Tests/Fixtures/input_definition_1.md new file mode 100644 index 0000000..e69de29 diff --git a/vendor/symfony/console/Tests/Fixtures/input_definition_1.txt b/vendor/symfony/console/Tests/Fixtures/input_definition_1.txt new file mode 100644 index 0000000..e69de29 diff --git a/vendor/symfony/console/Tests/Fixtures/input_definition_1.xml b/vendor/symfony/console/Tests/Fixtures/input_definition_1.xml new file mode 100644 index 0000000..b5481ce --- /dev/null +++ b/vendor/symfony/console/Tests/Fixtures/input_definition_1.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/vendor/symfony/console/Tests/Fixtures/input_definition_2.json b/vendor/symfony/console/Tests/Fixtures/input_definition_2.json new file mode 100644 index 0000000..9964a55 --- /dev/null +++ b/vendor/symfony/console/Tests/Fixtures/input_definition_2.json @@ -0,0 +1 @@ +{"arguments":{"argument_name":{"name":"argument_name","is_required":true,"is_array":false,"description":"","default":null}},"options":[]} diff --git a/vendor/symfony/console/Tests/Fixtures/input_definition_2.md b/vendor/symfony/console/Tests/Fixtures/input_definition_2.md new file mode 100644 index 0000000..923191c --- /dev/null +++ b/vendor/symfony/console/Tests/Fixtures/input_definition_2.md @@ -0,0 +1,9 @@ +### Arguments: + +**argument_name:** + +* Name: argument_name +* Is required: yes +* Is array: no +* Description: +* Default: `NULL` diff --git a/vendor/symfony/console/Tests/Fixtures/input_definition_2.txt b/vendor/symfony/console/Tests/Fixtures/input_definition_2.txt new file mode 100644 index 0000000..73b0f30 --- /dev/null +++ b/vendor/symfony/console/Tests/Fixtures/input_definition_2.txt @@ -0,0 +1,2 @@ +Arguments: + argument_name diff --git a/vendor/symfony/console/Tests/Fixtures/input_definition_2.xml b/vendor/symfony/console/Tests/Fixtures/input_definition_2.xml new file mode 100644 index 0000000..102efc1 --- /dev/null +++ b/vendor/symfony/console/Tests/Fixtures/input_definition_2.xml @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/vendor/symfony/console/Tests/Fixtures/input_definition_3.json b/vendor/symfony/console/Tests/Fixtures/input_definition_3.json new file mode 100644 index 0000000..6a86056 --- /dev/null +++ b/vendor/symfony/console/Tests/Fixtures/input_definition_3.json @@ -0,0 +1 @@ +{"arguments":[],"options":{"option_name":{"name":"--option_name","shortcut":"-o","accept_value":false,"is_value_required":false,"is_multiple":false,"description":"","default":false}}} diff --git a/vendor/symfony/console/Tests/Fixtures/input_definition_3.md b/vendor/symfony/console/Tests/Fixtures/input_definition_3.md new file mode 100644 index 0000000..40fd7b0 --- /dev/null +++ b/vendor/symfony/console/Tests/Fixtures/input_definition_3.md @@ -0,0 +1,11 @@ +### Options: + +**option_name:** + +* Name: `--option_name` +* Shortcut: `-o` +* Accept value: no +* Is value required: no +* Is multiple: no +* Description: +* Default: `false` diff --git a/vendor/symfony/console/Tests/Fixtures/input_definition_3.txt b/vendor/symfony/console/Tests/Fixtures/input_definition_3.txt new file mode 100644 index 0000000..c02766f --- /dev/null +++ b/vendor/symfony/console/Tests/Fixtures/input_definition_3.txt @@ -0,0 +1,2 @@ +Options: + -o, --option_name diff --git a/vendor/symfony/console/Tests/Fixtures/input_definition_3.xml b/vendor/symfony/console/Tests/Fixtures/input_definition_3.xml new file mode 100644 index 0000000..bc95151 --- /dev/null +++ b/vendor/symfony/console/Tests/Fixtures/input_definition_3.xml @@ -0,0 +1,9 @@ + + + + + + + diff --git a/vendor/symfony/console/Tests/Fixtures/input_definition_4.json b/vendor/symfony/console/Tests/Fixtures/input_definition_4.json new file mode 100644 index 0000000..c5a0019 --- /dev/null +++ b/vendor/symfony/console/Tests/Fixtures/input_definition_4.json @@ -0,0 +1 @@ +{"arguments":{"argument_name":{"name":"argument_name","is_required":true,"is_array":false,"description":"","default":null}},"options":{"option_name":{"name":"--option_name","shortcut":"-o","accept_value":false,"is_value_required":false,"is_multiple":false,"description":"","default":false}}} diff --git a/vendor/symfony/console/Tests/Fixtures/input_definition_4.md b/vendor/symfony/console/Tests/Fixtures/input_definition_4.md new file mode 100644 index 0000000..a31feea --- /dev/null +++ b/vendor/symfony/console/Tests/Fixtures/input_definition_4.md @@ -0,0 +1,21 @@ +### Arguments: + +**argument_name:** + +* Name: argument_name +* Is required: yes +* Is array: no +* Description: +* Default: `NULL` + +### Options: + +**option_name:** + +* Name: `--option_name` +* Shortcut: `-o` +* Accept value: no +* Is value required: no +* Is multiple: no +* Description: +* Default: `false` diff --git a/vendor/symfony/console/Tests/Fixtures/input_definition_4.txt b/vendor/symfony/console/Tests/Fixtures/input_definition_4.txt new file mode 100644 index 0000000..63aa81d --- /dev/null +++ b/vendor/symfony/console/Tests/Fixtures/input_definition_4.txt @@ -0,0 +1,5 @@ +Arguments: + argument_name + +Options: + -o, --option_name diff --git a/vendor/symfony/console/Tests/Fixtures/input_definition_4.xml b/vendor/symfony/console/Tests/Fixtures/input_definition_4.xml new file mode 100644 index 0000000..cffceec --- /dev/null +++ b/vendor/symfony/console/Tests/Fixtures/input_definition_4.xml @@ -0,0 +1,14 @@ + + + + + + + + + + + + diff --git a/vendor/symfony/console/Tests/Fixtures/input_option_1.json b/vendor/symfony/console/Tests/Fixtures/input_option_1.json new file mode 100644 index 0000000..60c5b56 --- /dev/null +++ b/vendor/symfony/console/Tests/Fixtures/input_option_1.json @@ -0,0 +1 @@ +{"name":"--option_name","shortcut":"-o","accept_value":false,"is_value_required":false,"is_multiple":false,"description":"","default":false} diff --git a/vendor/symfony/console/Tests/Fixtures/input_option_1.md b/vendor/symfony/console/Tests/Fixtures/input_option_1.md new file mode 100644 index 0000000..6f9e9a7 --- /dev/null +++ b/vendor/symfony/console/Tests/Fixtures/input_option_1.md @@ -0,0 +1,9 @@ +**option_name:** + +* Name: `--option_name` +* Shortcut: `-o` +* Accept value: no +* Is value required: no +* Is multiple: no +* Description: +* Default: `false` diff --git a/vendor/symfony/console/Tests/Fixtures/input_option_1.txt b/vendor/symfony/console/Tests/Fixtures/input_option_1.txt new file mode 100644 index 0000000..3a5e4ee --- /dev/null +++ b/vendor/symfony/console/Tests/Fixtures/input_option_1.txt @@ -0,0 +1 @@ + -o, --option_name diff --git a/vendor/symfony/console/Tests/Fixtures/input_option_1.xml b/vendor/symfony/console/Tests/Fixtures/input_option_1.xml new file mode 100644 index 0000000..8a64ea6 --- /dev/null +++ b/vendor/symfony/console/Tests/Fixtures/input_option_1.xml @@ -0,0 +1,4 @@ + + diff --git a/vendor/symfony/console/Tests/Fixtures/input_option_2.json b/vendor/symfony/console/Tests/Fixtures/input_option_2.json new file mode 100644 index 0000000..04e4228 --- /dev/null +++ b/vendor/symfony/console/Tests/Fixtures/input_option_2.json @@ -0,0 +1 @@ +{"name":"--option_name","shortcut":"-o","accept_value":true,"is_value_required":false,"is_multiple":false,"description":"option description","default":"default_value"} diff --git a/vendor/symfony/console/Tests/Fixtures/input_option_2.md b/vendor/symfony/console/Tests/Fixtures/input_option_2.md new file mode 100644 index 0000000..634ac0b --- /dev/null +++ b/vendor/symfony/console/Tests/Fixtures/input_option_2.md @@ -0,0 +1,9 @@ +**option_name:** + +* Name: `--option_name` +* Shortcut: `-o` +* Accept value: yes +* Is value required: no +* Is multiple: no +* Description: option description +* Default: `'default_value'` diff --git a/vendor/symfony/console/Tests/Fixtures/input_option_2.txt b/vendor/symfony/console/Tests/Fixtures/input_option_2.txt new file mode 100644 index 0000000..1009eff --- /dev/null +++ b/vendor/symfony/console/Tests/Fixtures/input_option_2.txt @@ -0,0 +1 @@ + -o, --option_name[=OPTION_NAME] option description [default: "default_value"] diff --git a/vendor/symfony/console/Tests/Fixtures/input_option_2.xml b/vendor/symfony/console/Tests/Fixtures/input_option_2.xml new file mode 100644 index 0000000..4afac5b --- /dev/null +++ b/vendor/symfony/console/Tests/Fixtures/input_option_2.xml @@ -0,0 +1,7 @@ + + diff --git a/vendor/symfony/console/Tests/Fixtures/input_option_3.json b/vendor/symfony/console/Tests/Fixtures/input_option_3.json new file mode 100644 index 0000000..c1ea120 --- /dev/null +++ b/vendor/symfony/console/Tests/Fixtures/input_option_3.json @@ -0,0 +1 @@ +{"name":"--option_name","shortcut":"-o","accept_value":true,"is_value_required":true,"is_multiple":false,"description":"option description","default":null} diff --git a/vendor/symfony/console/Tests/Fixtures/input_option_3.md b/vendor/symfony/console/Tests/Fixtures/input_option_3.md new file mode 100644 index 0000000..3428289 --- /dev/null +++ b/vendor/symfony/console/Tests/Fixtures/input_option_3.md @@ -0,0 +1,9 @@ +**option_name:** + +* Name: `--option_name` +* Shortcut: `-o` +* Accept value: yes +* Is value required: yes +* Is multiple: no +* Description: option description +* Default: `NULL` diff --git a/vendor/symfony/console/Tests/Fixtures/input_option_3.txt b/vendor/symfony/console/Tests/Fixtures/input_option_3.txt new file mode 100644 index 0000000..947bb65 --- /dev/null +++ b/vendor/symfony/console/Tests/Fixtures/input_option_3.txt @@ -0,0 +1 @@ + -o, --option_name=OPTION_NAME option description diff --git a/vendor/symfony/console/Tests/Fixtures/input_option_3.xml b/vendor/symfony/console/Tests/Fixtures/input_option_3.xml new file mode 100644 index 0000000..dcc0631 --- /dev/null +++ b/vendor/symfony/console/Tests/Fixtures/input_option_3.xml @@ -0,0 +1,5 @@ + + diff --git a/vendor/symfony/console/Tests/Fixtures/input_option_4.json b/vendor/symfony/console/Tests/Fixtures/input_option_4.json new file mode 100644 index 0000000..1b671d8 --- /dev/null +++ b/vendor/symfony/console/Tests/Fixtures/input_option_4.json @@ -0,0 +1 @@ +{"name":"--option_name","shortcut":"-o","accept_value":true,"is_value_required":false,"is_multiple":true,"description":"option description","default":[]} diff --git a/vendor/symfony/console/Tests/Fixtures/input_option_4.md b/vendor/symfony/console/Tests/Fixtures/input_option_4.md new file mode 100644 index 0000000..8ffba56 --- /dev/null +++ b/vendor/symfony/console/Tests/Fixtures/input_option_4.md @@ -0,0 +1,9 @@ +**option_name:** + +* Name: `--option_name` +* Shortcut: `-o` +* Accept value: yes +* Is value required: no +* Is multiple: yes +* Description: option description +* Default: `array ()` diff --git a/vendor/symfony/console/Tests/Fixtures/input_option_4.txt b/vendor/symfony/console/Tests/Fixtures/input_option_4.txt new file mode 100644 index 0000000..27edf77 --- /dev/null +++ b/vendor/symfony/console/Tests/Fixtures/input_option_4.txt @@ -0,0 +1 @@ + -o, --option_name[=OPTION_NAME] option description (multiple values allowed) diff --git a/vendor/symfony/console/Tests/Fixtures/input_option_4.xml b/vendor/symfony/console/Tests/Fixtures/input_option_4.xml new file mode 100644 index 0000000..5e2418b --- /dev/null +++ b/vendor/symfony/console/Tests/Fixtures/input_option_4.xml @@ -0,0 +1,5 @@ + + diff --git a/vendor/symfony/console/Tests/Fixtures/input_option_5.json b/vendor/symfony/console/Tests/Fixtures/input_option_5.json new file mode 100644 index 0000000..35a1405 --- /dev/null +++ b/vendor/symfony/console/Tests/Fixtures/input_option_5.json @@ -0,0 +1 @@ +{"name":"--option_name","shortcut":"-o","accept_value":true,"is_value_required":true,"is_multiple":false,"description":"multiline option description","default":null} diff --git a/vendor/symfony/console/Tests/Fixtures/input_option_5.md b/vendor/symfony/console/Tests/Fixtures/input_option_5.md new file mode 100644 index 0000000..82f51ca --- /dev/null +++ b/vendor/symfony/console/Tests/Fixtures/input_option_5.md @@ -0,0 +1,10 @@ +**option_name:** + +* Name: `--option_name` +* Shortcut: `-o` +* Accept value: yes +* Is value required: yes +* Is multiple: no +* Description: multiline + option description +* Default: `NULL` diff --git a/vendor/symfony/console/Tests/Fixtures/input_option_5.txt b/vendor/symfony/console/Tests/Fixtures/input_option_5.txt new file mode 100644 index 0000000..4368883 --- /dev/null +++ b/vendor/symfony/console/Tests/Fixtures/input_option_5.txt @@ -0,0 +1,2 @@ + -o, --option_name=OPTION_NAME multiline + option description diff --git a/vendor/symfony/console/Tests/Fixtures/input_option_5.xml b/vendor/symfony/console/Tests/Fixtures/input_option_5.xml new file mode 100644 index 0000000..90040cc --- /dev/null +++ b/vendor/symfony/console/Tests/Fixtures/input_option_5.xml @@ -0,0 +1,6 @@ + + diff --git a/vendor/symfony/console/Tests/Fixtures/input_option_6.json b/vendor/symfony/console/Tests/Fixtures/input_option_6.json new file mode 100644 index 0000000..d84e872 --- /dev/null +++ b/vendor/symfony/console/Tests/Fixtures/input_option_6.json @@ -0,0 +1 @@ +{"name":"--option_name","shortcut":"-o|-O","accept_value":true,"is_value_required":true,"is_multiple":false,"description":"option with multiple shortcuts","default":null} diff --git a/vendor/symfony/console/Tests/Fixtures/input_option_6.md b/vendor/symfony/console/Tests/Fixtures/input_option_6.md new file mode 100644 index 0000000..ed1ea1c --- /dev/null +++ b/vendor/symfony/console/Tests/Fixtures/input_option_6.md @@ -0,0 +1,9 @@ +**option_name:** + +* Name: `--option_name` +* Shortcut: `-o|-O` +* Accept value: yes +* Is value required: yes +* Is multiple: no +* Description: option with multiple shortcuts +* Default: `NULL` diff --git a/vendor/symfony/console/Tests/Fixtures/input_option_6.txt b/vendor/symfony/console/Tests/Fixtures/input_option_6.txt new file mode 100644 index 0000000..0e6c975 --- /dev/null +++ b/vendor/symfony/console/Tests/Fixtures/input_option_6.txt @@ -0,0 +1 @@ + -o|O, --option_name=OPTION_NAME option with multiple shortcuts diff --git a/vendor/symfony/console/Tests/Fixtures/input_option_6.xml b/vendor/symfony/console/Tests/Fixtures/input_option_6.xml new file mode 100644 index 0000000..06126a2 --- /dev/null +++ b/vendor/symfony/console/Tests/Fixtures/input_option_6.xml @@ -0,0 +1,5 @@ + + diff --git a/vendor/symfony/console/Tests/Formatter/OutputFormatterStyleStackTest.php b/vendor/symfony/console/Tests/Formatter/OutputFormatterStyleStackTest.php new file mode 100644 index 0000000..774df26 --- /dev/null +++ b/vendor/symfony/console/Tests/Formatter/OutputFormatterStyleStackTest.php @@ -0,0 +1,70 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Tests\Formatter; + +use Symfony\Component\Console\Formatter\OutputFormatterStyleStack; +use Symfony\Component\Console\Formatter\OutputFormatterStyle; + +class OutputFormatterStyleStackTest extends \PHPUnit_Framework_TestCase +{ + public function testPush() + { + $stack = new OutputFormatterStyleStack(); + $stack->push($s1 = new OutputFormatterStyle('white', 'black')); + $stack->push($s2 = new OutputFormatterStyle('yellow', 'blue')); + + $this->assertEquals($s2, $stack->getCurrent()); + + $stack->push($s3 = new OutputFormatterStyle('green', 'red')); + + $this->assertEquals($s3, $stack->getCurrent()); + } + + public function testPop() + { + $stack = new OutputFormatterStyleStack(); + $stack->push($s1 = new OutputFormatterStyle('white', 'black')); + $stack->push($s2 = new OutputFormatterStyle('yellow', 'blue')); + + $this->assertEquals($s2, $stack->pop()); + $this->assertEquals($s1, $stack->pop()); + } + + public function testPopEmpty() + { + $stack = new OutputFormatterStyleStack(); + $style = new OutputFormatterStyle(); + + $this->assertEquals($style, $stack->pop()); + } + + public function testPopNotLast() + { + $stack = new OutputFormatterStyleStack(); + $stack->push($s1 = new OutputFormatterStyle('white', 'black')); + $stack->push($s2 = new OutputFormatterStyle('yellow', 'blue')); + $stack->push($s3 = new OutputFormatterStyle('green', 'red')); + + $this->assertEquals($s2, $stack->pop($s2)); + $this->assertEquals($s1, $stack->pop()); + } + + /** + * @expectedException \InvalidArgumentException + */ + public function testInvalidPop() + { + $stack = new OutputFormatterStyleStack(); + $stack->push(new OutputFormatterStyle('white', 'black')); + $stack->pop(new OutputFormatterStyle('yellow', 'blue')); + } +} diff --git a/vendor/symfony/console/Tests/Formatter/OutputFormatterStyleTest.php b/vendor/symfony/console/Tests/Formatter/OutputFormatterStyleTest.php new file mode 100644 index 0000000..0abfb3c --- /dev/null +++ b/vendor/symfony/console/Tests/Formatter/OutputFormatterStyleTest.php @@ -0,0 +1,99 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Tests\Formatter; + +use Symfony\Component\Console\Formatter\OutputFormatterStyle; + +class OutputFormatterStyleTest extends \PHPUnit_Framework_TestCase +{ + public function testConstructor() + { + $style = new OutputFormatterStyle('green', 'black', array('bold', 'underscore')); + $this->assertEquals("\033[32;40;1;4mfoo\033[39;49;22;24m", $style->apply('foo')); + + $style = new OutputFormatterStyle('red', null, array('blink')); + $this->assertEquals("\033[31;5mfoo\033[39;25m", $style->apply('foo')); + + $style = new OutputFormatterStyle(null, 'white'); + $this->assertEquals("\033[47mfoo\033[49m", $style->apply('foo')); + } + + public function testForeground() + { + $style = new OutputFormatterStyle(); + + $style->setForeground('black'); + $this->assertEquals("\033[30mfoo\033[39m", $style->apply('foo')); + + $style->setForeground('blue'); + $this->assertEquals("\033[34mfoo\033[39m", $style->apply('foo')); + + $style->setForeground('default'); + $this->assertEquals("\033[39mfoo\033[39m", $style->apply('foo')); + + $this->setExpectedException('InvalidArgumentException'); + $style->setForeground('undefined-color'); + } + + public function testBackground() + { + $style = new OutputFormatterStyle(); + + $style->setBackground('black'); + $this->assertEquals("\033[40mfoo\033[49m", $style->apply('foo')); + + $style->setBackground('yellow'); + $this->assertEquals("\033[43mfoo\033[49m", $style->apply('foo')); + + $style->setBackground('default'); + $this->assertEquals("\033[49mfoo\033[49m", $style->apply('foo')); + + $this->setExpectedException('InvalidArgumentException'); + $style->setBackground('undefined-color'); + } + + public function testOptions() + { + $style = new OutputFormatterStyle(); + + $style->setOptions(array('reverse', 'conceal')); + $this->assertEquals("\033[7;8mfoo\033[27;28m", $style->apply('foo')); + + $style->setOption('bold'); + $this->assertEquals("\033[7;8;1mfoo\033[27;28;22m", $style->apply('foo')); + + $style->unsetOption('reverse'); + $this->assertEquals("\033[8;1mfoo\033[28;22m", $style->apply('foo')); + + $style->setOption('bold'); + $this->assertEquals("\033[8;1mfoo\033[28;22m", $style->apply('foo')); + + $style->setOptions(array('bold')); + $this->assertEquals("\033[1mfoo\033[22m", $style->apply('foo')); + + try { + $style->setOption('foo'); + $this->fail('->setOption() throws an \InvalidArgumentException when the option does not exist in the available options'); + } catch (\Exception $e) { + $this->assertInstanceOf('\InvalidArgumentException', $e, '->setOption() throws an \InvalidArgumentException when the option does not exist in the available options'); + $this->assertContains('Invalid option specified: "foo"', $e->getMessage(), '->setOption() throws an \InvalidArgumentException when the option does not exist in the available options'); + } + + try { + $style->unsetOption('foo'); + $this->fail('->unsetOption() throws an \InvalidArgumentException when the option does not exist in the available options'); + } catch (\Exception $e) { + $this->assertInstanceOf('\InvalidArgumentException', $e, '->unsetOption() throws an \InvalidArgumentException when the option does not exist in the available options'); + $this->assertContains('Invalid option specified: "foo"', $e->getMessage(), '->unsetOption() throws an \InvalidArgumentException when the option does not exist in the available options'); + } + } +} diff --git a/vendor/symfony/console/Tests/Formatter/OutputFormatterTest.php b/vendor/symfony/console/Tests/Formatter/OutputFormatterTest.php new file mode 100644 index 0000000..510a4e7 --- /dev/null +++ b/vendor/symfony/console/Tests/Formatter/OutputFormatterTest.php @@ -0,0 +1,273 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Tests\Formatter; + +use Symfony\Component\Console\Formatter\OutputFormatter; +use Symfony\Component\Console\Formatter\OutputFormatterStyle; + +class OutputFormatterTest extends \PHPUnit_Framework_TestCase +{ + public function testEmptyTag() + { + $formatter = new OutputFormatter(true); + $this->assertEquals('foo<>bar', $formatter->format('foo<>bar')); + } + + public function testLGCharEscaping() + { + $formatter = new OutputFormatter(true); + + $this->assertEquals('fooformat('foo\\assertEquals('some info', $formatter->format('\\some info\\')); + $this->assertEquals('\\some info\\', OutputFormatter::escape('some info')); + + $this->assertEquals( + "\033[33mSymfony\\Component\\Console does work very well!\033[39m", + $formatter->format('Symfony\Component\Console does work very well!') + ); + } + + public function testBundledStyles() + { + $formatter = new OutputFormatter(true); + + $this->assertTrue($formatter->hasStyle('error')); + $this->assertTrue($formatter->hasStyle('info')); + $this->assertTrue($formatter->hasStyle('comment')); + $this->assertTrue($formatter->hasStyle('question')); + + $this->assertEquals( + "\033[37;41msome error\033[39;49m", + $formatter->format('some error') + ); + $this->assertEquals( + "\033[32msome info\033[39m", + $formatter->format('some info') + ); + $this->assertEquals( + "\033[33msome comment\033[39m", + $formatter->format('some comment') + ); + $this->assertEquals( + "\033[30;46msome question\033[39;49m", + $formatter->format('some question') + ); + } + + public function testNestedStyles() + { + $formatter = new OutputFormatter(true); + + $this->assertEquals( + "\033[37;41msome \033[39;49m\033[32msome info\033[39m\033[37;41m error\033[39;49m", + $formatter->format('some some info error') + ); + } + + public function testAdjacentStyles() + { + $formatter = new OutputFormatter(true); + + $this->assertEquals( + "\033[37;41msome error\033[39;49m\033[32msome info\033[39m", + $formatter->format('some errorsome info') + ); + } + + public function testStyleMatchingNotGreedy() + { + $formatter = new OutputFormatter(true); + + $this->assertEquals( + "(\033[32m>=2.0,<2.3\033[39m)", + $formatter->format('(>=2.0,<2.3)') + ); + } + + public function testStyleEscaping() + { + $formatter = new OutputFormatter(true); + + $this->assertEquals( + "(\033[32mz>=2.0,format('('.$formatter->escape('z>=2.0,)') + ); + + $this->assertEquals( + "\033[32msome error\033[39m", + $formatter->format(''.$formatter->escape('some error').'') + ); + } + + public function testDeepNestedStyles() + { + $formatter = new OutputFormatter(true); + + $this->assertEquals( + "\033[37;41merror\033[39;49m\033[32minfo\033[39m\033[33mcomment\033[39m\033[37;41merror\033[39;49m", + $formatter->format('errorinfocommenterror') + ); + } + + public function testNewStyle() + { + $formatter = new OutputFormatter(true); + + $style = new OutputFormatterStyle('blue', 'white'); + $formatter->setStyle('test', $style); + + $this->assertEquals($style, $formatter->getStyle('test')); + $this->assertNotEquals($style, $formatter->getStyle('info')); + + $style = new OutputFormatterStyle('blue', 'white'); + $formatter->setStyle('b', $style); + + $this->assertEquals("\033[34;47msome \033[39;49m\033[34;47mcustom\033[39;49m\033[34;47m msg\033[39;49m", $formatter->format('some custom msg')); + } + + public function testRedefineStyle() + { + $formatter = new OutputFormatter(true); + + $style = new OutputFormatterStyle('blue', 'white'); + $formatter->setStyle('info', $style); + + $this->assertEquals("\033[34;47msome custom msg\033[39;49m", $formatter->format('some custom msg')); + } + + public function testInlineStyle() + { + $formatter = new OutputFormatter(true); + + $this->assertEquals("\033[34;41msome text\033[39;49m", $formatter->format('some text')); + $this->assertEquals("\033[34;41msome text\033[39;49m", $formatter->format('some text')); + } + + public function testNonStyleTag() + { + $formatter = new OutputFormatter(true); + + $this->assertEquals("\033[32msome \033[39m\033[32m\033[39m\033[32m \033[39m\033[32m\033[39m\033[32m styled \033[39m\033[32m

    \033[39m\033[32msingle-char tag\033[39m\033[32m

    \033[39m", $formatter->format('some styled

    single-char tag

    ')); + } + + public function testFormatLongString() + { + $formatter = new OutputFormatter(true); + $long = str_repeat('\\', 14000); + $this->assertEquals("\033[37;41msome error\033[39;49m".$long, $formatter->format('some error'.$long)); + } + + public function testFormatToStringObject() + { + $formatter = new OutputFormatter(false); + $this->assertEquals( + 'some info', $formatter->format(new TableCell()) + ); + } + + public function testNotDecoratedFormatter() + { + $formatter = new OutputFormatter(false); + + $this->assertTrue($formatter->hasStyle('error')); + $this->assertTrue($formatter->hasStyle('info')); + $this->assertTrue($formatter->hasStyle('comment')); + $this->assertTrue($formatter->hasStyle('question')); + + $this->assertEquals( + 'some error', $formatter->format('some error') + ); + $this->assertEquals( + 'some info', $formatter->format('some info') + ); + $this->assertEquals( + 'some comment', $formatter->format('some comment') + ); + $this->assertEquals( + 'some question', $formatter->format('some question') + ); + + $formatter->setDecorated(true); + + $this->assertEquals( + "\033[37;41msome error\033[39;49m", $formatter->format('some error') + ); + $this->assertEquals( + "\033[32msome info\033[39m", $formatter->format('some info') + ); + $this->assertEquals( + "\033[33msome comment\033[39m", $formatter->format('some comment') + ); + $this->assertEquals( + "\033[30;46msome question\033[39;49m", $formatter->format('some question') + ); + } + + public function testContentWithLineBreaks() + { + $formatter = new OutputFormatter(true); + + $this->assertEquals(<<format(<< +some text
    +EOF + )); + + $this->assertEquals(<<format(<<some text +
    +EOF + )); + + $this->assertEquals(<<format(<< +some text +
    +EOF + )); + + $this->assertEquals(<<format(<< +some text +more text +
    +EOF + )); + } +} + +class TableCell +{ + public function __toString() + { + return 'some info'; + } +} diff --git a/vendor/symfony/console/Tests/Helper/FormatterHelperTest.php b/vendor/symfony/console/Tests/Helper/FormatterHelperTest.php new file mode 100644 index 0000000..e332774 --- /dev/null +++ b/vendor/symfony/console/Tests/Helper/FormatterHelperTest.php @@ -0,0 +1,99 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Tests\Helper; + +use Symfony\Component\Console\Helper\FormatterHelper; + +class FormatterHelperTest extends \PHPUnit_Framework_TestCase +{ + public function testFormatSection() + { + $formatter = new FormatterHelper(); + + $this->assertEquals( + '[cli] Some text to display', + $formatter->formatSection('cli', 'Some text to display'), + '::formatSection() formats a message in a section' + ); + } + + public function testFormatBlock() + { + $formatter = new FormatterHelper(); + + $this->assertEquals( + ' Some text to display ', + $formatter->formatBlock('Some text to display', 'error'), + '::formatBlock() formats a message in a block' + ); + + $this->assertEquals( + ' Some text to display '."\n". + ' foo bar ', + $formatter->formatBlock(array('Some text to display', 'foo bar'), 'error'), + '::formatBlock() formats a message in a block' + ); + + $this->assertEquals( + ' '."\n". + ' Some text to display '."\n". + ' ', + $formatter->formatBlock('Some text to display', 'error', true), + '::formatBlock() formats a message in a block' + ); + } + + public function testFormatBlockWithDiacriticLetters() + { + if (!function_exists('mb_detect_encoding')) { + $this->markTestSkipped('This test requires mbstring to work.'); + } + + $formatter = new FormatterHelper(); + + $this->assertEquals( + ' '."\n". + ' Du texte à afficher '."\n". + ' ', + $formatter->formatBlock('Du texte à afficher', 'error', true), + '::formatBlock() formats a message in a block' + ); + } + + public function testFormatBlockWithDoubleWidthDiacriticLetters() + { + if (!extension_loaded('mbstring')) { + $this->markTestSkipped('This test requires mbstring to work.'); + } + $formatter = new FormatterHelper(); + $this->assertEquals( + ' '."\n". + ' 表示するテキスト '."\n". + ' ', + $formatter->formatBlock('表示するテキスト', 'error', true), + '::formatBlock() formats a message in a block' + ); + } + + public function testFormatBlockLGEscaping() + { + $formatter = new FormatterHelper(); + + $this->assertEquals( + ' '."\n". + ' \some info\ '."\n". + ' ', + $formatter->formatBlock('some info', 'error', true), + '::formatBlock() escapes \'<\' chars' + ); + } +} diff --git a/vendor/symfony/console/Tests/Helper/HelperSetTest.php b/vendor/symfony/console/Tests/Helper/HelperSetTest.php new file mode 100644 index 0000000..bf58a45 --- /dev/null +++ b/vendor/symfony/console/Tests/Helper/HelperSetTest.php @@ -0,0 +1,153 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Tests\Helper; + +use Symfony\Component\Console\Helper\HelperSet; +use Symfony\Component\Console\Command\Command; + +class HelperSetTest extends \PHPUnit_Framework_TestCase +{ + /** + * @covers \Symfony\Component\Console\Helper\HelperSet::__construct + */ + public function testConstructor() + { + $mock_helper = $this->getGenericMockHelper('fake_helper'); + $helperset = new HelperSet(array('fake_helper_alias' => $mock_helper)); + + $this->assertEquals($mock_helper, $helperset->get('fake_helper_alias'), '__construct sets given helper to helpers'); + $this->assertTrue($helperset->has('fake_helper_alias'), '__construct sets helper alias for given helper'); + } + + /** + * @covers \Symfony\Component\Console\Helper\HelperSet::set + */ + public function testSet() + { + $helperset = new HelperSet(); + $helperset->set($this->getGenericMockHelper('fake_helper', $helperset)); + $this->assertTrue($helperset->has('fake_helper'), '->set() adds helper to helpers'); + + $helperset = new HelperSet(); + $helperset->set($this->getGenericMockHelper('fake_helper_01', $helperset)); + $helperset->set($this->getGenericMockHelper('fake_helper_02', $helperset)); + $this->assertTrue($helperset->has('fake_helper_01'), '->set() will set multiple helpers on consecutive calls'); + $this->assertTrue($helperset->has('fake_helper_02'), '->set() will set multiple helpers on consecutive calls'); + + $helperset = new HelperSet(); + $helperset->set($this->getGenericMockHelper('fake_helper', $helperset), 'fake_helper_alias'); + $this->assertTrue($helperset->has('fake_helper'), '->set() adds helper alias when set'); + $this->assertTrue($helperset->has('fake_helper_alias'), '->set() adds helper alias when set'); + } + + /** + * @covers \Symfony\Component\Console\Helper\HelperSet::has + */ + public function testHas() + { + $helperset = new HelperSet(array('fake_helper_alias' => $this->getGenericMockHelper('fake_helper'))); + $this->assertTrue($helperset->has('fake_helper'), '->has() finds set helper'); + $this->assertTrue($helperset->has('fake_helper_alias'), '->has() finds set helper by alias'); + } + + /** + * @covers \Symfony\Component\Console\Helper\HelperSet::get + */ + public function testGet() + { + $helper_01 = $this->getGenericMockHelper('fake_helper_01'); + $helper_02 = $this->getGenericMockHelper('fake_helper_02'); + $helperset = new HelperSet(array('fake_helper_01_alias' => $helper_01, 'fake_helper_02_alias' => $helper_02)); + $this->assertEquals($helper_01, $helperset->get('fake_helper_01'), '->get() returns correct helper by name'); + $this->assertEquals($helper_01, $helperset->get('fake_helper_01_alias'), '->get() returns correct helper by alias'); + $this->assertEquals($helper_02, $helperset->get('fake_helper_02'), '->get() returns correct helper by name'); + $this->assertEquals($helper_02, $helperset->get('fake_helper_02_alias'), '->get() returns correct helper by alias'); + + $helperset = new HelperSet(); + try { + $helperset->get('foo'); + $this->fail('->get() throws \InvalidArgumentException when helper not found'); + } catch (\Exception $e) { + $this->assertInstanceOf('\InvalidArgumentException', $e, '->get() throws \InvalidArgumentException when helper not found'); + $this->assertContains('The helper "foo" is not defined.', $e->getMessage(), '->get() throws \InvalidArgumentException when helper not found'); + } + } + + /** + * @covers \Symfony\Component\Console\Helper\HelperSet::setCommand + */ + public function testSetCommand() + { + $cmd_01 = new Command('foo'); + $cmd_02 = new Command('bar'); + + $helperset = new HelperSet(); + $helperset->setCommand($cmd_01); + $this->assertEquals($cmd_01, $helperset->getCommand(), '->setCommand() stores given command'); + + $helperset = new HelperSet(); + $helperset->setCommand($cmd_01); + $helperset->setCommand($cmd_02); + $this->assertEquals($cmd_02, $helperset->getCommand(), '->setCommand() overwrites stored command with consecutive calls'); + } + + /** + * @covers \Symfony\Component\Console\Helper\HelperSet::getCommand + */ + public function testGetCommand() + { + $cmd = new Command('foo'); + $helperset = new HelperSet(); + $helperset->setCommand($cmd); + $this->assertEquals($cmd, $helperset->getCommand(), '->getCommand() retrieves stored command'); + } + + /** + * @covers \Symfony\Component\Console\Helper\HelperSet::getIterator + */ + public function testIteration() + { + $helperset = new HelperSet(); + $helperset->set($this->getGenericMockHelper('fake_helper_01', $helperset)); + $helperset->set($this->getGenericMockHelper('fake_helper_02', $helperset)); + + $helpers = array('fake_helper_01', 'fake_helper_02'); + $i = 0; + + foreach ($helperset as $helper) { + $this->assertEquals($helpers[$i++], $helper->getName()); + } + } + + /** + * Create a generic mock for the helper interface. Optionally check for a call to setHelperSet with a specific + * helperset instance. + * + * @param string $name + * @param HelperSet $helperset allows a mock to verify a particular helperset set is being added to the Helper + */ + private function getGenericMockHelper($name, HelperSet $helperset = null) + { + $mock_helper = $this->getMock('\Symfony\Component\Console\Helper\HelperInterface'); + $mock_helper->expects($this->any()) + ->method('getName') + ->will($this->returnValue($name)); + + if ($helperset) { + $mock_helper->expects($this->any()) + ->method('setHelperSet') + ->with($this->equalTo($helperset)); + } + + return $mock_helper; + } +} diff --git a/vendor/symfony/console/Tests/Helper/LegacyDialogHelperTest.php b/vendor/symfony/console/Tests/Helper/LegacyDialogHelperTest.php new file mode 100644 index 0000000..e130cdc --- /dev/null +++ b/vendor/symfony/console/Tests/Helper/LegacyDialogHelperTest.php @@ -0,0 +1,195 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Tests\Helper; + +use Symfony\Component\Console\Input\ArrayInput; +use Symfony\Component\Console\Helper\DialogHelper; +use Symfony\Component\Console\Helper\HelperSet; +use Symfony\Component\Console\Helper\FormatterHelper; +use Symfony\Component\Console\Output\StreamOutput; + +/** + * @group legacy + */ +class LegacyDialogHelperTest extends \PHPUnit_Framework_TestCase +{ + public function testSelect() + { + $dialog = new DialogHelper(); + + $helperSet = new HelperSet(array(new FormatterHelper())); + $dialog->setHelperSet($helperSet); + + $heroes = array('Superman', 'Batman', 'Spiderman'); + + $dialog->setInputStream($this->getInputStream("\n1\n 1 \nFabien\n1\nFabien\n1\n0,2\n 0 , 2 \n\n\n")); + $this->assertEquals('2', $dialog->select($this->getOutputStream(), 'What is your favorite superhero?', $heroes, '2')); + $this->assertEquals('1', $dialog->select($this->getOutputStream(), 'What is your favorite superhero?', $heroes)); + $this->assertEquals('1', $dialog->select($this->getOutputStream(), 'What is your favorite superhero?', $heroes)); + $this->assertEquals('1', $dialog->select($output = $this->getOutputStream(), 'What is your favorite superhero?', $heroes, null, false, 'Input "%s" is not a superhero!', false)); + + rewind($output->getStream()); + $this->assertContains('Input "Fabien" is not a superhero!', stream_get_contents($output->getStream())); + + try { + $this->assertEquals('1', $dialog->select($output = $this->getOutputStream(), 'What is your favorite superhero?', $heroes, null, 1)); + $this->fail(); + } catch (\InvalidArgumentException $e) { + $this->assertEquals('Value "Fabien" is invalid', $e->getMessage()); + } + + $this->assertEquals(array('1'), $dialog->select($this->getOutputStream(), 'What is your favorite superhero?', $heroes, null, false, 'Input "%s" is not a superhero!', true)); + $this->assertEquals(array('0', '2'), $dialog->select($this->getOutputStream(), 'What is your favorite superhero?', $heroes, null, false, 'Input "%s" is not a superhero!', true)); + $this->assertEquals(array('0', '2'), $dialog->select($this->getOutputStream(), 'What is your favorite superhero?', $heroes, null, false, 'Input "%s" is not a superhero!', true)); + $this->assertEquals(array('0', '1'), $dialog->select($this->getOutputStream(), 'What is your favorite superhero?', $heroes, '0,1', false, 'Input "%s" is not a superhero!', true)); + $this->assertEquals(array('0', '1'), $dialog->select($this->getOutputStream(), 'What is your favorite superhero?', $heroes, ' 0 , 1 ', false, 'Input "%s" is not a superhero!', true)); + } + + public function testAsk() + { + $dialog = new DialogHelper(); + + $dialog->setInputStream($this->getInputStream("\n8AM\n")); + + $this->assertEquals('2PM', $dialog->ask($this->getOutputStream(), 'What time is it?', '2PM')); + $this->assertEquals('8AM', $dialog->ask($output = $this->getOutputStream(), 'What time is it?', '2PM')); + + rewind($output->getStream()); + $this->assertEquals('What time is it?', stream_get_contents($output->getStream())); + } + + public function testAskWithAutocomplete() + { + if (!$this->hasSttyAvailable()) { + $this->markTestSkipped('`stty` is required to test autocomplete functionality'); + } + + // Acm + // AcsTest + // + // + // Test + // + // S + // F00oo + $inputStream = $this->getInputStream("Acm\nAc\177\177s\tTest\n\n\033[A\033[A\n\033[A\033[A\033[A\033[A\033[A\tTest\n\033[B\nS\177\177\033[B\033[B\nF00\177\177oo\t\n"); + + $dialog = new DialogHelper(); + $dialog->setInputStream($inputStream); + + $bundles = array('AcmeDemoBundle', 'AsseticBundle', 'SecurityBundle', 'FooBundle'); + + $this->assertEquals('AcmeDemoBundle', $dialog->ask($this->getOutputStream(), 'Please select a bundle', 'FrameworkBundle', $bundles)); + $this->assertEquals('AsseticBundleTest', $dialog->ask($this->getOutputStream(), 'Please select a bundle', 'FrameworkBundle', $bundles)); + $this->assertEquals('FrameworkBundle', $dialog->ask($this->getOutputStream(), 'Please select a bundle', 'FrameworkBundle', $bundles)); + $this->assertEquals('SecurityBundle', $dialog->ask($this->getOutputStream(), 'Please select a bundle', 'FrameworkBundle', $bundles)); + $this->assertEquals('FooBundleTest', $dialog->ask($this->getOutputStream(), 'Please select a bundle', 'FrameworkBundle', $bundles)); + $this->assertEquals('AcmeDemoBundle', $dialog->ask($this->getOutputStream(), 'Please select a bundle', 'FrameworkBundle', $bundles)); + $this->assertEquals('AsseticBundle', $dialog->ask($this->getOutputStream(), 'Please select a bundle', 'FrameworkBundle', $bundles)); + $this->assertEquals('FooBundle', $dialog->ask($this->getOutputStream(), 'Please select a bundle', 'FrameworkBundle', $bundles)); + } + + /** + * @group tty + */ + public function testAskHiddenResponse() + { + if ('\\' === DIRECTORY_SEPARATOR) { + $this->markTestSkipped('This test is not supported on Windows'); + } + + $dialog = new DialogHelper(); + + $dialog->setInputStream($this->getInputStream("8AM\n")); + + $this->assertEquals('8AM', $dialog->askHiddenResponse($this->getOutputStream(), 'What time is it?')); + } + + public function testAskConfirmation() + { + $dialog = new DialogHelper(); + + $dialog->setInputStream($this->getInputStream("\n\n")); + $this->assertTrue($dialog->askConfirmation($this->getOutputStream(), 'Do you like French fries?')); + $this->assertFalse($dialog->askConfirmation($this->getOutputStream(), 'Do you like French fries?', false)); + + $dialog->setInputStream($this->getInputStream("y\nyes\n")); + $this->assertTrue($dialog->askConfirmation($this->getOutputStream(), 'Do you like French fries?', false)); + $this->assertTrue($dialog->askConfirmation($this->getOutputStream(), 'Do you like French fries?', false)); + + $dialog->setInputStream($this->getInputStream("n\nno\n")); + $this->assertFalse($dialog->askConfirmation($this->getOutputStream(), 'Do you like French fries?', true)); + $this->assertFalse($dialog->askConfirmation($this->getOutputStream(), 'Do you like French fries?', true)); + } + + public function testAskAndValidate() + { + $dialog = new DialogHelper(); + $helperSet = new HelperSet(array(new FormatterHelper())); + $dialog->setHelperSet($helperSet); + + $question = 'What color was the white horse of Henry IV?'; + $error = 'This is not a color!'; + $validator = function ($color) use ($error) { + if (!in_array($color, array('white', 'black'))) { + throw new \InvalidArgumentException($error); + } + + return $color; + }; + + $dialog->setInputStream($this->getInputStream("\nblack\n")); + $this->assertEquals('white', $dialog->askAndValidate($this->getOutputStream(), $question, $validator, 2, 'white')); + $this->assertEquals('black', $dialog->askAndValidate($this->getOutputStream(), $question, $validator, 2, 'white')); + + $dialog->setInputStream($this->getInputStream("green\nyellow\norange\n")); + try { + $this->assertEquals('white', $dialog->askAndValidate($this->getOutputStream(), $question, $validator, 2, 'white')); + $this->fail(); + } catch (\InvalidArgumentException $e) { + $this->assertEquals($error, $e->getMessage()); + } + } + + public function testNoInteraction() + { + $dialog = new DialogHelper(); + + $input = new ArrayInput(array()); + $input->setInteractive(false); + + $dialog->setInput($input); + + $this->assertEquals('not yet', $dialog->ask($this->getOutputStream(), 'Do you have a job?', 'not yet')); + } + + protected function getInputStream($input) + { + $stream = fopen('php://memory', 'r+', false); + fwrite($stream, $input); + rewind($stream); + + return $stream; + } + + protected function getOutputStream() + { + return new StreamOutput(fopen('php://memory', 'r+', false)); + } + + private function hasSttyAvailable() + { + exec('stty 2>&1', $output, $exitcode); + + return $exitcode === 0; + } +} diff --git a/vendor/symfony/console/Tests/Helper/LegacyProgressHelperTest.php b/vendor/symfony/console/Tests/Helper/LegacyProgressHelperTest.php new file mode 100644 index 0000000..7b9cf29 --- /dev/null +++ b/vendor/symfony/console/Tests/Helper/LegacyProgressHelperTest.php @@ -0,0 +1,227 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Tests\Helper; + +use Symfony\Component\Console\Helper\ProgressHelper; +use Symfony\Component\Console\Output\StreamOutput; + +/** + * @group legacy + */ +class LegacyProgressHelperTest extends \PHPUnit_Framework_TestCase +{ + public function testAdvance() + { + $progress = new ProgressHelper(); + $progress->start($output = $this->getOutputStream()); + $progress->advance(); + + rewind($output->getStream()); + $this->assertEquals($this->generateOutput(' 1 [->--------------------------]'), stream_get_contents($output->getStream())); + } + + public function testAdvanceWithStep() + { + $progress = new ProgressHelper(); + $progress->start($output = $this->getOutputStream()); + $progress->advance(5); + + rewind($output->getStream()); + $this->assertEquals($this->generateOutput(' 5 [----->----------------------]'), stream_get_contents($output->getStream())); + } + + public function testAdvanceMultipleTimes() + { + $progress = new ProgressHelper(); + $progress->start($output = $this->getOutputStream()); + $progress->advance(3); + $progress->advance(2); + + rewind($output->getStream()); + $this->assertEquals($this->generateOutput(' 3 [--->------------------------]').$this->generateOutput(' 5 [----->----------------------]'), stream_get_contents($output->getStream())); + } + + public function testCustomizations() + { + $progress = new ProgressHelper(); + $progress->setBarWidth(10); + $progress->setBarCharacter('_'); + $progress->setEmptyBarCharacter(' '); + $progress->setProgressCharacter('/'); + $progress->setFormat(' %current%/%max% [%bar%] %percent%%'); + $progress->start($output = $this->getOutputStream(), 10); + $progress->advance(); + + rewind($output->getStream()); + $this->assertEquals($this->generateOutput(' 1/10 [_/ ] 10%'), stream_get_contents($output->getStream())); + } + + public function testPercent() + { + $progress = new ProgressHelper(); + $progress->start($output = $this->getOutputStream(), 50); + $progress->display(); + $progress->advance(); + $progress->advance(); + + rewind($output->getStream()); + $this->assertEquals($this->generateOutput(' 0/50 [>---------------------------] 0%').$this->generateOutput(' 1/50 [>---------------------------] 2%').$this->generateOutput(' 2/50 [=>--------------------------] 4%'), stream_get_contents($output->getStream())); + } + + public function testOverwriteWithShorterLine() + { + $progress = new ProgressHelper(); + $progress->setFormat(' %current%/%max% [%bar%] %percent%%'); + $progress->start($output = $this->getOutputStream(), 50); + $progress->display(); + $progress->advance(); + + // set shorter format + $progress->setFormat(' %current%/%max% [%bar%]'); + $progress->advance(); + + rewind($output->getStream()); + $this->assertEquals( + $this->generateOutput(' 0/50 [>---------------------------] 0%'). + $this->generateOutput(' 1/50 [>---------------------------] 2%'). + $this->generateOutput(' 2/50 [=>--------------------------] '), + stream_get_contents($output->getStream()) + ); + } + + public function testSetCurrentProgress() + { + $progress = new ProgressHelper(); + $progress->start($output = $this->getOutputStream(), 50); + $progress->display(); + $progress->advance(); + $progress->setCurrent(15); + $progress->setCurrent(25); + + rewind($output->getStream()); + $this->assertEquals( + $this->generateOutput(' 0/50 [>---------------------------] 0%'). + $this->generateOutput(' 1/50 [>---------------------------] 2%'). + $this->generateOutput(' 15/50 [========>-------------------] 30%'). + $this->generateOutput(' 25/50 [==============>-------------] 50%'), + stream_get_contents($output->getStream()) + ); + } + + /** + * @expectedException \LogicException + * @expectedExceptionMessage You must start the progress bar + */ + public function testSetCurrentBeforeStarting() + { + $progress = new ProgressHelper(); + $progress->setCurrent(15); + } + + /** + * @expectedException \LogicException + * @expectedExceptionMessage You can't regress the progress bar + */ + public function testRegressProgress() + { + $progress = new ProgressHelper(); + $progress->start($output = $this->getOutputStream(), 50); + $progress->setCurrent(15); + $progress->setCurrent(10); + } + + public function testRedrawFrequency() + { + $progress = $this->getMock('Symfony\Component\Console\Helper\ProgressHelper', array('display')); + $progress->expects($this->exactly(4)) + ->method('display'); + + $progress->setRedrawFrequency(2); + + $progress->start($output = $this->getOutputStream(), 6); + $progress->setCurrent(1); + $progress->advance(2); + $progress->advance(2); + $progress->advance(1); + } + + public function testMultiByteSupport() + { + if (!function_exists('mb_strlen') || (false === $encoding = mb_detect_encoding('■'))) { + $this->markTestSkipped('The mbstring extension is needed for multi-byte support'); + } + + $progress = new ProgressHelper(); + $progress->start($output = $this->getOutputStream()); + $progress->setBarCharacter('■'); + $progress->advance(3); + + rewind($output->getStream()); + $this->assertEquals($this->generateOutput(' 3 [■■■>------------------------]'), stream_get_contents($output->getStream())); + } + + public function testClear() + { + $progress = new ProgressHelper(); + $progress->start($output = $this->getOutputStream(), 50); + $progress->setCurrent(25); + $progress->clear(); + + rewind($output->getStream()); + $this->assertEquals( + $this->generateOutput(' 25/50 [==============>-------------] 50%').$this->generateOutput(''), + stream_get_contents($output->getStream()) + ); + } + + public function testPercentNotHundredBeforeComplete() + { + $progress = new ProgressHelper(); + $progress->start($output = $this->getOutputStream(), 200); + $progress->display(); + $progress->advance(199); + $progress->advance(); + + rewind($output->getStream()); + $this->assertEquals($this->generateOutput(' 0/200 [>---------------------------] 0%').$this->generateOutput(' 199/200 [===========================>] 99%').$this->generateOutput(' 200/200 [============================] 100%'), stream_get_contents($output->getStream())); + } + + public function testNonDecoratedOutput() + { + $progress = new ProgressHelper(); + $progress->start($output = $this->getOutputStream(false)); + $progress->advance(); + + rewind($output->getStream()); + $this->assertEquals('', stream_get_contents($output->getStream())); + } + + protected function getOutputStream($decorated = true) + { + return new StreamOutput(fopen('php://memory', 'r+', false), StreamOutput::VERBOSITY_NORMAL, $decorated); + } + + protected $lastMessagesLength; + + protected function generateOutput($expected) + { + $expectedout = $expected; + + if ($this->lastMessagesLength !== null) { + $expectedout = str_pad($expected, $this->lastMessagesLength, "\x20", STR_PAD_RIGHT); + } + + $this->lastMessagesLength = strlen($expectedout); + + return "\x0D".$expectedout; + } +} diff --git a/vendor/symfony/console/Tests/Helper/LegacyTableHelperTest.php b/vendor/symfony/console/Tests/Helper/LegacyTableHelperTest.php new file mode 100644 index 0000000..3b32423 --- /dev/null +++ b/vendor/symfony/console/Tests/Helper/LegacyTableHelperTest.php @@ -0,0 +1,324 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Tests\Helper; + +use Symfony\Component\Console\Helper\TableHelper; +use Symfony\Component\Console\Output\StreamOutput; + +/** + * @group legacy + */ +class LegacyTableHelperTest extends \PHPUnit_Framework_TestCase +{ + protected $stream; + + protected function setUp() + { + $this->stream = fopen('php://memory', 'r+'); + } + + protected function tearDown() + { + fclose($this->stream); + $this->stream = null; + } + + /** + * @dataProvider testRenderProvider + */ + public function testRender($headers, $rows, $layout, $expected) + { + $table = new TableHelper(); + $table + ->setHeaders($headers) + ->setRows($rows) + ->setLayout($layout) + ; + $table->render($output = $this->getOutputStream()); + + $this->assertEquals($expected, $this->getOutputContent($output)); + } + + /** + * @dataProvider testRenderProvider + */ + public function testRenderAddRows($headers, $rows, $layout, $expected) + { + $table = new TableHelper(); + $table + ->setHeaders($headers) + ->addRows($rows) + ->setLayout($layout) + ; + $table->render($output = $this->getOutputStream()); + + $this->assertEquals($expected, $this->getOutputContent($output)); + } + + /** + * @dataProvider testRenderProvider + */ + public function testRenderAddRowsOneByOne($headers, $rows, $layout, $expected) + { + $table = new TableHelper(); + $table + ->setHeaders($headers) + ->setLayout($layout) + ; + foreach ($rows as $row) { + $table->addRow($row); + } + $table->render($output = $this->getOutputStream()); + + $this->assertEquals($expected, $this->getOutputContent($output)); + } + + public function testRenderProvider() + { + $books = array( + array('99921-58-10-7', 'Divine Comedy', 'Dante Alighieri'), + array('9971-5-0210-0', 'A Tale of Two Cities', 'Charles Dickens'), + array('960-425-059-0', 'The Lord of the Rings', 'J. R. R. Tolkien'), + array('80-902734-1-6', 'And Then There Were None', 'Agatha Christie'), + ); + + return array( + array( + array('ISBN', 'Title', 'Author'), + $books, + TableHelper::LAYOUT_DEFAULT, +<< array( + array('ISBN', 'Title', 'Author'), + array( + array('99921-58-10-7', 'Divine Comedy', 'Dante Alighieri'), + array('9971-5-0210-0', 'A Tale of Two Cities', 'Charles Dickens'), + ), + TableHelper::LAYOUT_DEFAULT, +<<
    array( + array('ISBN', 'Title', 'Author'), + array( + array('99921-58-10-700', 'Divine Com', 'Dante Alighieri'), + array('9971-5-0210-0', 'A Tale of Two Cities', 'Charles Dickens'), + ), + TableHelper::LAYOUT_DEFAULT, +<<
    99921-58-10-700 | Divine Com | Dante Alighieri | +| 9971-5-0210-0 | A Tale of Two Cities | Charles Dickens | ++----------------------------------+----------------------+-----------------+ + +TABLE + ), + ); + } + + public function testRenderMultiByte() + { + if (!function_exists('mb_strwidth')) { + $this->markTestSkipped('The "mbstring" extension is not available'); + } + + $table = new TableHelper(); + $table + ->setHeaders(array('■■')) + ->setRows(array(array(1234))) + ->setLayout(TableHelper::LAYOUT_DEFAULT) + ; + $table->render($output = $this->getOutputStream()); + + $expected = +<<
    assertEquals($expected, $this->getOutputContent($output)); + } + + public function testRenderFullWidthCharacters() + { + if (!function_exists('mb_strwidth')) { + $this->markTestSkipped('The "mbstring" extension is not available'); + } + + $table = new TableHelper(); + $table + ->setHeaders(array('あいうえお')) + ->setRows(array(array(1234567890))) + ->setLayout(TableHelper::LAYOUT_DEFAULT) + ; + $table->render($output = $this->getOutputStream()); + + $expected = + <<
    assertEquals($expected, $this->getOutputContent($output)); + } + + protected function getOutputStream() + { + return new StreamOutput($this->stream, StreamOutput::VERBOSITY_NORMAL, false); + } + + protected function getOutputContent(StreamOutput $output) + { + rewind($output->getStream()); + + return str_replace(PHP_EOL, "\n", stream_get_contents($output->getStream())); + } +} diff --git a/vendor/symfony/console/Tests/Helper/ProcessHelperTest.php b/vendor/symfony/console/Tests/Helper/ProcessHelperTest.php new file mode 100644 index 0000000..a51fb43 --- /dev/null +++ b/vendor/symfony/console/Tests/Helper/ProcessHelperTest.php @@ -0,0 +1,117 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Tests\Helper; + +use Symfony\Component\Console\Helper\DebugFormatterHelper; +use Symfony\Component\Console\Helper\HelperSet; +use Symfony\Component\Console\Output\StreamOutput; +use Symfony\Component\Console\Helper\ProcessHelper; +use Symfony\Component\Process\Process; + +class ProcessHelperTest extends \PHPUnit_Framework_TestCase +{ + /** + * @dataProvider provideCommandsAndOutput + */ + public function testVariousProcessRuns($expected, $cmd, $verbosity, $error) + { + $helper = new ProcessHelper(); + $helper->setHelperSet(new HelperSet(array(new DebugFormatterHelper()))); + $output = $this->getOutputStream($verbosity); + $helper->run($output, $cmd, $error); + $this->assertEquals($expected, $this->getOutput($output)); + } + + public function testPassedCallbackIsExecuted() + { + $helper = new ProcessHelper(); + $helper->setHelperSet(new HelperSet(array(new DebugFormatterHelper()))); + $output = $this->getOutputStream(StreamOutput::VERBOSITY_NORMAL); + + $executed = false; + $callback = function () use (&$executed) { $executed = true; }; + + $helper->run($output, 'php -r "echo 42;"', null, $callback); + $this->assertTrue($executed); + } + + public function provideCommandsAndOutput() + { + $successOutputVerbose = <<42';" + OUT 42 + RES Command ran successfully + +EOT; + $successOutputProcessDebug = <<42\';"', StreamOutput::VERBOSITY_DEBUG, null), + array('', 'php -r "syntax error"', StreamOutput::VERBOSITY_VERBOSE, null), + array($syntaxErrorOutputVerbose, 'php -r "fwrite(STDERR, \'error message\');usleep(50000);fwrite(STDOUT, \'out message\');exit(252);"', StreamOutput::VERBOSITY_VERY_VERBOSE, null), + array($syntaxErrorOutputDebug, 'php -r "fwrite(STDERR, \'error message\');usleep(500000);fwrite(STDOUT, \'out message\');exit(252);"', StreamOutput::VERBOSITY_DEBUG, null), + array($errorMessage.PHP_EOL, 'php -r "fwrite(STDERR, \'error message\');usleep(50000);fwrite(STDOUT, \'out message\');exit(252);"', StreamOutput::VERBOSITY_VERBOSE, $errorMessage), + array($syntaxErrorOutputVerbose.$errorMessage.PHP_EOL, 'php -r "fwrite(STDERR, \'error message\');usleep(50000);fwrite(STDOUT, \'out message\');exit(252);"', StreamOutput::VERBOSITY_VERY_VERBOSE, $errorMessage), + array($syntaxErrorOutputDebug.$errorMessage.PHP_EOL, 'php -r "fwrite(STDERR, \'error message\');usleep(500000);fwrite(STDOUT, \'out message\');exit(252);"', StreamOutput::VERBOSITY_DEBUG, $errorMessage), + array($successOutputProcessDebug, array('php', '-r', 'echo 42;'), StreamOutput::VERBOSITY_DEBUG, null), + array($successOutputDebug, new Process('php -r "echo 42;"'), StreamOutput::VERBOSITY_DEBUG, null), + ); + } + + private function getOutputStream($verbosity) + { + return new StreamOutput(fopen('php://memory', 'r+', false), $verbosity, false); + } + + private function getOutput(StreamOutput $output) + { + rewind($output->getStream()); + + return stream_get_contents($output->getStream()); + } +} diff --git a/vendor/symfony/console/Tests/Helper/ProgressBarTest.php b/vendor/symfony/console/Tests/Helper/ProgressBarTest.php new file mode 100644 index 0000000..51962f3 --- /dev/null +++ b/vendor/symfony/console/Tests/Helper/ProgressBarTest.php @@ -0,0 +1,601 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Tests\Helper; + +use Symfony\Component\Console\Helper\ProgressBar; +use Symfony\Component\Console\Helper\Helper; +use Symfony\Component\Console\Output\StreamOutput; + +class ProgressBarTest extends \PHPUnit_Framework_TestCase +{ + public function testMultipleStart() + { + $bar = new ProgressBar($output = $this->getOutputStream()); + $bar->start(); + $bar->advance(); + $bar->start(); + + rewind($output->getStream()); + $this->assertEquals( + $this->generateOutput(' 0 [>---------------------------]'). + $this->generateOutput(' 1 [->--------------------------]'). + $this->generateOutput(' 0 [>---------------------------]'), + stream_get_contents($output->getStream()) + ); + } + + public function testAdvance() + { + $bar = new ProgressBar($output = $this->getOutputStream()); + $bar->start(); + $bar->advance(); + + rewind($output->getStream()); + $this->assertEquals( + $this->generateOutput(' 0 [>---------------------------]'). + $this->generateOutput(' 1 [->--------------------------]'), + stream_get_contents($output->getStream()) + ); + } + + public function testAdvanceWithStep() + { + $bar = new ProgressBar($output = $this->getOutputStream()); + $bar->start(); + $bar->advance(5); + + rewind($output->getStream()); + $this->assertEquals( + $this->generateOutput(' 0 [>---------------------------]'). + $this->generateOutput(' 5 [----->----------------------]'), + stream_get_contents($output->getStream()) + ); + } + + public function testAdvanceMultipleTimes() + { + $bar = new ProgressBar($output = $this->getOutputStream()); + $bar->start(); + $bar->advance(3); + $bar->advance(2); + + rewind($output->getStream()); + $this->assertEquals( + $this->generateOutput(' 0 [>---------------------------]'). + $this->generateOutput(' 3 [--->------------------------]'). + $this->generateOutput(' 5 [----->----------------------]'), + stream_get_contents($output->getStream()) + ); + } + + public function testAdvanceOverMax() + { + $bar = new ProgressBar($output = $this->getOutputStream(), 10); + $bar->setProgress(9); + $bar->advance(); + $bar->advance(); + + rewind($output->getStream()); + $this->assertEquals( + $this->generateOutput(' 9/10 [=========================>--] 90%'). + $this->generateOutput(' 10/10 [============================] 100%'). + $this->generateOutput(' 11/11 [============================] 100%'), + stream_get_contents($output->getStream()) + ); + } + + public function testCustomizations() + { + $bar = new ProgressBar($output = $this->getOutputStream(), 10); + $bar->setBarWidth(10); + $bar->setBarCharacter('_'); + $bar->setEmptyBarCharacter(' '); + $bar->setProgressCharacter('/'); + $bar->setFormat(' %current%/%max% [%bar%] %percent:3s%%'); + $bar->start(); + $bar->advance(); + + rewind($output->getStream()); + $this->assertEquals( + $this->generateOutput(' 0/10 [/ ] 0%'). + $this->generateOutput(' 1/10 [_/ ] 10%'), + stream_get_contents($output->getStream()) + ); + } + + public function testDisplayWithoutStart() + { + $bar = new ProgressBar($output = $this->getOutputStream(), 50); + $bar->display(); + + rewind($output->getStream()); + $this->assertEquals( + $this->generateOutput(' 0/50 [>---------------------------] 0%'), + stream_get_contents($output->getStream()) + ); + } + + public function testDisplayWithQuietVerbosity() + { + $bar = new ProgressBar($output = $this->getOutputStream(true, StreamOutput::VERBOSITY_QUIET), 50); + $bar->display(); + + rewind($output->getStream()); + $this->assertEquals( + '', + stream_get_contents($output->getStream()) + ); + } + + public function testFinishWithoutStart() + { + $bar = new ProgressBar($output = $this->getOutputStream(), 50); + $bar->finish(); + + rewind($output->getStream()); + $this->assertEquals( + $this->generateOutput(' 50/50 [============================] 100%'), + stream_get_contents($output->getStream()) + ); + } + + public function testPercent() + { + $bar = new ProgressBar($output = $this->getOutputStream(), 50); + $bar->start(); + $bar->display(); + $bar->advance(); + $bar->advance(); + + rewind($output->getStream()); + $this->assertEquals( + $this->generateOutput(' 0/50 [>---------------------------] 0%'). + $this->generateOutput(' 0/50 [>---------------------------] 0%'). + $this->generateOutput(' 1/50 [>---------------------------] 2%'). + $this->generateOutput(' 2/50 [=>--------------------------] 4%'), + stream_get_contents($output->getStream()) + ); + } + + public function testOverwriteWithShorterLine() + { + $bar = new ProgressBar($output = $this->getOutputStream(), 50); + $bar->setFormat(' %current%/%max% [%bar%] %percent:3s%%'); + $bar->start(); + $bar->display(); + $bar->advance(); + + // set shorter format + $bar->setFormat(' %current%/%max% [%bar%]'); + $bar->advance(); + + rewind($output->getStream()); + $this->assertEquals( + $this->generateOutput(' 0/50 [>---------------------------] 0%'). + $this->generateOutput(' 0/50 [>---------------------------] 0%'). + $this->generateOutput(' 1/50 [>---------------------------] 2%'). + $this->generateOutput(' 2/50 [=>--------------------------] '), + stream_get_contents($output->getStream()) + ); + } + + public function testStartWithMax() + { + $bar = new ProgressBar($output = $this->getOutputStream()); + $bar->setFormat('%current%/%max% [%bar%]'); + $bar->start(50); + $bar->advance(); + + rewind($output->getStream()); + $this->assertEquals( + $this->generateOutput(' 0/50 [>---------------------------]'). + $this->generateOutput(' 1/50 [>---------------------------]'), + stream_get_contents($output->getStream()) + ); + } + + public function testSetCurrentProgress() + { + $bar = new ProgressBar($output = $this->getOutputStream(), 50); + $bar->start(); + $bar->display(); + $bar->advance(); + $bar->setProgress(15); + $bar->setProgress(25); + + rewind($output->getStream()); + $this->assertEquals( + $this->generateOutput(' 0/50 [>---------------------------] 0%'). + $this->generateOutput(' 0/50 [>---------------------------] 0%'). + $this->generateOutput(' 1/50 [>---------------------------] 2%'). + $this->generateOutput(' 15/50 [========>-------------------] 30%'). + $this->generateOutput(' 25/50 [==============>-------------] 50%'), + stream_get_contents($output->getStream()) + ); + } + + /** + */ + public function testSetCurrentBeforeStarting() + { + $bar = new ProgressBar($this->getOutputStream()); + $bar->setProgress(15); + $this->assertNotNull($bar->getStartTime()); + } + + /** + * @expectedException \LogicException + * @expectedExceptionMessage You can't regress the progress bar + */ + public function testRegressProgress() + { + $bar = new ProgressBar($output = $this->getOutputStream(), 50); + $bar->start(); + $bar->setProgress(15); + $bar->setProgress(10); + } + + public function testRedrawFrequency() + { + $bar = $this->getMock('Symfony\Component\Console\Helper\ProgressBar', array('display'), array($output = $this->getOutputStream(), 6)); + $bar->expects($this->exactly(4))->method('display'); + + $bar->setRedrawFrequency(2); + $bar->start(); + $bar->setProgress(1); + $bar->advance(2); + $bar->advance(2); + $bar->advance(1); + } + + public function testMultiByteSupport() + { + if (!function_exists('mb_strlen') || (false === $encoding = mb_detect_encoding('■'))) { + $this->markTestSkipped('The mbstring extension is needed for multi-byte support'); + } + + $bar = new ProgressBar($output = $this->getOutputStream()); + $bar->start(); + $bar->setBarCharacter('■'); + $bar->advance(3); + + rewind($output->getStream()); + $this->assertEquals( + $this->generateOutput(' 0 [>---------------------------]'). + $this->generateOutput(' 3 [■■■>------------------------]'), + stream_get_contents($output->getStream()) + ); + } + + public function testClear() + { + $bar = new ProgressBar($output = $this->getOutputStream(), 50); + $bar->start(); + $bar->setProgress(25); + $bar->clear(); + + rewind($output->getStream()); + $this->assertEquals( + $this->generateOutput(' 0/50 [>---------------------------] 0%'). + $this->generateOutput(' 25/50 [==============>-------------] 50%'). + $this->generateOutput(' '), + stream_get_contents($output->getStream()) + ); + } + + public function testPercentNotHundredBeforeComplete() + { + $bar = new ProgressBar($output = $this->getOutputStream(), 200); + $bar->start(); + $bar->display(); + $bar->advance(199); + $bar->advance(); + + rewind($output->getStream()); + $this->assertEquals( + $this->generateOutput(' 0/200 [>---------------------------] 0%'). + $this->generateOutput(' 0/200 [>---------------------------] 0%'). + $this->generateOutput(' 199/200 [===========================>] 99%'). + $this->generateOutput(' 200/200 [============================] 100%'), + stream_get_contents($output->getStream()) + ); + } + + public function testNonDecoratedOutput() + { + $bar = new ProgressBar($output = $this->getOutputStream(false), 200); + $bar->start(); + + for ($i = 0; $i < 200; ++$i) { + $bar->advance(); + } + + $bar->finish(); + + rewind($output->getStream()); + $this->assertEquals( + ' 0/200 [>---------------------------] 0%'.PHP_EOL. + ' 20/200 [==>-------------------------] 10%'.PHP_EOL. + ' 40/200 [=====>----------------------] 20%'.PHP_EOL. + ' 60/200 [========>-------------------] 30%'.PHP_EOL. + ' 80/200 [===========>----------------] 40%'.PHP_EOL. + ' 100/200 [==============>-------------] 50%'.PHP_EOL. + ' 120/200 [================>-----------] 60%'.PHP_EOL. + ' 140/200 [===================>--------] 70%'.PHP_EOL. + ' 160/200 [======================>-----] 80%'.PHP_EOL. + ' 180/200 [=========================>--] 90%'.PHP_EOL. + ' 200/200 [============================] 100%', + stream_get_contents($output->getStream()) + ); + } + + public function testNonDecoratedOutputWithClear() + { + $bar = new ProgressBar($output = $this->getOutputStream(false), 50); + $bar->start(); + $bar->setProgress(25); + $bar->clear(); + $bar->setProgress(50); + $bar->finish(); + + rewind($output->getStream()); + $this->assertEquals( + ' 0/50 [>---------------------------] 0%'.PHP_EOL. + ' 25/50 [==============>-------------] 50%'.PHP_EOL. + ' 50/50 [============================] 100%', + stream_get_contents($output->getStream()) + ); + } + + public function testNonDecoratedOutputWithoutMax() + { + $bar = new ProgressBar($output = $this->getOutputStream(false)); + $bar->start(); + $bar->advance(); + + rewind($output->getStream()); + $this->assertEquals( + ' 0 [>---------------------------]'.PHP_EOL. + ' 1 [->--------------------------]', + stream_get_contents($output->getStream()) + ); + } + + public function testParallelBars() + { + $output = $this->getOutputStream(); + $bar1 = new ProgressBar($output, 2); + $bar2 = new ProgressBar($output, 3); + $bar2->setProgressCharacter('#'); + $bar3 = new ProgressBar($output); + + $bar1->start(); + $output->write("\n"); + $bar2->start(); + $output->write("\n"); + $bar3->start(); + + for ($i = 1; $i <= 3; ++$i) { + // up two lines + $output->write("\033[2A"); + if ($i <= 2) { + $bar1->advance(); + } + $output->write("\n"); + $bar2->advance(); + $output->write("\n"); + $bar3->advance(); + } + $output->write("\033[2A"); + $output->write("\n"); + $output->write("\n"); + $bar3->finish(); + + rewind($output->getStream()); + $this->assertEquals( + $this->generateOutput(' 0/2 [>---------------------------] 0%')."\n". + $this->generateOutput(' 0/3 [#---------------------------] 0%')."\n". + rtrim($this->generateOutput(' 0 [>---------------------------]')). + + "\033[2A". + $this->generateOutput(' 1/2 [==============>-------------] 50%')."\n". + $this->generateOutput(' 1/3 [=========#------------------] 33%')."\n". + rtrim($this->generateOutput(' 1 [->--------------------------]')). + + "\033[2A". + $this->generateOutput(' 2/2 [============================] 100%')."\n". + $this->generateOutput(' 2/3 [==================#---------] 66%')."\n". + rtrim($this->generateOutput(' 2 [-->-------------------------]')). + + "\033[2A". + "\n". + $this->generateOutput(' 3/3 [============================] 100%')."\n". + rtrim($this->generateOutput(' 3 [--->------------------------]')). + + "\033[2A". + "\n". + "\n". + rtrim($this->generateOutput(' 3 [============================]')), + stream_get_contents($output->getStream()) + ); + } + + public function testWithoutMax() + { + $output = $this->getOutputStream(); + + $bar = new ProgressBar($output); + $bar->start(); + $bar->advance(); + $bar->advance(); + $bar->advance(); + $bar->finish(); + + rewind($output->getStream()); + $this->assertEquals( + rtrim($this->generateOutput(' 0 [>---------------------------]')). + rtrim($this->generateOutput(' 1 [->--------------------------]')). + rtrim($this->generateOutput(' 2 [-->-------------------------]')). + rtrim($this->generateOutput(' 3 [--->------------------------]')). + rtrim($this->generateOutput(' 3 [============================]')), + stream_get_contents($output->getStream()) + ); + } + + public function testAddingPlaceholderFormatter() + { + ProgressBar::setPlaceholderFormatterDefinition('remaining_steps', function (ProgressBar $bar) { + return $bar->getMaxSteps() - $bar->getProgress(); + }); + $bar = new ProgressBar($output = $this->getOutputStream(), 3); + $bar->setFormat(' %remaining_steps% [%bar%]'); + + $bar->start(); + $bar->advance(); + $bar->finish(); + + rewind($output->getStream()); + $this->assertEquals( + $this->generateOutput(' 3 [>---------------------------]'). + $this->generateOutput(' 2 [=========>------------------]'). + $this->generateOutput(' 0 [============================]'), + stream_get_contents($output->getStream()) + ); + } + + public function testMultilineFormat() + { + $bar = new ProgressBar($output = $this->getOutputStream(), 3); + $bar->setFormat("%bar%\nfoobar"); + + $bar->start(); + $bar->advance(); + $bar->clear(); + $bar->finish(); + + rewind($output->getStream()); + $this->assertEquals( + $this->generateOutput(">---------------------------\nfoobar"). + $this->generateOutput("=========>------------------\nfoobar "). + $this->generateOutput(" \n "). + $this->generateOutput("============================\nfoobar "), + stream_get_contents($output->getStream()) + ); + } + + /** + * @requires extension mbstring + */ + public function testAnsiColorsAndEmojis() + { + $bar = new ProgressBar($output = $this->getOutputStream(), 15); + ProgressBar::setPlaceholderFormatterDefinition('memory', function (ProgressBar $bar) { + static $i = 0; + $mem = 100000 * $i; + $colors = $i++ ? '41;37' : '44;37'; + + return "\033[".$colors.'m '.Helper::formatMemory($mem)." \033[0m"; + }); + $bar->setFormat(" \033[44;37m %title:-37s% \033[0m\n %current%/%max% %bar% %percent:3s%%\n 🏁 %remaining:-10s% %memory:37s%"); + $bar->setBarCharacter($done = "\033[32m●\033[0m"); + $bar->setEmptyBarCharacter($empty = "\033[31m●\033[0m"); + $bar->setProgressCharacter($progress = "\033[32m➤ \033[0m"); + + $bar->setMessage('Starting the demo... fingers crossed', 'title'); + $bar->start(); + $bar->setMessage('Looks good to me...', 'title'); + $bar->advance(4); + $bar->setMessage('Thanks, bye', 'title'); + $bar->finish(); + + rewind($output->getStream()); + $this->assertEquals( + $this->generateOutput( + " \033[44;37m Starting the demo... fingers crossed \033[0m\n". + ' 0/15 '.$progress.str_repeat($empty, 26)." 0%\n". + " \xf0\x9f\x8f\x81 1 sec \033[44;37m 0 B \033[0m" + ). + $this->generateOutput( + " \033[44;37m Looks good to me... \033[0m\n". + ' 4/15 '.str_repeat($done, 7).$progress.str_repeat($empty, 19)." 26%\n". + " \xf0\x9f\x8f\x81 1 sec \033[41;37m 97 KiB \033[0m" + ). + $this->generateOutput( + " \033[44;37m Thanks, bye \033[0m\n". + ' 15/15 '.str_repeat($done, 28)." 100%\n". + " \xf0\x9f\x8f\x81 1 sec \033[41;37m 195 KiB \033[0m" + ), + stream_get_contents($output->getStream()) + ); + } + + public function testSetFormat() + { + $bar = new ProgressBar($output = $this->getOutputStream()); + $bar->setFormat('normal'); + $bar->start(); + rewind($output->getStream()); + $this->assertEquals( + $this->generateOutput(' 0 [>---------------------------]'), + stream_get_contents($output->getStream()) + ); + + $bar = new ProgressBar($output = $this->getOutputStream(), 10); + $bar->setFormat('normal'); + $bar->start(); + rewind($output->getStream()); + $this->assertEquals( + $this->generateOutput(' 0/10 [>---------------------------] 0%'), + stream_get_contents($output->getStream()) + ); + } + + /** + * @dataProvider provideFormat + */ + public function testFormatsWithoutMax($format) + { + $bar = new ProgressBar($output = $this->getOutputStream()); + $bar->setFormat($format); + $bar->start(); + + rewind($output->getStream()); + $this->assertNotEmpty(stream_get_contents($output->getStream())); + } + + /** + * Provides each defined format. + * + * @return array + */ + public function provideFormat() + { + return array( + array('normal'), + array('verbose'), + array('very_verbose'), + array('debug'), + ); + } + + protected function getOutputStream($decorated = true, $verbosity = StreamOutput::VERBOSITY_NORMAL) + { + return new StreamOutput(fopen('php://memory', 'r+', false), $verbosity, $decorated); + } + + protected function generateOutput($expected) + { + $count = substr_count($expected, "\n"); + + return "\x0D".($count ? sprintf("\033[%dA", $count) : '').$expected; + } +} diff --git a/vendor/symfony/console/Tests/Helper/QuestionHelperTest.php b/vendor/symfony/console/Tests/Helper/QuestionHelperTest.php new file mode 100644 index 0000000..a1f85b1 --- /dev/null +++ b/vendor/symfony/console/Tests/Helper/QuestionHelperTest.php @@ -0,0 +1,383 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Tests\Helper; + +use Symfony\Component\Console\Helper\QuestionHelper; +use Symfony\Component\Console\Helper\HelperSet; +use Symfony\Component\Console\Helper\FormatterHelper; +use Symfony\Component\Console\Output\StreamOutput; +use Symfony\Component\Console\Question\ChoiceQuestion; +use Symfony\Component\Console\Question\ConfirmationQuestion; +use Symfony\Component\Console\Question\Question; + +/** + * @group tty + */ +class QuestionHelperTest extends \PHPUnit_Framework_TestCase +{ + public function testAskChoice() + { + $questionHelper = new QuestionHelper(); + + $helperSet = new HelperSet(array(new FormatterHelper())); + $questionHelper->setHelperSet($helperSet); + + $heroes = array('Superman', 'Batman', 'Spiderman'); + + $questionHelper->setInputStream($this->getInputStream("\n1\n 1 \nFabien\n1\nFabien\n1\n0,2\n 0 , 2 \n\n\n")); + + $question = new ChoiceQuestion('What is your favorite superhero?', $heroes, '2'); + $question->setMaxAttempts(1); + // first answer is an empty answer, we're supposed to receive the default value + $this->assertEquals('Spiderman', $questionHelper->ask($this->createInputInterfaceMock(), $this->createOutputInterface(), $question)); + + $question = new ChoiceQuestion('What is your favorite superhero?', $heroes); + $question->setMaxAttempts(1); + $this->assertEquals('Batman', $questionHelper->ask($this->createInputInterfaceMock(), $this->createOutputInterface(), $question)); + $this->assertEquals('Batman', $questionHelper->ask($this->createInputInterfaceMock(), $this->createOutputInterface(), $question)); + + $question = new ChoiceQuestion('What is your favorite superhero?', $heroes); + $question->setErrorMessage('Input "%s" is not a superhero!'); + $question->setMaxAttempts(2); + $this->assertEquals('Batman', $questionHelper->ask($this->createInputInterfaceMock(), $output = $this->createOutputInterface(), $question)); + + rewind($output->getStream()); + $stream = stream_get_contents($output->getStream()); + $this->assertContains('Input "Fabien" is not a superhero!', $stream); + + try { + $question = new ChoiceQuestion('What is your favorite superhero?', $heroes, '1'); + $question->setMaxAttempts(1); + $questionHelper->ask($this->createInputInterfaceMock(), $output = $this->createOutputInterface(), $question); + $this->fail(); + } catch (\InvalidArgumentException $e) { + $this->assertEquals('Value "Fabien" is invalid', $e->getMessage()); + } + + $question = new ChoiceQuestion('What is your favorite superhero?', $heroes, null); + $question->setMaxAttempts(1); + $question->setMultiselect(true); + + $this->assertEquals(array('Batman'), $questionHelper->ask($this->createInputInterfaceMock(), $this->createOutputInterface(), $question)); + $this->assertEquals(array('Superman', 'Spiderman'), $questionHelper->ask($this->createInputInterfaceMock(), $this->createOutputInterface(), $question)); + $this->assertEquals(array('Superman', 'Spiderman'), $questionHelper->ask($this->createInputInterfaceMock(), $this->createOutputInterface(), $question)); + + $question = new ChoiceQuestion('What is your favorite superhero?', $heroes, '0,1'); + $question->setMaxAttempts(1); + $question->setMultiselect(true); + + $this->assertEquals(array('Superman', 'Batman'), $questionHelper->ask($this->createInputInterfaceMock(), $this->createOutputInterface(), $question)); + + $question = new ChoiceQuestion('What is your favorite superhero?', $heroes, ' 0 , 1 '); + $question->setMaxAttempts(1); + $question->setMultiselect(true); + + $this->assertEquals(array('Superman', 'Batman'), $questionHelper->ask($this->createInputInterfaceMock(), $this->createOutputInterface(), $question)); + } + + public function testAsk() + { + $dialog = new QuestionHelper(); + + $dialog->setInputStream($this->getInputStream("\n8AM\n")); + + $question = new Question('What time is it?', '2PM'); + $this->assertEquals('2PM', $dialog->ask($this->createInputInterfaceMock(), $this->createOutputInterface(), $question)); + + $question = new Question('What time is it?', '2PM'); + $this->assertEquals('8AM', $dialog->ask($this->createInputInterfaceMock(), $output = $this->createOutputInterface(), $question)); + + rewind($output->getStream()); + $this->assertEquals('What time is it?', stream_get_contents($output->getStream())); + } + + public function testAskWithAutocomplete() + { + if (!$this->hasSttyAvailable()) { + $this->markTestSkipped('`stty` is required to test autocomplete functionality'); + } + + // Acm + // AcsTest + // + // + // Test + // + // S + // F00oo + $inputStream = $this->getInputStream("Acm\nAc\177\177s\tTest\n\n\033[A\033[A\n\033[A\033[A\033[A\033[A\033[A\tTest\n\033[B\nS\177\177\033[B\033[B\nF00\177\177oo\t\n"); + + $dialog = new QuestionHelper(); + $dialog->setInputStream($inputStream); + $helperSet = new HelperSet(array(new FormatterHelper())); + $dialog->setHelperSet($helperSet); + + $question = new Question('Please select a bundle', 'FrameworkBundle'); + $question->setAutocompleterValues(array('AcmeDemoBundle', 'AsseticBundle', 'SecurityBundle', 'FooBundle')); + + $this->assertEquals('AcmeDemoBundle', $dialog->ask($this->createInputInterfaceMock(), $this->createOutputInterface(), $question)); + $this->assertEquals('AsseticBundleTest', $dialog->ask($this->createInputInterfaceMock(), $this->createOutputInterface(), $question)); + $this->assertEquals('FrameworkBundle', $dialog->ask($this->createInputInterfaceMock(), $this->createOutputInterface(), $question)); + $this->assertEquals('SecurityBundle', $dialog->ask($this->createInputInterfaceMock(), $this->createOutputInterface(), $question)); + $this->assertEquals('FooBundleTest', $dialog->ask($this->createInputInterfaceMock(), $this->createOutputInterface(), $question)); + $this->assertEquals('AcmeDemoBundle', $dialog->ask($this->createInputInterfaceMock(), $this->createOutputInterface(), $question)); + $this->assertEquals('AsseticBundle', $dialog->ask($this->createInputInterfaceMock(), $this->createOutputInterface(), $question)); + $this->assertEquals('FooBundle', $dialog->ask($this->createInputInterfaceMock(), $this->createOutputInterface(), $question)); + } + + public function testAskHiddenResponse() + { + if ('\\' === DIRECTORY_SEPARATOR) { + $this->markTestSkipped('This test is not supported on Windows'); + } + + $dialog = new QuestionHelper(); + $dialog->setInputStream($this->getInputStream("8AM\n")); + + $question = new Question('What time is it?'); + $question->setHidden(true); + + $this->assertEquals('8AM', $dialog->ask($this->createInputInterfaceMock(), $this->createOutputInterface(), $question)); + } + + /** + * @dataProvider getAskConfirmationData + */ + public function testAskConfirmation($question, $expected, $default = true) + { + $dialog = new QuestionHelper(); + + $dialog->setInputStream($this->getInputStream($question."\n")); + $question = new ConfirmationQuestion('Do you like French fries?', $default); + $this->assertEquals($expected, $dialog->ask($this->createInputInterfaceMock(), $this->createOutputInterface(), $question), 'confirmation question should '.($expected ? 'pass' : 'cancel')); + } + + public function getAskConfirmationData() + { + return array( + array('', true), + array('', false, false), + array('y', true), + array('yes', true), + array('n', false), + array('no', false), + ); + } + + public function testAskConfirmationWithCustomTrueAnswer() + { + $dialog = new QuestionHelper(); + + $dialog->setInputStream($this->getInputStream("j\ny\n")); + $question = new ConfirmationQuestion('Do you like French fries?', false, '/^(j|y)/i'); + $this->assertTrue($dialog->ask($this->createInputInterfaceMock(), $this->createOutputInterface(), $question)); + $question = new ConfirmationQuestion('Do you like French fries?', false, '/^(j|y)/i'); + $this->assertTrue($dialog->ask($this->createInputInterfaceMock(), $this->createOutputInterface(), $question)); + } + + public function testAskAndValidate() + { + $dialog = new QuestionHelper(); + $helperSet = new HelperSet(array(new FormatterHelper())); + $dialog->setHelperSet($helperSet); + + $error = 'This is not a color!'; + $validator = function ($color) use ($error) { + if (!in_array($color, array('white', 'black'))) { + throw new \InvalidArgumentException($error); + } + + return $color; + }; + + $question = new Question('What color was the white horse of Henry IV?', 'white'); + $question->setValidator($validator); + $question->setMaxAttempts(2); + + $dialog->setInputStream($this->getInputStream("\nblack\n")); + $this->assertEquals('white', $dialog->ask($this->createInputInterfaceMock(), $this->createOutputInterface(), $question)); + $this->assertEquals('black', $dialog->ask($this->createInputInterfaceMock(), $this->createOutputInterface(), $question)); + + $dialog->setInputStream($this->getInputStream("green\nyellow\norange\n")); + try { + $dialog->ask($this->createInputInterfaceMock(), $this->createOutputInterface(), $question); + $this->fail(); + } catch (\InvalidArgumentException $e) { + $this->assertEquals($error, $e->getMessage()); + } + } + + /** + * @dataProvider simpleAnswerProvider + */ + public function testSelectChoiceFromSimpleChoices($providedAnswer, $expectedValue) + { + $possibleChoices = array( + 'My environment 1', + 'My environment 2', + 'My environment 3', + ); + + $dialog = new QuestionHelper(); + $dialog->setInputStream($this->getInputStream($providedAnswer."\n")); + $helperSet = new HelperSet(array(new FormatterHelper())); + $dialog->setHelperSet($helperSet); + + $question = new ChoiceQuestion('Please select the environment to load', $possibleChoices); + $question->setMaxAttempts(1); + $answer = $dialog->ask($this->createInputInterfaceMock(), $this->createOutputInterface(), $question); + + $this->assertSame($expectedValue, $answer); + } + + public function simpleAnswerProvider() + { + return array( + array(0, 'My environment 1'), + array(1, 'My environment 2'), + array(2, 'My environment 3'), + array('My environment 1', 'My environment 1'), + array('My environment 2', 'My environment 2'), + array('My environment 3', 'My environment 3'), + ); + } + + /** + * @dataProvider mixedKeysChoiceListAnswerProvider + */ + public function testChoiceFromChoicelistWithMixedKeys($providedAnswer, $expectedValue) + { + $possibleChoices = array( + '0' => 'No environment', + '1' => 'My environment 1', + 'env_2' => 'My environment 2', + 3 => 'My environment 3', + ); + + $dialog = new QuestionHelper(); + $dialog->setInputStream($this->getInputStream($providedAnswer."\n")); + $helperSet = new HelperSet(array(new FormatterHelper())); + $dialog->setHelperSet($helperSet); + + $question = new ChoiceQuestion('Please select the environment to load', $possibleChoices); + $question->setMaxAttempts(1); + $answer = $dialog->ask($this->createInputInterfaceMock(), $this->createOutputInterface(), $question); + + $this->assertSame($expectedValue, $answer); + } + + public function mixedKeysChoiceListAnswerProvider() + { + return array( + array('0', '0'), + array('No environment', '0'), + array('1', '1'), + array('env_2', 'env_2'), + array(3, '3'), + array('My environment 1', '1'), + ); + } + + /** + * @dataProvider answerProvider + */ + public function testSelectChoiceFromChoiceList($providedAnswer, $expectedValue) + { + $possibleChoices = array( + 'env_1' => 'My environment 1', + 'env_2' => 'My environment', + 'env_3' => 'My environment', + ); + + $dialog = new QuestionHelper(); + $dialog->setInputStream($this->getInputStream($providedAnswer."\n")); + $helperSet = new HelperSet(array(new FormatterHelper())); + $dialog->setHelperSet($helperSet); + + $question = new ChoiceQuestion('Please select the environment to load', $possibleChoices); + $question->setMaxAttempts(1); + $answer = $dialog->ask($this->createInputInterfaceMock(), $this->createOutputInterface(), $question); + + $this->assertSame($expectedValue, $answer); + } + + /** + * @expectedException \InvalidArgumentException + * @expectedExceptionMessage The provided answer is ambiguous. Value should be one of env_2 or env_3. + */ + public function testAmbiguousChoiceFromChoicelist() + { + $possibleChoices = array( + 'env_1' => 'My first environment', + 'env_2' => 'My environment', + 'env_3' => 'My environment', + ); + + $dialog = new QuestionHelper(); + $dialog->setInputStream($this->getInputStream("My environment\n")); + $helperSet = new HelperSet(array(new FormatterHelper())); + $dialog->setHelperSet($helperSet); + + $question = new ChoiceQuestion('Please select the environment to load', $possibleChoices); + $question->setMaxAttempts(1); + + $dialog->ask($this->createInputInterfaceMock(), $this->createOutputInterface(), $question); + } + + public function answerProvider() + { + return array( + array('env_1', 'env_1'), + array('env_2', 'env_2'), + array('env_3', 'env_3'), + array('My environment 1', 'env_1'), + ); + } + + public function testNoInteraction() + { + $dialog = new QuestionHelper(); + $question = new Question('Do you have a job?', 'not yet'); + $this->assertEquals('not yet', $dialog->ask($this->createInputInterfaceMock(false), $this->createOutputInterface(), $question)); + } + + protected function getInputStream($input) + { + $stream = fopen('php://memory', 'r+', false); + fwrite($stream, $input); + rewind($stream); + + return $stream; + } + + protected function createOutputInterface() + { + return new StreamOutput(fopen('php://memory', 'r+', false)); + } + + protected function createInputInterfaceMock($interactive = true) + { + $mock = $this->getMock('Symfony\Component\Console\Input\InputInterface'); + $mock->expects($this->any()) + ->method('isInteractive') + ->will($this->returnValue($interactive)); + + return $mock; + } + + private function hasSttyAvailable() + { + exec('stty 2>&1', $output, $exitcode); + + return $exitcode === 0; + } +} diff --git a/vendor/symfony/console/Tests/Helper/TableStyleTest.php b/vendor/symfony/console/Tests/Helper/TableStyleTest.php new file mode 100644 index 0000000..587d841 --- /dev/null +++ b/vendor/symfony/console/Tests/Helper/TableStyleTest.php @@ -0,0 +1,27 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Tests\Helper; + +use Symfony\Component\Console\Helper\TableStyle; + +class TableStyleTest extends \PHPUnit_Framework_TestCase +{ + /** + * @expectedException \InvalidArgumentException + * @expectedExceptionMessage Invalid padding type. Expected one of (STR_PAD_LEFT, STR_PAD_RIGHT, STR_PAD_BOTH). + */ + public function testSetPadTypeWithInvalidType() + { + $style = new TableStyle(); + $style->setPadType('TEST'); + } +} diff --git a/vendor/symfony/console/Tests/Helper/TableTest.php b/vendor/symfony/console/Tests/Helper/TableTest.php new file mode 100644 index 0000000..ad05379 --- /dev/null +++ b/vendor/symfony/console/Tests/Helper/TableTest.php @@ -0,0 +1,568 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Tests\Helper; + +use Symfony\Component\Console\Helper\Table; +use Symfony\Component\Console\Helper\TableStyle; +use Symfony\Component\Console\Helper\TableSeparator; +use Symfony\Component\Console\Helper\TableCell; +use Symfony\Component\Console\Output\StreamOutput; + +class TableTest extends \PHPUnit_Framework_TestCase +{ + protected $stream; + + protected function setUp() + { + $this->stream = fopen('php://memory', 'r+'); + } + + protected function tearDown() + { + fclose($this->stream); + $this->stream = null; + } + + /** + * @dataProvider testRenderProvider + */ + public function testRender($headers, $rows, $style, $expected) + { + $table = new Table($output = $this->getOutputStream()); + $table + ->setHeaders($headers) + ->setRows($rows) + ->setStyle($style) + ; + $table->render(); + + $this->assertEquals($expected, $this->getOutputContent($output)); + } + + /** + * @dataProvider testRenderProvider + */ + public function testRenderAddRows($headers, $rows, $style, $expected) + { + $table = new Table($output = $this->getOutputStream()); + $table + ->setHeaders($headers) + ->addRows($rows) + ->setStyle($style) + ; + $table->render(); + + $this->assertEquals($expected, $this->getOutputContent($output)); + } + + /** + * @dataProvider testRenderProvider + */ + public function testRenderAddRowsOneByOne($headers, $rows, $style, $expected) + { + $table = new Table($output = $this->getOutputStream()); + $table + ->setHeaders($headers) + ->setStyle($style) + ; + foreach ($rows as $row) { + $table->addRow($row); + } + $table->render(); + + $this->assertEquals($expected, $this->getOutputContent($output)); + } + + public function testRenderProvider() + { + $books = array( + array('99921-58-10-7', 'Divine Comedy', 'Dante Alighieri'), + array('9971-5-0210-0', 'A Tale of Two Cities', 'Charles Dickens'), + array('960-425-059-0', 'The Lord of the Rings', 'J. R. R. Tolkien'), + array('80-902734-1-6', 'And Then There Were None', 'Agatha Christie'), + ); + + return array( + array( + array('ISBN', 'Title', 'Author'), + $books, + 'default', +<<
    array( + array('ISBN', 'Title', 'Author'), + array( + array('99921-58-10-7', 'Divine Comedy', 'Dante Alighieri'), + array('9971-5-0210-0', 'A Tale of Two Cities', 'Charles Dickens'), + ), + 'default', +<<
    array( + array('ISBN', 'Title', 'Author'), + array( + array('99921-58-10-700', 'Divine Com', 'Dante Alighieri'), + array('9971-5-0210-0', 'A Tale of Two Cities', 'Charles Dickens'), + ), + 'default', +<<
    99921-58-10-700 | Divine Com | Dante Alighieri | +| 9971-5-0210-0 | A Tale of Two Cities | Charles Dickens | ++----------------------------------+----------------------+-----------------+ + +TABLE + ), + 'Cell with colspan' => array( + array('ISBN', 'Title', 'Author'), + array( + array('99921-58-10-7', 'Divine Comedy', 'Dante Alighieri'), + new TableSeparator(), + array(new TableCell('Divine Comedy(Dante Alighieri)', array('colspan' => 3))), + new TableSeparator(), + array( + new TableCell('Arduino: A Quick-Start Guide', array('colspan' => 2)), + 'Mark Schmidt', + ), + new TableSeparator(), + array( + '9971-5-0210-0', + new TableCell("A Tale of \nTwo Cities", array('colspan' => 2)), + ), + ), + 'default', +<<
    array( + array('ISBN', 'Title', 'Author'), + array( + array( + new TableCell('9971-5-0210-0', array('rowspan' => 3)), + 'Divine Comedy', + 'Dante Alighieri', + ), + array('A Tale of Two Cities', 'Charles Dickens'), + array("The Lord of \nthe Rings", "J. R. \nR. Tolkien"), + new TableSeparator(), + array('80-902734-1-6', new TableCell("And Then \nThere \nWere None", array('rowspan' => 3)), 'Agatha Christie'), + array('80-902734-1-7', 'Test'), + ), + 'default', +<<
    array( + array('ISBN', 'Title', 'Author'), + array( + array( + new TableCell('9971-5-0210-0', array('rowspan' => 2, 'colspan' => 2)), + 'Dante Alighieri', + ), + array('Charles Dickens'), + new TableSeparator(), + array( + 'Dante Alighieri', + new TableCell('9971-5-0210-0', array('rowspan' => 3, 'colspan' => 2)), + ), + array('J. R. R. Tolkien'), + array('J. R. R'), + ), + 'default', +<<
    array( + array('ISBN', 'Title', 'Author'), + array( + array( + new TableCell("9971\n-5-\n021\n0-0", array('rowspan' => 2, 'colspan' => 2)), + 'Dante Alighieri', + ), + array('Charles Dickens'), + new TableSeparator(), + array( + 'Dante Alighieri', + new TableCell("9971\n-5-\n021\n0-0", array('rowspan' => 2, 'colspan' => 2)), + ), + array('Charles Dickens'), + new TableSeparator(), + array( + new TableCell("9971\n-5-\n021\n0-0", array('rowspan' => 2, 'colspan' => 2)), + new TableCell("Dante \nAlighieri", array('rowspan' => 2, 'colspan' => 1)), + ), + ), + 'default', +<<
    array( + array('ISBN', 'Title', 'Author'), + array( + array( + new TableCell("9971\n-5-\n021\n0-0", array('rowspan' => 2, 'colspan' => 2)), + 'Dante Alighieri', + ), + array('Charles Dickens'), + array( + 'Dante Alighieri', + new TableCell("9971\n-5-\n021\n0-0", array('rowspan' => 2, 'colspan' => 2)), + ), + array('Charles Dickens'), + ), + 'default', +<<
    array( + array('ISBN', 'Author'), + array( + array( + new TableCell('9971-5-0210-0', array('rowspan' => 3, 'colspan' => 1)), + 'Dante Alighieri', + ), + array(new TableSeparator()), + array('Charles Dickens'), + ), + 'default', +<<
    array( + array( + array(new TableCell('Main title', array('colspan' => 3))), + array('ISBN', 'Title', 'Author'), + ), + array(), + 'default', +<<
    markTestSkipped('The "mbstring" extension is not available'); + } + + $table = new Table($output = $this->getOutputStream()); + $table + ->setHeaders(array('■■')) + ->setRows(array(array(1234))) + ->setStyle('default') + ; + $table->render(); + + $expected = +<<
    assertEquals($expected, $this->getOutputContent($output)); + } + + public function testStyle() + { + $style = new TableStyle(); + $style + ->setHorizontalBorderChar('.') + ->setVerticalBorderChar('.') + ->setCrossingChar('.') + ; + + Table::setStyleDefinition('dotfull', $style); + $table = new Table($output = $this->getOutputStream()); + $table + ->setHeaders(array('Foo')) + ->setRows(array(array('Bar'))) + ->setStyle('dotfull'); + $table->render(); + + $expected = +<<
    assertEquals($expected, $this->getOutputContent($output)); + } + + public function testRowSeparator() + { + $table = new Table($output = $this->getOutputStream()); + $table + ->setHeaders(array('Foo')) + ->setRows(array( + array('Bar1'), + new TableSeparator(), + array('Bar2'), + new TableSeparator(), + array('Bar3'), + )); + $table->render(); + + $expected = +<<
    assertEquals($expected, $this->getOutputContent($output)); + + $this->assertEquals($table, $table->addRow(new TableSeparator()), 'fluent interface on addRow() with a single TableSeparator() works'); + } + + protected function getOutputStream() + { + return new StreamOutput($this->stream, StreamOutput::VERBOSITY_NORMAL, false); + } + + protected function getOutputContent(StreamOutput $output) + { + rewind($output->getStream()); + + return str_replace(PHP_EOL, "\n", stream_get_contents($output->getStream())); + } +} diff --git a/vendor/symfony/console/Tests/Input/ArgvInputTest.php b/vendor/symfony/console/Tests/Input/ArgvInputTest.php new file mode 100644 index 0000000..d2c540e --- /dev/null +++ b/vendor/symfony/console/Tests/Input/ArgvInputTest.php @@ -0,0 +1,317 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Tests\Input; + +use Symfony\Component\Console\Input\ArgvInput; +use Symfony\Component\Console\Input\InputDefinition; +use Symfony\Component\Console\Input\InputArgument; +use Symfony\Component\Console\Input\InputOption; + +class ArgvInputTest extends \PHPUnit_Framework_TestCase +{ + public function testConstructor() + { + $_SERVER['argv'] = array('cli.php', 'foo'); + $input = new ArgvInput(); + $r = new \ReflectionObject($input); + $p = $r->getProperty('tokens'); + $p->setAccessible(true); + + $this->assertEquals(array('foo'), $p->getValue($input), '__construct() automatically get its input from the argv server variable'); + } + + public function testParseArguments() + { + $input = new ArgvInput(array('cli.php', 'foo')); + $input->bind(new InputDefinition(array(new InputArgument('name')))); + $this->assertEquals(array('name' => 'foo'), $input->getArguments(), '->parse() parses required arguments'); + + $input->bind(new InputDefinition(array(new InputArgument('name')))); + $this->assertEquals(array('name' => 'foo'), $input->getArguments(), '->parse() is stateless'); + } + + /** + * @dataProvider provideOptions + */ + public function testParseOptions($input, $options, $expectedOptions, $message) + { + $input = new ArgvInput($input); + $input->bind(new InputDefinition($options)); + + $this->assertEquals($expectedOptions, $input->getOptions(), $message); + } + + public function provideOptions() + { + return array( + array( + array('cli.php', '--foo'), + array(new InputOption('foo')), + array('foo' => true), + '->parse() parses long options without a value', + ), + array( + array('cli.php', '--foo=bar'), + array(new InputOption('foo', 'f', InputOption::VALUE_REQUIRED)), + array('foo' => 'bar'), + '->parse() parses long options with a required value (with a = separator)', + ), + array( + array('cli.php', '--foo', 'bar'), + array(new InputOption('foo', 'f', InputOption::VALUE_REQUIRED)), + array('foo' => 'bar'), + '->parse() parses long options with a required value (with a space separator)', + ), + array( + array('cli.php', '-f'), + array(new InputOption('foo', 'f')), + array('foo' => true), + '->parse() parses short options without a value', + ), + array( + array('cli.php', '-fbar'), + array(new InputOption('foo', 'f', InputOption::VALUE_REQUIRED)), + array('foo' => 'bar'), + '->parse() parses short options with a required value (with no separator)', + ), + array( + array('cli.php', '-f', 'bar'), + array(new InputOption('foo', 'f', InputOption::VALUE_REQUIRED)), + array('foo' => 'bar'), + '->parse() parses short options with a required value (with a space separator)', + ), + array( + array('cli.php', '-f', ''), + array(new InputOption('foo', 'f', InputOption::VALUE_OPTIONAL)), + array('foo' => ''), + '->parse() parses short options with an optional empty value', + ), + array( + array('cli.php', '-f', '', 'foo'), + array(new InputArgument('name'), new InputOption('foo', 'f', InputOption::VALUE_OPTIONAL)), + array('foo' => ''), + '->parse() parses short options with an optional empty value followed by an argument', + ), + array( + array('cli.php', '-f', '', '-b'), + array(new InputOption('foo', 'f', InputOption::VALUE_OPTIONAL), new InputOption('bar', 'b')), + array('foo' => '', 'bar' => true), + '->parse() parses short options with an optional empty value followed by an option', + ), + array( + array('cli.php', '-f', '-b', 'foo'), + array(new InputArgument('name'), new InputOption('foo', 'f', InputOption::VALUE_OPTIONAL), new InputOption('bar', 'b')), + array('foo' => null, 'bar' => true), + '->parse() parses short options with an optional value which is not present', + ), + array( + array('cli.php', '-fb'), + array(new InputOption('foo', 'f'), new InputOption('bar', 'b')), + array('foo' => true, 'bar' => true), + '->parse() parses short options when they are aggregated as a single one', + ), + array( + array('cli.php', '-fb', 'bar'), + array(new InputOption('foo', 'f'), new InputOption('bar', 'b', InputOption::VALUE_REQUIRED)), + array('foo' => true, 'bar' => 'bar'), + '->parse() parses short options when they are aggregated as a single one and the last one has a required value', + ), + array( + array('cli.php', '-fb', 'bar'), + array(new InputOption('foo', 'f'), new InputOption('bar', 'b', InputOption::VALUE_OPTIONAL)), + array('foo' => true, 'bar' => 'bar'), + '->parse() parses short options when they are aggregated as a single one and the last one has an optional value', + ), + array( + array('cli.php', '-fbbar'), + array(new InputOption('foo', 'f'), new InputOption('bar', 'b', InputOption::VALUE_OPTIONAL)), + array('foo' => true, 'bar' => 'bar'), + '->parse() parses short options when they are aggregated as a single one and the last one has an optional value with no separator', + ), + array( + array('cli.php', '-fbbar'), + array(new InputOption('foo', 'f', InputOption::VALUE_OPTIONAL), new InputOption('bar', 'b', InputOption::VALUE_OPTIONAL)), + array('foo' => 'bbar', 'bar' => null), + '->parse() parses short options when they are aggregated as a single one and one of them takes a value', + ), + ); + } + + /** + * @dataProvider provideInvalidInput + */ + public function testInvalidInput($argv, $definition, $expectedExceptionMessage) + { + $this->setExpectedException('RuntimeException', $expectedExceptionMessage); + + $input = new ArgvInput($argv); + $input->bind($definition); + } + + public function provideInvalidInput() + { + return array( + array( + array('cli.php', '--foo'), + new InputDefinition(array(new InputOption('foo', 'f', InputOption::VALUE_REQUIRED))), + 'The "--foo" option requires a value.', + ), + array( + array('cli.php', '-f'), + new InputDefinition(array(new InputOption('foo', 'f', InputOption::VALUE_REQUIRED))), + 'The "--foo" option requires a value.', + ), + array( + array('cli.php', '-ffoo'), + new InputDefinition(array(new InputOption('foo', 'f', InputOption::VALUE_NONE))), + 'The "-o" option does not exist.', + ), + array( + array('cli.php', '--foo=bar'), + new InputDefinition(array(new InputOption('foo', 'f', InputOption::VALUE_NONE))), + 'The "--foo" option does not accept a value.', + ), + array( + array('cli.php', 'foo', 'bar'), + new InputDefinition(), + 'Too many arguments.', + ), + array( + array('cli.php', '--foo'), + new InputDefinition(), + 'The "--foo" option does not exist.', + ), + array( + array('cli.php', '-f'), + new InputDefinition(), + 'The "-f" option does not exist.', + ), + array( + array('cli.php', '-1'), + new InputDefinition(array(new InputArgument('number'))), + 'The "-1" option does not exist.', + ), + ); + } + + public function testParseArrayArgument() + { + $input = new ArgvInput(array('cli.php', 'foo', 'bar', 'baz', 'bat')); + $input->bind(new InputDefinition(array(new InputArgument('name', InputArgument::IS_ARRAY)))); + + $this->assertEquals(array('name' => array('foo', 'bar', 'baz', 'bat')), $input->getArguments(), '->parse() parses array arguments'); + } + + public function testParseArrayOption() + { + $input = new ArgvInput(array('cli.php', '--name=foo', '--name=bar', '--name=baz')); + $input->bind(new InputDefinition(array(new InputOption('name', null, InputOption::VALUE_OPTIONAL | InputOption::VALUE_IS_ARRAY)))); + + $this->assertEquals(array('name' => array('foo', 'bar', 'baz')), $input->getOptions(), '->parse() parses array options ("--option=value" syntax)'); + + $input = new ArgvInput(array('cli.php', '--name', 'foo', '--name', 'bar', '--name', 'baz')); + $input->bind(new InputDefinition(array(new InputOption('name', null, InputOption::VALUE_OPTIONAL | InputOption::VALUE_IS_ARRAY)))); + $this->assertEquals(array('name' => array('foo', 'bar', 'baz')), $input->getOptions(), '->parse() parses array options ("--option value" syntax)'); + + $input = new ArgvInput(array('cli.php', '--name=foo', '--name=bar', '--name=')); + $input->bind(new InputDefinition(array(new InputOption('name', null, InputOption::VALUE_OPTIONAL | InputOption::VALUE_IS_ARRAY)))); + $this->assertSame(array('name' => array('foo', 'bar', null)), $input->getOptions(), '->parse() parses empty array options as null ("--option=value" syntax)'); + + $input = new ArgvInput(array('cli.php', '--name', 'foo', '--name', 'bar', '--name', '--anotherOption')); + $input->bind(new InputDefinition(array( + new InputOption('name', null, InputOption::VALUE_OPTIONAL | InputOption::VALUE_IS_ARRAY), + new InputOption('anotherOption', null, InputOption::VALUE_NONE), + ))); + $this->assertSame(array('name' => array('foo', 'bar', null), 'anotherOption' => true), $input->getOptions(), '->parse() parses empty array options as null ("--option value" syntax)'); + } + + public function testParseNegativeNumberAfterDoubleDash() + { + $input = new ArgvInput(array('cli.php', '--', '-1')); + $input->bind(new InputDefinition(array(new InputArgument('number')))); + $this->assertEquals(array('number' => '-1'), $input->getArguments(), '->parse() parses arguments with leading dashes as arguments after having encountered a double-dash sequence'); + + $input = new ArgvInput(array('cli.php', '-f', 'bar', '--', '-1')); + $input->bind(new InputDefinition(array(new InputArgument('number'), new InputOption('foo', 'f', InputOption::VALUE_OPTIONAL)))); + $this->assertEquals(array('foo' => 'bar'), $input->getOptions(), '->parse() parses arguments with leading dashes as options before having encountered a double-dash sequence'); + $this->assertEquals(array('number' => '-1'), $input->getArguments(), '->parse() parses arguments with leading dashes as arguments after having encountered a double-dash sequence'); + } + + public function testParseEmptyStringArgument() + { + $input = new ArgvInput(array('cli.php', '-f', 'bar', '')); + $input->bind(new InputDefinition(array(new InputArgument('empty'), new InputOption('foo', 'f', InputOption::VALUE_OPTIONAL)))); + + $this->assertEquals(array('empty' => ''), $input->getArguments(), '->parse() parses empty string arguments'); + } + + public function testGetFirstArgument() + { + $input = new ArgvInput(array('cli.php', '-fbbar')); + $this->assertNull($input->getFirstArgument(), '->getFirstArgument() returns null when there is no arguments'); + + $input = new ArgvInput(array('cli.php', '-fbbar', 'foo')); + $this->assertEquals('foo', $input->getFirstArgument(), '->getFirstArgument() returns the first argument from the raw input'); + } + + public function testHasParameterOption() + { + $input = new ArgvInput(array('cli.php', '-f', 'foo')); + $this->assertTrue($input->hasParameterOption('-f'), '->hasParameterOption() returns true if the given short option is in the raw input'); + + $input = new ArgvInput(array('cli.php', '--foo', 'foo')); + $this->assertTrue($input->hasParameterOption('--foo'), '->hasParameterOption() returns true if the given short option is in the raw input'); + + $input = new ArgvInput(array('cli.php', 'foo')); + $this->assertFalse($input->hasParameterOption('--foo'), '->hasParameterOption() returns false if the given short option is not in the raw input'); + + $input = new ArgvInput(array('cli.php', '--foo=bar')); + $this->assertTrue($input->hasParameterOption('--foo'), '->hasParameterOption() returns true if the given option with provided value is in the raw input'); + } + + public function testToString() + { + $input = new ArgvInput(array('cli.php', '-f', 'foo')); + $this->assertEquals('-f foo', (string) $input); + + $input = new ArgvInput(array('cli.php', '-f', '--bar=foo', 'a b c d', "A\nB'C")); + $this->assertEquals('-f --bar=foo '.escapeshellarg('a b c d').' '.escapeshellarg("A\nB'C"), (string) $input); + } + + /** + * @dataProvider provideGetParameterOptionValues + */ + public function testGetParameterOptionEqualSign($argv, $key, $expected) + { + $input = new ArgvInput($argv); + $this->assertEquals($expected, $input->getParameterOption($key), '->getParameterOption() returns the expected value'); + } + + public function provideGetParameterOptionValues() + { + return array( + array(array('app/console', 'foo:bar', '-e', 'dev'), '-e', 'dev'), + array(array('app/console', 'foo:bar', '--env=dev'), '--env', 'dev'), + array(array('app/console', 'foo:bar', '-e', 'dev'), array('-e', '--env'), 'dev'), + array(array('app/console', 'foo:bar', '--env=dev'), array('-e', '--env'), 'dev'), + array(array('app/console', 'foo:bar', '--env=dev', '--en=1'), array('--en'), '1'), + array(array('app/console', 'foo:bar', '--env=dev', '', '--en=1'), array('--en'), '1'), + ); + } + + public function testParseSingleDashAsArgument() + { + $input = new ArgvInput(array('cli.php', '-')); + $input->bind(new InputDefinition(array(new InputArgument('file')))); + $this->assertEquals(array('file' => '-'), $input->getArguments(), '->parse() parses single dash as an argument'); + } +} diff --git a/vendor/symfony/console/Tests/Input/ArrayInputTest.php b/vendor/symfony/console/Tests/Input/ArrayInputTest.php new file mode 100644 index 0000000..cc89083 --- /dev/null +++ b/vendor/symfony/console/Tests/Input/ArrayInputTest.php @@ -0,0 +1,138 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Tests\Input; + +use Symfony\Component\Console\Input\ArrayInput; +use Symfony\Component\Console\Input\InputDefinition; +use Symfony\Component\Console\Input\InputArgument; +use Symfony\Component\Console\Input\InputOption; + +class ArrayInputTest extends \PHPUnit_Framework_TestCase +{ + public function testGetFirstArgument() + { + $input = new ArrayInput(array()); + $this->assertNull($input->getFirstArgument(), '->getFirstArgument() returns null if no argument were passed'); + $input = new ArrayInput(array('name' => 'Fabien')); + $this->assertEquals('Fabien', $input->getFirstArgument(), '->getFirstArgument() returns the first passed argument'); + $input = new ArrayInput(array('--foo' => 'bar', 'name' => 'Fabien')); + $this->assertEquals('Fabien', $input->getFirstArgument(), '->getFirstArgument() returns the first passed argument'); + } + + public function testHasParameterOption() + { + $input = new ArrayInput(array('name' => 'Fabien', '--foo' => 'bar')); + $this->assertTrue($input->hasParameterOption('--foo'), '->hasParameterOption() returns true if an option is present in the passed parameters'); + $this->assertFalse($input->hasParameterOption('--bar'), '->hasParameterOption() returns false if an option is not present in the passed parameters'); + + $input = new ArrayInput(array('--foo')); + $this->assertTrue($input->hasParameterOption('--foo'), '->hasParameterOption() returns true if an option is present in the passed parameters'); + } + + public function testGetParameterOption() + { + $input = new ArrayInput(array('name' => 'Fabien', '--foo' => 'bar')); + $this->assertEquals('bar', $input->getParameterOption('--foo'), '->getParameterOption() returns the option of specified name'); + + $input = new ArrayInput(array('Fabien', '--foo' => 'bar')); + $this->assertEquals('bar', $input->getParameterOption('--foo'), '->getParameterOption() returns the option of specified name'); + } + + public function testParseArguments() + { + $input = new ArrayInput(array('name' => 'foo'), new InputDefinition(array(new InputArgument('name')))); + + $this->assertEquals(array('name' => 'foo'), $input->getArguments(), '->parse() parses required arguments'); + } + + /** + * @dataProvider provideOptions + */ + public function testParseOptions($input, $options, $expectedOptions, $message) + { + $input = new ArrayInput($input, new InputDefinition($options)); + + $this->assertEquals($expectedOptions, $input->getOptions(), $message); + } + + public function provideOptions() + { + return array( + array( + array('--foo' => 'bar'), + array(new InputOption('foo')), + array('foo' => 'bar'), + '->parse() parses long options', + ), + array( + array('--foo' => 'bar'), + array(new InputOption('foo', 'f', InputOption::VALUE_OPTIONAL, '', 'default')), + array('foo' => 'bar'), + '->parse() parses long options with a default value', + ), + array( + array('--foo' => null), + array(new InputOption('foo', 'f', InputOption::VALUE_OPTIONAL, '', 'default')), + array('foo' => 'default'), + '->parse() parses long options with a default value', + ), + array( + array('-f' => 'bar'), + array(new InputOption('foo', 'f')), + array('foo' => 'bar'), + '->parse() parses short options', + ), + ); + } + + /** + * @dataProvider provideInvalidInput + */ + public function testParseInvalidInput($parameters, $definition, $expectedExceptionMessage) + { + $this->setExpectedException('InvalidArgumentException', $expectedExceptionMessage); + + new ArrayInput($parameters, $definition); + } + + public function provideInvalidInput() + { + return array( + array( + array('foo' => 'foo'), + new InputDefinition(array(new InputArgument('name'))), + 'The "foo" argument does not exist.', + ), + array( + array('--foo' => null), + new InputDefinition(array(new InputOption('foo', 'f', InputOption::VALUE_REQUIRED))), + 'The "--foo" option requires a value.', + ), + array( + array('--foo' => 'foo'), + new InputDefinition(), + 'The "--foo" option does not exist.', + ), + array( + array('-o' => 'foo'), + new InputDefinition(), + 'The "-o" option does not exist.', + ), + ); + } + + public function testToString() + { + $input = new ArrayInput(array('-f' => null, '-b' => 'bar', '--foo' => 'b a z', '--lala' => null, 'test' => 'Foo', 'test2' => "A\nB'C")); + $this->assertEquals('-f -b=bar --foo='.escapeshellarg('b a z').' --lala Foo '.escapeshellarg("A\nB'C"), (string) $input); + } +} diff --git a/vendor/symfony/console/Tests/Input/InputArgumentTest.php b/vendor/symfony/console/Tests/Input/InputArgumentTest.php new file mode 100644 index 0000000..cfb37cd --- /dev/null +++ b/vendor/symfony/console/Tests/Input/InputArgumentTest.php @@ -0,0 +1,111 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Tests\Input; + +use Symfony\Component\Console\Input\InputArgument; + +class InputArgumentTest extends \PHPUnit_Framework_TestCase +{ + public function testConstructor() + { + $argument = new InputArgument('foo'); + $this->assertEquals('foo', $argument->getName(), '__construct() takes a name as its first argument'); + } + + public function testModes() + { + $argument = new InputArgument('foo'); + $this->assertFalse($argument->isRequired(), '__construct() gives a "InputArgument::OPTIONAL" mode by default'); + + $argument = new InputArgument('foo', null); + $this->assertFalse($argument->isRequired(), '__construct() can take "InputArgument::OPTIONAL" as its mode'); + + $argument = new InputArgument('foo', InputArgument::OPTIONAL); + $this->assertFalse($argument->isRequired(), '__construct() can take "InputArgument::OPTIONAL" as its mode'); + + $argument = new InputArgument('foo', InputArgument::REQUIRED); + $this->assertTrue($argument->isRequired(), '__construct() can take "InputArgument::REQUIRED" as its mode'); + } + + /** + * @dataProvider provideInvalidModes + */ + public function testInvalidModes($mode) + { + $this->setExpectedException('InvalidArgumentException', sprintf('Argument mode "%s" is not valid.', $mode)); + + new InputArgument('foo', $mode); + } + + public function provideInvalidModes() + { + return array( + array('ANOTHER_ONE'), + array(-1), + ); + } + + public function testIsArray() + { + $argument = new InputArgument('foo', InputArgument::IS_ARRAY); + $this->assertTrue($argument->isArray(), '->isArray() returns true if the argument can be an array'); + $argument = new InputArgument('foo', InputArgument::OPTIONAL | InputArgument::IS_ARRAY); + $this->assertTrue($argument->isArray(), '->isArray() returns true if the argument can be an array'); + $argument = new InputArgument('foo', InputArgument::OPTIONAL); + $this->assertFalse($argument->isArray(), '->isArray() returns false if the argument can not be an array'); + } + + public function testGetDescription() + { + $argument = new InputArgument('foo', null, 'Some description'); + $this->assertEquals('Some description', $argument->getDescription(), '->getDescription() return the message description'); + } + + public function testGetDefault() + { + $argument = new InputArgument('foo', InputArgument::OPTIONAL, '', 'default'); + $this->assertEquals('default', $argument->getDefault(), '->getDefault() return the default value'); + } + + public function testSetDefault() + { + $argument = new InputArgument('foo', InputArgument::OPTIONAL, '', 'default'); + $argument->setDefault(null); + $this->assertNull($argument->getDefault(), '->setDefault() can reset the default value by passing null'); + $argument->setDefault('another'); + $this->assertEquals('another', $argument->getDefault(), '->setDefault() changes the default value'); + + $argument = new InputArgument('foo', InputArgument::OPTIONAL | InputArgument::IS_ARRAY); + $argument->setDefault(array(1, 2)); + $this->assertEquals(array(1, 2), $argument->getDefault(), '->setDefault() changes the default value'); + } + + /** + * @expectedException \LogicException + * @expectedExceptionMessage Cannot set a default value except for InputArgument::OPTIONAL mode. + */ + public function testSetDefaultWithRequiredArgument() + { + $argument = new InputArgument('foo', InputArgument::REQUIRED); + $argument->setDefault('default'); + } + + /** + * @expectedException \LogicException + * @expectedExceptionMessage A default value for an array argument must be an array. + */ + public function testSetDefaultWithArrayArgument() + { + $argument = new InputArgument('foo', InputArgument::IS_ARRAY); + $argument->setDefault('default'); + } +} diff --git a/vendor/symfony/console/Tests/Input/InputDefinitionTest.php b/vendor/symfony/console/Tests/Input/InputDefinitionTest.php new file mode 100644 index 0000000..7e0a242 --- /dev/null +++ b/vendor/symfony/console/Tests/Input/InputDefinitionTest.php @@ -0,0 +1,437 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Tests\Input; + +use Symfony\Component\Console\Input\InputDefinition; +use Symfony\Component\Console\Input\InputArgument; +use Symfony\Component\Console\Input\InputOption; + +class InputDefinitionTest extends \PHPUnit_Framework_TestCase +{ + protected static $fixtures; + + protected $foo, $bar, $foo1, $foo2; + + public static function setUpBeforeClass() + { + self::$fixtures = __DIR__.'/../Fixtures/'; + } + + public function testConstructorArguments() + { + $this->initializeArguments(); + + $definition = new InputDefinition(); + $this->assertEquals(array(), $definition->getArguments(), '__construct() creates a new InputDefinition object'); + + $definition = new InputDefinition(array($this->foo, $this->bar)); + $this->assertEquals(array('foo' => $this->foo, 'bar' => $this->bar), $definition->getArguments(), '__construct() takes an array of InputArgument objects as its first argument'); + } + + public function testConstructorOptions() + { + $this->initializeOptions(); + + $definition = new InputDefinition(); + $this->assertEquals(array(), $definition->getOptions(), '__construct() creates a new InputDefinition object'); + + $definition = new InputDefinition(array($this->foo, $this->bar)); + $this->assertEquals(array('foo' => $this->foo, 'bar' => $this->bar), $definition->getOptions(), '__construct() takes an array of InputOption objects as its first argument'); + } + + public function testSetArguments() + { + $this->initializeArguments(); + + $definition = new InputDefinition(); + $definition->setArguments(array($this->foo)); + $this->assertEquals(array('foo' => $this->foo), $definition->getArguments(), '->setArguments() sets the array of InputArgument objects'); + $definition->setArguments(array($this->bar)); + + $this->assertEquals(array('bar' => $this->bar), $definition->getArguments(), '->setArguments() clears all InputArgument objects'); + } + + public function testAddArguments() + { + $this->initializeArguments(); + + $definition = new InputDefinition(); + $definition->addArguments(array($this->foo)); + $this->assertEquals(array('foo' => $this->foo), $definition->getArguments(), '->addArguments() adds an array of InputArgument objects'); + $definition->addArguments(array($this->bar)); + $this->assertEquals(array('foo' => $this->foo, 'bar' => $this->bar), $definition->getArguments(), '->addArguments() does not clear existing InputArgument objects'); + } + + public function testAddArgument() + { + $this->initializeArguments(); + + $definition = new InputDefinition(); + $definition->addArgument($this->foo); + $this->assertEquals(array('foo' => $this->foo), $definition->getArguments(), '->addArgument() adds a InputArgument object'); + $definition->addArgument($this->bar); + $this->assertEquals(array('foo' => $this->foo, 'bar' => $this->bar), $definition->getArguments(), '->addArgument() adds a InputArgument object'); + } + + /** + * @expectedException \LogicException + * @expectedExceptionMessage An argument with name "foo" already exists. + */ + public function testArgumentsMustHaveDifferentNames() + { + $this->initializeArguments(); + + $definition = new InputDefinition(); + $definition->addArgument($this->foo); + $definition->addArgument($this->foo1); + } + + /** + * @expectedException \LogicException + * @expectedExceptionMessage Cannot add an argument after an array argument. + */ + public function testArrayArgumentHasToBeLast() + { + $this->initializeArguments(); + + $definition = new InputDefinition(); + $definition->addArgument(new InputArgument('fooarray', InputArgument::IS_ARRAY)); + $definition->addArgument(new InputArgument('anotherbar')); + } + + /** + * @expectedException \LogicException + * @expectedExceptionMessage Cannot add a required argument after an optional one. + */ + public function testRequiredArgumentCannotFollowAnOptionalOne() + { + $this->initializeArguments(); + + $definition = new InputDefinition(); + $definition->addArgument($this->foo); + $definition->addArgument($this->foo2); + } + + public function testGetArgument() + { + $this->initializeArguments(); + + $definition = new InputDefinition(); + $definition->addArguments(array($this->foo)); + $this->assertEquals($this->foo, $definition->getArgument('foo'), '->getArgument() returns a InputArgument by its name'); + } + + /** + * @expectedException \InvalidArgumentException + * @expectedExceptionMessage The "bar" argument does not exist. + */ + public function testGetInvalidArgument() + { + $this->initializeArguments(); + + $definition = new InputDefinition(); + $definition->addArguments(array($this->foo)); + $definition->getArgument('bar'); + } + + public function testHasArgument() + { + $this->initializeArguments(); + + $definition = new InputDefinition(); + $definition->addArguments(array($this->foo)); + + $this->assertTrue($definition->hasArgument('foo'), '->hasArgument() returns true if a InputArgument exists for the given name'); + $this->assertFalse($definition->hasArgument('bar'), '->hasArgument() returns false if a InputArgument exists for the given name'); + } + + public function testGetArgumentRequiredCount() + { + $this->initializeArguments(); + + $definition = new InputDefinition(); + $definition->addArgument($this->foo2); + $this->assertEquals(1, $definition->getArgumentRequiredCount(), '->getArgumentRequiredCount() returns the number of required arguments'); + $definition->addArgument($this->foo); + $this->assertEquals(1, $definition->getArgumentRequiredCount(), '->getArgumentRequiredCount() returns the number of required arguments'); + } + + public function testGetArgumentCount() + { + $this->initializeArguments(); + + $definition = new InputDefinition(); + $definition->addArgument($this->foo2); + $this->assertEquals(1, $definition->getArgumentCount(), '->getArgumentCount() returns the number of arguments'); + $definition->addArgument($this->foo); + $this->assertEquals(2, $definition->getArgumentCount(), '->getArgumentCount() returns the number of arguments'); + } + + public function testGetArgumentDefaults() + { + $definition = new InputDefinition(array( + new InputArgument('foo1', InputArgument::OPTIONAL), + new InputArgument('foo2', InputArgument::OPTIONAL, '', 'default'), + new InputArgument('foo3', InputArgument::OPTIONAL | InputArgument::IS_ARRAY), + // new InputArgument('foo4', InputArgument::OPTIONAL | InputArgument::IS_ARRAY, '', array(1, 2)), + )); + $this->assertEquals(array('foo1' => null, 'foo2' => 'default', 'foo3' => array()), $definition->getArgumentDefaults(), '->getArgumentDefaults() return the default values for each argument'); + + $definition = new InputDefinition(array( + new InputArgument('foo4', InputArgument::OPTIONAL | InputArgument::IS_ARRAY, '', array(1, 2)), + )); + $this->assertEquals(array('foo4' => array(1, 2)), $definition->getArgumentDefaults(), '->getArgumentDefaults() return the default values for each argument'); + } + + public function testSetOptions() + { + $this->initializeOptions(); + + $definition = new InputDefinition(array($this->foo)); + $this->assertEquals(array('foo' => $this->foo), $definition->getOptions(), '->setOptions() sets the array of InputOption objects'); + $definition->setOptions(array($this->bar)); + $this->assertEquals(array('bar' => $this->bar), $definition->getOptions(), '->setOptions() clears all InputOption objects'); + } + + /** + * @expectedException \InvalidArgumentException + * @expectedExceptionMessage The "-f" option does not exist. + */ + public function testSetOptionsClearsOptions() + { + $this->initializeOptions(); + + $definition = new InputDefinition(array($this->foo)); + $definition->setOptions(array($this->bar)); + $definition->getOptionForShortcut('f'); + } + + public function testAddOptions() + { + $this->initializeOptions(); + + $definition = new InputDefinition(array($this->foo)); + $this->assertEquals(array('foo' => $this->foo), $definition->getOptions(), '->addOptions() adds an array of InputOption objects'); + $definition->addOptions(array($this->bar)); + $this->assertEquals(array('foo' => $this->foo, 'bar' => $this->bar), $definition->getOptions(), '->addOptions() does not clear existing InputOption objects'); + } + + public function testAddOption() + { + $this->initializeOptions(); + + $definition = new InputDefinition(); + $definition->addOption($this->foo); + $this->assertEquals(array('foo' => $this->foo), $definition->getOptions(), '->addOption() adds a InputOption object'); + $definition->addOption($this->bar); + $this->assertEquals(array('foo' => $this->foo, 'bar' => $this->bar), $definition->getOptions(), '->addOption() adds a InputOption object'); + } + + /** + * @expectedException \LogicException + * @expectedExceptionMessage An option named "foo" already exists. + */ + public function testAddDuplicateOption() + { + $this->initializeOptions(); + + $definition = new InputDefinition(); + $definition->addOption($this->foo); + $definition->addOption($this->foo2); + } + + /** + * @expectedException \LogicException + * @expectedExceptionMessage An option with shortcut "f" already exists. + */ + public function testAddDuplicateShortcutOption() + { + $this->initializeOptions(); + + $definition = new InputDefinition(); + $definition->addOption($this->foo); + $definition->addOption($this->foo1); + } + + public function testGetOption() + { + $this->initializeOptions(); + + $definition = new InputDefinition(array($this->foo)); + $this->assertEquals($this->foo, $definition->getOption('foo'), '->getOption() returns a InputOption by its name'); + } + + /** + * @expectedException \InvalidArgumentException + * @expectedExceptionMessage The "--bar" option does not exist. + */ + public function testGetInvalidOption() + { + $this->initializeOptions(); + + $definition = new InputDefinition(array($this->foo)); + $definition->getOption('bar'); + } + + public function testHasOption() + { + $this->initializeOptions(); + + $definition = new InputDefinition(array($this->foo)); + $this->assertTrue($definition->hasOption('foo'), '->hasOption() returns true if a InputOption exists for the given name'); + $this->assertFalse($definition->hasOption('bar'), '->hasOption() returns false if a InputOption exists for the given name'); + } + + public function testHasShortcut() + { + $this->initializeOptions(); + + $definition = new InputDefinition(array($this->foo)); + $this->assertTrue($definition->hasShortcut('f'), '->hasShortcut() returns true if a InputOption exists for the given shortcut'); + $this->assertFalse($definition->hasShortcut('b'), '->hasShortcut() returns false if a InputOption exists for the given shortcut'); + } + + public function testGetOptionForShortcut() + { + $this->initializeOptions(); + + $definition = new InputDefinition(array($this->foo)); + $this->assertEquals($this->foo, $definition->getOptionForShortcut('f'), '->getOptionForShortcut() returns a InputOption by its shortcut'); + } + + public function testGetOptionForMultiShortcut() + { + $this->initializeOptions(); + + $definition = new InputDefinition(array($this->multi)); + $this->assertEquals($this->multi, $definition->getOptionForShortcut('m'), '->getOptionForShortcut() returns a InputOption by its shortcut'); + $this->assertEquals($this->multi, $definition->getOptionForShortcut('mmm'), '->getOptionForShortcut() returns a InputOption by its shortcut'); + } + + /** + * @expectedException \InvalidArgumentException + * @expectedExceptionMessage The "-l" option does not exist. + */ + public function testGetOptionForInvalidShortcut() + { + $this->initializeOptions(); + + $definition = new InputDefinition(array($this->foo)); + $definition->getOptionForShortcut('l'); + } + + public function testGetOptionDefaults() + { + $definition = new InputDefinition(array( + new InputOption('foo1', null, InputOption::VALUE_NONE), + new InputOption('foo2', null, InputOption::VALUE_REQUIRED), + new InputOption('foo3', null, InputOption::VALUE_REQUIRED, '', 'default'), + new InputOption('foo4', null, InputOption::VALUE_OPTIONAL), + new InputOption('foo5', null, InputOption::VALUE_OPTIONAL, '', 'default'), + new InputOption('foo6', null, InputOption::VALUE_OPTIONAL | InputOption::VALUE_IS_ARRAY), + new InputOption('foo7', null, InputOption::VALUE_OPTIONAL | InputOption::VALUE_IS_ARRAY, '', array(1, 2)), + )); + $defaults = array( + 'foo1' => false, + 'foo2' => null, + 'foo3' => 'default', + 'foo4' => null, + 'foo5' => 'default', + 'foo6' => array(), + 'foo7' => array(1, 2), + ); + $this->assertSame($defaults, $definition->getOptionDefaults(), '->getOptionDefaults() returns the default values for all options'); + } + + /** + * @dataProvider getGetSynopsisData + */ + public function testGetSynopsis(InputDefinition $definition, $expectedSynopsis, $message = null) + { + $this->assertEquals($expectedSynopsis, $definition->getSynopsis(), $message ? '->getSynopsis() '.$message : ''); + } + + public function getGetSynopsisData() + { + return array( + array(new InputDefinition(array(new InputOption('foo'))), '[--foo]', 'puts optional options in square brackets'), + array(new InputDefinition(array(new InputOption('foo', 'f'))), '[-f|--foo]', 'separates shortcut with a pipe'), + array(new InputDefinition(array(new InputOption('foo', 'f', InputOption::VALUE_REQUIRED))), '[-f|--foo FOO]', 'uses shortcut as value placeholder'), + array(new InputDefinition(array(new InputOption('foo', 'f', InputOption::VALUE_OPTIONAL))), '[-f|--foo [FOO]]', 'puts optional values in square brackets'), + + array(new InputDefinition(array(new InputArgument('foo', InputArgument::REQUIRED))), '', 'puts arguments in angle brackets'), + array(new InputDefinition(array(new InputArgument('foo'))), '[]', 'puts optional arguments in square brackets'), + array(new InputDefinition(array(new InputArgument('foo', InputArgument::IS_ARRAY))), '[]...', 'uses an ellipsis for array arguments'), + array(new InputDefinition(array(new InputArgument('foo', InputArgument::REQUIRED | InputArgument::IS_ARRAY))), ' ()...', 'uses parenthesis and ellipsis for required array arguments'), + + array(new InputDefinition(array(new InputOption('foo'), new InputArgument('foo', InputArgument::REQUIRED))), '[--foo] [--] ', 'puts [--] between options and arguments'), + ); + } + + public function testGetShortSynopsis() + { + $definition = new InputDefinition(array(new InputOption('foo'), new InputOption('bar'), new InputArgument('cat'))); + $this->assertEquals('[options] [--] []', $definition->getSynopsis(true), '->getSynopsis(true) groups options in [options]'); + } + + /** + * @group legacy + */ + public function testLegacyAsText() + { + $definition = new InputDefinition(array( + new InputArgument('foo', InputArgument::OPTIONAL, 'The foo argument'), + new InputArgument('baz', InputArgument::OPTIONAL, 'The baz argument', true), + new InputArgument('bar', InputArgument::OPTIONAL | InputArgument::IS_ARRAY, 'The bar argument', array('http://foo.com/')), + new InputOption('foo', 'f', InputOption::VALUE_REQUIRED, 'The foo option'), + new InputOption('baz', null, InputOption::VALUE_OPTIONAL, 'The baz option', false), + new InputOption('bar', 'b', InputOption::VALUE_OPTIONAL, 'The bar option', 'bar'), + new InputOption('qux', '', InputOption::VALUE_OPTIONAL | InputOption::VALUE_IS_ARRAY, 'The qux option', array('http://foo.com/', 'bar')), + new InputOption('qux2', '', InputOption::VALUE_OPTIONAL | InputOption::VALUE_IS_ARRAY, 'The qux2 option', array('foo' => 'bar')), + )); + + $this->assertStringEqualsFile(self::$fixtures.'/definition_astext.txt', $definition->asText(), '->asText() returns a textual representation of the InputDefinition'); + } + + /** + * @group legacy + */ + public function testLegacyAsXml() + { + $definition = new InputDefinition(array( + new InputArgument('foo', InputArgument::OPTIONAL, 'The foo argument'), + new InputArgument('baz', InputArgument::OPTIONAL, 'The baz argument', true), + new InputArgument('bar', InputArgument::OPTIONAL | InputArgument::IS_ARRAY, 'The bar argument', array('bar')), + new InputOption('foo', 'f', InputOption::VALUE_REQUIRED, 'The foo option'), + new InputOption('baz', null, InputOption::VALUE_OPTIONAL, 'The baz option', false), + new InputOption('bar', 'b', InputOption::VALUE_OPTIONAL, 'The bar option', 'bar'), + )); + $this->assertXmlStringEqualsXmlFile(self::$fixtures.'/definition_asxml.txt', $definition->asXml(), '->asXml() returns an XML representation of the InputDefinition'); + } + + protected function initializeArguments() + { + $this->foo = new InputArgument('foo'); + $this->bar = new InputArgument('bar'); + $this->foo1 = new InputArgument('foo'); + $this->foo2 = new InputArgument('foo2', InputArgument::REQUIRED); + } + + protected function initializeOptions() + { + $this->foo = new InputOption('foo', 'f'); + $this->bar = new InputOption('bar', 'b'); + $this->foo1 = new InputOption('fooBis', 'f'); + $this->foo2 = new InputOption('foo', 'p'); + $this->multi = new InputOption('multi', 'm|mm|mmm'); + } +} diff --git a/vendor/symfony/console/Tests/Input/InputOptionTest.php b/vendor/symfony/console/Tests/Input/InputOptionTest.php new file mode 100644 index 0000000..53ce1df --- /dev/null +++ b/vendor/symfony/console/Tests/Input/InputOptionTest.php @@ -0,0 +1,204 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Tests\Input; + +use Symfony\Component\Console\Input\InputOption; + +class InputOptionTest extends \PHPUnit_Framework_TestCase +{ + public function testConstructor() + { + $option = new InputOption('foo'); + $this->assertEquals('foo', $option->getName(), '__construct() takes a name as its first argument'); + $option = new InputOption('--foo'); + $this->assertEquals('foo', $option->getName(), '__construct() removes the leading -- of the option name'); + } + + /** + * @expectedException \InvalidArgumentException + * @expectedExceptionMessage Impossible to have an option mode VALUE_IS_ARRAY if the option does not accept a value. + */ + public function testArrayModeWithoutValue() + { + new InputOption('foo', 'f', InputOption::VALUE_IS_ARRAY); + } + + public function testShortcut() + { + $option = new InputOption('foo', 'f'); + $this->assertEquals('f', $option->getShortcut(), '__construct() can take a shortcut as its second argument'); + $option = new InputOption('foo', '-f|-ff|fff'); + $this->assertEquals('f|ff|fff', $option->getShortcut(), '__construct() removes the leading - of the shortcuts'); + $option = new InputOption('foo', array('f', 'ff', '-fff')); + $this->assertEquals('f|ff|fff', $option->getShortcut(), '__construct() removes the leading - of the shortcuts'); + $option = new InputOption('foo'); + $this->assertNull($option->getShortcut(), '__construct() makes the shortcut null by default'); + } + + public function testModes() + { + $option = new InputOption('foo', 'f'); + $this->assertFalse($option->acceptValue(), '__construct() gives a "InputOption::VALUE_NONE" mode by default'); + $this->assertFalse($option->isValueRequired(), '__construct() gives a "InputOption::VALUE_NONE" mode by default'); + $this->assertFalse($option->isValueOptional(), '__construct() gives a "InputOption::VALUE_NONE" mode by default'); + + $option = new InputOption('foo', 'f', null); + $this->assertFalse($option->acceptValue(), '__construct() can take "InputOption::VALUE_NONE" as its mode'); + $this->assertFalse($option->isValueRequired(), '__construct() can take "InputOption::VALUE_NONE" as its mode'); + $this->assertFalse($option->isValueOptional(), '__construct() can take "InputOption::VALUE_NONE" as its mode'); + + $option = new InputOption('foo', 'f', InputOption::VALUE_NONE); + $this->assertFalse($option->acceptValue(), '__construct() can take "InputOption::VALUE_NONE" as its mode'); + $this->assertFalse($option->isValueRequired(), '__construct() can take "InputOption::VALUE_NONE" as its mode'); + $this->assertFalse($option->isValueOptional(), '__construct() can take "InputOption::VALUE_NONE" as its mode'); + + $option = new InputOption('foo', 'f', InputOption::VALUE_REQUIRED); + $this->assertTrue($option->acceptValue(), '__construct() can take "InputOption::VALUE_REQUIRED" as its mode'); + $this->assertTrue($option->isValueRequired(), '__construct() can take "InputOption::VALUE_REQUIRED" as its mode'); + $this->assertFalse($option->isValueOptional(), '__construct() can take "InputOption::VALUE_REQUIRED" as its mode'); + + $option = new InputOption('foo', 'f', InputOption::VALUE_OPTIONAL); + $this->assertTrue($option->acceptValue(), '__construct() can take "InputOption::VALUE_OPTIONAL" as its mode'); + $this->assertFalse($option->isValueRequired(), '__construct() can take "InputOption::VALUE_OPTIONAL" as its mode'); + $this->assertTrue($option->isValueOptional(), '__construct() can take "InputOption::VALUE_OPTIONAL" as its mode'); + } + + /** + * @dataProvider provideInvalidModes + */ + public function testInvalidModes($mode) + { + $this->setExpectedException('InvalidArgumentException', sprintf('Option mode "%s" is not valid.', $mode)); + + new InputOption('foo', 'f', $mode); + } + + public function provideInvalidModes() + { + return array( + array('ANOTHER_ONE'), + array(-1), + ); + } + + /** + * @expectedException \InvalidArgumentException + */ + public function testEmptyNameIsInvalid() + { + new InputOption(''); + } + + /** + * @expectedException \InvalidArgumentException + */ + public function testDoubleDashNameIsInvalid() + { + new InputOption('--'); + } + + /** + * @expectedException \InvalidArgumentException + */ + public function testSingleDashOptionIsInvalid() + { + new InputOption('foo', '-'); + } + + public function testIsArray() + { + $option = new InputOption('foo', null, InputOption::VALUE_OPTIONAL | InputOption::VALUE_IS_ARRAY); + $this->assertTrue($option->isArray(), '->isArray() returns true if the option can be an array'); + $option = new InputOption('foo', null, InputOption::VALUE_NONE); + $this->assertFalse($option->isArray(), '->isArray() returns false if the option can not be an array'); + } + + public function testGetDescription() + { + $option = new InputOption('foo', 'f', null, 'Some description'); + $this->assertEquals('Some description', $option->getDescription(), '->getDescription() returns the description message'); + } + + public function testGetDefault() + { + $option = new InputOption('foo', null, InputOption::VALUE_OPTIONAL, '', 'default'); + $this->assertEquals('default', $option->getDefault(), '->getDefault() returns the default value'); + + $option = new InputOption('foo', null, InputOption::VALUE_REQUIRED, '', 'default'); + $this->assertEquals('default', $option->getDefault(), '->getDefault() returns the default value'); + + $option = new InputOption('foo', null, InputOption::VALUE_REQUIRED); + $this->assertNull($option->getDefault(), '->getDefault() returns null if no default value is configured'); + + $option = new InputOption('foo', null, InputOption::VALUE_OPTIONAL | InputOption::VALUE_IS_ARRAY); + $this->assertEquals(array(), $option->getDefault(), '->getDefault() returns an empty array if option is an array'); + + $option = new InputOption('foo', null, InputOption::VALUE_NONE); + $this->assertFalse($option->getDefault(), '->getDefault() returns false if the option does not take a value'); + } + + public function testSetDefault() + { + $option = new InputOption('foo', null, InputOption::VALUE_REQUIRED, '', 'default'); + $option->setDefault(null); + $this->assertNull($option->getDefault(), '->setDefault() can reset the default value by passing null'); + $option->setDefault('another'); + $this->assertEquals('another', $option->getDefault(), '->setDefault() changes the default value'); + + $option = new InputOption('foo', null, InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY); + $option->setDefault(array(1, 2)); + $this->assertEquals(array(1, 2), $option->getDefault(), '->setDefault() changes the default value'); + } + + /** + * @expectedException \LogicException + * @expectedExceptionMessage Cannot set a default value when using InputOption::VALUE_NONE mode. + */ + public function testDefaultValueWithValueNoneMode() + { + $option = new InputOption('foo', 'f', InputOption::VALUE_NONE); + $option->setDefault('default'); + } + + /** + * @expectedException \LogicException + * @expectedExceptionMessage A default value for an array option must be an array. + */ + public function testDefaultValueWithIsArrayMode() + { + $option = new InputOption('foo', 'f', InputOption::VALUE_OPTIONAL | InputOption::VALUE_IS_ARRAY); + $option->setDefault('default'); + } + + public function testEquals() + { + $option = new InputOption('foo', 'f', null, 'Some description'); + $option2 = new InputOption('foo', 'f', null, 'Alternative description'); + $this->assertTrue($option->equals($option2)); + + $option = new InputOption('foo', 'f', InputOption::VALUE_OPTIONAL, 'Some description'); + $option2 = new InputOption('foo', 'f', InputOption::VALUE_OPTIONAL, 'Some description', true); + $this->assertFalse($option->equals($option2)); + + $option = new InputOption('foo', 'f', null, 'Some description'); + $option2 = new InputOption('bar', 'f', null, 'Some description'); + $this->assertFalse($option->equals($option2)); + + $option = new InputOption('foo', 'f', null, 'Some description'); + $option2 = new InputOption('foo', '', null, 'Some description'); + $this->assertFalse($option->equals($option2)); + + $option = new InputOption('foo', 'f', null, 'Some description'); + $option2 = new InputOption('foo', 'f', InputOption::VALUE_OPTIONAL, 'Some description'); + $this->assertFalse($option->equals($option2)); + } +} diff --git a/vendor/symfony/console/Tests/Input/InputTest.php b/vendor/symfony/console/Tests/Input/InputTest.php new file mode 100644 index 0000000..0b3e38f --- /dev/null +++ b/vendor/symfony/console/Tests/Input/InputTest.php @@ -0,0 +1,121 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Tests\Input; + +use Symfony\Component\Console\Input\ArrayInput; +use Symfony\Component\Console\Input\InputDefinition; +use Symfony\Component\Console\Input\InputArgument; +use Symfony\Component\Console\Input\InputOption; + +class InputTest extends \PHPUnit_Framework_TestCase +{ + public function testConstructor() + { + $input = new ArrayInput(array('name' => 'foo'), new InputDefinition(array(new InputArgument('name')))); + $this->assertEquals('foo', $input->getArgument('name'), '->__construct() takes a InputDefinition as an argument'); + } + + public function testOptions() + { + $input = new ArrayInput(array('--name' => 'foo'), new InputDefinition(array(new InputOption('name')))); + $this->assertEquals('foo', $input->getOption('name'), '->getOption() returns the value for the given option'); + + $input->setOption('name', 'bar'); + $this->assertEquals('bar', $input->getOption('name'), '->setOption() sets the value for a given option'); + $this->assertEquals(array('name' => 'bar'), $input->getOptions(), '->getOptions() returns all option values'); + + $input = new ArrayInput(array('--name' => 'foo'), new InputDefinition(array(new InputOption('name'), new InputOption('bar', '', InputOption::VALUE_OPTIONAL, '', 'default')))); + $this->assertEquals('default', $input->getOption('bar'), '->getOption() returns the default value for optional options'); + $this->assertEquals(array('name' => 'foo', 'bar' => 'default'), $input->getOptions(), '->getOptions() returns all option values, even optional ones'); + } + + /** + * @expectedException \InvalidArgumentException + * @expectedExceptionMessage The "foo" option does not exist. + */ + public function testSetInvalidOption() + { + $input = new ArrayInput(array('--name' => 'foo'), new InputDefinition(array(new InputOption('name'), new InputOption('bar', '', InputOption::VALUE_OPTIONAL, '', 'default')))); + $input->setOption('foo', 'bar'); + } + + /** + * @expectedException \InvalidArgumentException + * @expectedExceptionMessage The "foo" option does not exist. + */ + public function testGetInvalidOption() + { + $input = new ArrayInput(array('--name' => 'foo'), new InputDefinition(array(new InputOption('name'), new InputOption('bar', '', InputOption::VALUE_OPTIONAL, '', 'default')))); + $input->getOption('foo'); + } + + public function testArguments() + { + $input = new ArrayInput(array('name' => 'foo'), new InputDefinition(array(new InputArgument('name')))); + $this->assertEquals('foo', $input->getArgument('name'), '->getArgument() returns the value for the given argument'); + + $input->setArgument('name', 'bar'); + $this->assertEquals('bar', $input->getArgument('name'), '->setArgument() sets the value for a given argument'); + $this->assertEquals(array('name' => 'bar'), $input->getArguments(), '->getArguments() returns all argument values'); + + $input = new ArrayInput(array('name' => 'foo'), new InputDefinition(array(new InputArgument('name'), new InputArgument('bar', InputArgument::OPTIONAL, '', 'default')))); + $this->assertEquals('default', $input->getArgument('bar'), '->getArgument() returns the default value for optional arguments'); + $this->assertEquals(array('name' => 'foo', 'bar' => 'default'), $input->getArguments(), '->getArguments() returns all argument values, even optional ones'); + } + + /** + * @expectedException \InvalidArgumentException + * @expectedExceptionMessage The "foo" argument does not exist. + */ + public function testSetInvalidArgument() + { + $input = new ArrayInput(array('name' => 'foo'), new InputDefinition(array(new InputArgument('name'), new InputArgument('bar', InputArgument::OPTIONAL, '', 'default')))); + $input->setArgument('foo', 'bar'); + } + + /** + * @expectedException \InvalidArgumentException + * @expectedExceptionMessage The "foo" argument does not exist. + */ + public function testGetInvalidArgument() + { + $input = new ArrayInput(array('name' => 'foo'), new InputDefinition(array(new InputArgument('name'), new InputArgument('bar', InputArgument::OPTIONAL, '', 'default')))); + $input->getArgument('foo'); + } + + /** + * @expectedException \RuntimeException + * @expectedExceptionMessage Not enough arguments. + */ + public function testValidateWithMissingArguments() + { + $input = new ArrayInput(array()); + $input->bind(new InputDefinition(array(new InputArgument('name', InputArgument::REQUIRED)))); + $input->validate(); + } + + public function testValidate() + { + $input = new ArrayInput(array('name' => 'foo')); + $input->bind(new InputDefinition(array(new InputArgument('name', InputArgument::REQUIRED)))); + + $this->assertNull($input->validate()); + } + + public function testSetGetInteractive() + { + $input = new ArrayInput(array()); + $this->assertTrue($input->isInteractive(), '->isInteractive() returns whether the input should be interactive or not'); + $input->setInteractive(false); + $this->assertFalse($input->isInteractive(), '->setInteractive() changes the interactive flag'); + } +} diff --git a/vendor/symfony/console/Tests/Input/StringInputTest.php b/vendor/symfony/console/Tests/Input/StringInputTest.php new file mode 100644 index 0000000..ccf9289 --- /dev/null +++ b/vendor/symfony/console/Tests/Input/StringInputTest.php @@ -0,0 +1,99 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Tests\Input; + +use Symfony\Component\Console\Input\InputDefinition; +use Symfony\Component\Console\Input\InputOption; +use Symfony\Component\Console\Input\StringInput; + +class StringInputTest extends \PHPUnit_Framework_TestCase +{ + /** + * @dataProvider getTokenizeData + */ + public function testTokenize($input, $tokens, $message) + { + $input = new StringInput($input); + $r = new \ReflectionClass('Symfony\Component\Console\Input\ArgvInput'); + $p = $r->getProperty('tokens'); + $p->setAccessible(true); + $this->assertEquals($tokens, $p->getValue($input), $message); + } + + public function testInputOptionWithGivenString() + { + $definition = new InputDefinition( + array(new InputOption('foo', null, InputOption::VALUE_REQUIRED)) + ); + + // call to bind + $input = new StringInput('--foo=bar'); + $input->bind($definition); + $this->assertEquals('bar', $input->getOption('foo')); + } + + /** + * @group legacy + */ + public function testLegacyInputOptionDefinitionInConstructor() + { + $definition = new InputDefinition( + array(new InputOption('foo', null, InputOption::VALUE_REQUIRED)) + ); + + $input = new StringInput('--foo=bar', $definition); + $this->assertEquals('bar', $input->getOption('foo')); + } + + public function getTokenizeData() + { + return array( + array('', array(), '->tokenize() parses an empty string'), + array('foo', array('foo'), '->tokenize() parses arguments'), + array(' foo bar ', array('foo', 'bar'), '->tokenize() ignores whitespaces between arguments'), + array('"quoted"', array('quoted'), '->tokenize() parses quoted arguments'), + array("'quoted'", array('quoted'), '->tokenize() parses quoted arguments'), + array("'a\rb\nc\td'", array("a\rb\nc\td"), '->tokenize() parses whitespace chars in strings'), + array("'a'\r'b'\n'c'\t'd'", array('a','b','c','d'), '->tokenize() parses whitespace chars between args as spaces'), + array('\"quoted\"', array('"quoted"'), '->tokenize() parses escaped-quoted arguments'), + array("\'quoted\'", array('\'quoted\''), '->tokenize() parses escaped-quoted arguments'), + array('-a', array('-a'), '->tokenize() parses short options'), + array('-azc', array('-azc'), '->tokenize() parses aggregated short options'), + array('-awithavalue', array('-awithavalue'), '->tokenize() parses short options with a value'), + array('-a"foo bar"', array('-afoo bar'), '->tokenize() parses short options with a value'), + array('-a"foo bar""foo bar"', array('-afoo barfoo bar'), '->tokenize() parses short options with a value'), + array('-a\'foo bar\'', array('-afoo bar'), '->tokenize() parses short options with a value'), + array('-a\'foo bar\'\'foo bar\'', array('-afoo barfoo bar'), '->tokenize() parses short options with a value'), + array('-a\'foo bar\'"foo bar"', array('-afoo barfoo bar'), '->tokenize() parses short options with a value'), + array('--long-option', array('--long-option'), '->tokenize() parses long options'), + array('--long-option=foo', array('--long-option=foo'), '->tokenize() parses long options with a value'), + array('--long-option="foo bar"', array('--long-option=foo bar'), '->tokenize() parses long options with a value'), + array('--long-option="foo bar""another"', array('--long-option=foo baranother'), '->tokenize() parses long options with a value'), + array('--long-option=\'foo bar\'', array('--long-option=foo bar'), '->tokenize() parses long options with a value'), + array("--long-option='foo bar''another'", array('--long-option=foo baranother'), '->tokenize() parses long options with a value'), + array("--long-option='foo bar'\"another\"", array('--long-option=foo baranother'), '->tokenize() parses long options with a value'), + array('foo -a -ffoo --long bar', array('foo', '-a', '-ffoo', '--long', 'bar'), '->tokenize() parses when several arguments and options'), + ); + } + + public function testToString() + { + $input = new StringInput('-f foo'); + $this->assertEquals('-f foo', (string) $input); + + $input = new StringInput('-f --bar=foo "a b c d"'); + $this->assertEquals('-f --bar=foo '.escapeshellarg('a b c d'), (string) $input); + + $input = new StringInput('-f --bar=foo \'a b c d\' '."'A\nB\\'C'"); + $this->assertEquals('-f --bar=foo '.escapeshellarg('a b c d').' '.escapeshellarg("A\nB'C"), (string) $input); + } +} diff --git a/vendor/symfony/console/Tests/Logger/ConsoleLoggerTest.php b/vendor/symfony/console/Tests/Logger/ConsoleLoggerTest.php new file mode 100644 index 0000000..c5eca2c --- /dev/null +++ b/vendor/symfony/console/Tests/Logger/ConsoleLoggerTest.php @@ -0,0 +1,58 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Tests\Logger; + +use Psr\Log\Test\LoggerInterfaceTest; +use Psr\Log\LogLevel; +use Symfony\Component\Console\Logger\ConsoleLogger; +use Symfony\Component\Console\Tests\Fixtures\DummyOutput; +use Symfony\Component\Console\Output\OutputInterface; + +/** + * Console logger test. + * + * @author Kévin Dunglas + */ +class ConsoleLoggerTest extends LoggerInterfaceTest +{ + /** + * @var DummyOutput + */ + protected $output; + + /** + * {@inheritdoc} + */ + public function getLogger() + { + $this->output = new DummyOutput(OutputInterface::VERBOSITY_VERBOSE); + + return new ConsoleLogger($this->output, array( + LogLevel::EMERGENCY => OutputInterface::VERBOSITY_NORMAL, + LogLevel::ALERT => OutputInterface::VERBOSITY_NORMAL, + LogLevel::CRITICAL => OutputInterface::VERBOSITY_NORMAL, + LogLevel::ERROR => OutputInterface::VERBOSITY_NORMAL, + LogLevel::WARNING => OutputInterface::VERBOSITY_NORMAL, + LogLevel::NOTICE => OutputInterface::VERBOSITY_NORMAL, + LogLevel::INFO => OutputInterface::VERBOSITY_NORMAL, + LogLevel::DEBUG => OutputInterface::VERBOSITY_NORMAL, + )); + } + + /** + * {@inheritdoc} + */ + public function getLogs() + { + return $this->output->getLogs(); + } +} diff --git a/vendor/symfony/console/Tests/Output/ConsoleOutputTest.php b/vendor/symfony/console/Tests/Output/ConsoleOutputTest.php new file mode 100644 index 0000000..1afbbb6 --- /dev/null +++ b/vendor/symfony/console/Tests/Output/ConsoleOutputTest.php @@ -0,0 +1,25 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Tests\Output; + +use Symfony\Component\Console\Output\ConsoleOutput; +use Symfony\Component\Console\Output\Output; + +class ConsoleOutputTest extends \PHPUnit_Framework_TestCase +{ + public function testConstructor() + { + $output = new ConsoleOutput(Output::VERBOSITY_QUIET, true); + $this->assertEquals(Output::VERBOSITY_QUIET, $output->getVerbosity(), '__construct() takes the verbosity as its first argument'); + $this->assertSame($output->getFormatter(), $output->getErrorOutput()->getFormatter(), '__construct() takes a formatter or null as the third argument'); + } +} diff --git a/vendor/symfony/console/Tests/Output/NullOutputTest.php b/vendor/symfony/console/Tests/Output/NullOutputTest.php new file mode 100644 index 0000000..b20ae4e --- /dev/null +++ b/vendor/symfony/console/Tests/Output/NullOutputTest.php @@ -0,0 +1,39 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Tests\Output; + +use Symfony\Component\Console\Output\NullOutput; +use Symfony\Component\Console\Output\OutputInterface; + +class NullOutputTest extends \PHPUnit_Framework_TestCase +{ + public function testConstructor() + { + $output = new NullOutput(); + + ob_start(); + $output->write('foo'); + $buffer = ob_get_clean(); + + $this->assertSame('', $buffer, '->write() does nothing (at least nothing is printed)'); + $this->assertFalse($output->isDecorated(), '->isDecorated() returns false'); + } + + public function testVerbosity() + { + $output = new NullOutput(); + $this->assertSame(OutputInterface::VERBOSITY_QUIET, $output->getVerbosity(), '->getVerbosity() returns VERBOSITY_QUIET for NullOutput by default'); + + $output->setVerbosity(OutputInterface::VERBOSITY_VERBOSE); + $this->assertSame(OutputInterface::VERBOSITY_QUIET, $output->getVerbosity(), '->getVerbosity() always returns VERBOSITY_QUIET for NullOutput'); + } +} diff --git a/vendor/symfony/console/Tests/Output/OutputTest.php b/vendor/symfony/console/Tests/Output/OutputTest.php new file mode 100644 index 0000000..cfb4afe --- /dev/null +++ b/vendor/symfony/console/Tests/Output/OutputTest.php @@ -0,0 +1,156 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Tests\Output; + +use Symfony\Component\Console\Output\Output; +use Symfony\Component\Console\Formatter\OutputFormatterStyle; + +class OutputTest extends \PHPUnit_Framework_TestCase +{ + public function testConstructor() + { + $output = new TestOutput(Output::VERBOSITY_QUIET, true); + $this->assertEquals(Output::VERBOSITY_QUIET, $output->getVerbosity(), '__construct() takes the verbosity as its first argument'); + $this->assertTrue($output->isDecorated(), '__construct() takes the decorated flag as its second argument'); + } + + public function testSetIsDecorated() + { + $output = new TestOutput(); + $output->setDecorated(true); + $this->assertTrue($output->isDecorated(), 'setDecorated() sets the decorated flag'); + } + + public function testSetGetVerbosity() + { + $output = new TestOutput(); + $output->setVerbosity(Output::VERBOSITY_QUIET); + $this->assertEquals(Output::VERBOSITY_QUIET, $output->getVerbosity(), '->setVerbosity() sets the verbosity'); + + $this->assertTrue($output->isQuiet()); + $this->assertFalse($output->isVerbose()); + $this->assertFalse($output->isVeryVerbose()); + $this->assertFalse($output->isDebug()); + + $output->setVerbosity(Output::VERBOSITY_NORMAL); + $this->assertFalse($output->isQuiet()); + $this->assertFalse($output->isVerbose()); + $this->assertFalse($output->isVeryVerbose()); + $this->assertFalse($output->isDebug()); + + $output->setVerbosity(Output::VERBOSITY_VERBOSE); + $this->assertFalse($output->isQuiet()); + $this->assertTrue($output->isVerbose()); + $this->assertFalse($output->isVeryVerbose()); + $this->assertFalse($output->isDebug()); + + $output->setVerbosity(Output::VERBOSITY_VERY_VERBOSE); + $this->assertFalse($output->isQuiet()); + $this->assertTrue($output->isVerbose()); + $this->assertTrue($output->isVeryVerbose()); + $this->assertFalse($output->isDebug()); + + $output->setVerbosity(Output::VERBOSITY_DEBUG); + $this->assertFalse($output->isQuiet()); + $this->assertTrue($output->isVerbose()); + $this->assertTrue($output->isVeryVerbose()); + $this->assertTrue($output->isDebug()); + } + + public function testWriteWithVerbosityQuiet() + { + $output = new TestOutput(Output::VERBOSITY_QUIET); + $output->writeln('foo'); + $this->assertEquals('', $output->output, '->writeln() outputs nothing if verbosity is set to VERBOSITY_QUIET'); + } + + public function testWriteAnArrayOfMessages() + { + $output = new TestOutput(); + $output->writeln(array('foo', 'bar')); + $this->assertEquals("foo\nbar\n", $output->output, '->writeln() can take an array of messages to output'); + } + + /** + * @dataProvider provideWriteArguments + */ + public function testWriteRawMessage($message, $type, $expectedOutput) + { + $output = new TestOutput(); + $output->writeln($message, $type); + $this->assertEquals($expectedOutput, $output->output); + } + + public function provideWriteArguments() + { + return array( + array('foo', Output::OUTPUT_RAW, "foo\n"), + array('foo', Output::OUTPUT_PLAIN, "foo\n"), + ); + } + + public function testWriteWithDecorationTurnedOff() + { + $output = new TestOutput(); + $output->setDecorated(false); + $output->writeln('foo'); + $this->assertEquals("foo\n", $output->output, '->writeln() strips decoration tags if decoration is set to false'); + } + + public function testWriteDecoratedMessage() + { + $fooStyle = new OutputFormatterStyle('yellow', 'red', array('blink')); + $output = new TestOutput(); + $output->getFormatter()->setStyle('FOO', $fooStyle); + $output->setDecorated(true); + $output->writeln('foo'); + $this->assertEquals("\033[33;41;5mfoo\033[39;49;25m\n", $output->output, '->writeln() decorates the output'); + } + + /** + * @expectedException \InvalidArgumentException + * @expectedExceptionMessage Unknown output type given (24) + */ + public function testWriteWithInvalidOutputType() + { + $output = new TestOutput(); + $output->writeln('foo', 24); + } + + public function testWriteWithInvalidStyle() + { + $output = new TestOutput(); + + $output->clear(); + $output->write('foo'); + $this->assertEquals('foo', $output->output, '->write() do nothing when a style does not exist'); + + $output->clear(); + $output->writeln('foo'); + $this->assertEquals("foo\n", $output->output, '->writeln() do nothing when a style does not exist'); + } +} + +class TestOutput extends Output +{ + public $output = ''; + + public function clear() + { + $this->output = ''; + } + + protected function doWrite($message, $newline) + { + $this->output .= $message.($newline ? "\n" : ''); + } +} diff --git a/vendor/symfony/console/Tests/Output/StreamOutputTest.php b/vendor/symfony/console/Tests/Output/StreamOutputTest.php new file mode 100644 index 0000000..2fd4f61 --- /dev/null +++ b/vendor/symfony/console/Tests/Output/StreamOutputTest.php @@ -0,0 +1,60 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Tests\Output; + +use Symfony\Component\Console\Output\Output; +use Symfony\Component\Console\Output\StreamOutput; + +class StreamOutputTest extends \PHPUnit_Framework_TestCase +{ + protected $stream; + + protected function setUp() + { + $this->stream = fopen('php://memory', 'a', false); + } + + protected function tearDown() + { + $this->stream = null; + } + + public function testConstructor() + { + $output = new StreamOutput($this->stream, Output::VERBOSITY_QUIET, true); + $this->assertEquals(Output::VERBOSITY_QUIET, $output->getVerbosity(), '__construct() takes the verbosity as its first argument'); + $this->assertTrue($output->isDecorated(), '__construct() takes the decorated flag as its second argument'); + } + + /** + * @expectedException \InvalidArgumentException + * @expectedExceptionMessage The StreamOutput class needs a stream as its first argument. + */ + public function testStreamIsRequired() + { + new StreamOutput('foo'); + } + + public function testGetStream() + { + $output = new StreamOutput($this->stream); + $this->assertEquals($this->stream, $output->getStream(), '->getStream() returns the current stream'); + } + + public function testDoWrite() + { + $output = new StreamOutput($this->stream); + $output->writeln('foo'); + rewind($output->getStream()); + $this->assertEquals('foo'.PHP_EOL, stream_get_contents($output->getStream()), '->doWrite() writes to the stream'); + } +} diff --git a/vendor/symfony/console/Tests/Style/SymfonyStyleTest.php b/vendor/symfony/console/Tests/Style/SymfonyStyleTest.php new file mode 100644 index 0000000..2df4f40 --- /dev/null +++ b/vendor/symfony/console/Tests/Style/SymfonyStyleTest.php @@ -0,0 +1,64 @@ +command = new Command('sfstyle'); + $this->tester = new CommandTester($this->command); + } + + protected function tearDown() + { + $this->command = null; + $this->tester = null; + } + + /** + * @dataProvider inputCommandToOutputFilesProvider + */ + public function testOutputs($inputCommandFilepath, $outputFilepath) + { + $code = require $inputCommandFilepath; + $this->command->setCode($code); + $this->tester->execute(array(), array('interactive' => false, 'decorated' => false)); + $this->assertStringEqualsFile($outputFilepath, $this->tester->getDisplay(true)); + } + + public function inputCommandToOutputFilesProvider() + { + $baseDir = __DIR__.'/../Fixtures/Style/SymfonyStyle'; + + return array_map(null, glob($baseDir.'/command/command_*.php'), glob($baseDir.'/output/output_*.txt')); + } + + public function testLongWordsBlockWrapping() + { + $word = 'Lopadotemachoselachogaleokranioleipsanodrimhypotrimmatosilphioparaomelitokatakechymenokichlepikossyphophattoperisteralektryonoptekephalliokigklopeleiolagoiosiraiobaphetraganopterygon'; + $wordLength = strlen($word); + $maxLineLength = SymfonyStyle::MAX_LINE_LENGTH - 3; + + $this->command->setCode(function (InputInterface $input, OutputInterface $output) use ($word) { + $sfStyle = new SymfonyStyle($input, $output); + $sfStyle->block($word, 'CUSTOM', 'fg=white;bg=blue', ' § ', false); + }); + + $this->tester->execute(array(), array('interactive' => false, 'decorated' => false)); + $expectedCount = (int) ceil($wordLength / ($maxLineLength)) + (int) ($wordLength > $maxLineLength - 5); + $this->assertSame($expectedCount, substr_count($this->tester->getDisplay(true), ' § ')); + } +} diff --git a/vendor/symfony/console/Tests/Tester/ApplicationTesterTest.php b/vendor/symfony/console/Tests/Tester/ApplicationTesterTest.php new file mode 100644 index 0000000..a8389dd --- /dev/null +++ b/vendor/symfony/console/Tests/Tester/ApplicationTesterTest.php @@ -0,0 +1,69 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Tests\Tester; + +use Symfony\Component\Console\Application; +use Symfony\Component\Console\Output\Output; +use Symfony\Component\Console\Tester\ApplicationTester; + +class ApplicationTesterTest extends \PHPUnit_Framework_TestCase +{ + protected $application; + protected $tester; + + protected function setUp() + { + $this->application = new Application(); + $this->application->setAutoExit(false); + $this->application->register('foo') + ->addArgument('foo') + ->setCode(function ($input, $output) { $output->writeln('foo'); }) + ; + + $this->tester = new ApplicationTester($this->application); + $this->tester->run(array('command' => 'foo', 'foo' => 'bar'), array('interactive' => false, 'decorated' => false, 'verbosity' => Output::VERBOSITY_VERBOSE)); + } + + protected function tearDown() + { + $this->application = null; + $this->tester = null; + } + + public function testRun() + { + $this->assertFalse($this->tester->getInput()->isInteractive(), '->execute() takes an interactive option'); + $this->assertFalse($this->tester->getOutput()->isDecorated(), '->execute() takes a decorated option'); + $this->assertEquals(Output::VERBOSITY_VERBOSE, $this->tester->getOutput()->getVerbosity(), '->execute() takes a verbosity option'); + } + + public function testGetInput() + { + $this->assertEquals('bar', $this->tester->getInput()->getArgument('foo'), '->getInput() returns the current input instance'); + } + + public function testGetOutput() + { + rewind($this->tester->getOutput()->getStream()); + $this->assertEquals('foo'.PHP_EOL, stream_get_contents($this->tester->getOutput()->getStream()), '->getOutput() returns the current output instance'); + } + + public function testGetDisplay() + { + $this->assertEquals('foo'.PHP_EOL, $this->tester->getDisplay(), '->getDisplay() returns the display of the last execution'); + } + + public function testGetStatusCode() + { + $this->assertSame(0, $this->tester->getStatusCode(), '->getStatusCode() returns the status code'); + } +} diff --git a/vendor/symfony/console/Tests/Tester/CommandTesterTest.php b/vendor/symfony/console/Tests/Tester/CommandTesterTest.php new file mode 100644 index 0000000..b54c00e --- /dev/null +++ b/vendor/symfony/console/Tests/Tester/CommandTesterTest.php @@ -0,0 +1,84 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Tests\Tester; + +use Symfony\Component\Console\Application; +use Symfony\Component\Console\Command\Command; +use Symfony\Component\Console\Output\Output; +use Symfony\Component\Console\Tester\CommandTester; + +class CommandTesterTest extends \PHPUnit_Framework_TestCase +{ + protected $command; + protected $tester; + + protected function setUp() + { + $this->command = new Command('foo'); + $this->command->addArgument('command'); + $this->command->addArgument('foo'); + $this->command->setCode(function ($input, $output) { $output->writeln('foo'); }); + + $this->tester = new CommandTester($this->command); + $this->tester->execute(array('foo' => 'bar'), array('interactive' => false, 'decorated' => false, 'verbosity' => Output::VERBOSITY_VERBOSE)); + } + + protected function tearDown() + { + $this->command = null; + $this->tester = null; + } + + public function testExecute() + { + $this->assertFalse($this->tester->getInput()->isInteractive(), '->execute() takes an interactive option'); + $this->assertFalse($this->tester->getOutput()->isDecorated(), '->execute() takes a decorated option'); + $this->assertEquals(Output::VERBOSITY_VERBOSE, $this->tester->getOutput()->getVerbosity(), '->execute() takes a verbosity option'); + } + + public function testGetInput() + { + $this->assertEquals('bar', $this->tester->getInput()->getArgument('foo'), '->getInput() returns the current input instance'); + } + + public function testGetOutput() + { + rewind($this->tester->getOutput()->getStream()); + $this->assertEquals('foo'.PHP_EOL, stream_get_contents($this->tester->getOutput()->getStream()), '->getOutput() returns the current output instance'); + } + + public function testGetDisplay() + { + $this->assertEquals('foo'.PHP_EOL, $this->tester->getDisplay(), '->getDisplay() returns the display of the last execution'); + } + + public function testGetStatusCode() + { + $this->assertSame(0, $this->tester->getStatusCode(), '->getStatusCode() returns the status code'); + } + + public function testCommandFromApplication() + { + $application = new Application(); + $application->setAutoExit(false); + + $command = new Command('foo'); + $command->setCode(function ($input, $output) { $output->writeln('foo'); }); + + $application->add($command); + + $tester = new CommandTester($application->find('foo')); + + // check that there is no need to pass the command name here + $this->assertEquals(0, $tester->execute(array())); + } +} diff --git a/vendor/symfony/console/composer.json b/vendor/symfony/console/composer.json new file mode 100644 index 0000000..16b7b81 --- /dev/null +++ b/vendor/symfony/console/composer.json @@ -0,0 +1,41 @@ +{ + "name": "symfony/console", + "type": "library", + "description": "Symfony Console Component", + "keywords": [], + "homepage": "https://symfony.com", + "license": "MIT", + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "require": { + "php": ">=5.3.9" + }, + "require-dev": { + "symfony/phpunit-bridge": "~2.7", + "symfony/event-dispatcher": "~2.1", + "symfony/process": "~2.1", + "psr/log": "~1.0" + }, + "suggest": { + "symfony/event-dispatcher": "", + "symfony/process": "", + "psr/log": "For using the console logger" + }, + "autoload": { + "psr-4": { "Symfony\\Component\\Console\\": "" } + }, + "minimum-stability": "dev", + "extra": { + "branch-alias": { + "dev-master": "2.7-dev" + } + } +} diff --git a/vendor/symfony/console/phpunit.xml.dist b/vendor/symfony/console/phpunit.xml.dist new file mode 100644 index 0000000..ae0dcbe --- /dev/null +++ b/vendor/symfony/console/phpunit.xml.dist @@ -0,0 +1,29 @@ + + + + + + + + + + ./Tests/ + + + + + + ./ + + ./Resources + ./Tests + ./vendor + + + + diff --git a/vendor/symfony/event-dispatcher/.gitignore b/vendor/symfony/event-dispatcher/.gitignore new file mode 100644 index 0000000..c49a5d8 --- /dev/null +++ b/vendor/symfony/event-dispatcher/.gitignore @@ -0,0 +1,3 @@ +vendor/ +composer.lock +phpunit.xml diff --git a/vendor/symfony/event-dispatcher/CHANGELOG.md b/vendor/symfony/event-dispatcher/CHANGELOG.md new file mode 100644 index 0000000..bb42ee1 --- /dev/null +++ b/vendor/symfony/event-dispatcher/CHANGELOG.md @@ -0,0 +1,23 @@ +CHANGELOG +========= + +2.5.0 +----- + + * added Debug\TraceableEventDispatcher (originally in HttpKernel) + * changed Debug\TraceableEventDispatcherInterface to extend EventDispatcherInterface + * added RegisterListenersPass (originally in HttpKernel) + +2.1.0 +----- + + * added TraceableEventDispatcherInterface + * added ContainerAwareEventDispatcher + * added a reference to the EventDispatcher on the Event + * added a reference to the Event name on the event + * added fluid interface to the dispatch() method which now returns the Event + object + * added GenericEvent event class + * added the possibility for subscribers to subscribe several times for the + same event + * added ImmutableEventDispatcher diff --git a/vendor/symfony/event-dispatcher/ContainerAwareEventDispatcher.php b/vendor/symfony/event-dispatcher/ContainerAwareEventDispatcher.php new file mode 100644 index 0000000..76f0e38 --- /dev/null +++ b/vendor/symfony/event-dispatcher/ContainerAwareEventDispatcher.php @@ -0,0 +1,202 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\EventDispatcher; + +use Symfony\Component\DependencyInjection\ContainerInterface; + +/** + * Lazily loads listeners and subscribers from the dependency injection + * container. + * + * @author Fabien Potencier + * @author Bernhard Schussek + * @author Jordan Alliot + */ +class ContainerAwareEventDispatcher extends EventDispatcher +{ + /** + * The container from where services are loaded. + * + * @var ContainerInterface + */ + private $container; + + /** + * The service IDs of the event listeners and subscribers. + * + * @var array + */ + private $listenerIds = array(); + + /** + * The services registered as listeners. + * + * @var array + */ + private $listeners = array(); + + /** + * Constructor. + * + * @param ContainerInterface $container A ContainerInterface instance + */ + public function __construct(ContainerInterface $container) + { + $this->container = $container; + } + + /** + * Adds a service as event listener. + * + * @param string $eventName Event for which the listener is added + * @param array $callback The service ID of the listener service & the method + * name that has to be called + * @param int $priority The higher this value, the earlier an event listener + * will be triggered in the chain. + * Defaults to 0. + * + * @throws \InvalidArgumentException + */ + public function addListenerService($eventName, $callback, $priority = 0) + { + if (!is_array($callback) || 2 !== count($callback)) { + throw new \InvalidArgumentException('Expected an array("service", "method") argument'); + } + + $this->listenerIds[$eventName][] = array($callback[0], $callback[1], $priority); + } + + public function removeListener($eventName, $listener) + { + $this->lazyLoad($eventName); + + if (isset($this->listenerIds[$eventName])) { + foreach ($this->listenerIds[$eventName] as $i => $args) { + list($serviceId, $method, $priority) = $args; + $key = $serviceId.'.'.$method; + if (isset($this->listeners[$eventName][$key]) && $listener === array($this->listeners[$eventName][$key], $method)) { + unset($this->listeners[$eventName][$key]); + if (empty($this->listeners[$eventName])) { + unset($this->listeners[$eventName]); + } + unset($this->listenerIds[$eventName][$i]); + if (empty($this->listenerIds[$eventName])) { + unset($this->listenerIds[$eventName]); + } + } + } + } + + parent::removeListener($eventName, $listener); + } + + /** + * @see EventDispatcherInterface::hasListeners() + */ + public function hasListeners($eventName = null) + { + if (null === $eventName) { + return (bool) count($this->listenerIds) || (bool) count($this->listeners); + } + + if (isset($this->listenerIds[$eventName])) { + return true; + } + + return parent::hasListeners($eventName); + } + + /** + * @see EventDispatcherInterface::getListeners() + */ + public function getListeners($eventName = null) + { + if (null === $eventName) { + foreach ($this->listenerIds as $serviceEventName => $args) { + $this->lazyLoad($serviceEventName); + } + } else { + $this->lazyLoad($eventName); + } + + return parent::getListeners($eventName); + } + + /** + * Adds a service as event subscriber. + * + * @param string $serviceId The service ID of the subscriber service + * @param string $class The service's class name (which must implement EventSubscriberInterface) + */ + public function addSubscriberService($serviceId, $class) + { + foreach ($class::getSubscribedEvents() as $eventName => $params) { + if (is_string($params)) { + $this->listenerIds[$eventName][] = array($serviceId, $params, 0); + } elseif (is_string($params[0])) { + $this->listenerIds[$eventName][] = array($serviceId, $params[0], isset($params[1]) ? $params[1] : 0); + } else { + foreach ($params as $listener) { + $this->listenerIds[$eventName][] = array($serviceId, $listener[0], isset($listener[1]) ? $listener[1] : 0); + } + } + } + } + + /** + * {@inheritdoc} + * + * Lazily loads listeners for this event from the dependency injection + * container. + * + * @throws \InvalidArgumentException if the service is not defined + */ + public function dispatch($eventName, Event $event = null) + { + $this->lazyLoad($eventName); + + return parent::dispatch($eventName, $event); + } + + public function getContainer() + { + return $this->container; + } + + /** + * Lazily loads listeners for this event from the dependency injection + * container. + * + * @param string $eventName The name of the event to dispatch. The name of + * the event is the name of the method that is + * invoked on listeners. + */ + protected function lazyLoad($eventName) + { + if (isset($this->listenerIds[$eventName])) { + foreach ($this->listenerIds[$eventName] as $args) { + list($serviceId, $method, $priority) = $args; + $listener = $this->container->get($serviceId); + + $key = $serviceId.'.'.$method; + if (!isset($this->listeners[$eventName][$key])) { + $this->addListener($eventName, array($listener, $method), $priority); + } elseif ($listener !== $this->listeners[$eventName][$key]) { + parent::removeListener($eventName, array($this->listeners[$eventName][$key], $method)); + $this->addListener($eventName, array($listener, $method), $priority); + } + + $this->listeners[$eventName][$key] = $listener; + } + } + } +} diff --git a/vendor/symfony/event-dispatcher/Debug/TraceableEventDispatcher.php b/vendor/symfony/event-dispatcher/Debug/TraceableEventDispatcher.php new file mode 100644 index 0000000..7653ccf --- /dev/null +++ b/vendor/symfony/event-dispatcher/Debug/TraceableEventDispatcher.php @@ -0,0 +1,335 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\EventDispatcher\Debug; + +use Symfony\Component\EventDispatcher\EventDispatcherInterface; +use Symfony\Component\EventDispatcher\EventSubscriberInterface; +use Symfony\Component\EventDispatcher\Event; +use Symfony\Component\Stopwatch\Stopwatch; +use Psr\Log\LoggerInterface; + +/** + * Collects some data about event listeners. + * + * This event dispatcher delegates the dispatching to another one. + * + * @author Fabien Potencier + */ +class TraceableEventDispatcher implements TraceableEventDispatcherInterface +{ + protected $logger; + protected $stopwatch; + + private $called; + private $dispatcher; + private $wrappedListeners; + + /** + * Constructor. + * + * @param EventDispatcherInterface $dispatcher An EventDispatcherInterface instance + * @param Stopwatch $stopwatch A Stopwatch instance + * @param LoggerInterface $logger A LoggerInterface instance + */ + public function __construct(EventDispatcherInterface $dispatcher, Stopwatch $stopwatch, LoggerInterface $logger = null) + { + $this->dispatcher = $dispatcher; + $this->stopwatch = $stopwatch; + $this->logger = $logger; + $this->called = array(); + $this->wrappedListeners = array(); + } + + /** + * {@inheritdoc} + */ + public function addListener($eventName, $listener, $priority = 0) + { + $this->dispatcher->addListener($eventName, $listener, $priority); + } + + /** + * {@inheritdoc} + */ + public function addSubscriber(EventSubscriberInterface $subscriber) + { + $this->dispatcher->addSubscriber($subscriber); + } + + /** + * {@inheritdoc} + */ + public function removeListener($eventName, $listener) + { + if (isset($this->wrappedListeners[$eventName])) { + foreach ($this->wrappedListeners[$eventName] as $index => $wrappedListener) { + if ($wrappedListener->getWrappedListener() === $listener) { + $listener = $wrappedListener; + unset($this->wrappedListeners[$eventName][$index]); + break; + } + } + } + + return $this->dispatcher->removeListener($eventName, $listener); + } + + /** + * {@inheritdoc} + */ + public function removeSubscriber(EventSubscriberInterface $subscriber) + { + return $this->dispatcher->removeSubscriber($subscriber); + } + + /** + * {@inheritdoc} + */ + public function getListeners($eventName = null) + { + return $this->dispatcher->getListeners($eventName); + } + + /** + * {@inheritdoc} + */ + public function hasListeners($eventName = null) + { + return $this->dispatcher->hasListeners($eventName); + } + + /** + * {@inheritdoc} + */ + public function dispatch($eventName, Event $event = null) + { + if (null === $event) { + $event = new Event(); + } + + $this->preProcess($eventName); + $this->preDispatch($eventName, $event); + + $e = $this->stopwatch->start($eventName, 'section'); + + $this->dispatcher->dispatch($eventName, $event); + + if ($e->isStarted()) { + $e->stop(); + } + + $this->postDispatch($eventName, $event); + $this->postProcess($eventName); + + return $event; + } + + /** + * {@inheritdoc} + */ + public function getCalledListeners() + { + $called = array(); + foreach ($this->called as $eventName => $listeners) { + foreach ($listeners as $listener) { + $info = $this->getListenerInfo($listener->getWrappedListener(), $eventName); + $called[$eventName.'.'.$info['pretty']] = $info; + } + } + + return $called; + } + + /** + * {@inheritdoc} + */ + public function getNotCalledListeners() + { + try { + $allListeners = $this->getListeners(); + } catch (\Exception $e) { + if (null !== $this->logger) { + $this->logger->info('An exception was thrown while getting the uncalled listeners.', array('exception' => $e)); + } + + // unable to retrieve the uncalled listeners + return array(); + } + + $notCalled = array(); + foreach ($allListeners as $eventName => $listeners) { + foreach ($listeners as $listener) { + $called = false; + if (isset($this->called[$eventName])) { + foreach ($this->called[$eventName] as $l) { + if ($l->getWrappedListener() === $listener) { + $called = true; + + break; + } + } + } + + if (!$called) { + $info = $this->getListenerInfo($listener, $eventName); + $notCalled[$eventName.'.'.$info['pretty']] = $info; + } + } + } + + return $notCalled; + } + + /** + * Proxies all method calls to the original event dispatcher. + * + * @param string $method The method name + * @param array $arguments The method arguments + * + * @return mixed + */ + public function __call($method, $arguments) + { + return call_user_func_array(array($this->dispatcher, $method), $arguments); + } + + /** + * Called before dispatching the event. + * + * @param string $eventName The event name + * @param Event $event The event + */ + protected function preDispatch($eventName, Event $event) + { + } + + /** + * Called after dispatching the event. + * + * @param string $eventName The event name + * @param Event $event The event + */ + protected function postDispatch($eventName, Event $event) + { + } + + private function preProcess($eventName) + { + foreach ($this->dispatcher->getListeners($eventName) as $listener) { + $this->dispatcher->removeListener($eventName, $listener); + $info = $this->getListenerInfo($listener, $eventName); + $name = isset($info['class']) ? $info['class'] : $info['type']; + $wrappedListener = new WrappedListener($listener, $name, $this->stopwatch, $this); + $this->wrappedListeners[$eventName][] = $wrappedListener; + $this->dispatcher->addListener($eventName, $wrappedListener); + } + } + + private function postProcess($eventName) + { + unset($this->wrappedListeners[$eventName]); + $skipped = false; + foreach ($this->dispatcher->getListeners($eventName) as $listener) { + if (!$listener instanceof WrappedListener) { // #12845: a new listener was added during dispatch. + continue; + } + // Unwrap listener + $this->dispatcher->removeListener($eventName, $listener); + $this->dispatcher->addListener($eventName, $listener->getWrappedListener()); + + $info = $this->getListenerInfo($listener->getWrappedListener(), $eventName); + if ($listener->wasCalled()) { + if (null !== $this->logger) { + $this->logger->debug(sprintf('Notified event "%s" to listener "%s".', $eventName, $info['pretty'])); + } + + if (!isset($this->called[$eventName])) { + $this->called[$eventName] = new \SplObjectStorage(); + } + + $this->called[$eventName]->attach($listener); + } + + if (null !== $this->logger && $skipped) { + $this->logger->debug(sprintf('Listener "%s" was not called for event "%s".', $info['pretty'], $eventName)); + } + + if ($listener->stoppedPropagation()) { + if (null !== $this->logger) { + $this->logger->debug(sprintf('Listener "%s" stopped propagation of the event "%s".', $info['pretty'], $eventName)); + } + + $skipped = true; + } + } + } + + /** + * Returns information about the listener. + * + * @param object $listener The listener + * @param string $eventName The event name + * + * @return array Information about the listener + */ + private function getListenerInfo($listener, $eventName) + { + $info = array( + 'event' => $eventName, + ); + if ($listener instanceof \Closure) { + $info += array( + 'type' => 'Closure', + 'pretty' => 'closure', + ); + } elseif (is_string($listener)) { + try { + $r = new \ReflectionFunction($listener); + $file = $r->getFileName(); + $line = $r->getStartLine(); + } catch (\ReflectionException $e) { + $file = null; + $line = null; + } + $info += array( + 'type' => 'Function', + 'function' => $listener, + 'file' => $file, + 'line' => $line, + 'pretty' => $listener, + ); + } elseif (is_array($listener) || (is_object($listener) && is_callable($listener))) { + if (!is_array($listener)) { + $listener = array($listener, '__invoke'); + } + $class = is_object($listener[0]) ? get_class($listener[0]) : $listener[0]; + try { + $r = new \ReflectionMethod($class, $listener[1]); + $file = $r->getFileName(); + $line = $r->getStartLine(); + } catch (\ReflectionException $e) { + $file = null; + $line = null; + } + $info += array( + 'type' => 'Method', + 'class' => $class, + 'method' => $listener[1], + 'file' => $file, + 'line' => $line, + 'pretty' => $class.'::'.$listener[1], + ); + } + + return $info; + } +} diff --git a/vendor/symfony/event-dispatcher/Debug/TraceableEventDispatcherInterface.php b/vendor/symfony/event-dispatcher/Debug/TraceableEventDispatcherInterface.php new file mode 100644 index 0000000..5483e81 --- /dev/null +++ b/vendor/symfony/event-dispatcher/Debug/TraceableEventDispatcherInterface.php @@ -0,0 +1,34 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\EventDispatcher\Debug; + +use Symfony\Component\EventDispatcher\EventDispatcherInterface; + +/** + * @author Fabien Potencier + */ +interface TraceableEventDispatcherInterface extends EventDispatcherInterface +{ + /** + * Gets the called listeners. + * + * @return array An array of called listeners + */ + public function getCalledListeners(); + + /** + * Gets the not called listeners. + * + * @return array An array of not called listeners + */ + public function getNotCalledListeners(); +} diff --git a/vendor/symfony/event-dispatcher/Debug/WrappedListener.php b/vendor/symfony/event-dispatcher/Debug/WrappedListener.php new file mode 100644 index 0000000..e16627d --- /dev/null +++ b/vendor/symfony/event-dispatcher/Debug/WrappedListener.php @@ -0,0 +1,71 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\EventDispatcher\Debug; + +use Symfony\Component\Stopwatch\Stopwatch; +use Symfony\Component\EventDispatcher\Event; +use Symfony\Component\EventDispatcher\EventDispatcherInterface; + +/** + * @author Fabien Potencier + */ +class WrappedListener +{ + private $listener; + private $name; + private $called; + private $stoppedPropagation; + private $stopwatch; + private $dispatcher; + + public function __construct($listener, $name, Stopwatch $stopwatch, EventDispatcherInterface $dispatcher = null) + { + $this->listener = $listener; + $this->name = $name; + $this->stopwatch = $stopwatch; + $this->dispatcher = $dispatcher; + $this->called = false; + $this->stoppedPropagation = false; + } + + public function getWrappedListener() + { + return $this->listener; + } + + public function wasCalled() + { + return $this->called; + } + + public function stoppedPropagation() + { + return $this->stoppedPropagation; + } + + public function __invoke(Event $event, $eventName, EventDispatcherInterface $dispatcher) + { + $this->called = true; + + $e = $this->stopwatch->start($this->name, 'event_listener'); + + call_user_func($this->listener, $event, $eventName, $this->dispatcher ?: $dispatcher); + + if ($e->isStarted()) { + $e->stop(); + } + + if ($event->isPropagationStopped()) { + $this->stoppedPropagation = true; + } + } +} diff --git a/vendor/symfony/event-dispatcher/DependencyInjection/RegisterListenersPass.php b/vendor/symfony/event-dispatcher/DependencyInjection/RegisterListenersPass.php new file mode 100644 index 0000000..7e74a37 --- /dev/null +++ b/vendor/symfony/event-dispatcher/DependencyInjection/RegisterListenersPass.php @@ -0,0 +1,110 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\EventDispatcher\DependencyInjection; + +use Symfony\Component\DependencyInjection\ContainerBuilder; +use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface; + +/** + * Compiler pass to register tagged services for an event dispatcher. + */ +class RegisterListenersPass implements CompilerPassInterface +{ + /** + * @var string + */ + protected $dispatcherService; + + /** + * @var string + */ + protected $listenerTag; + + /** + * @var string + */ + protected $subscriberTag; + + /** + * Constructor. + * + * @param string $dispatcherService Service name of the event dispatcher in processed container + * @param string $listenerTag Tag name used for listener + * @param string $subscriberTag Tag name used for subscribers + */ + public function __construct($dispatcherService = 'event_dispatcher', $listenerTag = 'kernel.event_listener', $subscriberTag = 'kernel.event_subscriber') + { + $this->dispatcherService = $dispatcherService; + $this->listenerTag = $listenerTag; + $this->subscriberTag = $subscriberTag; + } + + public function process(ContainerBuilder $container) + { + if (!$container->hasDefinition($this->dispatcherService) && !$container->hasAlias($this->dispatcherService)) { + return; + } + + $definition = $container->findDefinition($this->dispatcherService); + + foreach ($container->findTaggedServiceIds($this->listenerTag) as $id => $events) { + $def = $container->getDefinition($id); + if (!$def->isPublic()) { + throw new \InvalidArgumentException(sprintf('The service "%s" must be public as event listeners are lazy-loaded.', $id)); + } + + if ($def->isAbstract()) { + throw new \InvalidArgumentException(sprintf('The service "%s" must not be abstract as event listeners are lazy-loaded.', $id)); + } + + foreach ($events as $event) { + $priority = isset($event['priority']) ? $event['priority'] : 0; + + if (!isset($event['event'])) { + throw new \InvalidArgumentException(sprintf('Service "%s" must define the "event" attribute on "%s" tags.', $id, $this->listenerTag)); + } + + if (!isset($event['method'])) { + $event['method'] = 'on'.preg_replace_callback(array( + '/(?<=\b)[a-z]/i', + '/[^a-z0-9]/i', + ), function ($matches) { return strtoupper($matches[0]); }, $event['event']); + $event['method'] = preg_replace('/[^a-z0-9]/i', '', $event['method']); + } + + $definition->addMethodCall('addListenerService', array($event['event'], array($id, $event['method']), $priority)); + } + } + + foreach ($container->findTaggedServiceIds($this->subscriberTag) as $id => $attributes) { + $def = $container->getDefinition($id); + if (!$def->isPublic()) { + throw new \InvalidArgumentException(sprintf('The service "%s" must be public as event subscribers are lazy-loaded.', $id)); + } + + if ($def->isAbstract()) { + throw new \InvalidArgumentException(sprintf('The service "%s" must not be abstract as event subscribers are lazy-loaded.', $id)); + } + + // We must assume that the class value has been correctly filled, even if the service is created by a factory + $class = $container->getParameterBag()->resolveValue($def->getClass()); + + $refClass = new \ReflectionClass($class); + $interface = 'Symfony\Component\EventDispatcher\EventSubscriberInterface'; + if (!$refClass->implementsInterface($interface)) { + throw new \InvalidArgumentException(sprintf('Service "%s" must implement interface "%s".', $id, $interface)); + } + + $definition->addMethodCall('addSubscriberService', array($id, $class)); + } + } +} diff --git a/vendor/symfony/event-dispatcher/Event.php b/vendor/symfony/event-dispatcher/Event.php new file mode 100644 index 0000000..048bf0a --- /dev/null +++ b/vendor/symfony/event-dispatcher/Event.php @@ -0,0 +1,134 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\EventDispatcher; + +/** + * Event is the base class for classes containing event data. + * + * This class contains no event data. It is used by events that do not pass + * state information to an event handler when an event is raised. + * + * You can call the method stopPropagation() to abort the execution of + * further listeners in your event listener. + * + * @author Guilherme Blanco + * @author Jonathan Wage + * @author Roman Borschel + * @author Bernhard Schussek + * + * @api + */ +class Event +{ + /** + * @var bool Whether no further event listeners should be triggered + */ + private $propagationStopped = false; + + /** + * @var EventDispatcher Dispatcher that dispatched this event + */ + private $dispatcher; + + /** + * @var string This event's name + */ + private $name; + + /** + * Returns whether further event listeners should be triggered. + * + * @see Event::stopPropagation() + * + * @return bool Whether propagation was already stopped for this event. + * + * @api + */ + public function isPropagationStopped() + { + return $this->propagationStopped; + } + + /** + * Stops the propagation of the event to further event listeners. + * + * If multiple event listeners are connected to the same event, no + * further event listener will be triggered once any trigger calls + * stopPropagation(). + * + * @api + */ + public function stopPropagation() + { + $this->propagationStopped = true; + } + + /** + * Stores the EventDispatcher that dispatches this Event. + * + * @param EventDispatcherInterface $dispatcher + * + * @deprecated since version 2.4, to be removed in 3.0. The event dispatcher is passed to the listener call. + * + * @api + */ + public function setDispatcher(EventDispatcherInterface $dispatcher) + { + $this->dispatcher = $dispatcher; + } + + /** + * Returns the EventDispatcher that dispatches this Event. + * + * @return EventDispatcherInterface + * + * @deprecated since version 2.4, to be removed in 3.0. The event dispatcher is passed to the listener call. + * + * @api + */ + public function getDispatcher() + { + @trigger_error('The '.__METHOD__.' method is deprecated since version 2.4 and will be removed in 3.0. The event dispatcher instance can be received in the listener call instead.', E_USER_DEPRECATED); + + return $this->dispatcher; + } + + /** + * Gets the event's name. + * + * @return string + * + * @deprecated since version 2.4, to be removed in 3.0. The event name is passed to the listener call. + * + * @api + */ + public function getName() + { + @trigger_error('The '.__METHOD__.' method is deprecated since version 2.4 and will be removed in 3.0. The event name can be received in the listener call instead.', E_USER_DEPRECATED); + + return $this->name; + } + + /** + * Sets the event's name property. + * + * @param string $name The event name. + * + * @deprecated since version 2.4, to be removed in 3.0. The event name is passed to the listener call. + * + * @api + */ + public function setName($name) + { + $this->name = $name; + } +} diff --git a/vendor/symfony/event-dispatcher/EventDispatcher.php b/vendor/symfony/event-dispatcher/EventDispatcher.php new file mode 100644 index 0000000..46c1110 --- /dev/null +++ b/vendor/symfony/event-dispatcher/EventDispatcher.php @@ -0,0 +1,185 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\EventDispatcher; + +/** + * The EventDispatcherInterface is the central point of Symfony's event listener system. + * + * Listeners are registered on the manager and events are dispatched through the + * manager. + * + * @author Guilherme Blanco + * @author Jonathan Wage + * @author Roman Borschel + * @author Bernhard Schussek + * @author Fabien Potencier + * @author Jordi Boggiano + * @author Jordan Alliot + * + * @api + */ +class EventDispatcher implements EventDispatcherInterface +{ + private $listeners = array(); + private $sorted = array(); + + /** + * @see EventDispatcherInterface::dispatch() + * + * @api + */ + public function dispatch($eventName, Event $event = null) + { + if (null === $event) { + $event = new Event(); + } + + $event->setDispatcher($this); + $event->setName($eventName); + + if (!isset($this->listeners[$eventName])) { + return $event; + } + + $this->doDispatch($this->getListeners($eventName), $eventName, $event); + + return $event; + } + + /** + * @see EventDispatcherInterface::getListeners() + */ + public function getListeners($eventName = null) + { + if (null !== $eventName) { + if (!isset($this->sorted[$eventName])) { + $this->sortListeners($eventName); + } + + return $this->sorted[$eventName]; + } + + foreach ($this->listeners as $eventName => $eventListeners) { + if (!isset($this->sorted[$eventName])) { + $this->sortListeners($eventName); + } + } + + return array_filter($this->sorted); + } + + /** + * @see EventDispatcherInterface::hasListeners() + */ + public function hasListeners($eventName = null) + { + return (bool) count($this->getListeners($eventName)); + } + + /** + * @see EventDispatcherInterface::addListener() + * + * @api + */ + public function addListener($eventName, $listener, $priority = 0) + { + $this->listeners[$eventName][$priority][] = $listener; + unset($this->sorted[$eventName]); + } + + /** + * @see EventDispatcherInterface::removeListener() + */ + public function removeListener($eventName, $listener) + { + if (!isset($this->listeners[$eventName])) { + return; + } + + foreach ($this->listeners[$eventName] as $priority => $listeners) { + if (false !== ($key = array_search($listener, $listeners, true))) { + unset($this->listeners[$eventName][$priority][$key], $this->sorted[$eventName]); + } + } + } + + /** + * @see EventDispatcherInterface::addSubscriber() + * + * @api + */ + public function addSubscriber(EventSubscriberInterface $subscriber) + { + foreach ($subscriber->getSubscribedEvents() as $eventName => $params) { + if (is_string($params)) { + $this->addListener($eventName, array($subscriber, $params)); + } elseif (is_string($params[0])) { + $this->addListener($eventName, array($subscriber, $params[0]), isset($params[1]) ? $params[1] : 0); + } else { + foreach ($params as $listener) { + $this->addListener($eventName, array($subscriber, $listener[0]), isset($listener[1]) ? $listener[1] : 0); + } + } + } + } + + /** + * @see EventDispatcherInterface::removeSubscriber() + */ + public function removeSubscriber(EventSubscriberInterface $subscriber) + { + foreach ($subscriber->getSubscribedEvents() as $eventName => $params) { + if (is_array($params) && is_array($params[0])) { + foreach ($params as $listener) { + $this->removeListener($eventName, array($subscriber, $listener[0])); + } + } else { + $this->removeListener($eventName, array($subscriber, is_string($params) ? $params : $params[0])); + } + } + } + + /** + * Triggers the listeners of an event. + * + * This method can be overridden to add functionality that is executed + * for each listener. + * + * @param callable[] $listeners The event listeners. + * @param string $eventName The name of the event to dispatch. + * @param Event $event The event object to pass to the event handlers/listeners. + */ + protected function doDispatch($listeners, $eventName, Event $event) + { + foreach ($listeners as $listener) { + call_user_func($listener, $event, $eventName, $this); + if ($event->isPropagationStopped()) { + break; + } + } + } + + /** + * Sorts the internal list of listeners for the given event by priority. + * + * @param string $eventName The name of the event. + */ + private function sortListeners($eventName) + { + $this->sorted[$eventName] = array(); + + if (isset($this->listeners[$eventName])) { + krsort($this->listeners[$eventName]); + $this->sorted[$eventName] = call_user_func_array('array_merge', $this->listeners[$eventName]); + } + } +} diff --git a/vendor/symfony/event-dispatcher/EventDispatcherInterface.php b/vendor/symfony/event-dispatcher/EventDispatcherInterface.php new file mode 100644 index 0000000..9d9fc4d --- /dev/null +++ b/vendor/symfony/event-dispatcher/EventDispatcherInterface.php @@ -0,0 +1,96 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\EventDispatcher; + +/** + * The EventDispatcherInterface is the central point of Symfony's event listener system. + * Listeners are registered on the manager and events are dispatched through the + * manager. + * + * @author Bernhard Schussek + * + * @api + */ +interface EventDispatcherInterface +{ + /** + * Dispatches an event to all registered listeners. + * + * @param string $eventName The name of the event to dispatch. The name of + * the event is the name of the method that is + * invoked on listeners. + * @param Event $event The event to pass to the event handlers/listeners. + * If not supplied, an empty Event instance is created. + * + * @return Event + * + * @api + */ + public function dispatch($eventName, Event $event = null); + + /** + * Adds an event listener that listens on the specified events. + * + * @param string $eventName The event to listen on + * @param callable $listener The listener + * @param int $priority The higher this value, the earlier an event + * listener will be triggered in the chain (defaults to 0) + * + * @api + */ + public function addListener($eventName, $listener, $priority = 0); + + /** + * Adds an event subscriber. + * + * The subscriber is asked for all the events he is + * interested in and added as a listener for these events. + * + * @param EventSubscriberInterface $subscriber The subscriber. + * + * @api + */ + public function addSubscriber(EventSubscriberInterface $subscriber); + + /** + * Removes an event listener from the specified events. + * + * @param string $eventName The event to remove a listener from + * @param callable $listener The listener to remove + */ + public function removeListener($eventName, $listener); + + /** + * Removes an event subscriber. + * + * @param EventSubscriberInterface $subscriber The subscriber + */ + public function removeSubscriber(EventSubscriberInterface $subscriber); + + /** + * Gets the listeners of a specific event or all listeners sorted by descending priority. + * + * @param string $eventName The name of the event + * + * @return array The event listeners for the specified event, or all event listeners by event name + */ + public function getListeners($eventName = null); + + /** + * Checks whether an event has any registered listeners. + * + * @param string $eventName The name of the event + * + * @return bool true if the specified event has any listeners, false otherwise + */ + public function hasListeners($eventName = null); +} diff --git a/vendor/symfony/event-dispatcher/EventSubscriberInterface.php b/vendor/symfony/event-dispatcher/EventSubscriberInterface.php new file mode 100644 index 0000000..ff7e305 --- /dev/null +++ b/vendor/symfony/event-dispatcher/EventSubscriberInterface.php @@ -0,0 +1,50 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\EventDispatcher; + +/** + * An EventSubscriber knows himself what events he is interested in. + * If an EventSubscriber is added to an EventDispatcherInterface, the manager invokes + * {@link getSubscribedEvents} and registers the subscriber as a listener for all + * returned events. + * + * @author Guilherme Blanco + * @author Jonathan Wage + * @author Roman Borschel + * @author Bernhard Schussek + * + * @api + */ +interface EventSubscriberInterface +{ + /** + * Returns an array of event names this subscriber wants to listen to. + * + * The array keys are event names and the value can be: + * + * * The method name to call (priority defaults to 0) + * * An array composed of the method name to call and the priority + * * An array of arrays composed of the method names to call and respective + * priorities, or 0 if unset + * + * For instance: + * + * * array('eventName' => 'methodName') + * * array('eventName' => array('methodName', $priority)) + * * array('eventName' => array(array('methodName1', $priority), array('methodName2')) + * + * @return array The event names to listen to + * + * @api + */ + public static function getSubscribedEvents(); +} diff --git a/vendor/symfony/event-dispatcher/GenericEvent.php b/vendor/symfony/event-dispatcher/GenericEvent.php new file mode 100644 index 0000000..6458180 --- /dev/null +++ b/vendor/symfony/event-dispatcher/GenericEvent.php @@ -0,0 +1,186 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\EventDispatcher; + +/** + * Event encapsulation class. + * + * Encapsulates events thus decoupling the observer from the subject they encapsulate. + * + * @author Drak + */ +class GenericEvent extends Event implements \ArrayAccess, \IteratorAggregate +{ + /** + * Event subject. + * + * @var mixed usually object or callable + */ + protected $subject; + + /** + * Array of arguments. + * + * @var array + */ + protected $arguments; + + /** + * Encapsulate an event with $subject and $args. + * + * @param mixed $subject The subject of the event, usually an object. + * @param array $arguments Arguments to store in the event. + */ + public function __construct($subject = null, array $arguments = array()) + { + $this->subject = $subject; + $this->arguments = $arguments; + } + + /** + * Getter for subject property. + * + * @return mixed $subject The observer subject. + */ + public function getSubject() + { + return $this->subject; + } + + /** + * Get argument by key. + * + * @param string $key Key. + * + * @throws \InvalidArgumentException If key is not found. + * + * @return mixed Contents of array key. + */ + public function getArgument($key) + { + if ($this->hasArgument($key)) { + return $this->arguments[$key]; + } + + throw new \InvalidArgumentException(sprintf('Argument "%s" not found.', $key)); + } + + /** + * Add argument to event. + * + * @param string $key Argument name. + * @param mixed $value Value. + * + * @return GenericEvent + */ + public function setArgument($key, $value) + { + $this->arguments[$key] = $value; + + return $this; + } + + /** + * Getter for all arguments. + * + * @return array + */ + public function getArguments() + { + return $this->arguments; + } + + /** + * Set args property. + * + * @param array $args Arguments. + * + * @return GenericEvent + */ + public function setArguments(array $args = array()) + { + $this->arguments = $args; + + return $this; + } + + /** + * Has argument. + * + * @param string $key Key of arguments array. + * + * @return bool + */ + public function hasArgument($key) + { + return array_key_exists($key, $this->arguments); + } + + /** + * ArrayAccess for argument getter. + * + * @param string $key Array key. + * + * @throws \InvalidArgumentException If key does not exist in $this->args. + * + * @return mixed + */ + public function offsetGet($key) + { + return $this->getArgument($key); + } + + /** + * ArrayAccess for argument setter. + * + * @param string $key Array key to set. + * @param mixed $value Value. + */ + public function offsetSet($key, $value) + { + $this->setArgument($key, $value); + } + + /** + * ArrayAccess for unset argument. + * + * @param string $key Array key. + */ + public function offsetUnset($key) + { + if ($this->hasArgument($key)) { + unset($this->arguments[$key]); + } + } + + /** + * ArrayAccess has argument. + * + * @param string $key Array key. + * + * @return bool + */ + public function offsetExists($key) + { + return $this->hasArgument($key); + } + + /** + * IteratorAggregate for iterating over the object like an array. + * + * @return \ArrayIterator + */ + public function getIterator() + { + return new \ArrayIterator($this->arguments); + } +} diff --git a/vendor/symfony/event-dispatcher/ImmutableEventDispatcher.php b/vendor/symfony/event-dispatcher/ImmutableEventDispatcher.php new file mode 100644 index 0000000..7ef9ece --- /dev/null +++ b/vendor/symfony/event-dispatcher/ImmutableEventDispatcher.php @@ -0,0 +1,93 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\EventDispatcher; + +/** + * A read-only proxy for an event dispatcher. + * + * @author Bernhard Schussek + */ +class ImmutableEventDispatcher implements EventDispatcherInterface +{ + /** + * The proxied dispatcher. + * + * @var EventDispatcherInterface + */ + private $dispatcher; + + /** + * Creates an unmodifiable proxy for an event dispatcher. + * + * @param EventDispatcherInterface $dispatcher The proxied event dispatcher. + */ + public function __construct(EventDispatcherInterface $dispatcher) + { + $this->dispatcher = $dispatcher; + } + + /** + * {@inheritdoc} + */ + public function dispatch($eventName, Event $event = null) + { + return $this->dispatcher->dispatch($eventName, $event); + } + + /** + * {@inheritdoc} + */ + public function addListener($eventName, $listener, $priority = 0) + { + throw new \BadMethodCallException('Unmodifiable event dispatchers must not be modified.'); + } + + /** + * {@inheritdoc} + */ + public function addSubscriber(EventSubscriberInterface $subscriber) + { + throw new \BadMethodCallException('Unmodifiable event dispatchers must not be modified.'); + } + + /** + * {@inheritdoc} + */ + public function removeListener($eventName, $listener) + { + throw new \BadMethodCallException('Unmodifiable event dispatchers must not be modified.'); + } + + /** + * {@inheritdoc} + */ + public function removeSubscriber(EventSubscriberInterface $subscriber) + { + throw new \BadMethodCallException('Unmodifiable event dispatchers must not be modified.'); + } + + /** + * {@inheritdoc} + */ + public function getListeners($eventName = null) + { + return $this->dispatcher->getListeners($eventName); + } + + /** + * {@inheritdoc} + */ + public function hasListeners($eventName = null) + { + return $this->dispatcher->hasListeners($eventName); + } +} diff --git a/vendor/symfony/event-dispatcher/LICENSE b/vendor/symfony/event-dispatcher/LICENSE new file mode 100644 index 0000000..43028bc --- /dev/null +++ b/vendor/symfony/event-dispatcher/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2004-2015 Fabien Potencier + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is furnished +to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/vendor/symfony/event-dispatcher/README.md b/vendor/symfony/event-dispatcher/README.md new file mode 100644 index 0000000..8031f4d --- /dev/null +++ b/vendor/symfony/event-dispatcher/README.md @@ -0,0 +1,27 @@ +EventDispatcher Component +========================= + +The Symfony EventDispatcher component implements the Mediator pattern in a +simple and effective way to make your projects truly extensible. + +```php +use Symfony\Component\EventDispatcher\EventDispatcher; +use Symfony\Component\EventDispatcher\Event; + +$dispatcher = new EventDispatcher(); + +$dispatcher->addListener('event_name', function (Event $event) { + // ... +}); + +$dispatcher->dispatch('event_name'); +``` + +Resources +--------- + +You can run the unit tests with the following command: + + $ cd path/to/Symfony/Component/EventDispatcher/ + $ composer install + $ phpunit diff --git a/vendor/symfony/event-dispatcher/Tests/AbstractEventDispatcherTest.php b/vendor/symfony/event-dispatcher/Tests/AbstractEventDispatcherTest.php new file mode 100644 index 0000000..199d2c0 --- /dev/null +++ b/vendor/symfony/event-dispatcher/Tests/AbstractEventDispatcherTest.php @@ -0,0 +1,381 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\EventDispatcher\Tests; + +use Symfony\Component\EventDispatcher\Event; +use Symfony\Component\EventDispatcher\EventSubscriberInterface; + +abstract class AbstractEventDispatcherTest extends \PHPUnit_Framework_TestCase +{ + /* Some pseudo events */ + const preFoo = 'pre.foo'; + const postFoo = 'post.foo'; + const preBar = 'pre.bar'; + const postBar = 'post.bar'; + + /** + * @var EventDispatcher + */ + private $dispatcher; + + private $listener; + + protected function setUp() + { + $this->dispatcher = $this->createEventDispatcher(); + $this->listener = new TestEventListener(); + } + + protected function tearDown() + { + $this->dispatcher = null; + $this->listener = null; + } + + abstract protected function createEventDispatcher(); + + public function testInitialState() + { + $this->assertEquals(array(), $this->dispatcher->getListeners()); + $this->assertFalse($this->dispatcher->hasListeners(self::preFoo)); + $this->assertFalse($this->dispatcher->hasListeners(self::postFoo)); + } + + public function testAddListener() + { + $this->dispatcher->addListener('pre.foo', array($this->listener, 'preFoo')); + $this->dispatcher->addListener('post.foo', array($this->listener, 'postFoo')); + $this->assertTrue($this->dispatcher->hasListeners(self::preFoo)); + $this->assertTrue($this->dispatcher->hasListeners(self::postFoo)); + $this->assertCount(1, $this->dispatcher->getListeners(self::preFoo)); + $this->assertCount(1, $this->dispatcher->getListeners(self::postFoo)); + $this->assertCount(2, $this->dispatcher->getListeners()); + } + + public function testGetListenersSortsByPriority() + { + $listener1 = new TestEventListener(); + $listener2 = new TestEventListener(); + $listener3 = new TestEventListener(); + $listener1->name = '1'; + $listener2->name = '2'; + $listener3->name = '3'; + + $this->dispatcher->addListener('pre.foo', array($listener1, 'preFoo'), -10); + $this->dispatcher->addListener('pre.foo', array($listener2, 'preFoo'), 10); + $this->dispatcher->addListener('pre.foo', array($listener3, 'preFoo')); + + $expected = array( + array($listener2, 'preFoo'), + array($listener3, 'preFoo'), + array($listener1, 'preFoo'), + ); + + $this->assertSame($expected, $this->dispatcher->getListeners('pre.foo')); + } + + public function testGetAllListenersSortsByPriority() + { + $listener1 = new TestEventListener(); + $listener2 = new TestEventListener(); + $listener3 = new TestEventListener(); + $listener4 = new TestEventListener(); + $listener5 = new TestEventListener(); + $listener6 = new TestEventListener(); + + $this->dispatcher->addListener('pre.foo', $listener1, -10); + $this->dispatcher->addListener('pre.foo', $listener2); + $this->dispatcher->addListener('pre.foo', $listener3, 10); + $this->dispatcher->addListener('post.foo', $listener4, -10); + $this->dispatcher->addListener('post.foo', $listener5); + $this->dispatcher->addListener('post.foo', $listener6, 10); + + $expected = array( + 'pre.foo' => array($listener3, $listener2, $listener1), + 'post.foo' => array($listener6, $listener5, $listener4), + ); + + $this->assertSame($expected, $this->dispatcher->getListeners()); + } + + public function testDispatch() + { + $this->dispatcher->addListener('pre.foo', array($this->listener, 'preFoo')); + $this->dispatcher->addListener('post.foo', array($this->listener, 'postFoo')); + $this->dispatcher->dispatch(self::preFoo); + $this->assertTrue($this->listener->preFooInvoked); + $this->assertFalse($this->listener->postFooInvoked); + $this->assertInstanceOf('Symfony\Component\EventDispatcher\Event', $this->dispatcher->dispatch('noevent')); + $this->assertInstanceOf('Symfony\Component\EventDispatcher\Event', $this->dispatcher->dispatch(self::preFoo)); + $event = new Event(); + $return = $this->dispatcher->dispatch(self::preFoo, $event); + $this->assertSame($event, $return); + } + + /** + * @group legacy + */ + public function testLegacyDispatch() + { + $event = new Event(); + $return = $this->dispatcher->dispatch(self::preFoo, $event); + $this->assertEquals('pre.foo', $event->getName()); + } + + public function testDispatchForClosure() + { + $invoked = 0; + $listener = function () use (&$invoked) { + ++$invoked; + }; + $this->dispatcher->addListener('pre.foo', $listener); + $this->dispatcher->addListener('post.foo', $listener); + $this->dispatcher->dispatch(self::preFoo); + $this->assertEquals(1, $invoked); + } + + public function testStopEventPropagation() + { + $otherListener = new TestEventListener(); + + // postFoo() stops the propagation, so only one listener should + // be executed + // Manually set priority to enforce $this->listener to be called first + $this->dispatcher->addListener('post.foo', array($this->listener, 'postFoo'), 10); + $this->dispatcher->addListener('post.foo', array($otherListener, 'preFoo')); + $this->dispatcher->dispatch(self::postFoo); + $this->assertTrue($this->listener->postFooInvoked); + $this->assertFalse($otherListener->postFooInvoked); + } + + public function testDispatchByPriority() + { + $invoked = array(); + $listener1 = function () use (&$invoked) { + $invoked[] = '1'; + }; + $listener2 = function () use (&$invoked) { + $invoked[] = '2'; + }; + $listener3 = function () use (&$invoked) { + $invoked[] = '3'; + }; + $this->dispatcher->addListener('pre.foo', $listener1, -10); + $this->dispatcher->addListener('pre.foo', $listener2); + $this->dispatcher->addListener('pre.foo', $listener3, 10); + $this->dispatcher->dispatch(self::preFoo); + $this->assertEquals(array('3', '2', '1'), $invoked); + } + + public function testRemoveListener() + { + $this->dispatcher->addListener('pre.bar', $this->listener); + $this->assertTrue($this->dispatcher->hasListeners(self::preBar)); + $this->dispatcher->removeListener('pre.bar', $this->listener); + $this->assertFalse($this->dispatcher->hasListeners(self::preBar)); + $this->dispatcher->removeListener('notExists', $this->listener); + } + + public function testAddSubscriber() + { + $eventSubscriber = new TestEventSubscriber(); + $this->dispatcher->addSubscriber($eventSubscriber); + $this->assertTrue($this->dispatcher->hasListeners(self::preFoo)); + $this->assertTrue($this->dispatcher->hasListeners(self::postFoo)); + } + + public function testAddSubscriberWithPriorities() + { + $eventSubscriber = new TestEventSubscriber(); + $this->dispatcher->addSubscriber($eventSubscriber); + + $eventSubscriber = new TestEventSubscriberWithPriorities(); + $this->dispatcher->addSubscriber($eventSubscriber); + + $listeners = $this->dispatcher->getListeners('pre.foo'); + $this->assertTrue($this->dispatcher->hasListeners(self::preFoo)); + $this->assertCount(2, $listeners); + $this->assertInstanceOf('Symfony\Component\EventDispatcher\Tests\TestEventSubscriberWithPriorities', $listeners[0][0]); + } + + public function testAddSubscriberWithMultipleListeners() + { + $eventSubscriber = new TestEventSubscriberWithMultipleListeners(); + $this->dispatcher->addSubscriber($eventSubscriber); + + $listeners = $this->dispatcher->getListeners('pre.foo'); + $this->assertTrue($this->dispatcher->hasListeners(self::preFoo)); + $this->assertCount(2, $listeners); + $this->assertEquals('preFoo2', $listeners[0][1]); + } + + public function testRemoveSubscriber() + { + $eventSubscriber = new TestEventSubscriber(); + $this->dispatcher->addSubscriber($eventSubscriber); + $this->assertTrue($this->dispatcher->hasListeners(self::preFoo)); + $this->assertTrue($this->dispatcher->hasListeners(self::postFoo)); + $this->dispatcher->removeSubscriber($eventSubscriber); + $this->assertFalse($this->dispatcher->hasListeners(self::preFoo)); + $this->assertFalse($this->dispatcher->hasListeners(self::postFoo)); + } + + public function testRemoveSubscriberWithPriorities() + { + $eventSubscriber = new TestEventSubscriberWithPriorities(); + $this->dispatcher->addSubscriber($eventSubscriber); + $this->assertTrue($this->dispatcher->hasListeners(self::preFoo)); + $this->dispatcher->removeSubscriber($eventSubscriber); + $this->assertFalse($this->dispatcher->hasListeners(self::preFoo)); + } + + public function testRemoveSubscriberWithMultipleListeners() + { + $eventSubscriber = new TestEventSubscriberWithMultipleListeners(); + $this->dispatcher->addSubscriber($eventSubscriber); + $this->assertTrue($this->dispatcher->hasListeners(self::preFoo)); + $this->assertCount(2, $this->dispatcher->getListeners(self::preFoo)); + $this->dispatcher->removeSubscriber($eventSubscriber); + $this->assertFalse($this->dispatcher->hasListeners(self::preFoo)); + } + + /** + * @group legacy + */ + public function testLegacyEventReceivesTheDispatcherInstance() + { + $dispatcher = null; + $this->dispatcher->addListener('test', function ($event) use (&$dispatcher) { + $dispatcher = $event->getDispatcher(); + }); + $this->dispatcher->dispatch('test'); + $this->assertSame($this->dispatcher, $dispatcher); + } + + public function testEventReceivesTheDispatcherInstanceAsArgument() + { + $listener = new TestWithDispatcher(); + $this->dispatcher->addListener('test', array($listener, 'foo')); + $this->assertNull($listener->name); + $this->assertNull($listener->dispatcher); + $this->dispatcher->dispatch('test'); + $this->assertEquals('test', $listener->name); + $this->assertSame($this->dispatcher, $listener->dispatcher); + } + + /** + * @see https://bugs.php.net/bug.php?id=62976 + * + * This bug affects: + * - The PHP 5.3 branch for versions < 5.3.18 + * - The PHP 5.4 branch for versions < 5.4.8 + * - The PHP 5.5 branch is not affected + */ + public function testWorkaroundForPhpBug62976() + { + $dispatcher = $this->createEventDispatcher(); + $dispatcher->addListener('bug.62976', new CallableClass()); + $dispatcher->removeListener('bug.62976', function () {}); + $this->assertTrue($dispatcher->hasListeners('bug.62976')); + } + + public function testHasListenersWhenAddedCallbackListenerIsRemoved() + { + $listener = function () {}; + $this->dispatcher->addListener('foo', $listener); + $this->dispatcher->removeListener('foo', $listener); + $this->assertFalse($this->dispatcher->hasListeners()); + } + + public function testGetListenersWhenAddedCallbackListenerIsRemoved() + { + $listener = function () {}; + $this->dispatcher->addListener('foo', $listener); + $this->dispatcher->removeListener('foo', $listener); + $this->assertSame(array(), $this->dispatcher->getListeners()); + } + + public function testHasListenersWithoutEventsReturnsFalseAfterHasListenersWithEventHasBeenCalled() + { + $this->assertFalse($this->dispatcher->hasListeners('foo')); + $this->assertFalse($this->dispatcher->hasListeners()); + } +} + +class CallableClass +{ + public function __invoke() + { + } +} + +class TestEventListener +{ + public $preFooInvoked = false; + public $postFooInvoked = false; + + /* Listener methods */ + + public function preFoo(Event $e) + { + $this->preFooInvoked = true; + } + + public function postFoo(Event $e) + { + $this->postFooInvoked = true; + + $e->stopPropagation(); + } +} + +class TestWithDispatcher +{ + public $name; + public $dispatcher; + + public function foo(Event $e, $name, $dispatcher) + { + $this->name = $name; + $this->dispatcher = $dispatcher; + } +} + +class TestEventSubscriber implements EventSubscriberInterface +{ + public static function getSubscribedEvents() + { + return array('pre.foo' => 'preFoo', 'post.foo' => 'postFoo'); + } +} + +class TestEventSubscriberWithPriorities implements EventSubscriberInterface +{ + public static function getSubscribedEvents() + { + return array( + 'pre.foo' => array('preFoo', 10), + 'post.foo' => array('postFoo'), + ); + } +} + +class TestEventSubscriberWithMultipleListeners implements EventSubscriberInterface +{ + public static function getSubscribedEvents() + { + return array('pre.foo' => array( + array('preFoo1'), + array('preFoo2', 10), + )); + } +} diff --git a/vendor/symfony/event-dispatcher/Tests/ContainerAwareEventDispatcherTest.php b/vendor/symfony/event-dispatcher/Tests/ContainerAwareEventDispatcherTest.php new file mode 100644 index 0000000..6f2fbcb --- /dev/null +++ b/vendor/symfony/event-dispatcher/Tests/ContainerAwareEventDispatcherTest.php @@ -0,0 +1,249 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\EventDispatcher\Tests; + +use Symfony\Component\DependencyInjection\Container; +use Symfony\Component\DependencyInjection\Scope; +use Symfony\Component\EventDispatcher\ContainerAwareEventDispatcher; +use Symfony\Component\EventDispatcher\Event; +use Symfony\Component\EventDispatcher\EventSubscriberInterface; + +class ContainerAwareEventDispatcherTest extends AbstractEventDispatcherTest +{ + protected function createEventDispatcher() + { + $container = new Container(); + + return new ContainerAwareEventDispatcher($container); + } + + public function testAddAListenerService() + { + $event = new Event(); + + $service = $this->getMock('Symfony\Component\EventDispatcher\Tests\Service'); + + $service + ->expects($this->once()) + ->method('onEvent') + ->with($event) + ; + + $container = new Container(); + $container->set('service.listener', $service); + + $dispatcher = new ContainerAwareEventDispatcher($container); + $dispatcher->addListenerService('onEvent', array('service.listener', 'onEvent')); + + $dispatcher->dispatch('onEvent', $event); + } + + public function testAddASubscriberService() + { + $event = new Event(); + + $service = $this->getMock('Symfony\Component\EventDispatcher\Tests\SubscriberService'); + + $service + ->expects($this->once()) + ->method('onEvent') + ->with($event) + ; + + $container = new Container(); + $container->set('service.subscriber', $service); + + $dispatcher = new ContainerAwareEventDispatcher($container); + $dispatcher->addSubscriberService('service.subscriber', 'Symfony\Component\EventDispatcher\Tests\SubscriberService'); + + $dispatcher->dispatch('onEvent', $event); + } + + public function testPreventDuplicateListenerService() + { + $event = new Event(); + + $service = $this->getMock('Symfony\Component\EventDispatcher\Tests\Service'); + + $service + ->expects($this->once()) + ->method('onEvent') + ->with($event) + ; + + $container = new Container(); + $container->set('service.listener', $service); + + $dispatcher = new ContainerAwareEventDispatcher($container); + $dispatcher->addListenerService('onEvent', array('service.listener', 'onEvent'), 5); + $dispatcher->addListenerService('onEvent', array('service.listener', 'onEvent'), 10); + + $dispatcher->dispatch('onEvent', $event); + } + + /** + * @expectedException \InvalidArgumentException + */ + public function testTriggerAListenerServiceOutOfScope() + { + $service = $this->getMock('Symfony\Component\EventDispatcher\Tests\Service'); + + $scope = new Scope('scope'); + $container = new Container(); + $container->addScope($scope); + $container->enterScope('scope'); + + $container->set('service.listener', $service, 'scope'); + + $dispatcher = new ContainerAwareEventDispatcher($container); + $dispatcher->addListenerService('onEvent', array('service.listener', 'onEvent')); + + $container->leaveScope('scope'); + $dispatcher->dispatch('onEvent'); + } + + public function testReEnteringAScope() + { + $event = new Event(); + + $service1 = $this->getMock('Symfony\Component\EventDispatcher\Tests\Service'); + + $service1 + ->expects($this->exactly(2)) + ->method('onEvent') + ->with($event) + ; + + $scope = new Scope('scope'); + $container = new Container(); + $container->addScope($scope); + $container->enterScope('scope'); + + $container->set('service.listener', $service1, 'scope'); + + $dispatcher = new ContainerAwareEventDispatcher($container); + $dispatcher->addListenerService('onEvent', array('service.listener', 'onEvent')); + $dispatcher->dispatch('onEvent', $event); + + $service2 = $this->getMock('Symfony\Component\EventDispatcher\Tests\Service'); + + $service2 + ->expects($this->once()) + ->method('onEvent') + ->with($event) + ; + + $container->enterScope('scope'); + $container->set('service.listener', $service2, 'scope'); + + $dispatcher->dispatch('onEvent', $event); + + $container->leaveScope('scope'); + + $dispatcher->dispatch('onEvent'); + } + + public function testHasListenersOnLazyLoad() + { + $event = new Event(); + + $service = $this->getMock('Symfony\Component\EventDispatcher\Tests\Service'); + + $container = new Container(); + $container->set('service.listener', $service); + + $dispatcher = new ContainerAwareEventDispatcher($container); + $dispatcher->addListenerService('onEvent', array('service.listener', 'onEvent')); + + $event->setDispatcher($dispatcher); + $event->setName('onEvent'); + + $service + ->expects($this->once()) + ->method('onEvent') + ->with($event) + ; + + $this->assertTrue($dispatcher->hasListeners()); + + if ($dispatcher->hasListeners('onEvent')) { + $dispatcher->dispatch('onEvent'); + } + } + + public function testGetListenersOnLazyLoad() + { + $service = $this->getMock('Symfony\Component\EventDispatcher\Tests\Service'); + + $container = new Container(); + $container->set('service.listener', $service); + + $dispatcher = new ContainerAwareEventDispatcher($container); + $dispatcher->addListenerService('onEvent', array('service.listener', 'onEvent')); + + $listeners = $dispatcher->getListeners(); + + $this->assertTrue(isset($listeners['onEvent'])); + + $this->assertCount(1, $dispatcher->getListeners('onEvent')); + } + + public function testRemoveAfterDispatch() + { + $service = $this->getMock('Symfony\Component\EventDispatcher\Tests\Service'); + + $container = new Container(); + $container->set('service.listener', $service); + + $dispatcher = new ContainerAwareEventDispatcher($container); + $dispatcher->addListenerService('onEvent', array('service.listener', 'onEvent')); + + $dispatcher->dispatch('onEvent', new Event()); + $dispatcher->removeListener('onEvent', array($container->get('service.listener'), 'onEvent')); + $this->assertFalse($dispatcher->hasListeners('onEvent')); + } + + public function testRemoveBeforeDispatch() + { + $service = $this->getMock('Symfony\Component\EventDispatcher\Tests\Service'); + + $container = new Container(); + $container->set('service.listener', $service); + + $dispatcher = new ContainerAwareEventDispatcher($container); + $dispatcher->addListenerService('onEvent', array('service.listener', 'onEvent')); + + $dispatcher->removeListener('onEvent', array($container->get('service.listener'), 'onEvent')); + $this->assertFalse($dispatcher->hasListeners('onEvent')); + } +} + +class Service +{ + public function onEvent(Event $e) + { + } +} + +class SubscriberService implements EventSubscriberInterface +{ + public static function getSubscribedEvents() + { + return array( + 'onEvent' => array('onEvent'), + ); + } + + public function onEvent(Event $e) + { + } +} diff --git a/vendor/symfony/event-dispatcher/Tests/Debug/TraceableEventDispatcherTest.php b/vendor/symfony/event-dispatcher/Tests/Debug/TraceableEventDispatcherTest.php new file mode 100644 index 0000000..4aa6226 --- /dev/null +++ b/vendor/symfony/event-dispatcher/Tests/Debug/TraceableEventDispatcherTest.php @@ -0,0 +1,199 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\EventDispatcher\Tests\Debug; + +use Symfony\Component\EventDispatcher\Debug\TraceableEventDispatcher; +use Symfony\Component\EventDispatcher\EventDispatcherInterface; +use Symfony\Component\EventDispatcher\EventSubscriberInterface; +use Symfony\Component\EventDispatcher\EventDispatcher; +use Symfony\Component\EventDispatcher\Event; +use Symfony\Component\Stopwatch\Stopwatch; + +class TraceableEventDispatcherTest extends \PHPUnit_Framework_TestCase +{ + public function testAddRemoveListener() + { + $dispatcher = new EventDispatcher(); + $tdispatcher = new TraceableEventDispatcher($dispatcher, new Stopwatch()); + + $tdispatcher->addListener('foo', $listener = function () {; }); + $listeners = $dispatcher->getListeners('foo'); + $this->assertCount(1, $listeners); + $this->assertSame($listener, $listeners[0]); + + $tdispatcher->removeListener('foo', $listener); + $this->assertCount(0, $dispatcher->getListeners('foo')); + } + + public function testGetListeners() + { + $dispatcher = new EventDispatcher(); + $tdispatcher = new TraceableEventDispatcher($dispatcher, new Stopwatch()); + + $tdispatcher->addListener('foo', $listener = function () {; }); + $this->assertSame($dispatcher->getListeners('foo'), $tdispatcher->getListeners('foo')); + } + + public function testHasListeners() + { + $dispatcher = new EventDispatcher(); + $tdispatcher = new TraceableEventDispatcher($dispatcher, new Stopwatch()); + + $this->assertFalse($dispatcher->hasListeners('foo')); + $this->assertFalse($tdispatcher->hasListeners('foo')); + + $tdispatcher->addListener('foo', $listener = function () {; }); + $this->assertTrue($dispatcher->hasListeners('foo')); + $this->assertTrue($tdispatcher->hasListeners('foo')); + } + + public function testAddRemoveSubscriber() + { + $dispatcher = new EventDispatcher(); + $tdispatcher = new TraceableEventDispatcher($dispatcher, new Stopwatch()); + + $subscriber = new EventSubscriber(); + + $tdispatcher->addSubscriber($subscriber); + $listeners = $dispatcher->getListeners('foo'); + $this->assertCount(1, $listeners); + $this->assertSame(array($subscriber, 'call'), $listeners[0]); + + $tdispatcher->removeSubscriber($subscriber); + $this->assertCount(0, $dispatcher->getListeners('foo')); + } + + public function testGetCalledListeners() + { + $dispatcher = new EventDispatcher(); + $tdispatcher = new TraceableEventDispatcher($dispatcher, new Stopwatch()); + $tdispatcher->addListener('foo', $listener = function () {; }); + + $this->assertEquals(array(), $tdispatcher->getCalledListeners()); + $this->assertEquals(array('foo.closure' => array('event' => 'foo', 'type' => 'Closure', 'pretty' => 'closure')), $tdispatcher->getNotCalledListeners()); + + $tdispatcher->dispatch('foo'); + + $this->assertEquals(array('foo.closure' => array('event' => 'foo', 'type' => 'Closure', 'pretty' => 'closure')), $tdispatcher->getCalledListeners()); + $this->assertEquals(array(), $tdispatcher->getNotCalledListeners()); + } + + public function testGetCalledListenersNested() + { + $tdispatcher = null; + $dispatcher = new TraceableEventDispatcher(new EventDispatcher(), new Stopwatch()); + $dispatcher->addListener('foo', function (Event $event, $eventName, $dispatcher) use (&$tdispatcher) { + $tdispatcher = $dispatcher; + $dispatcher->dispatch('bar'); + }); + $dispatcher->addListener('bar', function (Event $event) {}); + $dispatcher->dispatch('foo'); + $this->assertSame($dispatcher, $tdispatcher); + $this->assertCount(2, $dispatcher->getCalledListeners()); + } + + public function testLogger() + { + $logger = $this->getMock('Psr\Log\LoggerInterface'); + + $dispatcher = new EventDispatcher(); + $tdispatcher = new TraceableEventDispatcher($dispatcher, new Stopwatch(), $logger); + $tdispatcher->addListener('foo', $listener1 = function () {; }); + $tdispatcher->addListener('foo', $listener2 = function () {; }); + + $logger->expects($this->at(0))->method('debug')->with('Notified event "foo" to listener "closure".'); + $logger->expects($this->at(1))->method('debug')->with('Notified event "foo" to listener "closure".'); + + $tdispatcher->dispatch('foo'); + } + + public function testLoggerWithStoppedEvent() + { + $logger = $this->getMock('Psr\Log\LoggerInterface'); + + $dispatcher = new EventDispatcher(); + $tdispatcher = new TraceableEventDispatcher($dispatcher, new Stopwatch(), $logger); + $tdispatcher->addListener('foo', $listener1 = function (Event $event) { $event->stopPropagation(); }); + $tdispatcher->addListener('foo', $listener2 = function () {; }); + + $logger->expects($this->at(0))->method('debug')->with('Notified event "foo" to listener "closure".'); + $logger->expects($this->at(1))->method('debug')->with('Listener "closure" stopped propagation of the event "foo".'); + $logger->expects($this->at(2))->method('debug')->with('Listener "closure" was not called for event "foo".'); + + $tdispatcher->dispatch('foo'); + } + + public function testDispatchCallListeners() + { + $called = array(); + + $dispatcher = new EventDispatcher(); + $tdispatcher = new TraceableEventDispatcher($dispatcher, new Stopwatch()); + $tdispatcher->addListener('foo', $listener1 = function () use (&$called) { $called[] = 'foo1'; }); + $tdispatcher->addListener('foo', $listener2 = function () use (&$called) { $called[] = 'foo2'; }); + + $tdispatcher->dispatch('foo'); + + $this->assertEquals(array('foo1', 'foo2'), $called); + } + + public function testDispatchNested() + { + $dispatcher = new TraceableEventDispatcher(new EventDispatcher(), new Stopwatch()); + $loop = 1; + $dispatcher->addListener('foo', $listener1 = function () use ($dispatcher, &$loop) { + ++$loop; + if (2 == $loop) { + $dispatcher->dispatch('foo'); + } + }); + + $dispatcher->dispatch('foo'); + } + + public function testDispatchReusedEventNested() + { + $nestedCall = false; + $dispatcher = new TraceableEventDispatcher(new EventDispatcher(), new Stopwatch()); + $dispatcher->addListener('foo', function (Event $e) use ($dispatcher) { + $dispatcher->dispatch('bar', $e); + }); + $dispatcher->addListener('bar', function (Event $e) use (&$nestedCall) { + $nestedCall = true; + }); + + $this->assertFalse($nestedCall); + $dispatcher->dispatch('foo'); + $this->assertTrue($nestedCall); + } + + public function testListenerCanRemoveItselfWhenExecuted() + { + $eventDispatcher = new TraceableEventDispatcher(new EventDispatcher(), new Stopwatch()); + $listener1 = function ($event, $eventName, EventDispatcherInterface $dispatcher) use (&$listener1) { + $dispatcher->removeListener('foo', $listener1); + }; + $eventDispatcher->addListener('foo', $listener1); + $eventDispatcher->addListener('foo', function () {}); + $eventDispatcher->dispatch('foo'); + + $this->assertCount(1, $eventDispatcher->getListeners('foo'), 'expected listener1 to be removed'); + } +} + +class EventSubscriber implements EventSubscriberInterface +{ + public static function getSubscribedEvents() + { + return array('foo' => 'call'); + } +} diff --git a/vendor/symfony/event-dispatcher/Tests/DependencyInjection/RegisterListenersPassTest.php b/vendor/symfony/event-dispatcher/Tests/DependencyInjection/RegisterListenersPassTest.php new file mode 100644 index 0000000..0fdd637 --- /dev/null +++ b/vendor/symfony/event-dispatcher/Tests/DependencyInjection/RegisterListenersPassTest.php @@ -0,0 +1,200 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\EventDispatcher\Tests\DependencyInjection; + +use Symfony\Component\DependencyInjection\ContainerBuilder; +use Symfony\Component\EventDispatcher\DependencyInjection\RegisterListenersPass; + +class RegisterListenersPassTest extends \PHPUnit_Framework_TestCase +{ + /** + * Tests that event subscribers not implementing EventSubscriberInterface + * trigger an exception. + * + * @expectedException \InvalidArgumentException + */ + public function testEventSubscriberWithoutInterface() + { + // one service, not implementing any interface + $services = array( + 'my_event_subscriber' => array(0 => array()), + ); + + $definition = $this->getMock('Symfony\Component\DependencyInjection\Definition'); + $definition->expects($this->atLeastOnce()) + ->method('isPublic') + ->will($this->returnValue(true)); + $definition->expects($this->atLeastOnce()) + ->method('getClass') + ->will($this->returnValue('stdClass')); + + $builder = $this->getMock( + 'Symfony\Component\DependencyInjection\ContainerBuilder', + array('hasDefinition', 'findTaggedServiceIds', 'getDefinition') + ); + $builder->expects($this->any()) + ->method('hasDefinition') + ->will($this->returnValue(true)); + + // We don't test kernel.event_listener here + $builder->expects($this->atLeastOnce()) + ->method('findTaggedServiceIds') + ->will($this->onConsecutiveCalls(array(), $services)); + + $builder->expects($this->atLeastOnce()) + ->method('getDefinition') + ->will($this->returnValue($definition)); + + $registerListenersPass = new RegisterListenersPass(); + $registerListenersPass->process($builder); + } + + public function testValidEventSubscriber() + { + $services = array( + 'my_event_subscriber' => array(0 => array()), + ); + + $definition = $this->getMock('Symfony\Component\DependencyInjection\Definition'); + $definition->expects($this->atLeastOnce()) + ->method('isPublic') + ->will($this->returnValue(true)); + $definition->expects($this->atLeastOnce()) + ->method('getClass') + ->will($this->returnValue('Symfony\Component\EventDispatcher\Tests\DependencyInjection\SubscriberService')); + + $builder = $this->getMock( + 'Symfony\Component\DependencyInjection\ContainerBuilder', + array('hasDefinition', 'findTaggedServiceIds', 'getDefinition', 'findDefinition') + ); + $builder->expects($this->any()) + ->method('hasDefinition') + ->will($this->returnValue(true)); + + // We don't test kernel.event_listener here + $builder->expects($this->atLeastOnce()) + ->method('findTaggedServiceIds') + ->will($this->onConsecutiveCalls(array(), $services)); + + $builder->expects($this->atLeastOnce()) + ->method('getDefinition') + ->will($this->returnValue($definition)); + + $builder->expects($this->atLeastOnce()) + ->method('findDefinition') + ->will($this->returnValue($definition)); + + $registerListenersPass = new RegisterListenersPass(); + $registerListenersPass->process($builder); + } + + /** + * @expectedException \InvalidArgumentException + * @expectedExceptionMessage The service "foo" must be public as event listeners are lazy-loaded. + */ + public function testPrivateEventListener() + { + $container = new ContainerBuilder(); + $container->register('foo', 'stdClass')->setPublic(false)->addTag('kernel.event_listener', array()); + $container->register('event_dispatcher', 'stdClass'); + + $registerListenersPass = new RegisterListenersPass(); + $registerListenersPass->process($container); + } + + /** + * @expectedException \InvalidArgumentException + * @expectedExceptionMessage The service "foo" must be public as event subscribers are lazy-loaded. + */ + public function testPrivateEventSubscriber() + { + $container = new ContainerBuilder(); + $container->register('foo', 'stdClass')->setPublic(false)->addTag('kernel.event_subscriber', array()); + $container->register('event_dispatcher', 'stdClass'); + + $registerListenersPass = new RegisterListenersPass(); + $registerListenersPass->process($container); + } + + /** + * @expectedException \InvalidArgumentException + * @expectedExceptionMessage The service "foo" must not be abstract as event listeners are lazy-loaded. + */ + public function testAbstractEventListener() + { + $container = new ContainerBuilder(); + $container->register('foo', 'stdClass')->setAbstract(true)->addTag('kernel.event_listener', array()); + $container->register('event_dispatcher', 'stdClass'); + + $registerListenersPass = new RegisterListenersPass(); + $registerListenersPass->process($container); + } + + /** + * @expectedException \InvalidArgumentException + * @expectedExceptionMessage The service "foo" must not be abstract as event subscribers are lazy-loaded. + */ + public function testAbstractEventSubscriber() + { + $container = new ContainerBuilder(); + $container->register('foo', 'stdClass')->setAbstract(true)->addTag('kernel.event_subscriber', array()); + $container->register('event_dispatcher', 'stdClass'); + + $registerListenersPass = new RegisterListenersPass(); + $registerListenersPass->process($container); + } + + public function testEventSubscriberResolvableClassName() + { + $container = new ContainerBuilder(); + + $container->setParameter('subscriber.class', 'Symfony\Component\EventDispatcher\Tests\DependencyInjection\SubscriberService'); + $container->register('foo', '%subscriber.class%')->addTag('kernel.event_subscriber', array()); + $container->register('event_dispatcher', 'stdClass'); + + $registerListenersPass = new RegisterListenersPass(); + $registerListenersPass->process($container); + + $definition = $container->getDefinition('event_dispatcher'); + $expected_calls = array( + array( + 'addSubscriberService', + array( + 'foo', + 'Symfony\Component\EventDispatcher\Tests\DependencyInjection\SubscriberService', + ), + ), + ); + $this->assertSame($expected_calls, $definition->getMethodCalls()); + } + + /** + * @expectedException \InvalidArgumentException + * @expectedExceptionMessage You have requested a non-existent parameter "subscriber.class" + */ + public function testEventSubscriberUnresolvableClassName() + { + $container = new ContainerBuilder(); + $container->register('foo', '%subscriber.class%')->addTag('kernel.event_subscriber', array()); + $container->register('event_dispatcher', 'stdClass'); + + $registerListenersPass = new RegisterListenersPass(); + $registerListenersPass->process($container); + } +} + +class SubscriberService implements \Symfony\Component\EventDispatcher\EventSubscriberInterface +{ + public static function getSubscribedEvents() + { + } +} diff --git a/vendor/symfony/event-dispatcher/Tests/EventDispatcherTest.php b/vendor/symfony/event-dispatcher/Tests/EventDispatcherTest.php new file mode 100644 index 0000000..5faa5c8 --- /dev/null +++ b/vendor/symfony/event-dispatcher/Tests/EventDispatcherTest.php @@ -0,0 +1,22 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\EventDispatcher\Tests; + +use Symfony\Component\EventDispatcher\EventDispatcher; + +class EventDispatcherTest extends AbstractEventDispatcherTest +{ + protected function createEventDispatcher() + { + return new EventDispatcher(); + } +} diff --git a/vendor/symfony/event-dispatcher/Tests/EventTest.php b/vendor/symfony/event-dispatcher/Tests/EventTest.php new file mode 100644 index 0000000..9a82267 --- /dev/null +++ b/vendor/symfony/event-dispatcher/Tests/EventTest.php @@ -0,0 +1,96 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\EventDispatcher\Tests; + +use Symfony\Component\EventDispatcher\Event; +use Symfony\Component\EventDispatcher\EventDispatcher; + +/** + * Test class for Event. + */ +class EventTest extends \PHPUnit_Framework_TestCase +{ + /** + * @var \Symfony\Component\EventDispatcher\Event + */ + protected $event; + + /** + * @var \Symfony\Component\EventDispatcher\EventDispatcher + */ + protected $dispatcher; + + /** + * Sets up the fixture, for example, opens a network connection. + * This method is called before a test is executed. + */ + protected function setUp() + { + $this->event = new Event(); + $this->dispatcher = new EventDispatcher(); + } + + /** + * Tears down the fixture, for example, closes a network connection. + * This method is called after a test is executed. + */ + protected function tearDown() + { + $this->event = null; + $this->dispatcher = null; + } + + public function testIsPropagationStopped() + { + $this->assertFalse($this->event->isPropagationStopped()); + } + + public function testStopPropagationAndIsPropagationStopped() + { + $this->event->stopPropagation(); + $this->assertTrue($this->event->isPropagationStopped()); + } + + /** + * @group legacy + */ + public function testLegacySetDispatcher() + { + $this->event->setDispatcher($this->dispatcher); + $this->assertSame($this->dispatcher, $this->event->getDispatcher()); + } + + /** + * @group legacy + */ + public function testLegacyGetDispatcher() + { + $this->assertNull($this->event->getDispatcher()); + } + + /** + * @group legacy + */ + public function testLegacyGetName() + { + $this->assertNull($this->event->getName()); + } + + /** + * @group legacy + */ + public function testLegacySetName() + { + $this->event->setName('foo'); + $this->assertEquals('foo', $this->event->getName()); + } +} diff --git a/vendor/symfony/event-dispatcher/Tests/GenericEventTest.php b/vendor/symfony/event-dispatcher/Tests/GenericEventTest.php new file mode 100644 index 0000000..aebd82d --- /dev/null +++ b/vendor/symfony/event-dispatcher/Tests/GenericEventTest.php @@ -0,0 +1,139 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\EventDispatcher\Tests; + +use Symfony\Component\EventDispatcher\GenericEvent; + +/** + * Test class for Event. + */ +class GenericEventTest extends \PHPUnit_Framework_TestCase +{ + /** + * @var GenericEvent + */ + private $event; + + private $subject; + + /** + * Prepares the environment before running a test. + */ + protected function setUp() + { + parent::setUp(); + + $this->subject = new \stdClass(); + $this->event = new GenericEvent($this->subject, array('name' => 'Event')); + } + + /** + * Cleans up the environment after running a test. + */ + protected function tearDown() + { + $this->subject = null; + $this->event = null; + + parent::tearDown(); + } + + public function testConstruct() + { + $this->assertEquals($this->event, new GenericEvent($this->subject, array('name' => 'Event'))); + } + + /** + * Tests Event->getArgs(). + */ + public function testGetArguments() + { + // test getting all + $this->assertSame(array('name' => 'Event'), $this->event->getArguments()); + } + + public function testSetArguments() + { + $result = $this->event->setArguments(array('foo' => 'bar')); + $this->assertAttributeSame(array('foo' => 'bar'), 'arguments', $this->event); + $this->assertSame($this->event, $result); + } + + public function testSetArgument() + { + $result = $this->event->setArgument('foo2', 'bar2'); + $this->assertAttributeSame(array('name' => 'Event', 'foo2' => 'bar2'), 'arguments', $this->event); + $this->assertEquals($this->event, $result); + } + + public function testGetArgument() + { + // test getting key + $this->assertEquals('Event', $this->event->getArgument('name')); + } + + /** + * @expectedException \InvalidArgumentException + */ + public function testGetArgException() + { + $this->event->getArgument('nameNotExist'); + } + + public function testOffsetGet() + { + // test getting key + $this->assertEquals('Event', $this->event['name']); + + // test getting invalid arg + $this->setExpectedException('InvalidArgumentException'); + $this->assertFalse($this->event['nameNotExist']); + } + + public function testOffsetSet() + { + $this->event['foo2'] = 'bar2'; + $this->assertAttributeSame(array('name' => 'Event', 'foo2' => 'bar2'), 'arguments', $this->event); + } + + public function testOffsetUnset() + { + unset($this->event['name']); + $this->assertAttributeSame(array(), 'arguments', $this->event); + } + + public function testOffsetIsset() + { + $this->assertTrue(isset($this->event['name'])); + $this->assertFalse(isset($this->event['nameNotExist'])); + } + + public function testHasArgument() + { + $this->assertTrue($this->event->hasArgument('name')); + $this->assertFalse($this->event->hasArgument('nameNotExist')); + } + + public function testGetSubject() + { + $this->assertSame($this->subject, $this->event->getSubject()); + } + + public function testHasIterator() + { + $data = array(); + foreach ($this->event as $key => $value) { + $data[$key] = $value; + } + $this->assertEquals(array('name' => 'Event'), $data); + } +} diff --git a/vendor/symfony/event-dispatcher/Tests/ImmutableEventDispatcherTest.php b/vendor/symfony/event-dispatcher/Tests/ImmutableEventDispatcherTest.php new file mode 100644 index 0000000..80a7e43 --- /dev/null +++ b/vendor/symfony/event-dispatcher/Tests/ImmutableEventDispatcherTest.php @@ -0,0 +1,105 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\EventDispatcher\Tests; + +use Symfony\Component\EventDispatcher\Event; +use Symfony\Component\EventDispatcher\ImmutableEventDispatcher; + +/** + * @author Bernhard Schussek + */ +class ImmutableEventDispatcherTest extends \PHPUnit_Framework_TestCase +{ + /** + * @var \PHPUnit_Framework_MockObject_MockObject + */ + private $innerDispatcher; + + /** + * @var ImmutableEventDispatcher + */ + private $dispatcher; + + protected function setUp() + { + $this->innerDispatcher = $this->getMock('Symfony\Component\EventDispatcher\EventDispatcherInterface'); + $this->dispatcher = new ImmutableEventDispatcher($this->innerDispatcher); + } + + public function testDispatchDelegates() + { + $event = new Event(); + + $this->innerDispatcher->expects($this->once()) + ->method('dispatch') + ->with('event', $event) + ->will($this->returnValue('result')); + + $this->assertSame('result', $this->dispatcher->dispatch('event', $event)); + } + + public function testGetListenersDelegates() + { + $this->innerDispatcher->expects($this->once()) + ->method('getListeners') + ->with('event') + ->will($this->returnValue('result')); + + $this->assertSame('result', $this->dispatcher->getListeners('event')); + } + + public function testHasListenersDelegates() + { + $this->innerDispatcher->expects($this->once()) + ->method('hasListeners') + ->with('event') + ->will($this->returnValue('result')); + + $this->assertSame('result', $this->dispatcher->hasListeners('event')); + } + + /** + * @expectedException \BadMethodCallException + */ + public function testAddListenerDisallowed() + { + $this->dispatcher->addListener('event', function () { return 'foo'; }); + } + + /** + * @expectedException \BadMethodCallException + */ + public function testAddSubscriberDisallowed() + { + $subscriber = $this->getMock('Symfony\Component\EventDispatcher\EventSubscriberInterface'); + + $this->dispatcher->addSubscriber($subscriber); + } + + /** + * @expectedException \BadMethodCallException + */ + public function testRemoveListenerDisallowed() + { + $this->dispatcher->removeListener('event', function () { return 'foo'; }); + } + + /** + * @expectedException \BadMethodCallException + */ + public function testRemoveSubscriberDisallowed() + { + $subscriber = $this->getMock('Symfony\Component\EventDispatcher\EventSubscriberInterface'); + + $this->dispatcher->removeSubscriber($subscriber); + } +} diff --git a/vendor/symfony/event-dispatcher/composer.json b/vendor/symfony/event-dispatcher/composer.json new file mode 100644 index 0000000..d705862 --- /dev/null +++ b/vendor/symfony/event-dispatcher/composer.json @@ -0,0 +1,42 @@ +{ + "name": "symfony/event-dispatcher", + "type": "library", + "description": "Symfony EventDispatcher Component", + "keywords": [], + "homepage": "https://symfony.com", + "license": "MIT", + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "require": { + "php": ">=5.3.9" + }, + "require-dev": { + "symfony/phpunit-bridge": "~2.7", + "symfony/dependency-injection": "~2.6", + "symfony/expression-language": "~2.6", + "symfony/config": "~2.0,>=2.0.5", + "symfony/stopwatch": "~2.3", + "psr/log": "~1.0" + }, + "suggest": { + "symfony/dependency-injection": "", + "symfony/http-kernel": "" + }, + "autoload": { + "psr-4": { "Symfony\\Component\\EventDispatcher\\": "" } + }, + "minimum-stability": "dev", + "extra": { + "branch-alias": { + "dev-master": "2.7-dev" + } + } +} diff --git a/vendor/symfony/event-dispatcher/phpunit.xml.dist b/vendor/symfony/event-dispatcher/phpunit.xml.dist new file mode 100644 index 0000000..ae0586e --- /dev/null +++ b/vendor/symfony/event-dispatcher/phpunit.xml.dist @@ -0,0 +1,29 @@ + + + + + + + + + + ./Tests/ + + + + + + ./ + + ./Resources + ./Tests + ./vendor + + + + diff --git a/vendor/symfony/serializer/.gitignore b/vendor/symfony/serializer/.gitignore new file mode 100644 index 0000000..c49a5d8 --- /dev/null +++ b/vendor/symfony/serializer/.gitignore @@ -0,0 +1,3 @@ +vendor/ +composer.lock +phpunit.xml diff --git a/vendor/symfony/serializer/Annotation/Groups.php b/vendor/symfony/serializer/Annotation/Groups.php new file mode 100644 index 0000000..519837a --- /dev/null +++ b/vendor/symfony/serializer/Annotation/Groups.php @@ -0,0 +1,64 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Serializer\Annotation; + +use Symfony\Component\Serializer\Exception\InvalidArgumentException; + +/** + * Annotation class for @Groups(). + * + * @Annotation + * @Target({"PROPERTY", "METHOD"}) + * + * @author Kévin Dunglas + */ +class Groups +{ + /** + * @var array + */ + private $groups; + + /** + * @param array $data + * + * @throws InvalidArgumentException + */ + public function __construct(array $data) + { + if (!isset($data['value']) || !$data['value']) { + throw new InvalidArgumentException(sprintf('Parameter of annotation "%s" cannot be empty.', get_class($this))); + } + + if (!is_array($data['value'])) { + throw new InvalidArgumentException(sprintf('Parameter of annotation "%s" must be an array of strings.', get_class($this))); + } + + foreach ($data['value'] as $group) { + if (!is_string($group)) { + throw new InvalidArgumentException(sprintf('Parameter of annotation "%s" must be an array of strings.', get_class($this))); + } + } + + $this->groups = $data['value']; + } + + /** + * Gets groups. + * + * @return array + */ + public function getGroups() + { + return $this->groups; + } +} diff --git a/vendor/symfony/serializer/CHANGELOG.md b/vendor/symfony/serializer/CHANGELOG.md new file mode 100644 index 0000000..ceeeeb1 --- /dev/null +++ b/vendor/symfony/serializer/CHANGELOG.md @@ -0,0 +1,96 @@ +CHANGELOG +========= + +2.7.0 +----- + + * added support for serialization and deserialization groups including + annotations, XML and YAML mapping. + * added `AbstractNormalizer` to factorise code and ease normalizers development + * added circular references handling for `PropertyNormalizer` + * added support for a context key called `object_to_populate` in `AbstractNormalizer` + to reuse existing objects in the deserialization process + * added `NameConverterInterface` and `CamelCaseToSnakeCaseNameConverter` + * [DEPRECATION] `GetSetMethodNormalizer::setCamelizedAttributes()` and + `PropertyNormalizer::setCamelizedAttributes()` are replaced by + `CamelCaseToSnakeCaseNameConverter` + * [DEPRECATION] the `Exception` interface has been renamed to `ExceptionInterface` + * added `ObjectNormalizer` leveraging the `PropertyAccess` component to normalize + objects containing both properties and getters / setters / issers / hassers methods. + +2.6.0 +----- + + * added a new serializer: `PropertyNormalizer`. Like `GetSetMethodNormalizer`, + this normalizer will map an object's properties to an array. + * added circular references handling for `GetSetMethodNormalizer` + +2.5.0 +----- + + * added support for `is.*` getters in `GetSetMethodNormalizer` + +2.4.0 +----- + + * added `$context` support for XMLEncoder. + * [DEPRECATION] JsonEncode and JsonDecode where modified to throw + an exception if error found. No need for get*Error() functions + +2.3.0 +----- + + * added `GetSetMethodNormalizer::setCamelizedAttributes` to allow calling + camel cased methods for underscored properties + +2.2.0 +----- + + * [BC BREAK] All Serializer, Normalizer and Encoder interfaces have been + modified to include an optional `$context` array parameter. + * The XML Root name can now be configured with the `xml_root_name` + parameter in the context option to the `XmlEncoder`. + * Options to `json_encode` and `json_decode` can be passed through + the context options of `JsonEncode` and `JsonDecode` encoder/decoders. + +2.1.0 +----- + + * added DecoderInterface::supportsDecoding(), + EncoderInterface::supportsEncoding() + * removed NormalizableInterface::denormalize(), + NormalizerInterface::denormalize(), + NormalizerInterface::supportsDenormalization() + * removed normalize() denormalize() encode() decode() supportsSerialization() + supportsDeserialization() supportsEncoding() supportsDecoding() + getEncoder() from SerializerInterface + * Serializer now implements NormalizerInterface, DenormalizerInterface, + EncoderInterface, DecoderInterface in addition to SerializerInterface + * added DenormalizableInterface and DenormalizerInterface + * [BC BREAK] changed `GetSetMethodNormalizer`'s key names from all lowercased + to camelCased (e.g. `mypropertyvalue` to `myPropertyValue`) + * [BC BREAK] convert the `item` XML tag to an array + + ``` xml + + + <![CDATA[title1]]><![CDATA[title2]]> + + ``` + + Before: + + Array() + + After: + + Array( + [item] => Array( + [0] => Array( + [title] => title1 + ) + [1] => Array( + [title] => title2 + ) + ) + ) diff --git a/vendor/symfony/serializer/Encoder/ChainDecoder.php b/vendor/symfony/serializer/Encoder/ChainDecoder.php new file mode 100644 index 0000000..f8f17b4 --- /dev/null +++ b/vendor/symfony/serializer/Encoder/ChainDecoder.php @@ -0,0 +1,82 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Serializer\Encoder; + +use Symfony\Component\Serializer\Exception\RuntimeException; + +/** + * Decoder delegating the decoding to a chain of decoders. + * + * @author Jordi Boggiano + * @author Johannes M. Schmitt + * @author Lukas Kahwe Smith + */ +class ChainDecoder implements DecoderInterface +{ + protected $decoders = array(); + protected $decoderByFormat = array(); + + public function __construct(array $decoders = array()) + { + $this->decoders = $decoders; + } + + /** + * {@inheritdoc} + */ + final public function decode($data, $format, array $context = array()) + { + return $this->getDecoder($format)->decode($data, $format, $context); + } + + /** + * {@inheritdoc} + */ + public function supportsDecoding($format) + { + try { + $this->getDecoder($format); + } catch (RuntimeException $e) { + return false; + } + + return true; + } + + /** + * Gets the decoder supporting the format. + * + * @param string $format + * + * @return DecoderInterface + * + * @throws RuntimeException if no decoder is found + */ + private function getDecoder($format) + { + if (isset($this->decoderByFormat[$format]) + && isset($this->decoders[$this->decoderByFormat[$format]]) + ) { + return $this->decoders[$this->decoderByFormat[$format]]; + } + + foreach ($this->decoders as $i => $decoder) { + if ($decoder->supportsDecoding($format)) { + $this->decoderByFormat[$format] = $i; + + return $decoder; + } + } + + throw new RuntimeException(sprintf('No decoder found for format "%s".', $format)); + } +} diff --git a/vendor/symfony/serializer/Encoder/ChainEncoder.php b/vendor/symfony/serializer/Encoder/ChainEncoder.php new file mode 100644 index 0000000..5ee352a --- /dev/null +++ b/vendor/symfony/serializer/Encoder/ChainEncoder.php @@ -0,0 +1,104 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Serializer\Encoder; + +use Symfony\Component\Serializer\Exception\RuntimeException; + +/** + * Encoder delegating the decoding to a chain of encoders. + * + * @author Jordi Boggiano + * @author Johannes M. Schmitt + * @author Lukas Kahwe Smith + */ +class ChainEncoder implements EncoderInterface +{ + protected $encoders = array(); + protected $encoderByFormat = array(); + + public function __construct(array $encoders = array()) + { + $this->encoders = $encoders; + } + + /** + * {@inheritdoc} + */ + final public function encode($data, $format, array $context = array()) + { + return $this->getEncoder($format)->encode($data, $format, $context); + } + + /** + * {@inheritdoc} + */ + public function supportsEncoding($format) + { + try { + $this->getEncoder($format); + } catch (RuntimeException $e) { + return false; + } + + return true; + } + + /** + * Checks whether the normalization is needed for the given format. + * + * @param string $format + * + * @return bool + */ + public function needsNormalization($format) + { + $encoder = $this->getEncoder($format); + + if (!$encoder instanceof NormalizationAwareInterface) { + return true; + } + + if ($encoder instanceof self) { + return $encoder->needsNormalization($format); + } + + return false; + } + + /** + * Gets the encoder supporting the format. + * + * @param string $format + * + * @return EncoderInterface + * + * @throws RuntimeException if no encoder is found + */ + private function getEncoder($format) + { + if (isset($this->encoderByFormat[$format]) + && isset($this->encoders[$this->encoderByFormat[$format]]) + ) { + return $this->encoders[$this->encoderByFormat[$format]]; + } + + foreach ($this->encoders as $i => $encoder) { + if ($encoder->supportsEncoding($format)) { + $this->encoderByFormat[$format] = $i; + + return $encoder; + } + } + + throw new RuntimeException(sprintf('No encoder found for format "%s".', $format)); + } +} diff --git a/vendor/symfony/serializer/Encoder/DecoderInterface.php b/vendor/symfony/serializer/Encoder/DecoderInterface.php new file mode 100644 index 0000000..910f4ce --- /dev/null +++ b/vendor/symfony/serializer/Encoder/DecoderInterface.php @@ -0,0 +1,49 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Serializer\Encoder; + +use Symfony\Component\Serializer\Exception\UnexpectedValueException; + +/** + * Defines the interface of decoders. + * + * @author Jordi Boggiano + */ +interface DecoderInterface +{ + /** + * Decodes a string into PHP data. + * + * @param string $data Data to decode + * @param string $format Format name + * @param array $context options that decoders have access to. + * + * The format parameter specifies which format the data is in; valid values + * depend on the specific implementation. Authors implementing this interface + * are encouraged to document which formats they support in a non-inherited + * phpdoc comment. + * + * @return mixed + * + * @throws UnexpectedValueException + */ + public function decode($data, $format, array $context = array()); + + /** + * Checks whether the deserializer can decode from given format. + * + * @param string $format format name + * + * @return bool + */ + public function supportsDecoding($format); +} diff --git a/vendor/symfony/serializer/Encoder/EncoderInterface.php b/vendor/symfony/serializer/Encoder/EncoderInterface.php new file mode 100644 index 0000000..fe7e777 --- /dev/null +++ b/vendor/symfony/serializer/Encoder/EncoderInterface.php @@ -0,0 +1,44 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Serializer\Encoder; + +use Symfony\Component\Serializer\Exception\UnexpectedValueException; + +/** + * Defines the interface of encoders. + * + * @author Jordi Boggiano + */ +interface EncoderInterface +{ + /** + * Encodes data into the given format. + * + * @param mixed $data Data to encode + * @param string $format Format name + * @param array $context options that normalizers/encoders have access to. + * + * @return scalar + * + * @throws UnexpectedValueException + */ + public function encode($data, $format, array $context = array()); + + /** + * Checks whether the serializer can encode to given format. + * + * @param string $format format name + * + * @return bool + */ + public function supportsEncoding($format); +} diff --git a/vendor/symfony/serializer/Encoder/JsonDecode.php b/vendor/symfony/serializer/Encoder/JsonDecode.php new file mode 100644 index 0000000..5f5f289 --- /dev/null +++ b/vendor/symfony/serializer/Encoder/JsonDecode.php @@ -0,0 +1,142 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Serializer\Encoder; + +use Symfony\Component\Serializer\Exception\UnexpectedValueException; + +/** + * Decodes JSON data. + * + * @author Sander Coolen + */ +class JsonDecode implements DecoderInterface +{ + /** + * Specifies if the returned result should be an associative array or a nested stdClass object hierarchy. + * + * @var bool + */ + private $associative; + + /** + * Specifies the recursion depth. + * + * @var int + */ + private $recursionDepth; + + private $lastError = JSON_ERROR_NONE; + + protected $serializer; + + /** + * Constructs a new JsonDecode instance. + * + * @param bool $associative True to return the result associative array, false for a nested stdClass hierarchy + * @param int $depth Specifies the recursion depth + */ + public function __construct($associative = false, $depth = 512) + { + $this->associative = $associative; + $this->recursionDepth = (int) $depth; + } + + /** + * Returns the last decoding error (if any). + * + * @return int + * + * @deprecated since version 2.5, to be removed in 3.0. + * The {@self decode()} method throws an exception if error found. + * @see http://php.net/manual/en/function.json-last-error.php json_last_error + */ + public function getLastError() + { + @trigger_error('The '.__METHOD__.' method is deprecated since version 2.5 and will be removed in 3.0. Catch the exception raised by the decode() method instead to get the last JSON decoding error.', E_USER_DEPRECATED); + + return $this->lastError; + } + + /** + * Decodes data. + * + * @param string $data The encoded JSON string to decode + * @param string $format Must be set to JsonEncoder::FORMAT + * @param array $context An optional set of options for the JSON decoder; see below + * + * The $context array is a simple key=>value array, with the following supported keys: + * + * json_decode_associative: boolean + * If true, returns the object as associative array. + * If false, returns the object as nested stdClass + * If not specified, this method will use the default set in JsonDecode::__construct + * + * json_decode_recursion_depth: integer + * Specifies the maximum recursion depth + * If not specified, this method will use the default set in JsonDecode::__construct + * + * json_decode_options: integer + * Specifies additional options as per documentation for json_decode. Only supported with PHP 5.4.0 and higher + * + * @return mixed + * + * @throws UnexpectedValueException + * + * @see http://php.net/json_decode json_decode + */ + public function decode($data, $format, array $context = array()) + { + $context = $this->resolveContext($context); + + $associative = $context['json_decode_associative']; + $recursionDepth = $context['json_decode_recursion_depth']; + $options = $context['json_decode_options']; + + if (PHP_VERSION_ID >= 50400) { + $decodedData = json_decode($data, $associative, $recursionDepth, $options); + } else { + $decodedData = json_decode($data, $associative, $recursionDepth); + } + + if (JSON_ERROR_NONE !== $this->lastError = json_last_error()) { + throw new UnexpectedValueException(JsonEncoder::getLastErrorMessage()); + } + + return $decodedData; + } + + /** + * {@inheritdoc} + */ + public function supportsDecoding($format) + { + return JsonEncoder::FORMAT === $format; + } + + /** + * Merges the default options of the Json Decoder with the passed context. + * + * @param array $context + * + * @return array + */ + private function resolveContext(array $context) + { + $defaultOptions = array( + 'json_decode_associative' => $this->associative, + 'json_decode_recursion_depth' => $this->recursionDepth, + 'json_decode_options' => 0, + ); + + return array_merge($defaultOptions, $context); + } +} diff --git a/vendor/symfony/serializer/Encoder/JsonEncode.php b/vendor/symfony/serializer/Encoder/JsonEncode.php new file mode 100644 index 0000000..3a6b2fd --- /dev/null +++ b/vendor/symfony/serializer/Encoder/JsonEncode.php @@ -0,0 +1,84 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Serializer\Encoder; + +use Symfony\Component\Serializer\Exception\UnexpectedValueException; + +/** + * Encodes JSON data. + * + * @author Sander Coolen + */ +class JsonEncode implements EncoderInterface +{ + private $options; + private $lastError = JSON_ERROR_NONE; + + public function __construct($bitmask = 0) + { + $this->options = $bitmask; + } + + /** + * Returns the last encoding error (if any). + * + * @return int + * + * @deprecated since version 2.5, to be removed in 3.0. + * The {@self encode()} throws an exception if error found. + * @see http://php.net/manual/en/function.json-last-error.php json_last_error + */ + public function getLastError() + { + @trigger_error('The '.__METHOD__.' method is deprecated since version 2.5 and will be removed in 3.0. Catch the exception raised by the encode() method instead to get the last JSON encoding error.', E_USER_DEPRECATED); + + return $this->lastError; + } + + /** + * Encodes PHP data to a JSON string. + * + * {@inheritdoc} + */ + public function encode($data, $format, array $context = array()) + { + $context = $this->resolveContext($context); + + $encodedJson = json_encode($data, $context['json_encode_options']); + + if (JSON_ERROR_NONE !== $this->lastError = json_last_error()) { + throw new UnexpectedValueException(JsonEncoder::getLastErrorMessage()); + } + + return $encodedJson; + } + + /** + * {@inheritdoc} + */ + public function supportsEncoding($format) + { + return JsonEncoder::FORMAT === $format; + } + + /** + * Merge default json encode options with context. + * + * @param array $context + * + * @return array + */ + private function resolveContext(array $context = array()) + { + return array_merge(array('json_encode_options' => $this->options), $context); + } +} diff --git a/vendor/symfony/serializer/Encoder/JsonEncoder.php b/vendor/symfony/serializer/Encoder/JsonEncoder.php new file mode 100644 index 0000000..284f579 --- /dev/null +++ b/vendor/symfony/serializer/Encoder/JsonEncoder.php @@ -0,0 +1,125 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Serializer\Encoder; + +/** + * Encodes JSON data. + * + * @author Jordi Boggiano + */ +class JsonEncoder implements EncoderInterface, DecoderInterface +{ + const FORMAT = 'json'; + + /** + * @var JsonEncode + */ + protected $encodingImpl; + + /** + * @var JsonDecode + */ + protected $decodingImpl; + + public function __construct(JsonEncode $encodingImpl = null, JsonDecode $decodingImpl = null) + { + $this->encodingImpl = $encodingImpl ?: new JsonEncode(); + $this->decodingImpl = $decodingImpl ?: new JsonDecode(true); + } + + /** + * Returns the last encoding error (if any). + * + * @return int + * + * @deprecated since version 2.5, to be removed in 3.0. JsonEncode throws exception if an error is found. + */ + public function getLastEncodingError() + { + @trigger_error('The '.__METHOD__.' method is deprecated since version 2.5 and will be removed in 3.0. Catch the exception raised by the Symfony\Component\Serializer\Encoder\JsonEncode::encode() method instead to get the last JSON encoding error.', E_USER_DEPRECATED); + + return $this->encodingImpl->getLastError(); + } + + /** + * Returns the last decoding error (if any). + * + * @return int + * + * @deprecated since version 2.5, to be removed in 3.0. JsonDecode throws exception if an error is found. + */ + public function getLastDecodingError() + { + @trigger_error('The '.__METHOD__.' method is deprecated since version 2.5 and will be removed in 3.0. Catch the exception raised by the Symfony\Component\Serializer\Encoder\JsonDecode::decode() method instead to get the last JSON decoding error.', E_USER_DEPRECATED); + + return $this->decodingImpl->getLastError(); + } + + /** + * {@inheritdoc} + */ + public function encode($data, $format, array $context = array()) + { + return $this->encodingImpl->encode($data, self::FORMAT, $context); + } + + /** + * {@inheritdoc} + */ + public function decode($data, $format, array $context = array()) + { + return $this->decodingImpl->decode($data, self::FORMAT, $context); + } + + /** + * {@inheritdoc} + */ + public function supportsEncoding($format) + { + return self::FORMAT === $format; + } + + /** + * {@inheritdoc} + */ + public function supportsDecoding($format) + { + return self::FORMAT === $format; + } + + /** + * Resolves json_last_error message. + * + * @return string + */ + public static function getLastErrorMessage() + { + if (function_exists('json_last_error_msg')) { + return json_last_error_msg(); + } + + switch (json_last_error()) { + case JSON_ERROR_DEPTH: + return 'Maximum stack depth exceeded'; + case JSON_ERROR_STATE_MISMATCH: + return 'Underflow or the modes mismatch'; + case JSON_ERROR_CTRL_CHAR: + return 'Unexpected control character found'; + case JSON_ERROR_SYNTAX: + return 'Syntax error, malformed JSON'; + case JSON_ERROR_UTF8: + return 'Malformed UTF-8 characters, possibly incorrectly encoded'; + default: + return 'Unknown error'; + } + } +} diff --git a/vendor/symfony/serializer/Encoder/NormalizationAwareInterface.php b/vendor/symfony/serializer/Encoder/NormalizationAwareInterface.php new file mode 100644 index 0000000..c066bd7 --- /dev/null +++ b/vendor/symfony/serializer/Encoder/NormalizationAwareInterface.php @@ -0,0 +1,24 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Serializer\Encoder; + +/** + * Defines the interface of encoders that will normalize data themselves. + * + * Implementing this interface essentially just tells the Serializer that the + * data should not be pre-normalized before being passed to this Encoder. + * + * @author Jordi Boggiano + */ +interface NormalizationAwareInterface +{ +} diff --git a/vendor/symfony/serializer/Encoder/SerializerAwareEncoder.php b/vendor/symfony/serializer/Encoder/SerializerAwareEncoder.php new file mode 100644 index 0000000..a3d8ff3 --- /dev/null +++ b/vendor/symfony/serializer/Encoder/SerializerAwareEncoder.php @@ -0,0 +1,33 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Serializer\Encoder; + +use Symfony\Component\Serializer\SerializerInterface; +use Symfony\Component\Serializer\SerializerAwareInterface; + +/** + * SerializerAware Encoder implementation. + * + * @author Jordi Boggiano + */ +abstract class SerializerAwareEncoder implements SerializerAwareInterface +{ + protected $serializer; + + /** + * {@inheritdoc} + */ + public function setSerializer(SerializerInterface $serializer) + { + $this->serializer = $serializer; + } +} diff --git a/vendor/symfony/serializer/Encoder/XmlEncoder.php b/vendor/symfony/serializer/Encoder/XmlEncoder.php new file mode 100644 index 0000000..ce0c475 --- /dev/null +++ b/vendor/symfony/serializer/Encoder/XmlEncoder.php @@ -0,0 +1,536 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Serializer\Encoder; + +use Symfony\Component\Serializer\Exception\UnexpectedValueException; + +/** + * Encodes XML data. + * + * @author Jordi Boggiano + * @author John Wards + * @author Fabian Vogler + * @author Kévin Dunglas + */ +class XmlEncoder extends SerializerAwareEncoder implements EncoderInterface, DecoderInterface, NormalizationAwareInterface +{ + /** + * @var \DOMDocument + */ + private $dom; + private $format; + private $context; + private $rootNodeName = 'response'; + + /** + * Construct new XmlEncoder and allow to change the root node element name. + * + * @param string $rootNodeName + */ + public function __construct($rootNodeName = 'response') + { + $this->rootNodeName = $rootNodeName; + } + + /** + * {@inheritdoc} + */ + public function encode($data, $format, array $context = array()) + { + if ($data instanceof \DOMDocument) { + return $data->saveXML(); + } + + $xmlRootNodeName = $this->resolveXmlRootName($context); + + $this->dom = $this->createDomDocument($context); + $this->format = $format; + $this->context = $context; + + if (null !== $data && !is_scalar($data)) { + $root = $this->dom->createElement($xmlRootNodeName); + $this->dom->appendChild($root); + $this->buildXml($root, $data, $xmlRootNodeName); + } else { + $this->appendNode($this->dom, $data, $xmlRootNodeName); + } + + return $this->dom->saveXML(); + } + + /** + * {@inheritdoc} + */ + public function decode($data, $format, array $context = array()) + { + if ('' === trim($data)) { + throw new UnexpectedValueException('Invalid XML data, it can not be empty.'); + } + + $internalErrors = libxml_use_internal_errors(true); + $disableEntities = libxml_disable_entity_loader(true); + libxml_clear_errors(); + + $dom = new \DOMDocument(); + $dom->loadXML($data, LIBXML_NONET | LIBXML_NOBLANKS); + + libxml_use_internal_errors($internalErrors); + libxml_disable_entity_loader($disableEntities); + + if ($error = libxml_get_last_error()) { + libxml_clear_errors(); + + throw new UnexpectedValueException($error->message); + } + + foreach ($dom->childNodes as $child) { + if ($child->nodeType === XML_DOCUMENT_TYPE_NODE) { + throw new UnexpectedValueException('Document types are not allowed.'); + } + } + + $rootNode = $dom->firstChild; + + // todo: throw an exception if the root node name is not correctly configured (bc) + + if ($rootNode->hasChildNodes()) { + $xpath = new \DOMXPath($dom); + $data = array(); + foreach ($xpath->query('namespace::*', $dom->documentElement) as $nsNode) { + $data['@'.$nsNode->nodeName] = $nsNode->nodeValue; + } + + unset($data['@xmlns:xml']); + + if (empty($data)) { + return $this->parseXml($rootNode); + } + + return array_merge($data, (array) $this->parseXml($rootNode)); + } + + if (!$rootNode->hasAttributes()) { + return $rootNode->nodeValue; + } + + $data = array(); + + foreach ($rootNode->attributes as $attrKey => $attr) { + $data['@'.$attrKey] = $attr->nodeValue; + } + + $data['#'] = $rootNode->nodeValue; + + return $data; + } + + /** + * {@inheritdoc} + */ + public function supportsEncoding($format) + { + return 'xml' === $format; + } + + /** + * {@inheritdoc} + */ + public function supportsDecoding($format) + { + return 'xml' === $format; + } + + /** + * Sets the root node name. + * + * @param string $name root node name + */ + public function setRootNodeName($name) + { + $this->rootNodeName = $name; + } + + /** + * Returns the root node name. + * + * @return string + */ + public function getRootNodeName() + { + return $this->rootNodeName; + } + + /** + * @param \DOMNode $node + * @param string $val + * + * @return bool + */ + final protected function appendXMLString(\DOMNode $node, $val) + { + if (strlen($val) > 0) { + $frag = $this->dom->createDocumentFragment(); + $frag->appendXML($val); + $node->appendChild($frag); + + return true; + } + + return false; + } + + /** + * @param \DOMNode $node + * @param string $val + * + * @return bool + */ + final protected function appendText(\DOMNode $node, $val) + { + $nodeText = $this->dom->createTextNode($val); + $node->appendChild($nodeText); + + return true; + } + + /** + * @param \DOMNode $node + * @param string $val + * + * @return bool + */ + final protected function appendCData(\DOMNode $node, $val) + { + $nodeText = $this->dom->createCDATASection($val); + $node->appendChild($nodeText); + + return true; + } + + /** + * @param \DOMNode $node + * @param \DOMDocumentFragment $fragment + * + * @return bool + */ + final protected function appendDocumentFragment(\DOMNode $node, $fragment) + { + if ($fragment instanceof \DOMDocumentFragment) { + $node->appendChild($fragment); + + return true; + } + + return false; + } + + /** + * Checks the name is a valid xml element name. + * + * @param string $name + * + * @return bool + */ + final protected function isElementNameValid($name) + { + return $name && + false === strpos($name, ' ') && + preg_match('#^[\pL_][\pL0-9._:-]*$#ui', $name); + } + + /** + * Parse the input DOMNode into an array or a string. + * + * @param \DOMNode $node xml to parse + * + * @return array|string + */ + private function parseXml(\DOMNode $node) + { + $data = $this->parseXmlAttributes($node); + + $value = $this->parseXmlValue($node); + + if (!count($data)) { + return $value; + } + + if (!is_array($value)) { + $data['#'] = $value; + + return $data; + } + + if (1 === count($value) && key($value)) { + $data[key($value)] = current($value); + + return $data; + } + + foreach ($value as $key => $val) { + $data[$key] = $val; + } + + return $data; + } + + /** + * Parse the input DOMNode attributes into an array. + * + * @param \DOMNode $node xml to parse + * + * @return array + */ + private function parseXmlAttributes(\DOMNode $node) + { + if (!$node->hasAttributes()) { + return array(); + } + + $data = array(); + + foreach ($node->attributes as $attr) { + if (ctype_digit($attr->nodeValue)) { + $data['@'.$attr->nodeName] = (int) $attr->nodeValue; + } else { + $data['@'.$attr->nodeName] = $attr->nodeValue; + } + } + + return $data; + } + + /** + * Parse the input DOMNode value (content and children) into an array or a string. + * + * @param \DOMNode $node xml to parse + * + * @return array|string + */ + private function parseXmlValue(\DOMNode $node) + { + if (!$node->hasChildNodes()) { + return $node->nodeValue; + } + + if (1 === $node->childNodes->length && in_array($node->firstChild->nodeType, array(XML_TEXT_NODE, XML_CDATA_SECTION_NODE))) { + return $node->firstChild->nodeValue; + } + + $value = array(); + + foreach ($node->childNodes as $subnode) { + $val = $this->parseXml($subnode); + + if ('item' === $subnode->nodeName && isset($val['@key'])) { + if (isset($val['#'])) { + $value[$val['@key']] = $val['#']; + } else { + $value[$val['@key']] = $val; + } + } else { + $value[$subnode->nodeName][] = $val; + } + } + + foreach ($value as $key => $val) { + if (is_array($val) && 1 === count($val)) { + $value[$key] = current($val); + } + } + + return $value; + } + + /** + * Parse the data and convert it to DOMElements. + * + * @param \DOMNode $parentNode + * @param array|object $data + * @param string|null $xmlRootNodeName + * + * @return bool + * + * @throws UnexpectedValueException + */ + private function buildXml(\DOMNode $parentNode, $data, $xmlRootNodeName = null) + { + $append = true; + + if (is_array($data) || $data instanceof \Traversable) { + foreach ($data as $key => $data) { + //Ah this is the magic @ attribute types. + if (0 === strpos($key, '@') && is_scalar($data) && $this->isElementNameValid($attributeName = substr($key, 1))) { + $parentNode->setAttribute($attributeName, $data); + } elseif ($key === '#') { + $append = $this->selectNodeType($parentNode, $data); + } elseif (is_array($data) && false === is_numeric($key)) { + // Is this array fully numeric keys? + if (ctype_digit(implode('', array_keys($data)))) { + /* + * Create nodes to append to $parentNode based on the $key of this array + * Produces 01 + * From array("item" => array(0,1));. + */ + foreach ($data as $subData) { + $append = $this->appendNode($parentNode, $subData, $key); + } + } else { + $append = $this->appendNode($parentNode, $data, $key); + } + } elseif (is_numeric($key) || !$this->isElementNameValid($key)) { + $append = $this->appendNode($parentNode, $data, 'item', $key); + } else { + $append = $this->appendNode($parentNode, $data, $key); + } + } + + return $append; + } + + if (is_object($data)) { + $data = $this->serializer->normalize($data, $this->format, $this->context); + if (null !== $data && !is_scalar($data)) { + return $this->buildXml($parentNode, $data, $xmlRootNodeName); + } + + // top level data object was normalized into a scalar + if (!$parentNode->parentNode->parentNode) { + $root = $parentNode->parentNode; + $root->removeChild($parentNode); + + return $this->appendNode($root, $data, $xmlRootNodeName); + } + + return $this->appendNode($parentNode, $data, 'data'); + } + + throw new UnexpectedValueException(sprintf('An unexpected value could not be serialized: %s', var_export($data, true))); + } + + /** + * Selects the type of node to create and appends it to the parent. + * + * @param \DOMNode $parentNode + * @param array|object $data + * @param string $nodeName + * @param string $key + * + * @return bool + */ + private function appendNode(\DOMNode $parentNode, $data, $nodeName, $key = null) + { + $node = $this->dom->createElement($nodeName); + if (null !== $key) { + $node->setAttribute('key', $key); + } + $appendNode = $this->selectNodeType($node, $data); + // we may have decided not to append this node, either in error or if its $nodeName is not valid + if ($appendNode) { + $parentNode->appendChild($node); + } + + return $appendNode; + } + + /** + * Checks if a value contains any characters which would require CDATA wrapping. + * + * @param string $val + * + * @return bool + */ + private function needsCdataWrapping($val) + { + return preg_match('/[<>&]/', $val); + } + + /** + * Tests the value being passed and decide what sort of element to create. + * + * @param \DOMNode $node + * @param mixed $val + * + * @return bool + */ + private function selectNodeType(\DOMNode $node, $val) + { + if (is_array($val)) { + return $this->buildXml($node, $val); + } elseif ($val instanceof \SimpleXMLElement) { + $child = $this->dom->importNode(dom_import_simplexml($val), true); + $node->appendChild($child); + } elseif ($val instanceof \Traversable) { + $this->buildXml($node, $val); + } elseif (is_object($val)) { + return $this->buildXml($node, $this->serializer->normalize($val, $this->format, $this->context)); + } elseif (is_numeric($val)) { + return $this->appendText($node, (string) $val); + } elseif (is_string($val) && $this->needsCdataWrapping($val)) { + return $this->appendCData($node, $val); + } elseif (is_string($val)) { + return $this->appendText($node, $val); + } elseif (is_bool($val)) { + return $this->appendText($node, (int) $val); + } elseif ($val instanceof \DOMNode) { + $child = $this->dom->importNode($val, true); + $node->appendChild($child); + } + + return true; + } + + /** + * Get real XML root node name, taking serializer options into account. + * + * @param array $context + * + * @return string + */ + private function resolveXmlRootName(array $context = array()) + { + return isset($context['xml_root_node_name']) + ? $context['xml_root_node_name'] + : $this->rootNodeName; + } + + /** + * Create a DOM document, taking serializer options into account. + * + * @param array $context options that the encoder has access to. + * + * @return \DOMDocument + */ + private function createDomDocument(array $context) + { + $document = new \DOMDocument(); + + // Set an attribute on the DOM document specifying, as part of the XML declaration, + $xmlOptions = array( + // nicely formats output with indentation and extra space + 'xml_format_output' => 'formatOutput', + // the version number of the document + 'xml_version' => 'xmlVersion', + // the encoding of the document + 'xml_encoding' => 'encoding', + // whether the document is standalone + 'xml_standalone' => 'xmlStandalone', + ); + foreach ($xmlOptions as $xmlOption => $documentProperty) { + if (isset($context[$xmlOption])) { + $document->$documentProperty = $context[$xmlOption]; + } + } + + return $document; + } +} diff --git a/vendor/symfony/serializer/Exception/CircularReferenceException.php b/vendor/symfony/serializer/Exception/CircularReferenceException.php new file mode 100644 index 0000000..dc84183 --- /dev/null +++ b/vendor/symfony/serializer/Exception/CircularReferenceException.php @@ -0,0 +1,21 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Serializer\Exception; + +/** + * CircularReferenceException. + * + * @author Kévin Dunglas + */ +class CircularReferenceException extends RuntimeException +{ +} diff --git a/vendor/symfony/serializer/Exception/Exception.php b/vendor/symfony/serializer/Exception/Exception.php new file mode 100644 index 0000000..fc0606e --- /dev/null +++ b/vendor/symfony/serializer/Exception/Exception.php @@ -0,0 +1,21 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Serializer\Exception; + +/** + * Base exception. + * + * @deprecated since version 2.7, to be removed in 3.0. Use ExceptionInterface instead. + */ +interface Exception +{ +} diff --git a/vendor/symfony/serializer/Exception/ExceptionInterface.php b/vendor/symfony/serializer/Exception/ExceptionInterface.php new file mode 100644 index 0000000..ff67edb --- /dev/null +++ b/vendor/symfony/serializer/Exception/ExceptionInterface.php @@ -0,0 +1,21 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Serializer\Exception; + +/** + * Base exception interface. + * + * @author Johannes M. Schmitt + */ +interface ExceptionInterface extends Exception +{ +} diff --git a/vendor/symfony/serializer/Exception/InvalidArgumentException.php b/vendor/symfony/serializer/Exception/InvalidArgumentException.php new file mode 100644 index 0000000..f4e645c --- /dev/null +++ b/vendor/symfony/serializer/Exception/InvalidArgumentException.php @@ -0,0 +1,21 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Serializer\Exception; + +/** + * InvalidArgumentException. + * + * @author Johannes M. Schmitt + */ +class InvalidArgumentException extends \InvalidArgumentException implements ExceptionInterface +{ +} diff --git a/vendor/symfony/serializer/Exception/LogicException.php b/vendor/symfony/serializer/Exception/LogicException.php new file mode 100644 index 0000000..08c53e0 --- /dev/null +++ b/vendor/symfony/serializer/Exception/LogicException.php @@ -0,0 +1,21 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Serializer\Exception; + +/** + * LogicException. + * + * @author Lukas Kahwe Smith + */ +class LogicException extends \LogicException implements ExceptionInterface +{ +} diff --git a/vendor/symfony/serializer/Exception/MappingException.php b/vendor/symfony/serializer/Exception/MappingException.php new file mode 100644 index 0000000..4df4eec --- /dev/null +++ b/vendor/symfony/serializer/Exception/MappingException.php @@ -0,0 +1,21 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Serializer\Exception; + +/** + * MappingException. + * + * @author Kévin Dunglas + */ +class MappingException extends RuntimeException +{ +} diff --git a/vendor/symfony/serializer/Exception/RuntimeException.php b/vendor/symfony/serializer/Exception/RuntimeException.php new file mode 100644 index 0000000..a287d97 --- /dev/null +++ b/vendor/symfony/serializer/Exception/RuntimeException.php @@ -0,0 +1,21 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Serializer\Exception; + +/** + * RuntimeException. + * + * @author Johannes M. Schmitt + */ +class RuntimeException extends \RuntimeException implements ExceptionInterface +{ +} diff --git a/vendor/symfony/serializer/Exception/UnexpectedValueException.php b/vendor/symfony/serializer/Exception/UnexpectedValueException.php new file mode 100644 index 0000000..2a63c5b --- /dev/null +++ b/vendor/symfony/serializer/Exception/UnexpectedValueException.php @@ -0,0 +1,21 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Serializer\Exception; + +/** + * UnexpectedValueException. + * + * @author Lukas Kahwe Smith + */ +class UnexpectedValueException extends \UnexpectedValueException implements ExceptionInterface +{ +} diff --git a/vendor/symfony/serializer/Exception/UnsupportedException.php b/vendor/symfony/serializer/Exception/UnsupportedException.php new file mode 100644 index 0000000..7dc44ee --- /dev/null +++ b/vendor/symfony/serializer/Exception/UnsupportedException.php @@ -0,0 +1,21 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Serializer\Exception; + +/** + * UnsupportedException. + * + * @author Johannes M. Schmitt + */ +class UnsupportedException extends InvalidArgumentException +{ +} diff --git a/vendor/symfony/serializer/LICENSE b/vendor/symfony/serializer/LICENSE new file mode 100644 index 0000000..43028bc --- /dev/null +++ b/vendor/symfony/serializer/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2004-2015 Fabien Potencier + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is furnished +to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/vendor/symfony/serializer/Mapping/AttributeMetadata.php b/vendor/symfony/serializer/Mapping/AttributeMetadata.php new file mode 100644 index 0000000..7a1d3db --- /dev/null +++ b/vendor/symfony/serializer/Mapping/AttributeMetadata.php @@ -0,0 +1,94 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Serializer\Mapping; + +/** + * {@inheritdoc} + * + * @author Kévin Dunglas + */ +class AttributeMetadata implements AttributeMetadataInterface +{ + /** + * @var string + * + * @internal This property is public in order to reduce the size of the + * class' serialized representation. Do not access it. Use + * {@link getName()} instead. + */ + public $name; + + /** + * @var array + * + * @internal This property is public in order to reduce the size of the + * class' serialized representation. Do not access it. Use + * {@link getGroups()} instead. + */ + public $groups = array(); + + /** + * Constructs a metadata for the given attribute. + * + * @param string $name + */ + public function __construct($name) + { + $this->name = $name; + } + + /** + * {@inheritdoc} + */ + public function getName() + { + return $this->name; + } + + /** + * {@inheritdoc} + */ + public function addGroup($group) + { + if (!in_array($group, $this->groups)) { + $this->groups[] = $group; + } + } + + /** + * {@inheritdoc} + */ + public function getGroups() + { + return $this->groups; + } + + /** + * {@inheritdoc} + */ + public function merge(AttributeMetadataInterface $attributeMetadata) + { + foreach ($attributeMetadata->getGroups() as $group) { + $this->addGroup($group); + } + } + + /** + * Returns the names of the properties that should be serialized. + * + * @return string[] + */ + public function __sleep() + { + return array('name', 'groups'); + } +} diff --git a/vendor/symfony/serializer/Mapping/AttributeMetadataInterface.php b/vendor/symfony/serializer/Mapping/AttributeMetadataInterface.php new file mode 100644 index 0000000..0701a58 --- /dev/null +++ b/vendor/symfony/serializer/Mapping/AttributeMetadataInterface.php @@ -0,0 +1,50 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Serializer\Mapping; + +/** + * Stores metadata needed for serializing and deserializing attributes. + * + * Primarily, the metadata stores serialization groups. + * + * @author Kévin Dunglas + */ +interface AttributeMetadataInterface +{ + /** + * Gets the attribute name. + * + * @return string + */ + public function getName(); + + /** + * Adds this attribute to the given group. + * + * @param string $group + */ + public function addGroup($group); + + /** + * Gets groups of this attribute. + * + * @return string[] + */ + public function getGroups(); + + /** + * Merges an {@see AttributeMetadataInterface} with in the current one. + * + * @param AttributeMetadataInterface $attributeMetadata + */ + public function merge(AttributeMetadataInterface $attributeMetadata); +} diff --git a/vendor/symfony/serializer/Mapping/ClassMetadata.php b/vendor/symfony/serializer/Mapping/ClassMetadata.php new file mode 100644 index 0000000..55ddf52 --- /dev/null +++ b/vendor/symfony/serializer/Mapping/ClassMetadata.php @@ -0,0 +1,116 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Serializer\Mapping; + +/** + * {@inheritdoc} + * + * @author Kévin Dunglas + */ +class ClassMetadata implements ClassMetadataInterface +{ + /** + * @var string + * + * @internal This property is public in order to reduce the size of the + * class' serialized representation. Do not access it. Use + * {@link getName()} instead. + */ + public $name; + + /** + * @var AttributeMetadataInterface[] + * + * @internal This property is public in order to reduce the size of the + * class' serialized representation. Do not access it. Use + * {@link getAttributesMetadata()} instead. + */ + public $attributesMetadata = array(); + + /** + * @var \ReflectionClass + */ + private $reflClass; + + /** + * Constructs a metadata for the given class. + * + * @param string $class + */ + public function __construct($class) + { + $this->name = $class; + } + + /** + * {@inheritdoc} + */ + public function getName() + { + return $this->name; + } + + /** + * {@inheritdoc} + */ + public function addAttributeMetadata(AttributeMetadataInterface $attributeMetadata) + { + $this->attributesMetadata[$attributeMetadata->getName()] = $attributeMetadata; + } + + /** + * {@inheritdoc} + */ + public function getAttributesMetadata() + { + return $this->attributesMetadata; + } + + /** + * {@inheritdoc} + */ + public function merge(ClassMetadataInterface $classMetadata) + { + foreach ($classMetadata->getAttributesMetadata() as $attributeMetadata) { + if (isset($this->attributesMetadata[$attributeMetadata->getName()])) { + $this->attributesMetadata[$attributeMetadata->getName()]->merge($attributeMetadata); + } else { + $this->addAttributeMetadata($attributeMetadata); + } + } + } + + /** + * {@inheritdoc} + */ + public function getReflectionClass() + { + if (!$this->reflClass) { + $this->reflClass = new \ReflectionClass($this->getName()); + } + + return $this->reflClass; + } + + /** + * Returns the names of the properties that should be serialized. + * + * @return string[] + */ + public function __sleep() + { + return array( + 'name', + 'attributesMetadata', + ); + } +} diff --git a/vendor/symfony/serializer/Mapping/ClassMetadataInterface.php b/vendor/symfony/serializer/Mapping/ClassMetadataInterface.php new file mode 100644 index 0000000..c967666 --- /dev/null +++ b/vendor/symfony/serializer/Mapping/ClassMetadataInterface.php @@ -0,0 +1,57 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Serializer\Mapping; + +/** + * Stores metadata needed for serializing and deserializing objects of specific class. + * + * Primarily, the metadata stores the list of attributes to serialize or deserialize. + * + * @author Kévin Dunglas + */ +interface ClassMetadataInterface +{ + /** + * Returns the name of the backing PHP class. + * + * @return string The name of the backing class. + */ + public function getName(); + + /** + * Adds an {@link AttributeMetadataInterface}. + * + * @param AttributeMetadataInterface $attributeMetadata + */ + public function addAttributeMetadata(AttributeMetadataInterface $attributeMetadata); + + /** + * Gets the list of {@link AttributeMetadataInterface}. + * + * @return AttributeMetadataInterface[] + */ + public function getAttributesMetadata(); + + /** + * Merges a {@link ClassMetadataInterface} in the current one. + * + * @param ClassMetadataInterface $classMetadata + */ + public function merge(ClassMetadataInterface $classMetadata); + + /** + * Returns a {@link \ReflectionClass} instance for this class. + * + * @return \ReflectionClass + */ + public function getReflectionClass(); +} diff --git a/vendor/symfony/serializer/Mapping/Factory/ClassMetadataFactory.php b/vendor/symfony/serializer/Mapping/Factory/ClassMetadataFactory.php new file mode 100644 index 0000000..3a354e3 --- /dev/null +++ b/vendor/symfony/serializer/Mapping/Factory/ClassMetadataFactory.php @@ -0,0 +1,118 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Serializer\Mapping\Factory; + +use Doctrine\Common\Cache\Cache; +use Symfony\Component\Serializer\Exception\InvalidArgumentException; +use Symfony\Component\Serializer\Mapping\ClassMetadata; +use Symfony\Component\Serializer\Mapping\Loader\LoaderInterface; + +/** + * Returns a {@link ClassMetadata}. + * + * @author Kévin Dunglas + */ +class ClassMetadataFactory implements ClassMetadataFactoryInterface +{ + /** + * @var LoaderInterface + */ + private $loader; + /** + * @var Cache + */ + private $cache; + /** + * @var array + */ + private $loadedClasses; + + /** + * @param LoaderInterface $loader + * @param Cache|null $cache + */ + public function __construct(LoaderInterface $loader, Cache $cache = null) + { + $this->loader = $loader; + $this->cache = $cache; + } + + /** + * {@inheritdoc} + */ + public function getMetadataFor($value) + { + $class = $this->getClass($value); + if (!$class) { + throw new InvalidArgumentException(sprintf('Cannot create metadata for non-objects. Got: "%s"', gettype($value))); + } + + if (isset($this->loadedClasses[$class])) { + return $this->loadedClasses[$class]; + } + + if ($this->cache && ($this->loadedClasses[$class] = $this->cache->fetch($class))) { + return $this->loadedClasses[$class]; + } + + if (!class_exists($class) && !interface_exists($class)) { + throw new InvalidArgumentException(sprintf('The class or interface "%s" does not exist.', $class)); + } + + $classMetadata = new ClassMetadata($class); + $this->loader->loadClassMetadata($classMetadata); + + $reflectionClass = $classMetadata->getReflectionClass(); + + // Include metadata from the parent class + if ($parent = $reflectionClass->getParentClass()) { + $classMetadata->merge($this->getMetadataFor($parent->name)); + } + + // Include metadata from all implemented interfaces + foreach ($reflectionClass->getInterfaces() as $interface) { + $classMetadata->merge($this->getMetadataFor($interface->name)); + } + + if ($this->cache) { + $this->cache->save($class, $classMetadata); + } + + return $this->loadedClasses[$class] = $classMetadata; + } + + /** + * {@inheritdoc} + */ + public function hasMetadataFor($value) + { + $class = $this->getClass($value); + + return class_exists($class) || interface_exists($class); + } + + /** + * Gets a class name for a given class or instance. + * + * @param mixed $value + * + * @return string|bool + */ + private function getClass($value) + { + if (!is_object($value) && !is_string($value)) { + return false; + } + + return ltrim(is_object($value) ? get_class($value) : $value, '\\'); + } +} diff --git a/vendor/symfony/serializer/Mapping/Factory/ClassMetadataFactoryInterface.php b/vendor/symfony/serializer/Mapping/Factory/ClassMetadataFactoryInterface.php new file mode 100644 index 0000000..7ef91a8 --- /dev/null +++ b/vendor/symfony/serializer/Mapping/Factory/ClassMetadataFactoryInterface.php @@ -0,0 +1,53 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Serializer\Mapping\Factory; + +use Symfony\Component\Serializer\Exception\InvalidArgumentException; +use Symfony\Component\Serializer\Mapping\ClassMetadataInterface; + +/** + * Returns a {@see ClassMetadataInterface}. + * + * @author Kévin Dunglas + */ +interface ClassMetadataFactoryInterface +{ + /** + * If the method was called with the same class name (or an object of that + * class) before, the same metadata instance is returned. + * + * If the factory was configured with a cache, this method will first look + * for an existing metadata instance in the cache. If an existing instance + * is found, it will be returned without further ado. + * + * Otherwise, a new metadata instance is created. If the factory was + * configured with a loader, the metadata is passed to the + * {@link \Symfony\Component\Serializer\Mapping\Loader\LoaderInterface::loadClassMetadata()} method for further + * configuration. At last, the new object is returned. + * + * @param string|object $value + * + * @return ClassMetadataInterface + * + * @throws InvalidArgumentException + */ + public function getMetadataFor($value); + + /** + * Checks if class has metadata. + * + * @param mixed $value + * + * @return bool + */ + public function hasMetadataFor($value); +} diff --git a/vendor/symfony/serializer/Mapping/Loader/AnnotationLoader.php b/vendor/symfony/serializer/Mapping/Loader/AnnotationLoader.php new file mode 100644 index 0000000..801c317 --- /dev/null +++ b/vendor/symfony/serializer/Mapping/Loader/AnnotationLoader.php @@ -0,0 +1,99 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Serializer\Mapping\Loader; + +use Doctrine\Common\Annotations\Reader; +use Symfony\Component\Serializer\Annotation\Groups; +use Symfony\Component\Serializer\Exception\MappingException; +use Symfony\Component\Serializer\Mapping\AttributeMetadata; +use Symfony\Component\Serializer\Mapping\ClassMetadataInterface; + +/** + * Annotation loader. + * + * @author Kévin Dunglas + */ +class AnnotationLoader implements LoaderInterface +{ + /** + * @var Reader + */ + private $reader; + + /** + * @param Reader $reader + */ + public function __construct(Reader $reader) + { + $this->reader = $reader; + } + + /** + * {@inheritdoc} + */ + public function loadClassMetadata(ClassMetadataInterface $classMetadata) + { + $reflectionClass = $classMetadata->getReflectionClass(); + $className = $reflectionClass->name; + $loaded = false; + + $attributesMetadata = $classMetadata->getAttributesMetadata(); + + foreach ($reflectionClass->getProperties() as $property) { + if (!isset($attributeMetadata[$property->name])) { + $attributesMetadata[$property->name] = new AttributeMetadata($property->name); + $classMetadata->addAttributeMetadata($attributesMetadata[$property->name]); + } + + if ($property->getDeclaringClass()->name === $className) { + foreach ($this->reader->getPropertyAnnotations($property) as $groups) { + if ($groups instanceof Groups) { + foreach ($groups->getGroups() as $group) { + $attributesMetadata[$property->name]->addGroup($group); + } + } + + $loaded = true; + } + } + } + + foreach ($reflectionClass->getMethods() as $method) { + if ($method->getDeclaringClass()->name === $className) { + foreach ($this->reader->getMethodAnnotations($method) as $groups) { + if ($groups instanceof Groups) { + if (preg_match('/^(get|is|has|set)(.+)$/i', $method->name, $matches)) { + $attributeName = lcfirst($matches[2]); + + if (isset($attributesMetadata[$attributeName])) { + $attributeMetadata = $attributesMetadata[$attributeName]; + } else { + $attributesMetadata[$attributeName] = $attributeMetadata = new AttributeMetadata($attributeName); + $classMetadata->addAttributeMetadata($attributeMetadata); + } + + foreach ($groups->getGroups() as $group) { + $attributeMetadata->addGroup($group); + } + } else { + throw new MappingException(sprintf('Groups on "%s::%s" cannot be added. Groups can only be added on methods beginning with "get", "is", "has" or "set".', $className, $method->name)); + } + } + + $loaded = true; + } + } + } + + return $loaded; + } +} diff --git a/vendor/symfony/serializer/Mapping/Loader/FileLoader.php b/vendor/symfony/serializer/Mapping/Loader/FileLoader.php new file mode 100644 index 0000000..38bb593 --- /dev/null +++ b/vendor/symfony/serializer/Mapping/Loader/FileLoader.php @@ -0,0 +1,47 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Serializer\Mapping\Loader; + +use Symfony\Component\Serializer\Exception\MappingException; + +/** + * Base class for all file based loaders. + * + * @author Kévin Dunglas + */ +abstract class FileLoader implements LoaderInterface +{ + /** + * @var string + */ + protected $file; + + /** + * Constructor. + * + * @param string $file The mapping file to load + * + * @throws MappingException if the mapping file does not exist or is not readable + */ + public function __construct($file) + { + if (!is_file($file)) { + throw new MappingException(sprintf('The mapping file %s does not exist', $file)); + } + + if (!is_readable($file)) { + throw new MappingException(sprintf('The mapping file %s is not readable', $file)); + } + + $this->file = $file; + } +} diff --git a/vendor/symfony/serializer/Mapping/Loader/LoaderChain.php b/vendor/symfony/serializer/Mapping/Loader/LoaderChain.php new file mode 100644 index 0000000..8bf1c17 --- /dev/null +++ b/vendor/symfony/serializer/Mapping/Loader/LoaderChain.php @@ -0,0 +1,66 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Serializer\Mapping\Loader; + +use Symfony\Component\Serializer\Exception\MappingException; +use Symfony\Component\Serializer\Mapping\ClassMetadataInterface; + +/** + * Calls multiple {@link LoaderInterface} instances in a chain. + * + * This class accepts multiple instances of LoaderInterface to be passed to the + * constructor. When {@link loadClassMetadata()} is called, the same method is called + * in all of these loaders, regardless of whether any of them was + * successful or not. + * + * @author Bernhard Schussek + * @author Kévin Dunglas + */ +class LoaderChain implements LoaderInterface +{ + /** + * @var LoaderInterface[] + */ + private $loaders; + + /** + * Accepts a list of LoaderInterface instances. + * + * @param LoaderInterface[] $loaders An array of LoaderInterface instances + * + * @throws MappingException If any of the loaders does not implement LoaderInterface + */ + public function __construct(array $loaders) + { + foreach ($loaders as $loader) { + if (!$loader instanceof LoaderInterface) { + throw new MappingException(sprintf('Class %s is expected to implement LoaderInterface', get_class($loader))); + } + } + + $this->loaders = $loaders; + } + + /** + * {@inheritdoc} + */ + public function loadClassMetadata(ClassMetadataInterface $metadata) + { + $success = false; + + foreach ($this->loaders as $loader) { + $success = $loader->loadClassMetadata($metadata) || $success; + } + + return $success; + } +} diff --git a/vendor/symfony/serializer/Mapping/Loader/LoaderInterface.php b/vendor/symfony/serializer/Mapping/Loader/LoaderInterface.php new file mode 100644 index 0000000..ebf84b6 --- /dev/null +++ b/vendor/symfony/serializer/Mapping/Loader/LoaderInterface.php @@ -0,0 +1,31 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Serializer\Mapping\Loader; + +use Symfony\Component\Serializer\Mapping\ClassMetadataInterface; + +/** + * Loads {@link ClassMetadataInterface}. + * + * @author Kévin Dunglas + */ +interface LoaderInterface +{ + /** + * Load class metadata. + * + * @param ClassMetadataInterface $classMetadata A metadata + * + * @return bool + */ + public function loadClassMetadata(ClassMetadataInterface $classMetadata); +} diff --git a/vendor/symfony/serializer/Mapping/Loader/XmlFileLoader.php b/vendor/symfony/serializer/Mapping/Loader/XmlFileLoader.php new file mode 100644 index 0000000..0da2f7d --- /dev/null +++ b/vendor/symfony/serializer/Mapping/Loader/XmlFileLoader.php @@ -0,0 +1,92 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Serializer\Mapping\Loader; + +use Symfony\Component\Config\Util\XmlUtils; +use Symfony\Component\Serializer\Exception\MappingException; +use Symfony\Component\Serializer\Mapping\AttributeMetadata; +use Symfony\Component\Serializer\Mapping\ClassMetadataInterface; + +/** + * Loads XML mapping files. + * + * @author Kévin Dunglas + */ +class XmlFileLoader extends FileLoader +{ + /** + * An array of {@class \SimpleXMLElement} instances. + * + * @var \SimpleXMLElement[]|null + */ + private $classes; + + /** + * {@inheritdoc} + */ + public function loadClassMetadata(ClassMetadataInterface $classMetadata) + { + if (null === $this->classes) { + $this->classes = array(); + $xml = $this->parseFile($this->file); + + foreach ($xml->class as $class) { + $this->classes[(string) $class['name']] = $class; + } + } + + $attributesMetadata = $classMetadata->getAttributesMetadata(); + + if (isset($this->classes[$classMetadata->getName()])) { + $xml = $this->classes[$classMetadata->getName()]; + + foreach ($xml->attribute as $attribute) { + $attributeName = (string) $attribute['name']; + + if (isset($attributesMetadata[$attributeName])) { + $attributeMetadata = $attributesMetadata[$attributeName]; + } else { + $attributeMetadata = new AttributeMetadata($attributeName); + $classMetadata->addAttributeMetadata($attributeMetadata); + } + + foreach ($attribute->group as $group) { + $attributeMetadata->addGroup((string) $group); + } + } + + return true; + } + + return false; + } + + /** + * Parses a XML File. + * + * @param string $file Path of file + * + * @return \SimpleXMLElement + * + * @throws MappingException + */ + private function parseFile($file) + { + try { + $dom = XmlUtils::loadFile($file, __DIR__.'/schema/dic/serializer-mapping/serializer-mapping-1.0.xsd'); + } catch (\Exception $e) { + throw new MappingException($e->getMessage(), $e->getCode(), $e); + } + + return simplexml_import_dom($dom); + } +} diff --git a/vendor/symfony/serializer/Mapping/Loader/YamlFileLoader.php b/vendor/symfony/serializer/Mapping/Loader/YamlFileLoader.php new file mode 100644 index 0000000..1c84698 --- /dev/null +++ b/vendor/symfony/serializer/Mapping/Loader/YamlFileLoader.php @@ -0,0 +1,89 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Serializer\Mapping\Loader; + +use Symfony\Component\Serializer\Exception\MappingException; +use Symfony\Component\Serializer\Mapping\AttributeMetadata; +use Symfony\Component\Serializer\Mapping\ClassMetadataInterface; +use Symfony\Component\Yaml\Parser; + +/** + * YAML File Loader. + * + * @author Kévin Dunglas + */ +class YamlFileLoader extends FileLoader +{ + private $yamlParser; + + /** + * An array of YAML class descriptions. + * + * @var array + */ + private $classes = null; + + /** + * {@inheritdoc} + */ + public function loadClassMetadata(ClassMetadataInterface $classMetadata) + { + if (null === $this->classes) { + if (!stream_is_local($this->file)) { + throw new MappingException(sprintf('This is not a local file "%s".', $this->file)); + } + + if (null === $this->yamlParser) { + $this->yamlParser = new Parser(); + } + + $classes = $this->yamlParser->parse(file_get_contents($this->file)); + + if (empty($classes)) { + return false; + } + + // not an array + if (!is_array($classes)) { + throw new MappingException(sprintf('The file "%s" must contain a YAML array.', $this->file)); + } + + $this->classes = $classes; + } + + if (isset($this->classes[$classMetadata->getName()])) { + $yaml = $this->classes[$classMetadata->getName()]; + + if (isset($yaml['attributes']) && is_array($yaml['attributes'])) { + $attributesMetadata = $classMetadata->getAttributesMetadata(); + foreach ($yaml['attributes'] as $attribute => $data) { + if (isset($attributesMetadata[$attribute])) { + $attributeMetadata = $attributesMetadata[$attribute]; + } else { + $attributeMetadata = new AttributeMetadata($attribute); + $classMetadata->addAttributeMetadata($attributeMetadata); + } + + if (isset($data['groups'])) { + foreach ($data['groups'] as $group) { + $attributeMetadata->addGroup($group); + } + } + } + } + + return true; + } + + return false; + } +} diff --git a/vendor/symfony/serializer/Mapping/Loader/schema/dic/serializer-mapping/serializer-mapping-1.0.xsd b/vendor/symfony/serializer/Mapping/Loader/schema/dic/serializer-mapping/serializer-mapping-1.0.xsd new file mode 100644 index 0000000..cd5a9a9 --- /dev/null +++ b/vendor/symfony/serializer/Mapping/Loader/schema/dic/serializer-mapping/serializer-mapping-1.0.xsd @@ -0,0 +1,56 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vendor/symfony/serializer/NameConverter/CamelCaseToSnakeCaseNameConverter.php b/vendor/symfony/serializer/NameConverter/CamelCaseToSnakeCaseNameConverter.php new file mode 100644 index 0000000..8ef851c --- /dev/null +++ b/vendor/symfony/serializer/NameConverter/CamelCaseToSnakeCaseNameConverter.php @@ -0,0 +1,82 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Serializer\NameConverter; + +/** + * CamelCase to Underscore name converter. + * + * @author Kévin Dunglas + */ +class CamelCaseToSnakeCaseNameConverter implements NameConverterInterface +{ + /** + * @var array|null + */ + private $attributes; + /** + * @var bool + */ + private $lowerCamelCase; + + /** + * @param null|array $attributes The list of attributes to rename or null for all attributes. + * @param bool $lowerCamelCase Use lowerCamelCase style. + */ + public function __construct(array $attributes = null, $lowerCamelCase = true) + { + $this->attributes = $attributes; + $this->lowerCamelCase = $lowerCamelCase; + } + + /** + * {@inheritdoc} + */ + public function normalize($propertyName) + { + if (null === $this->attributes || in_array($propertyName, $this->attributes)) { + $snakeCasedName = ''; + + $len = strlen($propertyName); + for ($i = 0; $i < $len; ++$i) { + if (ctype_upper($propertyName[$i])) { + $snakeCasedName .= '_'.strtolower($propertyName[$i]); + } else { + $snakeCasedName .= strtolower($propertyName[$i]); + } + } + + return $snakeCasedName; + } + + return $propertyName; + } + + /** + * {@inheritdoc} + */ + public function denormalize($propertyName) + { + $camelCasedName = preg_replace_callback('/(^|_|\.)+(.)/', function ($match) { + return ('.' === $match[1] ? '_' : '').strtoupper($match[2]); + }, $propertyName); + + if ($this->lowerCamelCase) { + $camelCasedName = lcfirst($camelCasedName); + } + + if (null === $this->attributes || in_array($camelCasedName, $this->attributes)) { + return $this->lowerCamelCase ? lcfirst($camelCasedName) : $camelCasedName; + } + + return $propertyName; + } +} diff --git a/vendor/symfony/serializer/NameConverter/NameConverterInterface.php b/vendor/symfony/serializer/NameConverter/NameConverterInterface.php new file mode 100644 index 0000000..c9f66b0 --- /dev/null +++ b/vendor/symfony/serializer/NameConverter/NameConverterInterface.php @@ -0,0 +1,38 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Serializer\NameConverter; + +/** + * Defines the interface for property name converters. + * + * @author Kévin Dunglas + */ +interface NameConverterInterface +{ + /** + * Converts a property name to its normalized value. + * + * @param string $propertyName + * + * @return string + */ + public function normalize($propertyName); + + /** + * Converts a property name to its denormalized value. + * + * @param string $propertyName + * + * @return string + */ + public function denormalize($propertyName); +} diff --git a/vendor/symfony/serializer/Normalizer/AbstractNormalizer.php b/vendor/symfony/serializer/Normalizer/AbstractNormalizer.php new file mode 100644 index 0000000..8cc85e5 --- /dev/null +++ b/vendor/symfony/serializer/Normalizer/AbstractNormalizer.php @@ -0,0 +1,345 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Serializer\Normalizer; + +use Symfony\Component\Serializer\Exception\CircularReferenceException; +use Symfony\Component\Serializer\Exception\InvalidArgumentException; +use Symfony\Component\Serializer\Exception\LogicException; +use Symfony\Component\Serializer\Exception\RuntimeException; +use Symfony\Component\Serializer\Mapping\Factory\ClassMetadataFactoryInterface; +use Symfony\Component\Serializer\Mapping\AttributeMetadataInterface; +use Symfony\Component\Serializer\NameConverter\CamelCaseToSnakeCaseNameConverter; +use Symfony\Component\Serializer\NameConverter\NameConverterInterface; + +/** + * Normalizer implementation. + * + * @author Kévin Dunglas + */ +abstract class AbstractNormalizer extends SerializerAwareNormalizer implements NormalizerInterface, DenormalizerInterface +{ + /** + * @var int + */ + protected $circularReferenceLimit = 1; + /** + * @var callable + */ + protected $circularReferenceHandler; + /** + * @var ClassMetadataFactoryInterface|null + */ + protected $classMetadataFactory; + /** + * @var NameConverterInterface|null + */ + protected $nameConverter; + /** + * @var array + */ + protected $callbacks = array(); + /** + * @var array + */ + protected $ignoredAttributes = array(); + /** + * @var array + */ + protected $camelizedAttributes = array(); + + /** + * Sets the {@link ClassMetadataFactoryInterface} to use. + * + * @param ClassMetadataFactoryInterface|null $classMetadataFactory + * @param NameConverterInterface|null $nameConverter + */ + public function __construct(ClassMetadataFactoryInterface $classMetadataFactory = null, NameConverterInterface $nameConverter = null) + { + $this->classMetadataFactory = $classMetadataFactory; + $this->nameConverter = $nameConverter; + } + + /** + * Set circular reference limit. + * + * @param int $circularReferenceLimit limit of iterations for the same object + * + * @return self + */ + public function setCircularReferenceLimit($circularReferenceLimit) + { + $this->circularReferenceLimit = $circularReferenceLimit; + + return $this; + } + + /** + * Set circular reference handler. + * + * @param callable $circularReferenceHandler + * + * @return self + * + * @throws InvalidArgumentException + */ + public function setCircularReferenceHandler($circularReferenceHandler) + { + if (!is_callable($circularReferenceHandler)) { + throw new InvalidArgumentException('The given circular reference handler is not callable.'); + } + + $this->circularReferenceHandler = $circularReferenceHandler; + + return $this; + } + + /** + * Set normalization callbacks. + * + * @param array $callbacks help normalize the result + * + * @return self + * + * @throws InvalidArgumentException if a non-callable callback is set + */ + public function setCallbacks(array $callbacks) + { + foreach ($callbacks as $attribute => $callback) { + if (!is_callable($callback)) { + throw new InvalidArgumentException(sprintf( + 'The given callback for attribute "%s" is not callable.', + $attribute + )); + } + } + $this->callbacks = $callbacks; + + return $this; + } + + /** + * Set ignored attributes for normalization and denormalization. + * + * @param array $ignoredAttributes + * + * @return self + */ + public function setIgnoredAttributes(array $ignoredAttributes) + { + $this->ignoredAttributes = $ignoredAttributes; + + return $this; + } + + /** + * Set attributes to be camelized on denormalize. + * + * @deprecated Deprecated since version 2.7, to be removed in 3.0. Use Symfony\Component\Serializer\NameConverter\CamelCaseToSnakeCaseNameConverter instead. + * + * @param array $camelizedAttributes + * + * @return self + * + * @throws LogicException + */ + public function setCamelizedAttributes(array $camelizedAttributes) + { + @trigger_error(sprintf('%s is deprecated since version 2.7 and will be removed in 3.0. Use Symfony\Component\Serializer\NameConverter\CamelCaseToSnakeCaseNameConverter instead.', __METHOD__), E_USER_DEPRECATED); + + if ($this->nameConverter && !$this->nameConverter instanceof CamelCaseToSnakeCaseNameConverter) { + throw new LogicException(sprintf('%s cannot be called if a custom Name Converter is defined.', __METHOD__)); + } + + $attributes = array(); + foreach ($camelizedAttributes as $camelizedAttribute) { + $attributes[] = lcfirst(preg_replace_callback('/(^|_|\.)+(.)/', function ($match) { + return ('.' === $match[1] ? '_' : '').strtoupper($match[2]); + }, $camelizedAttribute)); + } + + $this->nameConverter = new CamelCaseToSnakeCaseNameConverter($attributes); + + return $this; + } + + /** + * Detects if the configured circular reference limit is reached. + * + * @param object $object + * @param array $context + * + * @return bool + * + * @throws CircularReferenceException + */ + protected function isCircularReference($object, &$context) + { + $objectHash = spl_object_hash($object); + + if (isset($context['circular_reference_limit'][$objectHash])) { + if ($context['circular_reference_limit'][$objectHash] >= $this->circularReferenceLimit) { + unset($context['circular_reference_limit'][$objectHash]); + + return true; + } + + ++$context['circular_reference_limit'][$objectHash]; + } else { + $context['circular_reference_limit'][$objectHash] = 1; + } + + return false; + } + + /** + * Handles a circular reference. + * + * If a circular reference handler is set, it will be called. Otherwise, a + * {@class CircularReferenceException} will be thrown. + * + * @param object $object + * + * @return mixed + * + * @throws CircularReferenceException + */ + protected function handleCircularReference($object) + { + if ($this->circularReferenceHandler) { + return call_user_func($this->circularReferenceHandler, $object); + } + + throw new CircularReferenceException(sprintf('A circular reference has been detected (configured limit: %d).', $this->circularReferenceLimit)); + } + + /** + * Format an attribute name, for example to convert a snake_case name to camelCase. + * + * @deprecated Deprecated since version 2.7, to be removed in 3.0. Use Symfony\Component\Serializer\NameConverter\CamelCaseToSnakeCaseNameConverter instead. + * + * @param string $attributeName + * + * @return string + */ + protected function formatAttribute($attributeName) + { + @trigger_error(sprintf('%s is deprecated since version 2.7 and will be removed in 3.0. Use Symfony\Component\Serializer\NameConverter\CamelCaseToSnakeCaseNameConverter instead.', __METHOD__), E_USER_DEPRECATED); + + return $this->nameConverter ? $this->nameConverter->normalize($attributeName) : $attributeName; + } + + /** + * Gets attributes to normalize using groups. + * + * @param string|object $classOrObject + * @param array $context + * @param bool $attributesAsString If false, return an array of {@link AttributeMetadataInterface} + * + * @return string[]|AttributeMetadataInterface[]|bool + */ + protected function getAllowedAttributes($classOrObject, array $context, $attributesAsString = false) + { + if (!$this->classMetadataFactory || !isset($context['groups']) || !is_array($context['groups'])) { + return false; + } + + $allowedAttributes = array(); + foreach ($this->classMetadataFactory->getMetadataFor($classOrObject)->getAttributesMetadata() as $attributeMetadata) { + if (count(array_intersect($attributeMetadata->getGroups(), $context['groups']))) { + $allowedAttributes[] = $attributesAsString ? $attributeMetadata->getName() : $attributeMetadata; + } + } + + return array_unique($allowedAttributes); + } + + /** + * Normalizes the given data to an array. It's particularly useful during + * the denormalization process. + * + * @param object|array $data + * + * @return array + */ + protected function prepareForDenormalization($data) + { + return (array) $data; + } + + /** + * Instantiates an object using constructor parameters when needed. + * + * This method also allows to denormalize data into an existing object if + * it is present in the context with the object_to_populate key. + * + * @param array $data + * @param string $class + * @param array $context + * @param \ReflectionClass $reflectionClass + * @param array|bool $allowedAttributes + * + * @return object + * + * @throws RuntimeException + */ + protected function instantiateObject(array &$data, $class, array &$context, \ReflectionClass $reflectionClass, $allowedAttributes) + { + if ( + isset($context['object_to_populate']) && + is_object($context['object_to_populate']) && + $class === get_class($context['object_to_populate']) + ) { + return $context['object_to_populate']; + } + + $constructor = $reflectionClass->getConstructor(); + if ($constructor) { + $constructorParameters = $constructor->getParameters(); + + $params = array(); + foreach ($constructorParameters as $constructorParameter) { + $paramName = $constructorParameter->name; + $key = $this->nameConverter ? $this->nameConverter->normalize($paramName) : $paramName; + + $allowed = $allowedAttributes === false || in_array($paramName, $allowedAttributes); + $ignored = in_array($paramName, $this->ignoredAttributes); + if (method_exists($constructorParameter, 'isVariadic') && $constructorParameter->isVariadic()) { + if ($allowed && !$ignored && (isset($data[$key]) || array_key_exists($key, $data))) { + if (!is_array($data[$paramName])) { + throw new RuntimeException(sprintf('Cannot create an instance of %s from serialized data because the variadic parameter %s can only accept an array.', $class, $constructorParameter->name)); + } + + $params = array_merge($params, $data[$paramName]); + } + } elseif ($allowed && !$ignored && (isset($data[$key]) || array_key_exists($key, $data))) { + $params[] = $data[$key]; + // don't run set for a parameter passed to the constructor + unset($data[$key]); + } elseif ($constructorParameter->isDefaultValueAvailable()) { + $params[] = $constructorParameter->getDefaultValue(); + } else { + throw new RuntimeException( + sprintf( + 'Cannot create an instance of %s from serialized data because its constructor requires parameter "%s" to be present.', + $class, + $constructorParameter->name + ) + ); + } + } + + return $reflectionClass->newInstanceArgs($params); + } + + return new $class(); + } +} diff --git a/vendor/symfony/serializer/Normalizer/CustomNormalizer.php b/vendor/symfony/serializer/Normalizer/CustomNormalizer.php new file mode 100644 index 0000000..83c3c14 --- /dev/null +++ b/vendor/symfony/serializer/Normalizer/CustomNormalizer.php @@ -0,0 +1,66 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Serializer\Normalizer; + +/** + * @author Jordi Boggiano + */ +class CustomNormalizer extends SerializerAwareNormalizer implements NormalizerInterface, DenormalizerInterface +{ + /** + * {@inheritdoc} + */ + public function normalize($object, $format = null, array $context = array()) + { + return $object->normalize($this->serializer, $format, $context); + } + + /** + * {@inheritdoc} + */ + public function denormalize($data, $class, $format = null, array $context = array()) + { + $object = new $class(); + $object->denormalize($this->serializer, $data, $format, $context); + + return $object; + } + + /** + * Checks if the given class implements the NormalizableInterface. + * + * @param mixed $data Data to normalize. + * @param string $format The format being (de-)serialized from or into. + * + * @return bool + */ + public function supportsNormalization($data, $format = null) + { + return $data instanceof NormalizableInterface; + } + + /** + * Checks if the given class implements the NormalizableInterface. + * + * @param mixed $data Data to denormalize from. + * @param string $type The class to which the data should be denormalized. + * @param string $format The format being deserialized from. + * + * @return bool + */ + public function supportsDenormalization($data, $type, $format = null) + { + $class = new \ReflectionClass($type); + + return $class->isSubclassOf('Symfony\Component\Serializer\Normalizer\DenormalizableInterface'); + } +} diff --git a/vendor/symfony/serializer/Normalizer/DenormalizableInterface.php b/vendor/symfony/serializer/Normalizer/DenormalizableInterface.php new file mode 100644 index 0000000..86c2702 --- /dev/null +++ b/vendor/symfony/serializer/Normalizer/DenormalizableInterface.php @@ -0,0 +1,38 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Serializer\Normalizer; + +/** + * Defines the most basic interface a class must implement to be denormalizable. + * + * If a denormalizer is registered for the class and it doesn't implement + * the Denormalizable interfaces, the normalizer will be used instead + * + * @author Jordi Boggiano + */ +interface DenormalizableInterface +{ + /** + * Denormalizes the object back from an array of scalars|arrays. + * + * It is important to understand that the denormalize() call should denormalize + * recursively all child objects of the implementor. + * + * @param DenormalizerInterface $denormalizer The denormalizer is given so that you + * can use it to denormalize objects contained within this object + * @param array|scalar $data The data from which to re-create the object. + * @param string|null $format The format is optionally given to be able to denormalize differently + * based on different input formats + * @param array $context options for denormalizing + */ + public function denormalize(DenormalizerInterface $denormalizer, $data, $format = null, array $context = array()); +} diff --git a/vendor/symfony/serializer/Normalizer/DenormalizerInterface.php b/vendor/symfony/serializer/Normalizer/DenormalizerInterface.php new file mode 100644 index 0000000..8b6c233 --- /dev/null +++ b/vendor/symfony/serializer/Normalizer/DenormalizerInterface.php @@ -0,0 +1,43 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Serializer\Normalizer; + +/** + * Defines the interface of denormalizers. + * + * @author Jordi Boggiano + */ +interface DenormalizerInterface +{ + /** + * Denormalizes data back into an object of the given class. + * + * @param mixed $data data to restore + * @param string $class the expected class to instantiate + * @param string $format format the given data was extracted from + * @param array $context options available to the denormalizer + * + * @return object + */ + public function denormalize($data, $class, $format = null, array $context = array()); + + /** + * Checks whether the given class is supported for denormalization by this normalizer. + * + * @param mixed $data Data to denormalize from. + * @param string $type The class to which the data should be denormalized. + * @param string $format The format being deserialized from. + * + * @return bool + */ + public function supportsDenormalization($data, $type, $format = null); +} diff --git a/vendor/symfony/serializer/Normalizer/GetSetMethodNormalizer.php b/vendor/symfony/serializer/Normalizer/GetSetMethodNormalizer.php new file mode 100644 index 0000000..44a71cf --- /dev/null +++ b/vendor/symfony/serializer/Normalizer/GetSetMethodNormalizer.php @@ -0,0 +1,179 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Serializer\Normalizer; + +use Symfony\Component\Serializer\Exception\CircularReferenceException; +use Symfony\Component\Serializer\Exception\LogicException; +use Symfony\Component\Serializer\Exception\RuntimeException; + +/** + * Converts between objects with getter and setter methods and arrays. + * + * The normalization process looks at all public methods and calls the ones + * which have a name starting with get and take no parameters. The result is a + * map from property names (method name stripped of the get prefix and converted + * to lower case) to property values. Property values are normalized through the + * serializer. + * + * The denormalization first looks at the constructor of the given class to see + * if any of the parameters have the same name as one of the properties. The + * constructor is then called with all parameters or an exception is thrown if + * any required parameters were not present as properties. Then the denormalizer + * walks through the given map of property names to property values to see if a + * setter method exists for any of the properties. If a setter exists it is + * called with the property value. No automatic denormalization of the value + * takes place. + * + * @author Nils Adermann + * @author Kévin Dunglas + */ +class GetSetMethodNormalizer extends AbstractNormalizer +{ + /** + * {@inheritdoc} + * + * @throws LogicException + * @throws CircularReferenceException + */ + public function normalize($object, $format = null, array $context = array()) + { + if ($this->isCircularReference($object, $context)) { + return $this->handleCircularReference($object); + } + + $reflectionObject = new \ReflectionObject($object); + $reflectionMethods = $reflectionObject->getMethods(\ReflectionMethod::IS_PUBLIC); + $allowedAttributes = $this->getAllowedAttributes($object, $context, true); + + $attributes = array(); + foreach ($reflectionMethods as $method) { + if ($this->isGetMethod($method)) { + $attributeName = lcfirst(substr($method->name, 0 === strpos($method->name, 'is') ? 2 : 3)); + if (in_array($attributeName, $this->ignoredAttributes)) { + continue; + } + + if (false !== $allowedAttributes && !in_array($attributeName, $allowedAttributes)) { + continue; + } + + $attributeValue = $method->invoke($object); + if (isset($this->callbacks[$attributeName])) { + $attributeValue = call_user_func($this->callbacks[$attributeName], $attributeValue); + } + if (null !== $attributeValue && !is_scalar($attributeValue)) { + if (!$this->serializer instanceof NormalizerInterface) { + throw new LogicException(sprintf('Cannot normalize attribute "%s" because injected serializer is not a normalizer', $attributeName)); + } + + $attributeValue = $this->serializer->normalize($attributeValue, $format, $context); + } + + if ($this->nameConverter) { + $attributeName = $this->nameConverter->normalize($attributeName); + } + + $attributes[$attributeName] = $attributeValue; + } + } + + return $attributes; + } + + /** + * {@inheritdoc} + * + * @throws RuntimeException + */ + public function denormalize($data, $class, $format = null, array $context = array()) + { + $allowedAttributes = $this->getAllowedAttributes($class, $context, true); + $normalizedData = $this->prepareForDenormalization($data); + + $reflectionClass = new \ReflectionClass($class); + $object = $this->instantiateObject($normalizedData, $class, $context, $reflectionClass, $allowedAttributes); + + $classMethods = get_class_methods($object); + foreach ($normalizedData as $attribute => $value) { + if ($this->nameConverter) { + $attribute = $this->nameConverter->denormalize($attribute); + } + + $allowed = $allowedAttributes === false || in_array($attribute, $allowedAttributes); + $ignored = in_array($attribute, $this->ignoredAttributes); + + if ($allowed && !$ignored) { + $setter = 'set'.ucfirst($attribute); + + if (in_array($setter, $classMethods)) { + $object->$setter($value); + } + } + } + + return $object; + } + + /** + * {@inheritdoc} + */ + public function supportsNormalization($data, $format = null) + { + return is_object($data) && !$data instanceof \Traversable && $this->supports(get_class($data)); + } + + /** + * {@inheritdoc} + */ + public function supportsDenormalization($data, $type, $format = null) + { + return $this->supports($type); + } + + /** + * Checks if the given class has any get{Property} method. + * + * @param string $class + * + * @return bool + */ + private function supports($class) + { + $class = new \ReflectionClass($class); + $methods = $class->getMethods(\ReflectionMethod::IS_PUBLIC); + foreach ($methods as $method) { + if ($this->isGetMethod($method)) { + return true; + } + } + + return false; + } + + /** + * Checks if a method's name is get.* or is.*, and can be called without parameters. + * + * @param \ReflectionMethod $method the method to check + * + * @return bool whether the method is a getter or boolean getter. + */ + private function isGetMethod(\ReflectionMethod $method) + { + $methodLength = strlen($method->name); + + return ( + ((0 === strpos($method->name, 'get') && 3 < $methodLength) || + (0 === strpos($method->name, 'is') && 2 < $methodLength)) && + 0 === $method->getNumberOfRequiredParameters() + ); + } +} diff --git a/vendor/symfony/serializer/Normalizer/NormalizableInterface.php b/vendor/symfony/serializer/Normalizer/NormalizableInterface.php new file mode 100644 index 0000000..b9fefe8 --- /dev/null +++ b/vendor/symfony/serializer/Normalizer/NormalizableInterface.php @@ -0,0 +1,39 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Serializer\Normalizer; + +/** + * Defines the most basic interface a class must implement to be normalizable. + * + * If a normalizer is registered for the class and it doesn't implement + * the Normalizable interfaces, the normalizer will be used instead. + * + * @author Jordi Boggiano + */ +interface NormalizableInterface +{ + /** + * Normalizes the object into an array of scalars|arrays. + * + * It is important to understand that the normalize() call should normalize + * recursively all child objects of the implementor. + * + * @param NormalizerInterface $normalizer The normalizer is given so that you + * can use it to normalize objects contained within this object. + * @param string|null $format The format is optionally given to be able to normalize differently + * based on different output formats. + * @param array $context Options for normalizing this object + * + * @return array|string|bool|int|float|null + */ + public function normalize(NormalizerInterface $normalizer, $format = null, array $context = array()); +} diff --git a/vendor/symfony/serializer/Normalizer/NormalizerInterface.php b/vendor/symfony/serializer/Normalizer/NormalizerInterface.php new file mode 100644 index 0000000..2a51d63 --- /dev/null +++ b/vendor/symfony/serializer/Normalizer/NormalizerInterface.php @@ -0,0 +1,41 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Serializer\Normalizer; + +/** + * Defines the interface of normalizers. + * + * @author Jordi Boggiano + */ +interface NormalizerInterface +{ + /** + * Normalizes an object into a set of arrays/scalars. + * + * @param object $object object to normalize + * @param string $format format the normalization result will be encoded as + * @param array $context Context options for the normalizer + * + * @return array|string|bool|int|float|null + */ + public function normalize($object, $format = null, array $context = array()); + + /** + * Checks whether the given class is supported for normalization by this normalizer. + * + * @param mixed $data Data to normalize. + * @param string $format The format being (de-)serialized from or into. + * + * @return bool + */ + public function supportsNormalization($data, $format = null); +} diff --git a/vendor/symfony/serializer/Normalizer/ObjectNormalizer.php b/vendor/symfony/serializer/Normalizer/ObjectNormalizer.php new file mode 100644 index 0000000..ba84ac7 --- /dev/null +++ b/vendor/symfony/serializer/Normalizer/ObjectNormalizer.php @@ -0,0 +1,162 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Serializer\Normalizer; + +use Symfony\Component\PropertyAccess\Exception\NoSuchPropertyException; +use Symfony\Component\PropertyAccess\PropertyAccess; +use Symfony\Component\PropertyAccess\PropertyAccessorInterface; +use Symfony\Component\Serializer\Exception\CircularReferenceException; +use Symfony\Component\Serializer\Exception\LogicException; +use Symfony\Component\Serializer\Mapping\Factory\ClassMetadataFactoryInterface; +use Symfony\Component\Serializer\NameConverter\NameConverterInterface; + +/** + * Converts between objects and arrays using the PropertyAccess component. + * + * @author Kévin Dunglas + */ +class ObjectNormalizer extends AbstractNormalizer +{ + /** + * @var PropertyAccessorInterface + */ + protected $propertyAccessor; + + public function __construct(ClassMetadataFactoryInterface $classMetadataFactory = null, NameConverterInterface $nameConverter = null, PropertyAccessorInterface $propertyAccessor = null) + { + parent::__construct($classMetadataFactory, $nameConverter); + + $this->propertyAccessor = $propertyAccessor ?: PropertyAccess::createPropertyAccessor(); + } + + /** + * {@inheritdoc} + */ + public function supportsNormalization($data, $format = null) + { + return is_object($data) && !$data instanceof \Traversable; + } + + /** + * {@inheritdoc} + * + * @throws CircularReferenceException + */ + public function normalize($object, $format = null, array $context = array()) + { + if ($this->isCircularReference($object, $context)) { + return $this->handleCircularReference($object); + } + + $data = array(); + $attributes = $this->getAllowedAttributes($object, $context, true); + + // If not using groups, detect manually + if (false === $attributes) { + $attributes = array(); + + // methods + $reflClass = new \ReflectionClass($object); + foreach ($reflClass->getMethods(\ReflectionMethod::IS_PUBLIC) as $reflMethod) { + if ( + !$reflMethod->isConstructor() && + !$reflMethod->isDestructor() && + 0 === $reflMethod->getNumberOfRequiredParameters() + ) { + $name = $reflMethod->getName(); + + if (strpos($name, 'get') === 0 || strpos($name, 'has') === 0) { + // getters and hassers + $attributes[lcfirst(substr($name, 3))] = true; + } elseif (strpos($name, 'is') === 0) { + // issers + $attributes[lcfirst(substr($name, 2))] = true; + } + } + } + + // properties + foreach ($reflClass->getProperties(\ReflectionProperty::IS_PUBLIC) as $reflProperty) { + $attributes[$reflProperty->getName()] = true; + } + + $attributes = array_keys($attributes); + } + + foreach ($attributes as $attribute) { + if (in_array($attribute, $this->ignoredAttributes)) { + continue; + } + + $attributeValue = $this->propertyAccessor->getValue($object, $attribute); + + if (isset($this->callbacks[$attribute])) { + $attributeValue = call_user_func($this->callbacks[$attribute], $attributeValue); + } + + if (null !== $attributeValue && !is_scalar($attributeValue)) { + if (!$this->serializer instanceof NormalizerInterface) { + throw new LogicException(sprintf('Cannot normalize attribute "%s" because injected serializer is not a normalizer', $attribute)); + } + + $attributeValue = $this->serializer->normalize($attributeValue, $format, $context); + } + + if ($this->nameConverter) { + $attribute = $this->nameConverter->normalize($attribute); + } + + $data[$attribute] = $attributeValue; + } + + return $data; + } + + /** + * {@inheritdoc} + */ + public function supportsDenormalization($data, $type, $format = null) + { + return class_exists($type); + } + + /** + * {@inheritdoc} + */ + public function denormalize($data, $class, $format = null, array $context = array()) + { + $allowedAttributes = $this->getAllowedAttributes($class, $context, true); + $normalizedData = $this->prepareForDenormalization($data); + + $reflectionClass = new \ReflectionClass($class); + $object = $this->instantiateObject($normalizedData, $class, $context, $reflectionClass, $allowedAttributes); + + foreach ($normalizedData as $attribute => $value) { + if ($this->nameConverter) { + $attribute = $this->nameConverter->denormalize($attribute); + } + + $allowed = $allowedAttributes === false || in_array($attribute, $allowedAttributes); + $ignored = in_array($attribute, $this->ignoredAttributes); + + if ($allowed && !$ignored) { + try { + $this->propertyAccessor->setValue($object, $attribute, $value); + } catch (NoSuchPropertyException $exception) { + // Properties not found are ignored + } + } + } + + return $object; + } +} diff --git a/vendor/symfony/serializer/Normalizer/PropertyNormalizer.php b/vendor/symfony/serializer/Normalizer/PropertyNormalizer.php new file mode 100644 index 0000000..c8e83d1 --- /dev/null +++ b/vendor/symfony/serializer/Normalizer/PropertyNormalizer.php @@ -0,0 +1,161 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Serializer\Normalizer; + +use Symfony\Component\Serializer\Exception\CircularReferenceException; +use Symfony\Component\Serializer\Exception\LogicException; +use Symfony\Component\Serializer\Exception\RuntimeException; + +/** + * Converts between objects and arrays by mapping properties. + * + * The normalization process looks for all the object's properties (public and private). + * The result is a map from property names to property values. Property values + * are normalized through the serializer. + * + * The denormalization first looks at the constructor of the given class to see + * if any of the parameters have the same name as one of the properties. The + * constructor is then called with all parameters or an exception is thrown if + * any required parameters were not present as properties. Then the denormalizer + * walks through the given map of property names to property values to see if a + * property with the corresponding name exists. If found, the property gets the value. + * + * @author Matthieu Napoli + * @author Kévin Dunglas + */ +class PropertyNormalizer extends AbstractNormalizer +{ + /** + * {@inheritdoc} + * + * @throws CircularReferenceException + */ + public function normalize($object, $format = null, array $context = array()) + { + if ($this->isCircularReference($object, $context)) { + return $this->handleCircularReference($object); + } + + $reflectionObject = new \ReflectionObject($object); + $attributes = array(); + $allowedAttributes = $this->getAllowedAttributes($object, $context, true); + + foreach ($reflectionObject->getProperties() as $property) { + if (in_array($property->name, $this->ignoredAttributes)) { + continue; + } + + if (false !== $allowedAttributes && !in_array($property->name, $allowedAttributes)) { + continue; + } + + // Override visibility + if (!$property->isPublic()) { + $property->setAccessible(true); + } + + $attributeValue = $property->getValue($object); + + if (isset($this->callbacks[$property->name])) { + $attributeValue = call_user_func($this->callbacks[$property->name], $attributeValue); + } + if (null !== $attributeValue && !is_scalar($attributeValue)) { + if (!$this->serializer instanceof NormalizerInterface) { + throw new LogicException(sprintf('Cannot normalize attribute "%s" because injected serializer is not a normalizer', $property->name)); + } + + $attributeValue = $this->serializer->normalize($attributeValue, $format, $context); + } + + $propertyName = $property->name; + if ($this->nameConverter) { + $propertyName = $this->nameConverter->normalize($propertyName); + } + + $attributes[$propertyName] = $attributeValue; + } + + return $attributes; + } + + /** + * {@inheritdoc} + * + * @throws RuntimeException + */ + public function denormalize($data, $class, $format = null, array $context = array()) + { + $allowedAttributes = $this->getAllowedAttributes($class, $context, true); + $data = $this->prepareForDenormalization($data); + + $reflectionClass = new \ReflectionClass($class); + $object = $this->instantiateObject($data, $class, $context, $reflectionClass, $allowedAttributes); + + foreach ($data as $propertyName => $value) { + if ($this->nameConverter) { + $propertyName = $this->nameConverter->denormalize($propertyName); + } + + $allowed = $allowedAttributes === false || in_array($propertyName, $allowedAttributes); + $ignored = in_array($propertyName, $this->ignoredAttributes); + if ($allowed && !$ignored && $reflectionClass->hasProperty($propertyName)) { + $property = $reflectionClass->getProperty($propertyName); + + // Override visibility + if (!$property->isPublic()) { + $property->setAccessible(true); + } + + $property->setValue($object, $value); + } + } + + return $object; + } + + /** + * {@inheritdoc} + */ + public function supportsNormalization($data, $format = null) + { + return is_object($data) && !$data instanceof \Traversable && $this->supports(get_class($data)); + } + + /** + * {@inheritdoc} + */ + public function supportsDenormalization($data, $type, $format = null) + { + return $this->supports($type); + } + + /** + * Checks if the given class has any non-static property. + * + * @param string $class + * + * @return bool + */ + private function supports($class) + { + $class = new \ReflectionClass($class); + + // We look for at least one non-static property + foreach ($class->getProperties() as $property) { + if (!$property->isStatic()) { + return true; + } + } + + return false; + } +} diff --git a/vendor/symfony/serializer/Normalizer/SerializerAwareNormalizer.php b/vendor/symfony/serializer/Normalizer/SerializerAwareNormalizer.php new file mode 100644 index 0000000..3956857 --- /dev/null +++ b/vendor/symfony/serializer/Normalizer/SerializerAwareNormalizer.php @@ -0,0 +1,36 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Serializer\Normalizer; + +use Symfony\Component\Serializer\SerializerInterface; +use Symfony\Component\Serializer\SerializerAwareInterface; + +/** + * SerializerAware Normalizer implementation. + * + * @author Jordi Boggiano + */ +abstract class SerializerAwareNormalizer implements SerializerAwareInterface +{ + /** + * @var SerializerInterface + */ + protected $serializer; + + /** + * {@inheritdoc} + */ + public function setSerializer(SerializerInterface $serializer) + { + $this->serializer = $serializer; + } +} diff --git a/vendor/symfony/serializer/README.md b/vendor/symfony/serializer/README.md new file mode 100644 index 0000000..156a288 --- /dev/null +++ b/vendor/symfony/serializer/README.md @@ -0,0 +1,15 @@ +Serializer Component +==================== + +With the Serializer component it's possible to handle serializing data structures, +including object graphs, into array structures or other formats like XML and JSON. +It can also handle deserializing XML and JSON back to object graphs. + +Resources +--------- + +You can run the unit tests with the following command: + + $ cd path/to/Symfony/Component/Serializer/ + $ composer install + $ phpunit diff --git a/vendor/symfony/serializer/Serializer.php b/vendor/symfony/serializer/Serializer.php new file mode 100644 index 0000000..4aeddab --- /dev/null +++ b/vendor/symfony/serializer/Serializer.php @@ -0,0 +1,310 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Serializer; + +use Symfony\Component\Serializer\Encoder\ChainDecoder; +use Symfony\Component\Serializer\Encoder\ChainEncoder; +use Symfony\Component\Serializer\Encoder\EncoderInterface; +use Symfony\Component\Serializer\Encoder\DecoderInterface; +use Symfony\Component\Serializer\Normalizer\NormalizerInterface; +use Symfony\Component\Serializer\Normalizer\DenormalizerInterface; +use Symfony\Component\Serializer\Exception\LogicException; +use Symfony\Component\Serializer\Exception\UnexpectedValueException; + +/** + * Serializer serializes and deserializes data. + * + * objects are turned into arrays by normalizers. + * arrays are turned into various output formats by encoders. + * + * $serializer->serialize($obj, 'xml') + * $serializer->decode($data, 'xml') + * $serializer->denormalize($data, 'Class', 'xml') + * + * @author Jordi Boggiano + * @author Johannes M. Schmitt + * @author Lukas Kahwe Smith + * @author Kévin Dunglas + */ +class Serializer implements SerializerInterface, NormalizerInterface, DenormalizerInterface, EncoderInterface, DecoderInterface +{ + /** + * @var Encoder\ChainEncoder + */ + protected $encoder; + /** + * @var Encoder\ChainDecoder + */ + protected $decoder; + /** + * @var array + */ + protected $normalizers = array(); + /** + * @var array + */ + protected $normalizerCache = array(); + /** + * @var array + */ + protected $denormalizerCache = array(); + + public function __construct(array $normalizers = array(), array $encoders = array()) + { + foreach ($normalizers as $normalizer) { + if ($normalizer instanceof SerializerAwareInterface) { + $normalizer->setSerializer($this); + } + } + $this->normalizers = $normalizers; + + $decoders = array(); + $realEncoders = array(); + foreach ($encoders as $encoder) { + if ($encoder instanceof SerializerAwareInterface) { + $encoder->setSerializer($this); + } + if ($encoder instanceof DecoderInterface) { + $decoders[] = $encoder; + } + if ($encoder instanceof EncoderInterface) { + $realEncoders[] = $encoder; + } + } + $this->encoder = new ChainEncoder($realEncoders); + $this->decoder = new ChainDecoder($decoders); + } + + /** + * {@inheritdoc} + */ + final public function serialize($data, $format, array $context = array()) + { + if (!$this->supportsEncoding($format)) { + throw new UnexpectedValueException(sprintf('Serialization for the format %s is not supported', $format)); + } + + if ($this->encoder->needsNormalization($format)) { + $data = $this->normalize($data, $format, $context); + } + + return $this->encode($data, $format, $context); + } + + /** + * {@inheritdoc} + */ + final public function deserialize($data, $type, $format, array $context = array()) + { + if (!$this->supportsDecoding($format)) { + throw new UnexpectedValueException(sprintf('Deserialization for the format %s is not supported', $format)); + } + + $data = $this->decode($data, $format, $context); + + return $this->denormalize($data, $type, $format, $context); + } + + /** + * {@inheritdoc} + */ + public function normalize($data, $format = null, array $context = array()) + { + // If a normalizer supports the given data, use it + if ($normalizer = $this->getNormalizer($data, $format)) { + return $normalizer->normalize($data, $format, $context); + } + + if (null === $data || is_scalar($data)) { + return $data; + } + if (is_object($data) && $this->supportsNormalization($data, $format)) { + return $this->normalizeObject($data, $format, $context); + } + if ($data instanceof \Traversable) { + $normalized = array(); + foreach ($data as $key => $val) { + $normalized[$key] = $this->normalize($val, $format, $context); + } + + return $normalized; + } + if (is_object($data)) { + return $this->normalizeObject($data, $format, $context); + } + if (is_array($data)) { + foreach ($data as $key => $val) { + $data[$key] = $this->normalize($val, $format, $context); + } + + return $data; + } + throw new UnexpectedValueException(sprintf('An unexpected value could not be normalized: %s', var_export($data, true))); + } + + /** + * {@inheritdoc} + */ + public function denormalize($data, $type, $format = null, array $context = array()) + { + return $this->denormalizeObject($data, $type, $format, $context); + } + + /** + * {@inheritdoc} + */ + public function supportsNormalization($data, $format = null) + { + return null !== $this->getNormalizer($data, $format); + } + + /** + * {@inheritdoc} + */ + public function supportsDenormalization($data, $type, $format = null) + { + return null !== $this->getDenormalizer($data, $type, $format); + } + + /** + * Returns a matching normalizer. + * + * @param mixed $data Data to get the serializer for + * @param string $format format name, present to give the option to normalizers to act differently based on formats + * + * @return NormalizerInterface|null + */ + private function getNormalizer($data, $format) + { + if ($isObject = is_object($data)) { + $class = get_class($data); + if (isset($this->normalizerCache[$class][$format])) { + return $this->normalizerCache[$class][$format]; + } + } + + foreach ($this->normalizers as $normalizer) { + if ($normalizer instanceof NormalizerInterface && $normalizer->supportsNormalization($data, $format)) { + if ($isObject) { + $this->normalizerCache[$class][$format] = $normalizer; + } + + return $normalizer; + } + } + } + + /** + * Returns a matching denormalizer. + * + * @param mixed $data data to restore + * @param string $class the expected class to instantiate + * @param string $format format name, present to give the option to normalizers to act differently based on formats + * + * @return DenormalizerInterface|null + */ + private function getDenormalizer($data, $class, $format) + { + if (isset($this->denormalizerCache[$class][$format])) { + return $this->denormalizerCache[$class][$format]; + } + + foreach ($this->normalizers as $normalizer) { + if ($normalizer instanceof DenormalizerInterface && $normalizer->supportsDenormalization($data, $class, $format)) { + $this->denormalizerCache[$class][$format] = $normalizer; + + return $normalizer; + } + } + } + + /** + * {@inheritdoc} + */ + final public function encode($data, $format, array $context = array()) + { + return $this->encoder->encode($data, $format, $context); + } + + /** + * {@inheritdoc} + */ + final public function decode($data, $format, array $context = array()) + { + return $this->decoder->decode($data, $format, $context); + } + + /** + * Normalizes an object into a set of arrays/scalars. + * + * @param object $object object to normalize + * @param string $format format name, present to give the option to normalizers to act differently based on formats + * @param array $context The context data for this particular normalization + * + * @return array|string|bool|int|float|null + * + * @throws LogicException + * @throws UnexpectedValueException + */ + private function normalizeObject($object, $format, array $context = array()) + { + if (!$this->normalizers) { + throw new LogicException('You must register at least one normalizer to be able to normalize objects.'); + } + + if ($normalizer = $this->getNormalizer($object, $format)) { + return $normalizer->normalize($object, $format, $context); + } + throw new UnexpectedValueException(sprintf('Could not normalize object of type %s, no supporting normalizer found.', get_class($object))); + } + + /** + * Denormalizes data back into an object of the given class. + * + * @param mixed $data data to restore + * @param string $class the expected class to instantiate + * @param string $format format name, present to give the option to normalizers to act differently based on formats + * @param array $context The context data for this particular denormalization + * + * @return object + * + * @throws LogicException + * @throws UnexpectedValueException + */ + private function denormalizeObject($data, $class, $format, array $context = array()) + { + if (!$this->normalizers) { + throw new LogicException('You must register at least one normalizer to be able to denormalize objects.'); + } + + if ($normalizer = $this->getDenormalizer($data, $class, $format)) { + return $normalizer->denormalize($data, $class, $format, $context); + } + throw new UnexpectedValueException(sprintf('Could not denormalize object of type %s, no supporting normalizer found.', $class)); + } + + /** + * {@inheritdoc} + */ + public function supportsEncoding($format) + { + return $this->encoder->supportsEncoding($format); + } + + /** + * {@inheritdoc} + */ + public function supportsDecoding($format) + { + return $this->decoder->supportsDecoding($format); + } +} diff --git a/vendor/symfony/serializer/SerializerAwareInterface.php b/vendor/symfony/serializer/SerializerAwareInterface.php new file mode 100644 index 0000000..dd0a62e --- /dev/null +++ b/vendor/symfony/serializer/SerializerAwareInterface.php @@ -0,0 +1,27 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Serializer; + +/** + * Defines the interface of encoders. + * + * @author Jordi Boggiano + */ +interface SerializerAwareInterface +{ + /** + * Sets the owning Serializer object. + * + * @param SerializerInterface $serializer + */ + public function setSerializer(SerializerInterface $serializer); +} diff --git a/vendor/symfony/serializer/SerializerInterface.php b/vendor/symfony/serializer/SerializerInterface.php new file mode 100644 index 0000000..c79db91 --- /dev/null +++ b/vendor/symfony/serializer/SerializerInterface.php @@ -0,0 +1,43 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Serializer; + +/** + * Defines the interface of the Serializer. + * + * @author Jordi Boggiano + */ +interface SerializerInterface +{ + /** + * Serializes data in the appropriate format. + * + * @param mixed $data any data + * @param string $format format name + * @param array $context options normalizers/encoders have access to + * + * @return string + */ + public function serialize($data, $format, array $context = array()); + + /** + * Deserializes data into the given type. + * + * @param mixed $data + * @param string $type + * @param string $format + * @param array $context + * + * @return object + */ + public function deserialize($data, $type, $format, array $context = array()); +} diff --git a/vendor/symfony/serializer/Tests/Annotation/GroupsTest.php b/vendor/symfony/serializer/Tests/Annotation/GroupsTest.php new file mode 100644 index 0000000..72b8777 --- /dev/null +++ b/vendor/symfony/serializer/Tests/Annotation/GroupsTest.php @@ -0,0 +1,52 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Serializer\Tests\Annotation; + +use Symfony\Component\Serializer\Annotation\Groups; + +/** + * @author Kévin Dunglas + */ +class GroupsTest extends \PHPUnit_Framework_TestCase +{ + /** + * @expectedException \Symfony\Component\Serializer\Exception\InvalidArgumentException + */ + public function testEmptyGroupsParameter() + { + new Groups(array('value' => array())); + } + + /** + * @expectedException \Symfony\Component\Serializer\Exception\InvalidArgumentException + */ + public function testNotAnArrayGroupsParameter() + { + new Groups(array('value' => 'coopTilleuls')); + } + + /** + * @expectedException \Symfony\Component\Serializer\Exception\InvalidArgumentException + */ + public function testInvalidGroupsParameter() + { + new Groups(array('value' => array('a', 1, new \stdClass()))); + } + + public function testGroupsParameters() + { + $validData = array('a', 'b'); + + $groups = new Groups(array('value' => $validData)); + $this->assertEquals($validData, $groups->getGroups()); + } +} diff --git a/vendor/symfony/serializer/Tests/Encoder/JsonEncoderTest.php b/vendor/symfony/serializer/Tests/Encoder/JsonEncoderTest.php new file mode 100644 index 0000000..c7bd11e --- /dev/null +++ b/vendor/symfony/serializer/Tests/Encoder/JsonEncoderTest.php @@ -0,0 +1,79 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Serializer\Tests\Encoder; + +use Symfony\Component\Serializer\Encoder\JsonEncoder; +use Symfony\Component\Serializer\Serializer; +use Symfony\Component\Serializer\Normalizer\CustomNormalizer; + +class JsonEncoderTest extends \PHPUnit_Framework_TestCase +{ + protected function setUp() + { + $this->encoder = new JsonEncoder(); + $this->serializer = new Serializer(array(new CustomNormalizer()), array('json' => new JsonEncoder())); + } + + public function testEncodeScalar() + { + $obj = new \stdClass(); + $obj->foo = 'foo'; + + $expected = '{"foo":"foo"}'; + + $this->assertEquals($expected, $this->encoder->encode($obj, 'json')); + } + + public function testComplexObject() + { + $obj = $this->getObject(); + + $expected = $this->getJsonSource(); + + $this->assertEquals($expected, $this->encoder->encode($obj, 'json')); + } + + public function testOptions() + { + $context = array('json_encode_options' => JSON_NUMERIC_CHECK); + + $arr = array(); + $arr['foo'] = '3'; + + $expected = '{"foo":3}'; + + $this->assertEquals($expected, $this->serializer->serialize($arr, 'json', $context)); + + $arr = array(); + $arr['foo'] = '3'; + + $expected = '{"foo":"3"}'; + + $this->assertEquals($expected, $this->serializer->serialize($arr, 'json'), 'Context should not be persistent'); + } + + protected function getJsonSource() + { + return '{"foo":"foo","bar":["a","b"],"baz":{"key":"val","key2":"val","A B":"bar","item":[{"title":"title1"},{"title":"title2"}],"Barry":{"FooBar":{"Baz":"Ed","@id":1}}},"qux":"1"}'; + } + + protected function getObject() + { + $obj = new \stdClass(); + $obj->foo = 'foo'; + $obj->bar = array('a', 'b'); + $obj->baz = array('key' => 'val', 'key2' => 'val', 'A B' => 'bar', 'item' => array(array('title' => 'title1'), array('title' => 'title2')), 'Barry' => array('FooBar' => array('Baz' => 'Ed', '@id' => 1))); + $obj->qux = '1'; + + return $obj; + } +} diff --git a/vendor/symfony/serializer/Tests/Encoder/XmlEncoderTest.php b/vendor/symfony/serializer/Tests/Encoder/XmlEncoderTest.php new file mode 100644 index 0000000..a62de61 --- /dev/null +++ b/vendor/symfony/serializer/Tests/Encoder/XmlEncoderTest.php @@ -0,0 +1,510 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Serializer\Tests\Encoder; + +use Symfony\Component\Serializer\Tests\Fixtures\Dummy; +use Symfony\Component\Serializer\Tests\Fixtures\ScalarDummy; +use Symfony\Component\Serializer\Encoder\XmlEncoder; +use Symfony\Component\Serializer\Serializer; +use Symfony\Component\Serializer\Exception\UnexpectedValueException; +use Symfony\Component\Serializer\Normalizer\CustomNormalizer; + +class XmlEncoderTest extends \PHPUnit_Framework_TestCase +{ + private $encoder; + + protected function setUp() + { + $this->encoder = new XmlEncoder(); + $serializer = new Serializer(array(new CustomNormalizer()), array('xml' => new XmlEncoder())); + $this->encoder->setSerializer($serializer); + } + + public function testEncodeScalar() + { + $obj = new ScalarDummy(); + $obj->xmlFoo = 'foo'; + + $expected = ''."\n". + 'foo'."\n"; + + $this->assertEquals($expected, $this->encoder->encode($obj, 'xml')); + } + + public function testSetRootNodeName() + { + $obj = new ScalarDummy(); + $obj->xmlFoo = 'foo'; + + $this->encoder->setRootNodeName('test'); + $expected = ''."\n". + 'foo'."\n"; + + $this->assertEquals($expected, $this->encoder->encode($obj, 'xml')); + } + + /** + * @expectedException \Symfony\Component\Serializer\Exception\UnexpectedValueException + * @expectedExceptionMessage Document types are not allowed. + */ + public function testDocTypeIsNotAllowed() + { + $this->encoder->decode('', 'foo'); + } + + public function testAttributes() + { + $obj = new ScalarDummy(); + $obj->xmlFoo = array( + 'foo-bar' => array( + '@id' => 1, + '@name' => 'Bar', + ), + 'Foo' => array( + 'Bar' => 'Test', + '@Type' => 'test', + ), + 'föo_bär' => 'a', + 'Bar' => array(1,2,3), + 'a' => 'b', + ); + $expected = ''."\n". + ''. + ''. + 'Test'. + 'a'. + '1'. + '2'. + '3'. + 'b'. + ''."\n"; + $this->assertEquals($expected, $this->encoder->encode($obj, 'xml')); + } + + public function testElementNameValid() + { + $obj = new ScalarDummy(); + $obj->xmlFoo = array( + 'foo-bar' => 'a', + 'foo_bar' => 'a', + 'föo_bär' => 'a', + ); + + $expected = ''."\n". + ''. + 'a'. + 'a'. + 'a'. + ''."\n"; + + $this->assertEquals($expected, $this->encoder->encode($obj, 'xml')); + } + + public function testEncodeSimpleXML() + { + $xml = simplexml_load_string('Peter'); + $array = array('person' => $xml); + + $expected = ''."\n". + 'Peter'."\n"; + + $this->assertEquals($expected, $this->encoder->encode($array, 'xml')); + } + + public function testEncodeXmlAttributes() + { + $xml = simplexml_load_string('Peter'); + $array = array('person' => $xml); + + $expected = ''."\n". + 'Peter'."\n"; + + $context = array( + 'xml_version' => '1.1', + 'xml_encoding' => 'utf-8', + 'xml_standalone' => true, + ); + + $this->assertSame($expected, $this->encoder->encode($array, 'xml', $context)); + } + + public function testContext() + { + $array = array('person' => array('name' => 'George Abitbol')); + $expected = << + + + George Abitbol + + + +XML; + + $context = array( + 'xml_format_output' => true, + ); + + $this->assertSame($expected, $this->encoder->encode($array, 'xml', $context)); + } + + public function testEncodeScalarRootAttributes() + { + $array = array( + '#' => 'Paul', + '@gender' => 'm', + ); + + $expected = ''."\n". + 'Paul'."\n"; + + $this->assertEquals($expected, $this->encoder->encode($array, 'xml')); + } + + public function testEncodeRootAttributes() + { + $array = array( + 'firstname' => 'Paul', + '@gender' => 'm', + ); + + $expected = ''."\n". + 'Paul'."\n"; + + $this->assertEquals($expected, $this->encoder->encode($array, 'xml')); + } + + public function testEncodeCdataWrapping() + { + $array = array( + 'firstname' => 'Paul ', + ); + + $expected = ''."\n". + ']]>'."\n"; + + $this->assertEquals($expected, $this->encoder->encode($array, 'xml')); + } + + public function testEncodeScalarWithAttribute() + { + $array = array( + 'person' => array('@gender' => 'M', '#' => 'Peter'), + ); + + $expected = ''."\n". + 'Peter'."\n"; + + $this->assertEquals($expected, $this->encoder->encode($array, 'xml')); + } + + public function testDecodeScalar() + { + $source = ''."\n". + 'foo'."\n"; + + $this->assertEquals('foo', $this->encoder->decode($source, 'xml')); + } + + public function testEncode() + { + $source = $this->getXmlSource(); + $obj = $this->getObject(); + + $this->assertEquals($source, $this->encoder->encode($obj, 'xml')); + } + + public function testEncodeWithNamespace() + { + $source = $this->getNamespacedXmlSource(); + $array = $this->getNamespacedArray(); + + $this->assertEquals($source, $this->encoder->encode($array, 'xml')); + } + + public function testEncodeSerializerXmlRootNodeNameOption() + { + $options = array('xml_root_node_name' => 'test'); + $this->encoder = new XmlEncoder(); + $serializer = new Serializer(array(), array('xml' => new XmlEncoder())); + $this->encoder->setSerializer($serializer); + + $array = array( + 'person' => array('@gender' => 'M', '#' => 'Peter'), + ); + + $expected = ''."\n". + 'Peter'."\n"; + + $this->assertEquals($expected, $serializer->serialize($array, 'xml', $options)); + } + + public function testDecode() + { + $source = $this->getXmlSource(); + $obj = $this->getObject(); + + $this->assertEquals(get_object_vars($obj), $this->encoder->decode($source, 'xml')); + } + + public function testDecodeCdataWrapping() + { + $expected = array( + 'firstname' => 'Paul ', + ); + + $xml = ''."\n". + ']]>'."\n"; + + $this->assertEquals($expected, $this->encoder->decode($xml, 'xml')); + } + + public function testDecodeCdataWrappingAndWhitespace() + { + $expected = array( + 'firstname' => 'Paul ', + ); + + $xml = ''."\n". + ''."\n". + ']]>'."\n"; + + $this->assertEquals($expected, $this->encoder->decode($xml, 'xml')); + } + + public function testDecodeWithNamespace() + { + $source = $this->getNamespacedXmlSource(); + $array = $this->getNamespacedArray(); + + $this->assertEquals($array, $this->encoder->decode($source, 'xml')); + } + + public function testDecodeScalarWithAttribute() + { + $source = ''."\n". + 'Peter'."\n"; + + $expected = array( + 'person' => array('@gender' => 'M', '#' => 'Peter'), + ); + + $this->assertEquals($expected, $this->encoder->decode($source, 'xml')); + } + + public function testDecodeScalarRootAttributes() + { + $source = ''."\n". + 'Peter'."\n"; + + $expected = array( + '#' => 'Peter', + '@gender' => 'M', + ); + + $this->assertEquals($expected, $this->encoder->decode($source, 'xml')); + } + + public function testDecodeRootAttributes() + { + $source = ''."\n". + 'PeterMac Calloway'."\n"; + + $expected = array( + 'firstname' => 'Peter', + 'lastname' => 'Mac Calloway', + '@gender' => 'M', + ); + + $this->assertEquals($expected, $this->encoder->decode($source, 'xml')); + } + + public function testDecodeArray() + { + $source = ''."\n". + ''. + ''. + 'BenjaminAlexandre'. + 'DamienClay'. + ''. + ''."\n"; + + $expected = array( + 'people' => array('person' => array( + array('firstname' => 'Benjamin', 'lastname' => 'Alexandre'), + array('firstname' => 'Damien', 'lastname' => 'Clay'), + )), + ); + + $this->assertEquals($expected, $this->encoder->decode($source, 'xml')); + } + + public function testDecodeIgnoreWhiteSpace() + { + $source = << + + + Benjamin + Alexandre + + + Damien + Clay + + +XML; + $expected = array('person' => array( + array('firstname' => 'Benjamin', 'lastname' => 'Alexandre'), + array('firstname' => 'Damien', 'lastname' => 'Clay'), + )); + + $this->assertEquals($expected, $this->encoder->decode($source, 'xml')); + } + + public function testDecodeWithoutItemHash() + { + $obj = new ScalarDummy(); + $obj->xmlFoo = array( + 'foo-bar' => array( + '@key' => 'value', + 'item' => array('@key' => 'key', 'key-val' => 'val'), + ), + 'Foo' => array( + 'Bar' => 'Test', + '@Type' => 'test', + ), + 'föo_bär' => 'a', + 'Bar' => array(1,2,3), + 'a' => 'b', + ); + $expected = array( + 'foo-bar' => array( + '@key' => 'value', + 'key' => array('@key' => 'key', 'key-val' => 'val'), + ), + 'Foo' => array( + 'Bar' => 'Test', + '@Type' => 'test', + ), + 'föo_bär' => 'a', + 'Bar' => array(1,2,3), + 'a' => 'b', + ); + $xml = $this->encoder->encode($obj, 'xml'); + $this->assertEquals($expected, $this->encoder->decode($xml, 'xml')); + } + + /** + * @expectedException \Symfony\Component\Serializer\Exception\UnexpectedValueException + */ + public function testDecodeInvalidXml() + { + $this->encoder->decode('', 'xml'); + } + + public function testPreventsComplexExternalEntities() + { + $oldCwd = getcwd(); + chdir(__DIR__); + + try { + $this->encoder->decode(']>&test;', 'xml'); + chdir($oldCwd); + + $this->fail('No exception was thrown.'); + } catch (\Exception $e) { + chdir($oldCwd); + + if (!$e instanceof UnexpectedValueException) { + $this->fail('Expected UnexpectedValueException'); + } + } + } + + public function testDecodeEmptyXml() + { + $this->setExpectedException('Symfony\Component\Serializer\Exception\UnexpectedValueException', 'Invalid XML data, it can not be empty.'); + $this->encoder->decode(' ', 'xml'); + } + + protected function getXmlSource() + { + return ''."\n". + ''. + 'foo'. + 'ab'. + 'valvalbar'. + 'title1title2'. + 'Ed'. + '1'. + ''."\n"; + } + + protected function getNamespacedXmlSource() + { + return ''."\n". + ''. + '1'. + 'foo'. + 'ab'. + 'valvalbar'. + 'title1title2'. + 'Ed'. + ''."\n"; + } + + protected function getNamespacedArray() + { + return array( + '@xmlns' => 'http://www.w3.org/2005/Atom', + '@xmlns:app' => 'http://www.w3.org/2007/app', + '@xmlns:media' => 'http://search.yahoo.com/mrss/', + '@xmlns:gd' => 'http://schemas.google.com/g/2005', + '@xmlns:yt' => 'http://gdata.youtube.com/schemas/2007', + 'qux' => '1', + 'app:foo' => 'foo', + 'yt:bar' => array('a', 'b'), + 'media:baz' => array( + 'media:key' => 'val', + 'media:key2' => 'val', + 'A B' => 'bar', + 'item' => array( + array( + 'title' => 'title1', + ), + array( + 'title' => 'title2', + ), + ), + 'Barry' => array( + '@size' => 'large', + 'FooBar' => array( + 'Baz' => 'Ed', + '@gd:id' => 1, + ), + ), + ), + ); + } + + protected function getObject() + { + $obj = new Dummy(); + $obj->foo = 'foo'; + $obj->bar = array('a', 'b'); + $obj->baz = array('key' => 'val', 'key2' => 'val', 'A B' => 'bar', 'item' => array(array('title' => 'title1'), array('title' => 'title2')), 'Barry' => array('FooBar' => array('Baz' => 'Ed', '@id' => 1))); + $obj->qux = '1'; + + return $obj; + } +} diff --git a/vendor/symfony/serializer/Tests/Fixtures/CircularReferenceDummy.php b/vendor/symfony/serializer/Tests/Fixtures/CircularReferenceDummy.php new file mode 100644 index 0000000..cc07015 --- /dev/null +++ b/vendor/symfony/serializer/Tests/Fixtures/CircularReferenceDummy.php @@ -0,0 +1,23 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Serializer\Tests\Fixtures; + +/** + * @author Kévin Dunglas + */ +class CircularReferenceDummy +{ + public function getMe() + { + return $this; + } +} diff --git a/vendor/symfony/serializer/Tests/Fixtures/DenormalizableDummy.php b/vendor/symfony/serializer/Tests/Fixtures/DenormalizableDummy.php new file mode 100644 index 0000000..d78f34a --- /dev/null +++ b/vendor/symfony/serializer/Tests/Fixtures/DenormalizableDummy.php @@ -0,0 +1,22 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Serializer\Tests\Fixtures; + +use Symfony\Component\Serializer\Normalizer\DenormalizableInterface; +use Symfony\Component\Serializer\Normalizer\DenormalizerInterface; + +class DenormalizableDummy implements DenormalizableInterface +{ + public function denormalize(DenormalizerInterface $denormalizer, $data, $format = null, array $context = array()) + { + } +} diff --git a/vendor/symfony/serializer/Tests/Fixtures/Dummy.php b/vendor/symfony/serializer/Tests/Fixtures/Dummy.php new file mode 100644 index 0000000..6b33e84 --- /dev/null +++ b/vendor/symfony/serializer/Tests/Fixtures/Dummy.php @@ -0,0 +1,43 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Serializer\Tests\Fixtures; + +use Symfony\Component\Serializer\Normalizer\NormalizableInterface; +use Symfony\Component\Serializer\Normalizer\DenormalizableInterface; +use Symfony\Component\Serializer\Normalizer\NormalizerInterface; +use Symfony\Component\Serializer\Normalizer\DenormalizerInterface; + +class Dummy implements NormalizableInterface, DenormalizableInterface +{ + public $foo; + public $bar; + public $baz; + public $qux; + + public function normalize(NormalizerInterface $normalizer, $format = null, array $context = array()) + { + return array( + 'foo' => $this->foo, + 'bar' => $this->bar, + 'baz' => $this->baz, + 'qux' => $this->qux, + ); + } + + public function denormalize(DenormalizerInterface $denormalizer, $data, $format = null, array $context = array()) + { + $this->foo = $data['foo']; + $this->bar = $data['bar']; + $this->baz = $data['baz']; + $this->qux = $data['qux']; + } +} diff --git a/vendor/symfony/serializer/Tests/Fixtures/GroupDummy.php b/vendor/symfony/serializer/Tests/Fixtures/GroupDummy.php new file mode 100644 index 0000000..37bfa7e --- /dev/null +++ b/vendor/symfony/serializer/Tests/Fixtures/GroupDummy.php @@ -0,0 +1,80 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Serializer\Tests\Fixtures; + +use Symfony\Component\Serializer\Annotation\Groups; + +/** + * @author Kévin Dunglas + */ +class GroupDummy extends GroupDummyParent implements GroupDummyInterface +{ + /** + * @Groups({"a"}) + */ + private $foo; + /** + * @Groups({"b", "c", "name_converter"}) + */ + protected $bar; + private $fooBar; + private $symfony; + + /** + * @Groups({"b"}) + */ + public function setBar($bar) + { + $this->bar = $bar; + } + + /** + * @Groups({"c"}) + */ + public function getBar() + { + return $this->bar; + } + + public function setFoo($foo) + { + $this->foo = $foo; + } + + public function getFoo() + { + return $this->foo; + } + + public function setFooBar($fooBar) + { + $this->fooBar = $fooBar; + } + + /** + * @Groups({"a", "b", "name_converter"}) + */ + public function isFooBar() + { + return $this->fooBar; + } + + public function setSymfony($symfony) + { + $this->symfony = $symfony; + } + + public function getSymfony() + { + return $this->symfony; + } +} diff --git a/vendor/symfony/serializer/Tests/Fixtures/GroupDummyInterface.php b/vendor/symfony/serializer/Tests/Fixtures/GroupDummyInterface.php new file mode 100644 index 0000000..a60629e --- /dev/null +++ b/vendor/symfony/serializer/Tests/Fixtures/GroupDummyInterface.php @@ -0,0 +1,25 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Serializer\Tests\Fixtures; + +use Symfony\Component\Serializer\Annotation\Groups; + +/** + * @author Kévin Dunglas + */ +interface GroupDummyInterface +{ + /** + * @Groups({"a", "name_converter"}) + */ + public function getSymfony(); +} diff --git a/vendor/symfony/serializer/Tests/Fixtures/GroupDummyParent.php b/vendor/symfony/serializer/Tests/Fixtures/GroupDummyParent.php new file mode 100644 index 0000000..dd24233 --- /dev/null +++ b/vendor/symfony/serializer/Tests/Fixtures/GroupDummyParent.php @@ -0,0 +1,49 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Serializer\Tests\Fixtures; + +use Symfony\Component\Serializer\Annotation\Groups; + +/** + * @author Kévin Dunglas + */ +class GroupDummyParent +{ + /** + * @Groups({"a"}) + */ + private $kevin; + private $coopTilleuls; + + public function setKevin($kevin) + { + $this->kevin = $kevin; + } + + public function getKevin() + { + return $this->kevin; + } + + public function setCoopTilleuls($coopTilleuls) + { + $this->coopTilleuls = $coopTilleuls; + } + + /** + * @Groups({"a", "b"}) + */ + public function getCoopTilleuls() + { + return $this->coopTilleuls; + } +} diff --git a/vendor/symfony/serializer/Tests/Fixtures/NormalizableTraversableDummy.php b/vendor/symfony/serializer/Tests/Fixtures/NormalizableTraversableDummy.php new file mode 100644 index 0000000..3ac2fe3 --- /dev/null +++ b/vendor/symfony/serializer/Tests/Fixtures/NormalizableTraversableDummy.php @@ -0,0 +1,36 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Serializer\Tests\Fixtures; + +use Symfony\Component\Serializer\Normalizer\NormalizableInterface; +use Symfony\Component\Serializer\Normalizer\DenormalizableInterface; +use Symfony\Component\Serializer\Normalizer\NormalizerInterface; +use Symfony\Component\Serializer\Normalizer\DenormalizerInterface; + +class NormalizableTraversableDummy extends TraversableDummy implements NormalizableInterface, DenormalizableInterface +{ + public function normalize(NormalizerInterface $normalizer, $format = null, array $context = array()) + { + return array( + 'foo' => 'normalizedFoo', + 'bar' => 'normalizedBar', + ); + } + + public function denormalize(DenormalizerInterface $denormalizer, $data, $format = null, array $context = array()) + { + return array( + 'foo' => 'denormalizedFoo', + 'bar' => 'denormalizedBar', + ); + } +} diff --git a/vendor/symfony/serializer/Tests/Fixtures/PropertyCircularReferenceDummy.php b/vendor/symfony/serializer/Tests/Fixtures/PropertyCircularReferenceDummy.php new file mode 100644 index 0000000..8a1d9d8 --- /dev/null +++ b/vendor/symfony/serializer/Tests/Fixtures/PropertyCircularReferenceDummy.php @@ -0,0 +1,25 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Serializer\Tests\Fixtures; + +/** + * @author Kévin Dunglas + */ +class PropertyCircularReferenceDummy +{ + public $me; + + public function __construct() + { + $this->me = $this; + } +} diff --git a/vendor/symfony/serializer/Tests/Fixtures/PropertySiblingHolder.php b/vendor/symfony/serializer/Tests/Fixtures/PropertySiblingHolder.php new file mode 100644 index 0000000..af993e6 --- /dev/null +++ b/vendor/symfony/serializer/Tests/Fixtures/PropertySiblingHolder.php @@ -0,0 +1,39 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Serializer\Tests\Fixtures; + +/** + * @author Kévin Dunglas + */ +class PropertySiblingHolder +{ + public $sibling0; + public $sibling1; + public $sibling2; + + public function __construct() + { + $sibling = new PropertySibling(); + + $this->sibling0 = $sibling; + $this->sibling1 = $sibling; + $this->sibling2 = $sibling; + } +} + +/** + * @author Kévin Dunglas + */ +class PropertySibling +{ + public $coopTilleuls = 'Les-Tilleuls.coop'; +} diff --git a/vendor/symfony/serializer/Tests/Fixtures/ScalarDummy.php b/vendor/symfony/serializer/Tests/Fixtures/ScalarDummy.php new file mode 100644 index 0000000..e9db238 --- /dev/null +++ b/vendor/symfony/serializer/Tests/Fixtures/ScalarDummy.php @@ -0,0 +1,37 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Serializer\Tests\Fixtures; + +use Symfony\Component\Serializer\Normalizer\NormalizableInterface; +use Symfony\Component\Serializer\Normalizer\DenormalizableInterface; +use Symfony\Component\Serializer\Normalizer\NormalizerInterface; +use Symfony\Component\Serializer\Normalizer\DenormalizerInterface; + +class ScalarDummy implements NormalizableInterface, DenormalizableInterface +{ + public $foo; + public $xmlFoo; + + public function normalize(NormalizerInterface $normalizer, $format = null, array $context = array()) + { + return $format === 'xml' ? $this->xmlFoo : $this->foo; + } + + public function denormalize(DenormalizerInterface $denormalizer, $data, $format = null, array $context = array()) + { + if ($format === 'xml') { + $this->xmlFoo = $data; + } else { + $this->foo = $data; + } + } +} diff --git a/vendor/symfony/serializer/Tests/Fixtures/SiblingHolder.php b/vendor/symfony/serializer/Tests/Fixtures/SiblingHolder.php new file mode 100644 index 0000000..acd4fe9 --- /dev/null +++ b/vendor/symfony/serializer/Tests/Fixtures/SiblingHolder.php @@ -0,0 +1,57 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Serializer\Tests\Fixtures; + +/** + * @author Kévin Dunglas + */ +class SiblingHolder +{ + private $sibling0; + private $sibling1; + private $sibling2; + + public function __construct() + { + $sibling = new Sibling(); + + $this->sibling0 = $sibling; + $this->sibling1 = $sibling; + $this->sibling2 = $sibling; + } + + public function getSibling0() + { + return $this->sibling0; + } + + public function getSibling1() + { + return $this->sibling1; + } + + public function getSibling2() + { + return $this->sibling2; + } +} + +/** + * @author Kévin Dunglas + */ +class Sibling +{ + public function getCoopTilleuls() + { + return 'Les-Tilleuls.coop'; + } +} diff --git a/vendor/symfony/serializer/Tests/Fixtures/TraversableDummy.php b/vendor/symfony/serializer/Tests/Fixtures/TraversableDummy.php new file mode 100644 index 0000000..bcf46e5 --- /dev/null +++ b/vendor/symfony/serializer/Tests/Fixtures/TraversableDummy.php @@ -0,0 +1,23 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Serializer\Tests\Fixtures; + +class TraversableDummy implements \IteratorAggregate +{ + public $foo = 'foo'; + public $bar = 'bar'; + + public function getIterator() + { + return new \ArrayIterator(get_object_vars($this)); + } +} diff --git a/vendor/symfony/serializer/Tests/Fixtures/VariadicConstructorArgsDummy.php b/vendor/symfony/serializer/Tests/Fixtures/VariadicConstructorArgsDummy.php new file mode 100644 index 0000000..c04aeba --- /dev/null +++ b/vendor/symfony/serializer/Tests/Fixtures/VariadicConstructorArgsDummy.php @@ -0,0 +1,27 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Serializer\Tests\Fixtures; + +class VariadicConstructorArgsDummy +{ + private $foo; + + public function __construct(...$foo) + { + $this->foo = $foo; + } + + public function getFoo() + { + return $this->foo; + } +} diff --git a/vendor/symfony/serializer/Tests/Fixtures/empty-mapping.yml b/vendor/symfony/serializer/Tests/Fixtures/empty-mapping.yml new file mode 100644 index 0000000..e69de29 diff --git a/vendor/symfony/serializer/Tests/Fixtures/invalid-mapping.yml b/vendor/symfony/serializer/Tests/Fixtures/invalid-mapping.yml new file mode 100644 index 0000000..1910281 --- /dev/null +++ b/vendor/symfony/serializer/Tests/Fixtures/invalid-mapping.yml @@ -0,0 +1 @@ +foo \ No newline at end of file diff --git a/vendor/symfony/serializer/Tests/Fixtures/serialization.xml b/vendor/symfony/serializer/Tests/Fixtures/serialization.xml new file mode 100644 index 0000000..6e95aaf --- /dev/null +++ b/vendor/symfony/serializer/Tests/Fixtures/serialization.xml @@ -0,0 +1,18 @@ + + + + + + + group1 + group2 + + + + group2 + + + + diff --git a/vendor/symfony/serializer/Tests/Fixtures/serialization.yml b/vendor/symfony/serializer/Tests/Fixtures/serialization.yml new file mode 100644 index 0000000..e855ea4 --- /dev/null +++ b/vendor/symfony/serializer/Tests/Fixtures/serialization.yml @@ -0,0 +1,6 @@ +Symfony\Component\Serializer\Tests\Fixtures\GroupDummy: + attributes: + foo: + groups: ['group1', 'group2'] + bar: + groups: ['group2'] diff --git a/vendor/symfony/serializer/Tests/Mapping/AttributeMetadataTest.php b/vendor/symfony/serializer/Tests/Mapping/AttributeMetadataTest.php new file mode 100644 index 0000000..4a32831 --- /dev/null +++ b/vendor/symfony/serializer/Tests/Mapping/AttributeMetadataTest.php @@ -0,0 +1,67 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Serializer\Tests\Mapping; + +use Symfony\Component\Serializer\Mapping\AttributeMetadata; + +/** + * @author Kévin Dunglas + */ +class AttributeMetadataTest extends \PHPUnit_Framework_TestCase +{ + public function testInterface() + { + $attributeMetadata = new AttributeMetadata('name'); + $this->assertInstanceOf('Symfony\Component\Serializer\Mapping\AttributeMetadataInterface', $attributeMetadata); + } + + public function testGetName() + { + $attributeMetadata = new AttributeMetadata('name'); + $this->assertEquals('name', $attributeMetadata->getName()); + } + + public function testGroups() + { + $attributeMetadata = new AttributeMetadata('group'); + $attributeMetadata->addGroup('a'); + $attributeMetadata->addGroup('a'); + $attributeMetadata->addGroup('b'); + + $this->assertEquals(array('a', 'b'), $attributeMetadata->getGroups()); + } + + public function testMerge() + { + $attributeMetadata1 = new AttributeMetadata('a1'); + $attributeMetadata1->addGroup('a'); + $attributeMetadata1->addGroup('b'); + + $attributeMetadata2 = new AttributeMetadata('a2'); + $attributeMetadata2->addGroup('a'); + $attributeMetadata2->addGroup('c'); + + $attributeMetadata1->merge($attributeMetadata2); + + $this->assertEquals(array('a', 'b', 'c'), $attributeMetadata1->getGroups()); + } + + public function testSerialize() + { + $attributeMetadata = new AttributeMetadata('attribute'); + $attributeMetadata->addGroup('a'); + $attributeMetadata->addGroup('b'); + + $serialized = serialize($attributeMetadata); + $this->assertEquals($attributeMetadata, unserialize($serialized)); + } +} diff --git a/vendor/symfony/serializer/Tests/Mapping/ClassMetadataTest.php b/vendor/symfony/serializer/Tests/Mapping/ClassMetadataTest.php new file mode 100644 index 0000000..629c17b --- /dev/null +++ b/vendor/symfony/serializer/Tests/Mapping/ClassMetadataTest.php @@ -0,0 +1,82 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Serializer\Tests\Mapping; + +use Symfony\Component\Serializer\Mapping\ClassMetadata; + +/** + * @author Kévin Dunglas + */ +class ClassMetadataTest extends \PHPUnit_Framework_TestCase +{ + public function testInterface() + { + $classMetadata = new ClassMetadata('name'); + $this->assertInstanceOf('Symfony\Component\Serializer\Mapping\ClassMetadataInterface', $classMetadata); + } + + public function testAttributeMetadata() + { + $classMetadata = new ClassMetadata('c'); + + $a1 = $this->getMock('Symfony\Component\Serializer\Mapping\AttributeMetadataInterface'); + $a1->method('getName')->willReturn('a1'); + + $a2 = $this->getMock('Symfony\Component\Serializer\Mapping\AttributeMetadataInterface'); + $a2->method('getName')->willReturn('a2'); + + $classMetadata->addAttributeMetadata($a1); + $classMetadata->addAttributeMetadata($a2); + + $this->assertEquals(array('a1' => $a1, 'a2' => $a2), $classMetadata->getAttributesMetadata()); + } + + public function testMerge() + { + $classMetadata1 = new ClassMetadata('c1'); + $classMetadata2 = new ClassMetadata('c2'); + + $ac1 = $this->getMock('Symfony\Component\Serializer\Mapping\AttributeMetadataInterface'); + $ac1->method('getName')->willReturn('a1'); + $ac1->method('getGroups')->willReturn(array('a', 'b')); + + $ac2 = $this->getMock('Symfony\Component\Serializer\Mapping\AttributeMetadataInterface'); + $ac2->method('getName')->willReturn('a1'); + $ac2->method('getGroups')->willReturn(array('b', 'c')); + + $classMetadata1->addAttributeMetadata($ac1); + $classMetadata2->addAttributeMetadata($ac2); + + $classMetadata1->merge($classMetadata2); + + $ac1->method('getGroups')->willReturn('a', 'b', 'c'); + + $this->assertEquals(array('a1' => $ac1), $classMetadata2->getAttributesMetadata()); + } + + public function testSerialize() + { + $classMetadata = new ClassMetadata('a'); + + $a1 = $this->getMock('Symfony\Component\Serializer\Mapping\AttributeMetadataInterface'); + $a1->method('getName')->willReturn('b1'); + + $a2 = $this->getMock('Symfony\Component\Serializer\Mapping\AttributeMetadataInterface'); + $a2->method('getName')->willReturn('b2'); + + $classMetadata->addAttributeMetadata($a1); + $classMetadata->addAttributeMetadata($a2); + + $serialized = serialize($classMetadata); + $this->assertEquals($classMetadata, unserialize($serialized)); + } +} diff --git a/vendor/symfony/serializer/Tests/Mapping/Factory/ClassMetadataFactoryTest.php b/vendor/symfony/serializer/Tests/Mapping/Factory/ClassMetadataFactoryTest.php new file mode 100644 index 0000000..2e2ba22 --- /dev/null +++ b/vendor/symfony/serializer/Tests/Mapping/Factory/ClassMetadataFactoryTest.php @@ -0,0 +1,78 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Serializer\Tests\Mapping\Factory; + +use Doctrine\Common\Annotations\AnnotationReader; +use Symfony\Component\Serializer\Mapping\Factory\ClassMetadataFactory; +use Symfony\Component\Serializer\Mapping\Loader\AnnotationLoader; +use Symfony\Component\Serializer\Mapping\Loader\LoaderChain; +use Symfony\Component\Serializer\Tests\Mapping\TestClassMetadataFactory; + +/** + * @author Kévin Dunglas + */ +class ClassMetadataFactoryTest extends \PHPUnit_Framework_TestCase +{ + public function testInterface() + { + $classMetadata = new ClassMetadataFactory(new LoaderChain(array())); + $this->assertInstanceOf('Symfony\Component\Serializer\Mapping\Factory\ClassMetadataFactory', $classMetadata); + } + + public function testGetMetadataFor() + { + $factory = new ClassMetadataFactory(new AnnotationLoader(new AnnotationReader())); + $classMetadata = $factory->getMetadataFor('Symfony\Component\Serializer\Tests\Fixtures\GroupDummy'); + + $this->assertEquals(TestClassMetadataFactory::createClassMetadata(true, true), $classMetadata); + } + + public function testHasMetadataFor() + { + $factory = new ClassMetadataFactory(new AnnotationLoader(new AnnotationReader())); + $this->assertTrue($factory->hasMetadataFor('Symfony\Component\Serializer\Tests\Fixtures\GroupDummy')); + $this->assertTrue($factory->hasMetadataFor('Symfony\Component\Serializer\Tests\Fixtures\GroupDummyParent')); + $this->assertTrue($factory->hasMetadataFor('Symfony\Component\Serializer\Tests\Fixtures\GroupDummyInterface')); + $this->assertFalse($factory->hasMetadataFor('Dunglas\Entity')); + } + + public function testCacheExists() + { + $cache = $this->getMock('Doctrine\Common\Cache\Cache'); + $cache + ->expects($this->once()) + ->method('fetch') + ->will($this->returnValue('foo')) + ; + + $factory = new ClassMetadataFactory(new AnnotationLoader(new AnnotationReader()), $cache); + $this->assertEquals('foo', $factory->getMetadataFor('Symfony\Component\Serializer\Tests\Fixtures\GroupDummy')); + } + + public function testCacheNotExists() + { + $cache = $this->getMock('Doctrine\Common\Cache\Cache'); + $cache + ->method('fetch') + ->will($this->returnValue(false)) + ; + + $cache + ->method('save') + ; + + $factory = new ClassMetadataFactory(new AnnotationLoader(new AnnotationReader()), $cache); + $metadata = $factory->getMetadataFor('Symfony\Component\Serializer\Tests\Fixtures\GroupDummy'); + + $this->assertEquals(TestClassMetadataFactory::createClassMetadata(true, true), $metadata); + } +} diff --git a/vendor/symfony/serializer/Tests/Mapping/Loader/AnnotationLoaderTest.php b/vendor/symfony/serializer/Tests/Mapping/Loader/AnnotationLoaderTest.php new file mode 100644 index 0000000..484d062 --- /dev/null +++ b/vendor/symfony/serializer/Tests/Mapping/Loader/AnnotationLoaderTest.php @@ -0,0 +1,66 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Serializer\Tests\Mapping\Loader; + +use Doctrine\Common\Annotations\AnnotationReader; +use Symfony\Component\Serializer\Mapping\ClassMetadata; +use Symfony\Component\Serializer\Mapping\Loader\AnnotationLoader; +use Symfony\Component\Serializer\Tests\Mapping\TestClassMetadataFactory; + +/** + * @author Kévin Dunglas + */ +class AnnotationLoaderTest extends \PHPUnit_Framework_TestCase +{ + /** + * @var AnnotationLoader + */ + private $loader; + + protected function setUp() + { + $this->loader = new AnnotationLoader(new AnnotationReader()); + } + + public function testInterface() + { + $this->assertInstanceOf('Symfony\Component\Serializer\Mapping\Loader\LoaderInterface', $this->loader); + } + + public function testLoadClassMetadataReturnsTrueIfSuccessful() + { + $classMetadata = new ClassMetadata('Symfony\Component\Serializer\Tests\Fixtures\GroupDummy'); + + $this->assertTrue($this->loader->loadClassMetadata($classMetadata)); + } + + public function testLoadClassMetadata() + { + $classMetadata = new ClassMetadata('Symfony\Component\Serializer\Tests\Fixtures\GroupDummy'); + $this->loader->loadClassMetadata($classMetadata); + + $this->assertEquals(TestClassMetadataFactory::createClassMetadata(), $classMetadata); + } + + public function testLoadClassMetadataAndMerge() + { + $classMetadata = new ClassMetadata('Symfony\Component\Serializer\Tests\Fixtures\GroupDummy'); + $parentClassMetadata = new ClassMetadata('Symfony\Component\Serializer\Tests\Fixtures\GroupDummyParent'); + + $this->loader->loadClassMetadata($parentClassMetadata); + $classMetadata->merge($parentClassMetadata); + + $this->loader->loadClassMetadata($classMetadata); + + $this->assertEquals(TestClassMetadataFactory::createClassMetadata(true), $classMetadata); + } +} diff --git a/vendor/symfony/serializer/Tests/Mapping/Loader/XmlFileLoaderTest.php b/vendor/symfony/serializer/Tests/Mapping/Loader/XmlFileLoaderTest.php new file mode 100644 index 0000000..6b468ff --- /dev/null +++ b/vendor/symfony/serializer/Tests/Mapping/Loader/XmlFileLoaderTest.php @@ -0,0 +1,54 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Serializer\Tests\Mapping\Loader; + +use Symfony\Component\Serializer\Mapping\Loader\XmlFileLoader; +use Symfony\Component\Serializer\Mapping\ClassMetadata; +use Symfony\Component\Serializer\Tests\Mapping\TestClassMetadataFactory; + +/** + * @author Kévin Dunglas + */ +class XmlFileLoaderTest extends \PHPUnit_Framework_TestCase +{ + /** + * @var XmlFileLoader + */ + private $loader; + /** + * @var ClassMetadata + */ + private $metadata; + + protected function setUp() + { + $this->loader = new XmlFileLoader(__DIR__.'/../../Fixtures/serialization.xml'); + $this->metadata = new ClassMetadata('Symfony\Component\Serializer\Tests\Fixtures\GroupDummy'); + } + + public function testInterface() + { + $this->assertInstanceOf('Symfony\Component\Serializer\Mapping\Loader\LoaderInterface', $this->loader); + } + + public function testLoadClassMetadataReturnsTrueIfSuccessful() + { + $this->assertTrue($this->loader->loadClassMetadata($this->metadata)); + } + + public function testLoadClassMetadata() + { + $this->loader->loadClassMetadata($this->metadata); + + $this->assertEquals(TestClassMetadataFactory::createXmlCLassMetadata(), $this->metadata); + } +} diff --git a/vendor/symfony/serializer/Tests/Mapping/Loader/YamlFileLoaderTest.php b/vendor/symfony/serializer/Tests/Mapping/Loader/YamlFileLoaderTest.php new file mode 100644 index 0000000..72d146f --- /dev/null +++ b/vendor/symfony/serializer/Tests/Mapping/Loader/YamlFileLoaderTest.php @@ -0,0 +1,69 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Serializer\Tests\Mapping\Loader; + +use Symfony\Component\Serializer\Mapping\Loader\YamlFileLoader; +use Symfony\Component\Serializer\Mapping\ClassMetadata; +use Symfony\Component\Serializer\Tests\Mapping\TestClassMetadataFactory; + +/** + * @author Kévin Dunglas + */ +class YamlFileLoaderTest extends \PHPUnit_Framework_TestCase +{ + /** + * @var YamlFileLoader + */ + private $loader; + /** + * @var ClassMetadata + */ + private $metadata; + + protected function setUp() + { + $this->loader = new YamlFileLoader(__DIR__.'/../../Fixtures/serialization.yml'); + $this->metadata = new ClassMetadata('Symfony\Component\Serializer\Tests\Fixtures\GroupDummy'); + } + + public function testInterface() + { + $this->assertInstanceOf('Symfony\Component\Serializer\Mapping\Loader\LoaderInterface', $this->loader); + } + + public function testLoadClassMetadataReturnsTrueIfSuccessful() + { + $this->assertTrue($this->loader->loadClassMetadata($this->metadata)); + } + + public function testLoadClassMetadataReturnsFalseWhenEmpty() + { + $loader = new YamlFileLoader(__DIR__.'/../../Fixtures/empty-mapping.yml'); + $this->assertFalse($loader->loadClassMetadata($this->metadata)); + } + + /** + * @expectedException \Symfony\Component\Serializer\Exception\MappingException + */ + public function testLoadClassMetadataReturnsThrowsInvalidMapping() + { + $loader = new YamlFileLoader(__DIR__.'/../../Fixtures/invalid-mapping.yml'); + $loader->loadClassMetadata($this->metadata); + } + + public function testLoadClassMetadata() + { + $this->loader->loadClassMetadata($this->metadata); + + $this->assertEquals(TestClassMetadataFactory::createXmlCLassMetadata(), $this->metadata); + } +} diff --git a/vendor/symfony/serializer/Tests/Mapping/TestClassMetadataFactory.php b/vendor/symfony/serializer/Tests/Mapping/TestClassMetadataFactory.php new file mode 100644 index 0000000..f435d36 --- /dev/null +++ b/vendor/symfony/serializer/Tests/Mapping/TestClassMetadataFactory.php @@ -0,0 +1,82 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Serializer\Tests\Mapping; + +use Symfony\Component\Serializer\Mapping\AttributeMetadata; +use Symfony\Component\Serializer\Mapping\ClassMetadata; + +/** + * @author Kévin Dunglas + */ +class TestClassMetadataFactory +{ + public static function createClassMetadata($withParent = false, $withInterface = false) + { + $expected = new ClassMetadata('Symfony\Component\Serializer\Tests\Fixtures\GroupDummy'); + + $foo = new AttributeMetadata('foo'); + $foo->addGroup('a'); + $expected->addAttributeMetadata($foo); + + $bar = new AttributeMetadata('bar'); + $bar->addGroup('b'); + $bar->addGroup('c'); + $bar->addGroup('name_converter'); + $expected->addAttributeMetadata($bar); + + $fooBar = new AttributeMetadata('fooBar'); + $fooBar->addGroup('a'); + $fooBar->addGroup('b'); + $fooBar->addGroup('name_converter'); + $expected->addAttributeMetadata($fooBar); + + $symfony = new AttributeMetadata('symfony'); + $expected->addAttributeMetadata($symfony); + + if ($withParent) { + $kevin = new AttributeMetadata('kevin'); + $kevin->addGroup('a'); + $expected->addAttributeMetadata($kevin); + + $coopTilleuls = new AttributeMetadata('coopTilleuls'); + $coopTilleuls->addGroup('a'); + $coopTilleuls->addGroup('b'); + $expected->addAttributeMetadata($coopTilleuls); + } + + if ($withInterface) { + $symfony->addGroup('a'); + $symfony->addGroup('name_converter'); + } + + // load reflection class so that the comparison passes + $expected->getReflectionClass(); + + return $expected; + } + + public static function createXmlCLassMetadata() + { + $expected = new ClassMetadata('Symfony\Component\Serializer\Tests\Fixtures\GroupDummy'); + + $foo = new AttributeMetadata('foo'); + $foo->addGroup('group1'); + $foo->addGroup('group2'); + $expected->addAttributeMetadata($foo); + + $bar = new AttributeMetadata('bar'); + $bar->addGroup('group2'); + $expected->addAttributeMetadata($bar); + + return $expected; + } +} diff --git a/vendor/symfony/serializer/Tests/NameConverter/CamelCaseToSnakeCaseNameConverterTest.php b/vendor/symfony/serializer/Tests/NameConverter/CamelCaseToSnakeCaseNameConverterTest.php new file mode 100644 index 0000000..2d57017 --- /dev/null +++ b/vendor/symfony/serializer/Tests/NameConverter/CamelCaseToSnakeCaseNameConverterTest.php @@ -0,0 +1,53 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Serializer\Tests\NameConverter; + +use Symfony\Component\Serializer\NameConverter\CamelCaseToSnakeCaseNameConverter; + +/** + * @author Kévin Dunglas + */ +class CamelCaseToSnakeCaseNameConverterTest extends \PHPUnit_Framework_TestCase +{ + public function testInterface() + { + $attributeMetadata = new CamelCaseToSnakeCaseNameConverter(); + $this->assertInstanceOf('Symfony\Component\Serializer\NameConverter\NameConverterInterface', $attributeMetadata); + } + + /** + * @dataProvider attributeProvider + */ + public function testNormalize($underscored, $lowerCamelCased) + { + $nameConverter = new CamelCaseToSnakeCaseNameConverter(); + $this->assertEquals($nameConverter->normalize($lowerCamelCased), $underscored); + } + + /** + * @dataProvider attributeProvider + */ + public function testDenormalize($underscored, $lowerCamelCased) + { + $nameConverter = new CamelCaseToSnakeCaseNameConverter(); + $this->assertEquals($nameConverter->denormalize($underscored), $lowerCamelCased); + } + + public function attributeProvider() + { + return array( + array('coop_tilleuls', 'coopTilleuls'), + array('_kevin_dunglas', '_kevinDunglas'), + array('this_is_a_test', 'thisIsATest'), + ); + } +} diff --git a/vendor/symfony/serializer/Tests/Normalizer/CustomNormalizerTest.php b/vendor/symfony/serializer/Tests/Normalizer/CustomNormalizerTest.php new file mode 100644 index 0000000..86ae003 --- /dev/null +++ b/vendor/symfony/serializer/Tests/Normalizer/CustomNormalizerTest.php @@ -0,0 +1,69 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Serializer\Tests\Normalizer; + +use Symfony\Component\Serializer\Tests\Fixtures\ScalarDummy; +use Symfony\Component\Serializer\Normalizer\CustomNormalizer; +use Symfony\Component\Serializer\Serializer; + +class CustomNormalizerTest extends \PHPUnit_Framework_TestCase +{ + /** + * @var CustomNormalizer + */ + private $normalizer; + + protected function setUp() + { + $this->normalizer = new CustomNormalizer(); + $this->normalizer->setSerializer(new Serializer()); + } + + public function testInterface() + { + $this->assertInstanceOf('Symfony\Component\Serializer\Normalizer\NormalizerInterface', $this->normalizer); + $this->assertInstanceOf('Symfony\Component\Serializer\Normalizer\DenormalizerInterface', $this->normalizer); + } + + public function testSerialize() + { + $obj = new ScalarDummy(); + $obj->foo = 'foo'; + $obj->xmlFoo = 'xml'; + $this->assertEquals('foo', $this->normalizer->normalize($obj, 'json')); + $this->assertEquals('xml', $this->normalizer->normalize($obj, 'xml')); + } + + public function testDeserialize() + { + $obj = $this->normalizer->denormalize('foo', get_class(new ScalarDummy()), 'xml'); + $this->assertEquals('foo', $obj->xmlFoo); + $this->assertNull($obj->foo); + + $obj = $this->normalizer->denormalize('foo', get_class(new ScalarDummy()), 'json'); + $this->assertEquals('foo', $obj->foo); + $this->assertNull($obj->xmlFoo); + } + + public function testSupportsNormalization() + { + $this->assertTrue($this->normalizer->supportsNormalization(new ScalarDummy())); + $this->assertFalse($this->normalizer->supportsNormalization(new \stdClass())); + } + + public function testSupportsDenormalization() + { + $this->assertTrue($this->normalizer->supportsDenormalization(array(), 'Symfony\Component\Serializer\Tests\Fixtures\ScalarDummy')); + $this->assertFalse($this->normalizer->supportsDenormalization(array(), 'stdClass')); + $this->assertTrue($this->normalizer->supportsDenormalization(array(), 'Symfony\Component\Serializer\Tests\Fixtures\DenormalizableDummy')); + } +} diff --git a/vendor/symfony/serializer/Tests/Normalizer/GetSetMethodNormalizerTest.php b/vendor/symfony/serializer/Tests/Normalizer/GetSetMethodNormalizerTest.php new file mode 100644 index 0000000..5336962 --- /dev/null +++ b/vendor/symfony/serializer/Tests/Normalizer/GetSetMethodNormalizerTest.php @@ -0,0 +1,799 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Serializer\Tests\Normalizer; + +use Doctrine\Common\Annotations\AnnotationReader; +use Symfony\Component\Serializer\NameConverter\CamelCaseToSnakeCaseNameConverter; +use Symfony\Component\Serializer\Normalizer\GetSetMethodNormalizer; +use Symfony\Component\Serializer\Serializer; +use Symfony\Component\Serializer\SerializerInterface; +use Symfony\Component\Serializer\Normalizer\NormalizerInterface; +use Symfony\Component\Serializer\Tests\Fixtures\CircularReferenceDummy; +use Symfony\Component\Serializer\Tests\Fixtures\SiblingHolder; +use Symfony\Component\Serializer\Mapping\Loader\AnnotationLoader; +use Symfony\Component\Serializer\Mapping\Factory\ClassMetadataFactory; +use Symfony\Component\Serializer\Tests\Fixtures\GroupDummy; + +class GetSetMethodNormalizerTest extends \PHPUnit_Framework_TestCase +{ + /** + * @var GetSetMethodNormalizer + */ + private $normalizer; + /** + * @var SerializerInterface + */ + private $serializer; + + protected function setUp() + { + $this->serializer = $this->getMock(__NAMESPACE__.'\SerializerNormalizer'); + $this->normalizer = new GetSetMethodNormalizer(); + $this->normalizer->setSerializer($this->serializer); + } + + public function testInterface() + { + $this->assertInstanceOf('Symfony\Component\Serializer\Normalizer\NormalizerInterface', $this->normalizer); + $this->assertInstanceOf('Symfony\Component\Serializer\Normalizer\DenormalizerInterface', $this->normalizer); + } + + public function testNormalize() + { + $obj = new GetSetDummy(); + $object = new \stdClass(); + $obj->setFoo('foo'); + $obj->setBar('bar'); + $obj->setBaz(true); + $obj->setCamelCase('camelcase'); + $obj->setObject($object); + + $this->serializer + ->expects($this->once()) + ->method('normalize') + ->with($object, 'any') + ->will($this->returnValue('string_object')) + ; + + $this->assertEquals( + array( + 'foo' => 'foo', + 'bar' => 'bar', + 'baz' => true, + 'fooBar' => 'foobar', + 'camelCase' => 'camelcase', + 'object' => 'string_object', + ), + $this->normalizer->normalize($obj, 'any') + ); + } + + public function testDenormalize() + { + $obj = $this->normalizer->denormalize( + array('foo' => 'foo', 'bar' => 'bar', 'baz' => true, 'fooBar' => 'foobar'), + __NAMESPACE__.'\GetSetDummy', + 'any' + ); + $this->assertEquals('foo', $obj->getFoo()); + $this->assertEquals('bar', $obj->getBar()); + $this->assertTrue($obj->isBaz()); + } + + public function testDenormalizeWithObject() + { + $data = new \stdClass(); + $data->foo = 'foo'; + $data->bar = 'bar'; + $data->fooBar = 'foobar'; + $obj = $this->normalizer->denormalize($data, __NAMESPACE__.'\GetSetDummy', 'any'); + $this->assertEquals('foo', $obj->getFoo()); + $this->assertEquals('bar', $obj->getBar()); + } + + /** + * @group legacy + */ + public function testLegacyDenormalizeOnCamelCaseFormat() + { + $this->normalizer->setCamelizedAttributes(array('camel_case')); + $obj = $this->normalizer->denormalize( + array('camel_case' => 'camelCase'), + __NAMESPACE__.'\GetSetDummy' + ); + + $this->assertEquals('camelCase', $obj->getCamelCase()); + } + + public function testNameConverterSupport() + { + $this->normalizer = new GetSetMethodNormalizer(null, new CamelCaseToSnakeCaseNameConverter()); + $obj = $this->normalizer->denormalize( + array('camel_case' => 'camelCase'), + __NAMESPACE__.'\GetSetDummy' + ); + $this->assertEquals('camelCase', $obj->getCamelCase()); + } + + public function testDenormalizeNull() + { + $this->assertEquals(new GetSetDummy(), $this->normalizer->denormalize(null, __NAMESPACE__.'\GetSetDummy')); + } + + /** + * @group legacy + */ + public function testLegacyCamelizedAttributesNormalize() + { + $obj = new GetCamelizedDummy('dunglas.fr'); + $obj->setFooBar('les-tilleuls.coop'); + $obj->setBar_foo('lostinthesupermarket.fr'); + + $this->normalizer->setCamelizedAttributes(array('kevin_dunglas')); + $this->assertEquals($this->normalizer->normalize($obj), array( + 'kevin_dunglas' => 'dunglas.fr', + 'fooBar' => 'les-tilleuls.coop', + 'bar_foo' => 'lostinthesupermarket.fr', + )); + + $this->normalizer->setCamelizedAttributes(array('foo_bar')); + $this->assertEquals($this->normalizer->normalize($obj), array( + 'kevinDunglas' => 'dunglas.fr', + 'foo_bar' => 'les-tilleuls.coop', + 'bar_foo' => 'lostinthesupermarket.fr', + )); + } + + /** + * @group legacy + */ + public function testLegacyCamelizedAttributesDenormalize() + { + $obj = new GetCamelizedDummy('dunglas.fr'); + $obj->setFooBar('les-tilleuls.coop'); + $obj->setBar_foo('lostinthesupermarket.fr'); + + $this->normalizer->setCamelizedAttributes(array('kevin_dunglas')); + $this->assertEquals($this->normalizer->denormalize(array( + 'kevin_dunglas' => 'dunglas.fr', + 'fooBar' => 'les-tilleuls.coop', + 'bar_foo' => 'lostinthesupermarket.fr', + ), __NAMESPACE__.'\GetCamelizedDummy'), $obj); + + $this->normalizer->setCamelizedAttributes(array('foo_bar')); + $this->assertEquals($this->normalizer->denormalize(array( + 'kevinDunglas' => 'dunglas.fr', + 'foo_bar' => 'les-tilleuls.coop', + 'bar_foo' => 'lostinthesupermarket.fr', + ), __NAMESPACE__.'\GetCamelizedDummy'), $obj); + } + + public function testConstructorDenormalize() + { + $obj = $this->normalizer->denormalize( + array('foo' => 'foo', 'bar' => 'bar', 'baz' => true, 'fooBar' => 'foobar'), + __NAMESPACE__.'\GetConstructorDummy', 'any'); + $this->assertEquals('foo', $obj->getFoo()); + $this->assertEquals('bar', $obj->getBar()); + $this->assertTrue($obj->isBaz()); + } + + public function testConstructorDenormalizeWithNullArgument() + { + $obj = $this->normalizer->denormalize( + array('foo' => 'foo', 'bar' => null, 'baz' => true), + __NAMESPACE__.'\GetConstructorDummy', 'any'); + $this->assertEquals('foo', $obj->getFoo()); + $this->assertNull($obj->getBar()); + $this->assertTrue($obj->isBaz()); + } + + public function testConstructorDenormalizeWithMissingOptionalArgument() + { + $obj = $this->normalizer->denormalize( + array('foo' => 'test', 'baz' => array(1, 2, 3)), + __NAMESPACE__.'\GetConstructorOptionalArgsDummy', 'any'); + $this->assertEquals('test', $obj->getFoo()); + $this->assertEquals(array(), $obj->getBar()); + $this->assertEquals(array(1, 2, 3), $obj->getBaz()); + } + + public function testConstructorDenormalizeWithOptionalDefaultArgument() + { + if (PHP_VERSION_ID <= 50316) { + $this->markTestSkipped('See https://bugs.php.net/62715'); + } + $obj = $this->normalizer->denormalize( + array('bar' => 'test'), + __NAMESPACE__.'\GetConstructorArgsWithDefaultValueDummy', 'any'); + $this->assertEquals(array(), $obj->getFoo()); + $this->assertEquals('test', $obj->getBar()); + } + + /** + * @requires PHP 5.6 + */ + public function testConstructorDenormalizeWithVariadicArgument() + { + $obj = $this->normalizer->denormalize( + array('foo' => array(1, 2, 3)), + 'Symfony\Component\Serializer\Tests\Fixtures\VariadicConstructorArgsDummy', 'any'); + $this->assertEquals(array(1, 2, 3), $obj->getFoo()); + } + + /** + * @requires PHP 5.6 + */ + public function testConstructorDenormalizeWithMissingVariadicArgument() + { + $obj = $this->normalizer->denormalize( + array(), + 'Symfony\Component\Serializer\Tests\Fixtures\VariadicConstructorArgsDummy', 'any'); + $this->assertEquals(array(), $obj->getFoo()); + } + + public function testConstructorWithObjectDenormalize() + { + $data = new \stdClass(); + $data->foo = 'foo'; + $data->bar = 'bar'; + $data->baz = true; + $data->fooBar = 'foobar'; + $obj = $this->normalizer->denormalize($data, __NAMESPACE__.'\GetConstructorDummy', 'any'); + $this->assertEquals('foo', $obj->getFoo()); + $this->assertEquals('bar', $obj->getBar()); + } + + public function testConstructorWArgWithPrivateMutator() + { + $obj = $this->normalizer->denormalize(array('foo' => 'bar'), __NAMESPACE__.'\ObjectConstructorArgsWithPrivateMutatorDummy', 'any'); + $this->assertEquals('bar', $obj->getFoo()); + } + + public function testGroupsNormalize() + { + $classMetadataFactory = new ClassMetadataFactory(new AnnotationLoader(new AnnotationReader())); + $this->normalizer = new GetSetMethodNormalizer($classMetadataFactory); + $this->normalizer->setSerializer($this->serializer); + + $obj = new GroupDummy(); + $obj->setFoo('foo'); + $obj->setBar('bar'); + $obj->setFooBar('fooBar'); + $obj->setSymfony('symfony'); + $obj->setKevin('kevin'); + $obj->setCoopTilleuls('coopTilleuls'); + + $this->assertEquals(array( + 'bar' => 'bar', + ), $this->normalizer->normalize($obj, null, array('groups' => array('c')))); + + $this->assertEquals(array( + 'symfony' => 'symfony', + 'foo' => 'foo', + 'fooBar' => 'fooBar', + 'bar' => 'bar', + 'kevin' => 'kevin', + 'coopTilleuls' => 'coopTilleuls', + ), $this->normalizer->normalize($obj, null, array('groups' => array('a', 'c')))); + } + + public function testGroupsDenormalize() + { + $classMetadataFactory = new ClassMetadataFactory(new AnnotationLoader(new AnnotationReader())); + $this->normalizer = new GetSetMethodNormalizer($classMetadataFactory); + $this->normalizer->setSerializer($this->serializer); + + $obj = new GroupDummy(); + $obj->setFoo('foo'); + + $toNormalize = array('foo' => 'foo', 'bar' => 'bar'); + + $normalized = $this->normalizer->denormalize( + $toNormalize, + 'Symfony\Component\Serializer\Tests\Fixtures\GroupDummy', + null, + array('groups' => array('a')) + ); + $this->assertEquals($obj, $normalized); + + $obj->setBar('bar'); + + $normalized = $this->normalizer->denormalize( + $toNormalize, + 'Symfony\Component\Serializer\Tests\Fixtures\GroupDummy', + null, + array('groups' => array('a', 'b')) + ); + $this->assertEquals($obj, $normalized); + } + + public function testGroupsNormalizeWithNameConverter() + { + $classMetadataFactory = new ClassMetadataFactory(new AnnotationLoader(new AnnotationReader())); + $this->normalizer = new GetSetMethodNormalizer($classMetadataFactory, new CamelCaseToSnakeCaseNameConverter()); + $this->normalizer->setSerializer($this->serializer); + + $obj = new GroupDummy(); + $obj->setFooBar('@dunglas'); + $obj->setSymfony('@coopTilleuls'); + $obj->setCoopTilleuls('les-tilleuls.coop'); + + $this->assertEquals( + array( + 'bar' => null, + 'foo_bar' => '@dunglas', + 'symfony' => '@coopTilleuls', + ), + $this->normalizer->normalize($obj, null, array('groups' => array('name_converter'))) + ); + } + + public function testGroupsDenormalizeWithNameConverter() + { + $classMetadataFactory = new ClassMetadataFactory(new AnnotationLoader(new AnnotationReader())); + $this->normalizer = new GetSetMethodNormalizer($classMetadataFactory, new CamelCaseToSnakeCaseNameConverter()); + $this->normalizer->setSerializer($this->serializer); + + $obj = new GroupDummy(); + $obj->setFooBar('@dunglas'); + $obj->setSymfony('@coopTilleuls'); + + $this->assertEquals( + $obj, + $this->normalizer->denormalize(array( + 'bar' => null, + 'foo_bar' => '@dunglas', + 'symfony' => '@coopTilleuls', + 'coop_tilleuls' => 'les-tilleuls.coop', + ), 'Symfony\Component\Serializer\Tests\Fixtures\GroupDummy', null, array('groups' => array('name_converter'))) + ); + } + + /** + * @dataProvider provideCallbacks + */ + public function testCallbacks($callbacks, $value, $result, $message) + { + $this->normalizer->setCallbacks($callbacks); + + $obj = new GetConstructorDummy('', $value, true); + + $this->assertEquals( + $result, + $this->normalizer->normalize($obj, 'any'), + $message + ); + } + + /** + * @expectedException \InvalidArgumentException + */ + public function testUncallableCallbacks() + { + $this->normalizer->setCallbacks(array('bar' => null)); + + $obj = new GetConstructorDummy('baz', 'quux', true); + + $this->normalizer->normalize($obj, 'any'); + } + + public function testIgnoredAttributes() + { + $this->normalizer->setIgnoredAttributes(array('foo', 'bar', 'baz', 'camelCase', 'object')); + + $obj = new GetSetDummy(); + $obj->setFoo('foo'); + $obj->setBar('bar'); + $obj->setBaz(true); + + $this->assertEquals( + array('fooBar' => 'foobar'), + $this->normalizer->normalize($obj, 'any') + ); + } + + public function provideCallbacks() + { + return array( + array( + array( + 'bar' => function ($bar) { + return 'baz'; + }, + ), + 'baz', + array('foo' => '', 'bar' => 'baz', 'baz' => true), + 'Change a string', + ), + array( + array( + 'bar' => function ($bar) { + return; + }, + ), + 'baz', + array('foo' => '', 'bar' => null, 'baz' => true), + 'Null an item', + ), + array( + array( + 'bar' => function ($bar) { + return $bar->format('d-m-Y H:i:s'); + }, + ), + new \DateTime('2011-09-10 06:30:00'), + array('foo' => '', 'bar' => '10-09-2011 06:30:00', 'baz' => true), + 'Format a date', + ), + array( + array( + 'bar' => function ($bars) { + $foos = ''; + foreach ($bars as $bar) { + $foos .= $bar->getFoo(); + } + + return $foos; + }, + ), + array(new GetConstructorDummy('baz', '', false), new GetConstructorDummy('quux', '', false)), + array('foo' => '', 'bar' => 'bazquux', 'baz' => true), + 'Collect a property', + ), + array( + array( + 'bar' => function ($bars) { + return count($bars); + }, + ), + array(new GetConstructorDummy('baz', '', false), new GetConstructorDummy('quux', '', false)), + array('foo' => '', 'bar' => 2, 'baz' => true), + 'Count a property', + ), + ); + } + + /** + * @expectedException \Symfony\Component\Serializer\Exception\LogicException + * @expectedExceptionMessage Cannot normalize attribute "object" because injected serializer is not a normalizer + */ + public function testUnableToNormalizeObjectAttribute() + { + $serializer = $this->getMock('Symfony\Component\Serializer\SerializerInterface'); + $this->normalizer->setSerializer($serializer); + + $obj = new GetSetDummy(); + $object = new \stdClass(); + $obj->setObject($object); + + $this->normalizer->normalize($obj, 'any'); + } + + /** + * @expectedException \Symfony\Component\Serializer\Exception\CircularReferenceException + */ + public function testUnableToNormalizeCircularReference() + { + $serializer = new Serializer(array($this->normalizer)); + $this->normalizer->setSerializer($serializer); + $this->normalizer->setCircularReferenceLimit(2); + + $obj = new CircularReferenceDummy(); + + $this->normalizer->normalize($obj); + } + + public function testSiblingReference() + { + $serializer = new Serializer(array($this->normalizer)); + $this->normalizer->setSerializer($serializer); + + $siblingHolder = new SiblingHolder(); + + $expected = array( + 'sibling0' => array('coopTilleuls' => 'Les-Tilleuls.coop'), + 'sibling1' => array('coopTilleuls' => 'Les-Tilleuls.coop'), + 'sibling2' => array('coopTilleuls' => 'Les-Tilleuls.coop'), + ); + $this->assertEquals($expected, $this->normalizer->normalize($siblingHolder)); + } + + public function testCircularReferenceHandler() + { + $serializer = new Serializer(array($this->normalizer)); + $this->normalizer->setSerializer($serializer); + $this->normalizer->setCircularReferenceHandler(function ($obj) { + return get_class($obj); + }); + + $obj = new CircularReferenceDummy(); + + $expected = array('me' => 'Symfony\Component\Serializer\Tests\Fixtures\CircularReferenceDummy'); + $this->assertEquals($expected, $this->normalizer->normalize($obj)); + } + + public function testObjectToPopulate() + { + $dummy = new GetSetDummy(); + $dummy->setFoo('foo'); + + $obj = $this->normalizer->denormalize( + array('bar' => 'bar'), + __NAMESPACE__.'\GetSetDummy', + null, + array('object_to_populate' => $dummy) + ); + + $this->assertEquals($dummy, $obj); + $this->assertEquals('foo', $obj->getFoo()); + $this->assertEquals('bar', $obj->getBar()); + } + + public function testDenormalizeNonExistingAttribute() + { + $this->assertEquals( + new GetSetDummy(), + $this->normalizer->denormalize(array('non_existing' => true), __NAMESPACE__.'\GetSetDummy') + ); + } + + public function testNoTraversableSupport() + { + $this->assertFalse($this->normalizer->supportsNormalization(new \ArrayObject())); + } + + public function testPrivateSetter() + { + $obj = $this->normalizer->denormalize(array('foo' => 'foobar'), __NAMESPACE__.'\ObjectWithPrivateSetterDummy'); + $this->assertEquals('bar', $obj->getFoo()); + } +} + +class GetSetDummy +{ + protected $foo; + private $bar; + private $baz; + protected $camelCase; + protected $object; + + public function getFoo() + { + return $this->foo; + } + + public function setFoo($foo) + { + $this->foo = $foo; + } + + public function getBar() + { + return $this->bar; + } + + public function setBar($bar) + { + $this->bar = $bar; + } + + public function isBaz() + { + return $this->baz; + } + + public function setBaz($baz) + { + $this->baz = $baz; + } + + public function getFooBar() + { + return $this->foo.$this->bar; + } + + public function getCamelCase() + { + return $this->camelCase; + } + + public function setCamelCase($camelCase) + { + $this->camelCase = $camelCase; + } + + public function otherMethod() + { + throw new \RuntimeException('Dummy::otherMethod() should not be called'); + } + + public function setObject($object) + { + $this->object = $object; + } + + public function getObject() + { + return $this->object; + } +} + +class GetConstructorDummy +{ + protected $foo; + private $bar; + private $baz; + + public function __construct($foo, $bar, $baz) + { + $this->foo = $foo; + $this->bar = $bar; + $this->baz = $baz; + } + + public function getFoo() + { + return $this->foo; + } + + public function getBar() + { + return $this->bar; + } + + public function isBaz() + { + return $this->baz; + } + + public function otherMethod() + { + throw new \RuntimeException('Dummy::otherMethod() should not be called'); + } +} + +abstract class SerializerNormalizer implements SerializerInterface, NormalizerInterface +{ +} + +class GetConstructorOptionalArgsDummy +{ + protected $foo; + private $bar; + private $baz; + + public function __construct($foo, $bar = array(), $baz = array()) + { + $this->foo = $foo; + $this->bar = $bar; + $this->baz = $baz; + } + + public function getFoo() + { + return $this->foo; + } + + public function getBar() + { + return $this->bar; + } + + public function getBaz() + { + return $this->baz; + } + + public function otherMethod() + { + throw new \RuntimeException('Dummy::otherMethod() should not be called'); + } +} + +class GetConstructorArgsWithDefaultValueDummy +{ + protected $foo; + protected $bar; + + public function __construct($foo = array(), $bar) + { + $this->foo = $foo; + $this->bar = $bar; + } + + public function getFoo() + { + return $this->foo; + } + + public function getBar() + { + return $this->bar; + } + + public function otherMethod() + { + throw new \RuntimeException('Dummy::otherMethod() should not be called'); + } +} + +class GetCamelizedDummy +{ + private $kevinDunglas; + private $fooBar; + private $bar_foo; + + public function __construct($kevinDunglas = null) + { + $this->kevinDunglas = $kevinDunglas; + } + + public function getKevinDunglas() + { + return $this->kevinDunglas; + } + + public function setFooBar($fooBar) + { + $this->fooBar = $fooBar; + } + + public function getFooBar() + { + return $this->fooBar; + } + + public function setBar_foo($bar_foo) + { + $this->bar_foo = $bar_foo; + } + + public function getBar_foo() + { + return $this->bar_foo; + } +} + +class ObjectConstructorArgsWithPrivateMutatorDummy +{ + private $foo; + + public function __construct($foo) + { + $this->setFoo($foo); + } + + public function getFoo() + { + return $this->foo; + } + + private function setFoo($foo) + { + $this->foo = $foo; + } +} + +class ObjectWithPrivateSetterDummy +{ + private $foo = 'bar'; + + public function getFoo() + { + return $this->foo; + } + + private function setFoo($foo) + { + } +} diff --git a/vendor/symfony/serializer/Tests/Normalizer/ObjectNormalizerTest.php b/vendor/symfony/serializer/Tests/Normalizer/ObjectNormalizerTest.php new file mode 100644 index 0000000..3080c8d --- /dev/null +++ b/vendor/symfony/serializer/Tests/Normalizer/ObjectNormalizerTest.php @@ -0,0 +1,605 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Serializer\Tests\Normalizer; + +use Doctrine\Common\Annotations\AnnotationReader; +use Symfony\Component\Serializer\NameConverter\CamelCaseToSnakeCaseNameConverter; +use Symfony\Component\Serializer\Normalizer\ObjectNormalizer; +use Symfony\Component\Serializer\Serializer; +use Symfony\Component\Serializer\SerializerInterface; +use Symfony\Component\Serializer\Normalizer\NormalizerInterface; +use Symfony\Component\Serializer\Tests\Fixtures\CircularReferenceDummy; +use Symfony\Component\Serializer\Tests\Fixtures\SiblingHolder; +use Symfony\Component\Serializer\Mapping\Loader\AnnotationLoader; +use Symfony\Component\Serializer\Mapping\Factory\ClassMetadataFactory; +use Symfony\Component\Serializer\Tests\Fixtures\GroupDummy; + +/** + * @author Kévin Dunglas + */ +class ObjectNormalizerTest extends \PHPUnit_Framework_TestCase +{ + /** + * @var ObjectNormalizerTest + */ + private $normalizer; + /** + * @var SerializerInterface + */ + private $serializer; + + protected function setUp() + { + $this->serializer = $this->getMock(__NAMESPACE__.'\ObjectSerializerNormalizer'); + $this->normalizer = new ObjectNormalizer(); + $this->normalizer->setSerializer($this->serializer); + } + + public function testNormalize() + { + $obj = new ObjectDummy(); + $object = new \stdClass(); + $obj->setFoo('foo'); + $obj->bar = 'bar'; + $obj->setBaz(true); + $obj->setCamelCase('camelcase'); + $obj->setObject($object); + + $this->serializer + ->expects($this->once()) + ->method('normalize') + ->with($object, 'any') + ->will($this->returnValue('string_object')) + ; + + $this->assertEquals( + array( + 'foo' => 'foo', + 'bar' => 'bar', + 'baz' => true, + 'fooBar' => 'foobar', + 'camelCase' => 'camelcase', + 'object' => 'string_object', + ), + $this->normalizer->normalize($obj, 'any') + ); + } + + public function testDenormalize() + { + $obj = $this->normalizer->denormalize( + array('foo' => 'foo', 'bar' => 'bar', 'baz' => true, 'fooBar' => 'foobar'), + __NAMESPACE__.'\ObjectDummy', + 'any' + ); + $this->assertEquals('foo', $obj->getFoo()); + $this->assertEquals('bar', $obj->bar); + $this->assertTrue($obj->isBaz()); + } + + public function testDenormalizeWithObject() + { + $data = new \stdClass(); + $data->foo = 'foo'; + $data->bar = 'bar'; + $data->fooBar = 'foobar'; + $obj = $this->normalizer->denormalize($data, __NAMESPACE__.'\ObjectDummy', 'any'); + $this->assertEquals('foo', $obj->getFoo()); + $this->assertEquals('bar', $obj->bar); + } + + /** + * @group legacy + */ + public function testLegacyDenormalizeOnCamelCaseFormat() + { + $this->normalizer->setCamelizedAttributes(array('camel_case')); + $obj = $this->normalizer->denormalize( + array('camel_case' => 'camelCase'), + __NAMESPACE__.'\ObjectDummy' + ); + $this->assertEquals('camelCase', $obj->getCamelCase()); + } + + public function testNameConverterSupport() + { + $this->normalizer = new ObjectNormalizer(null, new CamelCaseToSnakeCaseNameConverter()); + $obj = $this->normalizer->denormalize( + array('camel_case' => 'camelCase'), + __NAMESPACE__.'\ObjectDummy' + ); + $this->assertEquals('camelCase', $obj->getCamelCase()); + } + + public function testDenormalizeNull() + { + $this->assertEquals(new ObjectDummy(), $this->normalizer->denormalize(null, __NAMESPACE__.'\ObjectDummy')); + } + + public function testConstructorDenormalize() + { + $obj = $this->normalizer->denormalize( + array('foo' => 'foo', 'bar' => 'bar', 'baz' => true, 'fooBar' => 'foobar'), + __NAMESPACE__.'\ObjectConstructorDummy', 'any'); + $this->assertEquals('foo', $obj->getFoo()); + $this->assertEquals('bar', $obj->bar); + $this->assertTrue($obj->isBaz()); + } + + public function testConstructorDenormalizeWithNullArgument() + { + $obj = $this->normalizer->denormalize( + array('foo' => 'foo', 'bar' => null, 'baz' => true), + __NAMESPACE__.'\ObjectConstructorDummy', 'any'); + $this->assertEquals('foo', $obj->getFoo()); + $this->assertNull($obj->bar); + $this->assertTrue($obj->isBaz()); + } + + public function testConstructorDenormalizeWithMissingOptionalArgument() + { + $obj = $this->normalizer->denormalize( + array('foo' => 'test', 'baz' => array(1, 2, 3)), + __NAMESPACE__.'\ObjectConstructorOptionalArgsDummy', 'any'); + $this->assertEquals('test', $obj->getFoo()); + $this->assertEquals(array(), $obj->bar); + $this->assertEquals(array(1, 2, 3), $obj->getBaz()); + } + + public function testConstructorDenormalizeWithOptionalDefaultArgument() + { + if (PHP_VERSION_ID <= 50316) { + $this->markTestSkipped('See https://bugs.php.net/62715'); + } + $obj = $this->normalizer->denormalize( + array('bar' => 'test'), + __NAMESPACE__.'\ObjectConstructorArgsWithDefaultValueDummy', 'any'); + $this->assertEquals(array(), $obj->getFoo()); + $this->assertEquals('test', $obj->getBar()); + } + + public function testConstructorWithObjectDenormalize() + { + $data = new \stdClass(); + $data->foo = 'foo'; + $data->bar = 'bar'; + $data->baz = true; + $data->fooBar = 'foobar'; + $obj = $this->normalizer->denormalize($data, __NAMESPACE__.'\ObjectConstructorDummy', 'any'); + $this->assertEquals('foo', $obj->getFoo()); + $this->assertEquals('bar', $obj->bar); + } + + public function testGroupsNormalize() + { + $classMetadataFactory = new ClassMetadataFactory(new AnnotationLoader(new AnnotationReader())); + $this->normalizer = new ObjectNormalizer($classMetadataFactory); + $this->normalizer->setSerializer($this->serializer); + + $obj = new GroupDummy(); + $obj->setFoo('foo'); + $obj->setBar('bar'); + $obj->setFooBar('fooBar'); + $obj->setSymfony('symfony'); + $obj->setKevin('kevin'); + $obj->setCoopTilleuls('coopTilleuls'); + + $this->assertEquals(array( + 'bar' => 'bar', + ), $this->normalizer->normalize($obj, null, array('groups' => array('c')))); + + $this->assertEquals(array( + 'symfony' => 'symfony', + 'foo' => 'foo', + 'fooBar' => 'fooBar', + 'bar' => 'bar', + 'kevin' => 'kevin', + 'coopTilleuls' => 'coopTilleuls', + ), $this->normalizer->normalize($obj, null, array('groups' => array('a', 'c')))); + } + + public function testGroupsDenormalize() + { + $classMetadataFactory = new ClassMetadataFactory(new AnnotationLoader(new AnnotationReader())); + $this->normalizer = new ObjectNormalizer($classMetadataFactory); + $this->normalizer->setSerializer($this->serializer); + + $obj = new GroupDummy(); + $obj->setFoo('foo'); + + $toNormalize = array('foo' => 'foo', 'bar' => 'bar'); + + $normalized = $this->normalizer->denormalize( + $toNormalize, + 'Symfony\Component\Serializer\Tests\Fixtures\GroupDummy', + null, + array('groups' => array('a')) + ); + $this->assertEquals($obj, $normalized); + + $obj->setBar('bar'); + + $normalized = $this->normalizer->denormalize( + $toNormalize, + 'Symfony\Component\Serializer\Tests\Fixtures\GroupDummy', + null, + array('groups' => array('a', 'b')) + ); + $this->assertEquals($obj, $normalized); + } + + public function testGroupsNormalizeWithNameConverter() + { + $classMetadataFactory = new ClassMetadataFactory(new AnnotationLoader(new AnnotationReader())); + $this->normalizer = new ObjectNormalizer($classMetadataFactory, new CamelCaseToSnakeCaseNameConverter()); + $this->normalizer->setSerializer($this->serializer); + + $obj = new GroupDummy(); + $obj->setFooBar('@dunglas'); + $obj->setSymfony('@coopTilleuls'); + $obj->setCoopTilleuls('les-tilleuls.coop'); + + $this->assertEquals( + array( + 'bar' => null, + 'foo_bar' => '@dunglas', + 'symfony' => '@coopTilleuls', + ), + $this->normalizer->normalize($obj, null, array('groups' => array('name_converter'))) + ); + } + + public function testGroupsDenormalizeWithNameConverter() + { + $classMetadataFactory = new ClassMetadataFactory(new AnnotationLoader(new AnnotationReader())); + $this->normalizer = new ObjectNormalizer($classMetadataFactory, new CamelCaseToSnakeCaseNameConverter()); + $this->normalizer->setSerializer($this->serializer); + + $obj = new GroupDummy(); + $obj->setFooBar('@dunglas'); + $obj->setSymfony('@coopTilleuls'); + + $this->assertEquals( + $obj, + $this->normalizer->denormalize(array( + 'bar' => null, + 'foo_bar' => '@dunglas', + 'symfony' => '@coopTilleuls', + 'coop_tilleuls' => 'les-tilleuls.coop', + ), 'Symfony\Component\Serializer\Tests\Fixtures\GroupDummy', null, array('groups' => array('name_converter'))) + ); + } + + /** + * @dataProvider provideCallbacks + */ + public function testCallbacks($callbacks, $value, $result, $message) + { + $this->normalizer->setCallbacks($callbacks); + + $obj = new ObjectConstructorDummy('', $value, true); + + $this->assertEquals( + $result, + $this->normalizer->normalize($obj, 'any'), + $message + ); + } + + /** + * @expectedException \InvalidArgumentException + */ + public function testUncallableCallbacks() + { + $this->normalizer->setCallbacks(array('bar' => null)); + + $obj = new ObjectConstructorDummy('baz', 'quux', true); + + $this->normalizer->normalize($obj, 'any'); + } + + public function testIgnoredAttributes() + { + $this->normalizer->setIgnoredAttributes(array('foo', 'bar', 'baz', 'camelCase', 'object')); + + $obj = new ObjectDummy(); + $obj->setFoo('foo'); + $obj->bar = 'bar'; + $obj->setBaz(true); + + $this->assertEquals( + array('fooBar' => 'foobar'), + $this->normalizer->normalize($obj, 'any') + ); + } + + public function provideCallbacks() + { + return array( + array( + array( + 'bar' => function ($bar) { + return 'baz'; + }, + ), + 'baz', + array('foo' => '', 'bar' => 'baz', 'baz' => true), + 'Change a string', + ), + array( + array( + 'bar' => function ($bar) { + return; + }, + ), + 'baz', + array('foo' => '', 'bar' => null, 'baz' => true), + 'Null an item', + ), + array( + array( + 'bar' => function ($bar) { + return $bar->format('d-m-Y H:i:s'); + }, + ), + new \DateTime('2011-09-10 06:30:00'), + array('foo' => '', 'bar' => '10-09-2011 06:30:00', 'baz' => true), + 'Format a date', + ), + array( + array( + 'bar' => function ($bars) { + $foos = ''; + foreach ($bars as $bar) { + $foos .= $bar->getFoo(); + } + + return $foos; + }, + ), + array(new ObjectConstructorDummy('baz', '', false), new ObjectConstructorDummy('quux', '', false)), + array('foo' => '', 'bar' => 'bazquux', 'baz' => true), + 'Collect a property', + ), + array( + array( + 'bar' => function ($bars) { + return count($bars); + }, + ), + array(new ObjectConstructorDummy('baz', '', false), new ObjectConstructorDummy('quux', '', false)), + array('foo' => '', 'bar' => 2, 'baz' => true), + 'Count a property', + ), + ); + } + + /** + * @expectedException \Symfony\Component\Serializer\Exception\LogicException + * @expectedExceptionMessage Cannot normalize attribute "object" because injected serializer is not a normalizer + */ + public function testUnableToNormalizeObjectAttribute() + { + $serializer = $this->getMock('Symfony\Component\Serializer\SerializerInterface'); + $this->normalizer->setSerializer($serializer); + + $obj = new ObjectDummy(); + $object = new \stdClass(); + $obj->setObject($object); + + $this->normalizer->normalize($obj, 'any'); + } + + /** + * @expectedException \Symfony\Component\Serializer\Exception\CircularReferenceException + */ + public function testUnableToNormalizeCircularReference() + { + $serializer = new Serializer(array($this->normalizer)); + $this->normalizer->setSerializer($serializer); + $this->normalizer->setCircularReferenceLimit(2); + + $obj = new CircularReferenceDummy(); + + $this->normalizer->normalize($obj); + } + + public function testSiblingReference() + { + $serializer = new Serializer(array($this->normalizer)); + $this->normalizer->setSerializer($serializer); + + $siblingHolder = new SiblingHolder(); + + $expected = array( + 'sibling0' => array('coopTilleuls' => 'Les-Tilleuls.coop'), + 'sibling1' => array('coopTilleuls' => 'Les-Tilleuls.coop'), + 'sibling2' => array('coopTilleuls' => 'Les-Tilleuls.coop'), + ); + $this->assertEquals($expected, $this->normalizer->normalize($siblingHolder)); + } + + public function testCircularReferenceHandler() + { + $serializer = new Serializer(array($this->normalizer)); + $this->normalizer->setSerializer($serializer); + $this->normalizer->setCircularReferenceHandler(function ($obj) { + return get_class($obj); + }); + + $obj = new CircularReferenceDummy(); + + $expected = array('me' => 'Symfony\Component\Serializer\Tests\Fixtures\CircularReferenceDummy'); + $this->assertEquals($expected, $this->normalizer->normalize($obj)); + } + + public function testDenormalizeNonExistingAttribute() + { + $this->assertEquals( + new ObjectDummy(), + $this->normalizer->denormalize(array('non_existing' => true), __NAMESPACE__.'\ObjectDummy') + ); + } + + public function testNoTraversableSupport() + { + $this->assertFalse($this->normalizer->supportsNormalization(new \ArrayObject())); + } +} + +class ObjectDummy +{ + protected $foo; + public $bar; + private $baz; + protected $camelCase; + protected $object; + + public function getFoo() + { + return $this->foo; + } + + public function setFoo($foo) + { + $this->foo = $foo; + } + + public function isBaz() + { + return $this->baz; + } + + public function setBaz($baz) + { + $this->baz = $baz; + } + + public function getFooBar() + { + return $this->foo.$this->bar; + } + + public function getCamelCase() + { + return $this->camelCase; + } + + public function setCamelCase($camelCase) + { + $this->camelCase = $camelCase; + } + + public function otherMethod() + { + throw new \RuntimeException('Dummy::otherMethod() should not be called'); + } + + public function setObject($object) + { + $this->object = $object; + } + + public function getObject() + { + return $this->object; + } +} + +class ObjectConstructorDummy +{ + protected $foo; + public $bar; + private $baz; + + public function __construct($foo, $bar, $baz) + { + $this->foo = $foo; + $this->bar = $bar; + $this->baz = $baz; + } + + public function getFoo() + { + return $this->foo; + } + + public function isBaz() + { + return $this->baz; + } + + public function otherMethod() + { + throw new \RuntimeException('Dummy::otherMethod() should not be called'); + } +} + +abstract class ObjectSerializerNormalizer implements SerializerInterface, NormalizerInterface +{ +} + +class ObjectConstructorOptionalArgsDummy +{ + protected $foo; + public $bar; + private $baz; + + public function __construct($foo, $bar = array(), $baz = array()) + { + $this->foo = $foo; + $this->bar = $bar; + $this->baz = $baz; + } + + public function getFoo() + { + return $this->foo; + } + + public function getBaz() + { + return $this->baz; + } + + public function otherMethod() + { + throw new \RuntimeException('Dummy::otherMethod() should not be called'); + } +} + +class ObjectConstructorArgsWithDefaultValueDummy +{ + protected $foo; + protected $bar; + + public function __construct($foo = array(), $bar) + { + $this->foo = $foo; + $this->bar = $bar; + } + + public function getFoo() + { + return $this->foo; + } + + public function getBar() + { + return $this->bar; + } + + public function otherMethod() + { + throw new \RuntimeException('Dummy::otherMethod() should not be called'); + } +} diff --git a/vendor/symfony/serializer/Tests/Normalizer/PropertyNormalizerTest.php b/vendor/symfony/serializer/Tests/Normalizer/PropertyNormalizerTest.php new file mode 100644 index 0000000..62e6d5d --- /dev/null +++ b/vendor/symfony/serializer/Tests/Normalizer/PropertyNormalizerTest.php @@ -0,0 +1,493 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Serializer\Tests\Normalizer; + +use Doctrine\Common\Annotations\AnnotationReader; +use Symfony\Component\Serializer\Mapping\Factory\ClassMetadataFactory; +use Symfony\Component\Serializer\Mapping\Loader\AnnotationLoader; +use Symfony\Component\Serializer\NameConverter\CamelCaseToSnakeCaseNameConverter; +use Symfony\Component\Serializer\Normalizer\PropertyNormalizer; +use Symfony\Component\Serializer\Serializer; +use Symfony\Component\Serializer\SerializerInterface; +use Symfony\Component\Serializer\Tests\Fixtures\GroupDummy; +use Symfony\Component\Serializer\Tests\Fixtures\PropertyCircularReferenceDummy; +use Symfony\Component\Serializer\Tests\Fixtures\PropertySiblingHolder; + +class PropertyNormalizerTest extends \PHPUnit_Framework_TestCase +{ + /** + * @var PropertyNormalizer + */ + private $normalizer; + /** + * @var SerializerInterface + */ + private $serializer; + + protected function setUp() + { + $this->serializer = $this->getMock('Symfony\Component\Serializer\SerializerInterface'); + $this->normalizer = new PropertyNormalizer(); + $this->normalizer->setSerializer($this->serializer); + } + + public function testNormalize() + { + $obj = new PropertyDummy(); + $obj->foo = 'foo'; + $obj->setBar('bar'); + $obj->setCamelCase('camelcase'); + $this->assertEquals( + array('foo' => 'foo', 'bar' => 'bar', 'camelCase' => 'camelcase'), + $this->normalizer->normalize($obj, 'any') + ); + } + + public function testDenormalize() + { + $obj = $this->normalizer->denormalize( + array('foo' => 'foo', 'bar' => 'bar'), + __NAMESPACE__.'\PropertyDummy', + 'any' + ); + $this->assertEquals('foo', $obj->foo); + $this->assertEquals('bar', $obj->getBar()); + } + + /** + * @group legacy + */ + public function testLegacyDenormalizeOnCamelCaseFormat() + { + $this->normalizer->setCamelizedAttributes(array('camel_case')); + $obj = $this->normalizer->denormalize( + array('camel_case' => 'value'), + __NAMESPACE__.'\PropertyDummy' + ); + $this->assertEquals('value', $obj->getCamelCase()); + } + + /** + * @group legacy + */ + public function testLegacyCamelizedAttributesNormalize() + { + $obj = new PropertyCamelizedDummy('dunglas.fr'); + $obj->fooBar = 'les-tilleuls.coop'; + $obj->bar_foo = 'lostinthesupermarket.fr'; + + $this->normalizer->setCamelizedAttributes(array('kevin_dunglas')); + $this->assertEquals($this->normalizer->normalize($obj), array( + 'kevin_dunglas' => 'dunglas.fr', + 'fooBar' => 'les-tilleuls.coop', + 'bar_foo' => 'lostinthesupermarket.fr', + )); + + $this->normalizer->setCamelizedAttributes(array('foo_bar')); + $this->assertEquals($this->normalizer->normalize($obj), array( + 'kevinDunglas' => 'dunglas.fr', + 'foo_bar' => 'les-tilleuls.coop', + 'bar_foo' => 'lostinthesupermarket.fr', + )); + } + + /** + * @group legacy + */ + public function testLegacyCamelizedAttributesDenormalize() + { + $obj = new PropertyCamelizedDummy('dunglas.fr'); + $obj->fooBar = 'les-tilleuls.coop'; + $obj->bar_foo = 'lostinthesupermarket.fr'; + + $this->normalizer->setCamelizedAttributes(array('kevin_dunglas')); + $this->assertEquals($this->normalizer->denormalize(array( + 'kevin_dunglas' => 'dunglas.fr', + 'fooBar' => 'les-tilleuls.coop', + 'bar_foo' => 'lostinthesupermarket.fr', + ), __NAMESPACE__.'\PropertyCamelizedDummy'), $obj); + + $this->normalizer->setCamelizedAttributes(array('foo_bar')); + $this->assertEquals($this->normalizer->denormalize(array( + 'kevinDunglas' => 'dunglas.fr', + 'foo_bar' => 'les-tilleuls.coop', + 'bar_foo' => 'lostinthesupermarket.fr', + ), __NAMESPACE__.'\PropertyCamelizedDummy'), $obj); + } + + public function testNameConverterSupport() + { + $this->normalizer = new PropertyNormalizer(null, new CamelCaseToSnakeCaseNameConverter()); + $obj = $this->normalizer->denormalize( + array('camel_case' => 'camelCase'), + __NAMESPACE__.'\PropertyDummy' + ); + $this->assertEquals('camelCase', $obj->getCamelCase()); + } + + public function testConstructorDenormalize() + { + $obj = $this->normalizer->denormalize( + array('foo' => 'foo', 'bar' => 'bar'), + __NAMESPACE__.'\PropertyConstructorDummy', + 'any' + ); + $this->assertEquals('foo', $obj->getFoo()); + $this->assertEquals('bar', $obj->getBar()); + } + + public function testConstructorDenormalizeWithNullArgument() + { + $obj = $this->normalizer->denormalize( + array('foo' => null, 'bar' => 'bar'), + __NAMESPACE__.'\PropertyConstructorDummy', ' + any' + ); + $this->assertNull($obj->getFoo()); + $this->assertEquals('bar', $obj->getBar()); + } + + /** + * @dataProvider provideCallbacks + */ + public function testCallbacks($callbacks, $value, $result, $message) + { + $this->normalizer->setCallbacks($callbacks); + + $obj = new PropertyConstructorDummy('', $value); + + $this->assertEquals( + $result, + $this->normalizer->normalize($obj, 'any'), + $message + ); + } + + /** + * @expectedException \InvalidArgumentException + */ + public function testUncallableCallbacks() + { + $this->normalizer->setCallbacks(array('bar' => null)); + + $obj = new PropertyConstructorDummy('baz', 'quux'); + + $this->normalizer->normalize($obj, 'any'); + } + + public function testIgnoredAttributes() + { + $this->normalizer->setIgnoredAttributes(array('foo', 'bar', 'camelCase')); + + $obj = new PropertyDummy(); + $obj->foo = 'foo'; + $obj->setBar('bar'); + + $this->assertEquals( + array(), + $this->normalizer->normalize($obj, 'any') + ); + } + + public function testGroupsNormalize() + { + $classMetadataFactory = new ClassMetadataFactory(new AnnotationLoader(new AnnotationReader())); + $this->normalizer = new PropertyNormalizer($classMetadataFactory); + $this->normalizer->setSerializer($this->serializer); + + $obj = new GroupDummy(); + $obj->setFoo('foo'); + $obj->setBar('bar'); + $obj->setFooBar('fooBar'); + $obj->setSymfony('symfony'); + $obj->setKevin('kevin'); + $obj->setCoopTilleuls('coopTilleuls'); + + $this->assertEquals(array( + 'bar' => 'bar', + ), $this->normalizer->normalize($obj, null, array('groups' => array('c')))); + + // The PropertyNormalizer is not able to hydrate properties from parent classes + $this->assertEquals(array( + 'symfony' => 'symfony', + 'foo' => 'foo', + 'fooBar' => 'fooBar', + 'bar' => 'bar', + ), $this->normalizer->normalize($obj, null, array('groups' => array('a', 'c')))); + } + + public function testGroupsDenormalize() + { + $classMetadataFactory = new ClassMetadataFactory(new AnnotationLoader(new AnnotationReader())); + $this->normalizer = new PropertyNormalizer($classMetadataFactory); + $this->normalizer->setSerializer($this->serializer); + + $obj = new GroupDummy(); + $obj->setFoo('foo'); + + $toNormalize = array('foo' => 'foo', 'bar' => 'bar'); + + $normalized = $this->normalizer->denormalize( + $toNormalize, + 'Symfony\Component\Serializer\Tests\Fixtures\GroupDummy', + null, + array('groups' => array('a')) + ); + $this->assertEquals($obj, $normalized); + + $obj->setBar('bar'); + + $normalized = $this->normalizer->denormalize( + $toNormalize, + 'Symfony\Component\Serializer\Tests\Fixtures\GroupDummy', + null, + array('groups' => array('a', 'b')) + ); + $this->assertEquals($obj, $normalized); + } + + public function testGroupsNormalizeWithNameConverter() + { + $classMetadataFactory = new ClassMetadataFactory(new AnnotationLoader(new AnnotationReader())); + $this->normalizer = new PropertyNormalizer($classMetadataFactory, new CamelCaseToSnakeCaseNameConverter()); + $this->normalizer->setSerializer($this->serializer); + + $obj = new GroupDummy(); + $obj->setFooBar('@dunglas'); + $obj->setSymfony('@coopTilleuls'); + $obj->setCoopTilleuls('les-tilleuls.coop'); + + $this->assertEquals( + array( + 'bar' => null, + 'foo_bar' => '@dunglas', + 'symfony' => '@coopTilleuls', + ), + $this->normalizer->normalize($obj, null, array('groups' => array('name_converter'))) + ); + } + + public function testGroupsDenormalizeWithNameConverter() + { + $classMetadataFactory = new ClassMetadataFactory(new AnnotationLoader(new AnnotationReader())); + $this->normalizer = new PropertyNormalizer($classMetadataFactory, new CamelCaseToSnakeCaseNameConverter()); + $this->normalizer->setSerializer($this->serializer); + + $obj = new GroupDummy(); + $obj->setFooBar('@dunglas'); + $obj->setSymfony('@coopTilleuls'); + + $this->assertEquals( + $obj, + $this->normalizer->denormalize(array( + 'bar' => null, + 'foo_bar' => '@dunglas', + 'symfony' => '@coopTilleuls', + 'coop_tilleuls' => 'les-tilleuls.coop', + ), 'Symfony\Component\Serializer\Tests\Fixtures\GroupDummy', null, array('groups' => array('name_converter'))) + ); + } + + public function provideCallbacks() + { + return array( + array( + array( + 'bar' => function ($bar) { + return 'baz'; + }, + ), + 'baz', + array('foo' => '', 'bar' => 'baz'), + 'Change a string', + ), + array( + array( + 'bar' => function ($bar) { + return; + }, + ), + 'baz', + array('foo' => '', 'bar' => null), + 'Null an item', + ), + array( + array( + 'bar' => function ($bar) { + return $bar->format('d-m-Y H:i:s'); + }, + ), + new \DateTime('2011-09-10 06:30:00'), + array('foo' => '', 'bar' => '10-09-2011 06:30:00'), + 'Format a date', + ), + array( + array( + 'bar' => function ($bars) { + $foos = ''; + foreach ($bars as $bar) { + $foos .= $bar->getFoo(); + } + + return $foos; + }, + ), + array(new PropertyConstructorDummy('baz', ''), new PropertyConstructorDummy('quux', '')), + array('foo' => '', 'bar' => 'bazquux'), + 'Collect a property', + ), + array( + array( + 'bar' => function ($bars) { + return count($bars); + }, + ), + array(new PropertyConstructorDummy('baz', ''), new PropertyConstructorDummy('quux', '')), + array('foo' => '', 'bar' => 2), + 'Count a property', + ), + ); + } + + /** + * @expectedException \Symfony\Component\Serializer\Exception\CircularReferenceException + */ + public function testUnableToNormalizeCircularReference() + { + $serializer = new Serializer(array($this->normalizer)); + $this->normalizer->setSerializer($serializer); + $this->normalizer->setCircularReferenceLimit(2); + + $obj = new PropertyCircularReferenceDummy(); + + $this->normalizer->normalize($obj); + } + + public function testSiblingReference() + { + $serializer = new Serializer(array($this->normalizer)); + $this->normalizer->setSerializer($serializer); + + $siblingHolder = new PropertySiblingHolder(); + + $expected = array( + 'sibling0' => array('coopTilleuls' => 'Les-Tilleuls.coop'), + 'sibling1' => array('coopTilleuls' => 'Les-Tilleuls.coop'), + 'sibling2' => array('coopTilleuls' => 'Les-Tilleuls.coop'), + ); + $this->assertEquals($expected, $this->normalizer->normalize($siblingHolder)); + } + + public function testCircularReferenceHandler() + { + $serializer = new Serializer(array($this->normalizer)); + $this->normalizer->setSerializer($serializer); + $this->normalizer->setCircularReferenceHandler(function ($obj) { + return get_class($obj); + }); + + $obj = new PropertyCircularReferenceDummy(); + + $expected = array('me' => 'Symfony\Component\Serializer\Tests\Fixtures\PropertyCircularReferenceDummy'); + $this->assertEquals($expected, $this->normalizer->normalize($obj)); + } + + public function testDenormalizeNonExistingAttribute() + { + $this->assertEquals( + new PropertyDummy(), + $this->normalizer->denormalize(array('non_existing' => true), __NAMESPACE__.'\PropertyDummy') + ); + } + + /** + * @expectedException \Symfony\Component\Serializer\Exception\LogicException + * @expectedExceptionMessage Cannot normalize attribute "bar" because injected serializer is not a normalizer + */ + public function testUnableToNormalizeObjectAttribute() + { + $serializer = $this->getMock('Symfony\Component\Serializer\SerializerInterface'); + $this->normalizer->setSerializer($serializer); + + $obj = new PropertyDummy(); + $object = new \stdClass(); + $obj->setBar($object); + + $this->normalizer->normalize($obj, 'any'); + } + + public function testNoTraversableSupport() + { + $this->assertFalse($this->normalizer->supportsNormalization(new \ArrayObject())); + } +} + +class PropertyDummy +{ + public $foo; + private $bar; + protected $camelCase; + + public function getBar() + { + return $this->bar; + } + + public function setBar($bar) + { + $this->bar = $bar; + } + + public function getCamelCase() + { + return $this->camelCase; + } + + public function setCamelCase($camelCase) + { + $this->camelCase = $camelCase; + } +} + +class PropertyConstructorDummy +{ + protected $foo; + private $bar; + + public function __construct($foo, $bar) + { + $this->foo = $foo; + $this->bar = $bar; + } + + public function getFoo() + { + return $this->foo; + } + + public function getBar() + { + return $this->bar; + } +} + +class PropertyCamelizedDummy +{ + private $kevinDunglas; + public $fooBar; + public $bar_foo; + + public function __construct($kevinDunglas = null) + { + $this->kevinDunglas = $kevinDunglas; + } +} diff --git a/vendor/symfony/serializer/Tests/Normalizer/TestDenormalizer.php b/vendor/symfony/serializer/Tests/Normalizer/TestDenormalizer.php new file mode 100644 index 0000000..7525d5c --- /dev/null +++ b/vendor/symfony/serializer/Tests/Normalizer/TestDenormalizer.php @@ -0,0 +1,37 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Serializer\Tests\Normalizer; + +use Symfony\Component\Serializer\Normalizer\DenormalizerInterface; + +/** + * Provides a test Normalizer which only implements the DenormalizerInterface. + * + * @author Lin Clark + */ +class TestDenormalizer implements DenormalizerInterface +{ + /** + * {@inheritdoc} + */ + public function denormalize($data, $class, $format = null, array $context = array()) + { + } + + /** + * {@inheritdoc} + */ + public function supportsDenormalization($data, $type, $format = null) + { + return true; + } +} diff --git a/vendor/symfony/serializer/Tests/Normalizer/TestNormalizer.php b/vendor/symfony/serializer/Tests/Normalizer/TestNormalizer.php new file mode 100644 index 0000000..4b29e8f --- /dev/null +++ b/vendor/symfony/serializer/Tests/Normalizer/TestNormalizer.php @@ -0,0 +1,37 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Serializer\Tests\Normalizer; + +use Symfony\Component\Serializer\Normalizer\NormalizerInterface; + +/** + * Provides a test Normalizer which only implements the NormalizerInterface. + * + * @author Lin Clark + */ +class TestNormalizer implements NormalizerInterface +{ + /** + * {@inheritdoc} + */ + public function normalize($object, $format = null, array $context = array()) + { + } + + /** + * {@inheritdoc} + */ + public function supportsNormalization($data, $format = null) + { + return true; + } +} diff --git a/vendor/symfony/serializer/Tests/SerializerTest.php b/vendor/symfony/serializer/Tests/SerializerTest.php new file mode 100644 index 0000000..68f70fc --- /dev/null +++ b/vendor/symfony/serializer/Tests/SerializerTest.php @@ -0,0 +1,267 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Serializer\Tests; + +use Symfony\Component\Serializer\Serializer; +use Symfony\Component\Serializer\Encoder\JsonEncoder; +use Symfony\Component\Serializer\Normalizer\GetSetMethodNormalizer; +use Symfony\Component\Serializer\Normalizer\CustomNormalizer; +use Symfony\Component\Serializer\Tests\Fixtures\TraversableDummy; +use Symfony\Component\Serializer\Tests\Fixtures\NormalizableTraversableDummy; +use Symfony\Component\Serializer\Tests\Normalizer\TestNormalizer; +use Symfony\Component\Serializer\Tests\Normalizer\TestDenormalizer; + +class SerializerTest extends \PHPUnit_Framework_TestCase +{ + public function testInterface() + { + $serializer = new Serializer(); + + $this->assertInstanceOf('Symfony\Component\Serializer\SerializerInterface', $serializer); + $this->assertInstanceOf('Symfony\Component\Serializer\Normalizer\NormalizerInterface', $serializer); + $this->assertInstanceOf('Symfony\Component\Serializer\Normalizer\DenormalizerInterface', $serializer); + $this->assertInstanceOf('Symfony\Component\Serializer\Encoder\EncoderInterface', $serializer); + $this->assertInstanceOf('Symfony\Component\Serializer\Encoder\DecoderInterface', $serializer); + } + + /** + * @expectedException \Symfony\Component\Serializer\Exception\UnexpectedValueException + */ + public function testNormalizeNoMatch() + { + $this->serializer = new Serializer(array($this->getMock('Symfony\Component\Serializer\Normalizer\CustomNormalizer'))); + $this->serializer->normalize(new \stdClass(), 'xml'); + } + + public function testNormalizeTraversable() + { + $this->serializer = new Serializer(array(), array('json' => new JsonEncoder())); + $result = $this->serializer->serialize(new TraversableDummy(), 'json'); + $this->assertEquals('{"foo":"foo","bar":"bar"}', $result); + } + + public function testNormalizeGivesPriorityToInterfaceOverTraversable() + { + $this->serializer = new Serializer(array(new CustomNormalizer()), array('json' => new JsonEncoder())); + $result = $this->serializer->serialize(new NormalizableTraversableDummy(), 'json'); + $this->assertEquals('{"foo":"normalizedFoo","bar":"normalizedBar"}', $result); + } + + /** + * @expectedException \Symfony\Component\Serializer\Exception\UnexpectedValueException + */ + public function testNormalizeOnDenormalizer() + { + $this->serializer = new Serializer(array(new TestDenormalizer()), array()); + $this->assertTrue($this->serializer->normalize(new \stdClass(), 'json')); + } + + /** + * @expectedException \Symfony\Component\Serializer\Exception\UnexpectedValueException + */ + public function testDenormalizeNoMatch() + { + $this->serializer = new Serializer(array($this->getMock('Symfony\Component\Serializer\Normalizer\CustomNormalizer'))); + $this->serializer->denormalize('foo', 'stdClass'); + } + + /** + * @expectedException \Symfony\Component\Serializer\Exception\UnexpectedValueException + */ + public function testDenormalizeOnNormalizer() + { + $this->serializer = new Serializer(array(new TestNormalizer()), array()); + $data = array('title' => 'foo', 'numbers' => array(5, 3)); + $this->assertTrue($this->serializer->denormalize(json_encode($data), 'stdClass', 'json')); + } + + public function testCustomNormalizerCanNormalizeCollectionsAndScalar() + { + $this->serializer = new Serializer(array(new TestNormalizer()), array()); + $this->assertNull($this->serializer->normalize(array('a', 'b'))); + $this->assertNull($this->serializer->normalize(new \ArrayObject(array('c', 'd')))); + $this->assertNull($this->serializer->normalize(array())); + $this->assertNull($this->serializer->normalize('test')); + } + + public function testSerialize() + { + $this->serializer = new Serializer(array(new GetSetMethodNormalizer()), array('json' => new JsonEncoder())); + $data = array('title' => 'foo', 'numbers' => array(5, 3)); + $result = $this->serializer->serialize(Model::fromArray($data), 'json'); + $this->assertEquals(json_encode($data), $result); + } + + public function testSerializeScalar() + { + $this->serializer = new Serializer(array(), array('json' => new JsonEncoder())); + $result = $this->serializer->serialize('foo', 'json'); + $this->assertEquals('"foo"', $result); + } + + public function testSerializeArrayOfScalars() + { + $this->serializer = new Serializer(array(), array('json' => new JsonEncoder())); + $data = array('foo', array(5, 3)); + $result = $this->serializer->serialize($data, 'json'); + $this->assertEquals(json_encode($data), $result); + } + + /** + * @expectedException \Symfony\Component\Serializer\Exception\UnexpectedValueException + */ + public function testSerializeNoEncoder() + { + $this->serializer = new Serializer(array(), array()); + $data = array('title' => 'foo', 'numbers' => array(5, 3)); + $this->serializer->serialize($data, 'json'); + } + + /** + * @expectedException \Symfony\Component\Serializer\Exception\LogicException + */ + public function testSerializeNoNormalizer() + { + $this->serializer = new Serializer(array(), array('json' => new JsonEncoder())); + $data = array('title' => 'foo', 'numbers' => array(5, 3)); + $this->serializer->serialize(Model::fromArray($data), 'json'); + } + + public function testDeserialize() + { + $this->serializer = new Serializer(array(new GetSetMethodNormalizer()), array('json' => new JsonEncoder())); + $data = array('title' => 'foo', 'numbers' => array(5, 3)); + $result = $this->serializer->deserialize(json_encode($data), '\Symfony\Component\Serializer\Tests\Model', 'json'); + $this->assertEquals($data, $result->toArray()); + } + + public function testDeserializeUseCache() + { + $this->serializer = new Serializer(array(new GetSetMethodNormalizer()), array('json' => new JsonEncoder())); + $data = array('title' => 'foo', 'numbers' => array(5, 3)); + $this->serializer->deserialize(json_encode($data), '\Symfony\Component\Serializer\Tests\Model', 'json'); + $data = array('title' => 'bar', 'numbers' => array(2, 8)); + $result = $this->serializer->deserialize(json_encode($data), '\Symfony\Component\Serializer\Tests\Model', 'json'); + $this->assertEquals($data, $result->toArray()); + } + + /** + * @expectedException \Symfony\Component\Serializer\Exception\LogicException + */ + public function testDeserializeNoNormalizer() + { + $this->serializer = new Serializer(array(), array('json' => new JsonEncoder())); + $data = array('title' => 'foo', 'numbers' => array(5, 3)); + $this->serializer->deserialize(json_encode($data), '\Symfony\Component\Serializer\Tests\Model', 'json'); + } + + /** + * @expectedException \Symfony\Component\Serializer\Exception\UnexpectedValueException + */ + public function testDeserializeWrongNormalizer() + { + $this->serializer = new Serializer(array(new CustomNormalizer()), array('json' => new JsonEncoder())); + $data = array('title' => 'foo', 'numbers' => array(5, 3)); + $this->serializer->deserialize(json_encode($data), '\Symfony\Component\Serializer\Tests\Model', 'json'); + } + + /** + * @expectedException \Symfony\Component\Serializer\Exception\UnexpectedValueException + */ + public function testDeserializeNoEncoder() + { + $this->serializer = new Serializer(array(), array()); + $data = array('title' => 'foo', 'numbers' => array(5, 3)); + $this->serializer->deserialize(json_encode($data), '\Symfony\Component\Serializer\Tests\Model', 'json'); + } + + public function testDeserializeSupported() + { + $this->serializer = new Serializer(array(new GetSetMethodNormalizer()), array()); + $data = array('title' => 'foo', 'numbers' => array(5, 3)); + $this->assertTrue($this->serializer->supportsDenormalization(json_encode($data), '\Symfony\Component\Serializer\Tests\Model', 'json')); + } + + public function testDeserializeNotSupported() + { + $this->serializer = new Serializer(array(new GetSetMethodNormalizer()), array()); + $data = array('title' => 'foo', 'numbers' => array(5, 3)); + $this->assertFalse($this->serializer->supportsDenormalization(json_encode($data), 'stdClass', 'json')); + } + + public function testDeserializeNotSupportedMissing() + { + $this->serializer = new Serializer(array(), array()); + $data = array('title' => 'foo', 'numbers' => array(5, 3)); + $this->assertFalse($this->serializer->supportsDenormalization(json_encode($data), '\Symfony\Component\Serializer\Tests\Model', 'json')); + } + + public function testEncode() + { + $this->serializer = new Serializer(array(), array('json' => new JsonEncoder())); + $data = array('foo', array(5, 3)); + $result = $this->serializer->encode($data, 'json'); + $this->assertEquals(json_encode($data), $result); + } + + public function testDecode() + { + $this->serializer = new Serializer(array(), array('json' => new JsonEncoder())); + $data = array('foo', array(5, 3)); + $result = $this->serializer->decode(json_encode($data), 'json'); + $this->assertEquals($data, $result); + } +} + +class Model +{ + private $title; + private $numbers; + + public static function fromArray($array) + { + $model = new self(); + if (isset($array['title'])) { + $model->setTitle($array['title']); + } + if (isset($array['numbers'])) { + $model->setNumbers($array['numbers']); + } + + return $model; + } + + public function getTitle() + { + return $this->title; + } + + public function setTitle($title) + { + $this->title = $title; + } + + public function getNumbers() + { + return $this->numbers; + } + + public function setNumbers($numbers) + { + $this->numbers = $numbers; + } + + public function toArray() + { + return array('title' => $this->title, 'numbers' => $this->numbers); + } +} diff --git a/vendor/symfony/serializer/composer.json b/vendor/symfony/serializer/composer.json new file mode 100644 index 0000000..bfd3d9c --- /dev/null +++ b/vendor/symfony/serializer/composer.json @@ -0,0 +1,45 @@ +{ + "name": "symfony/serializer", + "type": "library", + "description": "Symfony Serializer Component", + "keywords": [], + "homepage": "https://symfony.com", + "license": "MIT", + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "require": { + "php": ">=5.3.9" + }, + "require-dev": { + "symfony/phpunit-bridge": "~2.7", + "symfony/yaml": "~2.0,>=2.0.5", + "symfony/config": "~2.2", + "symfony/property-access": "~2.3", + "doctrine/annotations": "~1.0", + "doctrine/cache": "~1.0" + }, + "suggest": { + "doctrine/annotations": "For using the annotation mapping. You will also need doctrine/cache.", + "doctrine/cache": "For using the default cached annotation reader and metadata cache.", + "symfony/yaml": "For using the default YAML mapping loader.", + "symfony/config": "For using the XML mapping loader.", + "symfony/property-access": "For using the ObjectNormalizer." + }, + "autoload": { + "psr-4": { "Symfony\\Component\\Serializer\\": "" } + }, + "minimum-stability": "dev", + "extra": { + "branch-alias": { + "dev-master": "2.7-dev" + } + } +} diff --git a/vendor/symfony/serializer/phpunit.xml.dist b/vendor/symfony/serializer/phpunit.xml.dist new file mode 100644 index 0000000..279e1eb --- /dev/null +++ b/vendor/symfony/serializer/phpunit.xml.dist @@ -0,0 +1,28 @@ + + + + + + + + + + ./Tests/ + + + + + + ./ + + ./vendor + ./Tests + + + +