summaryrefslogtreecommitdiff
path: root/vendor
diff options
context:
space:
mode:
Diffstat (limited to 'vendor')
-rw-r--r--vendor/README.md30
-rw-r--r--vendor/autoload.php2
-rw-r--r--vendor/composer.json35
-rw-r--r--vendor/composer.lock1064
-rw-r--r--vendor/composer/LICENSE21
-rw-r--r--vendor/composer/autoload_classmap.php509
-rw-r--r--vendor/composer/autoload_files.php10
-rw-r--r--vendor/composer/autoload_namespaces.php7
-rw-r--r--vendor/composer/autoload_psr4.php9
-rw-r--r--vendor/composer/autoload_real.php14
-rw-r--r--vendor/composer/installed.json949
-rw-r--r--vendor/composer/semver/CHANGELOG.md28
-rw-r--r--vendor/composer/semver/LICENSE19
-rw-r--r--vendor/composer/semver/README.md70
-rw-r--r--vendor/composer/semver/composer.json57
-rw-r--r--vendor/composer/semver/src/Comparator.php111
-rw-r--r--vendor/composer/semver/src/Constraint/AbstractConstraint.php65
-rw-r--r--vendor/composer/semver/src/Constraint/Constraint.php181
-rw-r--r--vendor/composer/semver/src/Constraint/ConstraintInterface.php37
-rw-r--r--vendor/composer/semver/src/Constraint/EmptyConstraint.php59
-rw-r--r--vendor/composer/semver/src/Constraint/MultiConstraint.php96
-rw-r--r--vendor/composer/semver/src/Semver.php127
-rw-r--r--vendor/composer/semver/src/VersionParser.php520
-rw-r--r--vendor/firebase/php-jwt/Authentication/JWT.php334
-rw-r--r--vendor/firebase/php-jwt/Exceptions/BeforeValidException.php6
-rw-r--r--vendor/firebase/php-jwt/Exceptions/ExpiredException.php6
-rw-r--r--vendor/firebase/php-jwt/Exceptions/SignatureInvalidException.php6
-rw-r--r--vendor/firebase/php-jwt/LICENSE30
-rw-r--r--vendor/firebase/php-jwt/README.md93
-rw-r--r--vendor/firebase/php-jwt/composer.json25
-rw-r--r--vendor/firebase/php-jwt/package.xml77
-rw-r--r--vendor/firebase/php-jwt/phpunit.xml.dist19
-rw-r--r--vendor/firebase/php-jwt/run-tests.sh38
-rw-r--r--vendor/firebase/php-jwt/tests/JWTTest.php231
-rw-r--r--vendor/firebase/php-jwt/tests/autoload.php.dist17
-rw-r--r--vendor/firebase/php-jwt/tests/bootstrap.php7
-rw-r--r--vendor/kzykhys/pygments/README.md99
-rw-r--r--vendor/kzykhys/pygments/composer.json17
-rw-r--r--vendor/kzykhys/pygments/composer.lock118
-rw-r--r--vendor/kzykhys/pygments/phpunit.xml.dist28
-rw-r--r--vendor/kzykhys/pygments/src/KzykHys/Pygments/Pygments.php200
-rw-r--r--vendor/kzykhys/pygments/test/KzykHys/Pygments/PygmentsTest.php116
-rw-r--r--vendor/kzykhys/pygments/test/KzykHys/Pygments/Resources/css/default.css61
-rw-r--r--vendor/kzykhys/pygments/test/KzykHys/Pygments/Resources/css/default.prefix.css62
-rw-r--r--vendor/kzykhys/pygments/test/KzykHys/Pygments/Resources/example/php.php.in21
-rw-r--r--vendor/kzykhys/pygments/test/KzykHys/Pygments/Resources/example/php.php.linenos.out43
-rw-r--r--vendor/kzykhys/pygments/test/KzykHys/Pygments/Resources/example/php.php.out22
-rw-r--r--vendor/leafo/lessphp/LICENSE660
-rw-r--r--vendor/leafo/lessphp/Makefile7
-rw-r--r--vendor/leafo/lessphp/README.md96
-rw-r--r--vendor/leafo/lessphp/composer.json25
-rw-r--r--vendor/leafo/lessphp/docs/docs.md1400
-rw-r--r--vendor/leafo/lessphp/lessc.inc.php3768
-rw-r--r--vendor/leafo/lessphp/lessify23
-rw-r--r--vendor/leafo/lessphp/lessify.inc.php447
-rw-r--r--vendor/leafo/lessphp/package.sh35
-rw-r--r--vendor/leafo/lessphp/plessc250
-rw-r--r--vendor/leafo/lessphp/tests/ApiTest.php196
-rw-r--r--vendor/leafo/lessphp/tests/ErrorHandlingTest.php81
-rw-r--r--vendor/leafo/lessphp/tests/InputTest.php89
-rw-r--r--vendor/leafo/lessphp/tests/README.md24
-rw-r--r--vendor/leafo/lessphp/tests/bootstrap.sh38
-rw-r--r--vendor/leafo/lessphp/tests/inputs/accessors.less.disable36
-rw-r--r--vendor/leafo/lessphp/tests/inputs/arity.less77
-rw-r--r--vendor/leafo/lessphp/tests/inputs/attributes.less41
-rw-r--r--vendor/leafo/lessphp/tests/inputs/builtins.less96
-rw-r--r--vendor/leafo/lessphp/tests/inputs/colors.less154
-rw-r--r--vendor/leafo/lessphp/tests/inputs/compile_on_mixin.less39
-rw-r--r--vendor/leafo/lessphp/tests/inputs/data-uri.less7
-rw-r--r--vendor/leafo/lessphp/tests/inputs/directives.less28
-rw-r--r--vendor/leafo/lessphp/tests/inputs/escape.less18
-rw-r--r--vendor/leafo/lessphp/tests/inputs/font_family.less28
-rw-r--r--vendor/leafo/lessphp/tests/inputs/guards.less74
-rw-r--r--vendor/leafo/lessphp/tests/inputs/hacks.less6
-rw-r--r--vendor/leafo/lessphp/tests/inputs/hi.less5
-rw-r--r--vendor/leafo/lessphp/tests/inputs/ie.less12
-rw-r--r--vendor/leafo/lessphp/tests/inputs/import.less56
-rw-r--r--vendor/leafo/lessphp/tests/inputs/interpolation.less47
-rw-r--r--vendor/leafo/lessphp/tests/inputs/keyframes.less52
-rw-r--r--vendor/leafo/lessphp/tests/inputs/math.less122
-rw-r--r--vendor/leafo/lessphp/tests/inputs/media.less68
-rw-r--r--vendor/leafo/lessphp/tests/inputs/misc.less100
-rw-r--r--vendor/leafo/lessphp/tests/inputs/mixin_functions.less33
-rw-r--r--vendor/leafo/lessphp/tests/inputs/mixin_merging.less.disable100
-rw-r--r--vendor/leafo/lessphp/tests/inputs/mixins.less197
-rw-r--r--vendor/leafo/lessphp/tests/inputs/nested.less60
-rw-r--r--vendor/leafo/lessphp/tests/inputs/pattern_matching.less157
-rw-r--r--vendor/leafo/lessphp/tests/inputs/scopes.less40
-rw-r--r--vendor/leafo/lessphp/tests/inputs/selector_expressions.less29
-rw-r--r--vendor/leafo/lessphp/tests/inputs/site_demos.less120
-rw-r--r--vendor/leafo/lessphp/tests/inputs/test-imports/a.less6
-rw-r--r--vendor/leafo/lessphp/tests/inputs/test-imports/b.less12
-rw-r--r--vendor/leafo/lessphp/tests/inputs/test-imports/file1.less16
-rw-r--r--vendor/leafo/lessphp/tests/inputs/test-imports/file2.less6
-rw-r--r--vendor/leafo/lessphp/tests/inputs/test-imports/file3.less7
-rw-r--r--vendor/leafo/lessphp/tests/inputs/test-imports/inner/file1.less6
-rw-r--r--vendor/leafo/lessphp/tests/inputs/test-imports/inner/file2.less4
-rw-r--r--vendor/leafo/lessphp/tests/inputs/variables.less44
-rw-r--r--vendor/leafo/lessphp/tests/inputs_lessjs/mixins-args.less205
-rw-r--r--vendor/leafo/lessphp/tests/inputs_lessjs/mixins-named-args.less36
-rw-r--r--vendor/leafo/lessphp/tests/inputs_lessjs/strings.less51
-rw-r--r--vendor/leafo/lessphp/tests/outputs/accessors.css14
-rw-r--r--vendor/leafo/lessphp/tests/outputs/arity.css25
-rw-r--r--vendor/leafo/lessphp/tests/outputs/attributes.css105
-rw-r--r--vendor/leafo/lessphp/tests/outputs/builtins.css61
-rw-r--r--vendor/leafo/lessphp/tests/outputs/colors.css103
-rw-r--r--vendor/leafo/lessphp/tests/outputs/compile_on_mixin.css29
-rw-r--r--vendor/leafo/lessphp/tests/outputs/data-uri.css6
-rw-r--r--vendor/leafo/lessphp/tests/outputs/directives.css27
-rw-r--r--vendor/leafo/lessphp/tests/outputs/escape.css14
-rw-r--r--vendor/leafo/lessphp/tests/outputs/font_family.css17
-rw-r--r--vendor/leafo/lessphp/tests/outputs/guards.css27
-rw-r--r--vendor/leafo/lessphp/tests/outputs/hacks.css4
-rw-r--r--vendor/leafo/lessphp/tests/outputs/hi.css3
-rw-r--r--vendor/leafo/lessphp/tests/outputs/ie.css9
-rw-r--r--vendor/leafo/lessphp/tests/outputs/import.css51
-rw-r--r--vendor/leafo/lessphp/tests/outputs/interpolation.css28
-rw-r--r--vendor/leafo/lessphp/tests/outputs/keyframes.css48
-rw-r--r--vendor/leafo/lessphp/tests/outputs/math.css69
-rw-r--r--vendor/leafo/lessphp/tests/outputs/media.css70
-rw-r--r--vendor/leafo/lessphp/tests/outputs/misc.css68
-rw-r--r--vendor/leafo/lessphp/tests/outputs/mixin_functions.css7
-rw-r--r--vendor/leafo/lessphp/tests/outputs/mixin_merging.css42
-rw-r--r--vendor/leafo/lessphp/tests/outputs/mixins.css92
-rw-r--r--vendor/leafo/lessphp/tests/outputs/nested.css51
-rw-r--r--vendor/leafo/lessphp/tests/outputs/nesting.css6
-rw-r--r--vendor/leafo/lessphp/tests/outputs/pattern_matching.css72
-rw-r--r--vendor/leafo/lessphp/tests/outputs/scopes.css11
-rw-r--r--vendor/leafo/lessphp/tests/outputs/selector_expressions.css25
-rw-r--r--vendor/leafo/lessphp/tests/outputs/site_demos.css76
-rw-r--r--vendor/leafo/lessphp/tests/outputs/variables.css19
-rw-r--r--vendor/leafo/lessphp/tests/outputs_lessjs/mixins-args.css113
-rw-r--r--vendor/leafo/lessphp/tests/outputs_lessjs/mixins-named-args.css27
-rw-r--r--vendor/leafo/lessphp/tests/outputs_lessjs/strings.css40
-rw-r--r--vendor/leafo/lessphp/tests/sort.php57
-rw-r--r--vendor/liuggio/statsd-php-client/CHANGELOG.md17
-rw-r--r--vendor/liuggio/statsd-php-client/README.md152
-rw-r--r--vendor/liuggio/statsd-php-client/Readme.md149
-rw-r--r--vendor/liuggio/statsd-php-client/composer.json2
-rw-r--r--vendor/liuggio/statsd-php-client/phpunit.xml (renamed from vendor/liuggio/statsd-php-client/phpunit.xml.dist)0
-rw-r--r--vendor/liuggio/statsd-php-client/src/Liuggio/StatsdClient/Entity/StatsdData.php28
-rw-r--r--vendor/liuggio/statsd-php-client/src/Liuggio/StatsdClient/Entity/StatsdDataInterface.php6
-rw-r--r--vendor/liuggio/statsd-php-client/src/Liuggio/StatsdClient/Service/StatsdService.php196
-rw-r--r--vendor/liuggio/statsd-php-client/src/Liuggio/StatsdClient/StatsdClient.php8
-rw-r--r--vendor/liuggio/statsd-php-client/tests/Liuggio/StatsdClient/Service/StatsdServiceTest.php86
-rw-r--r--vendor/mediawiki/at-ease/COPYING342
-rw-r--r--vendor/mediawiki/at-ease/README.md59
-rw-r--r--vendor/mediawiki/at-ease/src/Functions.php75
-rw-r--r--vendor/monolog/monolog/.php_cs15
-rw-r--r--vendor/monolog/monolog/CHANGELOG.mdown226
-rw-r--r--vendor/monolog/monolog/LICENSE19
-rw-r--r--vendor/monolog/monolog/README.mdown302
-rw-r--r--vendor/monolog/monolog/composer.json61
-rw-r--r--vendor/monolog/monolog/doc/extending.md76
-rw-r--r--vendor/monolog/monolog/doc/sockets.md37
-rw-r--r--vendor/monolog/monolog/doc/usage.md162
-rw-r--r--vendor/monolog/monolog/phpunit.xml.dist19
-rw-r--r--vendor/monolog/monolog/src/Monolog/ErrorHandler.php208
-rw-r--r--vendor/monolog/monolog/src/Monolog/Formatter/ChromePHPFormatter.php79
-rw-r--r--vendor/monolog/monolog/src/Monolog/Formatter/ElasticaFormatter.php87
-rw-r--r--vendor/monolog/monolog/src/Monolog/Formatter/FlowdockFormatter.php104
-rw-r--r--vendor/monolog/monolog/src/Monolog/Formatter/FormatterInterface.php36
-rw-r--r--vendor/monolog/monolog/src/Monolog/Formatter/GelfMessageFormatter.php111
-rw-r--r--vendor/monolog/monolog/src/Monolog/Formatter/HtmlFormatter.php140
-rw-r--r--vendor/monolog/monolog/src/Monolog/Formatter/JsonFormatter.php116
-rw-r--r--vendor/monolog/monolog/src/Monolog/Formatter/LineFormatter.php159
-rw-r--r--vendor/monolog/monolog/src/Monolog/Formatter/LogglyFormatter.php47
-rw-r--r--vendor/monolog/monolog/src/Monolog/Formatter/LogstashFormatter.php165
-rw-r--r--vendor/monolog/monolog/src/Monolog/Formatter/MongoDBFormatter.php105
-rw-r--r--vendor/monolog/monolog/src/Monolog/Formatter/NormalizerFormatter.php158
-rw-r--r--vendor/monolog/monolog/src/Monolog/Formatter/ScalarFormatter.php48
-rw-r--r--vendor/monolog/monolog/src/Monolog/Formatter/WildfireFormatter.php113
-rw-r--r--vendor/monolog/monolog/src/Monolog/Handler/AbstractHandler.php184
-rw-r--r--vendor/monolog/monolog/src/Monolog/Handler/AbstractProcessingHandler.php66
-rw-r--r--vendor/monolog/monolog/src/Monolog/Handler/AbstractSyslogHandler.php92
-rw-r--r--vendor/monolog/monolog/src/Monolog/Handler/AmqpHandler.php98
-rw-r--r--vendor/monolog/monolog/src/Monolog/Handler/BrowserConsoleHandler.php184
-rw-r--r--vendor/monolog/monolog/src/Monolog/Handler/BufferHandler.php117
-rw-r--r--vendor/monolog/monolog/src/Monolog/Handler/ChromePHPHandler.php204
-rw-r--r--vendor/monolog/monolog/src/Monolog/Handler/CouchDBHandler.php72
-rw-r--r--vendor/monolog/monolog/src/Monolog/Handler/CubeHandler.php151
-rw-r--r--vendor/monolog/monolog/src/Monolog/Handler/DoctrineCouchDBHandler.php45
-rw-r--r--vendor/monolog/monolog/src/Monolog/Handler/DynamoDbHandler.php89
-rw-r--r--vendor/monolog/monolog/src/Monolog/Handler/ElasticSearchHandler.php128
-rw-r--r--vendor/monolog/monolog/src/Monolog/Handler/ErrorLogHandler.php82
-rw-r--r--vendor/monolog/monolog/src/Monolog/Handler/FilterHandler.php140
-rw-r--r--vendor/monolog/monolog/src/Monolog/Handler/FingersCrossed/ActivationStrategyInterface.php28
-rw-r--r--vendor/monolog/monolog/src/Monolog/Handler/FingersCrossed/ChannelLevelActivationStrategy.php59
-rw-r--r--vendor/monolog/monolog/src/Monolog/Handler/FingersCrossed/ErrorLevelActivationStrategy.php34
-rw-r--r--vendor/monolog/monolog/src/Monolog/Handler/FingersCrossedHandler.php153
-rw-r--r--vendor/monolog/monolog/src/Monolog/Handler/FirePHPHandler.php195
-rw-r--r--vendor/monolog/monolog/src/Monolog/Handler/FleepHookHandler.php126
-rw-r--r--vendor/monolog/monolog/src/Monolog/Handler/FlowdockHandler.php103
-rw-r--r--vendor/monolog/monolog/src/Monolog/Handler/GelfHandler.php73
-rw-r--r--vendor/monolog/monolog/src/Monolog/Handler/GroupHandler.php80
-rw-r--r--vendor/monolog/monolog/src/Monolog/Handler/HandlerInterface.php90
-rw-r--r--vendor/monolog/monolog/src/Monolog/Handler/HipChatHandler.php337
-rw-r--r--vendor/monolog/monolog/src/Monolog/Handler/LogEntriesHandler.php55
-rw-r--r--vendor/monolog/monolog/src/Monolog/Handler/LogglyHandler.php106
-rw-r--r--vendor/monolog/monolog/src/Monolog/Handler/MailHandler.php55
-rw-r--r--vendor/monolog/monolog/src/Monolog/Handler/MandrillHandler.php71
-rw-r--r--vendor/monolog/monolog/src/Monolog/Handler/MissingExtensionException.php21
-rw-r--r--vendor/monolog/monolog/src/Monolog/Handler/MongoDBHandler.php55
-rw-r--r--vendor/monolog/monolog/src/Monolog/Handler/NativeMailerHandler.php176
-rw-r--r--vendor/monolog/monolog/src/Monolog/Handler/NewRelicHandler.php198
-rw-r--r--vendor/monolog/monolog/src/Monolog/Handler/NullHandler.php45
-rw-r--r--vendor/monolog/monolog/src/Monolog/Handler/PHPConsoleHandler.php243
-rw-r--r--vendor/monolog/monolog/src/Monolog/Handler/PsrHandler.php56
-rw-r--r--vendor/monolog/monolog/src/Monolog/Handler/PushoverHandler.php185
-rw-r--r--vendor/monolog/monolog/src/Monolog/Handler/RavenHandler.php190
-rw-r--r--vendor/monolog/monolog/src/Monolog/Handler/RedisHandler.php63
-rw-r--r--vendor/monolog/monolog/src/Monolog/Handler/RollbarHandler.php73
-rw-r--r--vendor/monolog/monolog/src/Monolog/Handler/RotatingFileHandler.php153
-rw-r--r--vendor/monolog/monolog/src/Monolog/Handler/SamplingHandler.php82
-rw-r--r--vendor/monolog/monolog/src/Monolog/Handler/SlackHandler.php292
-rw-r--r--vendor/monolog/monolog/src/Monolog/Handler/SocketHandler.php284
-rw-r--r--vendor/monolog/monolog/src/Monolog/Handler/StreamHandler.php104
-rw-r--r--vendor/monolog/monolog/src/Monolog/Handler/SwiftMailerHandler.php87
-rw-r--r--vendor/monolog/monolog/src/Monolog/Handler/SyslogHandler.php67
-rw-r--r--vendor/monolog/monolog/src/Monolog/Handler/SyslogUdp/UdpSocket.php46
-rw-r--r--vendor/monolog/monolog/src/Monolog/Handler/SyslogUdpHandler.php80
-rw-r--r--vendor/monolog/monolog/src/Monolog/Handler/TestHandler.php195
-rw-r--r--vendor/monolog/monolog/src/Monolog/Handler/WhatFailureGroupHandler.php57
-rw-r--r--vendor/monolog/monolog/src/Monolog/Handler/ZendMonitorHandler.php95
-rw-r--r--vendor/monolog/monolog/src/Monolog/Logger.php629
-rw-r--r--vendor/monolog/monolog/src/Monolog/Processor/GitProcessor.php64
-rw-r--r--vendor/monolog/monolog/src/Monolog/Processor/IntrospectionProcessor.php82
-rw-r--r--vendor/monolog/monolog/src/Monolog/Processor/MemoryPeakUsageProcessor.php40
-rw-r--r--vendor/monolog/monolog/src/Monolog/Processor/MemoryProcessor.php63
-rw-r--r--vendor/monolog/monolog/src/Monolog/Processor/MemoryUsageProcessor.php40
-rw-r--r--vendor/monolog/monolog/src/Monolog/Processor/ProcessIdProcessor.php31
-rw-r--r--vendor/monolog/monolog/src/Monolog/Processor/PsrLogMessageProcessor.php48
-rw-r--r--vendor/monolog/monolog/src/Monolog/Processor/TagProcessor.php34
-rw-r--r--vendor/monolog/monolog/src/Monolog/Processor/UidProcessor.php38
-rw-r--r--vendor/monolog/monolog/src/Monolog/Processor/WebProcessor.php105
-rw-r--r--vendor/monolog/monolog/src/Monolog/Registry.php134
-rw-r--r--vendor/monolog/monolog/tests/Monolog/ErrorHandlerTest.php31
-rw-r--r--vendor/monolog/monolog/tests/Monolog/Formatter/ChromePHPFormatterTest.php158
-rw-r--r--vendor/monolog/monolog/tests/Monolog/Formatter/ElasticaFormatterTest.php79
-rw-r--r--vendor/monolog/monolog/tests/Monolog/Formatter/FlowdockFormatterTest.php55
-rw-r--r--vendor/monolog/monolog/tests/Monolog/Formatter/GelfMessageFormatterTest.php204
-rw-r--r--vendor/monolog/monolog/tests/Monolog/Formatter/JsonFormatterTest.php78
-rw-r--r--vendor/monolog/monolog/tests/Monolog/Formatter/LineFormatterTest.php208
-rw-r--r--vendor/monolog/monolog/tests/Monolog/Formatter/LogglyFormatterTest.php40
-rw-r--r--vendor/monolog/monolog/tests/Monolog/Formatter/LogstashFormatterTest.php289
-rw-r--r--vendor/monolog/monolog/tests/Monolog/Formatter/MongoDBFormatterTest.php253
-rw-r--r--vendor/monolog/monolog/tests/Monolog/Formatter/NormalizerFormatterTest.php254
-rw-r--r--vendor/monolog/monolog/tests/Monolog/Formatter/ScalarFormatterTest.php98
-rw-r--r--vendor/monolog/monolog/tests/Monolog/Formatter/WildfireFormatterTest.php142
-rw-r--r--vendor/monolog/monolog/tests/Monolog/Handler/AbstractHandlerTest.php115
-rw-r--r--vendor/monolog/monolog/tests/Monolog/Handler/AbstractProcessingHandlerTest.php80
-rw-r--r--vendor/monolog/monolog/tests/Monolog/Handler/AmqpHandlerTest.php136
-rw-r--r--vendor/monolog/monolog/tests/Monolog/Handler/BrowserConsoleHandlerTest.php130
-rw-r--r--vendor/monolog/monolog/tests/Monolog/Handler/BufferHandlerTest.php158
-rw-r--r--vendor/monolog/monolog/tests/Monolog/Handler/ChromePHPHandlerTest.php141
-rw-r--r--vendor/monolog/monolog/tests/Monolog/Handler/CouchDBHandlerTest.php31
-rw-r--r--vendor/monolog/monolog/tests/Monolog/Handler/DoctrineCouchDBHandlerTest.php52
-rw-r--r--vendor/monolog/monolog/tests/Monolog/Handler/DynamoDbHandlerTest.php73
-rw-r--r--vendor/monolog/monolog/tests/Monolog/Handler/ElasticSearchHandlerTest.php239
-rw-r--r--vendor/monolog/monolog/tests/Monolog/Handler/ErrorLogHandlerTest.php66
-rw-r--r--vendor/monolog/monolog/tests/Monolog/Handler/FilterHandlerTest.php170
-rw-r--r--vendor/monolog/monolog/tests/Monolog/Handler/FingersCrossedHandlerTest.php255
-rw-r--r--vendor/monolog/monolog/tests/Monolog/Handler/FirePHPHandlerTest.php96
-rw-r--r--vendor/monolog/monolog/tests/Monolog/Handler/FleepHookHandlerTest.php85
-rw-r--r--vendor/monolog/monolog/tests/Monolog/Handler/FlowdockHandlerTest.php88
-rw-r--r--vendor/monolog/monolog/tests/Monolog/Handler/GelfHandlerLegacyTest.php95
-rw-r--r--vendor/monolog/monolog/tests/Monolog/Handler/GelfHandlerTest.php117
-rw-r--r--vendor/monolog/monolog/tests/Monolog/Handler/GelfMockMessagePublisher.php25
-rw-r--r--vendor/monolog/monolog/tests/Monolog/Handler/GroupHandlerTest.php89
-rw-r--r--vendor/monolog/monolog/tests/Monolog/Handler/HipChatHandlerTest.php240
-rw-r--r--vendor/monolog/monolog/tests/Monolog/Handler/LogEntriesHandlerTest.php84
-rw-r--r--vendor/monolog/monolog/tests/Monolog/Handler/MailHandlerTest.php75
-rw-r--r--vendor/monolog/monolog/tests/Monolog/Handler/MockRavenClient.php27
-rw-r--r--vendor/monolog/monolog/tests/Monolog/Handler/MongoDBHandlerTest.php65
-rw-r--r--vendor/monolog/monolog/tests/Monolog/Handler/NativeMailerHandlerTest.php61
-rw-r--r--vendor/monolog/monolog/tests/Monolog/Handler/NewRelicHandlerTest.php192
-rw-r--r--vendor/monolog/monolog/tests/Monolog/Handler/NullHandlerTest.php33
-rw-r--r--vendor/monolog/monolog/tests/Monolog/Handler/PHPConsoleHandlerTest.php271
-rw-r--r--vendor/monolog/monolog/tests/Monolog/Handler/PsrHandlerTest.php50
-rw-r--r--vendor/monolog/monolog/tests/Monolog/Handler/PushoverHandlerTest.php141
-rw-r--r--vendor/monolog/monolog/tests/Monolog/Handler/RavenHandlerTest.php185
-rw-r--r--vendor/monolog/monolog/tests/Monolog/Handler/RedisHandlerTest.php71
-rw-r--r--vendor/monolog/monolog/tests/Monolog/Handler/RotatingFileHandlerTest.php99
-rw-r--r--vendor/monolog/monolog/tests/Monolog/Handler/SamplingHandlerTest.php33
-rw-r--r--vendor/monolog/monolog/tests/Monolog/Handler/SlackHandlerTest.php133
-rw-r--r--vendor/monolog/monolog/tests/Monolog/Handler/SocketHandlerTest.php282
-rw-r--r--vendor/monolog/monolog/tests/Monolog/Handler/StreamHandlerTest.php118
-rw-r--r--vendor/monolog/monolog/tests/Monolog/Handler/SwiftMailerHandlerTest.php65
-rw-r--r--vendor/monolog/monolog/tests/Monolog/Handler/SyslogHandlerTest.php44
-rw-r--r--vendor/monolog/monolog/tests/Monolog/Handler/SyslogUdpHandlerTest.php49
-rw-r--r--vendor/monolog/monolog/tests/Monolog/Handler/TestHandlerTest.php58
-rw-r--r--vendor/monolog/monolog/tests/Monolog/Handler/UdpSocketTest.php46
-rw-r--r--vendor/monolog/monolog/tests/Monolog/Handler/WhatFailureGroupHandlerTest.php121
-rw-r--r--vendor/monolog/monolog/tests/Monolog/Handler/ZendMonitorHandlerTest.php69
-rw-r--r--vendor/monolog/monolog/tests/Monolog/LoggerTest.php447
-rw-r--r--vendor/monolog/monolog/tests/Monolog/Processor/GitProcessorTest.php29
-rw-r--r--vendor/monolog/monolog/tests/Monolog/Processor/IntrospectionProcessorTest.php123
-rw-r--r--vendor/monolog/monolog/tests/Monolog/Processor/MemoryPeakUsageProcessorTest.php42
-rw-r--r--vendor/monolog/monolog/tests/Monolog/Processor/MemoryUsageProcessorTest.php42
-rw-r--r--vendor/monolog/monolog/tests/Monolog/Processor/ProcessIdProcessorTest.php30
-rw-r--r--vendor/monolog/monolog/tests/Monolog/Processor/PsrLogMessageProcessorTest.php43
-rw-r--r--vendor/monolog/monolog/tests/Monolog/Processor/TagProcessorTest.php29
-rw-r--r--vendor/monolog/monolog/tests/Monolog/Processor/UidProcessorTest.php27
-rw-r--r--vendor/monolog/monolog/tests/Monolog/Processor/WebProcessorTest.php98
-rw-r--r--vendor/monolog/monolog/tests/Monolog/PsrLogCompatTest.php47
-rw-r--r--vendor/monolog/monolog/tests/Monolog/RegistryTest.php63
-rw-r--r--vendor/monolog/monolog/tests/Monolog/TestCase.php58
-rw-r--r--vendor/nmred/kafka-php/LICENSE27
-rw-r--r--vendor/nmred/kafka-php/README.md496
-rw-r--r--vendor/nmred/kafka-php/src/Kafka/Client.php290
-rw-r--r--vendor/nmred/kafka-php/src/Kafka/ClusterMetaData.php53
-rw-r--r--vendor/nmred/kafka-php/src/Kafka/Consumer.php378
-rw-r--r--vendor/nmred/kafka-php/src/Kafka/Exception.php31
-rw-r--r--vendor/nmred/kafka-php/src/Kafka/Exception/NotSupported.php33
-rw-r--r--vendor/nmred/kafka-php/src/Kafka/Exception/OutOfRange.php33
-rw-r--r--vendor/nmred/kafka-php/src/Kafka/Exception/Protocol.php33
-rw-r--r--vendor/nmred/kafka-php/src/Kafka/Exception/Socket.php33
-rw-r--r--vendor/nmred/kafka-php/src/Kafka/Exception/SocketConnect.php33
-rw-r--r--vendor/nmred/kafka-php/src/Kafka/Exception/SocketEOF.php33
-rw-r--r--vendor/nmred/kafka-php/src/Kafka/Exception/SocketTimeout.php33
-rw-r--r--vendor/nmred/kafka-php/src/Kafka/Log.php78
-rw-r--r--vendor/nmred/kafka-php/src/Kafka/MetaDataFromKafka.php200
-rw-r--r--vendor/nmred/kafka-php/src/Kafka/Offset.php305
-rw-r--r--vendor/nmred/kafka-php/src/Kafka/Produce.php337
-rw-r--r--vendor/nmred/kafka-php/src/Kafka/Protocol/Decoder.php430
-rw-r--r--vendor/nmred/kafka-php/src/Kafka/Protocol/Encoder.php652
-rw-r--r--vendor/nmred/kafka-php/src/Kafka/Protocol/Fetch/Helper/CommitOffset.php119
-rw-r--r--vendor/nmred/kafka-php/src/Kafka/Protocol/Fetch/Helper/Consumer.php39
-rw-r--r--vendor/nmred/kafka-php/src/Kafka/Protocol/Fetch/Helper/FreeStream.php117
-rw-r--r--vendor/nmred/kafka-php/src/Kafka/Protocol/Fetch/Helper/Helper.php160
-rw-r--r--vendor/nmred/kafka-php/src/Kafka/Protocol/Fetch/Helper/HelperAbstract.php71
-rw-r--r--vendor/nmred/kafka-php/src/Kafka/Protocol/Fetch/Message.php175
-rw-r--r--vendor/nmred/kafka-php/src/Kafka/Protocol/Fetch/MessageSet.php269
-rw-r--r--vendor/nmred/kafka-php/src/Kafka/Protocol/Fetch/Partition.php375
-rw-r--r--vendor/nmred/kafka-php/src/Kafka/Protocol/Fetch/Topic.php345
-rw-r--r--vendor/nmred/kafka-php/src/Kafka/Protocol/Protocol.php230
-rw-r--r--vendor/nmred/kafka-php/src/Kafka/Socket.php365
-rw-r--r--vendor/nmred/kafka-php/src/Kafka/ZooKeeper.php364
-rw-r--r--vendor/oojs/oojs-ui/.csscomb.json24
-rw-r--r--vendor/oojs/oojs-ui/.csslintrc11
-rw-r--r--vendor/oojs/oojs-ui/.npmignore2
-rw-r--r--vendor/oojs/oojs-ui/AUTHORS.txt3
-rw-r--r--vendor/oojs/oojs-ui/Doxyfile33
-rw-r--r--vendor/oojs/oojs-ui/Gruntfile.js401
-rw-r--r--vendor/oojs/oojs-ui/History.md1240
-rw-r--r--vendor/oojs/oojs-ui/LICENSE-MIT2
-rw-r--r--vendor/oojs/oojs-ui/README.md12
-rw-r--r--vendor/oojs/oojs-ui/bin/docparser.rb70
-rw-r--r--vendor/oojs/oojs-ui/bin/generate-JSPHP-for-karma.php20
-rw-r--r--vendor/oojs/oojs-ui/bin/testsuitegenerator.rb12
-rw-r--r--vendor/oojs/oojs-ui/build/banner.txt10
-rw-r--r--vendor/oojs/oojs-ui/build/modules.json240
-rw-r--r--vendor/oojs/oojs-ui/build/tasks/colorize-svg.js538
-rw-r--r--vendor/oojs/oojs-ui/build/tasks/typos.js89
-rw-r--r--vendor/oojs/oojs-ui/build/typos.json17
-rw-r--r--vendor/oojs/oojs-ui/composer.json24
-rw-r--r--vendor/oojs/oojs-ui/demos/demo.js55
-rw-r--r--vendor/oojs/oojs-ui/demos/index.html11
-rw-r--r--vendor/oojs/oojs-ui/demos/infusion.js58
-rw-r--r--vendor/oojs/oojs-ui/demos/pages/dialogs.js318
-rw-r--r--vendor/oojs/oojs-ui/demos/pages/icons.js16
-rw-r--r--vendor/oojs/oojs-ui/demos/pages/toolbars.js27
-rw-r--r--vendor/oojs/oojs-ui/demos/pages/widgets.js470
-rw-r--r--vendor/oojs/oojs-ui/demos/styles/demo.css12
-rw-r--r--vendor/oojs/oojs-ui/demos/widgets.php309
-rw-r--r--vendor/oojs/oojs-ui/i18n/af.json8
-rw-r--r--vendor/oojs/oojs-ui/i18n/ar.json10
-rw-r--r--vendor/oojs/oojs-ui/i18n/arq.json7
-rw-r--r--vendor/oojs/oojs-ui/i18n/as.json25
-rw-r--r--vendor/oojs/oojs-ui/i18n/ast.json9
-rw-r--r--vendor/oojs/oojs-ui/i18n/be-tarask.json21
-rw-r--r--vendor/oojs/oojs-ui/i18n/be.json17
-rw-r--r--vendor/oojs/oojs-ui/i18n/bg.json13
-rw-r--r--vendor/oojs/oojs-ui/i18n/bn.json9
-rw-r--r--vendor/oojs/oojs-ui/i18n/bs.json5
-rw-r--r--vendor/oojs/oojs-ui/i18n/ca.json11
-rw-r--r--vendor/oojs/oojs-ui/i18n/ckb.json13
-rw-r--r--vendor/oojs/oojs-ui/i18n/cs.json4
-rw-r--r--vendor/oojs/oojs-ui/i18n/cu.json3
-rw-r--r--vendor/oojs/oojs-ui/i18n/da.json7
-rw-r--r--vendor/oojs/oojs-ui/i18n/de.json6
-rw-r--r--vendor/oojs/oojs-ui/i18n/dty.json18
-rw-r--r--vendor/oojs/oojs-ui/i18n/el.json8
-rw-r--r--vendor/oojs/oojs-ui/i18n/en-ca.json22
-rw-r--r--vendor/oojs/oojs-ui/i18n/en.json6
-rw-r--r--vendor/oojs/oojs-ui/i18n/eo.json17
-rw-r--r--vendor/oojs/oojs-ui/i18n/es.json6
-rw-r--r--vendor/oojs/oojs-ui/i18n/et.json9
-rw-r--r--vendor/oojs/oojs-ui/i18n/eu.json10
-rw-r--r--vendor/oojs/oojs-ui/i18n/fa.json15
-rw-r--r--vendor/oojs/oojs-ui/i18n/fi.json14
-rw-r--r--vendor/oojs/oojs-ui/i18n/fr.json18
-rw-r--r--vendor/oojs/oojs-ui/i18n/gl.json6
-rw-r--r--vendor/oojs/oojs-ui/i18n/glk.json23
-rw-r--r--vendor/oojs/oojs-ui/i18n/gu.json12
-rw-r--r--vendor/oojs/oojs-ui/i18n/he.json6
-rw-r--r--vendor/oojs/oojs-ui/i18n/hi.json7
-rw-r--r--vendor/oojs/oojs-ui/i18n/hrx.json12
-rw-r--r--vendor/oojs/oojs-ui/i18n/hu-formal.json21
-rw-r--r--vendor/oojs/oojs-ui/i18n/hu.json10
-rw-r--r--vendor/oojs/oojs-ui/i18n/hy.json7
-rw-r--r--vendor/oojs/oojs-ui/i18n/ia.json9
-rw-r--r--vendor/oojs/oojs-ui/i18n/id.json4
-rw-r--r--vendor/oojs/oojs-ui/i18n/ilo.json4
-rw-r--r--vendor/oojs/oojs-ui/i18n/is.json6
-rw-r--r--vendor/oojs/oojs-ui/i18n/it.json13
-rw-r--r--vendor/oojs/oojs-ui/i18n/ja.json9
-rw-r--r--vendor/oojs/oojs-ui/i18n/jv.json18
-rw-r--r--vendor/oojs/oojs-ui/i18n/ka.json4
-rw-r--r--vendor/oojs/oojs-ui/i18n/km.json23
-rw-r--r--vendor/oojs/oojs-ui/i18n/ko.json13
-rw-r--r--vendor/oojs/oojs-ui/i18n/krc.json4
-rw-r--r--vendor/oojs/oojs-ui/i18n/krl.json10
-rw-r--r--vendor/oojs/oojs-ui/i18n/ksh.json5
-rw-r--r--vendor/oojs/oojs-ui/i18n/ku-latn.json7
-rw-r--r--vendor/oojs/oojs-ui/i18n/la.json15
-rw-r--r--vendor/oojs/oojs-ui/i18n/lb.json5
-rw-r--r--vendor/oojs/oojs-ui/i18n/li.json21
-rw-r--r--vendor/oojs/oojs-ui/i18n/lt.json20
-rw-r--r--vendor/oojs/oojs-ui/i18n/luz.json21
-rw-r--r--vendor/oojs/oojs-ui/i18n/mk.json6
-rw-r--r--vendor/oojs/oojs-ui/i18n/ml.json18
-rw-r--r--vendor/oojs/oojs-ui/i18n/mr.json11
-rw-r--r--vendor/oojs/oojs-ui/i18n/ms.json11
-rw-r--r--vendor/oojs/oojs-ui/i18n/nap.json21
-rw-r--r--vendor/oojs/oojs-ui/i18n/nb.json6
-rw-r--r--vendor/oojs/oojs-ui/i18n/nl.json4
-rw-r--r--vendor/oojs/oojs-ui/i18n/oc.json9
-rw-r--r--vendor/oojs/oojs-ui/i18n/olo.json23
-rw-r--r--vendor/oojs/oojs-ui/i18n/om.json4
-rw-r--r--vendor/oojs/oojs-ui/i18n/or.json7
-rw-r--r--vendor/oojs/oojs-ui/i18n/pa.json9
-rw-r--r--vendor/oojs/oojs-ui/i18n/pl.json11
-rw-r--r--vendor/oojs/oojs-ui/i18n/pms.json13
-rw-r--r--vendor/oojs/oojs-ui/i18n/ps.json6
-rw-r--r--vendor/oojs/oojs-ui/i18n/pt-br.json17
-rw-r--r--vendor/oojs/oojs-ui/i18n/pt.json8
-rw-r--r--vendor/oojs/oojs-ui/i18n/qqq.json6
-rw-r--r--vendor/oojs/oojs-ui/i18n/ro.json6
-rw-r--r--vendor/oojs/oojs-ui/i18n/roa-tara.json6
-rw-r--r--vendor/oojs/oojs-ui/i18n/ru.json9
-rw-r--r--vendor/oojs/oojs-ui/i18n/sa.json14
-rw-r--r--vendor/oojs/oojs-ui/i18n/sah.json16
-rw-r--r--vendor/oojs/oojs-ui/i18n/sco.json15
-rw-r--r--vendor/oojs/oojs-ui/i18n/sh.json14
-rw-r--r--vendor/oojs/oojs-ui/i18n/sk.json14
-rw-r--r--vendor/oojs/oojs-ui/i18n/sl.json4
-rw-r--r--vendor/oojs/oojs-ui/i18n/sq.json11
-rw-r--r--vendor/oojs/oojs-ui/i18n/sr-ec.json4
-rw-r--r--vendor/oojs/oojs-ui/i18n/su.json21
-rw-r--r--vendor/oojs/oojs-ui/i18n/sv.json9
-rw-r--r--vendor/oojs/oojs-ui/i18n/ta.json17
-rw-r--r--vendor/oojs/oojs-ui/i18n/te.json11
-rw-r--r--vendor/oojs/oojs-ui/i18n/tl.json13
-rw-r--r--vendor/oojs/oojs-ui/i18n/uk.json10
-rw-r--r--vendor/oojs/oojs-ui/i18n/vec.json11
-rw-r--r--vendor/oojs/oojs-ui/i18n/vi.json13
-rw-r--r--vendor/oojs/oojs-ui/i18n/xmf.json19
-rw-r--r--vendor/oojs/oojs-ui/i18n/yi.json7
-rw-r--r--vendor/oojs/oojs-ui/i18n/yue.json16
-rw-r--r--vendor/oojs/oojs-ui/i18n/zh-hans.json17
-rw-r--r--vendor/oojs/oojs-ui/i18n/zh-hant.json9
-rw-r--r--vendor/oojs/oojs-ui/jsduck.categories.json80
-rw-r--r--vendor/oojs/oojs-ui/jsduck.eg-iframe.html33
-rw-r--r--vendor/oojs/oojs-ui/jsduck.external.js26
-rw-r--r--vendor/oojs/oojs-ui/jsduck.json16
-rw-r--r--vendor/oojs/oojs-ui/php/Element.php48
-rw-r--r--vendor/oojs/oojs-ui/php/HtmlSnippet.php2
-rw-r--r--vendor/oojs/oojs-ui/php/Tag.php20
-rw-r--r--vendor/oojs/oojs-ui/php/Theme.php26
-rw-r--r--vendor/oojs/oojs-ui/php/Widget.php10
-rw-r--r--vendor/oojs/oojs-ui/php/elements/ButtonElement.php102
-rw-r--r--vendor/oojs/oojs-ui/php/layouts/ActionFieldLayout.php55
-rw-r--r--vendor/oojs/oojs-ui/php/layouts/FieldLayout.php73
-rw-r--r--vendor/oojs/oojs-ui/php/layouts/FormLayout.php2
-rw-r--r--vendor/oojs/oojs-ui/php/layouts/HorizontalLayout.php27
-rw-r--r--vendor/oojs/oojs-ui/php/mixins/AccessKeyedElement.php76
-rw-r--r--vendor/oojs/oojs-ui/php/mixins/ButtonElement.php69
-rw-r--r--vendor/oojs/oojs-ui/php/mixins/FlaggedElement.php (renamed from vendor/oojs/oojs-ui/php/elements/FlaggedElement.php)0
-rw-r--r--vendor/oojs/oojs-ui/php/mixins/GroupElement.php (renamed from vendor/oojs/oojs-ui/php/elements/GroupElement.php)0
-rw-r--r--vendor/oojs/oojs-ui/php/mixins/IconElement.php (renamed from vendor/oojs/oojs-ui/php/elements/IconElement.php)0
-rw-r--r--vendor/oojs/oojs-ui/php/mixins/IndicatorElement.php (renamed from vendor/oojs/oojs-ui/php/elements/IndicatorElement.php)0
-rw-r--r--vendor/oojs/oojs-ui/php/mixins/LabelElement.php (renamed from vendor/oojs/oojs-ui/php/elements/LabelElement.php)0
-rw-r--r--vendor/oojs/oojs-ui/php/mixins/TabIndexedElement.php (renamed from vendor/oojs/oojs-ui/php/elements/TabIndexedElement.php)0
-rw-r--r--vendor/oojs/oojs-ui/php/mixins/TitledElement.php (renamed from vendor/oojs/oojs-ui/php/elements/TitledElement.php)0
-rw-r--r--vendor/oojs/oojs-ui/php/widgets/ButtonInputWidget.php14
-rw-r--r--vendor/oojs/oojs-ui/php/widgets/ButtonWidget.php2
-rw-r--r--vendor/oojs/oojs-ui/php/widgets/CheckboxInputWidget.php2
-rw-r--r--vendor/oojs/oojs-ui/php/widgets/DropdownInputWidget.php11
-rw-r--r--vendor/oojs/oojs-ui/php/widgets/IconWidget.php2
-rw-r--r--vendor/oojs/oojs-ui/php/widgets/IndicatorWidget.php2
-rw-r--r--vendor/oojs/oojs-ui/php/widgets/InputWidget.php10
-rw-r--r--vendor/oojs/oojs-ui/php/widgets/LabelWidget.php2
-rw-r--r--vendor/oojs/oojs-ui/php/widgets/RadioInputWidget.php2
-rw-r--r--vendor/oojs/oojs-ui/php/widgets/RadioSelectInputWidget.php127
-rw-r--r--vendor/oojs/oojs-ui/php/widgets/TextInputWidget.php63
-rw-r--r--vendor/oojs/oojs-ui/src/ActionSet.js504
-rw-r--r--vendor/oojs/oojs-ui/src/Dialog.js323
-rw-r--r--vendor/oojs/oojs-ui/src/Element.js748
-rw-r--r--vendor/oojs/oojs-ui/src/Error.js91
-rw-r--r--vendor/oojs/oojs-ui/src/HtmlSnippet.js29
-rw-r--r--vendor/oojs/oojs-ui/src/Layout.js33
-rw-r--r--vendor/oojs/oojs-ui/src/Process.js166
-rw-r--r--vendor/oojs/oojs-ui/src/Theme.js48
-rw-r--r--vendor/oojs/oojs-ui/src/Tool.js279
-rw-r--r--vendor/oojs/oojs-ui/src/ToolFactory.js120
-rw-r--r--vendor/oojs/oojs-ui/src/ToolGroup.js338
-rw-r--r--vendor/oojs/oojs-ui/src/ToolGroupFactory.js38
-rw-r--r--vendor/oojs/oojs-ui/src/Toolbar.js481
-rw-r--r--vendor/oojs/oojs-ui/src/Widget.js102
-rw-r--r--vendor/oojs/oojs-ui/src/Window.js628
-rw-r--r--vendor/oojs/oojs-ui/src/WindowManager.js675
-rw-r--r--vendor/oojs/oojs-ui/src/core.js286
-rw-r--r--vendor/oojs/oojs-ui/src/dialogs/MessageDialog.js325
-rw-r--r--vendor/oojs/oojs-ui/src/dialogs/ProcessDialog.js296
-rw-r--r--vendor/oojs/oojs-ui/src/elements/ButtonElement.js263
-rw-r--r--vendor/oojs/oojs-ui/src/elements/ClippableElement.js205
-rw-r--r--vendor/oojs/oojs-ui/src/elements/DraggableElement.js142
-rw-r--r--vendor/oojs/oojs-ui/src/elements/DraggableGroupElement.js261
-rw-r--r--vendor/oojs/oojs-ui/src/elements/FlaggedElement.js209
-rw-r--r--vendor/oojs/oojs-ui/src/elements/GroupElement.js290
-rw-r--r--vendor/oojs/oojs-ui/src/elements/IconElement.js187
-rw-r--r--vendor/oojs/oojs-ui/src/elements/IndicatorElement.js168
-rw-r--r--vendor/oojs/oojs-ui/src/elements/LabelElement.js152
-rw-r--r--vendor/oojs/oojs-ui/src/elements/LookupElement.js352
-rw-r--r--vendor/oojs/oojs-ui/src/elements/PendingElement.js84
-rw-r--r--vendor/oojs/oojs-ui/src/elements/PopupElement.js36
-rw-r--r--vendor/oojs/oojs-ui/src/elements/TabIndexedElement.js138
-rw-r--r--vendor/oojs/oojs-ui/src/elements/TitledElement.js106
-rw-r--r--vendor/oojs/oojs-ui/src/intro.js.txt3
-rw-r--r--vendor/oojs/oojs-ui/src/layouts/ActionFieldLayout.js81
-rw-r--r--vendor/oojs/oojs-ui/src/layouts/BookletLayout.js542
-rw-r--r--vendor/oojs/oojs-ui/src/layouts/CardLayout.js138
-rw-r--r--vendor/oojs/oojs-ui/src/layouts/FieldLayout.js160
-rw-r--r--vendor/oojs/oojs-ui/src/layouts/FieldsetLayout.js86
-rw-r--r--vendor/oojs/oojs-ui/src/layouts/FormLayout.js119
-rw-r--r--vendor/oojs/oojs-ui/src/layouts/IndexLayout.js452
-rw-r--r--vendor/oojs/oojs-ui/src/layouts/MenuLayout.js156
-rw-r--r--vendor/oojs/oojs-ui/src/layouts/PageLayout.js138
-rw-r--r--vendor/oojs/oojs-ui/src/layouts/PanelLayout.js55
-rw-r--r--vendor/oojs/oojs-ui/src/layouts/StackLayout.js214
-rw-r--r--vendor/oojs/oojs-ui/src/outro.js.txt1
-rw-r--r--vendor/oojs/oojs-ui/src/styles/Dialog.less35
-rw-r--r--vendor/oojs/oojs-ui/src/styles/Element.less9
-rw-r--r--vendor/oojs/oojs-ui/src/styles/Layout.less5
-rw-r--r--vendor/oojs/oojs-ui/src/styles/Tool.less5
-rw-r--r--vendor/oojs/oojs-ui/src/styles/ToolGroup.less21
-rw-r--r--vendor/oojs/oojs-ui/src/styles/Toolbar.less52
-rw-r--r--vendor/oojs/oojs-ui/src/styles/Widget.less5
-rw-r--r--vendor/oojs/oojs-ui/src/styles/Window.less32
-rw-r--r--vendor/oojs/oojs-ui/src/styles/WindowManager.less39
-rw-r--r--vendor/oojs/oojs-ui/src/styles/common.less102
-rw-r--r--vendor/oojs/oojs-ui/src/styles/core.less114
-rw-r--r--vendor/oojs/oojs-ui/src/styles/dialogs/MessageDialog.less45
-rw-r--r--vendor/oojs/oojs-ui/src/styles/dialogs/ProcessDialog.less52
-rw-r--r--vendor/oojs/oojs-ui/src/styles/elements/ButtonElement.less62
-rw-r--r--vendor/oojs/oojs-ui/src/styles/elements/ClippableElement.less7
-rw-r--r--vendor/oojs/oojs-ui/src/styles/elements/DraggableElement.less22
-rw-r--r--vendor/oojs/oojs-ui/src/styles/elements/DraggableGroupElement.less11
-rw-r--r--vendor/oojs/oojs-ui/src/styles/elements/FlaggedElement.less5
-rw-r--r--vendor/oojs/oojs-ui/src/styles/elements/GroupElement.less5
-rw-r--r--vendor/oojs/oojs-ui/src/styles/elements/IconElement.less5
-rw-r--r--vendor/oojs/oojs-ui/src/styles/elements/IndicatorElement.less5
-rw-r--r--vendor/oojs/oojs-ui/src/styles/elements/LabelElement.less5
-rw-r--r--vendor/oojs/oojs-ui/src/styles/elements/LookupElement.less10
-rw-r--r--vendor/oojs/oojs-ui/src/styles/elements/PopupElement.less5
-rw-r--r--vendor/oojs/oojs-ui/src/styles/elements/TabIndexedElement.less5
-rw-r--r--vendor/oojs/oojs-ui/src/styles/elements/TitledElement.less5
-rw-r--r--vendor/oojs/oojs-ui/src/styles/images/grab.curbin326 -> 0 bytes
-rw-r--r--vendor/oojs/oojs-ui/src/styles/images/grabbing.curbin326 -> 0 bytes
-rw-r--r--vendor/oojs/oojs-ui/src/styles/layouts/ActionFieldLayout.less26
-rw-r--r--vendor/oojs/oojs-ui/src/styles/layouts/BookletLayout.less43
-rw-r--r--vendor/oojs/oojs-ui/src/styles/layouts/CardLayout.less5
-rw-r--r--vendor/oojs/oojs-ui/src/styles/layouts/FieldLayout.less59
-rw-r--r--vendor/oojs/oojs-ui/src/styles/layouts/FieldsetLayout.less31
-rw-r--r--vendor/oojs/oojs-ui/src/styles/layouts/FormLayout.less5
-rw-r--r--vendor/oojs/oojs-ui/src/styles/layouts/IndexLayout.less13
-rw-r--r--vendor/oojs/oojs-ui/src/styles/layouts/MenuLayout.less108
-rw-r--r--vendor/oojs/oojs-ui/src/styles/layouts/PageLayout.less5
-rw-r--r--vendor/oojs/oojs-ui/src/styles/layouts/PanelLayout.less19
-rw-r--r--vendor/oojs/oojs-ui/src/styles/layouts/StackLayout.less10
-rw-r--r--vendor/oojs/oojs-ui/src/styles/theme.less91
-rw-r--r--vendor/oojs/oojs-ui/src/styles/toolgroups/BarToolGroup.less51
-rw-r--r--vendor/oojs/oojs-ui/src/styles/toolgroups/ListToolGroup.less21
-rw-r--r--vendor/oojs/oojs-ui/src/styles/toolgroups/MenuToolGroup.less19
-rw-r--r--vendor/oojs/oojs-ui/src/styles/toolgroups/PopupToolGroup.less73
-rw-r--r--vendor/oojs/oojs-ui/src/styles/tools/PopupTool.less12
-rw-r--r--vendor/oojs/oojs-ui/src/styles/tools/ToolGroupTool.less5
-rw-r--r--vendor/oojs/oojs-ui/src/styles/widgets/ActionWidget.less5
-rw-r--r--vendor/oojs/oojs-ui/src/styles/widgets/ButtonGroupWidget.less5
-rw-r--r--vendor/oojs/oojs-ui/src/styles/widgets/ButtonInputWidget.less8
-rw-r--r--vendor/oojs/oojs-ui/src/styles/widgets/ButtonOptionWidget.less18
-rw-r--r--vendor/oojs/oojs-ui/src/styles/widgets/ButtonSelectWidget.less8
-rw-r--r--vendor/oojs/oojs-ui/src/styles/widgets/ButtonWidget.less8
-rw-r--r--vendor/oojs/oojs-ui/src/styles/widgets/CheckboxInputWidget.less5
-rw-r--r--vendor/oojs/oojs-ui/src/styles/widgets/ComboBoxWidget.less13
-rw-r--r--vendor/oojs/oojs-ui/src/styles/widgets/DecoratedOptionWidget.less12
-rw-r--r--vendor/oojs/oojs-ui/src/styles/widgets/DropdownInputWidget.less17
-rw-r--r--vendor/oojs/oojs-ui/src/styles/widgets/DropdownWidget.less33
-rw-r--r--vendor/oojs/oojs-ui/src/styles/widgets/IconWidget.less10
-rw-r--r--vendor/oojs/oojs-ui/src/styles/widgets/IndicatorWidget.less10
-rw-r--r--vendor/oojs/oojs-ui/src/styles/widgets/InputWidget.less5
-rw-r--r--vendor/oojs/oojs-ui/src/styles/widgets/LabelWidget.less7
-rw-r--r--vendor/oojs/oojs-ui/src/styles/widgets/MenuOptionWidget.less21
-rw-r--r--vendor/oojs/oojs-ui/src/styles/widgets/MenuSectionOptionWidget.less8
-rw-r--r--vendor/oojs/oojs-ui/src/styles/widgets/MenuSelectWidget.less15
-rw-r--r--vendor/oojs/oojs-ui/src/styles/widgets/OptionWidget.less20
-rw-r--r--vendor/oojs/oojs-ui/src/styles/widgets/OutlineControlsWidget.less32
-rw-r--r--vendor/oojs/oojs-ui/src/styles/widgets/OutlineOptionWidget.less9
-rw-r--r--vendor/oojs/oojs-ui/src/styles/widgets/OutlineSelectWidget.less5
-rw-r--r--vendor/oojs/oojs-ui/src/styles/widgets/PopupButtonWidget.less12
-rw-r--r--vendor/oojs/oojs-ui/src/styles/widgets/PopupWidget.less49
-rw-r--r--vendor/oojs/oojs-ui/src/styles/widgets/ProgressBarWidget.less5
-rw-r--r--vendor/oojs/oojs-ui/src/styles/widgets/RadioInputWidget.less5
-rw-r--r--vendor/oojs/oojs-ui/src/styles/widgets/RadioOptionWidget.less13
-rw-r--r--vendor/oojs/oojs-ui/src/styles/widgets/RadioSelectWidget.less5
-rw-r--r--vendor/oojs/oojs-ui/src/styles/widgets/SearchWidget.less25
-rw-r--r--vendor/oojs/oojs-ui/src/styles/widgets/SelectWidget.less5
-rw-r--r--vendor/oojs/oojs-ui/src/styles/widgets/TabOptionWidget.less8
-rw-r--r--vendor/oojs/oojs-ui/src/styles/widgets/TabSelectWidget.less9
-rw-r--r--vendor/oojs/oojs-ui/src/styles/widgets/TextInputMenuSelectWidget.less5
-rw-r--r--vendor/oojs/oojs-ui/src/styles/widgets/TextInputWidget.less71
-rw-r--r--vendor/oojs/oojs-ui/src/styles/widgets/ToggleButtonWidget.less8
-rw-r--r--vendor/oojs/oojs-ui/src/styles/widgets/ToggleSwitchWidget.less41
-rw-r--r--vendor/oojs/oojs-ui/src/styles/widgets/ToggleWidget.less5
-rw-r--r--vendor/oojs/oojs-ui/src/themes/apex/ApexTheme.js18
-rw-r--r--vendor/oojs/oojs-ui/src/themes/apex/common.less27
-rw-r--r--vendor/oojs/oojs-ui/src/themes/apex/core.less12
-rw-r--r--vendor/oojs/oojs-ui/src/themes/apex/elements.less247
-rw-r--r--vendor/oojs/oojs-ui/src/themes/apex/icons-editing-advanced.json75
-rw-r--r--vendor/oojs/oojs-ui/src/themes/apex/icons-editing-core.json24
-rw-r--r--vendor/oojs/oojs-ui/src/themes/apex/icons-editing-list.json22
-rw-r--r--vendor/oojs/oojs-ui/src/themes/apex/icons-editing-styling.json72
-rw-r--r--vendor/oojs/oojs-ui/src/themes/apex/icons-moderation.json33
-rw-r--r--vendor/oojs/oojs-ui/src/themes/apex/icons-movement.json27
-rw-r--r--vendor/oojs/oojs-ui/src/themes/apex/icons.json50
-rw-r--r--vendor/oojs/oojs-ui/src/themes/apex/images/icons/add.svg6
-rw-r--r--vendor/oojs/oojs-ui/src/themes/apex/images/icons/advanced.svg6
-rw-r--r--vendor/oojs/oojs-ui/src/themes/apex/images/icons/alert.svg8
-rw-r--r--vendor/oojs/oojs-ui/src/themes/apex/images/icons/align-center.svg6
-rw-r--r--vendor/oojs/oojs-ui/src/themes/apex/images/icons/align-float-left.svg6
-rw-r--r--vendor/oojs/oojs-ui/src/themes/apex/images/icons/align-float-right.svg6
-rw-r--r--vendor/oojs/oojs-ui/src/themes/apex/images/icons/arched-arrow-ltr.svg6
-rw-r--r--vendor/oojs/oojs-ui/src/themes/apex/images/icons/arched-arrow-rtl.svg6
-rw-r--r--vendor/oojs/oojs-ui/src/themes/apex/images/icons/arrow-ltr.svg6
-rw-r--r--vendor/oojs/oojs-ui/src/themes/apex/images/icons/arrow-rtl.svg6
-rw-r--r--vendor/oojs/oojs-ui/src/themes/apex/images/icons/bigger-ltr.svg7
-rw-r--r--vendor/oojs/oojs-ui/src/themes/apex/images/icons/bigger-rtl.svg7
-rw-r--r--vendor/oojs/oojs-ui/src/themes/apex/images/icons/block.svg4
-rw-r--r--vendor/oojs/oojs-ui/src/themes/apex/images/icons/blockUndo-ltr.svg6
-rw-r--r--vendor/oojs/oojs-ui/src/themes/apex/images/icons/blockUndo-rtl.svg6
-rw-r--r--vendor/oojs/oojs-ui/src/themes/apex/images/icons/bold-a.svg6
-rw-r--r--vendor/oojs/oojs-ui/src/themes/apex/images/icons/bold-arab-ain.svg6
-rw-r--r--vendor/oojs/oojs-ui/src/themes/apex/images/icons/bold-arab-dad.svg6
-rw-r--r--vendor/oojs/oojs-ui/src/themes/apex/images/icons/bold-armn-to.svg6
-rw-r--r--vendor/oojs/oojs-ui/src/themes/apex/images/icons/bold-b.svg6
-rw-r--r--vendor/oojs/oojs-ui/src/themes/apex/images/icons/bold-cyrl-be.svg6
-rw-r--r--vendor/oojs/oojs-ui/src/themes/apex/images/icons/bold-cyrl-te.svg6
-rw-r--r--vendor/oojs/oojs-ui/src/themes/apex/images/icons/bold-cyrl-zhe.svg6
-rw-r--r--vendor/oojs/oojs-ui/src/themes/apex/images/icons/bold-f.svg6
-rw-r--r--vendor/oojs/oojs-ui/src/themes/apex/images/icons/bold-g.svg6
-rw-r--r--vendor/oojs/oojs-ui/src/themes/apex/images/icons/bold-geor-man.svg6
-rw-r--r--vendor/oojs/oojs-ui/src/themes/apex/images/icons/bold-l.svg6
-rw-r--r--vendor/oojs/oojs-ui/src/themes/apex/images/icons/bold-n.svg6
-rw-r--r--vendor/oojs/oojs-ui/src/themes/apex/images/icons/bold-v.svg6
-rw-r--r--vendor/oojs/oojs-ui/src/themes/apex/images/icons/cancel.svg6
-rw-r--r--vendor/oojs/oojs-ui/src/themes/apex/images/icons/caret-ltr.svg4
-rw-r--r--vendor/oojs/oojs-ui/src/themes/apex/images/icons/caret-rtl.svg4
-rw-r--r--vendor/oojs/oojs-ui/src/themes/apex/images/icons/caretDown.svg4
-rw-r--r--vendor/oojs/oojs-ui/src/themes/apex/images/icons/caretUp.svg4
-rw-r--r--vendor/oojs/oojs-ui/src/themes/apex/images/icons/case-sensitive.svg7
-rw-r--r--vendor/oojs/oojs-ui/src/themes/apex/images/icons/check.svg6
-rw-r--r--vendor/oojs/oojs-ui/src/themes/apex/images/icons/circle.svg2
-rw-r--r--vendor/oojs/oojs-ui/src/themes/apex/images/icons/close.svg6
-rw-r--r--vendor/oojs/oojs-ui/src/themes/apex/images/icons/code.svg7
-rw-r--r--vendor/oojs/oojs-ui/src/themes/apex/images/icons/collapse.svg6
-rw-r--r--vendor/oojs/oojs-ui/src/themes/apex/images/icons/comment.svg6
-rw-r--r--vendor/oojs/oojs-ui/src/themes/apex/images/icons/downTriangle.svg4
-rw-r--r--vendor/oojs/oojs-ui/src/themes/apex/images/icons/edit-ltr.svg6
-rw-r--r--vendor/oojs/oojs-ui/src/themes/apex/images/icons/edit-rtl.svg6
-rw-r--r--vendor/oojs/oojs-ui/src/themes/apex/images/icons/editLock-ltr.svg8
-rw-r--r--vendor/oojs/oojs-ui/src/themes/apex/images/icons/editLock-rtl.svg8
-rw-r--r--vendor/oojs/oojs-ui/src/themes/apex/images/icons/editUndo-ltr.svg11
-rw-r--r--vendor/oojs/oojs-ui/src/themes/apex/images/icons/editUndo-rtl.svg11
-rw-r--r--vendor/oojs/oojs-ui/src/themes/apex/images/icons/ellipsis.svg14
-rw-r--r--vendor/oojs/oojs-ui/src/themes/apex/images/icons/expand.svg6
-rw-r--r--vendor/oojs/oojs-ui/src/themes/apex/images/icons/external-link-ltr.svg7
-rw-r--r--vendor/oojs/oojs-ui/src/themes/apex/images/icons/external-link-rtl.svg7
-rw-r--r--vendor/oojs/oojs-ui/src/themes/apex/images/icons/find-ltr.svg7
-rw-r--r--vendor/oojs/oojs-ui/src/themes/apex/images/icons/find-rtl.svg7
-rw-r--r--vendor/oojs/oojs-ui/src/themes/apex/images/icons/flag-ltr.svg4
-rw-r--r--vendor/oojs/oojs-ui/src/themes/apex/images/icons/flag-rtl.svg4
-rw-r--r--vendor/oojs/oojs-ui/src/themes/apex/images/icons/flagUndo-ltr.svg16
-rw-r--r--vendor/oojs/oojs-ui/src/themes/apex/images/icons/flagUndo-rtl.svg16
-rw-r--r--vendor/oojs/oojs-ui/src/themes/apex/images/icons/help-ltr.svg10
-rw-r--r--vendor/oojs/oojs-ui/src/themes/apex/images/icons/help-rtl.svg10
-rw-r--r--vendor/oojs/oojs-ui/src/themes/apex/images/icons/history.svg7
-rw-r--r--vendor/oojs/oojs-ui/src/themes/apex/images/icons/indent-ltr.svg9
-rw-r--r--vendor/oojs/oojs-ui/src/themes/apex/images/icons/indent-rtl.svg9
-rw-r--r--vendor/oojs/oojs-ui/src/themes/apex/images/icons/info.svg6
-rw-r--r--vendor/oojs/oojs-ui/src/themes/apex/images/icons/insert.svg6
-rw-r--r--vendor/oojs/oojs-ui/src/themes/apex/images/icons/italic-a.svg6
-rw-r--r--vendor/oojs/oojs-ui/src/themes/apex/images/icons/italic-arab-keheh-jeem.svg6
-rw-r--r--vendor/oojs/oojs-ui/src/themes/apex/images/icons/italic-arab-meem.svg6
-rw-r--r--vendor/oojs/oojs-ui/src/themes/apex/images/icons/italic-armn-sha.svg6
-rw-r--r--vendor/oojs/oojs-ui/src/themes/apex/images/icons/italic-c.svg6
-rw-r--r--vendor/oojs/oojs-ui/src/themes/apex/images/icons/italic-d.svg6
-rw-r--r--vendor/oojs/oojs-ui/src/themes/apex/images/icons/italic-e.svg6
-rw-r--r--vendor/oojs/oojs-ui/src/themes/apex/images/icons/italic-geor-kan.svg6
-rw-r--r--vendor/oojs/oojs-ui/src/themes/apex/images/icons/italic-i.svg6
-rw-r--r--vendor/oojs/oojs-ui/src/themes/apex/images/icons/italic-k.svg6
-rw-r--r--vendor/oojs/oojs-ui/src/themes/apex/images/icons/italic-s.svg6
-rw-r--r--vendor/oojs/oojs-ui/src/themes/apex/images/icons/language.svg7
-rw-r--r--vendor/oojs/oojs-ui/src/themes/apex/images/icons/layout-ltr.svg7
-rw-r--r--vendor/oojs/oojs-ui/src/themes/apex/images/icons/layout-rtl.svg7
-rw-r--r--vendor/oojs/oojs-ui/src/themes/apex/images/icons/link.svg8
-rw-r--r--vendor/oojs/oojs-ui/src/themes/apex/images/icons/listBullet-ltr.svg11
-rw-r--r--vendor/oojs/oojs-ui/src/themes/apex/images/icons/listBullet-rtl.svg11
-rw-r--r--vendor/oojs/oojs-ui/src/themes/apex/images/icons/listNumbered-ltr.svg11
-rw-r--r--vendor/oojs/oojs-ui/src/themes/apex/images/icons/listNumbered-rtl.svg11
-rw-r--r--vendor/oojs/oojs-ui/src/themes/apex/images/icons/lock.svg6
-rw-r--r--vendor/oojs/oojs-ui/src/themes/apex/images/icons/menu.svg6
-rw-r--r--vendor/oojs/oojs-ui/src/themes/apex/images/icons/move-ltr.svg6
-rw-r--r--vendor/oojs/oojs-ui/src/themes/apex/images/icons/move-rtl.svg6
-rw-r--r--vendor/oojs/oojs-ui/src/themes/apex/images/icons/move.svg4
-rw-r--r--vendor/oojs/oojs-ui/src/themes/apex/images/icons/newline-ltr.svg6
-rw-r--r--vendor/oojs/oojs-ui/src/themes/apex/images/icons/newline-rtl.svg6
-rw-r--r--vendor/oojs/oojs-ui/src/themes/apex/images/icons/noWikiText-ltr.svg6
-rw-r--r--vendor/oojs/oojs-ui/src/themes/apex/images/icons/noWikiText-rtl.svg6
-rw-r--r--vendor/oojs/oojs-ui/src/themes/apex/images/icons/outdent-ltr.svg9
-rw-r--r--vendor/oojs/oojs-ui/src/themes/apex/images/icons/outdent-rtl.svg9
-rw-r--r--vendor/oojs/oojs-ui/src/themes/apex/images/icons/outline-ltr.svg7
-rw-r--r--vendor/oojs/oojs-ui/src/themes/apex/images/icons/outline-rtl.svg7
-rw-r--r--vendor/oojs/oojs-ui/src/themes/apex/images/icons/picture.svg8
-rw-r--r--vendor/oojs/oojs-ui/src/themes/apex/images/icons/puzzle-ltr.svg4
-rw-r--r--vendor/oojs/oojs-ui/src/themes/apex/images/icons/puzzle-rtl.svg4
-rw-r--r--vendor/oojs/oojs-ui/src/themes/apex/images/icons/quotes-ltr.svg6
-rw-r--r--vendor/oojs/oojs-ui/src/themes/apex/images/icons/quotes-rtl.svg6
-rw-r--r--vendor/oojs/oojs-ui/src/themes/apex/images/icons/quotesAdd-ltr.svg6
-rw-r--r--vendor/oojs/oojs-ui/src/themes/apex/images/icons/quotesAdd-rtl.svg6
-rw-r--r--vendor/oojs/oojs-ui/src/themes/apex/images/icons/redirect-ltr.svg8
-rw-r--r--vendor/oojs/oojs-ui/src/themes/apex/images/icons/redirect-rtl.svg9
-rw-r--r--vendor/oojs/oojs-ui/src/themes/apex/images/icons/regular-expression.svg9
-rw-r--r--vendor/oojs/oojs-ui/src/themes/apex/images/icons/remove.svg6
-rw-r--r--vendor/oojs/oojs-ui/src/themes/apex/images/icons/search.svg6
-rw-r--r--vendor/oojs/oojs-ui/src/themes/apex/images/icons/secure-link.svg6
-rw-r--r--vendor/oojs/oojs-ui/src/themes/apex/images/icons/settings.svg6
-rw-r--r--vendor/oojs/oojs-ui/src/themes/apex/images/icons/smaller-ltr.svg7
-rw-r--r--vendor/oojs/oojs-ui/src/themes/apex/images/icons/smaller-rtl.svg7
-rw-r--r--vendor/oojs/oojs-ui/src/themes/apex/images/icons/specialCharacter.svg6
-rw-r--r--vendor/oojs/oojs-ui/src/themes/apex/images/icons/star.svg4
-rw-r--r--vendor/oojs/oojs-ui/src/themes/apex/images/icons/strikethrough-a.svg7
-rw-r--r--vendor/oojs/oojs-ui/src/themes/apex/images/icons/strikethrough-s.svg7
-rw-r--r--vendor/oojs/oojs-ui/src/themes/apex/images/icons/strikethrough-y.svg7
-rw-r--r--vendor/oojs/oojs-ui/src/themes/apex/images/icons/subscript-ltr.svg5
-rw-r--r--vendor/oojs/oojs-ui/src/themes/apex/images/icons/subscript-rtl.svg5
-rw-r--r--vendor/oojs/oojs-ui/src/themes/apex/images/icons/superscript-ltr.svg5
-rw-r--r--vendor/oojs/oojs-ui/src/themes/apex/images/icons/superscript-rtl.svg5
-rw-r--r--vendor/oojs/oojs-ui/src/themes/apex/images/icons/table-caption.svg7
-rw-r--r--vendor/oojs/oojs-ui/src/themes/apex/images/icons/table-insert-column-ltr.svg11
-rw-r--r--vendor/oojs/oojs-ui/src/themes/apex/images/icons/table-insert-column-rtl.svg11
-rw-r--r--vendor/oojs/oojs-ui/src/themes/apex/images/icons/table-insert-row-after.svg11
-rw-r--r--vendor/oojs/oojs-ui/src/themes/apex/images/icons/table-insert-row-before.svg11
-rw-r--r--vendor/oojs/oojs-ui/src/themes/apex/images/icons/table-merge-cells.svg10
-rw-r--r--vendor/oojs/oojs-ui/src/themes/apex/images/icons/table.svg7
-rw-r--r--vendor/oojs/oojs-ui/src/themes/apex/images/icons/tag.svg6
-rw-r--r--vendor/oojs/oojs-ui/src/themes/apex/images/icons/templateAdd-ltr.svg7
-rw-r--r--vendor/oojs/oojs-ui/src/themes/apex/images/icons/templateAdd-rtl.svg7
-rw-r--r--vendor/oojs/oojs-ui/src/themes/apex/images/icons/text-dir-lefttoright.svg6
-rw-r--r--vendor/oojs/oojs-ui/src/themes/apex/images/icons/text-dir-righttoleft.svg6
-rw-r--r--vendor/oojs/oojs-ui/src/themes/apex/images/icons/text-style.svg7
-rw-r--r--vendor/oojs/oojs-ui/src/themes/apex/images/icons/translation-ltr.svg4
-rw-r--r--vendor/oojs/oojs-ui/src/themes/apex/images/icons/translation-rtl.svg4
-rw-r--r--vendor/oojs/oojs-ui/src/themes/apex/images/icons/trash.svg4
-rw-r--r--vendor/oojs/oojs-ui/src/themes/apex/images/icons/trashUndo-ltr.svg6
-rw-r--r--vendor/oojs/oojs-ui/src/themes/apex/images/icons/trashUndo-rtl.svg6
-rw-r--r--vendor/oojs/oojs-ui/src/themes/apex/images/icons/unLock-ltr.svg4
-rw-r--r--vendor/oojs/oojs-ui/src/themes/apex/images/icons/unLock-rtl.svg4
-rw-r--r--vendor/oojs/oojs-ui/src/themes/apex/images/icons/unStar.svg4
-rw-r--r--vendor/oojs/oojs-ui/src/themes/apex/images/icons/underline-a.svg7
-rw-r--r--vendor/oojs/oojs-ui/src/themes/apex/images/icons/underline-u.svg7
-rw-r--r--vendor/oojs/oojs-ui/src/themes/apex/images/icons/upTriangle.svg4
-rw-r--r--vendor/oojs/oojs-ui/src/themes/apex/images/icons/wikiText.svg15
-rw-r--r--vendor/oojs/oojs-ui/src/themes/apex/images/icons/window.svg7
-rw-r--r--vendor/oojs/oojs-ui/src/themes/apex/images/indicators/alert.svg6
-rw-r--r--vendor/oojs/oojs-ui/src/themes/apex/images/indicators/arrow-down.svg6
-rw-r--r--vendor/oojs/oojs-ui/src/themes/apex/images/indicators/arrow-ltr.svg6
-rw-r--r--vendor/oojs/oojs-ui/src/themes/apex/images/indicators/arrow-rtl.svg6
-rw-r--r--vendor/oojs/oojs-ui/src/themes/apex/images/indicators/arrow-up.svg6
-rw-r--r--vendor/oojs/oojs-ui/src/themes/apex/images/indicators/required.svg6
-rw-r--r--vendor/oojs/oojs-ui/src/themes/apex/images/indicators/search-ltr.svg6
-rw-r--r--vendor/oojs/oojs-ui/src/themes/apex/images/indicators/search-rtl.svg6
-rw-r--r--vendor/oojs/oojs-ui/src/themes/apex/images/textures/pending.gifbin2032 -> 0 bytes
-rw-r--r--vendor/oojs/oojs-ui/src/themes/apex/images/textures/transparency.svg10
-rw-r--r--vendor/oojs/oojs-ui/src/themes/apex/images/toolbar-shadow.pngbin131 -> 0 bytes
-rw-r--r--vendor/oojs/oojs-ui/src/themes/apex/indicators.json22
-rw-r--r--vendor/oojs/oojs-ui/src/themes/apex/layouts.less135
-rw-r--r--vendor/oojs/oojs-ui/src/themes/apex/textures.json8
-rw-r--r--vendor/oojs/oojs-ui/src/themes/apex/tools.less422
-rw-r--r--vendor/oojs/oojs-ui/src/themes/apex/widgets.less797
-rw-r--r--vendor/oojs/oojs-ui/src/themes/apex/windows.less307
-rw-r--r--vendor/oojs/oojs-ui/src/themes/blank/BlankTheme.js32
-rw-r--r--vendor/oojs/oojs-ui/src/themes/blank/common.less10
-rw-r--r--vendor/oojs/oojs-ui/src/themes/blank/core.less12
-rw-r--r--vendor/oojs/oojs-ui/src/themes/blank/elements.less29
-rw-r--r--vendor/oojs/oojs-ui/src/themes/blank/images/icons/README.txt1
-rw-r--r--vendor/oojs/oojs-ui/src/themes/blank/images/indicators/README.txt1
-rw-r--r--vendor/oojs/oojs-ui/src/themes/blank/images/textures/README.txt1
-rw-r--r--vendor/oojs/oojs-ui/src/themes/blank/layouts.less26
-rw-r--r--vendor/oojs/oojs-ui/src/themes/blank/tools.less20
-rw-r--r--vendor/oojs/oojs-ui/src/themes/blank/widgets.less77
-rw-r--r--vendor/oojs/oojs-ui/src/themes/blank/windows.less11
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/MediaWikiTheme.js56
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/common.less69
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/core.less12
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/elements.less319
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/icons-alerts.json33
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/icons-content.json50
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/icons-editing-advanced.json75
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/icons-editing-core.json45
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/icons-editing-list.json22
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/icons-editing-styling.json72
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/icons-interactions.json52
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/icons-layout.json43
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/icons-location.json19
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/icons-media.json27
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/icons-moderation.json52
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/icons-movement.json27
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/icons-user.json19
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/icons-wikimedia.json9
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/icons.json75
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/add.svg6
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/advanced.svg4
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/alert.svg8
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/align-center.svg6
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/align-float-left.svg6
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/align-float-right.svg6
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/arched-arrow-ltr.svg6
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/arched-arrow-rtl.svg6
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/arrow-ltr.svg6
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/arrow-rtl.svg6
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/article-ltr.svg6
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/article-rtl.svg6
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/articleCheck-ltr.svg9
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/articleCheck-rtl.svg9
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/articleSearch-ltr.svg6
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/articleSearch-rtl.svg6
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/bell.svg4
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/bellOn-ltr.svg4
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/bellOn-rtl.svg4
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/beta.svg4
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/betaLaunch.svg4
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/bigger-ltr.svg7
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/bigger-rtl.svg7
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/block.svg4
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/blockUndo-ltr.svg6
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/blockUndo-rtl.svg6
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/bold-a.svg6
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/bold-arab-ain.svg6
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/bold-arab-dad.svg6
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/bold-armn-to.svg6
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/bold-b.svg6
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/bold-cyrl-be.svg6
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/bold-cyrl-te.svg6
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/bold-cyrl-zhe.svg6
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/bold-f.svg6
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/bold-g.svg6
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/bold-geor-man.svg6
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/bold-l.svg6
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/bold-n.svg6
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/bold-v.svg6
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/book-ltr.svg4
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/book-rtl.svg4
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/bookmark-ltr.svg4
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/bookmark-rtl.svg4
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/browser-ltr.svg4
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/browser-rtl.svg4
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/cancel.svg6
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/caret-ltr.svg4
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/caret-rtl.svg4
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/caretDown.svg4
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/caretUp.svg4
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/case-sensitive.svg7
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/check.svg6
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/circle.svg2
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/citeArticle-ltr.svg6
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/citeArticle-rtl.svg6
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/clear.svg6
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/clock.svg6
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/close-ltr.svg4
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/close-rtl.svg4
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/code.svg7
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/collapse.svg6
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/comment.svg6
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/die-ltr.svg4
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/die-rtl.svg4
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/downTriangle.svg4
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/download-ltr.svg6
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/download-rtl.svg6
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/edit-ltr.svg6
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/edit-rtl.svg6
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/editLock-ltr.svg8
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/editLock-rtl.svg8
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/editUndo-ltr.svg11
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/editUndo-rtl.svg11
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/ellipsis.svg14
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/expand.svg6
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/external-link-ltr.svg7
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/external-link-rtl.svg7
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/eye.svg7
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/eyeClosed.svg4
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/find-ltr.svg7
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/find-rtl.svg7
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/flag-ltr.svg4
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/flag-rtl.svg4
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/flagUndo-ltr.svg16
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/flagUndo-rtl.svg16
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/folderPlaceholder-ltr.svg4
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/folderPlaceholder-rtl.svg4
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/funnel-ltr.svg6
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/funnel-rtl.svg6
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/heart.svg4
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/help-ltr.svg10
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/help-rtl.svg10
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/history.svg7
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/image-ltr.svg6
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/image-rtl.svg6
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/imageAdd-ltr.svg7
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/imageAdd-rtl.svg7
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/imageLock-ltr.svg4
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/imageLock-rtl.svg4
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/indent-ltr.svg6
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/indent-rtl.svg6
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/info.svg6
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/insert.svg6
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/italic-a.svg6
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/italic-arab-keheh-jeem.svg6
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/italic-arab-meem.svg6
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/italic-armn-sha.svg6
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/italic-c.svg6
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/italic-d.svg6
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/italic-e.svg6
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/italic-geor-kan.svg6
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/italic-i.svg6
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/italic-k.svg6
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/italic-s.svg6
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/journal-ltr.svg4
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/journal-rtl.svg4
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/key-ltr.svg4
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/key-rtl.svg4
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/keyboard-ltr.svg6
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/keyboard-rtl.svg6
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/language.svg7
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/layout-ltr.svg7
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/layout-rtl.svg7
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/link-ltr.svg13
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/link-rtl.svg6
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/listBullet-ltr.svg4
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/listBullet-rtl.svg4
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/listNumbered-ltr.svg4
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/listNumbered-rtl.svg4
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/lock-ltr.svg6
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/lock-rtl.svg6
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/logOut-ltr.svg6
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/logOut-rtl.svg6
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/logo-cc.svg6
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/logo-wikimediaCommons.svg7
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/logo-wikipedia.svg6
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/map-ltr.svg4
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/map-rtl.svg4
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/mapPin.svg4
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/mapPinAdd-ltr.svg9
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/mapPinAdd-rtl.svg9
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/menu.svg10
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/message-ltr.svg6
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/message-rtl.svg6
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/move-ltr.svg6
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/move-rtl.svg6
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/move.svg4
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/newWindow-ltr.svg6
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/newWindow-rtl.svg6
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/newline-ltr.svg6
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/newline-rtl.svg6
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/newspaper-ltr.svg4
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/newspaper-rtl.svg4
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/noWikiText-ltr.svg6
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/noWikiText-rtl.svg6
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/outdent-ltr.svg6
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/outdent-rtl.svg6
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/outline-ltr.svg7
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/outline-rtl.svg7
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/photoGallery-ltr.svg6
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/photoGallery-rtl.svg6
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/picture.svg8
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/play-ltr.svg6
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/play-rtl.svg6
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/printer-ltr.svg4
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/printer-rtl.svg4
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/puzzle-ltr.svg4
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/puzzle-rtl.svg4
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/quotes-ltr.svg11
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/quotes-rtl.svg11
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/quotesAdd-ltr.svg6
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/quotesAdd-rtl.svg6
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/redirect-ltr.svg8
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/redirect-rtl.svg9
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/regular-expression.svg9
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/remove.svg6
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/ribbonPrize.svg9
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/search-ltr.svg6
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/search-rtl.svg6
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/secure-link.svg6
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/settings.svg6
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/signature-ltr.svg4
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/signature-rtl.svg4
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/smaller-ltr.svg7
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/smaller-rtl.svg7
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/specialCharacter.svg6
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/speechBubble-ltr.svg6
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/speechBubble-rtl.svg6
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/speechBubbleAdd-ltr.svg7
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/speechBubbleAdd-rtl.svg7
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/speechBubbles-ltr.svg6
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/speechBubbles-rtl.svg6
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/star.svg4
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/stop.svg4
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/strikethrough-a.svg7
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/strikethrough-s.svg7
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/strikethrough-y.svg7
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/stripeFlow-ltr.svg4
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/stripeFlow-rtl.svg4
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/stripeSideMenu.svg12
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/stripeSummary-ltr.svg6
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/stripeSummary-rtl.svg6
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/stripeToC-ltr.svg6
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/stripeToC-rtl.svg6
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/subscript-ltr.svg5
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/subscript-rtl.svg5
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/sun-ltr.svg5
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/sun-rtl.svg5
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/superscript-ltr.svg5
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/superscript-rtl.svg5
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/table-caption.svg7
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/table-insert-column-ltr.svg11
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/table-insert-column-rtl.svg11
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/table-insert-row-after.svg11
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/table-insert-row-before.svg11
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/table-merge-cells.svg10
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/table.svg7
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/tag.svg6
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/templateAdd-ltr.svg7
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/templateAdd-rtl.svg7
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/text-dir-lefttoright.svg6
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/text-dir-righttoleft.svg6
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/text-style.svg7
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/translation-ltr.svg4
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/translation-rtl.svg4
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/trash.svg4
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/trashUndo-ltr.svg6
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/trashUndo-rtl.svg6
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/unLock-ltr.svg4
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/unLock-rtl.svg4
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/unStar.svg4
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/underline-a.svg7
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/underline-u.svg7
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/upTriangle.svg4
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/upload-ltr.svg6
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/upload-rtl.svg6
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/userActive-ltr.svg4
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/userActive-rtl.svg4
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/userAvatar.svg8
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/userInactive-ltr.svg4
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/userInactive-rtl.svg4
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/userTalk-ltr.svg4
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/userTalk-rtl.svg4
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/viewCompact.svg14
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/viewDetails-ltr.svg9
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/viewDetails-rtl.svg9
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/visionSimulator.svg4
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/watchlist-ltr.svg6
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/watchlist-rtl.svg6
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/wikiText.svg15
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/wikitrail-ltr.svg8
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/wikitrail-rtl.svg8
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/window.svg7
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/indicators/alert.svg6
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/indicators/arrow-down.svg8
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/indicators/arrow-ltr.svg8
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/indicators/arrow-rtl.svg8
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/indicators/arrow-up.svg8
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/indicators/required.svg6
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/indicators/search-ltr.svg6
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/indicators/search-rtl.svg6
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/textures/pending.gifbin2032 -> 0 bytes
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/images/textures/transparency.svg10
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/indicators.json29
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/layouts.less135
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/textures.json8
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/tools.less422
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/widgets.less978
-rw-r--r--vendor/oojs/oojs-ui/src/themes/mediawiki/windows.less300
-rw-r--r--vendor/oojs/oojs-ui/src/toolgroups/BarToolGroup.js35
-rw-r--r--vendor/oojs/oojs-ui/src/toolgroups/ListToolGroup.js133
-rw-r--r--vendor/oojs/oojs-ui/src/toolgroups/MenuToolGroup.js58
-rw-r--r--vendor/oojs/oojs-ui/src/toolgroups/PopupToolGroup.js187
-rw-r--r--vendor/oojs/oojs-ui/src/tools/PopupTool.js59
-rw-r--r--vendor/oojs/oojs-ui/src/tools/ToolGroupTool.js96
-rw-r--r--vendor/oojs/oojs-ui/src/widgets/ActionWidget.js170
-rw-r--r--vendor/oojs/oojs-ui/src/widgets/ButtonGroupWidget.js53
-rw-r--r--vendor/oojs/oojs-ui/src/widgets/ButtonInputWidget.js121
-rw-r--r--vendor/oojs/oojs-ui/src/widgets/ButtonOptionWidget.js60
-rw-r--r--vendor/oojs/oojs-ui/src/widgets/ButtonSelectWidget.js62
-rw-r--r--vendor/oojs/oojs-ui/src/widgets/ButtonWidget.js215
-rw-r--r--vendor/oojs/oojs-ui/src/widgets/CheckboxInputWidget.js110
-rw-r--r--vendor/oojs/oojs-ui/src/widgets/ComboBoxWidget.js230
-rw-r--r--vendor/oojs/oojs-ui/src/widgets/DecoratedOptionWidget.js55
-rw-r--r--vendor/oojs/oojs-ui/src/widgets/DropdownInputWidget.js137
-rw-r--r--vendor/oojs/oojs-ui/src/widgets/DropdownWidget.js149
-rw-r--r--vendor/oojs/oojs-ui/src/widgets/GroupWidget.js48
-rw-r--r--vendor/oojs/oojs-ui/src/widgets/IconWidget.js54
-rw-r--r--vendor/oojs/oojs-ui/src/widgets/IndicatorWidget.js52
-rw-r--r--vendor/oojs/oojs-ui/src/widgets/InputWidget.js207
-rw-r--r--vendor/oojs/oojs-ui/src/widgets/ItemWidget.js48
-rw-r--r--vendor/oojs/oojs-ui/src/widgets/LabelWidget.js84
-rw-r--r--vendor/oojs/oojs-ui/src/widgets/MenuOptionWidget.js33
-rw-r--r--vendor/oojs/oojs-ui/src/widgets/MenuSectionOptionWidget.js55
-rw-r--r--vendor/oojs/oojs-ui/src/widgets/MenuSelectWidget.js254
-rw-r--r--vendor/oojs/oojs-ui/src/widgets/OptionWidget.js177
-rw-r--r--vendor/oojs/oojs-ui/src/widgets/OutlineControlsWidget.js145
-rw-r--r--vendor/oojs/oojs-ui/src/widgets/OutlineOptionWidget.js130
-rw-r--r--vendor/oojs/oojs-ui/src/widgets/OutlineSelectWidget.js34
-rw-r--r--vendor/oojs/oojs-ui/src/widgets/PopupButtonWidget.js57
-rw-r--r--vendor/oojs/oojs-ui/src/widgets/PopupWidget.js395
-rw-r--r--vendor/oojs/oojs-ui/src/widgets/ProgressBarWidget.js96
-rw-r--r--vendor/oojs/oojs-ui/src/widgets/RadioInputWidget.js94
-rw-r--r--vendor/oojs/oojs-ui/src/widgets/RadioOptionWidget.js66
-rw-r--r--vendor/oojs/oojs-ui/src/widgets/RadioSelectWidget.js58
-rw-r--r--vendor/oojs/oojs-ui/src/widgets/SearchWidget.js176
-rw-r--r--vendor/oojs/oojs-ui/src/widgets/SelectWidget.js630
-rw-r--r--vendor/oojs/oojs-ui/src/widgets/TabOptionWidget.js31
-rw-r--r--vendor/oojs/oojs-ui/src/widgets/TabSelectWidget.js33
-rw-r--r--vendor/oojs/oojs-ui/src/widgets/TextInputMenuSelectWidget.js103
-rw-r--r--vendor/oojs/oojs-ui/src/widgets/TextInputWidget.js535
-rw-r--r--vendor/oojs/oojs-ui/src/widgets/ToggleButtonWidget.js114
-rw-r--r--vendor/oojs/oojs-ui/src/widgets/ToggleSwitchWidget.js92
-rw-r--r--vendor/oojs/oojs-ui/src/widgets/ToggleWidget.js71
-rw-r--r--vendor/oojs/oojs-ui/tests/Element.test.js52
-rw-r--r--vendor/oojs/oojs-ui/tests/JSPHP.test.karma.js61
-rw-r--r--vendor/oojs/oojs-ui/tests/JSPHP.test.standalone.js55
-rw-r--r--vendor/oojs/oojs-ui/tests/Process.test.js179
-rw-r--r--vendor/oojs/oojs-ui/tests/QUnit.assert.equalDomElement.js113
-rw-r--r--vendor/oojs/oojs-ui/tests/elements/FlaggedElement.test.js64
-rw-r--r--vendor/oojs/oojs-ui/tests/index.php77
-rw-r--r--vendor/oyejorge/less.php/CHANGES.md6
-rw-r--r--vendor/oyejorge/less.php/LICENSE178
-rw-r--r--vendor/oyejorge/less.php/README.md322
-rw-r--r--vendor/oyejorge/less.php/bin/lessc191
-rw-r--r--vendor/oyejorge/less.php/composer.json31
-rw-r--r--vendor/oyejorge/less.php/lessc.inc.php268
-rw-r--r--vendor/oyejorge/less.php/lib/Less/.easymin/ignore_prefixes2
-rw-r--r--vendor/oyejorge/less.php/lib/Less/Autoloader.php79
-rw-r--r--vendor/oyejorge/less.php/lib/Less/Cache.php316
-rw-r--r--vendor/oyejorge/less.php/lib/Less/Colors.php170
-rw-r--r--vendor/oyejorge/less.php/lib/Less/Configurable.php69
-rw-r--r--vendor/oyejorge/less.php/lib/Less/Environment.php166
-rw-r--r--vendor/oyejorge/less.php/lib/Less/Exception/Chunk.php203
-rw-r--r--vendor/oyejorge/less.php/lib/Less/Exception/Compiler.php11
-rw-r--r--vendor/oyejorge/less.php/lib/Less/Exception/Parser.php125
-rw-r--r--vendor/oyejorge/less.php/lib/Less/Functions.php1183
-rw-r--r--vendor/oyejorge/less.php/lib/Less/Less.php.combine17
-rw-r--r--vendor/oyejorge/less.php/lib/Less/Mime.php41
-rw-r--r--vendor/oyejorge/less.php/lib/Less/Output.php49
-rw-r--r--vendor/oyejorge/less.php/lib/Less/Output/Mapped.php122
-rw-r--r--vendor/oyejorge/less.php/lib/Less/Parser.php2627
-rw-r--r--vendor/oyejorge/less.php/lib/Less/SourceMap/Base64VLQ.php187
-rw-r--r--vendor/oyejorge/less.php/lib/Less/SourceMap/Generator.php365
-rw-r--r--vendor/oyejorge/less.php/lib/Less/Tree.php90
-rw-r--r--vendor/oyejorge/less.php/lib/Less/Tree/Alpha.php51
-rw-r--r--vendor/oyejorge/less.php/lib/Less/Tree/Anonymous.php58
-rw-r--r--vendor/oyejorge/less.php/lib/Less/Tree/Assignment.php39
-rw-r--r--vendor/oyejorge/less.php/lib/Less/Tree/Attribute.php54
-rw-r--r--vendor/oyejorge/less.php/lib/Less/Tree/Call.php121
-rw-r--r--vendor/oyejorge/less.php/lib/Less/Tree/Color.php230
-rw-r--r--vendor/oyejorge/less.php/lib/Less/Tree/Comment.php51
-rw-r--r--vendor/oyejorge/less.php/lib/Less/Tree/Condition.php72
-rw-r--r--vendor/oyejorge/less.php/lib/Less/Tree/DefaultFunc.php34
-rw-r--r--vendor/oyejorge/less.php/lib/Less/Tree/DetachedRuleset.php40
-rw-r--r--vendor/oyejorge/less.php/lib/Less/Tree/Dimension.php201
-rw-r--r--vendor/oyejorge/less.php/lib/Less/Tree/Directive.php100
-rw-r--r--vendor/oyejorge/less.php/lib/Less/Tree/Element.php75
-rw-r--r--vendor/oyejorge/less.php/lib/Less/Tree/Expression.php97
-rw-r--r--vendor/oyejorge/less.php/lib/Less/Tree/Extend.php77
-rw-r--r--vendor/oyejorge/less.php/lib/Less/Tree/Import.php307
-rw-r--r--vendor/oyejorge/less.php/lib/Less/Tree/Javascript.php30
-rw-r--r--vendor/oyejorge/less.php/lib/Less/Tree/Keyword.php44
-rw-r--r--vendor/oyejorge/less.php/lib/Less/Tree/Media.php179
-rw-r--r--vendor/oyejorge/less.php/lib/Less/Tree/Mixin/Call.php202
-rw-r--r--vendor/oyejorge/less.php/lib/Less/Tree/Mixin/Definition.php241
-rw-r--r--vendor/oyejorge/less.php/lib/Less/Tree/NameValue.php41
-rw-r--r--vendor/oyejorge/less.php/lib/Less/Tree/Negative.php37
-rw-r--r--vendor/oyejorge/less.php/lib/Less/Tree/Operation.php70
-rw-r--r--vendor/oyejorge/less.php/lib/Less/Tree/Paren.php35
-rw-r--r--vendor/oyejorge/less.php/lib/Less/Tree/Quoted.php81
-rw-r--r--vendor/oyejorge/less.php/lib/Less/Tree/Rule.php115
-rw-r--r--vendor/oyejorge/less.php/lib/Less/Tree/Ruleset.php643
-rw-r--r--vendor/oyejorge/less.php/lib/Less/Tree/RulesetCall.php26
-rw-r--r--vendor/oyejorge/less.php/lib/Less/Tree/Selector.php168
-rw-r--r--vendor/oyejorge/less.php/lib/Less/Tree/UnicodeDescriptor.php29
-rw-r--r--vendor/oyejorge/less.php/lib/Less/Tree/Unit.php147
-rw-r--r--vendor/oyejorge/less.php/lib/Less/Tree/UnitConversions.php35
-rw-r--r--vendor/oyejorge/less.php/lib/Less/Tree/Url.php76
-rw-r--r--vendor/oyejorge/less.php/lib/Less/Tree/Value.php48
-rw-r--r--vendor/oyejorge/less.php/lib/Less/Tree/Variable.php52
-rw-r--r--vendor/oyejorge/less.php/lib/Less/Version.php15
-rw-r--r--vendor/oyejorge/less.php/lib/Less/Visitor.php49
-rw-r--r--vendor/oyejorge/less.php/lib/Less/Visitor/extendFinder.php114
-rw-r--r--vendor/oyejorge/less.php/lib/Less/Visitor/import.php139
-rw-r--r--vendor/oyejorge/less.php/lib/Less/Visitor/joinSelector.php70
-rw-r--r--vendor/oyejorge/less.php/lib/Less/Visitor/processExtends.php469
-rw-r--r--vendor/oyejorge/less.php/lib/Less/Visitor/toCSS.php292
-rw-r--r--vendor/oyejorge/less.php/lib/Less/VisitorReplacing.php75
-rw-r--r--vendor/psr/log/Psr/Log/LoggerAwareTrait.php22
-rw-r--r--vendor/psr/log/Psr/Log/LoggerTrait.php131
-rw-r--r--vendor/ruflin/elastica/CHANGELOG.md1038
-rw-r--r--vendor/ruflin/elastica/CONTRIBUTING.md75
-rw-r--r--vendor/ruflin/elastica/Dockerfile58
-rw-r--r--vendor/ruflin/elastica/LICENSE.txt21
-rw-r--r--vendor/ruflin/elastica/Makefile108
-rw-r--r--vendor/ruflin/elastica/README.md31
-rw-r--r--vendor/ruflin/elastica/Vagrantfile18
-rw-r--r--vendor/ruflin/elastica/ansible/es-playbook.yml20
-rw-r--r--vendor/ruflin/elastica/ansible/provision.sh63
-rw-r--r--vendor/ruflin/elastica/ansible/roles/base/tasks/main.yml13
-rw-r--r--vendor/ruflin/elastica/ansible/roles/elasticsearch/handlers/main.yml6
-rw-r--r--vendor/ruflin/elastica/ansible/roles/elasticsearch/tasks/main.yml101
-rw-r--r--vendor/ruflin/elastica/ansible/roles/elasticsearch/templates/config-0.yml10
-rw-r--r--vendor/ruflin/elastica/ansible/roles/elasticsearch/templates/config-1.yml10
-rw-r--r--vendor/ruflin/elastica/ansible/roles/elasticsearch/templates/config-default.yml40
-rw-r--r--vendor/ruflin/elastica/ansible/roles/elasticsearch/templates/elasticsearch.service229
-rw-r--r--vendor/ruflin/elastica/ansible/roles/elasticsearch/templates/logging.yml56
-rw-r--r--vendor/ruflin/elastica/ansible/roles/nginx/handlers/main.yml6
-rw-r--r--vendor/ruflin/elastica/ansible/roles/nginx/tasks/main.yml26
-rw-r--r--vendor/ruflin/elastica/ansible/roles/nginx/templates/mime.types.j2109
-rw-r--r--vendor/ruflin/elastica/ansible/roles/nginx/templates/nginx.conf.j235
-rw-r--r--vendor/ruflin/elastica/ansible/roles/php/tasks/main.yml43
-rw-r--r--vendor/ruflin/elastica/composer.json43
-rw-r--r--vendor/ruflin/elastica/docker-compose.yml27
-rw-r--r--vendor/ruflin/elastica/env/elasticsearch/Dockerfile26
-rw-r--r--vendor/ruflin/elastica/env/elasticsearch/elasticsearch.yml39
-rw-r--r--vendor/ruflin/elastica/env/elasticsearch/logging.yml56
-rw-r--r--vendor/ruflin/elastica/env/nginx/mime.types109
-rw-r--r--vendor/ruflin/elastica/env/nginx/nginx.conf38
-rw-r--r--vendor/ruflin/elastica/lib/Elastica/AbstractUpdateAction.php568
-rw-r--r--vendor/ruflin/elastica/lib/Elastica/Aggregation/AbstractAggregation.php97
-rw-r--r--vendor/ruflin/elastica/lib/Elastica/Aggregation/AbstractSimpleAggregation.php37
-rw-r--r--vendor/ruflin/elastica/lib/Elastica/Aggregation/AbstractTermsAggregation.php97
-rw-r--r--vendor/ruflin/elastica/lib/Elastica/Aggregation/Avg.php11
-rw-r--r--vendor/ruflin/elastica/lib/Elastica/Aggregation/Cardinality.php38
-rw-r--r--vendor/ruflin/elastica/lib/Elastica/Aggregation/DateHistogram.php130
-rw-r--r--vendor/ruflin/elastica/lib/Elastica/Aggregation/DateRange.php22
-rw-r--r--vendor/ruflin/elastica/lib/Elastica/Aggregation/ExtendedStats.php11
-rw-r--r--vendor/ruflin/elastica/lib/Elastica/Aggregation/Filter.php53
-rw-r--r--vendor/ruflin/elastica/lib/Elastica/Aggregation/Filters.php59
-rw-r--r--vendor/ruflin/elastica/lib/Elastica/Aggregation/GeoDistance.php104
-rw-r--r--vendor/ruflin/elastica/lib/Elastica/Aggregation/GeohashGrid.php68
-rw-r--r--vendor/ruflin/elastica/lib/Elastica/Aggregation/GlobalAggregation.php11
-rw-r--r--vendor/ruflin/elastica/lib/Elastica/Aggregation/Histogram.php59
-rw-r--r--vendor/ruflin/elastica/lib/Elastica/Aggregation/IpRange.php72
-rw-r--r--vendor/ruflin/elastica/lib/Elastica/Aggregation/Max.php11
-rw-r--r--vendor/ruflin/elastica/lib/Elastica/Aggregation/Min.php11
-rw-r--r--vendor/ruflin/elastica/lib/Elastica/Aggregation/Missing.php32
-rw-r--r--vendor/ruflin/elastica/lib/Elastica/Aggregation/Nested.php32
-rw-r--r--vendor/ruflin/elastica/lib/Elastica/Aggregation/Percentiles.php59
-rw-r--r--vendor/ruflin/elastica/lib/Elastica/Aggregation/Range.php58
-rw-r--r--vendor/ruflin/elastica/lib/Elastica/Aggregation/ReverseNested.php49
-rw-r--r--vendor/ruflin/elastica/lib/Elastica/Aggregation/ScriptedMetric.php82
-rw-r--r--vendor/ruflin/elastica/lib/Elastica/Aggregation/SignificantTerms.php27
-rw-r--r--vendor/ruflin/elastica/lib/Elastica/Aggregation/Stats.php11
-rw-r--r--vendor/ruflin/elastica/lib/Elastica/Aggregation/Sum.php11
-rw-r--r--vendor/ruflin/elastica/lib/Elastica/Aggregation/Terms.php23
-rw-r--r--vendor/ruflin/elastica/lib/Elastica/Aggregation/TopHits.php156
-rw-r--r--vendor/ruflin/elastica/lib/Elastica/Aggregation/ValueCount.php32
-rw-r--r--vendor/ruflin/elastica/lib/Elastica/Bulk.php442
-rw-r--r--vendor/ruflin/elastica/lib/Elastica/Bulk/Action.php228
-rw-r--r--vendor/ruflin/elastica/lib/Elastica/Bulk/Action/AbstractDocument.php166
-rw-r--r--vendor/ruflin/elastica/lib/Elastica/Bulk/Action/CreateDocument.php10
-rw-r--r--vendor/ruflin/elastica/lib/Elastica/Bulk/Action/DeleteDocument.php33
-rw-r--r--vendor/ruflin/elastica/lib/Elastica/Bulk/Action/IndexDocument.php53
-rw-r--r--vendor/ruflin/elastica/lib/Elastica/Bulk/Action/UpdateDocument.php65
-rw-r--r--vendor/ruflin/elastica/lib/Elastica/Bulk/Response.php46
-rw-r--r--vendor/ruflin/elastica/lib/Elastica/Bulk/ResponseSet.php141
-rw-r--r--vendor/ruflin/elastica/lib/Elastica/Client.php719
-rw-r--r--vendor/ruflin/elastica/lib/Elastica/Cluster.php192
-rw-r--r--vendor/ruflin/elastica/lib/Elastica/Cluster/Health.php185
-rw-r--r--vendor/ruflin/elastica/lib/Elastica/Cluster/Health/Index.php137
-rw-r--r--vendor/ruflin/elastica/lib/Elastica/Cluster/Health/Shard.php102
-rw-r--r--vendor/ruflin/elastica/lib/Elastica/Cluster/Settings.php202
-rw-r--r--vendor/ruflin/elastica/lib/Elastica/Connection.php320
-rw-r--r--vendor/ruflin/elastica/lib/Elastica/Connection/ConnectionPool.php122
-rw-r--r--vendor/ruflin/elastica/lib/Elastica/Connection/Strategy/CallbackStrategy.php51
-rw-r--r--vendor/ruflin/elastica/lib/Elastica/Connection/Strategy/RoundRobin.php24
-rw-r--r--vendor/ruflin/elastica/lib/Elastica/Connection/Strategy/Simple.php30
-rw-r--r--vendor/ruflin/elastica/lib/Elastica/Connection/Strategy/StrategyFactory.php45
-rw-r--r--vendor/ruflin/elastica/lib/Elastica/Connection/Strategy/StrategyInterface.php17
-rw-r--r--vendor/ruflin/elastica/lib/Elastica/Document.php356
-rw-r--r--vendor/ruflin/elastica/lib/Elastica/Exception/Bulk/Response/ActionException.php65
-rw-r--r--vendor/ruflin/elastica/lib/Elastica/Exception/Bulk/ResponseException.php98
-rw-r--r--vendor/ruflin/elastica/lib/Elastica/Exception/Bulk/UdpException.php8
-rw-r--r--vendor/ruflin/elastica/lib/Elastica/Exception/BulkException.php6
-rw-r--r--vendor/ruflin/elastica/lib/Elastica/Exception/ClientException.php11
-rw-r--r--vendor/ruflin/elastica/lib/Elastica/Exception/Connection/GuzzleException.php50
-rw-r--r--vendor/ruflin/elastica/lib/Elastica/Exception/Connection/HttpException.php86
-rw-r--r--vendor/ruflin/elastica/lib/Elastica/Exception/Connection/MemcacheException.php13
-rw-r--r--vendor/ruflin/elastica/lib/Elastica/Exception/Connection/ThriftException.php49
-rw-r--r--vendor/ruflin/elastica/lib/Elastica/Exception/ConnectionException.php58
-rw-r--r--vendor/ruflin/elastica/lib/Elastica/Exception/ElasticsearchException.php91
-rw-r--r--vendor/ruflin/elastica/lib/Elastica/Exception/ExceptionInterface.php11
-rw-r--r--vendor/ruflin/elastica/lib/Elastica/Exception/InvalidException.php11
-rw-r--r--vendor/ruflin/elastica/lib/Elastica/Exception/JSONParseException.php9
-rw-r--r--vendor/ruflin/elastica/lib/Elastica/Exception/NotFoundException.php11
-rw-r--r--vendor/ruflin/elastica/lib/Elastica/Exception/NotImplementedException.php13
-rw-r--r--vendor/ruflin/elastica/lib/Elastica/Exception/PartialShardFailureException.php28
-rw-r--r--vendor/ruflin/elastica/lib/Elastica/Exception/QueryBuilderException.php11
-rw-r--r--vendor/ruflin/elastica/lib/Elastica/Exception/ResponseException.php70
-rw-r--r--vendor/ruflin/elastica/lib/Elastica/Exception/RuntimeException.php11
-rw-r--r--vendor/ruflin/elastica/lib/Elastica/Facet/AbstractFacet.php145
-rw-r--r--vendor/ruflin/elastica/lib/Elastica/Facet/DateHistogram.php58
-rw-r--r--vendor/ruflin/elastica/lib/Elastica/Facet/Filter.php27
-rw-r--r--vendor/ruflin/elastica/lib/Elastica/Facet/GeoCluster.php66
-rw-r--r--vendor/ruflin/elastica/lib/Elastica/Facet/GeoDistance.php69
-rw-r--r--vendor/ruflin/elastica/lib/Elastica/Facet/Histogram.php96
-rw-r--r--vendor/ruflin/elastica/lib/Elastica/Facet/Query.php27
-rw-r--r--vendor/ruflin/elastica/lib/Elastica/Facet/Range.php143
-rw-r--r--vendor/ruflin/elastica/lib/Elastica/Facet/Statistical.php64
-rw-r--r--vendor/ruflin/elastica/lib/Elastica/Facet/Terms.php137
-rw-r--r--vendor/ruflin/elastica/lib/Elastica/Facet/TermsStats.php107
-rw-r--r--vendor/ruflin/elastica/lib/Elastica/Filter/AbstractFilter.php59
-rw-r--r--vendor/ruflin/elastica/lib/Elastica/Filter/AbstractGeoDistance.php198
-rw-r--r--vendor/ruflin/elastica/lib/Elastica/Filter/AbstractGeoShape.php52
-rw-r--r--vendor/ruflin/elastica/lib/Elastica/Filter/AbstractMulti.php89
-rw-r--r--vendor/ruflin/elastica/lib/Elastica/Filter/Bool.php15
-rw-r--r--vendor/ruflin/elastica/lib/Elastica/Filter/BoolAnd.php20
-rw-r--r--vendor/ruflin/elastica/lib/Elastica/Filter/BoolFilter.php133
-rw-r--r--vendor/ruflin/elastica/lib/Elastica/Filter/BoolNot.php42
-rw-r--r--vendor/ruflin/elastica/lib/Elastica/Filter/BoolOr.php20
-rw-r--r--vendor/ruflin/elastica/lib/Elastica/Filter/Exists.php34
-rw-r--r--vendor/ruflin/elastica/lib/Elastica/Filter/GeoBoundingBox.php49
-rw-r--r--vendor/ruflin/elastica/lib/Elastica/Filter/GeoDistance.php76
-rw-r--r--vendor/ruflin/elastica/lib/Elastica/Filter/GeoDistanceRange.php103
-rw-r--r--vendor/ruflin/elastica/lib/Elastica/Filter/GeoPolygon.php56
-rw-r--r--vendor/ruflin/elastica/lib/Elastica/Filter/GeoShapePreIndexed.php84
-rw-r--r--vendor/ruflin/elastica/lib/Elastica/Filter/GeoShapeProvided.php73
-rw-r--r--vendor/ruflin/elastica/lib/Elastica/Filter/GeohashCell.php47
-rw-r--r--vendor/ruflin/elastica/lib/Elastica/Filter/HasChild.php95
-rw-r--r--vendor/ruflin/elastica/lib/Elastica/Filter/HasParent.php69
-rw-r--r--vendor/ruflin/elastica/lib/Elastica/Filter/Ids.php94
-rw-r--r--vendor/ruflin/elastica/lib/Elastica/Filter/Indices.php78
-rw-r--r--vendor/ruflin/elastica/lib/Elastica/Filter/Limit.php34
-rw-r--r--vendor/ruflin/elastica/lib/Elastica/Filter/MatchAll.php20
-rw-r--r--vendor/ruflin/elastica/lib/Elastica/Filter/Missing.php60
-rw-r--r--vendor/ruflin/elastica/lib/Elastica/Filter/Nested.php62
-rw-r--r--vendor/ruflin/elastica/lib/Elastica/Filter/NumericRange.php13
-rw-r--r--vendor/ruflin/elastica/lib/Elastica/Filter/Prefix.php80
-rw-r--r--vendor/ruflin/elastica/lib/Elastica/Filter/Query.php91
-rw-r--r--vendor/ruflin/elastica/lib/Elastica/Filter/Range.php73
-rw-r--r--vendor/ruflin/elastica/lib/Elastica/Filter/Regexp.php112
-rw-r--r--vendor/ruflin/elastica/lib/Elastica/Filter/Script.php47
-rw-r--r--vendor/ruflin/elastica/lib/Elastica/Filter/Term.php47
-rw-r--r--vendor/ruflin/elastica/lib/Elastica/Filter/Terms.php149
-rw-r--r--vendor/ruflin/elastica/lib/Elastica/Filter/Type.php59
-rw-r--r--vendor/ruflin/elastica/lib/Elastica/Index.php515
-rw-r--r--vendor/ruflin/elastica/lib/Elastica/Index/Settings.php366
-rw-r--r--vendor/ruflin/elastica/lib/Elastica/Index/Stats.php108
-rw-r--r--vendor/ruflin/elastica/lib/Elastica/Index/Status.php150
-rw-r--r--vendor/ruflin/elastica/lib/Elastica/JSON.php67
-rw-r--r--vendor/ruflin/elastica/lib/Elastica/Log.php81
-rw-r--r--vendor/ruflin/elastica/lib/Elastica/Multi/ResultSet.php205
-rw-r--r--vendor/ruflin/elastica/lib/Elastica/Multi/Search.php203
-rw-r--r--vendor/ruflin/elastica/lib/Elastica/Node.php161
-rw-r--r--vendor/ruflin/elastica/lib/Elastica/Node/Info.php220
-rw-r--r--vendor/ruflin/elastica/lib/Elastica/Node/Stats.php113
-rw-r--r--vendor/ruflin/elastica/lib/Elastica/Param.php167
-rw-r--r--vendor/ruflin/elastica/lib/Elastica/Percolator.php194
-rw-r--r--vendor/ruflin/elastica/lib/Elastica/Query.php488
-rw-r--r--vendor/ruflin/elastica/lib/Elastica/Query/AbstractQuery.php13
-rw-r--r--vendor/ruflin/elastica/lib/Elastica/Query/Bool.php15
-rw-r--r--vendor/ruflin/elastica/lib/Elastica/Query/BoolQuery.php111
-rw-r--r--vendor/ruflin/elastica/lib/Elastica/Query/Boosting.php50
-rw-r--r--vendor/ruflin/elastica/lib/Elastica/Query/Builder.php935
-rw-r--r--vendor/ruflin/elastica/lib/Elastica/Query/Common.php172
-rw-r--r--vendor/ruflin/elastica/lib/Elastica/Query/ConstantScore.php70
-rw-r--r--vendor/ruflin/elastica/lib/Elastica/Query/DisMax.php62
-rw-r--r--vendor/ruflin/elastica/lib/Elastica/Query/Filtered.php97
-rw-r--r--vendor/ruflin/elastica/lib/Elastica/Query/FunctionScore.php260
-rw-r--r--vendor/ruflin/elastica/lib/Elastica/Query/Fuzzy.php87
-rw-r--r--vendor/ruflin/elastica/lib/Elastica/Query/FuzzyLikeThis.php217
-rw-r--r--vendor/ruflin/elastica/lib/Elastica/Query/HasChild.php65
-rw-r--r--vendor/ruflin/elastica/lib/Elastica/Query/HasParent.php63
-rw-r--r--vendor/ruflin/elastica/lib/Elastica/Query/Ids.php121
-rw-r--r--vendor/ruflin/elastica/lib/Elastica/Query/Image.php187
-rw-r--r--vendor/ruflin/elastica/lib/Elastica/Query/Match.php222
-rw-r--r--vendor/ruflin/elastica/lib/Elastica/Query/MatchAll.php20
-rw-r--r--vendor/ruflin/elastica/lib/Elastica/Query/MatchPhrase.php13
-rw-r--r--vendor/ruflin/elastica/lib/Elastica/Query/MatchPhrasePrefix.php13
-rw-r--r--vendor/ruflin/elastica/lib/Elastica/Query/MoreLikeThis.php198
-rw-r--r--vendor/ruflin/elastica/lib/Elastica/Query/MultiMatch.php191
-rw-r--r--vendor/ruflin/elastica/lib/Elastica/Query/Nested.php48
-rw-r--r--vendor/ruflin/elastica/lib/Elastica/Query/Prefix.php47
-rw-r--r--vendor/ruflin/elastica/lib/Elastica/Query/QueryString.php282
-rw-r--r--vendor/ruflin/elastica/lib/Elastica/Query/Range.php38
-rw-r--r--vendor/ruflin/elastica/lib/Elastica/Query/Regexp.php40
-rw-r--r--vendor/ruflin/elastica/lib/Elastica/Query/Simple.php54
-rw-r--r--vendor/ruflin/elastica/lib/Elastica/Query/SimpleQueryString.php83
-rw-r--r--vendor/ruflin/elastica/lib/Elastica/Query/Term.php49
-rw-r--r--vendor/ruflin/elastica/lib/Elastica/Query/Terms.php107
-rw-r--r--vendor/ruflin/elastica/lib/Elastica/Query/TopChildren.php53
-rw-r--r--vendor/ruflin/elastica/lib/Elastica/Query/Wildcard.php40
-rw-r--r--vendor/ruflin/elastica/lib/Elastica/QueryBuilder.php114
-rw-r--r--vendor/ruflin/elastica/lib/Elastica/QueryBuilder/DSL.php22
-rw-r--r--vendor/ruflin/elastica/lib/Elastica/QueryBuilder/DSL/Aggregation.php470
-rw-r--r--vendor/ruflin/elastica/lib/Elastica/QueryBuilder/DSL/Filter.php480
-rw-r--r--vendor/ruflin/elastica/lib/Elastica/QueryBuilder/DSL/Query.php586
-rw-r--r--vendor/ruflin/elastica/lib/Elastica/QueryBuilder/DSL/Suggest.php83
-rw-r--r--vendor/ruflin/elastica/lib/Elastica/QueryBuilder/Facade.php64
-rw-r--r--vendor/ruflin/elastica/lib/Elastica/QueryBuilder/Version.php101
-rw-r--r--vendor/ruflin/elastica/lib/Elastica/QueryBuilder/Version/Version090.php97
-rw-r--r--vendor/ruflin/elastica/lib/Elastica/QueryBuilder/Version/Version100.php123
-rw-r--r--vendor/ruflin/elastica/lib/Elastica/QueryBuilder/Version/Version110.php131
-rw-r--r--vendor/ruflin/elastica/lib/Elastica/QueryBuilder/Version/Version120.php137
-rw-r--r--vendor/ruflin/elastica/lib/Elastica/QueryBuilder/Version/Version130.php142
-rw-r--r--vendor/ruflin/elastica/lib/Elastica/QueryBuilder/Version/Version140.php145
-rw-r--r--vendor/ruflin/elastica/lib/Elastica/QueryBuilder/Version/Version150.php14
-rw-r--r--vendor/ruflin/elastica/lib/Elastica/Request.php204
-rw-r--r--vendor/ruflin/elastica/lib/Elastica/Rescore/AbstractRescore.php36
-rw-r--r--vendor/ruflin/elastica/lib/Elastica/Rescore/Query.php91
-rw-r--r--vendor/ruflin/elastica/lib/Elastica/Response.php308
-rw-r--r--vendor/ruflin/elastica/lib/Elastica/Result.php217
-rw-r--r--vendor/ruflin/elastica/lib/Elastica/ResultSet.php433
-rw-r--r--vendor/ruflin/elastica/lib/Elastica/ScanAndScroll.php80
-rw-r--r--vendor/ruflin/elastica/lib/Elastica/Script.php163
-rw-r--r--vendor/ruflin/elastica/lib/Elastica/ScriptFields.php65
-rw-r--r--vendor/ruflin/elastica/lib/Elastica/Scroll.php174
-rw-r--r--vendor/ruflin/elastica/lib/Elastica/Search.php553
-rw-r--r--vendor/ruflin/elastica/lib/Elastica/SearchableInterface.php52
-rw-r--r--vendor/ruflin/elastica/lib/Elastica/Snapshot.php176
-rw-r--r--vendor/ruflin/elastica/lib/Elastica/Status.php177
-rw-r--r--vendor/ruflin/elastica/lib/Elastica/Suggest.php65
-rw-r--r--vendor/ruflin/elastica/lib/Elastica/Suggest/AbstractSuggest.php97
-rw-r--r--vendor/ruflin/elastica/lib/Elastica/Suggest/CandidateGenerator/AbstractCandidateGenerator.php8
-rw-r--r--vendor/ruflin/elastica/lib/Elastica/Suggest/CandidateGenerator/DirectGenerator.php140
-rw-r--r--vendor/ruflin/elastica/lib/Elastica/Suggest/Completion.php26
-rw-r--r--vendor/ruflin/elastica/lib/Elastica/Suggest/Phrase.php164
-rw-r--r--vendor/ruflin/elastica/lib/Elastica/Suggest/Term.php129
-rw-r--r--vendor/ruflin/elastica/lib/Elastica/Tool/CrossIndex.php160
-rw-r--r--vendor/ruflin/elastica/lib/Elastica/Transport/AbstractTransport.php113
-rw-r--r--vendor/ruflin/elastica/lib/Elastica/Transport/Guzzle.php179
-rw-r--r--vendor/ruflin/elastica/lib/Elastica/Transport/Http.php190
-rw-r--r--vendor/ruflin/elastica/lib/Elastica/Transport/HttpAdapter.php156
-rw-r--r--vendor/ruflin/elastica/lib/Elastica/Transport/Https.php27
-rw-r--r--vendor/ruflin/elastica/lib/Elastica/Transport/Memcache.php109
-rw-r--r--vendor/ruflin/elastica/lib/Elastica/Transport/Null.php13
-rw-r--r--vendor/ruflin/elastica/lib/Elastica/Transport/NullTransport.php46
-rw-r--r--vendor/ruflin/elastica/lib/Elastica/Transport/Thrift.php176
-rw-r--r--vendor/ruflin/elastica/lib/Elastica/Type.php572
-rw-r--r--vendor/ruflin/elastica/lib/Elastica/Type/AbstractType.php205
-rw-r--r--vendor/ruflin/elastica/lib/Elastica/Type/Mapping.php297
-rw-r--r--vendor/ruflin/elastica/lib/Elastica/Util.php194
-rw-r--r--vendor/ruflin/elastica/phpdoc.dist.xml13
-rw-r--r--vendor/ruflin/elastica/test/bootstrap.php5
-rw-r--r--vendor/ruflin/elastica/test/data/test.docbin0 -> 22016 bytes
-rw-r--r--vendor/ruflin/elastica/test/data/test.docxbin0 -> 25890 bytes
-rw-r--r--vendor/ruflin/elastica/test/data/test.jpgbin0 -> 4459 bytes
-rw-r--r--vendor/ruflin/elastica/test/data/test.pdfbin0 -> 16107 bytes
-rw-r--r--vendor/ruflin/elastica/test/data/test.txt1
-rw-r--r--vendor/ruflin/elastica/test/lib/Elastica/Test/Aggregation/AvgTest.php39
-rw-r--r--vendor/ruflin/elastica/test/lib/Elastica/Test/Aggregation/BaseAggregationTest.php8
-rw-r--r--vendor/ruflin/elastica/test/lib/Elastica/Test/Aggregation/CardinalityTest.php132
-rw-r--r--vendor/ruflin/elastica/test/lib/Elastica/Test/Aggregation/DateHistogramTest.php103
-rw-r--r--vendor/ruflin/elastica/test/lib/Elastica/Test/Aggregation/DateRangeTest.php52
-rw-r--r--vendor/ruflin/elastica/test/lib/Elastica/Test/Aggregation/ExtendedStatsTest.php45
-rw-r--r--vendor/ruflin/elastica/test/lib/Elastica/Test/Aggregation/FilterTest.php113
-rw-r--r--vendor/ruflin/elastica/test/lib/Elastica/Test/Aggregation/FiltersTest.php120
-rw-r--r--vendor/ruflin/elastica/test/lib/Elastica/Test/Aggregation/GeoDistanceTest.php46
-rw-r--r--vendor/ruflin/elastica/test/lib/Elastica/Test/Aggregation/GeohashGridTest.php46
-rw-r--r--vendor/ruflin/elastica/test/lib/Elastica/Test/Aggregation/GlobalAggregationTest.php27
-rw-r--r--vendor/ruflin/elastica/test/lib/Elastica/Test/Aggregation/HistogramTest.php47
-rw-r--r--vendor/ruflin/elastica/test/lib/Elastica/Test/Aggregation/IpRangeTest.php57
-rw-r--r--vendor/ruflin/elastica/test/lib/Elastica/Test/Aggregation/MaxTest.php79
-rw-r--r--vendor/ruflin/elastica/test/lib/Elastica/Test/Aggregation/MinTest.php40
-rw-r--r--vendor/ruflin/elastica/test/lib/Elastica/Test/Aggregation/MissingTest.php39
-rw-r--r--vendor/ruflin/elastica/test/lib/Elastica/Test/Aggregation/NestedTest.php63
-rw-r--r--vendor/ruflin/elastica/test/lib/Elastica/Test/Aggregation/PercentilesTest.php125
-rw-r--r--vendor/ruflin/elastica/test/lib/Elastica/Test/Aggregation/RangeTest.php78
-rw-r--r--vendor/ruflin/elastica/test/lib/Elastica/Test/Aggregation/ReverseNestedTest.php134
-rw-r--r--vendor/ruflin/elastica/test/lib/Elastica/Test/Aggregation/ScriptTest.php87
-rw-r--r--vendor/ruflin/elastica/test/lib/Elastica/Test/Aggregation/ScriptedMetricTest.php50
-rw-r--r--vendor/ruflin/elastica/test/lib/Elastica/Test/Aggregation/SignificantTermsTest.php72
-rw-r--r--vendor/ruflin/elastica/test/lib/Elastica/Test/Aggregation/StatsTest.php44
-rw-r--r--vendor/ruflin/elastica/test/lib/Elastica/Test/Aggregation/SumTest.php40
-rw-r--r--vendor/ruflin/elastica/test/lib/Elastica/Test/Aggregation/TermsTest.php41
-rw-r--r--vendor/ruflin/elastica/test/lib/Elastica/Test/Aggregation/TopHitsTest.php385
-rw-r--r--vendor/ruflin/elastica/test/lib/Elastica/Test/Aggregation/ValueCountTest.php40
-rw-r--r--vendor/ruflin/elastica/test/lib/Elastica/Test/Base.php142
-rw-r--r--vendor/ruflin/elastica/test/lib/Elastica/Test/Bulk/ActionTest.php66
-rw-r--r--vendor/ruflin/elastica/test/lib/Elastica/Test/Bulk/ResponseSetTest.php200
-rw-r--r--vendor/ruflin/elastica/test/lib/Elastica/Test/BulkTest.php792
-rw-r--r--vendor/ruflin/elastica/test/lib/Elastica/Test/ClientTest.php1160
-rw-r--r--vendor/ruflin/elastica/test/lib/Elastica/Test/Cluster/Health/IndexTest.php144
-rw-r--r--vendor/ruflin/elastica/test/lib/Elastica/Test/Cluster/Health/ShardTest.php85
-rw-r--r--vendor/ruflin/elastica/test/lib/Elastica/Test/Cluster/HealthTest.php147
-rw-r--r--vendor/ruflin/elastica/test/lib/Elastica/Test/Cluster/SettingsTest.php117
-rw-r--r--vendor/ruflin/elastica/test/lib/Elastica/Test/ClusterTest.php83
-rw-r--r--vendor/ruflin/elastica/test/lib/Elastica/Test/Connection/ConnectionPoolTest.php112
-rw-r--r--vendor/ruflin/elastica/test/lib/Elastica/Test/Connection/Strategy/CallbackStrategyTest.php97
-rw-r--r--vendor/ruflin/elastica/test/lib/Elastica/Test/Connection/Strategy/CallbackStrategyTestHelper.php20
-rw-r--r--vendor/ruflin/elastica/test/lib/Elastica/Test/Connection/Strategy/EmptyStrategy.php17
-rw-r--r--vendor/ruflin/elastica/test/lib/Elastica/Test/Connection/Strategy/RoundRobinTest.php128
-rw-r--r--vendor/ruflin/elastica/test/lib/Elastica/Test/Connection/Strategy/SimpleTest.php113
-rw-r--r--vendor/ruflin/elastica/test/lib/Elastica/Test/Connection/Strategy/StrategyFactoryTest.php84
-rw-r--r--vendor/ruflin/elastica/test/lib/Elastica/Test/ConnectionTest.php121
-rw-r--r--vendor/ruflin/elastica/test/lib/Elastica/Test/DocumentTest.php349
-rw-r--r--vendor/ruflin/elastica/test/lib/Elastica/Test/ExampleTest.php61
-rw-r--r--vendor/ruflin/elastica/test/lib/Elastica/Test/Exception/AbstractExceptionTest.php31
-rw-r--r--vendor/ruflin/elastica/test/lib/Elastica/Test/Exception/Bulk/Response/ActionExceptionTest.php8
-rw-r--r--vendor/ruflin/elastica/test/lib/Elastica/Test/Exception/Bulk/ResponseExceptionTest.php8
-rw-r--r--vendor/ruflin/elastica/test/lib/Elastica/Test/Exception/Bulk/UdpExceptionTest.php8
-rw-r--r--vendor/ruflin/elastica/test/lib/Elastica/Test/Exception/BulkExceptionTest.php6
-rw-r--r--vendor/ruflin/elastica/test/lib/Elastica/Test/Exception/ClientExceptionTest.php6
-rw-r--r--vendor/ruflin/elastica/test/lib/Elastica/Test/Exception/Connection/GuzzleExceptionTest.php14
-rw-r--r--vendor/ruflin/elastica/test/lib/Elastica/Test/Exception/Connection/HttpExceptionTest.php8
-rw-r--r--vendor/ruflin/elastica/test/lib/Elastica/Test/Exception/Connection/MemcacheExceptionTest.php8
-rw-r--r--vendor/ruflin/elastica/test/lib/Elastica/Test/Exception/Connection/ThriftExceptionTest.php14
-rw-r--r--vendor/ruflin/elastica/test/lib/Elastica/Test/Exception/ConnectionExceptionTest.php6
-rw-r--r--vendor/ruflin/elastica/test/lib/Elastica/Test/Exception/ElasticsearchExceptionTest.php6
-rw-r--r--vendor/ruflin/elastica/test/lib/Elastica/Test/Exception/InvalidExceptionTest.php6
-rw-r--r--vendor/ruflin/elastica/test/lib/Elastica/Test/Exception/JSONParseExceptionTest.php6
-rw-r--r--vendor/ruflin/elastica/test/lib/Elastica/Test/Exception/NotFoundExceptionTest.php6
-rw-r--r--vendor/ruflin/elastica/test/lib/Elastica/Test/Exception/NotImplementedExceptionTest.php19
-rw-r--r--vendor/ruflin/elastica/test/lib/Elastica/Test/Exception/PartialShardFailureExceptionTest.php54
-rw-r--r--vendor/ruflin/elastica/test/lib/Elastica/Test/Exception/QueryBuilderExceptionTest.php6
-rw-r--r--vendor/ruflin/elastica/test/lib/Elastica/Test/Exception/ResponseExceptionTest.php65
-rw-r--r--vendor/ruflin/elastica/test/lib/Elastica/Test/Exception/RuntimeExceptionTest.php6
-rw-r--r--vendor/ruflin/elastica/test/lib/Elastica/Test/Facet/DateHistogramTest.php106
-rw-r--r--vendor/ruflin/elastica/test/lib/Elastica/Test/Facet/FilterTest.php42
-rw-r--r--vendor/ruflin/elastica/test/lib/Elastica/Test/Facet/GeoClusterTest.php57
-rw-r--r--vendor/ruflin/elastica/test/lib/Elastica/Test/Facet/QueryTest.php42
-rw-r--r--vendor/ruflin/elastica/test/lib/Elastica/Test/Facet/StatisticalTest.php82
-rw-r--r--vendor/ruflin/elastica/test/lib/Elastica/Test/Facet/TermsStatsTest.php113
-rw-r--r--vendor/ruflin/elastica/test/lib/Elastica/Test/Facet/TermsTest.php74
-rw-r--r--vendor/ruflin/elastica/test/lib/Elastica/Test/Filter/AbstractTest.php81
-rw-r--r--vendor/ruflin/elastica/test/lib/Elastica/Test/Filter/BoolAndTest.php86
-rw-r--r--vendor/ruflin/elastica/test/lib/Elastica/Test/Filter/BoolFilterTest.php200
-rw-r--r--vendor/ruflin/elastica/test/lib/Elastica/Test/Filter/BoolNotTest.php27
-rw-r--r--vendor/ruflin/elastica/test/lib/Elastica/Test/Filter/BoolOrTest.php90
-rw-r--r--vendor/ruflin/elastica/test/lib/Elastica/Test/Filter/ExistsTest.php36
-rw-r--r--vendor/ruflin/elastica/test/lib/Elastica/Test/Filter/GeoBoundingBoxTest.php55
-rw-r--r--vendor/ruflin/elastica/test/lib/Elastica/Test/Filter/GeoDistanceRangeTest.php220
-rw-r--r--vendor/ruflin/elastica/test/lib/Elastica/Test/Filter/GeoDistanceTest.php141
-rw-r--r--vendor/ruflin/elastica/test/lib/Elastica/Test/Filter/GeoPolygonTest.php65
-rw-r--r--vendor/ruflin/elastica/test/lib/Elastica/Test/Filter/GeoShapePreIndexedTest.php102
-rw-r--r--vendor/ruflin/elastica/test/lib/Elastica/Test/Filter/GeoShapeProvidedTest.php103
-rw-r--r--vendor/ruflin/elastica/test/lib/Elastica/Test/Filter/GeohashCellTest.php68
-rw-r--r--vendor/ruflin/elastica/test/lib/Elastica/Test/Filter/HasChildTest.php213
-rw-r--r--vendor/ruflin/elastica/test/lib/Elastica/Test/Filter/HasParentTest.php153
-rw-r--r--vendor/ruflin/elastica/test/lib/Elastica/Test/Filter/IdsTest.php244
-rw-r--r--vendor/ruflin/elastica/test/lib/Elastica/Test/Filter/IndicesTest.php125
-rw-r--r--vendor/ruflin/elastica/test/lib/Elastica/Test/Filter/LimitTest.php34
-rw-r--r--vendor/ruflin/elastica/test/lib/Elastica/Test/Filter/MatchAllTest.php20
-rw-r--r--vendor/ruflin/elastica/test/lib/Elastica/Test/Filter/MissingTest.php78
-rw-r--r--vendor/ruflin/elastica/test/lib/Elastica/Test/Filter/MultiTest.php109
-rw-r--r--vendor/ruflin/elastica/test/lib/Elastica/Test/Filter/NestedFilterWithSetFilterTest.php110
-rw-r--r--vendor/ruflin/elastica/test/lib/Elastica/Test/Filter/NestedTest.php127
-rw-r--r--vendor/ruflin/elastica/test/lib/Elastica/Test/Filter/NumericRangeTest.php37
-rw-r--r--vendor/ruflin/elastica/test/lib/Elastica/Test/Filter/PrefixTest.php138
-rw-r--r--vendor/ruflin/elastica/test/lib/Elastica/Test/Filter/QueryTest.php51
-rw-r--r--vendor/ruflin/elastica/test/lib/Elastica/Test/Filter/RangeTest.php61
-rw-r--r--vendor/ruflin/elastica/test/lib/Elastica/Test/Filter/RegexpTest.php162
-rw-r--r--vendor/ruflin/elastica/test/lib/Elastica/Test/Filter/ScriptTest.php57
-rw-r--r--vendor/ruflin/elastica/test/lib/Elastica/Test/Filter/TermTest.php24
-rw-r--r--vendor/ruflin/elastica/test/lib/Elastica/Test/Filter/TermsTest.php129
-rw-r--r--vendor/ruflin/elastica/test/lib/Elastica/Test/Filter/TypeTest.php32
-rw-r--r--vendor/ruflin/elastica/test/lib/Elastica/Test/Index/SettingsTest.php338
-rw-r--r--vendor/ruflin/elastica/test/lib/Elastica/Test/Index/StatsTest.php24
-rw-r--r--vendor/ruflin/elastica/test/lib/Elastica/Test/Index/StatusTest.php74
-rw-r--r--vendor/ruflin/elastica/test/lib/Elastica/Test/IndexTest.php901
-rw-r--r--vendor/ruflin/elastica/test/lib/Elastica/Test/LogTest.php196
-rw-r--r--vendor/ruflin/elastica/test/lib/Elastica/Test/Multi/SearchTest.php575
-rw-r--r--vendor/ruflin/elastica/test/lib/Elastica/Test/Node/InfoTest.php79
-rw-r--r--vendor/ruflin/elastica/test/lib/Elastica/Test/NodeTest.php75
-rw-r--r--vendor/ruflin/elastica/test/lib/Elastica/Test/ParamTest.php115
-rw-r--r--vendor/ruflin/elastica/test/lib/Elastica/Test/PercolatorTest.php328
-rw-r--r--vendor/ruflin/elastica/test/lib/Elastica/Test/Query/BoolQueryTest.php171
-rw-r--r--vendor/ruflin/elastica/test/lib/Elastica/Test/Query/BoostingTest.php89
-rw-r--r--vendor/ruflin/elastica/test/lib/Elastica/Test/Query/BuilderTest.php273
-rw-r--r--vendor/ruflin/elastica/test/lib/Elastica/Test/Query/CommonTest.php63
-rw-r--r--vendor/ruflin/elastica/test/lib/Elastica/Test/Query/ConstantScoreTest.php162
-rw-r--r--vendor/ruflin/elastica/test/lib/Elastica/Test/Query/DisMaxTest.php84
-rw-r--r--vendor/ruflin/elastica/test/lib/Elastica/Test/Query/EscapeStringTest.php36
-rw-r--r--vendor/ruflin/elastica/test/lib/Elastica/Test/Query/FilteredTest.php124
-rw-r--r--vendor/ruflin/elastica/test/lib/Elastica/Test/Query/FunctionScoreTest.php324
-rw-r--r--vendor/ruflin/elastica/test/lib/Elastica/Test/Query/FuzzyLikeThisTest.php300
-rw-r--r--vendor/ruflin/elastica/test/lib/Elastica/Test/Query/FuzzyTest.php136
-rw-r--r--vendor/ruflin/elastica/test/lib/Elastica/Test/Query/HasChildTest.php117
-rw-r--r--vendor/ruflin/elastica/test/lib/Elastica/Test/Query/HasParentTest.php108
-rw-r--r--vendor/ruflin/elastica/test/lib/Elastica/Test/Query/HighlightTest.php48
-rw-r--r--vendor/ruflin/elastica/test/lib/Elastica/Test/Query/IdsTest.php187
-rw-r--r--vendor/ruflin/elastica/test/lib/Elastica/Test/Query/ImageTest.php159
-rw-r--r--vendor/ruflin/elastica/test/lib/Elastica/Test/Query/MatchAllTest.php49
-rw-r--r--vendor/ruflin/elastica/test/lib/Elastica/Test/Query/MatchTest.php339
-rw-r--r--vendor/ruflin/elastica/test/lib/Elastica/Test/Query/MoreLikeThisTest.php240
-rw-r--r--vendor/ruflin/elastica/test/lib/Elastica/Test/Query/MultiMatchTest.php214
-rw-r--r--vendor/ruflin/elastica/test/lib/Elastica/Test/Query/NestedTest.php30
-rw-r--r--vendor/ruflin/elastica/test/lib/Elastica/Test/Query/PostFilterTest.php64
-rw-r--r--vendor/ruflin/elastica/test/lib/Elastica/Test/Query/PrefixTest.php27
-rw-r--r--vendor/ruflin/elastica/test/lib/Elastica/Test/Query/QueryStringTest.php189
-rw-r--r--vendor/ruflin/elastica/test/lib/Elastica/Test/Query/RangeTest.php79
-rw-r--r--vendor/ruflin/elastica/test/lib/Elastica/Test/Query/RegexpTest.php31
-rw-r--r--vendor/ruflin/elastica/test/lib/Elastica/Test/Query/RescoreTest.php236
-rw-r--r--vendor/ruflin/elastica/test/lib/Elastica/Test/Query/SimpleQueryStringTest.php103
-rw-r--r--vendor/ruflin/elastica/test/lib/Elastica/Test/Query/SimpleTest.php19
-rw-r--r--vendor/ruflin/elastica/test/lib/Elastica/Test/Query/TermTest.php27
-rw-r--r--vendor/ruflin/elastica/test/lib/Elastica/Test/Query/TermsTest.php65
-rw-r--r--vendor/ruflin/elastica/test/lib/Elastica/Test/Query/WildcardTest.php106
-rw-r--r--vendor/ruflin/elastica/test/lib/Elastica/Test/QueryBuilder/DSL/AbstractDSLTest.php97
-rw-r--r--vendor/ruflin/elastica/test/lib/Elastica/Test/QueryBuilder/DSL/AggregationTest.php58
-rw-r--r--vendor/ruflin/elastica/test/lib/Elastica/Test/QueryBuilder/DSL/FilterTest.php58
-rw-r--r--vendor/ruflin/elastica/test/lib/Elastica/Test/QueryBuilder/DSL/QueryTest.php85
-rw-r--r--vendor/ruflin/elastica/test/lib/Elastica/Test/QueryBuilder/DSL/SuggestTest.php32
-rw-r--r--vendor/ruflin/elastica/test/lib/Elastica/Test/QueryBuilder/VersionTest.php67
-rw-r--r--vendor/ruflin/elastica/test/lib/Elastica/Test/QueryBuilderTest.php88
-rw-r--r--vendor/ruflin/elastica/test/lib/Elastica/Test/QueryTest.php458
-rw-r--r--vendor/ruflin/elastica/test/lib/Elastica/Test/RequestTest.php95
-rw-r--r--vendor/ruflin/elastica/test/lib/Elastica/Test/ResponseTest.php205
-rw-r--r--vendor/ruflin/elastica/test/lib/Elastica/Test/ResultSetTest.php95
-rw-r--r--vendor/ruflin/elastica/test/lib/Elastica/Test/ResultTest.php131
-rw-r--r--vendor/ruflin/elastica/test/lib/Elastica/Test/ScanAndScrollTest.php78
-rw-r--r--vendor/ruflin/elastica/test/lib/Elastica/Test/ScriptFieldsTest.php93
-rw-r--r--vendor/ruflin/elastica/test/lib/Elastica/Test/ScriptTest.php169
-rw-r--r--vendor/ruflin/elastica/test/lib/Elastica/Test/ScrollTest.php105
-rw-r--r--vendor/ruflin/elastica/test/lib/Elastica/Test/SearchTest.php647
-rw-r--r--vendor/ruflin/elastica/test/lib/Elastica/Test/ShutdownTest.php74
-rw-r--r--vendor/ruflin/elastica/test/lib/Elastica/Test/SnapshotTest.php109
-rw-r--r--vendor/ruflin/elastica/test/lib/Elastica/Test/StatusTest.php133
-rw-r--r--vendor/ruflin/elastica/test/lib/Elastica/Test/Suggest/CompletionTest.php140
-rw-r--r--vendor/ruflin/elastica/test/lib/Elastica/Test/Suggest/PhraseTest.php82
-rw-r--r--vendor/ruflin/elastica/test/lib/Elastica/Test/Suggest/TermTest.php105
-rw-r--r--vendor/ruflin/elastica/test/lib/Elastica/Test/Tool/CrossIndexTest.php135
-rw-r--r--vendor/ruflin/elastica/test/lib/Elastica/Test/Transport/AbstractTransportTest.php80
-rw-r--r--vendor/ruflin/elastica/test/lib/Elastica/Test/Transport/GuzzleTest.php180
-rw-r--r--vendor/ruflin/elastica/test/lib/Elastica/Test/Transport/HttpTest.php246
-rw-r--r--vendor/ruflin/elastica/test/lib/Elastica/Test/Transport/MemcacheTest.php176
-rw-r--r--vendor/ruflin/elastica/test/lib/Elastica/Test/Transport/NullTransportTest.php96
-rw-r--r--vendor/ruflin/elastica/test/lib/Elastica/Test/Transport/ThriftTest.php135
-rw-r--r--vendor/ruflin/elastica/test/lib/Elastica/Test/Transport/TransportBenchmarkTest.php261
-rw-r--r--vendor/ruflin/elastica/test/lib/Elastica/Test/Type/MappingTest.php331
-rw-r--r--vendor/ruflin/elastica/test/lib/Elastica/Test/TypeTest.php968
-rw-r--r--vendor/ruflin/elastica/test/lib/Elastica/Test/UtilTest.php139
-rw-r--r--vendor/ruflin/elastica/test/phpunit.xhprof.xml39
-rw-r--r--vendor/ruflin/elastica/test/phpunit.xml.dist27
-rw-r--r--vendor/symfony/process/CHANGELOG.md40
-rw-r--r--vendor/symfony/process/Exception/ExceptionInterface.php21
-rw-r--r--vendor/symfony/process/Exception/InvalidArgumentException.php21
-rw-r--r--vendor/symfony/process/Exception/LogicException.php21
-rw-r--r--vendor/symfony/process/Exception/ProcessFailedException.php53
-rw-r--r--vendor/symfony/process/Exception/ProcessTimedOutException.php69
-rw-r--r--vendor/symfony/process/Exception/RuntimeException.php21
-rw-r--r--vendor/symfony/process/ExecutableFinder.php89
-rw-r--r--vendor/symfony/process/LICENSE19
-rw-r--r--vendor/symfony/process/PhpExecutableFinder.php86
-rw-r--r--vendor/symfony/process/PhpProcess.php71
-rw-r--r--vendor/symfony/process/Pipes/AbstractPipes.php74
-rw-r--r--vendor/symfony/process/Pipes/PipesInterface.php60
-rw-r--r--vendor/symfony/process/Pipes/UnixPipes.php214
-rw-r--r--vendor/symfony/process/Pipes/WindowsPipes.php254
-rw-r--r--vendor/symfony/process/Process.php1526
-rw-r--r--vendor/symfony/process/ProcessBuilder.php287
-rw-r--r--vendor/symfony/process/ProcessUtils.php115
-rw-r--r--vendor/symfony/process/README.md51
-rw-r--r--vendor/symfony/process/Tests/AbstractProcessTest.php1205
-rw-r--r--vendor/symfony/process/Tests/ExecutableFinderTest.php149
-rw-r--r--vendor/symfony/process/Tests/NonStopableProcess.php36
-rw-r--r--vendor/symfony/process/Tests/PhpExecutableFinderTest.php97
-rw-r--r--vendor/symfony/process/Tests/PhpProcessTest.php49
-rw-r--r--vendor/symfony/process/Tests/PipeStdinInStdoutStdErrStreamSelect.php63
-rw-r--r--vendor/symfony/process/Tests/ProcessBuilderTest.php225
-rw-r--r--vendor/symfony/process/Tests/ProcessFailedExceptionTest.php136
-rw-r--r--vendor/symfony/process/Tests/ProcessInSigchildEnvironment.php22
-rw-r--r--vendor/symfony/process/Tests/ProcessUtilsTest.php48
-rw-r--r--vendor/symfony/process/Tests/SigchildDisabledProcessTest.php263
-rw-r--r--vendor/symfony/process/Tests/SigchildEnabledProcessTest.php148
-rw-r--r--vendor/symfony/process/Tests/SignalListener.php16
-rw-r--r--vendor/symfony/process/Tests/SimpleProcessTest.php222
-rw-r--r--vendor/symfony/process/composer.json33
-rw-r--r--vendor/symfony/process/phpunit.xml.dist27
-rw-r--r--vendor/wikimedia/assert/COPYING21
-rw-r--r--vendor/wikimedia/assert/README.md43
-rw-r--r--vendor/wikimedia/assert/composer.json24
-rw-r--r--vendor/wikimedia/assert/phpunit.xml.dist27
-rw-r--r--vendor/wikimedia/assert/src/Assert.php204
-rw-r--r--vendor/wikimedia/assert/src/AssertionException.php16
-rw-r--r--vendor/wikimedia/assert/src/InvariantException.php18
-rw-r--r--vendor/wikimedia/assert/src/ParameterAssertionException.php49
-rw-r--r--vendor/wikimedia/assert/src/ParameterElementTypeException.php43
-rw-r--r--vendor/wikimedia/assert/src/ParameterTypeException.php43
-rw-r--r--vendor/wikimedia/assert/src/PostconditionException.php18
-rw-r--r--vendor/wikimedia/assert/src/PreconditionException.php17
-rw-r--r--vendor/wikimedia/assert/tests/phpunit/AssertTest.php156
-rw-r--r--vendor/wikimedia/avro/LICENSE.txt308
-rw-r--r--vendor/wikimedia/avro/NOTICE.txt9
-rw-r--r--vendor/wikimedia/avro/README.md23
-rw-r--r--vendor/wikimedia/avro/lib/avro.php195
-rw-r--r--vendor/wikimedia/avro/lib/avro/data_file.php535
-rw-r--r--vendor/wikimedia/avro/lib/avro/datum.php984
-rw-r--r--vendor/wikimedia/avro/lib/avro/debug.php194
-rw-r--r--vendor/wikimedia/avro/lib/avro/gmp.php222
-rw-r--r--vendor/wikimedia/avro/lib/avro/io.php494
-rw-r--r--vendor/wikimedia/avro/lib/avro/protocol.php86
-rw-r--r--vendor/wikimedia/avro/lib/avro/schema.php1457
-rw-r--r--vendor/wikimedia/avro/lib/avro/util.php67
-rw-r--r--vendor/wikimedia/cdb/COPYING183
-rw-r--r--vendor/wikimedia/cdb/Doxyfile32
-rw-r--r--vendor/wikimedia/cdb/README.md31
-rw-r--r--vendor/wikimedia/cdb/composer.json26
-rw-r--r--vendor/wikimedia/cdb/doc/README1
-rw-r--r--vendor/wikimedia/cdb/src/Reader.php17
-rw-r--r--vendor/wikimedia/cdb/src/Reader/DBA.php13
-rw-r--r--vendor/wikimedia/cdb/src/Reader/PHP.php286
-rw-r--r--vendor/wikimedia/cdb/src/Writer.php2
-rw-r--r--vendor/wikimedia/cdb/src/Writer/DBA.php1
-rw-r--r--vendor/wikimedia/cdb/src/Writer/PHP.php1
-rw-r--r--vendor/wikimedia/cdb/test/CdbTest.php95
-rw-r--r--vendor/wikimedia/composer-merge-plugin/.arcconfig6
-rw-r--r--vendor/wikimedia/composer-merge-plugin/.arclint13
-rw-r--r--vendor/wikimedia/composer-merge-plugin/LICENSE2
-rw-r--r--vendor/wikimedia/composer-merge-plugin/README.md133
-rw-r--r--vendor/wikimedia/composer-merge-plugin/composer.json18
-rw-r--r--vendor/wikimedia/composer-merge-plugin/src/Logger.php102
-rw-r--r--vendor/wikimedia/composer-merge-plugin/src/Merge/ExtraPackage.php487
-rw-r--r--vendor/wikimedia/composer-merge-plugin/src/Merge/MissingFileException.php18
-rw-r--r--vendor/wikimedia/composer-merge-plugin/src/Merge/PluginState.php327
-rw-r--r--vendor/wikimedia/composer-merge-plugin/src/Merge/StabilityFlags.php181
-rw-r--r--vendor/wikimedia/composer-merge-plugin/src/MergePlugin.php427
-rw-r--r--vendor/wikimedia/ip-set/COPYING339
-rw-r--r--vendor/wikimedia/ip-set/README.md83
-rw-r--r--vendor/wikimedia/ip-set/src/IPSet.php284
-rw-r--r--vendor/wikimedia/utfnormal/COPYING342
-rw-r--r--vendor/wikimedia/utfnormal/Doxyfile32
-rw-r--r--vendor/wikimedia/wrappedstring/LICENSE19
-rw-r--r--vendor/wikimedia/wrappedstring/README.md24
-rw-r--r--vendor/wikimedia/wrappedstring/src/WrappedString.php110
-rw-r--r--vendor/zordius/lightncandy/HISTORY.md180
-rw-r--r--vendor/zordius/lightncandy/LICENSE.txt2
-rw-r--r--vendor/zordius/lightncandy/README.md91
-rw-r--r--vendor/zordius/lightncandy/UPGRADE.md4
-rw-r--r--vendor/zordius/lightncandy/build/gen_doc2
-rw-r--r--vendor/zordius/lightncandy/src/lightncandy.php540
-rw-r--r--vendor/zordius/lightncandy/tests/LCRun3Test.php18
-rw-r--r--vendor/zordius/lightncandy/tests/LightnCandyTest.php159
-rw-r--r--vendor/zordius/lightncandy/tests/contextTest.php300
-rw-r--r--vendor/zordius/lightncandy/tests/errorTest.php23
-rw-r--r--vendor/zordius/lightncandy/tests/helpers_for_test.php12
-rw-r--r--vendor/zordius/lightncandy/tests/regressionTest.php609
1762 files changed, 112402 insertions, 41317 deletions
diff --git a/vendor/README.md b/vendor/README.md
new file mode 100644
index 00000000..71959751
--- /dev/null
+++ b/vendor/README.md
@@ -0,0 +1,30 @@
+MediaWiki-Vendor
+================
+
+[Composer] managed libraries required or recommended for use with [MediaWiki].
+This repository is maintained for use on the Wikimedia Foundation production
+and testing clusters, but may be useful for anyone wishing to avoid directly
+managing MediaWiki dependencies with Composer.
+
+
+Usage
+-----
+
+Checkout this library into $IP/vendor using `git clone <URL>` or add the
+repository as a git submodule using `git submodule add <URL> vendor` followed
+by `git submodule update --init`.
+
+
+Adding or updating libraries
+----------------------------
+
+0. Read the [documentation] on the process for adding new libraries.
+1. Edit the composer.json file
+2. Run `composer update` to download files and update the autoloader files.
+3. Add and commit changes as a gerrit patch.
+4. Review and merge changes.
+
+
+[Composer]: https://getcomposer.org/
+[MediaWiki]: https://www.mediawiki.org/wiki/MediaWiki
+[documentation]: https://www.mediawiki.org/wiki/Manual:External_libraries
diff --git a/vendor/autoload.php b/vendor/autoload.php
index eea313e2..9bcfa9fe 100644
--- a/vendor/autoload.php
+++ b/vendor/autoload.php
@@ -4,4 +4,4 @@
require_once __DIR__ . '/composer' . '/autoload_real.php';
-return ComposerAutoloaderInite2ef576e4023c6f0949f5e8e1cdf8649::getLoader();
+return ComposerAutoloaderInit_mediawiki_vendor::getLoader();
diff --git a/vendor/composer.json b/vendor/composer.json
new file mode 100644
index 00000000..f3a5ba0f
--- /dev/null
+++ b/vendor/composer.json
@@ -0,0 +1,35 @@
+{
+ "config": {
+ "autoloader-suffix": "_mediawiki_vendor",
+ "classmap-authoritative": true,
+ "optimize-autoloader": true,
+ "preferred-install": "dist",
+ "prepend-autoloader": false,
+ "vendor-dir": "."
+ },
+ "prefer-stable": true,
+ "require": {
+ "composer/semver": "1.0.0",
+ "cssjanus/cssjanus": "1.1.1",
+ "firebase/php-jwt": "2.1.0",
+ "kzykhys/pygments": "1.0",
+ "liuggio/statsd-php-client": "1.0.16",
+ "mediawiki/at-ease": "1.1.0",
+ "monolog/monolog": "1.14.0",
+ "oojs/oojs-ui": "0.12.12",
+ "oyejorge/less.php": "1.7.0.9",
+ "nmred/kafka-php": "0.1.4",
+ "php": ">=5.3.3",
+ "psr/log": "1.0.0",
+ "ruflin/elastica": "2.2.0",
+ "symfony/process": "2.7.3",
+ "wikimedia/assert": "0.2.2",
+ "wikimedia/avro": "1.7.7",
+ "wikimedia/cdb": "1.3.0",
+ "wikimedia/composer-merge-plugin": "1.3.0",
+ "wikimedia/ip-set": "1.0.1",
+ "wikimedia/utfnormal": "1.0.3",
+ "wikimedia/wrappedstring": "2.0.0",
+ "zordius/lightncandy": "0.21"
+ }
+}
diff --git a/vendor/composer.lock b/vendor/composer.lock
new file mode 100644
index 00000000..cd4210d1
--- /dev/null
+++ b/vendor/composer.lock
@@ -0,0 +1,1064 @@
+{
+ "_readme": [
+ "This file locks the dependencies of your project to a known state",
+ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
+ "This file is @generated automatically"
+ ],
+ "hash": "a8e4bd12c298a91fbc07f1175b5ae66c",
+ "content-hash": "9662af67b5bbd488991d27c0f11a617b",
+ "packages": [
+ {
+ "name": "composer/semver",
+ "version": "1.0.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/composer/semver.git",
+ "reference": "d0e1ccc6d44ab318b758d709e19176037da6b1ba"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/composer/semver/zipball/d0e1ccc6d44ab318b758d709e19176037da6b1ba",
+ "reference": "d0e1ccc6d44ab318b758d709e19176037da6b1ba",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.3.2"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "~4.5",
+ "phpunit/phpunit-mock-objects": "~2.3"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "0.1-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Composer\\Semver\\": "src"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Rob Bast",
+ "email": "rob.bast@gmail.com"
+ },
+ {
+ "name": "Nils Adermann",
+ "email": "naderman@naderman.de",
+ "homepage": "http://www.naderman.de"
+ },
+ {
+ "name": "Jordi Boggiano",
+ "email": "j.boggiano@seld.be",
+ "homepage": "http://seld.be"
+ }
+ ],
+ "description": "Semver library that offers utilities, version constraint parsing and validation.",
+ "keywords": [
+ "semantic",
+ "semver",
+ "validation",
+ "versioning"
+ ],
+ "time": "2015-09-21 09:42:36"
+ },
+ {
+ "name": "cssjanus/cssjanus",
+ "version": "v1.1.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/cssjanus/php-cssjanus.git",
+ "reference": "62a9c32e6e140de09082b40a6e99d868ad14d4e0"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/cssjanus/php-cssjanus/zipball/62a9c32e6e140de09082b40a6e99d868ad14d4e0",
+ "reference": "62a9c32e6e140de09082b40a6e99d868ad14d4e0",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.3.3"
+ },
+ "require-dev": {
+ "jakub-onderka/php-parallel-lint": "0.8.*",
+ "phpunit/phpunit": "3.7.*",
+ "squizlabs/php_codesniffer": "1.*"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-0": {
+ "": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "Apache-2.0"
+ ],
+ "description": "Convert CSS stylesheets between left-to-right and right-to-left.",
+ "time": "2014-11-14 20:00:50"
+ },
+ {
+ "name": "firebase/php-jwt",
+ "version": "v2.1.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/firebase/php-jwt.git",
+ "reference": "fb219727e199dd80a72d5274ebb5c8b24d58dd9b"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/firebase/php-jwt/zipball/fb219727e199dd80a72d5274ebb5c8b24d58dd9b",
+ "reference": "fb219727e199dd80a72d5274ebb5c8b24d58dd9b",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.2.0"
+ },
+ "type": "library",
+ "autoload": {
+ "classmap": [
+ "Authentication/",
+ "Exceptions/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Neuman Vong",
+ "email": "neuman+pear@twilio.com",
+ "role": "Developer"
+ },
+ {
+ "name": "Anant Narayanan",
+ "email": "anant@php.net",
+ "role": "Developer"
+ }
+ ],
+ "description": "A simple library to encode and decode JSON Web Tokens (JWT) in PHP. Should conform to the current spec.",
+ "homepage": "https://github.com/firebase/php-jwt",
+ "time": "2015-05-20 19:16:04"
+ },
+ {
+ "name": "kzykhys/pygments",
+ "version": "v1.0.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/kzykhys/Pygments.php.git",
+ "reference": "7bde970d3c378d075ef0e005bb93a91055e17994"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/kzykhys/Pygments.php/zipball/7bde970d3c378d075ef0e005bb93a91055e17994",
+ "reference": "7bde970d3c378d075ef0e005bb93a91055e17994",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.3.2",
+ "symfony/process": ">=2.3"
+ },
+ "require-dev": {
+ "symfony/finder": ">=2.3"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-0": {
+ "": "src"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "description": "A Thin Wrapper for the Python Pygments",
+ "time": "2013-12-18 15:22:37"
+ },
+ {
+ "name": "liuggio/statsd-php-client",
+ "version": "v1.0.16",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/liuggio/statsd-php-client.git",
+ "reference": "a84fbef1a7afbfafd0ca4f1ebae4935bd1a7d920"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/liuggio/statsd-php-client/zipball/a84fbef1a7afbfafd0ca4f1ebae4935bd1a7d920",
+ "reference": "a84fbef1a7afbfafd0ca4f1ebae4935bd1a7d920",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.3.2"
+ },
+ "require-dev": {
+ "monolog/monolog": ">=1.2.0"
+ },
+ "suggest": {
+ "monolog/monolog": "Monolog, in order to do generate statistic from log >=1.2.0)"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-0": {
+ "Liuggio": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Giulio De Donato",
+ "email": "liuggio@gmail.com"
+ }
+ ],
+ "description": "Statsd (Object Oriented) client library for PHP",
+ "homepage": "https://github.com/liuggio/statsd-php-client/",
+ "keywords": [
+ "etsy",
+ "monitoring",
+ "php",
+ "statsd"
+ ],
+ "time": "2015-04-27 08:12:26"
+ },
+ {
+ "name": "mediawiki/at-ease",
+ "version": "v1.1.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/wikimedia/at-ease.git",
+ "reference": "94c0b84888841d160419f915c2745d9d08fbf0c3"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/wikimedia/at-ease/zipball/94c0b84888841d160419f915c2745d9d08fbf0c3",
+ "reference": "94c0b84888841d160419f915c2745d9d08fbf0c3",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.3.3"
+ },
+ "require-dev": {
+ "jakub-onderka/php-parallel-lint": "0.9",
+ "mediawiki/mediawiki-codesniffer": "0.3.0",
+ "phpunit/phpunit": "~4.5",
+ "squizlabs/php_codesniffer": "2.3.0"
+ },
+ "type": "library",
+ "autoload": {
+ "files": [
+ "src/Functions.php"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "GPL-2.0+"
+ ],
+ "authors": [
+ {
+ "name": "Tim Starling",
+ "email": "tstarling@wikimedia.org"
+ },
+ {
+ "name": "MediaWiki developers",
+ "email": "wikitech-l@lists.wikimedia.org"
+ }
+ ],
+ "description": "Safe replacement to @ for suppressing warnings.",
+ "homepage": "https://www.mediawiki.org/wiki/at-ease",
+ "time": "2015-09-18 07:02:06"
+ },
+ {
+ "name": "monolog/monolog",
+ "version": "1.14.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/Seldaek/monolog.git",
+ "reference": "b287fbbe1ca27847064beff2bad7fb6920bf08cc"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/Seldaek/monolog/zipball/b287fbbe1ca27847064beff2bad7fb6920bf08cc",
+ "reference": "b287fbbe1ca27847064beff2bad7fb6920bf08cc",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.3.0",
+ "psr/log": "~1.0"
+ },
+ "provide": {
+ "psr/log-implementation": "1.0.0"
+ },
+ "require-dev": {
+ "aws/aws-sdk-php": "^2.4.9",
+ "doctrine/couchdb": "~1.0@dev",
+ "graylog2/gelf-php": "~1.0",
+ "php-console/php-console": "^3.1.3",
+ "phpunit/phpunit": "~4.5",
+ "phpunit/phpunit-mock-objects": "2.3.0",
+ "raven/raven": "~0.8",
+ "ruflin/elastica": ">=0.90 <3.0",
+ "swiftmailer/swiftmailer": "~5.3",
+ "videlalvaro/php-amqplib": "~2.4"
+ },
+ "suggest": {
+ "aws/aws-sdk-php": "Allow sending log messages to AWS services like DynamoDB",
+ "doctrine/couchdb": "Allow sending log messages to a CouchDB server",
+ "ext-amqp": "Allow sending log messages to an AMQP server (1.0+ required)",
+ "ext-mongo": "Allow sending log messages to a MongoDB server",
+ "graylog2/gelf-php": "Allow sending log messages to a GrayLog2 server",
+ "php-console/php-console": "Allow sending log messages to Google Chrome",
+ "raven/raven": "Allow sending log messages to a Sentry server",
+ "rollbar/rollbar": "Allow sending log messages to Rollbar",
+ "ruflin/elastica": "Allow sending log messages to an Elastic Search server",
+ "videlalvaro/php-amqplib": "Allow sending log messages to an AMQP server using php-amqplib"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "1.14.x-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Monolog\\": "src/Monolog"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Jordi Boggiano",
+ "email": "j.boggiano@seld.be",
+ "homepage": "http://seld.be"
+ }
+ ],
+ "description": "Sends your logs to files, sockets, inboxes, databases and various web services",
+ "homepage": "http://github.com/Seldaek/monolog",
+ "keywords": [
+ "log",
+ "logging",
+ "psr-3"
+ ],
+ "time": "2015-06-19 13:29:54"
+ },
+ {
+ "name": "nmred/kafka-php",
+ "version": "v0.1.4",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/nmred/kafka-php.git",
+ "reference": "06817c95e40b23918c3a420960ee9526e499275d"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/nmred/kafka-php/zipball/06817c95e40b23918c3a420960ee9526e499275d",
+ "reference": "06817c95e40b23918c3a420960ee9526e499275d",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.3.3"
+ },
+ "require-dev": {
+ "phpunit/phpcov": "*",
+ "phpunit/phpunit": "~4.0",
+ "satooshi/php-coveralls": "dev-master"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-0": {
+ "Kafka\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "description": "Kafka client for php",
+ "homepage": "http://www.swanlinux.net",
+ "keywords": [
+ "client",
+ "kafka"
+ ],
+ "time": "2015-09-06 01:39:05"
+ },
+ {
+ "name": "oojs/oojs-ui",
+ "version": "v0.12.12",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/wikimedia/oojs-ui.git",
+ "reference": "221a66e8df215e767ff4b55b637138a73fcffdb2"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/wikimedia/oojs-ui/zipball/221a66e8df215e767ff4b55b637138a73fcffdb2",
+ "reference": "221a66e8df215e767ff4b55b637138a73fcffdb2",
+ "shasum": ""
+ },
+ "require": {
+ "mediawiki/at-ease": "1.1.0",
+ "php": ">=5.3.3"
+ },
+ "require-dev": {
+ "jakub-onderka/php-parallel-lint": "0.9",
+ "mediawiki/mediawiki-codesniffer": "0.4.0",
+ "phpunit/phpunit": "~4.5"
+ },
+ "type": "library",
+ "autoload": {
+ "classmap": [
+ "php/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Bartosz Dziewoński",
+ "email": "matma.rex@gmail.com"
+ },
+ {
+ "name": "Ed Sanders",
+ "email": "esanders@wikimedia.org"
+ },
+ {
+ "name": "James D. Forrester",
+ "email": "jforrester@wikimedia.org"
+ },
+ {
+ "name": "Kirsten Menger-Anderson",
+ "email": "kmenger@wikimedia.org"
+ },
+ {
+ "name": "Rob Moen",
+ "email": "rmoen@wikimedia.org"
+ },
+ {
+ "name": "Roan Kattouw",
+ "email": "roan@wikimedia.org"
+ },
+ {
+ "name": "Timo Tijhof",
+ "email": "timo@wikimedia.org"
+ },
+ {
+ "name": "Trevor Parscal",
+ "email": "trevor@wikimedia.org"
+ }
+ ],
+ "description": "Provides library of common widgets, layouts, and windows.",
+ "homepage": "https://www.mediawiki.org/wiki/OOjs_UI",
+ "time": "2015-10-13 20:29:29"
+ },
+ {
+ "name": "oyejorge/less.php",
+ "version": "v1.7.0.9",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/oyejorge/less.php.git",
+ "reference": "fb64e2f6ef647a229c50e9fa0f2076240a3484c6"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/oyejorge/less.php/zipball/fb64e2f6ef647a229c50e9fa0f2076240a3484c6",
+ "reference": "fb64e2f6ef647a229c50e9fa0f2076240a3484c6",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.3"
+ },
+ "bin": [
+ "bin/lessc"
+ ],
+ "type": "library",
+ "autoload": {
+ "psr-0": {
+ "Less": "lib/"
+ },
+ "classmap": [
+ "lessc.inc.php"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "Apache-2.0"
+ ],
+ "authors": [
+ {
+ "name": "Matt Agar",
+ "homepage": "https://github.com/agar"
+ },
+ {
+ "name": "Martin Jantošovič",
+ "homepage": "https://github.com/Mordred"
+ },
+ {
+ "name": "Josh Schmidt",
+ "homepage": "https://github.com/oyejorge"
+ }
+ ],
+ "description": "PHP port of the Javascript version of LESS http://lesscss.org",
+ "homepage": "http://lessphp.gpeasy.com",
+ "keywords": [
+ "css",
+ "less",
+ "less.js",
+ "lesscss",
+ "php",
+ "stylesheet"
+ ],
+ "time": "2015-09-28 01:11:47"
+ },
+ {
+ "name": "psr/log",
+ "version": "1.0.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/php-fig/log.git",
+ "reference": "fe0936ee26643249e916849d48e3a51d5f5e278b"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/php-fig/log/zipball/fe0936ee26643249e916849d48e3a51d5f5e278b",
+ "reference": "fe0936ee26643249e916849d48e3a51d5f5e278b",
+ "shasum": ""
+ },
+ "type": "library",
+ "autoload": {
+ "psr-0": {
+ "Psr\\Log\\": ""
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "PHP-FIG",
+ "homepage": "http://www.php-fig.org/"
+ }
+ ],
+ "description": "Common interface for logging libraries",
+ "keywords": [
+ "log",
+ "psr",
+ "psr-3"
+ ],
+ "time": "2012-12-21 11:40:51"
+ },
+ {
+ "name": "ruflin/elastica",
+ "version": "2.2.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/ruflin/Elastica.git",
+ "reference": "eb3a787259a6c50f87bce507ff24b124d91c4fe7"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/ruflin/Elastica/zipball/eb3a787259a6c50f87bce507ff24b124d91c4fe7",
+ "reference": "eb3a787259a6c50f87bce507ff24b124d91c4fe7",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.3.3",
+ "psr/log": "~1.0"
+ },
+ "require-dev": {
+ "guzzlehttp/guzzle": "5.3.*",
+ "munkie/elasticsearch-thrift-php": "1.4.*"
+ },
+ "suggest": {
+ "egeloen/http-adapter": "Allow using httpadapter transport",
+ "guzzlehttp/guzzle": "Allow using guzzle 5.3.x as the http transport (Requires php 5.4)",
+ "monolog/monolog": "Logging request",
+ "munkie/elasticsearch-thrift-php": "Allow using thrift transport"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "2.0.x-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Elastica\\": "lib/Elastica/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Nicolas Ruflin",
+ "homepage": "http://ruflin.com/"
+ }
+ ],
+ "description": "Elasticsearch Client",
+ "homepage": "http://elastica.io/",
+ "keywords": [
+ "client",
+ "search"
+ ],
+ "time": "2015-07-08 05:57:43"
+ },
+ {
+ "name": "symfony/process",
+ "version": "v2.7.3",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/Process.git",
+ "reference": "48aeb0e48600321c272955132d7606ab0a49adb3"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/Process/zipball/48aeb0e48600321c272955132d7606ab0a49adb3",
+ "reference": "48aeb0e48600321c272955132d7606ab0a49adb3",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.3.9"
+ },
+ "require-dev": {
+ "symfony/phpunit-bridge": "~2.7"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "2.7-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Symfony\\Component\\Process\\": ""
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Fabien Potencier",
+ "email": "fabien@symfony.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ }
+ ],
+ "description": "Symfony Process Component",
+ "homepage": "https://symfony.com",
+ "time": "2015-07-01 11:25:50"
+ },
+ {
+ "name": "wikimedia/assert",
+ "version": "v0.2.2",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/wmde/Assert.git",
+ "reference": "2da55927525975f8d52825fc3ee02e5e36f5036c"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/wmde/Assert/zipball/2da55927525975f8d52825fc3ee02e5e36f5036c",
+ "reference": "2da55927525975f8d52825fc3ee02e5e36f5036c",
+ "shasum": ""
+ },
+ "require-dev": {
+ "phpunit/phpunit": "3.7.*"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "Wikimedia\\Assert\\": "src/",
+ "Wikimedia\\Assert\\Test\\": "tests/phpunit/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Daniel Kinzler"
+ }
+ ],
+ "description": "Provides runtime assertions",
+ "homepage": "https://github.com/wmde/Assert",
+ "keywords": [
+ "assert",
+ "assertions",
+ "php",
+ "postcondition",
+ "precondition",
+ "qa"
+ ],
+ "time": "2015-04-29 17:23:50"
+ },
+ {
+ "name": "wikimedia/avro",
+ "version": "v1.7.7",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/wikimedia/avro-php.git",
+ "reference": "b642da9fd895aab7cb3261a22624228115471f47"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/wikimedia/avro-php/zipball/b642da9fd895aab7cb3261a22624228115471f47",
+ "reference": "b642da9fd895aab7cb3261a22624228115471f47",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.3.3"
+ },
+ "require-dev": {
+ "jakub-onderka/php-parallel-lint": "^0.9",
+ "phpunit/phpunit": "^4.0.0"
+ },
+ "suggest": {
+ "ext-gmp": "Large integer support for 32-bit platforms."
+ },
+ "type": "library",
+ "autoload": {
+ "classmap": [
+ "lib/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "Apache-2.0"
+ ],
+ "authors": [
+ {
+ "name": "Michael Glaesemann",
+ "email": "grzm@seespotcode.net"
+ },
+ {
+ "name": "Andy Wick",
+ "email": "awick@purple.org"
+ },
+ {
+ "name": "Saleem Shafi",
+ "email": "saleemshafi@gmail.com"
+ },
+ {
+ "name": "A B",
+ "email": "abawany@x.com"
+ },
+ {
+ "name": "Doug Cutting",
+ "email": "cutting@apache.org"
+ },
+ {
+ "name": "Tom White",
+ "email": "tom@cloudera.com"
+ }
+ ],
+ "description": "A library for using Apache Avro with PHP.",
+ "homepage": "https://avro.apache.org/",
+ "keywords": [
+ "serialization"
+ ],
+ "time": "2015-09-05 18:49:27"
+ },
+ {
+ "name": "wikimedia/cdb",
+ "version": "1.3.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/wikimedia/cdb.git",
+ "reference": "68f8fd495ca94ca0e965dd511e234893c515bb95"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/wikimedia/cdb/zipball/68f8fd495ca94ca0e965dd511e234893c515bb95",
+ "reference": "68f8fd495ca94ca0e965dd511e234893c515bb95",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.3.2"
+ },
+ "require-dev": {
+ "jakub-onderka/php-parallel-lint": "0.9",
+ "mediawiki/mediawiki-codesniffer": "0.3.0",
+ "phpunit/phpunit": "4.6.*"
+ },
+ "type": "library",
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "GPL-2.0+"
+ ],
+ "authors": [
+ {
+ "name": "Tim Starling",
+ "email": "tstarling@wikimedia.org"
+ },
+ {
+ "name": "Chad Horohoe",
+ "email": "chad@wikimedia.org"
+ },
+ {
+ "name": "Ori Livneh",
+ "email": "ori@wikimedia.org"
+ }
+ ],
+ "description": "Constant Database (CDB) wrapper library for PHP. Provides pure-PHP fallback when dba_* functions are absent.",
+ "homepage": "https://www.mediawiki.org/wiki/CDB",
+ "time": "2015-09-08 19:53:04"
+ },
+ {
+ "name": "wikimedia/composer-merge-plugin",
+ "version": "v1.3.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/wikimedia/composer-merge-plugin.git",
+ "reference": "bfed1f8d4eb97e9ba80eee57ea46229d7e5364d9"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/wikimedia/composer-merge-plugin/zipball/bfed1f8d4eb97e9ba80eee57ea46229d7e5364d9",
+ "reference": "bfed1f8d4eb97e9ba80eee57ea46229d7e5364d9",
+ "shasum": ""
+ },
+ "require": {
+ "composer-plugin-api": "^1.0",
+ "php": ">=5.3.2"
+ },
+ "require-dev": {
+ "composer/composer": "1.0.*@dev",
+ "jakub-onderka/php-parallel-lint": "~0.8",
+ "phpunit/phpunit": "~4.8|~5.0",
+ "squizlabs/php_codesniffer": "~2.1.0"
+ },
+ "type": "composer-plugin",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "1.3.x-dev"
+ },
+ "class": "Wikimedia\\Composer\\MergePlugin"
+ },
+ "autoload": {
+ "psr-4": {
+ "Wikimedia\\Composer\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Bryan Davis",
+ "email": "bd808@wikimedia.org"
+ }
+ ],
+ "description": "Composer plugin to merge multiple composer.json files",
+ "time": "2015-11-06 20:31:16"
+ },
+ {
+ "name": "wikimedia/ip-set",
+ "version": "1.0.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/wikimedia/IPSet.git",
+ "reference": "3c2dd6706546fe616e6ceba02044e64dce4fc9be"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/wikimedia/IPSet/zipball/3c2dd6706546fe616e6ceba02044e64dce4fc9be",
+ "reference": "3c2dd6706546fe616e6ceba02044e64dce4fc9be",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.3.3"
+ },
+ "require-dev": {
+ "jakub-onderka/php-parallel-lint": "0.9",
+ "mediawiki/mediawiki-codesniffer": "0.3.0",
+ "phpunit/phpunit": "4.6.*"
+ },
+ "type": "library",
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "GPL-2.0+"
+ ],
+ "authors": [
+ {
+ "name": "Brandon Black",
+ "email": "blblack@gmail.com"
+ }
+ ],
+ "description": "Efficiently match IP addresses against a set of CIDR specifications.",
+ "homepage": "https://github.com/wikimedia/IPSet",
+ "time": "2015-06-29 20:21:27"
+ },
+ {
+ "name": "wikimedia/utfnormal",
+ "version": "v1.0.3",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/wikimedia/utfnormal.git",
+ "reference": "bcb81d1d87bae400af45cc419a850dcf9883775b"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/wikimedia/utfnormal/zipball/bcb81d1d87bae400af45cc419a850dcf9883775b",
+ "reference": "bcb81d1d87bae400af45cc419a850dcf9883775b",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.3.3"
+ },
+ "require-dev": {
+ "ext-mbstring": "*",
+ "jakub-onderka/php-parallel-lint": "0.8.*",
+ "mediawiki/mediawiki-codesniffer": "0.1.0",
+ "phpunit/phpunit": "4.6.*",
+ "squizlabs/php_codesniffer": "2.2.*"
+ },
+ "type": "library",
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "GPL-2.0+"
+ ],
+ "authors": [
+ {
+ "name": "Brion Vibber",
+ "email": "bvibber@wikimedia.org"
+ }
+ ],
+ "description": "Contains Unicode normalization routines, including both pure PHP implementations and automatic use of the 'intl' PHP extension when present",
+ "homepage": "https://www.mediawiki.org/wiki/utfnormal",
+ "time": "2015-08-29 14:13:27"
+ },
+ {
+ "name": "wikimedia/wrappedstring",
+ "version": "v2.0.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/wikimedia/WrappedString.git",
+ "reference": "1b27e0ea23bd915644dade17c3fe1e45fdbadf11"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/wikimedia/WrappedString/zipball/1b27e0ea23bd915644dade17c3fe1e45fdbadf11",
+ "reference": "1b27e0ea23bd915644dade17c3fe1e45fdbadf11",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.3.3"
+ },
+ "require-dev": {
+ "jakub-onderka/php-parallel-lint": "^0.9.0.0",
+ "mediawiki/mediawiki-codesniffer": "^0.3.0.0",
+ "phpunit/phpunit": "^4.7.7.0"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "WrappedString\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Timo Tijhof",
+ "email": "krinklemail@gmail.com"
+ }
+ ],
+ "description": "Automatically compact sequentially-outputted strings that share a common prefix / suffix pair.",
+ "homepage": "https://www.mediawiki.org/wiki/WrappedString",
+ "time": "2015-07-31 00:06:22"
+ },
+ {
+ "name": "zordius/lightncandy",
+ "version": "v0.21",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/zordius/lightncandy.git",
+ "reference": "015fed62d0ae6fe7601d3910b8e4b6a6964f86a0"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/zordius/lightncandy/zipball/015fed62d0ae6fe7601d3910b8e4b6a6964f86a0",
+ "reference": "015fed62d0ae6fe7601d3910b8e4b6a6964f86a0",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.3.0"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "4.0.17"
+ },
+ "type": "library",
+ "autoload": {
+ "classmap": [
+ "src/lightncandy.php"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Zordius Chen",
+ "email": "zordius@yahoo-inc.com"
+ }
+ ],
+ "description": "An extremely fast PHP implementation of handlebars ( http://handlebarsjs.com/ ) and mustache ( http://mustache.github.io/ ).",
+ "homepage": "https://github.com/zordius/lightncandy",
+ "keywords": [
+ "handlebars",
+ "logicless",
+ "mustache",
+ "php",
+ "template"
+ ],
+ "time": "2015-05-08 01:56:46"
+ }
+ ],
+ "packages-dev": [],
+ "aliases": [],
+ "minimum-stability": "stable",
+ "stability-flags": [],
+ "prefer-stable": true,
+ "prefer-lowest": false,
+ "platform": {
+ "php": ">=5.3.3"
+ },
+ "platform-dev": []
+}
diff --git a/vendor/composer/LICENSE b/vendor/composer/LICENSE
new file mode 100644
index 00000000..c8d57af8
--- /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
index 79053ea1..386604c2 100644
--- a/vendor/composer/autoload_classmap.php
+++ b/vendor/composer/autoload_classmap.php
@@ -3,9 +3,45 @@
// autoload_classmap.php @generated by Composer
$vendorDir = dirname(dirname(__FILE__));
-$baseDir = dirname($vendorDir);
+$baseDir = $vendorDir;
return array(
+ 'Avro' => $vendorDir . '/wikimedia/avro/lib/avro.php',
+ 'AvroArraySchema' => $vendorDir . '/wikimedia/avro/lib/avro/schema.php',
+ 'AvroDataIO' => $vendorDir . '/wikimedia/avro/lib/avro/data_file.php',
+ 'AvroDataIOException' => $vendorDir . '/wikimedia/avro/lib/avro/data_file.php',
+ 'AvroDataIOReader' => $vendorDir . '/wikimedia/avro/lib/avro/data_file.php',
+ 'AvroDataIOWriter' => $vendorDir . '/wikimedia/avro/lib/avro/data_file.php',
+ 'AvroDebug' => $vendorDir . '/wikimedia/avro/lib/avro/debug.php',
+ 'AvroEnumSchema' => $vendorDir . '/wikimedia/avro/lib/avro/schema.php',
+ 'AvroException' => $vendorDir . '/wikimedia/avro/lib/avro.php',
+ 'AvroField' => $vendorDir . '/wikimedia/avro/lib/avro/schema.php',
+ 'AvroFile' => $vendorDir . '/wikimedia/avro/lib/avro/io.php',
+ 'AvroFixedSchema' => $vendorDir . '/wikimedia/avro/lib/avro/schema.php',
+ 'AvroGMP' => $vendorDir . '/wikimedia/avro/lib/avro/gmp.php',
+ 'AvroIO' => $vendorDir . '/wikimedia/avro/lib/avro/io.php',
+ 'AvroIOBinaryDecoder' => $vendorDir . '/wikimedia/avro/lib/avro/datum.php',
+ 'AvroIOBinaryEncoder' => $vendorDir . '/wikimedia/avro/lib/avro/datum.php',
+ 'AvroIODatumReader' => $vendorDir . '/wikimedia/avro/lib/avro/datum.php',
+ 'AvroIODatumWriter' => $vendorDir . '/wikimedia/avro/lib/avro/datum.php',
+ 'AvroIOException' => $vendorDir . '/wikimedia/avro/lib/avro/io.php',
+ 'AvroIOSchemaMatchException' => $vendorDir . '/wikimedia/avro/lib/avro/datum.php',
+ 'AvroIOTypeException' => $vendorDir . '/wikimedia/avro/lib/avro/datum.php',
+ 'AvroMapSchema' => $vendorDir . '/wikimedia/avro/lib/avro/schema.php',
+ 'AvroName' => $vendorDir . '/wikimedia/avro/lib/avro/schema.php',
+ 'AvroNamedSchema' => $vendorDir . '/wikimedia/avro/lib/avro/schema.php',
+ 'AvroNamedSchemata' => $vendorDir . '/wikimedia/avro/lib/avro/schema.php',
+ 'AvroPrimitiveSchema' => $vendorDir . '/wikimedia/avro/lib/avro/schema.php',
+ 'AvroProtocol' => $vendorDir . '/wikimedia/avro/lib/avro/protocol.php',
+ 'AvroProtocolMessage' => $vendorDir . '/wikimedia/avro/lib/avro/protocol.php',
+ 'AvroProtocolParseException' => $vendorDir . '/wikimedia/avro/lib/avro/protocol.php',
+ 'AvroRecordSchema' => $vendorDir . '/wikimedia/avro/lib/avro/schema.php',
+ 'AvroSchema' => $vendorDir . '/wikimedia/avro/lib/avro/schema.php',
+ 'AvroSchemaParseException' => $vendorDir . '/wikimedia/avro/lib/avro/schema.php',
+ 'AvroStringIO' => $vendorDir . '/wikimedia/avro/lib/avro/io.php',
+ 'AvroUnionSchema' => $vendorDir . '/wikimedia/avro/lib/avro/schema.php',
+ 'AvroUtil' => $vendorDir . '/wikimedia/avro/lib/avro/util.php',
+ 'BeforeValidException' => $vendorDir . '/firebase/php-jwt/Exceptions/BeforeValidException.php',
'CSSJanus' => $vendorDir . '/cssjanus/cssjanus/src/CSSJanus.php',
'CSSJanusTokenizer' => $vendorDir . '/cssjanus/cssjanus/src/CSSJanus.php',
'Cdb\\Exception' => $vendorDir . '/wikimedia/cdb/src/Exception.php',
@@ -16,8 +52,322 @@ return array(
'Cdb\\Writer' => $vendorDir . '/wikimedia/cdb/src/Writer.php',
'Cdb\\Writer\\DBA' => $vendorDir . '/wikimedia/cdb/src/Writer/DBA.php',
'Cdb\\Writer\\PHP' => $vendorDir . '/wikimedia/cdb/src/Writer/PHP.php',
- 'ComposerHookHandler' => $baseDir . '/includes/composer/ComposerHookHandler.php',
+ 'Composer\\Semver\\Comparator' => $vendorDir . '/composer/semver/src/Comparator.php',
+ 'Composer\\Semver\\Constraint\\AbstractConstraint' => $vendorDir . '/composer/semver/src/Constraint/AbstractConstraint.php',
+ 'Composer\\Semver\\Constraint\\Constraint' => $vendorDir . '/composer/semver/src/Constraint/Constraint.php',
+ 'Composer\\Semver\\Constraint\\ConstraintInterface' => $vendorDir . '/composer/semver/src/Constraint/ConstraintInterface.php',
+ 'Composer\\Semver\\Constraint\\EmptyConstraint' => $vendorDir . '/composer/semver/src/Constraint/EmptyConstraint.php',
+ 'Composer\\Semver\\Constraint\\MultiConstraint' => $vendorDir . '/composer/semver/src/Constraint/MultiConstraint.php',
+ 'Composer\\Semver\\Semver' => $vendorDir . '/composer/semver/src/Semver.php',
+ 'Composer\\Semver\\VersionParser' => $vendorDir . '/composer/semver/src/VersionParser.php',
+ 'Elastica\\AbstractUpdateAction' => $vendorDir . '/ruflin/elastica/lib/Elastica/AbstractUpdateAction.php',
+ 'Elastica\\Aggregation\\AbstractAggregation' => $vendorDir . '/ruflin/elastica/lib/Elastica/Aggregation/AbstractAggregation.php',
+ 'Elastica\\Aggregation\\AbstractSimpleAggregation' => $vendorDir . '/ruflin/elastica/lib/Elastica/Aggregation/AbstractSimpleAggregation.php',
+ 'Elastica\\Aggregation\\AbstractTermsAggregation' => $vendorDir . '/ruflin/elastica/lib/Elastica/Aggregation/AbstractTermsAggregation.php',
+ 'Elastica\\Aggregation\\Avg' => $vendorDir . '/ruflin/elastica/lib/Elastica/Aggregation/Avg.php',
+ 'Elastica\\Aggregation\\Cardinality' => $vendorDir . '/ruflin/elastica/lib/Elastica/Aggregation/Cardinality.php',
+ 'Elastica\\Aggregation\\DateHistogram' => $vendorDir . '/ruflin/elastica/lib/Elastica/Aggregation/DateHistogram.php',
+ 'Elastica\\Aggregation\\DateRange' => $vendorDir . '/ruflin/elastica/lib/Elastica/Aggregation/DateRange.php',
+ 'Elastica\\Aggregation\\ExtendedStats' => $vendorDir . '/ruflin/elastica/lib/Elastica/Aggregation/ExtendedStats.php',
+ 'Elastica\\Aggregation\\Filter' => $vendorDir . '/ruflin/elastica/lib/Elastica/Aggregation/Filter.php',
+ 'Elastica\\Aggregation\\Filters' => $vendorDir . '/ruflin/elastica/lib/Elastica/Aggregation/Filters.php',
+ 'Elastica\\Aggregation\\GeoDistance' => $vendorDir . '/ruflin/elastica/lib/Elastica/Aggregation/GeoDistance.php',
+ 'Elastica\\Aggregation\\GeohashGrid' => $vendorDir . '/ruflin/elastica/lib/Elastica/Aggregation/GeohashGrid.php',
+ 'Elastica\\Aggregation\\GlobalAggregation' => $vendorDir . '/ruflin/elastica/lib/Elastica/Aggregation/GlobalAggregation.php',
+ 'Elastica\\Aggregation\\Histogram' => $vendorDir . '/ruflin/elastica/lib/Elastica/Aggregation/Histogram.php',
+ 'Elastica\\Aggregation\\IpRange' => $vendorDir . '/ruflin/elastica/lib/Elastica/Aggregation/IpRange.php',
+ 'Elastica\\Aggregation\\Max' => $vendorDir . '/ruflin/elastica/lib/Elastica/Aggregation/Max.php',
+ 'Elastica\\Aggregation\\Min' => $vendorDir . '/ruflin/elastica/lib/Elastica/Aggregation/Min.php',
+ 'Elastica\\Aggregation\\Missing' => $vendorDir . '/ruflin/elastica/lib/Elastica/Aggregation/Missing.php',
+ 'Elastica\\Aggregation\\Nested' => $vendorDir . '/ruflin/elastica/lib/Elastica/Aggregation/Nested.php',
+ 'Elastica\\Aggregation\\Percentiles' => $vendorDir . '/ruflin/elastica/lib/Elastica/Aggregation/Percentiles.php',
+ 'Elastica\\Aggregation\\Range' => $vendorDir . '/ruflin/elastica/lib/Elastica/Aggregation/Range.php',
+ 'Elastica\\Aggregation\\ReverseNested' => $vendorDir . '/ruflin/elastica/lib/Elastica/Aggregation/ReverseNested.php',
+ 'Elastica\\Aggregation\\ScriptedMetric' => $vendorDir . '/ruflin/elastica/lib/Elastica/Aggregation/ScriptedMetric.php',
+ 'Elastica\\Aggregation\\SignificantTerms' => $vendorDir . '/ruflin/elastica/lib/Elastica/Aggregation/SignificantTerms.php',
+ 'Elastica\\Aggregation\\Stats' => $vendorDir . '/ruflin/elastica/lib/Elastica/Aggregation/Stats.php',
+ 'Elastica\\Aggregation\\Sum' => $vendorDir . '/ruflin/elastica/lib/Elastica/Aggregation/Sum.php',
+ 'Elastica\\Aggregation\\Terms' => $vendorDir . '/ruflin/elastica/lib/Elastica/Aggregation/Terms.php',
+ 'Elastica\\Aggregation\\TopHits' => $vendorDir . '/ruflin/elastica/lib/Elastica/Aggregation/TopHits.php',
+ 'Elastica\\Aggregation\\ValueCount' => $vendorDir . '/ruflin/elastica/lib/Elastica/Aggregation/ValueCount.php',
+ 'Elastica\\Bulk' => $vendorDir . '/ruflin/elastica/lib/Elastica/Bulk.php',
+ 'Elastica\\Bulk\\Action' => $vendorDir . '/ruflin/elastica/lib/Elastica/Bulk/Action.php',
+ 'Elastica\\Bulk\\Action\\AbstractDocument' => $vendorDir . '/ruflin/elastica/lib/Elastica/Bulk/Action/AbstractDocument.php',
+ 'Elastica\\Bulk\\Action\\CreateDocument' => $vendorDir . '/ruflin/elastica/lib/Elastica/Bulk/Action/CreateDocument.php',
+ 'Elastica\\Bulk\\Action\\DeleteDocument' => $vendorDir . '/ruflin/elastica/lib/Elastica/Bulk/Action/DeleteDocument.php',
+ 'Elastica\\Bulk\\Action\\IndexDocument' => $vendorDir . '/ruflin/elastica/lib/Elastica/Bulk/Action/IndexDocument.php',
+ 'Elastica\\Bulk\\Action\\UpdateDocument' => $vendorDir . '/ruflin/elastica/lib/Elastica/Bulk/Action/UpdateDocument.php',
+ 'Elastica\\Bulk\\Response' => $vendorDir . '/ruflin/elastica/lib/Elastica/Bulk/Response.php',
+ 'Elastica\\Bulk\\ResponseSet' => $vendorDir . '/ruflin/elastica/lib/Elastica/Bulk/ResponseSet.php',
+ 'Elastica\\Client' => $vendorDir . '/ruflin/elastica/lib/Elastica/Client.php',
+ 'Elastica\\Cluster' => $vendorDir . '/ruflin/elastica/lib/Elastica/Cluster.php',
+ 'Elastica\\Cluster\\Health' => $vendorDir . '/ruflin/elastica/lib/Elastica/Cluster/Health.php',
+ 'Elastica\\Cluster\\Health\\Index' => $vendorDir . '/ruflin/elastica/lib/Elastica/Cluster/Health/Index.php',
+ 'Elastica\\Cluster\\Health\\Shard' => $vendorDir . '/ruflin/elastica/lib/Elastica/Cluster/Health/Shard.php',
+ 'Elastica\\Cluster\\Settings' => $vendorDir . '/ruflin/elastica/lib/Elastica/Cluster/Settings.php',
+ 'Elastica\\Connection' => $vendorDir . '/ruflin/elastica/lib/Elastica/Connection.php',
+ 'Elastica\\Connection\\ConnectionPool' => $vendorDir . '/ruflin/elastica/lib/Elastica/Connection/ConnectionPool.php',
+ 'Elastica\\Connection\\Strategy\\CallbackStrategy' => $vendorDir . '/ruflin/elastica/lib/Elastica/Connection/Strategy/CallbackStrategy.php',
+ 'Elastica\\Connection\\Strategy\\RoundRobin' => $vendorDir . '/ruflin/elastica/lib/Elastica/Connection/Strategy/RoundRobin.php',
+ 'Elastica\\Connection\\Strategy\\Simple' => $vendorDir . '/ruflin/elastica/lib/Elastica/Connection/Strategy/Simple.php',
+ 'Elastica\\Connection\\Strategy\\StrategyFactory' => $vendorDir . '/ruflin/elastica/lib/Elastica/Connection/Strategy/StrategyFactory.php',
+ 'Elastica\\Connection\\Strategy\\StrategyInterface' => $vendorDir . '/ruflin/elastica/lib/Elastica/Connection/Strategy/StrategyInterface.php',
+ 'Elastica\\Document' => $vendorDir . '/ruflin/elastica/lib/Elastica/Document.php',
+ 'Elastica\\Exception\\BulkException' => $vendorDir . '/ruflin/elastica/lib/Elastica/Exception/BulkException.php',
+ 'Elastica\\Exception\\Bulk\\ResponseException' => $vendorDir . '/ruflin/elastica/lib/Elastica/Exception/Bulk/ResponseException.php',
+ 'Elastica\\Exception\\Bulk\\Response\\ActionException' => $vendorDir . '/ruflin/elastica/lib/Elastica/Exception/Bulk/Response/ActionException.php',
+ 'Elastica\\Exception\\Bulk\\UdpException' => $vendorDir . '/ruflin/elastica/lib/Elastica/Exception/Bulk/UdpException.php',
+ 'Elastica\\Exception\\ClientException' => $vendorDir . '/ruflin/elastica/lib/Elastica/Exception/ClientException.php',
+ 'Elastica\\Exception\\ConnectionException' => $vendorDir . '/ruflin/elastica/lib/Elastica/Exception/ConnectionException.php',
+ 'Elastica\\Exception\\Connection\\GuzzleException' => $vendorDir . '/ruflin/elastica/lib/Elastica/Exception/Connection/GuzzleException.php',
+ 'Elastica\\Exception\\Connection\\HttpException' => $vendorDir . '/ruflin/elastica/lib/Elastica/Exception/Connection/HttpException.php',
+ 'Elastica\\Exception\\Connection\\MemcacheException' => $vendorDir . '/ruflin/elastica/lib/Elastica/Exception/Connection/MemcacheException.php',
+ 'Elastica\\Exception\\Connection\\ThriftException' => $vendorDir . '/ruflin/elastica/lib/Elastica/Exception/Connection/ThriftException.php',
+ 'Elastica\\Exception\\ElasticsearchException' => $vendorDir . '/ruflin/elastica/lib/Elastica/Exception/ElasticsearchException.php',
+ 'Elastica\\Exception\\ExceptionInterface' => $vendorDir . '/ruflin/elastica/lib/Elastica/Exception/ExceptionInterface.php',
+ 'Elastica\\Exception\\InvalidException' => $vendorDir . '/ruflin/elastica/lib/Elastica/Exception/InvalidException.php',
+ 'Elastica\\Exception\\JSONParseException' => $vendorDir . '/ruflin/elastica/lib/Elastica/Exception/JSONParseException.php',
+ 'Elastica\\Exception\\NotFoundException' => $vendorDir . '/ruflin/elastica/lib/Elastica/Exception/NotFoundException.php',
+ 'Elastica\\Exception\\NotImplementedException' => $vendorDir . '/ruflin/elastica/lib/Elastica/Exception/NotImplementedException.php',
+ 'Elastica\\Exception\\PartialShardFailureException' => $vendorDir . '/ruflin/elastica/lib/Elastica/Exception/PartialShardFailureException.php',
+ 'Elastica\\Exception\\QueryBuilderException' => $vendorDir . '/ruflin/elastica/lib/Elastica/Exception/QueryBuilderException.php',
+ 'Elastica\\Exception\\ResponseException' => $vendorDir . '/ruflin/elastica/lib/Elastica/Exception/ResponseException.php',
+ 'Elastica\\Exception\\RuntimeException' => $vendorDir . '/ruflin/elastica/lib/Elastica/Exception/RuntimeException.php',
+ 'Elastica\\Facet\\AbstractFacet' => $vendorDir . '/ruflin/elastica/lib/Elastica/Facet/AbstractFacet.php',
+ 'Elastica\\Facet\\DateHistogram' => $vendorDir . '/ruflin/elastica/lib/Elastica/Facet/DateHistogram.php',
+ 'Elastica\\Facet\\Filter' => $vendorDir . '/ruflin/elastica/lib/Elastica/Facet/Filter.php',
+ 'Elastica\\Facet\\GeoCluster' => $vendorDir . '/ruflin/elastica/lib/Elastica/Facet/GeoCluster.php',
+ 'Elastica\\Facet\\GeoDistance' => $vendorDir . '/ruflin/elastica/lib/Elastica/Facet/GeoDistance.php',
+ 'Elastica\\Facet\\Histogram' => $vendorDir . '/ruflin/elastica/lib/Elastica/Facet/Histogram.php',
+ 'Elastica\\Facet\\Query' => $vendorDir . '/ruflin/elastica/lib/Elastica/Facet/Query.php',
+ 'Elastica\\Facet\\Range' => $vendorDir . '/ruflin/elastica/lib/Elastica/Facet/Range.php',
+ 'Elastica\\Facet\\Statistical' => $vendorDir . '/ruflin/elastica/lib/Elastica/Facet/Statistical.php',
+ 'Elastica\\Facet\\Terms' => $vendorDir . '/ruflin/elastica/lib/Elastica/Facet/Terms.php',
+ 'Elastica\\Facet\\TermsStats' => $vendorDir . '/ruflin/elastica/lib/Elastica/Facet/TermsStats.php',
+ 'Elastica\\Filter\\AbstractFilter' => $vendorDir . '/ruflin/elastica/lib/Elastica/Filter/AbstractFilter.php',
+ 'Elastica\\Filter\\AbstractGeoDistance' => $vendorDir . '/ruflin/elastica/lib/Elastica/Filter/AbstractGeoDistance.php',
+ 'Elastica\\Filter\\AbstractGeoShape' => $vendorDir . '/ruflin/elastica/lib/Elastica/Filter/AbstractGeoShape.php',
+ 'Elastica\\Filter\\AbstractMulti' => $vendorDir . '/ruflin/elastica/lib/Elastica/Filter/AbstractMulti.php',
+ 'Elastica\\Filter\\Bool' => $vendorDir . '/ruflin/elastica/lib/Elastica/Filter/Bool.php',
+ 'Elastica\\Filter\\BoolAnd' => $vendorDir . '/ruflin/elastica/lib/Elastica/Filter/BoolAnd.php',
+ 'Elastica\\Filter\\BoolFilter' => $vendorDir . '/ruflin/elastica/lib/Elastica/Filter/BoolFilter.php',
+ 'Elastica\\Filter\\BoolNot' => $vendorDir . '/ruflin/elastica/lib/Elastica/Filter/BoolNot.php',
+ 'Elastica\\Filter\\BoolOr' => $vendorDir . '/ruflin/elastica/lib/Elastica/Filter/BoolOr.php',
+ 'Elastica\\Filter\\Exists' => $vendorDir . '/ruflin/elastica/lib/Elastica/Filter/Exists.php',
+ 'Elastica\\Filter\\GeoBoundingBox' => $vendorDir . '/ruflin/elastica/lib/Elastica/Filter/GeoBoundingBox.php',
+ 'Elastica\\Filter\\GeoDistance' => $vendorDir . '/ruflin/elastica/lib/Elastica/Filter/GeoDistance.php',
+ 'Elastica\\Filter\\GeoDistanceRange' => $vendorDir . '/ruflin/elastica/lib/Elastica/Filter/GeoDistanceRange.php',
+ 'Elastica\\Filter\\GeoPolygon' => $vendorDir . '/ruflin/elastica/lib/Elastica/Filter/GeoPolygon.php',
+ 'Elastica\\Filter\\GeoShapePreIndexed' => $vendorDir . '/ruflin/elastica/lib/Elastica/Filter/GeoShapePreIndexed.php',
+ 'Elastica\\Filter\\GeoShapeProvided' => $vendorDir . '/ruflin/elastica/lib/Elastica/Filter/GeoShapeProvided.php',
+ 'Elastica\\Filter\\GeohashCell' => $vendorDir . '/ruflin/elastica/lib/Elastica/Filter/GeohashCell.php',
+ 'Elastica\\Filter\\HasChild' => $vendorDir . '/ruflin/elastica/lib/Elastica/Filter/HasChild.php',
+ 'Elastica\\Filter\\HasParent' => $vendorDir . '/ruflin/elastica/lib/Elastica/Filter/HasParent.php',
+ 'Elastica\\Filter\\Ids' => $vendorDir . '/ruflin/elastica/lib/Elastica/Filter/Ids.php',
+ 'Elastica\\Filter\\Indices' => $vendorDir . '/ruflin/elastica/lib/Elastica/Filter/Indices.php',
+ 'Elastica\\Filter\\Limit' => $vendorDir . '/ruflin/elastica/lib/Elastica/Filter/Limit.php',
+ 'Elastica\\Filter\\MatchAll' => $vendorDir . '/ruflin/elastica/lib/Elastica/Filter/MatchAll.php',
+ 'Elastica\\Filter\\Missing' => $vendorDir . '/ruflin/elastica/lib/Elastica/Filter/Missing.php',
+ 'Elastica\\Filter\\Nested' => $vendorDir . '/ruflin/elastica/lib/Elastica/Filter/Nested.php',
+ 'Elastica\\Filter\\NumericRange' => $vendorDir . '/ruflin/elastica/lib/Elastica/Filter/NumericRange.php',
+ 'Elastica\\Filter\\Prefix' => $vendorDir . '/ruflin/elastica/lib/Elastica/Filter/Prefix.php',
+ 'Elastica\\Filter\\Query' => $vendorDir . '/ruflin/elastica/lib/Elastica/Filter/Query.php',
+ 'Elastica\\Filter\\Range' => $vendorDir . '/ruflin/elastica/lib/Elastica/Filter/Range.php',
+ 'Elastica\\Filter\\Regexp' => $vendorDir . '/ruflin/elastica/lib/Elastica/Filter/Regexp.php',
+ 'Elastica\\Filter\\Script' => $vendorDir . '/ruflin/elastica/lib/Elastica/Filter/Script.php',
+ 'Elastica\\Filter\\Term' => $vendorDir . '/ruflin/elastica/lib/Elastica/Filter/Term.php',
+ 'Elastica\\Filter\\Terms' => $vendorDir . '/ruflin/elastica/lib/Elastica/Filter/Terms.php',
+ 'Elastica\\Filter\\Type' => $vendorDir . '/ruflin/elastica/lib/Elastica/Filter/Type.php',
+ 'Elastica\\Index' => $vendorDir . '/ruflin/elastica/lib/Elastica/Index.php',
+ 'Elastica\\Index\\Settings' => $vendorDir . '/ruflin/elastica/lib/Elastica/Index/Settings.php',
+ 'Elastica\\Index\\Stats' => $vendorDir . '/ruflin/elastica/lib/Elastica/Index/Stats.php',
+ 'Elastica\\Index\\Status' => $vendorDir . '/ruflin/elastica/lib/Elastica/Index/Status.php',
+ 'Elastica\\JSON' => $vendorDir . '/ruflin/elastica/lib/Elastica/JSON.php',
+ 'Elastica\\Log' => $vendorDir . '/ruflin/elastica/lib/Elastica/Log.php',
+ 'Elastica\\Multi\\ResultSet' => $vendorDir . '/ruflin/elastica/lib/Elastica/Multi/ResultSet.php',
+ 'Elastica\\Multi\\Search' => $vendorDir . '/ruflin/elastica/lib/Elastica/Multi/Search.php',
+ 'Elastica\\Node' => $vendorDir . '/ruflin/elastica/lib/Elastica/Node.php',
+ 'Elastica\\Node\\Info' => $vendorDir . '/ruflin/elastica/lib/Elastica/Node/Info.php',
+ 'Elastica\\Node\\Stats' => $vendorDir . '/ruflin/elastica/lib/Elastica/Node/Stats.php',
+ 'Elastica\\Param' => $vendorDir . '/ruflin/elastica/lib/Elastica/Param.php',
+ 'Elastica\\Percolator' => $vendorDir . '/ruflin/elastica/lib/Elastica/Percolator.php',
+ 'Elastica\\Query' => $vendorDir . '/ruflin/elastica/lib/Elastica/Query.php',
+ 'Elastica\\QueryBuilder' => $vendorDir . '/ruflin/elastica/lib/Elastica/QueryBuilder.php',
+ 'Elastica\\QueryBuilder\\DSL' => $vendorDir . '/ruflin/elastica/lib/Elastica/QueryBuilder/DSL.php',
+ 'Elastica\\QueryBuilder\\DSL\\Aggregation' => $vendorDir . '/ruflin/elastica/lib/Elastica/QueryBuilder/DSL/Aggregation.php',
+ 'Elastica\\QueryBuilder\\DSL\\Filter' => $vendorDir . '/ruflin/elastica/lib/Elastica/QueryBuilder/DSL/Filter.php',
+ 'Elastica\\QueryBuilder\\DSL\\Query' => $vendorDir . '/ruflin/elastica/lib/Elastica/QueryBuilder/DSL/Query.php',
+ 'Elastica\\QueryBuilder\\DSL\\Suggest' => $vendorDir . '/ruflin/elastica/lib/Elastica/QueryBuilder/DSL/Suggest.php',
+ 'Elastica\\QueryBuilder\\Facade' => $vendorDir . '/ruflin/elastica/lib/Elastica/QueryBuilder/Facade.php',
+ 'Elastica\\QueryBuilder\\Version' => $vendorDir . '/ruflin/elastica/lib/Elastica/QueryBuilder/Version.php',
+ 'Elastica\\QueryBuilder\\Version\\Version090' => $vendorDir . '/ruflin/elastica/lib/Elastica/QueryBuilder/Version/Version090.php',
+ 'Elastica\\QueryBuilder\\Version\\Version100' => $vendorDir . '/ruflin/elastica/lib/Elastica/QueryBuilder/Version/Version100.php',
+ 'Elastica\\QueryBuilder\\Version\\Version110' => $vendorDir . '/ruflin/elastica/lib/Elastica/QueryBuilder/Version/Version110.php',
+ 'Elastica\\QueryBuilder\\Version\\Version120' => $vendorDir . '/ruflin/elastica/lib/Elastica/QueryBuilder/Version/Version120.php',
+ 'Elastica\\QueryBuilder\\Version\\Version130' => $vendorDir . '/ruflin/elastica/lib/Elastica/QueryBuilder/Version/Version130.php',
+ 'Elastica\\QueryBuilder\\Version\\Version140' => $vendorDir . '/ruflin/elastica/lib/Elastica/QueryBuilder/Version/Version140.php',
+ 'Elastica\\QueryBuilder\\Version\\Version150' => $vendorDir . '/ruflin/elastica/lib/Elastica/QueryBuilder/Version/Version150.php',
+ 'Elastica\\Query\\AbstractQuery' => $vendorDir . '/ruflin/elastica/lib/Elastica/Query/AbstractQuery.php',
+ 'Elastica\\Query\\Bool' => $vendorDir . '/ruflin/elastica/lib/Elastica/Query/Bool.php',
+ 'Elastica\\Query\\BoolQuery' => $vendorDir . '/ruflin/elastica/lib/Elastica/Query/BoolQuery.php',
+ 'Elastica\\Query\\Boosting' => $vendorDir . '/ruflin/elastica/lib/Elastica/Query/Boosting.php',
+ 'Elastica\\Query\\Builder' => $vendorDir . '/ruflin/elastica/lib/Elastica/Query/Builder.php',
+ 'Elastica\\Query\\Common' => $vendorDir . '/ruflin/elastica/lib/Elastica/Query/Common.php',
+ 'Elastica\\Query\\ConstantScore' => $vendorDir . '/ruflin/elastica/lib/Elastica/Query/ConstantScore.php',
+ 'Elastica\\Query\\DisMax' => $vendorDir . '/ruflin/elastica/lib/Elastica/Query/DisMax.php',
+ 'Elastica\\Query\\Filtered' => $vendorDir . '/ruflin/elastica/lib/Elastica/Query/Filtered.php',
+ 'Elastica\\Query\\FunctionScore' => $vendorDir . '/ruflin/elastica/lib/Elastica/Query/FunctionScore.php',
+ 'Elastica\\Query\\Fuzzy' => $vendorDir . '/ruflin/elastica/lib/Elastica/Query/Fuzzy.php',
+ 'Elastica\\Query\\FuzzyLikeThis' => $vendorDir . '/ruflin/elastica/lib/Elastica/Query/FuzzyLikeThis.php',
+ 'Elastica\\Query\\HasChild' => $vendorDir . '/ruflin/elastica/lib/Elastica/Query/HasChild.php',
+ 'Elastica\\Query\\HasParent' => $vendorDir . '/ruflin/elastica/lib/Elastica/Query/HasParent.php',
+ 'Elastica\\Query\\Ids' => $vendorDir . '/ruflin/elastica/lib/Elastica/Query/Ids.php',
+ 'Elastica\\Query\\Image' => $vendorDir . '/ruflin/elastica/lib/Elastica/Query/Image.php',
+ 'Elastica\\Query\\Match' => $vendorDir . '/ruflin/elastica/lib/Elastica/Query/Match.php',
+ 'Elastica\\Query\\MatchAll' => $vendorDir . '/ruflin/elastica/lib/Elastica/Query/MatchAll.php',
+ 'Elastica\\Query\\MatchPhrase' => $vendorDir . '/ruflin/elastica/lib/Elastica/Query/MatchPhrase.php',
+ 'Elastica\\Query\\MatchPhrasePrefix' => $vendorDir . '/ruflin/elastica/lib/Elastica/Query/MatchPhrasePrefix.php',
+ 'Elastica\\Query\\MoreLikeThis' => $vendorDir . '/ruflin/elastica/lib/Elastica/Query/MoreLikeThis.php',
+ 'Elastica\\Query\\MultiMatch' => $vendorDir . '/ruflin/elastica/lib/Elastica/Query/MultiMatch.php',
+ 'Elastica\\Query\\Nested' => $vendorDir . '/ruflin/elastica/lib/Elastica/Query/Nested.php',
+ 'Elastica\\Query\\Prefix' => $vendorDir . '/ruflin/elastica/lib/Elastica/Query/Prefix.php',
+ 'Elastica\\Query\\QueryString' => $vendorDir . '/ruflin/elastica/lib/Elastica/Query/QueryString.php',
+ 'Elastica\\Query\\Range' => $vendorDir . '/ruflin/elastica/lib/Elastica/Query/Range.php',
+ 'Elastica\\Query\\Regexp' => $vendorDir . '/ruflin/elastica/lib/Elastica/Query/Regexp.php',
+ 'Elastica\\Query\\Simple' => $vendorDir . '/ruflin/elastica/lib/Elastica/Query/Simple.php',
+ 'Elastica\\Query\\SimpleQueryString' => $vendorDir . '/ruflin/elastica/lib/Elastica/Query/SimpleQueryString.php',
+ 'Elastica\\Query\\Term' => $vendorDir . '/ruflin/elastica/lib/Elastica/Query/Term.php',
+ 'Elastica\\Query\\Terms' => $vendorDir . '/ruflin/elastica/lib/Elastica/Query/Terms.php',
+ 'Elastica\\Query\\TopChildren' => $vendorDir . '/ruflin/elastica/lib/Elastica/Query/TopChildren.php',
+ 'Elastica\\Query\\Wildcard' => $vendorDir . '/ruflin/elastica/lib/Elastica/Query/Wildcard.php',
+ 'Elastica\\Request' => $vendorDir . '/ruflin/elastica/lib/Elastica/Request.php',
+ 'Elastica\\Rescore\\AbstractRescore' => $vendorDir . '/ruflin/elastica/lib/Elastica/Rescore/AbstractRescore.php',
+ 'Elastica\\Rescore\\Query' => $vendorDir . '/ruflin/elastica/lib/Elastica/Rescore/Query.php',
+ 'Elastica\\Response' => $vendorDir . '/ruflin/elastica/lib/Elastica/Response.php',
+ 'Elastica\\Result' => $vendorDir . '/ruflin/elastica/lib/Elastica/Result.php',
+ 'Elastica\\ResultSet' => $vendorDir . '/ruflin/elastica/lib/Elastica/ResultSet.php',
+ 'Elastica\\ScanAndScroll' => $vendorDir . '/ruflin/elastica/lib/Elastica/ScanAndScroll.php',
+ 'Elastica\\Script' => $vendorDir . '/ruflin/elastica/lib/Elastica/Script.php',
+ 'Elastica\\ScriptFields' => $vendorDir . '/ruflin/elastica/lib/Elastica/ScriptFields.php',
+ 'Elastica\\Scroll' => $vendorDir . '/ruflin/elastica/lib/Elastica/Scroll.php',
+ 'Elastica\\Search' => $vendorDir . '/ruflin/elastica/lib/Elastica/Search.php',
+ 'Elastica\\SearchableInterface' => $vendorDir . '/ruflin/elastica/lib/Elastica/SearchableInterface.php',
+ 'Elastica\\Snapshot' => $vendorDir . '/ruflin/elastica/lib/Elastica/Snapshot.php',
+ 'Elastica\\Status' => $vendorDir . '/ruflin/elastica/lib/Elastica/Status.php',
+ 'Elastica\\Suggest' => $vendorDir . '/ruflin/elastica/lib/Elastica/Suggest.php',
+ 'Elastica\\Suggest\\AbstractSuggest' => $vendorDir . '/ruflin/elastica/lib/Elastica/Suggest/AbstractSuggest.php',
+ 'Elastica\\Suggest\\CandidateGenerator\\AbstractCandidateGenerator' => $vendorDir . '/ruflin/elastica/lib/Elastica/Suggest/CandidateGenerator/AbstractCandidateGenerator.php',
+ 'Elastica\\Suggest\\CandidateGenerator\\DirectGenerator' => $vendorDir . '/ruflin/elastica/lib/Elastica/Suggest/CandidateGenerator/DirectGenerator.php',
+ 'Elastica\\Suggest\\Completion' => $vendorDir . '/ruflin/elastica/lib/Elastica/Suggest/Completion.php',
+ 'Elastica\\Suggest\\Phrase' => $vendorDir . '/ruflin/elastica/lib/Elastica/Suggest/Phrase.php',
+ 'Elastica\\Suggest\\Term' => $vendorDir . '/ruflin/elastica/lib/Elastica/Suggest/Term.php',
+ 'Elastica\\Tool\\CrossIndex' => $vendorDir . '/ruflin/elastica/lib/Elastica/Tool/CrossIndex.php',
+ 'Elastica\\Transport\\AbstractTransport' => $vendorDir . '/ruflin/elastica/lib/Elastica/Transport/AbstractTransport.php',
+ 'Elastica\\Transport\\Guzzle' => $vendorDir . '/ruflin/elastica/lib/Elastica/Transport/Guzzle.php',
+ 'Elastica\\Transport\\Http' => $vendorDir . '/ruflin/elastica/lib/Elastica/Transport/Http.php',
+ 'Elastica\\Transport\\HttpAdapter' => $vendorDir . '/ruflin/elastica/lib/Elastica/Transport/HttpAdapter.php',
+ 'Elastica\\Transport\\Https' => $vendorDir . '/ruflin/elastica/lib/Elastica/Transport/Https.php',
+ 'Elastica\\Transport\\Memcache' => $vendorDir . '/ruflin/elastica/lib/Elastica/Transport/Memcache.php',
+ 'Elastica\\Transport\\Null' => $vendorDir . '/ruflin/elastica/lib/Elastica/Transport/Null.php',
+ 'Elastica\\Transport\\NullTransport' => $vendorDir . '/ruflin/elastica/lib/Elastica/Transport/NullTransport.php',
+ 'Elastica\\Transport\\Thrift' => $vendorDir . '/ruflin/elastica/lib/Elastica/Transport/Thrift.php',
+ 'Elastica\\Type' => $vendorDir . '/ruflin/elastica/lib/Elastica/Type.php',
+ 'Elastica\\Type\\AbstractType' => $vendorDir . '/ruflin/elastica/lib/Elastica/Type/AbstractType.php',
+ 'Elastica\\Type\\Mapping' => $vendorDir . '/ruflin/elastica/lib/Elastica/Type/Mapping.php',
+ 'Elastica\\Util' => $vendorDir . '/ruflin/elastica/lib/Elastica/Util.php',
+ 'ExpiredException' => $vendorDir . '/firebase/php-jwt/Exceptions/ExpiredException.php',
+ 'IPSet\\IPSet' => $vendorDir . '/wikimedia/ip-set/src/IPSet.php',
+ 'JWT' => $vendorDir . '/firebase/php-jwt/Authentication/JWT.php',
+ 'Kafka\\Client' => $vendorDir . '/nmred/kafka-php/src/Kafka/Client.php',
+ 'Kafka\\ClusterMetaData' => $vendorDir . '/nmred/kafka-php/src/Kafka/ClusterMetaData.php',
+ 'Kafka\\Consumer' => $vendorDir . '/nmred/kafka-php/src/Kafka/Consumer.php',
+ 'Kafka\\Exception' => $vendorDir . '/nmred/kafka-php/src/Kafka/Exception.php',
+ 'Kafka\\Exception\\NotSupported' => $vendorDir . '/nmred/kafka-php/src/Kafka/Exception/NotSupported.php',
+ 'Kafka\\Exception\\OutOfRange' => $vendorDir . '/nmred/kafka-php/src/Kafka/Exception/OutOfRange.php',
+ 'Kafka\\Exception\\Protocol' => $vendorDir . '/nmred/kafka-php/src/Kafka/Exception/Protocol.php',
+ 'Kafka\\Exception\\Socket' => $vendorDir . '/nmred/kafka-php/src/Kafka/Exception/Socket.php',
+ 'Kafka\\Exception\\SocketConnect' => $vendorDir . '/nmred/kafka-php/src/Kafka/Exception/SocketConnect.php',
+ 'Kafka\\Exception\\SocketEOF' => $vendorDir . '/nmred/kafka-php/src/Kafka/Exception/SocketEOF.php',
+ 'Kafka\\Exception\\SocketTimeout' => $vendorDir . '/nmred/kafka-php/src/Kafka/Exception/SocketTimeout.php',
+ 'Kafka\\Log' => $vendorDir . '/nmred/kafka-php/src/Kafka/Log.php',
+ 'Kafka\\MetaDataFromKafka' => $vendorDir . '/nmred/kafka-php/src/Kafka/MetaDataFromKafka.php',
+ 'Kafka\\Offset' => $vendorDir . '/nmred/kafka-php/src/Kafka/Offset.php',
+ 'Kafka\\Produce' => $vendorDir . '/nmred/kafka-php/src/Kafka/Produce.php',
+ 'Kafka\\Protocol\\Decoder' => $vendorDir . '/nmred/kafka-php/src/Kafka/Protocol/Decoder.php',
+ 'Kafka\\Protocol\\Encoder' => $vendorDir . '/nmred/kafka-php/src/Kafka/Protocol/Encoder.php',
+ 'Kafka\\Protocol\\Fetch\\Helper\\CommitOffset' => $vendorDir . '/nmred/kafka-php/src/Kafka/Protocol/Fetch/Helper/CommitOffset.php',
+ 'Kafka\\Protocol\\Fetch\\Helper\\Consumer' => $vendorDir . '/nmred/kafka-php/src/Kafka/Protocol/Fetch/Helper/Consumer.php',
+ 'Kafka\\Protocol\\Fetch\\Helper\\FreeStream' => $vendorDir . '/nmred/kafka-php/src/Kafka/Protocol/Fetch/Helper/FreeStream.php',
+ 'Kafka\\Protocol\\Fetch\\Helper\\Helper' => $vendorDir . '/nmred/kafka-php/src/Kafka/Protocol/Fetch/Helper/Helper.php',
+ 'Kafka\\Protocol\\Fetch\\Helper\\HelperAbstract' => $vendorDir . '/nmred/kafka-php/src/Kafka/Protocol/Fetch/Helper/HelperAbstract.php',
+ 'Kafka\\Protocol\\Fetch\\Message' => $vendorDir . '/nmred/kafka-php/src/Kafka/Protocol/Fetch/Message.php',
+ 'Kafka\\Protocol\\Fetch\\MessageSet' => $vendorDir . '/nmred/kafka-php/src/Kafka/Protocol/Fetch/MessageSet.php',
+ 'Kafka\\Protocol\\Fetch\\Partition' => $vendorDir . '/nmred/kafka-php/src/Kafka/Protocol/Fetch/Partition.php',
+ 'Kafka\\Protocol\\Fetch\\Topic' => $vendorDir . '/nmred/kafka-php/src/Kafka/Protocol/Fetch/Topic.php',
+ 'Kafka\\Protocol\\Protocol' => $vendorDir . '/nmred/kafka-php/src/Kafka/Protocol/Protocol.php',
+ 'Kafka\\Socket' => $vendorDir . '/nmred/kafka-php/src/Kafka/Socket.php',
+ 'Kafka\\ZooKeeper' => $vendorDir . '/nmred/kafka-php/src/Kafka/ZooKeeper.php',
+ 'KzykHys\\Pygments\\Pygments' => $vendorDir . '/kzykhys/pygments/src/KzykHys/Pygments/Pygments.php',
'LCRun3' => $vendorDir . '/zordius/lightncandy/src/lightncandy.php',
+ 'Less_Autoloader' => $vendorDir . '/oyejorge/less.php/lib/Less/Autoloader.php',
+ 'Less_Cache' => $vendorDir . '/oyejorge/less.php/lib/Less/Cache.php',
+ 'Less_Colors' => $vendorDir . '/oyejorge/less.php/lib/Less/Colors.php',
+ 'Less_Configurable' => $vendorDir . '/oyejorge/less.php/lib/Less/Configurable.php',
+ 'Less_Environment' => $vendorDir . '/oyejorge/less.php/lib/Less/Environment.php',
+ 'Less_Exception_Chunk' => $vendorDir . '/oyejorge/less.php/lib/Less/Exception/Chunk.php',
+ 'Less_Exception_Compiler' => $vendorDir . '/oyejorge/less.php/lib/Less/Exception/Compiler.php',
+ 'Less_Exception_Parser' => $vendorDir . '/oyejorge/less.php/lib/Less/Exception/Parser.php',
+ 'Less_Functions' => $vendorDir . '/oyejorge/less.php/lib/Less/Functions.php',
+ 'Less_Mime' => $vendorDir . '/oyejorge/less.php/lib/Less/Mime.php',
+ 'Less_Output' => $vendorDir . '/oyejorge/less.php/lib/Less/Output.php',
+ 'Less_Output_Mapped' => $vendorDir . '/oyejorge/less.php/lib/Less/Output/Mapped.php',
+ 'Less_Parser' => $vendorDir . '/oyejorge/less.php/lib/Less/Parser.php',
+ 'Less_SourceMap_Base64VLQ' => $vendorDir . '/oyejorge/less.php/lib/Less/SourceMap/Base64VLQ.php',
+ 'Less_SourceMap_Generator' => $vendorDir . '/oyejorge/less.php/lib/Less/SourceMap/Generator.php',
+ 'Less_Tree' => $vendorDir . '/oyejorge/less.php/lib/Less/Tree.php',
+ 'Less_Tree_Alpha' => $vendorDir . '/oyejorge/less.php/lib/Less/Tree/Alpha.php',
+ 'Less_Tree_Anonymous' => $vendorDir . '/oyejorge/less.php/lib/Less/Tree/Anonymous.php',
+ 'Less_Tree_Assignment' => $vendorDir . '/oyejorge/less.php/lib/Less/Tree/Assignment.php',
+ 'Less_Tree_Attribute' => $vendorDir . '/oyejorge/less.php/lib/Less/Tree/Attribute.php',
+ 'Less_Tree_Call' => $vendorDir . '/oyejorge/less.php/lib/Less/Tree/Call.php',
+ 'Less_Tree_Color' => $vendorDir . '/oyejorge/less.php/lib/Less/Tree/Color.php',
+ 'Less_Tree_Comment' => $vendorDir . '/oyejorge/less.php/lib/Less/Tree/Comment.php',
+ 'Less_Tree_Condition' => $vendorDir . '/oyejorge/less.php/lib/Less/Tree/Condition.php',
+ 'Less_Tree_DefaultFunc' => $vendorDir . '/oyejorge/less.php/lib/Less/Tree/DefaultFunc.php',
+ 'Less_Tree_DetachedRuleset' => $vendorDir . '/oyejorge/less.php/lib/Less/Tree/DetachedRuleset.php',
+ 'Less_Tree_Dimension' => $vendorDir . '/oyejorge/less.php/lib/Less/Tree/Dimension.php',
+ 'Less_Tree_Directive' => $vendorDir . '/oyejorge/less.php/lib/Less/Tree/Directive.php',
+ 'Less_Tree_Element' => $vendorDir . '/oyejorge/less.php/lib/Less/Tree/Element.php',
+ 'Less_Tree_Expression' => $vendorDir . '/oyejorge/less.php/lib/Less/Tree/Expression.php',
+ 'Less_Tree_Extend' => $vendorDir . '/oyejorge/less.php/lib/Less/Tree/Extend.php',
+ 'Less_Tree_Import' => $vendorDir . '/oyejorge/less.php/lib/Less/Tree/Import.php',
+ 'Less_Tree_Javascript' => $vendorDir . '/oyejorge/less.php/lib/Less/Tree/Javascript.php',
+ 'Less_Tree_Keyword' => $vendorDir . '/oyejorge/less.php/lib/Less/Tree/Keyword.php',
+ 'Less_Tree_Media' => $vendorDir . '/oyejorge/less.php/lib/Less/Tree/Media.php',
+ 'Less_Tree_Mixin_Call' => $vendorDir . '/oyejorge/less.php/lib/Less/Tree/Mixin/Call.php',
+ 'Less_Tree_Mixin_Definition' => $vendorDir . '/oyejorge/less.php/lib/Less/Tree/Mixin/Definition.php',
+ 'Less_Tree_NameValue' => $vendorDir . '/oyejorge/less.php/lib/Less/Tree/NameValue.php',
+ 'Less_Tree_Negative' => $vendorDir . '/oyejorge/less.php/lib/Less/Tree/Negative.php',
+ 'Less_Tree_Operation' => $vendorDir . '/oyejorge/less.php/lib/Less/Tree/Operation.php',
+ 'Less_Tree_Paren' => $vendorDir . '/oyejorge/less.php/lib/Less/Tree/Paren.php',
+ 'Less_Tree_Quoted' => $vendorDir . '/oyejorge/less.php/lib/Less/Tree/Quoted.php',
+ 'Less_Tree_Rule' => $vendorDir . '/oyejorge/less.php/lib/Less/Tree/Rule.php',
+ 'Less_Tree_Ruleset' => $vendorDir . '/oyejorge/less.php/lib/Less/Tree/Ruleset.php',
+ 'Less_Tree_RulesetCall' => $vendorDir . '/oyejorge/less.php/lib/Less/Tree/RulesetCall.php',
+ 'Less_Tree_Selector' => $vendorDir . '/oyejorge/less.php/lib/Less/Tree/Selector.php',
+ 'Less_Tree_UnicodeDescriptor' => $vendorDir . '/oyejorge/less.php/lib/Less/Tree/UnicodeDescriptor.php',
+ 'Less_Tree_Unit' => $vendorDir . '/oyejorge/less.php/lib/Less/Tree/Unit.php',
+ 'Less_Tree_UnitConversions' => $vendorDir . '/oyejorge/less.php/lib/Less/Tree/UnitConversions.php',
+ 'Less_Tree_Url' => $vendorDir . '/oyejorge/less.php/lib/Less/Tree/Url.php',
+ 'Less_Tree_Value' => $vendorDir . '/oyejorge/less.php/lib/Less/Tree/Value.php',
+ 'Less_Tree_Variable' => $vendorDir . '/oyejorge/less.php/lib/Less/Tree/Variable.php',
+ 'Less_Version' => $vendorDir . '/oyejorge/less.php/lib/Less/Version.php',
+ 'Less_Visitor' => $vendorDir . '/oyejorge/less.php/lib/Less/Visitor.php',
+ 'Less_VisitorReplacing' => $vendorDir . '/oyejorge/less.php/lib/Less/VisitorReplacing.php',
+ 'Less_Visitor_extendFinder' => $vendorDir . '/oyejorge/less.php/lib/Less/Visitor/extendFinder.php',
+ 'Less_Visitor_joinSelector' => $vendorDir . '/oyejorge/less.php/lib/Less/Visitor/joinSelector.php',
+ 'Less_Visitor_processExtends' => $vendorDir . '/oyejorge/less.php/lib/Less/Visitor/processExtends.php',
+ 'Less_Visitor_toCSS' => $vendorDir . '/oyejorge/less.php/lib/Less/Visitor/toCSS.php',
'LightnCandy' => $vendorDir . '/zordius/lightncandy/src/lightncandy.php',
'Liuggio\\StatsdClient\\Entity\\StatsdData' => $vendorDir . '/liuggio/statsd-php-client/src/Liuggio/StatsdClient/Entity/StatsdData.php',
'Liuggio\\StatsdClient\\Entity\\StatsdDataInterface' => $vendorDir . '/liuggio/statsd-php-client/src/Liuggio/StatsdClient/Entity/StatsdDataInterface.php',
@@ -30,10 +380,92 @@ return array(
'Liuggio\\StatsdClient\\Sender\\SenderInterface' => $vendorDir . '/liuggio/statsd-php-client/src/Liuggio/StatsdClient/Sender/SenderInterface.php',
'Liuggio\\StatsdClient\\Sender\\SocketSender' => $vendorDir . '/liuggio/statsd-php-client/src/Liuggio/StatsdClient/Sender/SocketSender.php',
'Liuggio\\StatsdClient\\Sender\\SysLogSender' => $vendorDir . '/liuggio/statsd-php-client/src/Liuggio/StatsdClient/Sender/SysLogSender.php',
+ 'Liuggio\\StatsdClient\\Service\\StatsdService' => $vendorDir . '/liuggio/statsd-php-client/src/Liuggio/StatsdClient/Service/StatsdService.php',
'Liuggio\\StatsdClient\\StatsdClient' => $vendorDir . '/liuggio/statsd-php-client/src/Liuggio/StatsdClient/StatsdClient.php',
'Liuggio\\StatsdClient\\StatsdClientInterface' => $vendorDir . '/liuggio/statsd-php-client/src/Liuggio/StatsdClient/StatsdClientInterface.php',
+ 'Monolog\\ErrorHandler' => $vendorDir . '/monolog/monolog/src/Monolog/ErrorHandler.php',
+ 'Monolog\\Formatter\\ChromePHPFormatter' => $vendorDir . '/monolog/monolog/src/Monolog/Formatter/ChromePHPFormatter.php',
+ 'Monolog\\Formatter\\ElasticaFormatter' => $vendorDir . '/monolog/monolog/src/Monolog/Formatter/ElasticaFormatter.php',
+ 'Monolog\\Formatter\\FlowdockFormatter' => $vendorDir . '/monolog/monolog/src/Monolog/Formatter/FlowdockFormatter.php',
+ 'Monolog\\Formatter\\FormatterInterface' => $vendorDir . '/monolog/monolog/src/Monolog/Formatter/FormatterInterface.php',
+ 'Monolog\\Formatter\\GelfMessageFormatter' => $vendorDir . '/monolog/monolog/src/Monolog/Formatter/GelfMessageFormatter.php',
+ 'Monolog\\Formatter\\HtmlFormatter' => $vendorDir . '/monolog/monolog/src/Monolog/Formatter/HtmlFormatter.php',
+ 'Monolog\\Formatter\\JsonFormatter' => $vendorDir . '/monolog/monolog/src/Monolog/Formatter/JsonFormatter.php',
+ 'Monolog\\Formatter\\LineFormatter' => $vendorDir . '/monolog/monolog/src/Monolog/Formatter/LineFormatter.php',
+ 'Monolog\\Formatter\\LogglyFormatter' => $vendorDir . '/monolog/monolog/src/Monolog/Formatter/LogglyFormatter.php',
+ 'Monolog\\Formatter\\LogstashFormatter' => $vendorDir . '/monolog/monolog/src/Monolog/Formatter/LogstashFormatter.php',
+ 'Monolog\\Formatter\\MongoDBFormatter' => $vendorDir . '/monolog/monolog/src/Monolog/Formatter/MongoDBFormatter.php',
+ 'Monolog\\Formatter\\NormalizerFormatter' => $vendorDir . '/monolog/monolog/src/Monolog/Formatter/NormalizerFormatter.php',
+ 'Monolog\\Formatter\\ScalarFormatter' => $vendorDir . '/monolog/monolog/src/Monolog/Formatter/ScalarFormatter.php',
+ 'Monolog\\Formatter\\WildfireFormatter' => $vendorDir . '/monolog/monolog/src/Monolog/Formatter/WildfireFormatter.php',
+ 'Monolog\\Handler\\AbstractHandler' => $vendorDir . '/monolog/monolog/src/Monolog/Handler/AbstractHandler.php',
+ 'Monolog\\Handler\\AbstractProcessingHandler' => $vendorDir . '/monolog/monolog/src/Monolog/Handler/AbstractProcessingHandler.php',
+ 'Monolog\\Handler\\AbstractSyslogHandler' => $vendorDir . '/monolog/monolog/src/Monolog/Handler/AbstractSyslogHandler.php',
+ 'Monolog\\Handler\\AmqpHandler' => $vendorDir . '/monolog/monolog/src/Monolog/Handler/AmqpHandler.php',
+ 'Monolog\\Handler\\BrowserConsoleHandler' => $vendorDir . '/monolog/monolog/src/Monolog/Handler/BrowserConsoleHandler.php',
+ 'Monolog\\Handler\\BufferHandler' => $vendorDir . '/monolog/monolog/src/Monolog/Handler/BufferHandler.php',
+ 'Monolog\\Handler\\ChromePHPHandler' => $vendorDir . '/monolog/monolog/src/Monolog/Handler/ChromePHPHandler.php',
+ 'Monolog\\Handler\\CouchDBHandler' => $vendorDir . '/monolog/monolog/src/Monolog/Handler/CouchDBHandler.php',
+ 'Monolog\\Handler\\CubeHandler' => $vendorDir . '/monolog/monolog/src/Monolog/Handler/CubeHandler.php',
+ 'Monolog\\Handler\\DoctrineCouchDBHandler' => $vendorDir . '/monolog/monolog/src/Monolog/Handler/DoctrineCouchDBHandler.php',
+ 'Monolog\\Handler\\DynamoDbHandler' => $vendorDir . '/monolog/monolog/src/Monolog/Handler/DynamoDbHandler.php',
+ 'Monolog\\Handler\\ElasticSearchHandler' => $vendorDir . '/monolog/monolog/src/Monolog/Handler/ElasticSearchHandler.php',
+ 'Monolog\\Handler\\ErrorLogHandler' => $vendorDir . '/monolog/monolog/src/Monolog/Handler/ErrorLogHandler.php',
+ 'Monolog\\Handler\\FilterHandler' => $vendorDir . '/monolog/monolog/src/Monolog/Handler/FilterHandler.php',
+ 'Monolog\\Handler\\FingersCrossedHandler' => $vendorDir . '/monolog/monolog/src/Monolog/Handler/FingersCrossedHandler.php',
+ 'Monolog\\Handler\\FingersCrossed\\ActivationStrategyInterface' => $vendorDir . '/monolog/monolog/src/Monolog/Handler/FingersCrossed/ActivationStrategyInterface.php',
+ 'Monolog\\Handler\\FingersCrossed\\ChannelLevelActivationStrategy' => $vendorDir . '/monolog/monolog/src/Monolog/Handler/FingersCrossed/ChannelLevelActivationStrategy.php',
+ 'Monolog\\Handler\\FingersCrossed\\ErrorLevelActivationStrategy' => $vendorDir . '/monolog/monolog/src/Monolog/Handler/FingersCrossed/ErrorLevelActivationStrategy.php',
+ 'Monolog\\Handler\\FirePHPHandler' => $vendorDir . '/monolog/monolog/src/Monolog/Handler/FirePHPHandler.php',
+ 'Monolog\\Handler\\FleepHookHandler' => $vendorDir . '/monolog/monolog/src/Monolog/Handler/FleepHookHandler.php',
+ 'Monolog\\Handler\\FlowdockHandler' => $vendorDir . '/monolog/monolog/src/Monolog/Handler/FlowdockHandler.php',
+ 'Monolog\\Handler\\GelfHandler' => $vendorDir . '/monolog/monolog/src/Monolog/Handler/GelfHandler.php',
+ 'Monolog\\Handler\\GroupHandler' => $vendorDir . '/monolog/monolog/src/Monolog/Handler/GroupHandler.php',
+ 'Monolog\\Handler\\HandlerInterface' => $vendorDir . '/monolog/monolog/src/Monolog/Handler/HandlerInterface.php',
+ 'Monolog\\Handler\\HipChatHandler' => $vendorDir . '/monolog/monolog/src/Monolog/Handler/HipChatHandler.php',
+ 'Monolog\\Handler\\LogEntriesHandler' => $vendorDir . '/monolog/monolog/src/Monolog/Handler/LogEntriesHandler.php',
+ 'Monolog\\Handler\\LogglyHandler' => $vendorDir . '/monolog/monolog/src/Monolog/Handler/LogglyHandler.php',
+ 'Monolog\\Handler\\MailHandler' => $vendorDir . '/monolog/monolog/src/Monolog/Handler/MailHandler.php',
+ 'Monolog\\Handler\\MandrillHandler' => $vendorDir . '/monolog/monolog/src/Monolog/Handler/MandrillHandler.php',
+ 'Monolog\\Handler\\MissingExtensionException' => $vendorDir . '/monolog/monolog/src/Monolog/Handler/MissingExtensionException.php',
+ 'Monolog\\Handler\\MongoDBHandler' => $vendorDir . '/monolog/monolog/src/Monolog/Handler/MongoDBHandler.php',
+ 'Monolog\\Handler\\NativeMailerHandler' => $vendorDir . '/monolog/monolog/src/Monolog/Handler/NativeMailerHandler.php',
+ 'Monolog\\Handler\\NewRelicHandler' => $vendorDir . '/monolog/monolog/src/Monolog/Handler/NewRelicHandler.php',
+ 'Monolog\\Handler\\NullHandler' => $vendorDir . '/monolog/monolog/src/Monolog/Handler/NullHandler.php',
+ 'Monolog\\Handler\\PHPConsoleHandler' => $vendorDir . '/monolog/monolog/src/Monolog/Handler/PHPConsoleHandler.php',
+ 'Monolog\\Handler\\PsrHandler' => $vendorDir . '/monolog/monolog/src/Monolog/Handler/PsrHandler.php',
+ 'Monolog\\Handler\\PushoverHandler' => $vendorDir . '/monolog/monolog/src/Monolog/Handler/PushoverHandler.php',
+ 'Monolog\\Handler\\RavenHandler' => $vendorDir . '/monolog/monolog/src/Monolog/Handler/RavenHandler.php',
+ 'Monolog\\Handler\\RedisHandler' => $vendorDir . '/monolog/monolog/src/Monolog/Handler/RedisHandler.php',
+ 'Monolog\\Handler\\RollbarHandler' => $vendorDir . '/monolog/monolog/src/Monolog/Handler/RollbarHandler.php',
+ 'Monolog\\Handler\\RotatingFileHandler' => $vendorDir . '/monolog/monolog/src/Monolog/Handler/RotatingFileHandler.php',
+ 'Monolog\\Handler\\SamplingHandler' => $vendorDir . '/monolog/monolog/src/Monolog/Handler/SamplingHandler.php',
+ 'Monolog\\Handler\\SlackHandler' => $vendorDir . '/monolog/monolog/src/Monolog/Handler/SlackHandler.php',
+ 'Monolog\\Handler\\SocketHandler' => $vendorDir . '/monolog/monolog/src/Monolog/Handler/SocketHandler.php',
+ 'Monolog\\Handler\\StreamHandler' => $vendorDir . '/monolog/monolog/src/Monolog/Handler/StreamHandler.php',
+ 'Monolog\\Handler\\SwiftMailerHandler' => $vendorDir . '/monolog/monolog/src/Monolog/Handler/SwiftMailerHandler.php',
+ 'Monolog\\Handler\\SyslogHandler' => $vendorDir . '/monolog/monolog/src/Monolog/Handler/SyslogHandler.php',
+ 'Monolog\\Handler\\SyslogUdpHandler' => $vendorDir . '/monolog/monolog/src/Monolog/Handler/SyslogUdpHandler.php',
+ 'Monolog\\Handler\\SyslogUdp\\UdpSocket' => $vendorDir . '/monolog/monolog/src/Monolog/Handler/SyslogUdp/UdpSocket.php',
+ 'Monolog\\Handler\\TestHandler' => $vendorDir . '/monolog/monolog/src/Monolog/Handler/TestHandler.php',
+ 'Monolog\\Handler\\WhatFailureGroupHandler' => $vendorDir . '/monolog/monolog/src/Monolog/Handler/WhatFailureGroupHandler.php',
+ 'Monolog\\Handler\\ZendMonitorHandler' => $vendorDir . '/monolog/monolog/src/Monolog/Handler/ZendMonitorHandler.php',
+ 'Monolog\\Logger' => $vendorDir . '/monolog/monolog/src/Monolog/Logger.php',
+ 'Monolog\\Processor\\GitProcessor' => $vendorDir . '/monolog/monolog/src/Monolog/Processor/GitProcessor.php',
+ 'Monolog\\Processor\\IntrospectionProcessor' => $vendorDir . '/monolog/monolog/src/Monolog/Processor/IntrospectionProcessor.php',
+ 'Monolog\\Processor\\MemoryPeakUsageProcessor' => $vendorDir . '/monolog/monolog/src/Monolog/Processor/MemoryPeakUsageProcessor.php',
+ 'Monolog\\Processor\\MemoryProcessor' => $vendorDir . '/monolog/monolog/src/Monolog/Processor/MemoryProcessor.php',
+ 'Monolog\\Processor\\MemoryUsageProcessor' => $vendorDir . '/monolog/monolog/src/Monolog/Processor/MemoryUsageProcessor.php',
+ 'Monolog\\Processor\\ProcessIdProcessor' => $vendorDir . '/monolog/monolog/src/Monolog/Processor/ProcessIdProcessor.php',
+ 'Monolog\\Processor\\PsrLogMessageProcessor' => $vendorDir . '/monolog/monolog/src/Monolog/Processor/PsrLogMessageProcessor.php',
+ 'Monolog\\Processor\\TagProcessor' => $vendorDir . '/monolog/monolog/src/Monolog/Processor/TagProcessor.php',
+ 'Monolog\\Processor\\UidProcessor' => $vendorDir . '/monolog/monolog/src/Monolog/Processor/UidProcessor.php',
+ 'Monolog\\Processor\\WebProcessor' => $vendorDir . '/monolog/monolog/src/Monolog/Processor/WebProcessor.php',
+ 'Monolog\\Registry' => $vendorDir . '/monolog/monolog/src/Monolog/Registry.php',
+ 'OOUI\\AccessKeyedElement' => $vendorDir . '/oojs/oojs-ui/php/mixins/AccessKeyedElement.php',
+ 'OOUI\\ActionFieldLayout' => $vendorDir . '/oojs/oojs-ui/php/layouts/ActionFieldLayout.php',
'OOUI\\ApexTheme' => $vendorDir . '/oojs/oojs-ui/php/themes/ApexTheme.php',
- 'OOUI\\ButtonElement' => $vendorDir . '/oojs/oojs-ui/php/elements/ButtonElement.php',
+ 'OOUI\\ButtonElement' => $vendorDir . '/oojs/oojs-ui/php/mixins/ButtonElement.php',
'OOUI\\ButtonGroupWidget' => $vendorDir . '/oojs/oojs-ui/php/widgets/ButtonGroupWidget.php',
'OOUI\\ButtonInputWidget' => $vendorDir . '/oojs/oojs-ui/php/widgets/ButtonInputWidget.php',
'OOUI\\ButtonWidget' => $vendorDir . '/oojs/oojs-ui/php/widgets/ButtonWidget.php',
@@ -44,42 +476,85 @@ return array(
'OOUI\\Exception' => $vendorDir . '/oojs/oojs-ui/php/Exception.php',
'OOUI\\FieldLayout' => $vendorDir . '/oojs/oojs-ui/php/layouts/FieldLayout.php',
'OOUI\\FieldsetLayout' => $vendorDir . '/oojs/oojs-ui/php/layouts/FieldsetLayout.php',
- 'OOUI\\FlaggedElement' => $vendorDir . '/oojs/oojs-ui/php/elements/FlaggedElement.php',
+ 'OOUI\\FlaggedElement' => $vendorDir . '/oojs/oojs-ui/php/mixins/FlaggedElement.php',
'OOUI\\FormLayout' => $vendorDir . '/oojs/oojs-ui/php/layouts/FormLayout.php',
- 'OOUI\\GroupElement' => $vendorDir . '/oojs/oojs-ui/php/elements/GroupElement.php',
+ 'OOUI\\GroupElement' => $vendorDir . '/oojs/oojs-ui/php/mixins/GroupElement.php',
+ 'OOUI\\HorizontalLayout' => $vendorDir . '/oojs/oojs-ui/php/layouts/HorizontalLayout.php',
'OOUI\\HtmlSnippet' => $vendorDir . '/oojs/oojs-ui/php/HtmlSnippet.php',
- 'OOUI\\IconElement' => $vendorDir . '/oojs/oojs-ui/php/elements/IconElement.php',
+ 'OOUI\\IconElement' => $vendorDir . '/oojs/oojs-ui/php/mixins/IconElement.php',
'OOUI\\IconWidget' => $vendorDir . '/oojs/oojs-ui/php/widgets/IconWidget.php',
- 'OOUI\\IndicatorElement' => $vendorDir . '/oojs/oojs-ui/php/elements/IndicatorElement.php',
+ 'OOUI\\IndicatorElement' => $vendorDir . '/oojs/oojs-ui/php/mixins/IndicatorElement.php',
'OOUI\\IndicatorWidget' => $vendorDir . '/oojs/oojs-ui/php/widgets/IndicatorWidget.php',
'OOUI\\InputWidget' => $vendorDir . '/oojs/oojs-ui/php/widgets/InputWidget.php',
- 'OOUI\\LabelElement' => $vendorDir . '/oojs/oojs-ui/php/elements/LabelElement.php',
+ 'OOUI\\LabelElement' => $vendorDir . '/oojs/oojs-ui/php/mixins/LabelElement.php',
'OOUI\\LabelWidget' => $vendorDir . '/oojs/oojs-ui/php/widgets/LabelWidget.php',
'OOUI\\Layout' => $vendorDir . '/oojs/oojs-ui/php/Layout.php',
'OOUI\\MediaWikiTheme' => $vendorDir . '/oojs/oojs-ui/php/themes/MediaWikiTheme.php',
'OOUI\\PanelLayout' => $vendorDir . '/oojs/oojs-ui/php/layouts/PanelLayout.php',
'OOUI\\RadioInputWidget' => $vendorDir . '/oojs/oojs-ui/php/widgets/RadioInputWidget.php',
- 'OOUI\\TabIndexedElement' => $vendorDir . '/oojs/oojs-ui/php/elements/TabIndexedElement.php',
+ 'OOUI\\RadioSelectInputWidget' => $vendorDir . '/oojs/oojs-ui/php/widgets/RadioSelectInputWidget.php',
+ 'OOUI\\TabIndexedElement' => $vendorDir . '/oojs/oojs-ui/php/mixins/TabIndexedElement.php',
'OOUI\\Tag' => $vendorDir . '/oojs/oojs-ui/php/Tag.php',
'OOUI\\TextInputWidget' => $vendorDir . '/oojs/oojs-ui/php/widgets/TextInputWidget.php',
'OOUI\\Theme' => $vendorDir . '/oojs/oojs-ui/php/Theme.php',
- 'OOUI\\TitledElement' => $vendorDir . '/oojs/oojs-ui/php/elements/TitledElement.php',
+ 'OOUI\\TitledElement' => $vendorDir . '/oojs/oojs-ui/php/mixins/TitledElement.php',
'OOUI\\Widget' => $vendorDir . '/oojs/oojs-ui/php/Widget.php',
'Psr\\Log\\AbstractLogger' => $vendorDir . '/psr/log/Psr/Log/AbstractLogger.php',
'Psr\\Log\\InvalidArgumentException' => $vendorDir . '/psr/log/Psr/Log/InvalidArgumentException.php',
'Psr\\Log\\LogLevel' => $vendorDir . '/psr/log/Psr/Log/LogLevel.php',
'Psr\\Log\\LoggerAwareInterface' => $vendorDir . '/psr/log/Psr/Log/LoggerAwareInterface.php',
- 'Psr\\Log\\LoggerAwareTrait' => $vendorDir . '/psr/log/Psr/Log/LoggerAwareTrait.php',
'Psr\\Log\\LoggerInterface' => $vendorDir . '/psr/log/Psr/Log/LoggerInterface.php',
- 'Psr\\Log\\LoggerTrait' => $vendorDir . '/psr/log/Psr/Log/LoggerTrait.php',
'Psr\\Log\\NullLogger' => $vendorDir . '/psr/log/Psr/Log/NullLogger.php',
+ 'Psr\\Log\\Test\\DummyTest' => $vendorDir . '/psr/log/Psr/Log/Test/LoggerInterfaceTest.php',
+ 'Psr\\Log\\Test\\LoggerInterfaceTest' => $vendorDir . '/psr/log/Psr/Log/Test/LoggerInterfaceTest.php',
+ 'SignatureInvalidException' => $vendorDir . '/firebase/php-jwt/Exceptions/SignatureInvalidException.php',
+ 'Symfony\\Component\\Process\\Exception\\ExceptionInterface' => $vendorDir . '/symfony/process/Exception/ExceptionInterface.php',
+ 'Symfony\\Component\\Process\\Exception\\InvalidArgumentException' => $vendorDir . '/symfony/process/Exception/InvalidArgumentException.php',
+ 'Symfony\\Component\\Process\\Exception\\LogicException' => $vendorDir . '/symfony/process/Exception/LogicException.php',
+ 'Symfony\\Component\\Process\\Exception\\ProcessFailedException' => $vendorDir . '/symfony/process/Exception/ProcessFailedException.php',
+ 'Symfony\\Component\\Process\\Exception\\ProcessTimedOutException' => $vendorDir . '/symfony/process/Exception/ProcessTimedOutException.php',
+ 'Symfony\\Component\\Process\\Exception\\RuntimeException' => $vendorDir . '/symfony/process/Exception/RuntimeException.php',
+ 'Symfony\\Component\\Process\\ExecutableFinder' => $vendorDir . '/symfony/process/ExecutableFinder.php',
+ 'Symfony\\Component\\Process\\PhpExecutableFinder' => $vendorDir . '/symfony/process/PhpExecutableFinder.php',
+ 'Symfony\\Component\\Process\\PhpProcess' => $vendorDir . '/symfony/process/PhpProcess.php',
+ 'Symfony\\Component\\Process\\Pipes\\AbstractPipes' => $vendorDir . '/symfony/process/Pipes/AbstractPipes.php',
+ 'Symfony\\Component\\Process\\Pipes\\PipesInterface' => $vendorDir . '/symfony/process/Pipes/PipesInterface.php',
+ 'Symfony\\Component\\Process\\Pipes\\UnixPipes' => $vendorDir . '/symfony/process/Pipes/UnixPipes.php',
+ 'Symfony\\Component\\Process\\Pipes\\WindowsPipes' => $vendorDir . '/symfony/process/Pipes/WindowsPipes.php',
+ 'Symfony\\Component\\Process\\Process' => $vendorDir . '/symfony/process/Process.php',
+ 'Symfony\\Component\\Process\\ProcessBuilder' => $vendorDir . '/symfony/process/ProcessBuilder.php',
+ 'Symfony\\Component\\Process\\ProcessUtils' => $vendorDir . '/symfony/process/ProcessUtils.php',
+ 'Symfony\\Component\\Process\\Tests\\AbstractProcessTest' => $vendorDir . '/symfony/process/Tests/AbstractProcessTest.php',
+ 'Symfony\\Component\\Process\\Tests\\ExecutableFinderTest' => $vendorDir . '/symfony/process/Tests/ExecutableFinderTest.php',
+ 'Symfony\\Component\\Process\\Tests\\NonStringifiable' => $vendorDir . '/symfony/process/Tests/AbstractProcessTest.php',
+ 'Symfony\\Component\\Process\\Tests\\PhpExecutableFinderTest' => $vendorDir . '/symfony/process/Tests/PhpExecutableFinderTest.php',
+ 'Symfony\\Component\\Process\\Tests\\PhpProcessTest' => $vendorDir . '/symfony/process/Tests/PhpProcessTest.php',
+ 'Symfony\\Component\\Process\\Tests\\ProcessBuilderTest' => $vendorDir . '/symfony/process/Tests/ProcessBuilderTest.php',
+ 'Symfony\\Component\\Process\\Tests\\ProcessFailedExceptionTest' => $vendorDir . '/symfony/process/Tests/ProcessFailedExceptionTest.php',
+ 'Symfony\\Component\\Process\\Tests\\ProcessInSigchildEnvironment' => $vendorDir . '/symfony/process/Tests/ProcessInSigchildEnvironment.php',
+ 'Symfony\\Component\\Process\\Tests\\ProcessUtilsTest' => $vendorDir . '/symfony/process/Tests/ProcessUtilsTest.php',
+ 'Symfony\\Component\\Process\\Tests\\SigchildDisabledProcessTest' => $vendorDir . '/symfony/process/Tests/SigchildDisabledProcessTest.php',
+ 'Symfony\\Component\\Process\\Tests\\SigchildEnabledProcessTest' => $vendorDir . '/symfony/process/Tests/SigchildEnabledProcessTest.php',
+ 'Symfony\\Component\\Process\\Tests\\SimpleProcessTest' => $vendorDir . '/symfony/process/Tests/SimpleProcessTest.php',
+ 'Symfony\\Component\\Process\\Tests\\Stringifiable' => $vendorDir . '/symfony/process/Tests/AbstractProcessTest.php',
'UtfNormal\\Constants' => $vendorDir . '/wikimedia/utfnormal/src/Constants.php',
'UtfNormal\\Utils' => $vendorDir . '/wikimedia/utfnormal/src/Util.php',
'UtfNormal\\Validator' => $vendorDir . '/wikimedia/utfnormal/src/Validator.php',
+ 'Wikimedia\\Assert\\Assert' => $vendorDir . '/wikimedia/assert/src/Assert.php',
+ 'Wikimedia\\Assert\\AssertionException' => $vendorDir . '/wikimedia/assert/src/AssertionException.php',
+ 'Wikimedia\\Assert\\InvariantException' => $vendorDir . '/wikimedia/assert/src/InvariantException.php',
+ 'Wikimedia\\Assert\\ParameterAssertionException' => $vendorDir . '/wikimedia/assert/src/ParameterAssertionException.php',
+ 'Wikimedia\\Assert\\ParameterElementTypeException' => $vendorDir . '/wikimedia/assert/src/ParameterElementTypeException.php',
+ 'Wikimedia\\Assert\\ParameterTypeException' => $vendorDir . '/wikimedia/assert/src/ParameterTypeException.php',
+ 'Wikimedia\\Assert\\PostconditionException' => $vendorDir . '/wikimedia/assert/src/PostconditionException.php',
+ 'Wikimedia\\Assert\\PreconditionException' => $vendorDir . '/wikimedia/assert/src/PreconditionException.php',
+ 'Wikimedia\\Assert\\Test\\AssertTest' => $vendorDir . '/wikimedia/assert/tests/phpunit/AssertTest.php',
+ 'Wikimedia\\Composer\\Logger' => $vendorDir . '/wikimedia/composer-merge-plugin/src/Logger.php',
'Wikimedia\\Composer\\MergePlugin' => $vendorDir . '/wikimedia/composer-merge-plugin/src/MergePlugin.php',
- 'lessc' => $vendorDir . '/leafo/lessphp/lessc.inc.php',
- 'lessc_formatter_classic' => $vendorDir . '/leafo/lessphp/lessc.inc.php',
- 'lessc_formatter_compressed' => $vendorDir . '/leafo/lessphp/lessc.inc.php',
- 'lessc_formatter_lessjs' => $vendorDir . '/leafo/lessphp/lessc.inc.php',
- 'lessc_parser' => $vendorDir . '/leafo/lessphp/lessc.inc.php',
+ 'Wikimedia\\Composer\\Merge\\ExtraPackage' => $vendorDir . '/wikimedia/composer-merge-plugin/src/Merge/ExtraPackage.php',
+ 'Wikimedia\\Composer\\Merge\\MissingFileException' => $vendorDir . '/wikimedia/composer-merge-plugin/src/Merge/MissingFileException.php',
+ 'Wikimedia\\Composer\\Merge\\PluginState' => $vendorDir . '/wikimedia/composer-merge-plugin/src/Merge/PluginState.php',
+ 'Wikimedia\\Composer\\Merge\\StabilityFlags' => $vendorDir . '/wikimedia/composer-merge-plugin/src/Merge/StabilityFlags.php',
+ 'WrappedString\\WrappedString' => $vendorDir . '/wikimedia/wrappedstring/src/WrappedString.php',
+ 'lessc' => $vendorDir . '/oyejorge/less.php/lessc.inc.php',
);
diff --git a/vendor/composer/autoload_files.php b/vendor/composer/autoload_files.php
new file mode 100644
index 00000000..fba07a7c
--- /dev/null
+++ b/vendor/composer/autoload_files.php
@@ -0,0 +1,10 @@
+<?php
+
+// autoload_files.php @generated by Composer
+
+$vendorDir = dirname(dirname(__FILE__));
+$baseDir = $vendorDir;
+
+return array(
+ $vendorDir . '/mediawiki/at-ease/src/Functions.php',
+);
diff --git a/vendor/composer/autoload_namespaces.php b/vendor/composer/autoload_namespaces.php
index a0f180fa..653e51b2 100644
--- a/vendor/composer/autoload_namespaces.php
+++ b/vendor/composer/autoload_namespaces.php
@@ -3,11 +3,12 @@
// autoload_namespaces.php @generated by Composer
$vendorDir = dirname(dirname(__FILE__));
-$baseDir = dirname($vendorDir);
+$baseDir = $vendorDir;
return array(
'Psr\\Log\\' => array($vendorDir . '/psr/log'),
'Liuggio' => array($vendorDir . '/liuggio/statsd-php-client/src'),
- 'ComposerHookHandler' => array($baseDir . '/includes/composer'),
- '' => array($vendorDir . '/cssjanus/cssjanus/src'),
+ 'Less' => array($vendorDir . '/oyejorge/less.php/lib'),
+ 'Kafka\\' => array($vendorDir . '/nmred/kafka-php/src'),
+ '' => array($vendorDir . '/cssjanus/cssjanus/src', $vendorDir . '/kzykhys/pygments/src'),
);
diff --git a/vendor/composer/autoload_psr4.php b/vendor/composer/autoload_psr4.php
index 74a09133..9bba7ec0 100644
--- a/vendor/composer/autoload_psr4.php
+++ b/vendor/composer/autoload_psr4.php
@@ -3,8 +3,15 @@
// autoload_psr4.php @generated by Composer
$vendorDir = dirname(dirname(__FILE__));
-$baseDir = dirname($vendorDir);
+$baseDir = $vendorDir;
return array(
+ 'WrappedString\\' => array($vendorDir . '/wikimedia/wrappedstring/src'),
'Wikimedia\\Composer\\' => array($vendorDir . '/wikimedia/composer-merge-plugin/src'),
+ 'Wikimedia\\Assert\\Test\\' => array($vendorDir . '/wikimedia/assert/tests/phpunit'),
+ 'Wikimedia\\Assert\\' => array($vendorDir . '/wikimedia/assert/src'),
+ 'Symfony\\Component\\Process\\' => array($vendorDir . '/symfony/process'),
+ 'Monolog\\' => array($vendorDir . '/monolog/monolog/src/Monolog'),
+ 'Elastica\\' => array($vendorDir . '/ruflin/elastica/lib/Elastica'),
+ 'Composer\\Semver\\' => array($vendorDir . '/composer/semver/src'),
);
diff --git a/vendor/composer/autoload_real.php b/vendor/composer/autoload_real.php
index 0c5b84c2..c98cf206 100644
--- a/vendor/composer/autoload_real.php
+++ b/vendor/composer/autoload_real.php
@@ -2,7 +2,7 @@
// autoload_real.php @generated by Composer
-class ComposerAutoloaderInite2ef576e4023c6f0949f5e8e1cdf8649
+class ComposerAutoloaderInit_mediawiki_vendor
{
private static $loader;
@@ -19,9 +19,9 @@ class ComposerAutoloaderInite2ef576e4023c6f0949f5e8e1cdf8649
return self::$loader;
}
- spl_autoload_register(array('ComposerAutoloaderInite2ef576e4023c6f0949f5e8e1cdf8649', 'loadClassLoader'), true, false);
+ spl_autoload_register(array('ComposerAutoloaderInit_mediawiki_vendor', 'loadClassLoader'), true, false);
self::$loader = $loader = new \Composer\Autoload\ClassLoader();
- spl_autoload_unregister(array('ComposerAutoloaderInite2ef576e4023c6f0949f5e8e1cdf8649', 'loadClassLoader'));
+ spl_autoload_unregister(array('ComposerAutoloaderInit_mediawiki_vendor', 'loadClassLoader'));
$map = require __DIR__ . '/autoload_namespaces.php';
foreach ($map as $namespace => $path) {
@@ -38,13 +38,19 @@ class ComposerAutoloaderInite2ef576e4023c6f0949f5e8e1cdf8649
$loader->addClassMap($classMap);
}
+ $loader->setClassMapAuthoritative(true);
$loader->register(false);
+ $includeFiles = require __DIR__ . '/autoload_files.php';
+ foreach ($includeFiles as $file) {
+ composerRequire_mediawiki_vendor($file);
+ }
+
return $loader;
}
}
-function composerRequiree2ef576e4023c6f0949f5e8e1cdf8649($file)
+function composerRequire_mediawiki_vendor($file)
{
require $file;
}
diff --git a/vendor/composer/installed.json b/vendor/composer/installed.json
index e882cda4..62c92430 100644
--- a/vendor/composer/installed.json
+++ b/vendor/composer/installed.json
@@ -1,46 +1,43 @@
[
{
- "name": "wikimedia/composer-merge-plugin",
- "version": "v1.0.0",
+ "name": "psr/log",
+ "version": "1.0.0",
"version_normalized": "1.0.0.0",
"source": {
"type": "git",
- "url": "https://github.com/wikimedia/composer-merge-plugin.git",
- "reference": "ed426b785f9f786b33be4fd78584e43f4e962356"
+ "url": "https://github.com/php-fig/log.git",
+ "reference": "fe0936ee26643249e916849d48e3a51d5f5e278b"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/wikimedia/composer-merge-plugin/zipball/ed426b785f9f786b33be4fd78584e43f4e962356",
- "reference": "ed426b785f9f786b33be4fd78584e43f4e962356",
+ "url": "https://api.github.com/repos/php-fig/log/zipball/fe0936ee26643249e916849d48e3a51d5f5e278b",
+ "reference": "fe0936ee26643249e916849d48e3a51d5f5e278b",
"shasum": ""
},
- "require": {
- "composer-plugin-api": "1.0.0",
- "php": ">=5.3.2"
- },
- "require-dev": {
- "composer/composer": "1.0.*@dev",
- "jakub-onderka/php-parallel-lint": "~0.8",
- "phpspec/prophecy-phpunit": "~1.0",
- "phpunit/phpunit": "~4.0",
- "squizlabs/php_codesniffer": "~2.1.0"
- },
- "time": "2015-02-21 00:57:13",
- "type": "composer-plugin",
- "extra": {
- "class": "Wikimedia\\Composer\\MergePlugin"
- },
+ "time": "2012-12-21 11:40:51",
+ "type": "library",
"installation-source": "dist",
"autoload": {
- "psr-4": {
- "Wikimedia\\Composer\\": "src/"
+ "psr-0": {
+ "Psr\\Log\\": ""
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
- "description": "Composer plugin to merge multiple composer.json files"
+ "authors": [
+ {
+ "name": "PHP-FIG",
+ "homepage": "http://www.php-fig.org/"
+ }
+ ],
+ "description": "Common interface for logging libraries",
+ "keywords": [
+ "log",
+ "psr",
+ "psr-3"
+ ]
},
{
"name": "cssjanus/cssjanus",
@@ -80,65 +77,229 @@
"description": "Convert CSS stylesheets between left-to-right and right-to-left."
},
{
- "name": "leafo/lessphp",
- "version": "v0.5.0",
- "version_normalized": "0.5.0.0",
+ "name": "wikimedia/assert",
+ "version": "v0.2.2",
+ "version_normalized": "0.2.2.0",
"source": {
"type": "git",
- "url": "https://github.com/leafo/lessphp.git",
- "reference": "0f5a7f5545d2bcf4e9fad9a228c8ad89cc9aa283"
+ "url": "https://github.com/wmde/Assert.git",
+ "reference": "2da55927525975f8d52825fc3ee02e5e36f5036c"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/leafo/lessphp/zipball/0f5a7f5545d2bcf4e9fad9a228c8ad89cc9aa283",
- "reference": "0f5a7f5545d2bcf4e9fad9a228c8ad89cc9aa283",
+ "url": "https://api.github.com/repos/wmde/Assert/zipball/2da55927525975f8d52825fc3ee02e5e36f5036c",
+ "reference": "2da55927525975f8d52825fc3ee02e5e36f5036c",
"shasum": ""
},
- "time": "2014-11-24 18:39:20",
+ "require-dev": {
+ "phpunit/phpunit": "3.7.*"
+ },
+ "time": "2015-04-29 17:23:50",
"type": "library",
- "extra": {
- "branch-alias": {
- "dev-master": "0.4.x-dev"
+ "installation-source": "dist",
+ "autoload": {
+ "psr-4": {
+ "Wikimedia\\Assert\\": "src/",
+ "Wikimedia\\Assert\\Test\\": "tests/phpunit/"
}
},
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Daniel Kinzler"
+ }
+ ],
+ "description": "Provides runtime assertions",
+ "homepage": "https://github.com/wmde/Assert",
+ "keywords": [
+ "assert",
+ "assertions",
+ "php",
+ "postcondition",
+ "precondition",
+ "qa"
+ ]
+ },
+ {
+ "name": "zordius/lightncandy",
+ "version": "v0.21",
+ "version_normalized": "0.21.0.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/zordius/lightncandy.git",
+ "reference": "015fed62d0ae6fe7601d3910b8e4b6a6964f86a0"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/zordius/lightncandy/zipball/015fed62d0ae6fe7601d3910b8e4b6a6964f86a0",
+ "reference": "015fed62d0ae6fe7601d3910b8e4b6a6964f86a0",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.3.0"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "4.0.17"
+ },
+ "time": "2015-05-08 01:56:46",
+ "type": "library",
"installation-source": "dist",
"autoload": {
"classmap": [
- "lessc.inc.php"
+ "src/lightncandy.php"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
- "MIT",
- "GPL-3.0"
+ "MIT"
],
"authors": [
{
- "name": "Leaf Corcoran",
- "email": "leafot@gmail.com",
- "homepage": "http://leafo.net"
+ "name": "Zordius Chen",
+ "email": "zordius@yahoo-inc.com"
}
],
- "description": "lessphp is a compiler for LESS written in PHP.",
- "homepage": "http://leafo.net/lessphp/"
+ "description": "An extremely fast PHP implementation of handlebars ( http://handlebarsjs.com/ ) and mustache ( http://mustache.github.io/ ).",
+ "homepage": "https://github.com/zordius/lightncandy",
+ "keywords": [
+ "handlebars",
+ "logicless",
+ "mustache",
+ "php",
+ "template"
+ ]
+ },
+ {
+ "name": "kzykhys/pygments",
+ "version": "v1.0.0",
+ "version_normalized": "1.0.0.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/kzykhys/Pygments.php.git",
+ "reference": "7bde970d3c378d075ef0e005bb93a91055e17994"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/kzykhys/Pygments.php/zipball/7bde970d3c378d075ef0e005bb93a91055e17994",
+ "reference": "7bde970d3c378d075ef0e005bb93a91055e17994",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.3.2",
+ "symfony/process": ">=2.3"
+ },
+ "require-dev": {
+ "symfony/finder": ">=2.3"
+ },
+ "time": "2013-12-18 15:22:37",
+ "type": "library",
+ "installation-source": "dist",
+ "autoload": {
+ "psr-0": {
+ "": "src"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "description": "A Thin Wrapper for the Python Pygments"
+ },
+ {
+ "name": "monolog/monolog",
+ "version": "1.14.0",
+ "version_normalized": "1.14.0.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/Seldaek/monolog.git",
+ "reference": "b287fbbe1ca27847064beff2bad7fb6920bf08cc"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/Seldaek/monolog/zipball/b287fbbe1ca27847064beff2bad7fb6920bf08cc",
+ "reference": "b287fbbe1ca27847064beff2bad7fb6920bf08cc",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.3.0",
+ "psr/log": "~1.0"
+ },
+ "provide": {
+ "psr/log-implementation": "1.0.0"
+ },
+ "require-dev": {
+ "aws/aws-sdk-php": "^2.4.9",
+ "doctrine/couchdb": "~1.0@dev",
+ "graylog2/gelf-php": "~1.0",
+ "php-console/php-console": "^3.1.3",
+ "phpunit/phpunit": "~4.5",
+ "phpunit/phpunit-mock-objects": "2.3.0",
+ "raven/raven": "~0.8",
+ "ruflin/elastica": ">=0.90 <3.0",
+ "swiftmailer/swiftmailer": "~5.3",
+ "videlalvaro/php-amqplib": "~2.4"
+ },
+ "suggest": {
+ "aws/aws-sdk-php": "Allow sending log messages to AWS services like DynamoDB",
+ "doctrine/couchdb": "Allow sending log messages to a CouchDB server",
+ "ext-amqp": "Allow sending log messages to an AMQP server (1.0+ required)",
+ "ext-mongo": "Allow sending log messages to a MongoDB server",
+ "graylog2/gelf-php": "Allow sending log messages to a GrayLog2 server",
+ "php-console/php-console": "Allow sending log messages to Google Chrome",
+ "raven/raven": "Allow sending log messages to a Sentry server",
+ "rollbar/rollbar": "Allow sending log messages to Rollbar",
+ "ruflin/elastica": "Allow sending log messages to an Elastic Search server",
+ "videlalvaro/php-amqplib": "Allow sending log messages to an AMQP server using php-amqplib"
+ },
+ "time": "2015-06-19 13:29:54",
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "1.14.x-dev"
+ }
+ },
+ "installation-source": "dist",
+ "autoload": {
+ "psr-4": {
+ "Monolog\\": "src/Monolog"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Jordi Boggiano",
+ "email": "j.boggiano@seld.be",
+ "homepage": "http://seld.be"
+ }
+ ],
+ "description": "Sends your logs to files, sockets, inboxes, databases and various web services",
+ "homepage": "http://github.com/Seldaek/monolog",
+ "keywords": [
+ "log",
+ "logging",
+ "psr-3"
+ ]
},
{
"name": "liuggio/statsd-php-client",
- "version": "v1.0.12",
- "version_normalized": "1.0.12.0",
+ "version": "v1.0.16",
+ "version_normalized": "1.0.16.0",
"source": {
"type": "git",
"url": "https://github.com/liuggio/statsd-php-client.git",
- "reference": "a8c9ccd2a3af6cc49c7fc4f5f689d7b148ab19d7"
+ "reference": "a84fbef1a7afbfafd0ca4f1ebae4935bd1a7d920"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/liuggio/statsd-php-client/zipball/a8c9ccd2a3af6cc49c7fc4f5f689d7b148ab19d7",
- "reference": "a8c9ccd2a3af6cc49c7fc4f5f689d7b148ab19d7",
+ "url": "https://api.github.com/repos/liuggio/statsd-php-client/zipball/a84fbef1a7afbfafd0ca4f1ebae4935bd1a7d920",
+ "reference": "a84fbef1a7afbfafd0ca4f1ebae4935bd1a7d920",
"shasum": ""
},
"require": {
- "php": ">=5.2"
+ "php": ">=5.3.2"
},
"require-dev": {
"monolog/monolog": ">=1.2.0"
@@ -146,7 +307,7 @@
"suggest": {
"monolog/monolog": "Monolog, in order to do generate statistic from log >=1.2.0)"
},
- "time": "2014-09-17 21:37:49",
+ "time": "2015-04-27 08:12:26",
"type": "library",
"installation-source": "dist",
"autoload": {
@@ -174,64 +335,89 @@
]
},
{
- "name": "oojs/oojs-ui",
- "version": "v0.11.3",
- "version_normalized": "0.11.3.0",
+ "name": "wikimedia/wrappedstring",
+ "version": "v2.0.0",
+ "version_normalized": "2.0.0.0",
"source": {
"type": "git",
- "url": "https://github.com/wikimedia/oojs-ui.git",
- "reference": "a03de5681e28e4fad1e27f8cccab32a2c5b484e5"
+ "url": "https://github.com/wikimedia/WrappedString.git",
+ "reference": "1b27e0ea23bd915644dade17c3fe1e45fdbadf11"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/wikimedia/oojs-ui/zipball/a03de5681e28e4fad1e27f8cccab32a2c5b484e5",
- "reference": "a03de5681e28e4fad1e27f8cccab32a2c5b484e5",
+ "url": "https://api.github.com/repos/wikimedia/WrappedString/zipball/1b27e0ea23bd915644dade17c3fe1e45fdbadf11",
+ "reference": "1b27e0ea23bd915644dade17c3fe1e45fdbadf11",
"shasum": ""
},
"require": {
"php": ">=5.3.3"
},
"require-dev": {
- "jakub-onderka/php-parallel-lint": "0.8.*",
- "mediawiki/mediawiki-codesniffer": "0.1.0",
- "squizlabs/php_codesniffer": "2.1.*"
+ "jakub-onderka/php-parallel-lint": "^0.9.0.0",
+ "mediawiki/mediawiki-codesniffer": "^0.3.0.0",
+ "phpunit/phpunit": "^4.7.7.0"
},
- "time": "2015-05-12 11:58:55",
+ "time": "2015-07-31 00:06:22",
"type": "library",
"installation-source": "dist",
"autoload": {
- "classmap": [
- "php/"
- ]
+ "psr-4": {
+ "WrappedString\\": "src/"
+ }
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
- "description": "Provides library of common widgets, layouts, and windows.",
- "homepage": "https://www.mediawiki.org/wiki/OOjs_UI"
+ "authors": [
+ {
+ "name": "Timo Tijhof",
+ "email": "krinklemail@gmail.com"
+ }
+ ],
+ "description": "Automatically compact sequentially-outputted strings that share a common prefix / suffix pair.",
+ "homepage": "https://www.mediawiki.org/wiki/WrappedString"
},
{
- "name": "psr/log",
- "version": "1.0.0",
- "version_normalized": "1.0.0.0",
+ "name": "ruflin/elastica",
+ "version": "2.2.0",
+ "version_normalized": "2.2.0.0",
"source": {
"type": "git",
- "url": "https://github.com/php-fig/log.git",
- "reference": "fe0936ee26643249e916849d48e3a51d5f5e278b"
+ "url": "https://github.com/ruflin/Elastica.git",
+ "reference": "eb3a787259a6c50f87bce507ff24b124d91c4fe7"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/php-fig/log/zipball/fe0936ee26643249e916849d48e3a51d5f5e278b",
- "reference": "fe0936ee26643249e916849d48e3a51d5f5e278b",
+ "url": "https://api.github.com/repos/ruflin/Elastica/zipball/eb3a787259a6c50f87bce507ff24b124d91c4fe7",
+ "reference": "eb3a787259a6c50f87bce507ff24b124d91c4fe7",
"shasum": ""
},
- "time": "2012-12-21 11:40:51",
+ "require": {
+ "php": ">=5.3.3",
+ "psr/log": "~1.0"
+ },
+ "require-dev": {
+ "guzzlehttp/guzzle": "5.3.*",
+ "munkie/elasticsearch-thrift-php": "1.4.*"
+ },
+ "suggest": {
+ "egeloen/http-adapter": "Allow using httpadapter transport",
+ "guzzlehttp/guzzle": "Allow using guzzle 5.3.x as the http transport (Requires php 5.4)",
+ "monolog/monolog": "Logging request",
+ "munkie/elasticsearch-thrift-php": "Allow using thrift transport"
+ },
+ "time": "2015-07-08 05:57:43",
"type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "2.0.x-dev"
+ }
+ },
"installation-source": "dist",
"autoload": {
- "psr-0": {
- "Psr\\Log\\": ""
+ "psr-4": {
+ "Elastica\\": "lib/Elastica/"
}
},
"notification-url": "https://packagist.org/downloads/",
@@ -240,39 +426,138 @@
],
"authors": [
{
- "name": "PHP-FIG",
- "homepage": "http://www.php-fig.org/"
+ "name": "Nicolas Ruflin",
+ "homepage": "http://ruflin.com/"
}
],
- "description": "Common interface for logging libraries",
+ "description": "Elasticsearch Client",
+ "homepage": "http://elastica.io/",
"keywords": [
- "log",
- "psr",
- "psr-3"
+ "client",
+ "search"
]
},
{
- "name": "wikimedia/cdb",
+ "name": "symfony/process",
+ "version": "v2.7.3",
+ "version_normalized": "2.7.3.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/Process.git",
+ "reference": "48aeb0e48600321c272955132d7606ab0a49adb3"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/Process/zipball/48aeb0e48600321c272955132d7606ab0a49adb3",
+ "reference": "48aeb0e48600321c272955132d7606ab0a49adb3",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.3.9"
+ },
+ "require-dev": {
+ "symfony/phpunit-bridge": "~2.7"
+ },
+ "time": "2015-07-01 11:25:50",
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "2.7-dev"
+ }
+ },
+ "installation-source": "dist",
+ "autoload": {
+ "psr-4": {
+ "Symfony\\Component\\Process\\": ""
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Fabien Potencier",
+ "email": "fabien@symfony.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ }
+ ],
+ "description": "Symfony Process Component",
+ "homepage": "https://symfony.com"
+ },
+ {
+ "name": "firebase/php-jwt",
+ "version": "v2.1.0",
+ "version_normalized": "2.1.0.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/firebase/php-jwt.git",
+ "reference": "fb219727e199dd80a72d5274ebb5c8b24d58dd9b"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/firebase/php-jwt/zipball/fb219727e199dd80a72d5274ebb5c8b24d58dd9b",
+ "reference": "fb219727e199dd80a72d5274ebb5c8b24d58dd9b",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.2.0"
+ },
+ "time": "2015-05-20 19:16:04",
+ "type": "library",
+ "installation-source": "dist",
+ "autoload": {
+ "classmap": [
+ "Authentication/",
+ "Exceptions/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Neuman Vong",
+ "email": "neuman+pear@twilio.com",
+ "role": "Developer"
+ },
+ {
+ "name": "Anant Narayanan",
+ "email": "anant@php.net",
+ "role": "Developer"
+ }
+ ],
+ "description": "A simple library to encode and decode JSON Web Tokens (JWT) in PHP. Should conform to the current spec.",
+ "homepage": "https://github.com/firebase/php-jwt"
+ },
+ {
+ "name": "wikimedia/ip-set",
"version": "1.0.1",
"version_normalized": "1.0.1.0",
"source": {
"type": "git",
- "url": "https://github.com/wikimedia/cdb.git",
- "reference": "3b7d5366c88eccf2517ebac57c59eb557c82f46c"
+ "url": "https://github.com/wikimedia/IPSet.git",
+ "reference": "3c2dd6706546fe616e6ceba02044e64dce4fc9be"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/wikimedia/cdb/zipball/3b7d5366c88eccf2517ebac57c59eb557c82f46c",
- "reference": "3b7d5366c88eccf2517ebac57c59eb557c82f46c",
+ "url": "https://api.github.com/repos/wikimedia/IPSet/zipball/3c2dd6706546fe616e6ceba02044e64dce4fc9be",
+ "reference": "3c2dd6706546fe616e6ceba02044e64dce4fc9be",
"shasum": ""
},
"require": {
- "php": ">=5.3.2"
+ "php": ">=5.3.3"
},
"require-dev": {
- "phpunit/phpunit": "*"
+ "jakub-onderka/php-parallel-lint": "0.9",
+ "mediawiki/mediawiki-codesniffer": "0.3.0",
+ "phpunit/phpunit": "4.6.*"
},
- "time": "2014-12-08 19:26:44",
+ "time": "2015-06-29 20:21:27",
"type": "library",
"installation-source": "dist",
"autoload": {
@@ -282,34 +567,30 @@
},
"notification-url": "https://packagist.org/downloads/",
"license": [
- "GPL-2.0"
+ "GPL-2.0+"
],
"authors": [
{
- "name": "Tim Starling",
- "email": "tstarling@wikimedia.org"
- },
- {
- "name": "Chad Horohoe",
- "email": "chad@wikimedia.org"
+ "name": "Brandon Black",
+ "email": "blblack@gmail.com"
}
],
- "description": "Constant Database (CDB) wrapper library for PHP. Provides pure-PHP fallback when dba_* functions are absent.",
- "homepage": "https://www.mediawiki.org/wiki/CDB"
+ "description": "Efficiently match IP addresses against a set of CIDR specifications.",
+ "homepage": "https://github.com/wikimedia/IPSet"
},
{
"name": "wikimedia/utfnormal",
- "version": "v1.0.2",
- "version_normalized": "1.0.2.0",
+ "version": "v1.0.3",
+ "version_normalized": "1.0.3.0",
"source": {
"type": "git",
"url": "https://github.com/wikimedia/utfnormal.git",
- "reference": "bb892a53a76116ad0982445a849043687cb6e778"
+ "reference": "bcb81d1d87bae400af45cc419a850dcf9883775b"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/wikimedia/utfnormal/zipball/bb892a53a76116ad0982445a849043687cb6e778",
- "reference": "bb892a53a76116ad0982445a849043687cb6e778",
+ "url": "https://api.github.com/repos/wikimedia/utfnormal/zipball/bcb81d1d87bae400af45cc419a850dcf9883775b",
+ "reference": "bcb81d1d87bae400af45cc419a850dcf9883775b",
"shasum": ""
},
"require": {
@@ -319,10 +600,10 @@
"ext-mbstring": "*",
"jakub-onderka/php-parallel-lint": "0.8.*",
"mediawiki/mediawiki-codesniffer": "0.1.0",
- "phpunit/phpunit": "4.4.*",
- "squizlabs/php_codesniffer": "2.1.*"
+ "phpunit/phpunit": "4.6.*",
+ "squizlabs/php_codesniffer": "2.2.*"
},
- "time": "2015-03-12 01:54:47",
+ "time": "2015-08-29 14:13:27",
"type": "library",
"installation-source": "dist",
"autoload": {
@@ -340,55 +621,467 @@
"email": "bvibber@wikimedia.org"
}
],
+ "description": "Contains Unicode normalization routines, including both pure PHP implementations and automatic use of the 'intl' PHP extension when present",
"homepage": "https://www.mediawiki.org/wiki/utfnormal"
},
{
- "name": "zordius/lightncandy",
- "version": "v0.18",
- "version_normalized": "0.18.0.0",
+ "name": "wikimedia/cdb",
+ "version": "1.3.0",
+ "version_normalized": "1.3.0.0",
"source": {
"type": "git",
- "url": "https://github.com/zordius/lightncandy.git",
- "reference": "24be6909c37391f4648ce1fdf19036b11bd56d05"
+ "url": "https://github.com/wikimedia/cdb.git",
+ "reference": "68f8fd495ca94ca0e965dd511e234893c515bb95"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/zordius/lightncandy/zipball/24be6909c37391f4648ce1fdf19036b11bd56d05",
- "reference": "24be6909c37391f4648ce1fdf19036b11bd56d05",
+ "url": "https://api.github.com/repos/wikimedia/cdb/zipball/68f8fd495ca94ca0e965dd511e234893c515bb95",
+ "reference": "68f8fd495ca94ca0e965dd511e234893c515bb95",
"shasum": ""
},
"require": {
- "php": ">=5.3.0"
+ "php": ">=5.3.2"
},
"require-dev": {
- "phpunit/phpunit": "4.0.17"
+ "jakub-onderka/php-parallel-lint": "0.9",
+ "mediawiki/mediawiki-codesniffer": "0.3.0",
+ "phpunit/phpunit": "4.6.*"
},
- "time": "2015-01-01 04:37:19",
+ "time": "2015-09-08 19:53:04",
"type": "library",
"installation-source": "dist",
"autoload": {
"classmap": [
- "src/lightncandy.php"
+ "src/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
- "MIT"
+ "GPL-2.0+"
],
"authors": [
{
- "name": "Zordius Chen",
- "email": "zordius@yahoo-inc.com"
+ "name": "Tim Starling",
+ "email": "tstarling@wikimedia.org"
+ },
+ {
+ "name": "Chad Horohoe",
+ "email": "chad@wikimedia.org"
+ },
+ {
+ "name": "Ori Livneh",
+ "email": "ori@wikimedia.org"
}
],
- "description": "An extremely fast PHP implementation of handlebars ( http://handlebarsjs.com/ ) and mustache ( http://mustache.github.io/ ).",
- "homepage": "https://github.com/zordius/lightncandy",
+ "description": "Constant Database (CDB) wrapper library for PHP. Provides pure-PHP fallback when dba_* functions are absent.",
+ "homepage": "https://www.mediawiki.org/wiki/CDB"
+ },
+ {
+ "name": "nmred/kafka-php",
+ "version": "v0.1.4",
+ "version_normalized": "0.1.4.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/nmred/kafka-php.git",
+ "reference": "06817c95e40b23918c3a420960ee9526e499275d"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/nmred/kafka-php/zipball/06817c95e40b23918c3a420960ee9526e499275d",
+ "reference": "06817c95e40b23918c3a420960ee9526e499275d",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.3.3"
+ },
+ "require-dev": {
+ "phpunit/phpcov": "*",
+ "phpunit/phpunit": "~4.0",
+ "satooshi/php-coveralls": "dev-master"
+ },
+ "time": "2015-09-06 01:39:05",
+ "type": "library",
+ "installation-source": "dist",
+ "autoload": {
+ "psr-0": {
+ "Kafka\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "description": "Kafka client for php",
+ "homepage": "http://www.swanlinux.net",
"keywords": [
- "handlebars",
- "logicless",
- "mustache",
+ "client",
+ "kafka"
+ ]
+ },
+ {
+ "name": "wikimedia/avro",
+ "version": "v1.7.7",
+ "version_normalized": "1.7.7.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/wikimedia/avro-php.git",
+ "reference": "b642da9fd895aab7cb3261a22624228115471f47"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/wikimedia/avro-php/zipball/b642da9fd895aab7cb3261a22624228115471f47",
+ "reference": "b642da9fd895aab7cb3261a22624228115471f47",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.3.3"
+ },
+ "require-dev": {
+ "jakub-onderka/php-parallel-lint": "^0.9",
+ "phpunit/phpunit": "^4.0.0"
+ },
+ "suggest": {
+ "ext-gmp": "Large integer support for 32-bit platforms."
+ },
+ "time": "2015-09-05 18:49:27",
+ "type": "library",
+ "installation-source": "dist",
+ "autoload": {
+ "classmap": [
+ "lib/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "Apache-2.0"
+ ],
+ "authors": [
+ {
+ "name": "Michael Glaesemann",
+ "email": "grzm@seespotcode.net"
+ },
+ {
+ "name": "Andy Wick",
+ "email": "awick@purple.org"
+ },
+ {
+ "name": "Saleem Shafi",
+ "email": "saleemshafi@gmail.com"
+ },
+ {
+ "name": "A B",
+ "email": "abawany@x.com"
+ },
+ {
+ "name": "Doug Cutting",
+ "email": "cutting@apache.org"
+ },
+ {
+ "name": "Tom White",
+ "email": "tom@cloudera.com"
+ }
+ ],
+ "description": "A library for using Apache Avro with PHP.",
+ "homepage": "https://avro.apache.org/",
+ "keywords": [
+ "serialization"
+ ]
+ },
+ {
+ "name": "mediawiki/at-ease",
+ "version": "v1.1.0",
+ "version_normalized": "1.1.0.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/wikimedia/at-ease.git",
+ "reference": "94c0b84888841d160419f915c2745d9d08fbf0c3"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/wikimedia/at-ease/zipball/94c0b84888841d160419f915c2745d9d08fbf0c3",
+ "reference": "94c0b84888841d160419f915c2745d9d08fbf0c3",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.3.3"
+ },
+ "require-dev": {
+ "jakub-onderka/php-parallel-lint": "0.9",
+ "mediawiki/mediawiki-codesniffer": "0.3.0",
+ "phpunit/phpunit": "~4.5",
+ "squizlabs/php_codesniffer": "2.3.0"
+ },
+ "time": "2015-09-18 07:02:06",
+ "type": "library",
+ "installation-source": "dist",
+ "autoload": {
+ "files": [
+ "src/Functions.php"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "GPL-2.0+"
+ ],
+ "authors": [
+ {
+ "name": "Tim Starling",
+ "email": "tstarling@wikimedia.org"
+ },
+ {
+ "name": "MediaWiki developers",
+ "email": "wikitech-l@lists.wikimedia.org"
+ }
+ ],
+ "description": "Safe replacement to @ for suppressing warnings.",
+ "homepage": "https://www.mediawiki.org/wiki/at-ease"
+ },
+ {
+ "name": "oyejorge/less.php",
+ "version": "v1.7.0.9",
+ "version_normalized": "1.7.0.9",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/oyejorge/less.php.git",
+ "reference": "fb64e2f6ef647a229c50e9fa0f2076240a3484c6"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/oyejorge/less.php/zipball/fb64e2f6ef647a229c50e9fa0f2076240a3484c6",
+ "reference": "fb64e2f6ef647a229c50e9fa0f2076240a3484c6",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.3"
+ },
+ "time": "2015-09-28 01:11:47",
+ "bin": [
+ "bin/lessc"
+ ],
+ "type": "library",
+ "installation-source": "dist",
+ "autoload": {
+ "psr-0": {
+ "Less": "lib/"
+ },
+ "classmap": [
+ "lessc.inc.php"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "Apache-2.0"
+ ],
+ "authors": [
+ {
+ "name": "Matt Agar",
+ "homepage": "https://github.com/agar"
+ },
+ {
+ "name": "Martin Jantošovič",
+ "homepage": "https://github.com/Mordred"
+ },
+ {
+ "name": "Josh Schmidt",
+ "homepage": "https://github.com/oyejorge"
+ }
+ ],
+ "description": "PHP port of the Javascript version of LESS http://lesscss.org",
+ "homepage": "http://lessphp.gpeasy.com",
+ "keywords": [
+ "css",
+ "less",
+ "less.js",
+ "lesscss",
"php",
- "template"
+ "stylesheet"
]
+ },
+ {
+ "name": "composer/semver",
+ "version": "1.0.0",
+ "version_normalized": "1.0.0.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/composer/semver.git",
+ "reference": "d0e1ccc6d44ab318b758d709e19176037da6b1ba"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/composer/semver/zipball/d0e1ccc6d44ab318b758d709e19176037da6b1ba",
+ "reference": "d0e1ccc6d44ab318b758d709e19176037da6b1ba",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.3.2"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "~4.5",
+ "phpunit/phpunit-mock-objects": "~2.3"
+ },
+ "time": "2015-09-21 09:42:36",
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "0.1-dev"
+ }
+ },
+ "installation-source": "dist",
+ "autoload": {
+ "psr-4": {
+ "Composer\\Semver\\": "src"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Rob Bast",
+ "email": "rob.bast@gmail.com"
+ },
+ {
+ "name": "Nils Adermann",
+ "email": "naderman@naderman.de",
+ "homepage": "http://www.naderman.de"
+ },
+ {
+ "name": "Jordi Boggiano",
+ "email": "j.boggiano@seld.be",
+ "homepage": "http://seld.be"
+ }
+ ],
+ "description": "Semver library that offers utilities, version constraint parsing and validation.",
+ "keywords": [
+ "semantic",
+ "semver",
+ "validation",
+ "versioning"
+ ]
+ },
+ {
+ "name": "oojs/oojs-ui",
+ "version": "v0.12.12",
+ "version_normalized": "0.12.12.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/wikimedia/oojs-ui.git",
+ "reference": "221a66e8df215e767ff4b55b637138a73fcffdb2"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/wikimedia/oojs-ui/zipball/221a66e8df215e767ff4b55b637138a73fcffdb2",
+ "reference": "221a66e8df215e767ff4b55b637138a73fcffdb2",
+ "shasum": ""
+ },
+ "require": {
+ "mediawiki/at-ease": "1.1.0",
+ "php": ">=5.3.3"
+ },
+ "require-dev": {
+ "jakub-onderka/php-parallel-lint": "0.9",
+ "mediawiki/mediawiki-codesniffer": "0.4.0",
+ "phpunit/phpunit": "~4.5"
+ },
+ "time": "2015-10-13 20:29:29",
+ "type": "library",
+ "installation-source": "dist",
+ "autoload": {
+ "classmap": [
+ "php/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Bartosz Dziewoński",
+ "email": "matma.rex@gmail.com"
+ },
+ {
+ "name": "Ed Sanders",
+ "email": "esanders@wikimedia.org"
+ },
+ {
+ "name": "James D. Forrester",
+ "email": "jforrester@wikimedia.org"
+ },
+ {
+ "name": "Kirsten Menger-Anderson",
+ "email": "kmenger@wikimedia.org"
+ },
+ {
+ "name": "Rob Moen",
+ "email": "rmoen@wikimedia.org"
+ },
+ {
+ "name": "Roan Kattouw",
+ "email": "roan@wikimedia.org"
+ },
+ {
+ "name": "Timo Tijhof",
+ "email": "timo@wikimedia.org"
+ },
+ {
+ "name": "Trevor Parscal",
+ "email": "trevor@wikimedia.org"
+ }
+ ],
+ "description": "Provides library of common widgets, layouts, and windows.",
+ "homepage": "https://www.mediawiki.org/wiki/OOjs_UI"
+ },
+ {
+ "name": "wikimedia/composer-merge-plugin",
+ "version": "v1.3.0",
+ "version_normalized": "1.3.0.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/wikimedia/composer-merge-plugin.git",
+ "reference": "bfed1f8d4eb97e9ba80eee57ea46229d7e5364d9"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/wikimedia/composer-merge-plugin/zipball/bfed1f8d4eb97e9ba80eee57ea46229d7e5364d9",
+ "reference": "bfed1f8d4eb97e9ba80eee57ea46229d7e5364d9",
+ "shasum": ""
+ },
+ "require": {
+ "composer-plugin-api": "^1.0",
+ "php": ">=5.3.2"
+ },
+ "require-dev": {
+ "composer/composer": "1.0.*@dev",
+ "jakub-onderka/php-parallel-lint": "~0.8",
+ "phpunit/phpunit": "~4.8|~5.0",
+ "squizlabs/php_codesniffer": "~2.1.0"
+ },
+ "time": "2015-11-06 20:31:16",
+ "type": "composer-plugin",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "1.3.x-dev"
+ },
+ "class": "Wikimedia\\Composer\\MergePlugin"
+ },
+ "installation-source": "dist",
+ "autoload": {
+ "psr-4": {
+ "Wikimedia\\Composer\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Bryan Davis",
+ "email": "bd808@wikimedia.org"
+ }
+ ],
+ "description": "Composer plugin to merge multiple composer.json files"
}
]
diff --git a/vendor/composer/semver/CHANGELOG.md b/vendor/composer/semver/CHANGELOG.md
new file mode 100644
index 00000000..8352cb72
--- /dev/null
+++ b/vendor/composer/semver/CHANGELOG.md
@@ -0,0 +1,28 @@
+# Change Log
+
+All notable changes to this project will be documented in this file.
+This project adheres to [Semantic Versioning](http://semver.org/).
+
+### [1.0.0] 2015-09-21
+
+ * Break: `VersionConstraint` renamed to `Constraint`.
+ * Break: `SpecificConstraint` renamed to `AbstractConstraint`.
+ * Break: `LinkConstraintInterface` renamed to `ConstraintInterface`.
+ * Break: `VersionParser::parseNameVersionPairs` was removed.
+ * Changed: `VersionParser::parseConstraints` allows (but ignores) build metadata now.
+ * Changed: `VersionParser::parseConstraints` allows (but ignores) prefixing numeric versions with a 'v' now.
+ * Changed: Fixed namespace(s) of test files.
+ * Changed: `Comparator::compare` no longer throws `InvalidArgumentException`.
+ * Changed: `VersionConstraint` now throws `InvalidArgumentException`.
+
+### [0.1.0] 2015-07-23
+
+ * Added: `Composer\Semver\Comparator`, various methods to compare versions.
+ * Added: various documents such as README.md, LICENSE, etc.
+ * Added: configuration files for Git, Travis, php-cs-fixer, phpunit.
+ * Break: the following namespaces were renamed:
+ - Namespace: `Composer\Package\Version` -> `Composer\Semver`
+ - Namespace: `Composer\Package\LinkConstraint` -> `Composer\Semver\Constraint`
+ - Namespace: `Composer\Test\Package\Version` -> `Composer\Test\Semver`
+ - Namespace: `Composer\Test\Package\LinkConstraint` -> `Composer\Test\Semver\Constraint`
+ * Changed: code style using php-cs-fixer.
diff --git a/vendor/composer/semver/LICENSE b/vendor/composer/semver/LICENSE
new file mode 100644
index 00000000..46697586
--- /dev/null
+++ b/vendor/composer/semver/LICENSE
@@ -0,0 +1,19 @@
+Copyright (C) 2015 Composer
+
+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/semver/README.md b/vendor/composer/semver/README.md
new file mode 100644
index 00000000..c8b69798
--- /dev/null
+++ b/vendor/composer/semver/README.md
@@ -0,0 +1,70 @@
+composer/semver
+===============
+
+Semver library that offers utilities, version constraint parsing and validation.
+
+Originally written as part of [composer/composer](https://github.com/composer/composer),
+now extracted and made available as a stand-alone library.
+
+[![Build Status](https://travis-ci.org/composer/semver.svg?branch=master)](https://travis-ci.org/composer/semver)
+
+
+Installation
+------------
+
+Install the latest version with:
+
+```bash
+$ composer require composer/semver
+```
+
+
+Requirements
+------------
+
+* PHP 5.3.2 is required but using the latest version of PHP is highly recommended.
+
+
+Version Comparison
+------------------
+
+For details on how versions are compared, refer to the [Versions](https://getcomposer.org/doc/articles/versions.md)
+article in the documentation section of the [getcomposer.org](https://getcomposer.org) website.
+
+
+Basic usage
+-----------
+
+### Comparator
+
+The `Composer\Semver\Comparator` class provides the following methods for comparing versions:
+
+* greaterThan($v1, $v2)
+* greaterThanOrEqualTo($v1, $v2)
+* lessThan($v1, $v2)
+* lessThanOrEqualTo($v1, $v2)
+* equalTo($v1, $v2)
+* notEqualTo($v1, $v2)
+
+Each function takes two version strings as arguments. For example:
+
+```php
+use Composer\Semver\Comparator;
+
+Comparator::greaterThan('1.25.0', '1.24.0'); // 1.25.0 > 1.24.0
+```
+
+### Semver
+
+The `Composer\Semver\Semver` class providers the following methods:
+
+* satisfies($version, $constraints)
+* satisfiedBy($constraint, array $versions)
+* sort($versions)
+* rsort($versions)
+
+
+License
+-------
+
+composer/semver is licensed under the MIT License, see the LICENSE file for details.
diff --git a/vendor/composer/semver/composer.json b/vendor/composer/semver/composer.json
new file mode 100644
index 00000000..b996186f
--- /dev/null
+++ b/vendor/composer/semver/composer.json
@@ -0,0 +1,57 @@
+{
+ "name": "composer/semver",
+ "description": "Semver library that offers utilities, version constraint parsing and validation.",
+ "type": "library",
+ "license": "MIT",
+ "keywords": [
+ "semver",
+ "semantic",
+ "versioning",
+ "validation"
+ ],
+ "authors": [
+ {
+ "name": "Nils Adermann",
+ "email": "naderman@naderman.de",
+ "homepage": "http://www.naderman.de"
+ },
+ {
+ "name": "Jordi Boggiano",
+ "email": "j.boggiano@seld.be",
+ "homepage": "http://seld.be"
+ },
+ {
+ "name": "Rob Bast",
+ "email": "rob.bast@gmail.com"
+ }
+ ],
+ "support": {
+ "irc": "irc://irc.freenode.org/composer",
+ "issues": "https://github.com/composer/semver/issues"
+ },
+ "require": {
+ "php": ">=5.3.2"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "~4.5",
+ "phpunit/phpunit-mock-objects": "~2.3"
+ },
+ "autoload": {
+ "psr-4": {
+ "Composer\\Semver\\": "src"
+ }
+ },
+ "autoload-dev": {
+ "psr-4": {
+ "Composer\\Semver\\Test\\": "tests"
+ }
+ },
+ "extra": {
+ "branch-alias": {
+ "dev-master": "0.1-dev"
+ }
+ },
+ "scripts": {
+ "test": "phpunit"
+ }
+}
diff --git a/vendor/composer/semver/src/Comparator.php b/vendor/composer/semver/src/Comparator.php
new file mode 100644
index 00000000..a9d758f1
--- /dev/null
+++ b/vendor/composer/semver/src/Comparator.php
@@ -0,0 +1,111 @@
+<?php
+
+/*
+ * This file is part of composer/semver.
+ *
+ * (c) Composer <https://github.com/composer>
+ *
+ * For the full copyright and license information, please view
+ * the LICENSE file that was distributed with this source code.
+ */
+
+namespace Composer\Semver;
+
+use Composer\Semver\Constraint\Constraint;
+
+class Comparator
+{
+ /**
+ * Evaluates the expression: $version1 > $version2.
+ *
+ * @param string $version1
+ * @param string $version2
+ *
+ * @return bool
+ */
+ public static function greaterThan($version1, $version2)
+ {
+ return self::compare($version1, '>', $version2);
+ }
+
+ /**
+ * Evaluates the expression: $version1 >= $version2.
+ *
+ * @param string $version1
+ * @param string $version2
+ *
+ * @return bool
+ */
+ public static function greaterThanOrEqualTo($version1, $version2)
+ {
+ return self::compare($version1, '>=', $version2);
+ }
+
+ /**
+ * Evaluates the expression: $version1 < $version2.
+ *
+ * @param string $version1
+ * @param string $version2
+ *
+ * @return bool
+ */
+ public static function lessThan($version1, $version2)
+ {
+ return self::compare($version1, '<', $version2);
+ }
+
+ /**
+ * Evaluates the expression: $version1 <= $version2.
+ *
+ * @param string $version1
+ * @param string $version2
+ *
+ * @return bool
+ */
+ public static function lessThanOrEqualTo($version1, $version2)
+ {
+ return self::compare($version1, '<=', $version2);
+ }
+
+ /**
+ * Evaluates the expression: $version1 == $version2.
+ *
+ * @param string $version1
+ * @param string $version2
+ *
+ * @return bool
+ */
+ public static function equalTo($version1, $version2)
+ {
+ return self::compare($version1, '==', $version2);
+ }
+
+ /**
+ * Evaluates the expression: $version1 != $version2.
+ *
+ * @param string $version1
+ * @param string $version2
+ *
+ * @return bool
+ */
+ public static function notEqualTo($version1, $version2)
+ {
+ return self::compare($version1, '!=', $version2);
+ }
+
+ /**
+ * Evaluates the expression: $version1 $operator $version2.
+ *
+ * @param string $version1
+ * @param string $operator
+ * @param string $version2
+ *
+ * @return bool
+ */
+ public static function compare($version1, $operator, $version2)
+ {
+ $constraint = new Constraint($operator, $version2);
+
+ return $constraint->matches(new Constraint('==', $version1));
+ }
+}
diff --git a/vendor/composer/semver/src/Constraint/AbstractConstraint.php b/vendor/composer/semver/src/Constraint/AbstractConstraint.php
new file mode 100644
index 00000000..ccd834f6
--- /dev/null
+++ b/vendor/composer/semver/src/Constraint/AbstractConstraint.php
@@ -0,0 +1,65 @@
+<?php
+
+/*
+ * This file is part of composer/semver.
+ *
+ * (c) Composer <https://github.com/composer>
+ *
+ * For the full copyright and license information, please view
+ * the LICENSE file that was distributed with this source code.
+ */
+
+namespace Composer\Semver\Constraint;
+
+/**
+ * Base constraint class.
+ */
+abstract class AbstractConstraint implements ConstraintInterface
+{
+ /** @var string */
+ protected $prettyString;
+
+ /**
+ * @param ConstraintInterface $provider
+ *
+ * @return bool
+ */
+ public function matches(ConstraintInterface $provider)
+ {
+ if ($provider instanceof MultiConstraint) {
+ // turn matching around to find a match
+ return $provider->matches($this);
+ }
+
+ if ($provider instanceof $this) {
+ // see note at bottom of this class declaration
+ return $this->matchSpecific($provider);
+ }
+
+ return true;
+ }
+
+ /**
+ * @param string $prettyString
+ */
+ public function setPrettyString($prettyString)
+ {
+ $this->prettyString = $prettyString;
+ }
+
+ /**
+ * @return string
+ */
+ public function getPrettyString()
+ {
+ if ($this->prettyString) {
+ return $this->prettyString;
+ }
+
+ return $this->__toString();
+ }
+
+ // implementations must implement a method of this format:
+ // not declared abstract here because type hinting violates parameter coherence (TODO right word?)
+ // public function matchSpecific(<SpecificConstraintType> $provider);
+}
diff --git a/vendor/composer/semver/src/Constraint/Constraint.php b/vendor/composer/semver/src/Constraint/Constraint.php
new file mode 100644
index 00000000..8bc68db7
--- /dev/null
+++ b/vendor/composer/semver/src/Constraint/Constraint.php
@@ -0,0 +1,181 @@
+<?php
+
+/*
+ * This file is part of composer/semver.
+ *
+ * (c) Composer <https://github.com/composer>
+ *
+ * For the full copyright and license information, please view
+ * the LICENSE file that was distributed with this source code.
+ */
+
+namespace Composer\Semver\Constraint;
+
+/**
+ * Defines a constraint.
+ */
+class Constraint extends AbstractConstraint
+{
+ /* operator integer values */
+ const OP_EQ = 0;
+ const OP_LT = 1;
+ const OP_LE = 2;
+ const OP_GT = 3;
+ const OP_GE = 4;
+ const OP_NE = 5;
+
+ /**
+ * Operator to integer translation table.
+ *
+ * @var array
+ */
+ private static $transOpStr = array(
+ '=' => self::OP_EQ,
+ '==' => self::OP_EQ,
+ '<' => self::OP_LT,
+ '<=' => self::OP_LE,
+ '>' => self::OP_GT,
+ '>=' => self::OP_GE,
+ '<>' => self::OP_NE,
+ '!=' => self::OP_NE,
+ );
+
+ /**
+ * Integer to operator translation table.
+ *
+ * @var array
+ */
+ private static $transOpInt = array(
+ self::OP_EQ => '==',
+ self::OP_LT => '<',
+ self::OP_LE => '<=',
+ self::OP_GT => '>',
+ self::OP_GE => '>=',
+ self::OP_NE => '!=',
+ );
+
+ /** @var string */
+ private $operator;
+
+ /** @var string */
+ private $version;
+
+ /**
+ * Get all supported comparison operators.
+ *
+ * @return array
+ */
+ public static function getSupportedOperators()
+ {
+ return array_keys(self::$transOpStr);
+ }
+
+ /**
+ * Sets operator and version to compare with.
+ *
+ * @param string $operator
+ * @param string $version
+ *
+ * @throws \InvalidArgumentException if invalid operator is given.
+ */
+ public function __construct($operator, $version)
+ {
+ if (!isset(self::$transOpStr[$operator])) {
+ throw new \InvalidArgumentException(sprintf(
+ 'Invalid operator "%s" given, expected one of: %s',
+ $operator,
+ implode(', ', self::getSupportedOperators())
+ ));
+ }
+
+ $this->operator = self::$transOpStr[$operator];
+ $this->version = $version;
+ }
+
+ /**
+ * @param string $a
+ * @param string $b
+ * @param string $operator
+ * @param bool $compareBranches
+ *
+ * @throws \InvalidArgumentException if invalid operator is given.
+ *
+ * @return bool
+ */
+ public function versionCompare($a, $b, $operator, $compareBranches = false)
+ {
+ if (!isset(self::$transOpStr[$operator])) {
+ throw new \InvalidArgumentException(sprintf(
+ 'Invalid operator "%s" given, expected one of: %s',
+ $operator,
+ implode(', ', self::getSupportedOperators())
+ ));
+ }
+
+ $aIsBranch = 'dev-' === substr($a, 0, 4);
+ $bIsBranch = 'dev-' === substr($b, 0, 4);
+
+ if ($aIsBranch && $bIsBranch) {
+ return $operator === '==' && $a === $b;
+ }
+
+ // when branches are not comparable, we make sure dev branches never match anything
+ if (!$compareBranches && ($aIsBranch || $bIsBranch)) {
+ return false;
+ }
+
+ return version_compare($a, $b, $operator);
+ }
+
+ /**
+ * @param Constraint $provider
+ * @param bool $compareBranches
+ *
+ * @return bool
+ */
+ public function matchSpecific(Constraint $provider, $compareBranches = false)
+ {
+ $noEqualOp = str_replace('=', '', self::$transOpInt[$this->operator]);
+ $providerNoEqualOp = str_replace('=', '', self::$transOpInt[$provider->operator]);
+
+ $isEqualOp = self::OP_EQ === $this->operator;
+ $isNonEqualOp = self::OP_NE === $this->operator;
+ $isProviderEqualOp = self::OP_EQ === $provider->operator;
+ $isProviderNonEqualOp = self::OP_NE === $provider->operator;
+
+ // '!=' operator is match when other operator is not '==' operator or version is not match
+ // these kinds of comparisons always have a solution
+ if ($isNonEqualOp || $isProviderNonEqualOp) {
+ return !$isEqualOp && !$isProviderEqualOp
+ || $this->versionCompare($provider->version, $this->version, '!=', $compareBranches);
+ }
+
+ // an example for the condition is <= 2.0 & < 1.0
+ // these kinds of comparisons always have a solution
+ if ($this->operator !== self::OP_EQ && $noEqualOp === $providerNoEqualOp) {
+ return true;
+ }
+
+ if ($this->versionCompare($provider->version, $this->version, self::$transOpInt[$this->operator], $compareBranches)) {
+ // special case, e.g. require >= 1.0 and provide < 1.0
+ // 1.0 >= 1.0 but 1.0 is outside of the provided interval
+ if ($provider->version === $this->version
+ && self::$transOpInt[$provider->operator] === $providerNoEqualOp
+ && self::$transOpInt[$this->operator] !== $noEqualOp) {
+ return false;
+ }
+
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * @return string
+ */
+ public function __toString()
+ {
+ return self::$transOpInt[$this->operator] . ' ' . $this->version;
+ }
+}
diff --git a/vendor/composer/semver/src/Constraint/ConstraintInterface.php b/vendor/composer/semver/src/Constraint/ConstraintInterface.php
new file mode 100644
index 00000000..78c099ce
--- /dev/null
+++ b/vendor/composer/semver/src/Constraint/ConstraintInterface.php
@@ -0,0 +1,37 @@
+<?php
+
+/*
+ * This file is part of composer/semver.
+ *
+ * (c) Composer <https://github.com/composer>
+ *
+ * For the full copyright and license information, please view
+ * the LICENSE file that was distributed with this source code.
+ */
+
+namespace Composer\Semver\Constraint;
+
+interface ConstraintInterface
+{
+ /**
+ * @param ConstraintInterface $provider
+ *
+ * @return bool
+ */
+ public function matches(ConstraintInterface $provider);
+
+ /**
+ * @param string $prettyString
+ */
+ public function setPrettyString($prettyString);
+
+ /**
+ * @return string
+ */
+ public function getPrettyString();
+
+ /**
+ * @return string
+ */
+ public function __toString();
+}
diff --git a/vendor/composer/semver/src/Constraint/EmptyConstraint.php b/vendor/composer/semver/src/Constraint/EmptyConstraint.php
new file mode 100644
index 00000000..faba56bf
--- /dev/null
+++ b/vendor/composer/semver/src/Constraint/EmptyConstraint.php
@@ -0,0 +1,59 @@
+<?php
+
+/*
+ * This file is part of composer/semver.
+ *
+ * (c) Composer <https://github.com/composer>
+ *
+ * For the full copyright and license information, please view
+ * the LICENSE file that was distributed with this source code.
+ */
+
+namespace Composer\Semver\Constraint;
+
+/**
+ * Defines the absence of a constraint.
+ */
+class EmptyConstraint implements ConstraintInterface
+{
+ /** @var string */
+ protected $prettyString;
+
+ /**
+ * @param ConstraintInterface $provider
+ *
+ * @return bool
+ */
+ public function matches(ConstraintInterface $provider)
+ {
+ return true;
+ }
+
+ /**
+ * @param $prettyString
+ */
+ public function setPrettyString($prettyString)
+ {
+ $this->prettyString = $prettyString;
+ }
+
+ /**
+ * @return string
+ */
+ public function getPrettyString()
+ {
+ if ($this->prettyString) {
+ return $this->prettyString;
+ }
+
+ return $this->__toString();
+ }
+
+ /**
+ * @return string
+ */
+ public function __toString()
+ {
+ return '[]';
+ }
+}
diff --git a/vendor/composer/semver/src/Constraint/MultiConstraint.php b/vendor/composer/semver/src/Constraint/MultiConstraint.php
new file mode 100644
index 00000000..0d769b7c
--- /dev/null
+++ b/vendor/composer/semver/src/Constraint/MultiConstraint.php
@@ -0,0 +1,96 @@
+<?php
+
+/*
+ * This file is part of composer/semver.
+ *
+ * (c) Composer <https://github.com/composer>
+ *
+ * For the full copyright and license information, please view
+ * the LICENSE file that was distributed with this source code.
+ */
+
+namespace Composer\Semver\Constraint;
+
+/**
+ * Defines a conjunctive or disjunctive set of constraints.
+ */
+class MultiConstraint implements ConstraintInterface
+{
+ /** @var ConstraintInterface[] */
+ protected $constraints;
+
+ /** @var string */
+ protected $prettyString;
+
+ /** @var bool */
+ protected $conjunctive;
+
+ /**
+ * @param ConstraintInterface[] $constraints A set of constraints
+ * @param bool $conjunctive Whether the constraints should be treated as conjunctive or disjunctive
+ */
+ public function __construct(array $constraints, $conjunctive = true)
+ {
+ $this->constraints = $constraints;
+ $this->conjunctive = $conjunctive;
+ }
+
+ /**
+ * @param ConstraintInterface $provider
+ *
+ * @return bool
+ */
+ public function matches(ConstraintInterface $provider)
+ {
+ if (false === $this->conjunctive) {
+ foreach ($this->constraints as $constraint) {
+ if ($constraint->matches($provider)) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ foreach ($this->constraints as $constraint) {
+ if (!$constraint->matches($provider)) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ /**
+ * @param string $prettyString
+ */
+ public function setPrettyString($prettyString)
+ {
+ $this->prettyString = $prettyString;
+ }
+
+ /**
+ * @return string
+ */
+ public function getPrettyString()
+ {
+ if ($this->prettyString) {
+ return $this->prettyString;
+ }
+
+ return $this->__toString();
+ }
+
+ /**
+ * @return string
+ */
+ public function __toString()
+ {
+ $constraints = array();
+ foreach ($this->constraints as $constraint) {
+ $constraints[] = (string) $constraint;
+ }
+
+ return '[' . implode($this->conjunctive ? ' ' : ' || ', $constraints) . ']';
+ }
+}
diff --git a/vendor/composer/semver/src/Semver.php b/vendor/composer/semver/src/Semver.php
new file mode 100644
index 00000000..0225bb55
--- /dev/null
+++ b/vendor/composer/semver/src/Semver.php
@@ -0,0 +1,127 @@
+<?php
+
+/*
+ * This file is part of composer/semver.
+ *
+ * (c) Composer <https://github.com/composer>
+ *
+ * For the full copyright and license information, please view
+ * the LICENSE file that was distributed with this source code.
+ */
+
+namespace Composer\Semver;
+
+use Composer\Semver\Constraint\Constraint;
+
+class Semver
+{
+ const SORT_ASC = 1;
+ const SORT_DESC = -1;
+
+ /** @var VersionParser */
+ private static $versionParser;
+
+ /**
+ * Determine if given version satisfies given constraints.
+ *
+ * @param string $version
+ * @param string $constraints
+ *
+ * @return bool
+ */
+ public static function satisfies($version, $constraints)
+ {
+ if (null === self::$versionParser) {
+ self::$versionParser = new VersionParser();
+ }
+
+ $versionParser = self::$versionParser;
+ $provider = new Constraint('==', $versionParser->normalize($version));
+ $constraints = $versionParser->parseConstraints($constraints);
+
+ return $constraints->matches($provider);
+ }
+
+ /**
+ * Return all versions that satisfy given constraints.
+ *
+ * @param array $versions
+ * @param string $constraints
+ *
+ * @return array
+ */
+ public static function satisfiedBy(array $versions, $constraints)
+ {
+ $versions = array_filter($versions, function ($version) use ($constraints) {
+ return Semver::satisfies($version, $constraints);
+ });
+
+ return array_values($versions);
+ }
+
+ /**
+ * Sort given array of versions.
+ *
+ * @param array $versions
+ *
+ * @return array
+ */
+ public static function sort(array $versions)
+ {
+ return self::usort($versions, self::SORT_ASC);
+ }
+
+ /**
+ * Sort given array of versions in reverse.
+ *
+ * @param array $versions
+ *
+ * @return array
+ */
+ public static function rsort(array $versions)
+ {
+ return self::usort($versions, self::SORT_DESC);
+ }
+
+ /**
+ * @param array $versions
+ * @param int $direction
+ *
+ * @return array
+ */
+ private static function usort(array $versions, $direction)
+ {
+ if (null === self::$versionParser) {
+ self::$versionParser = new VersionParser();
+ }
+
+ $versionParser = self::$versionParser;
+ $normalized = array();
+
+ // Normalize outside of usort() scope for minor performance increase.
+ // Creates an array of arrays: [[normalized, key], ...]
+ foreach ($versions as $key => $version) {
+ $normalized[] = array($versionParser->normalize($version), $key);
+ }
+
+ usort($normalized, function (array $left, array $right) use ($direction) {
+ if ($left[0] === $right[0]) {
+ return 0;
+ }
+
+ if (Comparator::lessThan($left[0], $right[0])) {
+ return -$direction;
+ }
+
+ return $direction;
+ });
+
+ // Recreate input array, using the original indexes which are now in sorted order.
+ $sorted = array();
+ foreach ($normalized as $item) {
+ $sorted[] = $versions[$item[1]];
+ }
+
+ return $sorted;
+ }
+}
diff --git a/vendor/composer/semver/src/VersionParser.php b/vendor/composer/semver/src/VersionParser.php
new file mode 100644
index 00000000..269aee94
--- /dev/null
+++ b/vendor/composer/semver/src/VersionParser.php
@@ -0,0 +1,520 @@
+<?php
+
+/*
+ * This file is part of composer/semver.
+ *
+ * (c) Composer <https://github.com/composer>
+ *
+ * For the full copyright and license information, please view
+ * the LICENSE file that was distributed with this source code.
+ */
+
+namespace Composer\Semver;
+
+use Composer\Semver\Constraint\ConstraintInterface;
+use Composer\Semver\Constraint\EmptyConstraint;
+use Composer\Semver\Constraint\MultiConstraint;
+use Composer\Semver\Constraint\Constraint;
+
+/**
+ * Version parser.
+ *
+ * @author Jordi Boggiano <j.boggiano@seld.be>
+ */
+class VersionParser
+{
+ /** @var string */
+ private static $modifierRegex = '[._-]?(?:(stable|beta|b|RC|alpha|a|patch|pl|p)(?:[.-]?(\d+))?)?([.-]?dev)?';
+
+ /** @var array */
+ private static $stabilities = array(
+ 'stable', 'RC', 'beta', 'alpha', 'dev',
+ );
+
+ /**
+ * Returns the stability of a version.
+ *
+ * @param string $version
+ *
+ * @return string
+ */
+ public static function parseStability($version)
+ {
+ $version = preg_replace('{#.+$}i', '', $version);
+
+ if ('dev-' === substr($version, 0, 4) || '-dev' === substr($version, -4)) {
+ return 'dev';
+ }
+
+ preg_match('{' . self::$modifierRegex . '$}i', strtolower($version), $match);
+ if (!empty($match[3])) {
+ return 'dev';
+ }
+
+ if (!empty($match[1])) {
+ if ('beta' === $match[1] || 'b' === $match[1]) {
+ return 'beta';
+ }
+ if ('alpha' === $match[1] || 'a' === $match[1]) {
+ return 'alpha';
+ }
+ if ('rc' === $match[1]) {
+ return 'RC';
+ }
+ }
+
+ return 'stable';
+ }
+
+ /**
+ * @param string $stability
+ *
+ * @return string
+ */
+ public static function normalizeStability($stability)
+ {
+ $stability = strtolower($stability);
+
+ return $stability === 'rc' ? 'RC' : $stability;
+ }
+
+ /**
+ * Normalizes a version string to be able to perform comparisons on it.
+ *
+ * @param string $version
+ * @param string $fullVersion optional complete version string to give more context
+ *
+ * @throws \UnexpectedValueException
+ *
+ * @return string
+ */
+ public function normalize($version, $fullVersion = null)
+ {
+ $version = trim($version);
+ if (null === $fullVersion) {
+ $fullVersion = $version;
+ }
+
+ // strip off aliasing
+ if (preg_match('{^([^,\s]+) +as +([^,\s]+)$}', $version, $match)) {
+ $version = $match[1];
+ }
+
+ // strip off build metadata
+ if (preg_match('{^([^,\s+]+)\+[^\s]+$}', $version, $match)) {
+ $version = $match[1];
+ }
+
+ // match master-like branches
+ if (preg_match('{^(?:dev-)?(?:master|trunk|default)$}i', $version)) {
+ return '9999999-dev';
+ }
+
+ if ('dev-' === strtolower(substr($version, 0, 4))) {
+ return 'dev-' . substr($version, 4);
+ }
+
+ // match classical versioning
+ if (preg_match('{^v?(\d{1,5})(\.\d+)?(\.\d+)?(\.\d+)?' . self::$modifierRegex . '$}i', $version, $matches)) {
+ $version = $matches[1]
+ . (!empty($matches[2]) ? $matches[2] : '.0')
+ . (!empty($matches[3]) ? $matches[3] : '.0')
+ . (!empty($matches[4]) ? $matches[4] : '.0');
+ $index = 5;
+ // match date(time) based versioning
+ } elseif (preg_match('{^v?(\d{4}(?:[.:-]?\d{2}){1,6}(?:[.:-]?\d{1,3})?)' . self::$modifierRegex . '$}i', $version, $matches)) {
+ $version = preg_replace('{\D}', '-', $matches[1]);
+ $index = 2;
+ }
+
+ // add version modifiers if a version was matched
+ if (isset($index)) {
+ if (!empty($matches[$index])) {
+ if ('stable' === $matches[$index]) {
+ return $version;
+ }
+ $version .= '-' . $this->expandStability($matches[$index]) . (!empty($matches[$index + 1]) ? $matches[$index + 1] : '');
+ }
+
+ if (!empty($matches[$index + 2])) {
+ $version .= '-dev';
+ }
+
+ return $version;
+ }
+
+ // match dev branches
+ if (preg_match('{(.*?)[.-]?dev$}i', $version, $match)) {
+ try {
+ return $this->normalizeBranch($match[1]);
+ } catch (\Exception $e) {
+ }
+ }
+
+ $extraMessage = '';
+ if (preg_match('{ +as +' . preg_quote($version) . '$}', $fullVersion)) {
+ $extraMessage = ' in "' . $fullVersion . '", the alias must be an exact version';
+ } elseif (preg_match('{^' . preg_quote($version) . ' +as +}', $fullVersion)) {
+ $extraMessage = ' in "' . $fullVersion . '", the alias source must be an exact version, if it is a branch name you should prefix it with dev-';
+ }
+
+ throw new \UnexpectedValueException('Invalid version string "' . $version . '"' . $extraMessage);
+ }
+
+ /**
+ * Extract numeric prefix from alias, if it is in numeric format, suitable for version comparison.
+ *
+ * @param string $branch Branch name (e.g. 2.1.x-dev)
+ *
+ * @return string|false Numeric prefix if present (e.g. 2.1.) or false
+ */
+ public function parseNumericAliasPrefix($branch)
+ {
+ if (preg_match('{^(?P<version>(\d+\\.)*\d+)(?:\.x)?-dev$}i', $branch, $matches)) {
+ return $matches['version'] . '.';
+ }
+
+ return false;
+ }
+
+ /**
+ * Normalizes a branch name to be able to perform comparisons on it.
+ *
+ * @param string $name
+ *
+ * @return string
+ */
+ public function normalizeBranch($name)
+ {
+ $name = trim($name);
+
+ if (in_array($name, array('master', 'trunk', 'default'))) {
+ return $this->normalize($name);
+ }
+
+ if (preg_match('{^v?(\d+)(\.(?:\d+|[xX*]))?(\.(?:\d+|[xX*]))?(\.(?:\d+|[xX*]))?$}i', $name, $matches)) {
+ $version = '';
+ for ($i = 1; $i < 5; ++$i) {
+ $version .= isset($matches[$i]) ? str_replace(array('*', 'X'), 'x', $matches[$i]) : '.x';
+ }
+
+ return str_replace('x', '9999999', $version) . '-dev';
+ }
+
+ return 'dev-' . $name;
+ }
+
+ /**
+ * Parses as constraint string into LinkConstraint objects.
+ *
+ * @param string $constraints
+ *
+ * @return ConstraintInterface
+ */
+ public function parseConstraints($constraints)
+ {
+ $prettyConstraint = $constraints;
+
+ if (preg_match('{^([^,\s]*?)@(' . implode('|', self::$stabilities) . ')$}i', $constraints, $match)) {
+ $constraints = empty($match[1]) ? '*' : $match[1];
+ }
+
+ if (preg_match('{^(dev-[^,\s@]+?|[^,\s@]+?\.x-dev)#.+$}i', $constraints, $match)) {
+ $constraints = $match[1];
+ }
+
+ $orConstraints = preg_split('{\s*\|\|?\s*}', trim($constraints));
+ $orGroups = array();
+ foreach ($orConstraints as $constraints) {
+ $andConstraints = preg_split('{(?<!^|as|[=>< ,]) *(?<!-)[, ](?!-) *(?!,|as|$)}', $constraints);
+ if (count($andConstraints) > 1) {
+ $constraintObjects = array();
+ foreach ($andConstraints as $constraint) {
+ foreach ($this->parseConstraint($constraint) as $parsedConstraint) {
+ $constraintObjects[] = $parsedConstraint;
+ }
+ }
+ } else {
+ $constraintObjects = $this->parseConstraint($andConstraints[0]);
+ }
+
+ if (1 === count($constraintObjects)) {
+ $constraint = $constraintObjects[0];
+ } else {
+ $constraint = new MultiConstraint($constraintObjects);
+ }
+
+ $orGroups[] = $constraint;
+ }
+
+ if (1 === count($orGroups)) {
+ $constraint = $orGroups[0];
+ } else {
+ $constraint = new MultiConstraint($orGroups, false);
+ }
+
+ $constraint->setPrettyString($prettyConstraint);
+
+ return $constraint;
+ }
+
+ /**
+ * @param string $constraint
+ *
+ * @throws \UnexpectedValueException
+ *
+ * @return array
+ */
+ private function parseConstraint($constraint)
+ {
+ if (preg_match('{^([^,\s]+?)@(' . implode('|', self::$stabilities) . ')$}i', $constraint, $match)) {
+ $constraint = $match[1];
+ if ($match[2] !== 'stable') {
+ $stabilityModifier = $match[2];
+ }
+ }
+
+ if (preg_match('{^[xX*](\.[xX*])*$}i', $constraint)) {
+ return array(new EmptyConstraint());
+ }
+
+ $versionRegex = 'v?(\d+)(?:\.(\d+))?(?:\.(\d+))?(?:\.(\d+))?' . self::$modifierRegex . '(?:\+[^\s]+)?';
+
+ // Tilde Range
+ //
+ // Like wildcard constraints, unsuffixed tilde constraints say that they must be greater than the previous
+ // version, to ensure that unstable instances of the current version are allowed. However, if a stability
+ // suffix is added to the constraint, then a >= match on the current version is used instead.
+ if (preg_match('{^~>?' . $versionRegex . '$}i', $constraint, $matches)) {
+ if (substr($constraint, 0, 2) === '~>') {
+ throw new \UnexpectedValueException(
+ 'Could not parse version constraint ' . $constraint . ': ' .
+ 'Invalid operator "~>", you probably meant to use the "~" operator'
+ );
+ }
+
+ // Work out which position in the version we are operating at
+ if (isset($matches[4]) && '' !== $matches[4]) {
+ $position = 4;
+ } elseif (isset($matches[3]) && '' !== $matches[3]) {
+ $position = 3;
+ } elseif (isset($matches[2]) && '' !== $matches[2]) {
+ $position = 2;
+ } else {
+ $position = 1;
+ }
+
+ // Calculate the stability suffix
+ $stabilitySuffix = '';
+ if (!empty($matches[5])) {
+ $stabilitySuffix .= '-' . $this->expandStability($matches[5]) . (!empty($matches[6]) ? $matches[6] : '');
+ }
+
+ if (!empty($matches[7])) {
+ $stabilitySuffix .= '-dev';
+ }
+
+ if (!$stabilitySuffix) {
+ $stabilitySuffix = '-dev';
+ }
+
+ $lowVersion = $this->manipulateVersionString($matches, $position, 0) . $stabilitySuffix;
+ $lowerBound = new Constraint('>=', $lowVersion);
+
+ // For upper bound, we increment the position of one more significance,
+ // but highPosition = 0 would be illegal
+ $highPosition = max(1, $position - 1);
+ $highVersion = $this->manipulateVersionString($matches, $highPosition, 1) . '-dev';
+ $upperBound = new Constraint('<', $highVersion);
+
+ return array(
+ $lowerBound,
+ $upperBound,
+ );
+ }
+
+ // Caret Range
+ //
+ // Allows changes that do not modify the left-most non-zero digit in the [major, minor, patch] tuple.
+ // In other words, this allows patch and minor updates for versions 1.0.0 and above, patch updates for
+ // versions 0.X >=0.1.0, and no updates for versions 0.0.X
+ if (preg_match('{^\^' . $versionRegex . '($)}i', $constraint, $matches)) {
+ // Work out which position in the version we are operating at
+ if ('0' !== $matches[1] || '' === $matches[2]) {
+ $position = 1;
+ } elseif ('0' !== $matches[2] || '' === $matches[3]) {
+ $position = 2;
+ } else {
+ $position = 3;
+ }
+
+ // Calculate the stability suffix
+ $stabilitySuffix = '';
+ if (empty($matches[5]) && empty($matches[7])) {
+ $stabilitySuffix .= '-dev';
+ }
+
+ $lowVersion = $this->normalize(substr($constraint . $stabilitySuffix, 1));
+ $lowerBound = new Constraint('>=', $lowVersion);
+
+ // For upper bound, we increment the position of one more significance,
+ // but highPosition = 0 would be illegal
+ $highVersion = $this->manipulateVersionString($matches, $position, 1) . '-dev';
+ $upperBound = new Constraint('<', $highVersion);
+
+ return array(
+ $lowerBound,
+ $upperBound,
+ );
+ }
+
+ // X Range
+ //
+ // Any of X, x, or * may be used to "stand in" for one of the numeric values in the [major, minor, patch] tuple.
+ // A partial version range is treated as an X-Range, so the special character is in fact optional.
+ if (preg_match('{^(\d+)(?:\.(\d+))?(?:\.(\d+))?(?:\.[xX*])+$}', $constraint, $matches)) {
+ if (isset($matches[3]) && '' !== $matches[3]) {
+ $position = 3;
+ } elseif (isset($matches[2]) && '' !== $matches[2]) {
+ $position = 2;
+ } else {
+ $position = 1;
+ }
+
+ $lowVersion = $this->manipulateVersionString($matches, $position) . '-dev';
+ $highVersion = $this->manipulateVersionString($matches, $position, 1) . '-dev';
+
+ if ($lowVersion === '0.0.0.0-dev') {
+ return array(new Constraint('<', $highVersion));
+ }
+
+ return array(
+ new Constraint('>=', $lowVersion),
+ new Constraint('<', $highVersion),
+ );
+ }
+
+ // Hyphen Range
+ //
+ // Specifies an inclusive set. If a partial version is provided as the first version in the inclusive range,
+ // then the missing pieces are replaced with zeroes. If a partial version is provided as the second version in
+ // the inclusive range, then all versions that start with the supplied parts of the tuple are accepted, but
+ // nothing that would be greater than the provided tuple parts.
+ if (preg_match('{^(?P<from>' . $versionRegex . ') +- +(?P<to>' . $versionRegex . ')($)}i', $constraint, $matches)) {
+ // Calculate the stability suffix
+ $lowStabilitySuffix = '';
+ if (empty($matches[6]) && empty($matches[8])) {
+ $lowStabilitySuffix = '-dev';
+ }
+
+ $lowVersion = $this->normalize($matches['from']);
+ $lowerBound = new Constraint('>=', $lowVersion . $lowStabilitySuffix);
+
+ $empty = function ($x) {
+ return ($x === 0 || $x === '0') ? false : empty($x);
+ };
+
+ if ((!$empty($matches[11]) && !$empty($matches[12])) || !empty($matches[14]) || !empty($matches[16])) {
+ $highVersion = $this->normalize($matches['to']);
+ $upperBound = new Constraint('<=', $highVersion);
+ } else {
+ $highMatch = array('', $matches[10], $matches[11], $matches[12], $matches[13]);
+ $highVersion = $this->manipulateVersionString($highMatch, $empty($matches[11]) ? 1 : 2, 1) . '-dev';
+ $upperBound = new Constraint('<', $highVersion);
+ }
+
+ return array(
+ $lowerBound,
+ $upperBound,
+ );
+ }
+
+ // Basic Comparators
+ if (preg_match('{^(<>|!=|>=?|<=?|==?)?\s*(.*)}', $constraint, $matches)) {
+ try {
+ $version = $this->normalize($matches[2]);
+
+ if (!empty($stabilityModifier) && $this->parseStability($version) === 'stable') {
+ $version .= '-' . $stabilityModifier;
+ } elseif ('<' === $matches[1] || '>=' === $matches[1]) {
+ if (!preg_match('/-' . self::$modifierRegex . '$/', strtolower($matches[2]))) {
+ if (substr($matches[2], 0, 4) !== 'dev-') {
+ $version .= '-dev';
+ }
+ }
+ }
+
+ return array(new Constraint($matches[1] ?: '=', $version));
+ } catch (\Exception $e) {
+ }
+ }
+
+ $message = 'Could not parse version constraint ' . $constraint;
+ if (isset($e)) {
+ $message .= ': ' . $e->getMessage();
+ }
+
+ throw new \UnexpectedValueException($message);
+ }
+
+ /**
+ * Increment, decrement, or simply pad a version number.
+ *
+ * Support function for {@link parseConstraint()}
+ *
+ * @param array $matches Array with version parts in array indexes 1,2,3,4
+ * @param int $position 1,2,3,4 - which segment of the version to increment/decrement
+ * @param int $increment
+ * @param string $pad The string to pad version parts after $position
+ *
+ * @return string The new version
+ */
+ private function manipulateVersionString($matches, $position, $increment = 0, $pad = '0')
+ {
+ for ($i = 4; $i > 0; --$i) {
+ if ($i > $position) {
+ $matches[$i] = $pad;
+ } elseif ($i === $position && $increment) {
+ $matches[$i] += $increment;
+ // If $matches[$i] was 0, carry the decrement
+ if ($matches[$i] < 0) {
+ $matches[$i] = $pad;
+ --$position;
+
+ // Return null on a carry overflow
+ if ($i === 1) {
+ return;
+ }
+ }
+ }
+ }
+
+ return $matches[1] . '.' . $matches[2] . '.' . $matches[3] . '.' . $matches[4];
+ }
+
+ /**
+ * Expand shorthand stability string to long version.
+ *
+ * @param string $stability
+ *
+ * @return string
+ */
+ private function expandStability($stability)
+ {
+ $stability = strtolower($stability);
+
+ switch ($stability) {
+ case 'a':
+ return 'alpha';
+ case 'b':
+ return 'beta';
+ case 'p':
+ case 'pl':
+ return 'patch';
+ case 'rc':
+ return 'RC';
+ default:
+ return $stability;
+ }
+ }
+}
diff --git a/vendor/firebase/php-jwt/Authentication/JWT.php b/vendor/firebase/php-jwt/Authentication/JWT.php
new file mode 100644
index 00000000..7d6665bd
--- /dev/null
+++ b/vendor/firebase/php-jwt/Authentication/JWT.php
@@ -0,0 +1,334 @@
+<?php
+
+/**
+ * JSON Web Token implementation, based on this spec:
+ * http://tools.ietf.org/html/draft-ietf-oauth-json-web-token-06
+ *
+ * PHP version 5
+ *
+ * @category Authentication
+ * @package Authentication_JWT
+ * @author Neuman Vong <neuman@twilio.com>
+ * @author Anant Narayanan <anant@php.net>
+ * @license http://opensource.org/licenses/BSD-3-Clause 3-clause BSD
+ * @link https://github.com/firebase/php-jwt
+ */
+class JWT
+{
+
+ /**
+ * When checking nbf, iat or expiration times,
+ * we want to provide some extra leeway time to
+ * account for clock skew.
+ */
+ public static $leeway = 0;
+
+ public static $supported_algs = array(
+ 'HS256' => array('hash_hmac', 'SHA256'),
+ 'HS512' => array('hash_hmac', 'SHA512'),
+ 'HS384' => array('hash_hmac', 'SHA384'),
+ 'RS256' => array('openssl', 'SHA256'),
+ );
+
+ /**
+ * Decodes a JWT string into a PHP object.
+ *
+ * @param string $jwt The JWT
+ * @param string|Array|null $key The secret key, or map of keys
+ * @param Array $allowed_algs List of supported verification algorithms
+ *
+ * @return object The JWT's payload as a PHP object
+ *
+ * @throws DomainException Algorithm was not provided
+ * @throws UnexpectedValueException Provided JWT was invalid
+ * @throws SignatureInvalidException Provided JWT was invalid because the signature verification failed
+ * @throws BeforeValidException Provided JWT is trying to be used before it's eligible as defined by 'nbf'
+ * @throws BeforeValidException Provided JWT is trying to be used before it's been created as defined by 'iat'
+ * @throws ExpiredException Provided JWT has since expired, as defined by the 'exp' claim
+ *
+ * @uses jsonDecode
+ * @uses urlsafeB64Decode
+ */
+ public static function decode($jwt, $key = null, $allowed_algs = array())
+ {
+ $tks = explode('.', $jwt);
+ if (count($tks) != 3) {
+ throw new UnexpectedValueException('Wrong number of segments');
+ }
+ list($headb64, $bodyb64, $cryptob64) = $tks;
+ if (null === ($header = JWT::jsonDecode(JWT::urlsafeB64Decode($headb64)))) {
+ throw new UnexpectedValueException('Invalid header encoding');
+ }
+ if (null === $payload = JWT::jsonDecode(JWT::urlsafeB64Decode($bodyb64))) {
+ throw new UnexpectedValueException('Invalid claims encoding');
+ }
+ $sig = JWT::urlsafeB64Decode($cryptob64);
+ if (isset($key)) {
+ if (empty($header->alg)) {
+ throw new DomainException('Empty algorithm');
+ }
+ if (empty(self::$supported_algs[$header->alg])) {
+ throw new DomainException('Algorithm not supported');
+ }
+ if (!is_array($allowed_algs) || !in_array($header->alg, $allowed_algs)) {
+ throw new DomainException('Algorithm not allowed');
+ }
+ if (is_array($key) || $key instanceof \ArrayAccess) {
+ if (isset($header->kid)) {
+ $key = $key[$header->kid];
+ } else {
+ throw new DomainException('"kid" empty, unable to lookup correct key');
+ }
+ }
+
+ // Check the signature
+ if (!JWT::verify("$headb64.$bodyb64", $sig, $key, $header->alg)) {
+ throw new SignatureInvalidException('Signature verification failed');
+ }
+
+ // Check if the nbf if it is defined. This is the time that the
+ // token can actually be used. If it's not yet that time, abort.
+ if (isset($payload->nbf) && $payload->nbf > (time() + self::$leeway)) {
+ throw new BeforeValidException(
+ 'Cannot handle token prior to ' . date(DateTime::ISO8601, $payload->nbf)
+ );
+ }
+
+ // Check that this token has been created before 'now'. This prevents
+ // using tokens that have been created for later use (and haven't
+ // correctly used the nbf claim).
+ if (isset($payload->iat) && $payload->iat > (time() + self::$leeway)) {
+ throw new BeforeValidException(
+ 'Cannot handle token prior to ' . date(DateTime::ISO8601, $payload->iat)
+ );
+ }
+
+ // Check if this token has expired.
+ if (isset($payload->exp) && (time() - self::$leeway) >= $payload->exp) {
+ throw new ExpiredException('Expired token');
+ }
+ }
+
+ return $payload;
+ }
+
+ /**
+ * Converts and signs a PHP object or array into a JWT string.
+ *
+ * @param object|array $payload PHP object or array
+ * @param string $key The secret key
+ * @param string $alg The signing algorithm. Supported
+ * algorithms are 'HS256', 'HS384' and 'HS512'
+ *
+ * @return string A signed JWT
+ * @uses jsonEncode
+ * @uses urlsafeB64Encode
+ */
+ public static function encode($payload, $key, $alg = 'HS256', $keyId = null)
+ {
+ $header = array('typ' => 'JWT', 'alg' => $alg);
+ if ($keyId !== null) {
+ $header['kid'] = $keyId;
+ }
+ $segments = array();
+ $segments[] = JWT::urlsafeB64Encode(JWT::jsonEncode($header));
+ $segments[] = JWT::urlsafeB64Encode(JWT::jsonEncode($payload));
+ $signing_input = implode('.', $segments);
+
+ $signature = JWT::sign($signing_input, $key, $alg);
+ $segments[] = JWT::urlsafeB64Encode($signature);
+
+ return implode('.', $segments);
+ }
+
+ /**
+ * Sign a string with a given key and algorithm.
+ *
+ * @param string $msg The message to sign
+ * @param string|resource $key The secret key
+ * @param string $alg The signing algorithm. Supported algorithms
+ * are 'HS256', 'HS384', 'HS512' and 'RS256'
+ *
+ * @return string An encrypted message
+ * @throws DomainException Unsupported algorithm was specified
+ */
+ public static function sign($msg, $key, $alg = 'HS256')
+ {
+ if (empty(self::$supported_algs[$alg])) {
+ throw new DomainException('Algorithm not supported');
+ }
+ list($function, $algorithm) = self::$supported_algs[$alg];
+ switch($function) {
+ case 'hash_hmac':
+ return hash_hmac($algorithm, $msg, $key, true);
+ case 'openssl':
+ $signature = '';
+ $success = openssl_sign($msg, $signature, $key, $algorithm);
+ if (!$success) {
+ throw new DomainException("OpenSSL unable to sign data");
+ } else {
+ return $signature;
+ }
+ }
+ }
+
+ /**
+ * Verify a signature with the mesage, key and method. Not all methods
+ * are symmetric, so we must have a separate verify and sign method.
+ * @param string $msg the original message
+ * @param string $signature
+ * @param string|resource $key for HS*, a string key works. for RS*, must be a resource of an openssl public key
+ * @param string $alg
+ * @return bool
+ * @throws DomainException Invalid Algorithm or OpenSSL failure
+ */
+ private static function verify($msg, $signature, $key, $alg)
+ {
+ if (empty(self::$supported_algs[$alg])) {
+ throw new DomainException('Algorithm not supported');
+ }
+
+ list($function, $algorithm) = self::$supported_algs[$alg];
+ switch($function) {
+ case 'openssl':
+ $success = openssl_verify($msg, $signature, $key, $algorithm);
+ if (!$success) {
+ throw new DomainException("OpenSSL unable to verify data: " . openssl_error_string());
+ } else {
+ return $signature;
+ }
+ case 'hash_hmac':
+ default:
+ $hash = hash_hmac($algorithm, $msg, $key, true);
+ if (function_exists('hash_equals')) {
+ return hash_equals($signature, $hash);
+ }
+ $len = min(self::safeStrlen($signature), self::safeStrlen($hash));
+
+ $status = 0;
+ for ($i = 0; $i < $len; $i++) {
+ $status |= (ord($signature[$i]) ^ ord($hash[$i]));
+ }
+ $status |= (self::safeStrlen($signature) ^ self::safeStrlen($hash));
+
+ return ($status === 0);
+ }
+ }
+
+ /**
+ * Decode a JSON string into a PHP object.
+ *
+ * @param string $input JSON string
+ *
+ * @return object Object representation of JSON string
+ * @throws DomainException Provided string was invalid JSON
+ */
+ public static function jsonDecode($input)
+ {
+ if (version_compare(PHP_VERSION, '5.4.0', '>=') && !(defined('JSON_C_VERSION') && PHP_INT_SIZE > 4)) {
+ /** In PHP >=5.4.0, json_decode() accepts an options parameter, that allows you
+ * to specify that large ints (like Steam Transaction IDs) should be treated as
+ * strings, rather than the PHP default behaviour of converting them to floats.
+ */
+ $obj = json_decode($input, false, 512, JSON_BIGINT_AS_STRING);
+ } else {
+ /** Not all servers will support that, however, so for older versions we must
+ * manually detect large ints in the JSON string and quote them (thus converting
+ *them to strings) before decoding, hence the preg_replace() call.
+ */
+ $max_int_length = strlen((string) PHP_INT_MAX) - 1;
+ $json_without_bigints = preg_replace('/:\s*(-?\d{'.$max_int_length.',})/', ': "$1"', $input);
+ $obj = json_decode($json_without_bigints);
+ }
+
+ if (function_exists('json_last_error') && $errno = json_last_error()) {
+ JWT::handleJsonError($errno);
+ } elseif ($obj === null && $input !== 'null') {
+ throw new DomainException('Null result with non-null input');
+ }
+ return $obj;
+ }
+
+ /**
+ * Encode a PHP object into a JSON string.
+ *
+ * @param object|array $input A PHP object or array
+ *
+ * @return string JSON representation of the PHP object or array
+ * @throws DomainException Provided object could not be encoded to valid JSON
+ */
+ public static function jsonEncode($input)
+ {
+ $json = json_encode($input);
+ if (function_exists('json_last_error') && $errno = json_last_error()) {
+ JWT::handleJsonError($errno);
+ } elseif ($json === 'null' && $input !== null) {
+ throw new DomainException('Null result with non-null input');
+ }
+ return $json;
+ }
+
+ /**
+ * Decode a string with URL-safe Base64.
+ *
+ * @param string $input A Base64 encoded string
+ *
+ * @return string A decoded string
+ */
+ public static function urlsafeB64Decode($input)
+ {
+ $remainder = strlen($input) % 4;
+ if ($remainder) {
+ $padlen = 4 - $remainder;
+ $input .= str_repeat('=', $padlen);
+ }
+ return base64_decode(strtr($input, '-_', '+/'));
+ }
+
+ /**
+ * Encode a string with URL-safe Base64.
+ *
+ * @param string $input The string you want encoded
+ *
+ * @return string The base64 encode of what you passed in
+ */
+ public static function urlsafeB64Encode($input)
+ {
+ return str_replace('=', '', strtr(base64_encode($input), '+/', '-_'));
+ }
+
+ /**
+ * Helper method to create a JSON error.
+ *
+ * @param int $errno An error number from json_last_error()
+ *
+ * @return void
+ */
+ private static function handleJsonError($errno)
+ {
+ $messages = array(
+ JSON_ERROR_DEPTH => 'Maximum stack depth exceeded',
+ JSON_ERROR_CTRL_CHAR => 'Unexpected control character found',
+ JSON_ERROR_SYNTAX => 'Syntax error, malformed JSON'
+ );
+ throw new DomainException(
+ isset($messages[$errno])
+ ? $messages[$errno]
+ : 'Unknown JSON error: ' . $errno
+ );
+ }
+
+ /**
+ * Get the number of bytes in cryptographic strings.
+ *
+ * @param string
+ * @return int
+ */
+ private static function safeStrlen($str)
+ {
+ if (function_exists('mb_strlen')) {
+ return mb_strlen($str, '8bit');
+ }
+ return strlen($str);
+ }
+}
diff --git a/vendor/firebase/php-jwt/Exceptions/BeforeValidException.php b/vendor/firebase/php-jwt/Exceptions/BeforeValidException.php
new file mode 100644
index 00000000..5a84975e
--- /dev/null
+++ b/vendor/firebase/php-jwt/Exceptions/BeforeValidException.php
@@ -0,0 +1,6 @@
+<?php
+
+class BeforeValidException extends UnexpectedValueException
+{
+
+}
diff --git a/vendor/firebase/php-jwt/Exceptions/ExpiredException.php b/vendor/firebase/php-jwt/Exceptions/ExpiredException.php
new file mode 100644
index 00000000..bd80468f
--- /dev/null
+++ b/vendor/firebase/php-jwt/Exceptions/ExpiredException.php
@@ -0,0 +1,6 @@
+<?php
+
+class ExpiredException extends UnexpectedValueException
+{
+
+}
diff --git a/vendor/firebase/php-jwt/Exceptions/SignatureInvalidException.php b/vendor/firebase/php-jwt/Exceptions/SignatureInvalidException.php
new file mode 100644
index 00000000..d1222322
--- /dev/null
+++ b/vendor/firebase/php-jwt/Exceptions/SignatureInvalidException.php
@@ -0,0 +1,6 @@
+<?php
+
+class SignatureInvalidException extends UnexpectedValueException
+{
+
+}
diff --git a/vendor/firebase/php-jwt/LICENSE b/vendor/firebase/php-jwt/LICENSE
new file mode 100644
index 00000000..cb0c49b3
--- /dev/null
+++ b/vendor/firebase/php-jwt/LICENSE
@@ -0,0 +1,30 @@
+Copyright (c) 2011, Neuman Vong
+
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+
+ * Neither the name of Neuman Vong nor the names of other
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/vendor/firebase/php-jwt/README.md b/vendor/firebase/php-jwt/README.md
new file mode 100644
index 00000000..00bad2ef
--- /dev/null
+++ b/vendor/firebase/php-jwt/README.md
@@ -0,0 +1,93 @@
+[![Build Status](https://travis-ci.org/firebase/php-jwt.png?branch=master)](https://travis-ci.org/firebase/php-jwt)
+
+PHP-JWT
+=======
+A simple library to encode and decode JSON Web Tokens (JWT) in PHP. Should
+conform to the [current spec](http://tools.ietf.org/html/draft-ietf-oauth-json-web-token-06)
+
+Installation
+------------
+
+Use composer to manage your dependencies and download PHP-JWT:
+
+```bash
+composer require firebase/php-jwt
+```
+
+Example
+-------
+```php
+<?php
+
+$key = "example_key";
+$token = array(
+ "iss" => "http://example.org",
+ "aud" => "http://example.com",
+ "iat" => 1356999524,
+ "nbf" => 1357000000
+);
+
+/**
+ * IMPORTANT:
+ * You must specify supported algorithms for your application. See
+ * https://tools.ietf.org/html/draft-ietf-jose-json-web-algorithms-40
+ * for a list of spec-compliant algorithms.
+ */
+$jwt = JWT::encode($token, $key);
+$decoded = JWT::decode($jwt, $key, array('HS256'));
+
+print_r($decoded);
+
+/*
+ NOTE: This will now be an object instead of an associative array. To get
+ an associative array, you will need to cast it as such:
+*/
+
+$decoded_array = (array) $decoded;
+
+/**
+ * You can add a leeway to account for when there is a clock skew times between
+ * the signing and verifying servers. It is recommended that this leeway should
+ * not be bigger than a few minutes.
+ *
+ * Source: http://self-issued.info/docs/draft-ietf-oauth-json-web-token.html#nbfDef
+ */
+JWT::$leeway = 60; // $leeway in seconds
+$decoded = JWT::decode($jwt, $key, array('HS256'));
+
+?>
+```
+
+Changelog
+---------
+
+#### 2.1.0 / 2015-05-20
+- Add support for adding a leeway to `JWT:decode()` that accounts for clock skew
+between signing and verifying entities. Thanks to [@lcabral](https://github.com/lcabral)!
+- Add support for passing an object implementing the `ArrayAccess` interface for
+`$keys` argument in `JWT::decode()`. Thanks to [@aztech-dev](https://github.com/aztech-dev)!
+
+#### 2.0.0 / 2015-04-01
+- **Note**: It is strongly recommended that you update to > v2.0.0 to address
+ known security vulnerabilities in prior versions when both symmetric and
+ asymmetric keys are used together.
+- Update signature for `JWT::decode(...)` to require an array of supported
+ algorithms to use when verifying token signatures.
+
+
+Tests
+-----
+Run the tests using phpunit:
+
+```bash
+$ pear install PHPUnit
+$ phpunit --configuration phpunit.xml.dist
+PHPUnit 3.7.10 by Sebastian Bergmann.
+.....
+Time: 0 seconds, Memory: 2.50Mb
+OK (5 tests, 5 assertions)
+```
+
+License
+-------
+[3-Clause BSD](http://opensource.org/licenses/BSD-3-Clause).
diff --git a/vendor/firebase/php-jwt/composer.json b/vendor/firebase/php-jwt/composer.json
new file mode 100644
index 00000000..95560afd
--- /dev/null
+++ b/vendor/firebase/php-jwt/composer.json
@@ -0,0 +1,25 @@
+{
+ "name": "firebase/php-jwt",
+ "description": "A simple library to encode and decode JSON Web Tokens (JWT) in PHP. Should conform to the current spec.",
+ "homepage": "https://github.com/firebase/php-jwt",
+ "authors": [
+ {
+ "name": "Neuman Vong",
+ "email": "neuman+pear@twilio.com",
+ "role": "Developer"
+ },
+ {
+ "name": "Anant Narayanan",
+ "email": "anant@php.net",
+ "role": "Developer"
+ }
+ ],
+ "license": "BSD-3-Clause",
+ "require": {
+ "php": ">=5.2.0"
+ },
+ "autoload": {
+ "classmap": ["Authentication/", "Exceptions/"]
+ },
+ "minimum-stability": "dev"
+}
diff --git a/vendor/firebase/php-jwt/package.xml b/vendor/firebase/php-jwt/package.xml
new file mode 100644
index 00000000..b40da26d
--- /dev/null
+++ b/vendor/firebase/php-jwt/package.xml
@@ -0,0 +1,77 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<package packagerversion="1.9.2" version="2.0" xmlns="http://pear.php.net/dtd/package-2.0" xmlns:tasks="http://pear.php.net/dtd/tasks-1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://pear.php.net/dtd/tasks-1.0
+ http://pear.php.net/dtd/tasks-1.0.xsd
+ http://pear.php.net/dtd/package-2.0
+ http://pear.php.net/dtd/package-2.0.xsd">
+ <name>JWT</name>
+ <channel>pear.php.net</channel>
+ <summary>A JWT encoder/decoder.</summary>
+ <description>A JWT encoder/decoder library for PHP.</description>
+ <lead>
+ <name>Neuman Vong</name>
+ <user>lcfrs</user>
+ <email>neuman+pear@twilio.com</email>
+ <active>yes</active>
+ </lead>
+ <lead>
+ <name>Firebase Operations</name>
+ <user>firebase</user>
+ <email>operations@firebase.com</email>
+ <active>yes</active>
+ </lead>
+ <date>2015-05-20</date>
+ <version>
+ <release>2.1.0</release>
+ <api>2.1.0</api>
+ </version>
+ <stability>
+ <release>beta</release>
+ <api>beta</api>
+ </stability>
+ <license uri="http://opensource.org/licenses/BSD-3-Clause">BSD 3-Clause License</license>
+ <notes>
+Initial release with basic support for JWT encoding, decoding and signature verification.
+ </notes>
+ <contents>
+ <dir baseinstalldir="/" name="/">
+ <dir name="tests">
+ <file name="JWTTest.php" role="test" />
+ </dir>
+ <file name="Authentication/JWT.php" role="php" />
+ </dir>
+ </contents>
+ <dependencies>
+ <required>
+ <php>
+ <min>5.1</min>
+ </php>
+ <pearinstaller>
+ <min>1.7.0</min>
+ </pearinstaller>
+ <extension>
+ <name>json</name>
+ </extension>
+ <extension>
+ <name>hash</name>
+ </extension>
+ </required>
+ </dependencies>
+ <phprelease />
+ <changelog>
+ <release>
+ <version>
+ <release>0.1.0</release>
+ <api>0.1.0</api>
+ </version>
+ <stability>
+ <release>beta</release>
+ <api>beta</api>
+ </stability>
+ <date>2015-04-01</date>
+ <license uri="http://opensource.org/licenses/BSD-3-Clause">BSD 3-Clause License</license>
+ <notes>
+Initial release with basic support for JWT encoding, decoding and signature verification.
+ </notes>
+ </release>
+ </changelog>
+</package>
diff --git a/vendor/firebase/php-jwt/phpunit.xml.dist b/vendor/firebase/php-jwt/phpunit.xml.dist
new file mode 100644
index 00000000..9f85f5ba
--- /dev/null
+++ b/vendor/firebase/php-jwt/phpunit.xml.dist
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<phpunit backupGlobals="false"
+ backupStaticAttributes="false"
+ colors="true"
+ convertErrorsToExceptions="true"
+ convertNoticesToExceptions="true"
+ convertWarningsToExceptions="true"
+ processIsolation="false"
+ stopOnFailure="false"
+ syntaxCheck="false"
+ bootstrap="tests/bootstrap.php"
+>
+ <testsuites>
+ <testsuite name="PHP JSON Web Token Test Suite">
+ <directory>./tests</directory>
+ </testsuite>
+ </testsuites>
+</phpunit>
diff --git a/vendor/firebase/php-jwt/run-tests.sh b/vendor/firebase/php-jwt/run-tests.sh
new file mode 100644
index 00000000..d37c30fd
--- /dev/null
+++ b/vendor/firebase/php-jwt/run-tests.sh
@@ -0,0 +1,38 @@
+
+#!/usr/bin/env bash
+gpg --fingerprint D8406D0D82947747293778314AA394086372C20A
+if [ $? -ne 0 ]; then
+ echo -e "\033[33mDownloading PGP Public Key...\033[0m"
+ gpg --recv-keys D8406D0D82947747293778314AA394086372C20A
+ # Sebastian Bergmann <sb@sebastian-bergmann.de>
+ gpg --fingerprint D8406D0D82947747293778314AA394086372C20A
+ if [ $? -ne 0 ]; then
+ echo -e "\033[31mCould not download PGP public key for verification\033[0m"
+ exit
+ fi
+fi
+
+# Let's grab the latest release and its signature
+if [ ! -f phpunit.phar ]; then
+ wget https://phar.phpunit.de/phpunit.phar
+fi
+if [ ! -f phpunit.phar.asc ]; then
+ wget https://phar.phpunit.de/phpunit.phar.asc
+fi
+
+# Verify before running
+gpg --verify phpunit.phar.asc phpunit.phar
+if [ $? -eq 0 ]; then
+ echo
+ echo -e "\033[33mBegin Unit Testing\033[0m"
+ # Run the testing suite
+ php --version
+ php phpunit.phar --configuration phpunit.xml.dist
+else
+ echo
+ chmod -x phpunit.phar
+ mv phpunit.phar /tmp/bad-phpunit.phar
+ mv phpunit.phar.asc /tmp/bad-phpunit.phar.asc
+ echo -e "\033[31mSignature did not match! PHPUnit has been moved to /tmp/bad-phpunit.phar\033[0m"
+ exit 1
+fi
diff --git a/vendor/firebase/php-jwt/tests/JWTTest.php b/vendor/firebase/php-jwt/tests/JWTTest.php
new file mode 100644
index 00000000..0605e4ca
--- /dev/null
+++ b/vendor/firebase/php-jwt/tests/JWTTest.php
@@ -0,0 +1,231 @@
+<?php
+
+class JWTTest extends PHPUnit_Framework_TestCase
+{
+ public function testEncodeDecode()
+ {
+ $msg = JWT::encode('abc', 'my_key');
+ $this->assertEquals(JWT::decode($msg, 'my_key', array('HS256')), 'abc');
+ }
+
+ public function testDecodeFromPython()
+ {
+ $msg = 'eyJhbGciOiAiSFMyNTYiLCAidHlwIjogIkpXVCJ9.Iio6aHR0cDovL2FwcGxpY2F0aW9uL2NsaWNreT9ibGFoPTEuMjMmZi5vbz00NTYgQUMwMDAgMTIzIg.E_U8X2YpMT5K1cEiT_3-IvBYfrdIFIeVYeOqre_Z5Cg';
+ $this->assertEquals(
+ JWT::decode($msg, 'my_key', array('HS256')),
+ '*:http://application/clicky?blah=1.23&f.oo=456 AC000 123'
+ );
+ }
+
+ public function testUrlSafeCharacters()
+ {
+ $encoded = JWT::encode('f?', 'a');
+ $this->assertEquals('f?', JWT::decode($encoded, 'a', array('HS256')));
+ }
+
+ public function testMalformedUtf8StringsFail()
+ {
+ $this->setExpectedException('DomainException');
+ JWT::encode(pack('c', 128), 'a');
+ }
+
+ public function testMalformedJsonThrowsException()
+ {
+ $this->setExpectedException('DomainException');
+ JWT::jsonDecode('this is not valid JSON string');
+ }
+
+ public function testExpiredToken()
+ {
+ $this->setExpectedException('ExpiredException');
+ $payload = array(
+ "message" => "abc",
+ "exp" => time() - 20); // time in the past
+ $encoded = JWT::encode($payload, 'my_key');
+ JWT::decode($encoded, 'my_key', array('HS256'));
+ }
+
+ public function testBeforeValidTokenWithNbf()
+ {
+ $this->setExpectedException('BeforeValidException');
+ $payload = array(
+ "message" => "abc",
+ "nbf" => time() + 20); // time in the future
+ $encoded = JWT::encode($payload, 'my_key');
+ JWT::decode($encoded, 'my_key', array('HS256'));
+ }
+
+ public function testBeforeValidTokenWithIat()
+ {
+ $this->setExpectedException('BeforeValidException');
+ $payload = array(
+ "message" => "abc",
+ "iat" => time() + 20); // time in the future
+ $encoded = JWT::encode($payload, 'my_key');
+ JWT::decode($encoded, 'my_key', array('HS256'));
+ }
+
+ public function testValidToken()
+ {
+ $payload = array(
+ "message" => "abc",
+ "exp" => time() + JWT::$leeway + 20); // time in the future
+ $encoded = JWT::encode($payload, 'my_key');
+ $decoded = JWT::decode($encoded, 'my_key', array('HS256'));
+ $this->assertEquals($decoded->message, 'abc');
+ }
+
+ public function testValidTokenWithLeeway()
+ {
+ JWT::$leeway = 60;
+ $payload = array(
+ "message" => "abc",
+ "exp" => time() - 20); // time in the past
+ $encoded = JWT::encode($payload, 'my_key');
+ $decoded = JWT::decode($encoded, 'my_key', array('HS256'));
+ $this->assertEquals($decoded->message, 'abc');
+ JWT::$leeway = 0;
+ }
+
+ public function testExpiredTokenWithLeeway()
+ {
+ JWT::$leeway = 60;
+ $payload = array(
+ "message" => "abc",
+ "exp" => time() - 70); // time far in the past
+ $this->setExpectedException('ExpiredException');
+ $encoded = JWT::encode($payload, 'my_key');
+ $decoded = JWT::decode($encoded, 'my_key', array('HS256'));
+ $this->assertEquals($decoded->message, 'abc');
+ JWT::$leeway = 0;
+ }
+
+ public function testValidTokenWithList()
+ {
+ $payload = array(
+ "message" => "abc",
+ "exp" => time() + 20); // time in the future
+ $encoded = JWT::encode($payload, 'my_key');
+ $decoded = JWT::decode($encoded, 'my_key', array('HS256', 'HS512'));
+ $this->assertEquals($decoded->message, 'abc');
+ }
+
+ public function testValidTokenWithNbf()
+ {
+ $payload = array(
+ "message" => "abc",
+ "iat" => time(),
+ "exp" => time() + 20, // time in the future
+ "nbf" => time() - 20);
+ $encoded = JWT::encode($payload, 'my_key');
+ $decoded = JWT::decode($encoded, 'my_key', array('HS256'));
+ $this->assertEquals($decoded->message, 'abc');
+ }
+
+ public function testValidTokenWithNbfLeeway()
+ {
+ JWT::$leeway = 60;
+ $payload = array(
+ "message" => "abc",
+ "nbf" => time() + 20); // not before in near (leeway) future
+ $encoded = JWT::encode($payload, 'my_key');
+ $decoded = JWT::decode($encoded, 'my_key', array('HS256'));
+ $this->assertEquals($decoded->message, 'abc');
+ JWT::$leeway = 0;
+ }
+
+ public function testInvalidTokenWithNbfLeeway()
+ {
+ JWT::$leeway = 60;
+ $payload = array(
+ "message" => "abc",
+ "nbf" => time() + 65); // not before too far in future
+ $encoded = JWT::encode($payload, 'my_key');
+ $this->setExpectedException('BeforeValidException');
+ $decoded = JWT::decode($encoded, 'my_key', array('HS256'));
+ JWT::$leeway = 0;
+ }
+
+ public function testValidTokenWithIatLeeway()
+ {
+ JWT::$leeway = 60;
+ $payload = array(
+ "message" => "abc",
+ "iat" => time() + 20); // issued in near (leeway) future
+ $encoded = JWT::encode($payload, 'my_key');
+ $decoded = JWT::decode($encoded, 'my_key', array('HS256'));
+ $this->assertEquals($decoded->message, 'abc');
+ JWT::$leeway = 0;
+ }
+
+ public function testInvalidTokenWithIatLeeway()
+ {
+ JWT::$leeway = 60;
+ $payload = array(
+ "message" => "abc",
+ "iat" => time() + 65); // issued too far in future
+ $encoded = JWT::encode($payload, 'my_key');
+ $this->setExpectedException('BeforeValidException');
+ $decoded = JWT::decode($encoded, 'my_key', array('HS256'));
+ JWT::$leeway = 0;
+ }
+
+ public function testInvalidToken()
+ {
+ $payload = array(
+ "message" => "abc",
+ "exp" => time() + 20); // time in the future
+ $encoded = JWT::encode($payload, 'my_key');
+ $this->setExpectedException('SignatureInvalidException');
+ $decoded = JWT::decode($encoded, 'my_key2', array('HS256'));
+ }
+
+ public function testRSEncodeDecode()
+ {
+ $privKey = openssl_pkey_new(array('digest_alg' => 'sha256',
+ 'private_key_bits' => 1024,
+ 'private_key_type' => OPENSSL_KEYTYPE_RSA));
+ $msg = JWT::encode('abc', $privKey, 'RS256');
+ $pubKey = openssl_pkey_get_details($privKey);
+ $pubKey = $pubKey['key'];
+ $decoded = JWT::decode($msg, $pubKey, array('RS256'));
+ $this->assertEquals($decoded, 'abc');
+ }
+
+ public function testKIDChooser()
+ {
+ $keys = array('1' => 'my_key', '2' => 'my_key2');
+ $msg = JWT::encode('abc', $keys['1'], 'HS256', '1');
+ $decoded = JWT::decode($msg, $keys, array('HS256'));
+ $this->assertEquals($decoded, 'abc');
+ }
+
+ public function testArrayAccessKIDChooser()
+ {
+ $keys = new ArrayObject(array('1' => 'my_key', '2' => 'my_key2'));
+ $msg = JWT::encode('abc', $keys['1'], 'HS256', '1');
+ $decoded = JWT::decode($msg, $keys, array('HS256'));
+ $this->assertEquals($decoded, 'abc');
+ }
+
+ public function testNoneAlgorithm()
+ {
+ $msg = JWT::encode('abc', 'my_key');
+ $this->setExpectedException('DomainException');
+ JWT::decode($msg, 'my_key', array('none'));
+ }
+
+ public function testIncorrectAlgorithm()
+ {
+ $msg = JWT::encode('abc', 'my_key');
+ $this->setExpectedException('DomainException');
+ JWT::decode($msg, 'my_key', array('RS256'));
+ }
+
+ public function testMissingAlgorithm()
+ {
+ $msg = JWT::encode('abc', 'my_key');
+ $this->setExpectedException('DomainException');
+ JWT::decode($msg, 'my_key');
+ }
+}
diff --git a/vendor/firebase/php-jwt/tests/autoload.php.dist b/vendor/firebase/php-jwt/tests/autoload.php.dist
new file mode 100644
index 00000000..2e4310a0
--- /dev/null
+++ b/vendor/firebase/php-jwt/tests/autoload.php.dist
@@ -0,0 +1,17 @@
+<?php
+
+// if the library is the project, try to use the composer's autoload for the tests
+$composerAutoload = __DIR__ . '/../vendor/autoload.php';
+
+if (is_file($composerAutoload)) {
+ include $composerAutoload;
+} else {
+ die('Unable to find autoload.php file, please use composer to load dependencies:
+
+wget http://getcomposer.org/composer.phar
+php composer.phar install
+
+Visit http://getcomposer.org/ for more information.
+
+');
+}
diff --git a/vendor/firebase/php-jwt/tests/bootstrap.php b/vendor/firebase/php-jwt/tests/bootstrap.php
new file mode 100644
index 00000000..326c2166
--- /dev/null
+++ b/vendor/firebase/php-jwt/tests/bootstrap.php
@@ -0,0 +1,7 @@
+<?php
+
+if (file_exists($file = __DIR__ . '/autoload.php')) {
+ require_once $file;
+} elseif (file_exists($file = __DIR__ . '/autoload.php.dist')) {
+ require_once $file;
+}
diff --git a/vendor/kzykhys/pygments/README.md b/vendor/kzykhys/pygments/README.md
new file mode 100644
index 00000000..64ead7c7
--- /dev/null
+++ b/vendor/kzykhys/pygments/README.md
@@ -0,0 +1,99 @@
+Pygments.php - A Thin Wrapper for the Python Pygments
+=====================================================
+
+[![Latest Stable Version](https://poser.pugx.org/kzykhys/pygments/v/stable.png)](https://packagist.org/packages/kzykhys/pygments)
+[![Build Status](https://travis-ci.org/kzykhys/Pygments.php.png?branch=master)](https://travis-ci.org/kzykhys/Pygments.php)
+[![Coverage Status](https://coveralls.io/repos/kzykhys/Pygments.php/badge.png)](https://coveralls.io/r/kzykhys/Pygments.php)
+
+A PHP wrapper for the Python Pygments syntax highlighter
+
+Requirements
+------------
+
+* PHP5.3+
+* Python 2.4+
+* Pygments (`sudo easy_install Pygments`)
+
+Installation
+------------
+
+Create or update your composer.json and run `composer update`
+
+``` json
+{
+ "require": {
+ "kzykhys/pygments": ">=1.0"
+ }
+}
+```
+
+Usage
+-----
+
+### Highlight the source code
+
+``` php
+<?php
+
+use KzykHys\Pygments\Pygments;
+
+$pygments = new Pygments();
+$html = $pygments->highlight(file_get_contents('index.php'), 'php', 'html');
+$text = $pygments->highlight('package main', 'go', 'ansi');
+```
+
+### Generate a CSS
+
+``` php
+<?php
+
+use KzykHys\Pygments\Pygments;
+
+$pygments = new Pygments();
+$css = $pygments->getCss('monokai');
+$prefixedCss = $pygments->getCss('default', '.syntax');
+```
+
+### Guesses a lexer name
+
+``` php
+<?php
+
+use KzykHys\Pygments\Pygments;
+
+$pygments = new Pygments();
+$pygments->guessLexer('foo.rb'); // ruby
+```
+
+### Get a list of lexers/formatters/styles
+
+``` php
+<?php
+
+use KzykHys\Pygments\Pygments;
+
+$pygments = new Pygments();
+$pygments->getLexers()
+$pygments->getFormatters();
+$pygments->getStyles();
+```
+
+### Custom `pygmentize` path
+
+``` php
+<?php
+
+use KzykHys\Pygments\Pygments;
+
+$pygments = new Pygments('/path/to/pygmentize');
+```
+
+License
+-------
+
+The MIT License
+
+Author
+------
+
+Kazuyuki Hayashi (@kzykhys) \ No newline at end of file
diff --git a/vendor/kzykhys/pygments/composer.json b/vendor/kzykhys/pygments/composer.json
new file mode 100644
index 00000000..e9809a48
--- /dev/null
+++ b/vendor/kzykhys/pygments/composer.json
@@ -0,0 +1,17 @@
+{
+ "name": "kzykhys/pygments",
+ "description": "A Thin Wrapper for the Python Pygments",
+ "minimum-stability": "stable",
+ "require": {
+ "php": ">=5.3.2",
+ "symfony/process": ">=2.3"
+ },
+ "require-dev": {
+ "symfony/finder": ">=2.3"
+ },
+ "autoload": {
+ "psr-0": {
+ "": "src"
+ }
+ }
+} \ No newline at end of file
diff --git a/vendor/kzykhys/pygments/composer.lock b/vendor/kzykhys/pygments/composer.lock
new file mode 100644
index 00000000..fa031822
--- /dev/null
+++ b/vendor/kzykhys/pygments/composer.lock
@@ -0,0 +1,118 @@
+{
+ "_readme": [
+ "This file locks the dependencies of your project to a known state",
+ "Read more about it at http://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file"
+ ],
+ "hash": "d2e111fb167611c09ab96baa0504b60b",
+ "packages": [
+ {
+ "name": "symfony/process",
+ "version": "v2.4.0",
+ "target-dir": "Symfony/Component/Process",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/Process.git",
+ "reference": "87738ff42e2467730ed74d941866e95513844b70"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/Process/zipball/87738ff42e2467730ed74d941866e95513844b70",
+ "reference": "87738ff42e2467730ed74d941866e95513844b70",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.3.3"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "2.4-dev"
+ }
+ },
+ "autoload": {
+ "psr-0": {
+ "Symfony\\Component\\Process\\": ""
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Fabien Potencier",
+ "email": "fabien@symfony.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "http://symfony.com/contributors"
+ }
+ ],
+ "description": "Symfony Process Component",
+ "homepage": "http://symfony.com",
+ "time": "2013-11-26 16:40:27"
+ }
+ ],
+ "packages-dev": [
+ {
+ "name": "symfony/finder",
+ "version": "v2.4.0",
+ "target-dir": "Symfony/Component/Finder",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/Finder.git",
+ "reference": "72356bf0646b11af1bae666c28a639bd8ede459f"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/Finder/zipball/72356bf0646b11af1bae666c28a639bd8ede459f",
+ "reference": "72356bf0646b11af1bae666c28a639bd8ede459f",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.3.3"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "2.4-dev"
+ }
+ },
+ "autoload": {
+ "psr-0": {
+ "Symfony\\Component\\Finder\\": ""
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Fabien Potencier",
+ "email": "fabien@symfony.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "http://symfony.com/contributors"
+ }
+ ],
+ "description": "Symfony Finder Component",
+ "homepage": "http://symfony.com",
+ "time": "2013-11-26 16:40:27"
+ }
+ ],
+ "aliases": [
+
+ ],
+ "minimum-stability": "stable",
+ "stability-flags": [
+
+ ],
+ "platform": {
+ "php": ">=5.3.2"
+ },
+ "platform-dev": [
+
+ ]
+}
diff --git a/vendor/kzykhys/pygments/phpunit.xml.dist b/vendor/kzykhys/pygments/phpunit.xml.dist
new file mode 100644
index 00000000..ad8dd7b0
--- /dev/null
+++ b/vendor/kzykhys/pygments/phpunit.xml.dist
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!-- http://www.phpunit.de/manual/current/en/appendixes.configuration.html -->
+<phpunit
+ backupGlobals = "false"
+ backupStaticAttributes = "false"
+ colors = "true"
+ convertErrorsToExceptions = "true"
+ convertNoticesToExceptions = "true"
+ convertWarningsToExceptions = "true"
+ processIsolation = "false"
+ stopOnFailure = "false"
+ syntaxCheck = "false"
+ bootstrap = "vendor/autoload.php" >
+
+ <testsuites>
+ <testsuite name="Project Test Suite">
+ <directory>test</directory>
+ </testsuite>
+ </testsuites>
+
+ <filter>
+ <whitelist>
+ <directory>src</directory>
+ </whitelist>
+ </filter>
+
+</phpunit> \ No newline at end of file
diff --git a/vendor/kzykhys/pygments/src/KzykHys/Pygments/Pygments.php b/vendor/kzykhys/pygments/src/KzykHys/Pygments/Pygments.php
new file mode 100644
index 00000000..6ebd6522
--- /dev/null
+++ b/vendor/kzykhys/pygments/src/KzykHys/Pygments/Pygments.php
@@ -0,0 +1,200 @@
+<?php
+
+namespace KzykHys\Pygments;
+
+use Symfony\Component\Process\Process;
+use Symfony\Component\Process\ProcessBuilder;
+
+/**
+ * Pygments.php - A Thin Wrapper for the Python Pygments
+ *
+ * @author Kazuyuki Hayashi <hayashi@valnur.net>
+ */
+class Pygments
+{
+
+ /**
+ * @var string
+ */
+ private $pygmentize;
+
+ /**
+ * Constructor
+ *
+ * @param string $pygmentize The path to pygmentize command
+ */
+ public function __construct($pygmentize = 'pygmentize')
+ {
+ $this->pygmentize = $pygmentize;
+ }
+
+ /**
+ * Highlight the input code
+ *
+ * @param string $code The code to highlight
+ * @param string $lexer The name of the lexer (php, html,...)
+ * @param string $formatter The name of the formatter (html, ansi,...)
+ * @param array $options An array of options
+ *
+ * @return string
+ */
+ public function highlight($code, $lexer = null, $formatter = null, $options = array())
+ {
+ $builder = $this->createProcessBuilder();
+
+ if ($lexer) {
+ $builder->add('-l')->add($lexer);
+ } else {
+ $builder->add('-g');
+ }
+
+ if ($formatter) {
+ $builder->add('-f')->add($formatter);
+ }
+
+ if (count($options)) {
+ $arg = array();
+
+ foreach ($options as $key => $value) {
+ $arg[] = sprintf('%s=%s', $key, $value);
+ }
+
+ $builder->add('-O')->add(implode(',', $arg));
+ }
+
+ $process = $builder->getProcess()->setStdin($code);
+
+ return $this->getOutput($process);
+ }
+
+ /**
+ * Gets style definition
+ *
+ * @param string $style The name of the style (default, colorful,...)
+ * @param string $selector The css selector
+ *
+ * @return string
+ */
+ public function getCss($style = 'default', $selector = null)
+ {
+ $builder = $this->createProcessBuilder();
+ $builder->add('-f')->add('html');
+ $builder->add('-S')->add($style);
+
+ if ($selector) {
+ $builder->add('-a')->add($selector);
+ }
+
+ return $this->getOutput($builder->getProcess());
+ }
+
+ /**
+ * Guesses a lexer name based solely on the given filename
+ *
+ * @param string $fileName The file does not need to exist, or be readable.
+ *
+ * @return string
+ */
+ public function guessLexer($fileName)
+ {
+ $process = $this->createProcessBuilder()
+ ->setArguments(array('-N', $fileName))
+ ->getProcess();
+
+ return trim($this->getOutput($process));
+ }
+
+ /**
+ * Gets a list of lexers
+ *
+ * @return array
+ */
+ public function getLexers()
+ {
+ $process = $this->createProcessBuilder()
+ ->setArguments(array('-L', 'lexer'))
+ ->getProcess();
+
+ $output = $this->getOutput($process);
+
+ return $this->parseList($output);
+ }
+
+ /**
+ * Gets a list of formatters
+ *
+ * @return array
+ */
+ public function getFormatters()
+ {
+ $process = $this->createProcessBuilder()
+ ->setArguments(array('-L', 'formatter'))
+ ->getProcess();
+
+ $output = $this->getOutput($process);
+
+ return $this->parseList($output);
+ }
+
+ /**
+ * Gets a list of styles
+ *
+ * @return array
+ */
+ public function getStyles()
+ {
+ $process = $this->createProcessBuilder()
+ ->setArguments(array('-L', 'style'))
+ ->getProcess();
+
+ $output = $this->getOutput($process);
+
+ return $this->parseList($output);
+ }
+
+ /**
+ * @return ProcessBuilder
+ */
+ protected function createProcessBuilder()
+ {
+ return ProcessBuilder::create()->setPrefix($this->pygmentize);
+ }
+
+ /**
+ * @param Process $process
+ * @throws \RuntimeException
+ * @return string
+ */
+ protected function getOutput(Process $process)
+ {
+ $process->run();
+
+ if (!$process->isSuccessful()) {
+ throw new \RuntimeException($process->getErrorOutput());
+ }
+
+ return $process->getOutput();
+ }
+
+ /**
+ * @param string $input
+ * @return array
+ */
+ protected function parseList($input)
+ {
+ $list = array();
+
+ if (preg_match_all('/^\* (.*?):\r?\n *([^\r\n]*?)$/m', $input, $matches, PREG_SET_ORDER)) {
+ foreach ($matches as $match) {
+ $names = explode(',', $match[1]);
+
+ foreach ($names as $name) {
+ $list[trim($name)] = $match[2];
+ }
+ }
+ }
+
+ return $list;
+ }
+
+} \ No newline at end of file
diff --git a/vendor/kzykhys/pygments/test/KzykHys/Pygments/PygmentsTest.php b/vendor/kzykhys/pygments/test/KzykHys/Pygments/PygmentsTest.php
new file mode 100644
index 00000000..2110e0d8
--- /dev/null
+++ b/vendor/kzykhys/pygments/test/KzykHys/Pygments/PygmentsTest.php
@@ -0,0 +1,116 @@
+<?php
+
+use KzykHys\Pygments\Pygments;
+use Symfony\Component\Finder\Finder;
+
+/**
+ * @author Kazuyuki Hayashi <hayashi@valnur.net>
+ */
+class PygmentsTest extends PHPUnit_Framework_TestCase
+{
+
+ /**
+ * @dataProvider provideSamples
+ */
+ public function testHighlight($input, $expected, $expectedL, $lexer)
+ {
+ $pygments = new Pygments();
+
+ $this->assertEquals($expected, $pygments->highlight($input, null, 'html'));
+ $this->assertEquals($expected, $pygments->highlight($input, $lexer, 'html'));
+ $this->assertEquals($expectedL, $pygments->highlight($input, null, 'html', array('linenos' => 1)));
+ }
+
+ /**
+ * @dataProvider provideCss
+ */
+ public function testGetCss($expected, $expectedA, $style)
+ {
+ $pygments = new Pygments();
+
+ $this->assertEquals($expected, $pygments->getCss($style));
+ $this->assertEquals($expectedA, $pygments->getCss($style, '.syntax'));
+ }
+
+ public function testGetLexers()
+ {
+ $pygments = new Pygments();
+ $lexers = $pygments->getLexers();
+
+ $this->assertArrayHasKey('python', $lexers);
+ }
+
+ public function testGetFormatters()
+ {
+ $pygments = new Pygments();
+ $formatters = $pygments->getFormatters();
+
+ $this->assertArrayHasKey('html', $formatters);
+ }
+
+ public function testGetStyles()
+ {
+ $pygments = new Pygments();
+ $styles = $pygments->getStyles();
+
+ $this->assertArrayHasKey('monokai', $styles);
+ }
+
+ public function testGuessLexer()
+ {
+ $pygments = new Pygments();
+
+ $this->assertEquals('php', $pygments->guessLexer('index.php'));
+ $this->assertEquals('go', $pygments->guessLexer('main.go'));
+ }
+
+ public function provideSamples()
+ {
+ $finder = new Finder();
+ $finder
+ ->in(__DIR__ . '/Resources/example')
+ ->name("*.in")
+ ->notName('*.linenos.out')
+ ->files()
+ ->ignoreVCS(true);
+
+ $samples = array();
+
+ /* @var \Symfony\Component\Finder\SplFileInfo $file */
+ foreach ($finder as $file) {
+ $samples[] = array(
+ $file->getContents(),
+ file_get_contents(str_replace('.in', '.out', $file->getPathname())),
+ file_get_contents(str_replace('.in', '.linenos.out', $file->getPathname())),
+ preg_replace('/\..*/', '', $file->getFilename())
+ );
+ }
+
+ return $samples;
+ }
+
+ public function provideCss()
+ {
+ $finder = new Finder();
+ $finder
+ ->in(__DIR__ . '/Resources/css')
+ ->files()
+ ->ignoreVCS(true)
+ ->name('*.css')
+ ->notName('*.prefix.css');
+
+ $css = array();
+
+ /* @var \Symfony\Component\Finder\SplFileInfo $file */
+ foreach ($finder as $file) {
+ $css[] = array(
+ $file->getContents(),
+ file_get_contents(str_replace('.css', '.prefix.css', $file->getPathname())),
+ str_replace('.css', '', $file->getFilename())
+ );
+ }
+
+ return $css;
+ }
+
+} \ No newline at end of file
diff --git a/vendor/kzykhys/pygments/test/KzykHys/Pygments/Resources/css/default.css b/vendor/kzykhys/pygments/test/KzykHys/Pygments/Resources/css/default.css
new file mode 100644
index 00000000..67e6ea39
--- /dev/null
+++ b/vendor/kzykhys/pygments/test/KzykHys/Pygments/Resources/css/default.css
@@ -0,0 +1,61 @@
+.hll { background-color: #ffffcc }
+.c { color: #408080; font-style: italic } /* Comment */
+.err { border: 1px solid #FF0000 } /* Error */
+.k { color: #008000; font-weight: bold } /* Keyword */
+.o { color: #666666 } /* Operator */
+.cm { color: #408080; font-style: italic } /* Comment.Multiline */
+.cp { color: #BC7A00 } /* Comment.Preproc */
+.c1 { color: #408080; font-style: italic } /* Comment.Single */
+.cs { color: #408080; font-style: italic } /* Comment.Special */
+.gd { color: #A00000 } /* Generic.Deleted */
+.ge { font-style: italic } /* Generic.Emph */
+.gr { color: #FF0000 } /* Generic.Error */
+.gh { color: #000080; font-weight: bold } /* Generic.Heading */
+.gi { color: #00A000 } /* Generic.Inserted */
+.go { color: #888888 } /* Generic.Output */
+.gp { color: #000080; font-weight: bold } /* Generic.Prompt */
+.gs { font-weight: bold } /* Generic.Strong */
+.gu { color: #800080; font-weight: bold } /* Generic.Subheading */
+.gt { color: #0044DD } /* Generic.Traceback */
+.kc { color: #008000; font-weight: bold } /* Keyword.Constant */
+.kd { color: #008000; font-weight: bold } /* Keyword.Declaration */
+.kn { color: #008000; font-weight: bold } /* Keyword.Namespace */
+.kp { color: #008000 } /* Keyword.Pseudo */
+.kr { color: #008000; font-weight: bold } /* Keyword.Reserved */
+.kt { color: #B00040 } /* Keyword.Type */
+.m { color: #666666 } /* Literal.Number */
+.s { color: #BA2121 } /* Literal.String */
+.na { color: #7D9029 } /* Name.Attribute */
+.nb { color: #008000 } /* Name.Builtin */
+.nc { color: #0000FF; font-weight: bold } /* Name.Class */
+.no { color: #880000 } /* Name.Constant */
+.nd { color: #AA22FF } /* Name.Decorator */
+.ni { color: #999999; font-weight: bold } /* Name.Entity */
+.ne { color: #D2413A; font-weight: bold } /* Name.Exception */
+.nf { color: #0000FF } /* Name.Function */
+.nl { color: #A0A000 } /* Name.Label */
+.nn { color: #0000FF; font-weight: bold } /* Name.Namespace */
+.nt { color: #008000; font-weight: bold } /* Name.Tag */
+.nv { color: #19177C } /* Name.Variable */
+.ow { color: #AA22FF; font-weight: bold } /* Operator.Word */
+.w { color: #bbbbbb } /* Text.Whitespace */
+.mf { color: #666666 } /* Literal.Number.Float */
+.mh { color: #666666 } /* Literal.Number.Hex */
+.mi { color: #666666 } /* Literal.Number.Integer */
+.mo { color: #666666 } /* Literal.Number.Oct */
+.sb { color: #BA2121 } /* Literal.String.Backtick */
+.sc { color: #BA2121 } /* Literal.String.Char */
+.sd { color: #BA2121; font-style: italic } /* Literal.String.Doc */
+.s2 { color: #BA2121 } /* Literal.String.Double */
+.se { color: #BB6622; font-weight: bold } /* Literal.String.Escape */
+.sh { color: #BA2121 } /* Literal.String.Heredoc */
+.si { color: #BB6688; font-weight: bold } /* Literal.String.Interpol */
+.sx { color: #008000 } /* Literal.String.Other */
+.sr { color: #BB6688 } /* Literal.String.Regex */
+.s1 { color: #BA2121 } /* Literal.String.Single */
+.ss { color: #19177C } /* Literal.String.Symbol */
+.bp { color: #008000 } /* Name.Builtin.Pseudo */
+.vc { color: #19177C } /* Name.Variable.Class */
+.vg { color: #19177C } /* Name.Variable.Global */
+.vi { color: #19177C } /* Name.Variable.Instance */
+.il { color: #666666 } /* Literal.Number.Integer.Long */
diff --git a/vendor/kzykhys/pygments/test/KzykHys/Pygments/Resources/css/default.prefix.css b/vendor/kzykhys/pygments/test/KzykHys/Pygments/Resources/css/default.prefix.css
new file mode 100644
index 00000000..eb17bc3e
--- /dev/null
+++ b/vendor/kzykhys/pygments/test/KzykHys/Pygments/Resources/css/default.prefix.css
@@ -0,0 +1,62 @@
+.syntax .hll { background-color: #ffffcc }
+.syntax { background: #f8f8f8; }
+.syntax .c { color: #408080; font-style: italic } /* Comment */
+.syntax .err { border: 1px solid #FF0000 } /* Error */
+.syntax .k { color: #008000; font-weight: bold } /* Keyword */
+.syntax .o { color: #666666 } /* Operator */
+.syntax .cm { color: #408080; font-style: italic } /* Comment.Multiline */
+.syntax .cp { color: #BC7A00 } /* Comment.Preproc */
+.syntax .c1 { color: #408080; font-style: italic } /* Comment.Single */
+.syntax .cs { color: #408080; font-style: italic } /* Comment.Special */
+.syntax .gd { color: #A00000 } /* Generic.Deleted */
+.syntax .ge { font-style: italic } /* Generic.Emph */
+.syntax .gr { color: #FF0000 } /* Generic.Error */
+.syntax .gh { color: #000080; font-weight: bold } /* Generic.Heading */
+.syntax .gi { color: #00A000 } /* Generic.Inserted */
+.syntax .go { color: #888888 } /* Generic.Output */
+.syntax .gp { color: #000080; font-weight: bold } /* Generic.Prompt */
+.syntax .gs { font-weight: bold } /* Generic.Strong */
+.syntax .gu { color: #800080; font-weight: bold } /* Generic.Subheading */
+.syntax .gt { color: #0044DD } /* Generic.Traceback */
+.syntax .kc { color: #008000; font-weight: bold } /* Keyword.Constant */
+.syntax .kd { color: #008000; font-weight: bold } /* Keyword.Declaration */
+.syntax .kn { color: #008000; font-weight: bold } /* Keyword.Namespace */
+.syntax .kp { color: #008000 } /* Keyword.Pseudo */
+.syntax .kr { color: #008000; font-weight: bold } /* Keyword.Reserved */
+.syntax .kt { color: #B00040 } /* Keyword.Type */
+.syntax .m { color: #666666 } /* Literal.Number */
+.syntax .s { color: #BA2121 } /* Literal.String */
+.syntax .na { color: #7D9029 } /* Name.Attribute */
+.syntax .nb { color: #008000 } /* Name.Builtin */
+.syntax .nc { color: #0000FF; font-weight: bold } /* Name.Class */
+.syntax .no { color: #880000 } /* Name.Constant */
+.syntax .nd { color: #AA22FF } /* Name.Decorator */
+.syntax .ni { color: #999999; font-weight: bold } /* Name.Entity */
+.syntax .ne { color: #D2413A; font-weight: bold } /* Name.Exception */
+.syntax .nf { color: #0000FF } /* Name.Function */
+.syntax .nl { color: #A0A000 } /* Name.Label */
+.syntax .nn { color: #0000FF; font-weight: bold } /* Name.Namespace */
+.syntax .nt { color: #008000; font-weight: bold } /* Name.Tag */
+.syntax .nv { color: #19177C } /* Name.Variable */
+.syntax .ow { color: #AA22FF; font-weight: bold } /* Operator.Word */
+.syntax .w { color: #bbbbbb } /* Text.Whitespace */
+.syntax .mf { color: #666666 } /* Literal.Number.Float */
+.syntax .mh { color: #666666 } /* Literal.Number.Hex */
+.syntax .mi { color: #666666 } /* Literal.Number.Integer */
+.syntax .mo { color: #666666 } /* Literal.Number.Oct */
+.syntax .sb { color: #BA2121 } /* Literal.String.Backtick */
+.syntax .sc { color: #BA2121 } /* Literal.String.Char */
+.syntax .sd { color: #BA2121; font-style: italic } /* Literal.String.Doc */
+.syntax .s2 { color: #BA2121 } /* Literal.String.Double */
+.syntax .se { color: #BB6622; font-weight: bold } /* Literal.String.Escape */
+.syntax .sh { color: #BA2121 } /* Literal.String.Heredoc */
+.syntax .si { color: #BB6688; font-weight: bold } /* Literal.String.Interpol */
+.syntax .sx { color: #008000 } /* Literal.String.Other */
+.syntax .sr { color: #BB6688 } /* Literal.String.Regex */
+.syntax .s1 { color: #BA2121 } /* Literal.String.Single */
+.syntax .ss { color: #19177C } /* Literal.String.Symbol */
+.syntax .bp { color: #008000 } /* Name.Builtin.Pseudo */
+.syntax .vc { color: #19177C } /* Name.Variable.Class */
+.syntax .vg { color: #19177C } /* Name.Variable.Global */
+.syntax .vi { color: #19177C } /* Name.Variable.Instance */
+.syntax .il { color: #666666 } /* Literal.Number.Integer.Long */
diff --git a/vendor/kzykhys/pygments/test/KzykHys/Pygments/Resources/example/php.php.in b/vendor/kzykhys/pygments/test/KzykHys/Pygments/Resources/example/php.php.in
new file mode 100644
index 00000000..b5d94041
--- /dev/null
+++ b/vendor/kzykhys/pygments/test/KzykHys/Pygments/Resources/example/php.php.in
@@ -0,0 +1,21 @@
+<?php
+
+class Foo
+{
+ const TEST_CONST = 1;
+
+ public static $staticProperty = null;
+
+ public $property = null;
+
+ public static function staticMethod()
+ {
+ return new static();
+ }
+
+ public function method()
+ {
+ return $this;
+ }
+
+} \ No newline at end of file
diff --git a/vendor/kzykhys/pygments/test/KzykHys/Pygments/Resources/example/php.php.linenos.out b/vendor/kzykhys/pygments/test/KzykHys/Pygments/Resources/example/php.php.linenos.out
new file mode 100644
index 00000000..c646cc9d
--- /dev/null
+++ b/vendor/kzykhys/pygments/test/KzykHys/Pygments/Resources/example/php.php.linenos.out
@@ -0,0 +1,43 @@
+<table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre> 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21</pre></div></td><td class="code"><div class="highlight"><pre><span class="cp">&lt;?php</span>
+
+<span class="k">class</span> <span class="nc">Foo</span>
+<span class="p">{</span>
+ <span class="k">const</span> <span class="no">TEST_CONST</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>
+
+ <span class="k">public</span> <span class="k">static</span> <span class="nv">$staticProperty</span> <span class="o">=</span> <span class="k">null</span><span class="p">;</span>
+
+ <span class="k">public</span> <span class="nv">$property</span> <span class="o">=</span> <span class="k">null</span><span class="p">;</span>
+
+ <span class="k">public</span> <span class="k">static</span> <span class="k">function</span> <span class="nf">staticMethod</span><span class="p">()</span>
+ <span class="p">{</span>
+ <span class="k">return</span> <span class="k">new</span> <span class="k">static</span><span class="p">();</span>
+ <span class="p">}</span>
+
+ <span class="k">public</span> <span class="k">function</span> <span class="nf">method</span><span class="p">()</span>
+ <span class="p">{</span>
+ <span class="k">return</span> <span class="nv">$this</span><span class="p">;</span>
+ <span class="p">}</span>
+
+<span class="p">}</span>
+</pre></div>
+</td></tr></table> \ No newline at end of file
diff --git a/vendor/kzykhys/pygments/test/KzykHys/Pygments/Resources/example/php.php.out b/vendor/kzykhys/pygments/test/KzykHys/Pygments/Resources/example/php.php.out
new file mode 100644
index 00000000..c5e907f1
--- /dev/null
+++ b/vendor/kzykhys/pygments/test/KzykHys/Pygments/Resources/example/php.php.out
@@ -0,0 +1,22 @@
+<div class="highlight"><pre><span class="cp">&lt;?php</span>
+
+<span class="k">class</span> <span class="nc">Foo</span>
+<span class="p">{</span>
+ <span class="k">const</span> <span class="no">TEST_CONST</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>
+
+ <span class="k">public</span> <span class="k">static</span> <span class="nv">$staticProperty</span> <span class="o">=</span> <span class="k">null</span><span class="p">;</span>
+
+ <span class="k">public</span> <span class="nv">$property</span> <span class="o">=</span> <span class="k">null</span><span class="p">;</span>
+
+ <span class="k">public</span> <span class="k">static</span> <span class="k">function</span> <span class="nf">staticMethod</span><span class="p">()</span>
+ <span class="p">{</span>
+ <span class="k">return</span> <span class="k">new</span> <span class="k">static</span><span class="p">();</span>
+ <span class="p">}</span>
+
+ <span class="k">public</span> <span class="k">function</span> <span class="nf">method</span><span class="p">()</span>
+ <span class="p">{</span>
+ <span class="k">return</span> <span class="nv">$this</span><span class="p">;</span>
+ <span class="p">}</span>
+
+<span class="p">}</span>
+</pre></div>
diff --git a/vendor/leafo/lessphp/LICENSE b/vendor/leafo/lessphp/LICENSE
deleted file mode 100644
index 49c9ea41..00000000
--- a/vendor/leafo/lessphp/LICENSE
+++ /dev/null
@@ -1,660 +0,0 @@
-For ease of distribution, lessphp 0.4.0 is under a dual license.
-You are free to pick which one suits your needs.
-
-
-
-
-MIT LICENSE
-
-
-
-
-Copyright (c) 2013 Leaf Corcoran, http://leafo.net/lessphp
-
-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.
-
-
-
-
-GPL VERSION 3
-
-
-
-
- GNU GENERAL PUBLIC LICENSE
- Version 3, 29 June 2007
-
- Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
- Everyone is permitted to copy and distribute verbatim copies
- of this license document, but changing it is not allowed.
-
- Preamble
-
- The GNU General Public License is a free, copyleft license for
-software and other kinds of works.
-
- The licenses for most software and other practical works are designed
-to take away your freedom to share and change the works. By contrast,
-the GNU General Public License is intended to guarantee your freedom to
-share and change all versions of a program--to make sure it remains free
-software for all its users. We, the Free Software Foundation, use the
-GNU General Public License for most of our software; it applies also to
-any other work released this way by its authors. You can apply it to
-your programs, too.
-
- When we speak of free software, we are referring to freedom, not
-price. Our General Public Licenses are designed to make sure that you
-have the freedom to distribute copies of free software (and charge for
-them if you wish), that you receive source code or can get it if you
-want it, that you can change the software or use pieces of it in new
-free programs, and that you know you can do these things.
-
- To protect your rights, we need to prevent others from denying you
-these rights or asking you to surrender the rights. Therefore, you have
-certain responsibilities if you distribute copies of the software, or if
-you modify it: responsibilities to respect the freedom of others.
-
- For example, if you distribute copies of such a program, whether
-gratis or for a fee, you must pass on to the recipients the same
-freedoms that you received. You must make sure that they, too, receive
-or can get the source code. And you must show them these terms so they
-know their rights.
-
- Developers that use the GNU GPL protect your rights with two steps:
-(1) assert copyright on the software, and (2) offer you this License
-giving you legal permission to copy, distribute and/or modify it.
-
- For the developers' and authors' protection, the GPL clearly explains
-that there is no warranty for this free software. For both users' and
-authors' sake, the GPL requires that modified versions be marked as
-changed, so that their problems will not be attributed erroneously to
-authors of previous versions.
-
- Some devices are designed to deny users access to install or run
-modified versions of the software inside them, although the manufacturer
-can do so. This is fundamentally incompatible with the aim of
-protecting users' freedom to change the software. The systematic
-pattern of such abuse occurs in the area of products for individuals to
-use, which is precisely where it is most unacceptable. Therefore, we
-have designed this version of the GPL to prohibit the practice for those
-products. If such problems arise substantially in other domains, we
-stand ready to extend this provision to those domains in future versions
-of the GPL, as needed to protect the freedom of users.
-
- Finally, every program is threatened constantly by software patents.
-States should not allow patents to restrict development and use of
-software on general-purpose computers, but in those that do, we wish to
-avoid the special danger that patents applied to a free program could
-make it effectively proprietary. To prevent this, the GPL assures that
-patents cannot be used to render the program non-free.
-
- The precise terms and conditions for copying, distribution and
-modification follow.
-
- TERMS AND CONDITIONS
-
- 0. Definitions.
-
- "This License" refers to version 3 of the GNU General Public License.
-
- "Copyright" also means copyright-like laws that apply to other kinds of
-works, such as semiconductor masks.
-
- "The Program" refers to any copyrightable work licensed under this
-License. Each licensee is addressed as "you". "Licensees" and
-"recipients" may be individuals or organizations.
-
- To "modify" a work means to copy from or adapt all or part of the work
-in a fashion requiring copyright permission, other than the making of an
-exact copy. The resulting work is called a "modified version" of the
-earlier work or a work "based on" the earlier work.
-
- A "covered work" means either the unmodified Program or a work based
-on the Program.
-
- To "propagate" a work means to do anything with it that, without
-permission, would make you directly or secondarily liable for
-infringement under applicable copyright law, except executing it on a
-computer or modifying a private copy. Propagation includes copying,
-distribution (with or without modification), making available to the
-public, and in some countries other activities as well.
-
- To "convey" a work means any kind of propagation that enables other
-parties to make or receive copies. Mere interaction with a user through
-a computer network, with no transfer of a copy, is not conveying.
-
- An interactive user interface displays "Appropriate Legal Notices"
-to the extent that it includes a convenient and prominently visible
-feature that (1) displays an appropriate copyright notice, and (2)
-tells the user that there is no warranty for the work (except to the
-extent that warranties are provided), that licensees may convey the
-work under this License, and how to view a copy of this License. If
-the interface presents a list of user commands or options, such as a
-menu, a prominent item in the list meets this criterion.
-
- 1. Source Code.
-
- The "source code" for a work means the preferred form of the work
-for making modifications to it. "Object code" means any non-source
-form of a work.
-
- A "Standard Interface" means an interface that either is an official
-standard defined by a recognized standards body, or, in the case of
-interfaces specified for a particular programming language, one that
-is widely used among developers working in that language.
-
- The "System Libraries" of an executable work include anything, other
-than the work as a whole, that (a) is included in the normal form of
-packaging a Major Component, but which is not part of that Major
-Component, and (b) serves only to enable use of the work with that
-Major Component, or to implement a Standard Interface for which an
-implementation is available to the public in source code form. A
-"Major Component", in this context, means a major essential component
-(kernel, window system, and so on) of the specific operating system
-(if any) on which the executable work runs, or a compiler used to
-produce the work, or an object code interpreter used to run it.
-
- The "Corresponding Source" for a work in object code form means all
-the source code needed to generate, install, and (for an executable
-work) run the object code and to modify the work, including scripts to
-control those activities. However, it does not include the work's
-System Libraries, or general-purpose tools or generally available free
-programs which are used unmodified in performing those activities but
-which are not part of the work. For example, Corresponding Source
-includes interface definition files associated with source files for
-the work, and the source code for shared libraries and dynamically
-linked subprograms that the work is specifically designed to require,
-such as by intimate data communication or control flow between those
-subprograms and other parts of the work.
-
- The Corresponding Source need not include anything that users
-can regenerate automatically from other parts of the Corresponding
-Source.
-
- The Corresponding Source for a work in source code form is that
-same work.
-
- 2. Basic Permissions.
-
- All rights granted under this License are granted for the term of
-copyright on the Program, and are irrevocable provided the stated
-conditions are met. This License explicitly affirms your unlimited
-permission to run the unmodified Program. The output from running a
-covered work is covered by this License only if the output, given its
-content, constitutes a covered work. This License acknowledges your
-rights of fair use or other equivalent, as provided by copyright law.
-
- You may make, run and propagate covered works that you do not
-convey, without conditions so long as your license otherwise remains
-in force. You may convey covered works to others for the sole purpose
-of having them make modifications exclusively for you, or provide you
-with facilities for running those works, provided that you comply with
-the terms of this License in conveying all material for which you do
-not control copyright. Those thus making or running the covered works
-for you must do so exclusively on your behalf, under your direction
-and control, on terms that prohibit them from making any copies of
-your copyrighted material outside their relationship with you.
-
- Conveying under any other circumstances is permitted solely under
-the conditions stated below. Sublicensing is not allowed; section 10
-makes it unnecessary.
-
- 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
-
- No covered work shall be deemed part of an effective technological
-measure under any applicable law fulfilling obligations under article
-11 of the WIPO copyright treaty adopted on 20 December 1996, or
-similar laws prohibiting or restricting circumvention of such
-measures.
-
- When you convey a covered work, you waive any legal power to forbid
-circumvention of technological measures to the extent such circumvention
-is effected by exercising rights under this License with respect to
-the covered work, and you disclaim any intention to limit operation or
-modification of the work as a means of enforcing, against the work's
-users, your or third parties' legal rights to forbid circumvention of
-technological measures.
-
- 4. Conveying Verbatim Copies.
-
- You may convey verbatim copies of the Program's source code as you
-receive it, in any medium, provided that you conspicuously and
-appropriately publish on each copy an appropriate copyright notice;
-keep intact all notices stating that this License and any
-non-permissive terms added in accord with section 7 apply to the code;
-keep intact all notices of the absence of any warranty; and give all
-recipients a copy of this License along with the Program.
-
- You may charge any price or no price for each copy that you convey,
-and you may offer support or warranty protection for a fee.
-
- 5. Conveying Modified Source Versions.
-
- You may convey a work based on the Program, or the modifications to
-produce it from the Program, in the form of source code under the
-terms of section 4, provided that you also meet all of these conditions:
-
- a) The work must carry prominent notices stating that you modified
- it, and giving a relevant date.
-
- b) The work must carry prominent notices stating that it is
- released under this License and any conditions added under section
- 7. This requirement modifies the requirement in section 4 to
- "keep intact all notices".
-
- c) You must license the entire work, as a whole, under this
- License to anyone who comes into possession of a copy. This
- License will therefore apply, along with any applicable section 7
- additional terms, to the whole of the work, and all its parts,
- regardless of how they are packaged. This License gives no
- permission to license the work in any other way, but it does not
- invalidate such permission if you have separately received it.
-
- d) If the work has interactive user interfaces, each must display
- Appropriate Legal Notices; however, if the Program has interactive
- interfaces that do not display Appropriate Legal Notices, your
- work need not make them do so.
-
- A compilation of a covered work with other separate and independent
-works, which are not by their nature extensions of the covered work,
-and which are not combined with it such as to form a larger program,
-in or on a volume of a storage or distribution medium, is called an
-"aggregate" if the compilation and its resulting copyright are not
-used to limit the access or legal rights of the compilation's users
-beyond what the individual works permit. Inclusion of a covered work
-in an aggregate does not cause this License to apply to the other
-parts of the aggregate.
-
- 6. Conveying Non-Source Forms.
-
- You may convey a covered work in object code form under the terms
-of sections 4 and 5, provided that you also convey the
-machine-readable Corresponding Source under the terms of this License,
-in one of these ways:
-
- a) Convey the object code in, or embodied in, a physical product
- (including a physical distribution medium), accompanied by the
- Corresponding Source fixed on a durable physical medium
- customarily used for software interchange.
-
- b) Convey the object code in, or embodied in, a physical product
- (including a physical distribution medium), accompanied by a
- written offer, valid for at least three years and valid for as
- long as you offer spare parts or customer support for that product
- model, to give anyone who possesses the object code either (1) a
- copy of the Corresponding Source for all the software in the
- product that is covered by this License, on a durable physical
- medium customarily used for software interchange, for a price no
- more than your reasonable cost of physically performing this
- conveying of source, or (2) access to copy the
- Corresponding Source from a network server at no charge.
-
- c) Convey individual copies of the object code with a copy of the
- written offer to provide the Corresponding Source. This
- alternative is allowed only occasionally and noncommercially, and
- only if you received the object code with such an offer, in accord
- with subsection 6b.
-
- d) Convey the object code by offering access from a designated
- place (gratis or for a charge), and offer equivalent access to the
- Corresponding Source in the same way through the same place at no
- further charge. You need not require recipients to copy the
- Corresponding Source along with the object code. If the place to
- copy the object code is a network server, the Corresponding Source
- may be on a different server (operated by you or a third party)
- that supports equivalent copying facilities, provided you maintain
- clear directions next to the object code saying where to find the
- Corresponding Source. Regardless of what server hosts the
- Corresponding Source, you remain obligated to ensure that it is
- available for as long as needed to satisfy these requirements.
-
- e) Convey the object code using peer-to-peer transmission, provided
- you inform other peers where the object code and Corresponding
- Source of the work are being offered to the general public at no
- charge under subsection 6d.
-
- A separable portion of the object code, whose source code is excluded
-from the Corresponding Source as a System Library, need not be
-included in conveying the object code work.
-
- A "User Product" is either (1) a "consumer product", which means any
-tangible personal property which is normally used for personal, family,
-or household purposes, or (2) anything designed or sold for incorporation
-into a dwelling. In determining whether a product is a consumer product,
-doubtful cases shall be resolved in favor of coverage. For a particular
-product received by a particular user, "normally used" refers to a
-typical or common use of that class of product, regardless of the status
-of the particular user or of the way in which the particular user
-actually uses, or expects or is expected to use, the product. A product
-is a consumer product regardless of whether the product has substantial
-commercial, industrial or non-consumer uses, unless such uses represent
-the only significant mode of use of the product.
-
- "Installation Information" for a User Product means any methods,
-procedures, authorization keys, or other information required to install
-and execute modified versions of a covered work in that User Product from
-a modified version of its Corresponding Source. The information must
-suffice to ensure that the continued functioning of the modified object
-code is in no case prevented or interfered with solely because
-modification has been made.
-
- If you convey an object code work under this section in, or with, or
-specifically for use in, a User Product, and the conveying occurs as
-part of a transaction in which the right of possession and use of the
-User Product is transferred to the recipient in perpetuity or for a
-fixed term (regardless of how the transaction is characterized), the
-Corresponding Source conveyed under this section must be accompanied
-by the Installation Information. But this requirement does not apply
-if neither you nor any third party retains the ability to install
-modified object code on the User Product (for example, the work has
-been installed in ROM).
-
- The requirement to provide Installation Information does not include a
-requirement to continue to provide support service, warranty, or updates
-for a work that has been modified or installed by the recipient, or for
-the User Product in which it has been modified or installed. Access to a
-network may be denied when the modification itself materially and
-adversely affects the operation of the network or violates the rules and
-protocols for communication across the network.
-
- Corresponding Source conveyed, and Installation Information provided,
-in accord with this section must be in a format that is publicly
-documented (and with an implementation available to the public in
-source code form), and must require no special password or key for
-unpacking, reading or copying.
-
- 7. Additional Terms.
-
- "Additional permissions" are terms that supplement the terms of this
-License by making exceptions from one or more of its conditions.
-Additional permissions that are applicable to the entire Program shall
-be treated as though they were included in this License, to the extent
-that they are valid under applicable law. If additional permissions
-apply only to part of the Program, that part may be used separately
-under those permissions, but the entire Program remains governed by
-this License without regard to the additional permissions.
-
- When you convey a copy of a covered work, you may at your option
-remove any additional permissions from that copy, or from any part of
-it. (Additional permissions may be written to require their own
-removal in certain cases when you modify the work.) You may place
-additional permissions on material, added by you to a covered work,
-for which you have or can give appropriate copyright permission.
-
- Notwithstanding any other provision of this License, for material you
-add to a covered work, you may (if authorized by the copyright holders of
-that material) supplement the terms of this License with terms:
-
- a) Disclaiming warranty or limiting liability differently from the
- terms of sections 15 and 16 of this License; or
-
- b) Requiring preservation of specified reasonable legal notices or
- author attributions in that material or in the Appropriate Legal
- Notices displayed by works containing it; or
-
- c) Prohibiting misrepresentation of the origin of that material, or
- requiring that modified versions of such material be marked in
- reasonable ways as different from the original version; or
-
- d) Limiting the use for publicity purposes of names of licensors or
- authors of the material; or
-
- e) Declining to grant rights under trademark law for use of some
- trade names, trademarks, or service marks; or
-
- f) Requiring indemnification of licensors and authors of that
- material by anyone who conveys the material (or modified versions of
- it) with contractual assumptions of liability to the recipient, for
- any liability that these contractual assumptions directly impose on
- those licensors and authors.
-
- All other non-permissive additional terms are considered "further
-restrictions" within the meaning of section 10. If the Program as you
-received it, or any part of it, contains a notice stating that it is
-governed by this License along with a term that is a further
-restriction, you may remove that term. If a license document contains
-a further restriction but permits relicensing or conveying under this
-License, you may add to a covered work material governed by the terms
-of that license document, provided that the further restriction does
-not survive such relicensing or conveying.
-
- If you add terms to a covered work in accord with this section, you
-must place, in the relevant source files, a statement of the
-additional terms that apply to those files, or a notice indicating
-where to find the applicable terms.
-
- Additional terms, permissive or non-permissive, may be stated in the
-form of a separately written license, or stated as exceptions;
-the above requirements apply either way.
-
- 8. Termination.
-
- You may not propagate or modify a covered work except as expressly
-provided under this License. Any attempt otherwise to propagate or
-modify it is void, and will automatically terminate your rights under
-this License (including any patent licenses granted under the third
-paragraph of section 11).
-
- However, if you cease all violation of this License, then your
-license from a particular copyright holder is reinstated (a)
-provisionally, unless and until the copyright holder explicitly and
-finally terminates your license, and (b) permanently, if the copyright
-holder fails to notify you of the violation by some reasonable means
-prior to 60 days after the cessation.
-
- Moreover, your license from a particular copyright holder is
-reinstated permanently if the copyright holder notifies you of the
-violation by some reasonable means, this is the first time you have
-received notice of violation of this License (for any work) from that
-copyright holder, and you cure the violation prior to 30 days after
-your receipt of the notice.
-
- Termination of your rights under this section does not terminate the
-licenses of parties who have received copies or rights from you under
-this License. If your rights have been terminated and not permanently
-reinstated, you do not qualify to receive new licenses for the same
-material under section 10.
-
- 9. Acceptance Not Required for Having Copies.
-
- You are not required to accept this License in order to receive or
-run a copy of the Program. Ancillary propagation of a covered work
-occurring solely as a consequence of using peer-to-peer transmission
-to receive a copy likewise does not require acceptance. However,
-nothing other than this License grants you permission to propagate or
-modify any covered work. These actions infringe copyright if you do
-not accept this License. Therefore, by modifying or propagating a
-covered work, you indicate your acceptance of this License to do so.
-
- 10. Automatic Licensing of Downstream Recipients.
-
- Each time you convey a covered work, the recipient automatically
-receives a license from the original licensors, to run, modify and
-propagate that work, subject to this License. You are not responsible
-for enforcing compliance by third parties with this License.
-
- An "entity transaction" is a transaction transferring control of an
-organization, or substantially all assets of one, or subdividing an
-organization, or merging organizations. If propagation of a covered
-work results from an entity transaction, each party to that
-transaction who receives a copy of the work also receives whatever
-licenses to the work the party's predecessor in interest had or could
-give under the previous paragraph, plus a right to possession of the
-Corresponding Source of the work from the predecessor in interest, if
-the predecessor has it or can get it with reasonable efforts.
-
- You may not impose any further restrictions on the exercise of the
-rights granted or affirmed under this License. For example, you may
-not impose a license fee, royalty, or other charge for exercise of
-rights granted under this License, and you may not initiate litigation
-(including a cross-claim or counterclaim in a lawsuit) alleging that
-any patent claim is infringed by making, using, selling, offering for
-sale, or importing the Program or any portion of it.
-
- 11. Patents.
-
- A "contributor" is a copyright holder who authorizes use under this
-License of the Program or a work on which the Program is based. The
-work thus licensed is called the contributor's "contributor version".
-
- A contributor's "essential patent claims" are all patent claims
-owned or controlled by the contributor, whether already acquired or
-hereafter acquired, that would be infringed by some manner, permitted
-by this License, of making, using, or selling its contributor version,
-but do not include claims that would be infringed only as a
-consequence of further modification of the contributor version. For
-purposes of this definition, "control" includes the right to grant
-patent sublicenses in a manner consistent with the requirements of
-this License.
-
- Each contributor grants you a non-exclusive, worldwide, royalty-free
-patent license under the contributor's essential patent claims, to
-make, use, sell, offer for sale, import and otherwise run, modify and
-propagate the contents of its contributor version.
-
- In the following three paragraphs, a "patent license" is any express
-agreement or commitment, however denominated, not to enforce a patent
-(such as an express permission to practice a patent or covenant not to
-sue for patent infringement). To "grant" such a patent license to a
-party means to make such an agreement or commitment not to enforce a
-patent against the party.
-
- If you convey a covered work, knowingly relying on a patent license,
-and the Corresponding Source of the work is not available for anyone
-to copy, free of charge and under the terms of this License, through a
-publicly available network server or other readily accessible means,
-then you must either (1) cause the Corresponding Source to be so
-available, or (2) arrange to deprive yourself of the benefit of the
-patent license for this particular work, or (3) arrange, in a manner
-consistent with the requirements of this License, to extend the patent
-license to downstream recipients. "Knowingly relying" means you have
-actual knowledge that, but for the patent license, your conveying the
-covered work in a country, or your recipient's use of the covered work
-in a country, would infringe one or more identifiable patents in that
-country that you have reason to believe are valid.
-
- If, pursuant to or in connection with a single transaction or
-arrangement, you convey, or propagate by procuring conveyance of, a
-covered work, and grant a patent license to some of the parties
-receiving the covered work authorizing them to use, propagate, modify
-or convey a specific copy of the covered work, then the patent license
-you grant is automatically extended to all recipients of the covered
-work and works based on it.
-
- A patent license is "discriminatory" if it does not include within
-the scope of its coverage, prohibits the exercise of, or is
-conditioned on the non-exercise of one or more of the rights that are
-specifically granted under this License. You may not convey a covered
-work if you are a party to an arrangement with a third party that is
-in the business of distributing software, under which you make payment
-to the third party based on the extent of your activity of conveying
-the work, and under which the third party grants, to any of the
-parties who would receive the covered work from you, a discriminatory
-patent license (a) in connection with copies of the covered work
-conveyed by you (or copies made from those copies), or (b) primarily
-for and in connection with specific products or compilations that
-contain the covered work, unless you entered into that arrangement,
-or that patent license was granted, prior to 28 March 2007.
-
- Nothing in this License shall be construed as excluding or limiting
-any implied license or other defenses to infringement that may
-otherwise be available to you under applicable patent law.
-
- 12. No Surrender of Others' Freedom.
-
- If conditions are imposed on you (whether by court order, agreement or
-otherwise) that contradict the conditions of this License, they do not
-excuse you from the conditions of this License. If you cannot convey a
-covered work so as to satisfy simultaneously your obligations under this
-License and any other pertinent obligations, then as a consequence you may
-not convey it at all. For example, if you agree to terms that obligate you
-to collect a royalty for further conveying from those to whom you convey
-the Program, the only way you could satisfy both those terms and this
-License would be to refrain entirely from conveying the Program.
-
- 13. Use with the GNU Affero General Public License.
-
- Notwithstanding any other provision of this License, you have
-permission to link or combine any covered work with a work licensed
-under version 3 of the GNU Affero General Public License into a single
-combined work, and to convey the resulting work. The terms of this
-License will continue to apply to the part which is the covered work,
-but the special requirements of the GNU Affero General Public License,
-section 13, concerning interaction through a network will apply to the
-combination as such.
-
- 14. Revised Versions of this License.
-
- The Free Software Foundation may publish revised and/or new versions of
-the GNU General Public License from time to time. Such new versions will
-be similar in spirit to the present version, but may differ in detail to
-address new problems or concerns.
-
- Each version is given a distinguishing version number. If the
-Program specifies that a certain numbered version of the GNU General
-Public License "or any later version" applies to it, you have the
-option of following the terms and conditions either of that numbered
-version or of any later version published by the Free Software
-Foundation. If the Program does not specify a version number of the
-GNU General Public License, you may choose any version ever published
-by the Free Software Foundation.
-
- If the Program specifies that a proxy can decide which future
-versions of the GNU General Public License can be used, that proxy's
-public statement of acceptance of a version permanently authorizes you
-to choose that version for the Program.
-
- Later license versions may give you additional or different
-permissions. However, no additional obligations are imposed on any
-author or copyright holder as a result of your choosing to follow a
-later version.
-
- 15. Disclaimer of Warranty.
-
- THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
-APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
-HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
-OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
-THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
-PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
-IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
-ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
-
- 16. Limitation of Liability.
-
- IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
-WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
-THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
-GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
-USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
-DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
-PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
-EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
-SUCH DAMAGES.
-
- 17. Interpretation of Sections 15 and 16.
-
- If the disclaimer of warranty and limitation of liability provided
-above cannot be given local legal effect according to their terms,
-reviewing courts shall apply local law that most closely approximates
-an absolute waiver of all civil liability in connection with the
-Program, unless a warranty or assumption of liability accompanies a
-copy of the Program in return for a fee.
-
diff --git a/vendor/leafo/lessphp/Makefile b/vendor/leafo/lessphp/Makefile
deleted file mode 100644
index a5d262cd..00000000
--- a/vendor/leafo/lessphp/Makefile
+++ /dev/null
@@ -1,7 +0,0 @@
-
-test:
- phpunit --colors tests
-
-release:
- ./package.sh
-
diff --git a/vendor/leafo/lessphp/README.md b/vendor/leafo/lessphp/README.md
deleted file mode 100644
index 1379ddce..00000000
--- a/vendor/leafo/lessphp/README.md
+++ /dev/null
@@ -1,96 +0,0 @@
-[![Build Status](https://travis-ci.org/leafo/lessphp.svg?branch=master)](https://travis-ci.org/leafo/lessphp)
-
-# lessphp v0.5.0
-### <http://leafo.net/lessphp>
-
-`lessphp` is a compiler for LESS written in PHP. The documentation is great,
-so check it out: <http://leafo.net/lessphp/docs/>.
-
-Here's a quick tutorial:
-
-### How to use in your PHP project
-
-The only file required is `lessc.inc.php`, so copy that to your include directory.
-
-The typical flow of **lessphp** is to create a new instance of `lessc`,
-configure it how you like, then tell it to compile something using one built in
-compile methods.
-
-The `compile` method compiles a string of LESS code to CSS.
-
-```php
-<?php
-require "lessc.inc.php";
-
-$less = new lessc;
-echo $less->compile(".block { padding: 3 + 4px }");
-```
-
-The `compileFile` method reads and compiles a file. It will either return the
-result or write it to the path specified by an optional second argument.
-
-```php
-<?php
-echo $less->compileFile("input.less");
-```
-
-The `compileChecked` method is like `compileFile`, but it only compiles if the output
-file doesn't exist or it's older than the input file:
-
-```php
-<?php
-$less->checkedCompile("input.less", "output.css");
-```
-
-If there any problem compiling your code, an exception is thrown with a helpful message:
-
-```php
-<?php
-try {
- $less->compile("invalid LESS } {");
-} catch (exception $e) {
- echo "fatal error: " . $e->getMessage();
-}
-```
-
-The `lessc` object can be configured through an assortment of instance methods.
-Some possible configuration options include [changing the output format][1],
-[setting variables from PHP][2], and [controlling the preservation of
-comments][3], writing [custom functions][4] and much more. It's all described
-in [the documentation][0].
-
-
- [0]: http://leafo.net/lessphp/docs/
- [1]: http://leafo.net/lessphp/docs/#output_formatting
- [2]: http://leafo.net/lessphp/docs/#setting_variables_from_php
- [3]: http://leafo.net/lessphp/docs/#preserving_comments
- [4]: http://leafo.net/lessphp/docs/#custom_functions
-
-
-### How to use from the command line
-
-An additional script has been included to use the compiler from the command
-line. In the simplest invocation, you specify an input file and the compiled
-css is written to standard out:
-
- $ plessc input.less > output.css
-
-Using the -r flag, you can specify LESS code directly as an argument or, if
-the argument is left off, from standard in:
-
- $ plessc -r "my less code here"
-
-Finally, by using the -w flag you can watch a specified input file and have it
-compile as needed to the output file:
-
- $ plessc -w input-file output-file
-
-Errors from watch mode are written to standard out.
-
-The -f flag sets the [output formatter][1]. For example, to compress the
-output run this:
-
- $ plessc -f=compressed myfile.less
-
-For more help, run `plessc --help`
-
diff --git a/vendor/leafo/lessphp/composer.json b/vendor/leafo/lessphp/composer.json
deleted file mode 100644
index 0f06ba09..00000000
--- a/vendor/leafo/lessphp/composer.json
+++ /dev/null
@@ -1,25 +0,0 @@
-{
- "name": "leafo/lessphp",
- "type": "library",
- "description": "lessphp is a compiler for LESS written in PHP.",
- "homepage": "http://leafo.net/lessphp/",
- "license": [
- "MIT",
- "GPL-3.0"
- ],
- "authors": [
- {
- "name": "Leaf Corcoran",
- "email": "leafot@gmail.com",
- "homepage": "http://leafo.net"
- }
- ],
- "autoload": {
- "classmap": ["lessc.inc.php"]
- },
- "extra": {
- "branch-alias": {
- "dev-master": "0.4.x-dev"
- }
- }
-}
diff --git a/vendor/leafo/lessphp/docs/docs.md b/vendor/leafo/lessphp/docs/docs.md
deleted file mode 100644
index 112dc2ee..00000000
--- a/vendor/leafo/lessphp/docs/docs.md
+++ /dev/null
@@ -1,1400 +0,0 @@
- title: v0.5.0 documentation
- link_to_home: true
---
-
-<h2 skip="true">Documentation v0.5.0</h2>
-
-<div style="margin-bottom: 1em;">$index</div>
-
-**lessphp** is a compiler that generates CSS from a superset language which
-adds a collection of convenient features often seen in other languages. All CSS
-is compatible with LESS, so you can start using new features with your existing CSS.
-
-It is designed to be compatible with [less.js](http://lesscss.org), and suitable
-as a drop in replacement for PHP projects.
-
-## Getting Started
-
-The homepage for **lessphp** can be found at [http://leafo.net/lessphp/][1].
-
-You can follow development at the project's [GitHub][2].
-
-Including **lessphp** in your project is as simple as dropping the single
-include file into your code base and running the appropriate compile method as
-described in the [PHP Interface](#php_interface).
-
- [1]: http://leafo.net/lessphp "lessphp homepage"
- [2]: https://github.com/leafo/lessphp "lessphp GitHub page"
-
-## Installation
-
-**lessphp** is distributed entirely in a single stand-alone file. Download the
-latest version from either [the homepage][1] or [GitHub][2].
-
-Development versions can also be downloading from GitHub.
-
-Place `lessphp.inc.php` in a location available to your PHP scripts, and
-include it. That's it! you're ready to begin.
-
-## The Language
-
-**lessphp** is very easy to learn because it generally functions how you would
-expect it to. If you feel something is challenging or missing, feel free to
-open an issue on the [bug tracker](https://github.com/leafo/lessphp/issues).
-
-It is also easy to learn because any standards-compliant CSS code is valid LESS
-code. You are free to gradually enhance your existing CSS code base with LESS
-features without having to worry about rewriting anything.
-
-The following is a description of the new languages features provided by LESS.
-
-### Line Comments
-
-Simple but very useful; line comments are started with `//`:
-
- ```less
- // this is a comment
- body {
- color: red; // as is this
- /* block comments still work also */
- }
- ```
-
-### Variables
-
-Variables are identified with a name that starts with `@`. To declare a
-variable, you create an appropriately named CSS property and assign it a value:
-
- ```less
- @family: "verdana";
- @color: red;
- body {
- @mycolor: red;
- font-family: @family;
- color: @color;
- border-bottom: 1px solid @color;
- }
- ```
-
-Variable declarations will not appear in the output. Variables can be declared
-in the outer most scope of the file, or anywhere else a CSS property may
-appear. They can hold any CSS property value.
-
-Variables are only visible for use from their current scope, or any enclosed
-scopes.
-
-If you have a string or keyword in a variable, you can reference another
-variable by that name by repeating the `@`:
-
- ```less
- @value: 20px;
- @value_name: "value";
-
- width: @@value_name;
- ```
-
-### Expressions
-
-Expressions let you combine values and variables in meaningful ways. For
-example you can add to a color to make it a different shade. Or divide up the
-width of your layout logically. You can even concatenate strings.
-
-Use the mathematical operators to evaluate an expression:
-
- ```less
- @width: 960px;
- .nav {
- width: @width / 3;
- color: #001 + #abc;
- }
- .body {
- width: 2 * @width / 3;
- font-family: "hel" + "vetica";
- }
- ```
-
-Parentheses can be used to control the order of evaluation. They can also be
-used to force an evaluation for cases where CSS's syntax makes the expression
-ambiguous.
-
-The following property will produce two numbers, instead of doing the
-subtraction:
-
- ```less
- margin: 10px -5px;
- ```
-
-To force the subtraction:
-
- ```less
- margin: (10px -5px);
- ```
-
-It is also safe to surround mathematical operators by spaces to ensure that
-they are evaluated:
-
- ```less
- margin: 10px - 5px;
- ```
-
-Division has a special quirk. There are certain CSS properties that use the `/`
-operator as part of their value's syntax. Namely, the [font][4] shorthand and
-[border-radius][3].
-
- [3]: https://developer.mozilla.org/en/CSS/border-radius
- [4]: https://developer.mozilla.org/en/CSS/font
-
-
-Thus, **lessphp** will ignore any division in these properties unless it is
-wrapped in parentheses. For example, no division will take place here:
-
- ```less
- .font {
- font: 20px/80px "Times New Roman";
- }
- ```
-
-In order to force division we must wrap the expression in parentheses:
-
- ```less
- .font {
- font: (20px/80px) "Times New Roman";
- }
- ```
-
-If you want to write a literal `/` expression without dividing in another
-property (or a variable), you can use [string unquoting](#string_unquoting):
-
- ```less
- .var {
- @size: ~"20px/80px";
- font: @size sans-serif;
- }
- ```
-
-### Nested Blocks
-
-By nesting blocks we can build up a chain of CSS selectors through scope
-instead of repeating them. In addition to reducing repetition, this also helps
-logically organize the structure of our CSS.
-
- ```less
- ol.list {
- li.special {
- border: 1px solid red;
- }
-
- li.plain {
- font-weight: bold;
- }
- }
- ```
-
-
-This will produce two blocks, a `ol.list li.special` and `ol.list li.plain`.
-
-Blocks can be nested as deep as required in order to build a hierarchy of
-relationships.
-
-The `&` operator can be used in a selector to represent its parent's selector.
-If the `&` operator is used, then the default action of appending the parent to
-the front of the child selector separated by space is not performed.
-
- ```less
- b {
- a & {
- color: red;
- }
-
- // the following have the same effect
-
- & i {
- color: blue;
- }
-
- i {
- color: blue;
- }
- }
- ```
-
-
-Because the `&` operator respects the whitespace around it, we can use it to
-control how the child blocks are joined. Consider the differences between the
-following:
-
- ```less
- div {
- .child-class { color: purple; }
-
- &.isa-class { color: green; }
-
- #child-id { height: 200px; }
-
- &#div-id { height: 400px; }
-
- &:hover { color: red; }
-
- :link { color: blue; }
- }
- ```
-
-The `&` operator also works with [mixins](#mixins), which produces interesting results:
-
- ```less
- .within_box_style() {
- .box & {
- color: blue;
- }
- }
-
- #menu {
- .within_box_style;
- }
- ```
-
-### Mixins
-
-Any block can be mixed in just by naming it:
-
- ```less
- .mymixin {
- color: blue;
- border: 1px solid red;
-
- .special {
- font-weight: bold;
- }
- }
-
-
- h1 {
- font-size: 200px;
- .mymixin;
- }
- ```
-
-All properties and child blocks are mixed in.
-
-Mixins can be made parametric, meaning they can take arguments, in order to
-enhance their utility. A parametric mixin all by itself is not outputted when
-compiled. Its properties will only appear when mixed into another block.
-
-The canonical example is to create a rounded corners mixin that works across
-browsers:
-
- ```less
- .rounded-corners(@radius: 5px) {
- border-radius: @radius;
- -webkit-border-radius: @radius;
- -moz-border-radius: @radius;
- }
-
- .header {
- .rounded-corners();
- }
-
- .info {
- background: red;
- .rounded-corners(14px);
- }
- ```
-
-If you have a mixin that doesn't have any arguments, but you don't want it to
-show up in the output, give it a blank argument list:
-
- ```less
- .secret() {
- font-size: 6000px;
- }
-
- .div {
- .secret;
- }
- ```
-
-If the mixin doesn't need any arguments, you can leave off the parentheses when
-mixing it in, as seen above.
-
-You can also mixin a block that is nested inside other blocks. You can think of
-the outer block as a way of making a scope for your mixins. You just list the
-names of the mixins separated by spaces, which describes the path to the mixin
-you want to include. Optionally you can separate them by `>`.
-
- ```less
- .my_scope {
- .some_color {
- color: red;
- .inner_block {
- text-decoration: underline;
- }
- }
- .bold {
- font-weight: bold;
- color: blue;
- }
- }
-
- .a_block {
- .my_scope .some_color;
- .my_scope .some_color .inner_block;
- }
-
- .another_block {
- // the alternative syntax
- .my_scope > .bold;
- }
- ```
-
-
-#### Mixin Arguments
-
-When declaring a mixin you can specify default values for each argument. Any
-argument left out will be given the default value specified. Here's the
-syntax:
-
-```less
-.mix(@color: red, @height: 20px, @pad: 12px) {
- border: 1px solid @color;
- height: @height - @pad;
- padding: @pad;
-}
-
-.default1 {
- .mix();
-}
-
-.default2 {
- .mix(blue);
-}
-
-.default3 {
- .mix(blue, 40px, 5px);
-}
-```
-
-Additionally, you can also call a mixin using the argument names, this is
-useful if you want to replace a specific argument while having all the others
-take the default regardless of what position the argument appears in. The
-syntax looks something like this:
-
-
-```lessbasic
-div {
- .my_mixin(@paddding: 4px); // @color and @height get default values
- .my_mixin(@paddding: 4px, @height: 50px); // you can specify them in any order
-}
-```
-
-You can also combine the ordered arguments with the named ones:
-
-```lessbasic
-div {
- // @color is blue, @padding is 4px, @height is default
- .my_mixin(blue, @padding: 4px);
-}
-```
-
-Mixin arguments can be delimited with either a `,` or `;`, but only one can be
-active at once. This means that each argument is separated by either `,` or
-`;`. By default `,` is the delimiter, in all the above examples we used a `,`.
-
-A problem arises though, sometimes CSS value lists are made up with commas. In
-order to be able to pass a comma separated list literal we need to use `;` as
-the delimiter. (You don't need to worry about this if your list is stored in a
-variable)
-
-If a `;` appears anywhere in the argument list, then it will be used as the
-argument delimiter, and all commas we be used as part of the argument values.
-
-Here's a basic example:
-
-```less
-.fancy_mixin(@box_shadow, @color: blue) {
- border: 1px solid @color;
- box-shadow: @box_shadow;
-}
-
-
-div {
- // two arguments passed separated by ;
- .fancy_mixin(2px 2px, -2px -2px; red);
-}
-
-pre {
- // one argument passed, ends in ;
- .fancy_mixin(inset 4px 4px, -2px 2px;);
-}
-
-```
-
-If we only want to pass a single comma separated value we still need to use
-`;`, to do this we stick it on the end as demonstrated above.
-
-
-#### `@arguments` Variable
-
-Within an mixin there is a special variable named `@arguments` that contains
-all the arguments passed to the mixin along with any remaining arguments that
-have default values. The value of the variable has all the values separated by
-spaces.
-
-This useful for quickly assigning all the arguments:
-
- ```less
- .box-shadow(@x, @y, @blur, @color) {
- box-shadow: @arguments;
- -webkit-box-shadow: @arguments;
- -moz-box-shadow: @arguments;
- }
- .menu {
- .box-shadow(1px, 1px, 5px, #aaa);
- }
- ```
-
-In addition to the arguments passed to the mixin, `@arguments` will also include
-remaining default values assigned by the mixin:
-
-
- ```less
- .border-mixin(@width, @style: solid, @color: black) {
- border: @arguments;
- }
-
- pre {
- .border-mixin(4px, dotted);
- }
-
- ```
-
-
-#### Pattern Matching
-
-When you *mix in* a mixin, all the available mixins of that name in the current
-scope are checked to see if they match based on what was passed to the mixin
-and how it was declared.
-
-The simplest case is matching by number of arguments. Only the mixins that
-match the number of arguments passed in are used.
-
- ```less
- .simple() { // matches no arguments
- height: 10px;
- }
-
- .simple(@a, @b) { // matches two arguments
- color: red;
- }
-
- .simple(@a) { // matches one argument
- color: blue;
- }
-
- div {
- .simple(10);
- }
-
- span {
- .simple(10, 20);
- }
- ```
-
-Whether an argument has default values is also taken into account when matching
-based on number of arguments:
-
- ```less
- // matches one or two arguments
- .hello(@a, @b: blue) {
- height: @a;
- color: @b;
- }
-
- .hello(@a, @b) { // matches only two
- width: @a;
- border-color: @b;
- }
-
- .hello(@a) { // matches only one
- padding: 1em;
- }
-
- div {
- .hello(10px);
- }
-
- pre {
- .hello(10px, yellow);
- }
- ```
-
-Additionally, a *vararg* value can be used to further control how things are
-matched. A mixin's argument list can optionally end in the special argument
-named `...`. The `...` may match any number of arguments, including 0.
-
- ```less
- // this will match any number of arguments
- .first(...) {
- color: blue;
- }
-
- // matches at least 1 argument
- .second(@arg, ...) {
- height: 200px + @arg;
- }
-
- div { .first("some", "args"); }
- pre { .second(10px); }
- ```
-
-If you want to capture the values that get captured by the *vararg* you can
-give it a variable name by putting it directly before the `...`. This variable
-must be the last argument defined. It's value is just like the special
-[`@arguments` variable](#arguments_variable), a space separated list.
-
-
- ```less
- .hello(@first, @rest...) {
- color: @first;
- text-shadow: @rest;
- }
-
- span {
- .hello(red, 1px, 1px, 0px, white);
- }
-
- ```
-
-Another way of controlling whether a mixin matches is by specifying a value in
-place of an argument name when declaring the mixin:
-
- ```less
- .style(old, @size) {
- font: @size serif;
- }
-
- .style(new, @size) {
- font: @size sans-serif;
- }
-
- .style(@_, @size) {
- letter-spacing: floor(@size / 6px);
- }
-
- em {
- @switch: old;
- .style(@switch, 15px);
- }
- ```
-
-Notice that two of the three mixins were matched. The mixin with a matching
-first argument, and the generic mixin that matches two arguments. It's common
-to use `@_` as the name of a variable we intend to not use. It has no special
-meaning to LESS, just to the reader of the code.
-
-#### Guards
-
-Another way of restricting when a mixin is mixed in is by using guards. A guard
-is a special expression that is associated with a mixin declaration that is
-evaluated during the mixin process. It must evaluate to true before the mixin
-can be used.
-
-We use the `when` keyword to begin describing a list of guard expressions.
-
-Here's a simple example:
-
- ```less
- .guarded(@arg) when (@arg = hello) {
- color: blue;
- }
-
- div {
- .guarded(hello); // match
- }
-
- span {
- .guarded(world); // no match
- }
- ```
-Only the `div`'s mixin will match in this case, because the guard expression
-requires that `@arg` is equal to `hello`.
-
-We can include many different guard expressions by separating them by commas.
-Only one of them needs to match to trigger the mixin:
-
- ```less
- .x(@a, @b) when (@a = hello), (@b = world) {
- width: 960px;
- }
-
- div {
- .x(hello, bar); // match
- }
-
- span {
- .x(foo, world); // match
- }
-
- pre {
- .x(foo, bar); // no match
- }
- ```
-
-Instead of a comma, we can use `and` keyword to make it so all of the guards
-must match in order to trigger the mixin. `and` has higher precedence than the
-comma.
-
- ```less
- .y(@a, @b) when (@a = hello) and (@b = world) {
- height: 600px;
- }
-
- div {
- .y(hello, world); // match
- }
-
- span {
- .y(hello, bar); // no match
- }
- ```
-
-Commas and `and`s can be mixed and matched.
-
-You can also negate a guard expression by using `not` in from of the parentheses:
-
- ```less
- .x(@a) when not (@a = hello) {
- color: blue;
- }
-
- div {
- .x(hello); // no match
- }
- ```
-
-The `=` operator is used to check equality between any two values. For numbers
-the following comparison operators are also defined:
-
-`<`, `>`, `=<`, `>=`
-
-There is also a collection of predicate functions that can be used to test the
-type of a value.
-
-These are `isnumber`, `iscolor`, `iskeyword`, `isstring`, `ispixel`,
-`ispercentage` and `isem`.
-
- ```less
- .mix(@a) when (ispercentage(@a)) {
- height: 500px * @a;
- }
- .mix(@a) when (ispixel(@a)) {
- height: @a;
- }
-
- div.a {
- .mix(50%);
- }
-
- div.a {
- .mix(350px);
- }
- ```
-
-#### !important
-
-If you want to apply the `!important` suffix to every property when mixing in a
-mixin, just append `!important` to the end of the call to the mixin:
-
- ```less
- .make_bright {
- color: red;
- font-weight: bold;
- }
-
- .color {
- color: green;
- }
-
- body {
- .make_bright() !important;
- .color();
- }
-
- ```
-
-### Selector Expressions
-
-Sometimes we want to dynamically generate the selector of a block based on some
-variable or expression. We can do this by using *selector expressions*. Selector
-expressions are CSS selectors that are evaluated in the current scope before
-being written out.
-
-A simple example is a mixin that dynamically creates a selector named after the
-mixin's argument:
-
- ```less
- .create-selector(@name) {
- @{name} {
- color: red;
- }
- }
-
- .create-selector(hello);
- .create-selector(world);
- ```
-
-The string interpolation syntax works inside of selectors, letting you insert varaibles.
-
-Here's an interesting example adapted from Twitter Bootstrap. A couple advanced
-things are going on. We are using [Guards](#guards) along with a recursive
-mixin to work like a loop to generate a series of CSS blocks.
-
-
- ```less
- // create our recursive mixin:
- .spanX (@index) when (@index > 0) {
- .span@{index} {
- width: @index * 100px;
- }
- .spanX(@index - 1);
- }
- .spanX (0) {}
-
- // mix it into the global scopee:
- .spanX(4);
- ```
-
-### Import
-
-Multiple LESS files can be compiled into a single CSS file by using the
-`@import` statement. Be careful, the LESS import statement shares syntax with
-the CSS import statement. If the file being imported ends in a `.less`
-extension, or no extension, then it is treated as a LESS import. Otherwise it
-is left alone and outputted directly:
-
- ```lessbasic
- // my_file.less
- .some-mixin(@height) {
- height: @height;
- }
-
- // main.less
- @import "main.less" // will import the file if it can be found
- @import "main.css" // will be left alone
-
- body {
- .some-mixin(400px);
- }
- ```
-
-All of the following lines are valid ways to import the same file:
-
- ```lessbasic
- @import "file";
- @import 'file.less';
- @import url("file");
- @import url('file');
- @import url(file);
- ```
-
-When importing, the `importDir` is searched for files. This can be configured,
-see [PHP Interface](#php_interface).
-
-A file is only imported once. If you try to include the same file multiple
-times all the import statements after the first produce no output.
-
-### String Interpolation
-
-String interpolation is a convenient way to insert the value of a variable
-right into a string literal. Given some variable named `@var_name`, you just
-need to write it as `@{var_name}` from within the string to have its value
-inserted:
-
- ```less
- @symbol: ">";
- h1:before {
- content: "@{symbol}: ";
- }
-
- h2:before {
- content: "@{symbol}@{symbol}: ";
- }
- ```
-
-There are two kinds of strings, implicit and explicit strings. Explicit strings
-are wrapped by double quotes, `"hello I am a string"`, or single quotes `'I am
-another string'`. Implicit strings only appear when using `url()`. The text
-between the parentheses is considered a string and thus string interpolation is
-possible:
-
- ```less
- @path: "files/";
- body {
- background: url(@{path}my_background.png);
- }
- ```
-
-### String Format Function
-
-The `%` function can be used to insert values into strings using a *format
-string*. It works similar to `printf` seen in other languages. It has the
-same purpose as string interpolation above, but gives explicit control over
-the output format.
-
- ```less
- @symbol: ">";
- h1:before {
- content: %("%s: ", @symbol);
- }
- ```
-
-The `%` function takes as its first argument the format string, following any
-number of addition arguments that are inserted in place of the format
-directives.
-
-A format directive starts with a `%` and is followed by a single character that
-is either `a`, `d`, or `s`:
-
- ```less
- strings: %("%a %d %s %a", hi, 1, 'ok', 'cool');
- ```
-
-`%a` and `%d` format the value the same way: they compile the argument to its
-CSS value and insert it directly. When used with a string, the quotes are
-included in the output. This typically isn't what we want, so we have the `%s`
-format directive which strips quotes from strings before inserting them.
-
-The `%d` directive functions the same as `%a`, but is typically used for numbers
-assuming the output format of numbers might change in the future.
-
-### String Unquoting
-
-Sometimes you will need to write proprietary CSS syntax that is unable to be
-parsed. As a workaround you can place the code into a string and unquote it.
-Unquoting is the process of outputting a string without its surrounding quotes.
-There are two ways to unquote a string.
-
-The `~` operator in front of a string will unquote that string:
-
- ```less
- .class {
- // a made up, but problematic vendor specific CSS
- filter: ~"Microsoft.AlphaImage(src='image.png')";
- }
- ```
-
-If you are working with other types, such as variables, there is a built in
-function that let's you unquote any value. It is called `e`.
-
- ```less
- @color: "red";
- .class {
- color: e(@color);
- }
- ```
-
-### Built In Functions
-
-**lessphp** has a collection of built in functions:
-
-* `e(str)` -- returns a string without the surrounding quotes.
- See [String Unquoting](#string_unquoting)
-
-* `floor(number)` -- returns the floor of a numerical input
-* `round(number, [precision])` -- returns the rounded value of numerical input with optional precision
-
-* `lighten(color, percent)` -- lightens `color` by `percent` and returns it
-* `darken(color, percent)` -- darkens `color` by `percent` and returns it
-
-* `saturate(color, percent)` -- saturates `color` by `percent` and returns it
-* `desaturate(color, percent)` -- desaturates `color` by `percent` and returns it
-
-* `fadein(color, percent)` -- makes `color` less transparent by `percent` and returns it
-* `fadeout(color, percent)` -- makes `color` more transparent by `percent` and returns it
-
-* `spin(color, amount)` -- returns a color with `amount` degrees added to hue
-
-* `fade(color, amount)` -- returns a color with the alpha set to `amount`
-
-* `hue(color)` -- returns the hue of `color`
-
-* `saturation(color)` -- returns the saturation of `color`
-
-* `lightness(color)` -- returns the lightness of `color`
-
-* `alpha(color)` -- returns the alpha value of `color` or 1.0 if it doesn't have an alpha
-
-* `percentage(number)` -- converts a floating point number to a percentage, e.g. `0.65` -> `65%`
-
-* `mix(color1, color1, percent)` -- mixes two colors by percentage where 100%
- keeps all of `color1`, and 0% keeps all of `color2`. Will take into account
- the alpha of the colors if it exists. See
- <http://sass-lang.com/docs/yardoc/Sass/Script/Functions.html#mix-instance_method>.
-
-* `contrast(color, dark, light)` -- if `color` has a lightness value greater
- than 50% then `dark` is returned, otherwise return `light`.
-
-* `extract(list, index)` -- returns the `index`th item from `list`. The list is
- `1` indexed, meaning the first item's index is 1, the second is 2, and etc.
-
-* `pow(base, exp)` -- returns `base` raised to the power of `exp`
-
-* `pi()` -- returns pi
-
-* `mod(a,b)` -- returns `a` modulus `b`
-
-* `tan(a)` -- returns tangent of `a` where `a` is in radians
-
-* `cos(a)` -- returns cosine of `a` where `a` is in radians
-
-* `sin(a)` -- returns sine of `a` where `a` is in radians
-
-* `atan(a)` -- returns arc tangent of `a`
-
-* `acos(a)` -- returns arc cosine of `a`
-
-* `asin(a)` -- returns arc sine of `a`
-
-* `sqrt(a)` -- returns square root of `a`
-
-* `rgbahex(color)` -- returns a string containing 4 part hex color.
-
- This is used to convert a CSS color into the hex format that IE's filter
- method expects when working with an alpha component.
-
- ```less
- .class {
- @start: rgbahex(rgba(25, 34, 23, .5));
- @end: rgbahex(rgba(85, 74, 103, .6));
- // abridged example
- -ms-filter:
- e("gradient(start=@{start},end=@{end})");
- }
- ```
-
-## PHP Interface
-
-When working with **lessphp** from PHP, the typical flow is to create a new
-instance of `lessc`, configure it how you like, then tell it to compile
-something using one built in compile methods.
-
-Methods:
-
-* [`compile($string)`](#compiling[) -- Compile a string
-
-* [`compileFile($inFile, [$outFile])`](#compiling) -- Compile a file to another or return it
-
-* [`checkedCompile($inFile, $outFile)`](#compiling) -- Compile a file only if it's newer
-
-* [`cachedCompile($cacheOrFile, [$force])`](#compiling_automatically) -- Conditionally compile while tracking imports
-
-* [`setFormatter($formatterName)`](#output_formatting) -- Change how CSS output looks
-
-* [`setPreserveComments($keepComments)`](#preserving_comments) -- Change if comments are kept in output
-
-* [`registerFunction($name, $callable)`](#custom_functions) -- Add a custom function
-
-* [`unregisterFunction($name)`](#custom_functions) -- Remove a registered function
-
-* [`setVariables($vars)`](#setting_variables_from_php) -- Set a variable from PHP
-
-* [`unsetVariable($name)`](#setting_variables_from_php) -- Remove a PHP variable
-
-* [`setImportDir($dirs)`](#import_directory) -- Set the search path for imports
-
-* [`addImportDir($dir)`](#import_directory) -- Append directory to search path for imports
-
-
-### Compiling
-
-The `compile` method compiles a string of LESS code to CSS.
-
- ```php
- <?php
- require "lessc.inc.php";
-
- $less = new lessc;
- echo $less->compile(".block { padding: 3 + 4px }");
- ```
-
-The `compileFile` method reads and compiles a file. It will either return the
-result or write it to the path specified by an optional second argument.
-
- ```php
- echo $less->compileFile("input.less");
- ```
-
-The `compileChecked` method is like `compileFile`, but it only compiles if the output
-file doesn't exist or it's older than the input file:
-
- ```php
- $less->checkedCompile("input.less", "output.css");
- ```
-
-See [Compiling Automatically](#compiling_automatically) for a description of
-the more advanced `cachedCompile` method.
-
-### Output Formatting
-
-Output formatting controls the indentation of the output CSS. Besides the
-default formatter, two additional ones are included and it's also easy to make
-your own.
-
-To use a formatter, the method `setFormatter` is used. Just
-pass the name of the formatter:
-
- ```php
- $less = new lessc;
-
- $less->setFormatter("compressed");
- echo $less->compile("div { color: lighten(blue, 10%) }");
- ```
-
-In this example, the `compressed` formatter is used. The formatters are:
-
- * `lessjs` *(default)* -- Same style used in LESS for JavaScript
-
- * `compressed` -- Compresses all the unrequired whitespace
-
- * `classic` -- **lessphp**'s original formatter
-
-To revert to the default formatter, call `setFormatter` with a value of `null`.
-
-#### Custom Formatter
-
-The easiest way to customize the formatter is to create your own instance of an
-existing formatter and alter its public properties before passing it off to
-**lessphp**. The `setFormatter` method can also take an instance of a
-formatter.
-
-Each of the formatter names corresponds to a class with `lessc_formatter_`
-prepended in front of it. Here the classic formatter is customized to use tabs
-instead of spaces:
-
-
- ```php
- $formatter = new lessc_formatter_classic;
- $formatter->indentChar = "\t";
-
- $less = new lessc;
- $less->setFormatter($formatter);
- echo $less->compileFile("myfile.less");
- ```
-
-For more information about what can be configured with the formatter consult
-the source code.
-
-### Preserving Comments
-
-By default, all comments in the source LESS file are stripped when compiling.
-You might want to keep the `/* */` comments in the output though. For
-example, bundling a license in the file.
-
-Enable or disable comment preservation by calling `setPreserveComments`:
-
- ```php
- $less = new lessc;
- $less->setPreserveComments(true);
- echo $less->compile("/* hello! */");
- ```
-
-Comments are disabled by default because there is additional overhead, and more
-often than not they aren't needed.
-
-
-### Compiling Automatically
-
-Often, you want to only compile a LESS file only if it has been modified since
-last compile. This is very important because compiling is performance intensive
-and you should avoid a recompile if it possible.
-
-The `checkedCompile` compile method will do just that. It will check if the
-input file is newer than the output file, or if the output file doesn't exist
-yet, and compile only then.
-
- ```php
- $less->checkedCompile("input.less", "output.css");
- ```
-
-There's a problem though. `checkedCompile` is very basic, it only checks the
-input file's modification time. It is unaware of any files from `@import`.
-
-
-For this reason we also have `cachedCompile`. It's slightly more complex, but
-gives us the ability to check changes to all files including those imported. It
-takes one argument, either the name of the file we want to compile, or an
-existing *cache object*. Its return value is an updated cache object.
-
-If we don't have a cache object, then we call the function with the name of the
-file to get the initial cache object. If we do have a cache object, then we
-call the function with it. In both cases, an updated cache object is returned.
-
-The cache object keeps track of all the files that must be checked in order to
-determine if a rebuild is required.
-
-The cache object is a plain PHP `array`. It stores the last time it compiled in
-`$cache["updated"]` and output of the compile in `$cache["compiled"]`.
-
-Here we demonstrate creating an new cache object, then using it to see if we
-have a recompiled version available to be written:
-
-
- ```php
- $inputFile = "myfile.less";
- $outputFile = "myfile.css";
-
- $less = new lessc;
-
- // create a new cache object, and compile
- $cache = $less->cachedCompile($inputFile);
-
- file_put_contents($outputFile, $cache["compiled"]);
-
- // the next time we run, write only if it has updated
- $last_updated = $cache["updated"];
- $cache = $less->cachedCompile($cache);
- if ($cache["updated"] > $last_updated) {
- file_put_contents($outputFile, $cache["compiled"]);
- }
-
- ```
-
-In order for the system to fully work, we must save cache object between
-requests. Because it's a plain PHP `array`, it's sufficient to
-[`serialize`](http://php.net/serialize) it and save it the string somewhere
-like a file or in persistent memory.
-
-An example with saving cache object to a file:
-
- ```php
- function autoCompileLess($inputFile, $outputFile) {
- // load the cache
- $cacheFile = $inputFile.".cache";
-
- if (file_exists($cacheFile)) {
- $cache = unserialize(file_get_contents($cacheFile));
- } else {
- $cache = $inputFile;
- }
-
- $less = new lessc;
- $newCache = $less->cachedCompile($cache);
-
- if (!is_array($cache) || $newCache["updated"] > $cache["updated"]) {
- file_put_contents($cacheFile, serialize($newCache));
- file_put_contents($outputFile, $newCache['compiled']);
- }
- }
-
- autoCompileLess('myfile.less', 'myfile.css');
- ```
-
-`cachedCompile` method takes an optional second argument, `$force`. Passing in
-true will cause the input to always be recompiled.
-
-### Error Handling
-
-All of the compile methods will throw an `Exception` if the parsing fails or
-there is a compile time error. Compile time errors include things like passing
-incorrectly typed values for functions that expect specific things, like the
-color manipulation functions.
-
- ```php
- $less = new lessc;
- try {
- $less->compile("} invalid LESS }}}");
- } catch (Exception $ex) {
- echo "lessphp fatal error: ".$ex->getMessage();
- }
- ```
-### Setting Variables From PHP
-
-Before compiling any code you can set initial LESS variables from PHP. The
-`setVariables` method lets us do this. It takes an associative array of names
-to values. The values must be strings, and will be parsed into correct CSS
-values.
-
-
- ```php
- $less = new lessc;
-
- $less->setVariables(array(
- "color" => "red",
- "base" => "960px"
- ));
-
- echo $less->compile(".magic { color: @color; width: @base - 200; }");
- ```
-
-If you need to unset a variable, the `unsetVariable` method is available. It
-takes the name of the variable to unset.
-
- ```php
- $less->unsetVariable("color");
- ```
-
-Be aware that the value of the variable is a string containing a CSS value. So
-if you want to pass a LESS string in, you're going to need two sets of quotes.
-One for PHP and one for LESS.
-
-
- ```php
- $less->setVariables(array(
- "url" => "'http://example.com.com/'"
- ));
-
- echo $less->compile("body { background: url("@{url}/bg.png"); }");
- ```
-
-### Import Directory
-
-When running the `@import` directive, an array of directories called the import
-search path is searched through to find the file being asked for.
-
-By default, when using `compile`, the import search path just contains `""`,
-which is equivalent to the current directory of the script. If `compileFile` is
-used, then the directory of the file being compiled is used as the starting
-import search path.
-
-Two methods are available for configuring the search path.
-
-`setImportDir` will overwrite the search path with its argument. If the value
-isn't an array it will be converted to one.
-
-
-In this example, `@import "colors";` will look for either
-`assets/less/colors.less` or `assets/bootstrap/colors.less` in that order:
-
- ```php
- $less->setImportDir(array("assets/less/", "assets/bootstrap"));
-
- echo $less->compile('@import "colors";');
- ```
-
-`addImportDir` will append a single path to the import search path instead of
-overwriting the whole thing.
-
- ```php
- $less->addImportDir("public/stylesheets");
- ```
-
-### Custom Functions
-
-**lessphp** has a simple extension interface where you can implement user
-functions that will be exposed in LESS code during the compile. They can be a
-little tricky though because you need to work with the **lessphp** type system.
-
-The two methods we are interested in are `registerFunction` and
-`unregisterFunction`. `registerFunction` takes two arguments, a name and a
-callable value. `unregisterFunction` just takes the name of an existing
-function to remove.
-
-Here's an example that adds a function called `double` that doubles any numeric
-argument:
-
- ```php
- <?php
- include "lessc.inc.php";
-
- function lessphp_double($arg) {
- list($type, $value) = $arg;
- return array($type, $value*2);
- }
-
- $less = new lessc;
- $less->registerFunction("double", "lessphp_double");
-
- // gives us a width of 800px
- echo $less->compile("div { width: double(400px); }");
- ```
-
-The second argument to `registerFunction` is any *callable value* that is
-understood by [`call_user_func`](http://php.net/call_user_func).
-
-If we are using PHP 5.3 or above then we are free to pass a function literal
-like so:
-
- ```php
- $less->registerFunction("double", function($arg) {
- list($type, $value, $unit) = $arg;
- return array($type, $value*2, $unit);
- });
- ```
-
-Now let's talk about the `double` function itself.
-
-Although a little verbose, the implementation gives us some insight on the type
-system. All values in **lessphp** are stored in an array where the 0th element
-is a string representing the type, and the other elements make up the
-associated data for that value.
-
-The best way to get an understanding of the system is to register is dummy
-function which does a `var_dump` on the argument. Try passing the function
-different values from LESS and see what the results are.
-
-The return value of the registered function must also be a **lessphp** type,
-but if it is a string or numeric value, it will automatically be coerced into
-an appropriate typed value. In our example, we reconstruct the value with our
-modifications while making sure that we preserve the original type.
-
-The instance of **lessphp** itself is sent to the registered function as the
-second argument in addition to the arguments array.
-
-## Command Line Interface
-
-**lessphp** comes with a command line script written in PHP that can be used to
-invoke the compiler from the terminal. On Linux and OSX, all you need to do is
-place `plessc` and `lessc.inc.php` somewhere in your PATH (or you can run it in
-the current directory as well). On windows you'll need a copy of `php.exe` to
-run the file. To compile a file, `input.less` to CSS, run:
-
- ```bash
- $ plessc input.less
- ```
-
-To write to a file, redirect standard out:
-
- ```bash
- $ plessc input.less > output.css
- ```
-
-To compile code directly on the command line:
-
- ```bash
- $ plessc -r "@color: red; body { color: @color; }"
- ```
-
-To watch a file for changes, and compile it as needed, use the `-w` flag:
-
- ```bash
- $ plessc -w input-file output-file
- ```
-
-Errors from watch mode are written to standard out.
-
-
-## License
-
-Copyright (c) 2012 Leaf Corcoran, <http://leafo.net/lessphp>
-
-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.
-
-
-*Also under GPL3 if required, see `LICENSE` file*
-
diff --git a/vendor/leafo/lessphp/lessc.inc.php b/vendor/leafo/lessphp/lessc.inc.php
deleted file mode 100644
index 2292f219..00000000
--- a/vendor/leafo/lessphp/lessc.inc.php
+++ /dev/null
@@ -1,3768 +0,0 @@
-<?php
-
-/**
- * lessphp v0.5.0
- * http://leafo.net/lessphp
- *
- * LESS CSS compiler, adapted from http://lesscss.org
- *
- * Copyright 2013, Leaf Corcoran <leafot@gmail.com>
- * Licensed under MIT or GPLv3, see LICENSE
- */
-
-
-/**
- * The LESS compiler and parser.
- *
- * Converting LESS to CSS is a three stage process. The incoming file is parsed
- * by `lessc_parser` into a syntax tree, then it is compiled into another tree
- * representing the CSS structure by `lessc`. The CSS tree is fed into a
- * formatter, like `lessc_formatter` which then outputs CSS as a string.
- *
- * During the first compile, all values are *reduced*, which means that their
- * types are brought to the lowest form before being dump as strings. This
- * handles math equations, variable dereferences, and the like.
- *
- * The `parse` function of `lessc` is the entry point.
- *
- * In summary:
- *
- * The `lessc` class creates an instance of the parser, feeds it LESS code,
- * then transforms the resulting tree to a CSS tree. This class also holds the
- * evaluation context, such as all available mixins and variables at any given
- * time.
- *
- * The `lessc_parser` class is only concerned with parsing its input.
- *
- * The `lessc_formatter` takes a CSS tree, and dumps it to a formatted string,
- * handling things like indentation.
- */
-class lessc {
- static public $VERSION = "v0.5.0";
-
- static public $TRUE = array("keyword", "true");
- static public $FALSE = array("keyword", "false");
-
- protected $libFunctions = array();
- protected $registeredVars = array();
- protected $preserveComments = false;
-
- public $vPrefix = '@'; // prefix of abstract properties
- public $mPrefix = '$'; // prefix of abstract blocks
- public $parentSelector = '&';
-
- public $importDisabled = false;
- public $importDir = '';
-
- protected $numberPrecision = null;
-
- protected $allParsedFiles = array();
-
- // set to the parser that generated the current line when compiling
- // so we know how to create error messages
- protected $sourceParser = null;
- protected $sourceLoc = null;
-
- static protected $nextImportId = 0; // uniquely identify imports
-
- // attempts to find the path of an import url, returns null for css files
- protected function findImport($url) {
- foreach ((array)$this->importDir as $dir) {
- $full = $dir.(substr($dir, -1) != '/' ? '/' : '').$url;
- if ($this->fileExists($file = $full.'.less') || $this->fileExists($file = $full)) {
- return $file;
- }
- }
-
- return null;
- }
-
- protected function fileExists($name) {
- return is_file($name);
- }
-
- static public function compressList($items, $delim) {
- if (!isset($items[1]) && isset($items[0])) return $items[0];
- else return array('list', $delim, $items);
- }
-
- static public function preg_quote($what) {
- return preg_quote($what, '/');
- }
-
- protected function tryImport($importPath, $parentBlock, $out) {
- if ($importPath[0] == "function" && $importPath[1] == "url") {
- $importPath = $this->flattenList($importPath[2]);
- }
-
- $str = $this->coerceString($importPath);
- if ($str === null) return false;
-
- $url = $this->compileValue($this->lib_e($str));
-
- // don't import if it ends in css
- if (substr_compare($url, '.css', -4, 4) === 0) return false;
-
- $realPath = $this->findImport($url);
-
- if ($realPath === null) return false;
-
- if ($this->importDisabled) {
- return array(false, "/* import disabled */");
- }
-
- if (isset($this->allParsedFiles[realpath($realPath)])) {
- return array(false, null);
- }
-
- $this->addParsedFile($realPath);
- $parser = $this->makeParser($realPath);
- $root = $parser->parse(file_get_contents($realPath));
-
- // set the parents of all the block props
- foreach ($root->props as $prop) {
- if ($prop[0] == "block") {
- $prop[1]->parent = $parentBlock;
- }
- }
-
- // copy mixins into scope, set their parents
- // bring blocks from import into current block
- // TODO: need to mark the source parser these came from this file
- foreach ($root->children as $childName => $child) {
- if (isset($parentBlock->children[$childName])) {
- $parentBlock->children[$childName] = array_merge(
- $parentBlock->children[$childName],
- $child);
- } else {
- $parentBlock->children[$childName] = $child;
- }
- }
-
- $pi = pathinfo($realPath);
- $dir = $pi["dirname"];
-
- list($top, $bottom) = $this->sortProps($root->props, true);
- $this->compileImportedProps($top, $parentBlock, $out, $parser, $dir);
-
- return array(true, $bottom, $parser, $dir);
- }
-
- protected function compileImportedProps($props, $block, $out, $sourceParser, $importDir) {
- $oldSourceParser = $this->sourceParser;
-
- $oldImport = $this->importDir;
-
- // TODO: this is because the importDir api is stupid
- $this->importDir = (array)$this->importDir;
- array_unshift($this->importDir, $importDir);
-
- foreach ($props as $prop) {
- $this->compileProp($prop, $block, $out);
- }
-
- $this->importDir = $oldImport;
- $this->sourceParser = $oldSourceParser;
- }
-
- /**
- * Recursively compiles a block.
- *
- * A block is analogous to a CSS block in most cases. A single LESS document
- * is encapsulated in a block when parsed, but it does not have parent tags
- * so all of it's children appear on the root level when compiled.
- *
- * Blocks are made up of props and children.
- *
- * Props are property instructions, array tuples which describe an action
- * to be taken, eg. write a property, set a variable, mixin a block.
- *
- * The children of a block are just all the blocks that are defined within.
- * This is used to look up mixins when performing a mixin.
- *
- * Compiling the block involves pushing a fresh environment on the stack,
- * and iterating through the props, compiling each one.
- *
- * See lessc::compileProp()
- *
- */
- protected function compileBlock($block) {
- switch ($block->type) {
- case "root":
- $this->compileRoot($block);
- break;
- case null:
- $this->compileCSSBlock($block);
- break;
- case "media":
- $this->compileMedia($block);
- break;
- case "directive":
- $name = "@" . $block->name;
- if (!empty($block->value)) {
- $name .= " " . $this->compileValue($this->reduce($block->value));
- }
-
- $this->compileNestedBlock($block, array($name));
- break;
- default:
- $this->throwError("unknown block type: $block->type\n");
- }
- }
-
- protected function compileCSSBlock($block) {
- $env = $this->pushEnv();
-
- $selectors = $this->compileSelectors($block->tags);
- $env->selectors = $this->multiplySelectors($selectors);
- $out = $this->makeOutputBlock(null, $env->selectors);
-
- $this->scope->children[] = $out;
- $this->compileProps($block, $out);
-
- $block->scope = $env; // mixins carry scope with them!
- $this->popEnv();
- }
-
- protected function compileMedia($media) {
- $env = $this->pushEnv($media);
- $parentScope = $this->mediaParent($this->scope);
-
- $query = $this->compileMediaQuery($this->multiplyMedia($env));
-
- $this->scope = $this->makeOutputBlock($media->type, array($query));
- $parentScope->children[] = $this->scope;
-
- $this->compileProps($media, $this->scope);
-
- if (count($this->scope->lines) > 0) {
- $orphanSelelectors = $this->findClosestSelectors();
- if (!is_null($orphanSelelectors)) {
- $orphan = $this->makeOutputBlock(null, $orphanSelelectors);
- $orphan->lines = $this->scope->lines;
- array_unshift($this->scope->children, $orphan);
- $this->scope->lines = array();
- }
- }
-
- $this->scope = $this->scope->parent;
- $this->popEnv();
- }
-
- protected function mediaParent($scope) {
- while (!empty($scope->parent)) {
- if (!empty($scope->type) && $scope->type != "media") {
- break;
- }
- $scope = $scope->parent;
- }
-
- return $scope;
- }
-
- protected function compileNestedBlock($block, $selectors) {
- $this->pushEnv($block);
- $this->scope = $this->makeOutputBlock($block->type, $selectors);
- $this->scope->parent->children[] = $this->scope;
-
- $this->compileProps($block, $this->scope);
-
- $this->scope = $this->scope->parent;
- $this->popEnv();
- }
-
- protected function compileRoot($root) {
- $this->pushEnv();
- $this->scope = $this->makeOutputBlock($root->type);
- $this->compileProps($root, $this->scope);
- $this->popEnv();
- }
-
- protected function compileProps($block, $out) {
- foreach ($this->sortProps($block->props) as $prop) {
- $this->compileProp($prop, $block, $out);
- }
- $out->lines = $this->deduplicate($out->lines);
- }
-
- /**
- * Deduplicate lines in a block. Comments are not deduplicated. If a
- * duplicate rule is detected, the comments immediately preceding each
- * occurence are consolidated.
- */
- protected function deduplicate($lines) {
- $unique = array();
- $comments = array();
-
- foreach($lines as $line) {
- if (strpos($line, '/*') === 0) {
- $comments[] = $line;
- continue;
- }
- if (!in_array($line, $unique)) {
- $unique[] = $line;
- }
- array_splice($unique, array_search($line, $unique), 0, $comments);
- $comments = array();
- }
- return array_merge($unique, $comments);
- }
-
- protected function sortProps($props, $split = false) {
- $vars = array();
- $imports = array();
- $other = array();
- $stack = array();
-
- foreach ($props as $prop) {
- switch ($prop[0]) {
- case "comment":
- $stack[] = $prop;
- break;
- case "assign":
- $stack[] = $prop;
- if (isset($prop[1][0]) && $prop[1][0] == $this->vPrefix) {
- $vars = array_merge($vars, $stack);
- } else {
- $other = array_merge($other, $stack);
- }
- $stack = array();
- break;
- case "import":
- $id = self::$nextImportId++;
- $prop[] = $id;
- $stack[] = $prop;
- $imports = array_merge($imports, $stack);
- $other[] = array("import_mixin", $id);
- $stack = array();
- break;
- default:
- $stack[] = $prop;
- $other = array_merge($other, $stack);
- $stack = array();
- break;
- }
- }
- $other = array_merge($other, $stack);
-
- if ($split) {
- return array(array_merge($imports, $vars), $other);
- } else {
- return array_merge($imports, $vars, $other);
- }
- }
-
- protected function compileMediaQuery($queries) {
- $compiledQueries = array();
- foreach ($queries as $query) {
- $parts = array();
- foreach ($query as $q) {
- switch ($q[0]) {
- case "mediaType":
- $parts[] = implode(" ", array_slice($q, 1));
- break;
- case "mediaExp":
- if (isset($q[2])) {
- $parts[] = "($q[1]: " .
- $this->compileValue($this->reduce($q[2])) . ")";
- } else {
- $parts[] = "($q[1])";
- }
- break;
- case "variable":
- $parts[] = $this->compileValue($this->reduce($q));
- break;
- }
- }
-
- if (count($parts) > 0) {
- $compiledQueries[] = implode(" and ", $parts);
- }
- }
-
- $out = "@media";
- if (!empty($parts)) {
- $out .= " " .
- implode($this->formatter->selectorSeparator, $compiledQueries);
- }
- return $out;
- }
-
- protected function multiplyMedia($env, $childQueries = null) {
- if (is_null($env) ||
- !empty($env->block->type) && $env->block->type != "media")
- {
- return $childQueries;
- }
-
- // plain old block, skip
- if (empty($env->block->type)) {
- return $this->multiplyMedia($env->parent, $childQueries);
- }
-
- $out = array();
- $queries = $env->block->queries;
- if (is_null($childQueries)) {
- $out = $queries;
- } else {
- foreach ($queries as $parent) {
- foreach ($childQueries as $child) {
- $out[] = array_merge($parent, $child);
- }
- }
- }
-
- return $this->multiplyMedia($env->parent, $out);
- }
-
- protected function expandParentSelectors(&$tag, $replace) {
- $parts = explode("$&$", $tag);
- $count = 0;
- foreach ($parts as &$part) {
- $part = str_replace($this->parentSelector, $replace, $part, $c);
- $count += $c;
- }
- $tag = implode($this->parentSelector, $parts);
- return $count;
- }
-
- protected function findClosestSelectors() {
- $env = $this->env;
- $selectors = null;
- while ($env !== null) {
- if (isset($env->selectors)) {
- $selectors = $env->selectors;
- break;
- }
- $env = $env->parent;
- }
-
- return $selectors;
- }
-
-
- // multiply $selectors against the nearest selectors in env
- protected function multiplySelectors($selectors) {
- // find parent selectors
-
- $parentSelectors = $this->findClosestSelectors();
- if (is_null($parentSelectors)) {
- // kill parent reference in top level selector
- foreach ($selectors as &$s) {
- $this->expandParentSelectors($s, "");
- }
-
- return $selectors;
- }
-
- $out = array();
- foreach ($parentSelectors as $parent) {
- foreach ($selectors as $child) {
- $count = $this->expandParentSelectors($child, $parent);
-
- // don't prepend the parent tag if & was used
- if ($count > 0) {
- $out[] = trim($child);
- } else {
- $out[] = trim($parent . ' ' . $child);
- }
- }
- }
-
- return $out;
- }
-
- // reduces selector expressions
- protected function compileSelectors($selectors) {
- $out = array();
-
- foreach ($selectors as $s) {
- if (is_array($s)) {
- list(, $value) = $s;
- $out[] = trim($this->compileValue($this->reduce($value)));
- } else {
- $out[] = $s;
- }
- }
-
- return $out;
- }
-
- protected function eq($left, $right) {
- return $left == $right;
- }
-
- protected function patternMatch($block, $orderedArgs, $keywordArgs) {
- // match the guards if it has them
- // any one of the groups must have all its guards pass for a match
- if (!empty($block->guards)) {
- $groupPassed = false;
- foreach ($block->guards as $guardGroup) {
- foreach ($guardGroup as $guard) {
- $this->pushEnv();
- $this->zipSetArgs($block->args, $orderedArgs, $keywordArgs);
-
- $negate = false;
- if ($guard[0] == "negate") {
- $guard = $guard[1];
- $negate = true;
- }
-
- $passed = $this->reduce($guard) == self::$TRUE;
- if ($negate) $passed = !$passed;
-
- $this->popEnv();
-
- if ($passed) {
- $groupPassed = true;
- } else {
- $groupPassed = false;
- break;
- }
- }
-
- if ($groupPassed) break;
- }
-
- if (!$groupPassed) {
- return false;
- }
- }
-
- if (empty($block->args)) {
- return $block->isVararg || empty($orderedArgs) && empty($keywordArgs);
- }
-
- $remainingArgs = $block->args;
- if ($keywordArgs) {
- $remainingArgs = array();
- foreach ($block->args as $arg) {
- if ($arg[0] == "arg" && isset($keywordArgs[$arg[1]])) {
- continue;
- }
-
- $remainingArgs[] = $arg;
- }
- }
-
- $i = -1; // no args
- // try to match by arity or by argument literal
- foreach ($remainingArgs as $i => $arg) {
- switch ($arg[0]) {
- case "lit":
- if (empty($orderedArgs[$i]) || !$this->eq($arg[1], $orderedArgs[$i])) {
- return false;
- }
- break;
- case "arg":
- // no arg and no default value
- if (!isset($orderedArgs[$i]) && !isset($arg[2])) {
- return false;
- }
- break;
- case "rest":
- $i--; // rest can be empty
- break 2;
- }
- }
-
- if ($block->isVararg) {
- return true; // not having enough is handled above
- } else {
- $numMatched = $i + 1;
- // greater than becuase default values always match
- return $numMatched >= count($orderedArgs);
- }
- }
-
- protected function patternMatchAll($blocks, $orderedArgs, $keywordArgs, $skip=array()) {
- $matches = null;
- foreach ($blocks as $block) {
- // skip seen blocks that don't have arguments
- if (isset($skip[$block->id]) && !isset($block->args)) {
- continue;
- }
-
- if ($this->patternMatch($block, $orderedArgs, $keywordArgs)) {
- $matches[] = $block;
- }
- }
-
- return $matches;
- }
-
- // attempt to find blocks matched by path and args
- protected function findBlocks($searchIn, $path, $orderedArgs, $keywordArgs, $seen=array()) {
- if ($searchIn == null) return null;
- if (isset($seen[$searchIn->id])) return null;
- $seen[$searchIn->id] = true;
-
- $name = $path[0];
-
- if (isset($searchIn->children[$name])) {
- $blocks = $searchIn->children[$name];
- if (count($path) == 1) {
- $matches = $this->patternMatchAll($blocks, $orderedArgs, $keywordArgs, $seen);
- if (!empty($matches)) {
- // This will return all blocks that match in the closest
- // scope that has any matching block, like lessjs
- return $matches;
- }
- } else {
- $matches = array();
- foreach ($blocks as $subBlock) {
- $subMatches = $this->findBlocks($subBlock,
- array_slice($path, 1), $orderedArgs, $keywordArgs, $seen);
-
- if (!is_null($subMatches)) {
- foreach ($subMatches as $sm) {
- $matches[] = $sm;
- }
- }
- }
-
- return count($matches) > 0 ? $matches : null;
- }
- }
- if ($searchIn->parent === $searchIn) return null;
- return $this->findBlocks($searchIn->parent, $path, $orderedArgs, $keywordArgs, $seen);
- }
-
- // sets all argument names in $args to either the default value
- // or the one passed in through $values
- protected function zipSetArgs($args, $orderedValues, $keywordValues) {
- $assignedValues = array();
-
- $i = 0;
- foreach ($args as $a) {
- if ($a[0] == "arg") {
- if (isset($keywordValues[$a[1]])) {
- // has keyword arg
- $value = $keywordValues[$a[1]];
- } elseif (isset($orderedValues[$i])) {
- // has ordered arg
- $value = $orderedValues[$i];
- $i++;
- } elseif (isset($a[2])) {
- // has default value
- $value = $a[2];
- } else {
- $this->throwError("Failed to assign arg " . $a[1]);
- $value = null; // :(
- }
-
- $value = $this->reduce($value);
- $this->set($a[1], $value);
- $assignedValues[] = $value;
- } else {
- // a lit
- $i++;
- }
- }
-
- // check for a rest
- $last = end($args);
- if ($last[0] == "rest") {
- $rest = array_slice($orderedValues, count($args) - 1);
- $this->set($last[1], $this->reduce(array("list", " ", $rest)));
- }
-
- // wow is this the only true use of PHP's + operator for arrays?
- $this->env->arguments = $assignedValues + $orderedValues;
- }
-
- // compile a prop and update $lines or $blocks appropriately
- protected function compileProp($prop, $block, $out) {
- // set error position context
- $this->sourceLoc = isset($prop[-1]) ? $prop[-1] : -1;
-
- switch ($prop[0]) {
- case 'assign':
- list(, $name, $value) = $prop;
- if ($name[0] == $this->vPrefix) {
- $this->set($name, $value);
- } else {
- $out->lines[] = $this->formatter->property($name,
- $this->compileValue($this->reduce($value)));
- }
- break;
- case 'block':
- list(, $child) = $prop;
- $this->compileBlock($child);
- break;
- case 'mixin':
- list(, $path, $args, $suffix) = $prop;
-
- $orderedArgs = array();
- $keywordArgs = array();
- foreach ((array)$args as $arg) {
- $argval = null;
- switch ($arg[0]) {
- case "arg":
- if (!isset($arg[2])) {
- $orderedArgs[] = $this->reduce(array("variable", $arg[1]));
- } else {
- $keywordArgs[$arg[1]] = $this->reduce($arg[2]);
- }
- break;
-
- case "lit":
- $orderedArgs[] = $this->reduce($arg[1]);
- break;
- default:
- $this->throwError("Unknown arg type: " . $arg[0]);
- }
- }
-
- $mixins = $this->findBlocks($block, $path, $orderedArgs, $keywordArgs);
-
- if ($mixins === null) {
- $this->throwError("{$prop[1][0]} is undefined");
- }
-
- foreach ($mixins as $mixin) {
- if ($mixin === $block && !$orderedArgs) {
- continue;
- }
-
- $haveScope = false;
- if (isset($mixin->parent->scope)) {
- $haveScope = true;
- $mixinParentEnv = $this->pushEnv();
- $mixinParentEnv->storeParent = $mixin->parent->scope;
- }
-
- $haveArgs = false;
- if (isset($mixin->args)) {
- $haveArgs = true;
- $this->pushEnv();
- $this->zipSetArgs($mixin->args, $orderedArgs, $keywordArgs);
- }
-
- $oldParent = $mixin->parent;
- if ($mixin != $block) $mixin->parent = $block;
-
- foreach ($this->sortProps($mixin->props) as $subProp) {
- if ($suffix !== null &&
- $subProp[0] == "assign" &&
- is_string($subProp[1]) &&
- $subProp[1]{0} != $this->vPrefix)
- {
- $subProp[2] = array(
- 'list', ' ',
- array($subProp[2], array('keyword', $suffix))
- );
- }
-
- $this->compileProp($subProp, $mixin, $out);
- }
-
- $mixin->parent = $oldParent;
-
- if ($haveArgs) $this->popEnv();
- if ($haveScope) $this->popEnv();
- }
-
- break;
- case 'raw':
- $out->lines[] = $prop[1];
- break;
- case "directive":
- list(, $name, $value) = $prop;
- $out->lines[] = "@$name " . $this->compileValue($this->reduce($value)).';';
- break;
- case "comment":
- $out->lines[] = $prop[1];
- break;
- case "import";
- list(, $importPath, $importId) = $prop;
- $importPath = $this->reduce($importPath);
-
- if (!isset($this->env->imports)) {
- $this->env->imports = array();
- }
-
- $result = $this->tryImport($importPath, $block, $out);
-
- $this->env->imports[$importId] = $result === false ?
- array(false, "@import " . $this->compileValue($importPath).";") :
- $result;
-
- break;
- case "import_mixin":
- list(,$importId) = $prop;
- $import = $this->env->imports[$importId];
- if ($import[0] === false) {
- if (isset($import[1])) {
- $out->lines[] = $import[1];
- }
- } else {
- list(, $bottom, $parser, $importDir) = $import;
- $this->compileImportedProps($bottom, $block, $out, $parser, $importDir);
- }
-
- break;
- default:
- $this->throwError("unknown op: {$prop[0]}\n");
- }
- }
-
-
- /**
- * Compiles a primitive value into a CSS property value.
- *
- * Values in lessphp are typed by being wrapped in arrays, their format is
- * typically:
- *
- * array(type, contents [, additional_contents]*)
- *
- * The input is expected to be reduced. This function will not work on
- * things like expressions and variables.
- */
- public function compileValue($value) {
- switch ($value[0]) {
- case 'list':
- // [1] - delimiter
- // [2] - array of values
- return implode($value[1], array_map(array($this, 'compileValue'), $value[2]));
- case 'raw_color':
- if (!empty($this->formatter->compressColors)) {
- return $this->compileValue($this->coerceColor($value));
- }
- return $value[1];
- case 'keyword':
- // [1] - the keyword
- return $value[1];
- case 'number':
- list(, $num, $unit) = $value;
- // [1] - the number
- // [2] - the unit
- if ($this->numberPrecision !== null) {
- $num = round($num, $this->numberPrecision);
- }
- return $num . $unit;
- case 'string':
- // [1] - contents of string (includes quotes)
- list(, $delim, $content) = $value;
- foreach ($content as &$part) {
- if (is_array($part)) {
- $part = $this->compileValue($part);
- }
- }
- return $delim . implode($content) . $delim;
- case 'color':
- // [1] - red component (either number or a %)
- // [2] - green component
- // [3] - blue component
- // [4] - optional alpha component
- list(, $r, $g, $b) = $value;
- $r = round($r);
- $g = round($g);
- $b = round($b);
-
- if (count($value) == 5 && $value[4] != 1) { // rgba
- return 'rgba('.$r.','.$g.','.$b.','.$value[4].')';
- }
-
- $h = sprintf("#%02x%02x%02x", $r, $g, $b);
-
- if (!empty($this->formatter->compressColors)) {
- // Converting hex color to short notation (e.g. #003399 to #039)
- if ($h[1] === $h[2] && $h[3] === $h[4] && $h[5] === $h[6]) {
- $h = '#' . $h[1] . $h[3] . $h[5];
- }
- }
-
- return $h;
-
- case 'function':
- list(, $name, $args) = $value;
- return $name.'('.$this->compileValue($args).')';
- default: // assumed to be unit
- $this->throwError("unknown value type: $value[0]");
- }
- }
-
- protected function lib_pow($args) {
- list($base, $exp) = $this->assertArgs($args, 2, "pow");
- return pow($this->assertNumber($base), $this->assertNumber($exp));
- }
-
- protected function lib_pi() {
- return pi();
- }
-
- protected function lib_mod($args) {
- list($a, $b) = $this->assertArgs($args, 2, "mod");
- return $this->assertNumber($a) % $this->assertNumber($b);
- }
-
- protected function lib_tan($num) {
- return tan($this->assertNumber($num));
- }
-
- protected function lib_sin($num) {
- return sin($this->assertNumber($num));
- }
-
- protected function lib_cos($num) {
- return cos($this->assertNumber($num));
- }
-
- protected function lib_atan($num) {
- $num = atan($this->assertNumber($num));
- return array("number", $num, "rad");
- }
-
- protected function lib_asin($num) {
- $num = asin($this->assertNumber($num));
- return array("number", $num, "rad");
- }
-
- protected function lib_acos($num) {
- $num = acos($this->assertNumber($num));
- return array("number", $num, "rad");
- }
-
- protected function lib_sqrt($num) {
- return sqrt($this->assertNumber($num));
- }
-
- protected function lib_extract($value) {
- list($list, $idx) = $this->assertArgs($value, 2, "extract");
- $idx = $this->assertNumber($idx);
- // 1 indexed
- if ($list[0] == "list" && isset($list[2][$idx - 1])) {
- return $list[2][$idx - 1];
- }
- }
-
- protected function lib_isnumber($value) {
- return $this->toBool($value[0] == "number");
- }
-
- protected function lib_isstring($value) {
- return $this->toBool($value[0] == "string");
- }
-
- protected function lib_iscolor($value) {
- return $this->toBool($this->coerceColor($value));
- }
-
- protected function lib_iskeyword($value) {
- return $this->toBool($value[0] == "keyword");
- }
-
- protected function lib_ispixel($value) {
- return $this->toBool($value[0] == "number" && $value[2] == "px");
- }
-
- protected function lib_ispercentage($value) {
- return $this->toBool($value[0] == "number" && $value[2] == "%");
- }
-
- protected function lib_isem($value) {
- return $this->toBool($value[0] == "number" && $value[2] == "em");
- }
-
- protected function lib_isrem($value) {
- return $this->toBool($value[0] == "number" && $value[2] == "rem");
- }
-
- protected function lib_rgbahex($color) {
- $color = $this->coerceColor($color);
- if (is_null($color))
- $this->throwError("color expected for rgbahex");
-
- return sprintf("#%02x%02x%02x%02x",
- isset($color[4]) ? $color[4]*255 : 255,
- $color[1],$color[2], $color[3]);
- }
-
- protected function lib_argb($color){
- return $this->lib_rgbahex($color);
- }
-
- /**
- * Given an url, decide whether to output a regular link or the base64-encoded contents of the file
- *
- * @param array $value either an argument list (two strings) or a single string
- * @return string formatted url(), either as a link or base64-encoded
- */
- protected function lib_data_uri($value) {
- $mime = ($value[0] === 'list') ? $value[2][0][2] : null;
- $url = ($value[0] === 'list') ? $value[2][1][2][0] : $value[2][0];
-
- $fullpath = $this->findImport($url);
-
- if($fullpath && ($fsize = filesize($fullpath)) !== false) {
- // IE8 can't handle data uris larger than 32KB
- if($fsize/1024 < 32) {
- if(is_null($mime)) {
- if(class_exists('finfo')) { // php 5.3+
- $finfo = new finfo(FILEINFO_MIME);
- $mime = explode('; ', $finfo->file($fullpath));
- $mime = $mime[0];
- } elseif(function_exists('mime_content_type')) { // PHP 5.2
- $mime = mime_content_type($fullpath);
- }
- }
-
- if(!is_null($mime)) // fallback if the mime type is still unknown
- $url = sprintf('data:%s;base64,%s', $mime, base64_encode(file_get_contents($fullpath)));
- }
- }
-
- return 'url("'.$url.'")';
- }
-
- // utility func to unquote a string
- protected function lib_e($arg) {
- switch ($arg[0]) {
- case "list":
- $items = $arg[2];
- if (isset($items[0])) {
- return $this->lib_e($items[0]);
- }
- $this->throwError("unrecognised input");
- case "string":
- $arg[1] = "";
- return $arg;
- case "keyword":
- return $arg;
- default:
- return array("keyword", $this->compileValue($arg));
- }
- }
-
- protected function lib__sprintf($args) {
- if ($args[0] != "list") return $args;
- $values = $args[2];
- $string = array_shift($values);
- $template = $this->compileValue($this->lib_e($string));
-
- $i = 0;
- if (preg_match_all('/%[dsa]/', $template, $m)) {
- foreach ($m[0] as $match) {
- $val = isset($values[$i]) ?
- $this->reduce($values[$i]) : array('keyword', '');
-
- // lessjs compat, renders fully expanded color, not raw color
- if ($color = $this->coerceColor($val)) {
- $val = $color;
- }
-
- $i++;
- $rep = $this->compileValue($this->lib_e($val));
- $template = preg_replace('/'.self::preg_quote($match).'/',
- $rep, $template, 1);
- }
- }
-
- $d = $string[0] == "string" ? $string[1] : '"';
- return array("string", $d, array($template));
- }
-
- protected function lib_floor($arg) {
- $value = $this->assertNumber($arg);
- return array("number", floor($value), $arg[2]);
- }
-
- protected function lib_ceil($arg) {
- $value = $this->assertNumber($arg);
- return array("number", ceil($value), $arg[2]);
- }
-
- protected function lib_round($arg) {
- if($arg[0] != "list") {
- $value = $this->assertNumber($arg);
- return array("number", round($value), $arg[2]);
- } else {
- $value = $this->assertNumber($arg[2][0]);
- $precision = $this->assertNumber($arg[2][1]);
- return array("number", round($value, $precision), $arg[2][0][2]);
- }
- }
-
- protected function lib_unit($arg) {
- if ($arg[0] == "list") {
- list($number, $newUnit) = $arg[2];
- return array("number", $this->assertNumber($number),
- $this->compileValue($this->lib_e($newUnit)));
- } else {
- return array("number", $this->assertNumber($arg), "");
- }
- }
-
- /**
- * Helper function to get arguments for color manipulation functions.
- * takes a list that contains a color like thing and a percentage
- */
- public function colorArgs($args) {
- if ($args[0] != 'list' || count($args[2]) < 2) {
- return array(array('color', 0, 0, 0), 0);
- }
- list($color, $delta) = $args[2];
- $color = $this->assertColor($color);
- $delta = floatval($delta[1]);
-
- return array($color, $delta);
- }
-
- protected function lib_darken($args) {
- list($color, $delta) = $this->colorArgs($args);
-
- $hsl = $this->toHSL($color);
- $hsl[3] = $this->clamp($hsl[3] - $delta, 100);
- return $this->toRGB($hsl);
- }
-
- protected function lib_lighten($args) {
- list($color, $delta) = $this->colorArgs($args);
-
- $hsl = $this->toHSL($color);
- $hsl[3] = $this->clamp($hsl[3] + $delta, 100);
- return $this->toRGB($hsl);
- }
-
- protected function lib_saturate($args) {
- list($color, $delta) = $this->colorArgs($args);
-
- $hsl = $this->toHSL($color);
- $hsl[2] = $this->clamp($hsl[2] + $delta, 100);
- return $this->toRGB($hsl);
- }
-
- protected function lib_desaturate($args) {
- list($color, $delta) = $this->colorArgs($args);
-
- $hsl = $this->toHSL($color);
- $hsl[2] = $this->clamp($hsl[2] - $delta, 100);
- return $this->toRGB($hsl);
- }
-
- protected function lib_spin($args) {
- list($color, $delta) = $this->colorArgs($args);
-
- $hsl = $this->toHSL($color);
-
- $hsl[1] = $hsl[1] + $delta % 360;
- if ($hsl[1] < 0) $hsl[1] += 360;
-
- return $this->toRGB($hsl);
- }
-
- protected function lib_fadeout($args) {
- list($color, $delta) = $this->colorArgs($args);
- $color[4] = $this->clamp((isset($color[4]) ? $color[4] : 1) - $delta/100);
- return $color;
- }
-
- protected function lib_fadein($args) {
- list($color, $delta) = $this->colorArgs($args);
- $color[4] = $this->clamp((isset($color[4]) ? $color[4] : 1) + $delta/100);
- return $color;
- }
-
- protected function lib_hue($color) {
- $hsl = $this->toHSL($this->assertColor($color));
- return round($hsl[1]);
- }
-
- protected function lib_saturation($color) {
- $hsl = $this->toHSL($this->assertColor($color));
- return round($hsl[2]);
- }
-
- protected function lib_lightness($color) {
- $hsl = $this->toHSL($this->assertColor($color));
- return round($hsl[3]);
- }
-
- // get the alpha of a color
- // defaults to 1 for non-colors or colors without an alpha
- protected function lib_alpha($value) {
- if (!is_null($color = $this->coerceColor($value))) {
- return isset($color[4]) ? $color[4] : 1;
- }
- }
-
- // set the alpha of the color
- protected function lib_fade($args) {
- list($color, $alpha) = $this->colorArgs($args);
- $color[4] = $this->clamp($alpha / 100.0);
- return $color;
- }
-
- protected function lib_percentage($arg) {
- $num = $this->assertNumber($arg);
- return array("number", $num*100, "%");
- }
-
- // mixes two colors by weight
- // mix(@color1, @color2, [@weight: 50%]);
- // http://sass-lang.com/docs/yardoc/Sass/Script/Functions.html#mix-instance_method
- protected function lib_mix($args) {
- if ($args[0] != "list" || count($args[2]) < 2)
- $this->throwError("mix expects (color1, color2, weight)");
-
- list($first, $second) = $args[2];
- $first = $this->assertColor($first);
- $second = $this->assertColor($second);
-
- $first_a = $this->lib_alpha($first);
- $second_a = $this->lib_alpha($second);
-
- if (isset($args[2][2])) {
- $weight = $args[2][2][1] / 100.0;
- } else {
- $weight = 0.5;
- }
-
- $w = $weight * 2 - 1;
- $a = $first_a - $second_a;
-
- $w1 = (($w * $a == -1 ? $w : ($w + $a)/(1 + $w * $a)) + 1) / 2.0;
- $w2 = 1.0 - $w1;
-
- $new = array('color',
- $w1 * $first[1] + $w2 * $second[1],
- $w1 * $first[2] + $w2 * $second[2],
- $w1 * $first[3] + $w2 * $second[3],
- );
-
- if ($first_a != 1.0 || $second_a != 1.0) {
- $new[] = $first_a * $weight + $second_a * ($weight - 1);
- }
-
- return $this->fixColor($new);
- }
-
- protected function lib_contrast($args) {
- $darkColor = array('color', 0, 0, 0);
- $lightColor = array('color', 255, 255, 255);
- $threshold = 0.43;
-
- if ( $args[0] == 'list' ) {
- $inputColor = ( isset($args[2][0]) ) ? $this->assertColor($args[2][0]) : $lightColor;
- $darkColor = ( isset($args[2][1]) ) ? $this->assertColor($args[2][1]) : $darkColor;
- $lightColor = ( isset($args[2][2]) ) ? $this->assertColor($args[2][2]) : $lightColor;
- $threshold = ( isset($args[2][3]) ) ? $this->assertNumber($args[2][3]) : $threshold;
- }
- else {
- $inputColor = $this->assertColor($args);
- }
-
- $inputColor = $this->coerceColor($inputColor);
- $darkColor = $this->coerceColor($darkColor);
- $lightColor = $this->coerceColor($lightColor);
-
- //Figure out which is actually light and dark!
- if ( $this->lib_luma($darkColor) > $this->lib_luma($lightColor) ) {
- $t = $lightColor;
- $lightColor = $darkColor;
- $darkColor = $t;
- }
-
- $inputColor_alpha = $this->lib_alpha($inputColor);
- if ( ( $this->lib_luma($inputColor) * $inputColor_alpha) < $threshold) {
- return $lightColor;
- }
- return $darkColor;
- }
-
- protected function lib_luma($color) {
- $color = $this->coerceColor($color);
- return (0.2126 * $color[0] / 255) + (0.7152 * $color[1] / 255) + (0.0722 * $color[2] / 255);
- }
-
-
- public function assertColor($value, $error = "expected color value") {
- $color = $this->coerceColor($value);
- if (is_null($color)) $this->throwError($error);
- return $color;
- }
-
- public function assertNumber($value, $error = "expecting number") {
- if ($value[0] == "number") return $value[1];
- $this->throwError($error);
- }
-
- public function assertArgs($value, $expectedArgs, $name="") {
- if ($expectedArgs == 1) {
- return $value;
- } else {
- if ($value[0] !== "list" || $value[1] != ",") $this->throwError("expecting list");
- $values = $value[2];
- $numValues = count($values);
- if ($expectedArgs != $numValues) {
- if ($name) {
- $name = $name . ": ";
- }
-
- $this->throwError("${name}expecting $expectedArgs arguments, got $numValues");
- }
-
- return $values;
- }
- }
-
- protected function toHSL($color) {
- if ($color[0] == 'hsl') return $color;
-
- $r = $color[1] / 255;
- $g = $color[2] / 255;
- $b = $color[3] / 255;
-
- $min = min($r, $g, $b);
- $max = max($r, $g, $b);
-
- $L = ($min + $max) / 2;
- if ($min == $max) {
- $S = $H = 0;
- } else {
- if ($L < 0.5)
- $S = ($max - $min)/($max + $min);
- else
- $S = ($max - $min)/(2.0 - $max - $min);
-
- if ($r == $max) $H = ($g - $b)/($max - $min);
- elseif ($g == $max) $H = 2.0 + ($b - $r)/($max - $min);
- elseif ($b == $max) $H = 4.0 + ($r - $g)/($max - $min);
-
- }
-
- $out = array('hsl',
- ($H < 0 ? $H + 6 : $H)*60,
- $S*100,
- $L*100,
- );
-
- if (count($color) > 4) $out[] = $color[4]; // copy alpha
- return $out;
- }
-
- protected function toRGB_helper($comp, $temp1, $temp2) {
- if ($comp < 0) $comp += 1.0;
- elseif ($comp > 1) $comp -= 1.0;
-
- if (6 * $comp < 1) return $temp1 + ($temp2 - $temp1) * 6 * $comp;
- if (2 * $comp < 1) return $temp2;
- if (3 * $comp < 2) return $temp1 + ($temp2 - $temp1)*((2/3) - $comp) * 6;
-
- return $temp1;
- }
-
- /**
- * Converts a hsl array into a color value in rgb.
- * Expects H to be in range of 0 to 360, S and L in 0 to 100
- */
- protected function toRGB($color) {
- if ($color[0] == 'color') return $color;
-
- $H = $color[1] / 360;
- $S = $color[2] / 100;
- $L = $color[3] / 100;
-
- if ($S == 0) {
- $r = $g = $b = $L;
- } else {
- $temp2 = $L < 0.5 ?
- $L*(1.0 + $S) :
- $L + $S - $L * $S;
-
- $temp1 = 2.0 * $L - $temp2;
-
- $r = $this->toRGB_helper($H + 1/3, $temp1, $temp2);
- $g = $this->toRGB_helper($H, $temp1, $temp2);
- $b = $this->toRGB_helper($H - 1/3, $temp1, $temp2);
- }
-
- // $out = array('color', round($r*255), round($g*255), round($b*255));
- $out = array('color', $r*255, $g*255, $b*255);
- if (count($color) > 4) $out[] = $color[4]; // copy alpha
- return $out;
- }
-
- protected function clamp($v, $max = 1, $min = 0) {
- return min($max, max($min, $v));
- }
-
- /**
- * Convert the rgb, rgba, hsl color literals of function type
- * as returned by the parser into values of color type.
- */
- protected function funcToColor($func) {
- $fname = $func[1];
- if ($func[2][0] != 'list') return false; // need a list of arguments
- $rawComponents = $func[2][2];
-
- if ($fname == 'hsl' || $fname == 'hsla') {
- $hsl = array('hsl');
- $i = 0;
- foreach ($rawComponents as $c) {
- $val = $this->reduce($c);
- $val = isset($val[1]) ? floatval($val[1]) : 0;
-
- if ($i == 0) $clamp = 360;
- elseif ($i < 3) $clamp = 100;
- else $clamp = 1;
-
- $hsl[] = $this->clamp($val, $clamp);
- $i++;
- }
-
- while (count($hsl) < 4) $hsl[] = 0;
- return $this->toRGB($hsl);
-
- } elseif ($fname == 'rgb' || $fname == 'rgba') {
- $components = array();
- $i = 1;
- foreach ($rawComponents as $c) {
- $c = $this->reduce($c);
- if ($i < 4) {
- if ($c[0] == "number" && $c[2] == "%") {
- $components[] = 255 * ($c[1] / 100);
- } else {
- $components[] = floatval($c[1]);
- }
- } elseif ($i == 4) {
- if ($c[0] == "number" && $c[2] == "%") {
- $components[] = 1.0 * ($c[1] / 100);
- } else {
- $components[] = floatval($c[1]);
- }
- } else break;
-
- $i++;
- }
- while (count($components) < 3) $components[] = 0;
- array_unshift($components, 'color');
- return $this->fixColor($components);
- }
-
- return false;
- }
-
- protected function reduce($value, $forExpression = false) {
- switch ($value[0]) {
- case "interpolate":
- $reduced = $this->reduce($value[1]);
- $var = $this->compileValue($reduced);
- $res = $this->reduce(array("variable", $this->vPrefix . $var));
-
- if ($res[0] == "raw_color") {
- $res = $this->coerceColor($res);
- }
-
- if (empty($value[2])) $res = $this->lib_e($res);
-
- return $res;
- case "variable":
- $key = $value[1];
- if (is_array($key)) {
- $key = $this->reduce($key);
- $key = $this->vPrefix . $this->compileValue($this->lib_e($key));
- }
-
- $seen =& $this->env->seenNames;
-
- if (!empty($seen[$key])) {
- $this->throwError("infinite loop detected: $key");
- }
-
- $seen[$key] = true;
- $out = $this->reduce($this->get($key));
- $seen[$key] = false;
- return $out;
- case "list":
- foreach ($value[2] as &$item) {
- $item = $this->reduce($item, $forExpression);
- }
- return $value;
- case "expression":
- return $this->evaluate($value);
- case "string":
- foreach ($value[2] as &$part) {
- if (is_array($part)) {
- $strip = $part[0] == "variable";
- $part = $this->reduce($part);
- if ($strip) $part = $this->lib_e($part);
- }
- }
- return $value;
- case "escape":
- list(,$inner) = $value;
- return $this->lib_e($this->reduce($inner));
- case "function":
- $color = $this->funcToColor($value);
- if ($color) return $color;
-
- list(, $name, $args) = $value;
- if ($name == "%") $name = "_sprintf";
-
- $f = isset($this->libFunctions[$name]) ?
- $this->libFunctions[$name] : array($this, 'lib_'.str_replace('-', '_', $name));
-
- if (is_callable($f)) {
- if ($args[0] == 'list')
- $args = self::compressList($args[2], $args[1]);
-
- $ret = call_user_func($f, $this->reduce($args, true), $this);
-
- if (is_null($ret)) {
- return array("string", "", array(
- $name, "(", $args, ")"
- ));
- }
-
- // convert to a typed value if the result is a php primitive
- if (is_numeric($ret)) $ret = array('number', $ret, "");
- elseif (!is_array($ret)) $ret = array('keyword', $ret);
-
- return $ret;
- }
-
- // plain function, reduce args
- $value[2] = $this->reduce($value[2]);
- return $value;
- case "unary":
- list(, $op, $exp) = $value;
- $exp = $this->reduce($exp);
-
- if ($exp[0] == "number") {
- switch ($op) {
- case "+":
- return $exp;
- case "-":
- $exp[1] *= -1;
- return $exp;
- }
- }
- return array("string", "", array($op, $exp));
- }
-
- if ($forExpression) {
- switch ($value[0]) {
- case "keyword":
- if ($color = $this->coerceColor($value)) {
- return $color;
- }
- break;
- case "raw_color":
- return $this->coerceColor($value);
- }
- }
-
- return $value;
- }
-
-
- // coerce a value for use in color operation
- protected function coerceColor($value) {
- switch($value[0]) {
- case 'color': return $value;
- case 'raw_color':
- $c = array("color", 0, 0, 0);
- $colorStr = substr($value[1], 1);
- $num = hexdec($colorStr);
- $width = strlen($colorStr) == 3 ? 16 : 256;
-
- for ($i = 3; $i > 0; $i--) { // 3 2 1
- $t = $num % $width;
- $num /= $width;
-
- $c[$i] = $t * (256/$width) + $t * floor(16/$width);
- }
-
- return $c;
- case 'keyword':
- $name = $value[1];
- if (isset(self::$cssColors[$name])) {
- $rgba = explode(',', self::$cssColors[$name]);
-
- if(isset($rgba[3]))
- return array('color', $rgba[0], $rgba[1], $rgba[2], $rgba[3]);
-
- return array('color', $rgba[0], $rgba[1], $rgba[2]);
- }
- return null;
- }
- }
-
- // make something string like into a string
- protected function coerceString($value) {
- switch ($value[0]) {
- case "string":
- return $value;
- case "keyword":
- return array("string", "", array($value[1]));
- }
- return null;
- }
-
- // turn list of length 1 into value type
- protected function flattenList($value) {
- if ($value[0] == "list" && count($value[2]) == 1) {
- return $this->flattenList($value[2][0]);
- }
- return $value;
- }
-
- public function toBool($a) {
- if ($a) return self::$TRUE;
- else return self::$FALSE;
- }
-
- // evaluate an expression
- protected function evaluate($exp) {
- list(, $op, $left, $right, $whiteBefore, $whiteAfter) = $exp;
-
- $left = $this->reduce($left, true);
- $right = $this->reduce($right, true);
-
- if ($leftColor = $this->coerceColor($left)) {
- $left = $leftColor;
- }
-
- if ($rightColor = $this->coerceColor($right)) {
- $right = $rightColor;
- }
-
- $ltype = $left[0];
- $rtype = $right[0];
-
- // operators that work on all types
- if ($op == "and") {
- return $this->toBool($left == self::$TRUE && $right == self::$TRUE);
- }
-
- if ($op == "=") {
- return $this->toBool($this->eq($left, $right) );
- }
-
- if ($op == "+" && !is_null($str = $this->stringConcatenate($left, $right))) {
- return $str;
- }
-
- // type based operators
- $fname = "op_${ltype}_${rtype}";
- if (is_callable(array($this, $fname))) {
- $out = $this->$fname($op, $left, $right);
- if (!is_null($out)) return $out;
- }
-
- // make the expression look it did before being parsed
- $paddedOp = $op;
- if ($whiteBefore) $paddedOp = " " . $paddedOp;
- if ($whiteAfter) $paddedOp .= " ";
-
- return array("string", "", array($left, $paddedOp, $right));
- }
-
- protected function stringConcatenate($left, $right) {
- if ($strLeft = $this->coerceString($left)) {
- if ($right[0] == "string") {
- $right[1] = "";
- }
- $strLeft[2][] = $right;
- return $strLeft;
- }
-
- if ($strRight = $this->coerceString($right)) {
- array_unshift($strRight[2], $left);
- return $strRight;
- }
- }
-
-
- // make sure a color's components don't go out of bounds
- protected function fixColor($c) {
- foreach (range(1, 3) as $i) {
- if ($c[$i] < 0) $c[$i] = 0;
- if ($c[$i] > 255) $c[$i] = 255;
- }
-
- return $c;
- }
-
- protected function op_number_color($op, $lft, $rgt) {
- if ($op == '+' || $op == '*') {
- return $this->op_color_number($op, $rgt, $lft);
- }
- }
-
- protected function op_color_number($op, $lft, $rgt) {
- if ($rgt[0] == '%') $rgt[1] /= 100;
-
- return $this->op_color_color($op, $lft,
- array_fill(1, count($lft) - 1, $rgt[1]));
- }
-
- protected function op_color_color($op, $left, $right) {
- $out = array('color');
- $max = count($left) > count($right) ? count($left) : count($right);
- foreach (range(1, $max - 1) as $i) {
- $lval = isset($left[$i]) ? $left[$i] : 0;
- $rval = isset($right[$i]) ? $right[$i] : 0;
- switch ($op) {
- case '+':
- $out[] = $lval + $rval;
- break;
- case '-':
- $out[] = $lval - $rval;
- break;
- case '*':
- $out[] = $lval * $rval;
- break;
- case '%':
- $out[] = $lval % $rval;
- break;
- case '/':
- if ($rval == 0) $this->throwError("evaluate error: can't divide by zero");
- $out[] = $lval / $rval;
- break;
- default:
- $this->throwError('evaluate error: color op number failed on op '.$op);
- }
- }
- return $this->fixColor($out);
- }
-
- function lib_red($color){
- $color = $this->coerceColor($color);
- if (is_null($color)) {
- $this->throwError('color expected for red()');
- }
-
- return $color[1];
- }
-
- function lib_green($color){
- $color = $this->coerceColor($color);
- if (is_null($color)) {
- $this->throwError('color expected for green()');
- }
-
- return $color[2];
- }
-
- function lib_blue($color){
- $color = $this->coerceColor($color);
- if (is_null($color)) {
- $this->throwError('color expected for blue()');
- }
-
- return $color[3];
- }
-
-
- // operator on two numbers
- protected function op_number_number($op, $left, $right) {
- $unit = empty($left[2]) ? $right[2] : $left[2];
-
- $value = 0;
- switch ($op) {
- case '+':
- $value = $left[1] + $right[1];
- break;
- case '*':
- $value = $left[1] * $right[1];
- break;
- case '-':
- $value = $left[1] - $right[1];
- break;
- case '%':
- $value = $left[1] % $right[1];
- break;
- case '/':
- if ($right[1] == 0) $this->throwError('parse error: divide by zero');
- $value = $left[1] / $right[1];
- break;
- case '<':
- return $this->toBool($left[1] < $right[1]);
- case '>':
- return $this->toBool($left[1] > $right[1]);
- case '>=':
- return $this->toBool($left[1] >= $right[1]);
- case '=<':
- return $this->toBool($left[1] <= $right[1]);
- default:
- $this->throwError('parse error: unknown number operator: '.$op);
- }
-
- return array("number", $value, $unit);
- }
-
-
- /* environment functions */
-
- protected function makeOutputBlock($type, $selectors = null) {
- $b = new stdclass;
- $b->lines = array();
- $b->children = array();
- $b->selectors = $selectors;
- $b->type = $type;
- $b->parent = $this->scope;
- return $b;
- }
-
- // the state of execution
- protected function pushEnv($block = null) {
- $e = new stdclass;
- $e->parent = $this->env;
- $e->store = array();
- $e->block = $block;
-
- $this->env = $e;
- return $e;
- }
-
- // pop something off the stack
- protected function popEnv() {
- $old = $this->env;
- $this->env = $this->env->parent;
- return $old;
- }
-
- // set something in the current env
- protected function set($name, $value) {
- $this->env->store[$name] = $value;
- }
-
-
- // get the highest occurrence entry for a name
- protected function get($name) {
- $current = $this->env;
-
- $isArguments = $name == $this->vPrefix . 'arguments';
- while ($current) {
- if ($isArguments && isset($current->arguments)) {
- return array('list', ' ', $current->arguments);
- }
-
- if (isset($current->store[$name]))
- return $current->store[$name];
- else {
- $current = isset($current->storeParent) ?
- $current->storeParent : $current->parent;
- }
- }
-
- $this->throwError("variable $name is undefined");
- }
-
- // inject array of unparsed strings into environment as variables
- protected function injectVariables($args) {
- $this->pushEnv();
- $parser = new lessc_parser($this, __METHOD__);
- foreach ($args as $name => $strValue) {
- if ($name{0} != '@') $name = '@'.$name;
- $parser->count = 0;
- $parser->buffer = (string)$strValue;
- if (!$parser->propertyValue($value)) {
- throw new Exception("failed to parse passed in variable $name: $strValue");
- }
-
- $this->set($name, $value);
- }
- }
-
- /**
- * Initialize any static state, can initialize parser for a file
- * $opts isn't used yet
- */
- public function __construct($fname = null) {
- if ($fname !== null) {
- // used for deprecated parse method
- $this->_parseFile = $fname;
- }
- }
-
- public function compile($string, $name = null) {
- $locale = setlocale(LC_NUMERIC, 0);
- setlocale(LC_NUMERIC, "C");
-
- $this->parser = $this->makeParser($name);
- $root = $this->parser->parse($string);
-
- $this->env = null;
- $this->scope = null;
-
- $this->formatter = $this->newFormatter();
-
- if (!empty($this->registeredVars)) {
- $this->injectVariables($this->registeredVars);
- }
-
- $this->sourceParser = $this->parser; // used for error messages
- $this->compileBlock($root);
-
- ob_start();
- $this->formatter->block($this->scope);
- $out = ob_get_clean();
- setlocale(LC_NUMERIC, $locale);
- return $out;
- }
-
- public function compileFile($fname, $outFname = null) {
- if (!is_readable($fname)) {
- throw new Exception('load error: failed to find '.$fname);
- }
-
- $pi = pathinfo($fname);
-
- $oldImport = $this->importDir;
-
- $this->importDir = (array)$this->importDir;
- $this->importDir[] = $pi['dirname'].'/';
-
- $this->addParsedFile($fname);
-
- $out = $this->compile(file_get_contents($fname), $fname);
-
- $this->importDir = $oldImport;
-
- if ($outFname !== null) {
- return file_put_contents($outFname, $out);
- }
-
- return $out;
- }
-
- // compile only if changed input has changed or output doesn't exist
- public function checkedCompile($in, $out) {
- if (!is_file($out) || filemtime($in) > filemtime($out)) {
- $this->compileFile($in, $out);
- return true;
- }
- return false;
- }
-
- /**
- * Execute lessphp on a .less file or a lessphp cache structure
- *
- * The lessphp cache structure contains information about a specific
- * less file having been parsed. It can be used as a hint for future
- * calls to determine whether or not a rebuild is required.
- *
- * The cache structure contains two important keys that may be used
- * externally:
- *
- * compiled: The final compiled CSS
- * updated: The time (in seconds) the CSS was last compiled
- *
- * The cache structure is a plain-ol' PHP associative array and can
- * be serialized and unserialized without a hitch.
- *
- * @param mixed $in Input
- * @param bool $force Force rebuild?
- * @return array lessphp cache structure
- */
- public function cachedCompile($in, $force = false) {
- // assume no root
- $root = null;
-
- if (is_string($in)) {
- $root = $in;
- } elseif (is_array($in) and isset($in['root'])) {
- if ($force or ! isset($in['files'])) {
- // If we are forcing a recompile or if for some reason the
- // structure does not contain any file information we should
- // specify the root to trigger a rebuild.
- $root = $in['root'];
- } elseif (isset($in['files']) and is_array($in['files'])) {
- foreach ($in['files'] as $fname => $ftime ) {
- if (!file_exists($fname) or filemtime($fname) > $ftime) {
- // One of the files we knew about previously has changed
- // so we should look at our incoming root again.
- $root = $in['root'];
- break;
- }
- }
- }
- } else {
- // TODO: Throw an exception? We got neither a string nor something
- // that looks like a compatible lessphp cache structure.
- return null;
- }
-
- if ($root !== null) {
- // If we have a root value which means we should rebuild.
- $out = array();
- $out['root'] = $root;
- $out['compiled'] = $this->compileFile($root);
- $out['files'] = $this->allParsedFiles();
- $out['updated'] = time();
- return $out;
- } else {
- // No changes, pass back the structure
- // we were given initially.
- return $in;
- }
-
- }
-
- // parse and compile buffer
- // This is deprecated
- public function parse($str = null, $initialVariables = null) {
- if (is_array($str)) {
- $initialVariables = $str;
- $str = null;
- }
-
- $oldVars = $this->registeredVars;
- if ($initialVariables !== null) {
- $this->setVariables($initialVariables);
- }
-
- if ($str == null) {
- if (empty($this->_parseFile)) {
- throw new exception("nothing to parse");
- }
-
- $out = $this->compileFile($this->_parseFile);
- } else {
- $out = $this->compile($str);
- }
-
- $this->registeredVars = $oldVars;
- return $out;
- }
-
- protected function makeParser($name) {
- $parser = new lessc_parser($this, $name);
- $parser->writeComments = $this->preserveComments;
-
- return $parser;
- }
-
- public function setFormatter($name) {
- $this->formatterName = $name;
- }
-
- protected function newFormatter() {
- $className = "lessc_formatter_lessjs";
- if (!empty($this->formatterName)) {
- if (!is_string($this->formatterName))
- return $this->formatterName;
- $className = "lessc_formatter_$this->formatterName";
- }
-
- return new $className;
- }
-
- public function setPreserveComments($preserve) {
- $this->preserveComments = $preserve;
- }
-
- public function registerFunction($name, $func) {
- $this->libFunctions[$name] = $func;
- }
-
- public function unregisterFunction($name) {
- unset($this->libFunctions[$name]);
- }
-
- public function setVariables($variables) {
- $this->registeredVars = array_merge($this->registeredVars, $variables);
- }
-
- public function unsetVariable($name) {
- unset($this->registeredVars[$name]);
- }
-
- public function setImportDir($dirs) {
- $this->importDir = (array)$dirs;
- }
-
- public function addImportDir($dir) {
- $this->importDir = (array)$this->importDir;
- $this->importDir[] = $dir;
- }
-
- public function allParsedFiles() {
- return $this->allParsedFiles;
- }
-
- public function addParsedFile($file) {
- $this->allParsedFiles[realpath($file)] = filemtime($file);
- }
-
- /**
- * Uses the current value of $this->count to show line and line number
- */
- public function throwError($msg = null) {
- if ($this->sourceLoc >= 0) {
- $this->sourceParser->throwError($msg, $this->sourceLoc);
- }
- throw new exception($msg);
- }
-
- // compile file $in to file $out if $in is newer than $out
- // returns true when it compiles, false otherwise
- public static function ccompile($in, $out, $less = null) {
- if ($less === null) {
- $less = new self;
- }
- return $less->checkedCompile($in, $out);
- }
-
- public static function cexecute($in, $force = false, $less = null) {
- if ($less === null) {
- $less = new self;
- }
- return $less->cachedCompile($in, $force);
- }
-
- static protected $cssColors = array(
- 'aliceblue' => '240,248,255',
- 'antiquewhite' => '250,235,215',
- 'aqua' => '0,255,255',
- 'aquamarine' => '127,255,212',
- 'azure' => '240,255,255',
- 'beige' => '245,245,220',
- 'bisque' => '255,228,196',
- 'black' => '0,0,0',
- 'blanchedalmond' => '255,235,205',
- 'blue' => '0,0,255',
- 'blueviolet' => '138,43,226',
- 'brown' => '165,42,42',
- 'burlywood' => '222,184,135',
- 'cadetblue' => '95,158,160',
- 'chartreuse' => '127,255,0',
- 'chocolate' => '210,105,30',
- 'coral' => '255,127,80',
- 'cornflowerblue' => '100,149,237',
- 'cornsilk' => '255,248,220',
- 'crimson' => '220,20,60',
- 'cyan' => '0,255,255',
- 'darkblue' => '0,0,139',
- 'darkcyan' => '0,139,139',
- 'darkgoldenrod' => '184,134,11',
- 'darkgray' => '169,169,169',
- 'darkgreen' => '0,100,0',
- 'darkgrey' => '169,169,169',
- 'darkkhaki' => '189,183,107',
- 'darkmagenta' => '139,0,139',
- 'darkolivegreen' => '85,107,47',
- 'darkorange' => '255,140,0',
- 'darkorchid' => '153,50,204',
- 'darkred' => '139,0,0',
- 'darksalmon' => '233,150,122',
- 'darkseagreen' => '143,188,143',
- 'darkslateblue' => '72,61,139',
- 'darkslategray' => '47,79,79',
- 'darkslategrey' => '47,79,79',
- 'darkturquoise' => '0,206,209',
- 'darkviolet' => '148,0,211',
- 'deeppink' => '255,20,147',
- 'deepskyblue' => '0,191,255',
- 'dimgray' => '105,105,105',
- 'dimgrey' => '105,105,105',
- 'dodgerblue' => '30,144,255',
- 'firebrick' => '178,34,34',
- 'floralwhite' => '255,250,240',
- 'forestgreen' => '34,139,34',
- 'fuchsia' => '255,0,255',
- 'gainsboro' => '220,220,220',
- 'ghostwhite' => '248,248,255',
- 'gold' => '255,215,0',
- 'goldenrod' => '218,165,32',
- 'gray' => '128,128,128',
- 'green' => '0,128,0',
- 'greenyellow' => '173,255,47',
- 'grey' => '128,128,128',
- 'honeydew' => '240,255,240',
- 'hotpink' => '255,105,180',
- 'indianred' => '205,92,92',
- 'indigo' => '75,0,130',
- 'ivory' => '255,255,240',
- 'khaki' => '240,230,140',
- 'lavender' => '230,230,250',
- 'lavenderblush' => '255,240,245',
- 'lawngreen' => '124,252,0',
- 'lemonchiffon' => '255,250,205',
- 'lightblue' => '173,216,230',
- 'lightcoral' => '240,128,128',
- 'lightcyan' => '224,255,255',
- 'lightgoldenrodyellow' => '250,250,210',
- 'lightgray' => '211,211,211',
- 'lightgreen' => '144,238,144',
- 'lightgrey' => '211,211,211',
- 'lightpink' => '255,182,193',
- 'lightsalmon' => '255,160,122',
- 'lightseagreen' => '32,178,170',
- 'lightskyblue' => '135,206,250',
- 'lightslategray' => '119,136,153',
- 'lightslategrey' => '119,136,153',
- 'lightsteelblue' => '176,196,222',
- 'lightyellow' => '255,255,224',
- 'lime' => '0,255,0',
- 'limegreen' => '50,205,50',
- 'linen' => '250,240,230',
- 'magenta' => '255,0,255',
- 'maroon' => '128,0,0',
- 'mediumaquamarine' => '102,205,170',
- 'mediumblue' => '0,0,205',
- 'mediumorchid' => '186,85,211',
- 'mediumpurple' => '147,112,219',
- 'mediumseagreen' => '60,179,113',
- 'mediumslateblue' => '123,104,238',
- 'mediumspringgreen' => '0,250,154',
- 'mediumturquoise' => '72,209,204',
- 'mediumvioletred' => '199,21,133',
- 'midnightblue' => '25,25,112',
- 'mintcream' => '245,255,250',
- 'mistyrose' => '255,228,225',
- 'moccasin' => '255,228,181',
- 'navajowhite' => '255,222,173',
- 'navy' => '0,0,128',
- 'oldlace' => '253,245,230',
- 'olive' => '128,128,0',
- 'olivedrab' => '107,142,35',
- 'orange' => '255,165,0',
- 'orangered' => '255,69,0',
- 'orchid' => '218,112,214',
- 'palegoldenrod' => '238,232,170',
- 'palegreen' => '152,251,152',
- 'paleturquoise' => '175,238,238',
- 'palevioletred' => '219,112,147',
- 'papayawhip' => '255,239,213',
- 'peachpuff' => '255,218,185',
- 'peru' => '205,133,63',
- 'pink' => '255,192,203',
- 'plum' => '221,160,221',
- 'powderblue' => '176,224,230',
- 'purple' => '128,0,128',
- 'red' => '255,0,0',
- 'rosybrown' => '188,143,143',
- 'royalblue' => '65,105,225',
- 'saddlebrown' => '139,69,19',
- 'salmon' => '250,128,114',
- 'sandybrown' => '244,164,96',
- 'seagreen' => '46,139,87',
- 'seashell' => '255,245,238',
- 'sienna' => '160,82,45',
- 'silver' => '192,192,192',
- 'skyblue' => '135,206,235',
- 'slateblue' => '106,90,205',
- 'slategray' => '112,128,144',
- 'slategrey' => '112,128,144',
- 'snow' => '255,250,250',
- 'springgreen' => '0,255,127',
- 'steelblue' => '70,130,180',
- 'tan' => '210,180,140',
- 'teal' => '0,128,128',
- 'thistle' => '216,191,216',
- 'tomato' => '255,99,71',
- 'transparent' => '0,0,0,0',
- 'turquoise' => '64,224,208',
- 'violet' => '238,130,238',
- 'wheat' => '245,222,179',
- 'white' => '255,255,255',
- 'whitesmoke' => '245,245,245',
- 'yellow' => '255,255,0',
- 'yellowgreen' => '154,205,50'
- );
-}
-
-// responsible for taking a string of LESS code and converting it into a
-// syntax tree
-class lessc_parser {
- static protected $nextBlockId = 0; // used to uniquely identify blocks
-
- static protected $precedence = array(
- '=<' => 0,
- '>=' => 0,
- '=' => 0,
- '<' => 0,
- '>' => 0,
-
- '+' => 1,
- '-' => 1,
- '*' => 2,
- '/' => 2,
- '%' => 2,
- );
-
- static protected $whitePattern;
- static protected $commentMulti;
-
- static protected $commentSingle = "//";
- static protected $commentMultiLeft = "/*";
- static protected $commentMultiRight = "*/";
-
- // regex string to match any of the operators
- static protected $operatorString;
-
- // these properties will supress division unless it's inside parenthases
- static protected $supressDivisionProps =
- array('/border-radius$/i', '/^font$/i');
-
- protected $blockDirectives = array("font-face", "keyframes", "page", "-moz-document", "viewport", "-moz-viewport", "-o-viewport", "-ms-viewport");
- protected $lineDirectives = array("charset");
-
- /**
- * if we are in parens we can be more liberal with whitespace around
- * operators because it must evaluate to a single value and thus is less
- * ambiguous.
- *
- * Consider:
- * property1: 10 -5; // is two numbers, 10 and -5
- * property2: (10 -5); // should evaluate to 5
- */
- protected $inParens = false;
-
- // caches preg escaped literals
- static protected $literalCache = array();
-
- public function __construct($lessc, $sourceName = null) {
- $this->eatWhiteDefault = true;
- // reference to less needed for vPrefix, mPrefix, and parentSelector
- $this->lessc = $lessc;
-
- $this->sourceName = $sourceName; // name used for error messages
-
- $this->writeComments = false;
-
- if (!self::$operatorString) {
- self::$operatorString =
- '('.implode('|', array_map(array('lessc', 'preg_quote'),
- array_keys(self::$precedence))).')';
-
- $commentSingle = lessc::preg_quote(self::$commentSingle);
- $commentMultiLeft = lessc::preg_quote(self::$commentMultiLeft);
- $commentMultiRight = lessc::preg_quote(self::$commentMultiRight);
-
- self::$commentMulti = $commentMultiLeft.'.*?'.$commentMultiRight;
- self::$whitePattern = '/'.$commentSingle.'[^\n]*\s*|('.self::$commentMulti.')\s*|\s+/Ais';
- }
- }
-
- public function parse($buffer) {
- $this->count = 0;
- $this->line = 1;
-
- $this->env = null; // block stack
- $this->buffer = $this->writeComments ? $buffer : $this->removeComments($buffer);
- $this->pushSpecialBlock("root");
- $this->eatWhiteDefault = true;
- $this->seenComments = array();
-
- // trim whitespace on head
- // if (preg_match('/^\s+/', $this->buffer, $m)) {
- // $this->line += substr_count($m[0], "\n");
- // $this->buffer = ltrim($this->buffer);
- // }
- $this->whitespace();
-
- // parse the entire file
- while (false !== $this->parseChunk());
-
- if ($this->count != strlen($this->buffer))
- $this->throwError();
-
- // TODO report where the block was opened
- if ( !property_exists($this->env, 'parent') || !is_null($this->env->parent) )
- throw new exception('parse error: unclosed block');
-
- return $this->env;
- }
-
- /**
- * Parse a single chunk off the head of the buffer and append it to the
- * current parse environment.
- * Returns false when the buffer is empty, or when there is an error.
- *
- * This function is called repeatedly until the entire document is
- * parsed.
- *
- * This parser is most similar to a recursive descent parser. Single
- * functions represent discrete grammatical rules for the language, and
- * they are able to capture the text that represents those rules.
- *
- * Consider the function lessc::keyword(). (all parse functions are
- * structured the same)
- *
- * The function takes a single reference argument. When calling the
- * function it will attempt to match a keyword on the head of the buffer.
- * If it is successful, it will place the keyword in the referenced
- * argument, advance the position in the buffer, and return true. If it
- * fails then it won't advance the buffer and it will return false.
- *
- * All of these parse functions are powered by lessc::match(), which behaves
- * the same way, but takes a literal regular expression. Sometimes it is
- * more convenient to use match instead of creating a new function.
- *
- * Because of the format of the functions, to parse an entire string of
- * grammatical rules, you can chain them together using &&.
- *
- * But, if some of the rules in the chain succeed before one fails, then
- * the buffer position will be left at an invalid state. In order to
- * avoid this, lessc::seek() is used to remember and set buffer positions.
- *
- * Before parsing a chain, use $s = $this->seek() to remember the current
- * position into $s. Then if a chain fails, use $this->seek($s) to
- * go back where we started.
- */
- protected function parseChunk() {
- if (empty($this->buffer)) return false;
- $s = $this->seek();
-
- if ($this->whitespace()) {
- return true;
- }
-
- // setting a property
- if ($this->keyword($key) && $this->assign() &&
- $this->propertyValue($value, $key) && $this->end())
- {
- $this->append(array('assign', $key, $value), $s);
- return true;
- } else {
- $this->seek($s);
- }
-
-
- // look for special css blocks
- if ($this->literal('@', false)) {
- $this->count--;
-
- // media
- if ($this->literal('@media')) {
- if (($this->mediaQueryList($mediaQueries) || true)
- && $this->literal('{'))
- {
- $media = $this->pushSpecialBlock("media");
- $media->queries = is_null($mediaQueries) ? array() : $mediaQueries;
- return true;
- } else {
- $this->seek($s);
- return false;
- }
- }
-
- if ($this->literal("@", false) && $this->keyword($dirName)) {
- if ($this->isDirective($dirName, $this->blockDirectives)) {
- if (($this->openString("{", $dirValue, null, array(";")) || true) &&
- $this->literal("{"))
- {
- $dir = $this->pushSpecialBlock("directive");
- $dir->name = $dirName;
- if (isset($dirValue)) $dir->value = $dirValue;
- return true;
- }
- } elseif ($this->isDirective($dirName, $this->lineDirectives)) {
- if ($this->propertyValue($dirValue) && $this->end()) {
- $this->append(array("directive", $dirName, $dirValue));
- return true;
- }
- }
- }
-
- $this->seek($s);
- }
-
- // setting a variable
- if ($this->variable($var) && $this->assign() &&
- $this->propertyValue($value) && $this->end())
- {
- $this->append(array('assign', $var, $value), $s);
- return true;
- } else {
- $this->seek($s);
- }
-
- if ($this->import($importValue)) {
- $this->append($importValue, $s);
- return true;
- }
-
- // opening parametric mixin
- if ($this->tag($tag, true) && $this->argumentDef($args, $isVararg) &&
- ($this->guards($guards) || true) &&
- $this->literal('{'))
- {
- $block = $this->pushBlock($this->fixTags(array($tag)));
- $block->args = $args;
- $block->isVararg = $isVararg;
- if (!empty($guards)) $block->guards = $guards;
- return true;
- } else {
- $this->seek($s);
- }
-
- // opening a simple block
- if ($this->tags($tags) && $this->literal('{', false)) {
- $tags = $this->fixTags($tags);
- $this->pushBlock($tags);
- return true;
- } else {
- $this->seek($s);
- }
-
- // closing a block
- if ($this->literal('}', false)) {
- try {
- $block = $this->pop();
- } catch (exception $e) {
- $this->seek($s);
- $this->throwError($e->getMessage());
- }
-
- $hidden = false;
- if (is_null($block->type)) {
- $hidden = true;
- if (!isset($block->args)) {
- foreach ($block->tags as $tag) {
- if (!is_string($tag) || $tag{0} != $this->lessc->mPrefix) {
- $hidden = false;
- break;
- }
- }
- }
-
- foreach ($block->tags as $tag) {
- if (is_string($tag)) {
- $this->env->children[$tag][] = $block;
- }
- }
- }
-
- if (!$hidden) {
- $this->append(array('block', $block), $s);
- }
-
- // this is done here so comments aren't bundled into he block that
- // was just closed
- $this->whitespace();
- return true;
- }
-
- // mixin
- if ($this->mixinTags($tags) &&
- ($this->argumentDef($argv, $isVararg) || true) &&
- ($this->keyword($suffix) || true) && $this->end())
- {
- $tags = $this->fixTags($tags);
- $this->append(array('mixin', $tags, $argv, $suffix), $s);
- return true;
- } else {
- $this->seek($s);
- }
-
- // spare ;
- if ($this->literal(';')) return true;
-
- return false; // got nothing, throw error
- }
-
- protected function isDirective($dirname, $directives) {
- // TODO: cache pattern in parser
- $pattern = implode("|",
- array_map(array("lessc", "preg_quote"), $directives));
- $pattern = '/^(-[a-z-]+-)?(' . $pattern . ')$/i';
-
- return preg_match($pattern, $dirname);
- }
-
- protected function fixTags($tags) {
- // move @ tags out of variable namespace
- foreach ($tags as &$tag) {
- if ($tag{0} == $this->lessc->vPrefix)
- $tag[0] = $this->lessc->mPrefix;
- }
- return $tags;
- }
-
- // a list of expressions
- protected function expressionList(&$exps) {
- $values = array();
-
- while ($this->expression($exp)) {
- $values[] = $exp;
- }
-
- if (count($values) == 0) return false;
-
- $exps = lessc::compressList($values, ' ');
- return true;
- }
-
- /**
- * Attempt to consume an expression.
- * @link http://en.wikipedia.org/wiki/Operator-precedence_parser#Pseudo-code
- */
- protected function expression(&$out) {
- if ($this->value($lhs)) {
- $out = $this->expHelper($lhs, 0);
-
- // look for / shorthand
- if (!empty($this->env->supressedDivision)) {
- unset($this->env->supressedDivision);
- $s = $this->seek();
- if ($this->literal("/") && $this->value($rhs)) {
- $out = array("list", "",
- array($out, array("keyword", "/"), $rhs));
- } else {
- $this->seek($s);
- }
- }
-
- return true;
- }
- return false;
- }
-
- /**
- * recursively parse infix equation with $lhs at precedence $minP
- */
- protected function expHelper($lhs, $minP) {
- $this->inExp = true;
- $ss = $this->seek();
-
- while (true) {
- $whiteBefore = isset($this->buffer[$this->count - 1]) &&
- ctype_space($this->buffer[$this->count - 1]);
-
- // If there is whitespace before the operator, then we require
- // whitespace after the operator for it to be an expression
- $needWhite = $whiteBefore && !$this->inParens;
-
- if ($this->match(self::$operatorString.($needWhite ? '\s' : ''), $m) && self::$precedence[$m[1]] >= $minP) {
- if (!$this->inParens && isset($this->env->currentProperty) && $m[1] == "/" && empty($this->env->supressedDivision)) {
- foreach (self::$supressDivisionProps as $pattern) {
- if (preg_match($pattern, $this->env->currentProperty)) {
- $this->env->supressedDivision = true;
- break 2;
- }
- }
- }
-
-
- $whiteAfter = isset($this->buffer[$this->count - 1]) &&
- ctype_space($this->buffer[$this->count - 1]);
-
- if (!$this->value($rhs)) break;
-
- // peek for next operator to see what to do with rhs
- if ($this->peek(self::$operatorString, $next) && self::$precedence[$next[1]] > self::$precedence[$m[1]]) {
- $rhs = $this->expHelper($rhs, self::$precedence[$next[1]]);
- }
-
- $lhs = array('expression', $m[1], $lhs, $rhs, $whiteBefore, $whiteAfter);
- $ss = $this->seek();
-
- continue;
- }
-
- break;
- }
-
- $this->seek($ss);
-
- return $lhs;
- }
-
- // consume a list of values for a property
- public function propertyValue(&$value, $keyName = null) {
- $values = array();
-
- if ($keyName !== null) $this->env->currentProperty = $keyName;
-
- $s = null;
- while ($this->expressionList($v)) {
- $values[] = $v;
- $s = $this->seek();
- if (!$this->literal(',')) break;
- }
-
- if ($s) $this->seek($s);
-
- if ($keyName !== null) unset($this->env->currentProperty);
-
- if (count($values) == 0) return false;
-
- $value = lessc::compressList($values, ', ');
- return true;
- }
-
- protected function parenValue(&$out) {
- $s = $this->seek();
-
- // speed shortcut
- if (isset($this->buffer[$this->count]) && $this->buffer[$this->count] != "(") {
- return false;
- }
-
- $inParens = $this->inParens;
- if ($this->literal("(") &&
- ($this->inParens = true) && $this->expression($exp) &&
- $this->literal(")"))
- {
- $out = $exp;
- $this->inParens = $inParens;
- return true;
- } else {
- $this->inParens = $inParens;
- $this->seek($s);
- }
-
- return false;
- }
-
- // a single value
- protected function value(&$value) {
- $s = $this->seek();
-
- // speed shortcut
- if (isset($this->buffer[$this->count]) && $this->buffer[$this->count] == "-") {
- // negation
- if ($this->literal("-", false) &&
- (($this->variable($inner) && $inner = array("variable", $inner)) ||
- $this->unit($inner) ||
- $this->parenValue($inner)))
- {
- $value = array("unary", "-", $inner);
- return true;
- } else {
- $this->seek($s);
- }
- }
-
- if ($this->parenValue($value)) return true;
- if ($this->unit($value)) return true;
- if ($this->color($value)) return true;
- if ($this->func($value)) return true;
- if ($this->string($value)) return true;
-
- if ($this->keyword($word)) {
- $value = array('keyword', $word);
- return true;
- }
-
- // try a variable
- if ($this->variable($var)) {
- $value = array('variable', $var);
- return true;
- }
-
- // unquote string (should this work on any type?
- if ($this->literal("~") && $this->string($str)) {
- $value = array("escape", $str);
- return true;
- } else {
- $this->seek($s);
- }
-
- // css hack: \0
- if ($this->literal('\\') && $this->match('([0-9]+)', $m)) {
- $value = array('keyword', '\\'.$m[1]);
- return true;
- } else {
- $this->seek($s);
- }
-
- return false;
- }
-
- // an import statement
- protected function import(&$out) {
- if (!$this->literal('@import')) return false;
-
- // @import "something.css" media;
- // @import url("something.css") media;
- // @import url(something.css) media;
-
- if ($this->propertyValue($value)) {
- $out = array("import", $value);
- return true;
- }
- }
-
- protected function mediaQueryList(&$out) {
- if ($this->genericList($list, "mediaQuery", ",", false)) {
- $out = $list[2];
- return true;
- }
- return false;
- }
-
- protected function mediaQuery(&$out) {
- $s = $this->seek();
-
- $expressions = null;
- $parts = array();
-
- if (($this->literal("only") && ($only = true) || $this->literal("not") && ($not = true) || true) && $this->keyword($mediaType)) {
- $prop = array("mediaType");
- if (isset($only)) $prop[] = "only";
- if (isset($not)) $prop[] = "not";
- $prop[] = $mediaType;
- $parts[] = $prop;
- } else {
- $this->seek($s);
- }
-
-
- if (!empty($mediaType) && !$this->literal("and")) {
- // ~
- } else {
- $this->genericList($expressions, "mediaExpression", "and", false);
- if (is_array($expressions)) $parts = array_merge($parts, $expressions[2]);
- }
-
- if (count($parts) == 0) {
- $this->seek($s);
- return false;
- }
-
- $out = $parts;
- return true;
- }
-
- protected function mediaExpression(&$out) {
- $s = $this->seek();
- $value = null;
- if ($this->literal("(") &&
- $this->keyword($feature) &&
- ($this->literal(":") && $this->expression($value) || true) &&
- $this->literal(")"))
- {
- $out = array("mediaExp", $feature);
- if ($value) $out[] = $value;
- return true;
- } elseif ($this->variable($variable)) {
- $out = array('variable', $variable);
- return true;
- }
-
- $this->seek($s);
- return false;
- }
-
- // an unbounded string stopped by $end
- protected function openString($end, &$out, $nestingOpen=null, $rejectStrs = null) {
- $oldWhite = $this->eatWhiteDefault;
- $this->eatWhiteDefault = false;
-
- $stop = array("'", '"', "@{", $end);
- $stop = array_map(array("lessc", "preg_quote"), $stop);
- // $stop[] = self::$commentMulti;
-
- if (!is_null($rejectStrs)) {
- $stop = array_merge($stop, $rejectStrs);
- }
-
- $patt = '(.*?)('.implode("|", $stop).')';
-
- $nestingLevel = 0;
-
- $content = array();
- while ($this->match($patt, $m, false)) {
- if (!empty($m[1])) {
- $content[] = $m[1];
- if ($nestingOpen) {
- $nestingLevel += substr_count($m[1], $nestingOpen);
- }
- }
-
- $tok = $m[2];
-
- $this->count-= strlen($tok);
- if ($tok == $end) {
- if ($nestingLevel == 0) {
- break;
- } else {
- $nestingLevel--;
- }
- }
-
- if (($tok == "'" || $tok == '"') && $this->string($str)) {
- $content[] = $str;
- continue;
- }
-
- if ($tok == "@{" && $this->interpolation($inter)) {
- $content[] = $inter;
- continue;
- }
-
- if (!empty($rejectStrs) && in_array($tok, $rejectStrs)) {
- break;
- }
-
- $content[] = $tok;
- $this->count+= strlen($tok);
- }
-
- $this->eatWhiteDefault = $oldWhite;
-
- if (count($content) == 0) return false;
-
- // trim the end
- if (is_string(end($content))) {
- $content[count($content) - 1] = rtrim(end($content));
- }
-
- $out = array("string", "", $content);
- return true;
- }
-
- protected function string(&$out) {
- $s = $this->seek();
- if ($this->literal('"', false)) {
- $delim = '"';
- } elseif ($this->literal("'", false)) {
- $delim = "'";
- } else {
- return false;
- }
-
- $content = array();
-
- // look for either ending delim , escape, or string interpolation
- $patt = '([^\n]*?)(@\{|\\\\|' .
- lessc::preg_quote($delim).')';
-
- $oldWhite = $this->eatWhiteDefault;
- $this->eatWhiteDefault = false;
-
- while ($this->match($patt, $m, false)) {
- $content[] = $m[1];
- if ($m[2] == "@{") {
- $this->count -= strlen($m[2]);
- if ($this->interpolation($inter, false)) {
- $content[] = $inter;
- } else {
- $this->count += strlen($m[2]);
- $content[] = "@{"; // ignore it
- }
- } elseif ($m[2] == '\\') {
- $content[] = $m[2];
- if ($this->literal($delim, false)) {
- $content[] = $delim;
- }
- } else {
- $this->count -= strlen($delim);
- break; // delim
- }
- }
-
- $this->eatWhiteDefault = $oldWhite;
-
- if ($this->literal($delim)) {
- $out = array("string", $delim, $content);
- return true;
- }
-
- $this->seek($s);
- return false;
- }
-
- protected function interpolation(&$out) {
- $oldWhite = $this->eatWhiteDefault;
- $this->eatWhiteDefault = true;
-
- $s = $this->seek();
- if ($this->literal("@{") &&
- $this->openString("}", $interp, null, array("'", '"', ";")) &&
- $this->literal("}", false))
- {
- $out = array("interpolate", $interp);
- $this->eatWhiteDefault = $oldWhite;
- if ($this->eatWhiteDefault) $this->whitespace();
- return true;
- }
-
- $this->eatWhiteDefault = $oldWhite;
- $this->seek($s);
- return false;
- }
-
- protected function unit(&$unit) {
- // speed shortcut
- if (isset($this->buffer[$this->count])) {
- $char = $this->buffer[$this->count];
- if (!ctype_digit($char) && $char != ".") return false;
- }
-
- if ($this->match('([0-9]+(?:\.[0-9]*)?|\.[0-9]+)([%a-zA-Z]+)?', $m)) {
- $unit = array("number", $m[1], empty($m[2]) ? "" : $m[2]);
- return true;
- }
- return false;
- }
-
- // a # color
- protected function color(&$out) {
- if ($this->match('(#(?:[0-9a-f]{8}|[0-9a-f]{6}|[0-9a-f]{3}))', $m)) {
- if (strlen($m[1]) > 7) {
- $out = array("string", "", array($m[1]));
- } else {
- $out = array("raw_color", $m[1]);
- }
- return true;
- }
-
- return false;
- }
-
- // consume an argument definition list surrounded by ()
- // each argument is a variable name with optional value
- // or at the end a ... or a variable named followed by ...
- // arguments are separated by , unless a ; is in the list, then ; is the
- // delimiter.
- protected function argumentDef(&$args, &$isVararg) {
- $s = $this->seek();
- if (!$this->literal('(')) return false;
-
- $values = array();
- $delim = ",";
- $method = "expressionList";
-
- $isVararg = false;
- while (true) {
- if ($this->literal("...")) {
- $isVararg = true;
- break;
- }
-
- if ($this->$method($value)) {
- if ($value[0] == "variable") {
- $arg = array("arg", $value[1]);
- $ss = $this->seek();
-
- if ($this->assign() && $this->$method($rhs)) {
- $arg[] = $rhs;
- } else {
- $this->seek($ss);
- if ($this->literal("...")) {
- $arg[0] = "rest";
- $isVararg = true;
- }
- }
-
- $values[] = $arg;
- if ($isVararg) break;
- continue;
- } else {
- $values[] = array("lit", $value);
- }
- }
-
-
- if (!$this->literal($delim)) {
- if ($delim == "," && $this->literal(";")) {
- // found new delim, convert existing args
- $delim = ";";
- $method = "propertyValue";
-
- // transform arg list
- if (isset($values[1])) { // 2 items
- $newList = array();
- foreach ($values as $i => $arg) {
- switch($arg[0]) {
- case "arg":
- if ($i) {
- $this->throwError("Cannot mix ; and , as delimiter types");
- }
- $newList[] = $arg[2];
- break;
- case "lit":
- $newList[] = $arg[1];
- break;
- case "rest":
- $this->throwError("Unexpected rest before semicolon");
- }
- }
-
- $newList = array("list", ", ", $newList);
-
- switch ($values[0][0]) {
- case "arg":
- $newArg = array("arg", $values[0][1], $newList);
- break;
- case "lit":
- $newArg = array("lit", $newList);
- break;
- }
-
- } elseif ($values) { // 1 item
- $newArg = $values[0];
- }
-
- if ($newArg) {
- $values = array($newArg);
- }
- } else {
- break;
- }
- }
- }
-
- if (!$this->literal(')')) {
- $this->seek($s);
- return false;
- }
-
- $args = $values;
-
- return true;
- }
-
- // consume a list of tags
- // this accepts a hanging delimiter
- protected function tags(&$tags, $simple = false, $delim = ',') {
- $tags = array();
- while ($this->tag($tt, $simple)) {
- $tags[] = $tt;
- if (!$this->literal($delim)) break;
- }
- if (count($tags) == 0) return false;
-
- return true;
- }
-
- // list of tags of specifying mixin path
- // optionally separated by > (lazy, accepts extra >)
- protected function mixinTags(&$tags) {
- $tags = array();
- while ($this->tag($tt, true)) {
- $tags[] = $tt;
- $this->literal(">");
- }
-
- if (count($tags) == 0) return false;
-
- return true;
- }
-
- // a bracketed value (contained within in a tag definition)
- protected function tagBracket(&$parts, &$hasExpression) {
- // speed shortcut
- if (isset($this->buffer[$this->count]) && $this->buffer[$this->count] != "[") {
- return false;
- }
-
- $s = $this->seek();
-
- $hasInterpolation = false;
-
- if ($this->literal("[", false)) {
- $attrParts = array("[");
- // keyword, string, operator
- while (true) {
- if ($this->literal("]", false)) {
- $this->count--;
- break; // get out early
- }
-
- if ($this->match('\s+', $m)) {
- $attrParts[] = " ";
- continue;
- }
- if ($this->string($str)) {
- // escape parent selector, (yuck)
- foreach ($str[2] as &$chunk) {
- $chunk = str_replace($this->lessc->parentSelector, "$&$", $chunk);
- }
-
- $attrParts[] = $str;
- $hasInterpolation = true;
- continue;
- }
-
- if ($this->keyword($word)) {
- $attrParts[] = $word;
- continue;
- }
-
- if ($this->interpolation($inter, false)) {
- $attrParts[] = $inter;
- $hasInterpolation = true;
- continue;
- }
-
- // operator, handles attr namespace too
- if ($this->match('[|-~\$\*\^=]+', $m)) {
- $attrParts[] = $m[0];
- continue;
- }
-
- break;
- }
-
- if ($this->literal("]", false)) {
- $attrParts[] = "]";
- foreach ($attrParts as $part) {
- $parts[] = $part;
- }
- $hasExpression = $hasExpression || $hasInterpolation;
- return true;
- }
- $this->seek($s);
- }
-
- $this->seek($s);
- return false;
- }
-
- // a space separated list of selectors
- protected function tag(&$tag, $simple = false) {
- if ($simple)
- $chars = '^@,:;{}\][>\(\) "\'';
- else
- $chars = '^@,;{}["\'';
-
- $s = $this->seek();
-
- $hasExpression = false;
- $parts = array();
- while ($this->tagBracket($parts, $hasExpression));
-
- $oldWhite = $this->eatWhiteDefault;
- $this->eatWhiteDefault = false;
-
- while (true) {
- if ($this->match('(['.$chars.'0-9]['.$chars.']*)', $m)) {
- $parts[] = $m[1];
- if ($simple) break;
-
- while ($this->tagBracket($parts, $hasExpression));
- continue;
- }
-
- if (isset($this->buffer[$this->count]) && $this->buffer[$this->count] == "@") {
- if ($this->interpolation($interp)) {
- $hasExpression = true;
- $interp[2] = true; // don't unescape
- $parts[] = $interp;
- continue;
- }
-
- if ($this->literal("@")) {
- $parts[] = "@";
- continue;
- }
- }
-
- if ($this->unit($unit)) { // for keyframes
- $parts[] = $unit[1];
- $parts[] = $unit[2];
- continue;
- }
-
- break;
- }
-
- $this->eatWhiteDefault = $oldWhite;
- if (!$parts) {
- $this->seek($s);
- return false;
- }
-
- if ($hasExpression) {
- $tag = array("exp", array("string", "", $parts));
- } else {
- $tag = trim(implode($parts));
- }
-
- $this->whitespace();
- return true;
- }
-
- // a css function
- protected function func(&$func) {
- $s = $this->seek();
-
- if ($this->match('(%|[\w\-_][\w\-_:\.]+|[\w_])', $m) && $this->literal('(')) {
- $fname = $m[1];
-
- $sPreArgs = $this->seek();
-
- $args = array();
- while (true) {
- $ss = $this->seek();
- // this ugly nonsense is for ie filter properties
- if ($this->keyword($name) && $this->literal('=') && $this->expressionList($value)) {
- $args[] = array("string", "", array($name, "=", $value));
- } else {
- $this->seek($ss);
- if ($this->expressionList($value)) {
- $args[] = $value;
- }
- }
-
- if (!$this->literal(',')) break;
- }
- $args = array('list', ',', $args);
-
- if ($this->literal(')')) {
- $func = array('function', $fname, $args);
- return true;
- } elseif ($fname == 'url') {
- // couldn't parse and in url? treat as string
- $this->seek($sPreArgs);
- if ($this->openString(")", $string) && $this->literal(")")) {
- $func = array('function', $fname, $string);
- return true;
- }
- }
- }
-
- $this->seek($s);
- return false;
- }
-
- // consume a less variable
- protected function variable(&$name) {
- $s = $this->seek();
- if ($this->literal($this->lessc->vPrefix, false) &&
- ($this->variable($sub) || $this->keyword($name)))
- {
- if (!empty($sub)) {
- $name = array('variable', $sub);
- } else {
- $name = $this->lessc->vPrefix.$name;
- }
- return true;
- }
-
- $name = null;
- $this->seek($s);
- return false;
- }
-
- /**
- * Consume an assignment operator
- * Can optionally take a name that will be set to the current property name
- */
- protected function assign($name = null) {
- if ($name) $this->currentProperty = $name;
- return $this->literal(':') || $this->literal('=');
- }
-
- // consume a keyword
- protected function keyword(&$word) {
- if ($this->match('([\w_\-\*!"][\w\-_"]*)', $m)) {
- $word = $m[1];
- return true;
- }
- return false;
- }
-
- // consume an end of statement delimiter
- protected function end() {
- if ($this->literal(';', false)) {
- return true;
- } elseif ($this->count == strlen($this->buffer) || $this->buffer[$this->count] == '}') {
- // if there is end of file or a closing block next then we don't need a ;
- return true;
- }
- return false;
- }
-
- protected function guards(&$guards) {
- $s = $this->seek();
-
- if (!$this->literal("when")) {
- $this->seek($s);
- return false;
- }
-
- $guards = array();
-
- while ($this->guardGroup($g)) {
- $guards[] = $g;
- if (!$this->literal(",")) break;
- }
-
- if (count($guards) == 0) {
- $guards = null;
- $this->seek($s);
- return false;
- }
-
- return true;
- }
-
- // a bunch of guards that are and'd together
- // TODO rename to guardGroup
- protected function guardGroup(&$guardGroup) {
- $s = $this->seek();
- $guardGroup = array();
- while ($this->guard($guard)) {
- $guardGroup[] = $guard;
- if (!$this->literal("and")) break;
- }
-
- if (count($guardGroup) == 0) {
- $guardGroup = null;
- $this->seek($s);
- return false;
- }
-
- return true;
- }
-
- protected function guard(&$guard) {
- $s = $this->seek();
- $negate = $this->literal("not");
-
- if ($this->literal("(") && $this->expression($exp) && $this->literal(")")) {
- $guard = $exp;
- if ($negate) $guard = array("negate", $guard);
- return true;
- }
-
- $this->seek($s);
- return false;
- }
-
- /* raw parsing functions */
-
- protected function literal($what, $eatWhitespace = null) {
- if ($eatWhitespace === null) $eatWhitespace = $this->eatWhiteDefault;
-
- // shortcut on single letter
- if (!isset($what[1]) && isset($this->buffer[$this->count])) {
- if ($this->buffer[$this->count] == $what) {
- if (!$eatWhitespace) {
- $this->count++;
- return true;
- }
- // goes below...
- } else {
- return false;
- }
- }
-
- if (!isset(self::$literalCache[$what])) {
- self::$literalCache[$what] = lessc::preg_quote($what);
- }
-
- return $this->match(self::$literalCache[$what], $m, $eatWhitespace);
- }
-
- protected function genericList(&$out, $parseItem, $delim="", $flatten=true) {
- $s = $this->seek();
- $items = array();
- while ($this->$parseItem($value)) {
- $items[] = $value;
- if ($delim) {
- if (!$this->literal($delim)) break;
- }
- }
-
- if (count($items) == 0) {
- $this->seek($s);
- return false;
- }
-
- if ($flatten && count($items) == 1) {
- $out = $items[0];
- } else {
- $out = array("list", $delim, $items);
- }
-
- return true;
- }
-
-
- // advance counter to next occurrence of $what
- // $until - don't include $what in advance
- // $allowNewline, if string, will be used as valid char set
- protected function to($what, &$out, $until = false, $allowNewline = false) {
- if (is_string($allowNewline)) {
- $validChars = $allowNewline;
- } else {
- $validChars = $allowNewline ? "." : "[^\n]";
- }
- if (!$this->match('('.$validChars.'*?)'.lessc::preg_quote($what), $m, !$until)) return false;
- if ($until) $this->count -= strlen($what); // give back $what
- $out = $m[1];
- return true;
- }
-
- // try to match something on head of buffer
- protected function match($regex, &$out, $eatWhitespace = null) {
- if ($eatWhitespace === null) $eatWhitespace = $this->eatWhiteDefault;
-
- $r = '/'.$regex.($eatWhitespace && !$this->writeComments ? '\s*' : '').'/Ais';
- if (preg_match($r, $this->buffer, $out, null, $this->count)) {
- $this->count += strlen($out[0]);
- if ($eatWhitespace && $this->writeComments) $this->whitespace();
- return true;
- }
- return false;
- }
-
- // match some whitespace
- protected function whitespace() {
- if ($this->writeComments) {
- $gotWhite = false;
- while (preg_match(self::$whitePattern, $this->buffer, $m, null, $this->count)) {
- if (isset($m[1]) && empty($this->seenComments[$this->count])) {
- $this->append(array("comment", $m[1]));
- $this->seenComments[$this->count] = true;
- }
- $this->count += strlen($m[0]);
- $gotWhite = true;
- }
- return $gotWhite;
- } else {
- $this->match("", $m);
- return strlen($m[0]) > 0;
- }
- }
-
- // match something without consuming it
- protected function peek($regex, &$out = null, $from=null) {
- if (is_null($from)) $from = $this->count;
- $r = '/'.$regex.'/Ais';
- $result = preg_match($r, $this->buffer, $out, null, $from);
-
- return $result;
- }
-
- // seek to a spot in the buffer or return where we are on no argument
- protected function seek($where = null) {
- if ($where === null) return $this->count;
- else $this->count = $where;
- return true;
- }
-
- /* misc functions */
-
- public function throwError($msg = "parse error", $count = null) {
- $count = is_null($count) ? $this->count : $count;
-
- $line = $this->line +
- substr_count(substr($this->buffer, 0, $count), "\n");
-
- if (!empty($this->sourceName)) {
- $loc = "$this->sourceName on line $line";
- } else {
- $loc = "line: $line";
- }
-
- // TODO this depends on $this->count
- if ($this->peek("(.*?)(\n|$)", $m, $count)) {
- throw new exception("$msg: failed at `$m[1]` $loc");
- } else {
- throw new exception("$msg: $loc");
- }
- }
-
- protected function pushBlock($selectors=null, $type=null) {
- $b = new stdclass;
- $b->parent = $this->env;
-
- $b->type = $type;
- $b->id = self::$nextBlockId++;
-
- $b->isVararg = false; // TODO: kill me from here
- $b->tags = $selectors;
-
- $b->props = array();
- $b->children = array();
-
- $this->env = $b;
- return $b;
- }
-
- // push a block that doesn't multiply tags
- protected function pushSpecialBlock($type) {
- return $this->pushBlock(null, $type);
- }
-
- // append a property to the current block
- protected function append($prop, $pos = null) {
- if ($pos !== null) $prop[-1] = $pos;
- $this->env->props[] = $prop;
- }
-
- // pop something off the stack
- protected function pop() {
- $old = $this->env;
- $this->env = $this->env->parent;
- return $old;
- }
-
- // remove comments from $text
- // todo: make it work for all functions, not just url
- protected function removeComments($text) {
- $look = array(
- 'url(', '//', '/*', '"', "'"
- );
-
- $out = '';
- $min = null;
- while (true) {
- // find the next item
- foreach ($look as $token) {
- $pos = strpos($text, $token);
- if ($pos !== false) {
- if (!isset($min) || $pos < $min[1]) $min = array($token, $pos);
- }
- }
-
- if (is_null($min)) break;
-
- $count = $min[1];
- $skip = 0;
- $newlines = 0;
- switch ($min[0]) {
- case 'url(':
- if (preg_match('/url\(.*?\)/', $text, $m, 0, $count))
- $count += strlen($m[0]) - strlen($min[0]);
- break;
- case '"':
- case "'":
- if (preg_match('/'.$min[0].'.*?(?<!\\\\)'.$min[0].'/', $text, $m, 0, $count))
- $count += strlen($m[0]) - 1;
- break;
- case '//':
- $skip = strpos($text, "\n", $count);
- if ($skip === false) $skip = strlen($text) - $count;
- else $skip -= $count;
- break;
- case '/*':
- if (preg_match('/\/\*.*?\*\//s', $text, $m, 0, $count)) {
- $skip = strlen($m[0]);
- $newlines = substr_count($m[0], "\n");
- }
- break;
- }
-
- if ($skip == 0) $count += strlen($min[0]);
-
- $out .= substr($text, 0, $count).str_repeat("\n", $newlines);
- $text = substr($text, $count + $skip);
-
- $min = null;
- }
-
- return $out.$text;
- }
-
-}
-
-class lessc_formatter_classic {
- public $indentChar = " ";
-
- public $break = "\n";
- public $open = " {";
- public $close = "}";
- public $selectorSeparator = ", ";
- public $assignSeparator = ":";
-
- public $openSingle = " { ";
- public $closeSingle = " }";
-
- public $disableSingle = false;
- public $breakSelectors = false;
-
- public $compressColors = false;
-
- public function __construct() {
- $this->indentLevel = 0;
- }
-
- public function indentStr($n = 0) {
- return str_repeat($this->indentChar, max($this->indentLevel + $n, 0));
- }
-
- public function property($name, $value) {
- return $name . $this->assignSeparator . $value . ";";
- }
-
- protected function isEmpty($block) {
- if (empty($block->lines)) {
- foreach ($block->children as $child) {
- if (!$this->isEmpty($child)) return false;
- }
-
- return true;
- }
- return false;
- }
-
- public function block($block) {
- if ($this->isEmpty($block)) return;
-
- $inner = $pre = $this->indentStr();
-
- $isSingle = !$this->disableSingle &&
- is_null($block->type) && count($block->lines) == 1;
-
- if (!empty($block->selectors)) {
- $this->indentLevel++;
-
- if ($this->breakSelectors) {
- $selectorSeparator = $this->selectorSeparator . $this->break . $pre;
- } else {
- $selectorSeparator = $this->selectorSeparator;
- }
-
- echo $pre .
- implode($selectorSeparator, $block->selectors);
- if ($isSingle) {
- echo $this->openSingle;
- $inner = "";
- } else {
- echo $this->open . $this->break;
- $inner = $this->indentStr();
- }
-
- }
-
- if (!empty($block->lines)) {
- $glue = $this->break.$inner;
- echo $inner . implode($glue, $block->lines);
- if (!$isSingle && !empty($block->children)) {
- echo $this->break;
- }
- }
-
- foreach ($block->children as $child) {
- $this->block($child);
- }
-
- if (!empty($block->selectors)) {
- if (!$isSingle && empty($block->children)) echo $this->break;
-
- if ($isSingle) {
- echo $this->closeSingle . $this->break;
- } else {
- echo $pre . $this->close . $this->break;
- }
-
- $this->indentLevel--;
- }
- }
-}
-
-class lessc_formatter_compressed extends lessc_formatter_classic {
- public $disableSingle = true;
- public $open = "{";
- public $selectorSeparator = ",";
- public $assignSeparator = ":";
- public $break = "";
- public $compressColors = true;
-
- public function indentStr($n = 0) {
- return "";
- }
-}
-
-class lessc_formatter_lessjs extends lessc_formatter_classic {
- public $disableSingle = true;
- public $breakSelectors = true;
- public $assignSeparator = ": ";
- public $selectorSeparator = ",";
-}
-
-
diff --git a/vendor/leafo/lessphp/lessify b/vendor/leafo/lessphp/lessify
deleted file mode 100644
index becc5388..00000000
--- a/vendor/leafo/lessphp/lessify
+++ /dev/null
@@ -1,23 +0,0 @@
-#!/usr/bin/php
-<?php
-
-if (php_sapi_name() != "cli") {
- err($fa.$argv[0]." must be run in the command line.");
- exit(1);
-}
-$exe = array_shift($argv); // remove filename
-
-if (!$fname = array_shift($argv)) {
- exit("Usage: ".$exe." input-file\n");
-}
-
-require "lessify.inc.php";
-
-try {
- $parser = new lessify($fname);
- echo $parser->parse();
-} catch (exception $e) {
- exit("Fatal error: ".$e->getMessage()."\n");
-}
-
-
diff --git a/vendor/leafo/lessphp/lessify.inc.php b/vendor/leafo/lessphp/lessify.inc.php
deleted file mode 100644
index 91c14423..00000000
--- a/vendor/leafo/lessphp/lessify.inc.php
+++ /dev/null
@@ -1,447 +0,0 @@
-<?php
-/**
- * lessify
- * Convert a css file into a less file
- * http://leafo.net/lessphp
- * Copyright 2010, leaf corcoran <leafot@gmail.com>
- *
- * WARNING: THIS DOES NOT WORK ANYMORE. NEEDS TO BE UPDATED FOR
- * LATEST VERSION OF LESSPHP.
- *
- */
-
-require "lessc.inc.php";
-
-//
-// check if the merge during mixin is overwriting values. should or should it not?
-//
-
-//
-// 1. split apart class tags
-//
-
-class easyparse {
- var $buffer;
- var $count;
-
- function __construct($str) {
- $this->count = 0;
- $this->buffer = trim($str);
- }
-
- function seek($where = null) {
- if ($where === null) return $this->count;
- else $this->count = $where;
- return true;
- }
-
- function preg_quote($what) {
- return preg_quote($what, '/');
- }
-
- function match($regex, &$out, $eatWhitespace = true) {
- $r = '/'.$regex.($eatWhitespace ? '\s*' : '').'/Ais';
- if (preg_match($r, $this->buffer, $out, null, $this->count)) {
- $this->count += strlen($out[0]);
- return true;
- }
- return false;
- }
-
- function literal($what, $eatWhitespace = true) {
- // this is here mainly prevent notice from { } string accessor
- if ($this->count >= strlen($this->buffer)) return false;
-
- // shortcut on single letter
- if (!$eatWhitespace and strlen($what) == 1) {
- if ($this->buffer{$this->count} == $what) {
- $this->count++;
- return true;
- }
- else return false;
- }
-
- return $this->match($this->preg_quote($what), $m, $eatWhitespace);
- }
-
-}
-
-class tagparse extends easyparse {
- static private $combinators = null;
- static private $match_opts = null;
-
- function parse() {
- if (empty(self::$combinators)) {
- self::$combinators = '('.implode('|', array_map(array($this, 'preg_quote'),
- array('+', '>', '~'))).')';
- self::$match_opts = '('.implode('|', array_map(array($this, 'preg_quote'),
- array('=', '~=', '|=', '$=', '*='))).')';
- }
-
- // crush whitespace
- $this->buffer = preg_replace('/\s+/', ' ', $this->buffer).' ';
-
- $tags = array();
- while ($this->tag($t)) $tags[] = $t;
-
- return $tags;
- }
-
- static function compileString($string) {
- list(, $delim, $str) = $string;
- $str = str_replace($delim, "\\".$delim, $str);
- $str = str_replace("\n", "\\\n", $str);
- return $delim.$str.$delim;
- }
-
- static function compilePaths($paths) {
- return implode(', ', array_map(array('self', 'compilePath'), $paths));
- }
-
- // array of tags
- static function compilePath($path) {
- return implode(' ', array_map(array('self', 'compileTag'), $path));
- }
-
-
- static function compileTag($tag) {
- ob_start();
- if (isset($tag['comb'])) echo $tag['comb']." ";
- if (isset($tag['front'])) echo $tag['front'];
- if (isset($tag['attr'])) {
- echo '['.$tag['attr'];
- if (isset($tag['op'])) {
- echo $tag['op'].$tag['op_value'];
- }
- echo ']';
- }
- return ob_get_clean();
- }
-
- function string(&$out) {
- $s = $this->seek();
-
- if ($this->literal('"')) {
- $delim = '"';
- } elseif ($this->literal("'")) {
- $delim = "'";
- } else {
- return false;
- }
-
- while (true) {
- // step through letters looking for either end or escape
- $buff = "";
- $escapeNext = false;
- $finished = false;
- for ($i = $this->count; $i < strlen($this->buffer); $i++) {
- $char = $this->buffer[$i];
- switch ($char) {
- case $delim:
- if ($escapeNext) {
- $buff .= $char;
- $escapeNext = false;
- break;
- }
- $finished = true;
- break 2;
- case "\\":
- if ($escapeNext) {
- $buff .= $char;
- $escapeNext = false;
- } else {
- $escapeNext = true;
- }
- break;
- case "\n":
- if (!$escapeNext) {
- break 3;
- }
-
- $buff .= $char;
- $escapeNext = false;
- break;
- default:
- if ($escapeNext) {
- $buff .= "\\";
- $escapeNext = false;
- }
- $buff .= $char;
- }
- }
- if (!$finished) break;
- $out = array('string', $delim, $buff);
- $this->seek($i+1);
- return true;
- }
-
- $this->seek($s);
- return false;
- }
-
- function tag(&$out) {
- $s = $this->seek();
- $tag = array();
- if ($this->combinator($op)) $tag['comb'] = $op;
-
- if (!$this->match('(.*?)( |$|\[|'.self::$combinators.')', $match)) {
- $this->seek($s);
- return false;
- }
-
- if (!empty($match[3])) {
- // give back combinator
- $this->count-=strlen($match[3]);
- }
-
- if (!empty($match[1])) $tag['front'] = $match[1];
-
- if ($match[2] == '[') {
- if ($this->ident($i)) {
- $tag['attr'] = $i;
-
- if ($this->match(self::$match_opts, $m) && $this->value($v)) {
- $tag['op'] = $m[1];
- $tag['op_value'] = $v;
- }
-
- if ($this->literal(']')) {
- $out = $tag;
- return true;
- }
- }
- } elseif (isset($tag['front'])) {
- $out = $tag;
- return true;
- }
-
- $this->seek($s);
- return false;
- }
-
- function ident(&$out) {
- // [-]?{nmstart}{nmchar}*
- // nmstart: [_a-z]|{nonascii}|{escape}
- // nmchar: [_a-z0-9-]|{nonascii}|{escape}
- if ($this->match('(-?[_a-z][_\w]*)', $m)) {
- $out = $m[1];
- return true;
- }
- return false;
- }
-
- function value(&$out) {
- if ($this->string($str)) {
- $out = $this->compileString($str);
- return true;
- } elseif ($this->ident($id)) {
- $out = $id;
- return true;
- }
- return false;
- }
-
-
- function combinator(&$op) {
- if ($this->match(self::$combinators, $m)) {
- $op = $m[1];
- return true;
- }
- return false;
- }
-}
-
-class nodecounter {
- var $count = 0;
- var $children = array();
-
- var $name;
- var $child_blocks;
- var $the_block;
-
- function __construct($name) {
- $this->name = $name;
- }
-
- function dump($stack = null) {
- if (is_null($stack)) $stack = array();
- $stack[] = $this->getName();
- echo implode(' -> ', $stack)." ($this->count)\n";
- foreach ($this->children as $child) {
- $child->dump($stack);
- }
- }
-
- static function compileProperties($c, $block) {
- foreach($block as $name => $value) {
- if ($c->isProperty($name, $value)) {
- echo $c->compileProperty($name, $value)."\n";
- }
- }
- }
-
- function compile($c, $path = null) {
- if (is_null($path)) $path = array();
- $path[] = $this->name;
-
- $isVisible = !is_null($this->the_block) || !is_null($this->child_blocks);
-
- if ($isVisible) {
- echo $c->indent(implode(' ', $path).' {');
- $c->indentLevel++;
- $path = array();
-
- if ($this->the_block) {
- $this->compileProperties($c, $this->the_block);
- }
-
- if ($this->child_blocks) {
- foreach ($this->child_blocks as $block) {
- echo $c->indent(tagparse::compilePaths($block['__tags']).' {');
- $c->indentLevel++;
- $this->compileProperties($c, $block);
- $c->indentLevel--;
- echo $c->indent('}');
- }
- }
- }
-
- // compile child nodes
- foreach($this->children as $node) {
- $node->compile($c, $path);
- }
-
- if ($isVisible) {
- $c->indentLevel--;
- echo $c->indent('}');
- }
-
- }
-
- function getName() {
- if (is_null($this->name)) return "[root]";
- else return $this->name;
- }
-
- function getNode($name) {
- if (!isset($this->children[$name])) {
- $this->children[$name] = new nodecounter($name);
- }
-
- return $this->children[$name];
- }
-
- function findNode($path) {
- $current = $this;
- for ($i = 0; $i < count($path); $i++) {
- $t = tagparse::compileTag($path[$i]);
- $current = $current->getNode($t);
- }
-
- return $current;
- }
-
- function addBlock($path, $block) {
- $node = $this->findNode($path);
- if (!is_null($node->the_block)) throw new exception("can this happen?");
-
- unset($block['__tags']);
- $node->the_block = $block;
- }
-
- function addToNode($path, $block) {
- $node = $this->findNode($path);
- $node->child_blocks[] = $block;
- }
-}
-
-/**
- * create a less file from a css file by combining blocks where appropriate
- */
-class lessify extends lessc {
- public function dump() {
- print_r($this->env);
- }
-
- public function parse($str = null) {
- $this->prepareParser($str ? $str : $this->buffer);
- while (false !== $this->parseChunk());
-
- $root = new nodecounter(null);
-
- // attempt to preserve some of the block order
- $order = array();
-
- $visitedTags = array();
- foreach (end($this->env) as $name => $block) {
- if (!$this->isBlock($name, $block)) continue;
- if (isset($visitedTags[$name])) continue;
-
- foreach ($block['__tags'] as $t) {
- $visitedTags[$t] = true;
- }
-
- // skip those with more than 1
- if (count($block['__tags']) == 1) {
- $p = new tagparse(end($block['__tags']));
- $path = $p->parse();
- $root->addBlock($path, $block);
- $order[] = array('compressed', $path, $block);
- continue;
- } else {
- $common = null;
- $paths = array();
- foreach ($block['__tags'] as $rawtag) {
- $p = new tagparse($rawtag);
- $paths[] = $path = $p->parse();
- if (is_null($common)) $common = $path;
- else {
- $new_common = array();
- foreach ($path as $tag) {
- $head = array_shift($common);
- if ($tag == $head) {
- $new_common[] = $head;
- } else break;
- }
- $common = $new_common;
- if (empty($common)) {
- // nothing in common
- break;
- }
- }
- }
-
- if (!empty($common)) {
- $new_paths = array();
- foreach ($paths as $p) $new_paths[] = array_slice($p, count($common));
- $block['__tags'] = $new_paths;
- $root->addToNode($common, $block);
- $order[] = array('compressed', $common, $block);
- continue;
- }
-
- }
-
- $order[] = array('none', $block['__tags'], $block);
- }
-
-
- $compressed = $root->children;
- foreach ($order as $item) {
- list($type, $tags, $block) = $item;
- if ($type == 'compressed') {
- $top = tagparse::compileTag(reset($tags));
- if (isset($compressed[$top])) {
- $compressed[$top]->compile($this);
- unset($compressed[$top]);
- }
- } else {
- echo $this->indent(implode(', ', $tags).' {');
- $this->indentLevel++;
- nodecounter::compileProperties($this, $block);
- $this->indentLevel--;
- echo $this->indent('}');
- }
- }
- }
-}
diff --git a/vendor/leafo/lessphp/package.sh b/vendor/leafo/lessphp/package.sh
deleted file mode 100644
index f0888f12..00000000
--- a/vendor/leafo/lessphp/package.sh
+++ /dev/null
@@ -1,35 +0,0 @@
-#!/bin/sh
-
-# creates tar.gz for current version
-
-VERSION=`./plessc -v | sed -n 's/^v\(.*\)$/\1/p'`
-OUT_DIR="tmp/lessphp"
-TMP=`dirname $OUT_DIR`
-
-mkdir -p $OUT_DIR
-tar -c `git ls-files` | tar -C $OUT_DIR -x
-
-rm $OUT_DIR/.gitignore
-rm $OUT_DIR/package.sh
-rm $OUT_DIR/lessify
-rm $OUT_DIR/lessify.inc.php
-
-OUT_NAME="lessphp-$VERSION.tar.gz"
-tar -czf $OUT_NAME -C $TMP lessphp/
-echo "Wrote $OUT_NAME"
-
-rm -r $TMP
-
-
-echo
-echo "Don't forget to"
-echo "* Update the version in lessc.inc.php (two places)"
-echo "* Update the version in the README.md"
-echo "* Update the version in docs.md (two places)"
-echo "* Update the version in LICENSE"
-echo "* Update @current_version in site.moon"
-echo "* Add entry to feed.moon for changelog"
-echo "* Update the -New- area on homepage with date and features"
-echo
-
-
diff --git a/vendor/leafo/lessphp/plessc b/vendor/leafo/lessphp/plessc
deleted file mode 100644
index 1871dc77..00000000
--- a/vendor/leafo/lessphp/plessc
+++ /dev/null
@@ -1,250 +0,0 @@
-#!/usr/bin/env php
-<?php
-// Command line utility to compile LESS to STDOUT
-// Leaf Corcoran <leafot@gmail.com>, 2013
-
-$exe = array_shift($argv); // remove filename
-
-$HELP = <<<EOT
-Usage: $exe [options] input-file [output-file]
-
-Options include:
-
- -h, --help Show this message
- -v Print the version
- -f=format Set the output format, includes "default", "compressed"
- -c Keep /* */ comments in output
- -r Read from STDIN instead of input-file
- -w Watch input-file, and compile to output-file if it is changed
- -T Dump formatted parse tree
- -X Dump raw parse tree
-
-
-EOT;
-
-$opts = getopt('hvrwncXTf:', array('help'));
-while (count($argv) > 0 && preg_match('/^-([-hvrwncXT]$|[f]=)/', $argv[0])) {
- array_shift($argv);
-}
-
-function has() {
- global $opts;
- foreach (func_get_args() as $arg) {
- if (isset($opts[$arg])) return true;
- }
- return false;
-}
-
-if (has("h", "help")) {
- exit($HELP);
-}
-
-error_reporting(E_ALL);
-$path = realpath(dirname(__FILE__)).'/';
-
-require $path."lessc.inc.php";
-
-$VERSION = lessc::$VERSION;
-
-$fa = "Fatal Error: ";
-function err($msg) {
- fwrite(STDERR, $msg."\n");
-}
-
-if (php_sapi_name() != "cli") {
- err($fa.$argv[0]." must be run in the command line.");
- exit(1);
-}
-
-function make_less($fname = null) {
- global $opts;
- $l = new lessc($fname);
-
- if (has("f")) {
- $format = $opts["f"];
- if ($format != "default") $l->setFormatter($format);
- }
-
- if (has("c")) {
- $l->setPreserveComments(true);
- }
-
- return $l;
-}
-
-function process($data, $import = null) {
- global $fa;
-
- $l = make_less();
- if ($import) $l->importDir = $import;
-
- try {
- echo $l->parse($data);
- exit(0);
- } catch (exception $ex) {
- err($fa."\n".str_repeat('=', 20)."\n".
- $ex->getMessage());
- exit(1);
- }
-}
-
-if (has("v")) {
- exit($VERSION."\n");
-}
-
-if (has("r")) {
- if (!empty($argv)) {
- $data = $argv[0];
- } else {
- $data = "";
- while (!feof(STDIN)) {
- $data .= fread(STDIN, 8192);
- }
- }
- exit(process($data));
-}
-
-if (has("w")) {
- // need two files
- if (!is_file($in = array_shift($argv)) ||
- null == $out = array_shift($argv))
- {
- err($fa.$exe." -w infile outfile");
- exit(1);
- }
-
- echo "Watching ".$in.
- (has("n") ? ' with notifications' : '').
- ", press Ctrl + c to exit.\n";
-
- $cache = $in;
- $last_action = 0;
- while (true) {
- clearstatcache();
-
- // check if anything has changed since last fail
- $updated = false;
- if (is_array($cache)) {
- foreach ($cache['files'] as $fname=>$_) {
- if (filemtime($fname) > $last_action) {
- $updated = true;
- break;
- }
- }
- } else $updated = true;
-
- // try to compile it
- if ($updated) {
- $last_action = time();
-
- try {
- $cache = lessc::cexecute($cache);
- echo "Writing updated file: ".$out."\n";
- if (!file_put_contents($out, $cache['compiled'])) {
- err($fa."Could not write to file ".$out);
- exit(1);
- }
- } catch (exception $ex) {
- echo "\nFatal Error:\n".str_repeat('=', 20)."\n".
- $ex->getMessage()."\n\n";
-
- if (has("n")) {
- `notify-send -u critical "compile failed" "{$ex->getMessage()}"`;
- }
- }
- }
-
- sleep(1);
- }
- exit(0);
-}
-
-if (!$fname = array_shift($argv)) {
- echo $HELP;
- exit(1);
-}
-
-function dumpValue($node, $depth = 0) {
- if (is_object($node)) {
- $indent = str_repeat(" ", $depth);
- $out = array();
- foreach ($node->props as $prop) {
- $out[] = $indent . dumpValue($prop, $depth + 1);
- }
- $out = implode("\n", $out);
- if (!empty($node->tags)) {
- $out = "+ ".implode(", ", $node->tags)."\n".$out;
- }
- return $out;
- } elseif (is_array($node)) {
- if (empty($node)) return "[]";
- $type = $node[0];
- if ($type == "block")
- return dumpValue($node[1], $depth);
-
- $out = array();
- foreach ($node as $value) {
- $out[] = dumpValue($value, $depth);
- }
- return "{ ".implode(", ", $out)." }";
- } else {
- if (is_string($node) && preg_match("/[\s,]/", $node)) {
- return '"'.$node.'"';
- }
- return $node; // normal value
- }
-}
-
-
-function stripValue($o, $toStrip) {
- if (is_array($o) || is_object($o)) {
- $isObject = is_object($o);
- $o = (array)$o;
- foreach ($toStrip as $removeKey) {
- if (!empty($o[$removeKey])) {
- $o[$removeKey] = "*stripped*";
- }
- }
-
- foreach ($o as $k => $v) {
- $o[$k] = stripValue($v, $toStrip);
- }
-
- if ($isObject) {
- $o = (object)$o;
- }
- }
-
- return $o;
-}
-
-function dumpWithoutParent($o, $alsoStrip=array()) {
- $toStrip = array_merge(array("parent"), $alsoStrip);
- print_r(stripValue($o, $toStrip));
-}
-
-try {
- $less = make_less($fname);
- if (has("T", "X")) {
- $parser = new lessc_parser($less, $fname);
- $tree = $parser->parse(file_get_contents($fname));
- if (has("X"))
- $out = print_r($tree, 1);
- else
- $out = dumpValue($tree)."\n";
- } else {
- $out = $less->parse();
- }
-
- if (!$fout = array_shift($argv)) {
- echo $out;
- } else {
- file_put_contents($fout, $out);
- }
-
-} catch (exception $ex) {
- err($fa.$ex->getMessage());
- exit(1);
-}
-
-?>
diff --git a/vendor/leafo/lessphp/tests/ApiTest.php b/vendor/leafo/lessphp/tests/ApiTest.php
deleted file mode 100644
index fe1bbffa..00000000
--- a/vendor/leafo/lessphp/tests/ApiTest.php
+++ /dev/null
@@ -1,196 +0,0 @@
-<?php
-
-require_once __DIR__ . "/../lessc.inc.php";
-
-class ApiTest extends PHPUnit_Framework_TestCase {
- public function setUp() {
- $this->less = new lessc();
- $this->less->importDir = array(__DIR__ . "/inputs/test-imports");
- }
-
- public function testPreserveComments() {
- $input = <<<EOD
-// what is going on?
-
-/** what the heck **/
-
-/**
-
-Here is a block comment
-
-**/
-
-
-// this is a comment
-
-/*hello*/div /*yeah*/ { //surew
- border: 1px solid red; // world
- /* comment above the first occurrence of a duplicated rule */
- color: url('http://mage-page.com');
- string: "hello /* this is not a comment */";
- world: "// neither is this";
- /* comment above the second occurrence of a duplicated rule */
- color: url('http://mage-page.com');
- string: 'hello /* this is not a comment */' /*what if this is a comment */;
- world: '// neither is this' // hell world;
- ;
- /* duplicate comments are retained */
- /* duplicate comments are retained */
- what-ever: 100px;
- background: url(/*this is not a comment?*/); // uhh what happens here
-}
-EOD;
-
-
- $outputWithComments = <<<EOD
-/** what the heck **/
-/**
-
-Here is a block comment
-
-**/
-/*hello*/
-/*yeah*/
-div /*yeah*/ {
- border: 1px solid red;
- /* comment above the first occurrence of a duplicated rule */
- /* comment above the second occurrence of a duplicated rule */
- color: url('http://mage-page.com');
- string: "hello /* this is not a comment */";
- world: "// neither is this";
- /*what if this is a comment */
- string: 'hello /* this is not a comment */';
- world: '// neither is this';
- /* duplicate comments are retained */
- /* duplicate comments are retained */
- what-ever: 100px;
- /*this is not a comment?*/
- background: url();
-}
-EOD;
-
- $outputWithoutComments = <<<EOD
-div {
- border: 1px solid red;
- color: url('http://mage-page.com');
- string: "hello /* this is not a comment */";
- world: "// neither is this";
- string: 'hello /* this is not a comment */';
- world: '// neither is this';
- what-ever: 100px;
- background: url(/*this is not a comment?*/);
-}
-EOD;
-
- $this->assertEquals($this->compile($input), trim($outputWithoutComments));
- $this->less->setPreserveComments(true);
- $this->assertEquals($this->compile($input), trim($outputWithComments));
- }
-
- public function testOldInterface() {
- $this->less = new lessc(__DIR__ . "/inputs/hi.less");
- $out = $this->less->parse(array("hello" => "10px"));
- $this->assertEquals(trim($out), trim('
-div:before {
- content: "hi!";
-}'));
-
- }
-
- public function testInjectVars() {
- $out = $this->less->parse(".magic { color: @color; width: @base - 200; }",
- array(
- 'color' => 'red',
- 'base' => '960px'
- ));
-
- $this->assertEquals(trim($out), trim("
-.magic {
- color: red;
- width: 760px;
-}"));
-
- }
-
- public function testDisableImport() {
- $this->less->importDisabled = true;
- $this->assertEquals(
- "/* import disabled */",
- $this->compile("@import 'file3';"));
- }
-
- public function testUserFunction() {
- $this->less->registerFunction("add-two", function($list) {
- list($a, $b) = $list[2];
- return $a[1] + $b[1];
- });
-
- $this->assertEquals(
- $this->compile("result: add-two(10, 20);"),
- "result: 30;");
-
- return $this->less;
- }
-
- /**
- * @depends testUserFunction
- */
- public function testUnregisterFunction($less) {
- $less->unregisterFunction("add-two");
-
- $this->assertEquals(
- $this->compile("result: add-two(10, 20);"),
- "result: add-two(10,20);");
- }
-
-
-
- public function testFormatters() {
- $src = "
- div, pre {
- color: blue;
- span, .big, hello.world {
- height: 20px;
- color:#ffffff + #000;
- }
- }";
-
- $this->less->setFormatter("compressed");
- $this->assertEquals(
- $this->compile($src), "div,pre{color:blue;}div span,div .big,div hello.world,pre span,pre .big,pre hello.world{height:20px;color:#fff;}");
-
- // TODO: fix the output order of tags
- $this->less->setFormatter("lessjs");
- $this->assertEquals(
- $this->compile($src),
-"div,
-pre {
- color: blue;
-}
-div span,
-div .big,
-div hello.world,
-pre span,
-pre .big,
-pre hello.world {
- height: 20px;
- color: #ffffff;
-}");
-
- $this->less->setFormatter("classic");
- $this->assertEquals(
- $this->compile($src),
-trim("div, pre { color:blue; }
-div span, div .big, div hello.world, pre span, pre .big, pre hello.world {
- height:20px;
- color:#ffffff;
-}
-"));
-
- }
-
- public function compile($str) {
- return trim($this->less->parse($str));
- }
-
-}
diff --git a/vendor/leafo/lessphp/tests/ErrorHandlingTest.php b/vendor/leafo/lessphp/tests/ErrorHandlingTest.php
deleted file mode 100644
index de02f065..00000000
--- a/vendor/leafo/lessphp/tests/ErrorHandlingTest.php
+++ /dev/null
@@ -1,81 +0,0 @@
-<?php
-require_once __DIR__ . "/../lessc.inc.php";
-
-class ErrorHandlingTest extends PHPUnit_Framework_TestCase {
- public function setUp() {
- $this->less = new lessc();
- }
-
- public function compile() {
- $source = join("\n", func_get_args());
- return $this->less->compile($source);
- }
-
- /**
- * @expectedException Exception
- * @expectedExceptionMessage .parametric-mixin is undefined
- */
- public function testRequiredParametersMissing() {
- $this->compile(
- '.parametric-mixin (@a, @b) { a: @a; b: @b; }',
- '.selector { .parametric-mixin(12px); }'
- );
- }
-
- /**
- * @expectedException Exception
- * @expectedExceptionMessage .parametric-mixin is undefined
- */
- public function testTooManyParameters() {
- $this->compile(
- '.parametric-mixin (@a, @b) { a: @a; b: @b; }',
- '.selector { .parametric-mixin(12px, 13px, 14px); }'
- );
- }
-
- /**
- * @expectedException Exception
- * @expectedExceptionMessage unrecognised input
- */
- public function testRequiredArgumentsMissing() {
- $this->compile('.selector { rule: e(); }');
- }
-
- /**
- * @expectedException Exception
- * @expectedExceptionMessage variable @missing is undefined
- */
- public function testVariableMissing() {
- $this->compile('.selector { rule: @missing; }');
- }
-
- /**
- * @expectedException Exception
- * @expectedExceptionMessage .missing-mixin is undefined
- */
- public function testMixinMissing() {
- $this->compile('.selector { .missing-mixin; }');
- }
-
- /**
- * @expectedException Exception
- * @expectedExceptionMessage .flipped is undefined
- */
- public function testGuardUnmatchedValue() {
- $this->compile(
- '.flipped(@x) when (@x =< 10) { rule: value; }',
- '.selector { .flipped(12); }'
- );
- }
-
- /**
- * @expectedException Exception
- * @expectedExceptionMessage .colors-only is undefined
- */
- public function testGuardUnmatchedType() {
- $this->compile(
- '.colors-only(@x) when (iscolor(@x)) { rule: value; }',
- '.selector { .colors-only("string value"); }'
- );
- }
-}
diff --git a/vendor/leafo/lessphp/tests/InputTest.php b/vendor/leafo/lessphp/tests/InputTest.php
deleted file mode 100644
index 32db95bc..00000000
--- a/vendor/leafo/lessphp/tests/InputTest.php
+++ /dev/null
@@ -1,89 +0,0 @@
-<?php
-
-require_once __DIR__ . "/../lessc.inc.php";
-
-// Runs all the tests in inputs/ and compares their output to ouputs/
-
-function _dump($value) {
- fwrite(STDOUT, print_r($value, true));
-}
-
-function _quote($str) {
- return preg_quote($str, "/");
-}
-
-class InputTest extends PHPUnit_Framework_TestCase {
- protected static $importDirs = array("inputs/test-imports");
-
- protected static $testDirs = array(
- "inputs" => "outputs",
- "inputs_lessjs" => "outputs_lessjs",
- );
-
- public function setUp() {
- $this->less = new lessc();
- $this->less->importDir = array_map(function($path) {
- return __DIR__ . "/" . $path;
- }, self::$importDirs);
- }
-
- /**
- * @dataProvider fileNameProvider
- */
- public function testInputFile($inFname) {
- if ($pattern = getenv("BUILD")) {
- return $this->buildInput($inFname);
- }
-
- $outFname = self::outputNameFor($inFname);
-
- if (!is_readable($outFname)) {
- $this->fail("$outFname is missing, ".
- "consider building tests with BUILD=true");
- }
-
- $input = file_get_contents($inFname);
- $output = file_get_contents($outFname);
-
- $this->assertEquals($output, $this->less->parse($input));
- }
-
- public function fileNameProvider() {
- return array_map(function($a) { return array($a); },
- self::findInputNames());
- }
-
- // only run when env is set
- public function buildInput($inFname) {
- $css = $this->less->parse(file_get_contents($inFname));
- file_put_contents(self::outputNameFor($inFname), $css);
- }
-
- static public function findInputNames($pattern="*.less") {
- $files = array();
- foreach (self::$testDirs as $inputDir => $outputDir) {
- $files = array_merge($files, glob(__DIR__ . "/" . $inputDir . "/" . $pattern));
- }
-
- return array_filter($files, "is_file");
- }
-
- static public function outputNameFor($input) {
- $front = _quote(__DIR__ . "/");
- $out = preg_replace("/^$front/", "", $input);
-
- foreach (self::$testDirs as $inputDir => $outputDir) {
- $in = _quote($inputDir . "/");
- $rewritten = preg_replace("/$in/", $outputDir . "/", $out);
- if ($rewritten != $out) {
- $out = $rewritten;
- break;
- }
- }
-
- $out = preg_replace("/.less$/", ".css", $out);
-
- return __DIR__ . "/" . $out;
- }
-}
-
diff --git a/vendor/leafo/lessphp/tests/README.md b/vendor/leafo/lessphp/tests/README.md
deleted file mode 100644
index 85a75c05..00000000
--- a/vendor/leafo/lessphp/tests/README.md
+++ /dev/null
@@ -1,24 +0,0 @@
-lessphp uses [phpunit](https://github.com/sebastianbergmann/phpunit/) for its tests
-
-* `InputTest.php` iterates through all the less files in `inputs/`, compiles
- them, then compares the result with the respective file in `outputs/`.
-
-* `ApiTest.php` tests the behavior of lessphp's public API methods.
-
-* `ErrorHandlingTest.php` tests that lessphp throws appropriate errors when
- given invalid LESS as input.
-
-From the root you can run `make` to run all the tests.
-
-## lessjs tests
-
-Tests found in `inputs_lessjs` are extracted directly from
-[less.js](https://github.com/less/less.js). The following license applies to
-those tests: https://github.com/less/less.js/blob/master/LICENSE
-
-## bootstrap.sh
-
-Clones twitter bootsrap, compiles it with lessc and lessphp, cleans up results
-with sort.php, and outputs diff. To run it, you need to have git and lessc
-installed.
-
diff --git a/vendor/leafo/lessphp/tests/bootstrap.sh b/vendor/leafo/lessphp/tests/bootstrap.sh
deleted file mode 100644
index 18a90e87..00000000
--- a/vendor/leafo/lessphp/tests/bootstrap.sh
+++ /dev/null
@@ -1,38 +0,0 @@
-#!/bin/sh
-
-echo "This script clones Twitter Bootstrap, compiles it with lessc and lessphp,"
-echo "cleans up results with sort.php, and outputs diff. To run it, you need to"
-echo "have git and lessc installed."
-echo ""
-
-if [ -z "$input" ]; then
- input="bootstrap/less/bootstrap.less"
-fi
-dest=$(basename "$input")
-dest="${dest%.*}"
-
-if [ -z "$@" ]; then
- diff_tool="diff -b -u -t -B"
-else
- diff_tool=$@
-fi
-
-mkdir -p tmp
-
-if [ ! -d 'bootstrap/' ]; then
- echo ">> Cloning bootstrap to bootstrap/"
- git clone https://github.com/twbs/bootstrap
-fi
-
-echo ">> lessc compilation ($input)"
-lessc "$input" "tmp/$dest.lessc.css"
-
-echo ">> lessphp compilation ($input)"
-../plessc "$input" "tmp/$dest.lessphp.css"
-echo ">> Cleanup and convert"
-
-php sort.php "tmp/$dest.lessc.css" > "tmp/$dest.lessc.clean.css"
-php sort.php "tmp/$dest.lessphp.css" > "tmp/$dest.lessphp.clean.css"
-
-echo ">> Doing diff"
-$diff_tool "tmp/$dest.lessc.clean.css" "tmp/$dest.lessphp.clean.css"
diff --git a/vendor/leafo/lessphp/tests/inputs/accessors.less.disable b/vendor/leafo/lessphp/tests/inputs/accessors.less.disable
deleted file mode 100644
index 2990faab..00000000
--- a/vendor/leafo/lessphp/tests/inputs/accessors.less.disable
+++ /dev/null
@@ -1,36 +0,0 @@
-/* accessors */
-
-#defaults {
- @width: 960px;
- @color: black;
- .something {
- @space: 10px;
- @hello {
- color: green;
- }
- }
-}
-
-.article { color: #294366; }
-
-.comment {
- width: #defaults[@width];
- color: .article['color'];
- padding: #defaults > .something[@space];
-}
-
-.wow {
- height: .comment['width'];
- background-color: .comment['color'];
- color: #defaults > .something > @hello['color'];
-
- padding: #defaults > non-existant['padding'];
- margin: #defaults > .something['non-existant'];
-}
-
-.mix {
- #defaults;
- font-size: .something[@space];
-}
-
-
diff --git a/vendor/leafo/lessphp/tests/inputs/arity.less b/vendor/leafo/lessphp/tests/inputs/arity.less
deleted file mode 100644
index 9998fd4a..00000000
--- a/vendor/leafo/lessphp/tests/inputs/arity.less
+++ /dev/null
@@ -1,77 +0,0 @@
-
-// simple arity
-
-.hello(@a) {
- hello: one;
-}
-
-.hello(@a, @b) {
- hello: two;
-}
-
-.hello(@a, @b, @c) {
- hello: three;
-}
-
-
-.world(@a, @b, @c) {
- world: three;
-}
-
-.world(@a, @b) {
- world: two;
-}
-
-.world(@a) {
- world: one;
-}
-
-.one {
- .hello(1);
- .world(1);
-}
-
-.two {
- .hello(1, 1);
- .world(1, 1);
-}
-
-.three {
- .hello(1, 1, 1);
- .world(1, 1, 1);
-}
-
-
-// arity with default values
-
-.foo(@a, @b: cool) {
- foo: two @b;
-}
-
-.foo(@a, @b: cool, @c: yeah) {
- foo: three @b @c;
-}
-
-
-.baz(@a, @b, @c: yeah) {
- baz: three @c;
-}
-
-.baz(@a, @b: cool) {
- baz: two @b;
-}
-
-
-.multi-foo {
- .foo(1);
- .foo(1, 1);
- .foo(1,1,1);
-}
-
-.multi-baz {
- .baz(1);
- .baz(1, 1);
- .baz(1,1,1);
-}
-
-
diff --git a/vendor/leafo/lessphp/tests/inputs/attributes.less b/vendor/leafo/lessphp/tests/inputs/attributes.less
deleted file mode 100644
index 7ede4fc4..00000000
--- a/vendor/leafo/lessphp/tests/inputs/attributes.less
+++ /dev/null
@@ -1,41 +0,0 @@
-* { color: blue; }
-E { color: blue; }
-E[foo] { color: blue; }
-[foo] { color: blue; }
-[foo] .helloWorld { color: blue; }
-[foo].helloWorld { color: blue; }
-E[foo="barbar"] { color: blue; }
-E[foo~="hello#$@%@$#^"] { color: blue; }
-E[foo^="color: green;"] { color: blue; }
-E[foo$="239023"] { color: blue; }
-E[foo*="29302"] { color: blue; }
-E[foo|="239032"] { color: blue; }
-E:root { color: blue; }
-
-E:nth-child(odd) { color: blue; }
-E:nth-child(2n+1) { color: blue; }
-E:nth-child(5) { color: blue; }
-E:nth-last-child(-n+2) { color: blue; }
-E:nth-of-type(2n) { color: blue; }
-E:nth-last-of-type(n) { color: blue; }
-
-E:first-child { color: blue; }
-E:last-child { color: blue; }
-E:first-of-type { color: blue; }
-E:last-of-type { color: blue; }
-E:only-child { color: blue; }
-E:only-of-type { color: blue; }
-E:empty { color: blue; }
-
-E:lang(en) { color: blue; }
-E::first-line { color: blue; }
-E::before { color: blue; }
-
-E#id { color: blue; }
-E:not(:link) { color: blue; }
-
-E F { color: blue; }
-E > F { color: blue; }
-E + F { color: blue; }
-E ~ F { color: blue; }
-
diff --git a/vendor/leafo/lessphp/tests/inputs/builtins.less b/vendor/leafo/lessphp/tests/inputs/builtins.less
deleted file mode 100644
index f9301e04..00000000
--- a/vendor/leafo/lessphp/tests/inputs/builtins.less
+++ /dev/null
@@ -1,96 +0,0 @@
-// builtin
-
-@something: "hello world";
-@color: #112233;
-@color2: rgba(44,55,66, .6);
-
-body {
- color: @something;
-
- @num: 7 / 6;
- num-basic: @num + 4;
- num-floor: floor(@num) + 4px;
- num-ceil: ceil(@num) + 4px;
-
- @num2: 2 / 3;
- num2: @num2;
- num2-round: round(@num2);
- num2-floor: floor(@num2);
- num2-ceil: ceil(@num2);
-
- round-lit: round(10px / 3);
-
- rgba1: rgbahex(@color);
- rgba2: rgbahex(@color2);
- argb: argb(@color2);
-}
-
-
-format {
- @r: 32;
- format: %("rgb(%d, %d, %d)", @r, 128, 64);
- format-string: %("hello %s", "world");
- format-multiple: %("hello %s %d", "earth", 2);
- format-url-encode: %('red is %A', #ff0000);
- eformat: e(%("rgb(%d, %d, %d)", @r, 128, 64));
-}
-
-
-#functions {
- str1: isstring("hello");
- str2: isstring(one, two);
-
- num1: isnumber(2323px);
- num2: isnumber(2323);
- num3: isnumber(4/5);
- num4: isnumber("hello");
-
- col1: iscolor(red);
- col2: iscolor(hello);
- col3: iscolor(rgba(0,0,0,0.3));
- col4: iscolor(#fff);
-
- key1: iskeyword(hello);
- key2: iskeyword(3D);
-
- px1: ispixel(10px);
- px2: ispixel(10);
-
- per1: ispercentage(10%);
- per2: ispercentage(10);
-
- em1: isem(10em);
- em2: isem(10);
-
- ex1: extract(1 2 3 4, 2);
- ex2: extract(1 2, 1);
- ex3: extract(1, 1);
-
- @list: 1,2,3,4;
-
- ex4: extract(@list, 2);
-
- pow: pow(2,4);
- pi: pi();
- mod: mod(14,10);
-
- tan: tan(1);
- cos: cos(1);
- sin: sin(1);
-
- atan: atan(1);
- acos: acos(1);
- asin: asin(1);
-
- sqrt: sqrt(8);
-}
-
-
-#unit {
- @unit: "em";
- unit-lit: unit(10px);
- unit-arg: unit(10px, "s");
- unit-arg2: unit(10px, @unit);
- unit-math: unit(0.07407s) * 100%;
-}
-
diff --git a/vendor/leafo/lessphp/tests/inputs/colors.less b/vendor/leafo/lessphp/tests/inputs/colors.less
deleted file mode 100644
index 7fd47a3c..00000000
--- a/vendor/leafo/lessphp/tests/inputs/colors.less
+++ /dev/null
@@ -1,154 +0,0 @@
-
-body {
- color:rgb(red(#f00), red(#0F0), red(#00f));
- color:rgb(red(#f00), green(#0F0), blue(#00f));
- color:rgb(red(#0ff), green(#f0f), blue(#ff0));
-
- color: hsl(34, 50%, 40%);
- color: hsla(34, 50%, 40%, 0.3);
-
- lighten1: lighten(#efefef, 10%);
- lighten2: lighten(rgb(23, 53, 231), 22%);
- lighten3: lighten(rgba(212, 103, 88, 0.5), 10%);
-
- darken1: darken(#efefef, 10%);
- darken2: darken(rgb(23, 53, 231), 22%);
- darken3: darken(rgba(23, 53, 231, 0.5), 10%);
-
- saturate1: saturate(#efefef, 10%);
- saturate2: saturate(rgb(23, 53, 231), 22%);
- saturate3: saturate(rgba(23, 53, 231, 0.5), 10%);
-
- desaturate1: desaturate(#efefef, 10%);
- desaturate2: desaturate(rgb(23, 53, 231), 22%);
- desaturate3: desaturate(rgba(23, 53, 231, 0.5), 10%);
-
- spin1: spin(#efefef, 12);
- spin2: spin(rgb(23, 53, 231), 15);
- spin3: spin(rgba(23, 53, 231, 0.5), 19);
-
- spin2: spin(#efefef, -12);
- spin3: spin(rgb(23, 53, 231), -15);
- spin4: spin(rgba(23, 53, 231, 0.5), -19);
-
- one1: fadein(#abcdef, 10%);
- one2: fadeout(#abcdef, -10%);
-
- two1: fadeout(#029f23, 10%);
- two2: fadein(#029f23, -10%);
-
-
- three1: fadein(rgba(1,2,3, 0.5), 10%);
- three2: fadeout(rgba(1,2,3, 0.5), -10%);
-
- four1: fadeout(rgba(1,2,3, 0), 10%);
- four2: fadein(rgba(1,2,3, 0), -10%);
-
- hue: hue(rgb(34,20,40));
- sat: saturation(rgb(34,20,40));
- lit: lightness(rgb(34,20,40));
-
- @old: #34fa03;
- @new: hsl(hue(@old), 45%, 90%);
- what: @new;
-
- zero1: saturate(#123456, -100%);
- zero2: saturate(#123456, 100%);
- zero3: saturate(#000000, 100%);
- zero4: saturate(#ffffff, 100%);
-
- zero5: lighten(#123456, -100%);
- zero6: lighten(#123456, 100%);
- zero7: lighten(#000000, 100%);
- zero8: lighten(#ffffff, 100%);
-
- zero9: spin(#123456, -100);
- zeroa: spin(#123456, 100);
- zerob: spin(#000000, 100);
- zeroc: spin(#ffffff, 100);
-}
-
-
-alpha {
- // g: alpha(red);
- g1: alpha(rgba(0,0,0,0));
- g2: alpha(rgb(155,55,0));
-}
-
-fade {
- f1: fade(red, 50%);
- f2: fade(#fff, 20%);
- f3: fade(rgba(34,23,64,0.4), 50%);
-}
-
-@a: rgb(255,255,255);
-@b: rgb(0,0,0);
-
-.mix {
- color1: mix(@a, @b, 50%);
- color2: mix(@a, @b);
- color3: mix(rgba(5,3,1,0.3), rgba(6,3,2, 0.8), 50%);
-}
-
-.contrast {
- color1: contrast(#000, red, blue);
- color2: contrast(#fff, red, blue);
-}
-
-.percent {
- per: percentage(0.5);
-}
-
-// color keywords
-
-.colorz {
- color1: whitesmoke - 10;
- color2: spin(red, 34);
- color3: spin(blah);
-}
-
-
-
-// purposfuly whacky to match less.js
-
-@color: #fcf8e3;
-
-body {
- start: @color;
- spin: spin(@color, -10); // #fcf4e3
- chained: darken(spin(@color, -10), 3%); // gives #fbeed5, should be #fbefd5
- direct: darken(#fcf4e3, 3%); // #fbefd5
-}
-
-// spin around
-pre {
- @errorBackground: #f2dede;
- spin: spin(@errorBackground, -10);
-}
-
-dd {
- @white: #fff;
- background-color: mix(@white, darken(@white, 10%), 60%);
-}
-
-// math
-
-.ops {
- c1: red * 0.3;
- c2: green / 2;
- c3: purple % 7;
- c4: 4 * salmon;
- c5: 1 + salmon;
-
- c6: 132 / red;
- c7: 132 - red;
- c8: 132- red;
-}
-
-.transparent {
- r: red(transparent);
- g: green(transparent);
- b: blue(transparent);
- a: alpha(transparent);
-}
-
diff --git a/vendor/leafo/lessphp/tests/inputs/compile_on_mixin.less b/vendor/leafo/lessphp/tests/inputs/compile_on_mixin.less
deleted file mode 100644
index 79d628f4..00000000
--- a/vendor/leafo/lessphp/tests/inputs/compile_on_mixin.less
+++ /dev/null
@@ -1,39 +0,0 @@
-
-@mixin {
- height: 22px;
- ul {
- height: 20px;
- li {
- @color: red;
- height: 10px;
- div span, link {
- margin: 10px;
- color: @color;
- }
- }
-
- div, p {
- border: 1px;
- &.hello {
- color: green;
- }
-
- :what {
- color: blue;
- }
- }
-
-
- a {
- b {
- color: blue;
- }
- }
- }
-}
-
-
-
-body {
- @mixin;
-}
diff --git a/vendor/leafo/lessphp/tests/inputs/data-uri.less b/vendor/leafo/lessphp/tests/inputs/data-uri.less
deleted file mode 100644
index 0cfa941a..00000000
--- a/vendor/leafo/lessphp/tests/inputs/data-uri.less
+++ /dev/null
@@ -1,7 +0,0 @@
-.small {
- background: data-uri("../hi.less");
-}
-
-.large {
- background: data-uri('../../../lessc.inc.php');
-}
diff --git a/vendor/leafo/lessphp/tests/inputs/directives.less b/vendor/leafo/lessphp/tests/inputs/directives.less
deleted file mode 100644
index 1b3a9b58..00000000
--- a/vendor/leafo/lessphp/tests/inputs/directives.less
+++ /dev/null
@@ -1,28 +0,0 @@
-
-@hello: "utf-8";
-@charset @hello;
-
-@-moz-document url-prefix(){
- div {
- color: red;
- }
-}
-
-@page :left { margin-left: 4cm; }
-@page :right { margin-left: 3cm; }
-@page { margin: 2cm }
-
-@-ms-viewport {
- width: device-width;
-}
-@-moz-viewport {
- width: device-width;
-}
-@-o-viewport {
- width: device-width;
-}
-@viewport {
- width: device-width;
-}
-
-
diff --git a/vendor/leafo/lessphp/tests/inputs/escape.less b/vendor/leafo/lessphp/tests/inputs/escape.less
deleted file mode 100644
index 5c15e786..00000000
--- a/vendor/leafo/lessphp/tests/inputs/escape.less
+++ /dev/null
@@ -1,18 +0,0 @@
-
-body {
- @hello: "world";
- e1: e("this is simple");
- e2: e("this is simple", "cool lad");
- e3: e(1232);
- e4: e(@hello);
- e5: e("one" + 'more');
-
- t1: ~"eating rice";
- t2: ~"string cheese";
- t3: a b c ~"string me" d e f;
- t4: ~"string @{hello}";
-}
-
-.class {
- filter: ~"progid:DXImageTransform.Microsoft.AlphaImageLoader(src='image.png')";
-}
diff --git a/vendor/leafo/lessphp/tests/inputs/font_family.less b/vendor/leafo/lessphp/tests/inputs/font_family.less
deleted file mode 100644
index d1dfb72d..00000000
--- a/vendor/leafo/lessphp/tests/inputs/font_family.less
+++ /dev/null
@@ -1,28 +0,0 @@
-
-@font-directory: 'fonts/';
-@some-family: Gentium;
-
-@font-face: maroon; // won't collide with @font-face { }
-
-@font-face {
- font-family: Graublau Sans Web;
- src: url(@{font-directory}GraublauWeb.otf) format("opentype");
-}
-
-@font-face {
- font-family: @some-family;
- src: url('@{font-directory}Gentium.ttf');
-}
-
-@font-face {
- font-family: @some-family;
- src: url("@{font-directory}GentiumItalic.ttf");
- font-style: italic;
-}
-
-h2 {
- font-family: @some-family;
- crazy: @font-face;
-}
-
-
diff --git a/vendor/leafo/lessphp/tests/inputs/guards.less b/vendor/leafo/lessphp/tests/inputs/guards.less
deleted file mode 100644
index fc4e344e..00000000
--- a/vendor/leafo/lessphp/tests/inputs/guards.less
+++ /dev/null
@@ -1,74 +0,0 @@
-
-.simple(@hi) when (@hi) {
- simple: yellow;
-}
-
-
-.something(@hi) when (@hi = cool) {
- something: red;
-}
-
-.another(@x) when (@x > 10) {
- another: green;
-}
-
-
-.flipped(@x) when (@x =< 10) {
- flipped: teal;
-}
-
-.yeah(@arg) when (isnumber(@arg)) {
- yeah-number: purple @arg;
-}
-
-
-.yeah(@arg) when (ispixel(@arg)) {
- yeah-pixel: silver;
-}
-
-
-.hello(@arg) when not (@arg) {
- hello: orange;
-}
-
-dd {
- .simple(true);
-}
-
-b {
- .something(cool);
- .something(birthday);
-}
-
-img {
- .another(12);
- .flipped(2);
-}
-
-body {
- .yeah(232px);
- .yeah(232);
-}
-
-.something(@x) when (@x) and (@y), not (@x = what) {
- something-complex: blue @x;
-}
-
-div {
- @y: true;
- .something(true);
-
-}
-
-.coloras(@g) when (iscolor(@g)) {
- color: true @g;
-}
-
-link {
- .coloras(red);
- .coloras(#fff);
- .coloras(#fffddd);
- .coloras(rgb(0,0,0));
- .coloras(rgba(0,0,0, .34));
-}
-
diff --git a/vendor/leafo/lessphp/tests/inputs/hacks.less b/vendor/leafo/lessphp/tests/inputs/hacks.less
deleted file mode 100644
index e69b7bf9..00000000
--- a/vendor/leafo/lessphp/tests/inputs/hacks.less
+++ /dev/null
@@ -1,6 +0,0 @@
-// css hacks
-
-:root .alert-message, :root .btn {
- border-radius: 0 \0;
-}
-
diff --git a/vendor/leafo/lessphp/tests/inputs/hi.less b/vendor/leafo/lessphp/tests/inputs/hi.less
deleted file mode 100644
index 9a3d8198..00000000
--- a/vendor/leafo/lessphp/tests/inputs/hi.less
+++ /dev/null
@@ -1,5 +0,0 @@
-
-div:before {
- content: "hi!";
-}
-
diff --git a/vendor/leafo/lessphp/tests/inputs/ie.less b/vendor/leafo/lessphp/tests/inputs/ie.less
deleted file mode 100644
index 37a5f1f6..00000000
--- a/vendor/leafo/lessphp/tests/inputs/ie.less
+++ /dev/null
@@ -1,12 +0,0 @@
-
-foo {
- filter: progid:DXImageTransform.Microsoft.gradient(GradientType=1, startColorstr=#c0ff3300, endColorstr=#ff000000);
- filter:progid:DXImageTransform.Microsoft.gradient(GradientType=1, startColorstr=#c0ff3300, endColorstr=#ff000001);
-}
-
-
-foo {
- filter: alpha(opacity=20);
- filter: alpha(opacity=20, enabled=true);
- filter: blaznicate(foo=bar, baz=bang bip, bart=#fa4600);
-}
diff --git a/vendor/leafo/lessphp/tests/inputs/import.less b/vendor/leafo/lessphp/tests/inputs/import.less
deleted file mode 100644
index a5005674..00000000
--- a/vendor/leafo/lessphp/tests/inputs/import.less
+++ /dev/null
@@ -1,56 +0,0 @@
-
-@import 'file1.less'; // file found and imported
-
-@import "not-found";
-
-@import "something.css" media;
-@import url("something.css") media;
-@import url(something.css) media, screen, print;
-
-@color: maroon;
-
-@import url(file2); // found and imported
-
-body {
- line-height: 10em;
- @colors;
-}
-
-div {
- @color: fuchsia;
- @import "file2";
-}
-
-
-.mixin-import() {
- @import "file3";
-}
-
-.one {
- .mixin-import();
- color: blue;
-}
-
-.two {
- .mixin-import();
-}
-
-
-#merge-import-mixins {
- @import "a";
- @import "b";
- div { .just-a-class; }
-}
-
-
-@import "inner/file1";
-
-
-// test bubbling variables up from imports, while preserving order
-
-pre {
- color: @someValue;
-}
-
-@import "file3";
-
diff --git a/vendor/leafo/lessphp/tests/inputs/interpolation.less b/vendor/leafo/lessphp/tests/inputs/interpolation.less
deleted file mode 100644
index 8aad0004..00000000
--- a/vendor/leafo/lessphp/tests/inputs/interpolation.less
+++ /dev/null
@@ -1,47 +0,0 @@
-
-@cool-hello: "yes";
-@cool-yes: "okay";
-@var: "hello";
-
-div {
- interp1: ~"@{cool-hello}";
- interp2: ~"@{cool-@{var}}";
- interp3: ~"@{cool-@{cool-@{var}}}";
-}
-
-// interpolation in selectors
-
-@hello: 10;
-@world: "yeah";
-
-@{hello}@{world} {
- color: blue;
-}
-
-@{hello} {
- color: blue;
-}
-
-hello world @{hello} {
- color: red;
-}
-
-#@{world} {
- color: "hello @{hello}";
-}
-
-
-@num: 3;
-
-[prop],
-[prop="value@{num}"],
-[prop*="val@{num}"],
-[|prop~="val@{num}"],
-[*|prop$="val@{num}"],
-[ns|prop^="val@{num}"],
-[@{num}^="val@{num}"],
-[@{num}=@{num}],
-[@{num}] {
- attributes: yes;
-}
-
diff --git a/vendor/leafo/lessphp/tests/inputs/keyframes.less b/vendor/leafo/lessphp/tests/inputs/keyframes.less
deleted file mode 100644
index e65a38b9..00000000
--- a/vendor/leafo/lessphp/tests/inputs/keyframes.less
+++ /dev/null
@@ -1,52 +0,0 @@
-@keyframes 'bounce' {
- from {
- top: 100px;
- animation-timing-function: ease-out;
- }
-
- 25% {
- top: 50px;
- animation-timing-function: ease-in;
- }
-
- 50% {
- top: 100px;
- animation-timing-function: ease-out;
- }
-
- 75% {
- top: 75px;
- animation-timing-function: ease-in;
- }
-
- to {
- top: 100px;
- }
-}
-
-@-webkit-keyframes flowouttoleft {
- 0% { -webkit-transform: translateX(0) scale(1); }
- 60%, 70% { -webkit-transform: translateX(0) scale(.7); }
- 100% { -webkit-transform: translateX(-100%) scale(.7); }
-}
-
-div {
- animation-name: 'diagonal-slide';
- animation-duration: 5s;
- animation-iteration-count: 10;
-}
-
-@keyframes 'diagonal-slide' {
-
- from {
- left: 0;
- top: 0;
- }
-
- to {
- left: 100px;
- top: 100px;
- }
-
-}
-
diff --git a/vendor/leafo/lessphp/tests/inputs/math.less b/vendor/leafo/lessphp/tests/inputs/math.less
deleted file mode 100644
index db59d356..00000000
--- a/vendor/leafo/lessphp/tests/inputs/math.less
+++ /dev/null
@@ -1,122 +0,0 @@
-
-.unary {
- // all operators are parsable as unary operators, anything
- // but - throws an error right now though,
-
- // this gives two numbers
- sub: 10 -5;
- // add: 10 +5; // error
- // div: 10 /5; // error
- // mul: 10 *5; // error
-}
-
-.spaces {
- // we can make the parser do math by leaving out the
- // space after the first value, or putting spaces on both sides
-
- sub1: 10-5;
- sub2: 10 - 5;
-
- add1: 10+5;
- add2: 10 + 5;
-
- // div: 10/5; // this wont work, read on
- div: 10 / 5;
-
- mul1: 10*5;
- mul2: 10 * 5;
-}
-
-// these properties have divison not in parenthases
-.supress-division {
- border-radius: 10px / 10px;
- border-radius: 10px/12px;
- border-radius: hello (10px/10px) world;
- @x: 10px;
- font: @x/30 sans-serif;
- font: 10px / 20px sans-serif;
- font: 10px/22px sans-serif;
- border-radius:0 15px 15px 15px / 0 50% 50% 50%;
-}
-
-
-.parens {
- // if you are unsure, then just wrap the expression in parentheses and it will
- // always evaluate.
-
- // notice we no longer have unary operators, and these will evaluate
- sub: (10 -5);
- add: (10 +5);
- div1: (10 /5);
- div2: (10/5); // no longer interpreted as the shorthand
- mul: (10 *5);
-}
-
-.keyword-names {
- // watch out when doing math with keywords, - is a valid keyword character
- @a: 100;
- @b: 25;
- @a-: "hello";
- height: @a-@b; // here we get "hello" 25, not 75
-}
-
-
-.negation {
- neg1: -(1px);
- neg2: 0-(1px);
-
- @something: 10;
- neg3: -@something;
-}
-
-
-// and now here are the tests
-
-.test {
- single1: (5);
- single2: 5+(5);
- single3: (5)+((5));
-
- parens: (5 +(5)) -2;
- // parens: ((5 +(5)) -2); // FAILS - fixme
-
- math1: (5 + 5)*(2 / 1);
- math2: (5+5)*(2/1);
-
- complex1: 2 * (4 * (2 + (1 + 6))) - 1;
- complex2: ((2+3)*(2+3) / (9-4)) + 1;
- complex3: (2px + 4px) 1em 2px 2;
-
- @var: (2 * 2);
- var1: (2 * @var) 4 4 (@var * 1px);
- var2: (@var * @var) * 6;
- var3: 4 * (5 + 5) / 2 - (@var * 2);
-
- complex4: (7 * 7) + (8 * 8);
-}
-
-.percents {
- p1: 100 * 10%;
- p2: 10% * 100;
- p3: 10% * 10%;
-
- p4: 100px * 10%; // lessjs makes this px
- p5: 10% * 100px; // lessjs makes this %
-
- p6: 20% + 10%;
- p7: 20% - 10%;
-
- p8: 20% / 10%;
-}
-
-.misc {
- x: 10px * 4em;
- y: 10 * 4em;
-}
-
-
-.cond {
- c1: 10 < 10;
- c2: 10 >= 10;
-}
-
diff --git a/vendor/leafo/lessphp/tests/inputs/media.less b/vendor/leafo/lessphp/tests/inputs/media.less
deleted file mode 100644
index 8c16a3cf..00000000
--- a/vendor/leafo/lessphp/tests/inputs/media.less
+++ /dev/null
@@ -1,68 +0,0 @@
-@media screen, 3D {
- P { color: green; }
-}
-@media print {
- body { font-size: 10pt }
-}
-@media screen {
- body { font-size: 13px }
-}
-@media screen, print {
- body { line-height: 1.2 }
-}
-
-@media all and (min-width: 0px) {
- body { line-height: 1.2 }
-}
-
-@media all and (min-width: 0) {
- body { line-height: 1.2 }
-}
-
-@media
- screen and (min-width: 102.5em) and (max-width: 117.9375em),
- screen and (min-width: 150em) {
- body { color: blue }
-}
-
-
-@media screen and (min-height: 100px + 10px) {
- body { color: red; }
-}
-
-@cool: 100px;
-
-@media screen and (height: @cool) and (width: @cool + 10), (size: @cool + 20) {
- body { color: red; }
-}
-
-
-// media bubbling
-
-@media test {
- div {
- height: 20px;
- @media (hello) {
- color: red;
-
- pre {
- color: orange;
- }
- }
- }
-}
-
-// should not cross boundary
-@media yeah {
- @page {
- @media cool {
- color: red;
- }
- }
-}
-
-// variable in query
-@mobile: ~"(max-width: 599px)";
-@media @mobile {
- .helloworld { color: blue }
-}
diff --git a/vendor/leafo/lessphp/tests/inputs/misc.less b/vendor/leafo/lessphp/tests/inputs/misc.less
deleted file mode 100644
index eb690b9a..00000000
--- a/vendor/leafo/lessphp/tests/inputs/misc.less
+++ /dev/null
@@ -1,100 +0,0 @@
-
-@color: #fff;
-@base_path: "/assets/images/";
-@images: @base_path + "test/";
-.topbar { background: url(@{images}topbar.png); }
-.hello { test: empty-function(@images, 40%, to(@color)); }
-
-.css3 {
- background-image: -webkit-gradient(linear, 0% 0%, 0% 90%,
- from(#E9A000), to(#A37000));
-}
-
-
-/**
-
-Here is a block comment
-
-**/
-
-
-// this is a comment
-
-.test, /*hello*/.world {
- border: 1px solid red; // world
- /* another property */
- color: url(http://mage-page.com);
- string: "hello /* this is not a comment */";
- world: "// neither is this";
- string: 'hello /* this is not a comment */' /*what if this is a comment */;
- world: '// neither is this' // hell world;
- ;
- what-/*something?*/ever: 100px;
- background: url(/*no comment here*/);
-}
-
-
-.urls {
- @var: "http://google.com";
- background1: url(@var);
- background2: url(@{var});
- background3: url("@{var}");
-}
-
-.mix(@arg) { color: @arg; }
-@aaa: aaa;
-@bbb: bbb;
-// make sure the opening selector isn't too greedy
-.cool {.mix("@{aaa}, @{bbb}")}
-.cool();
-
-
-
-// merging of mixins
-.span-17 { float: left; }
-.span-17 { width: 660px; }
-
-.x {.span-17;}
-
-.hi {
- pre {
- color: red;
- }
-}
-
-.hi {
- pre {
- color: blue;
- }
-}
-
-.rad {
- .hi;
-}
-
-
-hello {
- numbers: 1.0 0.1 .1 1.;
- numbers: 1.0s 0.1s .1s 1.s;
- numbers: -1.0s -0.1s -.1s -1.s;
- numbers: -1.0 -0.1 -.1 -1.;
-}
-
-
-#string {
- hello: 'what\'s going on here';
- hello: 'blah blag @{ blah blah';
-
- join: 3434 + "hello";
- join: 3434 + hello;
-}
-
-
-.duplicates {
- hello: world;
- hello: "world";
- hello: world;
- hello: "what";
- hello: world;
- hello: "world";
-}
diff --git a/vendor/leafo/lessphp/tests/inputs/mixin_functions.less b/vendor/leafo/lessphp/tests/inputs/mixin_functions.less
deleted file mode 100644
index 2d858ad6..00000000
--- a/vendor/leafo/lessphp/tests/inputs/mixin_functions.less
+++ /dev/null
@@ -1,33 +0,0 @@
-
-@outer: 10px;
-@class(@var:22px, @car: 400px + @outer) {
- margin: @var;
- height: @car;
-}
-
-@group {
- @f(@color) {
- color: @color;
- }
- .cool {
- border-bottom: 1px solid green;
- }
-}
-
-.class(@width:200px) {
- padding: @width;
-}
-
-body {
- .class(2.0em);
- @group > @f(red);
- @class(10px, 10px + 2);
- @group > .cool;
-}
-
-
-@lots(@a: 10px, @b: 20px, @c: 30px, @d: 40px, @e: 4px, @f:3px, @g:2px, @h: 1px) {
- padding: @a @b @c @d;
- margin: @e @f @g @h;
-}
-
diff --git a/vendor/leafo/lessphp/tests/inputs/mixin_merging.less.disable b/vendor/leafo/lessphp/tests/inputs/mixin_merging.less.disable
deleted file mode 100644
index 86b3e0cb..00000000
--- a/vendor/leafo/lessphp/tests/inputs/mixin_merging.less.disable
+++ /dev/null
@@ -1,100 +0,0 @@
-
-@tester {
- p, div { height: 10px; }
-}
-
-#test1 {
- div { color: red; }
- @tester;
-}
-
-
-@cool {
- a,b,i { width: 1px; }
-}
-
-#test2 {
- b { color: red; }
- @cool;
-}
-
-#test3 {
- @cool;
- b { color: red; }
-}
-
-@cooler {
- a { margin: 1px; }
-}
-
-#test4 {
- a, div, html { color: blue; }
- @cooler;
-}
-
-@hi {
- img, strong { float: right; }
-}
-
-#test5 {
- img, strong { padding: 2px; }
- @hi;
-}
-
-@nested {
- div, span {
- a {
- color: red;
- }
- }
-}
-
-#test6 {
- div, span {
- a {
- line-height: 10px;
- }
- }
- @nested;
-}
-
-@broken-nesting {
- div, span {
- strong, b {
- color: red;
- }
- }
-
-}
-
-#test7 {
- div {
- strong {
- margin: 1px;
- }
- }
- @broken-nesting;
-}
-
-
-@another-nest {
- a,b {
- i {
- color: red;
- }
-
- s {
- color: blue;
- }
- }
-}
-
-#test8 {
- a, b {
- i,s {
- background: red;
- }
- }
- @another-nest;
-}
-
diff --git a/vendor/leafo/lessphp/tests/inputs/mixins.less b/vendor/leafo/lessphp/tests/inputs/mixins.less
deleted file mode 100644
index 768e6384..00000000
--- a/vendor/leafo/lessphp/tests/inputs/mixins.less
+++ /dev/null
@@ -1,197 +0,0 @@
-
-@rounded-corners {
- border-radius: 10px;
-}
-
-.bold {
- @font-size: 20px;
- font-size: @font-size;
- font-weight: bold;
-}
-
-body #window {
- @rounded-corners;
- .bold;
- line-height: @font-size * 1.5;
-}
-
-#bundle {
- .button {
- display: block;
- border: 1px solid black;
- background-color: grey;
- &:hover { background-color: white }
- }
-}
-#header a {
- color: orange;
- #bundle > .button; // mixin the button class
-}
-
-div {
- @abstract {
- hello: world;
- b {
- color: blue;
- }
- }
-
- @abstract > b;
- @abstract;
-}
-
-@poop {
- big: baby;
-}
-
-body {
- div;
-}
-
-// not using > to list mixins
-
-.hello {
- .world {
- color: blue;
- }
-}
-
-.foobar {
- .hello .world;
-}
-
-
-// arguments
-
-.spam(@something: 100, @dad: land) {
- @wow: 23434;
- foo: @arguments;
- bar: @arguments;
-}
-
-.eggs {
- .spam(1px, 2px);
- .spam();
-}
-
-.first(@one, @two, @three, @four: cool) {
- cool: @arguments;
-}
-
-#hello {
- .first(one, two, three);
-}
-
-#hello-important {
- .first(one, two, three) !important;
-}
-
-.rad(@name) {
- cool: @arguments;
-}
-
-#world {
- @hello: "world";
- .rad("@{hello}");
-}
-
-.second(@x, @y:skip, @z: me) {
- things: @arguments;
-}
-
-#another {
- .second(red, blue, green);
- .second(red blue green);
-}
-
-
-.another(@x, @y:skip, @z:me) {
- .cool {
- color: @arguments;
- }
-}
-
-#day {
- .another(one,two, three);
- .another(one two three);
-}
-
-
-.to-be-important() {
- color: red;
- @color: red;
- height: 20px;
-
- pre {
- color: @color;
- }
-}
-
-.mix-suffix {
- .to-be-important() !important;
-}
-
-
-
-
-#search-all {
- .red() {
- color:#f00 !important;
- }
-}
-
-#search-all {
- .green() {
- color: #0f0 !important;
- }
-}
-
-.search-test {
- #search-all > .red();
- #search-all > .green();
-}
-
-
-// mixin self without infinite loop
-.cowboy() {
- color: blue;
-}
-
-.cowboy {
- .cowboy;
-}
-
-
-// semicolon
-
-.semi1(@color: red, blue, green;) {
- color: @color;
-}
-
-.semi2(@color: red, blue, green; dad) {
- color: @color;
-}
-
-.semi3(hello; world; piss) {
- hello: world;
-}
-
-
-
-// self referencing skipping
-
-.nav-divider(@color: red){
- padding: 10px;
-}
-
-.nav {
- .nav-divider {
- .nav-divider();
- }
-}
-
-.nav-divider {
- .nav-divider();
-}
-
-
diff --git a/vendor/leafo/lessphp/tests/inputs/nested.less b/vendor/leafo/lessphp/tests/inputs/nested.less
deleted file mode 100644
index 0b62ea19..00000000
--- a/vendor/leafo/lessphp/tests/inputs/nested.less
+++ /dev/null
@@ -1,60 +0,0 @@
-#header {
- color: black;
-
- .navigation {
- font-size: 12px;
- .border {
- .outside {
- color: blue;
- }
- }
- }
- .logo {
- width: 300px;
- &:hover { text-decoration: none }
- }
-}
-
-a { b { ul { li { color: green; } } } }
-
-this { will { not { show { } } } }
-
-.cool {
- div & { color: green; }
- p & span { color: yellow; }
-}
-
-another {
- .cool;
-}
-
-b {
- & .something {
- color: blue;
- }
-
- &.something {
- color: blue;
- }
-}
-
-.foo {
- .bar, .baz {
- & .qux {
- display: block;
- }
- .qux & {
- display: inline;
- }
- .qux & .biz {
- display: none;
- }
- }
-}
-
-b {
- hello [x="&yeah"] {
- color: red;
- }
-}
-
diff --git a/vendor/leafo/lessphp/tests/inputs/pattern_matching.less b/vendor/leafo/lessphp/tests/inputs/pattern_matching.less
deleted file mode 100644
index c2a0da91..00000000
--- a/vendor/leafo/lessphp/tests/inputs/pattern_matching.less
+++ /dev/null
@@ -1,157 +0,0 @@
-
-.demo (light, @color) {
- color: lighten(@color, 10%);
-}
-.demo (@_, @color) {
- display: block;
-}
-
-@switch: light;
-
-.class {
- .demo(@switch, #888);
-}
-
-// by arity
-
-.mixin () {
- zero: 0;
-}
-.mixin (@a: 1px) {
- one: 1;
-}
-.mixin (@a) {
- one-req: 1;
-}
-.mixin (@a: 1px, @b: 2px) {
- two: 2;
-}
-
-.mixin (@a, @b, @c) {
- three-req: 3;
-}
-
-.mixin (@a: 1px, @b: 2px, @c: 3px) {
- three: 3;
-}
-
-.zero {
- .mixin();
-}
-
-.one {
- .mixin(1);
-}
-
-.two {
- .mixin(1, 2);
-}
-
-.three {
- .mixin(1, 2, 3);
-}
-
-//
-
-.mixout ('left') {
- left: 1;
-}
-
-.mixout ('right') {
- right: 1;
-}
-
-.left {
- .mixout('left');
-}
-.right {
- .mixout('right');
-}
-
-//
-
-.border (@side, @width) {
- color: black;
- .border-side(@side, @width);
-}
-.border-side (left, @w) {
- border-left: @w;
-}
-.border-side (right, @w) {
- border-right: @w;
-}
-
-.border-right {
- .border(right, 4px);
-}
-.border-left {
- .border(left, 4px);
-}
-
-//
-
-
-.border-radius (@r) {
- both: @r * 10;
-}
-.border-radius (@r, left) {
- left: @r;
-}
-.border-radius (@r, right) {
- right: @r;
-}
-
-.only-right {
- .border-radius(33, right);
-}
-.only-left {
- .border-radius(33, left);
-}
-.left-right {
- .border-radius(33);
-}
-
-.hola(hello, @hello...) {
- color: blue;
-}
-
-#hola {
- .hola(hello, world);
-}
-
-.resty(@hello, @world, @the_rest...) {
- padding: @hello @world;
- rest: @the_rest;
-}
-
-.defaults(@aa, @bb:e343, @cc: "heah", ...) {
- height: @aa;
-}
-
-#defaults_1 {
- .defaults(one);
- .defaults(two, one);
- .defaults(three, two, one);
- .defaults(four, three, two, one);
-}
-
-
-.thing() { color: green; }
-.thing(...) { color: blue; }
-.thing { color: red; }
-
-#aa {
- .thing();
-}
-
-#bb {
- .thing;
-}
-
-
-#cc {
- .thing(1);
-}
-
-
-
diff --git a/vendor/leafo/lessphp/tests/inputs/scopes.less b/vendor/leafo/lessphp/tests/inputs/scopes.less
deleted file mode 100644
index 42e46969..00000000
--- a/vendor/leafo/lessphp/tests/inputs/scopes.less
+++ /dev/null
@@ -1,40 +0,0 @@
-
-
-@a: 10;
-@some {
- @b: @a + 10;
- div {
- @c: @b + 10;
- other {
- @d: @c + 10;
- world {
- @e: @d + 10;
- height: @e;
- }
- }
- }
-}
-
-
-body {
- @some;
-}
-
-@some;
-
-.test(@x: 10) {
- height: @x;
- .test(@y: 11) {
- height: @y;
- .test(@z: 12) {
- height: @z;
- }
- .test;
- }
- .test;
-}
-
-pre {
- .test;
-}
-
diff --git a/vendor/leafo/lessphp/tests/inputs/selector_expressions.less b/vendor/leafo/lessphp/tests/inputs/selector_expressions.less
deleted file mode 100644
index b8aa2214..00000000
--- a/vendor/leafo/lessphp/tests/inputs/selector_expressions.less
+++ /dev/null
@@ -1,29 +0,0 @@
-
-@color: blue;
-
-something @{color}, world {
- color: blue;
-}
-
-.div {
- @color: red;
- (3434) {
- height: 100px;
- }
-
- cool @{color} {
- height: 4000px;
- }
-}
-
-.heck(@a) { color: @a+10 }
-
-.spanX (@index) when (@index > 0) {
- .span@{index} { .heck(@index) }
- .spanX(@index - 1);
-}
-.spanX (0) {}
-
-.spanX (5);
-
-
diff --git a/vendor/leafo/lessphp/tests/inputs/site_demos.less b/vendor/leafo/lessphp/tests/inputs/site_demos.less
deleted file mode 100644
index 08d7f1e5..00000000
--- a/vendor/leafo/lessphp/tests/inputs/site_demos.less
+++ /dev/null
@@ -1,120 +0,0 @@
-// these are the demos from the lessphp homepage
-
-default {
- @base: 24px;
- @border-color: #B2B;
-
- .underline { border-bottom: 1px solid green }
-
- #header {
- color: black;
- border: 1px solid @border-color + #222222;
-
- .navigation {
- font-size: @base / 2;
- a {
- .underline;
- }
- }
- .logo {
- width: 300px;
- &:hover { text-decoration: none }
- }
- }
-}
-
-variables {
- @a: 2;
- @x: @a * @a;
- @y: @x + 1;
- @z: @x * 2 + @y;
-
- @nice-blue: #5B83AD;
- @light-blue: @nice-blue + #111;
-
- @b: @a * 10;
- @c: #888;
- @fonts: "Trebuchet MS", Verdana, sans-serif;
-
- .variables {
- width: @z + 1cm; // 14cm
- height: @b + @x + 0px; // 24px
- color: @c;
- background: @light-blue;
- font-family: @fonts;
- }
-}
-
-mixins {
- .bordered {
- border-top: dotted 1px black;
- border-bottom: solid 2px black;
- }
- #menu a {
- color: #111;
- .bordered;
- }
-
- .post a {
- color: red;
- .bordered;
- }
-}
-
-nested-rules {
- #header {
- color: black;
-
- .navigation {
- font-size: 12px;
- }
- .logo {
- width: 300px;
- &:hover { text-decoration: none }
- }
- }
-}
-
-namespaces {
- #bundle {
- .button {
- display: block;
- border: 1px solid black;
- background-color: grey;
- &:hover { background-color: white }
- }
- }
- #header a {
- color: orange;
- #bundle > .button; // mixin the button class
- }
-}
-
-mixin-functions {
- @outer: 10px;
- @class(@var:22px, @car: 400px + @outer) {
- margin: @var;
- height: @car;
- }
-
- @group {
- @f(@color) {
- color: @color;
- }
- .cool {
- border-bottom: 1px solid green;
- }
- }
-
- .class(@width:200px) {
- padding: @width;
- }
-
- body {
- .class(2.0em);
- @group > @f(red);
- @class(10px, 10px + 2);
- @group > .cool;
- }
-}
-
diff --git a/vendor/leafo/lessphp/tests/inputs/test-imports/a.less b/vendor/leafo/lessphp/tests/inputs/test-imports/a.less
deleted file mode 100644
index a00464db..00000000
--- a/vendor/leafo/lessphp/tests/inputs/test-imports/a.less
+++ /dev/null
@@ -1,6 +0,0 @@
-.just-a-class { background: red; }
-
-.some-mixin() {
- height: 200px;
-}
-
diff --git a/vendor/leafo/lessphp/tests/inputs/test-imports/b.less b/vendor/leafo/lessphp/tests/inputs/test-imports/b.less
deleted file mode 100644
index 599ed3a4..00000000
--- a/vendor/leafo/lessphp/tests/inputs/test-imports/b.less
+++ /dev/null
@@ -1,12 +0,0 @@
-.just-a-class { background: blue; }
-
-.hello {
- .some-mixin();
-}
-
-
-@media cool {
- color: red;
- .some-mixin();
-}
-
diff --git a/vendor/leafo/lessphp/tests/inputs/test-imports/file1.less b/vendor/leafo/lessphp/tests/inputs/test-imports/file1.less
deleted file mode 100644
index 658de0c5..00000000
--- a/vendor/leafo/lessphp/tests/inputs/test-imports/file1.less
+++ /dev/null
@@ -1,16 +0,0 @@
-
-
-/**
- * This is a test import file
- */
-
-@colors {
- div.bright {
- color: red;
- }
-
- div.sad {
- color: blue;
- }
-}
-
diff --git a/vendor/leafo/lessphp/tests/inputs/test-imports/file2.less b/vendor/leafo/lessphp/tests/inputs/test-imports/file2.less
deleted file mode 100644
index 2cae8dce..00000000
--- a/vendor/leafo/lessphp/tests/inputs/test-imports/file2.less
+++ /dev/null
@@ -1,6 +0,0 @@
-
-b {
- color: @color;
- padding: 16px;
-}
-
diff --git a/vendor/leafo/lessphp/tests/inputs/test-imports/file3.less b/vendor/leafo/lessphp/tests/inputs/test-imports/file3.less
deleted file mode 100644
index 28b643ea..00000000
--- a/vendor/leafo/lessphp/tests/inputs/test-imports/file3.less
+++ /dev/null
@@ -1,7 +0,0 @@
-
-h2 {
- background: url("../images/logo.png") no-repeat;
-}
-
-@someValue: hello-from-file-3;
-
diff --git a/vendor/leafo/lessphp/tests/inputs/test-imports/inner/file1.less b/vendor/leafo/lessphp/tests/inputs/test-imports/inner/file1.less
deleted file mode 100644
index df654a7e..00000000
--- a/vendor/leafo/lessphp/tests/inputs/test-imports/inner/file1.less
+++ /dev/null
@@ -1,6 +0,0 @@
-
-.inner {
- content: "inner/file1.less"
-}
-
-@import "file2"; // should get the one in inner
diff --git a/vendor/leafo/lessphp/tests/inputs/test-imports/inner/file2.less b/vendor/leafo/lessphp/tests/inputs/test-imports/inner/file2.less
deleted file mode 100644
index f40d3c67..00000000
--- a/vendor/leafo/lessphp/tests/inputs/test-imports/inner/file2.less
+++ /dev/null
@@ -1,4 +0,0 @@
-
-.inner {
- content: "inner/file2.less"
-}
diff --git a/vendor/leafo/lessphp/tests/inputs/variables.less b/vendor/leafo/lessphp/tests/inputs/variables.less
deleted file mode 100644
index 6e18eb80..00000000
--- a/vendor/leafo/lessphp/tests/inputs/variables.less
+++ /dev/null
@@ -1,44 +0,0 @@
-@a: 2;
-@x: @a * @a;
-@y: @x + 1;
-@z: @y + @x * 2;
-@m: @z % @y;
-
-@nice-blue: #5B83AD;
-@light-blue: @nice-blue + #111;
-
-@rgb-color: rgb(20%, 15%, 80%);
-@rgba-color: rgba(23,68,149,0.5);
-
-@b: @a * 10px;
-@c: #888;
-@fonts: "Trebuchet MS", Verdana, sans-serif;
-
-.variables {
- width: @z + 1cm; // 14cm
- height: @b + @x + 0px; // 24px
- margin-top: -@b; // -20px
- margin-bottom: 10 - -@b; // 30px
- @d: @c + #001;
- color: @d;
- background: @light-blue;
- font-family: @fonts;
- margin: @m + 0px; // 3px
- font: 10px/12px serif;
- font: 120%/120% serif;
-}
-
-.external {
- color: @c;
- border: 1px solid @rgb-color;
- background: @rgba-color;
-}
-
-@hello: 44px;
-@something: "hello";
-@cool: something;
-
-outer1: @@something;
-outer2: @@@cool;
-
-
diff --git a/vendor/leafo/lessphp/tests/inputs_lessjs/mixins-args.less b/vendor/leafo/lessphp/tests/inputs_lessjs/mixins-args.less
deleted file mode 100644
index c3965924..00000000
--- a/vendor/leafo/lessphp/tests/inputs_lessjs/mixins-args.less
+++ /dev/null
@@ -1,205 +0,0 @@
-.mixin (@a: 1px, @b: 50%) {
- width: (@a * 5);
- height: (@b - 1%);
-}
-
-.mixina (@style, @width, @color: black) {
- border: @width @style @color;
-}
-
-.mixiny
-(@a: 0, @b: 0) {
- margin: @a;
- padding: @b;
-}
-
-.hidden() {
- color: transparent; // asd
-}
-
-#hidden {
- .hidden;
-}
-
-#hidden1 {
- .hidden();
-}
-
-.two-args {
- color: blue;
- .mixin(2px, 100%);
- .mixina(dotted, 2px);
-}
-
-.one-arg {
- .mixin(3px);
-}
-
-.no-parens {
- .mixin;
-}
-
-.no-args {
- .mixin();
-}
-
-.var-args {
- @var: 9;
- .mixin(@var, (@var * 2));
-}
-
-.multi-mix {
- .mixin(2px, 30%);
- .mixiny(4, 5);
-}
-
-.maxa(@arg1: 10, @arg2: #f00) {
- padding: (@arg1 * 2px);
- color: @arg2;
-}
-
-body {
- .maxa(15);
-}
-
-@glob: 5;
-.global-mixin(@a:2) {
- width: (@glob + @a);
-}
-
-.scope-mix {
- .global-mixin(3);
-}
-
-.nested-ruleset (@width: 200px) {
- width: @width;
- .column { margin: @width; }
-}
-.content {
- .nested-ruleset(600px);
-}
-
-//
-
-.same-var-name2(@radius) {
- radius: @radius;
-}
-.same-var-name(@radius) {
- .same-var-name2(@radius);
-}
-#same-var-name {
- .same-var-name(5px);
-}
-
-//
-
-.var-inside () {
- @var: 10px;
- width: @var;
-}
-#var-inside { .var-inside; }
-
-.mixin-arguments (@width: 0px, ...) {
- border: @arguments;
- width: @width;
-}
-
-.arguments {
- .mixin-arguments(1px, solid, black);
-}
-.arguments2 {
- .mixin-arguments();
-}
-.arguments3 {
- .mixin-arguments;
-}
-
-.mixin-arguments2 (@width, @rest...) {
- border: @arguments;
- rest: @rest;
- width: @width;
-}
-.arguments4 {
- .mixin-arguments2(0, 1, 2, 3, 4);
-}
-
-// Edge cases
-
-.edge-case {
- .mixin-arguments("{");
-}
-
-// Division vs. Literal Slash
-.border-radius(@r: 2px/5px) {
- border-radius: @r;
-}
-.slash-vs-math {
- .border-radius();
- .border-radius(5px/10px);
- .border-radius((3px * 2));
-}
-// semi-colon vs comma for delimiting
-
-.mixin-takes-one(@a) {
- one: @a;
-}
-
-.mixin-takes-two(@a; @b) {
- one: @a;
- two: @b;
-}
-
-.comma-vs-semi-colon {
- .mixin-takes-two(@a : a; @b : b, c);
- .mixin-takes-two(@a : d, e; @b : f);
- .mixin-takes-one(@a: g);
- .mixin-takes-one(@a : h;);
- .mixin-takes-one(i);
- .mixin-takes-one(j;);
- .mixin-takes-two(k, l);
- .mixin-takes-one(m, n;);
- .mixin-takes-two(o, p; q);
- .mixin-takes-two(r, s; t;);
-}
-
-.mixin-conflict(@a:defA, @b:defB, @c:defC) {
- three: @a, @b, @c;
-}
-
-.mixin-conflict(@a:defA, @b:defB, @c:defC, @d:defD) {
- four: @a, @b, @c, @d;
-}
-
-#named-conflict {
- .mixin-conflict(11, 12, 13, @a:a);
- .mixin-conflict(@a:a, 21, 22, 23);
-}
-@a: 3px;
-.mixin-default-arg(@a: 1px, @b: @a, @c: @b) {
- defaults: 1px 1px 1px;
- defaults: 2px 2px 2px;
-}
-
-.test-mixin-default-arg {
- .mixin-default-arg();
- .mixin-default-arg(2px);
-}
-
-.mixin-comma-default1(@color; @padding; @margin: 2, 2, 2, 2) {
- margin: @margin;
-}
-.selector {
- .mixin-comma-default1(#33acfe; 4);
-}
-.mixin-comma-default2(@margin: 2, 2, 2, 2;) {
- margin: @margin;
-}
-.selector2 {
- .mixin-comma-default2();
-}
-.mixin-comma-default3(@margin: 2, 2, 2, 2) {
- margin: @margin;
-}
-.selector3 {
- .mixin-comma-default3(4,2,2,2);
-}
diff --git a/vendor/leafo/lessphp/tests/inputs_lessjs/mixins-named-args.less b/vendor/leafo/lessphp/tests/inputs_lessjs/mixins-named-args.less
deleted file mode 100644
index f62dc86a..00000000
--- a/vendor/leafo/lessphp/tests/inputs_lessjs/mixins-named-args.less
+++ /dev/null
@@ -1,36 +0,0 @@
-.mixin (@a: 1px, @b: 50%) {
- width: (@a * 5);
- height: (@b - 1%);
- args: @arguments;
-}
-.mixin (@a: 1px, @b: 50%) when (@b > 75%){
- text-align: center;
-}
-
-.named-arg {
- color: blue;
- .mixin(@b: 100%);
-}
-
-.class {
- @var: 20%;
- .mixin(@b: @var);
-}
-
-.all-args-wrong-args {
- .mixin(@b: 10%, @a: 2px);
-}
-
-.mixin2 (@a: 1px, @b: 50%, @c: 50) {
- width: (@a * 5);
- height: (@b - 1%);
- color: (#000000 + @c);
-}
-
-.named-args2 {
- .mixin2(3px, @c: 100);
-}
-
-.named-args3 {
- .mixin2(@b: 30%, @c: #123456);
-}
diff --git a/vendor/leafo/lessphp/tests/inputs_lessjs/strings.less b/vendor/leafo/lessphp/tests/inputs_lessjs/strings.less
deleted file mode 100644
index 32fad721..00000000
--- a/vendor/leafo/lessphp/tests/inputs_lessjs/strings.less
+++ /dev/null
@@ -1,51 +0,0 @@
-#strings {
- background-image: url("http://son-of-a-banana.com");
- quotes: "~" "~";
- content: "#*%:&^,)!.(~*})";
- empty: "";
- brackets: "{" "}";
- escapes: "\"hello\" \\world";
- escapes2: "\"llo";
-}
-#comments {
- content: "/* hello */ // not-so-secret";
-}
-#single-quote {
- quotes: "'" "'";
- content: '""#!&""';
- empty: '';
- semi-colon: ';';
-}
-#escaped {
- filter: ~"DX.Transform.MS.BS.filter(opacity=50)";
-}
-#one-line { image: url(http://tooks.com) }
-#crazy { image: url(http://), "}", url("http://}") }
-#interpolation {
- @var: '/dev';
- url: "http://lesscss.org@{var}/image.jpg";
-
- @var2: 256;
- url2: "http://lesscss.org/image-@{var2}.jpg";
-
- @var3: #456;
- url3: "http://lesscss.org@{var3}";
-
- @var4: hello;
- url4: "http://lesscss.org/@{var4}";
-
- @var5: 54.4px;
- url5: "http://lesscss.org/@{var5}";
-}
-
-// multiple calls with string interpolation
-
-.mix-mul (@a: green) {
- color: ~"@{a}";
-}
-.mix-mul-class {
- .mix-mul(blue);
- .mix-mul(red);
- .mix-mul(black);
- .mix-mul(orange);
-}
diff --git a/vendor/leafo/lessphp/tests/outputs/accessors.css b/vendor/leafo/lessphp/tests/outputs/accessors.css
deleted file mode 100644
index 2f3c9e61..00000000
--- a/vendor/leafo/lessphp/tests/outputs/accessors.css
+++ /dev/null
@@ -1,14 +0,0 @@
-.article { color:#294366; }
-.comment {
- width:960px;
- color:#294366;
- padding:10px;
-}
-.wow {
- height:960px;
- background-color:#294366;
- color:green;
- padding:;
- margin:;
-}
-.mix { font-size:10px; }
diff --git a/vendor/leafo/lessphp/tests/outputs/arity.css b/vendor/leafo/lessphp/tests/outputs/arity.css
deleted file mode 100644
index 5173561d..00000000
--- a/vendor/leafo/lessphp/tests/outputs/arity.css
+++ /dev/null
@@ -1,25 +0,0 @@
-.one {
- hello: one;
- world: one;
-}
-.two {
- hello: two;
- world: two;
-}
-.three {
- hello: three;
- world: three;
-}
-.multi-foo {
- foo: two cool;
- foo: three cool yeah;
- foo: two 1;
- foo: three 1 yeah;
- foo: three 1 1;
-}
-.multi-baz {
- baz: two cool;
- baz: three yeah;
- baz: two 1;
- baz: three 1;
-}
diff --git a/vendor/leafo/lessphp/tests/outputs/attributes.css b/vendor/leafo/lessphp/tests/outputs/attributes.css
deleted file mode 100644
index fb0e176c..00000000
--- a/vendor/leafo/lessphp/tests/outputs/attributes.css
+++ /dev/null
@@ -1,105 +0,0 @@
-* {
- color: blue;
-}
-E {
- color: blue;
-}
-E[foo] {
- color: blue;
-}
-[foo] {
- color: blue;
-}
-[foo] .helloWorld {
- color: blue;
-}
-[foo].helloWorld {
- color: blue;
-}
-E[foo="barbar"] {
- color: blue;
-}
-E[foo~="hello#$@%@$#^"] {
- color: blue;
-}
-E[foo^="color: green;"] {
- color: blue;
-}
-E[foo$="239023"] {
- color: blue;
-}
-E[foo*="29302"] {
- color: blue;
-}
-E[foo|="239032"] {
- color: blue;
-}
-E:root {
- color: blue;
-}
-E:nth-child(odd) {
- color: blue;
-}
-E:nth-child(2n+1) {
- color: blue;
-}
-E:nth-child(5) {
- color: blue;
-}
-E:nth-last-child(-n+2) {
- color: blue;
-}
-E:nth-of-type(2n) {
- color: blue;
-}
-E:nth-last-of-type(n) {
- color: blue;
-}
-E:first-child {
- color: blue;
-}
-E:last-child {
- color: blue;
-}
-E:first-of-type {
- color: blue;
-}
-E:last-of-type {
- color: blue;
-}
-E:only-child {
- color: blue;
-}
-E:only-of-type {
- color: blue;
-}
-E:empty {
- color: blue;
-}
-E:lang(en) {
- color: blue;
-}
-E::first-line {
- color: blue;
-}
-E::before {
- color: blue;
-}
-E#id {
- color: blue;
-}
-E:not(:link) {
- color: blue;
-}
-E F {
- color: blue;
-}
-E > F {
- color: blue;
-}
-E + F {
- color: blue;
-}
-E ~ F {
- color: blue;
-}
diff --git a/vendor/leafo/lessphp/tests/outputs/builtins.css b/vendor/leafo/lessphp/tests/outputs/builtins.css
deleted file mode 100644
index 6ac21f2c..00000000
--- a/vendor/leafo/lessphp/tests/outputs/builtins.css
+++ /dev/null
@@ -1,61 +0,0 @@
-body {
- color: "hello world";
- num-basic: 5.1666666666667;
- num-floor: 5px;
- num-ceil: 6px;
- num2: 0.66666666666667;
- num2-round: 1;
- num2-floor: 0;
- num2-ceil: 1;
- round-lit: 3px;
- rgba1: #ff112233;
- rgba2: #992c3742;
- argb: #992c3742;
-}
-format {
- format: "rgb(32, 128, 64)";
- format-string: "hello world";
- format-multiple: "hello earth 2";
- format-url-encode: 'red is %A';
- eformat: rgb(32, 128, 64);
-}
-#functions {
- str1: true;
- str2: false;
- num1: true;
- num2: true;
- num3: true;
- num4: false;
- col1: true;
- col2: false;
- col3: true;
- col4: true;
- key1: true;
- key2: false;
- px1: true;
- px2: false;
- per1: true;
- per2: false;
- em1: true;
- em2: false;
- ex1: 2;
- ex2: 1;
- ex3: extract(1,1);
- ex4: 2;
- pow: 16;
- pi: 3.1415926535898;
- mod: 4;
- tan: 1.5574077246549;
- cos: 0.54030230586814;
- sin: 0.8414709848079;
- atan: 0.78539816339745rad;
- acos: 0rad;
- asin: 1.5707963267949rad;
- sqrt: 2.8284271247462;
-}
-#unit {
- unit-lit: 10;
- unit-arg: 10s;
- unit-arg2: 10em;
- unit-math: 7.407%;
-}
diff --git a/vendor/leafo/lessphp/tests/outputs/colors.css b/vendor/leafo/lessphp/tests/outputs/colors.css
deleted file mode 100644
index 5310ffb0..00000000
--- a/vendor/leafo/lessphp/tests/outputs/colors.css
+++ /dev/null
@@ -1,103 +0,0 @@
-body {
- color: #ff0000;
- color: #ffffff;
- color: #000000;
- color: #996d33;
- color: rgba(153,109,51,0.3);
- lighten1: #ffffff;
- lighten2: #7c8df2;
- lighten3: rgba(222,140,129,0.5);
- darken1: #d6d6d6;
- darken2: #0d1e81;
- darken3: rgba(18,42,185,0.5);
- saturate1: #f1eded;
- saturate2: #0025fe;
- saturate3: rgba(10,44,244,0.5);
- desaturate1: #efefef;
- desaturate2: #3349cb;
- desaturate3: rgba(36,62,218,0.5);
- spin1: #efefef;
- spin2: #2d17e7;
- spin3: rgba(59,23,231,0.5);
- spin2: #efefef;
- spin3: #1769e7;
- spin4: rgba(23,119,231,0.5);
- one1: #abcdef;
- one2: #abcdef;
- two1: rgba(2,159,35,0.9);
- two2: rgba(2,159,35,0.9);
- three1: rgba(1,2,3,0.6);
- three2: rgba(1,2,3,0.6);
- four1: rgba(1,2,3,0);
- four2: rgba(1,2,3,0);
- hue: 282;
- sat: 33;
- lit: 12;
- what: #dff1da;
- zero1: #343434;
- zero2: #003468;
- zero3: #000000;
- zero4: #ffffff;
- zero5: #000000;
- zero6: #ffffff;
- zero7: #ffffff;
- zero8: #ffffff;
- zero9: #1d5612;
- zeroa: #56124b;
- zerob: #000000;
- zeroc: #ffffff;
-}
-alpha {
- g1: 0;
- g2: 1;
-}
-fade {
- f1: rgba(255,0,0,0.5);
- f2: rgba(255,255,255,0.2);
- f3: rgba(34,23,64,0.5);
-}
-.mix {
- color1: #808080;
- color2: #808080;
- color3: rgba(6,3,2,-0.25);
-}
-.contrast {
- color1: #ff0000;
- color2: #0000ff;
-}
-.percent {
- per: 50%;
-}
-.colorz {
- color1: #ebebeb;
- color2: #ff9100;
- color3: #000000;
-}
-body {
- start: #fcf8e3;
- spin: #fcf4e3;
- chained: #fbeed5;
- direct: #fbefd5;
-}
-pre {
- spin: #f2dee1;
-}
-dd {
- background-color: #f5f5f5;
-}
-.ops {
- c1: #4d0000;
- c2: #004000;
- c3: #020002;
- c4: #ffffff;
- c5: #fb8173;
- c6: 132 / #ff0000;
- c7: 132 - #ff0000;
- c8: 132- #ff0000;
-}
-.transparent {
- r: 0;
- g: 0;
- b: 0;
- a: 0;
-}
diff --git a/vendor/leafo/lessphp/tests/outputs/compile_on_mixin.css b/vendor/leafo/lessphp/tests/outputs/compile_on_mixin.css
deleted file mode 100644
index 318526a5..00000000
--- a/vendor/leafo/lessphp/tests/outputs/compile_on_mixin.css
+++ /dev/null
@@ -1,29 +0,0 @@
-body {
- height: 22px;
-}
-body ul {
- height: 20px;
-}
-body ul li {
- height: 10px;
-}
-body ul li div span,
-body ul li link {
- margin: 10px;
- color: red;
-}
-body ul div,
-body ul p {
- border: 1px;
-}
-body ul div.hello,
-body ul p.hello {
- color: green;
-}
-body ul div :what,
-body ul p :what {
- color: blue;
-}
-body ul a b {
- color: blue;
-}
diff --git a/vendor/leafo/lessphp/tests/outputs/data-uri.css b/vendor/leafo/lessphp/tests/outputs/data-uri.css
deleted file mode 100644
index e51b8f9c..00000000
--- a/vendor/leafo/lessphp/tests/outputs/data-uri.css
+++ /dev/null
@@ -1,6 +0,0 @@
-.small {
- background: url("data:text/plain;base64,CmRpdjpiZWZvcmUgewoJY29udGVudDogImhpISI7Cn0KCg==");
-}
-.large {
- background: url("../../../lessc.inc.php");
-}
diff --git a/vendor/leafo/lessphp/tests/outputs/directives.css b/vendor/leafo/lessphp/tests/outputs/directives.css
deleted file mode 100644
index c2d82b83..00000000
--- a/vendor/leafo/lessphp/tests/outputs/directives.css
+++ /dev/null
@@ -1,27 +0,0 @@
-@charset "utf-8";
-@-moz-document url-prefix() {
- div {
- color: red;
- }
-}
-@page :left {
- margin-left: 4cm;
-}
-@page :right {
- margin-left: 3cm;
-}
-@page {
- margin: 2cm;
-}
-@-ms-viewport {
- width: device-width;
-}
-@-moz-viewport {
- width: device-width;
-}
-@-o-viewport {
- width: device-width;
-}
-@viewport {
- width: device-width;
-}
diff --git a/vendor/leafo/lessphp/tests/outputs/escape.css b/vendor/leafo/lessphp/tests/outputs/escape.css
deleted file mode 100644
index 0587bcab..00000000
--- a/vendor/leafo/lessphp/tests/outputs/escape.css
+++ /dev/null
@@ -1,14 +0,0 @@
-body {
- e1: this is simple;
- e2: this is simple;
- e3: 1232;
- e4: world;
- e5: onemore;
- t1: eating rice;
- t2: string cheese;
- t3: a b c string me d e f;
- t4: string world;
-}
-.class {
- filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='image.png');
-}
diff --git a/vendor/leafo/lessphp/tests/outputs/font_family.css b/vendor/leafo/lessphp/tests/outputs/font_family.css
deleted file mode 100644
index fc260fd4..00000000
--- a/vendor/leafo/lessphp/tests/outputs/font_family.css
+++ /dev/null
@@ -1,17 +0,0 @@
-@font-face {
- font-family: Graublau Sans Web;
- src: url(fonts/GraublauWeb.otf) format("opentype");
-}
-@font-face {
- font-family: Gentium;
- src: url('fonts/Gentium.ttf');
-}
-@font-face {
- font-family: Gentium;
- src: url("fonts/GentiumItalic.ttf");
- font-style: italic;
-}
-h2 {
- font-family: Gentium;
- crazy: maroon;
-}
diff --git a/vendor/leafo/lessphp/tests/outputs/guards.css b/vendor/leafo/lessphp/tests/outputs/guards.css
deleted file mode 100644
index 34af5495..00000000
--- a/vendor/leafo/lessphp/tests/outputs/guards.css
+++ /dev/null
@@ -1,27 +0,0 @@
-dd {
- simple: yellow;
-}
-b {
- something: red;
- something-complex: blue cool;
- something-complex: blue birthday;
-}
-img {
- another: green;
- flipped: teal;
-}
-body {
- yeah-number: purple 232px;
- yeah-pixel: silver;
- yeah-number: purple 232;
-}
-div {
- something-complex: blue true;
-}
-link {
- color: true red;
- color: true #fff;
- color: true #fffddd;
- color: true #000000;
- color: true rgba(0,0,0,0.34);
-}
diff --git a/vendor/leafo/lessphp/tests/outputs/hacks.css b/vendor/leafo/lessphp/tests/outputs/hacks.css
deleted file mode 100644
index b8327eb5..00000000
--- a/vendor/leafo/lessphp/tests/outputs/hacks.css
+++ /dev/null
@@ -1,4 +0,0 @@
-:root .alert-message,
-:root .btn {
- border-radius: 0 \0;
-}
diff --git a/vendor/leafo/lessphp/tests/outputs/hi.css b/vendor/leafo/lessphp/tests/outputs/hi.css
deleted file mode 100644
index 3bffcf0b..00000000
--- a/vendor/leafo/lessphp/tests/outputs/hi.css
+++ /dev/null
@@ -1,3 +0,0 @@
-div:before {
- content: "hi!";
-}
diff --git a/vendor/leafo/lessphp/tests/outputs/ie.css b/vendor/leafo/lessphp/tests/outputs/ie.css
deleted file mode 100644
index 7e4571c8..00000000
--- a/vendor/leafo/lessphp/tests/outputs/ie.css
+++ /dev/null
@@ -1,9 +0,0 @@
-foo {
- filter: progid:DXImageTransform.Microsoft.gradient(GradientType=1,startColorstr=#c0ff3300,endColorstr=#ff000000);
- filter: progid:DXImageTransform.Microsoft.gradient(GradientType=1,startColorstr=#c0ff3300,endColorstr=#ff000001);
-}
-foo {
- filter: alpha(opacity=20);
- filter: alpha(opacity=20,enabled=true);
- filter: blaznicate(foo=bar,baz=bang bip,bart=#fa4600);
-}
diff --git a/vendor/leafo/lessphp/tests/outputs/import.css b/vendor/leafo/lessphp/tests/outputs/import.css
deleted file mode 100644
index b76c25b5..00000000
--- a/vendor/leafo/lessphp/tests/outputs/import.css
+++ /dev/null
@@ -1,51 +0,0 @@
-@import "not-found";
-@import "something.css" media;
-@import url("something.css") media;
-@import url(something.css) media, screen, print;
-b {
- color: maroon;
- padding: 16px;
-}
-body {
- line-height: 10em;
-}
-body div.bright {
- color: red;
-}
-body div.sad {
- color: blue;
-}
-.one {
- color: blue;
-}
-#merge-import-mixins .just-a-class {
- background: red;
-}
-#merge-import-mixins .just-a-class {
- background: blue;
-}
-#merge-import-mixins .hello {
- height: 200px;
-}
-@media cool {
- #merge-import-mixins {
- color: red;
- height: 200px;
- }
-}
-#merge-import-mixins div {
- background: red;
- background: blue;
-}
-.inner {
- content: "inner/file1.less";
-}
-.inner {
- content: "inner/file2.less";
-}
-pre {
- color: hello-from-file-3;
-}
-h2 {
- background: url("../images/logo.png") no-repeat;
-}
diff --git a/vendor/leafo/lessphp/tests/outputs/interpolation.css b/vendor/leafo/lessphp/tests/outputs/interpolation.css
deleted file mode 100644
index c3ff1f42..00000000
--- a/vendor/leafo/lessphp/tests/outputs/interpolation.css
+++ /dev/null
@@ -1,28 +0,0 @@
-div {
- interp1: yes;
- interp2: yes;
- interp3: okay;
-}
-10"yeah" {
- color: blue;
-}
-10 {
- color: blue;
-}
-hello world 10 {
- color: red;
-}
-#"yeah" {
- color: "hello 10";
-}
-[prop],
-[prop="value3"],
-[prop*="val3"],
-[|prop~="val3"],
-[*|prop$="val3"],
-[ns|prop^="val3"],
-[3^="val3"],
-[3=3],
-[3] {
- attributes: yes;
-}
diff --git a/vendor/leafo/lessphp/tests/outputs/keyframes.css b/vendor/leafo/lessphp/tests/outputs/keyframes.css
deleted file mode 100644
index cf62be11..00000000
--- a/vendor/leafo/lessphp/tests/outputs/keyframes.css
+++ /dev/null
@@ -1,48 +0,0 @@
-@keyframes 'bounce' {
- from {
- top: 100px;
- animation-timing-function: ease-out;
- }
- 25% {
- top: 50px;
- animation-timing-function: ease-in;
- }
- 50% {
- top: 100px;
- animation-timing-function: ease-out;
- }
- 75% {
- top: 75px;
- animation-timing-function: ease-in;
- }
- to {
- top: 100px;
- }
-}
-@-webkit-keyframes flowouttoleft {
- 0% {
- -webkit-transform: translateX(0) scale(1);
- }
- 60%,
- 70% {
- -webkit-transform: translateX(0) scale(.7);
- }
- 100% {
- -webkit-transform: translateX(-100%) scale(.7);
- }
-}
-div {
- animation-name: 'diagonal-slide';
- animation-duration: 5s;
- animation-iteration-count: 10;
-}
-@keyframes 'diagonal-slide' {
- from {
- left: 0;
- top: 0;
- }
- to {
- left: 100px;
- top: 100px;
- }
-}
diff --git a/vendor/leafo/lessphp/tests/outputs/math.css b/vendor/leafo/lessphp/tests/outputs/math.css
deleted file mode 100644
index 8d425f30..00000000
--- a/vendor/leafo/lessphp/tests/outputs/math.css
+++ /dev/null
@@ -1,69 +0,0 @@
-.unary {
- sub: 10 -5;
-}
-.spaces {
- sub1: 5;
- sub2: 5;
- add1: 15;
- add2: 15;
- div: 2;
- mul1: 50;
- mul2: 50;
-}
-.supress-division {
- border-radius: 10px/10px;
- border-radius: 10px/12px;
- border-radius: hello(10px/10px) world;
- font: 10px/30 sans-serif;
- font: 10px/20px sans-serif;
- font: 10px/22px sans-serif;
- border-radius: 0 15px 15px 15px/0 50% 50% 50%;
-}
-.parens {
- sub: 5;
- add: 15;
- div1: 2;
- div2: 2;
- mul: 50;
-}
-.keyword-names {
- height: "hello" 25;
-}
-.negation {
- neg1: -1px;
- neg2: -1px;
- neg3: -10;
-}
-.test {
- single1: 5;
- single2: 10;
- single3: 10;
- parens: 10 -2;
- math1: 20;
- math2: 20;
- complex1: 71;
- complex2: 6;
- complex3: 6px 1em 2px 2;
- var1: 8 4 4 4px;
- var2: 96;
- var3: 12;
- complex4: 113;
-}
-.percents {
- p1: 1000%;
- p2: 1000%;
- p3: 100%;
- p4: 1000px;
- p5: 1000%;
- p6: 30%;
- p7: 10%;
- p8: 2%;
-}
-.misc {
- x: 40px;
- y: 40em;
-}
-.cond {
- c1: false;
- c2: true;
-}
diff --git a/vendor/leafo/lessphp/tests/outputs/media.css b/vendor/leafo/lessphp/tests/outputs/media.css
deleted file mode 100644
index 99da8c31..00000000
--- a/vendor/leafo/lessphp/tests/outputs/media.css
+++ /dev/null
@@ -1,70 +0,0 @@
-@media screen,3D {
- P {
- color: green;
- }
-}
-@media print {
- body {
- font-size: 10pt;
- }
-}
-@media screen {
- body {
- font-size: 13px;
- }
-}
-@media screen,print {
- body {
- line-height: 1.2;
- }
-}
-@media all and (min-width: 0px) {
- body {
- line-height: 1.2;
- }
-}
-@media all and (min-width: 0) {
- body {
- line-height: 1.2;
- }
-}
-@media screen and (min-width: 102.5em) and (max-width: 117.9375em),screen and (min-width: 150em) {
- body {
- color: blue;
- }
-}
-@media screen and (min-height: 110px) {
- body {
- color: red;
- }
-}
-@media screen and (height: 100px) and (width: 110px),(size: 120px) {
- body {
- color: red;
- }
-}
-@media test {
- div {
- height: 20px;
- }
-}
-@media test and (hello) {
- div {
- color: red;
- }
- div pre {
- color: orange;
- }
-}
-@media yeah {
- @page {
- @media cool {
- color: red;
- }
- }
-}
-@media (max-width: 599px) {
- .helloworld {
- color: blue;
- }
-}
diff --git a/vendor/leafo/lessphp/tests/outputs/misc.css b/vendor/leafo/lessphp/tests/outputs/misc.css
deleted file mode 100644
index 6c99cc39..00000000
--- a/vendor/leafo/lessphp/tests/outputs/misc.css
+++ /dev/null
@@ -1,68 +0,0 @@
-color: "aaa, bbb";
-.topbar {
- background: url(/assets/images/test/topbar.png);
-}
-.hello {
- test: empty-function("/assets/images/test/",40%,to(#fff));
-}
-.css3 {
- background-image: -webkit-gradient(linear,0% 0%,0% 90%,from(#E9A000),to(#A37000));
-}
-.test,
-.world {
- border: 1px solid red;
- color: url(http://mage-page.com);
- string: "hello /* this is not a comment */";
- world: "// neither is this";
- string: 'hello /* this is not a comment */';
- world: '// neither is this';
- what-ever: 100px;
- background: url(/*no comment here*/);
-}
-.urls {
- background1: url("http://google.com");
- background2: url(http://google.com);
- background3: url("http://google.com");
-}
-.cool {
- color: "aaa, bbb";
-}
-.span-17 {
- float: left;
-}
-.span-17 {
- width: 660px;
-}
-.x {
- float: left;
- width: 660px;
-}
-.hi pre {
- color: red;
-}
-.hi pre {
- color: blue;
-}
-.rad pre {
- color: red;
-}
-.rad pre {
- color: blue;
-}
-hello {
- numbers: 1.0 0.1 .1 1.;
- numbers: 1.0s 0.1s .1s 1.s;
- numbers: -1s -0.1s -0.1s -1s;
- numbers: -1 -0.1 -0.1 -1;
-}
-#string {
- hello: 'what\'s going on here';
- hello: 'blah blag @{ blah blah';
- join: "3434hello";
- join: 3434hello;
-}
-.duplicates {
- hello: world;
- hello: "world";
- hello: "what";
-}
diff --git a/vendor/leafo/lessphp/tests/outputs/mixin_functions.css b/vendor/leafo/lessphp/tests/outputs/mixin_functions.css
deleted file mode 100644
index 53785803..00000000
--- a/vendor/leafo/lessphp/tests/outputs/mixin_functions.css
+++ /dev/null
@@ -1,7 +0,0 @@
-body {
- padding: 2.0em;
- color: red;
- margin: 10px;
- height: 12px;
- border-bottom: 1px solid green;
-}
diff --git a/vendor/leafo/lessphp/tests/outputs/mixin_merging.css b/vendor/leafo/lessphp/tests/outputs/mixin_merging.css
deleted file mode 100644
index f396ba92..00000000
--- a/vendor/leafo/lessphp/tests/outputs/mixin_merging.css
+++ /dev/null
@@ -1,42 +0,0 @@
-#test1 div {
- color:red;
- height:10px;
-}
-#test1 p { height:10px; }
-#test2 b {
- color:red;
- width:1px;
-}
-#test2 a, #test2 i { width:1px; }
-#test3 a, #test3 i { width:1px; }
-#test3 b {
- width:1px;
- color:red;
-}
-#test4 a {
- color:blue;
- margin:1px;
-}
-#test4 div, #test4 html { color:blue; }
-#test5 img, #test5 strong {
- padding:2px;
- float:right;
-}
-#test6 div a, #test6 span a {
- line-height:10px;
- color:red;
-}
-#test7 div strong {
- margin:1px;
- color:red;
-}
-#test7 div b { color:red; }
-#test7 span strong, #test7 span b { color:red; }
-#test8 a i, #test8 b i {
- background:red;
- color:red;
-}
-#test8 a s, #test8 b s {
- background:red;
- color:blue;
-}
diff --git a/vendor/leafo/lessphp/tests/outputs/mixins.css b/vendor/leafo/lessphp/tests/outputs/mixins.css
deleted file mode 100644
index cce87eb4..00000000
--- a/vendor/leafo/lessphp/tests/outputs/mixins.css
+++ /dev/null
@@ -1,92 +0,0 @@
-.bold {
- font-size: 20px;
- font-weight: bold;
-}
-body #window {
- border-radius: 10px;
- font-size: 20px;
- font-weight: bold;
- line-height: 30px;
-}
-#bundle .button {
- display: block;
- border: 1px solid black;
- background-color: grey;
-}
-#bundle .button:hover {
- background-color: white;
-}
-#header a {
- color: orange;
- display: block;
- border: 1px solid black;
- background-color: grey;
-}
-#header a:hover {
- background-color: white;
-}
-div {
- color: blue;
- hello: world;
-}
-div b {
- color: blue;
-}
-body {
- color: blue;
- hello: world;
-}
-body b {
- color: blue;
-}
-.hello .world {
- color: blue;
-}
-.foobar {
- color: blue;
-}
-.eggs {
- foo: 1px 2px;
- bar: 1px 2px;
- foo: 100 land;
- bar: 100 land;
-}
-#hello {
- cool: one two three cool;
-}
-#hello-important {
- cool: one two three cool !important;
-}
-#world {
- cool: "world";
-}
-#another {
- things: red blue green;
- things: red blue green skip me;
-}
-#day .cool {
- color: one two three;
-}
-#day .cool {
- color: one two three skip me;
-}
-.mix-suffix {
- color: red !important;
- height: 20px !important;
-}
-.mix-suffix pre {
- color: red;
-}
-.search-test {
- color: #f00 !important;
- color: #0f0 !important;
-}
-.cowboy {
- color: blue;
-}
-.nav .nav-divider {
- padding: 10px;
-}
-.nav-divider {
- padding: 10px;
-}
diff --git a/vendor/leafo/lessphp/tests/outputs/nested.css b/vendor/leafo/lessphp/tests/outputs/nested.css
deleted file mode 100644
index 454dcfcc..00000000
--- a/vendor/leafo/lessphp/tests/outputs/nested.css
+++ /dev/null
@@ -1,51 +0,0 @@
-#header {
- color: black;
-}
-#header .navigation {
- font-size: 12px;
-}
-#header .navigation .border .outside {
- color: blue;
-}
-#header .logo {
- width: 300px;
-}
-#header .logo:hover {
- text-decoration: none;
-}
-a b ul li {
- color: green;
-}
-div .cool {
- color: green;
-}
-p .cool span {
- color: yellow;
-}
-div another {
- color: green;
-}
-p another span {
- color: yellow;
-}
-b .something {
- color: blue;
-}
-b.something {
- color: blue;
-}
-.foo .bar .qux,
-.foo .baz .qux {
- display: block;
-}
-.qux .foo .bar,
-.qux .foo .baz {
- display: inline;
-}
-.qux .foo .bar .biz,
-.qux .foo .baz .biz {
- display: none;
-}
-b hello [x="&yeah"] {
- color: red;
-}
diff --git a/vendor/leafo/lessphp/tests/outputs/nesting.css b/vendor/leafo/lessphp/tests/outputs/nesting.css
deleted file mode 100644
index 804a56bf..00000000
--- a/vendor/leafo/lessphp/tests/outputs/nesting.css
+++ /dev/null
@@ -1,6 +0,0 @@
-#header .navigation .border .outside { color:blue; }
-#header .navigation { font-size:12px; }
-#header .logo:hover { text-decoration:none; }
-#header .logo { width:300px; }
-#header { color:black; }
-a b ul li { color:green; }
diff --git a/vendor/leafo/lessphp/tests/outputs/pattern_matching.css b/vendor/leafo/lessphp/tests/outputs/pattern_matching.css
deleted file mode 100644
index 215371b0..00000000
--- a/vendor/leafo/lessphp/tests/outputs/pattern_matching.css
+++ /dev/null
@@ -1,72 +0,0 @@
-.class {
- color: #a2a2a2;
- display: block;
-}
-.zero {
- zero: 0;
- one: 1;
- two: 2;
- three: 3;
-}
-.one {
- one: 1;
- one-req: 1;
- two: 2;
- three: 3;
-}
-.two {
- two: 2;
- three: 3;
-}
-.three {
- three-req: 3;
- three: 3;
-}
-.left {
- left: 1;
-}
-.right {
- right: 1;
-}
-.border-right {
- color: black;
- border-right: 4px;
-}
-.border-left {
- color: black;
- border-left: 4px;
-}
-.only-right {
- right: 33;
-}
-.only-left {
- left: 33;
-}
-.left-right {
- both: 330;
-}
-#hola {
- color: blue;
-}
-#defaults_1 {
- height: one;
- height: two;
- height: three;
- height: four;
-}
-.thing {
- color: red;
-}
-#aa {
- color: green;
- color: blue;
- color: red;
-}
-#bb {
- color: green;
- color: blue;
- color: red;
-}
-#cc {
- color: blue;
-}
diff --git a/vendor/leafo/lessphp/tests/outputs/scopes.css b/vendor/leafo/lessphp/tests/outputs/scopes.css
deleted file mode 100644
index ea2a4573..00000000
--- a/vendor/leafo/lessphp/tests/outputs/scopes.css
+++ /dev/null
@@ -1,11 +0,0 @@
-body div other world {
- height: 50;
-}
-div other world {
- height: 50;
-}
-pre {
- height: 10;
- height: 11;
- height: 12;
-}
diff --git a/vendor/leafo/lessphp/tests/outputs/selector_expressions.css b/vendor/leafo/lessphp/tests/outputs/selector_expressions.css
deleted file mode 100644
index 71d4a5d8..00000000
--- a/vendor/leafo/lessphp/tests/outputs/selector_expressions.css
+++ /dev/null
@@ -1,25 +0,0 @@
-something blue,
-world {
- color: blue;
-}
-.div (3434) {
- height: 100px;
-}
-.div cool red {
- height: 4000px;
-}
-.span5 {
- color: 15;
-}
-.span4 {
- color: 14;
-}
-.span3 {
- color: 13;
-}
-.span2 {
- color: 12;
-}
-.span1 {
- color: 11;
-}
diff --git a/vendor/leafo/lessphp/tests/outputs/site_demos.css b/vendor/leafo/lessphp/tests/outputs/site_demos.css
deleted file mode 100644
index 3428ad3a..00000000
--- a/vendor/leafo/lessphp/tests/outputs/site_demos.css
+++ /dev/null
@@ -1,76 +0,0 @@
-default .underline {
- border-bottom: 1px solid green;
-}
-default #header {
- color: black;
- border: 1px solid #dd44dd;
-}
-default #header .navigation {
- font-size: 12px;
-}
-default #header .navigation a {
- border-bottom: 1px solid green;
-}
-default #header .logo {
- width: 300px;
-}
-default #header .logo:hover {
- text-decoration: none;
-}
-variables .variables {
- width: 14cm;
- height: 24px;
- color: #888;
- background: #6c94be;
- font-family: "Trebuchet MS", Verdana, sans-serif;
-}
-mixins .bordered {
- border-top: dotted 1px black;
- border-bottom: solid 2px black;
-}
-mixins #menu a {
- color: #111;
- border-top: dotted 1px black;
- border-bottom: solid 2px black;
-}
-mixins .post a {
- color: red;
- border-top: dotted 1px black;
- border-bottom: solid 2px black;
-}
-nested-rules #header {
- color: black;
-}
-nested-rules #header .navigation {
- font-size: 12px;
-}
-nested-rules #header .logo {
- width: 300px;
-}
-nested-rules #header .logo:hover {
- text-decoration: none;
-}
-namespaces #bundle .button {
- display: block;
- border: 1px solid black;
- background-color: grey;
-}
-namespaces #bundle .button:hover {
- background-color: white;
-}
-namespaces #header a {
- color: orange;
- display: block;
- border: 1px solid black;
- background-color: grey;
-}
-namespaces #header a:hover {
- background-color: white;
-}
-mixin-functions body {
- padding: 2.0em;
- color: red;
- margin: 10px;
- height: 12px;
- border-bottom: 1px solid green;
-}
diff --git a/vendor/leafo/lessphp/tests/outputs/variables.css b/vendor/leafo/lessphp/tests/outputs/variables.css
deleted file mode 100644
index c4857cc6..00000000
--- a/vendor/leafo/lessphp/tests/outputs/variables.css
+++ /dev/null
@@ -1,19 +0,0 @@
-outer1: 44px;
-outer2: 44px;
-.variables {
- width: 14cm;
- height: 24px;
- margin-top: -20px;
- margin-bottom: 30px;
- color: #888899;
- background: #6c94be;
- font-family: "Trebuchet MS", Verdana, sans-serif;
- margin: 3px;
- font: 10px/12px serif;
- font: 120%/120% serif;
-}
-.external {
- color: #888;
- border: 1px solid #3326cc;
- background: rgba(23,68,149,0.5);
-}
diff --git a/vendor/leafo/lessphp/tests/outputs_lessjs/mixins-args.css b/vendor/leafo/lessphp/tests/outputs_lessjs/mixins-args.css
deleted file mode 100644
index 0a8e6bee..00000000
--- a/vendor/leafo/lessphp/tests/outputs_lessjs/mixins-args.css
+++ /dev/null
@@ -1,113 +0,0 @@
-#hidden {
- color: transparent;
-}
-#hidden1 {
- color: transparent;
-}
-.two-args {
- color: blue;
- width: 10px;
- height: 99%;
- border: 2px dotted black;
-}
-.one-arg {
- width: 15px;
- height: 49%;
-}
-.no-parens {
- width: 5px;
- height: 49%;
-}
-.no-args {
- width: 5px;
- height: 49%;
-}
-.var-args {
- width: 45;
- height: 17%;
-}
-.multi-mix {
- width: 10px;
- height: 29%;
- margin: 4;
- padding: 5;
-}
-body {
- padding: 30px;
- color: #f00;
-}
-.scope-mix {
- width: 8;
-}
-.content {
- width: 600px;
-}
-.content .column {
- margin: 600px;
-}
-#same-var-name {
- radius: 5px;
-}
-#var-inside {
- width: 10px;
-}
-.arguments {
- border: 1px solid black;
- width: 1px;
-}
-.arguments2 {
- border: 0px;
- width: 0px;
-}
-.arguments3 {
- border: 0px;
- width: 0px;
-}
-.arguments4 {
- border: 0 1 2 3 4;
- rest: 1 2 3 4;
- width: 0;
-}
-.edge-case {
- border: "{";
- width: "{";
-}
-.slash-vs-math {
- border-radius: 0.4px;
- border-radius: 0.5px;
- border-radius: 6px;
-}
-.comma-vs-semi-colon {
- one: a;
- two: b, c;
- one: d, e;
- two: f;
- one: g;
- one: h;
- one: i;
- one: j;
- one: k;
- two: l;
- one: m, n;
- one: o, p;
- two: q;
- one: r, s;
- two: t;
-}
-#named-conflict {
- four: a, 11, 12, 13;
- four: a, 21, 22, 23;
-}
-.test-mixin-default-arg {
- defaults: 1px 1px 1px;
- defaults: 2px 2px 2px;
-}
-.selector {
- margin: 2, 2, 2, 2;
-}
-.selector2 {
- margin: 2, 2, 2, 2;
-}
-.selector3 {
- margin: 4;
-}
diff --git a/vendor/leafo/lessphp/tests/outputs_lessjs/mixins-named-args.css b/vendor/leafo/lessphp/tests/outputs_lessjs/mixins-named-args.css
deleted file mode 100644
index e460aa10..00000000
--- a/vendor/leafo/lessphp/tests/outputs_lessjs/mixins-named-args.css
+++ /dev/null
@@ -1,27 +0,0 @@
-.named-arg {
- color: blue;
- width: 5px;
- height: 99%;
- args: 1px 100%;
- text-align: center;
-}
-.class {
- width: 5px;
- height: 19%;
- args: 1px 20%;
-}
-.all-args-wrong-args {
- width: 10px;
- height: 9%;
- args: 2px 10%;
-}
-.named-args2 {
- width: 15px;
- height: 49%;
- color: #646464;
-}
-.named-args3 {
- width: 5px;
- height: 29%;
- color: #123456;
-}
diff --git a/vendor/leafo/lessphp/tests/outputs_lessjs/strings.css b/vendor/leafo/lessphp/tests/outputs_lessjs/strings.css
deleted file mode 100644
index f7b9c27d..00000000
--- a/vendor/leafo/lessphp/tests/outputs_lessjs/strings.css
+++ /dev/null
@@ -1,40 +0,0 @@
-#strings {
- background-image: url("http://son-of-a-banana.com");
- quotes: "~" "~";
- content: "#*%:&^,)!.(~*})";
- empty: "";
- brackets: "{" "}";
- escapes: "\"hello\" \\world";
- escapes2: "\"llo";
-}
-#comments {
- content: "/* hello */ // not-so-secret";
-}
-#single-quote {
- quotes: "'" "'";
- content: '""#!&""';
- empty: '';
- semi-colon: ';';
-}
-#escaped {
- filter: DX.Transform.MS.BS.filter(opacity=50);
-}
-#one-line {
- image: url(http://tooks.com);
-}
-#crazy {
- image: url(http://), "}", url("http://}");
-}
-#interpolation {
- url: "http://lesscss.org/dev/image.jpg";
- url2: "http://lesscss.org/image-256.jpg";
- url3: "http://lesscss.org#445566";
- url4: "http://lesscss.org/hello";
- url5: "http://lesscss.org/54.4px";
-}
-.mix-mul-class {
- color: blue;
- color: red;
- color: black;
- color: orange;
-}
diff --git a/vendor/leafo/lessphp/tests/sort.php b/vendor/leafo/lessphp/tests/sort.php
deleted file mode 100644
index 70b907ea..00000000
--- a/vendor/leafo/lessphp/tests/sort.php
+++ /dev/null
@@ -1,57 +0,0 @@
-<?php
-error_reporting(E_ALL);
-
-require realpath(dirname(__FILE__)).'/../lessc.inc.php';
-
-// sorts the selectors in stylesheet in order to normalize it for comparison
-
-$exe = array_shift($argv); // remove filename
-
-if (!$fname = array_shift($argv)) {
- $fname = "php://stdin";
-}
-
-class lesscNormalized extends lessc {
- public $numberPrecision = 3;
-
- public function compileValue($value) {
- if ($value[0] == "raw_color") {
- $value = $this->coerceColor($value);
- }
-
- return parent::compileValue($value);
- }
-}
-
-class SortingFormatter extends lessc_formatter_lessjs {
- function sortKey($block) {
- if (!isset($block->sortKey)) {
- sort($block->selectors, SORT_STRING);
- $block->sortKey = implode(",", $block->selectors);
- }
-
- return $block->sortKey;
- }
-
- function sortBlock($block) {
- usort($block->children, function($a, $b) {
- $sort = strcmp($this->sortKey($a), $this->sortKey($b));
- if ($sort == 0) {
- // TODO
- }
- return $sort;
- });
-
- }
-
- function block($block) {
- $this->sortBlock($block);
- return parent::block($block);
- }
-
-}
-
-$less = new lesscNormalized();
-$less->setFormatter(new SortingFormatter);
-echo $less->parse(file_get_contents($fname));
-
diff --git a/vendor/liuggio/statsd-php-client/CHANGELOG.md b/vendor/liuggio/statsd-php-client/CHANGELOG.md
new file mode 100644
index 00000000..e7ee9a44
--- /dev/null
+++ b/vendor/liuggio/statsd-php-client/CHANGELOG.md
@@ -0,0 +1,17 @@
+CHANGELOG for 1.x.x
+===================
+
+This changelog references the relevant changes (bug and security fixes) done
+in 1.x.x minor.
+
+To get the diff for a specific change, go to https://github.com/liuggio/statsd-php-client/commit/XXX where XXX is the change hash
+To get the diff between two versions, go to https://github.com/liuggio/statsd-php-client/compare/v1.0.12...v1.0.13
+
+### 1.0.14, 1.0.16
+ * fix minor casing issue
+ * php 5.3.2 instead of php5.2
+
+### 1.0.13
+ * add changelog
+ * feature StatsdService abstracting Client/Factory usage
+ * feature Deal with sampling in StatsdService
diff --git a/vendor/liuggio/statsd-php-client/README.md b/vendor/liuggio/statsd-php-client/README.md
new file mode 100644
index 00000000..e7c6f67a
--- /dev/null
+++ b/vendor/liuggio/statsd-php-client/README.md
@@ -0,0 +1,152 @@
+## statsd-php-client
+
+Be careful, see the [Upgrading section](Readme.md#upgrade) for <= v1.0.4, there's a BC.
+
+[![Build Status](https://secure.travis-ci.org/liuggio/statsd-php-client.png)](http://travis-ci.org/liuggio/statsd-php-client) [![Latest Stable Version](https://poser.pugx.org/liuggio/statsd-php-client/v/stable.png)](https://packagist.org/packages/liuggio/statsd-php-client) [![Total Downloads](https://poser.pugx.org/liuggio/statsd-php-client/downloads.png)](https://packagist.org/packages/liuggio/statsd-php-client)
+
+`statsd-php-client` is an Open Source, and **Object Oriented** Client for **etsy/statsd** written in php
+
+- `StatsdDataFactory` creates the `Liuggio\StatsdClient\Entity\StatsdDataInterface` Objects
+
+- `Sender` just sends data over the network (there are many sender)
+
+- `StatsdClient` sends the created objects via the `Sender` to the server
+
+## Why use this library instead the [statsd/php-example](https://github.com/etsy/statsd/blob/master/examples/php-example.php)?
+
+- You are wise.
+
+- You could also use monolog to redirect data to statsd
+
+- This library is tested.
+
+- This library optimizes the messages to send, compressing multiple messages in individual UDP packets.
+
+- This library pays attention to the maximum length of the UDP.
+
+- This library is made by Objects not array, but it also accepts array.
+
+- You do want to debug the packets, and using `SysLogSender` the packets will be logged in your `syslog` log (on debian-like distro: `tail -f /var/log/syslog`)
+
+
+## Example
+
+1. create the Sender
+
+2. create the Client
+
+3. create the Factory
+
+4. the Factory will help you to create data
+
+5. the Client will send the data
+
+### Standard Usage
+
+```php
+use Liuggio\StatsdClient\StatsdClient,
+ Liuggio\StatsdClient\Factory\StatsdDataFactory,
+ Liuggio\StatsdClient\Sender\SocketSender,
+ Liuggio\StatsdClient\Service\StatsdService;
+// use Liuggio\StatsdClient\Sender\SysLogSender;
+
+$sender = new SocketSender(/*'localhost', 8126, 'udp'*/);
+// $sender = new SysLogSender(); // enabling this, the packet will not send over the socket
+
+$client = new StatsdClient($sender);
+$factory = new StatsdDataFactory('\Liuggio\StatsdClient\Entity\StatsdData');
+$service = new StatsdService($client, $factory);
+
+// create the metrics with the service
+$service->timing('usageTime', 100);
+$service->increment('visitor');
+$service->decrement('click');
+$service->gauge('gaugor', 333);
+$service->set('uniques', 765);
+
+// send the data to statsd
+$service->flush();
+
+```
+
+### Usage with Monolog
+
+```php
+use Liuggio\StatsdClient\StatsdClient,
+ Liuggio\StatsdClient\Factory\StatsdDataFactory,
+ Liuggio\StatsdClient\Sender\SocketSender;
+// use Liuggio\StatsdClient\Sender\SysLogSender;
+
+use Monolog\Logger;
+use Liuggio\StatsdClient\Monolog\Handler\StatsDHandler;
+
+$sender = new SocketSender(/*'localhost', 8126, 'udp'*/);
+// $sender = new SysLogSender(); // enabling this, the packet will not send over the socket
+$client = new StatsdClient($sender);
+$factory = new StatsdDataFactory();
+
+$logger = new Logger('my_logger');
+$logger->pushHandler(new StatsDHandler($client, $factory, 'prefix', Logger::DEBUG));
+
+$logger->addInfo('My logger is now ready');
+```
+
+the output will be: `prefix.my_logger.INFO.My-logger:1|c" 36 Bytes`
+
+
+
+
+## Short Theory
+
+### Easily Install StatSD and Graphite
+
+In order to try this application monitor you have to install etsy/statsd and Graphite
+
+see this blog post to install it with vagrant [Easy install statsd graphite](http://welcometothebundle.com/easily-install-statsd-and-graphite-with-vagrant/).
+
+#### [StatsD](https://github.com/etsy/statsd)
+
+StatsD is a simple daemon for easy stats aggregation
+
+#### [Graphite](http://graphite.wikidot.com/)
+
+Graphite is a Scalable Realtime Graphing
+
+#### The Client sends data with UDP (faster)
+
+https://www.google.com/search?q=tcp+vs+udp
+
+## Contribution
+
+Active contribution and patches are very welcome.
+To keep things in shape we have quite a bunch of unit tests. If you're submitting pull requests please
+make sure that they are still passing and if you add functionality please
+take a look at the coverage as well it should be pretty high :)
+
+- First fork or clone the repository
+
+```
+git clone git://github.com/liuggio/statsd-php-client.git
+cd statsd-php-client
+```
+
+- Install vendors:
+
+``` bash
+composer.phar install
+```
+
+- This will give you proper results:
+
+``` bash
+phpunit --coverage-html reports
+```
+
+## Upgrade
+
+BC from the v1.0.4 version, [see Sender and Client differences](https://github.com/liuggio/statsd-php-client/pull/5/files).
+
+
+## TODO
+
+example with monolog
diff --git a/vendor/liuggio/statsd-php-client/Readme.md b/vendor/liuggio/statsd-php-client/Readme.md
deleted file mode 100644
index 81083e05..00000000
--- a/vendor/liuggio/statsd-php-client/Readme.md
+++ /dev/null
@@ -1,149 +0,0 @@
-## statsd-php-client
-
-Be careful, see the [Upgrading section](Readme.md#upgrade) for <= v1.0.4, there's a BC.
-
-[![Build Status](https://secure.travis-ci.org/liuggio/statsd-php-client.png)](http://travis-ci.org/liuggio/statsd-php-client) [![Latest Stable Version](https://poser.pugx.org/liuggio/statsd-php-client/v/stable.png)](https://packagist.org/packages/liuggio/statsd-php-client) [![Total Downloads](https://poser.pugx.org/liuggio/statsd-php-client/downloads.png)](https://packagist.org/packages/liuggio/statsd-php-client)
-
-`statsd-php-client` is an Open Source, and **Object Oriented** Client for **etsy/statsd** written in php
-
-- `StatsdDataFactory` creates the `Liuggio\StatsdClient\Entity\StatsdDataInterface` Objects
-
-- `Sender` just sends data over the network (there are many sender)
-
-- `StatsdClient` sends the created objects via the `Sender` to the server
-
-## Why use this library instead the [statsd/php-example](https://github.com/etsy/statsd/blob/master/examples/php-example.php)?
-
-- You are wise.
-
-- You could also use monolog to redirect data to statsd
-
-- This library is tested.
-
-- This library optimizes the messages to send, compressing multiple messages in individual UDP packets.
-
-- This library pays attention to the maximum length of the UDP.
-
-- This library is made by Objects not array, but it also accepts array.
-
-- You do want to debug the packets, and using `SysLogSender` the packets will be logged in your `syslog` log (on debian-like distro: `tail -f /var/log/syslog`)
-
-
-## Example
-
-1. create the Sender
-
-2. create the Client
-
-3. create the Factory
-
-4. the Factory will help you to create data
-
-5. the Client will send the data
-
-### Standard Usage
-
-```php
-use Liuggio\StatsdClient\StatsdClient,
- Liuggio\StatsdClient\Factory\StatsdDataFactory,
- Liuggio\StatsdClient\Sender\SocketSender;
-// use Liuggio\StatsdClient\Sender\SysLogSender;
-
-$sender = new SocketSender(/*'localhost', 8126, 'udp'*/);
-// $sender = new SysLogSender(); // enabling this, the packet will not send over the socket
-
-$client = new StatsdClient($sender);
-$factory = new StatsdDataFactory('\Liuggio\StatsdClient\Entity\StatsdData');
-
-// create the data with the factory
-$data[] = $factory->timing('usageTime', 100);
-$data[] = $factory->increment('visitor');
-$data[] = $factory->decrement('click');
-$data[] = $factory->gauge('gaugor', 333);
-$data[] = $factory->set('uniques', 765);
-
-// send the data as array or directly as object
-$client->send($data);
-```
-
-### Usage with Monolog
-
-```php
-use Liuggio\StatsdClient\StatsdClient,
- Liuggio\StatsdClient\Factory\StatsdDataFactory,
- Liuggio\StatsdClient\Sender\SocketSender;
-// use Liuggio\StatsdClient\Sender\SysLogSender;
-
-use Monolog\Logger;
-use Liuggio\StatsdClient\Monolog\Handler\StatsDHandler;
-
-$sender = new SocketSender(/*'localhost', 8126, 'udp'*/);
-// $sender = new SysLogSender(); // enabling this, the packet will not send over the socket
-$client = new StatsdClient($sender);
-$factory = new StatsdDataFactory();
-
-$logger = new Logger('my_logger');
-$logger->pushHandler(new StatsDHandler($client, $factory, 'prefix', Logger::DEBUG));
-
-$logger->addInfo('My logger is now ready');
-```
-
-the output will be: `prefix.my_logger.INFO.My-logger:1|c" 36 Bytes`
-
-
-
-
-## Short Theory
-
-### Easily Install StatSD and Graphite
-
-In order to try this application monitor you have to install etsy/statsd and Graphite
-
-see this blog post to install it with vagrant [Easy install statsd graphite](http://welcometothebundle.com/easily-install-statsd-and-graphite-with-vagrant/).
-
-#### [StatsD](https://github.com/etsy/statsd)
-
-StatsD is a simple daemon for easy stats aggregation
-
-#### [Graphite](http://graphite.wikidot.com/)
-
-Graphite is a Scalable Realtime Graphing
-
-#### The Client sends data with UDP (faster)
-
-https://www.google.com/search?q=tcp+vs+udp
-
-## Contribution
-
-Active contribution and patches are very welcome.
-To keep things in shape we have quite a bunch of unit tests. If you're submitting pull requests please
-make sure that they are still passing and if you add functionality please
-take a look at the coverage as well it should be pretty high :)
-
-- First fork or clone the repository
-
-```
-git clone git://github.com/liuggio/statsd-php-client.git
-cd statsd-php-client
-```
-
-- Install vendors:
-
-``` bash
-composer.phar install
-```
-
-- This will give you proper results:
-
-``` bash
-phpunit --coverage-html reports
-```
-
-## Upgrade
-
-BC from the v1.0.4 version, [see Sender and Client differences](https://github.com/liuggio/statsd-php-client/pull/5/files).
-
-
-## TODO
-
-example with monolog
diff --git a/vendor/liuggio/statsd-php-client/composer.json b/vendor/liuggio/statsd-php-client/composer.json
index 705dbdf8..b47e0fd6 100644
--- a/vendor/liuggio/statsd-php-client/composer.json
+++ b/vendor/liuggio/statsd-php-client/composer.json
@@ -6,7 +6,7 @@
"type": "library",
"license": "MIT",
"require": {
- "php": ">=5.2"
+ "php": ">=5.3.2"
},
"authors": [
{
diff --git a/vendor/liuggio/statsd-php-client/phpunit.xml.dist b/vendor/liuggio/statsd-php-client/phpunit.xml
index 621efd75..621efd75 100644
--- a/vendor/liuggio/statsd-php-client/phpunit.xml.dist
+++ b/vendor/liuggio/statsd-php-client/phpunit.xml
diff --git a/vendor/liuggio/statsd-php-client/src/Liuggio/StatsdClient/Entity/StatsdData.php b/vendor/liuggio/statsd-php-client/src/Liuggio/StatsdClient/Entity/StatsdData.php
index 9c6203db..2f030859 100644
--- a/vendor/liuggio/statsd-php-client/src/Liuggio/StatsdClient/Entity/StatsdData.php
+++ b/vendor/liuggio/statsd-php-client/src/Liuggio/StatsdClient/Entity/StatsdData.php
@@ -10,6 +10,7 @@ class StatsdData implements StatsdDataInterface
private $key;
private $value;
private $metric;
+ private $sampleRate = 1;
/**
* @param string $key
@@ -55,6 +56,22 @@ class StatsdData implements StatsdDataInterface
}
/**
+ * @param float $sampleRate
+ */
+ public function setSampleRate($sampleRate)
+ {
+ $this->sampleRate = $sampleRate;
+ }
+
+ /**
+ * @return float
+ */
+ public function getSampleRate()
+ {
+ return $this->sampleRate;
+ }
+
+ /**
* @param bool $withMetric
*
* @return string
@@ -62,10 +79,17 @@ class StatsdData implements StatsdDataInterface
public function getMessage($withMetric = true)
{
if (!$withMetric) {
- return sprintf('%s:%s', $this->getKey(), $this->getValue());
+ $result = sprintf('%s:%s', $this->getKey(), $this->getValue());
} else {
- return sprintf('%s:%s|%s', $this->getKey(), $this->getValue(), $this->getMetric());
+ $result = sprintf('%s:%s|%s', $this->getKey(), $this->getValue(), $this->getMetric());
}
+
+ $sampleRate = $this->getSampleRate();
+ if($sampleRate < 1){
+ $result.= "|@$sampleRate";
+ }
+
+ return $result;
}
/**
diff --git a/vendor/liuggio/statsd-php-client/src/Liuggio/StatsdClient/Entity/StatsdDataInterface.php b/vendor/liuggio/statsd-php-client/src/Liuggio/StatsdClient/Entity/StatsdDataInterface.php
index 846bc7cc..d7b07a80 100644
--- a/vendor/liuggio/statsd-php-client/src/Liuggio/StatsdClient/Entity/StatsdDataInterface.php
+++ b/vendor/liuggio/statsd-php-client/src/Liuggio/StatsdClient/Entity/StatsdDataInterface.php
@@ -35,6 +35,12 @@ interface StatsdDataInterface
/**
* @abstract
+ * @return float
+ */
+ function getSampleRate();
+
+ /**
+ * @abstract
* @return string
*/
function __toString();
diff --git a/vendor/liuggio/statsd-php-client/src/Liuggio/StatsdClient/Service/StatsdService.php b/vendor/liuggio/statsd-php-client/src/Liuggio/StatsdClient/Service/StatsdService.php
new file mode 100644
index 00000000..061e3510
--- /dev/null
+++ b/vendor/liuggio/statsd-php-client/src/Liuggio/StatsdClient/Service/StatsdService.php
@@ -0,0 +1,196 @@
+<?php
+
+namespace Liuggio\StatsdClient\Service;
+
+use Liuggio\StatsdClient\Entity\StatsdDataInterface;
+use Liuggio\StatsdClient\Factory\StatsdDataFactory;
+use Liuggio\StatsdClient\Factory\StatsdDataFactoryInterface;
+use Liuggio\StatsdClient\StatsdClient;
+use Liuggio\StatsdClient\Entity\StatsdData;
+
+/**
+ * Simplifies access to StatsD client and factory, buffers all data.
+ */
+class StatsdService implements StatsdDataFactoryInterface
+{
+ /**
+ * @var \Liuggio\StatsdClient\StatsdClient
+ */
+ protected $client;
+
+ /**
+ * @var \Liuggio\StatsdClient\Factory\StatsdDataFactoryInterface
+ */
+ protected $factory;
+
+ /**
+ * @var StatsdData[]
+ */
+ protected $buffer = array();
+
+ /**
+ * @var float
+ */
+ protected $samplingRate;
+
+ private $samplingFunction;
+
+ /**
+ * @param StatsdClient $client
+ * @param StatsdDataFactoryInterface $factory
+ * @param float $samplingRate see setSamplingRate
+ */
+ public function __construct(
+ StatsdClient $client,
+ StatsdDataFactoryInterface $factory = null,
+ $samplingRate = 1
+ ) {
+ $this->client = $client;
+ if (is_null($factory)) {
+ $factory = new StatsdDataFactory();
+ }
+ $this->factory = $factory;
+ $this->setSamplingRate($samplingRate);
+ }
+
+ /**
+ * Actually defines the sampling rate used by the service.
+ * If set to 0.1, the service will automatically discard 10%
+ * of the incoming metrics. It will also automatically flag these
+ * as sampled data to statsd.
+ *
+ * @param float $samplingRate
+ */
+ public function setSamplingRate($samplingRate)
+ {
+ if ($samplingRate <= 0.0 || 1.0 < $samplingRate) {
+ throw new \LogicException('Sampling rate shall be within ]0, 1]');
+ }
+ $this->samplingRate = $samplingRate;
+ $this->samplingFunction = function($min, $max){
+ return rand($min, $max);
+ };
+ }
+
+ /**
+ * @return float
+ */
+ public function getSamplingRate()
+ {
+ return $this->samplingRate;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function timing($key, $time)
+ {
+ $this->appendToBuffer(
+ $this->factory->timing($key, $time)
+ );
+
+ return $this;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function gauge($key, $value)
+ {
+ $this->appendToBuffer(
+ $this->factory->gauge($key, $value)
+ );
+
+ return $this;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function set($key, $value)
+ {
+ $this->appendToBuffer(
+ $this->factory->set($key, $value)
+ );
+
+ return $this;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function increment($key)
+ {
+ $this->appendToBuffer(
+ $this->factory->increment($key)
+ );
+
+ return $this;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function decrement($key)
+ {
+ $this->appendToBuffer(
+ $this->factory->decrement($key)
+ );
+
+ return $this;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function updateCount($key, $delta)
+ {
+ $this->appendToBuffer(
+ $this->factory->updateCount($key, $delta)
+ );
+
+ return $this;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function produceStatsdData($key, $value = 1, $metric = StatsdDataInterface::STATSD_METRIC_COUNT)
+ {
+ throw new \BadFunctionCallException('produceStatsdData is not implemented');
+ }
+
+ /**
+ * @param callable $samplingFunction rand() function by default.
+ */
+ public function setSamplingFunction(\Closure $samplingFunction)
+ {
+ $this->samplingFunction = $samplingFunction;
+ }
+
+ private function appendToBuffer(StatsdData $data)
+ {
+ if($this->samplingRate < 1){
+ $data->setSampleRate($this->samplingRate);
+ $result = call_user_func($this->samplingFunction, 0 , floor(1 / $this->samplingRate));
+ if ($result == 0) {
+ array_push($this->buffer, $data);
+ };
+ } else {
+ array_push($this->buffer, $data);
+ }
+ }
+
+ /**
+ * Send all buffered data to statsd.
+ *
+ * @return $this
+ */
+ public function flush()
+ {
+ $this->client->send($this->buffer);
+ $this->buffer = array();
+
+ return $this;
+ }
+}
diff --git a/vendor/liuggio/statsd-php-client/src/Liuggio/StatsdClient/StatsdClient.php b/vendor/liuggio/statsd-php-client/src/Liuggio/StatsdClient/StatsdClient.php
index a1d232a5..c5c16fed 100644
--- a/vendor/liuggio/statsd-php-client/src/Liuggio/StatsdClient/StatsdClient.php
+++ b/vendor/liuggio/statsd-php-client/src/Liuggio/StatsdClient/StatsdClient.php
@@ -109,12 +109,10 @@ class StatsdClient implements StatsdClientInterface
*/
public function appendSampleRate($data, $sampleRate = 1)
{
- $sampledData = array();
if ($sampleRate < 1) {
- foreach ($data as $key => $message) {
- $sampledData[$key] = sprintf('%s|@%s', $message, $sampleRate);
- }
- $data = $sampledData;
+ array_walk($data, function(&$message, $key) use ($sampleRate) {
+ $message = sprintf('%s|@%s', $message, $sampleRate);
+ });
}
return $data;
diff --git a/vendor/liuggio/statsd-php-client/tests/Liuggio/StatsdClient/Service/StatsdServiceTest.php b/vendor/liuggio/statsd-php-client/tests/Liuggio/StatsdClient/Service/StatsdServiceTest.php
new file mode 100644
index 00000000..dcf2710d
--- /dev/null
+++ b/vendor/liuggio/statsd-php-client/tests/Liuggio/StatsdClient/Service/StatsdServiceTest.php
@@ -0,0 +1,86 @@
+<?php
+
+namespace Liuggio\StatsdClient\Entity;
+
+use Liuggio\StatsdClient\Service\StatsdService;
+
+class StatsdServiceTest extends \PHPUnit_Framework_TestCase
+{
+ private $clientMock;
+ private $factoryMock;
+
+ public function setUp()
+ {
+ $this->clientMock = $this->getMockBuilder('Liuggio\StatsdClient\StatsdClient')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $this->factoryMock = $this->getMockBuilder('Liuggio\StatsdClient\Factory\StatsdDataFactoryInterface')
+ ->disableOriginalConstructor()
+ ->getMock();
+ }
+
+ public function testConstructorWithoutFactory()
+ {
+ $dut = new StatsdService($this->clientMock);
+ $dut->timing('foo.bar', 123);
+ }
+
+ public function testFactoryImplementation()
+ {
+ $data = new StatsdData();
+
+ // Configure the client mock.
+ $this->factoryMock->expects($this->once())->method('timing')->willReturn($data);
+ $this->factoryMock->expects($this->once())->method('gauge')->willReturn($data);
+ $this->factoryMock->expects($this->once())->method('set')->willReturn($data);
+ $this->factoryMock->expects($this->once())->method('increment')->willReturn($data);
+ $this->factoryMock->expects($this->once())->method('decrement')->willReturn($data);
+ $this->factoryMock->expects($this->once())->method('updateCount')->willReturn($data);
+
+ // Actual test
+ $dut = new StatsdService($this->clientMock, $this->factoryMock);
+ $dut->timing('foo.bar', 123);
+ $dut->gauge('foo.bar', 123);
+ $dut->set('foo.bar', 123);
+ $dut->increment('foo.bar');
+ $dut->decrement('foo.bar');
+ $dut->updateCount('foo.bar', 123);
+ }
+
+ public function testFlush()
+ {
+ $data = new StatsdData();
+ $this->factoryMock->expects($this->once())->method('timing')->willReturn($data);
+ $this->clientMock->expects($this->once())->method('send')
+ ->with($this->equalTo(array($data)));
+
+ // Actual test
+ $dut = new StatsdService($this->clientMock, $this->factoryMock);
+ $dut->timing('foobar', 123);
+ $dut->flush();
+ }
+
+ public function testSampling()
+ {
+ $tries = false;
+ $closure = function($a, $b) use (&$tries) {
+ $tries = !$tries;
+ return $tries ? 1 : 0;
+ };
+
+ $data = new StatsdData();
+ $this->factoryMock->expects($this->exactly(2))->method('timing')->willReturn($data);
+ $this->clientMock->expects($this->once())->method('send')
+ ->with($this->equalTo(array($data)));
+
+ // Actual test
+ $dut = new StatsdService($this->clientMock, $this->factoryMock);
+ $dut->setSamplingRate(0.1);
+ $dut->setSamplingFunction($closure);
+ $dut->timing('foo', 123);
+ $dut->timing('bar', 123);
+ $dut->flush();
+
+ $this->assertSame(0.1, $data->getSampleRate());
+ }
+}
diff --git a/vendor/mediawiki/at-ease/COPYING b/vendor/mediawiki/at-ease/COPYING
new file mode 100644
index 00000000..019694a9
--- /dev/null
+++ b/vendor/mediawiki/at-ease/COPYING
@@ -0,0 +1,342 @@
+== GNU GENERAL PUBLIC LICENSE ==
+
+Version 2, June 1991
+
+Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+Everyone is permitted to copy and distribute verbatim copies
+of this license document, but changing it is not allowed.
+
+=== Preamble ===
+
+The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+The precise terms and conditions for copying, distribution and
+modification follow.
+
+== TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION ==
+
+'''0.''' This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+'''1.''' You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+'''2.''' You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ '''a)''' You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ '''b)''' You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ '''c)''' If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+'''3.''' You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ '''a)''' Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ '''b)''' Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ '''c)''' Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+'''4.''' You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+'''5.''' You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+'''6.''' Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+'''7.''' If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+'''8.''' If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+'''9.''' The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+'''10.''' If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+=== NO WARRANTY ===
+
+'''11.''' BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+'''12.''' IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ '''END OF TERMS AND CONDITIONS'''
+
+== How to Apply These Terms to Your New Programs ==
+
+If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+
+ Copyright (C) <year> <name of author>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) year name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/vendor/mediawiki/at-ease/README.md b/vendor/mediawiki/at-ease/README.md
new file mode 100644
index 00000000..578f78ce
--- /dev/null
+++ b/vendor/mediawiki/at-ease/README.md
@@ -0,0 +1,59 @@
+[![Latest Stable Version]](https://packagist.org/packages/mediawiki/at-ease) [![License]](https://packagist.org/packages/mediawiki/at-ease)
+
+at-ease
+=======
+
+at-ease is a PHP library that provides a safe alternative to PHP's
+[@ error control operator][].
+
+`@` is broken when `E_STRICT` is enabled and it causes an unlogged,
+unexplained error if there is a fatal, which is hard to support. The proper
+method of handling errors is to actually handle the errors. For example, if
+you are thinking of using an error suppression operator to suppress an invalid
+array index warning, you should instead perform an `isset()` check on the
+array index before trying to access it. When possible, always prevent PHP
+errors rather than catching and handling them afterward. It makes the code
+more understandable and avoids dealing with slow error suppression methods.
+
+However, there are some cases where warnings are inevitable, even if you check
+beforehand, like when accessing files. You can check that the file exists by
+using `file_exists()` and `is_readable()`, but the file could have been
+deleted by the time you go to read it. In that case, you can use this library
+to suppress the warnings and prevent PHP from being noisy.
+
+
+Usage
+-----
+
+ // Suppress warnings in a block of code:
+ \MediaWiki\suppressWarnings();
+ $content = file_get_contents( 'foobar.txt' );
+ \MediaWiki\restoreWarnings();
+
+
+ // ..or in a callback function:
+ \MediaWiki\quietCall( 'file_get_contents', 'foobar.txt' );
+
+
+Running tests
+-------------
+
+ composer install --prefer-dist
+ composer test
+
+
+History
+-------
+
+This library was first introduced in [MediaWiki 1.3][] ([r4261][]). It was
+split out of the MediaWiki codebase and published as an independent library
+during the [MediaWiki 1.26][] development cycle.
+
+
+---
+[@ error control operator]: https://php.net/manual/en/language.operators.errorcontrol.php
+[MediaWiki 1.3]: https://www.mediawiki.org/wiki/MediaWiki_1.3
+[r4261]: https://www.mediawiki.org/wiki/Special:Code/MediaWiki/r4261
+[MediaWiki 1.26]: https://www.mediawiki.org/wiki/MediaWiki_1.26
+[Latest Stable Version]: https://poser.pugx.org/mediawiki/at-ease/v/stable.svg
+[License]: https://poser.pugx.org/mediawiki/at-ease/license.svg
diff --git a/vendor/mediawiki/at-ease/src/Functions.php b/vendor/mediawiki/at-ease/src/Functions.php
new file mode 100644
index 00000000..0be91eb6
--- /dev/null
+++ b/vendor/mediawiki/at-ease/src/Functions.php
@@ -0,0 +1,75 @@
+<?php
+/**
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ */
+
+namespace MediaWiki;
+
+/**
+ * Reference-counted warning suppression
+ *
+ * @param bool $end
+ */
+function suppressWarnings( $end = false ) {
+ static $suppressCount = 0;
+ static $originalLevel = false;
+
+ if ( $end ) {
+ if ( $suppressCount ) {
+ --$suppressCount;
+ if ( !$suppressCount ) {
+ error_reporting( $originalLevel );
+ }
+ }
+ } else {
+ if ( !$suppressCount ) {
+ $originalLevel = error_reporting( E_ALL & ~(
+ E_WARNING |
+ E_NOTICE |
+ E_USER_WARNING |
+ E_USER_NOTICE |
+ E_DEPRECATED |
+ E_USER_DEPRECATED |
+ E_STRICT
+ ) );
+ }
+ ++$suppressCount;
+ }
+}
+
+/**
+ * Restore error level to previous value
+ */
+function restoreWarnings() {
+ suppressWarnings( true );
+}
+
+
+/**
+ * Call the callback given by the first parameter, suppressing any warnings.
+ *
+ * @param callable $callback
+ * @return mixed
+ */
+function quietCall( $callback /*, parameters... */ ) {
+ $args = array_slice( func_get_args(), 1 );
+ suppressWarnings();
+ $rv = call_user_func_array( $callback, $args );
+ restoreWarnings();
+ return $rv;
+}
diff --git a/vendor/monolog/monolog/.php_cs b/vendor/monolog/monolog/.php_cs
new file mode 100644
index 00000000..2511e98c
--- /dev/null
+++ b/vendor/monolog/monolog/.php_cs
@@ -0,0 +1,15 @@
+<?php
+
+$finder = Symfony\CS\Finder\DefaultFinder::create()
+ ->files()
+ ->name('*.php')
+ ->in(__DIR__.'/src')
+ ->in(__DIR__.'/tests')
+;
+
+return Symfony\CS\Config\Config::create()
+ ->fixers(array(
+ 'psr0', 'encoding', 'short_tag', 'braces', 'elseif', 'eof_ending', 'function_declaration', 'indentation', 'line_after_namespace', 'linefeed', 'lowercase_constants', 'lowercase_keywords', 'multiple_use', 'php_closing_tag', 'trailing_spaces', 'visibility', 'duplicate_semicolon', 'extra_empty_lines', 'include', 'namespace_no_leading_whitespace', 'object_operator', 'operators_spaces', 'phpdoc_params', 'return', 'single_array_no_trailing_comma', 'spaces_cast', 'standardize_not_equal', 'ternary_spaces', 'unused_use', 'whitespacy_lines',
+ ))
+ ->finder($finder)
+;
diff --git a/vendor/monolog/monolog/CHANGELOG.mdown b/vendor/monolog/monolog/CHANGELOG.mdown
new file mode 100644
index 00000000..41d072e1
--- /dev/null
+++ b/vendor/monolog/monolog/CHANGELOG.mdown
@@ -0,0 +1,226 @@
+### 1.14.0 (2015-06-19)
+
+ * Added PHPConsoleHandler to send record to Chrome's PHP Console extension and library
+ * Added support for objects implementing __toString in the NormalizerFormatter
+ * Added support for HipChat's v2 API in HipChatHandler
+ * Added Logger::setTimezone() to initialize the timezone monolog should use in case date.timezone isn't correct for your app
+ * Added an option to send formatted message instead of the raw record on PushoverHandler via ->useFormattedMessage(true)
+ * Fixed curl errors being silently suppressed
+
+### 1.13.1 (2015-03-09)
+
+ * Fixed regression in HipChat requiring a new token to be created
+
+### 1.13.0 (2015-03-05)
+
+ * Added Registry::hasLogger to check for the presence of a logger instance
+ * Added context.user support to RavenHandler
+ * Added HipChat API v2 support in the HipChatHandler
+ * Added NativeMailerHandler::addParameter to pass params to the mail() process
+ * Added context data to SlackHandler when $includeContextAndExtra is true
+ * Added ability to customize the Swift_Message per-email in SwiftMailerHandler
+ * Fixed SwiftMailerHandler to lazily create message instances if a callback is provided
+ * Fixed serialization of INF and NaN values in Normalizer and LineFormatter
+
+### 1.12.0 (2014-12-29)
+
+ * Break: HandlerInterface::isHandling now receives a partial record containing only a level key. This was always the intent and does not break any Monolog handler but is strictly speaking a BC break and you should check if you relied on any other field in your own handlers.
+ * Added PsrHandler to forward records to another PSR-3 logger
+ * Added SamplingHandler to wrap around a handler and include only every Nth record
+ * Added MongoDBFormatter to support better storage with MongoDBHandler (it must be enabled manually for now)
+ * Added exception codes in the output of most formatters
+ * Added LineFormatter::includeStacktraces to enable exception stack traces in logs (uses more than one line)
+ * Added $useShortAttachment to SlackHandler to minify attachment size and $includeExtra to append extra data
+ * Added $host to HipChatHandler for users of private instances
+ * Added $transactionName to NewRelicHandler and support for a transaction_name context value
+ * Fixed MandrillHandler to avoid outputing API call responses
+ * Fixed some non-standard behaviors in SyslogUdpHandler
+
+### 1.11.0 (2014-09-30)
+
+ * Break: The NewRelicHandler extra and context data are now prefixed with extra_ and context_ to avoid clashes. Watch out if you have scripts reading those from the API and rely on names
+ * Added WhatFailureGroupHandler to suppress any exception coming from the wrapped handlers and avoid chain failures if a logging service fails
+ * Added MandrillHandler to send emails via the Mandrillapp.com API
+ * Added SlackHandler to log records to a Slack.com account
+ * Added FleepHookHandler to log records to a Fleep.io account
+ * Added LogglyHandler::addTag to allow adding tags to an existing handler
+ * Added $ignoreEmptyContextAndExtra to LineFormatter to avoid empty [] at the end
+ * Added $useLocking to StreamHandler and RotatingFileHandler to enable flock() while writing
+ * Added support for PhpAmqpLib in the AmqpHandler
+ * Added FingersCrossedHandler::clear and BufferHandler::clear to reset them between batches in long running jobs
+ * Added support for adding extra fields from $_SERVER in the WebProcessor
+ * Fixed support for non-string values in PrsLogMessageProcessor
+ * Fixed SwiftMailer messages being sent with the wrong date in long running scripts
+ * Fixed minor PHP 5.6 compatibility issues
+ * Fixed BufferHandler::close being called twice
+
+### 1.10.0 (2014-06-04)
+
+ * Added Logger::getHandlers() and Logger::getProcessors() methods
+ * Added $passthruLevel argument to FingersCrossedHandler to let it always pass some records through even if the trigger level is not reached
+ * Added support for extra data in NewRelicHandler
+ * Added $expandNewlines flag to the ErrorLogHandler to create multiple log entries when a message has multiple lines
+
+### 1.9.1 (2014-04-24)
+
+ * Fixed regression in RotatingFileHandler file permissions
+ * Fixed initialization of the BufferHandler to make sure it gets flushed after receiving records
+ * Fixed ChromePHPHandler and FirePHPHandler's activation strategies to be more conservative
+
+### 1.9.0 (2014-04-20)
+
+ * Added LogEntriesHandler to send logs to a LogEntries account
+ * Added $filePermissions to tweak file mode on StreamHandler and RotatingFileHandler
+ * Added $useFormatting flag to MemoryProcessor to make it send raw data in bytes
+ * Added support for table formatting in FirePHPHandler via the table context key
+ * Added a TagProcessor to add tags to records, and support for tags in RavenHandler
+ * Added $appendNewline flag to the JsonFormatter to enable using it when logging to files
+ * Added sound support to the PushoverHandler
+ * Fixed multi-threading support in StreamHandler
+ * Fixed empty headers issue when ChromePHPHandler received no records
+ * Fixed default format of the ErrorLogHandler
+
+### 1.8.0 (2014-03-23)
+
+ * Break: the LineFormatter now strips newlines by default because this was a bug, set $allowInlineLineBreaks to true if you need them
+ * Added BrowserConsoleHandler to send logs to any browser's console via console.log() injection in the output
+ * Added FilterHandler to filter records and only allow those of a given list of levels through to the wrapped handler
+ * Added FlowdockHandler to send logs to a Flowdock account
+ * Added RollbarHandler to send logs to a Rollbar account
+ * Added HtmlFormatter to send prettier log emails with colors for each log level
+ * Added GitProcessor to add the current branch/commit to extra record data
+ * Added a Monolog\Registry class to allow easier global access to pre-configured loggers
+ * Added support for the new official graylog2/gelf-php lib for GelfHandler, upgrade if you can by replacing the mlehner/gelf-php requirement
+ * Added support for HHVM
+ * Added support for Loggly batch uploads
+ * Added support for tweaking the content type and encoding in NativeMailerHandler
+ * Added $skipClassesPartials to tweak the ignored classes in the IntrospectionProcessor
+ * Fixed batch request support in GelfHandler
+
+### 1.7.0 (2013-11-14)
+
+ * Added ElasticSearchHandler to send logs to an Elastic Search server
+ * Added DynamoDbHandler and ScalarFormatter to send logs to Amazon's Dynamo DB
+ * Added SyslogUdpHandler to send logs to a remote syslogd server
+ * Added LogglyHandler to send logs to a Loggly account
+ * Added $level to IntrospectionProcessor so it only adds backtraces when needed
+ * Added $version to LogstashFormatter to allow using the new v1 Logstash format
+ * Added $appName to NewRelicHandler
+ * Added configuration of Pushover notification retries/expiry
+ * Added $maxColumnWidth to NativeMailerHandler to change the 70 chars default
+ * Added chainability to most setters for all handlers
+ * Fixed RavenHandler batch processing so it takes the message from the record with highest priority
+ * Fixed HipChatHandler batch processing so it sends all messages at once
+ * Fixed issues with eAccelerator
+ * Fixed and improved many small things
+
+### 1.6.0 (2013-07-29)
+
+ * Added HipChatHandler to send logs to a HipChat chat room
+ * Added ErrorLogHandler to send logs to PHP's error_log function
+ * Added NewRelicHandler to send logs to NewRelic's service
+ * Added Monolog\ErrorHandler helper class to register a Logger as exception/error/fatal handler
+ * Added ChannelLevelActivationStrategy for the FingersCrossedHandler to customize levels by channel
+ * Added stack traces output when normalizing exceptions (json output & co)
+ * Added Monolog\Logger::API constant (currently 1)
+ * Added support for ChromePHP's v4.0 extension
+ * Added support for message priorities in PushoverHandler, see $highPriorityLevel and $emergencyLevel
+ * Added support for sending messages to multiple users at once with the PushoverHandler
+ * Fixed RavenHandler's support for batch sending of messages (when behind a Buffer or FingersCrossedHandler)
+ * Fixed normalization of Traversables with very large data sets, only the first 1000 items are shown now
+ * Fixed issue in RotatingFileHandler when an open_basedir restriction is active
+ * Fixed minor issues in RavenHandler and bumped the API to Raven 0.5.0
+ * Fixed SyslogHandler issue when many were used concurrently with different facilities
+
+### 1.5.0 (2013-04-23)
+
+ * Added ProcessIdProcessor to inject the PID in log records
+ * Added UidProcessor to inject a unique identifier to all log records of one request/run
+ * Added support for previous exceptions in the LineFormatter exception serialization
+ * Added Monolog\Logger::getLevels() to get all available levels
+ * Fixed ChromePHPHandler so it avoids sending headers larger than Chrome can handle
+
+### 1.4.1 (2013-04-01)
+
+ * Fixed exception formatting in the LineFormatter to be more minimalistic
+ * Fixed RavenHandler's handling of context/extra data, requires Raven client >0.1.0
+ * Fixed log rotation in RotatingFileHandler to work with long running scripts spanning multiple days
+ * Fixed WebProcessor array access so it checks for data presence
+ * Fixed Buffer, Group and FingersCrossed handlers to make use of their processors
+
+### 1.4.0 (2013-02-13)
+
+ * Added RedisHandler to log to Redis via the Predis library or the phpredis extension
+ * Added ZendMonitorHandler to log to the Zend Server monitor
+ * Added the possibility to pass arrays of handlers and processors directly in the Logger constructor
+ * Added `$useSSL` option to the PushoverHandler which is enabled by default
+ * Fixed ChromePHPHandler and FirePHPHandler issue when multiple instances are used simultaneously
+ * Fixed header injection capability in the NativeMailHandler
+
+### 1.3.1 (2013-01-11)
+
+ * Fixed LogstashFormatter to be usable with stream handlers
+ * Fixed GelfMessageFormatter levels on Windows
+
+### 1.3.0 (2013-01-08)
+
+ * Added PSR-3 compliance, the `Monolog\Logger` class is now an instance of `Psr\Log\LoggerInterface`
+ * Added PsrLogMessageProcessor that you can selectively enable for full PSR-3 compliance
+ * Added LogstashFormatter (combine with SocketHandler or StreamHandler to send logs to Logstash)
+ * Added PushoverHandler to send mobile notifications
+ * Added CouchDBHandler and DoctrineCouchDBHandler
+ * Added RavenHandler to send data to Sentry servers
+ * Added support for the new MongoClient class in MongoDBHandler
+ * Added microsecond precision to log records' timestamps
+ * Added `$flushOnOverflow` param to BufferHandler to flush by batches instead of losing
+ the oldest entries
+ * Fixed normalization of objects with cyclic references
+
+### 1.2.1 (2012-08-29)
+
+ * Added new $logopts arg to SyslogHandler to provide custom openlog options
+ * Fixed fatal error in SyslogHandler
+
+### 1.2.0 (2012-08-18)
+
+ * Added AmqpHandler (for use with AMQP servers)
+ * Added CubeHandler
+ * Added NativeMailerHandler::addHeader() to send custom headers in mails
+ * Added the possibility to specify more than one recipient in NativeMailerHandler
+ * Added the possibility to specify float timeouts in SocketHandler
+ * Added NOTICE and EMERGENCY levels to conform with RFC 5424
+ * Fixed the log records to use the php default timezone instead of UTC
+ * Fixed BufferHandler not being flushed properly on PHP fatal errors
+ * Fixed normalization of exotic resource types
+ * Fixed the default format of the SyslogHandler to avoid duplicating datetimes in syslog
+
+### 1.1.0 (2012-04-23)
+
+ * Added Monolog\Logger::isHandling() to check if a handler will
+ handle the given log level
+ * Added ChromePHPHandler
+ * Added MongoDBHandler
+ * Added GelfHandler (for use with Graylog2 servers)
+ * Added SocketHandler (for use with syslog-ng for example)
+ * Added NormalizerFormatter
+ * Added the possibility to change the activation strategy of the FingersCrossedHandler
+ * Added possibility to show microseconds in logs
+ * Added `server` and `referer` to WebProcessor output
+
+### 1.0.2 (2011-10-24)
+
+ * Fixed bug in IE with large response headers and FirePHPHandler
+
+### 1.0.1 (2011-08-25)
+
+ * Added MemoryPeakUsageProcessor and MemoryUsageProcessor
+ * Added Monolog\Logger::getName() to get a logger's channel name
+
+### 1.0.0 (2011-07-06)
+
+ * Added IntrospectionProcessor to get info from where the logger was called
+ * Fixed WebProcessor in CLI
+
+### 1.0.0-RC1 (2011-07-01)
+
+ * Initial release
diff --git a/vendor/monolog/monolog/LICENSE b/vendor/monolog/monolog/LICENSE
new file mode 100644
index 00000000..56e08d55
--- /dev/null
+++ b/vendor/monolog/monolog/LICENSE
@@ -0,0 +1,19 @@
+Copyright (c) 2011-2015 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/monolog/monolog/README.mdown b/vendor/monolog/monolog/README.mdown
new file mode 100644
index 00000000..af745c8a
--- /dev/null
+++ b/vendor/monolog/monolog/README.mdown
@@ -0,0 +1,302 @@
+Monolog - Logging for PHP 5.3+ [![Build Status](https://secure.travis-ci.org/Seldaek/monolog.png)](http://travis-ci.org/Seldaek/monolog)
+==============================
+
+[![Total Downloads](https://poser.pugx.org/monolog/monolog/downloads.png)](https://packagist.org/packages/monolog/monolog)
+[![Latest Stable Version](https://poser.pugx.org/monolog/monolog/v/stable.png)](https://packagist.org/packages/monolog/monolog)
+[![Reference Status](https://www.versioneye.com/php/monolog:monolog/reference_badge.svg)](https://www.versioneye.com/php/monolog:monolog/references)
+
+
+Monolog sends your logs to files, sockets, inboxes, databases and various
+web services. See the complete list of handlers below. Special handlers
+allow you to build advanced logging strategies.
+
+This library implements the [PSR-3](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-3-logger-interface.md)
+interface that you can type-hint against in your own libraries to keep
+a maximum of interoperability. You can also use it in your applications to
+make sure you can always use another compatible logger at a later time.
+As of 1.11.0 Monolog public APIs will also accept PSR-3 log levels.
+Internally Monolog still uses its own level scheme since it predates PSR-3.
+
+Installation
+------------
+
+Install the latest version with
+
+```bash
+$ composer require monolog/monolog
+```
+
+Usage
+-----
+
+```php
+<?php
+
+use Monolog\Logger;
+use Monolog\Handler\StreamHandler;
+
+// create a log channel
+$log = new Logger('name');
+$log->pushHandler(new StreamHandler('path/to/your.log', Logger::WARNING));
+
+// add records to the log
+$log->addWarning('Foo');
+$log->addError('Bar');
+```
+
+Core Concepts
+-------------
+
+Every `Logger` instance has a channel (name) and a stack of handlers. Whenever
+you add a record to the logger, it traverses the handler stack. Each handler
+decides whether it fully handled the record, and if so, the propagation of the
+record ends there.
+
+This allows for flexible logging setups, for example having a `StreamHandler` at
+the bottom of the stack that will log anything to disk, and on top of that add
+a `MailHandler` that will send emails only when an error message is logged.
+Handlers also have a `$bubble` property which defines whether they block the
+record or not if they handled it. In this example, setting the `MailHandler`'s
+`$bubble` argument to false means that records handled by the `MailHandler` will
+not propagate to the `StreamHandler` anymore.
+
+You can create many `Logger`s, each defining a channel (e.g.: db, request,
+router, ..) and each of them combining various handlers, which can be shared
+or not. The channel is reflected in the logs and allows you to easily see or
+filter records.
+
+Each Handler also has a Formatter, a default one with settings that make sense
+will be created if you don't set one. The formatters normalize and format
+incoming records so that they can be used by the handlers to output useful
+information.
+
+Custom severity levels are not available. Only the eight
+[RFC 5424](http://tools.ietf.org/html/rfc5424) levels (debug, info, notice,
+warning, error, critical, alert, emergency) are present for basic filtering
+purposes, but for sorting and other use cases that would require
+flexibility, you should add Processors to the Logger that can add extra
+information (tags, user ip, ..) to the records before they are handled.
+
+Log Levels
+----------
+
+Monolog supports the logging levels described by [RFC 5424](http://tools.ietf.org/html/rfc5424).
+
+- **DEBUG** (100): Detailed debug information.
+
+- **INFO** (200): Interesting events. Examples: User logs in, SQL logs.
+
+- **NOTICE** (250): Normal but significant events.
+
+- **WARNING** (300): Exceptional occurrences that are not errors. Examples:
+ Use of deprecated APIs, poor use of an API, undesirable things that are not
+ necessarily wrong.
+
+- **ERROR** (400): Runtime errors that do not require immediate action but
+ should typically be logged and monitored.
+
+- **CRITICAL** (500): Critical conditions. Example: Application component
+ unavailable, unexpected exception.
+
+- **ALERT** (550): Action must be taken immediately. Example: Entire website
+ down, database unavailable, etc. This should trigger the SMS alerts and wake
+ you up.
+
+- **EMERGENCY** (600): Emergency: system is unusable.
+
+Docs
+====
+
+**See the `doc` directory for more detailed documentation.
+The following is only a list of all parts that come with Monolog.**
+
+Handlers
+--------
+
+### Log to files and syslog
+
+- _StreamHandler_: Logs records into any PHP stream, use this for log files.
+- _RotatingFileHandler_: Logs records to a file and creates one logfile per day.
+ It will also delete files older than `$maxFiles`. You should use
+ [logrotate](http://linuxcommand.org/man_pages/logrotate8.html) for high profile
+ setups though, this is just meant as a quick and dirty solution.
+- _SyslogHandler_: Logs records to the syslog.
+- _ErrorLogHandler_: Logs records to PHP's
+ [`error_log()`](http://docs.php.net/manual/en/function.error-log.php) function.
+
+### Send alerts and emails
+
+- _NativeMailerHandler_: Sends emails using PHP's
+ [`mail()`](http://php.net/manual/en/function.mail.php) function.
+- _SwiftMailerHandler_: Sends emails using a [`Swift_Mailer`](http://swiftmailer.org/) instance.
+- _PushoverHandler_: Sends mobile notifications via the [Pushover](https://www.pushover.net/) API.
+- _HipChatHandler_: Logs records to a [HipChat](http://hipchat.com) chat room using its API.
+- _FlowdockHandler_: Logs records to a [Flowdock](https://www.flowdock.com/) account.
+- _SlackHandler_: Logs records to a [Slack](https://www.slack.com/) account.
+- _MandrillHandler_: Sends emails via the Mandrill API using a [`Swift_Message`](http://swiftmailer.org/) instance.
+- _FleepHookHandler_: Logs records to a [Fleep](https://fleep.io/) conversation using Webhooks.
+
+### Log specific servers and networked logging
+
+- _SocketHandler_: Logs records to [sockets](http://php.net/fsockopen), use this
+ for UNIX and TCP sockets. See an [example](https://github.com/Seldaek/monolog/blob/master/doc/sockets.md).
+- _AmqpHandler_: Logs records to an [amqp](http://www.amqp.org/) compatible
+ server. Requires the [php-amqp](http://pecl.php.net/package/amqp) extension (1.0+).
+- _GelfHandler_: Logs records to a [Graylog2](http://www.graylog2.org) server.
+- _CubeHandler_: Logs records to a [Cube](http://square.github.com/cube/) server.
+- _RavenHandler_: Logs records to a [Sentry](http://getsentry.com/) server using
+ [raven](https://packagist.org/packages/raven/raven).
+- _ZendMonitorHandler_: Logs records to the Zend Monitor present in Zend Server.
+- _NewRelicHandler_: Logs records to a [NewRelic](http://newrelic.com/) application.
+- _LogglyHandler_: Logs records to a [Loggly](http://www.loggly.com/) account.
+- _RollbarHandler_: Logs records to a [Rollbar](https://rollbar.com/) account.
+- _SyslogUdpHandler_: Logs records to a remote [Syslogd](http://www.rsyslog.com/) server.
+- _LogEntriesHandler_: Logs records to a [LogEntries](http://logentries.com/) account.
+
+### Logging in development
+
+- _FirePHPHandler_: Handler for [FirePHP](http://www.firephp.org/), providing
+ inline `console` messages within [FireBug](http://getfirebug.com/).
+- _ChromePHPHandler_: Handler for [ChromePHP](http://www.chromephp.com/), providing
+ inline `console` messages within Chrome.
+- _BrowserConsoleHandler_: Handler to send logs to browser's Javascript `console` with
+ no browser extension required. Most browsers supporting `console` API are supported.
+- _PHPConsoleHandler_: Handler for [PHP Console](https://chrome.google.com/webstore/detail/php-console/nfhmhhlpfleoednkpnnnkolmclajemef), providing
+ inline `console` and notification popup messages within Chrome.
+
+### Log to databases
+
+- _RedisHandler_: Logs records to a [redis](http://redis.io) server.
+- _MongoDBHandler_: Handler to write records in MongoDB via a
+ [Mongo](http://pecl.php.net/package/mongo) extension connection.
+- _CouchDBHandler_: Logs records to a CouchDB server.
+- _DoctrineCouchDBHandler_: Logs records to a CouchDB server via the Doctrine CouchDB ODM.
+- _ElasticSearchHandler_: Logs records to an Elastic Search server.
+- _DynamoDbHandler_: Logs records to a DynamoDB table with the [AWS SDK](https://github.com/aws/aws-sdk-php).
+
+### Wrappers / Special Handlers
+
+- _FingersCrossedHandler_: A very interesting wrapper. It takes a logger as
+ parameter and will accumulate log records of all levels until a record
+ exceeds the defined severity level. At which point it delivers all records,
+ including those of lower severity, to the handler it wraps. This means that
+ until an error actually happens you will not see anything in your logs, but
+ when it happens you will have the full information, including debug and info
+ records. This provides you with all the information you need, but only when
+ you need it.
+- _WhatFailureGroupHandler_: This handler extends the _GroupHandler_ ignoring
+ exceptions raised by each child handler. This allows you to ignore issues
+ where a remote tcp connection may have died but you do not want your entire
+ application to crash and may wish to continue to log to other handlers.
+- _BufferHandler_: This handler will buffer all the log records it receives
+ until `close()` is called at which point it will call `handleBatch()` on the
+ handler it wraps with all the log messages at once. This is very useful to
+ send an email with all records at once for example instead of having one mail
+ for every log record.
+- _GroupHandler_: This handler groups other handlers. Every record received is
+ sent to all the handlers it is configured with.
+- _FilterHandler_: This handler only lets records of the given levels through
+ to the wrapped handler.
+- _SamplingHandler_: Wraps around another handler and lets you sample records
+ if you only want to store some of them.
+- _NullHandler_: Any record it can handle will be thrown away. This can be used
+ to put on top of an existing handler stack to disable it temporarily.
+- _PsrHandler_: Can be used to forward log records to an existing PSR-3 logger
+- _TestHandler_: Used for testing, it records everything that is sent to it and
+ has accessors to read out the information.
+
+Formatters
+----------
+
+- _LineFormatter_: Formats a log record into a one-line string.
+- _HtmlFormatter_: Used to format log records into a human readable html table, mainly suitable for emails.
+- _NormalizerFormatter_: Normalizes objects/resources down to strings so a record can easily be serialized/encoded.
+- _ScalarFormatter_: Used to format log records into an associative array of scalar values.
+- _JsonFormatter_: Encodes a log record into json.
+- _WildfireFormatter_: Used to format log records into the Wildfire/FirePHP protocol, only useful for the FirePHPHandler.
+- _ChromePHPFormatter_: Used to format log records into the ChromePHP format, only useful for the ChromePHPHandler.
+- _GelfMessageFormatter_: Used to format log records into Gelf message instances, only useful for the GelfHandler.
+- _LogstashFormatter_: Used to format log records into [logstash](http://logstash.net/) event json, useful for any handler listed under inputs [here](http://logstash.net/docs/latest).
+- _ElasticaFormatter_: Used to format log records into an Elastica\Document object, only useful for the ElasticSearchHandler.
+- _LogglyFormatter_: Used to format log records into Loggly messages, only useful for the LogglyHandler.
+- _FlowdockFormatter_: Used to format log records into Flowdock messages, only useful for the FlowdockHandler.
+- _MongoDBFormatter_: Converts \DateTime instances to \MongoDate and objects recursively to arrays, only useful with the MongoDBHandler.
+
+Processors
+----------
+
+- _IntrospectionProcessor_: Adds the line/file/class/method from which the log call originated.
+- _WebProcessor_: Adds the current request URI, request method and client IP to a log record.
+- _MemoryUsageProcessor_: Adds the current memory usage to a log record.
+- _MemoryPeakUsageProcessor_: Adds the peak memory usage to a log record.
+- _ProcessIdProcessor_: Adds the process id to a log record.
+- _UidProcessor_: Adds a unique identifier to a log record.
+- _GitProcessor_: Adds the current git branch and commit to a log record.
+- _TagProcessor_: Adds an array of predefined tags to a log record.
+
+Utilities
+---------
+
+- _Registry_: The `Monolog\Registry` class lets you configure global loggers that you
+ can then statically access from anywhere. It is not really a best practice but can
+ help in some older codebases or for ease of use.
+- _ErrorHandler_: The `Monolog\ErrorHandler` class allows you to easily register
+ a Logger instance as an exception handler, error handler or fatal error handler.
+- _ErrorLevelActivationStrategy_: Activates a FingersCrossedHandler when a certain log
+ level is reached.
+- _ChannelLevelActivationStrategy_: Activates a FingersCrossedHandler when a certain
+ log level is reached, depending on which channel received the log record.
+
+Third Party Packages
+--------------------
+
+Third party handlers, formatters and processors are
+[listed in the wiki](https://github.com/Seldaek/monolog/wiki/Third-Party-Packages). You
+can also add your own there if you publish one.
+
+About
+=====
+
+Requirements
+------------
+
+- Monolog works with PHP 5.3 or above, and is also tested to work with HHVM.
+
+Submitting bugs and feature requests
+------------------------------------
+
+Bugs and feature request are tracked on [GitHub](https://github.com/Seldaek/monolog/issues)
+
+Frameworks Integration
+----------------------
+
+- Frameworks and libraries using [PSR-3](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-3-logger-interface.md)
+ can be used very easily with Monolog since it implements the interface.
+- [Symfony2](http://symfony.com) comes out of the box with Monolog.
+- [Silex](http://silex.sensiolabs.org/) comes out of the box with Monolog.
+- [Laravel 4 & 5](http://laravel.com/) come out of the box with Monolog.
+- [Lumen](http://lumen.laravel.com/) comes out of the box with Monolog.
+- [PPI](http://www.ppi.io/) comes out of the box with Monolog.
+- [CakePHP](http://cakephp.org/) is usable with Monolog via the [cakephp-monolog](https://github.com/jadb/cakephp-monolog) plugin.
+- [Slim](http://www.slimframework.com/) is usable with Monolog via the [Slim-Monolog](https://github.com/Flynsarmy/Slim-Monolog) log writer.
+- [XOOPS 2.6](http://xoops.org/) comes out of the box with Monolog.
+- [Aura.Web_Project](https://github.com/auraphp/Aura.Web_Project) comes out of the box with Monolog.
+- [Nette Framework](http://nette.org/en/) can be used with Monolog via [Kdyby/Monolog](https://github.com/Kdyby/Monolog) extension.
+- [Proton Micro Framework](https://github.com/alexbilbie/Proton) comes out of the box with Monolog.
+
+Author
+------
+
+Jordi Boggiano - <j.boggiano@seld.be> - <http://twitter.com/seldaek><br />
+See also the list of [contributors](https://github.com/Seldaek/monolog/contributors) which participated in this project.
+
+License
+-------
+
+Monolog is licensed under the MIT License - see the `LICENSE` file for details
+
+Acknowledgements
+----------------
+
+This library is heavily inspired by Python's [Logbook](http://packages.python.org/Logbook/)
+library, although most concepts have been adjusted to fit to the PHP world.
diff --git a/vendor/monolog/monolog/composer.json b/vendor/monolog/monolog/composer.json
new file mode 100644
index 00000000..239484b3
--- /dev/null
+++ b/vendor/monolog/monolog/composer.json
@@ -0,0 +1,61 @@
+{
+ "name": "monolog/monolog",
+ "description": "Sends your logs to files, sockets, inboxes, databases and various web services",
+ "keywords": ["log", "logging", "psr-3"],
+ "homepage": "http://github.com/Seldaek/monolog",
+ "type": "library",
+ "license": "MIT",
+ "authors": [
+ {
+ "name": "Jordi Boggiano",
+ "email": "j.boggiano@seld.be",
+ "homepage": "http://seld.be"
+ }
+ ],
+ "require": {
+ "php": ">=5.3.0",
+ "psr/log": "~1.0"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "~4.5",
+ "graylog2/gelf-php": "~1.0",
+ "raven/raven": "~0.8",
+ "ruflin/elastica": ">=0.90 <3.0",
+ "doctrine/couchdb": "~1.0@dev",
+ "aws/aws-sdk-php": "^2.4.9",
+ "videlalvaro/php-amqplib": "~2.4",
+ "swiftmailer/swiftmailer": "~5.3",
+ "php-console/php-console": "^3.1.3",
+ "phpunit/phpunit-mock-objects": "2.3.0"
+ },
+ "_": "phpunit/phpunit-mock-objects required in 2.3.0 due to https://github.com/sebastianbergmann/phpunit-mock-objects/issues/223",
+ "suggest": {
+ "graylog2/gelf-php": "Allow sending log messages to a GrayLog2 server",
+ "raven/raven": "Allow sending log messages to a Sentry server",
+ "doctrine/couchdb": "Allow sending log messages to a CouchDB server",
+ "ruflin/elastica": "Allow sending log messages to an Elastic Search server",
+ "videlalvaro/php-amqplib": "Allow sending log messages to an AMQP server using php-amqplib",
+ "ext-amqp": "Allow sending log messages to an AMQP server (1.0+ required)",
+ "ext-mongo": "Allow sending log messages to a MongoDB server",
+ "aws/aws-sdk-php": "Allow sending log messages to AWS services like DynamoDB",
+ "rollbar/rollbar": "Allow sending log messages to Rollbar",
+ "php-console/php-console": "Allow sending log messages to Google Chrome"
+ },
+ "autoload": {
+ "psr-4": {"Monolog\\": "src/Monolog"}
+ },
+ "autoload-dev": {
+ "psr-4": {"Monolog\\": "tests/Monolog"}
+ },
+ "provide": {
+ "psr/log-implementation": "1.0.0"
+ },
+ "extra": {
+ "branch-alias": {
+ "dev-master": "1.14.x-dev"
+ }
+ },
+ "scripts": {
+ "test": "phpunit"
+ }
+}
diff --git a/vendor/monolog/monolog/doc/extending.md b/vendor/monolog/monolog/doc/extending.md
new file mode 100644
index 00000000..bb39ddcf
--- /dev/null
+++ b/vendor/monolog/monolog/doc/extending.md
@@ -0,0 +1,76 @@
+Extending Monolog
+=================
+
+Monolog is fully extensible, allowing you to adapt your logger to your needs.
+
+Writing your own handler
+------------------------
+
+Monolog provides many built-in handlers. But if the one you need does not
+exist, you can write it and use it in your logger. The only requirement is
+to implement `Monolog\Handler\HandlerInterface`.
+
+Let's write a PDOHandler to log records to a database. We will extend the
+abstract class provided by Monolog to keep things DRY.
+
+```php
+<?php
+
+use Monolog\Logger;
+use Monolog\Handler\AbstractProcessingHandler;
+
+class PDOHandler extends AbstractProcessingHandler
+{
+ private $initialized = false;
+ private $pdo;
+ private $statement;
+
+ public function __construct(PDO $pdo, $level = Logger::DEBUG, $bubble = true)
+ {
+ $this->pdo = $pdo;
+ parent::__construct($level, $bubble);
+ }
+
+ protected function write(array $record)
+ {
+ if (!$this->initialized) {
+ $this->initialize();
+ }
+
+ $this->statement->execute(array(
+ 'channel' => $record['channel'],
+ 'level' => $record['level'],
+ 'message' => $record['formatted'],
+ 'time' => $record['datetime']->format('U'),
+ ));
+ }
+
+ private function initialize()
+ {
+ $this->pdo->exec(
+ 'CREATE TABLE IF NOT EXISTS monolog '
+ .'(channel VARCHAR(255), level INTEGER, message LONGTEXT, time INTEGER UNSIGNED)'
+ );
+ $this->statement = $this->pdo->prepare(
+ 'INSERT INTO monolog (channel, level, message, time) VALUES (:channel, :level, :message, :time)'
+ );
+
+ $this->initialized = true;
+ }
+}
+```
+
+You can now use this handler in your logger:
+
+```php
+<?php
+
+$logger->pushHandler(new PDOHandler(new PDO('sqlite:logs.sqlite')));
+
+// You can now use your logger
+$logger->addInfo('My logger is now ready');
+```
+
+The `Monolog\Handler\AbstractProcessingHandler` class provides most of the
+logic needed for the handler, including the use of processors and the formatting
+of the record (which is why we use ``$record['formatted']`` instead of ``$record['message']``).
diff --git a/vendor/monolog/monolog/doc/sockets.md b/vendor/monolog/monolog/doc/sockets.md
new file mode 100644
index 00000000..fad30a9f
--- /dev/null
+++ b/vendor/monolog/monolog/doc/sockets.md
@@ -0,0 +1,37 @@
+Sockets Handler
+===============
+
+This handler allows you to write your logs to sockets using [fsockopen](http://php.net/fsockopen)
+or [pfsockopen](http://php.net/pfsockopen).
+
+Persistent sockets are mainly useful in web environments where you gain some performance not closing/opening
+the connections between requests.
+
+Basic Example
+-------------
+
+```php
+<?php
+
+use Monolog\Logger;
+use Monolog\Handler\SocketHandler;
+
+// Create the logger
+$logger = new Logger('my_logger');
+
+// Create the handler
+$handler = new SocketHandler('unix:///var/log/httpd_app_log.socket');
+$handler->setPersistent(true);
+
+// Now add the handler
+$logger->pushHandler($handler, Logger::DEBUG);
+
+// You can now use your logger
+$logger->addInfo('My logger is now ready');
+
+```
+
+In this example, using syslog-ng, you should see the log on the log server:
+
+ cweb1 [2012-02-26 00:12:03] my_logger.INFO: My logger is now ready [] []
+
diff --git a/vendor/monolog/monolog/doc/usage.md b/vendor/monolog/monolog/doc/usage.md
new file mode 100644
index 00000000..7585fa2a
--- /dev/null
+++ b/vendor/monolog/monolog/doc/usage.md
@@ -0,0 +1,162 @@
+Using Monolog
+=============
+
+Installation
+------------
+
+Monolog is available on Packagist ([monolog/monolog](http://packagist.org/packages/monolog/monolog))
+and as such installable via [Composer](http://getcomposer.org/).
+
+```bash
+php composer.phar require monolog/monolog
+```
+
+If you do not use Composer, you can grab the code from GitHub, and use any
+PSR-0 compatible autoloader (e.g. the [Symfony2 ClassLoader component](https://github.com/symfony/ClassLoader))
+to load Monolog classes.
+
+Configuring a logger
+--------------------
+
+Here is a basic setup to log to a file and to firephp on the DEBUG level:
+
+```php
+<?php
+
+use Monolog\Logger;
+use Monolog\Handler\StreamHandler;
+use Monolog\Handler\FirePHPHandler;
+
+// Create the logger
+$logger = new Logger('my_logger');
+// Now add some handlers
+$logger->pushHandler(new StreamHandler(__DIR__.'/my_app.log', Logger::DEBUG));
+$logger->pushHandler(new FirePHPHandler());
+
+// You can now use your logger
+$logger->addInfo('My logger is now ready');
+```
+
+Let's explain it. The first step is to create the logger instance which will
+be used in your code. The argument is a channel name, which is useful when
+you use several loggers (see below for more details about it).
+
+The logger itself does not know how to handle a record. It delegates it to
+some handlers. The code above registers two handlers in the stack to allow
+handling records in two different ways.
+
+Note that the FirePHPHandler is called first as it is added on top of the
+stack. This allows you to temporarily add a logger with bubbling disabled if
+you want to override other configured loggers.
+
+Adding extra data in the records
+--------------------------------
+
+Monolog provides two different ways to add extra informations along the simple
+textual message.
+
+### Using the logging context
+
+The first way is the context, allowing to pass an array of data along the
+record:
+
+```php
+<?php
+
+$logger->addInfo('Adding a new user', array('username' => 'Seldaek'));
+```
+
+Simple handlers (like the StreamHandler for instance) will simply format
+the array to a string but richer handlers can take advantage of the context
+(FirePHP is able to display arrays in pretty way for instance).
+
+### Using processors
+
+The second way is to add extra data for all records by using a processor.
+Processors can be any callable. They will get the record as parameter and
+must return it after having eventually changed the `extra` part of it. Let's
+write a processor adding some dummy data in the record:
+
+```php
+<?php
+
+$logger->pushProcessor(function ($record) {
+ $record['extra']['dummy'] = 'Hello world!';
+
+ return $record;
+});
+```
+
+Monolog provides some built-in processors that can be used in your project.
+Look at the [README file](https://github.com/Seldaek/monolog/blob/master/README.mdown) for the list.
+
+> Tip: processors can also be registered on a specific handler instead of
+ the logger to apply only for this handler.
+
+Leveraging channels
+-------------------
+
+Channels are a great way to identify to which part of the application a record
+is related. This is useful in big applications (and is leveraged by
+MonologBundle in Symfony2).
+
+Picture two loggers sharing a handler that writes to a single log file.
+Channels would allow you to identify the logger that issued every record.
+You can easily grep through the log files filtering this or that channel.
+
+```php
+<?php
+
+use Monolog\Logger;
+use Monolog\Handler\StreamHandler;
+use Monolog\Handler\FirePHPHandler;
+
+// Create some handlers
+$stream = new StreamHandler(__DIR__.'/my_app.log', Logger::DEBUG);
+$firephp = new FirePHPHandler();
+
+// Create the main logger of the app
+$logger = new Logger('my_logger');
+$logger->pushHandler($stream);
+$logger->pushHandler($firephp);
+
+// Create a logger for the security-related stuff with a different channel
+$securityLogger = new Logger('security');
+$securityLogger->pushHandler($stream);
+$securityLogger->pushHandler($firephp);
+```
+
+Customizing log format
+----------------------
+
+In Monolog it's easy to customize the format of the logs written into files,
+sockets, mails, databases and other handlers. Most of the handlers use the
+
+```php
+$record['formatted']
+```
+
+value to be automatically put into the log device. This value depends on the
+formatter settings. You can choose between predefined formatter classes or
+write your own (e.g. a multiline text file for human-readable output).
+
+To configure a predefined formatter class, just set it as the handler's field:
+
+```php
+// the default date format is "Y-m-d H:i:s"
+$dateFormat = "Y n j, g:i a";
+// the default output format is "[%datetime%] %channel%.%level_name%: %message% %context% %extra%\n"
+$output = "%datetime% > %level_name% > %message% %context% %extra%\n";
+// finally, create a formatter
+$formatter = new LineFormatter($output, $dateFormat);
+
+// Create a handler
+$stream = new StreamHandler(__DIR__.'/my_app.log', Logger::DEBUG);
+$stream->setFormatter($formatter);
+// bind it to a logger object
+$securityLogger = new Logger('security');
+$securityLogger->pushHandler($stream);
+```
+
+You may also reuse the same formatter between multiple handlers and share those
+handlers between multiple loggers.
diff --git a/vendor/monolog/monolog/phpunit.xml.dist b/vendor/monolog/monolog/phpunit.xml.dist
new file mode 100644
index 00000000..20d82b63
--- /dev/null
+++ b/vendor/monolog/monolog/phpunit.xml.dist
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<phpunit bootstrap="vendor/autoload.php" colors="true">
+ <testsuites>
+ <testsuite name="Monolog Test Suite">
+ <directory>tests/Monolog/</directory>
+ </testsuite>
+ </testsuites>
+
+ <filter>
+ <whitelist>
+ <directory suffix=".php">src/Monolog/</directory>
+ </whitelist>
+ </filter>
+
+ <php>
+ <ini name="date.timezone" value="UTC"/>
+ </php>
+</phpunit>
diff --git a/vendor/monolog/monolog/src/Monolog/ErrorHandler.php b/vendor/monolog/monolog/src/Monolog/ErrorHandler.php
new file mode 100644
index 00000000..c8923354
--- /dev/null
+++ b/vendor/monolog/monolog/src/Monolog/ErrorHandler.php
@@ -0,0 +1,208 @@
+<?php
+
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog;
+
+use Psr\Log\LoggerInterface;
+use Psr\Log\LogLevel;
+
+/**
+ * Monolog error handler
+ *
+ * A facility to enable logging of runtime errors, exceptions and fatal errors.
+ *
+ * Quick setup: <code>ErrorHandler::register($logger);</code>
+ *
+ * @author Jordi Boggiano <j.boggiano@seld.be>
+ */
+class ErrorHandler
+{
+ private $logger;
+
+ private $previousExceptionHandler;
+ private $uncaughtExceptionLevel;
+
+ private $previousErrorHandler;
+ private $errorLevelMap;
+
+ private $fatalLevel;
+ private $reservedMemory;
+ private static $fatalErrors = array(E_ERROR, E_PARSE, E_CORE_ERROR, E_COMPILE_ERROR, E_USER_ERROR);
+
+ public function __construct(LoggerInterface $logger)
+ {
+ $this->logger = $logger;
+ }
+
+ /**
+ * Registers a new ErrorHandler for a given Logger
+ *
+ * By default it will handle errors, exceptions and fatal errors
+ *
+ * @param LoggerInterface $logger
+ * @param array|false $errorLevelMap an array of E_* constant to LogLevel::* constant mapping, or false to disable error handling
+ * @param int|false $exceptionLevel a LogLevel::* constant, or false to disable exception handling
+ * @param int|false $fatalLevel a LogLevel::* constant, or false to disable fatal error handling
+ * @return ErrorHandler
+ */
+ public static function register(LoggerInterface $logger, $errorLevelMap = array(), $exceptionLevel = null, $fatalLevel = null)
+ {
+ $handler = new static($logger);
+ if ($errorLevelMap !== false) {
+ $handler->registerErrorHandler($errorLevelMap);
+ }
+ if ($exceptionLevel !== false) {
+ $handler->registerExceptionHandler($exceptionLevel);
+ }
+ if ($fatalLevel !== false) {
+ $handler->registerFatalHandler($fatalLevel);
+ }
+
+ return $handler;
+ }
+
+ public function registerExceptionHandler($level = null, $callPrevious = true)
+ {
+ $prev = set_exception_handler(array($this, 'handleException'));
+ $this->uncaughtExceptionLevel = $level;
+ if ($callPrevious && $prev) {
+ $this->previousExceptionHandler = $prev;
+ }
+ }
+
+ public function registerErrorHandler(array $levelMap = array(), $callPrevious = true, $errorTypes = -1)
+ {
+ $prev = set_error_handler(array($this, 'handleError'), $errorTypes);
+ $this->errorLevelMap = array_replace($this->defaultErrorLevelMap(), $levelMap);
+ if ($callPrevious) {
+ $this->previousErrorHandler = $prev ?: true;
+ }
+ }
+
+ public function registerFatalHandler($level = null, $reservedMemorySize = 20)
+ {
+ register_shutdown_function(array($this, 'handleFatalError'));
+
+ $this->reservedMemory = str_repeat(' ', 1024 * $reservedMemorySize);
+ $this->fatalLevel = $level;
+ }
+
+ protected function defaultErrorLevelMap()
+ {
+ return array(
+ E_ERROR => LogLevel::CRITICAL,
+ E_WARNING => LogLevel::WARNING,
+ E_PARSE => LogLevel::ALERT,
+ E_NOTICE => LogLevel::NOTICE,
+ E_CORE_ERROR => LogLevel::CRITICAL,
+ E_CORE_WARNING => LogLevel::WARNING,
+ E_COMPILE_ERROR => LogLevel::ALERT,
+ E_COMPILE_WARNING => LogLevel::WARNING,
+ E_USER_ERROR => LogLevel::ERROR,
+ E_USER_WARNING => LogLevel::WARNING,
+ E_USER_NOTICE => LogLevel::NOTICE,
+ E_STRICT => LogLevel::NOTICE,
+ E_RECOVERABLE_ERROR => LogLevel::ERROR,
+ E_DEPRECATED => LogLevel::NOTICE,
+ E_USER_DEPRECATED => LogLevel::NOTICE,
+ );
+ }
+
+ /**
+ * @private
+ */
+ public function handleException(\Exception $e)
+ {
+ $this->logger->log(
+ $this->uncaughtExceptionLevel === null ? LogLevel::ERROR : $this->uncaughtExceptionLevel,
+ sprintf('Uncaught Exception %s: "%s" at %s line %s', get_class($e), $e->getMessage(), $e->getFile(), $e->getLine()),
+ array('exception' => $e)
+ );
+
+ if ($this->previousExceptionHandler) {
+ call_user_func($this->previousExceptionHandler, $e);
+ }
+ }
+
+ /**
+ * @private
+ */
+ public function handleError($code, $message, $file = '', $line = 0, $context = array())
+ {
+ if (!(error_reporting() & $code)) {
+ return;
+ }
+
+ $level = isset($this->errorLevelMap[$code]) ? $this->errorLevelMap[$code] : LogLevel::CRITICAL;
+ $this->logger->log($level, self::codeToString($code).': '.$message, array('code' => $code, 'message' => $message, 'file' => $file, 'line' => $line));
+
+ if ($this->previousErrorHandler === true) {
+ return false;
+ } elseif ($this->previousErrorHandler) {
+ return call_user_func($this->previousErrorHandler, $code, $message, $file, $line, $context);
+ }
+ }
+
+ /**
+ * @private
+ */
+ public function handleFatalError()
+ {
+ $this->reservedMemory = null;
+
+ $lastError = error_get_last();
+ if ($lastError && in_array($lastError['type'], self::$fatalErrors)) {
+ $this->logger->log(
+ $this->fatalLevel === null ? LogLevel::ALERT : $this->fatalLevel,
+ 'Fatal Error ('.self::codeToString($lastError['type']).'): '.$lastError['message'],
+ array('code' => $lastError['type'], 'message' => $lastError['message'], 'file' => $lastError['file'], 'line' => $lastError['line'])
+ );
+ }
+ }
+
+ private static function codeToString($code)
+ {
+ switch ($code) {
+ case E_ERROR:
+ return 'E_ERROR';
+ case E_WARNING:
+ return 'E_WARNING';
+ case E_PARSE:
+ return 'E_PARSE';
+ case E_NOTICE:
+ return 'E_NOTICE';
+ case E_CORE_ERROR:
+ return 'E_CORE_ERROR';
+ case E_CORE_WARNING:
+ return 'E_CORE_WARNING';
+ case E_COMPILE_ERROR:
+ return 'E_COMPILE_ERROR';
+ case E_COMPILE_WARNING:
+ return 'E_COMPILE_WARNING';
+ case E_USER_ERROR:
+ return 'E_USER_ERROR';
+ case E_USER_WARNING:
+ return 'E_USER_WARNING';
+ case E_USER_NOTICE:
+ return 'E_USER_NOTICE';
+ case E_STRICT:
+ return 'E_STRICT';
+ case E_RECOVERABLE_ERROR:
+ return 'E_RECOVERABLE_ERROR';
+ case E_DEPRECATED:
+ return 'E_DEPRECATED';
+ case E_USER_DEPRECATED:
+ return 'E_USER_DEPRECATED';
+ }
+
+ return 'Unknown PHP error';
+ }
+}
diff --git a/vendor/monolog/monolog/src/Monolog/Formatter/ChromePHPFormatter.php b/vendor/monolog/monolog/src/Monolog/Formatter/ChromePHPFormatter.php
new file mode 100644
index 00000000..56d3e278
--- /dev/null
+++ b/vendor/monolog/monolog/src/Monolog/Formatter/ChromePHPFormatter.php
@@ -0,0 +1,79 @@
+<?php
+
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Formatter;
+
+use Monolog\Logger;
+
+/**
+ * Formats a log message according to the ChromePHP array format
+ *
+ * @author Christophe Coevoet <stof@notk.org>
+ */
+class ChromePHPFormatter implements FormatterInterface
+{
+ /**
+ * Translates Monolog log levels to Wildfire levels.
+ */
+ private $logLevels = array(
+ Logger::DEBUG => 'log',
+ Logger::INFO => 'info',
+ Logger::NOTICE => 'info',
+ Logger::WARNING => 'warn',
+ Logger::ERROR => 'error',
+ Logger::CRITICAL => 'error',
+ Logger::ALERT => 'error',
+ Logger::EMERGENCY => 'error',
+ );
+
+ /**
+ * {@inheritdoc}
+ */
+ public function format(array $record)
+ {
+ // Retrieve the line and file if set and remove them from the formatted extra
+ $backtrace = 'unknown';
+ if (isset($record['extra']['file']) && isset($record['extra']['line'])) {
+ $backtrace = $record['extra']['file'].' : '.$record['extra']['line'];
+ unset($record['extra']['file']);
+ unset($record['extra']['line']);
+ }
+
+ $message = array('message' => $record['message']);
+ if ($record['context']) {
+ $message['context'] = $record['context'];
+ }
+ if ($record['extra']) {
+ $message['extra'] = $record['extra'];
+ }
+ if (count($message) === 1) {
+ $message = reset($message);
+ }
+
+ return array(
+ $record['channel'],
+ $message,
+ $backtrace,
+ $this->logLevels[$record['level']],
+ );
+ }
+
+ public function formatBatch(array $records)
+ {
+ $formatted = array();
+
+ foreach ($records as $record) {
+ $formatted[] = $this->format($record);
+ }
+
+ return $formatted;
+ }
+}
diff --git a/vendor/monolog/monolog/src/Monolog/Formatter/ElasticaFormatter.php b/vendor/monolog/monolog/src/Monolog/Formatter/ElasticaFormatter.php
new file mode 100644
index 00000000..b0b0cf06
--- /dev/null
+++ b/vendor/monolog/monolog/src/Monolog/Formatter/ElasticaFormatter.php
@@ -0,0 +1,87 @@
+<?php
+
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Formatter;
+
+use Elastica\Document;
+
+/**
+ * Format a log message into an Elastica Document
+ *
+ * @author Jelle Vink <jelle.vink@gmail.com>
+ */
+class ElasticaFormatter extends NormalizerFormatter
+{
+ /**
+ * @var string Elastic search index name
+ */
+ protected $index;
+
+ /**
+ * @var string Elastic search document type
+ */
+ protected $type;
+
+ /**
+ * @param string $index Elastic Search index name
+ * @param string $type Elastic Search document type
+ */
+ public function __construct($index, $type)
+ {
+ parent::__construct(\DateTime::ISO8601);
+ $this->index = $index;
+ $this->type = $type;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function format(array $record)
+ {
+ $record = parent::format($record);
+
+ return $this->getDocument($record);
+ }
+
+ /**
+ * Getter index
+ * @return string
+ */
+ public function getIndex()
+ {
+ return $this->index;
+ }
+
+ /**
+ * Getter type
+ * @return string
+ */
+ public function getType()
+ {
+ return $this->type;
+ }
+
+ /**
+ * Convert a log message into an Elastica Document
+ *
+ * @param array $record Log message
+ * @return Document
+ */
+ protected function getDocument($record)
+ {
+ $document = new Document();
+ $document->setData($record);
+ $document->setType($this->type);
+ $document->setIndex($this->index);
+
+ return $document;
+ }
+}
diff --git a/vendor/monolog/monolog/src/Monolog/Formatter/FlowdockFormatter.php b/vendor/monolog/monolog/src/Monolog/Formatter/FlowdockFormatter.php
new file mode 100644
index 00000000..af63d011
--- /dev/null
+++ b/vendor/monolog/monolog/src/Monolog/Formatter/FlowdockFormatter.php
@@ -0,0 +1,104 @@
+<?php
+
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Formatter;
+
+/**
+ * formats the record to be used in the FlowdockHandler
+ *
+ * @author Dominik Liebler <liebler.dominik@gmail.com>
+ */
+class FlowdockFormatter implements FormatterInterface
+{
+ /**
+ * @var string
+ */
+ private $source;
+
+ /**
+ * @var string
+ */
+ private $sourceEmail;
+
+ /**
+ * @param string $source
+ * @param string $sourceEmail
+ */
+ public function __construct($source, $sourceEmail)
+ {
+ $this->source = $source;
+ $this->sourceEmail = $sourceEmail;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function format(array $record)
+ {
+ $tags = array(
+ '#logs',
+ '#' . strtolower($record['level_name']),
+ '#' . $record['channel'],
+ );
+
+ foreach ($record['extra'] as $value) {
+ $tags[] = '#' . $value;
+ }
+
+ $subject = sprintf(
+ 'in %s: %s - %s',
+ $this->source,
+ $record['level_name'],
+ $this->getShortMessage($record['message'])
+ );
+
+ $record['flowdock'] = array(
+ 'source' => $this->source,
+ 'from_address' => $this->sourceEmail,
+ 'subject' => $subject,
+ 'content' => $record['message'],
+ 'tags' => $tags,
+ 'project' => $this->source,
+ );
+
+ return $record;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function formatBatch(array $records)
+ {
+ $formatted = array();
+
+ foreach ($records as $record) {
+ $formatted[] = $this->format($record);
+ }
+
+ return $formatted;
+ }
+
+ /**
+ * @param string $message
+ *
+ * @return string
+ */
+ public function getShortMessage($message)
+ {
+ $maxLength = 45;
+
+ if (strlen($message) > $maxLength) {
+ $message = substr($message, 0, $maxLength - 4) . ' ...';
+ }
+
+ return $message;
+ }
+}
diff --git a/vendor/monolog/monolog/src/Monolog/Formatter/FormatterInterface.php b/vendor/monolog/monolog/src/Monolog/Formatter/FormatterInterface.php
new file mode 100644
index 00000000..b5de7511
--- /dev/null
+++ b/vendor/monolog/monolog/src/Monolog/Formatter/FormatterInterface.php
@@ -0,0 +1,36 @@
+<?php
+
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Formatter;
+
+/**
+ * Interface for formatters
+ *
+ * @author Jordi Boggiano <j.boggiano@seld.be>
+ */
+interface FormatterInterface
+{
+ /**
+ * Formats a log record.
+ *
+ * @param array $record A record to format
+ * @return mixed The formatted record
+ */
+ public function format(array $record);
+
+ /**
+ * Formats a set of log records.
+ *
+ * @param array $records A set of records to format
+ * @return mixed The formatted set of records
+ */
+ public function formatBatch(array $records);
+}
diff --git a/vendor/monolog/monolog/src/Monolog/Formatter/GelfMessageFormatter.php b/vendor/monolog/monolog/src/Monolog/Formatter/GelfMessageFormatter.php
new file mode 100644
index 00000000..1e431750
--- /dev/null
+++ b/vendor/monolog/monolog/src/Monolog/Formatter/GelfMessageFormatter.php
@@ -0,0 +1,111 @@
+<?php
+
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Formatter;
+
+use Monolog\Logger;
+use Gelf\Message;
+
+/**
+ * Serializes a log message to GELF
+ * @see http://www.graylog2.org/about/gelf
+ *
+ * @author Matt Lehner <mlehner@gmail.com>
+ */
+class GelfMessageFormatter extends NormalizerFormatter
+{
+ /**
+ * @var string the name of the system for the Gelf log message
+ */
+ protected $systemName;
+
+ /**
+ * @var string a prefix for 'extra' fields from the Monolog record (optional)
+ */
+ protected $extraPrefix;
+
+ /**
+ * @var string a prefix for 'context' fields from the Monolog record (optional)
+ */
+ protected $contextPrefix;
+
+ /**
+ * Translates Monolog log levels to Graylog2 log priorities.
+ */
+ private $logLevels = array(
+ Logger::DEBUG => 7,
+ Logger::INFO => 6,
+ Logger::NOTICE => 5,
+ Logger::WARNING => 4,
+ Logger::ERROR => 3,
+ Logger::CRITICAL => 2,
+ Logger::ALERT => 1,
+ Logger::EMERGENCY => 0,
+ );
+
+ public function __construct($systemName = null, $extraPrefix = null, $contextPrefix = 'ctxt_')
+ {
+ parent::__construct('U.u');
+
+ $this->systemName = $systemName ?: gethostname();
+
+ $this->extraPrefix = $extraPrefix;
+ $this->contextPrefix = $contextPrefix;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function format(array $record)
+ {
+ $record = parent::format($record);
+
+ if (!isset($record['datetime'], $record['message'], $record['level'])) {
+ throw new \InvalidArgumentException('The record should at least contain datetime, message and level keys, '.var_export($record, true).' given');
+ }
+
+ $message = new Message();
+ $message
+ ->setTimestamp($record['datetime'])
+ ->setShortMessage((string) $record['message'])
+ ->setHost($this->systemName)
+ ->setLevel($this->logLevels[$record['level']]);
+
+ if (isset($record['channel'])) {
+ $message->setFacility($record['channel']);
+ }
+ if (isset($record['extra']['line'])) {
+ $message->setLine($record['extra']['line']);
+ unset($record['extra']['line']);
+ }
+ if (isset($record['extra']['file'])) {
+ $message->setFile($record['extra']['file']);
+ unset($record['extra']['file']);
+ }
+
+ foreach ($record['extra'] as $key => $val) {
+ $message->setAdditional($this->extraPrefix . $key, is_scalar($val) ? $val : $this->toJson($val));
+ }
+
+ foreach ($record['context'] as $key => $val) {
+ $message->setAdditional($this->contextPrefix . $key, is_scalar($val) ? $val : $this->toJson($val));
+ }
+
+ if (null === $message->getFile() && isset($record['context']['exception']['file'])) {
+ if (preg_match("/^(.+):([0-9]+)$/", $record['context']['exception']['file'], $matches)) {
+ $message->setFile($matches[1]);
+ $message->setLine($matches[2]);
+ }
+ }
+
+ return $message;
+ }
+}
diff --git a/vendor/monolog/monolog/src/Monolog/Formatter/HtmlFormatter.php b/vendor/monolog/monolog/src/Monolog/Formatter/HtmlFormatter.php
new file mode 100644
index 00000000..255d2887
--- /dev/null
+++ b/vendor/monolog/monolog/src/Monolog/Formatter/HtmlFormatter.php
@@ -0,0 +1,140 @@
+<?php
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Formatter;
+
+use Monolog\Logger;
+
+/**
+ * Formats incoming records into an HTML table
+ *
+ * This is especially useful for html email logging
+ *
+ * @author Tiago Brito <tlfbrito@gmail.com>
+ */
+class HtmlFormatter extends NormalizerFormatter
+{
+ /**
+ * Translates Monolog log levels to html color priorities.
+ */
+ private $logLevels = array(
+ Logger::DEBUG => '#cccccc',
+ Logger::INFO => '#468847',
+ Logger::NOTICE => '#3a87ad',
+ Logger::WARNING => '#c09853',
+ Logger::ERROR => '#f0ad4e',
+ Logger::CRITICAL => '#FF7708',
+ Logger::ALERT => '#C12A19',
+ Logger::EMERGENCY => '#000000',
+ );
+
+ /**
+ * @param string $dateFormat The format of the timestamp: one supported by DateTime::format
+ */
+ public function __construct($dateFormat = null)
+ {
+ parent::__construct($dateFormat);
+ }
+
+ /**
+ * Creates an HTML table row
+ *
+ * @param string $th Row header content
+ * @param string $td Row standard cell content
+ * @param bool $escapeTd false if td content must not be html escaped
+ * @return string
+ */
+ private function addRow($th, $td = ' ', $escapeTd = true)
+ {
+ $th = htmlspecialchars($th, ENT_NOQUOTES, 'UTF-8');
+ if ($escapeTd) {
+ $td = '<pre>'.htmlspecialchars($td, ENT_NOQUOTES, 'UTF-8').'</pre>';
+ }
+
+ return "<tr style=\"padding: 4px;spacing: 0;text-align: left;\">\n<th style=\"background: #cccccc\" width=\"100px\">$th:</th>\n<td style=\"padding: 4px;spacing: 0;text-align: left;background: #eeeeee\">".$td."</td>\n</tr>";
+ }
+
+ /**
+ * Create a HTML h1 tag
+ *
+ * @param string $title Text to be in the h1
+ * @param integer $level Error level
+ * @return string
+ */
+ private function addTitle($title, $level)
+ {
+ $title = htmlspecialchars($title, ENT_NOQUOTES, 'UTF-8');
+
+ return '<h1 style="background: '.$this->logLevels[$level].';color: #ffffff;padding: 5px;" class="monolog-output">'.$title.'</h1>';
+ }
+ /**
+ * Formats a log record.
+ *
+ * @param array $record A record to format
+ * @return mixed The formatted record
+ */
+ public function format(array $record)
+ {
+ $output = $this->addTitle($record['level_name'], $record['level']);
+ $output .= '<table cellspacing="1" width="100%" class="monolog-output">';
+
+ $output .= $this->addRow('Message', (string) $record['message']);
+ $output .= $this->addRow('Time', $record['datetime']->format($this->dateFormat));
+ $output .= $this->addRow('Channel', $record['channel']);
+ if ($record['context']) {
+ $embeddedTable = '<table cellspacing="1" width="100%">';
+ foreach ($record['context'] as $key => $value) {
+ $embeddedTable .= $this->addRow($key, $this->convertToString($value));
+ }
+ $embeddedTable .= '</table>';
+ $output .= $this->addRow('Context', $embeddedTable, false);
+ }
+ if ($record['extra']) {
+ $embeddedTable = '<table cellspacing="1" width="100%">';
+ foreach ($record['extra'] as $key => $value) {
+ $embeddedTable .= $this->addRow($key, $this->convertToString($value));
+ }
+ $embeddedTable .= '</table>';
+ $output .= $this->addRow('Extra', $embeddedTable, false);
+ }
+
+ return $output.'</table>';
+ }
+
+ /**
+ * Formats a set of log records.
+ *
+ * @param array $records A set of records to format
+ * @return mixed The formatted set of records
+ */
+ public function formatBatch(array $records)
+ {
+ $message = '';
+ foreach ($records as $record) {
+ $message .= $this->format($record);
+ }
+
+ return $message;
+ }
+
+ protected function convertToString($data)
+ {
+ if (null === $data || is_scalar($data)) {
+ return (string) $data;
+ }
+
+ $data = $this->normalize($data);
+ if (version_compare(PHP_VERSION, '5.4.0', '>=')) {
+ return json_encode($data, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);
+ }
+
+ return str_replace('\\/', '/', json_encode($data));
+ }
+}
diff --git a/vendor/monolog/monolog/src/Monolog/Formatter/JsonFormatter.php b/vendor/monolog/monolog/src/Monolog/Formatter/JsonFormatter.php
new file mode 100644
index 00000000..e5a1d2c4
--- /dev/null
+++ b/vendor/monolog/monolog/src/Monolog/Formatter/JsonFormatter.php
@@ -0,0 +1,116 @@
+<?php
+
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Formatter;
+
+/**
+ * Encodes whatever record data is passed to it as json
+ *
+ * This can be useful to log to databases or remote APIs
+ *
+ * @author Jordi Boggiano <j.boggiano@seld.be>
+ */
+class JsonFormatter implements FormatterInterface
+{
+ const BATCH_MODE_JSON = 1;
+ const BATCH_MODE_NEWLINES = 2;
+
+ protected $batchMode;
+ protected $appendNewline;
+
+ /**
+ * @param int $batchMode
+ */
+ public function __construct($batchMode = self::BATCH_MODE_JSON, $appendNewline = true)
+ {
+ $this->batchMode = $batchMode;
+ $this->appendNewline = $appendNewline;
+ }
+
+ /**
+ * The batch mode option configures the formatting style for
+ * multiple records. By default, multiple records will be
+ * formatted as a JSON-encoded array. However, for
+ * compatibility with some API endpoints, alternative styles
+ * are available.
+ *
+ * @return int
+ */
+ public function getBatchMode()
+ {
+ return $this->batchMode;
+ }
+
+ /**
+ * True if newlines are appended to every formatted record
+ *
+ * @return bool
+ */
+ public function isAppendingNewlines()
+ {
+ return $this->appendNewline;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function format(array $record)
+ {
+ return json_encode($record) . ($this->appendNewline ? "\n" : '');
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function formatBatch(array $records)
+ {
+ switch ($this->batchMode) {
+ case static::BATCH_MODE_NEWLINES:
+ return $this->formatBatchNewlines($records);
+
+ case static::BATCH_MODE_JSON:
+ default:
+ return $this->formatBatchJson($records);
+ }
+ }
+
+ /**
+ * Return a JSON-encoded array of records.
+ *
+ * @param array $records
+ * @return string
+ */
+ protected function formatBatchJson(array $records)
+ {
+ return json_encode($records);
+ }
+
+ /**
+ * Use new lines to separate records instead of a
+ * JSON-encoded array.
+ *
+ * @param array $records
+ * @return string
+ */
+ protected function formatBatchNewlines(array $records)
+ {
+ $instance = $this;
+
+ $oldNewline = $this->appendNewline;
+ $this->appendNewline = false;
+ array_walk($records, function (&$value, $key) use ($instance) {
+ $value = $instance->format($value);
+ });
+ $this->appendNewline = $oldNewline;
+
+ return implode("\n", $records);
+ }
+}
diff --git a/vendor/monolog/monolog/src/Monolog/Formatter/LineFormatter.php b/vendor/monolog/monolog/src/Monolog/Formatter/LineFormatter.php
new file mode 100644
index 00000000..388e2266
--- /dev/null
+++ b/vendor/monolog/monolog/src/Monolog/Formatter/LineFormatter.php
@@ -0,0 +1,159 @@
+<?php
+
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Formatter;
+
+use Exception;
+
+/**
+ * Formats incoming records into a one-line string
+ *
+ * This is especially useful for logging to files
+ *
+ * @author Jordi Boggiano <j.boggiano@seld.be>
+ * @author Christophe Coevoet <stof@notk.org>
+ */
+class LineFormatter extends NormalizerFormatter
+{
+ const SIMPLE_FORMAT = "[%datetime%] %channel%.%level_name%: %message% %context% %extra%\n";
+
+ protected $format;
+ protected $allowInlineLineBreaks;
+ protected $ignoreEmptyContextAndExtra;
+ protected $includeStacktraces;
+
+ /**
+ * @param string $format The format of the message
+ * @param string $dateFormat The format of the timestamp: one supported by DateTime::format
+ * @param bool $allowInlineLineBreaks Whether to allow inline line breaks in log entries
+ * @param bool $ignoreEmptyContextAndExtra
+ */
+ public function __construct($format = null, $dateFormat = null, $allowInlineLineBreaks = false, $ignoreEmptyContextAndExtra = false)
+ {
+ $this->format = $format ?: static::SIMPLE_FORMAT;
+ $this->allowInlineLineBreaks = $allowInlineLineBreaks;
+ $this->ignoreEmptyContextAndExtra = $ignoreEmptyContextAndExtra;
+ parent::__construct($dateFormat);
+ }
+
+ public function includeStacktraces($include = true)
+ {
+ $this->includeStacktraces = $include;
+ if ($this->includeStacktraces) {
+ $this->allowInlineLineBreaks = true;
+ }
+ }
+
+ public function allowInlineLineBreaks($allow = true)
+ {
+ $this->allowInlineLineBreaks = $allow;
+ }
+
+ public function ignoreEmptyContextAndExtra($ignore = true)
+ {
+ $this->ignoreEmptyContextAndExtra = $ignore;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function format(array $record)
+ {
+ $vars = parent::format($record);
+
+ $output = $this->format;
+
+ foreach ($vars['extra'] as $var => $val) {
+ if (false !== strpos($output, '%extra.'.$var.'%')) {
+ $output = str_replace('%extra.'.$var.'%', $this->stringify($val), $output);
+ unset($vars['extra'][$var]);
+ }
+ }
+
+ if ($this->ignoreEmptyContextAndExtra) {
+ if (empty($vars['context'])) {
+ unset($vars['context']);
+ $output = str_replace('%context%', '', $output);
+ }
+
+ if (empty($vars['extra'])) {
+ unset($vars['extra']);
+ $output = str_replace('%extra%', '', $output);
+ }
+ }
+
+ foreach ($vars as $var => $val) {
+ if (false !== strpos($output, '%'.$var.'%')) {
+ $output = str_replace('%'.$var.'%', $this->stringify($val), $output);
+ }
+ }
+
+ return $output;
+ }
+
+ public function formatBatch(array $records)
+ {
+ $message = '';
+ foreach ($records as $record) {
+ $message .= $this->format($record);
+ }
+
+ return $message;
+ }
+
+ public function stringify($value)
+ {
+ return $this->replaceNewlines($this->convertToString($value));
+ }
+
+ protected function normalizeException(Exception $e)
+ {
+ $previousText = '';
+ if ($previous = $e->getPrevious()) {
+ do {
+ $previousText .= ', '.get_class($previous).'(code: '.$previous->getCode().'): '.$previous->getMessage().' at '.$previous->getFile().':'.$previous->getLine();
+ } while ($previous = $previous->getPrevious());
+ }
+
+ $str = '[object] ('.get_class($e).'(code: '.$e->getCode().'): '.$e->getMessage().' at '.$e->getFile().':'.$e->getLine().$previousText.')';
+ if ($this->includeStacktraces) {
+ $str .= "\n[stacktrace]\n".$e->getTraceAsString();
+ }
+
+ return $str;
+ }
+
+ protected function convertToString($data)
+ {
+ if (null === $data || is_bool($data)) {
+ return var_export($data, true);
+ }
+
+ if (is_scalar($data)) {
+ return (string) $data;
+ }
+
+ if (version_compare(PHP_VERSION, '5.4.0', '>=')) {
+ return $this->toJson($data, true);
+ }
+
+ return str_replace('\\/', '/', @json_encode($data));
+ }
+
+ protected function replaceNewlines($str)
+ {
+ if ($this->allowInlineLineBreaks) {
+ return $str;
+ }
+
+ return str_replace(array("\r\n", "\r", "\n"), ' ', $str);
+ }
+}
diff --git a/vendor/monolog/monolog/src/Monolog/Formatter/LogglyFormatter.php b/vendor/monolog/monolog/src/Monolog/Formatter/LogglyFormatter.php
new file mode 100644
index 00000000..f02bceb0
--- /dev/null
+++ b/vendor/monolog/monolog/src/Monolog/Formatter/LogglyFormatter.php
@@ -0,0 +1,47 @@
+<?php
+
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Formatter;
+
+/**
+ * Encodes message information into JSON in a format compatible with Loggly.
+ *
+ * @author Adam Pancutt <adam@pancutt.com>
+ */
+class LogglyFormatter extends JsonFormatter
+{
+ /**
+ * Overrides the default batch mode to new lines for compatibility with the
+ * Loggly bulk API.
+ *
+ * @param integer $batchMode
+ */
+ public function __construct($batchMode = self::BATCH_MODE_NEWLINES, $appendNewline = false)
+ {
+ parent::__construct($batchMode, $appendNewline);
+ }
+
+ /**
+ * Appends the 'timestamp' parameter for indexing by Loggly.
+ *
+ * @see https://www.loggly.com/docs/automated-parsing/#json
+ * @see \Monolog\Formatter\JsonFormatter::format()
+ */
+ public function format(array $record)
+ {
+ if (isset($record["datetime"]) && ($record["datetime"] instanceof \DateTime)) {
+ $record["timestamp"] = $record["datetime"]->format("Y-m-d\TH:i:s.uO");
+ // TODO 2.0 unset the 'datetime' parameter, retained for BC
+ }
+
+ return parent::format($record);
+ }
+}
diff --git a/vendor/monolog/monolog/src/Monolog/Formatter/LogstashFormatter.php b/vendor/monolog/monolog/src/Monolog/Formatter/LogstashFormatter.php
new file mode 100644
index 00000000..7a7b3b3c
--- /dev/null
+++ b/vendor/monolog/monolog/src/Monolog/Formatter/LogstashFormatter.php
@@ -0,0 +1,165 @@
+<?php
+
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Formatter;
+
+/**
+ * Serializes a log message to Logstash Event Format
+ *
+ * @see http://logstash.net/
+ * @see https://github.com/logstash/logstash/blob/master/lib/logstash/event.rb
+ *
+ * @author Tim Mower <timothy.mower@gmail.com>
+ */
+class LogstashFormatter extends NormalizerFormatter
+{
+ const V0 = 0;
+ const V1 = 1;
+
+ /**
+ * @var string the name of the system for the Logstash log message, used to fill the @source field
+ */
+ protected $systemName;
+
+ /**
+ * @var string an application name for the Logstash log message, used to fill the @type field
+ */
+ protected $applicationName;
+
+ /**
+ * @var string a prefix for 'extra' fields from the Monolog record (optional)
+ */
+ protected $extraPrefix;
+
+ /**
+ * @var string a prefix for 'context' fields from the Monolog record (optional)
+ */
+ protected $contextPrefix;
+
+ /**
+ * @var integer logstash format version to use
+ */
+ protected $version;
+
+ /**
+ * @param string $applicationName the application that sends the data, used as the "type" field of logstash
+ * @param string $systemName the system/machine name, used as the "source" field of logstash, defaults to the hostname of the machine
+ * @param string $extraPrefix prefix for extra keys inside logstash "fields"
+ * @param string $contextPrefix prefix for context keys inside logstash "fields", defaults to ctxt_
+ */
+ public function __construct($applicationName, $systemName = null, $extraPrefix = null, $contextPrefix = 'ctxt_', $version = self::V0)
+ {
+ // logstash requires a ISO 8601 format date with optional millisecond precision.
+ parent::__construct('Y-m-d\TH:i:s.uP');
+
+ $this->systemName = $systemName ?: gethostname();
+ $this->applicationName = $applicationName;
+ $this->extraPrefix = $extraPrefix;
+ $this->contextPrefix = $contextPrefix;
+ $this->version = $version;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function format(array $record)
+ {
+ $record = parent::format($record);
+
+ if ($this->version === self::V1) {
+ $message = $this->formatV1($record);
+ } else {
+ $message = $this->formatV0($record);
+ }
+
+ return $this->toJson($message) . "\n";
+ }
+
+ protected function formatV0(array $record)
+ {
+ if (empty($record['datetime'])) {
+ $record['datetime'] = gmdate('c');
+ }
+ $message = array(
+ '@timestamp' => $record['datetime'],
+ '@source' => $this->systemName,
+ '@fields' => array()
+ );
+ if (isset($record['message'])) {
+ $message['@message'] = $record['message'];
+ }
+ if (isset($record['channel'])) {
+ $message['@tags'] = array($record['channel']);
+ $message['@fields']['channel'] = $record['channel'];
+ }
+ if (isset($record['level'])) {
+ $message['@fields']['level'] = $record['level'];
+ }
+ if ($this->applicationName) {
+ $message['@type'] = $this->applicationName;
+ }
+ if (isset($record['extra']['server'])) {
+ $message['@source_host'] = $record['extra']['server'];
+ }
+ if (isset($record['extra']['url'])) {
+ $message['@source_path'] = $record['extra']['url'];
+ }
+ if (!empty($record['extra'])) {
+ foreach ($record['extra'] as $key => $val) {
+ $message['@fields'][$this->extraPrefix . $key] = $val;
+ }
+ }
+ if (!empty($record['context'])) {
+ foreach ($record['context'] as $key => $val) {
+ $message['@fields'][$this->contextPrefix . $key] = $val;
+ }
+ }
+
+ return $message;
+ }
+
+ protected function formatV1(array $record)
+ {
+ if (empty($record['datetime'])) {
+ $record['datetime'] = gmdate('c');
+ }
+ $message = array(
+ '@timestamp' => $record['datetime'],
+ '@version' => 1,
+ 'host' => $this->systemName,
+ );
+ if (isset($record['message'])) {
+ $message['message'] = $record['message'];
+ }
+ if (isset($record['channel'])) {
+ $message['type'] = $record['channel'];
+ $message['channel'] = $record['channel'];
+ }
+ if (isset($record['level_name'])) {
+ $message['level'] = $record['level_name'];
+ }
+ if ($this->applicationName) {
+ $message['type'] = $this->applicationName;
+ }
+ if (!empty($record['extra'])) {
+ foreach ($record['extra'] as $key => $val) {
+ $message[$this->extraPrefix . $key] = $val;
+ }
+ }
+ if (!empty($record['context'])) {
+ foreach ($record['context'] as $key => $val) {
+ $message[$this->contextPrefix . $key] = $val;
+ }
+ }
+
+ return $message;
+ }
+}
diff --git a/vendor/monolog/monolog/src/Monolog/Formatter/MongoDBFormatter.php b/vendor/monolog/monolog/src/Monolog/Formatter/MongoDBFormatter.php
new file mode 100644
index 00000000..eb067bb7
--- /dev/null
+++ b/vendor/monolog/monolog/src/Monolog/Formatter/MongoDBFormatter.php
@@ -0,0 +1,105 @@
+<?php
+
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Formatter;
+
+/**
+ * Formats a record for use with the MongoDBHandler.
+ *
+ * @author Florian Plattner <me@florianplattner.de>
+ */
+class MongoDBFormatter implements FormatterInterface
+{
+ private $exceptionTraceAsString;
+ private $maxNestingLevel;
+
+ /**
+ * @param int $maxNestingLevel 0 means infinite nesting, the $record itself is level 1, $record['context'] is 2
+ * @param bool $exceptionTraceAsString set to false to log exception traces as a sub documents instead of strings
+ */
+ public function __construct($maxNestingLevel = 3, $exceptionTraceAsString = true)
+ {
+ $this->maxNestingLevel = max($maxNestingLevel, 0);
+ $this->exceptionTraceAsString = (bool) $exceptionTraceAsString;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function format(array $record)
+ {
+ return $this->formatArray($record);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function formatBatch(array $records)
+ {
+ foreach ($records as $key => $record) {
+ $records[$key] = $this->format($record);
+ }
+
+ return $records;
+ }
+
+ protected function formatArray(array $record, $nestingLevel = 0)
+ {
+ if ($this->maxNestingLevel == 0 || $nestingLevel <= $this->maxNestingLevel) {
+ foreach ($record as $name => $value) {
+ if ($value instanceof \DateTime) {
+ $record[$name] = $this->formatDate($value, $nestingLevel + 1);
+ } elseif ($value instanceof \Exception) {
+ $record[$name] = $this->formatException($value, $nestingLevel + 1);
+ } elseif (is_array($value)) {
+ $record[$name] = $this->formatArray($value, $nestingLevel + 1);
+ } elseif (is_object($value)) {
+ $record[$name] = $this->formatObject($value, $nestingLevel + 1);
+ }
+ }
+ } else {
+ $record = '[...]';
+ }
+
+ return $record;
+ }
+
+ protected function formatObject($value, $nestingLevel)
+ {
+ $objectVars = get_object_vars($value);
+ $objectVars['class'] = get_class($value);
+
+ return $this->formatArray($objectVars, $nestingLevel);
+ }
+
+ protected function formatException(\Exception $exception, $nestingLevel)
+ {
+ $formattedException = array(
+ 'class' => get_class($exception),
+ 'message' => $exception->getMessage(),
+ 'code' => $exception->getCode(),
+ 'file' => $exception->getFile() . ':' . $exception->getLine(),
+ );
+
+ if ($this->exceptionTraceAsString === true) {
+ $formattedException['trace'] = $exception->getTraceAsString();
+ } else {
+ $formattedException['trace'] = $exception->getTrace();
+ }
+
+ return $this->formatArray($formattedException, $nestingLevel);
+ }
+
+ protected function formatDate(\DateTime $value, $nestingLevel)
+ {
+ return new \MongoDate($value->getTimestamp());
+ }
+}
diff --git a/vendor/monolog/monolog/src/Monolog/Formatter/NormalizerFormatter.php b/vendor/monolog/monolog/src/Monolog/Formatter/NormalizerFormatter.php
new file mode 100644
index 00000000..46bf41b3
--- /dev/null
+++ b/vendor/monolog/monolog/src/Monolog/Formatter/NormalizerFormatter.php
@@ -0,0 +1,158 @@
+<?php
+
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Formatter;
+
+use Exception;
+
+/**
+ * Normalizes incoming records to remove objects/resources so it's easier to dump to various targets
+ *
+ * @author Jordi Boggiano <j.boggiano@seld.be>
+ */
+class NormalizerFormatter implements FormatterInterface
+{
+ const SIMPLE_DATE = "Y-m-d H:i:s";
+
+ protected $dateFormat;
+
+ /**
+ * @param string $dateFormat The format of the timestamp: one supported by DateTime::format
+ */
+ public function __construct($dateFormat = null)
+ {
+ $this->dateFormat = $dateFormat ?: static::SIMPLE_DATE;
+ if (!function_exists('json_encode')) {
+ throw new \RuntimeException('PHP\'s json extension is required to use Monolog\'s NormalizerFormatter');
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function format(array $record)
+ {
+ return $this->normalize($record);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function formatBatch(array $records)
+ {
+ foreach ($records as $key => $record) {
+ $records[$key] = $this->format($record);
+ }
+
+ return $records;
+ }
+
+ protected function normalize($data)
+ {
+ if (null === $data || is_scalar($data)) {
+ if (is_float($data)) {
+ if (is_infinite($data)) {
+ return ($data > 0 ? '' : '-') . 'INF';
+ }
+ if (is_nan($data)) {
+ return 'NaN';
+ }
+ }
+
+ return $data;
+ }
+
+ if (is_array($data) || $data instanceof \Traversable) {
+ $normalized = array();
+
+ $count = 1;
+ foreach ($data as $key => $value) {
+ if ($count++ >= 1000) {
+ $normalized['...'] = 'Over 1000 items, aborting normalization';
+ break;
+ }
+ $normalized[$key] = $this->normalize($value);
+ }
+
+ return $normalized;
+ }
+
+ if ($data instanceof \DateTime) {
+ return $data->format($this->dateFormat);
+ }
+
+ if (is_object($data)) {
+ if ($data instanceof Exception) {
+ return $this->normalizeException($data);
+ }
+
+ // non-serializable objects that implement __toString stringified
+ if (method_exists($data, '__toString') && !$data instanceof \JsonSerializable) {
+ $value = (string) $data;
+ } else {
+ // the rest is json-serialized in some way
+ $value = $this->toJson($data, true);
+ }
+
+ return sprintf("[object] (%s: %s)", get_class($data), $value);
+ }
+
+ if (is_resource($data)) {
+ return '[resource]';
+ }
+
+ return '[unknown('.gettype($data).')]';
+ }
+
+ protected function normalizeException(Exception $e)
+ {
+ $data = array(
+ 'class' => get_class($e),
+ 'message' => $e->getMessage(),
+ 'code' => $e->getCode(),
+ 'file' => $e->getFile().':'.$e->getLine(),
+ );
+
+ $trace = $e->getTrace();
+ foreach ($trace as $frame) {
+ if (isset($frame['file'])) {
+ $data['trace'][] = $frame['file'].':'.$frame['line'];
+ } else {
+ // We should again normalize the frames, because it might contain invalid items
+ $data['trace'][] = $this->toJson($this->normalize($frame), true);
+ }
+ }
+
+ if ($previous = $e->getPrevious()) {
+ $data['previous'] = $this->normalizeException($previous);
+ }
+
+ return $data;
+ }
+
+ protected function toJson($data, $ignoreErrors = false)
+ {
+ // suppress json_encode errors since it's twitchy with some inputs
+ if ($ignoreErrors) {
+ if (version_compare(PHP_VERSION, '5.4.0', '>=')) {
+ return @json_encode($data, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);
+ }
+
+ return @json_encode($data);
+ }
+
+ if (version_compare(PHP_VERSION, '5.4.0', '>=')) {
+ return json_encode($data, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);
+ }
+
+ return json_encode($data);
+ }
+}
diff --git a/vendor/monolog/monolog/src/Monolog/Formatter/ScalarFormatter.php b/vendor/monolog/monolog/src/Monolog/Formatter/ScalarFormatter.php
new file mode 100644
index 00000000..5d345d53
--- /dev/null
+++ b/vendor/monolog/monolog/src/Monolog/Formatter/ScalarFormatter.php
@@ -0,0 +1,48 @@
+<?php
+
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Formatter;
+
+/**
+ * Formats data into an associative array of scalar values.
+ * Objects and arrays will be JSON encoded.
+ *
+ * @author Andrew Lawson <adlawson@gmail.com>
+ */
+class ScalarFormatter extends NormalizerFormatter
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function format(array $record)
+ {
+ foreach ($record as $key => $value) {
+ $record[$key] = $this->normalizeValue($value);
+ }
+
+ return $record;
+ }
+
+ /**
+ * @param mixed $value
+ * @return mixed
+ */
+ protected function normalizeValue($value)
+ {
+ $normalized = $this->normalize($value);
+
+ if (is_array($normalized) || is_object($normalized)) {
+ return $this->toJson($normalized, true);
+ }
+
+ return $normalized;
+ }
+}
diff --git a/vendor/monolog/monolog/src/Monolog/Formatter/WildfireFormatter.php b/vendor/monolog/monolog/src/Monolog/Formatter/WildfireFormatter.php
new file mode 100644
index 00000000..654710a8
--- /dev/null
+++ b/vendor/monolog/monolog/src/Monolog/Formatter/WildfireFormatter.php
@@ -0,0 +1,113 @@
+<?php
+
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Formatter;
+
+use Monolog\Logger;
+
+/**
+ * Serializes a log message according to Wildfire's header requirements
+ *
+ * @author Eric Clemmons (@ericclemmons) <eric@uxdriven.com>
+ * @author Christophe Coevoet <stof@notk.org>
+ * @author Kirill chEbba Chebunin <iam@chebba.org>
+ */
+class WildfireFormatter extends NormalizerFormatter
+{
+ const TABLE = 'table';
+
+ /**
+ * Translates Monolog log levels to Wildfire levels.
+ */
+ private $logLevels = array(
+ Logger::DEBUG => 'LOG',
+ Logger::INFO => 'INFO',
+ Logger::NOTICE => 'INFO',
+ Logger::WARNING => 'WARN',
+ Logger::ERROR => 'ERROR',
+ Logger::CRITICAL => 'ERROR',
+ Logger::ALERT => 'ERROR',
+ Logger::EMERGENCY => 'ERROR',
+ );
+
+ /**
+ * {@inheritdoc}
+ */
+ public function format(array $record)
+ {
+ // Retrieve the line and file if set and remove them from the formatted extra
+ $file = $line = '';
+ if (isset($record['extra']['file'])) {
+ $file = $record['extra']['file'];
+ unset($record['extra']['file']);
+ }
+ if (isset($record['extra']['line'])) {
+ $line = $record['extra']['line'];
+ unset($record['extra']['line']);
+ }
+
+ $record = $this->normalize($record);
+ $message = array('message' => $record['message']);
+ $handleError = false;
+ if ($record['context']) {
+ $message['context'] = $record['context'];
+ $handleError = true;
+ }
+ if ($record['extra']) {
+ $message['extra'] = $record['extra'];
+ $handleError = true;
+ }
+ if (count($message) === 1) {
+ $message = reset($message);
+ }
+
+ if (isset($record['context'][self::TABLE])) {
+ $type = 'TABLE';
+ $label = $record['channel'] .': '. $record['message'];
+ $message = $record['context'][self::TABLE];
+ } else {
+ $type = $this->logLevels[$record['level']];
+ $label = $record['channel'];
+ }
+
+ // Create JSON object describing the appearance of the message in the console
+ $json = $this->toJson(array(
+ array(
+ 'Type' => $type,
+ 'File' => $file,
+ 'Line' => $line,
+ 'Label' => $label,
+ ),
+ $message,
+ ), $handleError);
+
+ // The message itself is a serialization of the above JSON object + it's length
+ return sprintf(
+ '%s|%s|',
+ strlen($json),
+ $json
+ );
+ }
+
+ public function formatBatch(array $records)
+ {
+ throw new \BadMethodCallException('Batch formatting does not make sense for the WildfireFormatter');
+ }
+
+ protected function normalize($data)
+ {
+ if (is_object($data) && !$data instanceof \DateTime) {
+ return $data;
+ }
+
+ return parent::normalize($data);
+ }
+}
diff --git a/vendor/monolog/monolog/src/Monolog/Handler/AbstractHandler.php b/vendor/monolog/monolog/src/Monolog/Handler/AbstractHandler.php
new file mode 100644
index 00000000..69ede49a
--- /dev/null
+++ b/vendor/monolog/monolog/src/Monolog/Handler/AbstractHandler.php
@@ -0,0 +1,184 @@
+<?php
+
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Handler;
+
+use Monolog\Logger;
+use Monolog\Formatter\FormatterInterface;
+use Monolog\Formatter\LineFormatter;
+
+/**
+ * Base Handler class providing the Handler structure
+ *
+ * @author Jordi Boggiano <j.boggiano@seld.be>
+ */
+abstract class AbstractHandler implements HandlerInterface
+{
+ protected $level = Logger::DEBUG;
+ protected $bubble = true;
+
+ /**
+ * @var FormatterInterface
+ */
+ protected $formatter;
+ protected $processors = array();
+
+ /**
+ * @param integer $level The minimum logging level at which this handler will be triggered
+ * @param Boolean $bubble Whether the messages that are handled can bubble up the stack or not
+ */
+ public function __construct($level = Logger::DEBUG, $bubble = true)
+ {
+ $this->setLevel($level);
+ $this->bubble = $bubble;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function isHandling(array $record)
+ {
+ return $record['level'] >= $this->level;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function handleBatch(array $records)
+ {
+ foreach ($records as $record) {
+ $this->handle($record);
+ }
+ }
+
+ /**
+ * Closes the handler.
+ *
+ * This will be called automatically when the object is destroyed
+ */
+ public function close()
+ {
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function pushProcessor($callback)
+ {
+ if (!is_callable($callback)) {
+ throw new \InvalidArgumentException('Processors must be valid callables (callback or object with an __invoke method), '.var_export($callback, true).' given');
+ }
+ array_unshift($this->processors, $callback);
+
+ return $this;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function popProcessor()
+ {
+ if (!$this->processors) {
+ throw new \LogicException('You tried to pop from an empty processor stack.');
+ }
+
+ return array_shift($this->processors);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function setFormatter(FormatterInterface $formatter)
+ {
+ $this->formatter = $formatter;
+
+ return $this;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getFormatter()
+ {
+ if (!$this->formatter) {
+ $this->formatter = $this->getDefaultFormatter();
+ }
+
+ return $this->formatter;
+ }
+
+ /**
+ * Sets minimum logging level at which this handler will be triggered.
+ *
+ * @param integer $level
+ * @return self
+ */
+ public function setLevel($level)
+ {
+ $this->level = Logger::toMonologLevel($level);
+
+ return $this;
+ }
+
+ /**
+ * Gets minimum logging level at which this handler will be triggered.
+ *
+ * @return integer
+ */
+ public function getLevel()
+ {
+ return $this->level;
+ }
+
+ /**
+ * Sets the bubbling behavior.
+ *
+ * @param Boolean $bubble true means that this handler allows bubbling.
+ * false means that bubbling is not permitted.
+ * @return self
+ */
+ public function setBubble($bubble)
+ {
+ $this->bubble = $bubble;
+
+ return $this;
+ }
+
+ /**
+ * Gets the bubbling behavior.
+ *
+ * @return Boolean true means that this handler allows bubbling.
+ * false means that bubbling is not permitted.
+ */
+ public function getBubble()
+ {
+ return $this->bubble;
+ }
+
+ public function __destruct()
+ {
+ try {
+ $this->close();
+ } catch (\Exception $e) {
+ // do nothing
+ }
+ }
+
+ /**
+ * Gets the default formatter.
+ *
+ * @return FormatterInterface
+ */
+ protected function getDefaultFormatter()
+ {
+ return new LineFormatter();
+ }
+}
diff --git a/vendor/monolog/monolog/src/Monolog/Handler/AbstractProcessingHandler.php b/vendor/monolog/monolog/src/Monolog/Handler/AbstractProcessingHandler.php
new file mode 100644
index 00000000..6f18f72e
--- /dev/null
+++ b/vendor/monolog/monolog/src/Monolog/Handler/AbstractProcessingHandler.php
@@ -0,0 +1,66 @@
+<?php
+
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Handler;
+
+/**
+ * Base Handler class providing the Handler structure
+ *
+ * Classes extending it should (in most cases) only implement write($record)
+ *
+ * @author Jordi Boggiano <j.boggiano@seld.be>
+ * @author Christophe Coevoet <stof@notk.org>
+ */
+abstract class AbstractProcessingHandler extends AbstractHandler
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function handle(array $record)
+ {
+ if (!$this->isHandling($record)) {
+ return false;
+ }
+
+ $record = $this->processRecord($record);
+
+ $record['formatted'] = $this->getFormatter()->format($record);
+
+ $this->write($record);
+
+ return false === $this->bubble;
+ }
+
+ /**
+ * Writes the record down to the log of the implementing handler
+ *
+ * @param array $record
+ * @return void
+ */
+ abstract protected function write(array $record);
+
+ /**
+ * Processes a record.
+ *
+ * @param array $record
+ * @return array
+ */
+ protected function processRecord(array $record)
+ {
+ if ($this->processors) {
+ foreach ($this->processors as $processor) {
+ $record = call_user_func($processor, $record);
+ }
+ }
+
+ return $record;
+ }
+}
diff --git a/vendor/monolog/monolog/src/Monolog/Handler/AbstractSyslogHandler.php b/vendor/monolog/monolog/src/Monolog/Handler/AbstractSyslogHandler.php
new file mode 100644
index 00000000..3eb83bd4
--- /dev/null
+++ b/vendor/monolog/monolog/src/Monolog/Handler/AbstractSyslogHandler.php
@@ -0,0 +1,92 @@
+<?php
+
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Handler;
+
+use Monolog\Logger;
+use Monolog\Formatter\LineFormatter;
+
+/**
+ * Common syslog functionality
+ */
+abstract class AbstractSyslogHandler extends AbstractProcessingHandler
+{
+ protected $facility;
+
+ /**
+ * Translates Monolog log levels to syslog log priorities.
+ */
+ protected $logLevels = array(
+ Logger::DEBUG => LOG_DEBUG,
+ Logger::INFO => LOG_INFO,
+ Logger::NOTICE => LOG_NOTICE,
+ Logger::WARNING => LOG_WARNING,
+ Logger::ERROR => LOG_ERR,
+ Logger::CRITICAL => LOG_CRIT,
+ Logger::ALERT => LOG_ALERT,
+ Logger::EMERGENCY => LOG_EMERG,
+ );
+
+ /**
+ * List of valid log facility names.
+ */
+ protected $facilities = array(
+ 'auth' => LOG_AUTH,
+ 'authpriv' => LOG_AUTHPRIV,
+ 'cron' => LOG_CRON,
+ 'daemon' => LOG_DAEMON,
+ 'kern' => LOG_KERN,
+ 'lpr' => LOG_LPR,
+ 'mail' => LOG_MAIL,
+ 'news' => LOG_NEWS,
+ 'syslog' => LOG_SYSLOG,
+ 'user' => LOG_USER,
+ 'uucp' => LOG_UUCP,
+ );
+
+ /**
+ * @param mixed $facility
+ * @param integer $level The minimum logging level at which this handler will be triggered
+ * @param Boolean $bubble Whether the messages that are handled can bubble up the stack or not
+ */
+ public function __construct($facility = LOG_USER, $level = Logger::DEBUG, $bubble = true)
+ {
+ parent::__construct($level, $bubble);
+
+ if (!defined('PHP_WINDOWS_VERSION_BUILD')) {
+ $this->facilities['local0'] = LOG_LOCAL0;
+ $this->facilities['local1'] = LOG_LOCAL1;
+ $this->facilities['local2'] = LOG_LOCAL2;
+ $this->facilities['local3'] = LOG_LOCAL3;
+ $this->facilities['local4'] = LOG_LOCAL4;
+ $this->facilities['local5'] = LOG_LOCAL5;
+ $this->facilities['local6'] = LOG_LOCAL6;
+ $this->facilities['local7'] = LOG_LOCAL7;
+ }
+
+ // convert textual description of facility to syslog constant
+ if (array_key_exists(strtolower($facility), $this->facilities)) {
+ $facility = $this->facilities[strtolower($facility)];
+ } elseif (!in_array($facility, array_values($this->facilities), true)) {
+ throw new \UnexpectedValueException('Unknown facility value "'.$facility.'" given');
+ }
+
+ $this->facility = $facility;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function getDefaultFormatter()
+ {
+ return new LineFormatter('%channel%.%level_name%: %message% %context% %extra%');
+ }
+}
diff --git a/vendor/monolog/monolog/src/Monolog/Handler/AmqpHandler.php b/vendor/monolog/monolog/src/Monolog/Handler/AmqpHandler.php
new file mode 100644
index 00000000..a28ba02a
--- /dev/null
+++ b/vendor/monolog/monolog/src/Monolog/Handler/AmqpHandler.php
@@ -0,0 +1,98 @@
+<?php
+
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Handler;
+
+use Monolog\Logger;
+use Monolog\Formatter\JsonFormatter;
+use PhpAmqpLib\Message\AMQPMessage;
+use PhpAmqpLib\Channel\AMQPChannel;
+use AMQPExchange;
+
+class AmqpHandler extends AbstractProcessingHandler
+{
+ /**
+ * @var AMQPExchange|AMQPChannel $exchange
+ */
+ protected $exchange;
+
+ /**
+ * @var string
+ */
+ protected $exchangeName;
+
+ /**
+ * @param AMQPExchange|AMQPChannel $exchange AMQPExchange (php AMQP ext) or PHP AMQP lib channel, ready for use
+ * @param string $exchangeName
+ * @param int $level
+ * @param bool $bubble Whether the messages that are handled can bubble up the stack or not
+ */
+ public function __construct($exchange, $exchangeName = 'log', $level = Logger::DEBUG, $bubble = true)
+ {
+ if ($exchange instanceof AMQPExchange) {
+ $exchange->setName($exchangeName);
+ } elseif ($exchange instanceof AMQPChannel) {
+ $this->exchangeName = $exchangeName;
+ } else {
+ throw new \InvalidArgumentException('PhpAmqpLib\Channel\AMQPChannel or AMQPExchange instance required');
+ }
+ $this->exchange = $exchange;
+
+ parent::__construct($level, $bubble);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ protected function write(array $record)
+ {
+ $data = $record["formatted"];
+
+ $routingKey = sprintf(
+ '%s.%s',
+ // TODO 2.0 remove substr call
+ substr($record['level_name'], 0, 4),
+ $record['channel']
+ );
+
+ if ($this->exchange instanceof AMQPExchange) {
+ $this->exchange->publish(
+ $data,
+ strtolower($routingKey),
+ 0,
+ array(
+ 'delivery_mode' => 2,
+ 'Content-type' => 'application/json'
+ )
+ );
+ } else {
+ $this->exchange->basic_publish(
+ new AMQPMessage(
+ (string) $data,
+ array(
+ 'delivery_mode' => 2,
+ 'content_type' => 'application/json'
+ )
+ ),
+ $this->exchangeName,
+ strtolower($routingKey)
+ );
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ protected function getDefaultFormatter()
+ {
+ return new JsonFormatter(JsonFormatter::BATCH_MODE_JSON, false);
+ }
+}
diff --git a/vendor/monolog/monolog/src/Monolog/Handler/BrowserConsoleHandler.php b/vendor/monolog/monolog/src/Monolog/Handler/BrowserConsoleHandler.php
new file mode 100644
index 00000000..589ff779
--- /dev/null
+++ b/vendor/monolog/monolog/src/Monolog/Handler/BrowserConsoleHandler.php
@@ -0,0 +1,184 @@
+<?php
+
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Handler;
+
+use Monolog\Formatter\LineFormatter;
+
+/**
+ * Handler sending logs to browser's javascript console with no browser extension required
+ *
+ * @author Olivier Poitrey <rs@dailymotion.com>
+ */
+class BrowserConsoleHandler extends AbstractProcessingHandler
+{
+ protected static $initialized = false;
+ protected static $records = array();
+
+ /**
+ * {@inheritDoc}
+ *
+ * Formatted output may contain some formatting markers to be transferred to `console.log` using the %c format.
+ *
+ * Example of formatted string:
+ *
+ * You can do [[blue text]]{color: blue} or [[green background]]{background-color: green; color: white}
+ *
+ */
+ protected function getDefaultFormatter()
+ {
+ return new LineFormatter('[[%channel%]]{macro: autolabel} [[%level_name%]]{font-weight: bold} %message%');
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ protected function write(array $record)
+ {
+ // Accumulate records
+ self::$records[] = $record;
+
+ // Register shutdown handler if not already done
+ if (PHP_SAPI !== 'cli' && !self::$initialized) {
+ self::$initialized = true;
+ register_shutdown_function(array('Monolog\Handler\BrowserConsoleHandler', 'send'));
+ }
+ }
+
+ /**
+ * Convert records to javascript console commands and send it to the browser.
+ * This method is automatically called on PHP shutdown if output is HTML.
+ */
+ public static function send()
+ {
+ // Check content type
+ foreach (headers_list() as $header) {
+ if (stripos($header, 'content-type:') === 0) {
+ if (stripos($header, 'text/html') === false) {
+ // This handler only works with HTML outputs
+ return;
+ }
+ break;
+ }
+ }
+
+ if (count(self::$records)) {
+ echo '<script>' , self::generateScript() , '</script>';
+ self::reset();
+ }
+ }
+
+ /**
+ * Forget all logged records
+ */
+ public static function reset()
+ {
+ self::$records = array();
+ }
+
+ private static function generateScript()
+ {
+ $script = array();
+ foreach (self::$records as $record) {
+ $context = self::dump('Context', $record['context']);
+ $extra = self::dump('Extra', $record['extra']);
+
+ if (empty($context) && empty($extra)) {
+ $script[] = self::call_array('log', self::handleStyles($record['formatted']));
+ } else {
+ $script = array_merge($script,
+ array(self::call_array('groupCollapsed', self::handleStyles($record['formatted']))),
+ $context,
+ $extra,
+ array(self::call('groupEnd'))
+ );
+ }
+ }
+
+ return "(function (c) {if (c && c.groupCollapsed) {\n" . implode("\n", $script) . "\n}})(console);";
+ }
+
+ private static function handleStyles($formatted)
+ {
+ $args = array(self::quote('font-weight: normal'));
+ $format = '%c' . $formatted;
+ preg_match_all('/\[\[(.*?)\]\]\{([^}]*)\}/s', $format, $matches, PREG_OFFSET_CAPTURE | PREG_SET_ORDER);
+
+ foreach (array_reverse($matches) as $match) {
+ $args[] = self::quote(self::handleCustomStyles($match[2][0], $match[1][0]));
+ $args[] = '"font-weight: normal"';
+
+ $pos = $match[0][1];
+ $format = substr($format, 0, $pos) . '%c' . $match[1][0] . '%c' . substr($format, $pos + strlen($match[0][0]));
+ }
+
+ array_unshift($args, self::quote($format));
+
+ return $args;
+ }
+
+ private static function handleCustomStyles($style, $string)
+ {
+ static $colors = array('blue', 'green', 'red', 'magenta', 'orange', 'black', 'grey');
+ static $labels = array();
+
+ return preg_replace_callback('/macro\s*:(.*?)(?:;|$)/', function ($m) use ($string, &$colors, &$labels) {
+ if (trim($m[1]) === 'autolabel') {
+ // Format the string as a label with consistent auto assigned background color
+ if (!isset($labels[$string])) {
+ $labels[$string] = $colors[count($labels) % count($colors)];
+ }
+ $color = $labels[$string];
+
+ return "background-color: $color; color: white; border-radius: 3px; padding: 0 2px 0 2px";
+ }
+
+ return $m[1];
+ }, $style);
+ }
+
+ private static function dump($title, array $dict)
+ {
+ $script = array();
+ $dict = array_filter($dict);
+ if (empty($dict)) {
+ return $script;
+ }
+ $script[] = self::call('log', self::quote('%c%s'), self::quote('font-weight: bold'), self::quote($title));
+ foreach ($dict as $key => $value) {
+ $value = json_encode($value);
+ if (empty($value)) {
+ $value = self::quote('');
+ }
+ $script[] = self::call('log', self::quote('%s: %o'), self::quote($key), $value);
+ }
+
+ return $script;
+ }
+
+ private static function quote($arg)
+ {
+ return '"' . addcslashes($arg, "\"\n") . '"';
+ }
+
+ private static function call()
+ {
+ $args = func_get_args();
+ $method = array_shift($args);
+
+ return self::call_array($method, $args);
+ }
+
+ private static function call_array($method, array $args)
+ {
+ return 'c.' . $method . '(' . implode(', ', $args) . ');';
+ }
+}
diff --git a/vendor/monolog/monolog/src/Monolog/Handler/BufferHandler.php b/vendor/monolog/monolog/src/Monolog/Handler/BufferHandler.php
new file mode 100644
index 00000000..6d8136f7
--- /dev/null
+++ b/vendor/monolog/monolog/src/Monolog/Handler/BufferHandler.php
@@ -0,0 +1,117 @@
+<?php
+
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Handler;
+
+use Monolog\Logger;
+
+/**
+ * Buffers all records until closing the handler and then pass them as batch.
+ *
+ * This is useful for a MailHandler to send only one mail per request instead of
+ * sending one per log message.
+ *
+ * @author Christophe Coevoet <stof@notk.org>
+ */
+class BufferHandler extends AbstractHandler
+{
+ protected $handler;
+ protected $bufferSize = 0;
+ protected $bufferLimit;
+ protected $flushOnOverflow;
+ protected $buffer = array();
+ protected $initialized = false;
+
+ /**
+ * @param HandlerInterface $handler Handler.
+ * @param integer $bufferLimit How many entries should be buffered at most, beyond that the oldest items are removed from the buffer.
+ * @param integer $level The minimum logging level at which this handler will be triggered
+ * @param Boolean $bubble Whether the messages that are handled can bubble up the stack or not
+ * @param Boolean $flushOnOverflow If true, the buffer is flushed when the max size has been reached, by default oldest entries are discarded
+ */
+ public function __construct(HandlerInterface $handler, $bufferLimit = 0, $level = Logger::DEBUG, $bubble = true, $flushOnOverflow = false)
+ {
+ parent::__construct($level, $bubble);
+ $this->handler = $handler;
+ $this->bufferLimit = (int) $bufferLimit;
+ $this->flushOnOverflow = $flushOnOverflow;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function handle(array $record)
+ {
+ if ($record['level'] < $this->level) {
+ return false;
+ }
+
+ if (!$this->initialized) {
+ // __destructor() doesn't get called on Fatal errors
+ register_shutdown_function(array($this, 'close'));
+ $this->initialized = true;
+ }
+
+ if ($this->bufferLimit > 0 && $this->bufferSize === $this->bufferLimit) {
+ if ($this->flushOnOverflow) {
+ $this->flush();
+ } else {
+ array_shift($this->buffer);
+ $this->bufferSize--;
+ }
+ }
+
+ if ($this->processors) {
+ foreach ($this->processors as $processor) {
+ $record = call_user_func($processor, $record);
+ }
+ }
+
+ $this->buffer[] = $record;
+ $this->bufferSize++;
+
+ return false === $this->bubble;
+ }
+
+ public function flush()
+ {
+ if ($this->bufferSize === 0) {
+ return;
+ }
+
+ $this->handler->handleBatch($this->buffer);
+ $this->clear();
+ }
+
+ public function __destruct()
+ {
+ // suppress the parent behavior since we already have register_shutdown_function()
+ // to call close(), and the reference contained there will prevent this from being
+ // GC'd until the end of the request
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function close()
+ {
+ $this->flush();
+ }
+
+ /**
+ * Clears the buffer without flushing any messages down to the wrapped handler.
+ */
+ public function clear()
+ {
+ $this->bufferSize = 0;
+ $this->buffer = array();
+ }
+}
diff --git a/vendor/monolog/monolog/src/Monolog/Handler/ChromePHPHandler.php b/vendor/monolog/monolog/src/Monolog/Handler/ChromePHPHandler.php
new file mode 100644
index 00000000..bc659349
--- /dev/null
+++ b/vendor/monolog/monolog/src/Monolog/Handler/ChromePHPHandler.php
@@ -0,0 +1,204 @@
+<?php
+
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Handler;
+
+use Monolog\Formatter\ChromePHPFormatter;
+use Monolog\Logger;
+
+/**
+ * Handler sending logs to the ChromePHP extension (http://www.chromephp.com/)
+ *
+ * @author Christophe Coevoet <stof@notk.org>
+ */
+class ChromePHPHandler extends AbstractProcessingHandler
+{
+ /**
+ * Version of the extension
+ */
+ const VERSION = '4.0';
+
+ /**
+ * Header name
+ */
+ const HEADER_NAME = 'X-ChromeLogger-Data';
+
+ protected static $initialized = false;
+
+ /**
+ * Tracks whether we sent too much data
+ *
+ * Chrome limits the headers to 256KB, so when we sent 240KB we stop sending
+ *
+ * @var Boolean
+ */
+ protected static $overflowed = false;
+
+ protected static $json = array(
+ 'version' => self::VERSION,
+ 'columns' => array('label', 'log', 'backtrace', 'type'),
+ 'rows' => array(),
+ );
+
+ protected static $sendHeaders = true;
+
+ /**
+ * @param integer $level The minimum logging level at which this handler will be triggered
+ * @param Boolean $bubble Whether the messages that are handled can bubble up the stack or not
+ */
+ public function __construct($level = Logger::DEBUG, $bubble = true)
+ {
+ parent::__construct($level, $bubble);
+ if (!function_exists('json_encode')) {
+ throw new \RuntimeException('PHP\'s json extension is required to use Monolog\'s ChromePHPHandler');
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function handleBatch(array $records)
+ {
+ $messages = array();
+
+ foreach ($records as $record) {
+ if ($record['level'] < $this->level) {
+ continue;
+ }
+ $messages[] = $this->processRecord($record);
+ }
+
+ if (!empty($messages)) {
+ $messages = $this->getFormatter()->formatBatch($messages);
+ self::$json['rows'] = array_merge(self::$json['rows'], $messages);
+ $this->send();
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ protected function getDefaultFormatter()
+ {
+ return new ChromePHPFormatter();
+ }
+
+ /**
+ * Creates & sends header for a record
+ *
+ * @see sendHeader()
+ * @see send()
+ * @param array $record
+ */
+ protected function write(array $record)
+ {
+ self::$json['rows'][] = $record['formatted'];
+
+ $this->send();
+ }
+
+ /**
+ * Sends the log header
+ *
+ * @see sendHeader()
+ */
+ protected function send()
+ {
+ if (self::$overflowed || !self::$sendHeaders) {
+ return;
+ }
+
+ if (!self::$initialized) {
+ self::$initialized = true;
+
+ self::$sendHeaders = $this->headersAccepted();
+ if (!self::$sendHeaders) {
+ return;
+ }
+
+ self::$json['request_uri'] = isset($_SERVER['REQUEST_URI']) ? $_SERVER['REQUEST_URI'] : '';
+ }
+
+ $json = @json_encode(self::$json);
+ $data = base64_encode(utf8_encode($json));
+ if (strlen($data) > 240*1024) {
+ self::$overflowed = true;
+
+ $record = array(
+ 'message' => 'Incomplete logs, chrome header size limit reached',
+ 'context' => array(),
+ 'level' => Logger::WARNING,
+ 'level_name' => Logger::getLevelName(Logger::WARNING),
+ 'channel' => 'monolog',
+ 'datetime' => new \DateTime(),
+ 'extra' => array(),
+ );
+ self::$json['rows'][count(self::$json['rows']) - 1] = $this->getFormatter()->format($record);
+ $json = @json_encode(self::$json);
+ $data = base64_encode(utf8_encode($json));
+ }
+
+ if (trim($data) !== '') {
+ $this->sendHeader(self::HEADER_NAME, $data);
+ }
+ }
+
+ /**
+ * Send header string to the client
+ *
+ * @param string $header
+ * @param string $content
+ */
+ protected function sendHeader($header, $content)
+ {
+ if (!headers_sent() && self::$sendHeaders) {
+ header(sprintf('%s: %s', $header, $content));
+ }
+ }
+
+ /**
+ * Verifies if the headers are accepted by the current user agent
+ *
+ * @return Boolean
+ */
+ protected function headersAccepted()
+ {
+ if (empty($_SERVER['HTTP_USER_AGENT'])) {
+ return false;
+ }
+
+ return preg_match('{\bChrome/\d+[\.\d+]*\b}', $_SERVER['HTTP_USER_AGENT']);
+ }
+
+ /**
+ * BC getter for the sendHeaders property that has been made static
+ */
+ public function __get($property)
+ {
+ if ('sendHeaders' !== $property) {
+ throw new \InvalidArgumentException('Undefined property '.$property);
+ }
+
+ return static::$sendHeaders;
+ }
+
+ /**
+ * BC setter for the sendHeaders property that has been made static
+ */
+ public function __set($property, $value)
+ {
+ if ('sendHeaders' !== $property) {
+ throw new \InvalidArgumentException('Undefined property '.$property);
+ }
+
+ static::$sendHeaders = $value;
+ }
+}
diff --git a/vendor/monolog/monolog/src/Monolog/Handler/CouchDBHandler.php b/vendor/monolog/monolog/src/Monolog/Handler/CouchDBHandler.php
new file mode 100644
index 00000000..b3687c3d
--- /dev/null
+++ b/vendor/monolog/monolog/src/Monolog/Handler/CouchDBHandler.php
@@ -0,0 +1,72 @@
+<?php
+
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Handler;
+
+use Monolog\Formatter\JsonFormatter;
+use Monolog\Logger;
+
+/**
+ * CouchDB handler
+ *
+ * @author Markus Bachmann <markus.bachmann@bachi.biz>
+ */
+class CouchDBHandler extends AbstractProcessingHandler
+{
+ private $options;
+
+ public function __construct(array $options = array(), $level = Logger::DEBUG, $bubble = true)
+ {
+ $this->options = array_merge(array(
+ 'host' => 'localhost',
+ 'port' => 5984,
+ 'dbname' => 'logger',
+ 'username' => null,
+ 'password' => null,
+ ), $options);
+
+ parent::__construct($level, $bubble);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ protected function write(array $record)
+ {
+ $basicAuth = null;
+ if ($this->options['username']) {
+ $basicAuth = sprintf('%s:%s@', $this->options['username'], $this->options['password']);
+ }
+
+ $url = 'http://'.$basicAuth.$this->options['host'].':'.$this->options['port'].'/'.$this->options['dbname'];
+ $context = stream_context_create(array(
+ 'http' => array(
+ 'method' => 'POST',
+ 'content' => $record['formatted'],
+ 'ignore_errors' => true,
+ 'max_redirects' => 0,
+ 'header' => 'Content-type: application/json',
+ )
+ ));
+
+ if (false === @file_get_contents($url, null, $context)) {
+ throw new \RuntimeException(sprintf('Could not connect to %s', $url));
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ protected function getDefaultFormatter()
+ {
+ return new JsonFormatter(JsonFormatter::BATCH_MODE_JSON, false);
+ }
+}
diff --git a/vendor/monolog/monolog/src/Monolog/Handler/CubeHandler.php b/vendor/monolog/monolog/src/Monolog/Handler/CubeHandler.php
new file mode 100644
index 00000000..db8e6552
--- /dev/null
+++ b/vendor/monolog/monolog/src/Monolog/Handler/CubeHandler.php
@@ -0,0 +1,151 @@
+<?php
+
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Handler;
+
+use Monolog\Logger;
+
+/**
+ * Logs to Cube.
+ *
+ * @link http://square.github.com/cube/
+ * @author Wan Chen <kami@kamisama.me>
+ */
+class CubeHandler extends AbstractProcessingHandler
+{
+ private $udpConnection = null;
+ private $httpConnection = null;
+ private $scheme = null;
+ private $host = null;
+ private $port = null;
+ private $acceptedSchemes = array('http', 'udp');
+
+ /**
+ * Create a Cube handler
+ *
+ * @throws UnexpectedValueException when given url is not a valid url.
+ * A valid url must consists of three parts : protocol://host:port
+ * Only valid protocol used by Cube are http and udp
+ */
+ public function __construct($url, $level = Logger::DEBUG, $bubble = true)
+ {
+ $urlInfos = parse_url($url);
+
+ if (!isset($urlInfos['scheme']) || !isset($urlInfos['host']) || !isset($urlInfos['port'])) {
+ throw new \UnexpectedValueException('URL "'.$url.'" is not valid');
+ }
+
+ if (!in_array($urlInfos['scheme'], $this->acceptedSchemes)) {
+ throw new \UnexpectedValueException(
+ 'Invalid protocol (' . $urlInfos['scheme'] . ').'
+ . ' Valid options are ' . implode(', ', $this->acceptedSchemes));
+ }
+
+ $this->scheme = $urlInfos['scheme'];
+ $this->host = $urlInfos['host'];
+ $this->port = $urlInfos['port'];
+
+ parent::__construct($level, $bubble);
+ }
+
+ /**
+ * Establish a connection to an UDP socket
+ *
+ * @throws LogicException when unable to connect to the socket
+ */
+ protected function connectUdp()
+ {
+ if (!extension_loaded('sockets')) {
+ throw new MissingExtensionException('The sockets extension is required to use udp URLs with the CubeHandler');
+ }
+
+ $this->udpConnection = socket_create(AF_INET, SOCK_DGRAM, 0);
+ if (!$this->udpConnection) {
+ throw new \LogicException('Unable to create a socket');
+ }
+
+ if (!socket_connect($this->udpConnection, $this->host, $this->port)) {
+ throw new \LogicException('Unable to connect to the socket at ' . $this->host . ':' . $this->port);
+ }
+ }
+
+ /**
+ * Establish a connection to a http server
+ */
+ protected function connectHttp()
+ {
+ if (!extension_loaded('curl')) {
+ throw new \LogicException('The curl extension is needed to use http URLs with the CubeHandler');
+ }
+
+ $this->httpConnection = curl_init('http://'.$this->host.':'.$this->port.'/1.0/event/put');
+
+ if (!$this->httpConnection) {
+ throw new \LogicException('Unable to connect to ' . $this->host . ':' . $this->port);
+ }
+
+ curl_setopt($this->httpConnection, CURLOPT_CUSTOMREQUEST, "POST");
+ curl_setopt($this->httpConnection, CURLOPT_RETURNTRANSFER, true);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function write(array $record)
+ {
+ $date = $record['datetime'];
+
+ $data = array('time' => $date->format('Y-m-d\TH:i:s.uO'));
+ unset($record['datetime']);
+
+ if (isset($record['context']['type'])) {
+ $data['type'] = $record['context']['type'];
+ unset($record['context']['type']);
+ } else {
+ $data['type'] = $record['channel'];
+ }
+
+ $data['data'] = $record['context'];
+ $data['data']['level'] = $record['level'];
+
+ if ($this->scheme === 'http') {
+ $this->writeHttp(json_encode($data));
+ } else {
+ $this->writeUdp(json_encode($data));
+ }
+ }
+
+ private function writeUdp($data)
+ {
+ if (!$this->udpConnection) {
+ $this->connectUdp();
+ }
+
+ socket_send($this->udpConnection, $data, strlen($data), 0);
+ }
+
+ private function writeHttp($data)
+ {
+ if (!$this->httpConnection) {
+ $this->connectHttp();
+ }
+
+ curl_setopt($this->httpConnection, CURLOPT_POSTFIELDS, '['.$data.']');
+ curl_setopt($this->httpConnection, CURLOPT_HTTPHEADER, array(
+ 'Content-Type: application/json',
+ 'Content-Length: ' . strlen('['.$data.']'))
+ );
+
+ if (curl_exec($this->httpConnection) === false) {
+ throw new \RuntimeException(sprintf('Curl error (code %s): %s', curl_errno($ch), curl_error($ch)));
+ }
+ }
+}
diff --git a/vendor/monolog/monolog/src/Monolog/Handler/DoctrineCouchDBHandler.php b/vendor/monolog/monolog/src/Monolog/Handler/DoctrineCouchDBHandler.php
new file mode 100644
index 00000000..b91ffec9
--- /dev/null
+++ b/vendor/monolog/monolog/src/Monolog/Handler/DoctrineCouchDBHandler.php
@@ -0,0 +1,45 @@
+<?php
+
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Handler;
+
+use Monolog\Logger;
+use Monolog\Formatter\NormalizerFormatter;
+use Doctrine\CouchDB\CouchDBClient;
+
+/**
+ * CouchDB handler for Doctrine CouchDB ODM
+ *
+ * @author Markus Bachmann <markus.bachmann@bachi.biz>
+ */
+class DoctrineCouchDBHandler extends AbstractProcessingHandler
+{
+ private $client;
+
+ public function __construct(CouchDBClient $client, $level = Logger::DEBUG, $bubble = true)
+ {
+ $this->client = $client;
+ parent::__construct($level, $bubble);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ protected function write(array $record)
+ {
+ $this->client->postDocument($record['formatted']);
+ }
+
+ protected function getDefaultFormatter()
+ {
+ return new NormalizerFormatter;
+ }
+}
diff --git a/vendor/monolog/monolog/src/Monolog/Handler/DynamoDbHandler.php b/vendor/monolog/monolog/src/Monolog/Handler/DynamoDbHandler.php
new file mode 100644
index 00000000..e7f843c8
--- /dev/null
+++ b/vendor/monolog/monolog/src/Monolog/Handler/DynamoDbHandler.php
@@ -0,0 +1,89 @@
+<?php
+
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Handler;
+
+use Aws\Common\Aws;
+use Aws\DynamoDb\DynamoDbClient;
+use Monolog\Formatter\ScalarFormatter;
+use Monolog\Logger;
+
+/**
+ * Amazon DynamoDB handler (http://aws.amazon.com/dynamodb/)
+ *
+ * @link https://github.com/aws/aws-sdk-php/
+ * @author Andrew Lawson <adlawson@gmail.com>
+ */
+class DynamoDbHandler extends AbstractProcessingHandler
+{
+ const DATE_FORMAT = 'Y-m-d\TH:i:s.uO';
+
+ /**
+ * @var DynamoDbClient
+ */
+ protected $client;
+
+ /**
+ * @var string
+ */
+ protected $table;
+
+ /**
+ * @param DynamoDbClient $client
+ * @param string $table
+ * @param integer $level
+ * @param boolean $bubble
+ */
+ public function __construct(DynamoDbClient $client, $table, $level = Logger::DEBUG, $bubble = true)
+ {
+ if (!defined('Aws\Common\Aws::VERSION') || version_compare('3.0', Aws::VERSION, '<=')) {
+ throw new \RuntimeException('The DynamoDbHandler is only known to work with the AWS SDK 2.x releases');
+ }
+
+ $this->client = $client;
+ $this->table = $table;
+
+ parent::__construct($level, $bubble);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function write(array $record)
+ {
+ $filtered = $this->filterEmptyFields($record['formatted']);
+ $formatted = $this->client->formatAttributes($filtered);
+
+ $this->client->putItem(array(
+ 'TableName' => $this->table,
+ 'Item' => $formatted
+ ));
+ }
+
+ /**
+ * @param array $record
+ * @return array
+ */
+ protected function filterEmptyFields(array $record)
+ {
+ return array_filter($record, function ($value) {
+ return !empty($value) || false === $value || 0 === $value;
+ });
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function getDefaultFormatter()
+ {
+ return new ScalarFormatter(self::DATE_FORMAT);
+ }
+}
diff --git a/vendor/monolog/monolog/src/Monolog/Handler/ElasticSearchHandler.php b/vendor/monolog/monolog/src/Monolog/Handler/ElasticSearchHandler.php
new file mode 100644
index 00000000..96e5d57f
--- /dev/null
+++ b/vendor/monolog/monolog/src/Monolog/Handler/ElasticSearchHandler.php
@@ -0,0 +1,128 @@
+<?php
+
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Handler;
+
+use Monolog\Formatter\FormatterInterface;
+use Monolog\Formatter\ElasticaFormatter;
+use Monolog\Logger;
+use Elastica\Client;
+use Elastica\Exception\ExceptionInterface;
+
+/**
+ * Elastic Search handler
+ *
+ * Usage example:
+ *
+ * $client = new \Elastica\Client();
+ * $options = array(
+ * 'index' => 'elastic_index_name',
+ * 'type' => 'elastic_doc_type',
+ * );
+ * $handler = new ElasticSearchHandler($client, $options);
+ * $log = new Logger('application');
+ * $log->pushHandler($handler);
+ *
+ * @author Jelle Vink <jelle.vink@gmail.com>
+ */
+class ElasticSearchHandler extends AbstractProcessingHandler
+{
+ /**
+ * @var Client
+ */
+ protected $client;
+
+ /**
+ * @var array Handler config options
+ */
+ protected $options = array();
+
+ /**
+ * @param Client $client Elastica Client object
+ * @param array $options Handler configuration
+ * @param integer $level The minimum logging level at which this handler will be triggered
+ * @param Boolean $bubble Whether the messages that are handled can bubble up the stack or not
+ */
+ public function __construct(Client $client, array $options = array(), $level = Logger::DEBUG, $bubble = true)
+ {
+ parent::__construct($level, $bubble);
+ $this->client = $client;
+ $this->options = array_merge(
+ array(
+ 'index' => 'monolog', // Elastic index name
+ 'type' => 'record', // Elastic document type
+ 'ignore_error' => false, // Suppress Elastica exceptions
+ ),
+ $options
+ );
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ protected function write(array $record)
+ {
+ $this->bulkSend(array($record['formatted']));
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function setFormatter(FormatterInterface $formatter)
+ {
+ if ($formatter instanceof ElasticaFormatter) {
+ return parent::setFormatter($formatter);
+ }
+ throw new \InvalidArgumentException('ElasticSearchHandler is only compatible with ElasticaFormatter');
+ }
+
+ /**
+ * Getter options
+ * @return array
+ */
+ public function getOptions()
+ {
+ return $this->options;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ protected function getDefaultFormatter()
+ {
+ return new ElasticaFormatter($this->options['index'], $this->options['type']);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function handleBatch(array $records)
+ {
+ $documents = $this->getFormatter()->formatBatch($records);
+ $this->bulkSend($documents);
+ }
+
+ /**
+ * Use Elasticsearch bulk API to send list of documents
+ * @param array $documents
+ * @throws \RuntimeException
+ */
+ protected function bulkSend(array $documents)
+ {
+ try {
+ $this->client->addDocuments($documents);
+ } catch (ExceptionInterface $e) {
+ if (!$this->options['ignore_error']) {
+ throw new \RuntimeException("Error sending messages to Elasticsearch", 0, $e);
+ }
+ }
+ }
+}
diff --git a/vendor/monolog/monolog/src/Monolog/Handler/ErrorLogHandler.php b/vendor/monolog/monolog/src/Monolog/Handler/ErrorLogHandler.php
new file mode 100644
index 00000000..d1e1ee60
--- /dev/null
+++ b/vendor/monolog/monolog/src/Monolog/Handler/ErrorLogHandler.php
@@ -0,0 +1,82 @@
+<?php
+
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Handler;
+
+use Monolog\Formatter\LineFormatter;
+use Monolog\Logger;
+
+/**
+ * Stores to PHP error_log() handler.
+ *
+ * @author Elan Ruusamäe <glen@delfi.ee>
+ */
+class ErrorLogHandler extends AbstractProcessingHandler
+{
+ const OPERATING_SYSTEM = 0;
+ const SAPI = 4;
+
+ protected $messageType;
+ protected $expandNewlines;
+
+ /**
+ * @param integer $messageType Says where the error should go.
+ * @param integer $level The minimum logging level at which this handler will be triggered
+ * @param Boolean $bubble Whether the messages that are handled can bubble up the stack or not
+ * @param Boolean $expandNewlines If set to true, newlines in the message will be expanded to be take multiple log entries
+ */
+ public function __construct($messageType = self::OPERATING_SYSTEM, $level = Logger::DEBUG, $bubble = true, $expandNewlines = false)
+ {
+ parent::__construct($level, $bubble);
+
+ if (false === in_array($messageType, self::getAvailableTypes())) {
+ $message = sprintf('The given message type "%s" is not supported', print_r($messageType, true));
+ throw new \InvalidArgumentException($message);
+ }
+
+ $this->messageType = $messageType;
+ $this->expandNewlines = $expandNewlines;
+ }
+
+ /**
+ * @return array With all available types
+ */
+ public static function getAvailableTypes()
+ {
+ return array(
+ self::OPERATING_SYSTEM,
+ self::SAPI,
+ );
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ protected function getDefaultFormatter()
+ {
+ return new LineFormatter('[%datetime%] %channel%.%level_name%: %message% %context% %extra%');
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function write(array $record)
+ {
+ if ($this->expandNewlines) {
+ $lines = preg_split('{[\r\n]+}', (string) $record['formatted']);
+ foreach ($lines as $line) {
+ error_log($line, $this->messageType);
+ }
+ } else {
+ error_log((string) $record['formatted'], $this->messageType);
+ }
+ }
+}
diff --git a/vendor/monolog/monolog/src/Monolog/Handler/FilterHandler.php b/vendor/monolog/monolog/src/Monolog/Handler/FilterHandler.php
new file mode 100644
index 00000000..dad82273
--- /dev/null
+++ b/vendor/monolog/monolog/src/Monolog/Handler/FilterHandler.php
@@ -0,0 +1,140 @@
+<?php
+
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Handler;
+
+use Monolog\Logger;
+
+/**
+ * Simple handler wrapper that filters records based on a list of levels
+ *
+ * It can be configured with an exact list of levels to allow, or a min/max level.
+ *
+ * @author Hennadiy Verkh
+ * @author Jordi Boggiano <j.boggiano@seld.be>
+ */
+class FilterHandler extends AbstractHandler
+{
+ /**
+ * Handler or factory callable($record, $this)
+ *
+ * @var callable|\Monolog\Handler\HandlerInterface
+ */
+ protected $handler;
+
+ /**
+ * Minimum level for logs that are passes to handler
+ *
+ * @var int[]
+ */
+ protected $acceptedLevels;
+
+ /**
+ * Whether the messages that are handled can bubble up the stack or not
+ *
+ * @var Boolean
+ */
+ protected $bubble;
+
+ /**
+ * @param callable|HandlerInterface $handler Handler or factory callable($record, $this).
+ * @param int|array $minLevelOrList A list of levels to accept or a minimum level if maxLevel is provided
+ * @param int $maxLevel Maximum level to accept, only used if $minLevelOrList is not an array
+ * @param Boolean $bubble Whether the messages that are handled can bubble up the stack or not
+ */
+ public function __construct($handler, $minLevelOrList = Logger::DEBUG, $maxLevel = Logger::EMERGENCY, $bubble = true)
+ {
+ $this->handler = $handler;
+ $this->bubble = $bubble;
+ $this->setAcceptedLevels($minLevelOrList, $maxLevel);
+
+ if (!$this->handler instanceof HandlerInterface && !is_callable($this->handler)) {
+ throw new \RuntimeException("The given handler (".json_encode($this->handler).") is not a callable nor a Monolog\Handler\HandlerInterface object");
+ }
+ }
+
+ /**
+ * @return array
+ */
+ public function getAcceptedLevels()
+ {
+ return array_flip($this->acceptedLevels);
+ }
+
+ /**
+ * @param int|array $minLevelOrList A list of levels to accept or a minimum level if maxLevel is provided
+ * @param int $maxLevel Maximum level to accept, only used if $minLevelOrList is not an array
+ */
+ public function setAcceptedLevels($minLevelOrList = Logger::DEBUG, $maxLevel = Logger::EMERGENCY)
+ {
+ if (is_array($minLevelOrList)) {
+ $acceptedLevels = array_map('Monolog\Logger::toMonologLevel', $minLevelOrList);
+ } else {
+ $minLevelOrList = Logger::toMonologLevel($minLevelOrList);
+ $maxLevel = Logger::toMonologLevel($maxLevel);
+ $acceptedLevels = array_values(array_filter(Logger::getLevels(), function ($level) use ($minLevelOrList, $maxLevel) {
+ return $level >= $minLevelOrList && $level <= $maxLevel;
+ }));
+ }
+ $this->acceptedLevels = array_flip($acceptedLevels);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function isHandling(array $record)
+ {
+ return isset($this->acceptedLevels[$record['level']]);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function handle(array $record)
+ {
+ if (!$this->isHandling($record)) {
+ return false;
+ }
+
+ // The same logic as in FingersCrossedHandler
+ if (!$this->handler instanceof HandlerInterface) {
+ $this->handler = call_user_func($this->handler, $record, $this);
+ if (!$this->handler instanceof HandlerInterface) {
+ throw new \RuntimeException("The factory callable should return a HandlerInterface");
+ }
+ }
+
+ if ($this->processors) {
+ foreach ($this->processors as $processor) {
+ $record = call_user_func($processor, $record);
+ }
+ }
+
+ $this->handler->handle($record);
+
+ return false === $this->bubble;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function handleBatch(array $records)
+ {
+ $filtered = array();
+ foreach ($records as $record) {
+ if ($this->isHandling($record)) {
+ $filtered[] = $record;
+ }
+ }
+
+ $this->handler->handleBatch($filtered);
+ }
+}
diff --git a/vendor/monolog/monolog/src/Monolog/Handler/FingersCrossed/ActivationStrategyInterface.php b/vendor/monolog/monolog/src/Monolog/Handler/FingersCrossed/ActivationStrategyInterface.php
new file mode 100644
index 00000000..c3e42efe
--- /dev/null
+++ b/vendor/monolog/monolog/src/Monolog/Handler/FingersCrossed/ActivationStrategyInterface.php
@@ -0,0 +1,28 @@
+<?php
+
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Handler\FingersCrossed;
+
+/**
+ * Interface for activation strategies for the FingersCrossedHandler.
+ *
+ * @author Johannes M. Schmitt <schmittjoh@gmail.com>
+ */
+interface ActivationStrategyInterface
+{
+ /**
+ * Returns whether the given record activates the handler.
+ *
+ * @param array $record
+ * @return Boolean
+ */
+ public function isHandlerActivated(array $record);
+}
diff --git a/vendor/monolog/monolog/src/Monolog/Handler/FingersCrossed/ChannelLevelActivationStrategy.php b/vendor/monolog/monolog/src/Monolog/Handler/FingersCrossed/ChannelLevelActivationStrategy.php
new file mode 100644
index 00000000..e3b403f6
--- /dev/null
+++ b/vendor/monolog/monolog/src/Monolog/Handler/FingersCrossed/ChannelLevelActivationStrategy.php
@@ -0,0 +1,59 @@
+<?php
+
+/*
+ * This file is part of the Monolog package.
+*
+* (c) Jordi Boggiano <j.boggiano@seld.be>
+*
+* For the full copyright and license information, please view the LICENSE
+* file that was distributed with this source code.
+*/
+
+namespace Monolog\Handler\FingersCrossed;
+
+use Monolog\Logger;
+
+/**
+ * Channel and Error level based monolog activation strategy. Allows to trigger activation
+ * based on level per channel. e.g. trigger activation on level 'ERROR' by default, except
+ * for records of the 'sql' channel; those should trigger activation on level 'WARN'.
+ *
+ * Example:
+ *
+ * <code>
+ * $activationStrategy = new ChannelLevelActivationStrategy(
+ * Logger::CRITICAL,
+ * array(
+ * 'request' => Logger::ALERT,
+ * 'sensitive' => Logger::ERROR,
+ * )
+ * );
+ * $handler = new FingersCrossedHandler(new StreamHandler('php://stderr'), $activationStrategy);
+ * </code>
+ *
+ * @author Mike Meessen <netmikey@gmail.com>
+ */
+class ChannelLevelActivationStrategy implements ActivationStrategyInterface
+{
+ private $defaultActionLevel;
+ private $channelToActionLevel;
+
+ /**
+ * @param int $defaultActionLevel The default action level to be used if the record's category doesn't match any
+ * @param array $channelToActionLevel An array that maps channel names to action levels.
+ */
+ public function __construct($defaultActionLevel, $channelToActionLevel = array())
+ {
+ $this->defaultActionLevel = Logger::toMonologLevel($defaultActionLevel);
+ $this->channelToActionLevel = array_map('Monolog\Logger::toMonologLevel', $channelToActionLevel);
+ }
+
+ public function isHandlerActivated(array $record)
+ {
+ if (isset($this->channelToActionLevel[$record['channel']])) {
+ return $record['level'] >= $this->channelToActionLevel[$record['channel']];
+ }
+
+ return $record['level'] >= $this->defaultActionLevel;
+ }
+}
diff --git a/vendor/monolog/monolog/src/Monolog/Handler/FingersCrossed/ErrorLevelActivationStrategy.php b/vendor/monolog/monolog/src/Monolog/Handler/FingersCrossed/ErrorLevelActivationStrategy.php
new file mode 100644
index 00000000..6e630852
--- /dev/null
+++ b/vendor/monolog/monolog/src/Monolog/Handler/FingersCrossed/ErrorLevelActivationStrategy.php
@@ -0,0 +1,34 @@
+<?php
+
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Handler\FingersCrossed;
+
+use Monolog\Logger;
+
+/**
+ * Error level based activation strategy.
+ *
+ * @author Johannes M. Schmitt <schmittjoh@gmail.com>
+ */
+class ErrorLevelActivationStrategy implements ActivationStrategyInterface
+{
+ private $actionLevel;
+
+ public function __construct($actionLevel)
+ {
+ $this->actionLevel = Logger::toMonologLevel($actionLevel);
+ }
+
+ public function isHandlerActivated(array $record)
+ {
+ return $record['level'] >= $this->actionLevel;
+ }
+}
diff --git a/vendor/monolog/monolog/src/Monolog/Handler/FingersCrossedHandler.php b/vendor/monolog/monolog/src/Monolog/Handler/FingersCrossedHandler.php
new file mode 100644
index 00000000..30a85dd6
--- /dev/null
+++ b/vendor/monolog/monolog/src/Monolog/Handler/FingersCrossedHandler.php
@@ -0,0 +1,153 @@
+<?php
+
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Handler;
+
+use Monolog\Handler\FingersCrossed\ErrorLevelActivationStrategy;
+use Monolog\Handler\FingersCrossed\ActivationStrategyInterface;
+use Monolog\Logger;
+
+/**
+ * Buffers all records until a certain level is reached
+ *
+ * The advantage of this approach is that you don't get any clutter in your log files.
+ * Only requests which actually trigger an error (or whatever your actionLevel is) will be
+ * in the logs, but they will contain all records, not only those above the level threshold.
+ *
+ * You can find the various activation strategies in the
+ * Monolog\Handler\FingersCrossed\ namespace.
+ *
+ * @author Jordi Boggiano <j.boggiano@seld.be>
+ */
+class FingersCrossedHandler extends AbstractHandler
+{
+ protected $handler;
+ protected $activationStrategy;
+ protected $buffering = true;
+ protected $bufferSize;
+ protected $buffer = array();
+ protected $stopBuffering;
+ protected $passthruLevel;
+
+ /**
+ * @param callable|HandlerInterface $handler Handler or factory callable($record, $fingersCrossedHandler).
+ * @param int|ActivationStrategyInterface $activationStrategy Strategy which determines when this handler takes action
+ * @param int $bufferSize How many entries should be buffered at most, beyond that the oldest items are removed from the buffer.
+ * @param Boolean $bubble Whether the messages that are handled can bubble up the stack or not
+ * @param Boolean $stopBuffering Whether the handler should stop buffering after being triggered (default true)
+ * @param int $passthruLevel Minimum level to always flush to handler on close, even if strategy not triggered
+ */
+ public function __construct($handler, $activationStrategy = null, $bufferSize = 0, $bubble = true, $stopBuffering = true, $passthruLevel = null)
+ {
+ if (null === $activationStrategy) {
+ $activationStrategy = new ErrorLevelActivationStrategy(Logger::WARNING);
+ }
+
+ // convert simple int activationStrategy to an object
+ if (!$activationStrategy instanceof ActivationStrategyInterface) {
+ $activationStrategy = new ErrorLevelActivationStrategy($activationStrategy);
+ }
+
+ $this->handler = $handler;
+ $this->activationStrategy = $activationStrategy;
+ $this->bufferSize = $bufferSize;
+ $this->bubble = $bubble;
+ $this->stopBuffering = $stopBuffering;
+
+ if ($passthruLevel !== null) {
+ $this->passthruLevel = Logger::toMonologLevel($passthruLevel);
+ }
+
+ if (!$this->handler instanceof HandlerInterface && !is_callable($this->handler)) {
+ throw new \RuntimeException("The given handler (".json_encode($this->handler).") is not a callable nor a Monolog\Handler\HandlerInterface object");
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function isHandling(array $record)
+ {
+ return true;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function handle(array $record)
+ {
+ if ($this->processors) {
+ foreach ($this->processors as $processor) {
+ $record = call_user_func($processor, $record);
+ }
+ }
+
+ if ($this->buffering) {
+ $this->buffer[] = $record;
+ if ($this->bufferSize > 0 && count($this->buffer) > $this->bufferSize) {
+ array_shift($this->buffer);
+ }
+ if ($this->activationStrategy->isHandlerActivated($record)) {
+ if ($this->stopBuffering) {
+ $this->buffering = false;
+ }
+ if (!$this->handler instanceof HandlerInterface) {
+ $this->handler = call_user_func($this->handler, $record, $this);
+ if (!$this->handler instanceof HandlerInterface) {
+ throw new \RuntimeException("The factory callable should return a HandlerInterface");
+ }
+ }
+ $this->handler->handleBatch($this->buffer);
+ $this->buffer = array();
+ }
+ } else {
+ $this->handler->handle($record);
+ }
+
+ return false === $this->bubble;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function close()
+ {
+ if (null !== $this->passthruLevel) {
+ $level = $this->passthruLevel;
+ $this->buffer = array_filter($this->buffer, function ($record) use ($level) {
+ return $record['level'] >= $level;
+ });
+ if (count($this->buffer) > 0) {
+ $this->handler->handleBatch($this->buffer);
+ $this->buffer = array();
+ }
+ }
+ }
+
+ /**
+ * Resets the state of the handler. Stops forwarding records to the wrapped handler.
+ */
+ public function reset()
+ {
+ $this->buffering = true;
+ }
+
+ /**
+ * Clears the buffer without flushing any messages down to the wrapped handler.
+ *
+ * It also resets the handler to its initial buffering state.
+ */
+ public function clear()
+ {
+ $this->buffer = array();
+ $this->reset();
+ }
+}
diff --git a/vendor/monolog/monolog/src/Monolog/Handler/FirePHPHandler.php b/vendor/monolog/monolog/src/Monolog/Handler/FirePHPHandler.php
new file mode 100644
index 00000000..fee47950
--- /dev/null
+++ b/vendor/monolog/monolog/src/Monolog/Handler/FirePHPHandler.php
@@ -0,0 +1,195 @@
+<?php
+
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Handler;
+
+use Monolog\Formatter\WildfireFormatter;
+
+/**
+ * Simple FirePHP Handler (http://www.firephp.org/), which uses the Wildfire protocol.
+ *
+ * @author Eric Clemmons (@ericclemmons) <eric@uxdriven.com>
+ */
+class FirePHPHandler extends AbstractProcessingHandler
+{
+ /**
+ * WildFire JSON header message format
+ */
+ const PROTOCOL_URI = 'http://meta.wildfirehq.org/Protocol/JsonStream/0.2';
+
+ /**
+ * FirePHP structure for parsing messages & their presentation
+ */
+ const STRUCTURE_URI = 'http://meta.firephp.org/Wildfire/Structure/FirePHP/FirebugConsole/0.1';
+
+ /**
+ * Must reference a "known" plugin, otherwise headers won't display in FirePHP
+ */
+ const PLUGIN_URI = 'http://meta.firephp.org/Wildfire/Plugin/FirePHP/Library-FirePHPCore/0.3';
+
+ /**
+ * Header prefix for Wildfire to recognize & parse headers
+ */
+ const HEADER_PREFIX = 'X-Wf';
+
+ /**
+ * Whether or not Wildfire vendor-specific headers have been generated & sent yet
+ */
+ protected static $initialized = false;
+
+ /**
+ * Shared static message index between potentially multiple handlers
+ * @var int
+ */
+ protected static $messageIndex = 1;
+
+ protected static $sendHeaders = true;
+
+ /**
+ * Base header creation function used by init headers & record headers
+ *
+ * @param array $meta Wildfire Plugin, Protocol & Structure Indexes
+ * @param string $message Log message
+ * @return array Complete header string ready for the client as key and message as value
+ */
+ protected function createHeader(array $meta, $message)
+ {
+ $header = sprintf('%s-%s', self::HEADER_PREFIX, join('-', $meta));
+
+ return array($header => $message);
+ }
+
+ /**
+ * Creates message header from record
+ *
+ * @see createHeader()
+ * @param array $record
+ * @return string
+ */
+ protected function createRecordHeader(array $record)
+ {
+ // Wildfire is extensible to support multiple protocols & plugins in a single request,
+ // but we're not taking advantage of that (yet), so we're using "1" for simplicity's sake.
+ return $this->createHeader(
+ array(1, 1, 1, self::$messageIndex++),
+ $record['formatted']
+ );
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ protected function getDefaultFormatter()
+ {
+ return new WildfireFormatter();
+ }
+
+ /**
+ * Wildfire initialization headers to enable message parsing
+ *
+ * @see createHeader()
+ * @see sendHeader()
+ * @return array
+ */
+ protected function getInitHeaders()
+ {
+ // Initial payload consists of required headers for Wildfire
+ return array_merge(
+ $this->createHeader(array('Protocol', 1), self::PROTOCOL_URI),
+ $this->createHeader(array(1, 'Structure', 1), self::STRUCTURE_URI),
+ $this->createHeader(array(1, 'Plugin', 1), self::PLUGIN_URI)
+ );
+ }
+
+ /**
+ * Send header string to the client
+ *
+ * @param string $header
+ * @param string $content
+ */
+ protected function sendHeader($header, $content)
+ {
+ if (!headers_sent() && self::$sendHeaders) {
+ header(sprintf('%s: %s', $header, $content));
+ }
+ }
+
+ /**
+ * Creates & sends header for a record, ensuring init headers have been sent prior
+ *
+ * @see sendHeader()
+ * @see sendInitHeaders()
+ * @param array $record
+ */
+ protected function write(array $record)
+ {
+ if (!self::$sendHeaders) {
+ return;
+ }
+
+ // WildFire-specific headers must be sent prior to any messages
+ if (!self::$initialized) {
+ self::$initialized = true;
+
+ self::$sendHeaders = $this->headersAccepted();
+ if (!self::$sendHeaders) {
+ return;
+ }
+
+ foreach ($this->getInitHeaders() as $header => $content) {
+ $this->sendHeader($header, $content);
+ }
+ }
+
+ $header = $this->createRecordHeader($record);
+ if (trim(current($header)) !== '') {
+ $this->sendHeader(key($header), current($header));
+ }
+ }
+
+ /**
+ * Verifies if the headers are accepted by the current user agent
+ *
+ * @return Boolean
+ */
+ protected function headersAccepted()
+ {
+ if (!empty($_SERVER['HTTP_USER_AGENT']) && preg_match('{\bFirePHP/\d+\.\d+\b}', $_SERVER['HTTP_USER_AGENT'])) {
+ return true;
+ }
+
+ return isset($_SERVER['HTTP_X_FIREPHP_VERSION']);
+ }
+
+ /**
+ * BC getter for the sendHeaders property that has been made static
+ */
+ public function __get($property)
+ {
+ if ('sendHeaders' !== $property) {
+ throw new \InvalidArgumentException('Undefined property '.$property);
+ }
+
+ return static::$sendHeaders;
+ }
+
+ /**
+ * BC setter for the sendHeaders property that has been made static
+ */
+ public function __set($property, $value)
+ {
+ if ('sendHeaders' !== $property) {
+ throw new \InvalidArgumentException('Undefined property '.$property);
+ }
+
+ static::$sendHeaders = $value;
+ }
+}
diff --git a/vendor/monolog/monolog/src/Monolog/Handler/FleepHookHandler.php b/vendor/monolog/monolog/src/Monolog/Handler/FleepHookHandler.php
new file mode 100644
index 00000000..388692c4
--- /dev/null
+++ b/vendor/monolog/monolog/src/Monolog/Handler/FleepHookHandler.php
@@ -0,0 +1,126 @@
+<?php
+
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Handler;
+
+use Monolog\Formatter\LineFormatter;
+use Monolog\Logger;
+
+/**
+ * Sends logs to Fleep.io using Webhook integrations
+ *
+ * You'll need a Fleep.io account to use this handler.
+ *
+ * @see https://fleep.io/integrations/webhooks/ Fleep Webhooks Documentation
+ * @author Ando Roots <ando@sqroot.eu>
+ */
+class FleepHookHandler extends SocketHandler
+{
+ const FLEEP_HOST = 'fleep.io';
+
+ const FLEEP_HOOK_URI = '/hook/';
+
+ /**
+ * @var string Webhook token (specifies the conversation where logs are sent)
+ */
+ protected $token;
+
+ /**
+ * Construct a new Fleep.io Handler.
+ *
+ * For instructions on how to create a new web hook in your conversations
+ * see https://fleep.io/integrations/webhooks/
+ *
+ * @param string $token Webhook token
+ * @param bool|int $level The minimum logging level at which this handler will be triggered
+ * @param bool $bubble Whether the messages that are handled can bubble up the stack or not
+ * @throws MissingExtensionException
+ */
+ public function __construct($token, $level = Logger::DEBUG, $bubble = true)
+ {
+ if (!extension_loaded('openssl')) {
+ throw new MissingExtensionException('The OpenSSL PHP extension is required to use the FleepHookHandler');
+ }
+
+ $this->token = $token;
+
+ $connectionString = 'ssl://' . self::FLEEP_HOST . ':443';
+ parent::__construct($connectionString, $level, $bubble);
+ }
+
+ /**
+ * Returns the default formatter to use with this handler
+ *
+ * Overloaded to remove empty context and extra arrays from the end of the log message.
+ *
+ * @return LineFormatter
+ */
+ protected function getDefaultFormatter()
+ {
+ return new LineFormatter(null, null, true, true);
+ }
+
+ /**
+ * Handles a log record
+ *
+ * @param array $record
+ */
+ public function write(array $record)
+ {
+ parent::write($record);
+ $this->closeSocket();
+ }
+
+ /**
+ * {@inheritdoc}
+ *
+ * @param array $record
+ * @return string
+ */
+ protected function generateDataStream($record)
+ {
+ $content = $this->buildContent($record);
+
+ return $this->buildHeader($content) . $content;
+ }
+
+ /**
+ * Builds the header of the API Call
+ *
+ * @param string $content
+ * @return string
+ */
+ private function buildHeader($content)
+ {
+ $header = "POST " . self::FLEEP_HOOK_URI . $this->token . " HTTP/1.1\r\n";
+ $header .= "Host: " . self::FLEEP_HOST . "\r\n";
+ $header .= "Content-Type: application/x-www-form-urlencoded\r\n";
+ $header .= "Content-Length: " . strlen($content) . "\r\n";
+ $header .= "\r\n";
+
+ return $header;
+ }
+
+ /**
+ * Builds the body of API call
+ *
+ * @param array $record
+ * @return string
+ */
+ private function buildContent($record)
+ {
+ $dataArray = array(
+ 'message' => $record['formatted']
+ );
+
+ return http_build_query($dataArray);
+ }
+}
diff --git a/vendor/monolog/monolog/src/Monolog/Handler/FlowdockHandler.php b/vendor/monolog/monolog/src/Monolog/Handler/FlowdockHandler.php
new file mode 100644
index 00000000..6eaaa9d4
--- /dev/null
+++ b/vendor/monolog/monolog/src/Monolog/Handler/FlowdockHandler.php
@@ -0,0 +1,103 @@
+<?php
+
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Handler;
+
+use Monolog\Logger;
+
+/**
+ * Sends notifications through the Flowdock push API
+ *
+ * This must be configured with a FlowdockFormatter instance via setFormatter()
+ *
+ * Notes:
+ * API token - Flowdock API token
+ *
+ * @author Dominik Liebler <liebler.dominik@gmail.com>
+ * @see https://www.flowdock.com/api/push
+ */
+class FlowdockHandler extends SocketHandler
+{
+ /**
+ * @var string
+ */
+ protected $apiToken;
+
+ /**
+ * @param string $apiToken
+ * @param bool|int $level The minimum logging level at which this handler will be triggered
+ * @param bool $bubble Whether the messages that are handled can bubble up the stack or not
+ *
+ * @throws MissingExtensionException if OpenSSL is missing
+ */
+ public function __construct($apiToken, $level = Logger::DEBUG, $bubble = true)
+ {
+ if (!extension_loaded('openssl')) {
+ throw new MissingExtensionException('The OpenSSL PHP extension is required to use the FlowdockHandler');
+ }
+
+ parent::__construct('ssl://api.flowdock.com:443', $level, $bubble);
+ $this->apiToken = $apiToken;
+ }
+
+ /**
+ * {@inheritdoc}
+ *
+ * @param array $record
+ */
+ protected function write(array $record)
+ {
+ parent::write($record);
+
+ $this->closeSocket();
+ }
+
+ /**
+ * {@inheritdoc}
+ *
+ * @param array $record
+ * @return string
+ */
+ protected function generateDataStream($record)
+ {
+ $content = $this->buildContent($record);
+
+ return $this->buildHeader($content) . $content;
+ }
+
+ /**
+ * Builds the body of API call
+ *
+ * @param array $record
+ * @return string
+ */
+ private function buildContent($record)
+ {
+ return json_encode($record['formatted']['flowdock']);
+ }
+
+ /**
+ * Builds the header of the API Call
+ *
+ * @param string $content
+ * @return string
+ */
+ private function buildHeader($content)
+ {
+ $header = "POST /v1/messages/team_inbox/" . $this->apiToken . " HTTP/1.1\r\n";
+ $header .= "Host: api.flowdock.com\r\n";
+ $header .= "Content-Type: application/json\r\n";
+ $header .= "Content-Length: " . strlen($content) . "\r\n";
+ $header .= "\r\n";
+
+ return $header;
+ }
+}
diff --git a/vendor/monolog/monolog/src/Monolog/Handler/GelfHandler.php b/vendor/monolog/monolog/src/Monolog/Handler/GelfHandler.php
new file mode 100644
index 00000000..28c7b55f
--- /dev/null
+++ b/vendor/monolog/monolog/src/Monolog/Handler/GelfHandler.php
@@ -0,0 +1,73 @@
+<?php
+
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Handler;
+
+use Gelf\IMessagePublisher;
+use Gelf\PublisherInterface;
+use Gelf\Publisher;
+use InvalidArgumentException;
+use Monolog\Logger;
+use Monolog\Formatter\GelfMessageFormatter;
+
+/**
+ * Handler to send messages to a Graylog2 (http://www.graylog2.org) server
+ *
+ * @author Matt Lehner <mlehner@gmail.com>
+ * @author Benjamin Zikarsky <benjamin@zikarsky.de>
+ */
+class GelfHandler extends AbstractProcessingHandler
+{
+ /**
+ * @var Publisher the publisher object that sends the message to the server
+ */
+ protected $publisher;
+
+ /**
+ * @param PublisherInterface|IMessagePublisher|Publisher $publisher a publisher object
+ * @param integer $level The minimum logging level at which this handler will be triggered
+ * @param boolean $bubble Whether the messages that are handled can bubble up the stack or not
+ */
+ public function __construct($publisher, $level = Logger::DEBUG, $bubble = true)
+ {
+ parent::__construct($level, $bubble);
+
+ if (!$publisher instanceof Publisher && !$publisher instanceof IMessagePublisher && !$publisher instanceof PublisherInterface) {
+ throw new InvalidArgumentException("Invalid publisher, expected a Gelf\Publisher, Gelf\IMessagePublisher or Gelf\PublisherInterface instance");
+ }
+
+ $this->publisher = $publisher;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function close()
+ {
+ $this->publisher = null;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function write(array $record)
+ {
+ $this->publisher->publish($record['formatted']);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ protected function getDefaultFormatter()
+ {
+ return new GelfMessageFormatter();
+ }
+}
diff --git a/vendor/monolog/monolog/src/Monolog/Handler/GroupHandler.php b/vendor/monolog/monolog/src/Monolog/Handler/GroupHandler.php
new file mode 100644
index 00000000..99384d35
--- /dev/null
+++ b/vendor/monolog/monolog/src/Monolog/Handler/GroupHandler.php
@@ -0,0 +1,80 @@
+<?php
+
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Handler;
+
+/**
+ * Forwards records to multiple handlers
+ *
+ * @author Lenar Lõhmus <lenar@city.ee>
+ */
+class GroupHandler extends AbstractHandler
+{
+ protected $handlers;
+
+ /**
+ * @param array $handlers Array of Handlers.
+ * @param Boolean $bubble Whether the messages that are handled can bubble up the stack or not
+ */
+ public function __construct(array $handlers, $bubble = true)
+ {
+ foreach ($handlers as $handler) {
+ if (!$handler instanceof HandlerInterface) {
+ throw new \InvalidArgumentException('The first argument of the GroupHandler must be an array of HandlerInterface instances.');
+ }
+ }
+
+ $this->handlers = $handlers;
+ $this->bubble = $bubble;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function isHandling(array $record)
+ {
+ foreach ($this->handlers as $handler) {
+ if ($handler->isHandling($record)) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function handle(array $record)
+ {
+ if ($this->processors) {
+ foreach ($this->processors as $processor) {
+ $record = call_user_func($processor, $record);
+ }
+ }
+
+ foreach ($this->handlers as $handler) {
+ $handler->handle($record);
+ }
+
+ return false === $this->bubble;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function handleBatch(array $records)
+ {
+ foreach ($this->handlers as $handler) {
+ $handler->handleBatch($records);
+ }
+ }
+}
diff --git a/vendor/monolog/monolog/src/Monolog/Handler/HandlerInterface.php b/vendor/monolog/monolog/src/Monolog/Handler/HandlerInterface.php
new file mode 100644
index 00000000..d920c4ba
--- /dev/null
+++ b/vendor/monolog/monolog/src/Monolog/Handler/HandlerInterface.php
@@ -0,0 +1,90 @@
+<?php
+
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Handler;
+
+use Monolog\Formatter\FormatterInterface;
+
+/**
+ * Interface that all Monolog Handlers must implement
+ *
+ * @author Jordi Boggiano <j.boggiano@seld.be>
+ */
+interface HandlerInterface
+{
+ /**
+ * Checks whether the given record will be handled by this handler.
+ *
+ * This is mostly done for performance reasons, to avoid calling processors for nothing.
+ *
+ * Handlers should still check the record levels within handle(), returning false in isHandling()
+ * is no guarantee that handle() will not be called, and isHandling() might not be called
+ * for a given record.
+ *
+ * @param array $record Partial log record containing only a level key
+ *
+ * @return Boolean
+ */
+ public function isHandling(array $record);
+
+ /**
+ * Handles a record.
+ *
+ * All records may be passed to this method, and the handler should discard
+ * those that it does not want to handle.
+ *
+ * The return value of this function controls the bubbling process of the handler stack.
+ * Unless the bubbling is interrupted (by returning true), the Logger class will keep on
+ * calling further handlers in the stack with a given log record.
+ *
+ * @param array $record The record to handle
+ * @return Boolean true means that this handler handled the record, and that bubbling is not permitted.
+ * false means the record was either not processed or that this handler allows bubbling.
+ */
+ public function handle(array $record);
+
+ /**
+ * Handles a set of records at once.
+ *
+ * @param array $records The records to handle (an array of record arrays)
+ */
+ public function handleBatch(array $records);
+
+ /**
+ * Adds a processor in the stack.
+ *
+ * @param callable $callback
+ * @return self
+ */
+ public function pushProcessor($callback);
+
+ /**
+ * Removes the processor on top of the stack and returns it.
+ *
+ * @return callable
+ */
+ public function popProcessor();
+
+ /**
+ * Sets the formatter.
+ *
+ * @param FormatterInterface $formatter
+ * @return self
+ */
+ public function setFormatter(FormatterInterface $formatter);
+
+ /**
+ * Gets the formatter.
+ *
+ * @return FormatterInterface
+ */
+ public function getFormatter();
+}
diff --git a/vendor/monolog/monolog/src/Monolog/Handler/HipChatHandler.php b/vendor/monolog/monolog/src/Monolog/Handler/HipChatHandler.php
new file mode 100644
index 00000000..34d3437f
--- /dev/null
+++ b/vendor/monolog/monolog/src/Monolog/Handler/HipChatHandler.php
@@ -0,0 +1,337 @@
+<?php
+
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Handler;
+
+use Monolog\Logger;
+
+/**
+ * Sends notifications through the hipchat api to a hipchat room
+ *
+ * Notes:
+ * API token - HipChat API token
+ * Room - HipChat Room Id or name, where messages are sent
+ * Name - Name used to send the message (from)
+ * notify - Should the message trigger a notification in the clients
+ * version - The API version to use (HipChatHandler::API_V1 | HipChatHandler::API_V2)
+ *
+ * @author Rafael Dohms <rafael@doh.ms>
+ * @see https://www.hipchat.com/docs/api
+ */
+class HipChatHandler extends SocketHandler
+{
+ /**
+ * Use API version 1
+ */
+ const API_V1 = 'v1';
+
+ /**
+ * Use API version v2
+ */
+ const API_V2 = 'v2';
+
+ /**
+ * The maximum allowed length for the name used in the "from" field.
+ */
+ const MAXIMUM_NAME_LENGTH = 15;
+
+ /**
+ * The maximum allowed length for the message.
+ */
+ const MAXIMUM_MESSAGE_LENGTH = 9500;
+
+ /**
+ * @var string
+ */
+ private $token;
+
+ /**
+ * @var string
+ */
+ private $room;
+
+ /**
+ * @var string
+ */
+ private $name;
+
+ /**
+ * @var bool
+ */
+ private $notify;
+
+ /**
+ * @var string
+ */
+ private $format;
+
+ /**
+ * @var string
+ */
+ private $host;
+
+ /**
+ * @var string
+ */
+ private $version;
+
+ /**
+ * @param string $token HipChat API Token
+ * @param string $room The room that should be alerted of the message (Id or Name)
+ * @param string $name Name used in the "from" field. Not used for v2
+ * @param bool $notify Trigger a notification in clients or not
+ * @param int $level The minimum logging level at which this handler will be triggered
+ * @param bool $bubble Whether the messages that are handled can bubble up the stack or not
+ * @param bool $useSSL Whether to connect via SSL.
+ * @param string $format The format of the messages (default to text, can be set to html if you have html in the messages)
+ * @param string $host The HipChat server hostname.
+ * @param string $version The HipChat API version (default HipChatHandler::API_V1)
+ */
+ public function __construct($token, $room, $name = 'Monolog', $notify = false, $level = Logger::CRITICAL, $bubble = true, $useSSL = true, $format = 'text', $host = 'api.hipchat.com', $version = self::API_V1)
+ {
+ if ($version == self::API_V1 && !$this->validateStringLength($name, static::MAXIMUM_NAME_LENGTH)) {
+ throw new \InvalidArgumentException('The supplied name is too long. HipChat\'s v1 API supports names up to 15 UTF-8 characters.');
+ }
+
+ $connectionString = $useSSL ? 'ssl://'.$host.':443' : $host.':80';
+ parent::__construct($connectionString, $level, $bubble);
+
+ $this->token = $token;
+ $this->name = $name;
+ $this->notify = $notify;
+ $this->room = $room;
+ $this->format = $format;
+ $this->host = $host;
+ $this->version = $version;
+ }
+
+ /**
+ * {@inheritdoc}
+ *
+ * @param array $record
+ * @return string
+ */
+ protected function generateDataStream($record)
+ {
+ $content = $this->buildContent($record);
+
+ return $this->buildHeader($content) . $content;
+ }
+
+ /**
+ * Builds the body of API call
+ *
+ * @param array $record
+ * @return string
+ */
+ private function buildContent($record)
+ {
+ $dataArray = array(
+ 'notify' => $this->version == self::API_V1 ?
+ ($this->notify ? 1 : 0) :
+ ($this->notify ? 'true' : 'false'),
+ 'message' => $record['formatted'],
+ 'message_format' => $this->format,
+ 'color' => $this->getAlertColor($record['level']),
+ );
+
+ // if we are using the legacy API then we need to send some additional information
+ if ($this->version == self::API_V1) {
+ $dataArray['room_id'] = $this->room;
+ $dataArray['from'] = $this->name;
+ }
+
+ return http_build_query($dataArray);
+ }
+
+ /**
+ * Builds the header of the API Call
+ *
+ * @param string $content
+ * @return string
+ */
+ private function buildHeader($content)
+ {
+ if ($this->version == self::API_V1) {
+ $header = "POST /v1/rooms/message?format=json&auth_token={$this->token} HTTP/1.1\r\n";
+ } else {
+ // needed for rooms with special (spaces, etc) characters in the name
+ $room = rawurlencode($this->room);
+ $header = "POST /v2/room/{$room}/notification?auth_token={$this->token} HTTP/1.1\r\n";
+ }
+
+ $header .= "Host: {$this->host}\r\n";
+ $header .= "Content-Type: application/x-www-form-urlencoded\r\n";
+ $header .= "Content-Length: " . strlen($content) . "\r\n";
+ $header .= "\r\n";
+
+ return $header;
+ }
+
+ /**
+ * Assigns a color to each level of log records.
+ *
+ * @param integer $level
+ * @return string
+ */
+ protected function getAlertColor($level)
+ {
+ switch (true) {
+ case $level >= Logger::ERROR:
+ return 'red';
+ case $level >= Logger::WARNING:
+ return 'yellow';
+ case $level >= Logger::INFO:
+ return 'green';
+ case $level == Logger::DEBUG:
+ return 'gray';
+ default:
+ return 'yellow';
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ *
+ * @param array $record
+ */
+ protected function write(array $record)
+ {
+ parent::write($record);
+ $this->closeSocket();
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function handleBatch(array $records)
+ {
+ if (count($records) == 0) {
+ return true;
+ }
+
+ $batchRecords = $this->combineRecords($records);
+
+ $handled = false;
+ foreach ($batchRecords as $batchRecord) {
+ if ($this->isHandling($batchRecord)) {
+ $this->write($batchRecord);
+ $handled = true;
+ }
+ }
+
+ if (!$handled) {
+ return false;
+ }
+
+ return false === $this->bubble;
+ }
+
+ /**
+ * Combines multiple records into one. Error level of the combined record
+ * will be the highest level from the given records. Datetime will be taken
+ * from the first record.
+ *
+ * @param $records
+ * @return array
+ */
+ private function combineRecords($records)
+ {
+ $batchRecord = null;
+ $batchRecords = array();
+ $messages = array();
+ $formattedMessages = array();
+ $level = 0;
+ $levelName = null;
+ $datetime = null;
+
+ foreach ($records as $record) {
+ $record = $this->processRecord($record);
+
+ if ($record['level'] > $level) {
+ $level = $record['level'];
+ $levelName = $record['level_name'];
+ }
+
+ if (null === $datetime) {
+ $datetime = $record['datetime'];
+ }
+
+ $messages[] = $record['message'];
+ $messageStr = implode(PHP_EOL, $messages);
+ $formattedMessages[] = $this->getFormatter()->format($record);
+ $formattedMessageStr = implode('', $formattedMessages);
+
+ $batchRecord = array(
+ 'message' => $messageStr,
+ 'formatted' => $formattedMessageStr,
+ 'context' => array(),
+ 'extra' => array(),
+ );
+
+ if (!$this->validateStringLength($batchRecord['formatted'], static::MAXIMUM_MESSAGE_LENGTH)) {
+ // Pop the last message and implode the remaining messages
+ $lastMessage = array_pop($messages);
+ $lastFormattedMessage = array_pop($formattedMessages);
+ $batchRecord['message'] = implode(PHP_EOL, $messages);
+ $batchRecord['formatted'] = implode('', $formattedMessages);
+
+ $batchRecords[] = $batchRecord;
+ $messages = array($lastMessage);
+ $formattedMessages = array($lastFormattedMessage);
+
+ $batchRecord = null;
+ }
+ }
+
+ if (null !== $batchRecord) {
+ $batchRecords[] = $batchRecord;
+ }
+
+ // Set the max level and datetime for all records
+ foreach ($batchRecords as &$batchRecord) {
+ $batchRecord = array_merge(
+ $batchRecord,
+ array(
+ 'level' => $level,
+ 'level_name' => $levelName,
+ 'datetime' => $datetime
+ )
+ );
+ }
+
+ return $batchRecords;
+ }
+
+ /**
+ * Validates the length of a string.
+ *
+ * If the `mb_strlen()` function is available, it will use that, as HipChat
+ * allows UTF-8 characters. Otherwise, it will fall back to `strlen()`.
+ *
+ * Note that this might cause false failures in the specific case of using
+ * a valid name with less than 16 characters, but 16 or more bytes, on a
+ * system where `mb_strlen()` is unavailable.
+ *
+ * @param string $str
+ * @param int $length
+ *
+ * @return bool
+ */
+ private function validateStringLength($str, $length)
+ {
+ if (function_exists('mb_strlen')) {
+ return (mb_strlen($str) <= $length);
+ }
+
+ return (strlen($str) <= $length);
+ }
+}
diff --git a/vendor/monolog/monolog/src/Monolog/Handler/LogEntriesHandler.php b/vendor/monolog/monolog/src/Monolog/Handler/LogEntriesHandler.php
new file mode 100644
index 00000000..bd56230f
--- /dev/null
+++ b/vendor/monolog/monolog/src/Monolog/Handler/LogEntriesHandler.php
@@ -0,0 +1,55 @@
+<?php
+
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Handler;
+
+use Monolog\Logger;
+
+/**
+ * @author Robert Kaufmann III <rok3@rok3.me>
+ */
+class LogEntriesHandler extends SocketHandler
+{
+ /**
+ * @var string
+ */
+ protected $logToken;
+
+ /**
+ * @param string $token Log token supplied by LogEntries
+ * @param boolean $useSSL Whether or not SSL encryption should be used.
+ * @param int $level The minimum logging level to trigger this handler
+ * @param boolean $bubble Whether or not messages that are handled should bubble up the stack.
+ *
+ * @throws MissingExtensionException If SSL encryption is set to true and OpenSSL is missing
+ */
+ public function __construct($token, $useSSL = true, $level = Logger::DEBUG, $bubble = true)
+ {
+ if ($useSSL && !extension_loaded('openssl')) {
+ throw new MissingExtensionException('The OpenSSL PHP plugin is required to use SSL encrypted connection for LogEntriesHandler');
+ }
+
+ $endpoint = $useSSL ? 'ssl://data.logentries.com:443' : 'data.logentries.com:80';
+ parent::__construct($endpoint, $level, $bubble);
+ $this->logToken = $token;
+ }
+
+ /**
+ * {@inheritdoc}
+ *
+ * @param array $record
+ * @return string
+ */
+ protected function generateDataStream($record)
+ {
+ return $this->logToken . ' ' . $record['formatted'];
+ }
+}
diff --git a/vendor/monolog/monolog/src/Monolog/Handler/LogglyHandler.php b/vendor/monolog/monolog/src/Monolog/Handler/LogglyHandler.php
new file mode 100644
index 00000000..9785cec0
--- /dev/null
+++ b/vendor/monolog/monolog/src/Monolog/Handler/LogglyHandler.php
@@ -0,0 +1,106 @@
+<?php
+
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Handler;
+
+use Monolog\Logger;
+use Monolog\Formatter\LogglyFormatter;
+
+/**
+ * Sends errors to Loggly.
+ *
+ * @author Przemek Sobstel <przemek@sobstel.org>
+ * @author Adam Pancutt <adam@pancutt.com>
+ * @author Gregory Barchard <gregory@barchard.net>
+ */
+class LogglyHandler extends AbstractProcessingHandler
+{
+ const HOST = 'logs-01.loggly.com';
+ const ENDPOINT_SINGLE = 'inputs';
+ const ENDPOINT_BATCH = 'bulk';
+
+ protected $token;
+
+ protected $tag = array();
+
+ public function __construct($token, $level = Logger::DEBUG, $bubble = true)
+ {
+ if (!extension_loaded('curl')) {
+ throw new \LogicException('The curl extension is needed to use the LogglyHandler');
+ }
+
+ $this->token = $token;
+
+ parent::__construct($level, $bubble);
+ }
+
+ public function setTag($tag)
+ {
+ $tag = !empty($tag) ? $tag : array();
+ $this->tag = is_array($tag) ? $tag : array($tag);
+ }
+
+ public function addTag($tag)
+ {
+ if (!empty($tag)) {
+ $tag = is_array($tag) ? $tag : array($tag);
+ $this->tag = array_unique(array_merge($this->tag, $tag));
+ }
+ }
+
+ protected function write(array $record)
+ {
+ $this->send($record["formatted"], self::ENDPOINT_SINGLE);
+ }
+
+ public function handleBatch(array $records)
+ {
+ $level = $this->level;
+
+ $records = array_filter($records, function ($record) use ($level) {
+ return ($record['level'] >= $level);
+ });
+
+ if ($records) {
+ $this->send($this->getFormatter()->formatBatch($records), self::ENDPOINT_BATCH);
+ }
+ }
+
+ protected function send($data, $endpoint)
+ {
+ $url = sprintf("https://%s/%s/%s/", self::HOST, $endpoint, $this->token);
+
+ $headers = array('Content-Type: application/json');
+
+ if (!empty($this->tag)) {
+ $headers[] = 'X-LOGGLY-TAG: '.implode(',', $this->tag);
+ }
+
+ $ch = curl_init();
+
+ curl_setopt($ch, CURLOPT_URL, $url);
+ curl_setopt($ch, CURLOPT_POST, true);
+ curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
+ curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
+ curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
+
+ if (curl_exec($ch) === false) {
+ throw new \RuntimeException(sprintf('Curl error (code %s): %s', curl_errno($ch), curl_error($ch)));
+ }
+
+ curl_close($ch);
+ }
+
+ protected function getDefaultFormatter()
+ {
+ return new LogglyFormatter();
+ }
+}
diff --git a/vendor/monolog/monolog/src/Monolog/Handler/MailHandler.php b/vendor/monolog/monolog/src/Monolog/Handler/MailHandler.php
new file mode 100644
index 00000000..50ed6380
--- /dev/null
+++ b/vendor/monolog/monolog/src/Monolog/Handler/MailHandler.php
@@ -0,0 +1,55 @@
+<?php
+
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Handler;
+
+/**
+ * Base class for all mail handlers
+ *
+ * @author Gyula Sallai
+ */
+abstract class MailHandler extends AbstractProcessingHandler
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function handleBatch(array $records)
+ {
+ $messages = array();
+
+ foreach ($records as $record) {
+ if ($record['level'] < $this->level) {
+ continue;
+ }
+ $messages[] = $this->processRecord($record);
+ }
+
+ if (!empty($messages)) {
+ $this->send((string) $this->getFormatter()->formatBatch($messages), $messages);
+ }
+ }
+
+ /**
+ * Send a mail with the given content
+ *
+ * @param string $content formatted email body to be sent
+ * @param array $records the array of log records that formed this content
+ */
+ abstract protected function send($content, array $records);
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function write(array $record)
+ {
+ $this->send((string) $record['formatted'], array($record));
+ }
+}
diff --git a/vendor/monolog/monolog/src/Monolog/Handler/MandrillHandler.php b/vendor/monolog/monolog/src/Monolog/Handler/MandrillHandler.php
new file mode 100644
index 00000000..6726e1e4
--- /dev/null
+++ b/vendor/monolog/monolog/src/Monolog/Handler/MandrillHandler.php
@@ -0,0 +1,71 @@
+<?php
+
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Handler;
+
+use Monolog\Logger;
+
+/**
+ * MandrillHandler uses cURL to send the emails to the Mandrill API
+ *
+ * @author Adam Nicholson <adamnicholson10@gmail.com>
+ */
+class MandrillHandler extends MailHandler
+{
+ protected $client;
+ protected $message;
+
+ /**
+ * @param string $apiKey A valid Mandrill API key
+ * @param callable|\Swift_Message $message An example message for real messages, only the body will be replaced
+ * @param integer $level The minimum logging level at which this handler will be triggered
+ * @param Boolean $bubble Whether the messages that are handled can bubble up the stack or not
+ */
+ public function __construct($apiKey, $message, $level = Logger::ERROR, $bubble = true)
+ {
+ parent::__construct($level, $bubble);
+
+ if (!$message instanceof \Swift_Message && is_callable($message)) {
+ $message = call_user_func($message);
+ }
+ if (!$message instanceof \Swift_Message) {
+ throw new \InvalidArgumentException('You must provide either a Swift_Message instance or a callable returning it');
+ }
+ $this->message = $message;
+ $this->apiKey = $apiKey;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function send($content, array $records)
+ {
+ $message = clone $this->message;
+ $message->setBody($content);
+ $message->setDate(time());
+
+ $ch = curl_init();
+
+ curl_setopt($ch, CURLOPT_URL, 'https://mandrillapp.com/api/1.0/messages/send-raw.json');
+ curl_setopt($ch, CURLOPT_POST, 1);
+ curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
+ curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query(array(
+ 'key' => $this->apiKey,
+ 'raw_message' => (string) $message,
+ 'async' => false,
+ )));
+
+ if (curl_exec($ch) === false) {
+ throw new \RuntimeException(sprintf('Curl error (code %s): %s', curl_errno($ch), curl_error($ch)));
+ }
+ curl_close($ch);
+ }
+}
diff --git a/vendor/monolog/monolog/src/Monolog/Handler/MissingExtensionException.php b/vendor/monolog/monolog/src/Monolog/Handler/MissingExtensionException.php
new file mode 100644
index 00000000..4724a7e2
--- /dev/null
+++ b/vendor/monolog/monolog/src/Monolog/Handler/MissingExtensionException.php
@@ -0,0 +1,21 @@
+<?php
+
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Handler;
+
+/**
+ * Exception can be thrown if an extension for an handler is missing
+ *
+ * @author Christian Bergau <cbergau86@gmail.com>
+ */
+class MissingExtensionException extends \Exception
+{
+}
diff --git a/vendor/monolog/monolog/src/Monolog/Handler/MongoDBHandler.php b/vendor/monolog/monolog/src/Monolog/Handler/MongoDBHandler.php
new file mode 100644
index 00000000..6c431f2b
--- /dev/null
+++ b/vendor/monolog/monolog/src/Monolog/Handler/MongoDBHandler.php
@@ -0,0 +1,55 @@
+<?php
+
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Handler;
+
+use Monolog\Logger;
+use Monolog\Formatter\NormalizerFormatter;
+
+/**
+ * Logs to a MongoDB database.
+ *
+ * usage example:
+ *
+ * $log = new Logger('application');
+ * $mongodb = new MongoDBHandler(new \Mongo("mongodb://localhost:27017"), "logs", "prod");
+ * $log->pushHandler($mongodb);
+ *
+ * @author Thomas Tourlourat <thomas@tourlourat.com>
+ */
+class MongoDBHandler extends AbstractProcessingHandler
+{
+ protected $mongoCollection;
+
+ public function __construct($mongo, $database, $collection, $level = Logger::DEBUG, $bubble = true)
+ {
+ if (!($mongo instanceof \MongoClient || $mongo instanceof \Mongo)) {
+ throw new \InvalidArgumentException('MongoClient or Mongo instance required');
+ }
+
+ $this->mongoCollection = $mongo->selectCollection($database, $collection);
+
+ parent::__construct($level, $bubble);
+ }
+
+ protected function write(array $record)
+ {
+ $this->mongoCollection->save($record["formatted"]);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ protected function getDefaultFormatter()
+ {
+ return new NormalizerFormatter();
+ }
+}
diff --git a/vendor/monolog/monolog/src/Monolog/Handler/NativeMailerHandler.php b/vendor/monolog/monolog/src/Monolog/Handler/NativeMailerHandler.php
new file mode 100644
index 00000000..5118a0e2
--- /dev/null
+++ b/vendor/monolog/monolog/src/Monolog/Handler/NativeMailerHandler.php
@@ -0,0 +1,176 @@
+<?php
+
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Handler;
+
+use Monolog\Logger;
+
+/**
+ * NativeMailerHandler uses the mail() function to send the emails
+ *
+ * @author Christophe Coevoet <stof@notk.org>
+ * @author Mark Garrett <mark@moderndeveloperllc.com>
+ */
+class NativeMailerHandler extends MailHandler
+{
+ /**
+ * The email addresses to which the message will be sent
+ * @var array
+ */
+ protected $to;
+
+ /**
+ * The subject of the email
+ * @var string
+ */
+ protected $subject;
+
+ /**
+ * Optional headers for the message
+ * @var array
+ */
+ protected $headers = array();
+
+ /**
+ * Optional parameters for the message
+ * @var array
+ */
+ protected $parameters = array();
+
+ /**
+ * The wordwrap length for the message
+ * @var integer
+ */
+ protected $maxColumnWidth;
+
+ /**
+ * The Content-type for the message
+ * @var string
+ */
+ protected $contentType = 'text/plain';
+
+ /**
+ * The encoding for the message
+ * @var string
+ */
+ protected $encoding = 'utf-8';
+
+ /**
+ * @param string|array $to The receiver of the mail
+ * @param string $subject The subject of the mail
+ * @param string $from The sender of the mail
+ * @param integer $level The minimum logging level at which this handler will be triggered
+ * @param boolean $bubble Whether the messages that are handled can bubble up the stack or not
+ * @param int $maxColumnWidth The maximum column width that the message lines will have
+ */
+ public function __construct($to, $subject, $from, $level = Logger::ERROR, $bubble = true, $maxColumnWidth = 70)
+ {
+ parent::__construct($level, $bubble);
+ $this->to = is_array($to) ? $to : array($to);
+ $this->subject = $subject;
+ $this->addHeader(sprintf('From: %s', $from));
+ $this->maxColumnWidth = $maxColumnWidth;
+ }
+
+ /**
+ * Add headers to the message
+ *
+ * @param string|array $headers Custom added headers
+ * @return self
+ */
+ public function addHeader($headers)
+ {
+ foreach ((array) $headers as $header) {
+ if (strpos($header, "\n") !== false || strpos($header, "\r") !== false) {
+ throw new \InvalidArgumentException('Headers can not contain newline characters for security reasons');
+ }
+ $this->headers[] = $header;
+ }
+
+ return $this;
+ }
+
+ /**
+ * Add parameters to the message
+ *
+ * @param string|array $parameters Custom added parameters
+ * @return self
+ */
+ public function addParameter($parameters)
+ {
+ $this->parameters = array_merge($this->parameters, (array) $parameters);
+
+ return $this;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function send($content, array $records)
+ {
+ $content = wordwrap($content, $this->maxColumnWidth);
+ $headers = ltrim(implode("\r\n", $this->headers) . "\r\n", "\r\n");
+ $headers .= 'Content-type: ' . $this->getContentType() . '; charset=' . $this->getEncoding() . "\r\n";
+ if ($this->getContentType() == 'text/html' && false === strpos($headers, 'MIME-Version:')) {
+ $headers .= 'MIME-Version: 1.0' . "\r\n";
+ }
+ foreach ($this->to as $to) {
+ mail($to, $this->subject, $content, $headers, implode(' ', $this->parameters));
+ }
+ }
+
+ /**
+ * @return string $contentType
+ */
+ public function getContentType()
+ {
+ return $this->contentType;
+ }
+
+ /**
+ * @return string $encoding
+ */
+ public function getEncoding()
+ {
+ return $this->encoding;
+ }
+
+ /**
+ * @param string $contentType The content type of the email - Defaults to text/plain. Use text/html for HTML
+ * messages.
+ * @return self
+ */
+ public function setContentType($contentType)
+ {
+ if (strpos($contentType, "\n") !== false || strpos($contentType, "\r") !== false) {
+ throw new \InvalidArgumentException('The content type can not contain newline characters to prevent email header injection');
+ }
+
+ $this->contentType = $contentType;
+
+ return $this;
+ }
+
+ /**
+ * @param string $encoding
+ * @return self
+ */
+ public function setEncoding($encoding)
+ {
+ if (strpos($encoding, "\n") !== false || strpos($encoding, "\r") !== false) {
+ throw new \InvalidArgumentException('The encoding can not contain newline characters to prevent email header injection');
+ }
+
+ $this->encoding = $encoding;
+
+ return $this;
+ }
+}
diff --git a/vendor/monolog/monolog/src/Monolog/Handler/NewRelicHandler.php b/vendor/monolog/monolog/src/Monolog/Handler/NewRelicHandler.php
new file mode 100644
index 00000000..8cb4ab38
--- /dev/null
+++ b/vendor/monolog/monolog/src/Monolog/Handler/NewRelicHandler.php
@@ -0,0 +1,198 @@
+<?php
+
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Handler;
+
+use Monolog\Logger;
+use Monolog\Formatter\NormalizerFormatter;
+
+/**
+ * Class to record a log on a NewRelic application.
+ * Enabling New Relic High Security mode may prevent capture of useful information.
+ *
+ * @see https://docs.newrelic.com/docs/agents/php-agent
+ * @see https://docs.newrelic.com/docs/accounts-partnerships/accounts/security/high-security
+ */
+class NewRelicHandler extends AbstractProcessingHandler
+{
+ /**
+ * Name of the New Relic application that will receive logs from this handler.
+ *
+ * @var string
+ */
+ protected $appName;
+
+ /**
+ * Name of the current transaction
+ *
+ * @var string
+ */
+ protected $transactionName;
+
+ /**
+ * Some context and extra data is passed into the handler as arrays of values. Do we send them as is
+ * (useful if we are using the API), or explode them for display on the NewRelic RPM website?
+ *
+ * @var boolean
+ */
+ protected $explodeArrays;
+
+ /**
+ * {@inheritDoc}
+ *
+ * @param string $appName
+ * @param boolean $explodeArrays
+ * @param string $transactionName
+ */
+ public function __construct(
+ $level = Logger::ERROR,
+ $bubble = true,
+ $appName = null,
+ $explodeArrays = false,
+ $transactionName = null
+ ) {
+ parent::__construct($level, $bubble);
+
+ $this->appName = $appName;
+ $this->explodeArrays = $explodeArrays;
+ $this->transactionName = $transactionName;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ protected function write(array $record)
+ {
+ if (!$this->isNewRelicEnabled()) {
+ throw new MissingExtensionException('The newrelic PHP extension is required to use the NewRelicHandler');
+ }
+
+ if ($appName = $this->getAppName($record['context'])) {
+ $this->setNewRelicAppName($appName);
+ }
+
+ if ($transactionName = $this->getTransactionName($record['context'])) {
+ $this->setNewRelicTransactionName($transactionName);
+ unset($record['formatted']['context']['transaction_name']);
+ }
+
+ if (isset($record['context']['exception']) && $record['context']['exception'] instanceof \Exception) {
+ newrelic_notice_error($record['message'], $record['context']['exception']);
+ unset($record['formatted']['context']['exception']);
+ } else {
+ newrelic_notice_error($record['message']);
+ }
+
+ foreach ($record['formatted']['context'] as $key => $parameter) {
+ if (is_array($parameter) && $this->explodeArrays) {
+ foreach ($parameter as $paramKey => $paramValue) {
+ $this->setNewRelicParameter('context_' . $key . '_' . $paramKey, $paramValue);
+ }
+ } else {
+ $this->setNewRelicParameter('context_' . $key, $parameter);
+ }
+ }
+
+ foreach ($record['formatted']['extra'] as $key => $parameter) {
+ if (is_array($parameter) && $this->explodeArrays) {
+ foreach ($parameter as $paramKey => $paramValue) {
+ $this->setNewRelicParameter('extra_' . $key . '_' . $paramKey, $paramValue);
+ }
+ } else {
+ $this->setNewRelicParameter('extra_' . $key, $parameter);
+ }
+ }
+ }
+
+ /**
+ * Checks whether the NewRelic extension is enabled in the system.
+ *
+ * @return bool
+ */
+ protected function isNewRelicEnabled()
+ {
+ return extension_loaded('newrelic');
+ }
+
+ /**
+ * Returns the appname where this log should be sent. Each log can override the default appname, set in this
+ * handler's constructor, by providing the appname in it's context.
+ *
+ * @param array $context
+ * @return null|string
+ */
+ protected function getAppName(array $context)
+ {
+ if (isset($context['appname'])) {
+ return $context['appname'];
+ }
+
+ return $this->appName;
+ }
+
+ /**
+ * Returns the name of the current transaction. Each log can override the default transaction name, set in this
+ * handler's constructor, by providing the transaction_name in it's context
+ *
+ * @param array $context
+ *
+ * @return null|string
+ */
+ protected function getTransactionName(array $context)
+ {
+ if (isset($context['transaction_name'])) {
+ return $context['transaction_name'];
+ }
+
+ return $this->transactionName;
+ }
+
+ /**
+ * Sets the NewRelic application that should receive this log.
+ *
+ * @param string $appName
+ */
+ protected function setNewRelicAppName($appName)
+ {
+ newrelic_set_appname($appName);
+ }
+
+ /**
+ * Overwrites the name of the current transaction
+ *
+ * @param string $transactionName
+ */
+ protected function setNewRelicTransactionName($transactionName)
+ {
+ newrelic_name_transaction($transactionName);
+ }
+
+ /**
+ * @param string $key
+ * @param mixed $value
+ */
+ protected function setNewRelicParameter($key, $value)
+ {
+ if (null === $value || is_scalar($value)) {
+ newrelic_add_custom_parameter($key, $value);
+ } else {
+ newrelic_add_custom_parameter($key, @json_encode($value));
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ protected function getDefaultFormatter()
+ {
+ return new NormalizerFormatter();
+ }
+}
diff --git a/vendor/monolog/monolog/src/Monolog/Handler/NullHandler.php b/vendor/monolog/monolog/src/Monolog/Handler/NullHandler.php
new file mode 100644
index 00000000..3754e45d
--- /dev/null
+++ b/vendor/monolog/monolog/src/Monolog/Handler/NullHandler.php
@@ -0,0 +1,45 @@
+<?php
+
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Handler;
+
+use Monolog\Logger;
+
+/**
+ * Blackhole
+ *
+ * Any record it can handle will be thrown away. This can be used
+ * to put on top of an existing stack to override it temporarily.
+ *
+ * @author Jordi Boggiano <j.boggiano@seld.be>
+ */
+class NullHandler extends AbstractHandler
+{
+ /**
+ * @param integer $level The minimum logging level at which this handler will be triggered
+ */
+ public function __construct($level = Logger::DEBUG)
+ {
+ parent::__construct($level, false);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function handle(array $record)
+ {
+ if ($record['level'] < $this->level) {
+ return false;
+ }
+
+ return true;
+ }
+}
diff --git a/vendor/monolog/monolog/src/Monolog/Handler/PHPConsoleHandler.php b/vendor/monolog/monolog/src/Monolog/Handler/PHPConsoleHandler.php
new file mode 100644
index 00000000..169bea0e
--- /dev/null
+++ b/vendor/monolog/monolog/src/Monolog/Handler/PHPConsoleHandler.php
@@ -0,0 +1,243 @@
+<?php
+
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Handler;
+
+use Exception;
+use Monolog\Formatter\LineFormatter;
+use Monolog\Logger;
+use PhpConsole\Connector;
+use PhpConsole\Handler;
+use PhpConsole\Helper;
+
+/**
+ * Monolog handler for Google Chrome extension "PHP Console"
+ *
+ * Display PHP error/debug log messages in Google Chrome console and notification popups, executes PHP code remotely
+ *
+ * Usage:
+ * 1. Install Google Chrome extension https://chrome.google.com/webstore/detail/php-console/nfhmhhlpfleoednkpnnnkolmclajemef
+ * 2. See overview https://github.com/barbushin/php-console#overview
+ * 3. Install PHP Console library https://github.com/barbushin/php-console#installation
+ * 4. Example (result will looks like http://i.hizliresim.com/vg3Pz4.png)
+ *
+ * $logger = new \Monolog\Logger('all', array(new \Monolog\Handler\PHPConsoleHandler()));
+ * \Monolog\ErrorHandler::register($logger);
+ * echo $undefinedVar;
+ * $logger->addDebug('SELECT * FROM users', array('db', 'time' => 0.012));
+ * PC::debug($_SERVER); // PHP Console debugger for any type of vars
+ *
+ * @author Sergey Barbushin https://www.linkedin.com/in/barbushin
+ */
+class PHPConsoleHandler extends AbstractProcessingHandler
+{
+ private $options = array(
+ 'enabled' => true, // bool Is PHP Console server enabled
+ 'classesPartialsTraceIgnore' => array('Monolog\\'), // array Hide calls of classes started with...
+ 'debugTagsKeysInContext' => array(0, 'tag'), // bool Is PHP Console server enabled
+ 'useOwnErrorsHandler' => false, // bool Enable errors handling
+ 'useOwnExceptionsHandler' => false, // bool Enable exceptions handling
+ 'sourcesBasePath' => null, // string Base path of all project sources to strip in errors source paths
+ 'registerHelper' => true, // bool Register PhpConsole\Helper that allows short debug calls like PC::debug($var, 'ta.g.s')
+ 'serverEncoding' => null, // string|null Server internal encoding
+ 'headersLimit' => null, // int|null Set headers size limit for your web-server
+ 'password' => null, // string|null Protect PHP Console connection by password
+ 'enableSslOnlyMode' => false, // bool Force connection by SSL for clients with PHP Console installed
+ 'ipMasks' => array(), // array Set IP masks of clients that will be allowed to connect to PHP Console: array('192.168.*.*', '127.0.0.1')
+ 'enableEvalListener' => false, // bool Enable eval request to be handled by eval dispatcher(if enabled, 'password' option is also required)
+ 'dumperDetectCallbacks' => false, // bool Convert callback items in dumper vars to (callback SomeClass::someMethod) strings
+ 'dumperLevelLimit' => 5, // int Maximum dumped vars array or object nested dump level
+ 'dumperItemsCountLimit' => 100, // int Maximum dumped var same level array items or object properties number
+ 'dumperItemSizeLimit' => 5000, // int Maximum length of any string or dumped array item
+ 'dumperDumpSizeLimit' => 500000, // int Maximum approximate size of dumped vars result formatted in JSON
+ 'detectDumpTraceAndSource' => false, // bool Autodetect and append trace data to debug
+ 'dataStorage' => null, // PhpConsole\Storage|null Fixes problem with custom $_SESSION handler(see http://goo.gl/Ne8juJ)
+ );
+
+ /** @var Connector */
+ private $connector;
+
+ /**
+ * @param array $options See \Monolog\Handler\PHPConsoleHandler::$options for more details
+ * @param Connector|null $connector Instance of \PhpConsole\Connector class (optional)
+ * @param int $level
+ * @param bool $bubble
+ * @throws Exception
+ */
+ public function __construct(array $options = array(), Connector $connector = null, $level = Logger::DEBUG, $bubble = true)
+ {
+ if (!class_exists('PhpConsole\Connector')) {
+ throw new Exception('PHP Console library not found. See https://github.com/barbushin/php-console#installation');
+ }
+ parent::__construct($level, $bubble);
+ $this->options = $this->initOptions($options);
+ $this->connector = $this->initConnector($connector);
+ }
+
+ private function initOptions(array $options)
+ {
+ $wrongOptions = array_diff(array_keys($options), array_keys($this->options));
+ if ($wrongOptions) {
+ throw new Exception('Unknown options: ' . implode(', ', $wrongOptions));
+ }
+
+ return array_replace($this->options, $options);
+ }
+
+ private function initConnector(Connector $connector = null)
+ {
+ if (!$connector) {
+ if ($this->options['dataStorage']) {
+ Connector::setPostponeStorage($this->options['dataStorage']);
+ }
+ $connector = Connector::getInstance();
+ }
+
+ if ($this->options['registerHelper'] && !Helper::isRegistered()) {
+ Helper::register();
+ }
+
+ if ($this->options['enabled'] && $connector->isActiveClient()) {
+ if ($this->options['useOwnErrorsHandler'] || $this->options['useOwnExceptionsHandler']) {
+ $handler = Handler::getInstance();
+ $handler->setHandleErrors($this->options['useOwnErrorsHandler']);
+ $handler->setHandleExceptions($this->options['useOwnExceptionsHandler']);
+ $handler->start();
+ }
+ if ($this->options['sourcesBasePath']) {
+ $connector->setSourcesBasePath($this->options['sourcesBasePath']);
+ }
+ if ($this->options['serverEncoding']) {
+ $connector->setServerEncoding($this->options['serverEncoding']);
+ }
+ if ($this->options['password']) {
+ $connector->setPassword($this->options['password']);
+ }
+ if ($this->options['enableSslOnlyMode']) {
+ $connector->enableSslOnlyMode();
+ }
+ if ($this->options['ipMasks']) {
+ $connector->setAllowedIpMasks($this->options['ipMasks']);
+ }
+ if ($this->options['headersLimit']) {
+ $connector->setHeadersLimit($this->options['headersLimit']);
+ }
+ if ($this->options['detectDumpTraceAndSource']) {
+ $connector->getDebugDispatcher()->detectTraceAndSource = true;
+ }
+ $dumper = $connector->getDumper();
+ $dumper->levelLimit = $this->options['dumperLevelLimit'];
+ $dumper->itemsCountLimit = $this->options['dumperItemsCountLimit'];
+ $dumper->itemSizeLimit = $this->options['dumperItemSizeLimit'];
+ $dumper->dumpSizeLimit = $this->options['dumperDumpSizeLimit'];
+ $dumper->detectCallbacks = $this->options['dumperDetectCallbacks'];
+ if ($this->options['enableEvalListener']) {
+ $connector->startEvalRequestsListener();
+ }
+ }
+
+ return $connector;
+ }
+
+ public function getConnector()
+ {
+ return $this->connector;
+ }
+
+ public function getOptions()
+ {
+ return $this->options;
+ }
+
+ public function handle(array $record)
+ {
+ if ($this->options['enabled'] && $this->connector->isActiveClient()) {
+ return parent::handle($record);
+ }
+
+ return !$this->bubble;
+ }
+
+ /**
+ * Writes the record down to the log of the implementing handler
+ *
+ * @param array $record
+ * @return void
+ */
+ protected function write(array $record)
+ {
+ if ($record['level'] < Logger::NOTICE) {
+ $this->handleDebugRecord($record);
+ } elseif (isset($record['context']['exception']) && $record['context']['exception'] instanceof Exception) {
+ $this->handleExceptionRecord($record);
+ } else {
+ $this->handleErrorRecord($record);
+ }
+ }
+
+ private function handleDebugRecord(array $record)
+ {
+ $tags = $this->getRecordTags($record);
+ $message = $record['message'];
+ if ($record['context']) {
+ $message .= ' ' . json_encode($this->connector->getDumper()->dump(array_filter($record['context'])));
+ }
+ $this->connector->getDebugDispatcher()->dispatchDebug($message, $tags, $this->options['classesPartialsTraceIgnore']);
+ }
+
+ private function handleExceptionRecord(array $record)
+ {
+ $this->connector->getErrorsDispatcher()->dispatchException($record['context']['exception']);
+ }
+
+ private function handleErrorRecord(array $record)
+ {
+ $context = $record['context'];
+
+ $this->connector->getErrorsDispatcher()->dispatchError(
+ isset($context['code']) ? $context['code'] : null,
+ isset($context['message']) ? $context['message'] : $record['message'],
+ isset($context['file']) ? $context['file'] : null,
+ isset($context['line']) ? $context['line'] : null,
+ $this->options['classesPartialsTraceIgnore']
+ );
+ }
+
+ private function getRecordTags(array &$record)
+ {
+ $tags = null;
+ if (!empty($record['context'])) {
+ $context =& $record['context'];
+ foreach ($this->options['debugTagsKeysInContext'] as $key) {
+ if (!empty($context[$key])) {
+ $tags = $context[$key];
+ if ($key === 0) {
+ array_shift($context);
+ } else {
+ unset($context[$key]);
+ }
+ break;
+ }
+ }
+ }
+
+ return $tags ?: strtolower($record['level_name']);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ protected function getDefaultFormatter()
+ {
+ return new LineFormatter('%message%');
+ }
+}
+
diff --git a/vendor/monolog/monolog/src/Monolog/Handler/PsrHandler.php b/vendor/monolog/monolog/src/Monolog/Handler/PsrHandler.php
new file mode 100644
index 00000000..1ae85845
--- /dev/null
+++ b/vendor/monolog/monolog/src/Monolog/Handler/PsrHandler.php
@@ -0,0 +1,56 @@
+<?php
+
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Handler;
+
+use Monolog\Logger;
+use Psr\Log\LoggerInterface;
+
+/**
+ * Proxies log messages to an existing PSR-3 compliant logger.
+ *
+ * @author Michael Moussa <michael.moussa@gmail.com>
+ */
+class PsrHandler extends AbstractHandler
+{
+ /**
+ * PSR-3 compliant logger
+ *
+ * @var LoggerInterface
+ */
+ protected $logger;
+
+ /**
+ * @param LoggerInterface $logger The underlying PSR-3 compliant logger to which messages will be proxied
+ * @param int $level The minimum logging level at which this handler will be triggered
+ * @param Boolean $bubble Whether the messages that are handled can bubble up the stack or not
+ */
+ public function __construct(LoggerInterface $logger, $level = Logger::DEBUG, $bubble = true)
+ {
+ parent::__construct($level, $bubble);
+
+ $this->logger = $logger;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function handle(array $record)
+ {
+ if (!$this->isHandling($record)) {
+ return false;
+ }
+
+ $this->logger->log(strtolower($record['level_name']), $record['message'], $record['context']);
+
+ return false === $this->bubble;
+ }
+}
diff --git a/vendor/monolog/monolog/src/Monolog/Handler/PushoverHandler.php b/vendor/monolog/monolog/src/Monolog/Handler/PushoverHandler.php
new file mode 100644
index 00000000..9917b649
--- /dev/null
+++ b/vendor/monolog/monolog/src/Monolog/Handler/PushoverHandler.php
@@ -0,0 +1,185 @@
+<?php
+
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Handler;
+
+use Monolog\Logger;
+
+/**
+ * Sends notifications through the pushover api to mobile phones
+ *
+ * @author Sebastian Göttschkes <sebastian.goettschkes@googlemail.com>
+ * @see https://www.pushover.net/api
+ */
+class PushoverHandler extends SocketHandler
+{
+ private $token;
+ private $users;
+ private $title;
+ private $user;
+ private $retry;
+ private $expire;
+
+ private $highPriorityLevel;
+ private $emergencyLevel;
+ private $useFormattedMessage = false;
+
+ /**
+ * All parameters that can be sent to Pushover
+ * @see https://pushover.net/api
+ * @var array
+ */
+ private $parameterNames = array(
+ 'token' => true,
+ 'user' => true,
+ 'message' => true,
+ 'device' => true,
+ 'title' => true,
+ 'url' => true,
+ 'url_title' => true,
+ 'priority' => true,
+ 'timestamp' => true,
+ 'sound' => true,
+ 'retry' => true,
+ 'expire' => true,
+ 'callback' => true,
+ );
+
+ /**
+ * Sounds the api supports by default
+ * @see https://pushover.net/api#sounds
+ * @var array
+ */
+ private $sounds = array(
+ 'pushover', 'bike', 'bugle', 'cashregister', 'classical', 'cosmic', 'falling', 'gamelan', 'incoming',
+ 'intermission', 'magic', 'mechanical', 'pianobar', 'siren', 'spacealarm', 'tugboat', 'alien', 'climb',
+ 'persistent', 'echo', 'updown', 'none',
+ );
+
+ /**
+ * @param string $token Pushover api token
+ * @param string|array $users Pushover user id or array of ids the message will be sent to
+ * @param string $title Title sent to the Pushover API
+ * @param integer $level The minimum logging level at which this handler will be triggered
+ * @param Boolean $bubble Whether the messages that are handled can bubble up the stack or not
+ * @param Boolean $useSSL Whether to connect via SSL. Required when pushing messages to users that are not
+ * the pushover.net app owner. OpenSSL is required for this option.
+ * @param integer $highPriorityLevel The minimum logging level at which this handler will start
+ * sending "high priority" requests to the Pushover API
+ * @param integer $emergencyLevel The minimum logging level at which this handler will start
+ * sending "emergency" requests to the Pushover API
+ * @param integer $retry The retry parameter specifies how often (in seconds) the Pushover servers will send the same notification to the user.
+ * @param integer $expire The expire parameter specifies how many seconds your notification will continue to be retried for (every retry seconds).
+ */
+ public function __construct($token, $users, $title = null, $level = Logger::CRITICAL, $bubble = true, $useSSL = true, $highPriorityLevel = Logger::CRITICAL, $emergencyLevel = Logger::EMERGENCY, $retry = 30, $expire = 25200)
+ {
+ $connectionString = $useSSL ? 'ssl://api.pushover.net:443' : 'api.pushover.net:80';
+ parent::__construct($connectionString, $level, $bubble);
+
+ $this->token = $token;
+ $this->users = (array) $users;
+ $this->title = $title ?: gethostname();
+ $this->highPriorityLevel = Logger::toMonologLevel($highPriorityLevel);
+ $this->emergencyLevel = Logger::toMonologLevel($emergencyLevel);
+ $this->retry = $retry;
+ $this->expire = $expire;
+ }
+
+ protected function generateDataStream($record)
+ {
+ $content = $this->buildContent($record);
+
+ return $this->buildHeader($content) . $content;
+ }
+
+ private function buildContent($record)
+ {
+ // Pushover has a limit of 512 characters on title and message combined.
+ $maxMessageLength = 512 - strlen($this->title);
+
+ $message = ($this->useFormattedMessage) ? $record['formatted'] : $record['message'];
+ $message = substr($message, 0, $maxMessageLength);
+
+ $timestamp = $record['datetime']->getTimestamp();
+
+ $dataArray = array(
+ 'token' => $this->token,
+ 'user' => $this->user,
+ 'message' => $message,
+ 'title' => $this->title,
+ 'timestamp' => $timestamp
+ );
+
+ if (isset($record['level']) && $record['level'] >= $this->emergencyLevel) {
+ $dataArray['priority'] = 2;
+ $dataArray['retry'] = $this->retry;
+ $dataArray['expire'] = $this->expire;
+ } elseif (isset($record['level']) && $record['level'] >= $this->highPriorityLevel) {
+ $dataArray['priority'] = 1;
+ }
+
+ // First determine the available parameters
+ $context = array_intersect_key($record['context'], $this->parameterNames);
+ $extra = array_intersect_key($record['extra'], $this->parameterNames);
+
+ // Least important info should be merged with subsequent info
+ $dataArray = array_merge($extra, $context, $dataArray);
+
+ // Only pass sounds that are supported by the API
+ if (isset($dataArray['sound']) && !in_array($dataArray['sound'], $this->sounds)) {
+ unset($dataArray['sound']);
+ }
+
+ return http_build_query($dataArray);
+ }
+
+ private function buildHeader($content)
+ {
+ $header = "POST /1/messages.json HTTP/1.1\r\n";
+ $header .= "Host: api.pushover.net\r\n";
+ $header .= "Content-Type: application/x-www-form-urlencoded\r\n";
+ $header .= "Content-Length: " . strlen($content) . "\r\n";
+ $header .= "\r\n";
+
+ return $header;
+ }
+
+ protected function write(array $record)
+ {
+ foreach ($this->users as $user) {
+ $this->user = $user;
+
+ parent::write($record);
+ $this->closeSocket();
+ }
+
+ $this->user = null;
+ }
+
+ public function setHighPriorityLevel($value)
+ {
+ $this->highPriorityLevel = $value;
+ }
+
+ public function setEmergencyLevel($value)
+ {
+ $this->emergencyLevel = $value;
+ }
+
+ /**
+ * Use the formatted message?
+ * @param boolean $value
+ */
+ public function useFormattedMessage($value)
+ {
+ $this->useFormattedMessage = (boolean) $value;
+ }
+}
diff --git a/vendor/monolog/monolog/src/Monolog/Handler/RavenHandler.php b/vendor/monolog/monolog/src/Monolog/Handler/RavenHandler.php
new file mode 100644
index 00000000..7fedc16f
--- /dev/null
+++ b/vendor/monolog/monolog/src/Monolog/Handler/RavenHandler.php
@@ -0,0 +1,190 @@
+<?php
+
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Handler;
+
+use Monolog\Formatter\LineFormatter;
+use Monolog\Formatter\FormatterInterface;
+use Monolog\Logger;
+use Raven_Client;
+
+/**
+ * Handler to send messages to a Sentry (https://github.com/getsentry/sentry) server
+ * using raven-php (https://github.com/getsentry/raven-php)
+ *
+ * @author Marc Abramowitz <marc@marc-abramowitz.com>
+ */
+class RavenHandler extends AbstractProcessingHandler
+{
+ /**
+ * Translates Monolog log levels to Raven log levels.
+ */
+ private $logLevels = array(
+ Logger::DEBUG => Raven_Client::DEBUG,
+ Logger::INFO => Raven_Client::INFO,
+ Logger::NOTICE => Raven_Client::INFO,
+ Logger::WARNING => Raven_Client::WARNING,
+ Logger::ERROR => Raven_Client::ERROR,
+ Logger::CRITICAL => Raven_Client::FATAL,
+ Logger::ALERT => Raven_Client::FATAL,
+ Logger::EMERGENCY => Raven_Client::FATAL,
+ );
+
+ /**
+ * @var Raven_Client the client object that sends the message to the server
+ */
+ protected $ravenClient;
+
+ /**
+ * @var LineFormatter The formatter to use for the logs generated via handleBatch()
+ */
+ protected $batchFormatter;
+
+ /**
+ * @param Raven_Client $ravenClient
+ * @param integer $level The minimum logging level at which this handler will be triggered
+ * @param Boolean $bubble Whether the messages that are handled can bubble up the stack or not
+ */
+ public function __construct(Raven_Client $ravenClient, $level = Logger::DEBUG, $bubble = true)
+ {
+ parent::__construct($level, $bubble);
+
+ $this->ravenClient = $ravenClient;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function handleBatch(array $records)
+ {
+ $level = $this->level;
+
+ // filter records based on their level
+ $records = array_filter($records, function ($record) use ($level) {
+ return $record['level'] >= $level;
+ });
+
+ if (!$records) {
+ return;
+ }
+
+ // the record with the highest severity is the "main" one
+ $record = array_reduce($records, function ($highest, $record) {
+ if ($record['level'] >= $highest['level']) {
+ return $record;
+ }
+
+ return $highest;
+ });
+
+ // the other ones are added as a context item
+ $logs = array();
+ foreach ($records as $r) {
+ $logs[] = $this->processRecord($r);
+ }
+
+ if ($logs) {
+ $record['context']['logs'] = (string) $this->getBatchFormatter()->formatBatch($logs);
+ }
+
+ $this->handle($record);
+ }
+
+ /**
+ * Sets the formatter for the logs generated by handleBatch().
+ *
+ * @param FormatterInterface $formatter
+ */
+ public function setBatchFormatter(FormatterInterface $formatter)
+ {
+ $this->batchFormatter = $formatter;
+ }
+
+ /**
+ * Gets the formatter for the logs generated by handleBatch().
+ *
+ * @return FormatterInterface
+ */
+ public function getBatchFormatter()
+ {
+ if (!$this->batchFormatter) {
+ $this->batchFormatter = $this->getDefaultBatchFormatter();
+ }
+
+ return $this->batchFormatter;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function write(array $record)
+ {
+ $previousUserContext = false;
+ $options = array();
+ $options['level'] = $this->logLevels[$record['level']];
+ $options['tags'] = array();
+ if (!empty($record['extra']['tags'])) {
+ $options['tags'] = array_merge($options['tags'], $record['extra']['tags']);
+ unset($record['extra']['tags']);
+ }
+ if (!empty($record['context']['tags'])) {
+ $options['tags'] = array_merge($options['tags'], $record['context']['tags']);
+ unset($record['context']['tags']);
+ }
+ if (!empty($record['context']['logger'])) {
+ $options['logger'] = $record['context']['logger'];
+ unset($record['context']['logger']);
+ } else {
+ $options['logger'] = $record['channel'];
+ }
+ if (!empty($record['context'])) {
+ $options['extra']['context'] = $record['context'];
+ if (!empty($record['context']['user'])) {
+ $previousUserContext = $this->ravenClient->context->user;
+ $this->ravenClient->user_context($record['context']['user']);
+ unset($options['extra']['context']['user']);
+ }
+ }
+ if (!empty($record['extra'])) {
+ $options['extra']['extra'] = $record['extra'];
+ }
+
+ if (isset($record['context']['exception']) && $record['context']['exception'] instanceof \Exception) {
+ $options['extra']['message'] = $record['formatted'];
+ $this->ravenClient->captureException($record['context']['exception'], $options);
+ } else {
+ $this->ravenClient->captureMessage($record['formatted'], array(), $options);
+ }
+
+ if ($previousUserContext !== false) {
+ $this->ravenClient->user_context($previousUserContext);
+ }
+
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ protected function getDefaultFormatter()
+ {
+ return new LineFormatter('[%channel%] %message%');
+ }
+
+ /**
+ * Gets the default formatter for the logs generated by handleBatch().
+ *
+ * @return FormatterInterface
+ */
+ protected function getDefaultBatchFormatter()
+ {
+ return new LineFormatter();
+ }
+}
diff --git a/vendor/monolog/monolog/src/Monolog/Handler/RedisHandler.php b/vendor/monolog/monolog/src/Monolog/Handler/RedisHandler.php
new file mode 100644
index 00000000..ee8c2363
--- /dev/null
+++ b/vendor/monolog/monolog/src/Monolog/Handler/RedisHandler.php
@@ -0,0 +1,63 @@
+<?php
+
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Handler;
+
+use Monolog\Formatter\LineFormatter;
+use Monolog\Logger;
+
+/**
+ * Logs to a Redis key using rpush
+ *
+ * usage example:
+ *
+ * $log = new Logger('application');
+ * $redis = new RedisHandler(new Predis\Client("tcp://localhost:6379"), "logs", "prod");
+ * $log->pushHandler($redis);
+ *
+ * @author Thomas Tourlourat <thomas@tourlourat.com>
+ */
+class RedisHandler extends AbstractProcessingHandler
+{
+ private $redisClient;
+ private $redisKey;
+
+ /**
+ * @param \Predis\Client|\Redis $redis The redis instance
+ * @param string $key The key name to push records to
+ * @param integer $level The minimum logging level at which this handler will be triggered
+ * @param boolean $bubble Whether the messages that are handled can bubble up the stack or not
+ */
+ public function __construct($redis, $key, $level = Logger::DEBUG, $bubble = true)
+ {
+ if (!(($redis instanceof \Predis\Client) || ($redis instanceof \Redis))) {
+ throw new \InvalidArgumentException('Predis\Client or Redis instance required');
+ }
+
+ $this->redisClient = $redis;
+ $this->redisKey = $key;
+
+ parent::__construct($level, $bubble);
+ }
+
+ protected function write(array $record)
+ {
+ $this->redisClient->rpush($this->redisKey, $record["formatted"]);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ protected function getDefaultFormatter()
+ {
+ return new LineFormatter();
+ }
+}
diff --git a/vendor/monolog/monolog/src/Monolog/Handler/RollbarHandler.php b/vendor/monolog/monolog/src/Monolog/Handler/RollbarHandler.php
new file mode 100644
index 00000000..81abf086
--- /dev/null
+++ b/vendor/monolog/monolog/src/Monolog/Handler/RollbarHandler.php
@@ -0,0 +1,73 @@
+<?php
+
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Handler;
+
+use RollbarNotifier;
+use Exception;
+use Monolog\Logger;
+
+/**
+ * Sends errors to Rollbar
+ *
+ * @author Paul Statezny <paulstatezny@gmail.com>
+ */
+class RollbarHandler extends AbstractProcessingHandler
+{
+ /**
+ * Rollbar notifier
+ *
+ * @var RollbarNotifier
+ */
+ protected $rollbarNotifier;
+
+ /**
+ * @param RollbarNotifier $rollbarNotifier RollbarNotifier object constructed with valid token
+ * @param integer $level The minimum logging level at which this handler will be triggered
+ * @param boolean $bubble Whether the messages that are handled can bubble up the stack or not
+ */
+ public function __construct(RollbarNotifier $rollbarNotifier, $level = Logger::ERROR, $bubble = true)
+ {
+ $this->rollbarNotifier = $rollbarNotifier;
+
+ parent::__construct($level, $bubble);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function write(array $record)
+ {
+ if (isset($record['context']['exception']) && $record['context']['exception'] instanceof Exception) {
+ $this->rollbarNotifier->report_exception($record['context']['exception']);
+ } else {
+ $extraData = array(
+ 'level' => $record['level'],
+ 'channel' => $record['channel'],
+ 'datetime' => $record['datetime']->format('U'),
+ );
+
+ $this->rollbarNotifier->report_message(
+ $record['message'],
+ $record['level_name'],
+ array_merge($record['context'], $record['extra'], $extraData)
+ );
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function close()
+ {
+ $this->rollbarNotifier->flush();
+ }
+}
diff --git a/vendor/monolog/monolog/src/Monolog/Handler/RotatingFileHandler.php b/vendor/monolog/monolog/src/Monolog/Handler/RotatingFileHandler.php
new file mode 100644
index 00000000..4168c32f
--- /dev/null
+++ b/vendor/monolog/monolog/src/Monolog/Handler/RotatingFileHandler.php
@@ -0,0 +1,153 @@
+<?php
+
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Handler;
+
+use Monolog\Logger;
+
+/**
+ * Stores logs to files that are rotated every day and a limited number of files are kept.
+ *
+ * This rotation is only intended to be used as a workaround. Using logrotate to
+ * handle the rotation is strongly encouraged when you can use it.
+ *
+ * @author Christophe Coevoet <stof@notk.org>
+ * @author Jordi Boggiano <j.boggiano@seld.be>
+ */
+class RotatingFileHandler extends StreamHandler
+{
+ protected $filename;
+ protected $maxFiles;
+ protected $mustRotate;
+ protected $nextRotation;
+ protected $filenameFormat;
+ protected $dateFormat;
+
+ /**
+ * @param string $filename
+ * @param integer $maxFiles The maximal amount of files to keep (0 means unlimited)
+ * @param integer $level The minimum logging level at which this handler will be triggered
+ * @param Boolean $bubble Whether the messages that are handled can bubble up the stack or not
+ * @param int|null $filePermission Optional file permissions (default (0644) are only for owner read/write)
+ * @param Boolean $useLocking Try to lock log file before doing any writes
+ */
+ public function __construct($filename, $maxFiles = 0, $level = Logger::DEBUG, $bubble = true, $filePermission = null, $useLocking = false)
+ {
+ $this->filename = $filename;
+ $this->maxFiles = (int) $maxFiles;
+ $this->nextRotation = new \DateTime('tomorrow');
+ $this->filenameFormat = '{filename}-{date}';
+ $this->dateFormat = 'Y-m-d';
+
+ parent::__construct($this->getTimedFilename(), $level, $bubble, $filePermission, $useLocking);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function close()
+ {
+ parent::close();
+
+ if (true === $this->mustRotate) {
+ $this->rotate();
+ }
+ }
+
+ public function setFilenameFormat($filenameFormat, $dateFormat)
+ {
+ $this->filenameFormat = $filenameFormat;
+ $this->dateFormat = $dateFormat;
+ $this->url = $this->getTimedFilename();
+ $this->close();
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function write(array $record)
+ {
+ // on the first record written, if the log is new, we should rotate (once per day)
+ if (null === $this->mustRotate) {
+ $this->mustRotate = !file_exists($this->url);
+ }
+
+ if ($this->nextRotation < $record['datetime']) {
+ $this->mustRotate = true;
+ $this->close();
+ }
+
+ parent::write($record);
+ }
+
+ /**
+ * Rotates the files.
+ */
+ protected function rotate()
+ {
+ // update filename
+ $this->url = $this->getTimedFilename();
+ $this->nextRotation = new \DateTime('tomorrow');
+
+ // skip GC of old logs if files are unlimited
+ if (0 === $this->maxFiles) {
+ return;
+ }
+
+ $logFiles = glob($this->getGlobPattern());
+ if ($this->maxFiles >= count($logFiles)) {
+ // no files to remove
+ return;
+ }
+
+ // Sorting the files by name to remove the older ones
+ usort($logFiles, function ($a, $b) {
+ return strcmp($b, $a);
+ });
+
+ foreach (array_slice($logFiles, $this->maxFiles) as $file) {
+ if (is_writable($file)) {
+ unlink($file);
+ }
+ }
+ }
+
+ protected function getTimedFilename()
+ {
+ $fileInfo = pathinfo($this->filename);
+ $timedFilename = str_replace(
+ array('{filename}', '{date}'),
+ array($fileInfo['filename'], date($this->dateFormat)),
+ $fileInfo['dirname'] . '/' . $this->filenameFormat
+ );
+
+ if (!empty($fileInfo['extension'])) {
+ $timedFilename .= '.'.$fileInfo['extension'];
+ }
+
+ return $timedFilename;
+ }
+
+ protected function getGlobPattern()
+ {
+ $fileInfo = pathinfo($this->filename);
+ $glob = str_replace(
+ array('{filename}', '{date}'),
+ array($fileInfo['filename'], '*'),
+ $fileInfo['dirname'] . '/' . $this->filenameFormat
+ );
+ if (!empty($fileInfo['extension'])) {
+ $glob .= '.'.$fileInfo['extension'];
+ }
+
+ return $glob;
+ }
+}
diff --git a/vendor/monolog/monolog/src/Monolog/Handler/SamplingHandler.php b/vendor/monolog/monolog/src/Monolog/Handler/SamplingHandler.php
new file mode 100644
index 00000000..9509ae37
--- /dev/null
+++ b/vendor/monolog/monolog/src/Monolog/Handler/SamplingHandler.php
@@ -0,0 +1,82 @@
+<?php
+
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Handler;
+
+/**
+ * Sampling handler
+ *
+ * A sampled event stream can be useful for logging high frequency events in
+ * a production environment where you only need an idea of what is happening
+ * and are not concerned with capturing every occurrence. Since the decision to
+ * handle or not handle a particular event is determined randomly, the
+ * resulting sampled log is not guaranteed to contain 1/N of the events that
+ * occurred in the application, but based on the Law of large numbers, it will
+ * tend to be close to this ratio with a large number of attempts.
+ *
+ * @author Bryan Davis <bd808@wikimedia.org>
+ * @author Kunal Mehta <legoktm@gmail.com>
+ */
+class SamplingHandler extends AbstractHandler
+{
+ /**
+ * @var callable|HandlerInterface $handler
+ */
+ protected $handler;
+
+ /**
+ * @var int $factor
+ */
+ protected $factor;
+
+ /**
+ * @param callable|HandlerInterface $handler Handler or factory callable($record, $fingersCrossedHandler).
+ * @param int $factor Sample factor
+ */
+ public function __construct($handler, $factor)
+ {
+ parent::__construct();
+ $this->handler = $handler;
+ $this->factor = $factor;
+
+ if (!$this->handler instanceof HandlerInterface && !is_callable($this->handler)) {
+ throw new \RuntimeException("The given handler (".json_encode($this->handler).") is not a callable nor a Monolog\Handler\HandlerInterface object");
+ }
+ }
+
+ public function isHandling(array $record)
+ {
+ return $this->handler->isHandling($record);
+ }
+
+ public function handle(array $record)
+ {
+ if ($this->isHandling($record) && mt_rand(1, $this->factor) === 1) {
+ // The same logic as in FingersCrossedHandler
+ if (!$this->handler instanceof HandlerInterface) {
+ $this->handler = call_user_func($this->handler, $record, $this);
+ if (!$this->handler instanceof HandlerInterface) {
+ throw new \RuntimeException("The factory callable should return a HandlerInterface");
+ }
+ }
+
+ if ($this->processors) {
+ foreach ($this->processors as $processor) {
+ $record = call_user_func($processor, $record);
+ }
+ }
+
+ $this->handler->handle($record);
+ }
+
+ return false === $this->bubble;
+ }
+}
diff --git a/vendor/monolog/monolog/src/Monolog/Handler/SlackHandler.php b/vendor/monolog/monolog/src/Monolog/Handler/SlackHandler.php
new file mode 100644
index 00000000..c7a1c7e9
--- /dev/null
+++ b/vendor/monolog/monolog/src/Monolog/Handler/SlackHandler.php
@@ -0,0 +1,292 @@
+<?php
+
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Handler;
+
+use Monolog\Logger;
+use Monolog\Formatter\LineFormatter;
+
+/**
+ * Sends notifications through Slack API
+ *
+ * @author Greg Kedzierski <greg@gregkedzierski.com>
+ * @see https://api.slack.com/
+ */
+class SlackHandler extends SocketHandler
+{
+ /**
+ * Slack API token
+ * @var string
+ */
+ private $token;
+
+ /**
+ * Slack channel (encoded ID or name)
+ * @var string
+ */
+ private $channel;
+
+ /**
+ * Name of a bot
+ * @var string
+ */
+ private $username;
+
+ /**
+ * Emoji icon name
+ * @var string
+ */
+ private $iconEmoji;
+
+ /**
+ * Whether the message should be added to Slack as attachment (plain text otherwise)
+ * @var bool
+ */
+ private $useAttachment;
+
+ /**
+ * Whether the the context/extra messages added to Slack as attachments are in a short style
+ * @var bool
+ */
+ private $useShortAttachment;
+
+ /**
+ * Whether the attachment should include context and extra data
+ * @var bool
+ */
+ private $includeContextAndExtra;
+
+ /**
+ * @var LineFormatter
+ */
+ private $lineFormatter;
+
+ /**
+ * @param string $token Slack API token
+ * @param string $channel Slack channel (encoded ID or name)
+ * @param string $username Name of a bot
+ * @param bool $useAttachment Whether the message should be added to Slack as attachment (plain text otherwise)
+ * @param string|null $iconEmoji The emoji name to use (or null)
+ * @param int $level The minimum logging level at which this handler will be triggered
+ * @param bool $bubble Whether the messages that are handled can bubble up the stack or not
+ * @param bool $useShortAttachment Whether the the context/extra messages added to Slack as attachments are in a short style
+ * @param bool $includeContextAndExtra Whether the attachment should include context and extra data
+ */
+ public function __construct($token, $channel, $username = 'Monolog', $useAttachment = true, $iconEmoji = null, $level = Logger::CRITICAL, $bubble = true, $useShortAttachment = false, $includeContextAndExtra = false)
+ {
+ if (!extension_loaded('openssl')) {
+ throw new MissingExtensionException('The OpenSSL PHP extension is required to use the SlackHandler');
+ }
+
+ parent::__construct('ssl://slack.com:443', $level, $bubble);
+
+ $this->token = $token;
+ $this->channel = $channel;
+ $this->username = $username;
+ $this->iconEmoji = trim($iconEmoji, ':');
+ $this->useAttachment = $useAttachment;
+ $this->useShortAttachment = $useShortAttachment;
+ $this->includeContextAndExtra = $includeContextAndExtra;
+ if ($this->includeContextAndExtra) {
+ $this->lineFormatter = new LineFormatter;
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ *
+ * @param array $record
+ * @return string
+ */
+ protected function generateDataStream($record)
+ {
+ $content = $this->buildContent($record);
+
+ return $this->buildHeader($content) . $content;
+ }
+
+ /**
+ * Builds the body of API call
+ *
+ * @param array $record
+ * @return string
+ */
+ private function buildContent($record)
+ {
+ $dataArray = $this->prepareContentData($record);
+
+ return http_build_query($dataArray);
+ }
+
+ /**
+ * Prepares content data
+ *
+ * @param array $record
+ * @return array
+ */
+ protected function prepareContentData($record)
+ {
+ $dataArray = array(
+ 'token' => $this->token,
+ 'channel' => $this->channel,
+ 'username' => $this->username,
+ 'text' => '',
+ 'attachments' => array()
+ );
+
+ if ($this->useAttachment) {
+ $attachment = array(
+ 'fallback' => $record['message'],
+ 'color' => $this->getAttachmentColor($record['level'])
+ );
+
+ if ($this->useShortAttachment) {
+ $attachment['fields'] = array(
+ array(
+ 'title' => $record['level_name'],
+ 'value' => $record['message'],
+ 'short' => false
+ )
+ );
+ } else {
+ $attachment['fields'] = array(
+ array(
+ 'title' => 'Message',
+ 'value' => $record['message'],
+ 'short' => false
+ ),
+ array(
+ 'title' => 'Level',
+ 'value' => $record['level_name'],
+ 'short' => true
+ )
+ );
+ }
+
+ if ($this->includeContextAndExtra) {
+ if (!empty($record['extra'])) {
+ if ($this->useShortAttachment) {
+ $attachment['fields'][] = array(
+ 'title' => "Extra",
+ 'value' => $this->stringify($record['extra']),
+ 'short' => $this->useShortAttachment
+ );
+ } else {
+ // Add all extra fields as individual fields in attachment
+ foreach ($record['extra'] as $var => $val) {
+ $attachment['fields'][] = array(
+ 'title' => $var,
+ 'value' => $val,
+ 'short' => $this->useShortAttachment
+ );
+ }
+ }
+ }
+
+ if (!empty($record['context'])) {
+ if ($this->useShortAttachment) {
+ $attachment['fields'][] = array(
+ 'title' => "Context",
+ 'value' => $this->stringify($record['context']),
+ 'short' => $this->useShortAttachment
+ );
+ } else {
+ // Add all context fields as individual fields in attachment
+ foreach ($record['context'] as $var => $val) {
+ $attachment['fields'][] = array(
+ 'title' => $var,
+ 'value' => $val,
+ 'short' => $this->useShortAttachment
+ );
+ }
+ }
+ }
+ }
+
+ $dataArray['attachments'] = json_encode(array($attachment));
+ } else {
+ $dataArray['text'] = $record['message'];
+ }
+
+ if ($this->iconEmoji) {
+ $dataArray['icon_emoji'] = ":{$this->iconEmoji}:";
+ }
+ return $dataArray;
+ }
+
+ /**
+ * Builds the header of the API Call
+ *
+ * @param string $content
+ * @return string
+ */
+ private function buildHeader($content)
+ {
+ $header = "POST /api/chat.postMessage HTTP/1.1\r\n";
+ $header .= "Host: slack.com\r\n";
+ $header .= "Content-Type: application/x-www-form-urlencoded\r\n";
+ $header .= "Content-Length: " . strlen($content) . "\r\n";
+ $header .= "\r\n";
+
+ return $header;
+ }
+
+ /**
+ * {@inheritdoc}
+ *
+ * @param array $record
+ */
+ protected function write(array $record)
+ {
+ parent::write($record);
+ $this->closeSocket();
+ }
+
+ /**
+ * Returned a Slack message attachment color associated with
+ * provided level.
+ *
+ * @param int $level
+ * @return string
+ */
+ protected function getAttachmentColor($level)
+ {
+ switch (true) {
+ case $level >= Logger::ERROR:
+ return 'danger';
+ case $level >= Logger::WARNING:
+ return 'warning';
+ case $level >= Logger::INFO:
+ return 'good';
+ default:
+ return '#e3e4e6';
+ }
+ }
+
+ /**
+ * Stringifies an array of key/value pairs to be used in attachment fields
+ *
+ * @param array $fields
+ * @access protected
+ * @return string
+ */
+ protected function stringify($fields)
+ {
+ $string = '';
+ foreach ($fields as $var => $val) {
+ $string .= $var.': '.$this->lineFormatter->stringify($val)." | ";
+ }
+
+ $string = rtrim($string, " |");
+
+ return $string;
+ }
+}
diff --git a/vendor/monolog/monolog/src/Monolog/Handler/SocketHandler.php b/vendor/monolog/monolog/src/Monolog/Handler/SocketHandler.php
new file mode 100644
index 00000000..ee486f69
--- /dev/null
+++ b/vendor/monolog/monolog/src/Monolog/Handler/SocketHandler.php
@@ -0,0 +1,284 @@
+<?php
+
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Handler;
+
+use Monolog\Logger;
+
+/**
+ * Stores to any socket - uses fsockopen() or pfsockopen().
+ *
+ * @author Pablo de Leon Belloc <pablolb@gmail.com>
+ * @see http://php.net/manual/en/function.fsockopen.php
+ */
+class SocketHandler extends AbstractProcessingHandler
+{
+ private $connectionString;
+ private $connectionTimeout;
+ private $resource;
+ private $timeout = 0;
+ private $persistent = false;
+ private $errno;
+ private $errstr;
+
+ /**
+ * @param string $connectionString Socket connection string
+ * @param integer $level The minimum logging level at which this handler will be triggered
+ * @param Boolean $bubble Whether the messages that are handled can bubble up the stack or not
+ */
+ public function __construct($connectionString, $level = Logger::DEBUG, $bubble = true)
+ {
+ parent::__construct($level, $bubble);
+ $this->connectionString = $connectionString;
+ $this->connectionTimeout = (float) ini_get('default_socket_timeout');
+ }
+
+ /**
+ * Connect (if necessary) and write to the socket
+ *
+ * @param array $record
+ *
+ * @throws \UnexpectedValueException
+ * @throws \RuntimeException
+ */
+ protected function write(array $record)
+ {
+ $this->connectIfNotConnected();
+ $data = $this->generateDataStream($record);
+ $this->writeToSocket($data);
+ }
+
+ /**
+ * We will not close a PersistentSocket instance so it can be reused in other requests.
+ */
+ public function close()
+ {
+ if (!$this->isPersistent()) {
+ $this->closeSocket();
+ }
+ }
+
+ /**
+ * Close socket, if open
+ */
+ public function closeSocket()
+ {
+ if (is_resource($this->resource)) {
+ fclose($this->resource);
+ $this->resource = null;
+ }
+ }
+
+ /**
+ * Set socket connection to nbe persistent. It only has effect before the connection is initiated.
+ *
+ * @param type $boolean
+ */
+ public function setPersistent($boolean)
+ {
+ $this->persistent = (boolean) $boolean;
+ }
+
+ /**
+ * Set connection timeout. Only has effect before we connect.
+ *
+ * @param float $seconds
+ *
+ * @see http://php.net/manual/en/function.fsockopen.php
+ */
+ public function setConnectionTimeout($seconds)
+ {
+ $this->validateTimeout($seconds);
+ $this->connectionTimeout = (float) $seconds;
+ }
+
+ /**
+ * Set write timeout. Only has effect before we connect.
+ *
+ * @param float $seconds
+ *
+ * @see http://php.net/manual/en/function.stream-set-timeout.php
+ */
+ public function setTimeout($seconds)
+ {
+ $this->validateTimeout($seconds);
+ $this->timeout = (float) $seconds;
+ }
+
+ /**
+ * Get current connection string
+ *
+ * @return string
+ */
+ public function getConnectionString()
+ {
+ return $this->connectionString;
+ }
+
+ /**
+ * Get persistent setting
+ *
+ * @return boolean
+ */
+ public function isPersistent()
+ {
+ return $this->persistent;
+ }
+
+ /**
+ * Get current connection timeout setting
+ *
+ * @return float
+ */
+ public function getConnectionTimeout()
+ {
+ return $this->connectionTimeout;
+ }
+
+ /**
+ * Get current in-transfer timeout
+ *
+ * @return float
+ */
+ public function getTimeout()
+ {
+ return $this->timeout;
+ }
+
+ /**
+ * Check to see if the socket is currently available.
+ *
+ * UDP might appear to be connected but might fail when writing. See http://php.net/fsockopen for details.
+ *
+ * @return boolean
+ */
+ public function isConnected()
+ {
+ return is_resource($this->resource)
+ && !feof($this->resource); // on TCP - other party can close connection.
+ }
+
+ /**
+ * Wrapper to allow mocking
+ */
+ protected function pfsockopen()
+ {
+ return @pfsockopen($this->connectionString, -1, $this->errno, $this->errstr, $this->connectionTimeout);
+ }
+
+ /**
+ * Wrapper to allow mocking
+ */
+ protected function fsockopen()
+ {
+ return @fsockopen($this->connectionString, -1, $this->errno, $this->errstr, $this->connectionTimeout);
+ }
+
+ /**
+ * Wrapper to allow mocking
+ *
+ * @see http://php.net/manual/en/function.stream-set-timeout.php
+ */
+ protected function streamSetTimeout()
+ {
+ $seconds = floor($this->timeout);
+ $microseconds = round(($this->timeout - $seconds)*1e6);
+
+ return stream_set_timeout($this->resource, $seconds, $microseconds);
+ }
+
+ /**
+ * Wrapper to allow mocking
+ */
+ protected function fwrite($data)
+ {
+ return @fwrite($this->resource, $data);
+ }
+
+ /**
+ * Wrapper to allow mocking
+ */
+ protected function streamGetMetadata()
+ {
+ return stream_get_meta_data($this->resource);
+ }
+
+ private function validateTimeout($value)
+ {
+ $ok = filter_var($value, FILTER_VALIDATE_FLOAT);
+ if ($ok === false || $value < 0) {
+ throw new \InvalidArgumentException("Timeout must be 0 or a positive float (got $value)");
+ }
+ }
+
+ private function connectIfNotConnected()
+ {
+ if ($this->isConnected()) {
+ return;
+ }
+ $this->connect();
+ }
+
+ protected function generateDataStream($record)
+ {
+ return (string) $record['formatted'];
+ }
+
+ private function connect()
+ {
+ $this->createSocketResource();
+ $this->setSocketTimeout();
+ }
+
+ private function createSocketResource()
+ {
+ if ($this->isPersistent()) {
+ $resource = $this->pfsockopen();
+ } else {
+ $resource = $this->fsockopen();
+ }
+ if (!$resource) {
+ throw new \UnexpectedValueException("Failed connecting to $this->connectionString ($this->errno: $this->errstr)");
+ }
+ $this->resource = $resource;
+ }
+
+ private function setSocketTimeout()
+ {
+ if (!$this->streamSetTimeout()) {
+ throw new \UnexpectedValueException("Failed setting timeout with stream_set_timeout()");
+ }
+ }
+
+ private function writeToSocket($data)
+ {
+ $length = strlen($data);
+ $sent = 0;
+ while ($this->isConnected() && $sent < $length) {
+ if (0 == $sent) {
+ $chunk = $this->fwrite($data);
+ } else {
+ $chunk = $this->fwrite(substr($data, $sent));
+ }
+ if ($chunk === false) {
+ throw new \RuntimeException("Could not write to socket");
+ }
+ $sent += $chunk;
+ $socketInfo = $this->streamGetMetadata();
+ if ($socketInfo['timed_out']) {
+ throw new \RuntimeException("Write timed-out");
+ }
+ }
+ if (!$this->isConnected() && $sent < $length) {
+ throw new \RuntimeException("End-of-file reached, probably we got disconnected (sent $sent of $length)");
+ }
+ }
+}
diff --git a/vendor/monolog/monolog/src/Monolog/Handler/StreamHandler.php b/vendor/monolog/monolog/src/Monolog/Handler/StreamHandler.php
new file mode 100644
index 00000000..7965db74
--- /dev/null
+++ b/vendor/monolog/monolog/src/Monolog/Handler/StreamHandler.php
@@ -0,0 +1,104 @@
+<?php
+
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Handler;
+
+use Monolog\Logger;
+
+/**
+ * Stores to any stream resource
+ *
+ * Can be used to store into php://stderr, remote and local files, etc.
+ *
+ * @author Jordi Boggiano <j.boggiano@seld.be>
+ */
+class StreamHandler extends AbstractProcessingHandler
+{
+ protected $stream;
+ protected $url;
+ private $errorMessage;
+ protected $filePermission;
+ protected $useLocking;
+
+ /**
+ * @param resource|string $stream
+ * @param integer $level The minimum logging level at which this handler will be triggered
+ * @param Boolean $bubble Whether the messages that are handled can bubble up the stack or not
+ * @param int|null $filePermission Optional file permissions (default (0644) are only for owner read/write)
+ * @param Boolean $useLocking Try to lock log file before doing any writes
+ *
+ * @throws \InvalidArgumentException If stream is not a resource or string
+ */
+ public function __construct($stream, $level = Logger::DEBUG, $bubble = true, $filePermission = null, $useLocking = false)
+ {
+ parent::__construct($level, $bubble);
+ if (is_resource($stream)) {
+ $this->stream = $stream;
+ } elseif (is_string($stream)) {
+ $this->url = $stream;
+ } else {
+ throw new \InvalidArgumentException('A stream must either be a resource or a string.');
+ }
+
+ $this->filePermission = $filePermission;
+ $this->useLocking = $useLocking;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function close()
+ {
+ if (is_resource($this->stream)) {
+ fclose($this->stream);
+ }
+ $this->stream = null;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function write(array $record)
+ {
+ if (!is_resource($this->stream)) {
+ if (!$this->url) {
+ throw new \LogicException('Missing stream url, the stream can not be opened. This may be caused by a premature call to close().');
+ }
+ $this->errorMessage = null;
+ set_error_handler(array($this, 'customErrorHandler'));
+ $this->stream = fopen($this->url, 'a');
+ if ($this->filePermission !== null) {
+ @chmod($this->url, $this->filePermission);
+ }
+ restore_error_handler();
+ if (!is_resource($this->stream)) {
+ $this->stream = null;
+ throw new \UnexpectedValueException(sprintf('The stream or file "%s" could not be opened: '.$this->errorMessage, $this->url));
+ }
+ }
+
+ if ($this->useLocking) {
+ // ignoring errors here, there's not much we can do about them
+ flock($this->stream, LOCK_EX);
+ }
+
+ fwrite($this->stream, (string) $record['formatted']);
+
+ if ($this->useLocking) {
+ flock($this->stream, LOCK_UN);
+ }
+ }
+
+ private function customErrorHandler($code, $msg)
+ {
+ $this->errorMessage = preg_replace('{^fopen\(.*?\): }', '', $msg);
+ }
+}
diff --git a/vendor/monolog/monolog/src/Monolog/Handler/SwiftMailerHandler.php b/vendor/monolog/monolog/src/Monolog/Handler/SwiftMailerHandler.php
new file mode 100644
index 00000000..003a1a2a
--- /dev/null
+++ b/vendor/monolog/monolog/src/Monolog/Handler/SwiftMailerHandler.php
@@ -0,0 +1,87 @@
+<?php
+
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Handler;
+
+use Monolog\Logger;
+
+/**
+ * SwiftMailerHandler uses Swift_Mailer to send the emails
+ *
+ * @author Gyula Sallai
+ */
+class SwiftMailerHandler extends MailHandler
+{
+ protected $mailer;
+ private $messageTemplate;
+
+ /**
+ * @param \Swift_Mailer $mailer The mailer to use
+ * @param callable|\Swift_Message $message An example message for real messages, only the body will be replaced
+ * @param integer $level The minimum logging level at which this handler will be triggered
+ * @param Boolean $bubble Whether the messages that are handled can bubble up the stack or not
+ */
+ public function __construct(\Swift_Mailer $mailer, $message, $level = Logger::ERROR, $bubble = true)
+ {
+ parent::__construct($level, $bubble);
+
+ $this->mailer = $mailer;
+ $this->messageTemplate = $message;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function send($content, array $records)
+ {
+ $this->mailer->send($this->buildMessage($content, $records));
+ }
+
+ /**
+ * Creates instance of Swift_Message to be sent
+ *
+ * @param string $content formatted email body to be sent
+ * @param array $records Log records that formed the content
+ * @return \Swift_Message
+ */
+ protected function buildMessage($content, array $records)
+ {
+ $message = null;
+ if ($this->messageTemplate instanceof \Swift_Message) {
+ $message = clone $this->messageTemplate;
+ } else if (is_callable($this->messageTemplate)) {
+ $message = call_user_func($this->messageTemplate, $content, $records);
+ }
+
+ if (!$message instanceof \Swift_Message) {
+ throw new \InvalidArgumentException('Could not resolve message as instance of Swift_Message or a callable returning it');
+ }
+
+ $message->setBody($content);
+ $message->setDate(time());
+
+ return $message;
+ }
+
+ /**
+ * BC getter, to be removed in 2.0
+ */
+ public function __get($name)
+ {
+ if ($name === 'message') {
+ trigger_error('SwiftMailerHandler->message is deprecated, use ->buildMessage() instead to retrieve the message', E_USER_DEPRECATED);
+
+ return $this->buildMessage(null, array());
+ }
+
+ throw new \InvalidArgumentException('Invalid property '.$name);
+ }
+}
diff --git a/vendor/monolog/monolog/src/Monolog/Handler/SyslogHandler.php b/vendor/monolog/monolog/src/Monolog/Handler/SyslogHandler.php
new file mode 100644
index 00000000..47c73e12
--- /dev/null
+++ b/vendor/monolog/monolog/src/Monolog/Handler/SyslogHandler.php
@@ -0,0 +1,67 @@
+<?php
+
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Handler;
+
+use Monolog\Logger;
+
+/**
+ * Logs to syslog service.
+ *
+ * usage example:
+ *
+ * $log = new Logger('application');
+ * $syslog = new SyslogHandler('myfacility', 'local6');
+ * $formatter = new LineFormatter("%channel%.%level_name%: %message% %extra%");
+ * $syslog->setFormatter($formatter);
+ * $log->pushHandler($syslog);
+ *
+ * @author Sven Paulus <sven@karlsruhe.org>
+ */
+class SyslogHandler extends AbstractSyslogHandler
+{
+ protected $ident;
+ protected $logopts;
+
+ /**
+ * @param string $ident
+ * @param mixed $facility
+ * @param integer $level The minimum logging level at which this handler will be triggered
+ * @param Boolean $bubble Whether the messages that are handled can bubble up the stack or not
+ * @param int $logopts Option flags for the openlog() call, defaults to LOG_PID
+ */
+ public function __construct($ident, $facility = LOG_USER, $level = Logger::DEBUG, $bubble = true, $logopts = LOG_PID)
+ {
+ parent::__construct($facility, $level, $bubble);
+
+ $this->ident = $ident;
+ $this->logopts = $logopts;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function close()
+ {
+ closelog();
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function write(array $record)
+ {
+ if (!openlog($this->ident, $this->logopts, $this->facility)) {
+ throw new \LogicException('Can\'t open syslog for ident "'.$this->ident.'" and facility "'.$this->facility.'"');
+ }
+ syslog($this->logLevels[$record['level']], (string) $record['formatted']);
+ }
+}
diff --git a/vendor/monolog/monolog/src/Monolog/Handler/SyslogUdp/UdpSocket.php b/vendor/monolog/monolog/src/Monolog/Handler/SyslogUdp/UdpSocket.php
new file mode 100644
index 00000000..dcf3f1f9
--- /dev/null
+++ b/vendor/monolog/monolog/src/Monolog/Handler/SyslogUdp/UdpSocket.php
@@ -0,0 +1,46 @@
+<?php
+
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Handler\SyslogUdp;
+
+class UdpSocket
+{
+ const DATAGRAM_MAX_LENGTH = 65023;
+
+ public function __construct($ip, $port = 514)
+ {
+ $this->ip = $ip;
+ $this->port = $port;
+ $this->socket = socket_create(AF_INET, SOCK_DGRAM, SOL_UDP);
+ }
+
+ public function write($line, $header = "")
+ {
+ $this->send($this->assembleMessage($line, $header));
+ }
+
+ public function close()
+ {
+ socket_close($this->socket);
+ }
+
+ protected function send($chunk)
+ {
+ socket_sendto($this->socket, $chunk, strlen($chunk), $flags = 0, $this->ip, $this->port);
+ }
+
+ protected function assembleMessage($line, $header)
+ {
+ $chunkSize = self::DATAGRAM_MAX_LENGTH - strlen($header);
+
+ return $header . substr($line, 0, $chunkSize);
+ }
+}
diff --git a/vendor/monolog/monolog/src/Monolog/Handler/SyslogUdpHandler.php b/vendor/monolog/monolog/src/Monolog/Handler/SyslogUdpHandler.php
new file mode 100644
index 00000000..aa047c07
--- /dev/null
+++ b/vendor/monolog/monolog/src/Monolog/Handler/SyslogUdpHandler.php
@@ -0,0 +1,80 @@
+<?php
+
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Handler;
+
+use Monolog\Logger;
+use Monolog\Handler\SyslogUdp\UdpSocket;
+
+/**
+ * A Handler for logging to a remote syslogd server.
+ *
+ * @author Jesper Skovgaard Nielsen <nulpunkt@gmail.com>
+ */
+class SyslogUdpHandler extends AbstractSyslogHandler
+{
+ /**
+ * @param string $host
+ * @param int $port
+ * @param mixed $facility
+ * @param integer $level The minimum logging level at which this handler will be triggered
+ * @param Boolean $bubble Whether the messages that are handled can bubble up the stack or not
+ */
+ public function __construct($host, $port = 514, $facility = LOG_USER, $level = Logger::DEBUG, $bubble = true)
+ {
+ parent::__construct($facility, $level, $bubble);
+
+ $this->socket = new UdpSocket($host, $port ?: 514);
+ }
+
+ protected function write(array $record)
+ {
+ $lines = $this->splitMessageIntoLines($record['formatted']);
+
+ $header = $this->makeCommonSyslogHeader($this->logLevels[$record['level']]);
+
+ foreach ($lines as $line) {
+ $this->socket->write($line, $header);
+ }
+ }
+
+ public function close()
+ {
+ $this->socket->close();
+ }
+
+ private function splitMessageIntoLines($message)
+ {
+ if (is_array($message)) {
+ $message = implode("\n", $message);
+ }
+
+ return preg_split('/$\R?^/m', $message);
+ }
+
+ /**
+ * Make common syslog header (see rfc5424)
+ */
+ protected function makeCommonSyslogHeader($severity)
+ {
+ $priority = $severity + $this->facility;
+
+ return "<$priority>1 ";
+ }
+
+ /**
+ * Inject your own socket, mainly used for testing
+ */
+ public function setSocket($socket)
+ {
+ $this->socket = $socket;
+ }
+}
diff --git a/vendor/monolog/monolog/src/Monolog/Handler/TestHandler.php b/vendor/monolog/monolog/src/Monolog/Handler/TestHandler.php
new file mode 100644
index 00000000..80b7f283
--- /dev/null
+++ b/vendor/monolog/monolog/src/Monolog/Handler/TestHandler.php
@@ -0,0 +1,195 @@
+<?php
+
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Handler;
+
+use Monolog\Logger;
+
+/**
+ * Used for testing purposes.
+ *
+ * It records all records and gives you access to them for verification.
+ *
+ * @author Jordi Boggiano <j.boggiano@seld.be>
+ */
+class TestHandler extends AbstractProcessingHandler
+{
+ protected $records = array();
+ protected $recordsByLevel = array();
+
+ public function getRecords()
+ {
+ return $this->records;
+ }
+
+ public function hasEmergency($record)
+ {
+ return $this->hasRecord($record, Logger::EMERGENCY);
+ }
+
+ public function hasAlert($record)
+ {
+ return $this->hasRecord($record, Logger::ALERT);
+ }
+
+ public function hasCritical($record)
+ {
+ return $this->hasRecord($record, Logger::CRITICAL);
+ }
+
+ public function hasError($record)
+ {
+ return $this->hasRecord($record, Logger::ERROR);
+ }
+
+ public function hasWarning($record)
+ {
+ return $this->hasRecord($record, Logger::WARNING);
+ }
+
+ public function hasNotice($record)
+ {
+ return $this->hasRecord($record, Logger::NOTICE);
+ }
+
+ public function hasInfo($record)
+ {
+ return $this->hasRecord($record, Logger::INFO);
+ }
+
+ public function hasDebug($record)
+ {
+ return $this->hasRecord($record, Logger::DEBUG);
+ }
+
+ public function hasEmergencyRecords()
+ {
+ return isset($this->recordsByLevel[Logger::EMERGENCY]);
+ }
+
+ public function hasAlertRecords()
+ {
+ return isset($this->recordsByLevel[Logger::ALERT]);
+ }
+
+ public function hasCriticalRecords()
+ {
+ return isset($this->recordsByLevel[Logger::CRITICAL]);
+ }
+
+ public function hasErrorRecords()
+ {
+ return isset($this->recordsByLevel[Logger::ERROR]);
+ }
+
+ public function hasWarningRecords()
+ {
+ return isset($this->recordsByLevel[Logger::WARNING]);
+ }
+
+ public function hasNoticeRecords()
+ {
+ return isset($this->recordsByLevel[Logger::NOTICE]);
+ }
+
+ public function hasInfoRecords()
+ {
+ return isset($this->recordsByLevel[Logger::INFO]);
+ }
+
+ public function hasDebugRecords()
+ {
+ return isset($this->recordsByLevel[Logger::DEBUG]);
+ }
+
+ protected function hasRecord($record, $level)
+ {
+ if (!isset($this->recordsByLevel[$level])) {
+ return false;
+ }
+
+ if (is_array($record)) {
+ $record = $record['message'];
+ }
+
+ foreach ($this->recordsByLevel[$level] as $rec) {
+ if ($rec['message'] === $record) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ public function hasEmergencyThatContains($message)
+ {
+ return $this->hasRecordThatContains($message, Logger::EMERGENCY);
+ }
+
+ public function hasAlertThatContains($message)
+ {
+ return $this->hasRecordThatContains($message, Logger::ALERT);
+ }
+
+ public function hasCriticalThatContains($message)
+ {
+ return $this->hasRecordThatContains($message, Logger::CRITICAL);
+ }
+
+ public function hasErrorThatContains($message)
+ {
+ return $this->hasRecordThatContains($message, Logger::ERROR);
+ }
+
+ public function hasWarningThatContains($message)
+ {
+ return $this->hasRecordThatContains($message, Logger::WARNING);
+ }
+
+ public function hasNoticeThatContains($message)
+ {
+ return $this->hasRecordThatContains($message, Logger::NOTICE);
+ }
+
+ public function hasInfoThatContains($message)
+ {
+ return $this->hasRecordThatContains($message, Logger::INFO);
+ }
+
+ public function hasDebugThatContains($message)
+ {
+ return $this->hasRecordThatContains($message, Logger::DEBUG);
+ }
+
+ public function hasRecordThatContains($message, $level)
+ {
+ if (!isset($this->recordsByLevel[$level])) {
+ return false;
+ }
+
+ foreach ($this->recordsByLevel[$level] as $rec) {
+ if (strpos($rec['message'], $message) !== false) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function write(array $record)
+ {
+ $this->recordsByLevel[$record['level']][] = $record;
+ $this->records[] = $record;
+ }
+}
diff --git a/vendor/monolog/monolog/src/Monolog/Handler/WhatFailureGroupHandler.php b/vendor/monolog/monolog/src/Monolog/Handler/WhatFailureGroupHandler.php
new file mode 100644
index 00000000..05a88173
--- /dev/null
+++ b/vendor/monolog/monolog/src/Monolog/Handler/WhatFailureGroupHandler.php
@@ -0,0 +1,57 @@
+<?php
+
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Handler;
+
+/**
+ * Forwards records to multiple handlers suppressing failures of each handler
+ * and continuing through to give every handler a chance to succeed.
+ *
+ * @author Craig D'Amelio <craig@damelio.ca>
+ */
+class WhatFailureGroupHandler extends GroupHandler
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function handle(array $record)
+ {
+ if ($this->processors) {
+ foreach ($this->processors as $processor) {
+ $record = call_user_func($processor, $record);
+ }
+ }
+
+ foreach ($this->handlers as $handler) {
+ try {
+ $handler->handle($record);
+ } catch (\Exception $e) {
+ // What failure?
+ }
+ }
+
+ return false === $this->bubble;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function handleBatch(array $records)
+ {
+ foreach ($this->handlers as $handler) {
+ try {
+ $handler->handleBatch($records);
+ } catch (\Exception $e) {
+ // What failure?
+ }
+ }
+ }
+}
diff --git a/vendor/monolog/monolog/src/Monolog/Handler/ZendMonitorHandler.php b/vendor/monolog/monolog/src/Monolog/Handler/ZendMonitorHandler.php
new file mode 100644
index 00000000..f22cf218
--- /dev/null
+++ b/vendor/monolog/monolog/src/Monolog/Handler/ZendMonitorHandler.php
@@ -0,0 +1,95 @@
+<?php
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Handler;
+
+use Monolog\Formatter\NormalizerFormatter;
+use Monolog\Logger;
+
+/**
+ * Handler sending logs to Zend Monitor
+ *
+ * @author Christian Bergau <cbergau86@gmail.com>
+ */
+class ZendMonitorHandler extends AbstractProcessingHandler
+{
+ /**
+ * Monolog level / ZendMonitor Custom Event priority map
+ *
+ * @var array
+ */
+ protected $levelMap = array(
+ Logger::DEBUG => 1,
+ Logger::INFO => 2,
+ Logger::NOTICE => 3,
+ Logger::WARNING => 4,
+ Logger::ERROR => 5,
+ Logger::CRITICAL => 6,
+ Logger::ALERT => 7,
+ Logger::EMERGENCY => 0,
+ );
+
+ /**
+ * Construct
+ *
+ * @param int $level
+ * @param bool $bubble
+ * @throws MissingExtensionException
+ */
+ public function __construct($level = Logger::DEBUG, $bubble = true)
+ {
+ if (!function_exists('zend_monitor_custom_event')) {
+ throw new MissingExtensionException('You must have Zend Server installed in order to use this handler');
+ }
+ parent::__construct($level, $bubble);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function write(array $record)
+ {
+ $this->writeZendMonitorCustomEvent(
+ $this->levelMap[$record['level']],
+ $record['message'],
+ $record['formatted']
+ );
+ }
+
+ /**
+ * Write a record to Zend Monitor
+ *
+ * @param int $level
+ * @param string $message
+ * @param array $formatted
+ */
+ protected function writeZendMonitorCustomEvent($level, $message, $formatted)
+ {
+ zend_monitor_custom_event($level, $message, $formatted);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getDefaultFormatter()
+ {
+ return new NormalizerFormatter();
+ }
+
+ /**
+ * Get the level map
+ *
+ * @return array
+ */
+ public function getLevelMap()
+ {
+ return $this->levelMap;
+ }
+}
diff --git a/vendor/monolog/monolog/src/Monolog/Logger.php b/vendor/monolog/monolog/src/Monolog/Logger.php
new file mode 100644
index 00000000..32e3dd92
--- /dev/null
+++ b/vendor/monolog/monolog/src/Monolog/Logger.php
@@ -0,0 +1,629 @@
+<?php
+
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog;
+
+use Monolog\Handler\HandlerInterface;
+use Monolog\Handler\StreamHandler;
+use Psr\Log\LoggerInterface;
+use Psr\Log\InvalidArgumentException;
+
+/**
+ * Monolog log channel
+ *
+ * It contains a stack of Handlers and a stack of Processors,
+ * and uses them to store records that are added to it.
+ *
+ * @author Jordi Boggiano <j.boggiano@seld.be>
+ */
+class Logger implements LoggerInterface
+{
+ /**
+ * Detailed debug information
+ */
+ const DEBUG = 100;
+
+ /**
+ * Interesting events
+ *
+ * Examples: User logs in, SQL logs.
+ */
+ const INFO = 200;
+
+ /**
+ * Uncommon events
+ */
+ const NOTICE = 250;
+
+ /**
+ * Exceptional occurrences that are not errors
+ *
+ * Examples: Use of deprecated APIs, poor use of an API,
+ * undesirable things that are not necessarily wrong.
+ */
+ const WARNING = 300;
+
+ /**
+ * Runtime errors
+ */
+ const ERROR = 400;
+
+ /**
+ * Critical conditions
+ *
+ * Example: Application component unavailable, unexpected exception.
+ */
+ const CRITICAL = 500;
+
+ /**
+ * Action must be taken immediately
+ *
+ * Example: Entire website down, database unavailable, etc.
+ * This should trigger the SMS alerts and wake you up.
+ */
+ const ALERT = 550;
+
+ /**
+ * Urgent alert.
+ */
+ const EMERGENCY = 600;
+
+ /**
+ * Monolog API version
+ *
+ * This is only bumped when API breaks are done and should
+ * follow the major version of the library
+ *
+ * @var int
+ */
+ const API = 1;
+
+ /**
+ * Logging levels from syslog protocol defined in RFC 5424
+ *
+ * @var array $levels Logging levels
+ */
+ protected static $levels = array(
+ 100 => 'DEBUG',
+ 200 => 'INFO',
+ 250 => 'NOTICE',
+ 300 => 'WARNING',
+ 400 => 'ERROR',
+ 500 => 'CRITICAL',
+ 550 => 'ALERT',
+ 600 => 'EMERGENCY',
+ );
+
+ /**
+ * @var \DateTimeZone
+ */
+ protected static $timezone;
+
+ /**
+ * @var string
+ */
+ protected $name;
+
+ /**
+ * The handler stack
+ *
+ * @var HandlerInterface[]
+ */
+ protected $handlers;
+
+ /**
+ * Processors that will process all log records
+ *
+ * To process records of a single handler instead, add the processor on that specific handler
+ *
+ * @var callable[]
+ */
+ protected $processors;
+
+ /**
+ * @param string $name The logging channel
+ * @param HandlerInterface[] $handlers Optional stack of handlers, the first one in the array is called first, etc.
+ * @param callable[] $processors Optional array of processors
+ */
+ public function __construct($name, array $handlers = array(), array $processors = array())
+ {
+ $this->name = $name;
+ $this->handlers = $handlers;
+ $this->processors = $processors;
+ }
+
+ /**
+ * @return string
+ */
+ public function getName()
+ {
+ return $this->name;
+ }
+
+ /**
+ * Pushes a handler on to the stack.
+ *
+ * @param HandlerInterface $handler
+ * @return $this
+ */
+ public function pushHandler(HandlerInterface $handler)
+ {
+ array_unshift($this->handlers, $handler);
+ return $this;
+ }
+
+ /**
+ * Pops a handler from the stack
+ *
+ * @return HandlerInterface
+ */
+ public function popHandler()
+ {
+ if (!$this->handlers) {
+ throw new \LogicException('You tried to pop from an empty handler stack.');
+ }
+
+ return array_shift($this->handlers);
+ }
+
+ /**
+ * @return HandlerInterface[]
+ */
+ public function getHandlers()
+ {
+ return $this->handlers;
+ }
+
+ /**
+ * Adds a processor on to the stack.
+ *
+ * @param callable $callback
+ * @return $this
+ */
+ public function pushProcessor($callback)
+ {
+ if (!is_callable($callback)) {
+ throw new \InvalidArgumentException('Processors must be valid callables (callback or object with an __invoke method), '.var_export($callback, true).' given');
+ }
+ array_unshift($this->processors, $callback);
+ return $this;
+ }
+
+ /**
+ * Removes the processor on top of the stack and returns it.
+ *
+ * @return callable
+ */
+ public function popProcessor()
+ {
+ if (!$this->processors) {
+ throw new \LogicException('You tried to pop from an empty processor stack.');
+ }
+
+ return array_shift($this->processors);
+ }
+
+ /**
+ * @return callable[]
+ */
+ public function getProcessors()
+ {
+ return $this->processors;
+ }
+
+ /**
+ * Adds a log record.
+ *
+ * @param integer $level The logging level
+ * @param string $message The log message
+ * @param array $context The log context
+ * @return Boolean Whether the record has been processed
+ */
+ public function addRecord($level, $message, array $context = array())
+ {
+ if (!$this->handlers) {
+ $this->pushHandler(new StreamHandler('php://stderr', static::DEBUG));
+ }
+
+ $levelName = static::getLevelName($level);
+
+ // check if any handler will handle this message so we can return early and save cycles
+ $handlerKey = null;
+ foreach ($this->handlers as $key => $handler) {
+ if ($handler->isHandling(array('level' => $level))) {
+ $handlerKey = $key;
+ break;
+ }
+ }
+
+ if (null === $handlerKey) {
+ return false;
+ }
+
+ if (!static::$timezone) {
+ static::$timezone = new \DateTimeZone(date_default_timezone_get() ?: 'UTC');
+ }
+
+ $record = array(
+ 'message' => (string) $message,
+ 'context' => $context,
+ 'level' => $level,
+ 'level_name' => $levelName,
+ 'channel' => $this->name,
+ 'datetime' => \DateTime::createFromFormat('U.u', sprintf('%.6F', microtime(true)), static::$timezone)->setTimezone(static::$timezone),
+ 'extra' => array(),
+ );
+
+ foreach ($this->processors as $processor) {
+ $record = call_user_func($processor, $record);
+ }
+ while (isset($this->handlers[$handlerKey]) &&
+ false === $this->handlers[$handlerKey]->handle($record)) {
+ $handlerKey++;
+ }
+
+ return true;
+ }
+
+ /**
+ * Adds a log record at the DEBUG level.
+ *
+ * @param string $message The log message
+ * @param array $context The log context
+ * @return Boolean Whether the record has been processed
+ */
+ public function addDebug($message, array $context = array())
+ {
+ return $this->addRecord(static::DEBUG, $message, $context);
+ }
+
+ /**
+ * Adds a log record at the INFO level.
+ *
+ * @param string $message The log message
+ * @param array $context The log context
+ * @return Boolean Whether the record has been processed
+ */
+ public function addInfo($message, array $context = array())
+ {
+ return $this->addRecord(static::INFO, $message, $context);
+ }
+
+ /**
+ * Adds a log record at the NOTICE level.
+ *
+ * @param string $message The log message
+ * @param array $context The log context
+ * @return Boolean Whether the record has been processed
+ */
+ public function addNotice($message, array $context = array())
+ {
+ return $this->addRecord(static::NOTICE, $message, $context);
+ }
+
+ /**
+ * Adds a log record at the WARNING level.
+ *
+ * @param string $message The log message
+ * @param array $context The log context
+ * @return Boolean Whether the record has been processed
+ */
+ public function addWarning($message, array $context = array())
+ {
+ return $this->addRecord(static::WARNING, $message, $context);
+ }
+
+ /**
+ * Adds a log record at the ERROR level.
+ *
+ * @param string $message The log message
+ * @param array $context The log context
+ * @return Boolean Whether the record has been processed
+ */
+ public function addError($message, array $context = array())
+ {
+ return $this->addRecord(static::ERROR, $message, $context);
+ }
+
+ /**
+ * Adds a log record at the CRITICAL level.
+ *
+ * @param string $message The log message
+ * @param array $context The log context
+ * @return Boolean Whether the record has been processed
+ */
+ public function addCritical($message, array $context = array())
+ {
+ return $this->addRecord(static::CRITICAL, $message, $context);
+ }
+
+ /**
+ * Adds a log record at the ALERT level.
+ *
+ * @param string $message The log message
+ * @param array $context The log context
+ * @return Boolean Whether the record has been processed
+ */
+ public function addAlert($message, array $context = array())
+ {
+ return $this->addRecord(static::ALERT, $message, $context);
+ }
+
+ /**
+ * Adds a log record at the EMERGENCY level.
+ *
+ * @param string $message The log message
+ * @param array $context The log context
+ * @return Boolean Whether the record has been processed
+ */
+ public function addEmergency($message, array $context = array())
+ {
+ return $this->addRecord(static::EMERGENCY, $message, $context);
+ }
+
+ /**
+ * Gets all supported logging levels.
+ *
+ * @return array Assoc array with human-readable level names => level codes.
+ */
+ public static function getLevels()
+ {
+ return array_flip(static::$levels);
+ }
+
+ /**
+ * Gets the name of the logging level.
+ *
+ * @param integer $level
+ * @return string
+ */
+ public static function getLevelName($level)
+ {
+ if (!isset(static::$levels[$level])) {
+ throw new InvalidArgumentException('Level "'.$level.'" is not defined, use one of: '.implode(', ', array_keys(static::$levels)));
+ }
+
+ return static::$levels[$level];
+ }
+
+ /**
+ * Converts PSR-3 levels to Monolog ones if necessary
+ *
+ * @param string|int Level number (monolog) or name (PSR-3)
+ * @return int
+ */
+ public static function toMonologLevel($level)
+ {
+ if (is_string($level) && defined(__CLASS__.'::'.strtoupper($level))) {
+ return constant(__CLASS__.'::'.strtoupper($level));
+ }
+
+ return $level;
+ }
+
+ /**
+ * Checks whether the Logger has a handler that listens on the given level
+ *
+ * @param integer $level
+ * @return Boolean
+ */
+ public function isHandling($level)
+ {
+ $record = array(
+ 'level' => $level,
+ );
+
+ foreach ($this->handlers as $handler) {
+ if ($handler->isHandling($record)) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Adds a log record at an arbitrary level.
+ *
+ * This method allows for compatibility with common interfaces.
+ *
+ * @param mixed $level The log level
+ * @param string $message The log message
+ * @param array $context The log context
+ * @return Boolean Whether the record has been processed
+ */
+ public function log($level, $message, array $context = array())
+ {
+ $level = static::toMonologLevel($level);
+
+ return $this->addRecord($level, $message, $context);
+ }
+
+ /**
+ * Adds a log record at the DEBUG level.
+ *
+ * This method allows for compatibility with common interfaces.
+ *
+ * @param string $message The log message
+ * @param array $context The log context
+ * @return Boolean Whether the record has been processed
+ */
+ public function debug($message, array $context = array())
+ {
+ return $this->addRecord(static::DEBUG, $message, $context);
+ }
+
+ /**
+ * Adds a log record at the INFO level.
+ *
+ * This method allows for compatibility with common interfaces.
+ *
+ * @param string $message The log message
+ * @param array $context The log context
+ * @return Boolean Whether the record has been processed
+ */
+ public function info($message, array $context = array())
+ {
+ return $this->addRecord(static::INFO, $message, $context);
+ }
+
+ /**
+ * Adds a log record at the NOTICE level.
+ *
+ * This method allows for compatibility with common interfaces.
+ *
+ * @param string $message The log message
+ * @param array $context The log context
+ * @return Boolean Whether the record has been processed
+ */
+ public function notice($message, array $context = array())
+ {
+ return $this->addRecord(static::NOTICE, $message, $context);
+ }
+
+ /**
+ * Adds a log record at the WARNING level.
+ *
+ * This method allows for compatibility with common interfaces.
+ *
+ * @param string $message The log message
+ * @param array $context The log context
+ * @return Boolean Whether the record has been processed
+ */
+ public function warn($message, array $context = array())
+ {
+ return $this->addRecord(static::WARNING, $message, $context);
+ }
+
+ /**
+ * Adds a log record at the WARNING level.
+ *
+ * This method allows for compatibility with common interfaces.
+ *
+ * @param string $message The log message
+ * @param array $context The log context
+ * @return Boolean Whether the record has been processed
+ */
+ public function warning($message, array $context = array())
+ {
+ return $this->addRecord(static::WARNING, $message, $context);
+ }
+
+ /**
+ * Adds a log record at the ERROR level.
+ *
+ * This method allows for compatibility with common interfaces.
+ *
+ * @param string $message The log message
+ * @param array $context The log context
+ * @return Boolean Whether the record has been processed
+ */
+ public function err($message, array $context = array())
+ {
+ return $this->addRecord(static::ERROR, $message, $context);
+ }
+
+ /**
+ * Adds a log record at the ERROR level.
+ *
+ * This method allows for compatibility with common interfaces.
+ *
+ * @param string $message The log message
+ * @param array $context The log context
+ * @return Boolean Whether the record has been processed
+ */
+ public function error($message, array $context = array())
+ {
+ return $this->addRecord(static::ERROR, $message, $context);
+ }
+
+ /**
+ * Adds a log record at the CRITICAL level.
+ *
+ * This method allows for compatibility with common interfaces.
+ *
+ * @param string $message The log message
+ * @param array $context The log context
+ * @return Boolean Whether the record has been processed
+ */
+ public function crit($message, array $context = array())
+ {
+ return $this->addRecord(static::CRITICAL, $message, $context);
+ }
+
+ /**
+ * Adds a log record at the CRITICAL level.
+ *
+ * This method allows for compatibility with common interfaces.
+ *
+ * @param string $message The log message
+ * @param array $context The log context
+ * @return Boolean Whether the record has been processed
+ */
+ public function critical($message, array $context = array())
+ {
+ return $this->addRecord(static::CRITICAL, $message, $context);
+ }
+
+ /**
+ * Adds a log record at the ALERT level.
+ *
+ * This method allows for compatibility with common interfaces.
+ *
+ * @param string $message The log message
+ * @param array $context The log context
+ * @return Boolean Whether the record has been processed
+ */
+ public function alert($message, array $context = array())
+ {
+ return $this->addRecord(static::ALERT, $message, $context);
+ }
+
+ /**
+ * Adds a log record at the EMERGENCY level.
+ *
+ * This method allows for compatibility with common interfaces.
+ *
+ * @param string $message The log message
+ * @param array $context The log context
+ * @return Boolean Whether the record has been processed
+ */
+ public function emerg($message, array $context = array())
+ {
+ return $this->addRecord(static::EMERGENCY, $message, $context);
+ }
+
+ /**
+ * Adds a log record at the EMERGENCY level.
+ *
+ * This method allows for compatibility with common interfaces.
+ *
+ * @param string $message The log message
+ * @param array $context The log context
+ * @return Boolean Whether the record has been processed
+ */
+ public function emergency($message, array $context = array())
+ {
+ return $this->addRecord(static::EMERGENCY, $message, $context);
+ }
+
+ /**
+ * Set the timezone to be used for the timestamp of log records.
+ *
+ * This is stored globally for all Logger instances
+ *
+ * @param \DateTimeZone $tz Timezone object
+ */
+ public static function setTimezone(\DateTimeZone $tz)
+ {
+ self::$timezone = $tz;
+ }
+}
diff --git a/vendor/monolog/monolog/src/Monolog/Processor/GitProcessor.php b/vendor/monolog/monolog/src/Monolog/Processor/GitProcessor.php
new file mode 100644
index 00000000..1899400d
--- /dev/null
+++ b/vendor/monolog/monolog/src/Monolog/Processor/GitProcessor.php
@@ -0,0 +1,64 @@
+<?php
+
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Processor;
+
+use Monolog\Logger;
+
+/**
+ * Injects Git branch and Git commit SHA in all records
+ *
+ * @author Nick Otter
+ * @author Jordi Boggiano <j.boggiano@seld.be>
+ */
+class GitProcessor
+{
+ private $level;
+ private static $cache;
+
+ public function __construct($level = Logger::DEBUG)
+ {
+ $this->level = Logger::toMonologLevel($level);
+ }
+
+ /**
+ * @param array $record
+ * @return array
+ */
+ public function __invoke(array $record)
+ {
+ // return if the level is not high enough
+ if ($record['level'] < $this->level) {
+ return $record;
+ }
+
+ $record['extra']['git'] = self::getGitInfo();
+
+ return $record;
+ }
+
+ private static function getGitInfo()
+ {
+ if (self::$cache) {
+ return self::$cache;
+ }
+
+ $branches = `git branch -v --no-abbrev`;
+ if (preg_match('{^\* (.+?)\s+([a-f0-9]{40})(?:\s|$)}m', $branches, $matches)) {
+ return self::$cache = array(
+ 'branch' => $matches[1],
+ 'commit' => $matches[2],
+ );
+ }
+
+ return self::$cache = array();
+ }
+}
diff --git a/vendor/monolog/monolog/src/Monolog/Processor/IntrospectionProcessor.php b/vendor/monolog/monolog/src/Monolog/Processor/IntrospectionProcessor.php
new file mode 100644
index 00000000..294a295c
--- /dev/null
+++ b/vendor/monolog/monolog/src/Monolog/Processor/IntrospectionProcessor.php
@@ -0,0 +1,82 @@
+<?php
+
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Processor;
+
+use Monolog\Logger;
+
+/**
+ * Injects line/file:class/function where the log message came from
+ *
+ * Warning: This only works if the handler processes the logs directly.
+ * If you put the processor on a handler that is behind a FingersCrossedHandler
+ * for example, the processor will only be called once the trigger level is reached,
+ * and all the log records will have the same file/line/.. data from the call that
+ * triggered the FingersCrossedHandler.
+ *
+ * @author Jordi Boggiano <j.boggiano@seld.be>
+ */
+class IntrospectionProcessor
+{
+ private $level;
+
+ private $skipClassesPartials;
+
+ public function __construct($level = Logger::DEBUG, array $skipClassesPartials = array('Monolog\\'))
+ {
+ $this->level = Logger::toMonologLevel($level);
+ $this->skipClassesPartials = $skipClassesPartials;
+ }
+
+ /**
+ * @param array $record
+ * @return array
+ */
+ public function __invoke(array $record)
+ {
+ // return if the level is not high enough
+ if ($record['level'] < $this->level) {
+ return $record;
+ }
+
+ $trace = debug_backtrace();
+
+ // skip first since it's always the current method
+ array_shift($trace);
+ // the call_user_func call is also skipped
+ array_shift($trace);
+
+ $i = 0;
+
+ while (isset($trace[$i]['class'])) {
+ foreach ($this->skipClassesPartials as $part) {
+ if (strpos($trace[$i]['class'], $part) !== false) {
+ $i++;
+ continue 2;
+ }
+ }
+ break;
+ }
+
+ // we should have the call source now
+ $record['extra'] = array_merge(
+ $record['extra'],
+ array(
+ 'file' => isset($trace[$i-1]['file']) ? $trace[$i-1]['file'] : null,
+ 'line' => isset($trace[$i-1]['line']) ? $trace[$i-1]['line'] : null,
+ 'class' => isset($trace[$i]['class']) ? $trace[$i]['class'] : null,
+ 'function' => isset($trace[$i]['function']) ? $trace[$i]['function'] : null,
+ )
+ );
+
+ return $record;
+ }
+}
diff --git a/vendor/monolog/monolog/src/Monolog/Processor/MemoryPeakUsageProcessor.php b/vendor/monolog/monolog/src/Monolog/Processor/MemoryPeakUsageProcessor.php
new file mode 100644
index 00000000..552fd709
--- /dev/null
+++ b/vendor/monolog/monolog/src/Monolog/Processor/MemoryPeakUsageProcessor.php
@@ -0,0 +1,40 @@
+<?php
+
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Processor;
+
+/**
+ * Injects memory_get_peak_usage in all records
+ *
+ * @see Monolog\Processor\MemoryProcessor::__construct() for options
+ * @author Rob Jensen
+ */
+class MemoryPeakUsageProcessor extends MemoryProcessor
+{
+ /**
+ * @param array $record
+ * @return array
+ */
+ public function __invoke(array $record)
+ {
+ $bytes = memory_get_peak_usage($this->realUsage);
+ $formatted = $this->formatBytes($bytes);
+
+ $record['extra'] = array_merge(
+ $record['extra'],
+ array(
+ 'memory_peak_usage' => $formatted,
+ )
+ );
+
+ return $record;
+ }
+}
diff --git a/vendor/monolog/monolog/src/Monolog/Processor/MemoryProcessor.php b/vendor/monolog/monolog/src/Monolog/Processor/MemoryProcessor.php
new file mode 100644
index 00000000..0820def4
--- /dev/null
+++ b/vendor/monolog/monolog/src/Monolog/Processor/MemoryProcessor.php
@@ -0,0 +1,63 @@
+<?php
+
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Processor;
+
+/**
+ * Some methods that are common for all memory processors
+ *
+ * @author Rob Jensen
+ */
+abstract class MemoryProcessor
+{
+ /**
+ * @var boolean If true, get the real size of memory allocated from system. Else, only the memory used by emalloc() is reported.
+ */
+ protected $realUsage;
+
+ /**
+ * @var boolean If true, then format memory size to human readable string (MB, KB, B depending on size)
+ */
+ protected $useFormatting;
+
+ /**
+ * @param boolean $realUsage Set this to true to get the real size of memory allocated from system.
+ * @param boolean $useFormatting If true, then format memory size to human readable string (MB, KB, B depending on size)
+ */
+ public function __construct($realUsage = true, $useFormatting = true)
+ {
+ $this->realUsage = (boolean) $realUsage;
+ $this->useFormatting = (boolean) $useFormatting;
+ }
+
+ /**
+ * Formats bytes into a human readable string if $this->useFormatting is true, otherwise return $bytes as is
+ *
+ * @param int $bytes
+ * @return string|int Formatted string if $this->useFormatting is true, otherwise return $bytes as is
+ */
+ protected function formatBytes($bytes)
+ {
+ $bytes = (int) $bytes;
+
+ if (!$this->useFormatting) {
+ return $bytes;
+ }
+
+ if ($bytes > 1024*1024) {
+ return round($bytes/1024/1024, 2).' MB';
+ } elseif ($bytes > 1024) {
+ return round($bytes/1024, 2).' KB';
+ }
+
+ return $bytes . ' B';
+ }
+}
diff --git a/vendor/monolog/monolog/src/Monolog/Processor/MemoryUsageProcessor.php b/vendor/monolog/monolog/src/Monolog/Processor/MemoryUsageProcessor.php
new file mode 100644
index 00000000..0c4dd9ab
--- /dev/null
+++ b/vendor/monolog/monolog/src/Monolog/Processor/MemoryUsageProcessor.php
@@ -0,0 +1,40 @@
+<?php
+
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Processor;
+
+/**
+ * Injects memory_get_usage in all records
+ *
+ * @see Monolog\Processor\MemoryProcessor::__construct() for options
+ * @author Rob Jensen
+ */
+class MemoryUsageProcessor extends MemoryProcessor
+{
+ /**
+ * @param array $record
+ * @return array
+ */
+ public function __invoke(array $record)
+ {
+ $bytes = memory_get_usage($this->realUsage);
+ $formatted = $this->formatBytes($bytes);
+
+ $record['extra'] = array_merge(
+ $record['extra'],
+ array(
+ 'memory_usage' => $formatted,
+ )
+ );
+
+ return $record;
+ }
+}
diff --git a/vendor/monolog/monolog/src/Monolog/Processor/ProcessIdProcessor.php b/vendor/monolog/monolog/src/Monolog/Processor/ProcessIdProcessor.php
new file mode 100644
index 00000000..9d3f5590
--- /dev/null
+++ b/vendor/monolog/monolog/src/Monolog/Processor/ProcessIdProcessor.php
@@ -0,0 +1,31 @@
+<?php
+
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Processor;
+
+/**
+ * Adds value of getmypid into records
+ *
+ * @author Andreas Hörnicke
+ */
+class ProcessIdProcessor
+{
+ /**
+ * @param array $record
+ * @return array
+ */
+ public function __invoke(array $record)
+ {
+ $record['extra']['process_id'] = getmypid();
+
+ return $record;
+ }
+}
diff --git a/vendor/monolog/monolog/src/Monolog/Processor/PsrLogMessageProcessor.php b/vendor/monolog/monolog/src/Monolog/Processor/PsrLogMessageProcessor.php
new file mode 100644
index 00000000..c2686ce5
--- /dev/null
+++ b/vendor/monolog/monolog/src/Monolog/Processor/PsrLogMessageProcessor.php
@@ -0,0 +1,48 @@
+<?php
+
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Processor;
+
+/**
+ * Processes a record's message according to PSR-3 rules
+ *
+ * It replaces {foo} with the value from $context['foo']
+ *
+ * @author Jordi Boggiano <j.boggiano@seld.be>
+ */
+class PsrLogMessageProcessor
+{
+ /**
+ * @param array $record
+ * @return array
+ */
+ public function __invoke(array $record)
+ {
+ if (false === strpos($record['message'], '{')) {
+ return $record;
+ }
+
+ $replacements = array();
+ foreach ($record['context'] as $key => $val) {
+ if (is_null($val) || is_scalar($val) || (is_object($val) && method_exists($val, "__toString"))) {
+ $replacements['{'.$key.'}'] = $val;
+ } elseif (is_object($val)) {
+ $replacements['{'.$key.'}'] = '[object '.get_class($val).']';
+ } else {
+ $replacements['{'.$key.'}'] = '['.gettype($val).']';
+ }
+ }
+
+ $record['message'] = strtr($record['message'], $replacements);
+
+ return $record;
+ }
+}
diff --git a/vendor/monolog/monolog/src/Monolog/Processor/TagProcessor.php b/vendor/monolog/monolog/src/Monolog/Processor/TagProcessor.php
new file mode 100644
index 00000000..2784cef4
--- /dev/null
+++ b/vendor/monolog/monolog/src/Monolog/Processor/TagProcessor.php
@@ -0,0 +1,34 @@
+<?php
+
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Processor;
+
+/**
+ * Adds a tags array into record
+ *
+ * @author Martijn Riemers
+ */
+class TagProcessor
+{
+ private $tags;
+
+ public function __construct(array $tags = array())
+ {
+ $this->tags = $tags;
+ }
+
+ public function __invoke(array $record)
+ {
+ $record['extra']['tags'] = $this->tags;
+
+ return $record;
+ }
+}
diff --git a/vendor/monolog/monolog/src/Monolog/Processor/UidProcessor.php b/vendor/monolog/monolog/src/Monolog/Processor/UidProcessor.php
new file mode 100644
index 00000000..80270d08
--- /dev/null
+++ b/vendor/monolog/monolog/src/Monolog/Processor/UidProcessor.php
@@ -0,0 +1,38 @@
+<?php
+
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Processor;
+
+/**
+ * Adds a unique identifier into records
+ *
+ * @author Simon Mönch <sm@webfactory.de>
+ */
+class UidProcessor
+{
+ private $uid;
+
+ public function __construct($length = 7)
+ {
+ if (!is_int($length) || $length > 32 || $length < 1) {
+ throw new \InvalidArgumentException('The uid length must be an integer between 1 and 32');
+ }
+
+ $this->uid = substr(hash('md5', uniqid('', true)), 0, $length);
+ }
+
+ public function __invoke(array $record)
+ {
+ $record['extra']['uid'] = $this->uid;
+
+ return $record;
+ }
+}
diff --git a/vendor/monolog/monolog/src/Monolog/Processor/WebProcessor.php b/vendor/monolog/monolog/src/Monolog/Processor/WebProcessor.php
new file mode 100644
index 00000000..21f22a6e
--- /dev/null
+++ b/vendor/monolog/monolog/src/Monolog/Processor/WebProcessor.php
@@ -0,0 +1,105 @@
+<?php
+
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Processor;
+
+/**
+ * Injects url/method and remote IP of the current web request in all records
+ *
+ * @author Jordi Boggiano <j.boggiano@seld.be>
+ */
+class WebProcessor
+{
+ /**
+ * @var array|\ArrayAccess
+ */
+ protected $serverData;
+
+ /**
+ * @var array
+ */
+ protected $extraFields = array(
+ 'url' => 'REQUEST_URI',
+ 'ip' => 'REMOTE_ADDR',
+ 'http_method' => 'REQUEST_METHOD',
+ 'server' => 'SERVER_NAME',
+ 'referrer' => 'HTTP_REFERER',
+ );
+
+ /**
+ * @param array|\ArrayAccess $serverData Array or object w/ ArrayAccess that provides access to the $_SERVER data
+ * @param array|null $extraFields Extra field names to be added (all available by default)
+ */
+ public function __construct($serverData = null, array $extraFields = null)
+ {
+ if (null === $serverData) {
+ $this->serverData = &$_SERVER;
+ } elseif (is_array($serverData) || $serverData instanceof \ArrayAccess) {
+ $this->serverData = $serverData;
+ } else {
+ throw new \UnexpectedValueException('$serverData must be an array or object implementing ArrayAccess.');
+ }
+
+ if (null !== $extraFields) {
+ foreach (array_keys($this->extraFields) as $fieldName) {
+ if (!in_array($fieldName, $extraFields)) {
+ unset($this->extraFields[$fieldName]);
+ }
+ }
+ }
+ }
+
+ /**
+ * @param array $record
+ * @return array
+ */
+ public function __invoke(array $record)
+ {
+ // skip processing if for some reason request data
+ // is not present (CLI or wonky SAPIs)
+ if (!isset($this->serverData['REQUEST_URI'])) {
+ return $record;
+ }
+
+ $record['extra'] = $this->appendExtraFields($record['extra']);
+
+ return $record;
+ }
+
+ /**
+ * @param string $extraName
+ * @param string $serverName
+ * @return $this
+ */
+ public function addExtraField($extraName, $serverName)
+ {
+ $this->extraFields[$extraName] = $serverName;
+
+ return $this;
+ }
+
+ /**
+ * @param array $extra
+ * @return array
+ */
+ private function appendExtraFields(array $extra)
+ {
+ foreach ($this->extraFields as $extraName => $serverName) {
+ $extra[$extraName] = isset($this->serverData[$serverName]) ? $this->serverData[$serverName] : null;
+ }
+
+ if (isset($this->serverData['UNIQUE_ID'])) {
+ $extra['unique_id'] = $this->serverData['UNIQUE_ID'];
+ }
+
+ return $extra;
+ }
+}
diff --git a/vendor/monolog/monolog/src/Monolog/Registry.php b/vendor/monolog/monolog/src/Monolog/Registry.php
new file mode 100644
index 00000000..a33cb7c4
--- /dev/null
+++ b/vendor/monolog/monolog/src/Monolog/Registry.php
@@ -0,0 +1,134 @@
+<?php
+
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog;
+
+use InvalidArgumentException;
+
+/**
+ * Monolog log registry
+ *
+ * Allows to get `Logger` instances in the global scope
+ * via static method calls on this class.
+ *
+ * <code>
+ * $application = new Monolog\Logger('application');
+ * $api = new Monolog\Logger('api');
+ *
+ * Monolog\Registry::addLogger($application);
+ * Monolog\Registry::addLogger($api);
+ *
+ * function testLogger()
+ * {
+ * Monolog\Registry::api()->addError('Sent to $api Logger instance');
+ * Monolog\Registry::application()->addError('Sent to $application Logger instance');
+ * }
+ * </code>
+ *
+ * @author Tomas Tatarko <tomas@tatarko.sk>
+ */
+class Registry
+{
+ /**
+ * List of all loggers in the registry (by named indexes)
+ *
+ * @var Logger[]
+ */
+ private static $loggers = array();
+
+ /**
+ * Adds new logging channel to the registry
+ *
+ * @param Logger $logger Instance of the logging channel
+ * @param string|null $name Name of the logging channel ($logger->getName() by default)
+ * @param boolean $overwrite Overwrite instance in the registry if the given name already exists?
+ * @throws \InvalidArgumentException If $overwrite set to false and named Logger instance already exists
+ */
+ public static function addLogger(Logger $logger, $name = null, $overwrite = false)
+ {
+ $name = $name ?: $logger->getName();
+
+ if (isset(self::$loggers[$name]) && !$overwrite) {
+ throw new InvalidArgumentException('Logger with the given name already exists');
+ }
+
+ self::$loggers[$name] = $logger;
+ }
+
+ /**
+ * Checks if such logging channel exists by name or instance
+ *
+ * @param string|Logger $logger Name or logger instance
+ */
+ public static function hasLogger($logger)
+ {
+ if ($logger instanceof Logger) {
+ $index = array_search($logger, self::$loggers, true);
+
+ return false !== $index;
+ } else {
+ return isset(self::$loggers[$logger]);
+ }
+ }
+
+ /**
+ * Removes instance from registry by name or instance
+ *
+ * @param string|Logger $logger Name or logger instance
+ */
+ public static function removeLogger($logger)
+ {
+ if ($logger instanceof Logger) {
+ if (false !== ($idx = array_search($logger, self::$loggers, true))) {
+ unset(self::$loggers[$idx]);
+ }
+ } else {
+ unset(self::$loggers[$logger]);
+ }
+ }
+
+ /**
+ * Clears the registry
+ */
+ public static function clear()
+ {
+ self::$loggers = array();
+ }
+
+ /**
+ * Gets Logger instance from the registry
+ *
+ * @param string $name Name of the requested Logger instance
+ * @return Logger Requested instance of Logger
+ * @throws \InvalidArgumentException If named Logger instance is not in the registry
+ */
+ public static function getInstance($name)
+ {
+ if (!isset(self::$loggers[$name])) {
+ throw new InvalidArgumentException(sprintf('Requested "%s" logger instance is not in the registry', $name));
+ }
+
+ return self::$loggers[$name];
+ }
+
+ /**
+ * Gets Logger instance from the registry via static method call
+ *
+ * @param string $name Name of the requested Logger instance
+ * @param array $arguments Arguments passed to static method call
+ * @return Logger Requested instance of Logger
+ * @throws \InvalidArgumentException If named Logger instance is not in the registry
+ */
+ public static function __callStatic($name, $arguments)
+ {
+ return self::getInstance($name);
+ }
+}
diff --git a/vendor/monolog/monolog/tests/Monolog/ErrorHandlerTest.php b/vendor/monolog/monolog/tests/Monolog/ErrorHandlerTest.php
new file mode 100644
index 00000000..a9a3f301
--- /dev/null
+++ b/vendor/monolog/monolog/tests/Monolog/ErrorHandlerTest.php
@@ -0,0 +1,31 @@
+<?php
+
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog;
+
+use Monolog\Handler\TestHandler;
+
+class ErrorHandlerTest extends \PHPUnit_Framework_TestCase
+{
+ public function testHandleError()
+ {
+ $logger = new Logger('test', array($handler = new TestHandler));
+ $errHandler = new ErrorHandler($logger);
+
+ $errHandler->registerErrorHandler(array(E_USER_NOTICE => Logger::EMERGENCY), false);
+ trigger_error('Foo', E_USER_ERROR);
+ $this->assertCount(1, $handler->getRecords());
+ $this->assertTrue($handler->hasErrorRecords());
+ trigger_error('Foo', E_USER_NOTICE);
+ $this->assertCount(2, $handler->getRecords());
+ $this->assertTrue($handler->hasEmergencyRecords());
+ }
+}
diff --git a/vendor/monolog/monolog/tests/Monolog/Formatter/ChromePHPFormatterTest.php b/vendor/monolog/monolog/tests/Monolog/Formatter/ChromePHPFormatterTest.php
new file mode 100644
index 00000000..e7f7334e
--- /dev/null
+++ b/vendor/monolog/monolog/tests/Monolog/Formatter/ChromePHPFormatterTest.php
@@ -0,0 +1,158 @@
+<?php
+
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Formatter;
+
+use Monolog\Logger;
+
+class ChromePHPFormatterTest extends \PHPUnit_Framework_TestCase
+{
+ /**
+ * @covers Monolog\Formatter\ChromePHPFormatter::format
+ */
+ public function testDefaultFormat()
+ {
+ $formatter = new ChromePHPFormatter();
+ $record = array(
+ 'level' => Logger::ERROR,
+ 'level_name' => 'ERROR',
+ 'channel' => 'meh',
+ 'context' => array('from' => 'logger'),
+ 'datetime' => new \DateTime("@0"),
+ 'extra' => array('ip' => '127.0.0.1'),
+ 'message' => 'log',
+ );
+
+ $message = $formatter->format($record);
+
+ $this->assertEquals(
+ array(
+ 'meh',
+ array(
+ 'message' => 'log',
+ 'context' => array('from' => 'logger'),
+ 'extra' => array('ip' => '127.0.0.1'),
+ ),
+ 'unknown',
+ 'error'
+ ),
+ $message
+ );
+ }
+
+ /**
+ * @covers Monolog\Formatter\ChromePHPFormatter::format
+ */
+ public function testFormatWithFileAndLine()
+ {
+ $formatter = new ChromePHPFormatter();
+ $record = array(
+ 'level' => Logger::CRITICAL,
+ 'level_name' => 'CRITICAL',
+ 'channel' => 'meh',
+ 'context' => array('from' => 'logger'),
+ 'datetime' => new \DateTime("@0"),
+ 'extra' => array('ip' => '127.0.0.1', 'file' => 'test', 'line' => 14),
+ 'message' => 'log',
+ );
+
+ $message = $formatter->format($record);
+
+ $this->assertEquals(
+ array(
+ 'meh',
+ array(
+ 'message' => 'log',
+ 'context' => array('from' => 'logger'),
+ 'extra' => array('ip' => '127.0.0.1'),
+ ),
+ 'test : 14',
+ 'error'
+ ),
+ $message
+ );
+ }
+
+ /**
+ * @covers Monolog\Formatter\ChromePHPFormatter::format
+ */
+ public function testFormatWithoutContext()
+ {
+ $formatter = new ChromePHPFormatter();
+ $record = array(
+ 'level' => Logger::DEBUG,
+ 'level_name' => 'DEBUG',
+ 'channel' => 'meh',
+ 'context' => array(),
+ 'datetime' => new \DateTime("@0"),
+ 'extra' => array(),
+ 'message' => 'log',
+ );
+
+ $message = $formatter->format($record);
+
+ $this->assertEquals(
+ array(
+ 'meh',
+ 'log',
+ 'unknown',
+ 'log'
+ ),
+ $message
+ );
+ }
+
+ /**
+ * @covers Monolog\Formatter\ChromePHPFormatter::formatBatch
+ */
+ public function testBatchFormatThrowException()
+ {
+ $formatter = new ChromePHPFormatter();
+ $records = array(
+ array(
+ 'level' => Logger::INFO,
+ 'level_name' => 'INFO',
+ 'channel' => 'meh',
+ 'context' => array(),
+ 'datetime' => new \DateTime("@0"),
+ 'extra' => array(),
+ 'message' => 'log',
+ ),
+ array(
+ 'level' => Logger::WARNING,
+ 'level_name' => 'WARNING',
+ 'channel' => 'foo',
+ 'context' => array(),
+ 'datetime' => new \DateTime("@0"),
+ 'extra' => array(),
+ 'message' => 'log2',
+ ),
+ );
+
+ $this->assertEquals(
+ array(
+ array(
+ 'meh',
+ 'log',
+ 'unknown',
+ 'info'
+ ),
+ array(
+ 'foo',
+ 'log2',
+ 'unknown',
+ 'warn'
+ ),
+ ),
+ $formatter->formatBatch($records)
+ );
+ }
+}
diff --git a/vendor/monolog/monolog/tests/Monolog/Formatter/ElasticaFormatterTest.php b/vendor/monolog/monolog/tests/Monolog/Formatter/ElasticaFormatterTest.php
new file mode 100644
index 00000000..546e5c26
--- /dev/null
+++ b/vendor/monolog/monolog/tests/Monolog/Formatter/ElasticaFormatterTest.php
@@ -0,0 +1,79 @@
+<?php
+
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Formatter;
+
+use Monolog\Logger;
+
+class ElasticaFormatterTest extends \PHPUnit_Framework_TestCase
+{
+ public function setUp()
+ {
+ if (!class_exists("Elastica\Document")) {
+ $this->markTestSkipped("ruflin/elastica not installed");
+ }
+ }
+
+ /**
+ * @covers Monolog\Formatter\ElasticaFormatter::__construct
+ * @covers Monolog\Formatter\ElasticaFormatter::format
+ * @covers Monolog\Formatter\ElasticaFormatter::getDocument
+ */
+ public function testFormat()
+ {
+ // test log message
+ $msg = array(
+ 'level' => Logger::ERROR,
+ 'level_name' => 'ERROR',
+ 'channel' => 'meh',
+ 'context' => array('foo' => 7, 'bar', 'class' => new \stdClass),
+ 'datetime' => new \DateTime("@0"),
+ 'extra' => array(),
+ 'message' => 'log',
+ );
+
+ // expected values
+ $expected = $msg;
+ $expected['datetime'] = '1970-01-01T00:00:00+0000';
+ $expected['context'] = array(
+ 'class' => '[object] (stdClass: {})',
+ 'foo' => 7,
+ 0 => 'bar',
+ );
+
+ // format log message
+ $formatter = new ElasticaFormatter('my_index', 'doc_type');
+ $doc = $formatter->format($msg);
+ $this->assertInstanceOf('Elastica\Document', $doc);
+
+ // Document parameters
+ $params = $doc->getParams();
+ $this->assertEquals('my_index', $params['_index']);
+ $this->assertEquals('doc_type', $params['_type']);
+
+ // Document data values
+ $data = $doc->getData();
+ foreach (array_keys($expected) as $key) {
+ $this->assertEquals($expected[$key], $data[$key]);
+ }
+ }
+
+ /**
+ * @covers Monolog\Formatter\ElasticaFormatter::getIndex
+ * @covers Monolog\Formatter\ElasticaFormatter::getType
+ */
+ public function testGetters()
+ {
+ $formatter = new ElasticaFormatter('my_index', 'doc_type');
+ $this->assertEquals('my_index', $formatter->getIndex());
+ $this->assertEquals('doc_type', $formatter->getType());
+ }
+}
diff --git a/vendor/monolog/monolog/tests/Monolog/Formatter/FlowdockFormatterTest.php b/vendor/monolog/monolog/tests/Monolog/Formatter/FlowdockFormatterTest.php
new file mode 100644
index 00000000..1b2fd97a
--- /dev/null
+++ b/vendor/monolog/monolog/tests/Monolog/Formatter/FlowdockFormatterTest.php
@@ -0,0 +1,55 @@
+<?php
+
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Formatter;
+
+use Monolog\Logger;
+use Monolog\TestCase;
+
+class FlowdockFormatterTest extends TestCase
+{
+ /**
+ * @covers Monolog\Formatter\FlowdockFormatter::format
+ */
+ public function testFormat()
+ {
+ $formatter = new FlowdockFormatter('test_source', 'source@test.com');
+ $record = $this->getRecord();
+
+ $expected = array(
+ 'source' => 'test_source',
+ 'from_address' => 'source@test.com',
+ 'subject' => 'in test_source: WARNING - test',
+ 'content' => 'test',
+ 'tags' => array('#logs', '#warning', '#test'),
+ 'project' => 'test_source',
+ );
+ $formatted = $formatter->format($record);
+
+ $this->assertEquals($expected, $formatted['flowdock']);
+ }
+
+ /**
+ * @ covers Monolog\Formatter\FlowdockFormatter::formatBatch
+ */
+ public function testFormatBatch()
+ {
+ $formatter = new FlowdockFormatter('test_source', 'source@test.com');
+ $records = array(
+ $this->getRecord(Logger::WARNING),
+ $this->getRecord(Logger::DEBUG),
+ );
+ $formatted = $formatter->formatBatch($records);
+
+ $this->assertArrayHasKey('flowdock', $formatted[0]);
+ $this->assertArrayHasKey('flowdock', $formatted[1]);
+ }
+}
diff --git a/vendor/monolog/monolog/tests/Monolog/Formatter/GelfMessageFormatterTest.php b/vendor/monolog/monolog/tests/Monolog/Formatter/GelfMessageFormatterTest.php
new file mode 100644
index 00000000..6ac14854
--- /dev/null
+++ b/vendor/monolog/monolog/tests/Monolog/Formatter/GelfMessageFormatterTest.php
@@ -0,0 +1,204 @@
+<?php
+
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Formatter;
+
+use Monolog\Logger;
+
+class GelfMessageFormatterTest extends \PHPUnit_Framework_TestCase
+{
+ public function setUp()
+ {
+ if (!class_exists('\Gelf\Message')) {
+ $this->markTestSkipped("graylog2/gelf-php or mlehner/gelf-php is not installed");
+ }
+ }
+
+ /**
+ * @covers Monolog\Formatter\GelfMessageFormatter::format
+ */
+ public function testDefaultFormatter()
+ {
+ $formatter = new GelfMessageFormatter();
+ $record = array(
+ 'level' => Logger::ERROR,
+ 'level_name' => 'ERROR',
+ 'channel' => 'meh',
+ 'context' => array(),
+ 'datetime' => new \DateTime("@0"),
+ 'extra' => array(),
+ 'message' => 'log',
+ );
+
+ $message = $formatter->format($record);
+
+ $this->assertInstanceOf('Gelf\Message', $message);
+ $this->assertEquals(0, $message->getTimestamp());
+ $this->assertEquals('log', $message->getShortMessage());
+ $this->assertEquals('meh', $message->getFacility());
+ $this->assertEquals(null, $message->getLine());
+ $this->assertEquals(null, $message->getFile());
+ $this->assertEquals($this->isLegacy() ? 3 : 'error', $message->getLevel());
+ $this->assertNotEmpty($message->getHost());
+
+ $formatter = new GelfMessageFormatter('mysystem');
+
+ $message = $formatter->format($record);
+
+ $this->assertInstanceOf('Gelf\Message', $message);
+ $this->assertEquals('mysystem', $message->getHost());
+ }
+
+ /**
+ * @covers Monolog\Formatter\GelfMessageFormatter::format
+ */
+ public function testFormatWithFileAndLine()
+ {
+ $formatter = new GelfMessageFormatter();
+ $record = array(
+ 'level' => Logger::ERROR,
+ 'level_name' => 'ERROR',
+ 'channel' => 'meh',
+ 'context' => array('from' => 'logger'),
+ 'datetime' => new \DateTime("@0"),
+ 'extra' => array('file' => 'test', 'line' => 14),
+ 'message' => 'log',
+ );
+
+ $message = $formatter->format($record);
+
+ $this->assertInstanceOf('Gelf\Message', $message);
+ $this->assertEquals('test', $message->getFile());
+ $this->assertEquals(14, $message->getLine());
+ }
+
+ /**
+ * @covers Monolog\Formatter\GelfMessageFormatter::format
+ * @expectedException InvalidArgumentException
+ */
+ public function testFormatInvalidFails()
+ {
+ $formatter = new GelfMessageFormatter();
+ $record = array(
+ 'level' => Logger::ERROR,
+ 'level_name' => 'ERROR',
+ );
+
+ $formatter->format($record);
+ }
+
+ /**
+ * @covers Monolog\Formatter\GelfMessageFormatter::format
+ */
+ public function testFormatWithContext()
+ {
+ $formatter = new GelfMessageFormatter();
+ $record = array(
+ 'level' => Logger::ERROR,
+ 'level_name' => 'ERROR',
+ 'channel' => 'meh',
+ 'context' => array('from' => 'logger'),
+ 'datetime' => new \DateTime("@0"),
+ 'extra' => array('key' => 'pair'),
+ 'message' => 'log'
+ );
+
+ $message = $formatter->format($record);
+
+ $this->assertInstanceOf('Gelf\Message', $message);
+
+ $message_array = $message->toArray();
+
+ $this->assertArrayHasKey('_ctxt_from', $message_array);
+ $this->assertEquals('logger', $message_array['_ctxt_from']);
+
+ // Test with extraPrefix
+ $formatter = new GelfMessageFormatter(null, null, 'CTX');
+ $message = $formatter->format($record);
+
+ $this->assertInstanceOf('Gelf\Message', $message);
+
+ $message_array = $message->toArray();
+
+ $this->assertArrayHasKey('_CTXfrom', $message_array);
+ $this->assertEquals('logger', $message_array['_CTXfrom']);
+ }
+
+ /**
+ * @covers Monolog\Formatter\GelfMessageFormatter::format
+ */
+ public function testFormatWithContextContainingException()
+ {
+ $formatter = new GelfMessageFormatter();
+ $record = array(
+ 'level' => Logger::ERROR,
+ 'level_name' => 'ERROR',
+ 'channel' => 'meh',
+ 'context' => array('from' => 'logger', 'exception' => array(
+ 'class' => '\Exception',
+ 'file' => '/some/file/in/dir.php:56',
+ 'trace' => array('/some/file/1.php:23', '/some/file/2.php:3')
+ )),
+ 'datetime' => new \DateTime("@0"),
+ 'extra' => array(),
+ 'message' => 'log'
+ );
+
+ $message = $formatter->format($record);
+
+ $this->assertInstanceOf('Gelf\Message', $message);
+
+ $this->assertEquals("/some/file/in/dir.php", $message->getFile());
+ $this->assertEquals("56", $message->getLine());
+ }
+
+ /**
+ * @covers Monolog\Formatter\GelfMessageFormatter::format
+ */
+ public function testFormatWithExtra()
+ {
+ $formatter = new GelfMessageFormatter();
+ $record = array(
+ 'level' => Logger::ERROR,
+ 'level_name' => 'ERROR',
+ 'channel' => 'meh',
+ 'context' => array('from' => 'logger'),
+ 'datetime' => new \DateTime("@0"),
+ 'extra' => array('key' => 'pair'),
+ 'message' => 'log'
+ );
+
+ $message = $formatter->format($record);
+
+ $this->assertInstanceOf('Gelf\Message', $message);
+
+ $message_array = $message->toArray();
+
+ $this->assertArrayHasKey('_key', $message_array);
+ $this->assertEquals('pair', $message_array['_key']);
+
+ // Test with extraPrefix
+ $formatter = new GelfMessageFormatter(null, 'EXT');
+ $message = $formatter->format($record);
+
+ $this->assertInstanceOf('Gelf\Message', $message);
+
+ $message_array = $message->toArray();
+
+ $this->assertArrayHasKey('_EXTkey', $message_array);
+ $this->assertEquals('pair', $message_array['_EXTkey']);
+ }
+
+ private function isLegacy()
+ {
+ return interface_exists('\Gelf\IMessagePublisher');
+ }
+}
diff --git a/vendor/monolog/monolog/tests/Monolog/Formatter/JsonFormatterTest.php b/vendor/monolog/monolog/tests/Monolog/Formatter/JsonFormatterTest.php
new file mode 100644
index 00000000..69e20077
--- /dev/null
+++ b/vendor/monolog/monolog/tests/Monolog/Formatter/JsonFormatterTest.php
@@ -0,0 +1,78 @@
+<?php
+
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Formatter;
+
+use Monolog\Logger;
+use Monolog\TestCase;
+
+class JsonFormatterTest extends TestCase
+{
+ /**
+ * @covers Monolog\Formatter\JsonFormatter::__construct
+ * @covers Monolog\Formatter\JsonFormatter::getBatchMode
+ * @covers Monolog\Formatter\JsonFormatter::isAppendingNewlines
+ */
+ public function testConstruct()
+ {
+ $formatter = new JsonFormatter();
+ $this->assertEquals(JsonFormatter::BATCH_MODE_JSON, $formatter->getBatchMode());
+ $this->assertEquals(true, $formatter->isAppendingNewlines());
+ $formatter = new JsonFormatter(JsonFormatter::BATCH_MODE_NEWLINES, false);
+ $this->assertEquals(JsonFormatter::BATCH_MODE_NEWLINES, $formatter->getBatchMode());
+ $this->assertEquals(false, $formatter->isAppendingNewlines());
+ }
+
+ /**
+ * @covers Monolog\Formatter\JsonFormatter::format
+ */
+ public function testFormat()
+ {
+ $formatter = new JsonFormatter();
+ $record = $this->getRecord();
+ $this->assertEquals(json_encode($record)."\n", $formatter->format($record));
+
+ $formatter = new JsonFormatter(JsonFormatter::BATCH_MODE_JSON, false);
+ $record = $this->getRecord();
+ $this->assertEquals(json_encode($record), $formatter->format($record));
+ }
+
+ /**
+ * @covers Monolog\Formatter\JsonFormatter::formatBatch
+ * @covers Monolog\Formatter\JsonFormatter::formatBatchJson
+ */
+ public function testFormatBatch()
+ {
+ $formatter = new JsonFormatter();
+ $records = array(
+ $this->getRecord(Logger::WARNING),
+ $this->getRecord(Logger::DEBUG),
+ );
+ $this->assertEquals(json_encode($records), $formatter->formatBatch($records));
+ }
+
+ /**
+ * @covers Monolog\Formatter\JsonFormatter::formatBatch
+ * @covers Monolog\Formatter\JsonFormatter::formatBatchNewlines
+ */
+ public function testFormatBatchNewlines()
+ {
+ $formatter = new JsonFormatter(JsonFormatter::BATCH_MODE_NEWLINES);
+ $records = $expected = array(
+ $this->getRecord(Logger::WARNING),
+ $this->getRecord(Logger::DEBUG),
+ );
+ array_walk($expected, function (&$value, $key) {
+ $value = json_encode($value);
+ });
+ $this->assertEquals(implode("\n", $expected), $formatter->formatBatch($records));
+ }
+}
diff --git a/vendor/monolog/monolog/tests/Monolog/Formatter/LineFormatterTest.php b/vendor/monolog/monolog/tests/Monolog/Formatter/LineFormatterTest.php
new file mode 100644
index 00000000..c1b2e0ee
--- /dev/null
+++ b/vendor/monolog/monolog/tests/Monolog/Formatter/LineFormatterTest.php
@@ -0,0 +1,208 @@
+<?php
+
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Formatter;
+
+/**
+ * @covers Monolog\Formatter\LineFormatter
+ */
+class LineFormatterTest extends \PHPUnit_Framework_TestCase
+{
+ public function testDefFormatWithString()
+ {
+ $formatter = new LineFormatter(null, 'Y-m-d');
+ $message = $formatter->format(array(
+ 'level_name' => 'WARNING',
+ 'channel' => 'log',
+ 'context' => array(),
+ 'message' => 'foo',
+ 'datetime' => new \DateTime,
+ 'extra' => array(),
+ ));
+ $this->assertEquals('['.date('Y-m-d').'] log.WARNING: foo [] []'."\n", $message);
+ }
+
+ public function testDefFormatWithArrayContext()
+ {
+ $formatter = new LineFormatter(null, 'Y-m-d');
+ $message = $formatter->format(array(
+ 'level_name' => 'ERROR',
+ 'channel' => 'meh',
+ 'message' => 'foo',
+ 'datetime' => new \DateTime,
+ 'extra' => array(),
+ 'context' => array(
+ 'foo' => 'bar',
+ 'baz' => 'qux',
+ 'bool' => false,
+ 'null' => null,
+ )
+ ));
+ $this->assertEquals('['.date('Y-m-d').'] meh.ERROR: foo {"foo":"bar","baz":"qux","bool":false,"null":null} []'."\n", $message);
+ }
+
+ public function testDefFormatExtras()
+ {
+ $formatter = new LineFormatter(null, 'Y-m-d');
+ $message = $formatter->format(array(
+ 'level_name' => 'ERROR',
+ 'channel' => 'meh',
+ 'context' => array(),
+ 'datetime' => new \DateTime,
+ 'extra' => array('ip' => '127.0.0.1'),
+ 'message' => 'log',
+ ));
+ $this->assertEquals('['.date('Y-m-d').'] meh.ERROR: log [] {"ip":"127.0.0.1"}'."\n", $message);
+ }
+
+ public function testFormatExtras()
+ {
+ $formatter = new LineFormatter("[%datetime%] %channel%.%level_name%: %message% %context% %extra.file% %extra%\n", 'Y-m-d');
+ $message = $formatter->format(array(
+ 'level_name' => 'ERROR',
+ 'channel' => 'meh',
+ 'context' => array(),
+ 'datetime' => new \DateTime,
+ 'extra' => array('ip' => '127.0.0.1', 'file' => 'test'),
+ 'message' => 'log',
+ ));
+ $this->assertEquals('['.date('Y-m-d').'] meh.ERROR: log [] test {"ip":"127.0.0.1"}'."\n", $message);
+ }
+
+ public function testContextAndExtraOptionallyNotShownIfEmpty()
+ {
+ $formatter = new LineFormatter(null, 'Y-m-d', false, true);
+ $message = $formatter->format(array(
+ 'level_name' => 'ERROR',
+ 'channel' => 'meh',
+ 'context' => array(),
+ 'datetime' => new \DateTime,
+ 'extra' => array(),
+ 'message' => 'log',
+ ));
+ $this->assertEquals('['.date('Y-m-d').'] meh.ERROR: log '."\n", $message);
+ }
+
+ public function testDefFormatWithObject()
+ {
+ $formatter = new LineFormatter(null, 'Y-m-d');
+ $message = $formatter->format(array(
+ 'level_name' => 'ERROR',
+ 'channel' => 'meh',
+ 'context' => array(),
+ 'datetime' => new \DateTime,
+ 'extra' => array('foo' => new TestFoo, 'bar' => new TestBar, 'baz' => array(), 'res' => fopen('php://memory', 'rb')),
+ 'message' => 'foobar',
+ ));
+
+ $this->assertEquals('['.date('Y-m-d').'] meh.ERROR: foobar [] {"foo":"[object] (Monolog\\\\Formatter\\\\TestFoo: {\\"foo\\":\\"foo\\"})","bar":"[object] (Monolog\\\\Formatter\\\\TestBar: bar)","baz":[],"res":"[resource]"}'."\n", $message);
+ }
+
+ public function testDefFormatWithException()
+ {
+ $formatter = new LineFormatter(null, 'Y-m-d');
+ $message = $formatter->format(array(
+ 'level_name' => 'CRITICAL',
+ 'channel' => 'core',
+ 'context' => array('exception' => new \RuntimeException('Foo')),
+ 'datetime' => new \DateTime,
+ 'extra' => array(),
+ 'message' => 'foobar',
+ ));
+
+ $path = str_replace('\\/', '/', json_encode(__FILE__));
+
+ $this->assertEquals('['.date('Y-m-d').'] core.CRITICAL: foobar {"exception":"[object] (RuntimeException(code: 0): Foo at '.substr($path, 1, -1).':'.(__LINE__-8).')"} []'."\n", $message);
+ }
+
+ public function testDefFormatWithPreviousException()
+ {
+ $formatter = new LineFormatter(null, 'Y-m-d');
+ $previous = new \LogicException('Wut?');
+ $message = $formatter->format(array(
+ 'level_name' => 'CRITICAL',
+ 'channel' => 'core',
+ 'context' => array('exception' => new \RuntimeException('Foo', 0, $previous)),
+ 'datetime' => new \DateTime,
+ 'extra' => array(),
+ 'message' => 'foobar',
+ ));
+
+ $path = str_replace('\\/', '/', json_encode(__FILE__));
+
+ $this->assertEquals('['.date('Y-m-d').'] core.CRITICAL: foobar {"exception":"[object] (RuntimeException(code: 0): Foo at '.substr($path, 1, -1).':'.(__LINE__-8).', LogicException(code: 0): Wut? at '.substr($path, 1, -1).':'.(__LINE__-12).')"} []'."\n", $message);
+ }
+
+ public function testBatchFormat()
+ {
+ $formatter = new LineFormatter(null, 'Y-m-d');
+ $message = $formatter->formatBatch(array(
+ array(
+ 'level_name' => 'CRITICAL',
+ 'channel' => 'test',
+ 'message' => 'bar',
+ 'context' => array(),
+ 'datetime' => new \DateTime,
+ 'extra' => array(),
+ ),
+ array(
+ 'level_name' => 'WARNING',
+ 'channel' => 'log',
+ 'message' => 'foo',
+ 'context' => array(),
+ 'datetime' => new \DateTime,
+ 'extra' => array(),
+ ),
+ ));
+ $this->assertEquals('['.date('Y-m-d').'] test.CRITICAL: bar [] []'."\n".'['.date('Y-m-d').'] log.WARNING: foo [] []'."\n", $message);
+ }
+
+ public function testFormatShouldStripInlineLineBreaks()
+ {
+ $formatter = new LineFormatter(null, 'Y-m-d');
+ $message = $formatter->format(
+ array(
+ 'message' => "foo\nbar",
+ 'context' => array(),
+ 'extra' => array(),
+ )
+ );
+
+ $this->assertRegExp('/foo bar/', $message);
+ }
+
+ public function testFormatShouldNotStripInlineLineBreaksWhenFlagIsSet()
+ {
+ $formatter = new LineFormatter(null, 'Y-m-d', true);
+ $message = $formatter->format(
+ array(
+ 'message' => "foo\nbar",
+ 'context' => array(),
+ 'extra' => array(),
+ )
+ );
+
+ $this->assertRegExp('/foo\nbar/', $message);
+ }
+}
+
+class TestFoo
+{
+ public $foo = 'foo';
+}
+
+class TestBar
+{
+ public function __toString()
+ {
+ return 'bar';
+ }
+}
diff --git a/vendor/monolog/monolog/tests/Monolog/Formatter/LogglyFormatterTest.php b/vendor/monolog/monolog/tests/Monolog/Formatter/LogglyFormatterTest.php
new file mode 100644
index 00000000..6d59b3f3
--- /dev/null
+++ b/vendor/monolog/monolog/tests/Monolog/Formatter/LogglyFormatterTest.php
@@ -0,0 +1,40 @@
+<?php
+
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Formatter;
+
+use Monolog\TestCase;
+
+class LogglyFormatterTest extends TestCase
+{
+ /**
+ * @covers Monolog\Formatter\LogglyFormatter::__construct
+ */
+ public function testConstruct()
+ {
+ $formatter = new LogglyFormatter();
+ $this->assertEquals(LogglyFormatter::BATCH_MODE_NEWLINES, $formatter->getBatchMode());
+ $formatter = new LogglyFormatter(LogglyFormatter::BATCH_MODE_JSON);
+ $this->assertEquals(LogglyFormatter::BATCH_MODE_JSON, $formatter->getBatchMode());
+ }
+
+ /**
+ * @covers Monolog\Formatter\LogglyFormatter::format
+ */
+ public function testFormat()
+ {
+ $formatter = new LogglyFormatter();
+ $record = $this->getRecord();
+ $formatted_decoded = json_decode($formatter->format($record), true);
+ $this->assertArrayHasKey("timestamp", $formatted_decoded);
+ $this->assertEquals(new \DateTime($formatted_decoded["timestamp"]), $record["datetime"]);
+ }
+}
diff --git a/vendor/monolog/monolog/tests/Monolog/Formatter/LogstashFormatterTest.php b/vendor/monolog/monolog/tests/Monolog/Formatter/LogstashFormatterTest.php
new file mode 100644
index 00000000..de4a3c2c
--- /dev/null
+++ b/vendor/monolog/monolog/tests/Monolog/Formatter/LogstashFormatterTest.php
@@ -0,0 +1,289 @@
+<?php
+
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Formatter;
+
+use Monolog\Logger;
+
+class LogstashFormatterTest extends \PHPUnit_Framework_TestCase
+{
+ /**
+ * @covers Monolog\Formatter\LogstashFormatter::format
+ */
+ public function testDefaultFormatter()
+ {
+ $formatter = new LogstashFormatter('test', 'hostname');
+ $record = array(
+ 'level' => Logger::ERROR,
+ 'level_name' => 'ERROR',
+ 'channel' => 'meh',
+ 'context' => array(),
+ 'datetime' => new \DateTime("@0"),
+ 'extra' => array(),
+ 'message' => 'log',
+ );
+
+ $message = json_decode($formatter->format($record), true);
+
+ $this->assertEquals("1970-01-01T00:00:00.000000+00:00", $message['@timestamp']);
+ $this->assertEquals('log', $message['@message']);
+ $this->assertEquals('meh', $message['@fields']['channel']);
+ $this->assertContains('meh', $message['@tags']);
+ $this->assertEquals(Logger::ERROR, $message['@fields']['level']);
+ $this->assertEquals('test', $message['@type']);
+ $this->assertEquals('hostname', $message['@source']);
+
+ $formatter = new LogstashFormatter('mysystem');
+
+ $message = json_decode($formatter->format($record), true);
+
+ $this->assertEquals('mysystem', $message['@type']);
+ }
+
+ /**
+ * @covers Monolog\Formatter\LogstashFormatter::format
+ */
+ public function testFormatWithFileAndLine()
+ {
+ $formatter = new LogstashFormatter('test');
+ $record = array(
+ 'level' => Logger::ERROR,
+ 'level_name' => 'ERROR',
+ 'channel' => 'meh',
+ 'context' => array('from' => 'logger'),
+ 'datetime' => new \DateTime("@0"),
+ 'extra' => array('file' => 'test', 'line' => 14),
+ 'message' => 'log',
+ );
+
+ $message = json_decode($formatter->format($record), true);
+
+ $this->assertEquals('test', $message['@fields']['file']);
+ $this->assertEquals(14, $message['@fields']['line']);
+ }
+
+ /**
+ * @covers Monolog\Formatter\LogstashFormatter::format
+ */
+ public function testFormatWithContext()
+ {
+ $formatter = new LogstashFormatter('test');
+ $record = array(
+ 'level' => Logger::ERROR,
+ 'level_name' => 'ERROR',
+ 'channel' => 'meh',
+ 'context' => array('from' => 'logger'),
+ 'datetime' => new \DateTime("@0"),
+ 'extra' => array('key' => 'pair'),
+ 'message' => 'log'
+ );
+
+ $message = json_decode($formatter->format($record), true);
+
+ $message_array = $message['@fields'];
+
+ $this->assertArrayHasKey('ctxt_from', $message_array);
+ $this->assertEquals('logger', $message_array['ctxt_from']);
+
+ // Test with extraPrefix
+ $formatter = new LogstashFormatter('test', null, null, 'CTX');
+ $message = json_decode($formatter->format($record), true);
+
+ $message_array = $message['@fields'];
+
+ $this->assertArrayHasKey('CTXfrom', $message_array);
+ $this->assertEquals('logger', $message_array['CTXfrom']);
+ }
+
+ /**
+ * @covers Monolog\Formatter\LogstashFormatter::format
+ */
+ public function testFormatWithExtra()
+ {
+ $formatter = new LogstashFormatter('test');
+ $record = array(
+ 'level' => Logger::ERROR,
+ 'level_name' => 'ERROR',
+ 'channel' => 'meh',
+ 'context' => array('from' => 'logger'),
+ 'datetime' => new \DateTime("@0"),
+ 'extra' => array('key' => 'pair'),
+ 'message' => 'log'
+ );
+
+ $message = json_decode($formatter->format($record), true);
+
+ $message_array = $message['@fields'];
+
+ $this->assertArrayHasKey('key', $message_array);
+ $this->assertEquals('pair', $message_array['key']);
+
+ // Test with extraPrefix
+ $formatter = new LogstashFormatter('test', null, 'EXT');
+ $message = json_decode($formatter->format($record), true);
+
+ $message_array = $message['@fields'];
+
+ $this->assertArrayHasKey('EXTkey', $message_array);
+ $this->assertEquals('pair', $message_array['EXTkey']);
+ }
+
+ public function testFormatWithApplicationName()
+ {
+ $formatter = new LogstashFormatter('app', 'test');
+ $record = array(
+ 'level' => Logger::ERROR,
+ 'level_name' => 'ERROR',
+ 'channel' => 'meh',
+ 'context' => array('from' => 'logger'),
+ 'datetime' => new \DateTime("@0"),
+ 'extra' => array('key' => 'pair'),
+ 'message' => 'log'
+ );
+
+ $message = json_decode($formatter->format($record), true);
+
+ $this->assertArrayHasKey('@type', $message);
+ $this->assertEquals('app', $message['@type']);
+ }
+
+ /**
+ * @covers Monolog\Formatter\LogstashFormatter::format
+ */
+ public function testDefaultFormatterV1()
+ {
+ $formatter = new LogstashFormatter('test', 'hostname', null, 'ctxt_', LogstashFormatter::V1);
+ $record = array(
+ 'level' => Logger::ERROR,
+ 'level_name' => 'ERROR',
+ 'channel' => 'meh',
+ 'context' => array(),
+ 'datetime' => new \DateTime("@0"),
+ 'extra' => array(),
+ 'message' => 'log',
+ );
+
+ $message = json_decode($formatter->format($record), true);
+
+ $this->assertEquals("1970-01-01T00:00:00.000000+00:00", $message['@timestamp']);
+ $this->assertEquals("1", $message['@version']);
+ $this->assertEquals('log', $message['message']);
+ $this->assertEquals('meh', $message['channel']);
+ $this->assertEquals('ERROR', $message['level']);
+ $this->assertEquals('test', $message['type']);
+ $this->assertEquals('hostname', $message['host']);
+
+ $formatter = new LogstashFormatter('mysystem', null, null, 'ctxt_', LogstashFormatter::V1);
+
+ $message = json_decode($formatter->format($record), true);
+
+ $this->assertEquals('mysystem', $message['type']);
+ }
+
+ /**
+ * @covers Monolog\Formatter\LogstashFormatter::format
+ */
+ public function testFormatWithFileAndLineV1()
+ {
+ $formatter = new LogstashFormatter('test', null, null, 'ctxt_', LogstashFormatter::V1);
+ $record = array(
+ 'level' => Logger::ERROR,
+ 'level_name' => 'ERROR',
+ 'channel' => 'meh',
+ 'context' => array('from' => 'logger'),
+ 'datetime' => new \DateTime("@0"),
+ 'extra' => array('file' => 'test', 'line' => 14),
+ 'message' => 'log',
+ );
+
+ $message = json_decode($formatter->format($record), true);
+
+ $this->assertEquals('test', $message['file']);
+ $this->assertEquals(14, $message['line']);
+ }
+
+ /**
+ * @covers Monolog\Formatter\LogstashFormatter::format
+ */
+ public function testFormatWithContextV1()
+ {
+ $formatter = new LogstashFormatter('test', null, null, 'ctxt_', LogstashFormatter::V1);
+ $record = array(
+ 'level' => Logger::ERROR,
+ 'level_name' => 'ERROR',
+ 'channel' => 'meh',
+ 'context' => array('from' => 'logger'),
+ 'datetime' => new \DateTime("@0"),
+ 'extra' => array('key' => 'pair'),
+ 'message' => 'log'
+ );
+
+ $message = json_decode($formatter->format($record), true);
+
+ $this->assertArrayHasKey('ctxt_from', $message);
+ $this->assertEquals('logger', $message['ctxt_from']);
+
+ // Test with extraPrefix
+ $formatter = new LogstashFormatter('test', null, null, 'CTX', LogstashFormatter::V1);
+ $message = json_decode($formatter->format($record), true);
+
+ $this->assertArrayHasKey('CTXfrom', $message);
+ $this->assertEquals('logger', $message['CTXfrom']);
+ }
+
+ /**
+ * @covers Monolog\Formatter\LogstashFormatter::format
+ */
+ public function testFormatWithExtraV1()
+ {
+ $formatter = new LogstashFormatter('test', null, null, 'ctxt_', LogstashFormatter::V1);
+ $record = array(
+ 'level' => Logger::ERROR,
+ 'level_name' => 'ERROR',
+ 'channel' => 'meh',
+ 'context' => array('from' => 'logger'),
+ 'datetime' => new \DateTime("@0"),
+ 'extra' => array('key' => 'pair'),
+ 'message' => 'log'
+ );
+
+ $message = json_decode($formatter->format($record), true);
+
+ $this->assertArrayHasKey('key', $message);
+ $this->assertEquals('pair', $message['key']);
+
+ // Test with extraPrefix
+ $formatter = new LogstashFormatter('test', null, 'EXT', 'ctxt_', LogstashFormatter::V1);
+ $message = json_decode($formatter->format($record), true);
+
+ $this->assertArrayHasKey('EXTkey', $message);
+ $this->assertEquals('pair', $message['EXTkey']);
+ }
+
+ public function testFormatWithApplicationNameV1()
+ {
+ $formatter = new LogstashFormatter('app', 'test', null, 'ctxt_', LogstashFormatter::V1);
+ $record = array(
+ 'level' => Logger::ERROR,
+ 'level_name' => 'ERROR',
+ 'channel' => 'meh',
+ 'context' => array('from' => 'logger'),
+ 'datetime' => new \DateTime("@0"),
+ 'extra' => array('key' => 'pair'),
+ 'message' => 'log'
+ );
+
+ $message = json_decode($formatter->format($record), true);
+
+ $this->assertArrayHasKey('type', $message);
+ $this->assertEquals('app', $message['type']);
+ }
+}
diff --git a/vendor/monolog/monolog/tests/Monolog/Formatter/MongoDBFormatterTest.php b/vendor/monolog/monolog/tests/Monolog/Formatter/MongoDBFormatterTest.php
new file mode 100644
index 00000000..1554ef46
--- /dev/null
+++ b/vendor/monolog/monolog/tests/Monolog/Formatter/MongoDBFormatterTest.php
@@ -0,0 +1,253 @@
+<?php
+
+namespace Monolog\Formatter;
+
+use Monolog\Logger;
+
+/**
+ * @author Florian Plattner <me@florianplattner.de>
+ */
+class MongoDBFormatterTest extends \PHPUnit_Framework_TestCase
+{
+ public function setUp()
+ {
+ if (!class_exists('MongoDate')) {
+ $this->markTestSkipped('mongo extension not installed');
+ }
+ }
+
+ public function constructArgumentProvider()
+ {
+ return array(
+ array(1, true, 1, true),
+ array(0, false, 0, false),
+ );
+ }
+
+ /**
+ * @param $traceDepth
+ * @param $traceAsString
+ * @param $expectedTraceDepth
+ * @param $expectedTraceAsString
+ *
+ * @dataProvider constructArgumentProvider
+ */
+ public function testConstruct($traceDepth, $traceAsString, $expectedTraceDepth, $expectedTraceAsString)
+ {
+ $formatter = new MongoDBFormatter($traceDepth, $traceAsString);
+
+ $reflTrace = new \ReflectionProperty($formatter, 'exceptionTraceAsString');
+ $reflTrace->setAccessible(true);
+ $this->assertEquals($expectedTraceAsString, $reflTrace->getValue($formatter));
+
+ $reflDepth = new\ReflectionProperty($formatter, 'maxNestingLevel');
+ $reflDepth->setAccessible(true);
+ $this->assertEquals($expectedTraceDepth, $reflDepth->getValue($formatter));
+ }
+
+ public function testSimpleFormat()
+ {
+ $record = array(
+ 'message' => 'some log message',
+ 'context' => array(),
+ 'level' => Logger::WARNING,
+ 'level_name' => Logger::getLevelName(Logger::WARNING),
+ 'channel' => 'test',
+ 'datetime' => new \DateTime('2014-02-01 00:00:00'),
+ 'extra' => array(),
+ );
+
+ $formatter = new MongoDBFormatter();
+ $formattedRecord = $formatter->format($record);
+
+ $this->assertCount(7, $formattedRecord);
+ $this->assertEquals('some log message', $formattedRecord['message']);
+ $this->assertEquals(array(), $formattedRecord['context']);
+ $this->assertEquals(Logger::WARNING, $formattedRecord['level']);
+ $this->assertEquals(Logger::getLevelName(Logger::WARNING), $formattedRecord['level_name']);
+ $this->assertEquals('test', $formattedRecord['channel']);
+ $this->assertInstanceOf('\MongoDate', $formattedRecord['datetime']);
+ $this->assertEquals('0.00000000 1391212800', $formattedRecord['datetime']->__toString());
+ $this->assertEquals(array(), $formattedRecord['extra']);
+ }
+
+ public function testRecursiveFormat()
+ {
+ $someObject = new \stdClass();
+ $someObject->foo = 'something';
+ $someObject->bar = 'stuff';
+
+ $record = array(
+ 'message' => 'some log message',
+ 'context' => array(
+ 'stuff' => new \DateTime('2014-02-01 02:31:33'),
+ 'some_object' => $someObject,
+ 'context_string' => 'some string',
+ 'context_int' => 123456,
+ 'except' => new \Exception('exception message', 987),
+ ),
+ 'level' => Logger::WARNING,
+ 'level_name' => Logger::getLevelName(Logger::WARNING),
+ 'channel' => 'test',
+ 'datetime' => new \DateTime('2014-02-01 00:00:00'),
+ 'extra' => array(),
+ );
+
+ $formatter = new MongoDBFormatter();
+ $formattedRecord = $formatter->format($record);
+
+ $this->assertCount(5, $formattedRecord['context']);
+ $this->assertInstanceOf('\MongoDate', $formattedRecord['context']['stuff']);
+ $this->assertEquals('0.00000000 1391221893', $formattedRecord['context']['stuff']->__toString());
+ $this->assertEquals(
+ array(
+ 'foo' => 'something',
+ 'bar' => 'stuff',
+ 'class' => 'stdClass',
+ ),
+ $formattedRecord['context']['some_object']
+ );
+ $this->assertEquals('some string', $formattedRecord['context']['context_string']);
+ $this->assertEquals(123456, $formattedRecord['context']['context_int']);
+
+ $this->assertCount(5, $formattedRecord['context']['except']);
+ $this->assertEquals('exception message', $formattedRecord['context']['except']['message']);
+ $this->assertEquals(987, $formattedRecord['context']['except']['code']);
+ $this->assertInternalType('string', $formattedRecord['context']['except']['file']);
+ $this->assertInternalType('integer', $formattedRecord['context']['except']['code']);
+ $this->assertInternalType('string', $formattedRecord['context']['except']['trace']);
+ $this->assertEquals('Exception', $formattedRecord['context']['except']['class']);
+ }
+
+ public function testFormatDepthArray()
+ {
+ $record = array(
+ 'message' => 'some log message',
+ 'context' => array(
+ 'nest2' => array(
+ 'property' => 'anything',
+ 'nest3' => array(
+ 'nest4' => 'value',
+ 'property' => 'nothing'
+ )
+ )
+ ),
+ 'level' => Logger::WARNING,
+ 'level_name' => Logger::getLevelName(Logger::WARNING),
+ 'channel' => 'test',
+ 'datetime' => new \DateTime('2014-02-01 00:00:00'),
+ 'extra' => array(),
+ );
+
+ $formatter = new MongoDBFormatter(2);
+ $formattedResult = $formatter->format($record);
+
+ $this->assertEquals(
+ array(
+ 'nest2' => array(
+ 'property' => 'anything',
+ 'nest3' => '[...]',
+ )
+ ),
+ $formattedResult['context']
+ );
+ }
+
+ public function testFormatDepthArrayInfiniteNesting()
+ {
+ $record = array(
+ 'message' => 'some log message',
+ 'context' => array(
+ 'nest2' => array(
+ 'property' => 'something',
+ 'nest3' => array(
+ 'property' => 'anything',
+ 'nest4' => array(
+ 'property' => 'nothing',
+ ),
+ )
+ )
+ ),
+ 'level' => Logger::WARNING,
+ 'level_name' => Logger::getLevelName(Logger::WARNING),
+ 'channel' => 'test',
+ 'datetime' => new \DateTime('2014-02-01 00:00:00'),
+ 'extra' => array(),
+ );
+
+ $formatter = new MongoDBFormatter(0);
+ $formattedResult = $formatter->format($record);
+
+ $this->assertEquals(
+ array(
+ 'nest2' => array(
+ 'property' => 'something',
+ 'nest3' => array(
+ 'property' => 'anything',
+ 'nest4' => array(
+ 'property' => 'nothing',
+ )
+ ),
+ )
+ ),
+ $formattedResult['context']
+ );
+ }
+
+ public function testFormatDepthObjects()
+ {
+ $someObject = new \stdClass();
+ $someObject->property = 'anything';
+ $someObject->nest3 = new \stdClass();
+ $someObject->nest3->property = 'nothing';
+ $someObject->nest3->nest4 = 'invisible';
+
+ $record = array(
+ 'message' => 'some log message',
+ 'context' => array(
+ 'nest2' => $someObject
+ ),
+ 'level' => Logger::WARNING,
+ 'level_name' => Logger::getLevelName(Logger::WARNING),
+ 'channel' => 'test',
+ 'datetime' => new \DateTime('2014-02-01 00:00:00'),
+ 'extra' => array(),
+ );
+
+ $formatter = new MongoDBFormatter(2, true);
+ $formattedResult = $formatter->format($record);
+
+ $this->assertEquals(
+ array(
+ 'nest2' => array(
+ 'property' => 'anything',
+ 'nest3' => '[...]',
+ 'class' => 'stdClass',
+ ),
+ ),
+ $formattedResult['context']
+ );
+ }
+
+ public function testFormatDepthException()
+ {
+ $record = array(
+ 'message' => 'some log message',
+ 'context' => array(
+ 'nest2' => new \Exception('exception message', 987),
+ ),
+ 'level' => Logger::WARNING,
+ 'level_name' => Logger::getLevelName(Logger::WARNING),
+ 'channel' => 'test',
+ 'datetime' => new \DateTime('2014-02-01 00:00:00'),
+ 'extra' => array(),
+ );
+
+ $formatter = new MongoDBFormatter(2, false);
+ $formattedRecord = $formatter->format($record);
+
+ $this->assertEquals('exception message', $formattedRecord['context']['nest2']['message']);
+ $this->assertEquals(987, $formattedRecord['context']['nest2']['code']);
+ $this->assertEquals('[...]', $formattedRecord['context']['nest2']['trace']);
+ }
+}
diff --git a/vendor/monolog/monolog/tests/Monolog/Formatter/NormalizerFormatterTest.php b/vendor/monolog/monolog/tests/Monolog/Formatter/NormalizerFormatterTest.php
new file mode 100644
index 00000000..4ffeded0
--- /dev/null
+++ b/vendor/monolog/monolog/tests/Monolog/Formatter/NormalizerFormatterTest.php
@@ -0,0 +1,254 @@
+<?php
+
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Formatter;
+
+/**
+ * @covers Monolog\Formatter\NormalizerFormatter
+ */
+class NormalizerFormatterTest extends \PHPUnit_Framework_TestCase
+{
+ public function testFormat()
+ {
+ $formatter = new NormalizerFormatter('Y-m-d');
+ $formatted = $formatter->format(array(
+ 'level_name' => 'ERROR',
+ 'channel' => 'meh',
+ 'message' => 'foo',
+ 'datetime' => new \DateTime,
+ 'extra' => array('foo' => new TestFooNorm, 'bar' => new TestBarNorm, 'baz' => array(), 'res' => fopen('php://memory', 'rb')),
+ 'context' => array(
+ 'foo' => 'bar',
+ 'baz' => 'qux',
+ 'inf' => INF,
+ '-inf' => -INF,
+ 'nan' => acos(4),
+ ),
+ ));
+
+ $this->assertEquals(array(
+ 'level_name' => 'ERROR',
+ 'channel' => 'meh',
+ 'message' => 'foo',
+ 'datetime' => date('Y-m-d'),
+ 'extra' => array(
+ 'foo' => '[object] (Monolog\\Formatter\\TestFooNorm: {"foo":"foo"})',
+ 'bar' => '[object] (Monolog\\Formatter\\TestBarNorm: bar)',
+ 'baz' => array(),
+ 'res' => '[resource]',
+ ),
+ 'context' => array(
+ 'foo' => 'bar',
+ 'baz' => 'qux',
+ 'inf' => 'INF',
+ '-inf' => '-INF',
+ 'nan' => 'NaN',
+ )
+ ), $formatted);
+ }
+
+ public function testFormatExceptions()
+ {
+ $formatter = new NormalizerFormatter('Y-m-d');
+ $e = new \LogicException('bar');
+ $e2 = new \RuntimeException('foo', 0, $e);
+ $formatted = $formatter->format(array(
+ 'exception' => $e2,
+ ));
+
+ $this->assertGreaterThan(5, count($formatted['exception']['trace']));
+ $this->assertTrue(isset($formatted['exception']['previous']));
+ unset($formatted['exception']['trace'], $formatted['exception']['previous']);
+
+ $this->assertEquals(array(
+ 'exception' => array(
+ 'class' => get_class($e2),
+ 'message' => $e2->getMessage(),
+ 'code' => $e2->getCode(),
+ 'file' => $e2->getFile().':'.$e2->getLine(),
+ )
+ ), $formatted);
+ }
+
+ public function testBatchFormat()
+ {
+ $formatter = new NormalizerFormatter('Y-m-d');
+ $formatted = $formatter->formatBatch(array(
+ array(
+ 'level_name' => 'CRITICAL',
+ 'channel' => 'test',
+ 'message' => 'bar',
+ 'context' => array(),
+ 'datetime' => new \DateTime,
+ 'extra' => array(),
+ ),
+ array(
+ 'level_name' => 'WARNING',
+ 'channel' => 'log',
+ 'message' => 'foo',
+ 'context' => array(),
+ 'datetime' => new \DateTime,
+ 'extra' => array(),
+ ),
+ ));
+ $this->assertEquals(array(
+ array(
+ 'level_name' => 'CRITICAL',
+ 'channel' => 'test',
+ 'message' => 'bar',
+ 'context' => array(),
+ 'datetime' => date('Y-m-d'),
+ 'extra' => array(),
+ ),
+ array(
+ 'level_name' => 'WARNING',
+ 'channel' => 'log',
+ 'message' => 'foo',
+ 'context' => array(),
+ 'datetime' => date('Y-m-d'),
+ 'extra' => array(),
+ ),
+ ), $formatted);
+ }
+
+ /**
+ * Test issue #137
+ */
+ public function testIgnoresRecursiveObjectReferences()
+ {
+ // set up the recursion
+ $foo = new \stdClass();
+ $bar = new \stdClass();
+
+ $foo->bar = $bar;
+ $bar->foo = $foo;
+
+ // set an error handler to assert that the error is not raised anymore
+ $that = $this;
+ set_error_handler(function ($level, $message, $file, $line, $context) use ($that) {
+ if (error_reporting() & $level) {
+ restore_error_handler();
+ $that->fail("$message should not be raised");
+ }
+ });
+
+ $formatter = new NormalizerFormatter();
+ $reflMethod = new \ReflectionMethod($formatter, 'toJson');
+ $reflMethod->setAccessible(true);
+ $res = $reflMethod->invoke($formatter, array($foo, $bar), true);
+
+ restore_error_handler();
+
+ $this->assertEquals(@json_encode(array($foo, $bar)), $res);
+ }
+
+ public function testIgnoresInvalidTypes()
+ {
+ // set up the recursion
+ $resource = fopen(__FILE__, 'r');
+
+ // set an error handler to assert that the error is not raised anymore
+ $that = $this;
+ set_error_handler(function ($level, $message, $file, $line, $context) use ($that) {
+ if (error_reporting() & $level) {
+ restore_error_handler();
+ $that->fail("$message should not be raised");
+ }
+ });
+
+ $formatter = new NormalizerFormatter();
+ $reflMethod = new \ReflectionMethod($formatter, 'toJson');
+ $reflMethod->setAccessible(true);
+ $res = $reflMethod->invoke($formatter, array($resource), true);
+
+ restore_error_handler();
+
+ $this->assertEquals(@json_encode(array($resource)), $res);
+ }
+
+ public function testExceptionTraceWithArgs()
+ {
+ if (defined('HHVM_VERSION')) {
+ $this->markTestSkipped('Not supported in HHVM since it detects errors differently');
+ }
+
+ // This happens i.e. in React promises or Guzzle streams where stream wrappers are registered
+ // and no file or line are included in the trace because it's treated as internal function
+ set_error_handler(function ($errno, $errstr, $errfile, $errline) {
+ throw new \ErrorException($errstr, 0, $errno, $errfile, $errline);
+ });
+
+ try {
+ // This will contain $resource and $wrappedResource as arguments in the trace item
+ $resource = fopen('php://memory', 'rw+');
+ fwrite($resource, 'test_resource');
+ $wrappedResource = new TestFooNorm;
+ $wrappedResource->foo = $resource;
+ // Just do something stupid with a resource/wrapped resource as argument
+ array_keys($wrappedResource);
+ } catch (\Exception $e) {
+ restore_error_handler();
+ }
+
+ $formatter = new NormalizerFormatter();
+ $record = array('context' => array('exception' => $e));
+ $result = $formatter->format($record);
+
+ $this->assertRegExp(
+ '%"resource":"\[resource\]"%',
+ $result['context']['exception']['trace'][0]
+ );
+
+ if (version_compare(PHP_VERSION, '5.5.0', '>=')) {
+ $pattern = '%"wrappedResource":"\[object\] \(Monolog\\\\\\\\Formatter\\\\\\\\TestFooNorm: \)"%';
+ } else {
+ $pattern = '%\\\\"foo\\\\":null%';
+ }
+
+ // Tests that the wrapped resource is ignored while encoding, only works for PHP <= 5.4
+ $this->assertRegExp(
+ $pattern,
+ $result['context']['exception']['trace'][0]
+ );
+ }
+}
+
+class TestFooNorm
+{
+ public $foo = 'foo';
+}
+
+class TestBarNorm
+{
+ public function __toString()
+ {
+ return 'bar';
+ }
+}
+
+class TestStreamFoo
+{
+ public $foo;
+ public $resource;
+
+ public function __construct($resource)
+ {
+ $this->resource = $resource;
+ $this->foo = 'BAR';
+ }
+
+ public function __toString()
+ {
+ fseek($this->resource, 0);
+
+ return $this->foo . ' - ' . (string) stream_get_contents($this->resource);
+ }
+}
diff --git a/vendor/monolog/monolog/tests/Monolog/Formatter/ScalarFormatterTest.php b/vendor/monolog/monolog/tests/Monolog/Formatter/ScalarFormatterTest.php
new file mode 100644
index 00000000..c5a4ebb5
--- /dev/null
+++ b/vendor/monolog/monolog/tests/Monolog/Formatter/ScalarFormatterTest.php
@@ -0,0 +1,98 @@
+<?php
+namespace Monolog\Formatter;
+
+class ScalarFormatterTest extends \PHPUnit_Framework_TestCase
+{
+ public function setUp()
+ {
+ $this->formatter = new ScalarFormatter();
+ }
+
+ public function buildTrace(\Exception $e)
+ {
+ $data = array();
+ $trace = $e->getTrace();
+ foreach ($trace as $frame) {
+ if (isset($frame['file'])) {
+ $data[] = $frame['file'].':'.$frame['line'];
+ } else {
+ $data[] = json_encode($frame);
+ }
+ }
+
+ return $data;
+ }
+
+ public function encodeJson($data)
+ {
+ if (version_compare(PHP_VERSION, '5.4.0', '>=')) {
+ return json_encode($data, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);
+ }
+
+ return json_encode($data);
+ }
+
+ public function testFormat()
+ {
+ $exception = new \Exception('foo');
+ $formatted = $this->formatter->format(array(
+ 'foo' => 'string',
+ 'bar' => 1,
+ 'baz' => false,
+ 'bam' => array(1, 2, 3),
+ 'bat' => array('foo' => 'bar'),
+ 'bap' => \DateTime::createFromFormat(\DateTime::ISO8601, '1970-01-01T00:00:00+0000'),
+ 'ban' => $exception
+ ));
+
+ $this->assertSame(array(
+ 'foo' => 'string',
+ 'bar' => 1,
+ 'baz' => false,
+ 'bam' => $this->encodeJson(array(1, 2, 3)),
+ 'bat' => $this->encodeJson(array('foo' => 'bar')),
+ 'bap' => '1970-01-01 00:00:00',
+ 'ban' => $this->encodeJson(array(
+ 'class' => get_class($exception),
+ 'message' => $exception->getMessage(),
+ 'code' => $exception->getCode(),
+ 'file' => $exception->getFile() . ':' . $exception->getLine(),
+ 'trace' => $this->buildTrace($exception)
+ ))
+ ), $formatted);
+ }
+
+ public function testFormatWithErrorContext()
+ {
+ $context = array('file' => 'foo', 'line' => 1);
+ $formatted = $this->formatter->format(array(
+ 'context' => $context
+ ));
+
+ $this->assertSame(array(
+ 'context' => $this->encodeJson($context)
+ ), $formatted);
+ }
+
+ public function testFormatWithExceptionContext()
+ {
+ $exception = new \Exception('foo');
+ $formatted = $this->formatter->format(array(
+ 'context' => array(
+ 'exception' => $exception
+ )
+ ));
+
+ $this->assertSame(array(
+ 'context' => $this->encodeJson(array(
+ 'exception' => array(
+ 'class' => get_class($exception),
+ 'message' => $exception->getMessage(),
+ 'code' => $exception->getCode(),
+ 'file' => $exception->getFile() . ':' . $exception->getLine(),
+ 'trace' => $this->buildTrace($exception)
+ )
+ ))
+ ), $formatted);
+ }
+}
diff --git a/vendor/monolog/monolog/tests/Monolog/Formatter/WildfireFormatterTest.php b/vendor/monolog/monolog/tests/Monolog/Formatter/WildfireFormatterTest.php
new file mode 100644
index 00000000..52f15a36
--- /dev/null
+++ b/vendor/monolog/monolog/tests/Monolog/Formatter/WildfireFormatterTest.php
@@ -0,0 +1,142 @@
+<?php
+
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Formatter;
+
+use Monolog\Logger;
+
+class WildfireFormatterTest extends \PHPUnit_Framework_TestCase
+{
+ /**
+ * @covers Monolog\Formatter\WildfireFormatter::format
+ */
+ public function testDefaultFormat()
+ {
+ $wildfire = new WildfireFormatter();
+ $record = array(
+ 'level' => Logger::ERROR,
+ 'level_name' => 'ERROR',
+ 'channel' => 'meh',
+ 'context' => array('from' => 'logger'),
+ 'datetime' => new \DateTime("@0"),
+ 'extra' => array('ip' => '127.0.0.1'),
+ 'message' => 'log',
+ );
+
+ $message = $wildfire->format($record);
+
+ $this->assertEquals(
+ '125|[{"Type":"ERROR","File":"","Line":"","Label":"meh"},'
+ .'{"message":"log","context":{"from":"logger"},"extra":{"ip":"127.0.0.1"}}]|',
+ $message
+ );
+ }
+
+ /**
+ * @covers Monolog\Formatter\WildfireFormatter::format
+ */
+ public function testFormatWithFileAndLine()
+ {
+ $wildfire = new WildfireFormatter();
+ $record = array(
+ 'level' => Logger::ERROR,
+ 'level_name' => 'ERROR',
+ 'channel' => 'meh',
+ 'context' => array('from' => 'logger'),
+ 'datetime' => new \DateTime("@0"),
+ 'extra' => array('ip' => '127.0.0.1', 'file' => 'test', 'line' => 14),
+ 'message' => 'log',
+ );
+
+ $message = $wildfire->format($record);
+
+ $this->assertEquals(
+ '129|[{"Type":"ERROR","File":"test","Line":14,"Label":"meh"},'
+ .'{"message":"log","context":{"from":"logger"},"extra":{"ip":"127.0.0.1"}}]|',
+ $message
+ );
+ }
+
+ /**
+ * @covers Monolog\Formatter\WildfireFormatter::format
+ */
+ public function testFormatWithoutContext()
+ {
+ $wildfire = new WildfireFormatter();
+ $record = array(
+ 'level' => Logger::ERROR,
+ 'level_name' => 'ERROR',
+ 'channel' => 'meh',
+ 'context' => array(),
+ 'datetime' => new \DateTime("@0"),
+ 'extra' => array(),
+ 'message' => 'log',
+ );
+
+ $message = $wildfire->format($record);
+
+ $this->assertEquals(
+ '58|[{"Type":"ERROR","File":"","Line":"","Label":"meh"},"log"]|',
+ $message
+ );
+ }
+
+ /**
+ * @covers Monolog\Formatter\WildfireFormatter::formatBatch
+ * @expectedException BadMethodCallException
+ */
+ public function testBatchFormatThrowException()
+ {
+ $wildfire = new WildfireFormatter();
+ $record = array(
+ 'level' => Logger::ERROR,
+ 'level_name' => 'ERROR',
+ 'channel' => 'meh',
+ 'context' => array(),
+ 'datetime' => new \DateTime("@0"),
+ 'extra' => array(),
+ 'message' => 'log',
+ );
+
+ $wildfire->formatBatch(array($record));
+ }
+
+ /**
+ * @covers Monolog\Formatter\WildfireFormatter::format
+ */
+ public function testTableFormat()
+ {
+ $wildfire = new WildfireFormatter();
+ $record = array(
+ 'level' => Logger::ERROR,
+ 'level_name' => 'ERROR',
+ 'channel' => 'table-channel',
+ 'context' => array(
+ WildfireFormatter::TABLE => array(
+ array('col1', 'col2', 'col3'),
+ array('val1', 'val2', 'val3'),
+ array('foo1', 'foo2', 'foo3'),
+ array('bar1', 'bar2', 'bar3'),
+ ),
+ ),
+ 'datetime' => new \DateTime("@0"),
+ 'extra' => array(),
+ 'message' => 'table-message',
+ );
+
+ $message = $wildfire->format($record);
+
+ $this->assertEquals(
+ '171|[{"Type":"TABLE","File":"","Line":"","Label":"table-channel: table-message"},[["col1","col2","col3"],["val1","val2","val3"],["foo1","foo2","foo3"],["bar1","bar2","bar3"]]]|',
+ $message
+ );
+ }
+}
diff --git a/vendor/monolog/monolog/tests/Monolog/Handler/AbstractHandlerTest.php b/vendor/monolog/monolog/tests/Monolog/Handler/AbstractHandlerTest.php
new file mode 100644
index 00000000..568eb9da
--- /dev/null
+++ b/vendor/monolog/monolog/tests/Monolog/Handler/AbstractHandlerTest.php
@@ -0,0 +1,115 @@
+<?php
+
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Handler;
+
+use Monolog\TestCase;
+use Monolog\Logger;
+use Monolog\Formatter\LineFormatter;
+use Monolog\Processor\WebProcessor;
+
+class AbstractHandlerTest extends TestCase
+{
+ /**
+ * @covers Monolog\Handler\AbstractHandler::__construct
+ * @covers Monolog\Handler\AbstractHandler::getLevel
+ * @covers Monolog\Handler\AbstractHandler::setLevel
+ * @covers Monolog\Handler\AbstractHandler::getBubble
+ * @covers Monolog\Handler\AbstractHandler::setBubble
+ * @covers Monolog\Handler\AbstractHandler::getFormatter
+ * @covers Monolog\Handler\AbstractHandler::setFormatter
+ */
+ public function testConstructAndGetSet()
+ {
+ $handler = $this->getMockForAbstractClass('Monolog\Handler\AbstractHandler', array(Logger::WARNING, false));
+ $this->assertEquals(Logger::WARNING, $handler->getLevel());
+ $this->assertEquals(false, $handler->getBubble());
+
+ $handler->setLevel(Logger::ERROR);
+ $handler->setBubble(true);
+ $handler->setFormatter($formatter = new LineFormatter);
+ $this->assertEquals(Logger::ERROR, $handler->getLevel());
+ $this->assertEquals(true, $handler->getBubble());
+ $this->assertSame($formatter, $handler->getFormatter());
+ }
+
+ /**
+ * @covers Monolog\Handler\AbstractHandler::handleBatch
+ */
+ public function testHandleBatch()
+ {
+ $handler = $this->getMockForAbstractClass('Monolog\Handler\AbstractHandler');
+ $handler->expects($this->exactly(2))
+ ->method('handle');
+ $handler->handleBatch(array($this->getRecord(), $this->getRecord()));
+ }
+
+ /**
+ * @covers Monolog\Handler\AbstractHandler::isHandling
+ */
+ public function testIsHandling()
+ {
+ $handler = $this->getMockForAbstractClass('Monolog\Handler\AbstractHandler', array(Logger::WARNING, false));
+ $this->assertTrue($handler->isHandling($this->getRecord()));
+ $this->assertFalse($handler->isHandling($this->getRecord(Logger::DEBUG)));
+ }
+
+ /**
+ * @covers Monolog\Handler\AbstractHandler::__construct
+ */
+ public function testHandlesPsrStyleLevels()
+ {
+ $handler = $this->getMockForAbstractClass('Monolog\Handler\AbstractHandler', array('warning', false));
+ $this->assertFalse($handler->isHandling($this->getRecord(Logger::DEBUG)));
+ $handler->setLevel('debug');
+ $this->assertTrue($handler->isHandling($this->getRecord(Logger::DEBUG)));
+ }
+
+ /**
+ * @covers Monolog\Handler\AbstractHandler::getFormatter
+ * @covers Monolog\Handler\AbstractHandler::getDefaultFormatter
+ */
+ public function testGetFormatterInitializesDefault()
+ {
+ $handler = $this->getMockForAbstractClass('Monolog\Handler\AbstractHandler');
+ $this->assertInstanceOf('Monolog\Formatter\LineFormatter', $handler->getFormatter());
+ }
+
+ /**
+ * @covers Monolog\Handler\AbstractHandler::pushProcessor
+ * @covers Monolog\Handler\AbstractHandler::popProcessor
+ * @expectedException LogicException
+ */
+ public function testPushPopProcessor()
+ {
+ $logger = $this->getMockForAbstractClass('Monolog\Handler\AbstractHandler');
+ $processor1 = new WebProcessor;
+ $processor2 = new WebProcessor;
+
+ $logger->pushProcessor($processor1);
+ $logger->pushProcessor($processor2);
+
+ $this->assertEquals($processor2, $logger->popProcessor());
+ $this->assertEquals($processor1, $logger->popProcessor());
+ $logger->popProcessor();
+ }
+
+ /**
+ * @covers Monolog\Handler\AbstractHandler::pushProcessor
+ * @expectedException InvalidArgumentException
+ */
+ public function testPushProcessorWithNonCallable()
+ {
+ $handler = $this->getMockForAbstractClass('Monolog\Handler\AbstractHandler');
+
+ $handler->pushProcessor(new \stdClass());
+ }
+}
diff --git a/vendor/monolog/monolog/tests/Monolog/Handler/AbstractProcessingHandlerTest.php b/vendor/monolog/monolog/tests/Monolog/Handler/AbstractProcessingHandlerTest.php
new file mode 100644
index 00000000..24d4f63c
--- /dev/null
+++ b/vendor/monolog/monolog/tests/Monolog/Handler/AbstractProcessingHandlerTest.php
@@ -0,0 +1,80 @@
+<?php
+
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Handler;
+
+use Monolog\TestCase;
+use Monolog\Logger;
+use Monolog\Processor\WebProcessor;
+
+class AbstractProcessingHandlerTest extends TestCase
+{
+ /**
+ * @covers Monolog\Handler\AbstractProcessingHandler::handle
+ */
+ public function testHandleLowerLevelMessage()
+ {
+ $handler = $this->getMockForAbstractClass('Monolog\Handler\AbstractProcessingHandler', array(Logger::WARNING, true));
+ $this->assertFalse($handler->handle($this->getRecord(Logger::DEBUG)));
+ }
+
+ /**
+ * @covers Monolog\Handler\AbstractProcessingHandler::handle
+ */
+ public function testHandleBubbling()
+ {
+ $handler = $this->getMockForAbstractClass('Monolog\Handler\AbstractProcessingHandler', array(Logger::DEBUG, true));
+ $this->assertFalse($handler->handle($this->getRecord()));
+ }
+
+ /**
+ * @covers Monolog\Handler\AbstractProcessingHandler::handle
+ */
+ public function testHandleNotBubbling()
+ {
+ $handler = $this->getMockForAbstractClass('Monolog\Handler\AbstractProcessingHandler', array(Logger::DEBUG, false));
+ $this->assertTrue($handler->handle($this->getRecord()));
+ }
+
+ /**
+ * @covers Monolog\Handler\AbstractProcessingHandler::handle
+ */
+ public function testHandleIsFalseWhenNotHandled()
+ {
+ $handler = $this->getMockForAbstractClass('Monolog\Handler\AbstractProcessingHandler', array(Logger::WARNING, false));
+ $this->assertTrue($handler->handle($this->getRecord()));
+ $this->assertFalse($handler->handle($this->getRecord(Logger::DEBUG)));
+ }
+
+ /**
+ * @covers Monolog\Handler\AbstractProcessingHandler::processRecord
+ */
+ public function testProcessRecord()
+ {
+ $handler = $this->getMockForAbstractClass('Monolog\Handler\AbstractProcessingHandler');
+ $handler->pushProcessor(new WebProcessor(array(
+ 'REQUEST_URI' => '',
+ 'REQUEST_METHOD' => '',
+ 'REMOTE_ADDR' => '',
+ 'SERVER_NAME' => '',
+ 'UNIQUE_ID' => '',
+ )));
+ $handledRecord = null;
+ $handler->expects($this->once())
+ ->method('write')
+ ->will($this->returnCallback(function ($record) use (&$handledRecord) {
+ $handledRecord = $record;
+ }))
+ ;
+ $handler->handle($this->getRecord());
+ $this->assertEquals(6, count($handledRecord['extra']));
+ }
+}
diff --git a/vendor/monolog/monolog/tests/Monolog/Handler/AmqpHandlerTest.php b/vendor/monolog/monolog/tests/Monolog/Handler/AmqpHandlerTest.php
new file mode 100644
index 00000000..a71d6251
--- /dev/null
+++ b/vendor/monolog/monolog/tests/Monolog/Handler/AmqpHandlerTest.php
@@ -0,0 +1,136 @@
+<?php
+
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Handler;
+
+use Monolog\TestCase;
+use Monolog\Logger;
+use PhpAmqpLib\Message\AMQPMessage;
+use PhpAmqpLib\Connection\AMQPConnection;
+
+/**
+ * @covers Monolog\Handler\RotatingFileHandler
+ */
+class AmqpHandlerTest extends TestCase
+{
+ public function testHandleAmqpExt()
+ {
+ if (!class_exists('AMQPConnection') || !class_exists('AMQPExchange')) {
+ $this->markTestSkipped("amqp-php not installed");
+ }
+
+ if (!class_exists('AMQPChannel')) {
+ $this->markTestSkipped("Please update AMQP to version >= 1.0");
+ }
+
+ $messages = array();
+
+ $exchange = $this->getMock('AMQPExchange', array('publish', 'setName'), array(), '', false);
+ $exchange->expects($this->once())
+ ->method('setName')
+ ->with('log')
+ ;
+ $exchange->expects($this->any())
+ ->method('publish')
+ ->will($this->returnCallback(function ($message, $routing_key, $flags = 0, $attributes = array()) use (&$messages) {
+ $messages[] = array($message, $routing_key, $flags, $attributes);
+ }))
+ ;
+
+ $handler = new AmqpHandler($exchange, 'log');
+
+ $record = $this->getRecord(Logger::WARNING, 'test', array('data' => new \stdClass, 'foo' => 34));
+
+ $expected = array(
+ array(
+ 'message' => 'test',
+ 'context' => array(
+ 'data' => array(),
+ 'foo' => 34,
+ ),
+ 'level' => 300,
+ 'level_name' => 'WARNING',
+ 'channel' => 'test',
+ 'extra' => array(),
+ ),
+ 'warn.test',
+ 0,
+ array(
+ 'delivery_mode' => 2,
+ 'Content-type' => 'application/json'
+ )
+ );
+
+ $handler->handle($record);
+
+ $this->assertCount(1, $messages);
+ $messages[0][0] = json_decode($messages[0][0], true);
+ unset($messages[0][0]['datetime']);
+ $this->assertEquals($expected, $messages[0]);
+ }
+
+ public function testHandlePhpAmqpLib()
+ {
+ if (!class_exists('PhpAmqpLib\Connection\AMQPConnection')) {
+ $this->markTestSkipped("php-amqplib not installed");
+ }
+
+ $messages = array();
+
+ $exchange = $this->getMock('PhpAmqpLib\Channel\AMQPChannel', array('basic_publish', '__destruct'), array(), '', false);
+
+ $exchange->expects($this->any())
+ ->method('basic_publish')
+ ->will($this->returnCallback(function (AMQPMessage $msg, $exchange = "", $routing_key = "", $mandatory = false, $immediate = false, $ticket = null) use (&$messages) {
+ $messages[] = array($msg, $exchange, $routing_key, $mandatory, $immediate, $ticket);
+ }))
+ ;
+
+ $handler = new AmqpHandler($exchange, 'log');
+
+ $record = $this->getRecord(Logger::WARNING, 'test', array('data' => new \stdClass, 'foo' => 34));
+
+ $expected = array(
+ array(
+ 'message' => 'test',
+ 'context' => array(
+ 'data' => array(),
+ 'foo' => 34,
+ ),
+ 'level' => 300,
+ 'level_name' => 'WARNING',
+ 'channel' => 'test',
+ 'extra' => array(),
+ ),
+ 'log',
+ 'warn.test',
+ false,
+ false,
+ null,
+ array(
+ 'delivery_mode' => 2,
+ 'content_type' => 'application/json'
+ )
+ );
+
+ $handler->handle($record);
+
+ $this->assertCount(1, $messages);
+
+ /* @var $msg AMQPMessage */
+ $msg = $messages[0][0];
+ $messages[0][0] = json_decode($msg->body, true);
+ $messages[0][] = $msg->get_properties();
+ unset($messages[0][0]['datetime']);
+
+ $this->assertEquals($expected, $messages[0]);
+ }
+}
diff --git a/vendor/monolog/monolog/tests/Monolog/Handler/BrowserConsoleHandlerTest.php b/vendor/monolog/monolog/tests/Monolog/Handler/BrowserConsoleHandlerTest.php
new file mode 100644
index 00000000..ffb1d746
--- /dev/null
+++ b/vendor/monolog/monolog/tests/Monolog/Handler/BrowserConsoleHandlerTest.php
@@ -0,0 +1,130 @@
+<?php
+
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Handler;
+
+use Monolog\TestCase;
+use Monolog\Logger;
+
+/**
+ * @covers Monolog\Handler\BrowserConsoleHandlerTest
+ */
+class BrowserConsoleHandlerTest extends TestCase
+{
+ protected function setUp()
+ {
+ BrowserConsoleHandler::reset();
+ }
+
+ protected function generateScript()
+ {
+ $reflMethod = new \ReflectionMethod('Monolog\Handler\BrowserConsoleHandler', 'generateScript');
+ $reflMethod->setAccessible(true);
+
+ return $reflMethod->invoke(null);
+ }
+
+ public function testStyling()
+ {
+ $handler = new BrowserConsoleHandler();
+ $handler->setFormatter($this->getIdentityFormatter());
+
+ $handler->handle($this->getRecord(Logger::DEBUG, 'foo[[bar]]{color: red}'));
+
+ $expected = <<<EOF
+(function (c) {if (c && c.groupCollapsed) {
+c.log("%cfoo%cbar%c", "font-weight: normal", "color: red", "font-weight: normal");
+}})(console);
+EOF;
+
+ $this->assertEquals($expected, $this->generateScript());
+ }
+
+ public function testEscaping()
+ {
+ $handler = new BrowserConsoleHandler();
+ $handler->setFormatter($this->getIdentityFormatter());
+
+ $handler->handle($this->getRecord(Logger::DEBUG, "[foo] [[\"bar\n[baz]\"]]{color: red}"));
+
+ $expected = <<<EOF
+(function (c) {if (c && c.groupCollapsed) {
+c.log("%c[foo] %c\"bar\\n[baz]\"%c", "font-weight: normal", "color: red", "font-weight: normal");
+}})(console);
+EOF;
+
+ $this->assertEquals($expected, $this->generateScript());
+ }
+
+ public function testAutolabel()
+ {
+ $handler = new BrowserConsoleHandler();
+ $handler->setFormatter($this->getIdentityFormatter());
+
+ $handler->handle($this->getRecord(Logger::DEBUG, '[[foo]]{macro: autolabel}'));
+ $handler->handle($this->getRecord(Logger::DEBUG, '[[bar]]{macro: autolabel}'));
+ $handler->handle($this->getRecord(Logger::DEBUG, '[[foo]]{macro: autolabel}'));
+
+ $expected = <<<EOF
+(function (c) {if (c && c.groupCollapsed) {
+c.log("%c%cfoo%c", "font-weight: normal", "background-color: blue; color: white; border-radius: 3px; padding: 0 2px 0 2px", "font-weight: normal");
+c.log("%c%cbar%c", "font-weight: normal", "background-color: green; color: white; border-radius: 3px; padding: 0 2px 0 2px", "font-weight: normal");
+c.log("%c%cfoo%c", "font-weight: normal", "background-color: blue; color: white; border-radius: 3px; padding: 0 2px 0 2px", "font-weight: normal");
+}})(console);
+EOF;
+
+ $this->assertEquals($expected, $this->generateScript());
+ }
+
+ public function testContext()
+ {
+ $handler = new BrowserConsoleHandler();
+ $handler->setFormatter($this->getIdentityFormatter());
+
+ $handler->handle($this->getRecord(Logger::DEBUG, 'test', array('foo' => 'bar')));
+
+ $expected = <<<EOF
+(function (c) {if (c && c.groupCollapsed) {
+c.groupCollapsed("%ctest", "font-weight: normal");
+c.log("%c%s", "font-weight: bold", "Context");
+c.log("%s: %o", "foo", "bar");
+c.groupEnd();
+}})(console);
+EOF;
+
+ $this->assertEquals($expected, $this->generateScript());
+ }
+
+ public function testConcurrentHandlers()
+ {
+ $handler1 = new BrowserConsoleHandler();
+ $handler1->setFormatter($this->getIdentityFormatter());
+
+ $handler2 = new BrowserConsoleHandler();
+ $handler2->setFormatter($this->getIdentityFormatter());
+
+ $handler1->handle($this->getRecord(Logger::DEBUG, 'test1'));
+ $handler2->handle($this->getRecord(Logger::DEBUG, 'test2'));
+ $handler1->handle($this->getRecord(Logger::DEBUG, 'test3'));
+ $handler2->handle($this->getRecord(Logger::DEBUG, 'test4'));
+
+ $expected = <<<EOF
+(function (c) {if (c && c.groupCollapsed) {
+c.log("%ctest1", "font-weight: normal");
+c.log("%ctest2", "font-weight: normal");
+c.log("%ctest3", "font-weight: normal");
+c.log("%ctest4", "font-weight: normal");
+}})(console);
+EOF;
+
+ $this->assertEquals($expected, $this->generateScript());
+ }
+}
diff --git a/vendor/monolog/monolog/tests/Monolog/Handler/BufferHandlerTest.php b/vendor/monolog/monolog/tests/Monolog/Handler/BufferHandlerTest.php
new file mode 100644
index 00000000..da8b3c39
--- /dev/null
+++ b/vendor/monolog/monolog/tests/Monolog/Handler/BufferHandlerTest.php
@@ -0,0 +1,158 @@
+<?php
+
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Handler;
+
+use Monolog\TestCase;
+use Monolog\Logger;
+
+class BufferHandlerTest extends TestCase
+{
+ private $shutdownCheckHandler;
+
+ /**
+ * @covers Monolog\Handler\BufferHandler::__construct
+ * @covers Monolog\Handler\BufferHandler::handle
+ * @covers Monolog\Handler\BufferHandler::close
+ */
+ public function testHandleBuffers()
+ {
+ $test = new TestHandler();
+ $handler = new BufferHandler($test);
+ $handler->handle($this->getRecord(Logger::DEBUG));
+ $handler->handle($this->getRecord(Logger::INFO));
+ $this->assertFalse($test->hasDebugRecords());
+ $this->assertFalse($test->hasInfoRecords());
+ $handler->close();
+ $this->assertTrue($test->hasInfoRecords());
+ $this->assertTrue(count($test->getRecords()) === 2);
+ }
+
+ /**
+ * @covers Monolog\Handler\BufferHandler::close
+ * @covers Monolog\Handler\BufferHandler::flush
+ */
+ public function testPropagatesRecordsAtEndOfRequest()
+ {
+ $test = new TestHandler();
+ $handler = new BufferHandler($test);
+ $handler->handle($this->getRecord(Logger::WARNING));
+ $handler->handle($this->getRecord(Logger::DEBUG));
+ $this->shutdownCheckHandler = $test;
+ register_shutdown_function(array($this, 'checkPropagation'));
+ }
+
+ public function checkPropagation()
+ {
+ if (!$this->shutdownCheckHandler->hasWarningRecords() || !$this->shutdownCheckHandler->hasDebugRecords()) {
+ echo '!!! BufferHandlerTest::testPropagatesRecordsAtEndOfRequest failed to verify that the messages have been propagated' . PHP_EOL;
+ exit(1);
+ }
+ }
+
+ /**
+ * @covers Monolog\Handler\BufferHandler::handle
+ */
+ public function testHandleBufferLimit()
+ {
+ $test = new TestHandler();
+ $handler = new BufferHandler($test, 2);
+ $handler->handle($this->getRecord(Logger::DEBUG));
+ $handler->handle($this->getRecord(Logger::DEBUG));
+ $handler->handle($this->getRecord(Logger::INFO));
+ $handler->handle($this->getRecord(Logger::WARNING));
+ $handler->close();
+ $this->assertTrue($test->hasWarningRecords());
+ $this->assertTrue($test->hasInfoRecords());
+ $this->assertFalse($test->hasDebugRecords());
+ }
+
+ /**
+ * @covers Monolog\Handler\BufferHandler::handle
+ */
+ public function testHandleBufferLimitWithFlushOnOverflow()
+ {
+ $test = new TestHandler();
+ $handler = new BufferHandler($test, 3, Logger::DEBUG, true, true);
+
+ // send two records
+ $handler->handle($this->getRecord(Logger::DEBUG));
+ $handler->handle($this->getRecord(Logger::DEBUG));
+ $handler->handle($this->getRecord(Logger::DEBUG));
+ $this->assertFalse($test->hasDebugRecords());
+ $this->assertCount(0, $test->getRecords());
+
+ // overflow
+ $handler->handle($this->getRecord(Logger::INFO));
+ $this->assertTrue($test->hasDebugRecords());
+ $this->assertCount(3, $test->getRecords());
+
+ // should buffer again
+ $handler->handle($this->getRecord(Logger::WARNING));
+ $this->assertCount(3, $test->getRecords());
+
+ $handler->close();
+ $this->assertCount(5, $test->getRecords());
+ $this->assertTrue($test->hasWarningRecords());
+ $this->assertTrue($test->hasInfoRecords());
+ }
+
+ /**
+ * @covers Monolog\Handler\BufferHandler::handle
+ */
+ public function testHandleLevel()
+ {
+ $test = new TestHandler();
+ $handler = new BufferHandler($test, 0, Logger::INFO);
+ $handler->handle($this->getRecord(Logger::DEBUG));
+ $handler->handle($this->getRecord(Logger::INFO));
+ $handler->handle($this->getRecord(Logger::WARNING));
+ $handler->handle($this->getRecord(Logger::DEBUG));
+ $handler->close();
+ $this->assertTrue($test->hasWarningRecords());
+ $this->assertTrue($test->hasInfoRecords());
+ $this->assertFalse($test->hasDebugRecords());
+ }
+
+ /**
+ * @covers Monolog\Handler\BufferHandler::flush
+ */
+ public function testFlush()
+ {
+ $test = new TestHandler();
+ $handler = new BufferHandler($test, 0);
+ $handler->handle($this->getRecord(Logger::DEBUG));
+ $handler->handle($this->getRecord(Logger::INFO));
+ $handler->flush();
+ $this->assertTrue($test->hasInfoRecords());
+ $this->assertTrue($test->hasDebugRecords());
+ $this->assertFalse($test->hasWarningRecords());
+ }
+
+ /**
+ * @covers Monolog\Handler\BufferHandler::handle
+ */
+ public function testHandleUsesProcessors()
+ {
+ $test = new TestHandler();
+ $handler = new BufferHandler($test);
+ $handler->pushProcessor(function ($record) {
+ $record['extra']['foo'] = true;
+
+ return $record;
+ });
+ $handler->handle($this->getRecord(Logger::WARNING));
+ $handler->flush();
+ $this->assertTrue($test->hasWarningRecords());
+ $records = $test->getRecords();
+ $this->assertTrue($records[0]['extra']['foo']);
+ }
+}
diff --git a/vendor/monolog/monolog/tests/Monolog/Handler/ChromePHPHandlerTest.php b/vendor/monolog/monolog/tests/Monolog/Handler/ChromePHPHandlerTest.php
new file mode 100644
index 00000000..2f55faf8
--- /dev/null
+++ b/vendor/monolog/monolog/tests/Monolog/Handler/ChromePHPHandlerTest.php
@@ -0,0 +1,141 @@
+<?php
+
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Handler;
+
+use Monolog\TestCase;
+use Monolog\Logger;
+
+/**
+ * @covers Monolog\Handler\ChromePHPHandler
+ */
+class ChromePHPHandlerTest extends TestCase
+{
+ protected function setUp()
+ {
+ TestChromePHPHandler::reset();
+ $_SERVER['HTTP_USER_AGENT'] = 'Monolog Test; Chrome/1.0';
+ }
+
+ public function testHeaders()
+ {
+ $handler = new TestChromePHPHandler();
+ $handler->setFormatter($this->getIdentityFormatter());
+ $handler->handle($this->getRecord(Logger::DEBUG));
+ $handler->handle($this->getRecord(Logger::WARNING));
+
+ $expected = array(
+ 'X-ChromeLogger-Data' => base64_encode(utf8_encode(json_encode(array(
+ 'version' => ChromePHPHandler::VERSION,
+ 'columns' => array('label', 'log', 'backtrace', 'type'),
+ 'rows' => array(
+ 'test',
+ 'test',
+ ),
+ 'request_uri' => '',
+ ))))
+ );
+
+ $this->assertEquals($expected, $handler->getHeaders());
+ }
+
+ public function testHeadersOverflow()
+ {
+ $handler = new TestChromePHPHandler();
+ $handler->handle($this->getRecord(Logger::DEBUG));
+ $handler->handle($this->getRecord(Logger::WARNING, str_repeat('a', 150*1024)));
+
+ // overflow chrome headers limit
+ $handler->handle($this->getRecord(Logger::WARNING, str_repeat('a', 100*1024)));
+
+ $expected = array(
+ 'X-ChromeLogger-Data' => base64_encode(utf8_encode(json_encode(array(
+ 'version' => ChromePHPHandler::VERSION,
+ 'columns' => array('label', 'log', 'backtrace', 'type'),
+ 'rows' => array(
+ array(
+ 'test',
+ 'test',
+ 'unknown',
+ 'log',
+ ),
+ array(
+ 'test',
+ str_repeat('a', 150*1024),
+ 'unknown',
+ 'warn',
+ ),
+ array(
+ 'monolog',
+ 'Incomplete logs, chrome header size limit reached',
+ 'unknown',
+ 'warn',
+ ),
+ ),
+ 'request_uri' => '',
+ ))))
+ );
+
+ $this->assertEquals($expected, $handler->getHeaders());
+ }
+
+ public function testConcurrentHandlers()
+ {
+ $handler = new TestChromePHPHandler();
+ $handler->setFormatter($this->getIdentityFormatter());
+ $handler->handle($this->getRecord(Logger::DEBUG));
+ $handler->handle($this->getRecord(Logger::WARNING));
+
+ $handler2 = new TestChromePHPHandler();
+ $handler2->setFormatter($this->getIdentityFormatter());
+ $handler2->handle($this->getRecord(Logger::DEBUG));
+ $handler2->handle($this->getRecord(Logger::WARNING));
+
+ $expected = array(
+ 'X-ChromeLogger-Data' => base64_encode(utf8_encode(json_encode(array(
+ 'version' => ChromePHPHandler::VERSION,
+ 'columns' => array('label', 'log', 'backtrace', 'type'),
+ 'rows' => array(
+ 'test',
+ 'test',
+ 'test',
+ 'test',
+ ),
+ 'request_uri' => '',
+ ))))
+ );
+
+ $this->assertEquals($expected, $handler2->getHeaders());
+ }
+}
+
+class TestChromePHPHandler extends ChromePHPHandler
+{
+ protected $headers = array();
+
+ public static function reset()
+ {
+ self::$initialized = false;
+ self::$overflowed = false;
+ self::$sendHeaders = true;
+ self::$json['rows'] = array();
+ }
+
+ protected function sendHeader($header, $content)
+ {
+ $this->headers[$header] = $content;
+ }
+
+ public function getHeaders()
+ {
+ return $this->headers;
+ }
+}
diff --git a/vendor/monolog/monolog/tests/Monolog/Handler/CouchDBHandlerTest.php b/vendor/monolog/monolog/tests/Monolog/Handler/CouchDBHandlerTest.php
new file mode 100644
index 00000000..9fc4b388
--- /dev/null
+++ b/vendor/monolog/monolog/tests/Monolog/Handler/CouchDBHandlerTest.php
@@ -0,0 +1,31 @@
+<?php
+
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Handler;
+
+use Monolog\TestCase;
+use Monolog\Logger;
+
+class CouchDBHandlerTest extends TestCase
+{
+ public function testHandle()
+ {
+ $record = $this->getRecord(Logger::WARNING, 'test', array('data' => new \stdClass, 'foo' => 34));
+
+ $handler = new CouchDBHandler();
+
+ try {
+ $handler->handle($record);
+ } catch (\RuntimeException $e) {
+ $this->markTestSkipped('Could not connect to couchdb server on http://localhost:5984');
+ }
+ }
+}
diff --git a/vendor/monolog/monolog/tests/Monolog/Handler/DoctrineCouchDBHandlerTest.php b/vendor/monolog/monolog/tests/Monolog/Handler/DoctrineCouchDBHandlerTest.php
new file mode 100644
index 00000000..d67da90a
--- /dev/null
+++ b/vendor/monolog/monolog/tests/Monolog/Handler/DoctrineCouchDBHandlerTest.php
@@ -0,0 +1,52 @@
+<?php
+
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Handler;
+
+use Monolog\TestCase;
+use Monolog\Logger;
+
+class DoctrineCouchDBHandlerTest extends TestCase
+{
+ protected function setup()
+ {
+ if (!class_exists('Doctrine\CouchDB\CouchDBClient')) {
+ $this->markTestSkipped('The "doctrine/couchdb" package is not installed');
+ }
+ }
+
+ public function testHandle()
+ {
+ $client = $this->getMockBuilder('Doctrine\\CouchDB\\CouchDBClient')
+ ->setMethods(array('postDocument'))
+ ->disableOriginalConstructor()
+ ->getMock();
+
+ $record = $this->getRecord(Logger::WARNING, 'test', array('data' => new \stdClass, 'foo' => 34));
+
+ $expected = array(
+ 'message' => 'test',
+ 'context' => array('data' => '[object] (stdClass: {})', 'foo' => 34),
+ 'level' => Logger::WARNING,
+ 'level_name' => 'WARNING',
+ 'channel' => 'test',
+ 'datetime' => $record['datetime']->format('Y-m-d H:i:s'),
+ 'extra' => array(),
+ );
+
+ $client->expects($this->once())
+ ->method('postDocument')
+ ->with($expected);
+
+ $handler = new DoctrineCouchDBHandler($client);
+ $handler->handle($record);
+ }
+}
diff --git a/vendor/monolog/monolog/tests/Monolog/Handler/DynamoDbHandlerTest.php b/vendor/monolog/monolog/tests/Monolog/Handler/DynamoDbHandlerTest.php
new file mode 100644
index 00000000..a38a8cb7
--- /dev/null
+++ b/vendor/monolog/monolog/tests/Monolog/Handler/DynamoDbHandlerTest.php
@@ -0,0 +1,73 @@
+<?php
+
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Handler;
+
+use Monolog\TestCase;
+
+class DynamoDbHandlerTest extends TestCase
+{
+ public function setUp()
+ {
+ if (!class_exists('Aws\DynamoDb\DynamoDbClient')) {
+ $this->markTestSkipped('aws/aws-sdk-php not installed');
+ }
+
+ $this->client = $this->getMockBuilder('Aws\DynamoDb\DynamoDbClient')
+ ->setMethods(array('formatAttributes', '__call'))
+ ->disableOriginalConstructor()->getMock();
+ }
+
+ public function testConstruct()
+ {
+ $this->assertInstanceOf('Monolog\Handler\DynamoDbHandler', new DynamoDbHandler($this->client, 'foo'));
+ }
+
+ public function testInterface()
+ {
+ $this->assertInstanceOf('Monolog\Handler\HandlerInterface', new DynamoDbHandler($this->client, 'foo'));
+ }
+
+ public function testGetFormatter()
+ {
+ $handler = new DynamoDbHandler($this->client, 'foo');
+ $this->assertInstanceOf('Monolog\Formatter\ScalarFormatter', $handler->getFormatter());
+ }
+
+ public function testHandle()
+ {
+ $record = $this->getRecord();
+ $formatter = $this->getMock('Monolog\Formatter\FormatterInterface');
+ $formatted = array('foo' => 1, 'bar' => 2);
+ $handler = new DynamoDbHandler($this->client, 'foo');
+ $handler->setFormatter($formatter);
+
+ $formatter
+ ->expects($this->once())
+ ->method('format')
+ ->with($record)
+ ->will($this->returnValue($formatted));
+ $this->client
+ ->expects($this->once())
+ ->method('formatAttributes')
+ ->with($this->isType('array'))
+ ->will($this->returnValue($formatted));
+ $this->client
+ ->expects($this->once())
+ ->method('__call')
+ ->with('putItem', array(array(
+ 'TableName' => 'foo',
+ 'Item' => $formatted
+ )));
+
+ $handler->handle($record);
+ }
+}
diff --git a/vendor/monolog/monolog/tests/Monolog/Handler/ElasticSearchHandlerTest.php b/vendor/monolog/monolog/tests/Monolog/Handler/ElasticSearchHandlerTest.php
new file mode 100644
index 00000000..1687074b
--- /dev/null
+++ b/vendor/monolog/monolog/tests/Monolog/Handler/ElasticSearchHandlerTest.php
@@ -0,0 +1,239 @@
+<?php
+
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Handler;
+
+use Monolog\Formatter\ElasticaFormatter;
+use Monolog\Formatter\NormalizerFormatter;
+use Monolog\TestCase;
+use Monolog\Logger;
+use Elastica\Client;
+use Elastica\Request;
+use Elastica\Response;
+
+class ElasticSearchHandlerTest extends TestCase
+{
+ /**
+ * @var Client mock
+ */
+ protected $client;
+
+ /**
+ * @var array Default handler options
+ */
+ protected $options = array(
+ 'index' => 'my_index',
+ 'type' => 'doc_type',
+ );
+
+ public function setUp()
+ {
+ // Elastica lib required
+ if (!class_exists("Elastica\Client")) {
+ $this->markTestSkipped("ruflin/elastica not installed");
+ }
+
+ // base mock Elastica Client object
+ $this->client = $this->getMockBuilder('Elastica\Client')
+ ->setMethods(array('addDocuments'))
+ ->disableOriginalConstructor()
+ ->getMock();
+ }
+
+ /**
+ * @covers Monolog\Handler\ElasticSearchHandler::write
+ * @covers Monolog\Handler\ElasticSearchHandler::handleBatch
+ * @covers Monolog\Handler\ElasticSearchHandler::bulkSend
+ * @covers Monolog\Handler\ElasticSearchHandler::getDefaultFormatter
+ */
+ public function testHandle()
+ {
+ // log message
+ $msg = array(
+ 'level' => Logger::ERROR,
+ 'level_name' => 'ERROR',
+ 'channel' => 'meh',
+ 'context' => array('foo' => 7, 'bar', 'class' => new \stdClass),
+ 'datetime' => new \DateTime("@0"),
+ 'extra' => array(),
+ 'message' => 'log',
+ );
+
+ // format expected result
+ $formatter = new ElasticaFormatter($this->options['index'], $this->options['type']);
+ $expected = array($formatter->format($msg));
+
+ // setup ES client mock
+ $this->client->expects($this->any())
+ ->method('addDocuments')
+ ->with($expected);
+
+ // perform tests
+ $handler = new ElasticSearchHandler($this->client, $this->options);
+ $handler->handle($msg);
+ $handler->handleBatch(array($msg));
+ }
+
+ /**
+ * @covers Monolog\Handler\ElasticSearchHandler::setFormatter
+ */
+ public function testSetFormatter()
+ {
+ $handler = new ElasticSearchHandler($this->client);
+ $formatter = new ElasticaFormatter('index_new', 'type_new');
+ $handler->setFormatter($formatter);
+ $this->assertInstanceOf('Monolog\Formatter\ElasticaFormatter', $handler->getFormatter());
+ $this->assertEquals('index_new', $handler->getFormatter()->getIndex());
+ $this->assertEquals('type_new', $handler->getFormatter()->getType());
+ }
+
+ /**
+ * @covers Monolog\Handler\ElasticSearchHandler::setFormatter
+ * @expectedException InvalidArgumentException
+ * @expectedExceptionMessage ElasticSearchHandler is only compatible with ElasticaFormatter
+ */
+ public function testSetFormatterInvalid()
+ {
+ $handler = new ElasticSearchHandler($this->client);
+ $formatter = new NormalizerFormatter();
+ $handler->setFormatter($formatter);
+ }
+
+ /**
+ * @covers Monolog\Handler\ElasticSearchHandler::__construct
+ * @covers Monolog\Handler\ElasticSearchHandler::getOptions
+ */
+ public function testOptions()
+ {
+ $expected = array(
+ 'index' => $this->options['index'],
+ 'type' => $this->options['type'],
+ 'ignore_error' => false,
+ );
+ $handler = new ElasticSearchHandler($this->client, $this->options);
+ $this->assertEquals($expected, $handler->getOptions());
+ }
+
+ /**
+ * @covers Monolog\Handler\ElasticSearchHandler::bulkSend
+ * @dataProvider providerTestConnectionErrors
+ */
+ public function testConnectionErrors($ignore, $expectedError)
+ {
+ $clientOpts = array('host' => '127.0.0.1', 'port' => 1);
+ $client = new Client($clientOpts);
+ $handlerOpts = array('ignore_error' => $ignore);
+ $handler = new ElasticSearchHandler($client, $handlerOpts);
+
+ if ($expectedError) {
+ $this->setExpectedException($expectedError[0], $expectedError[1]);
+ $handler->handle($this->getRecord());
+ } else {
+ $this->assertFalse($handler->handle($this->getRecord()));
+ }
+ }
+
+ /**
+ * @return array
+ */
+ public function providerTestConnectionErrors()
+ {
+ return array(
+ array(false, array('RuntimeException', 'Error sending messages to Elasticsearch')),
+ array(true, false),
+ );
+ }
+
+ /**
+ * Integration test using localhost Elastic Search server
+ *
+ * @covers Monolog\Handler\ElasticSearchHandler::__construct
+ * @covers Monolog\Handler\ElasticSearchHandler::handleBatch
+ * @covers Monolog\Handler\ElasticSearchHandler::bulkSend
+ * @covers Monolog\Handler\ElasticSearchHandler::getDefaultFormatter
+ */
+ public function testHandleIntegration()
+ {
+ $msg = array(
+ 'level' => Logger::ERROR,
+ 'level_name' => 'ERROR',
+ 'channel' => 'meh',
+ 'context' => array('foo' => 7, 'bar', 'class' => new \stdClass),
+ 'datetime' => new \DateTime("@0"),
+ 'extra' => array(),
+ 'message' => 'log',
+ );
+
+ $expected = $msg;
+ $expected['datetime'] = $msg['datetime']->format(\DateTime::ISO8601);
+ $expected['context'] = array(
+ 'class' => '[object] (stdClass: {})',
+ 'foo' => 7,
+ 0 => 'bar',
+ );
+
+ $client = new Client();
+ $handler = new ElasticSearchHandler($client, $this->options);
+ try {
+ $handler->handleBatch(array($msg));
+ } catch (\RuntimeException $e) {
+ $this->markTestSkipped("Cannot connect to Elastic Search server on localhost");
+ }
+
+ // check document id from ES server response
+ $documentId = $this->getCreatedDocId($client->getLastResponse());
+ $this->assertNotEmpty($documentId, 'No elastic document id received');
+
+ // retrieve document source from ES and validate
+ $document = $this->getDocSourceFromElastic(
+ $client,
+ $this->options['index'],
+ $this->options['type'],
+ $documentId
+ );
+ $this->assertEquals($expected, $document);
+
+ // remove test index from ES
+ $client->request("/{$this->options['index']}", Request::DELETE);
+ }
+
+ /**
+ * Return last created document id from ES response
+ * @param Response $response Elastica Response object
+ * @return string|null
+ */
+ protected function getCreatedDocId(Response $response)
+ {
+ $data = $response->getData();
+ if (!empty($data['items'][0]['create']['_id'])) {
+ return $data['items'][0]['create']['_id'];
+ }
+ }
+
+ /**
+ * Retrieve document by id from Elasticsearch
+ * @param Client $client Elastica client
+ * @param string $index
+ * @param string $type
+ * @param string $documentId
+ * @return array
+ */
+ protected function getDocSourceFromElastic(Client $client, $index, $type, $documentId)
+ {
+ $resp = $client->request("/{$index}/{$type}/{$documentId}", Request::GET);
+ $data = $resp->getData();
+ if (!empty($data['_source'])) {
+ return $data['_source'];
+ }
+
+ return array();
+ }
+}
diff --git a/vendor/monolog/monolog/tests/Monolog/Handler/ErrorLogHandlerTest.php b/vendor/monolog/monolog/tests/Monolog/Handler/ErrorLogHandlerTest.php
new file mode 100644
index 00000000..99785cbb
--- /dev/null
+++ b/vendor/monolog/monolog/tests/Monolog/Handler/ErrorLogHandlerTest.php
@@ -0,0 +1,66 @@
+<?php
+
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Handler;
+
+use Monolog\TestCase;
+use Monolog\Logger;
+use Monolog\Formatter\LineFormatter;
+
+function error_log()
+{
+ $GLOBALS['error_log'][] = func_get_args();
+}
+
+class ErrorLogHandlerTest extends TestCase
+{
+ protected function setUp()
+ {
+ $GLOBALS['error_log'] = array();
+ }
+
+ /**
+ * @covers Monolog\Handler\ErrorLogHandler::__construct
+ * @expectedException InvalidArgumentException
+ * @expectedExceptionMessage The given message type "42" is not supported
+ */
+ public function testShouldNotAcceptAnInvalidTypeOnContructor()
+ {
+ new ErrorLogHandler(42);
+ }
+
+ /**
+ * @covers Monolog\Handler\ErrorLogHandler::write
+ */
+ public function testShouldLogMessagesUsingErrorLogFuncion()
+ {
+ $type = ErrorLogHandler::OPERATING_SYSTEM;
+ $handler = new ErrorLogHandler($type);
+ $handler->setFormatter(new LineFormatter('%channel%.%level_name%: %message% %context% %extra%', null, true));
+ $handler->handle($this->getRecord(Logger::ERROR, "Foo\nBar\r\n\r\nBaz"));
+
+ $this->assertSame("test.ERROR: Foo\nBar\r\n\r\nBaz [] []", $GLOBALS['error_log'][0][0]);
+ $this->assertSame($GLOBALS['error_log'][0][1], $type);
+
+ $handler = new ErrorLogHandler($type, Logger::DEBUG, true, true);
+ $handler->setFormatter(new LineFormatter(null, null, true));
+ $handler->handle($this->getRecord(Logger::ERROR, "Foo\nBar\r\n\r\nBaz"));
+
+ $this->assertStringMatchesFormat('[%s] test.ERROR: Foo', $GLOBALS['error_log'][1][0]);
+ $this->assertSame($GLOBALS['error_log'][1][1], $type);
+
+ $this->assertStringMatchesFormat('Bar', $GLOBALS['error_log'][2][0]);
+ $this->assertSame($GLOBALS['error_log'][2][1], $type);
+
+ $this->assertStringMatchesFormat('Baz [] []', $GLOBALS['error_log'][3][0]);
+ $this->assertSame($GLOBALS['error_log'][3][1], $type);
+ }
+}
diff --git a/vendor/monolog/monolog/tests/Monolog/Handler/FilterHandlerTest.php b/vendor/monolog/monolog/tests/Monolog/Handler/FilterHandlerTest.php
new file mode 100644
index 00000000..31b7686a
--- /dev/null
+++ b/vendor/monolog/monolog/tests/Monolog/Handler/FilterHandlerTest.php
@@ -0,0 +1,170 @@
+<?php
+
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Handler;
+
+use Monolog\Logger;
+use Monolog\TestCase;
+
+class FilterHandlerTest extends TestCase
+{
+ /**
+ * @covers Monolog\Handler\FilterHandler::isHandling
+ */
+ public function testIsHandling()
+ {
+ $test = new TestHandler();
+ $handler = new FilterHandler($test, Logger::INFO, Logger::NOTICE);
+ $this->assertFalse($handler->isHandling($this->getRecord(Logger::DEBUG)));
+ $this->assertTrue($handler->isHandling($this->getRecord(Logger::INFO)));
+ $this->assertTrue($handler->isHandling($this->getRecord(Logger::NOTICE)));
+ $this->assertFalse($handler->isHandling($this->getRecord(Logger::WARNING)));
+ $this->assertFalse($handler->isHandling($this->getRecord(Logger::ERROR)));
+ $this->assertFalse($handler->isHandling($this->getRecord(Logger::CRITICAL)));
+ $this->assertFalse($handler->isHandling($this->getRecord(Logger::ALERT)));
+ $this->assertFalse($handler->isHandling($this->getRecord(Logger::EMERGENCY)));
+ }
+
+ /**
+ * @covers Monolog\Handler\FilterHandler::handle
+ * @covers Monolog\Handler\FilterHandler::setAcceptedLevels
+ * @covers Monolog\Handler\FilterHandler::isHandling
+ */
+ public function testHandleProcessOnlyNeededLevels()
+ {
+ $test = new TestHandler();
+ $handler = new FilterHandler($test, Logger::INFO, Logger::NOTICE);
+
+ $handler->handle($this->getRecord(Logger::DEBUG));
+ $this->assertFalse($test->hasDebugRecords());
+
+ $handler->handle($this->getRecord(Logger::INFO));
+ $this->assertTrue($test->hasInfoRecords());
+ $handler->handle($this->getRecord(Logger::NOTICE));
+ $this->assertTrue($test->hasNoticeRecords());
+
+ $handler->handle($this->getRecord(Logger::WARNING));
+ $this->assertFalse($test->hasWarningRecords());
+ $handler->handle($this->getRecord(Logger::ERROR));
+ $this->assertFalse($test->hasErrorRecords());
+ $handler->handle($this->getRecord(Logger::CRITICAL));
+ $this->assertFalse($test->hasCriticalRecords());
+ $handler->handle($this->getRecord(Logger::ALERT));
+ $this->assertFalse($test->hasAlertRecords());
+ $handler->handle($this->getRecord(Logger::EMERGENCY));
+ $this->assertFalse($test->hasEmergencyRecords());
+
+ $test = new TestHandler();
+ $handler = new FilterHandler($test, array(Logger::INFO, Logger::ERROR));
+
+ $handler->handle($this->getRecord(Logger::DEBUG));
+ $this->assertFalse($test->hasDebugRecords());
+ $handler->handle($this->getRecord(Logger::INFO));
+ $this->assertTrue($test->hasInfoRecords());
+ $handler->handle($this->getRecord(Logger::NOTICE));
+ $this->assertFalse($test->hasNoticeRecords());
+ $handler->handle($this->getRecord(Logger::ERROR));
+ $this->assertTrue($test->hasErrorRecords());
+ $handler->handle($this->getRecord(Logger::CRITICAL));
+ $this->assertFalse($test->hasCriticalRecords());
+ }
+
+ /**
+ * @covers Monolog\Handler\FilterHandler::setAcceptedLevels
+ * @covers Monolog\Handler\FilterHandler::getAcceptedLevels
+ */
+ public function testAcceptedLevelApi()
+ {
+ $test = new TestHandler();
+ $handler = new FilterHandler($test);
+
+ $levels = array(Logger::INFO, Logger::ERROR);
+ $handler->setAcceptedLevels($levels);
+ $this->assertSame($levels, $handler->getAcceptedLevels());
+
+ $handler->setAcceptedLevels(array('info', 'error'));
+ $this->assertSame($levels, $handler->getAcceptedLevels());
+
+ $levels = array(Logger::CRITICAL, Logger::ALERT, Logger::EMERGENCY);
+ $handler->setAcceptedLevels(Logger::CRITICAL, Logger::EMERGENCY);
+ $this->assertSame($levels, $handler->getAcceptedLevels());
+
+ $handler->setAcceptedLevels('critical', 'emergency');
+ $this->assertSame($levels, $handler->getAcceptedLevels());
+ }
+
+ /**
+ * @covers Monolog\Handler\FilterHandler::handle
+ */
+ public function testHandleUsesProcessors()
+ {
+ $test = new TestHandler();
+ $handler = new FilterHandler($test, Logger::DEBUG, Logger::EMERGENCY);
+ $handler->pushProcessor(
+ function ($record) {
+ $record['extra']['foo'] = true;
+
+ return $record;
+ }
+ );
+ $handler->handle($this->getRecord(Logger::WARNING));
+ $this->assertTrue($test->hasWarningRecords());
+ $records = $test->getRecords();
+ $this->assertTrue($records[0]['extra']['foo']);
+ }
+
+ /**
+ * @covers Monolog\Handler\FilterHandler::handle
+ */
+ public function testHandleRespectsBubble()
+ {
+ $test = new TestHandler();
+
+ $handler = new FilterHandler($test, Logger::INFO, Logger::NOTICE, false);
+ $this->assertTrue($handler->handle($this->getRecord(Logger::INFO)));
+ $this->assertFalse($handler->handle($this->getRecord(Logger::WARNING)));
+
+ $handler = new FilterHandler($test, Logger::INFO, Logger::NOTICE, true);
+ $this->assertFalse($handler->handle($this->getRecord(Logger::INFO)));
+ $this->assertFalse($handler->handle($this->getRecord(Logger::WARNING)));
+ }
+
+ /**
+ * @covers Monolog\Handler\FilterHandler::handle
+ */
+ public function testHandleWithCallback()
+ {
+ $test = new TestHandler();
+ $handler = new FilterHandler(
+ function ($record, $handler) use ($test) {
+ return $test;
+ }, Logger::INFO, Logger::NOTICE, false
+ );
+ $handler->handle($this->getRecord(Logger::DEBUG));
+ $handler->handle($this->getRecord(Logger::INFO));
+ $this->assertFalse($test->hasDebugRecords());
+ $this->assertTrue($test->hasInfoRecords());
+ }
+
+ /**
+ * @covers Monolog\Handler\FilterHandler::handle
+ * @expectedException \RuntimeException
+ */
+ public function testHandleWithBadCallbackThrowsException()
+ {
+ $handler = new FilterHandler(
+ function ($record, $handler) {
+ return 'foo';
+ }
+ );
+ $handler->handle($this->getRecord(Logger::WARNING));
+ }
+}
diff --git a/vendor/monolog/monolog/tests/Monolog/Handler/FingersCrossedHandlerTest.php b/vendor/monolog/monolog/tests/Monolog/Handler/FingersCrossedHandlerTest.php
new file mode 100644
index 00000000..8e31e9b8
--- /dev/null
+++ b/vendor/monolog/monolog/tests/Monolog/Handler/FingersCrossedHandlerTest.php
@@ -0,0 +1,255 @@
+<?php
+
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Handler;
+
+use Monolog\TestCase;
+use Monolog\Logger;
+use Monolog\Handler\FingersCrossed\ErrorLevelActivationStrategy;
+use Monolog\Handler\FingersCrossed\ChannelLevelActivationStrategy;
+use Psr\Log\LogLevel;
+
+class FingersCrossedHandlerTest extends TestCase
+{
+ /**
+ * @covers Monolog\Handler\FingersCrossedHandler::__construct
+ * @covers Monolog\Handler\FingersCrossedHandler::handle
+ */
+ public function testHandleBuffers()
+ {
+ $test = new TestHandler();
+ $handler = new FingersCrossedHandler($test);
+ $handler->handle($this->getRecord(Logger::DEBUG));
+ $handler->handle($this->getRecord(Logger::INFO));
+ $this->assertFalse($test->hasDebugRecords());
+ $this->assertFalse($test->hasInfoRecords());
+ $handler->handle($this->getRecord(Logger::WARNING));
+ $handler->close();
+ $this->assertTrue($test->hasInfoRecords());
+ $this->assertTrue(count($test->getRecords()) === 3);
+ }
+
+ /**
+ * @covers Monolog\Handler\FingersCrossedHandler::handle
+ */
+ public function testHandleStopsBufferingAfterTrigger()
+ {
+ $test = new TestHandler();
+ $handler = new FingersCrossedHandler($test);
+ $handler->handle($this->getRecord(Logger::WARNING));
+ $handler->handle($this->getRecord(Logger::DEBUG));
+ $handler->close();
+ $this->assertTrue($test->hasWarningRecords());
+ $this->assertTrue($test->hasDebugRecords());
+ }
+
+ /**
+ * @covers Monolog\Handler\FingersCrossedHandler::handle
+ * @covers Monolog\Handler\FingersCrossedHandler::reset
+ */
+ public function testHandleRestartBufferingAfterReset()
+ {
+ $test = new TestHandler();
+ $handler = new FingersCrossedHandler($test);
+ $handler->handle($this->getRecord(Logger::WARNING));
+ $handler->handle($this->getRecord(Logger::DEBUG));
+ $handler->reset();
+ $handler->handle($this->getRecord(Logger::INFO));
+ $handler->close();
+ $this->assertTrue($test->hasWarningRecords());
+ $this->assertTrue($test->hasDebugRecords());
+ $this->assertFalse($test->hasInfoRecords());
+ }
+
+ /**
+ * @covers Monolog\Handler\FingersCrossedHandler::handle
+ */
+ public function testHandleRestartBufferingAfterBeingTriggeredWhenStopBufferingIsDisabled()
+ {
+ $test = new TestHandler();
+ $handler = new FingersCrossedHandler($test, Logger::WARNING, 0, false, false);
+ $handler->handle($this->getRecord(Logger::DEBUG));
+ $handler->handle($this->getRecord(Logger::WARNING));
+ $handler->handle($this->getRecord(Logger::INFO));
+ $handler->close();
+ $this->assertTrue($test->hasWarningRecords());
+ $this->assertTrue($test->hasDebugRecords());
+ $this->assertFalse($test->hasInfoRecords());
+ }
+
+ /**
+ * @covers Monolog\Handler\FingersCrossedHandler::handle
+ */
+ public function testHandleBufferLimit()
+ {
+ $test = new TestHandler();
+ $handler = new FingersCrossedHandler($test, Logger::WARNING, 2);
+ $handler->handle($this->getRecord(Logger::DEBUG));
+ $handler->handle($this->getRecord(Logger::DEBUG));
+ $handler->handle($this->getRecord(Logger::INFO));
+ $handler->handle($this->getRecord(Logger::WARNING));
+ $this->assertTrue($test->hasWarningRecords());
+ $this->assertTrue($test->hasInfoRecords());
+ $this->assertFalse($test->hasDebugRecords());
+ }
+
+ /**
+ * @covers Monolog\Handler\FingersCrossedHandler::handle
+ */
+ public function testHandleWithCallback()
+ {
+ $test = new TestHandler();
+ $handler = new FingersCrossedHandler(function ($record, $handler) use ($test) {
+ return $test;
+ });
+ $handler->handle($this->getRecord(Logger::DEBUG));
+ $handler->handle($this->getRecord(Logger::INFO));
+ $this->assertFalse($test->hasDebugRecords());
+ $this->assertFalse($test->hasInfoRecords());
+ $handler->handle($this->getRecord(Logger::WARNING));
+ $this->assertTrue($test->hasInfoRecords());
+ $this->assertTrue(count($test->getRecords()) === 3);
+ }
+
+ /**
+ * @covers Monolog\Handler\FingersCrossedHandler::handle
+ * @expectedException RuntimeException
+ */
+ public function testHandleWithBadCallbackThrowsException()
+ {
+ $handler = new FingersCrossedHandler(function ($record, $handler) {
+ return 'foo';
+ });
+ $handler->handle($this->getRecord(Logger::WARNING));
+ }
+
+ /**
+ * @covers Monolog\Handler\FingersCrossedHandler::isHandling
+ */
+ public function testIsHandlingAlways()
+ {
+ $test = new TestHandler();
+ $handler = new FingersCrossedHandler($test, Logger::ERROR);
+ $this->assertTrue($handler->isHandling($this->getRecord(Logger::DEBUG)));
+ }
+
+ /**
+ * @covers Monolog\Handler\FingersCrossedHandler::__construct
+ * @covers Monolog\Handler\FingersCrossed\ErrorLevelActivationStrategy::__construct
+ * @covers Monolog\Handler\FingersCrossed\ErrorLevelActivationStrategy::isHandlerActivated
+ */
+ public function testErrorLevelActivationStrategy()
+ {
+ $test = new TestHandler();
+ $handler = new FingersCrossedHandler($test, new ErrorLevelActivationStrategy(Logger::WARNING));
+ $handler->handle($this->getRecord(Logger::DEBUG));
+ $this->assertFalse($test->hasDebugRecords());
+ $handler->handle($this->getRecord(Logger::WARNING));
+ $this->assertTrue($test->hasDebugRecords());
+ $this->assertTrue($test->hasWarningRecords());
+ }
+
+ /**
+ * @covers Monolog\Handler\FingersCrossedHandler::__construct
+ * @covers Monolog\Handler\FingersCrossed\ErrorLevelActivationStrategy::__construct
+ * @covers Monolog\Handler\FingersCrossed\ErrorLevelActivationStrategy::isHandlerActivated
+ */
+ public function testErrorLevelActivationStrategyWithPsrLevel()
+ {
+ $test = new TestHandler();
+ $handler = new FingersCrossedHandler($test, new ErrorLevelActivationStrategy('warning'));
+ $handler->handle($this->getRecord(Logger::DEBUG));
+ $this->assertFalse($test->hasDebugRecords());
+ $handler->handle($this->getRecord(Logger::WARNING));
+ $this->assertTrue($test->hasDebugRecords());
+ $this->assertTrue($test->hasWarningRecords());
+ }
+
+ /**
+ * @covers Monolog\Handler\FingersCrossed\ChannelLevelActivationStrategy::__construct
+ * @covers Monolog\Handler\FingersCrossed\ChannelLevelActivationStrategy::isHandlerActivated
+ */
+ public function testChannelLevelActivationStrategy()
+ {
+ $test = new TestHandler();
+ $handler = new FingersCrossedHandler($test, new ChannelLevelActivationStrategy(Logger::ERROR, array('othertest' => Logger::DEBUG)));
+ $handler->handle($this->getRecord(Logger::WARNING));
+ $this->assertFalse($test->hasWarningRecords());
+ $record = $this->getRecord(Logger::DEBUG);
+ $record['channel'] = 'othertest';
+ $handler->handle($record);
+ $this->assertTrue($test->hasDebugRecords());
+ $this->assertTrue($test->hasWarningRecords());
+ }
+
+ /**
+ * @covers Monolog\Handler\FingersCrossed\ChannelLevelActivationStrategy::__construct
+ * @covers Monolog\Handler\FingersCrossed\ChannelLevelActivationStrategy::isHandlerActivated
+ */
+ public function testChannelLevelActivationStrategyWithPsrLevels()
+ {
+ $test = new TestHandler();
+ $handler = new FingersCrossedHandler($test, new ChannelLevelActivationStrategy('error', array('othertest' => 'debug')));
+ $handler->handle($this->getRecord(Logger::WARNING));
+ $this->assertFalse($test->hasWarningRecords());
+ $record = $this->getRecord(Logger::DEBUG);
+ $record['channel'] = 'othertest';
+ $handler->handle($record);
+ $this->assertTrue($test->hasDebugRecords());
+ $this->assertTrue($test->hasWarningRecords());
+ }
+
+ /**
+ * @covers Monolog\Handler\FingersCrossedHandler::handle
+ */
+ public function testHandleUsesProcessors()
+ {
+ $test = new TestHandler();
+ $handler = new FingersCrossedHandler($test, Logger::INFO);
+ $handler->pushProcessor(function ($record) {
+ $record['extra']['foo'] = true;
+
+ return $record;
+ });
+ $handler->handle($this->getRecord(Logger::WARNING));
+ $this->assertTrue($test->hasWarningRecords());
+ $records = $test->getRecords();
+ $this->assertTrue($records[0]['extra']['foo']);
+ }
+
+ /**
+ * @covers Monolog\Handler\FingersCrossedHandler::close
+ */
+ public function testPassthruOnClose()
+ {
+ $test = new TestHandler();
+ $handler = new FingersCrossedHandler($test, new ErrorLevelActivationStrategy(Logger::WARNING), 0, true, true, Logger::INFO);
+ $handler->handle($this->getRecord(Logger::DEBUG));
+ $handler->handle($this->getRecord(Logger::INFO));
+ $handler->close();
+ $this->assertFalse($test->hasDebugRecords());
+ $this->assertTrue($test->hasInfoRecords());
+ }
+
+ /**
+ * @covers Monolog\Handler\FingersCrossedHandler::close
+ */
+ public function testPsrLevelPassthruOnClose()
+ {
+ $test = new TestHandler();
+ $handler = new FingersCrossedHandler($test, new ErrorLevelActivationStrategy(Logger::WARNING), 0, true, true, LogLevel::INFO);
+ $handler->handle($this->getRecord(Logger::DEBUG));
+ $handler->handle($this->getRecord(Logger::INFO));
+ $handler->close();
+ $this->assertFalse($test->hasDebugRecords());
+ $this->assertTrue($test->hasInfoRecords());
+ }
+}
diff --git a/vendor/monolog/monolog/tests/Monolog/Handler/FirePHPHandlerTest.php b/vendor/monolog/monolog/tests/Monolog/Handler/FirePHPHandlerTest.php
new file mode 100644
index 00000000..0eb10a63
--- /dev/null
+++ b/vendor/monolog/monolog/tests/Monolog/Handler/FirePHPHandlerTest.php
@@ -0,0 +1,96 @@
+<?php
+
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Handler;
+
+use Monolog\TestCase;
+use Monolog\Logger;
+
+/**
+ * @covers Monolog\Handler\FirePHPHandler
+ */
+class FirePHPHandlerTest extends TestCase
+{
+ public function setUp()
+ {
+ TestFirePHPHandler::reset();
+ $_SERVER['HTTP_USER_AGENT'] = 'Monolog Test; FirePHP/1.0';
+ }
+
+ public function testHeaders()
+ {
+ $handler = new TestFirePHPHandler;
+ $handler->setFormatter($this->getIdentityFormatter());
+ $handler->handle($this->getRecord(Logger::DEBUG));
+ $handler->handle($this->getRecord(Logger::WARNING));
+
+ $expected = array(
+ 'X-Wf-Protocol-1' => 'http://meta.wildfirehq.org/Protocol/JsonStream/0.2',
+ 'X-Wf-1-Structure-1' => 'http://meta.firephp.org/Wildfire/Structure/FirePHP/FirebugConsole/0.1',
+ 'X-Wf-1-Plugin-1' => 'http://meta.firephp.org/Wildfire/Plugin/FirePHP/Library-FirePHPCore/0.3',
+ 'X-Wf-1-1-1-1' => 'test',
+ 'X-Wf-1-1-1-2' => 'test',
+ );
+
+ $this->assertEquals($expected, $handler->getHeaders());
+ }
+
+ public function testConcurrentHandlers()
+ {
+ $handler = new TestFirePHPHandler;
+ $handler->setFormatter($this->getIdentityFormatter());
+ $handler->handle($this->getRecord(Logger::DEBUG));
+ $handler->handle($this->getRecord(Logger::WARNING));
+
+ $handler2 = new TestFirePHPHandler;
+ $handler2->setFormatter($this->getIdentityFormatter());
+ $handler2->handle($this->getRecord(Logger::DEBUG));
+ $handler2->handle($this->getRecord(Logger::WARNING));
+
+ $expected = array(
+ 'X-Wf-Protocol-1' => 'http://meta.wildfirehq.org/Protocol/JsonStream/0.2',
+ 'X-Wf-1-Structure-1' => 'http://meta.firephp.org/Wildfire/Structure/FirePHP/FirebugConsole/0.1',
+ 'X-Wf-1-Plugin-1' => 'http://meta.firephp.org/Wildfire/Plugin/FirePHP/Library-FirePHPCore/0.3',
+ 'X-Wf-1-1-1-1' => 'test',
+ 'X-Wf-1-1-1-2' => 'test',
+ );
+
+ $expected2 = array(
+ 'X-Wf-1-1-1-3' => 'test',
+ 'X-Wf-1-1-1-4' => 'test',
+ );
+
+ $this->assertEquals($expected, $handler->getHeaders());
+ $this->assertEquals($expected2, $handler2->getHeaders());
+ }
+}
+
+class TestFirePHPHandler extends FirePHPHandler
+{
+ protected $headers = array();
+
+ public static function reset()
+ {
+ self::$initialized = false;
+ self::$sendHeaders = true;
+ self::$messageIndex = 1;
+ }
+
+ protected function sendHeader($header, $content)
+ {
+ $this->headers[$header] = $content;
+ }
+
+ public function getHeaders()
+ {
+ return $this->headers;
+ }
+}
diff --git a/vendor/monolog/monolog/tests/Monolog/Handler/FleepHookHandlerTest.php b/vendor/monolog/monolog/tests/Monolog/Handler/FleepHookHandlerTest.php
new file mode 100644
index 00000000..91cdd312
--- /dev/null
+++ b/vendor/monolog/monolog/tests/Monolog/Handler/FleepHookHandlerTest.php
@@ -0,0 +1,85 @@
+<?php
+
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Handler;
+
+use Monolog\Formatter\LineFormatter;
+use Monolog\Logger;
+use Monolog\TestCase;
+
+/**
+ * @coversDefaultClass \Monolog\Handler\FleepHookHandler
+ */
+class FleepHookHandlerTest extends TestCase
+{
+ /**
+ * Default token to use in tests
+ */
+ const TOKEN = '123abc';
+
+ /**
+ * @var FleepHookHandler
+ */
+ private $handler;
+
+ public function setUp()
+ {
+ parent::setUp();
+
+ if (!extension_loaded('openssl')) {
+ $this->markTestSkipped('This test requires openssl extension to run');
+ }
+
+ // Create instances of the handler and logger for convenience
+ $this->handler = new FleepHookHandler(self::TOKEN);
+ }
+
+ /**
+ * @covers ::__construct
+ */
+ public function testConstructorSetsExpectedDefaults()
+ {
+ $this->assertEquals(Logger::DEBUG, $this->handler->getLevel());
+ $this->assertEquals(true, $this->handler->getBubble());
+ }
+
+ /**
+ * @covers ::getDefaultFormatter
+ */
+ public function testHandlerUsesLineFormatterWhichIgnoresEmptyArrays()
+ {
+ $record = array(
+ 'message' => 'msg',
+ 'context' => array(),
+ 'level' => Logger::DEBUG,
+ 'level_name' => Logger::getLevelName(Logger::DEBUG),
+ 'channel' => 'channel',
+ 'datetime' => new \DateTime(),
+ 'extra' => array(),
+ );
+
+ $expectedFormatter = new LineFormatter(null, null, true, true);
+ $expected = $expectedFormatter->format($record);
+
+ $handlerFormatter = $this->handler->getFormatter();
+ $actual = $handlerFormatter->format($record);
+
+ $this->assertEquals($expected, $actual, 'Empty context and extra arrays should not be rendered');
+ }
+
+ /**
+ * @covers ::__construct
+ */
+ public function testConnectionStringisConstructedCorrectly()
+ {
+ $this->assertEquals('ssl://' . FleepHookHandler::FLEEP_HOST . ':443', $this->handler->getConnectionString());
+ }
+}
diff --git a/vendor/monolog/monolog/tests/Monolog/Handler/FlowdockHandlerTest.php b/vendor/monolog/monolog/tests/Monolog/Handler/FlowdockHandlerTest.php
new file mode 100644
index 00000000..4b120d51
--- /dev/null
+++ b/vendor/monolog/monolog/tests/Monolog/Handler/FlowdockHandlerTest.php
@@ -0,0 +1,88 @@
+<?php
+
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Handler;
+
+use Monolog\Formatter\FlowdockFormatter;
+use Monolog\TestCase;
+use Monolog\Logger;
+
+/**
+ * @author Dominik Liebler <liebler.dominik@gmail.com>
+ * @see https://www.hipchat.com/docs/api
+ */
+class FlowdockHandlerTest extends TestCase
+{
+ /**
+ * @var resource
+ */
+ private $res;
+
+ /**
+ * @var FlowdockHandler
+ */
+ private $handler;
+
+ public function setUp()
+ {
+ if (!extension_loaded('openssl')) {
+ $this->markTestSkipped('This test requires openssl to run');
+ }
+ }
+
+ public function testWriteHeader()
+ {
+ $this->createHandler();
+ $this->handler->handle($this->getRecord(Logger::CRITICAL, 'test1'));
+ fseek($this->res, 0);
+ $content = fread($this->res, 1024);
+
+ $this->assertRegexp('/POST \/v1\/messages\/team_inbox\/.* HTTP\/1.1\\r\\nHost: api.flowdock.com\\r\\nContent-Type: application\/json\\r\\nContent-Length: \d{2,4}\\r\\n\\r\\n/', $content);
+
+ return $content;
+ }
+
+ /**
+ * @depends testWriteHeader
+ */
+ public function testWriteContent($content)
+ {
+ $this->assertRegexp('/"source":"test_source"/', $content);
+ $this->assertRegexp('/"from_address":"source@test\.com"/', $content);
+ }
+
+ private function createHandler($token = 'myToken')
+ {
+ $constructorArgs = array($token, Logger::DEBUG);
+ $this->res = fopen('php://memory', 'a');
+ $this->handler = $this->getMock(
+ '\Monolog\Handler\FlowdockHandler',
+ array('fsockopen', 'streamSetTimeout', 'closeSocket'),
+ $constructorArgs
+ );
+
+ $reflectionProperty = new \ReflectionProperty('\Monolog\Handler\SocketHandler', 'connectionString');
+ $reflectionProperty->setAccessible(true);
+ $reflectionProperty->setValue($this->handler, 'localhost:1234');
+
+ $this->handler->expects($this->any())
+ ->method('fsockopen')
+ ->will($this->returnValue($this->res));
+ $this->handler->expects($this->any())
+ ->method('streamSetTimeout')
+ ->will($this->returnValue(true));
+ $this->handler->expects($this->any())
+ ->method('closeSocket')
+ ->will($this->returnValue(true));
+
+ $this->handler->setFormatter(new FlowdockFormatter('test_source', 'source@test.com'));
+ }
+}
diff --git a/vendor/monolog/monolog/tests/Monolog/Handler/GelfHandlerLegacyTest.php b/vendor/monolog/monolog/tests/Monolog/Handler/GelfHandlerLegacyTest.php
new file mode 100644
index 00000000..9d007b13
--- /dev/null
+++ b/vendor/monolog/monolog/tests/Monolog/Handler/GelfHandlerLegacyTest.php
@@ -0,0 +1,95 @@
+<?php
+
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Handler;
+
+use Gelf\Message;
+use Monolog\TestCase;
+use Monolog\Logger;
+use Monolog\Formatter\GelfMessageFormatter;
+
+class GelfHandlerLegacyTest extends TestCase
+{
+ public function setUp()
+ {
+ if (!class_exists('Gelf\MessagePublisher') || !class_exists('Gelf\Message')) {
+ $this->markTestSkipped("mlehner/gelf-php not installed");
+ }
+
+ require_once __DIR__ . '/GelfMockMessagePublisher.php';
+ }
+
+ /**
+ * @covers Monolog\Handler\GelfHandler::__construct
+ */
+ public function testConstruct()
+ {
+ $handler = new GelfHandler($this->getMessagePublisher());
+ $this->assertInstanceOf('Monolog\Handler\GelfHandler', $handler);
+ }
+
+ protected function getHandler($messagePublisher)
+ {
+ $handler = new GelfHandler($messagePublisher);
+
+ return $handler;
+ }
+
+ protected function getMessagePublisher()
+ {
+ return new GelfMockMessagePublisher('localhost');
+ }
+
+ public function testDebug()
+ {
+ $messagePublisher = $this->getMessagePublisher();
+ $handler = $this->getHandler($messagePublisher);
+
+ $record = $this->getRecord(Logger::DEBUG, "A test debug message");
+ $handler->handle($record);
+
+ $this->assertEquals(7, $messagePublisher->lastMessage->getLevel());
+ $this->assertEquals('test', $messagePublisher->lastMessage->getFacility());
+ $this->assertEquals($record['message'], $messagePublisher->lastMessage->getShortMessage());
+ $this->assertEquals(null, $messagePublisher->lastMessage->getFullMessage());
+ }
+
+ public function testWarning()
+ {
+ $messagePublisher = $this->getMessagePublisher();
+ $handler = $this->getHandler($messagePublisher);
+
+ $record = $this->getRecord(Logger::WARNING, "A test warning message");
+ $handler->handle($record);
+
+ $this->assertEquals(4, $messagePublisher->lastMessage->getLevel());
+ $this->assertEquals('test', $messagePublisher->lastMessage->getFacility());
+ $this->assertEquals($record['message'], $messagePublisher->lastMessage->getShortMessage());
+ $this->assertEquals(null, $messagePublisher->lastMessage->getFullMessage());
+ }
+
+ public function testInjectedGelfMessageFormatter()
+ {
+ $messagePublisher = $this->getMessagePublisher();
+ $handler = $this->getHandler($messagePublisher);
+
+ $handler->setFormatter(new GelfMessageFormatter('mysystem', 'EXT', 'CTX'));
+
+ $record = $this->getRecord(Logger::WARNING, "A test warning message");
+ $record['extra']['blarg'] = 'yep';
+ $record['context']['from'] = 'logger';
+ $handler->handle($record);
+
+ $this->assertEquals('mysystem', $messagePublisher->lastMessage->getHost());
+ $this->assertArrayHasKey('_EXTblarg', $messagePublisher->lastMessage->toArray());
+ $this->assertArrayHasKey('_CTXfrom', $messagePublisher->lastMessage->toArray());
+ }
+}
diff --git a/vendor/monolog/monolog/tests/Monolog/Handler/GelfHandlerTest.php b/vendor/monolog/monolog/tests/Monolog/Handler/GelfHandlerTest.php
new file mode 100644
index 00000000..8cdd64f4
--- /dev/null
+++ b/vendor/monolog/monolog/tests/Monolog/Handler/GelfHandlerTest.php
@@ -0,0 +1,117 @@
+<?php
+
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Handler;
+
+use Gelf\Message;
+use Monolog\TestCase;
+use Monolog\Logger;
+use Monolog\Formatter\GelfMessageFormatter;
+
+class GelfHandlerTest extends TestCase
+{
+ public function setUp()
+ {
+ if (!class_exists('Gelf\Publisher') || !class_exists('Gelf\Message')) {
+ $this->markTestSkipped("graylog2/gelf-php not installed");
+ }
+ }
+
+ /**
+ * @covers Monolog\Handler\GelfHandler::__construct
+ */
+ public function testConstruct()
+ {
+ $handler = new GelfHandler($this->getMessagePublisher());
+ $this->assertInstanceOf('Monolog\Handler\GelfHandler', $handler);
+ }
+
+ protected function getHandler($messagePublisher)
+ {
+ $handler = new GelfHandler($messagePublisher);
+
+ return $handler;
+ }
+
+ protected function getMessagePublisher()
+ {
+ return $this->getMock('Gelf\Publisher', array('publish'), array(), '', false);
+ }
+
+ public function testDebug()
+ {
+ $record = $this->getRecord(Logger::DEBUG, "A test debug message");
+ $expectedMessage = new Message();
+ $expectedMessage
+ ->setLevel(7)
+ ->setFacility("test")
+ ->setShortMessage($record['message'])
+ ->setTimestamp($record['datetime'])
+ ;
+
+ $messagePublisher = $this->getMessagePublisher();
+ $messagePublisher->expects($this->once())
+ ->method('publish')
+ ->with($expectedMessage);
+
+ $handler = $this->getHandler($messagePublisher);
+
+ $handler->handle($record);
+ }
+
+ public function testWarning()
+ {
+ $record = $this->getRecord(Logger::WARNING, "A test warning message");
+ $expectedMessage = new Message();
+ $expectedMessage
+ ->setLevel(4)
+ ->setFacility("test")
+ ->setShortMessage($record['message'])
+ ->setTimestamp($record['datetime'])
+ ;
+
+ $messagePublisher = $this->getMessagePublisher();
+ $messagePublisher->expects($this->once())
+ ->method('publish')
+ ->with($expectedMessage);
+
+ $handler = $this->getHandler($messagePublisher);
+
+ $handler->handle($record);
+ }
+
+ public function testInjectedGelfMessageFormatter()
+ {
+ $record = $this->getRecord(Logger::WARNING, "A test warning message");
+ $record['extra']['blarg'] = 'yep';
+ $record['context']['from'] = 'logger';
+
+ $expectedMessage = new Message();
+ $expectedMessage
+ ->setLevel(4)
+ ->setFacility("test")
+ ->setHost("mysystem")
+ ->setShortMessage($record['message'])
+ ->setTimestamp($record['datetime'])
+ ->setAdditional("EXTblarg", 'yep')
+ ->setAdditional("CTXfrom", 'logger')
+ ;
+
+ $messagePublisher = $this->getMessagePublisher();
+ $messagePublisher->expects($this->once())
+ ->method('publish')
+ ->with($expectedMessage);
+
+ $handler = $this->getHandler($messagePublisher);
+ $handler->setFormatter(new GelfMessageFormatter('mysystem', 'EXT', 'CTX'));
+ $handler->handle($record);
+ }
+}
diff --git a/vendor/monolog/monolog/tests/Monolog/Handler/GelfMockMessagePublisher.php b/vendor/monolog/monolog/tests/Monolog/Handler/GelfMockMessagePublisher.php
new file mode 100644
index 00000000..873d92fb
--- /dev/null
+++ b/vendor/monolog/monolog/tests/Monolog/Handler/GelfMockMessagePublisher.php
@@ -0,0 +1,25 @@
+<?php
+
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Handler;
+
+use Gelf\MessagePublisher;
+use Gelf\Message;
+
+class GelfMockMessagePublisher extends MessagePublisher
+{
+ public function publish(Message $message)
+ {
+ $this->lastMessage = $message;
+ }
+
+ public $lastMessage = null;
+}
diff --git a/vendor/monolog/monolog/tests/Monolog/Handler/GroupHandlerTest.php b/vendor/monolog/monolog/tests/Monolog/Handler/GroupHandlerTest.php
new file mode 100644
index 00000000..c6298a6e
--- /dev/null
+++ b/vendor/monolog/monolog/tests/Monolog/Handler/GroupHandlerTest.php
@@ -0,0 +1,89 @@
+<?php
+
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Handler;
+
+use Monolog\TestCase;
+use Monolog\Logger;
+
+class GroupHandlerTest extends TestCase
+{
+ /**
+ * @covers Monolog\Handler\GroupHandler::__construct
+ * @expectedException InvalidArgumentException
+ */
+ public function testConstructorOnlyTakesHandler()
+ {
+ new GroupHandler(array(new TestHandler(), "foo"));
+ }
+
+ /**
+ * @covers Monolog\Handler\GroupHandler::__construct
+ * @covers Monolog\Handler\GroupHandler::handle
+ */
+ public function testHandle()
+ {
+ $testHandlers = array(new TestHandler(), new TestHandler());
+ $handler = new GroupHandler($testHandlers);
+ $handler->handle($this->getRecord(Logger::DEBUG));
+ $handler->handle($this->getRecord(Logger::INFO));
+ foreach ($testHandlers as $test) {
+ $this->assertTrue($test->hasDebugRecords());
+ $this->assertTrue($test->hasInfoRecords());
+ $this->assertTrue(count($test->getRecords()) === 2);
+ }
+ }
+
+ /**
+ * @covers Monolog\Handler\GroupHandler::handleBatch
+ */
+ public function testHandleBatch()
+ {
+ $testHandlers = array(new TestHandler(), new TestHandler());
+ $handler = new GroupHandler($testHandlers);
+ $handler->handleBatch(array($this->getRecord(Logger::DEBUG), $this->getRecord(Logger::INFO)));
+ foreach ($testHandlers as $test) {
+ $this->assertTrue($test->hasDebugRecords());
+ $this->assertTrue($test->hasInfoRecords());
+ $this->assertTrue(count($test->getRecords()) === 2);
+ }
+ }
+
+ /**
+ * @covers Monolog\Handler\GroupHandler::isHandling
+ */
+ public function testIsHandling()
+ {
+ $testHandlers = array(new TestHandler(Logger::ERROR), new TestHandler(Logger::WARNING));
+ $handler = new GroupHandler($testHandlers);
+ $this->assertTrue($handler->isHandling($this->getRecord(Logger::ERROR)));
+ $this->assertTrue($handler->isHandling($this->getRecord(Logger::WARNING)));
+ $this->assertFalse($handler->isHandling($this->getRecord(Logger::DEBUG)));
+ }
+
+ /**
+ * @covers Monolog\Handler\GroupHandler::handle
+ */
+ public function testHandleUsesProcessors()
+ {
+ $test = new TestHandler();
+ $handler = new GroupHandler(array($test));
+ $handler->pushProcessor(function ($record) {
+ $record['extra']['foo'] = true;
+
+ return $record;
+ });
+ $handler->handle($this->getRecord(Logger::WARNING));
+ $this->assertTrue($test->hasWarningRecords());
+ $records = $test->getRecords();
+ $this->assertTrue($records[0]['extra']['foo']);
+ }
+}
diff --git a/vendor/monolog/monolog/tests/Monolog/Handler/HipChatHandlerTest.php b/vendor/monolog/monolog/tests/Monolog/Handler/HipChatHandlerTest.php
new file mode 100644
index 00000000..ff773c98
--- /dev/null
+++ b/vendor/monolog/monolog/tests/Monolog/Handler/HipChatHandlerTest.php
@@ -0,0 +1,240 @@
+<?php
+
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Handler;
+
+use Monolog\TestCase;
+use Monolog\Logger;
+
+/**
+ * @author Rafael Dohms <rafael@doh.ms>
+ * @see https://www.hipchat.com/docs/api
+ */
+class HipChatHandlerTest extends TestCase
+{
+ private $res;
+ private $handler;
+
+ public function testWriteHeader()
+ {
+ $this->createHandler();
+ $this->handler->handle($this->getRecord(Logger::CRITICAL, 'test1'));
+ fseek($this->res, 0);
+ $content = fread($this->res, 1024);
+
+ $this->assertRegexp('/POST \/v1\/rooms\/message\?format=json&auth_token=.* HTTP\/1.1\\r\\nHost: api.hipchat.com\\r\\nContent-Type: application\/x-www-form-urlencoded\\r\\nContent-Length: \d{2,4}\\r\\n\\r\\n/', $content);
+
+ return $content;
+ }
+
+ public function testWriteCustomHostHeader()
+ {
+ $this->createHandler('myToken', 'room1', 'Monolog', true, 'hipchat.foo.bar');
+ $this->handler->handle($this->getRecord(Logger::CRITICAL, 'test1'));
+ fseek($this->res, 0);
+ $content = fread($this->res, 1024);
+
+ $this->assertRegexp('/POST \/v1\/rooms\/message\?format=json&auth_token=.* HTTP\/1.1\\r\\nHost: hipchat.foo.bar\\r\\nContent-Type: application\/x-www-form-urlencoded\\r\\nContent-Length: \d{2,4}\\r\\n\\r\\n/', $content);
+
+ return $content;
+ }
+
+ public function testWriteV2() {
+ $this->createHandler('myToken', 'room1', 'Monolog', false, 'hipchat.foo.bar', 'v2');
+ $this->handler->handle($this->getRecord(Logger::CRITICAL, 'test1'));
+ fseek($this->res, 0);
+ $content = fread($this->res, 1024);
+
+ $this->assertRegexp('/POST \/v2\/room\/room1\/notification\?auth_token=.* HTTP\/1.1\\r\\nHost: hipchat.foo.bar\\r\\nContent-Type: application\/x-www-form-urlencoded\\r\\nContent-Length: \d{2,4}\\r\\n\\r\\n/', $content);
+
+ return $content;
+ }
+
+ public function testWriteV2Notify() {
+ $this->createHandler('myToken', 'room1', 'Monolog', true, 'hipchat.foo.bar', 'v2');
+ $this->handler->handle($this->getRecord(Logger::CRITICAL, 'test1'));
+ fseek($this->res, 0);
+ $content = fread($this->res, 1024);
+
+ $this->assertRegexp('/POST \/v2\/room\/room1\/notification\?auth_token=.* HTTP\/1.1\\r\\nHost: hipchat.foo.bar\\r\\nContent-Type: application\/x-www-form-urlencoded\\r\\nContent-Length: \d{2,4}\\r\\n\\r\\n/', $content);
+
+ return $content;
+ }
+
+ public function testRoomSpaces() {
+ $this->createHandler('myToken', 'room name', 'Monolog', false, 'hipchat.foo.bar', 'v2');
+ $this->handler->handle($this->getRecord(Logger::CRITICAL, 'test1'));
+ fseek($this->res, 0);
+ $content = fread($this->res, 1024);
+
+ $this->assertRegexp('/POST \/v2\/room\/room%20name\/notification\?auth_token=.* HTTP\/1.1\\r\\nHost: hipchat.foo.bar\\r\\nContent-Type: application\/x-www-form-urlencoded\\r\\nContent-Length: \d{2,4}\\r\\n\\r\\n/', $content);
+
+ return $content;
+ }
+
+ /**
+ * @depends testWriteHeader
+ */
+ public function testWriteContent($content)
+ {
+ $this->assertRegexp('/notify=0&message=test1&message_format=text&color=red&room_id=room1&from=Monolog$/', $content);
+ }
+
+ /**
+ * @depends testWriteCustomHostHeader
+ */
+ public function testWriteContentNotify($content)
+ {
+ $this->assertRegexp('/notify=1&message=test1&message_format=text&color=red&room_id=room1&from=Monolog$/', $content);
+ }
+
+ /**
+ * @depends testWriteV2
+ */
+ public function testWriteContentV2($content)
+ {
+ $this->assertRegexp('/notify=false&message=test1&message_format=text&color=red$/', $content);
+ }
+
+ /**
+ * @depends testWriteV2Notify
+ */
+ public function testWriteContentV2Notify($content)
+ {
+ $this->assertRegexp('/notify=true&message=test1&message_format=text&color=red$/', $content);
+ }
+
+ public function testWriteWithComplexMessage()
+ {
+ $this->createHandler();
+ $this->handler->handle($this->getRecord(Logger::CRITICAL, 'Backup of database "example" finished in 16 minutes.'));
+ fseek($this->res, 0);
+ $content = fread($this->res, 1024);
+
+ $this->assertRegexp('/message=Backup\+of\+database\+%22example%22\+finished\+in\+16\+minutes\./', $content);
+ }
+
+ /**
+ * @dataProvider provideLevelColors
+ */
+ public function testWriteWithErrorLevelsAndColors($level, $expectedColor)
+ {
+ $this->createHandler();
+ $this->handler->handle($this->getRecord($level, 'Backup of database "example" finished in 16 minutes.'));
+ fseek($this->res, 0);
+ $content = fread($this->res, 1024);
+
+ $this->assertRegexp('/color='.$expectedColor.'/', $content);
+ }
+
+ public function provideLevelColors()
+ {
+ return array(
+ array(Logger::DEBUG, 'gray'),
+ array(Logger::INFO, 'green'),
+ array(Logger::WARNING, 'yellow'),
+ array(Logger::ERROR, 'red'),
+ array(Logger::CRITICAL, 'red'),
+ array(Logger::ALERT, 'red'),
+ array(Logger::EMERGENCY,'red'),
+ array(Logger::NOTICE, 'green'),
+ );
+ }
+
+ /**
+ * @dataProvider provideBatchRecords
+ */
+ public function testHandleBatch($records, $expectedColor)
+ {
+ $this->createHandler();
+
+ $this->handler->handleBatch($records);
+
+ fseek($this->res, 0);
+ $content = fread($this->res, 1024);
+
+ $this->assertRegexp('/color='.$expectedColor.'/', $content);
+ }
+
+ public function provideBatchRecords()
+ {
+ return array(
+ array(
+ array(
+ array('level' => Logger::WARNING, 'message' => 'Oh bugger!', 'level_name' => 'warning', 'datetime' => new \DateTime()),
+ array('level' => Logger::NOTICE, 'message' => 'Something noticeable happened.', 'level_name' => 'notice', 'datetime' => new \DateTime()),
+ array('level' => Logger::CRITICAL, 'message' => 'Everything is broken!', 'level_name' => 'critical', 'datetime' => new \DateTime())
+ ),
+ 'red',
+ ),
+ array(
+ array(
+ array('level' => Logger::WARNING, 'message' => 'Oh bugger!', 'level_name' => 'warning', 'datetime' => new \DateTime()),
+ array('level' => Logger::NOTICE, 'message' => 'Something noticeable happened.', 'level_name' => 'notice', 'datetime' => new \DateTime()),
+ ),
+ 'yellow',
+ ),
+ array(
+ array(
+ array('level' => Logger::DEBUG, 'message' => 'Just debugging.', 'level_name' => 'debug', 'datetime' => new \DateTime()),
+ array('level' => Logger::NOTICE, 'message' => 'Something noticeable happened.', 'level_name' => 'notice', 'datetime' => new \DateTime()),
+ ),
+ 'green',
+ ),
+ array(
+ array(
+ array('level' => Logger::DEBUG, 'message' => 'Just debugging.', 'level_name' => 'debug', 'datetime' => new \DateTime()),
+ ),
+ 'gray',
+ ),
+ );
+ }
+
+ private function createHandler($token = 'myToken', $room = 'room1', $name = 'Monolog', $notify = false, $host = 'api.hipchat.com', $version = 'v1')
+ {
+ $constructorArgs = array($token, $room, $name, $notify, Logger::DEBUG, true, true, 'text', $host, $version);
+ $this->res = fopen('php://memory', 'a');
+ $this->handler = $this->getMock(
+ '\Monolog\Handler\HipChatHandler',
+ array('fsockopen', 'streamSetTimeout', 'closeSocket'),
+ $constructorArgs
+ );
+
+ $reflectionProperty = new \ReflectionProperty('\Monolog\Handler\SocketHandler', 'connectionString');
+ $reflectionProperty->setAccessible(true);
+ $reflectionProperty->setValue($this->handler, 'localhost:1234');
+
+ $this->handler->expects($this->any())
+ ->method('fsockopen')
+ ->will($this->returnValue($this->res));
+ $this->handler->expects($this->any())
+ ->method('streamSetTimeout')
+ ->will($this->returnValue(true));
+ $this->handler->expects($this->any())
+ ->method('closeSocket')
+ ->will($this->returnValue(true));
+
+ $this->handler->setFormatter($this->getIdentityFormatter());
+ }
+
+ /**
+ * @expectedException InvalidArgumentException
+ */
+ public function testCreateWithTooLongName()
+ {
+ $hipChatHandler = new \Monolog\Handler\HipChatHandler('token', 'room', 'SixteenCharsHere');
+ }
+
+ public function testCreateWithTooLongNameV2() {
+ // creating a handler with too long of a name but using the v2 api doesn't matter.
+ $hipChatHandler = new \Monolog\Handler\HipChatHandler('token', 'room', 'SixteenCharsHere', false, Logger::CRITICAL, true, true, 'test', 'api.hipchat.com', 'v2');
+ }
+}
diff --git a/vendor/monolog/monolog/tests/Monolog/Handler/LogEntriesHandlerTest.php b/vendor/monolog/monolog/tests/Monolog/Handler/LogEntriesHandlerTest.php
new file mode 100644
index 00000000..7af60be8
--- /dev/null
+++ b/vendor/monolog/monolog/tests/Monolog/Handler/LogEntriesHandlerTest.php
@@ -0,0 +1,84 @@
+<?php
+
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Handler;
+
+use Monolog\TestCase;
+use Monolog\Logger;
+
+/**
+ * @author Robert Kaufmann III <rok3@rok3.me>
+ */
+class LogEntriesHandlerTest extends TestCase
+{
+ /**
+ * @var resource
+ */
+ private $res;
+
+ /**
+ * @var LogEntriesHandler
+ */
+ private $handler;
+
+ public function testWriteContent()
+ {
+ $this->createHandler();
+ $this->handler->handle($this->getRecord(Logger::CRITICAL, 'Critical write test'));
+
+ fseek($this->res, 0);
+ $content = fread($this->res, 1024);
+
+ $this->assertRegexp('/testToken \[\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}\] test.CRITICAL: Critical write test/', $content);
+ }
+
+ public function testWriteBatchContent()
+ {
+ $records = array(
+ $this->getRecord(),
+ $this->getRecord(),
+ $this->getRecord()
+ );
+ $this->createHandler();
+ $this->handler->handleBatch($records);
+
+ fseek($this->res, 0);
+ $content = fread($this->res, 1024);
+
+ $this->assertRegexp('/(testToken \[\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}\] .* \[\] \[\]\n){3}/', $content);
+ }
+
+ private function createHandler()
+ {
+ $useSSL = extension_loaded('openssl');
+ $args = array('testToken', $useSSL, Logger::DEBUG, true);
+ $this->res = fopen('php://memory', 'a');
+ $this->handler = $this->getMock(
+ '\Monolog\Handler\LogEntriesHandler',
+ array('fsockopen', 'streamSetTimeout', 'closeSocket'),
+ $args
+ );
+
+ $reflectionProperty = new \ReflectionProperty('\Monolog\Handler\SocketHandler', 'connectionString');
+ $reflectionProperty->setAccessible(true);
+ $reflectionProperty->setValue($this->handler, 'localhost:1234');
+
+ $this->handler->expects($this->any())
+ ->method('fsockopen')
+ ->will($this->returnValue($this->res));
+ $this->handler->expects($this->any())
+ ->method('streamSetTimeout')
+ ->will($this->returnValue(true));
+ $this->handler->expects($this->any())
+ ->method('closeSocket')
+ ->will($this->returnValue(true));
+ }
+}
diff --git a/vendor/monolog/monolog/tests/Monolog/Handler/MailHandlerTest.php b/vendor/monolog/monolog/tests/Monolog/Handler/MailHandlerTest.php
new file mode 100644
index 00000000..6754f3d6
--- /dev/null
+++ b/vendor/monolog/monolog/tests/Monolog/Handler/MailHandlerTest.php
@@ -0,0 +1,75 @@
+<?php
+
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Handler;
+
+use Monolog\Logger;
+use Monolog\TestCase;
+
+class MailHandlerTest extends TestCase
+{
+ /**
+ * @covers Monolog\Handler\MailHandler::handleBatch
+ */
+ public function testHandleBatch()
+ {
+ $formatter = $this->getMock('Monolog\\Formatter\\FormatterInterface');
+ $formatter->expects($this->once())
+ ->method('formatBatch'); // Each record is formatted
+
+ $handler = $this->getMockForAbstractClass('Monolog\\Handler\\MailHandler');
+ $handler->expects($this->once())
+ ->method('send');
+ $handler->expects($this->never())
+ ->method('write'); // write is for individual records
+
+ $handler->setFormatter($formatter);
+
+ $handler->handleBatch($this->getMultipleRecords());
+ }
+
+ /**
+ * @covers Monolog\Handler\MailHandler::handleBatch
+ */
+ public function testHandleBatchNotSendsMailIfMessagesAreBelowLevel()
+ {
+ $records = array(
+ $this->getRecord(Logger::DEBUG, 'debug message 1'),
+ $this->getRecord(Logger::DEBUG, 'debug message 2'),
+ $this->getRecord(Logger::INFO, 'information'),
+ );
+
+ $handler = $this->getMockForAbstractClass('Monolog\\Handler\\MailHandler');
+ $handler->expects($this->never())
+ ->method('send');
+ $handler->setLevel(Logger::ERROR);
+
+ $handler->handleBatch($records);
+ }
+
+ /**
+ * @covers Monolog\Handler\MailHandler::write
+ */
+ public function testHandle()
+ {
+ $handler = $this->getMockForAbstractClass('Monolog\\Handler\\MailHandler');
+
+ $record = $this->getRecord();
+ $records = array($record);
+ $records[0]['formatted'] = '['.$record['datetime']->format('Y-m-d H:i:s').'] test.WARNING: test [] []'."\n";
+
+ $handler->expects($this->once())
+ ->method('send')
+ ->with($records[0]['formatted'], $records);
+
+ $handler->handle($record);
+ }
+}
diff --git a/vendor/monolog/monolog/tests/Monolog/Handler/MockRavenClient.php b/vendor/monolog/monolog/tests/Monolog/Handler/MockRavenClient.php
new file mode 100644
index 00000000..a0833225
--- /dev/null
+++ b/vendor/monolog/monolog/tests/Monolog/Handler/MockRavenClient.php
@@ -0,0 +1,27 @@
+<?php
+
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Handler;
+
+use Raven_Client;
+
+class MockRavenClient extends Raven_Client
+{
+ public function capture($data, $stack, $vars = null)
+ {
+ $data = array_merge($this->get_user_data(), $data);
+ $this->lastData = $data;
+ $this->lastStack = $stack;
+ }
+
+ public $lastData;
+ public $lastStack;
+}
diff --git a/vendor/monolog/monolog/tests/Monolog/Handler/MongoDBHandlerTest.php b/vendor/monolog/monolog/tests/Monolog/Handler/MongoDBHandlerTest.php
new file mode 100644
index 00000000..0fdef63a
--- /dev/null
+++ b/vendor/monolog/monolog/tests/Monolog/Handler/MongoDBHandlerTest.php
@@ -0,0 +1,65 @@
+<?php
+
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Handler;
+
+use Monolog\TestCase;
+use Monolog\Logger;
+
+class MongoDBHandlerTest extends TestCase
+{
+ /**
+ * @expectedException InvalidArgumentException
+ */
+ public function testConstructorShouldThrowExceptionForInvalidMongo()
+ {
+ new MongoDBHandler(new \stdClass(), 'DB', 'Collection');
+ }
+
+ public function testHandle()
+ {
+ $mongo = $this->getMock('Mongo', array('selectCollection'), array(), '', false);
+ $collection = $this->getMock('stdClass', array('save'));
+
+ $mongo->expects($this->once())
+ ->method('selectCollection')
+ ->with('DB', 'Collection')
+ ->will($this->returnValue($collection));
+
+ $record = $this->getRecord(Logger::WARNING, 'test', array('data' => new \stdClass, 'foo' => 34));
+
+ $expected = array(
+ 'message' => 'test',
+ 'context' => array('data' => '[object] (stdClass: {})', 'foo' => 34),
+ 'level' => Logger::WARNING,
+ 'level_name' => 'WARNING',
+ 'channel' => 'test',
+ 'datetime' => $record['datetime']->format('Y-m-d H:i:s'),
+ 'extra' => array(),
+ );
+
+ $collection->expects($this->once())
+ ->method('save')
+ ->with($expected);
+
+ $handler = new MongoDBHandler($mongo, 'DB', 'Collection');
+ $handler->handle($record);
+ }
+}
+
+if (!class_exists('Mongo')) {
+ class Mongo
+ {
+ public function selectCollection()
+ {
+ }
+ }
+}
diff --git a/vendor/monolog/monolog/tests/Monolog/Handler/NativeMailerHandlerTest.php b/vendor/monolog/monolog/tests/Monolog/Handler/NativeMailerHandlerTest.php
new file mode 100644
index 00000000..c2553ee4
--- /dev/null
+++ b/vendor/monolog/monolog/tests/Monolog/Handler/NativeMailerHandlerTest.php
@@ -0,0 +1,61 @@
+<?php
+
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Handler;
+
+use Monolog\TestCase;
+
+class NativeMailerHandlerTest extends TestCase
+{
+ /**
+ * @expectedException InvalidArgumentException
+ */
+ public function testConstructorHeaderInjection()
+ {
+ $mailer = new NativeMailerHandler('spammer@example.org', 'dear victim', "receiver@example.org\r\nFrom: faked@attacker.org");
+ }
+
+ /**
+ * @expectedException InvalidArgumentException
+ */
+ public function testSetterHeaderInjection()
+ {
+ $mailer = new NativeMailerHandler('spammer@example.org', 'dear victim', 'receiver@example.org');
+ $mailer->addHeader("Content-Type: text/html\r\nFrom: faked@attacker.org");
+ }
+
+ /**
+ * @expectedException InvalidArgumentException
+ */
+ public function testSetterArrayHeaderInjection()
+ {
+ $mailer = new NativeMailerHandler('spammer@example.org', 'dear victim', 'receiver@example.org');
+ $mailer->addHeader(array("Content-Type: text/html\r\nFrom: faked@attacker.org"));
+ }
+
+ /**
+ * @expectedException InvalidArgumentException
+ */
+ public function testSetterContentTypeInjection()
+ {
+ $mailer = new NativeMailerHandler('spammer@example.org', 'dear victim', 'receiver@example.org');
+ $mailer->setContentType("text/html\r\nFrom: faked@attacker.org");
+ }
+
+ /**
+ * @expectedException InvalidArgumentException
+ */
+ public function testSetterEncodingInjection()
+ {
+ $mailer = new NativeMailerHandler('spammer@example.org', 'dear victim', 'receiver@example.org');
+ $mailer->setEncoding("utf-8\r\nFrom: faked@attacker.org");
+ }
+}
diff --git a/vendor/monolog/monolog/tests/Monolog/Handler/NewRelicHandlerTest.php b/vendor/monolog/monolog/tests/Monolog/Handler/NewRelicHandlerTest.php
new file mode 100644
index 00000000..4eda6155
--- /dev/null
+++ b/vendor/monolog/monolog/tests/Monolog/Handler/NewRelicHandlerTest.php
@@ -0,0 +1,192 @@
+<?php
+
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Handler;
+
+use Monolog\TestCase;
+use Monolog\Logger;
+
+class NewRelicHandlerTest extends TestCase
+{
+ public static $appname;
+ public static $customParameters;
+ public static $transactionName;
+
+ public function setUp()
+ {
+ self::$appname = null;
+ self::$customParameters = array();
+ self::$transactionName = null;
+ }
+
+ /**
+ * @expectedException Monolog\Handler\MissingExtensionException
+ */
+ public function testThehandlerThrowsAnExceptionIfTheNRExtensionIsNotLoaded()
+ {
+ $handler = new StubNewRelicHandlerWithoutExtension();
+ $handler->handle($this->getRecord(Logger::ERROR));
+ }
+
+ public function testThehandlerCanHandleTheRecord()
+ {
+ $handler = new StubNewRelicHandler();
+ $handler->handle($this->getRecord(Logger::ERROR));
+ }
+
+ public function testThehandlerCanAddContextParamsToTheNewRelicTrace()
+ {
+ $handler = new StubNewRelicHandler();
+ $handler->handle($this->getRecord(Logger::ERROR, 'log message', array('a' => 'b')));
+ $this->assertEquals(array('context_a' => 'b'), self::$customParameters);
+ }
+
+ public function testThehandlerCanAddExplodedContextParamsToTheNewRelicTrace()
+ {
+ $handler = new StubNewRelicHandler(Logger::ERROR, true, self::$appname, true);
+ $handler->handle($this->getRecord(
+ Logger::ERROR,
+ 'log message',
+ array('a' => array('key1' => 'value1', 'key2' => 'value2'))
+ ));
+ $this->assertEquals(
+ array('context_a_key1' => 'value1', 'context_a_key2' => 'value2'),
+ self::$customParameters
+ );
+ }
+
+ public function testThehandlerCanAddExtraParamsToTheNewRelicTrace()
+ {
+ $record = $this->getRecord(Logger::ERROR, 'log message');
+ $record['extra'] = array('c' => 'd');
+
+ $handler = new StubNewRelicHandler();
+ $handler->handle($record);
+
+ $this->assertEquals(array('extra_c' => 'd'), self::$customParameters);
+ }
+
+ public function testThehandlerCanAddExplodedExtraParamsToTheNewRelicTrace()
+ {
+ $record = $this->getRecord(Logger::ERROR, 'log message');
+ $record['extra'] = array('c' => array('key1' => 'value1', 'key2' => 'value2'));
+
+ $handler = new StubNewRelicHandler(Logger::ERROR, true, self::$appname, true);
+ $handler->handle($record);
+
+ $this->assertEquals(
+ array('extra_c_key1' => 'value1', 'extra_c_key2' => 'value2'),
+ self::$customParameters
+ );
+ }
+
+ public function testThehandlerCanAddExtraContextAndParamsToTheNewRelicTrace()
+ {
+ $record = $this->getRecord(Logger::ERROR, 'log message', array('a' => 'b'));
+ $record['extra'] = array('c' => 'd');
+
+ $handler = new StubNewRelicHandler();
+ $handler->handle($record);
+
+ $expected = array(
+ 'context_a' => 'b',
+ 'extra_c' => 'd',
+ );
+
+ $this->assertEquals($expected, self::$customParameters);
+ }
+
+ public function testTheAppNameIsNullByDefault()
+ {
+ $handler = new StubNewRelicHandler();
+ $handler->handle($this->getRecord(Logger::ERROR, 'log message'));
+
+ $this->assertEquals(null, self::$appname);
+ }
+
+ public function testTheAppNameCanBeInjectedFromtheConstructor()
+ {
+ $handler = new StubNewRelicHandler(Logger::DEBUG, false, 'myAppName');
+ $handler->handle($this->getRecord(Logger::ERROR, 'log message'));
+
+ $this->assertEquals('myAppName', self::$appname);
+ }
+
+ public function testTheAppNameCanBeOverriddenFromEachLog()
+ {
+ $handler = new StubNewRelicHandler(Logger::DEBUG, false, 'myAppName');
+ $handler->handle($this->getRecord(Logger::ERROR, 'log message', array('appname' => 'logAppName')));
+
+ $this->assertEquals('logAppName', self::$appname);
+ }
+
+ public function testTheTransactionNameIsNullByDefault()
+ {
+ $handler = new StubNewRelicHandler();
+ $handler->handle($this->getRecord(Logger::ERROR, 'log message'));
+
+ $this->assertEquals(null, self::$transactionName);
+ }
+
+ public function testTheTransactionNameCanBeInjectedFromTheConstructor()
+ {
+ $handler = new StubNewRelicHandler(Logger::DEBUG, false, null, false, 'myTransaction');
+ $handler->handle($this->getRecord(Logger::ERROR, 'log message'));
+
+ $this->assertEquals('myTransaction', self::$transactionName);
+ }
+
+ public function testTheTransactionNameCanBeOverriddenFromEachLog()
+ {
+ $handler = new StubNewRelicHandler(Logger::DEBUG, false, null, false, 'myTransaction');
+ $handler->handle($this->getRecord(Logger::ERROR, 'log message', array('transaction_name' => 'logTransactName')));
+
+ $this->assertEquals('logTransactName', self::$transactionName);
+ }
+}
+
+class StubNewRelicHandlerWithoutExtension extends NewRelicHandler
+{
+ protected function isNewRelicEnabled()
+ {
+ return false;
+ }
+}
+
+class StubNewRelicHandler extends NewRelicHandler
+{
+ protected function isNewRelicEnabled()
+ {
+ return true;
+ }
+}
+
+function newrelic_notice_error()
+{
+ return true;
+}
+
+function newrelic_set_appname($appname)
+{
+ return NewRelicHandlerTest::$appname = $appname;
+}
+
+function newrelic_name_transaction($transactionName)
+{
+ return NewRelicHandlerTest::$transactionName = $transactionName;
+}
+
+function newrelic_add_custom_parameter($key, $value)
+{
+ NewRelicHandlerTest::$customParameters[$key] = $value;
+
+ return true;
+}
diff --git a/vendor/monolog/monolog/tests/Monolog/Handler/NullHandlerTest.php b/vendor/monolog/monolog/tests/Monolog/Handler/NullHandlerTest.php
new file mode 100644
index 00000000..292df78c
--- /dev/null
+++ b/vendor/monolog/monolog/tests/Monolog/Handler/NullHandlerTest.php
@@ -0,0 +1,33 @@
+<?php
+
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Handler;
+
+use Monolog\TestCase;
+use Monolog\Logger;
+
+/**
+ * @covers Monolog\Handler\NullHandler::handle
+ */
+class NullHandlerTest extends TestCase
+{
+ public function testHandle()
+ {
+ $handler = new NullHandler();
+ $this->assertTrue($handler->handle($this->getRecord()));
+ }
+
+ public function testHandleLowerLevelRecord()
+ {
+ $handler = new NullHandler(Logger::WARNING);
+ $this->assertFalse($handler->handle($this->getRecord(Logger::DEBUG)));
+ }
+}
diff --git a/vendor/monolog/monolog/tests/Monolog/Handler/PHPConsoleHandlerTest.php b/vendor/monolog/monolog/tests/Monolog/Handler/PHPConsoleHandlerTest.php
new file mode 100644
index 00000000..81684c5e
--- /dev/null
+++ b/vendor/monolog/monolog/tests/Monolog/Handler/PHPConsoleHandlerTest.php
@@ -0,0 +1,271 @@
+<?php
+
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Handler;
+
+use Exception;
+use Monolog\ErrorHandler;
+use Monolog\Logger;
+use Monolog\TestCase;
+use PhpConsole\Connector;
+use PhpConsole\Dispatcher\Debug as DebugDispatcher;
+use PhpConsole\Dispatcher\Errors as ErrorDispatcher;
+use PhpConsole\Handler;
+use PHPUnit_Framework_MockObject_MockObject;
+
+/**
+ * @covers Monolog\Handler\PHPConsoleHandler
+ * @author Sergey Barbushin https://www.linkedin.com/in/barbushin
+ */
+class PHPConsoleHandlerTest extends TestCase
+{
+
+ /** @var Connector|PHPUnit_Framework_MockObject_MockObject */
+ protected $connector;
+ /** @var DebugDispatcher|PHPUnit_Framework_MockObject_MockObject */
+ protected $debugDispatcher;
+ /** @var ErrorDispatcher|PHPUnit_Framework_MockObject_MockObject */
+ protected $errorDispatcher;
+
+ protected function setUp()
+ {
+ if (!class_exists('PhpConsole\Connector')) {
+ $this->markTestSkipped('PHP Console library not found. See https://github.com/barbushin/php-console#installation');
+ }
+ $this->connector = $this->initConnectorMock();
+
+ $this->debugDispatcher = $this->initDebugDispatcherMock($this->connector);
+ $this->connector->setDebugDispatcher($this->debugDispatcher);
+
+ $this->errorDispatcher = $this->initErrorDispatcherMock($this->connector);
+ $this->connector->setErrorsDispatcher($this->errorDispatcher);
+ }
+
+ protected function initDebugDispatcherMock(Connector $connector)
+ {
+ return $this->getMockBuilder('PhpConsole\Dispatcher\Debug')
+ ->disableOriginalConstructor()
+ ->setMethods(array('dispatchDebug'))
+ ->setConstructorArgs(array($connector, $connector->getDumper()))
+ ->getMock();
+ }
+
+ protected function initErrorDispatcherMock(Connector $connector)
+ {
+ return $this->getMockBuilder('PhpConsole\Dispatcher\Errors')
+ ->disableOriginalConstructor()
+ ->setMethods(array('dispatchError', 'dispatchException'))
+ ->setConstructorArgs(array($connector, $connector->getDumper()))
+ ->getMock();
+ }
+
+ protected function initConnectorMock()
+ {
+ $connector = $this->getMockBuilder('PhpConsole\Connector')
+ ->disableOriginalConstructor()
+ ->setMethods(array(
+ 'sendMessage',
+ 'onShutDown',
+ 'isActiveClient',
+ 'setSourcesBasePath',
+ 'setServerEncoding',
+ 'setPassword',
+ 'enableSslOnlyMode',
+ 'setAllowedIpMasks',
+ 'setHeadersLimit',
+ 'startEvalRequestsListener',
+ ))
+ ->getMock();
+
+ $connector->expects($this->any())
+ ->method('isActiveClient')
+ ->will($this->returnValue(true));
+
+ return $connector;
+ }
+
+ protected function getHandlerDefaultOption($name)
+ {
+ $handler = new PHPConsoleHandler(array(), $this->connector);
+ $options = $handler->getOptions();
+
+ return $options[$name];
+ }
+
+ protected function initLogger($handlerOptions = array(), $level = Logger::DEBUG)
+ {
+ return new Logger('test', array(
+ new PHPConsoleHandler($handlerOptions, $this->connector, $level)
+ ));
+ }
+
+ public function testInitWithDefaultConnector()
+ {
+ $handler = new PHPConsoleHandler();
+ $this->assertEquals(spl_object_hash(Connector::getInstance()), spl_object_hash($handler->getConnector()));
+ }
+
+ public function testInitWithCustomConnector()
+ {
+ $handler = new PHPConsoleHandler(array(), $this->connector);
+ $this->assertEquals(spl_object_hash($this->connector), spl_object_hash($handler->getConnector()));
+ }
+
+ public function testDebug()
+ {
+ $this->debugDispatcher->expects($this->once())->method('dispatchDebug')->with($this->equalTo('test'));
+ $this->initLogger()->addDebug('test');
+ }
+
+ public function testDebugContextInMessage()
+ {
+ $message = 'test';
+ $tag = 'tag';
+ $context = array($tag, 'custom' => mt_rand());
+ $expectedMessage = $message . ' ' . json_encode(array_slice($context, 1));
+ $this->debugDispatcher->expects($this->once())->method('dispatchDebug')->with(
+ $this->equalTo($expectedMessage),
+ $this->equalTo($tag)
+ );
+ $this->initLogger()->addDebug($message, $context);
+ }
+
+ public function testDebugTags($tagsContextKeys = null)
+ {
+ $expectedTags = mt_rand();
+ $logger = $this->initLogger($tagsContextKeys ? array('debugTagsKeysInContext' => $tagsContextKeys) : array());
+ if (!$tagsContextKeys) {
+ $tagsContextKeys = $this->getHandlerDefaultOption('debugTagsKeysInContext');
+ }
+ foreach ($tagsContextKeys as $key) {
+ $debugDispatcher = $this->initDebugDispatcherMock($this->connector);
+ $debugDispatcher->expects($this->once())->method('dispatchDebug')->with(
+ $this->anything(),
+ $this->equalTo($expectedTags)
+ );
+ $this->connector->setDebugDispatcher($debugDispatcher);
+ $logger->addDebug('test', array($key => $expectedTags));
+ }
+ }
+
+ public function testError($classesPartialsTraceIgnore = null)
+ {
+ $code = E_USER_NOTICE;
+ $message = 'message';
+ $file = __FILE__;
+ $line = __LINE__;
+ $this->errorDispatcher->expects($this->once())->method('dispatchError')->with(
+ $this->equalTo($code),
+ $this->equalTo($message),
+ $this->equalTo($file),
+ $this->equalTo($line),
+ $classesPartialsTraceIgnore ?: $this->equalTo($this->getHandlerDefaultOption('classesPartialsTraceIgnore'))
+ );
+ $errorHandler = ErrorHandler::register($this->initLogger($classesPartialsTraceIgnore ? array('classesPartialsTraceIgnore' => $classesPartialsTraceIgnore) : array()), false);
+ $errorHandler->registerErrorHandler(array(), false, E_USER_WARNING);
+ $errorHandler->handleError($code, $message, $file, $line);
+ }
+
+ public function testException()
+ {
+ $exception = new Exception();
+ $this->errorDispatcher->expects($this->once())->method('dispatchException')->with(
+ $this->equalTo($exception)
+ );
+ $errorHandler = ErrorHandler::register($this->initLogger(), false, false);
+ $errorHandler->registerExceptionHandler(null, false);
+ $errorHandler->handleException($exception);
+ }
+
+ /**
+ * @expectedException Exception
+ */
+ public function testWrongOptionsThrowsException()
+ {
+ new PHPConsoleHandler(array('xxx' => 1));
+ }
+
+ public function testOptionEnabled()
+ {
+ $this->debugDispatcher->expects($this->never())->method('dispatchDebug');
+ $this->initLogger(array('enabled' => false))->addDebug('test');
+ }
+
+ public function testOptionClassesPartialsTraceIgnore()
+ {
+ $this->testError(array('Class', 'Namespace\\'));
+ }
+
+ public function testOptionDebugTagsKeysInContext()
+ {
+ $this->testDebugTags(array('key1', 'key2'));
+ }
+
+ public function testOptionUseOwnErrorsAndExceptionsHandler()
+ {
+ $this->initLogger(array('useOwnErrorsHandler' => true, 'useOwnExceptionsHandler' => true));
+ $this->assertEquals(array(Handler::getInstance(), 'handleError'), set_error_handler(function () {
+ }));
+ $this->assertEquals(array(Handler::getInstance(), 'handleException'), set_exception_handler(function () {
+ }));
+ }
+
+ public static function provideConnectorMethodsOptionsSets()
+ {
+ return array(
+ array('sourcesBasePath', 'setSourcesBasePath', __DIR__),
+ array('serverEncoding', 'setServerEncoding', 'cp1251'),
+ array('password', 'setPassword', '******'),
+ array('enableSslOnlyMode', 'enableSslOnlyMode', true, false),
+ array('ipMasks', 'setAllowedIpMasks', array('127.0.0.*')),
+ array('headersLimit', 'setHeadersLimit', 2500),
+ array('enableEvalListener', 'startEvalRequestsListener', true, false),
+ );
+ }
+
+ /**
+ * @dataProvider provideConnectorMethodsOptionsSets
+ */
+ public function testOptionCallsConnectorMethod($option, $method, $value, $isArgument = true)
+ {
+ $expectCall = $this->connector->expects($this->once())->method($method);
+ if ($isArgument) {
+ $expectCall->with($value);
+ }
+ new PHPConsoleHandler(array($option => $value), $this->connector);
+ }
+
+ public function testOptionDetectDumpTraceAndSource()
+ {
+ new PHPConsoleHandler(array('detectDumpTraceAndSource' => true), $this->connector);
+ $this->assertTrue($this->connector->getDebugDispatcher()->detectTraceAndSource);
+ }
+
+ public static function provideDumperOptionsValues()
+ {
+ return array(
+ array('dumperLevelLimit', 'levelLimit', 1001),
+ array('dumperItemsCountLimit', 'itemsCountLimit', 1002),
+ array('dumperItemSizeLimit', 'itemSizeLimit', 1003),
+ array('dumperDumpSizeLimit', 'dumpSizeLimit', 1004),
+ array('dumperDetectCallbacks', 'detectCallbacks', true),
+ );
+ }
+
+ /**
+ * @dataProvider provideDumperOptionsValues
+ */
+ public function testDumperOptions($option, $dumperProperty, $value)
+ {
+ new PHPConsoleHandler(array($option => $value), $this->connector);
+ $this->assertEquals($value, $this->connector->getDumper()->$dumperProperty);
+ }
+}
diff --git a/vendor/monolog/monolog/tests/Monolog/Handler/PsrHandlerTest.php b/vendor/monolog/monolog/tests/Monolog/Handler/PsrHandlerTest.php
new file mode 100644
index 00000000..64eaab16
--- /dev/null
+++ b/vendor/monolog/monolog/tests/Monolog/Handler/PsrHandlerTest.php
@@ -0,0 +1,50 @@
+<?php
+
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Handler;
+
+use Monolog\TestCase;
+use Monolog\Logger;
+
+/**
+ * @covers Monolog\Handler\PsrHandler::handle
+ */
+class PsrHandlerTest extends TestCase
+{
+ public function logLevelProvider()
+ {
+ $levels = array();
+ $monologLogger = new Logger('');
+
+ foreach ($monologLogger->getLevels() as $levelName => $level) {
+ $levels[] = array($levelName, $level);
+ }
+
+ return $levels;
+ }
+
+ /**
+ * @dataProvider logLevelProvider
+ */
+ public function testHandlesAllLevels($levelName, $level)
+ {
+ $message = 'Hello, world! ' . $level;
+ $context = array('foo' => 'bar', 'level' => $level);
+
+ $psrLogger = $this->getMock('Psr\Log\NullLogger');
+ $psrLogger->expects($this->once())
+ ->method('log')
+ ->with(strtolower($levelName), $message, $context);
+
+ $handler = new PsrHandler($psrLogger);
+ $handler->handle(array('level' => $level, 'level_name' => $levelName, 'message' => $message, 'context' => $context));
+ }
+}
diff --git a/vendor/monolog/monolog/tests/Monolog/Handler/PushoverHandlerTest.php b/vendor/monolog/monolog/tests/Monolog/Handler/PushoverHandlerTest.php
new file mode 100644
index 00000000..89408236
--- /dev/null
+++ b/vendor/monolog/monolog/tests/Monolog/Handler/PushoverHandlerTest.php
@@ -0,0 +1,141 @@
+<?php
+
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Handler;
+
+use Monolog\TestCase;
+use Monolog\Logger;
+
+/**
+ * Almost all examples (expected header, titles, messages) taken from
+ * https://www.pushover.net/api
+ * @author Sebastian Göttschkes <sebastian.goettschkes@googlemail.com>
+ * @see https://www.pushover.net/api
+ */
+class PushoverHandlerTest extends TestCase
+{
+ private $res;
+ private $handler;
+
+ public function testWriteHeader()
+ {
+ $this->createHandler();
+ $this->handler->setHighPriorityLevel(Logger::EMERGENCY); // skip priority notifications
+ $this->handler->handle($this->getRecord(Logger::CRITICAL, 'test1'));
+ fseek($this->res, 0);
+ $content = fread($this->res, 1024);
+
+ $this->assertRegexp('/POST \/1\/messages.json HTTP\/1.1\\r\\nHost: api.pushover.net\\r\\nContent-Type: application\/x-www-form-urlencoded\\r\\nContent-Length: \d{2,4}\\r\\n\\r\\n/', $content);
+
+ return $content;
+ }
+
+ /**
+ * @depends testWriteHeader
+ */
+ public function testWriteContent($content)
+ {
+ $this->assertRegexp('/token=myToken&user=myUser&message=test1&title=Monolog&timestamp=\d{10}$/', $content);
+ }
+
+ public function testWriteWithComplexTitle()
+ {
+ $this->createHandler('myToken', 'myUser', 'Backup finished - SQL1', Logger::EMERGENCY);
+ $this->handler->handle($this->getRecord(Logger::CRITICAL, 'test1'));
+ fseek($this->res, 0);
+ $content = fread($this->res, 1024);
+
+ $this->assertRegexp('/title=Backup\+finished\+-\+SQL1/', $content);
+ }
+
+ public function testWriteWithComplexMessage()
+ {
+ $this->createHandler();
+ $this->handler->setHighPriorityLevel(Logger::EMERGENCY); // skip priority notifications
+ $this->handler->handle($this->getRecord(Logger::CRITICAL, 'Backup of database "example" finished in 16 minutes.'));
+ fseek($this->res, 0);
+ $content = fread($this->res, 1024);
+
+ $this->assertRegexp('/message=Backup\+of\+database\+%22example%22\+finished\+in\+16\+minutes\./', $content);
+ }
+
+ public function testWriteWithTooLongMessage()
+ {
+ $message = str_pad('test', 520, 'a');
+ $this->createHandler();
+ $this->handler->setHighPriorityLevel(Logger::EMERGENCY); // skip priority notifications
+ $this->handler->handle($this->getRecord(Logger::CRITICAL, $message));
+ fseek($this->res, 0);
+ $content = fread($this->res, 1024);
+
+ $expectedMessage = substr($message, 0, 505);
+
+ $this->assertRegexp('/message=' . $expectedMessage . '&title/', $content);
+ }
+
+ public function testWriteWithHighPriority()
+ {
+ $this->createHandler();
+ $this->handler->handle($this->getRecord(Logger::CRITICAL, 'test1'));
+ fseek($this->res, 0);
+ $content = fread($this->res, 1024);
+
+ $this->assertRegexp('/token=myToken&user=myUser&message=test1&title=Monolog&timestamp=\d{10}&priority=1$/', $content);
+ }
+
+ public function testWriteWithEmergencyPriority()
+ {
+ $this->createHandler();
+ $this->handler->handle($this->getRecord(Logger::EMERGENCY, 'test1'));
+ fseek($this->res, 0);
+ $content = fread($this->res, 1024);
+
+ $this->assertRegexp('/token=myToken&user=myUser&message=test1&title=Monolog&timestamp=\d{10}&priority=2&retry=30&expire=25200$/', $content);
+ }
+
+ public function testWriteToMultipleUsers()
+ {
+ $this->createHandler('myToken', array('userA', 'userB'));
+ $this->handler->handle($this->getRecord(Logger::EMERGENCY, 'test1'));
+ fseek($this->res, 0);
+ $content = fread($this->res, 1024);
+
+ $this->assertRegexp('/token=myToken&user=userA&message=test1&title=Monolog&timestamp=\d{10}&priority=2&retry=30&expire=25200POST/', $content);
+ $this->assertRegexp('/token=myToken&user=userB&message=test1&title=Monolog&timestamp=\d{10}&priority=2&retry=30&expire=25200$/', $content);
+ }
+
+ private function createHandler($token = 'myToken', $user = 'myUser', $title = 'Monolog')
+ {
+ $constructorArgs = array($token, $user, $title);
+ $this->res = fopen('php://memory', 'a');
+ $this->handler = $this->getMock(
+ '\Monolog\Handler\PushoverHandler',
+ array('fsockopen', 'streamSetTimeout', 'closeSocket'),
+ $constructorArgs
+ );
+
+ $reflectionProperty = new \ReflectionProperty('\Monolog\Handler\SocketHandler', 'connectionString');
+ $reflectionProperty->setAccessible(true);
+ $reflectionProperty->setValue($this->handler, 'localhost:1234');
+
+ $this->handler->expects($this->any())
+ ->method('fsockopen')
+ ->will($this->returnValue($this->res));
+ $this->handler->expects($this->any())
+ ->method('streamSetTimeout')
+ ->will($this->returnValue(true));
+ $this->handler->expects($this->any())
+ ->method('closeSocket')
+ ->will($this->returnValue(true));
+
+ $this->handler->setFormatter($this->getIdentityFormatter());
+ }
+}
diff --git a/vendor/monolog/monolog/tests/Monolog/Handler/RavenHandlerTest.php b/vendor/monolog/monolog/tests/Monolog/Handler/RavenHandlerTest.php
new file mode 100644
index 00000000..9a9d1006
--- /dev/null
+++ b/vendor/monolog/monolog/tests/Monolog/Handler/RavenHandlerTest.php
@@ -0,0 +1,185 @@
+<?php
+
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Handler;
+
+use Monolog\TestCase;
+use Monolog\Logger;
+use Monolog\Formatter\LineFormatter;
+
+class RavenHandlerTest extends TestCase
+{
+ public function setUp()
+ {
+ if (!class_exists('Raven_Client')) {
+ $this->markTestSkipped('raven/raven not installed');
+ }
+
+ require_once __DIR__ . '/MockRavenClient.php';
+ }
+
+ /**
+ * @covers Monolog\Handler\RavenHandler::__construct
+ */
+ public function testConstruct()
+ {
+ $handler = new RavenHandler($this->getRavenClient());
+ $this->assertInstanceOf('Monolog\Handler\RavenHandler', $handler);
+ }
+
+ protected function getHandler($ravenClient)
+ {
+ $handler = new RavenHandler($ravenClient);
+
+ return $handler;
+ }
+
+ protected function getRavenClient()
+ {
+ $dsn = 'http://43f6017361224d098402974103bfc53d:a6a0538fc2934ba2bed32e08741b2cd3@marca.python.live.cheggnet.com:9000/1';
+
+ return new MockRavenClient($dsn);
+ }
+
+ public function testDebug()
+ {
+ $ravenClient = $this->getRavenClient();
+ $handler = $this->getHandler($ravenClient);
+
+ $record = $this->getRecord(Logger::DEBUG, 'A test debug message');
+ $handler->handle($record);
+
+ $this->assertEquals($ravenClient::DEBUG, $ravenClient->lastData['level']);
+ $this->assertContains($record['message'], $ravenClient->lastData['message']);
+ }
+
+ public function testWarning()
+ {
+ $ravenClient = $this->getRavenClient();
+ $handler = $this->getHandler($ravenClient);
+
+ $record = $this->getRecord(Logger::WARNING, 'A test warning message');
+ $handler->handle($record);
+
+ $this->assertEquals($ravenClient::WARNING, $ravenClient->lastData['level']);
+ $this->assertContains($record['message'], $ravenClient->lastData['message']);
+ }
+
+ public function testTag()
+ {
+ $ravenClient = $this->getRavenClient();
+ $handler = $this->getHandler($ravenClient);
+
+ $tags = array(1, 2, 'foo');
+ $record = $this->getRecord(Logger::INFO, 'test', array('tags' => $tags));
+ $handler->handle($record);
+
+ $this->assertEquals($tags, $ravenClient->lastData['tags']);
+ }
+
+ public function testUserContext()
+ {
+ $ravenClient = $this->getRavenClient();
+ $handler = $this->getHandler($ravenClient);
+
+ $recordWithNoContext = $this->getRecord(Logger::INFO, 'test with default user context');
+ // set user context 'externally'
+
+ $user = array(
+ 'id' => '123',
+ 'email' => 'test@test.com'
+ );
+
+ $recordWithContext = $this->getRecord(Logger::INFO, 'test', array('user' => $user));
+
+ $ravenClient->user_context(array('id' => 'test_user_id'));
+ // handle context
+ $handler->handle($recordWithContext);
+ $this->assertEquals($user, $ravenClient->lastData['sentry.interfaces.User']);
+
+ // check to see if its reset
+ $handler->handle($recordWithNoContext);
+ $this->assertInternalType('array', $ravenClient->context->user);
+ $this->assertSame('test_user_id', $ravenClient->context->user['id']);
+
+ // handle with null context
+ $ravenClient->user_context(null);
+ $handler->handle($recordWithContext);
+ $this->assertEquals($user, $ravenClient->lastData['sentry.interfaces.User']);
+
+ // check to see if its reset
+ $handler->handle($recordWithNoContext);
+ $this->assertNull($ravenClient->context->user);
+ }
+
+ public function testException()
+ {
+ $ravenClient = $this->getRavenClient();
+ $handler = $this->getHandler($ravenClient);
+
+ try {
+ $this->methodThatThrowsAnException();
+ } catch (\Exception $e) {
+ $record = $this->getRecord(Logger::ERROR, $e->getMessage(), array('exception' => $e));
+ $handler->handle($record);
+ }
+
+ $this->assertEquals($record['message'], $ravenClient->lastData['message']);
+ }
+
+ public function testHandleBatch()
+ {
+ $records = $this->getMultipleRecords();
+ $records[] = $this->getRecord(Logger::WARNING, 'warning');
+ $records[] = $this->getRecord(Logger::WARNING, 'warning');
+
+ $logFormatter = $this->getMock('Monolog\\Formatter\\FormatterInterface');
+ $logFormatter->expects($this->once())->method('formatBatch');
+
+ $formatter = $this->getMock('Monolog\\Formatter\\FormatterInterface');
+ $formatter->expects($this->once())->method('format')->with($this->callback(function ($record) {
+ return $record['level'] == 400;
+ }));
+
+ $handler = $this->getHandler($this->getRavenClient());
+ $handler->setBatchFormatter($logFormatter);
+ $handler->setFormatter($formatter);
+ $handler->handleBatch($records);
+ }
+
+ public function testHandleBatchDoNothingIfRecordsAreBelowLevel()
+ {
+ $records = array(
+ $this->getRecord(Logger::DEBUG, 'debug message 1'),
+ $this->getRecord(Logger::DEBUG, 'debug message 2'),
+ $this->getRecord(Logger::INFO, 'information'),
+ );
+
+ $handler = $this->getMock('Monolog\Handler\RavenHandler', null, array($this->getRavenClient()));
+ $handler->expects($this->never())->method('handle');
+ $handler->setLevel(Logger::ERROR);
+ $handler->handleBatch($records);
+ }
+
+ public function testGetSetBatchFormatter()
+ {
+ $ravenClient = $this->getRavenClient();
+ $handler = $this->getHandler($ravenClient);
+
+ $handler->setBatchFormatter($formatter = new LineFormatter());
+ $this->assertSame($formatter, $handler->getBatchFormatter());
+ }
+
+ private function methodThatThrowsAnException()
+ {
+ throw new \Exception('This is an exception');
+ }
+}
diff --git a/vendor/monolog/monolog/tests/Monolog/Handler/RedisHandlerTest.php b/vendor/monolog/monolog/tests/Monolog/Handler/RedisHandlerTest.php
new file mode 100644
index 00000000..3629f8a2
--- /dev/null
+++ b/vendor/monolog/monolog/tests/Monolog/Handler/RedisHandlerTest.php
@@ -0,0 +1,71 @@
+<?php
+
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Handler;
+
+use Monolog\TestCase;
+use Monolog\Logger;
+use Monolog\Formatter\LineFormatter;
+
+class RedisHandlerTest extends TestCase
+{
+ /**
+ * @expectedException InvalidArgumentException
+ */
+ public function testConstructorShouldThrowExceptionForInvalidRedis()
+ {
+ new RedisHandler(new \stdClass(), 'key');
+ }
+
+ public function testConstructorShouldWorkWithPredis()
+ {
+ $redis = $this->getMock('Predis\Client');
+ $this->assertInstanceof('Monolog\Handler\RedisHandler', new RedisHandler($redis, 'key'));
+ }
+
+ public function testConstructorShouldWorkWithRedis()
+ {
+ $redis = $this->getMock('Redis');
+ $this->assertInstanceof('Monolog\Handler\RedisHandler', new RedisHandler($redis, 'key'));
+ }
+
+ public function testPredisHandle()
+ {
+ $redis = $this->getMock('Predis\Client', array('rpush'));
+
+ // Predis\Client uses rpush
+ $redis->expects($this->once())
+ ->method('rpush')
+ ->with('key', 'test');
+
+ $record = $this->getRecord(Logger::WARNING, 'test', array('data' => new \stdClass, 'foo' => 34));
+
+ $handler = new RedisHandler($redis, 'key');
+ $handler->setFormatter(new LineFormatter("%message%"));
+ $handler->handle($record);
+ }
+
+ public function testRedisHandle()
+ {
+ $redis = $this->getMock('Redis', array('rpush'));
+
+ // Redis uses rPush
+ $redis->expects($this->once())
+ ->method('rPush')
+ ->with('key', 'test');
+
+ $record = $this->getRecord(Logger::WARNING, 'test', array('data' => new \stdClass, 'foo' => 34));
+
+ $handler = new RedisHandler($redis, 'key');
+ $handler->setFormatter(new LineFormatter("%message%"));
+ $handler->handle($record);
+ }
+}
diff --git a/vendor/monolog/monolog/tests/Monolog/Handler/RotatingFileHandlerTest.php b/vendor/monolog/monolog/tests/Monolog/Handler/RotatingFileHandlerTest.php
new file mode 100644
index 00000000..f4cefda1
--- /dev/null
+++ b/vendor/monolog/monolog/tests/Monolog/Handler/RotatingFileHandlerTest.php
@@ -0,0 +1,99 @@
+<?php
+
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Handler;
+
+use Monolog\TestCase;
+
+/**
+ * @covers Monolog\Handler\RotatingFileHandler
+ */
+class RotatingFileHandlerTest extends TestCase
+{
+ public function setUp()
+ {
+ $dir = __DIR__.'/Fixtures';
+ chmod($dir, 0777);
+ if (!is_writable($dir)) {
+ $this->markTestSkipped($dir.' must be writeable to test the RotatingFileHandler.');
+ }
+ }
+
+ public function testRotationCreatesNewFile()
+ {
+ touch(__DIR__.'/Fixtures/foo-'.date('Y-m-d', time() - 86400).'.rot');
+
+ $handler = new RotatingFileHandler(__DIR__.'/Fixtures/foo.rot');
+ $handler->setFormatter($this->getIdentityFormatter());
+ $handler->handle($this->getRecord());
+
+ $log = __DIR__.'/Fixtures/foo-'.date('Y-m-d').'.rot';
+ $this->assertTrue(file_exists($log));
+ $this->assertEquals('test', file_get_contents($log));
+ }
+
+ /**
+ * @dataProvider rotationTests
+ */
+ public function testRotation($createFile)
+ {
+ touch($old1 = __DIR__.'/Fixtures/foo-'.date('Y-m-d', time() - 86400).'.rot');
+ touch($old2 = __DIR__.'/Fixtures/foo-'.date('Y-m-d', time() - 86400 * 2).'.rot');
+ touch($old3 = __DIR__.'/Fixtures/foo-'.date('Y-m-d', time() - 86400 * 3).'.rot');
+ touch($old4 = __DIR__.'/Fixtures/foo-'.date('Y-m-d', time() - 86400 * 4).'.rot');
+
+ $log = __DIR__.'/Fixtures/foo-'.date('Y-m-d').'.rot';
+
+ if ($createFile) {
+ touch($log);
+ }
+
+ $handler = new RotatingFileHandler(__DIR__.'/Fixtures/foo.rot', 2);
+ $handler->setFormatter($this->getIdentityFormatter());
+ $handler->handle($this->getRecord());
+
+ $handler->close();
+
+ $this->assertTrue(file_exists($log));
+ $this->assertTrue(file_exists($old1));
+ $this->assertEquals($createFile, file_exists($old2));
+ $this->assertEquals($createFile, file_exists($old3));
+ $this->assertEquals($createFile, file_exists($old4));
+ $this->assertEquals('test', file_get_contents($log));
+ }
+
+ public function rotationTests()
+ {
+ return array(
+ 'Rotation is triggered when the file of the current day is not present'
+ => array(true),
+ 'Rotation is not triggered when the file is already present'
+ => array(false),
+ );
+ }
+
+ public function testReuseCurrentFile()
+ {
+ $log = __DIR__.'/Fixtures/foo-'.date('Y-m-d').'.rot';
+ file_put_contents($log, "foo");
+ $handler = new RotatingFileHandler(__DIR__.'/Fixtures/foo.rot');
+ $handler->setFormatter($this->getIdentityFormatter());
+ $handler->handle($this->getRecord());
+ $this->assertEquals('footest', file_get_contents($log));
+ }
+
+ public function tearDown()
+ {
+ foreach (glob(__DIR__.'/Fixtures/*.rot') as $file) {
+ unlink($file);
+ }
+ }
+}
diff --git a/vendor/monolog/monolog/tests/Monolog/Handler/SamplingHandlerTest.php b/vendor/monolog/monolog/tests/Monolog/Handler/SamplingHandlerTest.php
new file mode 100644
index 00000000..b354cee1
--- /dev/null
+++ b/vendor/monolog/monolog/tests/Monolog/Handler/SamplingHandlerTest.php
@@ -0,0 +1,33 @@
+<?php
+
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Handler;
+
+use Monolog\TestCase;
+
+/**
+ * @covers Monolog\Handler\SamplingHandler::handle
+ */
+class SamplingHandlerTest extends TestCase
+{
+ public function testHandle()
+ {
+ $testHandler = new TestHandler();
+ $handler = new SamplingHandler($testHandler, 2);
+ for ($i = 0; $i < 10000; $i++) {
+ $handler->handle($this->getRecord());
+ }
+ $count = count($testHandler->getRecords());
+ // $count should be half of 10k, so between 4k and 6k
+ $this->assertLessThan(6000, $count);
+ $this->assertGreaterThan(4000, $count);
+ }
+}
diff --git a/vendor/monolog/monolog/tests/Monolog/Handler/SlackHandlerTest.php b/vendor/monolog/monolog/tests/Monolog/Handler/SlackHandlerTest.php
new file mode 100644
index 00000000..d657fae3
--- /dev/null
+++ b/vendor/monolog/monolog/tests/Monolog/Handler/SlackHandlerTest.php
@@ -0,0 +1,133 @@
+<?php
+
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Handler;
+
+use Monolog\TestCase;
+use Monolog\Logger;
+
+/**
+ * @author Greg Kedzierski <greg@gregkedzierski.com>
+ * @see https://api.slack.com/
+ */
+class SlackHandlerTest extends TestCase
+{
+ /**
+ * @var resource
+ */
+ private $res;
+
+ /**
+ * @var SlackHandler
+ */
+ private $handler;
+
+ public function setUp()
+ {
+ if (!extension_loaded('openssl')) {
+ $this->markTestSkipped('This test requires openssl to run');
+ }
+ }
+
+ public function testWriteHeader()
+ {
+ $this->createHandler();
+ $this->handler->handle($this->getRecord(Logger::CRITICAL, 'test1'));
+ fseek($this->res, 0);
+ $content = fread($this->res, 1024);
+
+ $this->assertRegexp('/POST \/api\/chat.postMessage HTTP\/1.1\\r\\nHost: slack.com\\r\\nContent-Type: application\/x-www-form-urlencoded\\r\\nContent-Length: \d{2,4}\\r\\n\\r\\n/', $content);
+ }
+
+ public function testWriteContent()
+ {
+ $this->createHandler();
+ $this->handler->handle($this->getRecord(Logger::CRITICAL, 'test1'));
+ fseek($this->res, 0);
+ $content = fread($this->res, 1024);
+
+ $this->assertRegexp('/token=myToken&channel=channel1&username=Monolog&text=&attachments=.*$/', $content);
+ }
+
+ public function testWriteContentWithEmoji()
+ {
+ $this->createHandler('myToken', 'channel1', 'Monolog', true, 'alien');
+ $this->handler->handle($this->getRecord(Logger::CRITICAL, 'test1'));
+ fseek($this->res, 0);
+ $content = fread($this->res, 1024);
+
+ $this->assertRegexp('/icon_emoji=%3Aalien%3A$/', $content);
+ }
+
+ /**
+ * @dataProvider provideLevelColors
+ */
+ public function testWriteContentWithColors($level, $expectedColor)
+ {
+ $this->createHandler();
+ $this->handler->handle($this->getRecord($level, 'test1'));
+ fseek($this->res, 0);
+ $content = fread($this->res, 1024);
+
+ $this->assertRegexp('/color%22%3A%22'.$expectedColor.'/', $content);
+ }
+
+ public function testWriteContentWithPlainTextMessage()
+ {
+ $this->createHandler('myToken', 'channel1', 'Monolog', false);
+ $this->handler->handle($this->getRecord(Logger::CRITICAL, 'test1'));
+ fseek($this->res, 0);
+ $content = fread($this->res, 1024);
+
+ $this->assertRegexp('/text=test1/', $content);
+ }
+
+ public function provideLevelColors()
+ {
+ return array(
+ array(Logger::DEBUG, '%23e3e4e6'), // escaped #e3e4e6
+ array(Logger::INFO, 'good'),
+ array(Logger::NOTICE, 'good'),
+ array(Logger::WARNING, 'warning'),
+ array(Logger::ERROR, 'danger'),
+ array(Logger::CRITICAL, 'danger'),
+ array(Logger::ALERT, 'danger'),
+ array(Logger::EMERGENCY,'danger'),
+ );
+ }
+
+ private function createHandler($token = 'myToken', $channel = 'channel1', $username = 'Monolog', $useAttachment = true, $iconEmoji = null, $useShortAttachment = false, $includeExtra = false)
+ {
+ $constructorArgs = array($token, $channel, $username, $useAttachment, $iconEmoji, Logger::DEBUG, true, $useShortAttachment, $includeExtra);
+ $this->res = fopen('php://memory', 'a');
+ $this->handler = $this->getMock(
+ '\Monolog\Handler\SlackHandler',
+ array('fsockopen', 'streamSetTimeout', 'closeSocket'),
+ $constructorArgs
+ );
+
+ $reflectionProperty = new \ReflectionProperty('\Monolog\Handler\SocketHandler', 'connectionString');
+ $reflectionProperty->setAccessible(true);
+ $reflectionProperty->setValue($this->handler, 'localhost:1234');
+
+ $this->handler->expects($this->any())
+ ->method('fsockopen')
+ ->will($this->returnValue($this->res));
+ $this->handler->expects($this->any())
+ ->method('streamSetTimeout')
+ ->will($this->returnValue(true));
+ $this->handler->expects($this->any())
+ ->method('closeSocket')
+ ->will($this->returnValue(true));
+
+ $this->handler->setFormatter($this->getIdentityFormatter());
+ }
+}
diff --git a/vendor/monolog/monolog/tests/Monolog/Handler/SocketHandlerTest.php b/vendor/monolog/monolog/tests/Monolog/Handler/SocketHandlerTest.php
new file mode 100644
index 00000000..2e3d504a
--- /dev/null
+++ b/vendor/monolog/monolog/tests/Monolog/Handler/SocketHandlerTest.php
@@ -0,0 +1,282 @@
+<?php
+
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Handler;
+
+use Monolog\TestCase;
+use Monolog\Logger;
+
+/**
+ * @author Pablo de Leon Belloc <pablolb@gmail.com>
+ */
+class SocketHandlerTest extends TestCase
+{
+ /**
+ * @var Monolog\Handler\SocketHandler
+ */
+ private $handler;
+
+ /**
+ * @var resource
+ */
+ private $res;
+
+ /**
+ * @expectedException UnexpectedValueException
+ */
+ public function testInvalidHostname()
+ {
+ $this->createHandler('garbage://here');
+ $this->writeRecord('data');
+ }
+
+ /**
+ * @expectedException \InvalidArgumentException
+ */
+ public function testBadConnectionTimeout()
+ {
+ $this->createHandler('localhost:1234');
+ $this->handler->setConnectionTimeout(-1);
+ }
+
+ public function testSetConnectionTimeout()
+ {
+ $this->createHandler('localhost:1234');
+ $this->handler->setConnectionTimeout(10.1);
+ $this->assertEquals(10.1, $this->handler->getConnectionTimeout());
+ }
+
+ /**
+ * @expectedException \InvalidArgumentException
+ */
+ public function testBadTimeout()
+ {
+ $this->createHandler('localhost:1234');
+ $this->handler->setTimeout(-1);
+ }
+
+ public function testSetTimeout()
+ {
+ $this->createHandler('localhost:1234');
+ $this->handler->setTimeout(10.25);
+ $this->assertEquals(10.25, $this->handler->getTimeout());
+ }
+
+ public function testSetConnectionString()
+ {
+ $this->createHandler('tcp://localhost:9090');
+ $this->assertEquals('tcp://localhost:9090', $this->handler->getConnectionString());
+ }
+
+ /**
+ * @expectedException UnexpectedValueException
+ */
+ public function testExceptionIsThrownOnFsockopenError()
+ {
+ $this->setMockHandler(array('fsockopen'));
+ $this->handler->expects($this->once())
+ ->method('fsockopen')
+ ->will($this->returnValue(false));
+ $this->writeRecord('Hello world');
+ }
+
+ /**
+ * @expectedException UnexpectedValueException
+ */
+ public function testExceptionIsThrownOnPfsockopenError()
+ {
+ $this->setMockHandler(array('pfsockopen'));
+ $this->handler->expects($this->once())
+ ->method('pfsockopen')
+ ->will($this->returnValue(false));
+ $this->handler->setPersistent(true);
+ $this->writeRecord('Hello world');
+ }
+
+ /**
+ * @expectedException UnexpectedValueException
+ */
+ public function testExceptionIsThrownIfCannotSetTimeout()
+ {
+ $this->setMockHandler(array('streamSetTimeout'));
+ $this->handler->expects($this->once())
+ ->method('streamSetTimeout')
+ ->will($this->returnValue(false));
+ $this->writeRecord('Hello world');
+ }
+
+ /**
+ * @expectedException RuntimeException
+ */
+ public function testWriteFailsOnIfFwriteReturnsFalse()
+ {
+ $this->setMockHandler(array('fwrite'));
+
+ $callback = function ($arg) {
+ $map = array(
+ 'Hello world' => 6,
+ 'world' => false,
+ );
+
+ return $map[$arg];
+ };
+
+ $this->handler->expects($this->exactly(2))
+ ->method('fwrite')
+ ->will($this->returnCallback($callback));
+
+ $this->writeRecord('Hello world');
+ }
+
+ /**
+ * @expectedException RuntimeException
+ */
+ public function testWriteFailsIfStreamTimesOut()
+ {
+ $this->setMockHandler(array('fwrite', 'streamGetMetadata'));
+
+ $callback = function ($arg) {
+ $map = array(
+ 'Hello world' => 6,
+ 'world' => 5,
+ );
+
+ return $map[$arg];
+ };
+
+ $this->handler->expects($this->exactly(1))
+ ->method('fwrite')
+ ->will($this->returnCallback($callback));
+ $this->handler->expects($this->exactly(1))
+ ->method('streamGetMetadata')
+ ->will($this->returnValue(array('timed_out' => true)));
+
+ $this->writeRecord('Hello world');
+ }
+
+ /**
+ * @expectedException RuntimeException
+ */
+ public function testWriteFailsOnIncompleteWrite()
+ {
+ $this->setMockHandler(array('fwrite', 'streamGetMetadata'));
+
+ $res = $this->res;
+ $callback = function ($string) use ($res) {
+ fclose($res);
+
+ return strlen('Hello');
+ };
+
+ $this->handler->expects($this->exactly(1))
+ ->method('fwrite')
+ ->will($this->returnCallback($callback));
+ $this->handler->expects($this->exactly(1))
+ ->method('streamGetMetadata')
+ ->will($this->returnValue(array('timed_out' => false)));
+
+ $this->writeRecord('Hello world');
+ }
+
+ public function testWriteWithMemoryFile()
+ {
+ $this->setMockHandler();
+ $this->writeRecord('test1');
+ $this->writeRecord('test2');
+ $this->writeRecord('test3');
+ fseek($this->res, 0);
+ $this->assertEquals('test1test2test3', fread($this->res, 1024));
+ }
+
+ public function testWriteWithMock()
+ {
+ $this->setMockHandler(array('fwrite'));
+
+ $callback = function ($arg) {
+ $map = array(
+ 'Hello world' => 6,
+ 'world' => 5,
+ );
+
+ return $map[$arg];
+ };
+
+ $this->handler->expects($this->exactly(2))
+ ->method('fwrite')
+ ->will($this->returnCallback($callback));
+
+ $this->writeRecord('Hello world');
+ }
+
+ public function testClose()
+ {
+ $this->setMockHandler();
+ $this->writeRecord('Hello world');
+ $this->assertInternalType('resource', $this->res);
+ $this->handler->close();
+ $this->assertFalse(is_resource($this->res), "Expected resource to be closed after closing handler");
+ }
+
+ public function testCloseDoesNotClosePersistentSocket()
+ {
+ $this->setMockHandler();
+ $this->handler->setPersistent(true);
+ $this->writeRecord('Hello world');
+ $this->assertTrue(is_resource($this->res));
+ $this->handler->close();
+ $this->assertTrue(is_resource($this->res));
+ }
+
+ private function createHandler($connectionString)
+ {
+ $this->handler = new SocketHandler($connectionString);
+ $this->handler->setFormatter($this->getIdentityFormatter());
+ }
+
+ private function writeRecord($string)
+ {
+ $this->handler->handle($this->getRecord(Logger::WARNING, $string));
+ }
+
+ private function setMockHandler(array $methods = array())
+ {
+ $this->res = fopen('php://memory', 'a');
+
+ $defaultMethods = array('fsockopen', 'pfsockopen', 'streamSetTimeout');
+ $newMethods = array_diff($methods, $defaultMethods);
+
+ $finalMethods = array_merge($defaultMethods, $newMethods);
+
+ $this->handler = $this->getMock(
+ '\Monolog\Handler\SocketHandler', $finalMethods, array('localhost:1234')
+ );
+
+ if (!in_array('fsockopen', $methods)) {
+ $this->handler->expects($this->any())
+ ->method('fsockopen')
+ ->will($this->returnValue($this->res));
+ }
+
+ if (!in_array('pfsockopen', $methods)) {
+ $this->handler->expects($this->any())
+ ->method('pfsockopen')
+ ->will($this->returnValue($this->res));
+ }
+
+ if (!in_array('streamSetTimeout', $methods)) {
+ $this->handler->expects($this->any())
+ ->method('streamSetTimeout')
+ ->will($this->returnValue(true));
+ }
+
+ $this->handler->setFormatter($this->getIdentityFormatter());
+ }
+}
diff --git a/vendor/monolog/monolog/tests/Monolog/Handler/StreamHandlerTest.php b/vendor/monolog/monolog/tests/Monolog/Handler/StreamHandlerTest.php
new file mode 100644
index 00000000..44d3d9f1
--- /dev/null
+++ b/vendor/monolog/monolog/tests/Monolog/Handler/StreamHandlerTest.php
@@ -0,0 +1,118 @@
+<?php
+
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Handler;
+
+use Monolog\TestCase;
+use Monolog\Logger;
+
+class StreamHandlerTest extends TestCase
+{
+ /**
+ * @covers Monolog\Handler\StreamHandler::__construct
+ * @covers Monolog\Handler\StreamHandler::write
+ */
+ public function testWrite()
+ {
+ $handle = fopen('php://memory', 'a+');
+ $handler = new StreamHandler($handle);
+ $handler->setFormatter($this->getIdentityFormatter());
+ $handler->handle($this->getRecord(Logger::WARNING, 'test'));
+ $handler->handle($this->getRecord(Logger::WARNING, 'test2'));
+ $handler->handle($this->getRecord(Logger::WARNING, 'test3'));
+ fseek($handle, 0);
+ $this->assertEquals('testtest2test3', fread($handle, 100));
+ }
+
+ /**
+ * @covers Monolog\Handler\StreamHandler::close
+ */
+ public function testClose()
+ {
+ $handle = fopen('php://memory', 'a+');
+ $handler = new StreamHandler($handle);
+ $this->assertTrue(is_resource($handle));
+ $handler->close();
+ $this->assertFalse(is_resource($handle));
+ }
+
+ /**
+ * @covers Monolog\Handler\StreamHandler::write
+ */
+ public function testWriteCreatesTheStreamResource()
+ {
+ $handler = new StreamHandler('php://memory');
+ $handler->handle($this->getRecord());
+ }
+
+ /**
+ * @covers Monolog\Handler\StreamHandler::__construct
+ * @covers Monolog\Handler\StreamHandler::write
+ */
+ public function testWriteLocking()
+ {
+ $temp = sys_get_temp_dir() . DIRECTORY_SEPARATOR . 'monolog_locked_log';
+ $handler = new StreamHandler($temp, Logger::DEBUG, true, null, true);
+ $handler->handle($this->getRecord());
+ }
+
+ /**
+ * @expectedException LogicException
+ * @covers Monolog\Handler\StreamHandler::__construct
+ * @covers Monolog\Handler\StreamHandler::write
+ */
+ public function testWriteMissingResource()
+ {
+ $handler = new StreamHandler(null);
+ $handler->handle($this->getRecord());
+ }
+
+ public function invalidArgumentProvider()
+ {
+ return array(
+ array(1),
+ array(array()),
+ array(array('bogus://url')),
+ );
+ }
+
+ /**
+ * @dataProvider invalidArgumentProvider
+ * @expectedException InvalidArgumentException
+ * @covers Monolog\Handler\StreamHandler::__construct
+ */
+ public function testWriteInvalidArgument($invalidArgument)
+ {
+ $handler = new StreamHandler($invalidArgument);
+ }
+
+ /**
+ * @expectedException UnexpectedValueException
+ * @covers Monolog\Handler\StreamHandler::__construct
+ * @covers Monolog\Handler\StreamHandler::write
+ */
+ public function testWriteInvalidResource()
+ {
+ $handler = new StreamHandler('bogus://url');
+ $handler->handle($this->getRecord());
+ }
+
+ /**
+ * @expectedException UnexpectedValueException
+ * @covers Monolog\Handler\StreamHandler::__construct
+ * @covers Monolog\Handler\StreamHandler::write
+ */
+ public function testWriteNonExistingResource()
+ {
+ $handler = new StreamHandler('/foo/bar/baz/'.rand(0, 10000));
+ $handler->handle($this->getRecord());
+ }
+}
diff --git a/vendor/monolog/monolog/tests/Monolog/Handler/SwiftMailerHandlerTest.php b/vendor/monolog/monolog/tests/Monolog/Handler/SwiftMailerHandlerTest.php
new file mode 100644
index 00000000..ac885220
--- /dev/null
+++ b/vendor/monolog/monolog/tests/Monolog/Handler/SwiftMailerHandlerTest.php
@@ -0,0 +1,65 @@
+<?php
+
+namespace Monolog\Handler;
+
+use Monolog\Logger;
+use Monolog\TestCase;
+
+class SwiftMailerHandlerTest extends TestCase
+{
+ /** @var \Swift_Mailer|\PHPUnit_Framework_MockObject_MockObject */
+ private $mailer;
+
+ public function setUp()
+ {
+ $this->mailer = $this
+ ->getMockBuilder('Swift_Mailer')
+ ->disableOriginalConstructor()
+ ->getMock();
+ }
+
+ public function testMessageCreationIsLazyWhenUsingCallback()
+ {
+ $this->mailer->expects($this->never())
+ ->method('send');
+
+ $callback = function () {
+ throw new \RuntimeException('Swift_Message creation callback should not have been called in this test');
+ };
+ $handler = new SwiftMailerHandler($this->mailer, $callback);
+
+ $records = array(
+ $this->getRecord(Logger::DEBUG),
+ $this->getRecord(Logger::INFO),
+ );
+ $handler->handleBatch($records);
+ }
+
+ public function testMessageCanBeCustomizedGivenLoggedData()
+ {
+ // Wire Mailer to expect a specific Swift_Message with a customized Subject
+ $expectedMessage = new \Swift_Message();
+ $this->mailer->expects($this->once())
+ ->method('send')
+ ->with($this->callback(function ($value) use ($expectedMessage) {
+ return $value instanceof \Swift_Message
+ && $value->getSubject() === 'Emergency'
+ && $value === $expectedMessage;
+ }));
+
+ // Callback dynamically changes subject based on number of logged records
+ $callback = function ($content, array $records) use ($expectedMessage) {
+ $subject = count($records) > 0 ? 'Emergency' : 'Normal';
+ $expectedMessage->setSubject($subject);
+
+ return $expectedMessage;
+ };
+ $handler = new SwiftMailerHandler($this->mailer, $callback);
+
+ // Logging 1 record makes this an Emergency
+ $records = array(
+ $this->getRecord(Logger::EMERGENCY),
+ );
+ $handler->handleBatch($records);
+ }
+}
diff --git a/vendor/monolog/monolog/tests/Monolog/Handler/SyslogHandlerTest.php b/vendor/monolog/monolog/tests/Monolog/Handler/SyslogHandlerTest.php
new file mode 100644
index 00000000..8f9e46bf
--- /dev/null
+++ b/vendor/monolog/monolog/tests/Monolog/Handler/SyslogHandlerTest.php
@@ -0,0 +1,44 @@
+<?php
+
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Handler;
+
+use Monolog\Logger;
+
+class SyslogHandlerTest extends \PHPUnit_Framework_TestCase
+{
+ /**
+ * @covers Monolog\Handler\SyslogHandler::__construct
+ */
+ public function testConstruct()
+ {
+ $handler = new SyslogHandler('test');
+ $this->assertInstanceOf('Monolog\Handler\SyslogHandler', $handler);
+
+ $handler = new SyslogHandler('test', LOG_USER);
+ $this->assertInstanceOf('Monolog\Handler\SyslogHandler', $handler);
+
+ $handler = new SyslogHandler('test', 'user');
+ $this->assertInstanceOf('Monolog\Handler\SyslogHandler', $handler);
+
+ $handler = new SyslogHandler('test', LOG_USER, Logger::DEBUG, true, LOG_PERROR);
+ $this->assertInstanceOf('Monolog\Handler\SyslogHandler', $handler);
+ }
+
+ /**
+ * @covers Monolog\Handler\SyslogHandler::__construct
+ */
+ public function testConstructInvalidFacility()
+ {
+ $this->setExpectedException('UnexpectedValueException');
+ $handler = new SyslogHandler('test', 'unknown');
+ }
+}
diff --git a/vendor/monolog/monolog/tests/Monolog/Handler/SyslogUdpHandlerTest.php b/vendor/monolog/monolog/tests/Monolog/Handler/SyslogUdpHandlerTest.php
new file mode 100644
index 00000000..497812b3
--- /dev/null
+++ b/vendor/monolog/monolog/tests/Monolog/Handler/SyslogUdpHandlerTest.php
@@ -0,0 +1,49 @@
+<?php
+
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Handler;
+
+/**
+ * @requires extension sockets
+ */
+class SyslogUdpHandlerTest extends \PHPUnit_Framework_TestCase
+{
+ /**
+ * @expectedException UnexpectedValueException
+ */
+ public function testWeValidateFacilities()
+ {
+ $handler = new SyslogUdpHandler("ip", null, "invalidFacility");
+ }
+
+ public function testWeSplitIntoLines()
+ {
+ $handler = new SyslogUdpHandler("127.0.0.1", 514, "authpriv");
+ $handler->setFormatter(new \Monolog\Formatter\ChromePHPFormatter());
+
+ $socket = $this->getMock('\Monolog\Handler\SyslogUdp\UdpSocket', array('write'), array('lol', 'lol'));
+ $socket->expects($this->at(0))
+ ->method('write')
+ ->with("lol", "<".(LOG_AUTHPRIV + LOG_WARNING).">1 ");
+ $socket->expects($this->at(1))
+ ->method('write')
+ ->with("hej", "<".(LOG_AUTHPRIV + LOG_WARNING).">1 ");
+
+ $handler->setSocket($socket);
+
+ $handler->handle($this->getRecordWithMessage("hej\nlol"));
+ }
+
+ protected function getRecordWithMessage($msg)
+ {
+ return array('message' => $msg, 'level' => \Monolog\Logger::WARNING, 'context' => null, 'extra' => array(), 'channel' => 'lol');
+ }
+}
diff --git a/vendor/monolog/monolog/tests/Monolog/Handler/TestHandlerTest.php b/vendor/monolog/monolog/tests/Monolog/Handler/TestHandlerTest.php
new file mode 100644
index 00000000..2a79fdc6
--- /dev/null
+++ b/vendor/monolog/monolog/tests/Monolog/Handler/TestHandlerTest.php
@@ -0,0 +1,58 @@
+<?php
+
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Handler;
+
+use Monolog\TestCase;
+use Monolog\Logger;
+
+/**
+ * @covers Monolog\Handler\TestHandler
+ */
+class TestHandlerTest extends TestCase
+{
+ /**
+ * @dataProvider methodProvider
+ */
+ public function testHandler($method, $level)
+ {
+ $handler = new TestHandler;
+ $record = $this->getRecord($level, 'test'.$method);
+ $this->assertFalse($handler->{'has'.$method}($record));
+ $this->assertFalse($handler->{'has'.$method.'ThatContains'}('test'));
+ $this->assertFalse($handler->{'has'.$method.'Records'}());
+ $handler->handle($record);
+
+ $this->assertFalse($handler->{'has'.$method}('bar'));
+ $this->assertTrue($handler->{'has'.$method}($record));
+ $this->assertTrue($handler->{'has'.$method}('test'.$method));
+ $this->assertTrue($handler->{'has'.$method.'ThatContains'}('test'));
+ $this->assertTrue($handler->{'has'.$method.'Records'}());
+
+ $records = $handler->getRecords();
+ unset($records[0]['formatted']);
+ $this->assertEquals(array($record), $records);
+ }
+
+ public function methodProvider()
+ {
+ return array(
+ array('Emergency', Logger::EMERGENCY),
+ array('Alert' , Logger::ALERT),
+ array('Critical' , Logger::CRITICAL),
+ array('Error' , Logger::ERROR),
+ array('Warning' , Logger::WARNING),
+ array('Info' , Logger::INFO),
+ array('Notice' , Logger::NOTICE),
+ array('Debug' , Logger::DEBUG),
+ );
+ }
+}
diff --git a/vendor/monolog/monolog/tests/Monolog/Handler/UdpSocketTest.php b/vendor/monolog/monolog/tests/Monolog/Handler/UdpSocketTest.php
new file mode 100644
index 00000000..bcaf52b3
--- /dev/null
+++ b/vendor/monolog/monolog/tests/Monolog/Handler/UdpSocketTest.php
@@ -0,0 +1,46 @@
+<?php
+
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Handler;
+
+use Monolog\TestCase;
+
+/**
+ * @requires extension sockets
+ */
+class UdpSocketTest extends TestCase
+{
+ public function testWeDoNotTruncateShortMessages()
+ {
+ $socket = $this->getMock('\Monolog\Handler\SyslogUdp\UdpSocket', array('send'), array('lol', 'lol'));
+
+ $socket->expects($this->at(0))
+ ->method('send')
+ ->with("HEADER: The quick brown fox jumps over the lazy dog");
+
+ $socket->write("The quick brown fox jumps over the lazy dog", "HEADER: ");
+ }
+
+ public function testLongMessagesAreTruncated()
+ {
+ $socket = $this->getMock('\Monolog\Handler\SyslogUdp\UdpSocket', array('send'), array('lol', 'lol'));
+
+ $truncatedString = str_repeat("derp", 16254).'d';
+
+ $socket->expects($this->exactly(1))
+ ->method('send')
+ ->with("HEADER" . $truncatedString);
+
+ $longString = str_repeat("derp", 20000);
+
+ $socket->write($longString, "HEADER");
+ }
+}
diff --git a/vendor/monolog/monolog/tests/Monolog/Handler/WhatFailureGroupHandlerTest.php b/vendor/monolog/monolog/tests/Monolog/Handler/WhatFailureGroupHandlerTest.php
new file mode 100644
index 00000000..8d37a1fc
--- /dev/null
+++ b/vendor/monolog/monolog/tests/Monolog/Handler/WhatFailureGroupHandlerTest.php
@@ -0,0 +1,121 @@
+<?php
+
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Handler;
+
+use Monolog\TestCase;
+use Monolog\Logger;
+
+class WhatFailureGroupHandlerTest extends TestCase
+{
+ /**
+ * @covers Monolog\Handler\WhatFailureGroupHandler::__construct
+ * @expectedException InvalidArgumentException
+ */
+ public function testConstructorOnlyTakesHandler()
+ {
+ new WhatFailureGroupHandler(array(new TestHandler(), "foo"));
+ }
+
+ /**
+ * @covers Monolog\Handler\WhatFailureGroupHandler::__construct
+ * @covers Monolog\Handler\WhatFailureGroupHandler::handle
+ */
+ public function testHandle()
+ {
+ $testHandlers = array(new TestHandler(), new TestHandler());
+ $handler = new WhatFailureGroupHandler($testHandlers);
+ $handler->handle($this->getRecord(Logger::DEBUG));
+ $handler->handle($this->getRecord(Logger::INFO));
+ foreach ($testHandlers as $test) {
+ $this->assertTrue($test->hasDebugRecords());
+ $this->assertTrue($test->hasInfoRecords());
+ $this->assertTrue(count($test->getRecords()) === 2);
+ }
+ }
+
+ /**
+ * @covers Monolog\Handler\WhatFailureGroupHandler::handleBatch
+ */
+ public function testHandleBatch()
+ {
+ $testHandlers = array(new TestHandler(), new TestHandler());
+ $handler = new WhatFailureGroupHandler($testHandlers);
+ $handler->handleBatch(array($this->getRecord(Logger::DEBUG), $this->getRecord(Logger::INFO)));
+ foreach ($testHandlers as $test) {
+ $this->assertTrue($test->hasDebugRecords());
+ $this->assertTrue($test->hasInfoRecords());
+ $this->assertTrue(count($test->getRecords()) === 2);
+ }
+ }
+
+ /**
+ * @covers Monolog\Handler\WhatFailureGroupHandler::isHandling
+ */
+ public function testIsHandling()
+ {
+ $testHandlers = array(new TestHandler(Logger::ERROR), new TestHandler(Logger::WARNING));
+ $handler = new WhatFailureGroupHandler($testHandlers);
+ $this->assertTrue($handler->isHandling($this->getRecord(Logger::ERROR)));
+ $this->assertTrue($handler->isHandling($this->getRecord(Logger::WARNING)));
+ $this->assertFalse($handler->isHandling($this->getRecord(Logger::DEBUG)));
+ }
+
+ /**
+ * @covers Monolog\Handler\WhatFailureGroupHandler::handle
+ */
+ public function testHandleUsesProcessors()
+ {
+ $test = new TestHandler();
+ $handler = new WhatFailureGroupHandler(array($test));
+ $handler->pushProcessor(function ($record) {
+ $record['extra']['foo'] = true;
+
+ return $record;
+ });
+ $handler->handle($this->getRecord(Logger::WARNING));
+ $this->assertTrue($test->hasWarningRecords());
+ $records = $test->getRecords();
+ $this->assertTrue($records[0]['extra']['foo']);
+ }
+
+ /**
+ * @covers Monolog\Handler\WhatFailureGroupHandler::handle
+ */
+ public function testHandleException()
+ {
+ $test = new TestHandler();
+ $exception = new ExceptionTestHandler();
+ $handler = new WhatFailureGroupHandler(array($exception, $test, $exception));
+ $handler->pushProcessor(function ($record) {
+ $record['extra']['foo'] = true;
+
+ return $record;
+ });
+ $handler->handle($this->getRecord(Logger::WARNING));
+ $this->assertTrue($test->hasWarningRecords());
+ $records = $test->getRecords();
+ $this->assertTrue($records[0]['extra']['foo']);
+ }
+}
+
+class ExceptionTestHandler extends TestHandler
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function handle(array $record)
+ {
+ parent::handle($record);
+
+ throw new \Exception("ExceptionTestHandler::handle");
+ }
+}
diff --git a/vendor/monolog/monolog/tests/Monolog/Handler/ZendMonitorHandlerTest.php b/vendor/monolog/monolog/tests/Monolog/Handler/ZendMonitorHandlerTest.php
new file mode 100644
index 00000000..416039e6
--- /dev/null
+++ b/vendor/monolog/monolog/tests/Monolog/Handler/ZendMonitorHandlerTest.php
@@ -0,0 +1,69 @@
+<?php
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Handler;
+
+use Monolog\TestCase;
+
+class ZendMonitorHandlerTest extends TestCase
+{
+ protected $zendMonitorHandler;
+
+ public function setUp()
+ {
+ if (!function_exists('zend_monitor_custom_event')) {
+ $this->markTestSkipped('ZendServer is not installed');
+ }
+ }
+
+ /**
+ * @covers Monolog\Handler\ZendMonitorHandler::write
+ */
+ public function testWrite()
+ {
+ $record = $this->getRecord();
+ $formatterResult = array(
+ 'message' => $record['message']
+ );
+
+ $zendMonitor = $this->getMockBuilder('Monolog\Handler\ZendMonitorHandler')
+ ->setMethods(array('writeZendMonitorCustomEvent', 'getDefaultFormatter'))
+ ->getMock();
+
+ $formatterMock = $this->getMockBuilder('Monolog\Formatter\NormalizerFormatter')
+ ->disableOriginalConstructor()
+ ->getMock();
+
+ $formatterMock->expects($this->once())
+ ->method('format')
+ ->will($this->returnValue($formatterResult));
+
+ $zendMonitor->expects($this->once())
+ ->method('getDefaultFormatter')
+ ->will($this->returnValue($formatterMock));
+
+ $levelMap = $zendMonitor->getLevelMap();
+
+ $zendMonitor->expects($this->once())
+ ->method('writeZendMonitorCustomEvent')
+ ->with($levelMap[$record['level']], $record['message'], $formatterResult);
+
+ $zendMonitor->handle($record);
+ }
+
+ /**
+ * @covers Monolog\Handler\ZendMonitorHandler::getDefaultFormatter
+ */
+ public function testGetDefaultFormatterReturnsNormalizerFormatter()
+ {
+ $zendMonitor = new ZendMonitorHandler();
+ $this->assertInstanceOf('Monolog\Formatter\NormalizerFormatter', $zendMonitor->getDefaultFormatter());
+ }
+}
diff --git a/vendor/monolog/monolog/tests/Monolog/LoggerTest.php b/vendor/monolog/monolog/tests/Monolog/LoggerTest.php
new file mode 100644
index 00000000..146b6f1b
--- /dev/null
+++ b/vendor/monolog/monolog/tests/Monolog/LoggerTest.php
@@ -0,0 +1,447 @@
+<?php
+
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog;
+
+use Monolog\Processor\WebProcessor;
+use Monolog\Handler\TestHandler;
+
+class LoggerTest extends \PHPUnit_Framework_TestCase
+{
+ /**
+ * @covers Monolog\Logger::getName
+ */
+ public function testGetName()
+ {
+ $logger = new Logger('foo');
+ $this->assertEquals('foo', $logger->getName());
+ }
+
+ /**
+ * @covers Monolog\Logger::getLevelName
+ */
+ public function testGetLevelName()
+ {
+ $this->assertEquals('ERROR', Logger::getLevelName(Logger::ERROR));
+ }
+
+ /**
+ * @covers Monolog\Logger::toMonologLevel
+ */
+ public function testConvertPSR3ToMonologLevel()
+ {
+ $this->assertEquals(Logger::toMonologLevel('debug'), 100);
+ $this->assertEquals(Logger::toMonologLevel('info'), 200);
+ $this->assertEquals(Logger::toMonologLevel('notice'), 250);
+ $this->assertEquals(Logger::toMonologLevel('warning'), 300);
+ $this->assertEquals(Logger::toMonologLevel('error'), 400);
+ $this->assertEquals(Logger::toMonologLevel('critical'), 500);
+ $this->assertEquals(Logger::toMonologLevel('alert'), 550);
+ $this->assertEquals(Logger::toMonologLevel('emergency'), 600);
+ }
+
+ /**
+ * @covers Monolog\Logger::getLevelName
+ * @expectedException InvalidArgumentException
+ */
+ public function testGetLevelNameThrows()
+ {
+ Logger::getLevelName(5);
+ }
+
+ /**
+ * @covers Monolog\Logger::__construct
+ */
+ public function testChannel()
+ {
+ $logger = new Logger('foo');
+ $handler = new TestHandler;
+ $logger->pushHandler($handler);
+ $logger->addWarning('test');
+ list($record) = $handler->getRecords();
+ $this->assertEquals('foo', $record['channel']);
+ }
+
+ /**
+ * @covers Monolog\Logger::addRecord
+ */
+ public function testLog()
+ {
+ $logger = new Logger(__METHOD__);
+
+ $handler = $this->getMock('Monolog\Handler\NullHandler', array('handle'));
+ $handler->expects($this->once())
+ ->method('handle');
+ $logger->pushHandler($handler);
+
+ $this->assertTrue($logger->addWarning('test'));
+ }
+
+ /**
+ * @covers Monolog\Logger::addRecord
+ */
+ public function testLogNotHandled()
+ {
+ $logger = new Logger(__METHOD__);
+
+ $handler = $this->getMock('Monolog\Handler\NullHandler', array('handle'), array(Logger::ERROR));
+ $handler->expects($this->never())
+ ->method('handle');
+ $logger->pushHandler($handler);
+
+ $this->assertFalse($logger->addWarning('test'));
+ }
+
+ public function testHandlersInCtor()
+ {
+ $handler1 = new TestHandler;
+ $handler2 = new TestHandler;
+ $logger = new Logger(__METHOD__, array($handler1, $handler2));
+
+ $this->assertEquals($handler1, $logger->popHandler());
+ $this->assertEquals($handler2, $logger->popHandler());
+ }
+
+ public function testProcessorsInCtor()
+ {
+ $processor1 = new WebProcessor;
+ $processor2 = new WebProcessor;
+ $logger = new Logger(__METHOD__, array(), array($processor1, $processor2));
+
+ $this->assertEquals($processor1, $logger->popProcessor());
+ $this->assertEquals($processor2, $logger->popProcessor());
+ }
+
+ /**
+ * @covers Monolog\Logger::pushHandler
+ * @covers Monolog\Logger::popHandler
+ * @expectedException LogicException
+ */
+ public function testPushPopHandler()
+ {
+ $logger = new Logger(__METHOD__);
+ $handler1 = new TestHandler;
+ $handler2 = new TestHandler;
+
+ $logger->pushHandler($handler1);
+ $logger->pushHandler($handler2);
+
+ $this->assertEquals($handler2, $logger->popHandler());
+ $this->assertEquals($handler1, $logger->popHandler());
+ $logger->popHandler();
+ }
+
+ /**
+ * @covers Monolog\Logger::pushProcessor
+ * @covers Monolog\Logger::popProcessor
+ * @expectedException LogicException
+ */
+ public function testPushPopProcessor()
+ {
+ $logger = new Logger(__METHOD__);
+ $processor1 = new WebProcessor;
+ $processor2 = new WebProcessor;
+
+ $logger->pushProcessor($processor1);
+ $logger->pushProcessor($processor2);
+
+ $this->assertEquals($processor2, $logger->popProcessor());
+ $this->assertEquals($processor1, $logger->popProcessor());
+ $logger->popProcessor();
+ }
+
+ /**
+ * @covers Monolog\Logger::pushProcessor
+ * @expectedException InvalidArgumentException
+ */
+ public function testPushProcessorWithNonCallable()
+ {
+ $logger = new Logger(__METHOD__);
+
+ $logger->pushProcessor(new \stdClass());
+ }
+
+ /**
+ * @covers Monolog\Logger::addRecord
+ */
+ public function testProcessorsAreExecuted()
+ {
+ $logger = new Logger(__METHOD__);
+ $handler = new TestHandler;
+ $logger->pushHandler($handler);
+ $logger->pushProcessor(function ($record) {
+ $record['extra']['win'] = true;
+
+ return $record;
+ });
+ $logger->addError('test');
+ list($record) = $handler->getRecords();
+ $this->assertTrue($record['extra']['win']);
+ }
+
+ /**
+ * @covers Monolog\Logger::addRecord
+ */
+ public function testProcessorsAreCalledOnlyOnce()
+ {
+ $logger = new Logger(__METHOD__);
+ $handler = $this->getMock('Monolog\Handler\HandlerInterface');
+ $handler->expects($this->any())
+ ->method('isHandling')
+ ->will($this->returnValue(true))
+ ;
+ $handler->expects($this->any())
+ ->method('handle')
+ ->will($this->returnValue(true))
+ ;
+ $logger->pushHandler($handler);
+
+ $processor = $this->getMockBuilder('Monolog\Processor\WebProcessor')
+ ->disableOriginalConstructor()
+ ->setMethods(array('__invoke'))
+ ->getMock()
+ ;
+ $processor->expects($this->once())
+ ->method('__invoke')
+ ->will($this->returnArgument(0))
+ ;
+ $logger->pushProcessor($processor);
+
+ $logger->addError('test');
+ }
+
+ /**
+ * @covers Monolog\Logger::addRecord
+ */
+ public function testProcessorsNotCalledWhenNotHandled()
+ {
+ $logger = new Logger(__METHOD__);
+ $handler = $this->getMock('Monolog\Handler\HandlerInterface');
+ $handler->expects($this->once())
+ ->method('isHandling')
+ ->will($this->returnValue(false))
+ ;
+ $logger->pushHandler($handler);
+ $that = $this;
+ $logger->pushProcessor(function ($record) use ($that) {
+ $that->fail('The processor should not be called');
+ });
+ $logger->addAlert('test');
+ }
+
+ /**
+ * @covers Monolog\Logger::addRecord
+ */
+ public function testHandlersNotCalledBeforeFirstHandling()
+ {
+ $logger = new Logger(__METHOD__);
+
+ $handler1 = $this->getMock('Monolog\Handler\HandlerInterface');
+ $handler1->expects($this->never())
+ ->method('isHandling')
+ ->will($this->returnValue(false))
+ ;
+ $handler1->expects($this->once())
+ ->method('handle')
+ ->will($this->returnValue(false))
+ ;
+ $logger->pushHandler($handler1);
+
+ $handler2 = $this->getMock('Monolog\Handler\HandlerInterface');
+ $handler2->expects($this->once())
+ ->method('isHandling')
+ ->will($this->returnValue(true))
+ ;
+ $handler2->expects($this->once())
+ ->method('handle')
+ ->will($this->returnValue(false))
+ ;
+ $logger->pushHandler($handler2);
+
+ $handler3 = $this->getMock('Monolog\Handler\HandlerInterface');
+ $handler3->expects($this->once())
+ ->method('isHandling')
+ ->will($this->returnValue(false))
+ ;
+ $handler3->expects($this->never())
+ ->method('handle')
+ ;
+ $logger->pushHandler($handler3);
+
+ $logger->debug('test');
+ }
+
+ /**
+ * @covers Monolog\Logger::addRecord
+ */
+ public function testBubblingWhenTheHandlerReturnsFalse()
+ {
+ $logger = new Logger(__METHOD__);
+
+ $handler1 = $this->getMock('Monolog\Handler\HandlerInterface');
+ $handler1->expects($this->any())
+ ->method('isHandling')
+ ->will($this->returnValue(true))
+ ;
+ $handler1->expects($this->once())
+ ->method('handle')
+ ->will($this->returnValue(false))
+ ;
+ $logger->pushHandler($handler1);
+
+ $handler2 = $this->getMock('Monolog\Handler\HandlerInterface');
+ $handler2->expects($this->any())
+ ->method('isHandling')
+ ->will($this->returnValue(true))
+ ;
+ $handler2->expects($this->once())
+ ->method('handle')
+ ->will($this->returnValue(false))
+ ;
+ $logger->pushHandler($handler2);
+
+ $logger->debug('test');
+ }
+
+ /**
+ * @covers Monolog\Logger::addRecord
+ */
+ public function testNotBubblingWhenTheHandlerReturnsTrue()
+ {
+ $logger = new Logger(__METHOD__);
+
+ $handler1 = $this->getMock('Monolog\Handler\HandlerInterface');
+ $handler1->expects($this->any())
+ ->method('isHandling')
+ ->will($this->returnValue(true))
+ ;
+ $handler1->expects($this->never())
+ ->method('handle')
+ ;
+ $logger->pushHandler($handler1);
+
+ $handler2 = $this->getMock('Monolog\Handler\HandlerInterface');
+ $handler2->expects($this->any())
+ ->method('isHandling')
+ ->will($this->returnValue(true))
+ ;
+ $handler2->expects($this->once())
+ ->method('handle')
+ ->will($this->returnValue(true))
+ ;
+ $logger->pushHandler($handler2);
+
+ $logger->debug('test');
+ }
+
+ /**
+ * @covers Monolog\Logger::isHandling
+ */
+ public function testIsHandling()
+ {
+ $logger = new Logger(__METHOD__);
+
+ $handler1 = $this->getMock('Monolog\Handler\HandlerInterface');
+ $handler1->expects($this->any())
+ ->method('isHandling')
+ ->will($this->returnValue(false))
+ ;
+
+ $logger->pushHandler($handler1);
+ $this->assertFalse($logger->isHandling(Logger::DEBUG));
+
+ $handler2 = $this->getMock('Monolog\Handler\HandlerInterface');
+ $handler2->expects($this->any())
+ ->method('isHandling')
+ ->will($this->returnValue(true))
+ ;
+
+ $logger->pushHandler($handler2);
+ $this->assertTrue($logger->isHandling(Logger::DEBUG));
+ }
+
+ /**
+ * @dataProvider logMethodProvider
+ * @covers Monolog\Logger::addDebug
+ * @covers Monolog\Logger::addInfo
+ * @covers Monolog\Logger::addNotice
+ * @covers Monolog\Logger::addWarning
+ * @covers Monolog\Logger::addError
+ * @covers Monolog\Logger::addCritical
+ * @covers Monolog\Logger::addAlert
+ * @covers Monolog\Logger::addEmergency
+ * @covers Monolog\Logger::debug
+ * @covers Monolog\Logger::info
+ * @covers Monolog\Logger::notice
+ * @covers Monolog\Logger::warn
+ * @covers Monolog\Logger::err
+ * @covers Monolog\Logger::crit
+ * @covers Monolog\Logger::alert
+ * @covers Monolog\Logger::emerg
+ */
+ public function testLogMethods($method, $expectedLevel)
+ {
+ $logger = new Logger('foo');
+ $handler = new TestHandler;
+ $logger->pushHandler($handler);
+ $logger->{$method}('test');
+ list($record) = $handler->getRecords();
+ $this->assertEquals($expectedLevel, $record['level']);
+ }
+
+ public function logMethodProvider()
+ {
+ return array(
+ // monolog methods
+ array('addDebug', Logger::DEBUG),
+ array('addInfo', Logger::INFO),
+ array('addNotice', Logger::NOTICE),
+ array('addWarning', Logger::WARNING),
+ array('addError', Logger::ERROR),
+ array('addCritical', Logger::CRITICAL),
+ array('addAlert', Logger::ALERT),
+ array('addEmergency', Logger::EMERGENCY),
+
+ // ZF/Sf2 compat methods
+ array('debug', Logger::DEBUG),
+ array('info', Logger::INFO),
+ array('notice', Logger::NOTICE),
+ array('warn', Logger::WARNING),
+ array('err', Logger::ERROR),
+ array('crit', Logger::CRITICAL),
+ array('alert', Logger::ALERT),
+ array('emerg', Logger::EMERGENCY),
+ );
+ }
+
+ /**
+ * @dataProvider setTimezoneProvider
+ * @covers Monolog\Logger::setTimezone
+ */
+ public function testSetTimezone($tz)
+ {
+ Logger::setTimezone($tz);
+ $logger = new Logger('foo');
+ $handler = new TestHandler;
+ $logger->pushHandler($handler);
+ $logger->info('test');
+ list($record) = $handler->getRecords();
+ $this->assertEquals($tz, $record['datetime']->getTimezone());
+ }
+
+ public function setTimezoneProvider()
+ {
+ return array_map(
+ function ($tz) { return array(new \DateTimeZone($tz)); },
+ \DateTimeZone::listIdentifiers()
+ );
+ }
+}
diff --git a/vendor/monolog/monolog/tests/Monolog/Processor/GitProcessorTest.php b/vendor/monolog/monolog/tests/Monolog/Processor/GitProcessorTest.php
new file mode 100644
index 00000000..5adb505d
--- /dev/null
+++ b/vendor/monolog/monolog/tests/Monolog/Processor/GitProcessorTest.php
@@ -0,0 +1,29 @@
+<?php
+
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Processor;
+
+use Monolog\TestCase;
+
+class GitProcessorTest extends TestCase
+{
+ /**
+ * @covers Monolog\Processor\GitProcessor::__invoke
+ */
+ public function testProcessor()
+ {
+ $processor = new GitProcessor();
+ $record = $processor($this->getRecord());
+
+ $this->assertArrayHasKey('git', $record['extra']);
+ $this->assertTrue(!is_array($record['extra']['git']['branch']));
+ }
+}
diff --git a/vendor/monolog/monolog/tests/Monolog/Processor/IntrospectionProcessorTest.php b/vendor/monolog/monolog/tests/Monolog/Processor/IntrospectionProcessorTest.php
new file mode 100644
index 00000000..0dd411d7
--- /dev/null
+++ b/vendor/monolog/monolog/tests/Monolog/Processor/IntrospectionProcessorTest.php
@@ -0,0 +1,123 @@
+<?php
+
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Acme;
+
+class Tester
+{
+ public function test($handler, $record)
+ {
+ $handler->handle($record);
+ }
+}
+
+function tester($handler, $record)
+{
+ $handler->handle($record);
+}
+
+namespace Monolog\Processor;
+
+use Monolog\Logger;
+use Monolog\TestCase;
+use Monolog\Handler\TestHandler;
+
+class IntrospectionProcessorTest extends TestCase
+{
+ public function getHandler()
+ {
+ $processor = new IntrospectionProcessor();
+ $handler = new TestHandler();
+ $handler->pushProcessor($processor);
+
+ return $handler;
+ }
+
+ public function testProcessorFromClass()
+ {
+ $handler = $this->getHandler();
+ $tester = new \Acme\Tester;
+ $tester->test($handler, $this->getRecord());
+ list($record) = $handler->getRecords();
+ $this->assertEquals(__FILE__, $record['extra']['file']);
+ $this->assertEquals(18, $record['extra']['line']);
+ $this->assertEquals('Acme\Tester', $record['extra']['class']);
+ $this->assertEquals('test', $record['extra']['function']);
+ }
+
+ public function testProcessorFromFunc()
+ {
+ $handler = $this->getHandler();
+ \Acme\tester($handler, $this->getRecord());
+ list($record) = $handler->getRecords();
+ $this->assertEquals(__FILE__, $record['extra']['file']);
+ $this->assertEquals(24, $record['extra']['line']);
+ $this->assertEquals(null, $record['extra']['class']);
+ $this->assertEquals('Acme\tester', $record['extra']['function']);
+ }
+
+ public function testLevelTooLow()
+ {
+ $input = array(
+ 'level' => Logger::DEBUG,
+ 'extra' => array(),
+ );
+
+ $expected = $input;
+
+ $processor = new IntrospectionProcessor(Logger::CRITICAL);
+ $actual = $processor($input);
+
+ $this->assertEquals($expected, $actual);
+ }
+
+ public function testLevelEqual()
+ {
+ $input = array(
+ 'level' => Logger::CRITICAL,
+ 'extra' => array(),
+ );
+
+ $expected = $input;
+ $expected['extra'] = array(
+ 'file' => null,
+ 'line' => null,
+ 'class' => 'ReflectionMethod',
+ 'function' => 'invokeArgs',
+ );
+
+ $processor = new IntrospectionProcessor(Logger::CRITICAL);
+ $actual = $processor($input);
+
+ $this->assertEquals($expected, $actual);
+ }
+
+ public function testLevelHigher()
+ {
+ $input = array(
+ 'level' => Logger::EMERGENCY,
+ 'extra' => array(),
+ );
+
+ $expected = $input;
+ $expected['extra'] = array(
+ 'file' => null,
+ 'line' => null,
+ 'class' => 'ReflectionMethod',
+ 'function' => 'invokeArgs',
+ );
+
+ $processor = new IntrospectionProcessor(Logger::CRITICAL);
+ $actual = $processor($input);
+
+ $this->assertEquals($expected, $actual);
+ }
+}
diff --git a/vendor/monolog/monolog/tests/Monolog/Processor/MemoryPeakUsageProcessorTest.php b/vendor/monolog/monolog/tests/Monolog/Processor/MemoryPeakUsageProcessorTest.php
new file mode 100644
index 00000000..eb666144
--- /dev/null
+++ b/vendor/monolog/monolog/tests/Monolog/Processor/MemoryPeakUsageProcessorTest.php
@@ -0,0 +1,42 @@
+<?php
+
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Processor;
+
+use Monolog\TestCase;
+
+class MemoryPeakUsageProcessorTest extends TestCase
+{
+ /**
+ * @covers Monolog\Processor\MemoryPeakUsageProcessor::__invoke
+ * @covers Monolog\Processor\MemoryProcessor::formatBytes
+ */
+ public function testProcessor()
+ {
+ $processor = new MemoryPeakUsageProcessor();
+ $record = $processor($this->getRecord());
+ $this->assertArrayHasKey('memory_peak_usage', $record['extra']);
+ $this->assertRegExp('#[0-9.]+ (M|K)?B$#', $record['extra']['memory_peak_usage']);
+ }
+
+ /**
+ * @covers Monolog\Processor\MemoryPeakUsageProcessor::__invoke
+ * @covers Monolog\Processor\MemoryProcessor::formatBytes
+ */
+ public function testProcessorWithoutFormatting()
+ {
+ $processor = new MemoryPeakUsageProcessor(true, false);
+ $record = $processor($this->getRecord());
+ $this->assertArrayHasKey('memory_peak_usage', $record['extra']);
+ $this->assertInternalType('int', $record['extra']['memory_peak_usage']);
+ $this->assertGreaterThan(0, $record['extra']['memory_peak_usage']);
+ }
+}
diff --git a/vendor/monolog/monolog/tests/Monolog/Processor/MemoryUsageProcessorTest.php b/vendor/monolog/monolog/tests/Monolog/Processor/MemoryUsageProcessorTest.php
new file mode 100644
index 00000000..4692dbfc
--- /dev/null
+++ b/vendor/monolog/monolog/tests/Monolog/Processor/MemoryUsageProcessorTest.php
@@ -0,0 +1,42 @@
+<?php
+
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Processor;
+
+use Monolog\TestCase;
+
+class MemoryUsageProcessorTest extends TestCase
+{
+ /**
+ * @covers Monolog\Processor\MemoryUsageProcessor::__invoke
+ * @covers Monolog\Processor\MemoryProcessor::formatBytes
+ */
+ public function testProcessor()
+ {
+ $processor = new MemoryUsageProcessor();
+ $record = $processor($this->getRecord());
+ $this->assertArrayHasKey('memory_usage', $record['extra']);
+ $this->assertRegExp('#[0-9.]+ (M|K)?B$#', $record['extra']['memory_usage']);
+ }
+
+ /**
+ * @covers Monolog\Processor\MemoryUsageProcessor::__invoke
+ * @covers Monolog\Processor\MemoryProcessor::formatBytes
+ */
+ public function testProcessorWithoutFormatting()
+ {
+ $processor = new MemoryUsageProcessor(true, false);
+ $record = $processor($this->getRecord());
+ $this->assertArrayHasKey('memory_usage', $record['extra']);
+ $this->assertInternalType('int', $record['extra']['memory_usage']);
+ $this->assertGreaterThan(0, $record['extra']['memory_usage']);
+ }
+}
diff --git a/vendor/monolog/monolog/tests/Monolog/Processor/ProcessIdProcessorTest.php b/vendor/monolog/monolog/tests/Monolog/Processor/ProcessIdProcessorTest.php
new file mode 100644
index 00000000..458d2a33
--- /dev/null
+++ b/vendor/monolog/monolog/tests/Monolog/Processor/ProcessIdProcessorTest.php
@@ -0,0 +1,30 @@
+<?php
+
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Processor;
+
+use Monolog\TestCase;
+
+class ProcessIdProcessorTest extends TestCase
+{
+ /**
+ * @covers Monolog\Processor\ProcessIdProcessor::__invoke
+ */
+ public function testProcessor()
+ {
+ $processor = new ProcessIdProcessor();
+ $record = $processor($this->getRecord());
+ $this->assertArrayHasKey('process_id', $record['extra']);
+ $this->assertInternalType('int', $record['extra']['process_id']);
+ $this->assertGreaterThan(0, $record['extra']['process_id']);
+ $this->assertEquals(getmypid(), $record['extra']['process_id']);
+ }
+}
diff --git a/vendor/monolog/monolog/tests/Monolog/Processor/PsrLogMessageProcessorTest.php b/vendor/monolog/monolog/tests/Monolog/Processor/PsrLogMessageProcessorTest.php
new file mode 100644
index 00000000..81bfbdc3
--- /dev/null
+++ b/vendor/monolog/monolog/tests/Monolog/Processor/PsrLogMessageProcessorTest.php
@@ -0,0 +1,43 @@
+<?php
+
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Processor;
+
+class PsrLogMessageProcessorTest extends \PHPUnit_Framework_TestCase
+{
+ /**
+ * @dataProvider getPairs
+ */
+ public function testReplacement($val, $expected)
+ {
+ $proc = new PsrLogMessageProcessor;
+
+ $message = $proc(array(
+ 'message' => '{foo}',
+ 'context' => array('foo' => $val)
+ ));
+ $this->assertEquals($expected, $message['message']);
+ }
+
+ public function getPairs()
+ {
+ return array(
+ array('foo', 'foo'),
+ array('3', '3'),
+ array(3, '3'),
+ array(null, ''),
+ array(true, '1'),
+ array(false, ''),
+ array(new \stdClass, '[object stdClass]'),
+ array(array(), '[array]'),
+ );
+ }
+}
diff --git a/vendor/monolog/monolog/tests/Monolog/Processor/TagProcessorTest.php b/vendor/monolog/monolog/tests/Monolog/Processor/TagProcessorTest.php
new file mode 100644
index 00000000..851a9dc2
--- /dev/null
+++ b/vendor/monolog/monolog/tests/Monolog/Processor/TagProcessorTest.php
@@ -0,0 +1,29 @@
+<?php
+
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Processor;
+
+use Monolog\TestCase;
+
+class TagProcessorTest extends TestCase
+{
+ /**
+ * @covers Monolog\Processor\TagProcessor::__invoke
+ */
+ public function testProcessor()
+ {
+ $tags = array(1, 2, 3);
+ $processor = new TagProcessor($tags);
+ $record = $processor($this->getRecord());
+
+ $this->assertEquals($tags, $record['extra']['tags']);
+ }
+}
diff --git a/vendor/monolog/monolog/tests/Monolog/Processor/UidProcessorTest.php b/vendor/monolog/monolog/tests/Monolog/Processor/UidProcessorTest.php
new file mode 100644
index 00000000..7ced62ca
--- /dev/null
+++ b/vendor/monolog/monolog/tests/Monolog/Processor/UidProcessorTest.php
@@ -0,0 +1,27 @@
+<?php
+
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Processor;
+
+use Monolog\TestCase;
+
+class UidProcessorTest extends TestCase
+{
+ /**
+ * @covers Monolog\Processor\UidProcessor::__invoke
+ */
+ public function testProcessor()
+ {
+ $processor = new UidProcessor();
+ $record = $processor($this->getRecord());
+ $this->assertArrayHasKey('uid', $record['extra']);
+ }
+}
diff --git a/vendor/monolog/monolog/tests/Monolog/Processor/WebProcessorTest.php b/vendor/monolog/monolog/tests/Monolog/Processor/WebProcessorTest.php
new file mode 100644
index 00000000..dba89412
--- /dev/null
+++ b/vendor/monolog/monolog/tests/Monolog/Processor/WebProcessorTest.php
@@ -0,0 +1,98 @@
+<?php
+
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Processor;
+
+use Monolog\TestCase;
+
+class WebProcessorTest extends TestCase
+{
+ public function testProcessor()
+ {
+ $server = array(
+ 'REQUEST_URI' => 'A',
+ 'REMOTE_ADDR' => 'B',
+ 'REQUEST_METHOD' => 'C',
+ 'HTTP_REFERER' => 'D',
+ 'SERVER_NAME' => 'F',
+ 'UNIQUE_ID' => 'G',
+ );
+
+ $processor = new WebProcessor($server);
+ $record = $processor($this->getRecord());
+ $this->assertEquals($server['REQUEST_URI'], $record['extra']['url']);
+ $this->assertEquals($server['REMOTE_ADDR'], $record['extra']['ip']);
+ $this->assertEquals($server['REQUEST_METHOD'], $record['extra']['http_method']);
+ $this->assertEquals($server['HTTP_REFERER'], $record['extra']['referrer']);
+ $this->assertEquals($server['SERVER_NAME'], $record['extra']['server']);
+ $this->assertEquals($server['UNIQUE_ID'], $record['extra']['unique_id']);
+ }
+
+ public function testProcessorDoNothingIfNoRequestUri()
+ {
+ $server = array(
+ 'REMOTE_ADDR' => 'B',
+ 'REQUEST_METHOD' => 'C',
+ );
+ $processor = new WebProcessor($server);
+ $record = $processor($this->getRecord());
+ $this->assertEmpty($record['extra']);
+ }
+
+ public function testProcessorReturnNullIfNoHttpReferer()
+ {
+ $server = array(
+ 'REQUEST_URI' => 'A',
+ 'REMOTE_ADDR' => 'B',
+ 'REQUEST_METHOD' => 'C',
+ 'SERVER_NAME' => 'F',
+ );
+ $processor = new WebProcessor($server);
+ $record = $processor($this->getRecord());
+ $this->assertNull($record['extra']['referrer']);
+ }
+
+ public function testProcessorDoesNotAddUniqueIdIfNotPresent()
+ {
+ $server = array(
+ 'REQUEST_URI' => 'A',
+ 'REMOTE_ADDR' => 'B',
+ 'REQUEST_METHOD' => 'C',
+ 'SERVER_NAME' => 'F',
+ );
+ $processor = new WebProcessor($server);
+ $record = $processor($this->getRecord());
+ $this->assertFalse(isset($record['extra']['unique_id']));
+ }
+
+ public function testProcessorAddsOnlyRequestedExtraFields()
+ {
+ $server = array(
+ 'REQUEST_URI' => 'A',
+ 'REMOTE_ADDR' => 'B',
+ 'REQUEST_METHOD' => 'C',
+ 'SERVER_NAME' => 'F',
+ );
+
+ $processor = new WebProcessor($server, array('url', 'http_method'));
+ $record = $processor($this->getRecord());
+
+ $this->assertSame(array('url' => 'A', 'http_method' => 'C'), $record['extra']);
+ }
+
+ /**
+ * @expectedException UnexpectedValueException
+ */
+ public function testInvalidData()
+ {
+ new WebProcessor(new \stdClass);
+ }
+}
diff --git a/vendor/monolog/monolog/tests/Monolog/PsrLogCompatTest.php b/vendor/monolog/monolog/tests/Monolog/PsrLogCompatTest.php
new file mode 100644
index 00000000..ab899449
--- /dev/null
+++ b/vendor/monolog/monolog/tests/Monolog/PsrLogCompatTest.php
@@ -0,0 +1,47 @@
+<?php
+
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog;
+
+use Monolog\Handler\TestHandler;
+use Monolog\Formatter\LineFormatter;
+use Monolog\Processor\PsrLogMessageProcessor;
+use Psr\Log\Test\LoggerInterfaceTest;
+
+class PsrLogCompatTest extends LoggerInterfaceTest
+{
+ private $handler;
+
+ public function getLogger()
+ {
+ $logger = new Logger('foo');
+ $logger->pushHandler($handler = new TestHandler);
+ $logger->pushProcessor(new PsrLogMessageProcessor);
+ $handler->setFormatter(new LineFormatter('%level_name% %message%'));
+
+ $this->handler = $handler;
+
+ return $logger;
+ }
+
+ public function getLogs()
+ {
+ $convert = function ($record) {
+ $lower = function ($match) {
+ return strtolower($match[0]);
+ };
+
+ return preg_replace_callback('{^[A-Z]+}', $lower, $record['formatted']);
+ };
+
+ return array_map($convert, $this->handler->getRecords());
+ }
+}
diff --git a/vendor/monolog/monolog/tests/Monolog/RegistryTest.php b/vendor/monolog/monolog/tests/Monolog/RegistryTest.php
new file mode 100644
index 00000000..29925f8a
--- /dev/null
+++ b/vendor/monolog/monolog/tests/Monolog/RegistryTest.php
@@ -0,0 +1,63 @@
+<?php
+
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog;
+
+
+class RegistryTest extends \PHPUnit_Framework_TestCase
+{
+ protected function setUp()
+ {
+ Registry::clear();
+ }
+
+ /**
+ * @dataProvider hasLoggerProvider
+ * @covers Monolog\Registry::hasLogger
+ */
+ public function testHasLogger(array $loggersToAdd, array $loggersToCheck, array $expectedResult)
+ {
+ foreach ($loggersToAdd as $loggerToAdd) {
+ Registry::addLogger($loggerToAdd);
+ }
+ foreach ($loggersToCheck as $index => $loggerToCheck) {
+ $this->assertSame($expectedResult[$index], Registry::hasLogger($loggerToCheck));
+ }
+ }
+
+ public function hasLoggerProvider()
+ {
+ $logger1 = new Logger('test1');
+ $logger2 = new Logger('test2');
+ $logger3 = new Logger('test3');
+
+ return array(
+ // only instances
+ array(
+ array($logger1),
+ array($logger1, $logger2),
+ array(true, false),
+ ),
+ // only names
+ array(
+ array($logger1),
+ array('test1', 'test2'),
+ array(true, false),
+ ),
+ // mixed case
+ array(
+ array($logger1, $logger2),
+ array('test1', $logger2, 'test3', $logger3),
+ array(true, true, false, false),
+ ),
+ );
+ }
+}
diff --git a/vendor/monolog/monolog/tests/Monolog/TestCase.php b/vendor/monolog/monolog/tests/Monolog/TestCase.php
new file mode 100644
index 00000000..cae79340
--- /dev/null
+++ b/vendor/monolog/monolog/tests/Monolog/TestCase.php
@@ -0,0 +1,58 @@
+<?php
+
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog;
+
+class TestCase extends \PHPUnit_Framework_TestCase
+{
+ /**
+ * @return array Record
+ */
+ protected function getRecord($level = Logger::WARNING, $message = 'test', $context = array())
+ {
+ return array(
+ 'message' => $message,
+ 'context' => $context,
+ 'level' => $level,
+ 'level_name' => Logger::getLevelName($level),
+ 'channel' => 'test',
+ 'datetime' => \DateTime::createFromFormat('U.u', sprintf('%.6F', microtime(true))),
+ 'extra' => array(),
+ );
+ }
+
+ /**
+ * @return array
+ */
+ protected function getMultipleRecords()
+ {
+ return array(
+ $this->getRecord(Logger::DEBUG, 'debug message 1'),
+ $this->getRecord(Logger::DEBUG, 'debug message 2'),
+ $this->getRecord(Logger::INFO, 'information'),
+ $this->getRecord(Logger::WARNING, 'warning'),
+ $this->getRecord(Logger::ERROR, 'error')
+ );
+ }
+
+ /**
+ * @return Monolog\Formatter\FormatterInterface
+ */
+ protected function getIdentityFormatter()
+ {
+ $formatter = $this->getMock('Monolog\\Formatter\\FormatterInterface');
+ $formatter->expects($this->any())
+ ->method('format')
+ ->will($this->returnCallback(function ($record) { return $record['message']; }));
+
+ return $formatter;
+ }
+}
diff --git a/vendor/nmred/kafka-php/LICENSE b/vendor/nmred/kafka-php/LICENSE
new file mode 100644
index 00000000..96d08492
--- /dev/null
+++ b/vendor/nmred/kafka-php/LICENSE
@@ -0,0 +1,27 @@
+Copyright (c) 2014, SWANSOFT
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+* Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+
+* Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+* Neither the name of the {organization} nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/vendor/nmred/kafka-php/README.md b/vendor/nmred/kafka-php/README.md
new file mode 100644
index 00000000..5ed12e23
--- /dev/null
+++ b/vendor/nmred/kafka-php/README.md
@@ -0,0 +1,496 @@
+Kafka-php
+==========
+
+[![Build Status](https://travis-ci.org/nmred/kafka-php.svg?branch=master)](https://travis-ci.org/nmred/Kafka-php)
+
+Kafka-php is a php client with Zookeeper integration for apache Kafka. It only supports the latest version of Kafka 0.8 which is still under development, so this module is _not production ready_ so far.
+
+The Zookeeper integration does the following jobs:
+
+* Loads broker metadata from Zookeeper before we can communicate with the Kafka server
+* Watches broker state, if broker changes, the client will refresh broker and topic metadata stored in the client
+
+## Requirements
+
+* Minimum PHP version: 5.3.3.
+* Apache Kafka 0.8.x
+* You need to have access to your Kafka instance and be able to connect through TCP. You can obtain a copy and instructions on how to setup kafka at https://github.com/kafka-dev/kafka [kafka-08-quick-start](https://cwiki.apache.org/KAFKA/kafka-08-quick-start.html)
+* The [PHP Zookeeper extension](https://github.com/andreiz/php-zookeeper) is required if you want to use the Zookeeper-based consumer.
+* Productor can not dependency zookeeper
+
+## Installation
+Add the lib directory to the PHP include_path and use an autoloader like the one in the examples directory (the code follows the PEAR/Zend one-class-per-file convention).
+
+## Composer Install
+
+Simply add a dependency on nmred/kafka-php to your project's composer.json file if you use Composer to manage the dependencies of your project. Here is a minimal example of a composer.json file :
+
+```
+{
+ "require": {
+ "nmred/kafka-php": "0.1.*"
+ }
+}
+```
+
+## Produce
+
+### \Kafka\Produce::getInstance($hostList, $timeout)
+
+* `hostList` : zookeeper host list , example 127.0.0.1:2181,192.168.1.114:2181
+* `timeout` : zookeeper timeout
+
+### \Kafka\Produce::setRequireAck($ack = -1)
+
+* `ack`: This field indicates how many acknowledgements the servers should receive before responding to the request.
+
+### \Kafka\Produce::setMessages($topicName, $partitionId, $messages)
+
+* `topicName` : The topic that data is being published to.
+* `partitionId` : The partition that data is being published to.
+* `messages` : [Array] publish message.
+
+### \Kafka\Produce::send()
+
+send message sets to the server.
+
+### Example
+
+``` php
+$produce = \Kafka\Produce::getInstance('localhost:2181', 3000);
+
+$produce->setRequireAck(-1);
+$produce->setMessages('test', 0, array('test1111111'));
+$produce->setMessages('test6', 0, array('test1111111'));
+$produce->setMessages('test6', 2, array('test1111111'));
+$produce->setMessages('test6', 1, array('test111111111133'));
+$result = $produce->send();
+var_dump($result);
+
+```
+
+## Consumer
+
+### \Kafka\Consumer::getInstance($hostList, $timeout)
+
+* `hostList` : zookeeper host list , example 127.0.0.1:2181,192.168.1.114:2181
+* `timeout` : zookeeper timeout
+
+### \Kafka\Consumer::setGroup($groupName)
+
+* `groupName` : Specify consumer group.
+
+### \Kafka\Consumer::setPartition($topicName, $partitionId, $offset = 0)
+
+* `topicName` : The topic that data is being fetch to.
+* `partitionId` : The partition that data is being fetch to.
+* `offset`: set fetch offset. default `0`.
+
+### \Kafka\Consumer::fetch()
+
+return fetch message Iterator. `\Kafka\Protocol\Fetch\Topic`
+
+### \Kafka\Protocol\Fetch\Topic
+
+this object is iterator
+
+`key` : topic name
+`value`: `\Kafka\Protocol\Fetch\Partition`
+
+### \Kafka\Protocol\Fetch\Partition
+
+this object is iterator.
+
+`key`: partition id
+`value`: messageSet object
+
+#### \Kafka\Protocol\Fetch\Partition::getErrCode()
+
+return partition fetch errcode.
+
+#### \Kafka\Protocol\Fetch\Partition::getHighOffset()
+
+return partition fetch offset.
+
+### \Kafka\Protocol\Fetch\MessageSet
+
+this object is iterator. `\Kafka\Protocol\Fetch\Message`
+
+### Example
+
+``` php
+$consumer = \Kafka\Consumer::getInstance('localhost:2181');
+
+$consumer->setGroup('testgroup');
+$consumer->setPartition('test', 0);
+$consumer->setPartition('test6', 2, 10);
+$result = $consumer->fetch();
+foreach ($result as $topicName => $topic) {
+ foreach ($topic as $partId => $partition) {
+ var_dump($partition->getHighOffset());
+ foreach ($partition as $message) {
+ var_dump((string)$message);
+ }
+ }
+}
+```
+
+## Basic Protocol
+### Produce API
+
+The produce API is used to send message sets to the server. For efficiency it allows sending message sets intended for many topic partitions in a single request.
+
+\Kafka\Protocol\Encoder::produceRequest
+
+#### Param struct
+``` php
+array(
+ 'required_ack' => 1,
+ // This field indicates how many acknowledgements the servers should receive before responding to the request. default `0`
+ // If it is 0 the server will not send any response
+ // If it is -1 the server will block until the message is committed by all in sync replicas before sending a response
+ // For any number > 1 the server will block waiting for this number of acknowledgements to occur
+ 'timeout' => 1000,
+ // This provides a maximum time in milliseconds the server can await the receipt of the number of acknowledgements in RequiredAcks.
+ 'data' => array(
+ array(
+ 'topic_name' => 'testtopic',
+ // The topic that data is being published to.[String]
+ 'partitions' => array(
+ array(
+ 'partition_id' => 0,
+ // The partition that data is being published to.
+ 'messages' => array(
+ 'message1',
+ // [String] message
+ ),
+ ),
+ ),
+ ),
+ ),
+);
+```
+
+#### Return
+
+Array
+
+#### Example
+
+``` php
+
+$data = array(
+ 'required_ack' => 1,
+ 'timeout' => 1000,
+ 'data' => array(
+ array(
+ 'topic_name' => 'test',
+ 'partitions' => array(
+ array(
+ 'partition_id' => 0,
+ 'messages' => array(
+ 'message1',
+ 'message2',
+ ),
+ ),
+ ),
+ ),
+ ),
+);
+
+$conn = new \Kafka\Socket('localhost', '9092');
+$conn->connect();
+$encoder = new \Kafka\Protocol\Encoder($conn);
+$encoder->produceRequest($data);
+
+$decoder = new \Kafka\Protocol\Decoder($conn);
+$result = $decoder->produceResponse();
+var_dump($result);
+
+```
+### Fetch API
+
+The fetch API is used to fetch a chunk of one or more logs for some topic-partitions. Logically one specifies the topics, partitions, and starting offset at which to begin the fetch and gets back a chunk of messages
+
+\Kafka\Protocol\Encoder::fetchRequest
+
+#### Param struct
+``` php
+array(
+ 'replica_id' => -1,
+ // The replica id indicates the node id of the replica initiating this request. default `-1`
+ 'max_wait_time' => 100,
+ // The max wait time is the maximum amount of time in milliseconds to block waiting if insufficient data is available at the time the request is issued. default 100 ms.
+ 'min_bytes' => 64 * 1024 // 64k
+ // This is the minimum number of bytes of messages that must be available to give a response. default 64k.
+ 'data' => array(
+ array(
+ 'topic_name' => 'testtopic',
+ // The topic that data is being published to.[String]
+ 'partitions' => array(
+ array(
+ 'partition_id' => 0,
+ // The partition that data is being published to.
+ 'offset' => 0,
+ // The offset to begin this fetch from. default 0
+ 'max_bytes' => 100 * 1024 * 1024,
+ // This is the minimum number of bytes of messages that must be available to give a response. default 100Mb
+ ),
+ ),
+ ),
+ ),
+);
+```
+
+#### Return
+
+\Kafka\Protocol\Fetch\Topic iterator
+
+#### Example
+``` php
+
+$data = array(
+ 'data' => array(
+ array(
+ 'topic_name' => 'test',
+ 'partitions' => array(
+ array(
+ 'partition_id' => 0,
+ 'offset' => 0,
+ ),
+ ),
+ ),
+ ),
+);
+
+$conn = new \Kafka\Socket('localhost', '9092');
+$conn->connect();
+$encoder = new \Kafka\Protocol\Encoder($conn);
+$encoder->fetchRequest($data);
+
+$decoder = new \Kafka\Protocol\Decoder($conn);
+$result = $decoder->fetchResponse();
+var_dump($result);
+
+```
+### Offset API
+
+This API describes the valid offset range available for a set of topic-partitions. As with the produce and fetch APIs requests must be directed to the broker that is currently the leader for the partitions in question. This can be determined using the metadata API.
+
+\Kafka\Protocol\Encoder::offsetRequest
+
+####param struct
+``` php
+array(
+ 'replica_id' => -1,
+ // The replica id indicates the node id of the replica initiating this request. default `-1`
+ 'data' => array(
+ array(
+ 'topic_name' => 'testtopic',
+ // The topic that data is being published to.[String]
+ 'partitions' => array(
+ array(
+ 'partition_id' => 0,
+ // The partition that get offset .
+ 'time' => -1,
+ // Used to ask for all messages before a certain time (ms).
+ // Specify -1 to receive the latest offsets
+ // Specify -2 to receive the earliest available offset.
+ 'max_offset' => 1,
+ // max return offset element. default 10000.
+ ),
+ ),
+ ),
+ ),
+);
+```
+
+#### Return
+
+Array.
+
+#### Example
+
+``` php
+
+$data = array(
+ 'data' => array(
+ array(
+ 'topic_name' => 'test',
+ 'partitions' => array(
+ array(
+ 'partition_id' => 0,
+ 'max_offset' => 10,
+ 'time' => -1,
+ ),
+ ),
+ ),
+ ),
+);
+
+$conn = new \Kafka\Socket('localhost', '9092');
+$conn->connect();
+$encoder = new \Kafka\Protocol\Encoder($conn);
+$encoder->offsetRequest($data);
+
+$decoder = new \Kafka\Protocol\Decoder($conn);
+$result = $decoder->offsetResponse();
+var_dump($result);
+
+```
+### Metadata API
+
+The metdata returned is at the partition level, but grouped together by topic for convenience and to avoid redundancy. For each partition the metadata contains the information for the leader as well as for all the replicas and the list of replicas that are currently in-sync.
+
+\Kafka\Protocol\Encoder::metadataRequest
+
+####param struct
+``` php
+array(
+ 'topic_name1', // topic name
+);
+```
+
+#### Return
+
+Array.
+
+#### Example
+
+``` php
+
+$data = array(
+ 'test'
+);
+
+$conn = new \Kafka\Socket('localhost', '9092');
+$conn->connect();
+$encoder = new \Kafka\Protocol\Encoder($conn);
+$encoder->metadataRequest($data);
+
+$decoder = new \Kafka\Protocol\Decoder($conn);
+$result = $decoder->metadataResponse();
+var_dump($result);
+
+```
+### Offset Commit API
+
+These APIs allow for centralized management of offsets.
+
+\Kafka\Protocol\Encoder::commitOffsetRequest
+
+####param struct
+``` php
+array(
+ 'group_id' => 'testgroup',
+ // consumer group
+ 'data' => array(
+ array(
+ 'topic_name' => 'testtopic',
+ // The topic that data is being published to.[String]
+ 'partitions' => array(
+ array(
+ 'partition_id' => 0,
+ // The partition that get offset .
+ 'offset' => 0,
+ // The offset to begin this fetch from.
+ 'time' => -1,
+ // If the time stamp field is set to -1, then the broker sets the time stamp to the receive time before committing the offset.
+ ),
+ ),
+ ),
+ ),
+);
+```
+
+#### Return
+
+Array.
+
+#### Example
+
+``` php
+$data = array(
+ 'group_id' => 'testgroup',
+ 'data' => array(
+ array(
+ 'topic_name' => 'test',
+ 'partitions' => array(
+ array(
+ 'partition_id' => 0,
+ 'offset' => 2,
+ ),
+ ),
+ ),
+ ),
+);
+
+
+$conn = new \Kafka\Socket('localhost', '9092');
+$conn->connect();
+$encoder = new \Kafka\Protocol\Encoder($conn);
+$encoder->commitOffsetRequest($data);
+
+$decoder = new \Kafka\Protocol\Decoder($conn);
+$result = $decoder->commitOffsetResponse();
+var_dump($result);
+
+```
+### Offset Fetch API
+
+These APIs allow for centralized management of offsets.
+
+\Kafka\Protocol\Encoder::fetchOffsetRequest
+
+####param struct
+``` php
+array(
+ 'group_id' => 'testgroup',
+ // consumer group
+ 'data' => array(
+ array(
+ 'topic_name' => 'testtopic',
+ // The topic that data is being published to.[String]
+ 'partitions' => array(
+ array(
+ 'partition_id' => 0,
+ // The partition that get offset .
+ ),
+ ),
+ ),
+ ),
+);
+```
+
+#### Return
+
+Array.
+
+#### Example
+
+``` php
+$data = array(
+ 'group_id' => 'testgroup',
+ 'data' => array(
+ array(
+ 'topic_name' => 'test',
+ 'partitions' => array(
+ array(
+ 'partition_id' => 0,
+ ),
+ ),
+ ),
+ ),
+);
+
+
+$conn = new \Kafka\Socket('localhost', '9092');
+$conn->connect();
+$encoder = new \Kafka\Protocol\Encoder($conn);
+$encoder->fetchOffsetRequest($data);
+
+$decoder = new \Kafka\Protocol\Decoder($conn);
+$result = $decoder->fetchOffsetResponse();
+var_dump($result);
+
+```
diff --git a/vendor/nmred/kafka-php/src/Kafka/Client.php b/vendor/nmred/kafka-php/src/Kafka/Client.php
new file mode 100644
index 00000000..a38e705b
--- /dev/null
+++ b/vendor/nmred/kafka-php/src/Kafka/Client.php
@@ -0,0 +1,290 @@
+<?php
+/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4 foldmethod=marker: */
+// +---------------------------------------------------------------------------
+// | SWAN [ $_SWANBR_SLOGAN_$ ]
+// +---------------------------------------------------------------------------
+// | Copyright $_SWANBR_COPYRIGHT_$
+// +---------------------------------------------------------------------------
+// | Version $_SWANBR_VERSION_$
+// +---------------------------------------------------------------------------
+// | Licensed ( $_SWANBR_LICENSED_URL_$ )
+// +---------------------------------------------------------------------------
+// | $_SWANBR_WEB_DOMAIN_$
+// +---------------------------------------------------------------------------
+
+namespace Kafka;
+
+/**
++------------------------------------------------------------------------------
+* Kafka protocol since Kafka v0.8
++------------------------------------------------------------------------------
+*
+* @package
+* @version $_SWANBR_VERSION_$
+* @copyright Copyleft
+* @author $_SWANBR_AUTHOR_$
++------------------------------------------------------------------------------
+*/
+
+class Client
+{
+ // {{{ consts
+ // }}}
+ // {{{ members
+
+ /**
+ * cluster metadata
+ *
+ * @var \Kafka\ClusterMetaData
+ * @access private
+ */
+ private $metadata = null;
+
+ /**
+ * broker host list
+ *
+ * @var array
+ * @access private
+ */
+ private $hostList = array();
+
+ /**
+ * save broker connection
+ *
+ * @var array
+ * @access private
+ */
+ private static $stream = array();
+
+ /**
+ * default stream options
+ *
+ * @var array
+ * @access private
+ */
+ private $streamOptions = array(
+ 'RecvTimeoutSec' => 0,
+ 'RecvTimeoutUsec' => 750000,
+ 'SendTimeoutSec' => 0,
+ 'SendTimeoutUsec' => 100000,
+ );
+
+ // }}}
+ // {{{ functions
+ // {{{ public function __construct()
+
+ /**
+ * __construct
+ *
+ * @access public
+ * @return void
+ */
+ public function __construct(ClusterMetaData $metadata)
+ {
+ $this->metadata = $metadata;
+ if (method_exists($metadata, 'setClient')) {
+ $this->metadata->setClient($this);
+ }
+ }
+
+ /**
+ * update stream options
+ *
+ * @param array $options
+ */
+ public function setStreamOptions($options = array())
+ {
+ // Merge the arrays
+ $this->streamOptions = array_merge($this->streamOptions, $options);
+ $this->updateStreamOptions();
+ }
+
+ /**
+ * @access public
+ * @param $name - name of stream option
+ * @param $value - value for option
+ */
+ public function setStreamOption($name, $value)
+ {
+ $this->streamOptions[$name] = $value;
+ $this->updateStreamOptions();
+ }
+
+ /**
+ * @access public
+ * @param $name - name of option
+ * @return mixed
+ */
+ public function getStreamOption($name)
+ {
+ if (array_key_exists($name, $this->streamOptions)) {
+ return $this->streamOptions[$name];
+ }
+ return null;
+ }
+
+ /**
+ * @access private
+ */
+ private function updateStreamOptions()
+ {
+ // Loop thru each stream
+ foreach (self::$stream as $host => $streams) {
+ foreach ($streams as $key => $info) {
+ // Update options
+ if (isset($info['stream'])) {
+ /** @var \Kafka\Socket $stream */
+ $stream = $info['stream'];
+ $stream->setRecvTimeoutSec($this->streamOptions['RecvTimeoutSec']);
+ $stream->setRecvTimeoutUsec($this->streamOptions['SendTimeoutUsec']);
+ $stream->setSendTimeoutSec($this->streamOptions['SendTimeoutSec']);
+ $stream->setSendTimeoutUsec($this->streamOptions['SendTimeoutUsec']);
+ }
+ }
+ }
+ }
+
+ // }}}
+ // {{{ public function getBrokers()
+
+ /**
+ * get broker server
+ *
+ * @access public
+ * @return void
+ */
+ public function getBrokers()
+ {
+ if (empty($this->hostList)) {
+ $brokerList = $this->metadata->listBrokers();
+ foreach ($brokerList as $brokerId => $info) {
+ if (!isset($info['host']) || !isset($info['port'])) {
+ continue;
+ }
+ $this->hostList[$brokerId] = $info['host'] . ':' . $info['port'];
+ }
+ }
+
+ return $this->hostList;
+ }
+
+ // }}}
+ // {{{ public function getHostByPartition()
+
+ /**
+ * get broker host by topic partition
+ *
+ * @param string $topicName
+ * @param int $partitionId
+ * @access public
+ * @return string
+ */
+ public function getHostByPartition($topicName, $partitionId = 0)
+ {
+ $partitionInfo = $this->metadata->getPartitionState($topicName, $partitionId);
+ if (!$partitionInfo) {
+ throw new \Kafka\Exception('topic:' . $topicName . ', partition id: ' . $partitionId . ' is not exists.');
+ }
+
+ $hostList = $this->getBrokers();
+ if (isset($partitionInfo['leader']) && isset($hostList[$partitionInfo['leader']])) {
+ return $hostList[$partitionInfo['leader']];
+ } else {
+ throw new \Kafka\Exception('can\'t find broker host.');
+ }
+ }
+
+ // }}}
+ // {{{ public function getZooKeeper()
+
+ /**
+ * get kafka zookeeper object
+ *
+ * @access public
+ * @return \Kafka\ZooKeeper
+ */
+ public function getZooKeeper()
+ {
+ if ($this->metadata instanceof \Kafka\ZooKeeper) {
+ return $this->metadata;
+ } else {
+ throw new \Kafka\Exception( 'ZooKeeper was not provided' );
+ }
+ }
+
+ // }}}
+ // {{{ public function getStream()
+
+ /**
+ * get broker broker connect
+ *
+ * @param string $host
+ * @access private
+ * @return void
+ */
+ public function getStream($host, $lockKey = null)
+ {
+ if (!$lockKey) {
+ $lockKey = uniqid($host);
+ }
+
+ list($hostname, $port) = explode(':', $host);
+ // find unlock stream
+ if (isset(self::$stream[$host])) {
+ foreach (self::$stream[$host] as $key => $info) {
+ if ($info['locked']) {
+ continue;
+ } else {
+ self::$stream[$host][$key]['locked'] = true;
+ $info['stream']->connect();
+ return array('key' => $key, 'stream' => $info['stream']);
+ }
+ }
+ }
+
+ // no idle stream
+ $stream = new \Kafka\Socket($hostname, $port, $this->getStreamOption('RecvTimeoutSec'), $this->getStreamOption('RecvTimeoutUsec'), $this->getStreamOption('SendTimeoutSec'), $this->getStreamOption('SendTimeoutUsec'));
+ $stream->connect();
+ self::$stream[$host][$lockKey] = array(
+ 'locked' => true,
+ 'stream' => $stream,
+ );
+ return array('key' => $lockKey, 'stream' => $stream);
+ }
+
+ // }}}
+ // {{{ public function freeStream()
+
+ /**
+ * free stream pool
+ *
+ * @param string $key
+ * @access public
+ * @return void
+ */
+ public function freeStream($key)
+ {
+ foreach (self::$stream as $host => $values) {
+ if (isset($values[$key])) {
+ self::$stream[$host][$key]['locked'] = false;
+ }
+ }
+ }
+
+ // }}}
+ // {{{ public function getTopicDetail()
+
+ /**
+ * get topic detail info
+ *
+ * @param string $topicName
+ * @return array
+ */
+ public function getTopicDetail($topicName)
+ {
+ return $this->metadata->getTopicDetail($topicName);
+ }
+
+ // }}}
+ // }}}
+}
diff --git a/vendor/nmred/kafka-php/src/Kafka/ClusterMetaData.php b/vendor/nmred/kafka-php/src/Kafka/ClusterMetaData.php
new file mode 100644
index 00000000..e9b3d064
--- /dev/null
+++ b/vendor/nmred/kafka-php/src/Kafka/ClusterMetaData.php
@@ -0,0 +1,53 @@
+<?php
+/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4 foldmethod=marker: */
+// +---------------------------------------------------------------------------
+// | SWAN [ $_SWANBR_SLOGAN_$ ]
+// +---------------------------------------------------------------------------
+// | Copyright $_SWANBR_COPYRIGHT_$
+// +---------------------------------------------------------------------------
+// | Version $_SWANBR_VERSION_$
+// +---------------------------------------------------------------------------
+// | Licensed ( $_SWANBR_LICENSED_URL_$ )
+// +---------------------------------------------------------------------------
+// | $_SWANBR_WEB_DOMAIN_$
+// +---------------------------------------------------------------------------
+
+namespace Kafka;
+
+/**
++------------------------------------------------------------------------------
+* Metadata about the kafka cluster
++------------------------------------------------------------------------------
+*
+* @package
+* @version $_SWANBR_VERSION_$
+* @copyright Copyleft
+* @author ebernhardson@wikimedia.org
++------------------------------------------------------------------------------
+*/
+
+interface ClusterMetaData
+{
+ /**
+ * get broker list from kafka metadata
+ *
+ * @access public
+ * @return array
+ */
+ public function listBrokers();
+
+ /**
+ * @param string $topicName
+ * @param integer $partitionId
+ * @access public
+ * @return array
+ */
+ public function getPartitionState($topicName, $partitionId = 0);
+
+ /**
+ * @param string $topicName
+ * @access public
+ * @return array
+ */
+ public function getTopicDetail($topicName);
+}
diff --git a/vendor/nmred/kafka-php/src/Kafka/Consumer.php b/vendor/nmred/kafka-php/src/Kafka/Consumer.php
new file mode 100644
index 00000000..5ff2d43f
--- /dev/null
+++ b/vendor/nmred/kafka-php/src/Kafka/Consumer.php
@@ -0,0 +1,378 @@
+<?php
+/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4 foldmethod=marker: */
+// +---------------------------------------------------------------------------
+// | SWAN [ $_SWANBR_SLOGAN_$ ]
+// +---------------------------------------------------------------------------
+// | Copyright $_SWANBR_COPYRIGHT_$
+// +---------------------------------------------------------------------------
+// | Version $_SWANBR_VERSION_$
+// +---------------------------------------------------------------------------
+// | Licensed ( $_SWANBR_LICENSED_URL_$ )
+// +---------------------------------------------------------------------------
+// | $_SWANBR_WEB_DOMAIN_$
+// +---------------------------------------------------------------------------
+
+namespace Kafka;
+
+/**
++------------------------------------------------------------------------------
+* Kafka protocol since Kafka v0.8
++------------------------------------------------------------------------------
+*
+* @package
+* @version $_SWANBR_VERSION_$
+* @copyright Copyleft
+* @author $_SWANBR_AUTHOR_$
++------------------------------------------------------------------------------
+*/
+
+class Consumer
+{
+ // {{{ consts
+ // }}}
+ // {{{ members
+
+ /**
+ * client
+ *
+ * @var mixed
+ * @access private
+ */
+ private $client = null;
+
+ /**
+ * send message options cache
+ *
+ * @var array
+ * @access private
+ */
+ private $payload = array();
+
+ /**
+ * consumer group
+ *
+ * @var string
+ * @access private
+ */
+ private $group = '';
+
+ /**
+ * from offset
+ *
+ * @var mixed
+ * @access private
+ */
+ private $fromOffset = true;
+
+ /**
+ * produce instance
+ *
+ * @var \Kafka\Produce
+ * @access private
+ */
+ private static $instance = null;
+
+ /**
+ * broker host list
+ *
+ * @var array
+ * @access private
+ */
+ private $hostList = array();
+
+ /**
+ * save broker connection
+ *
+ * @var array
+ * @access private
+ */
+ private $stream = array();
+
+ /**
+ * maxSize
+ *
+ * @var integer
+ */
+ private $maxSize = 1048576;
+
+ /**
+ * offsetStrategy
+ * @var integer
+ */
+ private $offsetStrategy = \Kafka\Offset::DEFAULT_EARLY;
+
+ // }}}
+ // {{{ functions
+ // {{{ public function static getInstance()
+
+ /**
+ * set send messages
+ *
+ * @access public
+ * @return void
+ */
+ public static function getInstance($hostList, $timeout = null)
+ {
+ if (is_null(self::$instance)) {
+ self::$instance = new self($hostList, $timeout);
+ }
+
+ return self::$instance;
+ }
+
+ // }}}
+ // {{{ private function __construct()
+
+ /**
+ * __construct
+ *
+ * @access public
+ * @return void
+ */
+ private function __construct($hostList, $timeout = null)
+ {
+ $zookeeper = new \Kafka\ZooKeeper($hostList, $timeout);
+ $this->client = new \Kafka\Client($zookeeper);
+ }
+
+ // }}}
+ // {{{ public function clearPayload()
+
+ /**
+ * clearPayload
+ *
+ * @access public
+ * @return void
+ */
+ public function clearPayload()
+ {
+ $this->payload = array();
+ }
+
+ // }}}
+ // {{{ public function setTopic()
+
+ /**
+ * set topic name
+ *
+ * @access public
+ * @return void
+ */
+ public function setTopic($topicName, $defaultOffset = null)
+ {
+ $parts = $this->client->getTopicDetail($topicName);
+ if (!isset($parts['partitions']) || empty($parts['partitions'])) {
+ // set topic fail.
+ return $this;
+ }
+
+ foreach ($parts['partitions'] as $partId => $info) {
+ $this->setPartition($topicName, $partId, $defaultOffset);
+ }
+
+ return $this;
+ }
+
+ // }}}
+ // {{{ public function setPartition()
+
+ /**
+ * set topic partition
+ *
+ * @access public
+ * @return void
+ */
+ public function setPartition($topicName, $partitionId = 0, $offset = null)
+ {
+ if (is_null($offset)) {
+ if ($this->fromOffset) {
+ $offsetObject = new \Kafka\Offset($this->client, $this->group, $topicName, $partitionId);
+ $offset = $offsetObject->getOffset($this->offsetStrategy);
+ \Kafka\Log::log('topic name:' . $topicName . ', part:' . $partitionId . 'get offset from kafka server, offet:' . $offset, LOG_DEBUG);
+ } else {
+ $offset = 0;
+ }
+ }
+ $this->payload[$topicName][$partitionId] = $offset;
+
+ return $this;
+ }
+
+ // }}}
+ // {{{ public function setFromOffset()
+
+ /**
+ * set whether starting offset fetch
+ *
+ * @param boolean $fromOffset
+ * @access public
+ * @return void
+ */
+ public function setFromOffset($fromOffset)
+ {
+ $this->fromOffset = (boolean) $fromOffset;
+ }
+
+ // }}}
+ // {{{ public function setMaxBytes()
+
+ /**
+ * set fetch message max bytes
+ *
+ * @param int $maxSize
+ * @access public
+ * @return void
+ */
+ public function setMaxBytes($maxSize)
+ {
+ $this->maxSize = $maxSize;
+ }
+
+ // }}}
+ // {{{ public function setGroup()
+
+ /**
+ * set consumer group
+ *
+ * @param string $group
+ * @access public
+ * @return void
+ */
+ public function setGroup($group)
+ {
+ $this->group = (string) $group;
+ return $this;
+ }
+
+ // }}}
+ // {{{ public function fetch()
+
+ /**
+ * fetch message to broker
+ *
+ * @access public
+ * @return void
+ */
+ public function fetch()
+ {
+ $data = $this->_formatPayload();
+ if (empty($data)) {
+ return false;
+ }
+
+ $responseData = array();
+ $streams = array();
+ foreach ($data as $host => $requestData) {
+ $connArr = $this->client->getStream($host);
+ $conn = $connArr['stream'];
+ $encoder = new \Kafka\Protocol\Encoder($conn);
+ $encoder->fetchRequest($requestData);
+ $streams[$connArr['key']] = $conn;
+ }
+
+ $fetch = new \Kafka\Protocol\Fetch\Topic($streams, $data);
+
+ // register fetch helper
+ $freeStream = new \Kafka\Protocol\Fetch\Helper\FreeStream($this->client);
+ $freeStream->setStreams($streams);
+ \Kafka\Protocol\Fetch\Helper\Helper::registerHelper('freeStream', $freeStream);
+
+ // register partition commit offset
+ $commitOffset = new \Kafka\Protocol\Fetch\Helper\CommitOffset($this->client);
+ $commitOffset->setGroup($this->group);
+ \Kafka\Protocol\Fetch\Helper\Helper::registerHelper('commitOffset', $commitOffset);
+
+ $updateConsumer = new \Kafka\Protocol\Fetch\Helper\Consumer($this);
+ \Kafka\Protocol\Fetch\Helper\Helper::registerHelper('updateConsumer', $updateConsumer);
+
+ return $fetch;
+ }
+
+ // }}}
+ // {{{ public function getClient()
+
+ /**
+ * get client object
+ *
+ * @access public
+ * @return void
+ */
+ public function getClient()
+ {
+ return $this->client;
+ }
+
+ /**
+ * passthru method to client for setting stream options
+ *
+ * @param array $options
+ */
+ public function setStreamOptions($options = array())
+ {
+ $this->client->setStreamOptions($options);
+ }
+
+ // }}}
+ // {{{ private function _formatPayload()
+
+ /**
+ * format payload array
+ *
+ * @access private
+ * @return array
+ */
+ private function _formatPayload()
+ {
+ if (empty($this->payload)) {
+ return array();
+ }
+
+ $data = array();
+ foreach ($this->payload as $topicName => $partitions) {
+ foreach ($partitions as $partitionId => $offset) {
+ $host = $this->client->getHostByPartition($topicName, $partitionId);
+ $data[$host][$topicName][$partitionId] = $offset;
+ }
+ }
+
+ $requestData = array();
+ foreach ($data as $host => $info) {
+ $topicData = array();
+ foreach ($info as $topicName => $partitions) {
+ $partitionData = array();
+ foreach ($partitions as $partitionId => $offset) {
+ $partitionData[] = array(
+ 'partition_id' => $partitionId,
+ 'offset' => $offset,
+ 'max_bytes' => $this->maxSize,
+ );
+ }
+ $topicData[] = array(
+ 'topic_name' => $topicName,
+ 'partitions' => $partitionData,
+ );
+ }
+
+ $requestData[$host] = array(
+ 'data' => $topicData,
+ );
+ }
+
+ return $requestData;
+ }
+
+ /**
+ * const LAST_OFFSET = -1;
+ * const EARLIEST_OFFSET = -2;
+ * const DEFAULT_LAST = -2;
+ * const DEFAULT_EARLY = -1;
+ * @param type $offsetStrategy
+ */
+ public function setOffsetStrategy($offsetStrategy)
+ {
+ $this->offsetStrategy = $offsetStrategy;
+ }
+
+ // }}}
+ // }}}
+}
diff --git a/vendor/nmred/kafka-php/src/Kafka/Exception.php b/vendor/nmred/kafka-php/src/Kafka/Exception.php
new file mode 100644
index 00000000..f336f1c3
--- /dev/null
+++ b/vendor/nmred/kafka-php/src/Kafka/Exception.php
@@ -0,0 +1,31 @@
+<?php
+/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4 foldmethod=marker: */
+// +---------------------------------------------------------------------------
+// | SWAN [ $_SWANBR_SLOGAN_$ ]
+// +---------------------------------------------------------------------------
+// | Copyright $_SWANBR_COPYRIGHT_$
+// +---------------------------------------------------------------------------
+// | Version $_SWANBR_VERSION_$
+// +---------------------------------------------------------------------------
+// | Licensed ( $_SWANBR_LICENSED_URL_$ )
+// +---------------------------------------------------------------------------
+// | $_SWANBR_WEB_DOMAIN_$
+// +---------------------------------------------------------------------------
+
+namespace Kafka;
+
+/**
++------------------------------------------------------------------------------
+* Kafka protocol since Kafka v0.8
++------------------------------------------------------------------------------
+*
+* @package
+* @version $_SWANBR_VERSION_$
+* @copyright Copyleft
+* @author $_SWANBR_AUTHOR_$
++------------------------------------------------------------------------------
+*/
+
+class Exception extends \RuntimeException
+{
+}
diff --git a/vendor/nmred/kafka-php/src/Kafka/Exception/NotSupported.php b/vendor/nmred/kafka-php/src/Kafka/Exception/NotSupported.php
new file mode 100644
index 00000000..011129a2
--- /dev/null
+++ b/vendor/nmred/kafka-php/src/Kafka/Exception/NotSupported.php
@@ -0,0 +1,33 @@
+<?php
+/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4 foldmethod=marker: */
+// +---------------------------------------------------------------------------
+// | SWAN [ $_SWANBR_SLOGAN_$ ]
+// +---------------------------------------------------------------------------
+// | Copyright $_SWANBR_COPYRIGHT_$
+// +---------------------------------------------------------------------------
+// | Version $_SWANBR_VERSION_$
+// +---------------------------------------------------------------------------
+// | Licensed ( $_SWANBR_LICENSED_URL_$ )
+// +---------------------------------------------------------------------------
+// | $_SWANBR_WEB_DOMAIN_$
+// +---------------------------------------------------------------------------
+
+namespace Kafka\Exception;
+
+use \Kafka\Exception;
+
+/**
++------------------------------------------------------------------------------
+* Kafka php client exception
++------------------------------------------------------------------------------
+*
+* @package
+* @version $_SWANBR_VERSION_$
+* @copyright Copyleft
+* @author $_SWANBR_AUTHOR_$
++------------------------------------------------------------------------------
+*/
+
+class NotSupported extends \Exception
+{
+}
diff --git a/vendor/nmred/kafka-php/src/Kafka/Exception/OutOfRange.php b/vendor/nmred/kafka-php/src/Kafka/Exception/OutOfRange.php
new file mode 100644
index 00000000..374d1538
--- /dev/null
+++ b/vendor/nmred/kafka-php/src/Kafka/Exception/OutOfRange.php
@@ -0,0 +1,33 @@
+<?php
+/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4 foldmethod=marker: */
+// +---------------------------------------------------------------------------
+// | SWAN [ $_SWANBR_SLOGAN_$ ]
+// +---------------------------------------------------------------------------
+// | Copyright $_SWANBR_COPYRIGHT_$
+// +---------------------------------------------------------------------------
+// | Version $_SWANBR_VERSION_$
+// +---------------------------------------------------------------------------
+// | Licensed ( $_SWANBR_LICENSED_URL_$ )
+// +---------------------------------------------------------------------------
+// | $_SWANBR_WEB_DOMAIN_$
+// +---------------------------------------------------------------------------
+
+namespace Kafka\Exception;
+
+use \Kafka\Exception;
+
+/**
++------------------------------------------------------------------------------
+* Kafka php client exception
++------------------------------------------------------------------------------
+*
+* @package
+* @version $_SWANBR_VERSION_$
+* @copyright Copyleft
+* @author $_SWANBR_AUTHOR_$
++------------------------------------------------------------------------------
+*/
+
+class OutOfRange extends Exception
+{
+}
diff --git a/vendor/nmred/kafka-php/src/Kafka/Exception/Protocol.php b/vendor/nmred/kafka-php/src/Kafka/Exception/Protocol.php
new file mode 100644
index 00000000..6e213f05
--- /dev/null
+++ b/vendor/nmred/kafka-php/src/Kafka/Exception/Protocol.php
@@ -0,0 +1,33 @@
+<?php
+/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4 foldmethod=marker: */
+// +---------------------------------------------------------------------------
+// | SWAN [ $_SWANBR_SLOGAN_$ ]
+// +---------------------------------------------------------------------------
+// | Copyright $_SWANBR_COPYRIGHT_$
+// +---------------------------------------------------------------------------
+// | Version $_SWANBR_VERSION_$
+// +---------------------------------------------------------------------------
+// | Licensed ( $_SWANBR_LICENSED_URL_$ )
+// +---------------------------------------------------------------------------
+// | $_SWANBR_WEB_DOMAIN_$
+// +---------------------------------------------------------------------------
+
+namespace Kafka\Exception;
+
+use \Kafka\Exception;
+
+/**
++------------------------------------------------------------------------------
+* Kafka php client exception
++------------------------------------------------------------------------------
+*
+* @package
+* @version $_SWANBR_VERSION_$
+* @copyright Copyleft
+* @author $_SWANBR_AUTHOR_$
++------------------------------------------------------------------------------
+*/
+
+class Protocol extends \Exception
+{
+}
diff --git a/vendor/nmred/kafka-php/src/Kafka/Exception/Socket.php b/vendor/nmred/kafka-php/src/Kafka/Exception/Socket.php
new file mode 100644
index 00000000..aca93e25
--- /dev/null
+++ b/vendor/nmred/kafka-php/src/Kafka/Exception/Socket.php
@@ -0,0 +1,33 @@
+<?php
+/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4 foldmethod=marker: */
+// +---------------------------------------------------------------------------
+// | SWAN [ $_SWANBR_SLOGAN_$ ]
+// +---------------------------------------------------------------------------
+// | Copyright $_SWANBR_COPYRIGHT_$
+// +---------------------------------------------------------------------------
+// | Version $_SWANBR_VERSION_$
+// +---------------------------------------------------------------------------
+// | Licensed ( $_SWANBR_LICENSED_URL_$ )
+// +---------------------------------------------------------------------------
+// | $_SWANBR_WEB_DOMAIN_$
+// +---------------------------------------------------------------------------
+
+namespace Kafka\Exception;
+
+use \Kafka\Exception;
+
+/**
++------------------------------------------------------------------------------
+* Kafka php client exception
++------------------------------------------------------------------------------
+*
+* @package
+* @version $_SWANBR_VERSION_$
+* @copyright Copyleft
+* @author $_SWANBR_AUTHOR_$
++------------------------------------------------------------------------------
+*/
+
+class Socket extends \Exception
+{
+}
diff --git a/vendor/nmred/kafka-php/src/Kafka/Exception/SocketConnect.php b/vendor/nmred/kafka-php/src/Kafka/Exception/SocketConnect.php
new file mode 100644
index 00000000..476b2a48
--- /dev/null
+++ b/vendor/nmred/kafka-php/src/Kafka/Exception/SocketConnect.php
@@ -0,0 +1,33 @@
+<?php
+/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4 foldmethod=marker: */
+// +---------------------------------------------------------------------------
+// | SWAN [ $_SWANBR_SLOGAN_$ ]
+// +---------------------------------------------------------------------------
+// | Copyright $_SWANBR_COPYRIGHT_$
+// +---------------------------------------------------------------------------
+// | Version $_SWANBR_VERSION_$
+// +---------------------------------------------------------------------------
+// | Licensed ( $_SWANBR_LICENSED_URL_$ )
+// +---------------------------------------------------------------------------
+// | $_SWANBR_WEB_DOMAIN_$
+// +---------------------------------------------------------------------------
+
+namespace Kafka\Exception;
+
+use \Kafka\Exception;
+
+/**
++------------------------------------------------------------------------------
+ * Kafka php client exception
++------------------------------------------------------------------------------
+ *
+ * @package
+ * @version $_SWANBR_VERSION_$
+ * @copyright Copyleft
+ * @author $_SWANBR_AUTHOR_$
++------------------------------------------------------------------------------
+ */
+
+class SocketConnect extends Socket
+{
+}
diff --git a/vendor/nmred/kafka-php/src/Kafka/Exception/SocketEOF.php b/vendor/nmred/kafka-php/src/Kafka/Exception/SocketEOF.php
new file mode 100644
index 00000000..35e34e07
--- /dev/null
+++ b/vendor/nmred/kafka-php/src/Kafka/Exception/SocketEOF.php
@@ -0,0 +1,33 @@
+<?php
+/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4 foldmethod=marker: */
+// +---------------------------------------------------------------------------
+// | SWAN [ $_SWANBR_SLOGAN_$ ]
+// +---------------------------------------------------------------------------
+// | Copyright $_SWANBR_COPYRIGHT_$
+// +---------------------------------------------------------------------------
+// | Version $_SWANBR_VERSION_$
+// +---------------------------------------------------------------------------
+// | Licensed ( $_SWANBR_LICENSED_URL_$ )
+// +---------------------------------------------------------------------------
+// | $_SWANBR_WEB_DOMAIN_$
+// +---------------------------------------------------------------------------
+
+namespace Kafka\Exception;
+
+use \Kafka\Exception;
+
+/**
++------------------------------------------------------------------------------
+* Kafka php client exception
++------------------------------------------------------------------------------
+*
+* @package
+* @version $_SWANBR_VERSION_$
+* @copyright Copyleft
+* @author $_SWANBR_AUTHOR_$
++------------------------------------------------------------------------------
+*/
+
+class SocketEOF extends Exception
+{
+}
diff --git a/vendor/nmred/kafka-php/src/Kafka/Exception/SocketTimeout.php b/vendor/nmred/kafka-php/src/Kafka/Exception/SocketTimeout.php
new file mode 100644
index 00000000..b0d38c2c
--- /dev/null
+++ b/vendor/nmred/kafka-php/src/Kafka/Exception/SocketTimeout.php
@@ -0,0 +1,33 @@
+<?php
+/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4 foldmethod=marker: */
+// +---------------------------------------------------------------------------
+// | SWAN [ $_SWANBR_SLOGAN_$ ]
+// +---------------------------------------------------------------------------
+// | Copyright $_SWANBR_COPYRIGHT_$
+// +---------------------------------------------------------------------------
+// | Version $_SWANBR_VERSION_$
+// +---------------------------------------------------------------------------
+// | Licensed ( $_SWANBR_LICENSED_URL_$ )
+// +---------------------------------------------------------------------------
+// | $_SWANBR_WEB_DOMAIN_$
+// +---------------------------------------------------------------------------
+
+namespace Kafka\Exception;
+
+use \Kafka\Exception;
+
+/**
++------------------------------------------------------------------------------
+* Kafka php client exception
++------------------------------------------------------------------------------
+*
+* @package
+* @version $_SWANBR_VERSION_$
+* @copyright Copyleft
+* @author $_SWANBR_AUTHOR_$
++------------------------------------------------------------------------------
+*/
+
+class SocketTimeout extends Exception
+{
+}
diff --git a/vendor/nmred/kafka-php/src/Kafka/Log.php b/vendor/nmred/kafka-php/src/Kafka/Log.php
new file mode 100644
index 00000000..481bfc3d
--- /dev/null
+++ b/vendor/nmred/kafka-php/src/Kafka/Log.php
@@ -0,0 +1,78 @@
+<?php
+/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4 foldmethod=marker: */
+// +---------------------------------------------------------------------------
+// | SWAN [ $_SWANBR_SLOGAN_$ ]
+// +---------------------------------------------------------------------------
+// | Copyright $_SWANBR_COPYRIGHT_$
+// +---------------------------------------------------------------------------
+// | Version $_SWANBR_VERSION_$
+// +---------------------------------------------------------------------------
+// | Licensed ( $_SWANBR_LICENSED_URL_$ )
+// +---------------------------------------------------------------------------
+// | $_SWANBR_WEB_DOMAIN_$
+// +---------------------------------------------------------------------------
+
+namespace Kafka;
+
+/**
++------------------------------------------------------------------------------
+* Kafka protocol since Kafka v0.8
++------------------------------------------------------------------------------
+*
+* @package
+* @version $_SWANBR_VERSION_$
+* @copyright Copyleft
+* @author $_SWANBR_AUTHOR_$
++------------------------------------------------------------------------------
+*/
+
+class Log
+{
+ // {{{ consts
+ // }}}
+ // {{{ members
+
+ /**
+ * log
+ *
+ * @var mixed
+ * @access private
+ */
+ private static $log = null;
+
+ // }}}
+ // {{{ functions
+ // {{{ public static function setLog()
+
+ /**
+ * setLog
+ *
+ * @access public
+ * @return void
+ */
+ public static function setLog($log)
+ {
+ if ($log) {
+ self::$log = $log;
+ }
+ }
+
+ // }}}
+ // {{{ public static function log()
+
+ /**
+ * log
+ *
+ * @access public
+ * @return void
+ */
+ public static function log($message, $level = LOG_DEBUG)
+ {
+ if (self::$log && method_exists(self::$log, 'log')) {
+ self::$log->log($message, $level);
+ }
+ }
+
+ // }}}
+ // }}}
+}
diff --git a/vendor/nmred/kafka-php/src/Kafka/MetaDataFromKafka.php b/vendor/nmred/kafka-php/src/Kafka/MetaDataFromKafka.php
new file mode 100644
index 00000000..9d2c613e
--- /dev/null
+++ b/vendor/nmred/kafka-php/src/Kafka/MetaDataFromKafka.php
@@ -0,0 +1,200 @@
+<?php
+
+/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4 foldmethod=marker: */
+// +---------------------------------------------------------------------------
+// | SWAN [ $_SWANBR_SLOGAN_$ ]
+// +---------------------------------------------------------------------------
+// | Copyright $_SWANBR_COPYRIGHT_$
+// +---------------------------------------------------------------------------
+// | Version $_SWANBR_VERSION_$
+// +---------------------------------------------------------------------------
+// | Licensed ( $_SWANBR_LICENSED_URL_$ )
+// +---------------------------------------------------------------------------
+// | $_SWANBR_WEB_DOMAIN_$
+// +---------------------------------------------------------------------------
+
+namespace Kafka;
+
+/**
++------------------------------------------------------------------------------
+* Cluster metadata provided by kafka
++------------------------------------------------------------------------------
+*
+* @package
+* @version $_SWANBR_VERSION_$
+* @copyright Copyleft
+* @author ebernhardson@wikimedia.org
++------------------------------------------------------------------------------
+*/
+
+class MetaDataFromKafka implements ClusterMetaData
+{
+ // {{{ consts
+ // }}}
+ // {{{ members
+
+ /**
+ * client
+ *
+ * @var \Kafka\Client
+ * @access private
+ */
+ private $client;
+
+ /**
+ * list of kafka brokers to get metadata from
+ *
+ * @var array
+ * @access private
+ */
+ private $hostList;
+
+ /**
+ * List of all kafka brokers
+ *
+ * @var array
+ * @access private
+ */
+ private $brokers = array();
+
+ /**
+ * List of all loaded topic metadata
+ *
+ * @var array
+ * @access private
+ */
+ private $topics = array();
+
+ // }}}
+ // {{{ functions
+ // {{{ public function __construct()
+
+ /**
+ * @var string|array $hostList List of kafka brokers to get metadata from
+ * @access public
+ */
+ public function __construct($hostList)
+ {
+ if (is_string($hostList)) { // support host list 127.0.0.1:9092,192.168.2.11:9092 form
+ $this->hostList = explode(',', $hostList);
+ } else {
+ $this->hostList = (array)$hostList;
+ }
+ // randomize the order of servers we collect metadata from
+ shuffle($this->hostList);
+ }
+
+ // }}}
+ // {{{ public function setClient()
+
+ /**
+ * @var \Kafka\Client $client
+ * @access public
+ * @return void
+ */
+ public function setClient(\Kafka\Client $client)
+ {
+ $this->client = $client;
+ }
+
+ // }}}
+ // {{{ public function listBrokers()
+
+ /**
+ * get broker list from kafka metadata
+ *
+ * @access public
+ * @return array
+ */
+ public function listBrokers()
+ {
+ if ($this->brokers === null) {
+ $this->loadBrokers();
+ }
+ return $this->brokers;
+ }
+
+ // }}}
+ // {{{ public function getPartitionState()
+
+ public function getPartitionState($topicName, $partitionId = 0)
+ {
+ if (!isset( $this->topics[$topicName] ) ) {
+ $this->loadTopicDetail(array($topicName));
+ }
+ if ( isset( $this->topics[$topicName]['partitions'][$partitionId] ) ) {
+ return $this->topics[$topicName]['partitions'][$partitionId];
+ } else {
+ return null;
+ }
+ }
+
+ // }}}
+ // {{{ public function getTopicDetail()
+
+ /**
+ *
+ * @param string $topicName
+ * @access public
+ * @return array
+ */
+ public function getTopicDetail($topicName)
+ {
+ if (!isset( $this->topics[$topicName] ) ) {
+ $this->loadTopicDetail(array($topicName));
+ }
+ if (isset( $this->topics[$topicName] ) ) {
+ return $this->topics[$topicName];
+ } else {
+ return array();
+ }
+ }
+
+ // }}}
+ // {{{ private function loadBrokers()
+
+ private function loadBrokers()
+ {
+ $this->brokers = array();
+ // not sure how to ask for only the brokers without a topic...
+ // just ask for a topic we don't care about
+ $this->loadTopicDetail(array('test'));
+ }
+
+ // }}}
+ // {{{ private function loadTopicDetail()
+
+ private function loadTopicDetail(array $topics)
+ {
+ if ($this->client === null) {
+ throw new \Kafka\Exception('client was not provided');
+ }
+ $response = null;
+ foreach ($this->hostList as $host) {
+ try {
+ $response = null;
+ $stream = $this->client->getStream($host);
+ $conn = $stream['stream'];
+ $encoder = new \Kafka\Protocol\Encoder($conn);
+ $encoder->metadataRequest($topics);
+ $decoder = new \Kafka\Protocol\Decoder($conn);
+ $response = $decoder->metadataResponse();
+ $this->client->freeStream($stream['key']);
+ break;
+ } catch (\Kafka\Exception $e) {
+ // keep trying
+ }
+ }
+ if ($response) {
+ // Merge arrays using "+" operator to preserve key (which are broker IDs)
+ // instead of array_merge (which reindex numeric keys)
+ $this->brokers = $response['brokers'] + $this->brokers;
+ $this->topics = array_merge($response['topics'], $this->topics);
+ } else {
+ throw new \Kafka\Exception('Could not connect to any kafka brokers');
+ }
+ }
+
+ // }}}
+ // }}}
+}
diff --git a/vendor/nmred/kafka-php/src/Kafka/Offset.php b/vendor/nmred/kafka-php/src/Kafka/Offset.php
new file mode 100644
index 00000000..7ad3f9d8
--- /dev/null
+++ b/vendor/nmred/kafka-php/src/Kafka/Offset.php
@@ -0,0 +1,305 @@
+<?php
+/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4 foldmethod=marker: */
+// +---------------------------------------------------------------------------
+// | SWAN [ $_SWANBR_SLOGAN_$ ]
+// +---------------------------------------------------------------------------
+// | Copyright $_SWANBR_COPYRIGHT_$
+// +---------------------------------------------------------------------------
+// | Version $_SWANBR_VERSION_$
+// +---------------------------------------------------------------------------
+// | Licensed ( $_SWANBR_LICENSED_URL_$ )
+// +---------------------------------------------------------------------------
+// | $_SWANBR_WEB_DOMAIN_$
+// +---------------------------------------------------------------------------
+
+namespace Kafka;
+
+use \Kafka\Log;
+
+/**
++------------------------------------------------------------------------------
+* Kafka protocol since Kafka v0.8
++------------------------------------------------------------------------------
+*
+* @package
+* @version $_SWANBR_VERSION_$
+* @copyright Copyleft
+* @author $_SWANBR_AUTHOR_$
++------------------------------------------------------------------------------
+*/
+
+class Offset
+{
+ // {{{ consts
+
+ /**
+ * receive the latest offset
+ */
+ const LAST_OFFSET = -1;
+
+ /**
+ * receive the earliest available offset.
+ */
+ const EARLIEST_OFFSET = -2;
+
+ /**
+ * function getOffset if read invalid value use latest offset instead of
+ */
+ const DEFAULT_LAST = -2;
+
+ /**
+ * function getOffset if read invalid value use earliest offset instead of
+ */
+ const DEFAULT_EARLY = -1;
+
+ // }}}
+ // {{{ members
+
+ /**
+ * client
+ *
+ * @var mixed
+ * @access private
+ */
+ private $client = null;
+
+ /**
+ * consumer group
+ *
+ * @var string
+ * @access private
+ */
+ private $groupId = '';
+
+ /**
+ * topic name
+ *
+ * @var string
+ * @access private
+ */
+ private $topicName = '';
+
+ /**
+ * topic partition id, default 0
+ *
+ * @var float
+ * @access private
+ */
+ private $partitionId = 0;
+
+ /**
+ * encoder
+ *
+ * @var mixed
+ * @access private
+ */
+ private $encoder = null;
+
+ /**
+ * decoder
+ *
+ * @var mixed
+ * @access private
+ */
+ private $decoder = null;
+
+ /**
+ * streamKey
+ *
+ * @var string
+ * @access private
+ */
+ private $streamKey = '';
+
+ // }}}
+ // {{{ functions
+ // {{{ public function __construct()
+
+ /**
+ * __construct
+ *
+ * @access public
+ * @return void
+ */
+ public function __construct($client, $groupId, $topicName, $partitionId = 0)
+ {
+ $this->client = $client;
+ $this->groupId = $groupId;
+ $this->topicName = $topicName;
+ $this->partitionId = $partitionId;
+
+ $host = $this->client->getHostByPartition($topicName, $partitionId);
+ $stream = $this->client->getStream($host);
+ $conn = $stream['stream'];
+ $this->streamKey = $stream['key'];
+ $this->encoder = new \Kafka\Protocol\Encoder($conn);
+ $this->decoder = new \Kafka\Protocol\Decoder($conn);
+ }
+
+ // }}}
+ // {{{ public function setOffset()
+
+ /**
+ * set consumer offset
+ *
+ * @param integer $offset
+ * @access public
+ * @return void
+ */
+ public function setOffset($offset)
+ {
+ $maxOffset = $this->getProduceOffset();
+ if ($offset > $maxOffset) {
+ throw new \Kafka\Exception('this offset is invalid. must less than max offset:' . $maxOffset);
+ }
+
+ $data = array(
+ 'group_id' => $this->groupId,
+ 'data' => array(
+ array(
+ 'topic_name' => $this->topicName,
+ 'partitions' => array(
+ array(
+ 'partition_id' => $this->partitionId,
+ 'offset' => $offset,
+ ),
+ ),
+ ),
+ ),
+ );
+
+ $topicName = $this->topicName;
+ $partitionId = $this->partitionId;
+
+ $this->encoder->commitOffsetRequest($data);
+ $result = $this->decoder->commitOffsetResponse();
+ $this->client->freeStream($this->streamKey);
+ if (!isset($result[$topicName][$partitionId]['errCode'])) {
+ throw new \Kafka\Exception('commit topic offset failed.');
+ }
+ if ($result[$topicName][$partitionId]['errCode'] != 0) {
+ throw new \Kafka\Exception(\Kafka\Protocol\Decoder::getError($result[$topicName][$partitionId]['errCode']));
+ }
+ }
+
+ // }}}
+ // {{{ public function getOffset()
+
+ /**
+ * get consumer offset
+ *
+ * @param integer $defaultOffset
+ * if defaultOffset -1 instead of early offset
+ * if defaultOffset -2 instead of last offset
+ * @access public
+ * @return void
+ */
+ public function getOffset($defaultOffset = self::DEFAULT_LAST)
+ {
+ $maxOffset = $this->getProduceOffset(self::LAST_OFFSET);
+ $minOffset = $this->getProduceOffset(self::EARLIEST_OFFSET);
+ $data = array(
+ 'group_id' => $this->groupId,
+ 'data' => array(
+ array(
+ 'topic_name' => $this->topicName,
+ 'partitions' => array(
+ array(
+ 'partition_id' => $this->partitionId,
+ ),
+ ),
+ ),
+ ),
+ );
+
+ $this->encoder->fetchOffsetRequest($data);
+ $result = $this->decoder->fetchOffsetResponse();
+ $this->client->freeStream($this->streamKey);
+
+ $topicName = $this->topicName;
+ $partitionId = $this->partitionId;
+ if (!isset($result[$topicName][$partitionId]['errCode'])) {
+ throw new \Kafka\Exception('fetch topic offset failed.');
+ }
+ if ($result[$topicName][$partitionId]['errCode'] == 3) {
+ switch ($defaultOffset) {
+ case self::DEFAULT_LAST:
+ return $maxOffset;
+ Log::log("topic name: $topicName, partitionId: $partitionId, get offset value is default last.", LOG_INFO);
+ case self::DEFAULT_EARLY:
+ Log::log("topic name: $topicName, partitionId: $partitionId, get offset value is default early.", LOG_INFO);
+ return $minOffset;
+ default:
+ $this->setOffset($defaultOffset);
+ Log::log("topic name: $topicName, partitionId: $partitionId, get offset value is default $defaultOffset.", LOG_INFO);
+ return $defaultOffset;
+ }
+ if ($defaultOffset) {
+ $this->setOffset($defaultOffset);
+ return $defaultOffset;
+ }
+ } elseif ($result[$topicName][$partitionId]['errCode'] == 0) {
+ $offset = $result[$topicName][$partitionId]['offset'];
+ if ($offset > $maxOffset || $offset < $minOffset) {
+ if ($defaultOffset == self::DEFAULT_EARLY) {
+ $offset = $minOffset;
+ } else {
+ $offset = $maxOffset;
+ }
+ }
+ Log::log("topic name: $topicName, partitionId: $partitionId, get offset value is $offset.", LOG_INFO);
+
+ return $offset;
+ } else {
+ throw new \Kafka\Exception(\Kafka\Protocol\Decoder::getError($result[$topicName][$partitionId]['errCode']));
+ }
+ }
+
+ // }}}
+ // {{{ public function getProduceOffset()
+
+ /**
+ * get produce server offset
+ *
+ * @param string $topicName
+ * @param integer $partitionId
+ * @access public
+ * @return int
+ */
+ public function getProduceOffset($timeLine = self::LAST_OFFSET)
+ {
+ $topicName = $this->topicName;
+ $partitionId = $this->partitionId;
+
+ $requestData = array(
+ 'data' => array(
+ array(
+ 'topic_name' => $this->topicName,
+ 'partitions' => array(
+ array(
+ 'partition_id' => $this->partitionId,
+ 'time' => $timeLine,
+ 'max_offset' => 1,
+ ),
+ ),
+ ),
+ ),
+ );
+ $this->encoder->offsetRequest($requestData);
+ $result = $this->decoder->offsetResponse();
+ $this->client->freeStream($this->streamKey);
+
+ if (!isset($result[$topicName][$partitionId]['offset'])) {
+ if (isset($result[$topicName][$partitionId]['errCode'])) {
+ throw new \Kafka\Exception(\Kafka\Protocol\Decoder::getError($result[$topicName][$partitionId]['errCode']));
+ } else {
+ throw new \Kafka\Exception('get offset failed. topic name:' . $this->topicName . ' partitionId: ' . $this->partitionId);
+ }
+ }
+
+ return array_shift($result[$topicName][$partitionId]['offset']);
+ }
+
+ // }}}
+ // }}}
+}
diff --git a/vendor/nmred/kafka-php/src/Kafka/Produce.php b/vendor/nmred/kafka-php/src/Kafka/Produce.php
new file mode 100644
index 00000000..2b9e6cd3
--- /dev/null
+++ b/vendor/nmred/kafka-php/src/Kafka/Produce.php
@@ -0,0 +1,337 @@
+<?php
+/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4 foldmethod=marker: */
+// +---------------------------------------------------------------------------
+// | SWAN [ $_SWANBR_SLOGAN_$ ]
+// +---------------------------------------------------------------------------
+// | Copyright $_SWANBR_COPYRIGHT_$
+// +---------------------------------------------------------------------------
+// | Version $_SWANBR_VERSION_$
+// +---------------------------------------------------------------------------
+// | Licensed ( $_SWANBR_LICENSED_URL_$ )
+// +---------------------------------------------------------------------------
+// | $_SWANBR_WEB_DOMAIN_$
+// +---------------------------------------------------------------------------
+
+namespace Kafka;
+
+/**
++------------------------------------------------------------------------------
+* Kafka protocol since Kafka v0.8
++------------------------------------------------------------------------------
+*
+* @package
+* @version $_SWANBR_VERSION_$
+* @copyright Copyleft
+* @author $_SWANBR_AUTHOR_$
++------------------------------------------------------------------------------
+*/
+
+class Produce
+{
+ // {{{ consts
+ // }}}
+ // {{{ members
+
+ /**
+ * client
+ *
+ * @var mixed
+ * @access private
+ */
+ private $client = null;
+
+ /**
+ * send message options cache
+ *
+ * @var array
+ * @access private
+ */
+ private $payload = array();
+
+ /**
+ * default the server will not send any response
+ *
+ * @var float
+ * @access private
+ */
+ private $requiredAck = 0;
+
+ /**
+ * default timeout is 100ms
+ *
+ * @var float
+ * @access private
+ */
+ private $timeout = 100;
+
+ /**
+ * produce instance
+ *
+ * @var \Kafka\Produce
+ * @access private
+ */
+ private static $instance = null;
+
+ /**
+ * broker host list
+ *
+ * @var array
+ * @access private
+ */
+ private $hostList = array();
+
+ /**
+ * save broker connection
+ *
+ * @var array
+ * @access private
+ */
+ private $stream = array();
+
+ // }}}
+ // {{{ functions
+ // {{{ public function static getInstance()
+
+ /**
+ * set send messages
+ *
+ * @access public
+ * @return void
+ */
+ public static function getInstance($hostList, $timeout, $kafkaHostList = null)
+ {
+ if (is_null(self::$instance)) {
+ self::$instance = new self($hostList, $timeout, $kafkaHostList);
+ }
+
+ return self::$instance;
+ }
+
+ // }}}
+ // {{{ public function __construct()
+
+ /**
+ * __construct
+ *
+ * @access public
+ * @return void
+ */
+ public function __construct($hostList, $timeout = null, $kafkaHostList = null)
+ {
+ if ($hostList instanceof \Kafka\ClusterMetaData) {
+ $metadata = $hostList;
+ } elseif ( $kafkaHostList !== null ) {
+ $metadata = new \Kafka\MetaDataFromKafka($kafkaHostList);
+ } else {
+ $metadata = new \Kafka\ZooKeeper($hostList, $timeout);
+ }
+ $this->client = new \Kafka\Client($metadata);
+ }
+
+ // }}}
+ // {{{ public function setMessages()
+
+ /**
+ * set send messages
+ *
+ * @access public
+ * @return void
+ */
+ public function setMessages($topicName, $partitionId = 0, $messages = array())
+ {
+ if (isset($this->payload[$topicName][$partitionId])) {
+ $this->payload[$topicName][$partitionId] =
+ array_merge($this->payload[$topicName][$partitionId], $messages);
+ } else {
+ $this->payload[$topicName][$partitionId] = $messages;
+ }
+
+ return $this;
+ }
+
+ // }}}
+ // {{{ public function setRequireAck()
+
+ /**
+ * set request mode
+ * This field indicates how many acknowledgements the servers should receive
+ * before responding to the request. If it is 0 the server will not send any
+ * response (this is the only case where the server will not reply to a
+ * request). If it is 1, the server will wait the data is written to the
+ * local log before sending a response. If it is -1 the server will block
+ * until the message is committed by all in sync replicas before sending a
+ * response. For any number > 1 the server will block waiting for this
+ * number of acknowledgements to occur (but the server will never wait for
+ * more acknowledgements than there are in-sync replicas).
+ *
+ * @param int $ack
+ * @access public
+ * @return void
+ */
+ public function setRequireAck($ack = 0)
+ {
+ if ($ack >= -1) {
+ $this->requiredAck = (int) $ack;
+ }
+
+ return $this;
+ }
+
+ // }}}
+ // {{{ public function setTimeOut()
+
+ /**
+ * set request timeout
+ *
+ * @param int $timeout
+ * @access public
+ * @return void
+ */
+ public function setTimeOut($timeout = 100)
+ {
+ if ((int) $timeout) {
+ $this->timeout = (int) $timeout;
+ }
+ return $this;
+ }
+
+ // }}}
+ // {{{ public function send()
+
+ /**
+ * send message to broker
+ *
+ * @access public
+ * @return void
+ */
+ public function send()
+ {
+ $data = $this->_formatPayload();
+ if (empty($data)) {
+ return false;
+ }
+
+ $responseData = array();
+ foreach ($data as $host => $requestData) {
+ $stream = $this->client->getStream($host);
+ $conn = $stream['stream'];
+ $encoder = new \Kafka\Protocol\Encoder($conn);
+ $encoder->produceRequest($requestData);
+ if ((int) $this->requiredAck !== 0) { // get broker response
+ $decoder = new \Kafka\Protocol\Decoder($conn);
+ $response = $decoder->produceResponse();
+ foreach ($response as $topicName => $info) {
+ if (!isset($responseData[$topicName])) {
+ $responseData[$topicName] = $info;
+ } else {
+ $responseData[$topicName] = array_merge($info, $responseData[$topicName]);
+ }
+ }
+ }
+
+ $this->client->freeStream($stream['key']);
+ }
+
+ $this->payload = array();
+ return $responseData;
+ }
+
+ // }}}
+ // {{{ public function getClient()
+
+ /**
+ * get client object
+ *
+ * @access public
+ * @return void
+ */
+ public function getClient()
+ {
+ return $this->client;
+ }
+
+ /**
+ * passthru method to client for setting stream options
+ *
+ * @access public
+ * @param array $options
+ */
+ public function setStreamOptions($options = array())
+ {
+ $this->client->setStreamOptions($options);
+ }
+
+ // }}}
+ // {{{ public function getAvailablePartitions()
+
+ /**
+ * get available partition
+ *
+ * @access public
+ * @return array
+ */
+ public function getAvailablePartitions($topicName)
+ {
+ $topicDetail = $this->client->getTopicDetail($topicName);
+ if (is_array($topicDetail) && isset($topicDetail['partitions'])) {
+ $topicPartitiions = array_keys($topicDetail['partitions']);
+ } else {
+ $topicPartitiions = array();
+ }
+
+ return $topicPartitiions;
+ }
+
+ // }}}
+ // {{{ private function _formatPayload()
+
+ /**
+ * format payload array
+ *
+ * @access private
+ * @return array
+ */
+ private function _formatPayload()
+ {
+ if (empty($this->payload)) {
+ return array();
+ }
+
+ $data = array();
+ foreach ($this->payload as $topicName => $partitions) {
+ foreach ($partitions as $partitionId => $messages) {
+ $host = $this->client->getHostByPartition($topicName, $partitionId);
+ $data[$host][$topicName][$partitionId] = $messages;
+ }
+ }
+
+ $requestData = array();
+ foreach ($data as $host => $info) {
+ $topicData = array();
+ foreach ($info as $topicName => $partitions) {
+ $partitionData = array();
+ foreach ($partitions as $partitionId => $messages) {
+ $partitionData[] = array(
+ 'partition_id' => $partitionId,
+ 'messages' => $messages,
+ );
+ }
+ $topicData[] = array(
+ 'topic_name' => $topicName,
+ 'partitions' => $partitionData,
+ );
+ }
+
+ $requestData[$host] = array(
+ 'required_ack' => $this->requiredAck,
+ 'timeout' => $this->timeout,
+ 'data' => $topicData,
+ );
+ }
+
+ return $requestData;
+ }
+
+ // }}}
+ // }}}
+}
diff --git a/vendor/nmred/kafka-php/src/Kafka/Protocol/Decoder.php b/vendor/nmred/kafka-php/src/Kafka/Protocol/Decoder.php
new file mode 100644
index 00000000..f1e4b496
--- /dev/null
+++ b/vendor/nmred/kafka-php/src/Kafka/Protocol/Decoder.php
@@ -0,0 +1,430 @@
+<?php
+/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4 foldmethod=marker: */
+// +---------------------------------------------------------------------------
+// | SWAN [ $_SWANBR_SLOGAN_$ ]
+// +---------------------------------------------------------------------------
+// | Copyright $_SWANBR_COPYRIGHT_$
+// +---------------------------------------------------------------------------
+// | Version $_SWANBR_VERSION_$
+// +---------------------------------------------------------------------------
+// | Licensed ( $_SWANBR_LICENSED_URL_$ )
+// +---------------------------------------------------------------------------
+// | $_SWANBR_WEB_DOMAIN_$
+// +---------------------------------------------------------------------------
+
+namespace Kafka\Protocol;
+
+/**
++------------------------------------------------------------------------------
+* Kafka protocol since Kafka v0.8
++------------------------------------------------------------------------------
+*
+* @package
+* @version $_SWANBR_VERSION_$
+* @copyright Copyleft
+* @author $_SWANBR_AUTHOR_$
++------------------------------------------------------------------------------
+*/
+
+class Decoder extends Protocol
+{
+ // {{{ functions
+ // {{{ public function produceResponse()
+
+ /**
+ * decode produce response
+ *
+ * @param string $data
+ * @access public
+ * @return array
+ */
+ public function produceResponse()
+ {
+ $result = array();
+ $dataLen = self::unpack(self::BIT_B32, $this->stream->read(4, true));
+ $dataLen = array_shift($dataLen);
+ if (!$dataLen) {
+ throw new \Kafka\Exception\Protocol('produce response invalid.');
+ }
+ $data = $this->stream->read($dataLen, true);
+
+ // parse data struct
+ $offset = 4;
+ $topicCount = self::unpack(self::BIT_B32, substr($data, $offset, 4));
+ $topicCount = array_shift($topicCount);
+ $offset += 4;
+ for ($i = 0; $i < $topicCount; $i++) {
+ $topicLen = self::unpack(self::BIT_B16, substr($data, $offset, 2)); // int16 topic name length
+ $topicLen = isset($topicLen[1]) ? $topicLen[1] : 0;
+ $offset += 2;
+ $topicName = substr($data, $offset, $topicLen);
+ $offset += $topicLen;
+ $partitionCount = self::unpack(self::BIT_B32, substr($data, $offset, 4));
+ $partitionCount = isset($partitionCount[1]) ? $partitionCount[1] : 0;
+ $offset += 4;
+ $result[$topicName] = array();
+ for ($j = 0; $j < $partitionCount; $j++) {
+ $partitionId = self::unpack(self::BIT_B32, substr($data, $offset, 4));
+ $offset += 4;
+ $errCode = self::unpack(self::BIT_B16, substr($data, $offset, 2));
+ $offset += 2;
+ $partitionOffset = self::unpack(self::BIT_B64, substr($data, $offset, 8));
+ $offset += 8;
+ $result[$topicName][$partitionId[1]] = array(
+ 'errCode' => $errCode[1],
+ 'offset' => $partitionOffset
+ );
+ }
+ }
+
+ return $result;
+ }
+
+ // }}}
+ // {{{ public function fetchResponse()
+
+ /**
+ * decode fetch response
+ *
+ * @param string $data
+ * @access public
+ * @return Iterator
+ */
+ public function fetchResponse()
+ {
+ return new \Kafka\Protocol\Fetch\Topic($this->stream);
+ }
+
+ // }}}
+ // {{{ public function metadataResponse()
+
+ /**
+ * decode metadata response
+ *
+ * @param string $data
+ * @access public
+ * @return array
+ */
+ public function metadataResponse()
+ {
+ $result = array();
+ $broker = array();
+ $topic = array();
+ $dataLen = self::unpack(self::BIT_B32, $this->stream->read(4, true));
+ $dataLen = array_shift($dataLen);
+ if (!$dataLen) {
+ throw new \Kafka\Exception\Protocol('metaData response invalid.');
+ }
+ $data = $this->stream->read($dataLen, true);
+ $offset = 4;
+ $brokerCount = self::unpack(self::BIT_B32, substr($data, $offset, 4));
+ $offset += 4;
+ $brokerCount = isset($brokerCount[1]) ? $brokerCount[1] : 0;
+ for ($i = 0; $i < $brokerCount; $i++) {
+ $nodeId = self::unpack(self::BIT_B32, substr($data, $offset, 4));
+ $nodeId = $nodeId[1];
+ $offset += 4;
+ $hostNameLen = self::unpack(self::BIT_B16, substr($data, $offset, 2)); // int16 host name length
+ $hostNameLen = isset($hostNameLen[1]) ? $hostNameLen[1] : 0;
+ $offset += 2;
+ $hostName = substr($data, $offset, $hostNameLen);
+ $offset += $hostNameLen;
+ $port = self::unpack(self::BIT_B32, substr($data, $offset, 4));
+ $offset += 4;
+ $broker[$nodeId] = array(
+ 'host' => $hostName,
+ 'port' => $port[1],
+ );
+ }
+
+ $topicMetaCount = self::unpack(self::BIT_B32, substr($data, $offset, 4));
+ $offset += 4;
+ $topicMetaCount = isset($topicMetaCount[1]) ? $topicMetaCount[1] : 0;
+ for ($i = 0; $i < $topicMetaCount; $i++) {
+ $topicErrCode = self::unpack(self::BIT_B16, substr($data, $offset, 2));
+ $offset += 2;
+ $topicLen = self::unpack(self::BIT_B16, substr($data, $offset, 2));
+ $offset += 2;
+ $topicName = substr($data, $offset, $topicLen[1]);
+ $offset += $topicLen[1];
+ $partitionCount = self::unpack(self::BIT_B32, substr($data, $offset, 4));
+ $offset += 4;
+ $partitionCount = isset($partitionCount[1]) ? $partitionCount[1] : 0;
+ $topic[$topicName]['errCode'] = $topicErrCode[1];
+ $partitions = array();
+ for ($j = 0; $j < $partitionCount; $j++) {
+ $partitionErrCode = self::unpack(self::BIT_B16, substr($data, $offset, 2));
+ $offset += 2;
+ $partitionId = self::unpack(self::BIT_B32, substr($data, $offset, 4));
+ $partitionId = isset($partitionId[1]) ? $partitionId[1] : 0;
+ $offset += 4;
+ $leaderId = self::unpack(self::BIT_B32, substr($data, $offset, 4));
+ $offset += 4;
+ $repliasCount = self::unpack(self::BIT_B32, substr($data, $offset, 4));
+ $offset += 4;
+ $repliasCount = isset($repliasCount[1]) ? $repliasCount[1] : 0;
+ $replias = array();
+ for ($z = 0; $z < $repliasCount; $z++) {
+ $repliaId = self::unpack(self::BIT_B32, substr($data, $offset, 4));
+ $offset += 4;
+ $replias[] = $repliaId[1];
+ }
+ $isrCount = self::unpack(self::BIT_B32, substr($data, $offset, 4));
+ $offset += 4;
+ $isrCount = isset($isrCount[1]) ? $isrCount[1] : 0;
+ $isrs = array();
+ for ($z = 0; $z < $isrCount; $z++) {
+ $isrId = self::unpack(self::BIT_B32, substr($data, $offset, 4));
+ $offset += 4;
+ $isrs[] = $isrId[1];
+ }
+
+ $partitions[$partitionId] = array(
+ 'errCode' => $partitionErrCode[1],
+ 'leader' => $leaderId[1],
+ 'replicas' => $replias,
+ 'isr' => $isrs,
+ );
+ }
+ $topic[$topicName]['partitions'] = $partitions;
+ }
+
+ $result = array(
+ 'brokers' => $broker,
+ 'topics' => $topic,
+ );
+ return $result;
+ }
+
+ // }}}
+ // {{{ public function offsetResponse()
+
+ /**
+ * decode offset response
+ *
+ * @param string $data
+ * @access public
+ * @return array
+ */
+ public function offsetResponse()
+ {
+ $result = array();
+ $dataLen = self::unpack(self::BIT_B32, $this->stream->read(4, true));
+ $dataLen = array_shift($dataLen);
+ if (!$dataLen) {
+ throw new \Kafka\Exception\Protocol('offset response invalid.');
+ }
+ $data = $this->stream->read($dataLen, true);
+ $offset = 4;
+ $topicCount = self::unpack(self::BIT_B32, substr($data, $offset, 4));
+ $offset += 4;
+ $topicCount = array_shift($topicCount);
+ for ($i = 0; $i < $topicCount; $i++) {
+ $topicLen = self::unpack(self::BIT_B16, substr($data, $offset, 2)); // int16 topic name length
+ $topicLen = isset($topicLen[1]) ? $topicLen[1] : 0;
+ $offset += 2;
+ $topicName = substr($data, $offset, $topicLen);
+ $offset += $topicLen;
+ $partitionCount = self::unpack(self::BIT_B32, substr($data, $offset, 4));
+ $partitionCount = isset($partitionCount[1]) ? $partitionCount[1] : 0;
+ $offset += 4;
+ $result[$topicName] = array();
+ for ($j = 0; $j < $partitionCount; $j++) {
+ $partitionId = self::unpack(self::BIT_B32, substr($data, $offset, 4));
+ $offset += 4;
+ $errCode = self::unpack(self::BIT_B16, substr($data, $offset, 2));
+ $offset += 2;
+ $offsetCount = self::unpack(self::BIT_B32, substr($data, $offset, 4));
+ $offset += 4;
+ $offsetCount = array_shift($offsetCount);
+ $offsetArr = array();
+ for ($z = 0; $z < $offsetCount; $z++) {
+ $offsetArr[] = self::unpack(self::BIT_B64, substr($data, $offset, 8));
+ $offset += 8;
+ }
+ $result[$topicName][$partitionId[1]] = array(
+ 'errCode' => $errCode[1],
+ 'offset' => $offsetArr
+ );
+ }
+ }
+ return $result;
+ }
+
+ // }}}
+ // {{{ public function commitOffsetResponse()
+
+ /**
+ * decode commit offset response
+ *
+ * @param string $data
+ * @access public
+ * @return array
+ */
+ public function commitOffsetResponse()
+ {
+ $result = array();
+ $dataLen = self::unpack(self::BIT_B32, $this->stream->read(4, true));
+ $dataLen = array_shift($dataLen);
+ if (!$dataLen) {
+ throw new \Kafka\Exception\Protocol('commit offset response invalid.');
+ }
+ $data = $this->stream->read($dataLen, true);
+ $offset = 4;
+ $topicCount = self::unpack(self::BIT_B32, substr($data, $offset, 4));
+ $offset += 4;
+ $topicCount = array_shift($topicCount);
+ for ($i = 0; $i < $topicCount; $i++) {
+ $topicLen = self::unpack(self::BIT_B16, substr($data, $offset, 2)); // int16 topic name length
+ $topicLen = isset($topicLen[1]) ? $topicLen[1] : 0;
+ $offset += 2;
+ $topicName = substr($data, $offset, $topicLen);
+ $offset += $topicLen;
+ $partitionCount = self::unpack(self::BIT_B32, substr($data, $offset, 4));
+ $partitionCount = isset($partitionCount[1]) ? $partitionCount[1] : 0;
+ $offset += 4;
+ $result[$topicName] = array();
+ for ($j = 0; $j < $partitionCount; $j++) {
+ $partitionId = self::unpack(self::BIT_B32, substr($data, $offset, 4));
+ $offset += 4;
+ $errCode = self::unpack(self::BIT_B16, substr($data, $offset, 2));
+ $offset += 2;
+ $result[$topicName][$partitionId[1]] = array(
+ 'errCode' => $errCode[1],
+ );
+ }
+ }
+ return $result;
+ }
+
+ // }}}
+ // {{{ public function fetchOffsetResponse()
+
+ /**
+ * decode fetch offset response
+ *
+ * @param string $data
+ * @access public
+ * @return array
+ */
+ public function fetchOffsetResponse()
+ {
+ $result = array();
+ $dataLen = self::unpack(self::BIT_B32, $this->stream->read(4, true));
+ $dataLen = array_shift($dataLen);
+ if (!$dataLen) {
+ throw new \Kafka\Exception\Protocol('fetch offset response invalid.');
+ }
+ $data = $this->stream->read($dataLen, true);
+ $offset = 4;
+ $topicCount = self::unpack(self::BIT_B32, substr($data, $offset, 4));
+ $offset += 4;
+ $topicCount = array_shift($topicCount);
+ for ($i = 0; $i < $topicCount; $i++) {
+ $topicLen = self::unpack(self::BIT_B16, substr($data, $offset, 2)); // int16 topic name length
+ $topicLen = isset($topicLen[1]) ? $topicLen[1] : 0;
+ $offset += 2;
+ $topicName = substr($data, $offset, $topicLen);
+ $offset += $topicLen;
+ $partitionCount = self::unpack(self::BIT_B32, substr($data, $offset, 4));
+ $partitionCount = isset($partitionCount[1]) ? $partitionCount[1] : 0;
+ $offset += 4;
+ $result[$topicName] = array();
+ for ($j = 0; $j < $partitionCount; $j++) {
+ $partitionId = self::unpack(self::BIT_B32, substr($data, $offset, 4));
+ $offset += 4;
+ $partitionOffset = self::unpack(self::BIT_B64, substr($data, $offset, 8));
+ $offset += 8;
+ $metaLen = self::unpack(self::BIT_B16, substr($data, $offset, 2));
+ $metaLen = array_shift($metaLen);
+ $offset += 2;
+ $metaData = '';
+ if ($metaLen) {
+ $metaData = substr($data, $offset, $metaLen);
+ $offset += $metaLen;
+ }
+ $errCode = self::unpack(self::BIT_B16, substr($data, $offset, 2));
+ $offset += 2;
+ $result[$topicName][$partitionId[1]] = array(
+ 'offset' => $partitionOffset,
+ 'metadata' => $metaData,
+ 'errCode' => $errCode[1],
+ );
+ }
+ }
+ return $result;
+ }
+
+ // }}}
+ // {{{ public static function getError()
+
+ /**
+ * get error
+ *
+ * @param integer $errCode
+ * @static
+ * @access public
+ * @return string
+ */
+ public static function getError($errCode)
+ {
+ $error = '';
+ switch($errCode) {
+ case 0:
+ $error = 'No error--it worked!';
+ break;
+ case -1:
+ $error = 'An unexpected server error';
+ break;
+ case 1:
+ $error = 'The requested offset is outside the range of offsets maintained by the server for the given topic/partition.';
+ break;
+ case 2:
+ $error = 'This indicates that a message contents does not match its CRC';
+ break;
+ case 3:
+ $error = 'This request is for a topic or partition that does not exist on this broker.';
+ break;
+ case 4:
+ $error = 'The message has a negative size';
+ break;
+ case 5:
+ $error = 'This error is thrown if we are in the middle of a leadership election and there is currently no leader for this partition and hence it is unavailable for writes';
+ break;
+ case 6:
+ $error = 'This error is thrown if the client attempts to send messages to a replica that is not the leader for some partition. It indicates that the clients metadata is out of date.';
+ break;
+ case 7:
+ $error = 'This error is thrown if the request exceeds the user-specified time limit in the request.';
+ break;
+ case 8:
+ $error = 'This is not a client facing error and is used only internally by intra-cluster broker communication.';
+ break;
+ case 10:
+ $error = 'The server has a configurable maximum message size to avoid unbounded memory allocation. This error is thrown if the client attempt to produce a message larger than this maximum.';
+ break;
+ case 11:
+ $error = 'Internal error code for broker-to-broker communication.';
+ break;
+ case 12:
+ $error = 'If you specify a string larger than configured maximum for offset metadata';
+ break;
+ case 14:
+ $error = 'The broker returns this error code for an offset fetch request if it is still loading offsets (after a leader change for that offsets topic partition).';
+ break;
+ case 15:
+ $error = 'The broker returns this error code for consumer metadata requests or offset commit requests if the offsets topic has not yet been created.';
+ break;
+ case 16:
+ $error = 'The broker returns this error code if it receives an offset fetch or commit request for a consumer group that it is not a coordinator for.';
+ break;
+ default:
+ $error = 'Unknown error';
+ }
+
+ return $error;
+ }
+
+ // }}}
+ // }}}
+}
diff --git a/vendor/nmred/kafka-php/src/Kafka/Protocol/Encoder.php b/vendor/nmred/kafka-php/src/Kafka/Protocol/Encoder.php
new file mode 100644
index 00000000..7d36e10f
--- /dev/null
+++ b/vendor/nmred/kafka-php/src/Kafka/Protocol/Encoder.php
@@ -0,0 +1,652 @@
+<?php
+/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4 foldmethod=marker: */
+// +---------------------------------------------------------------------------
+// | SWAN [ $_SWANBR_SLOGAN_$ ]
+// +---------------------------------------------------------------------------
+// | Copyright $_SWANBR_COPYRIGHT_$
+// +---------------------------------------------------------------------------
+// | Version $_SWANBR_VERSION_$
+// +---------------------------------------------------------------------------
+// | Licensed ( $_SWANBR_LICENSED_URL_$ )
+// +---------------------------------------------------------------------------
+// | $_SWANBR_WEB_DOMAIN_$
+// +---------------------------------------------------------------------------
+
+namespace Kafka\Protocol;
+
+/**
++------------------------------------------------------------------------------
+* Kafka protocol since Kafka v0.8
++------------------------------------------------------------------------------
+*
+* @package
+* @version $_SWANBR_VERSION_$
+* @copyright Copyleft
+* @author $_SWANBR_AUTHOR_$
++------------------------------------------------------------------------------
+*/
+
+class Encoder extends Protocol
+{
+ // {{{ functions
+ // {{{ public function produceRequest()
+
+ /**
+ * produce request
+ *
+ * @param array $payloads
+ * @static
+ * @access public
+ * @return void
+ */
+ public function produceRequest($payloads, $compression = self::COMPRESSION_NONE)
+ {
+ if (!isset($payloads['data'])) {
+ throw new \Kafka\Exception\Protocol('given procude data invalid. `data` is undefined.');
+ }
+
+ if (!isset($payloads['required_ack'])) {
+ // default server will not send any response
+ // (this is the only case where the server will not reply to a request)
+ $payloads['required_ack'] = 0;
+ }
+
+ if (!isset($payloads['timeout'])) {
+ $payloads['timeout'] = 100; // default timeout 100ms
+ }
+
+ $header = self::requestHeader('kafka-php', 0, self::PRODUCE_REQUEST);
+ $data = self::pack(self::BIT_B16, $payloads['required_ack']);
+ $data .= self::pack(self::BIT_B32, $payloads['timeout']);
+ $data .= self::encodeArray($payloads['data'], array(__CLASS__, '_encodeProcudeTopic'), $compression);
+ $data = self::encodeString($header . $data, self::PACK_INT32);
+
+ return $this->stream->write($data);
+ }
+
+ // }}}
+ // {{{ public function metadataRequest()
+
+ /**
+ * build metadata request protocol
+ *
+ * @param array $topics
+ * @access public
+ * @return string
+ */
+ public function metadataRequest($topics)
+ {
+ if (!is_array($topics)) {
+ $topics = array($topics);
+ }
+
+ foreach ($topics as $topic) {
+ if (!is_string($topic)) {
+ throw new \Kafka\Exception\Protocol('request metadata topic array have invalid value. ');
+ }
+ }
+
+ $header = self::requestHeader('kafka-php', 0, self::METADATA_REQUEST);
+ $data = self::encodeArray($topics, array(__CLASS__, 'encodeString'), self::PACK_INT16);
+ $data = self::encodeString($header . $data, self::PACK_INT32);
+
+ return $this->stream->write($data);
+ }
+
+ // }}}
+ // {{{ public function fetchRequest()
+
+ /**
+ * build fetch request
+ *
+ * @param array $payloads
+ * @access public
+ * @return string
+ */
+ public function fetchRequest($payloads)
+ {
+ if (!isset($payloads['data'])) {
+ throw new \Kafka\Exception\Protocol('given fetch kafka data invalid. `data` is undefined.');
+ }
+
+ if (!isset($payloads['replica_id'])) {
+ $payloads['replica_id'] = -1;
+ }
+
+ if (!isset($payloads['max_wait_time'])) {
+ $payloads['max_wait_time'] = 100; // default timeout 100ms
+ }
+
+ if (!isset($payloads['min_bytes'])) {
+ $payloads['min_bytes'] = 64 * 1024; // 64k
+ }
+
+ $header = self::requestHeader('kafka-php', 0, self::FETCH_REQUEST);
+ $data = self::pack(self::BIT_B32, $payloads['replica_id']);
+ $data .= self::pack(self::BIT_B32, $payloads['max_wait_time']);
+ $data .= self::pack(self::BIT_B32, $payloads['min_bytes']);
+ $data .= self::encodeArray($payloads['data'], array(__CLASS__, '_encodeFetchTopic'));
+ $data = self::encodeString($header . $data, self::PACK_INT32);
+
+ return $this->stream->write($data);
+ }
+
+ // }}}
+ // {{{ public function offsetRequest()
+
+ /**
+ * build offset request
+ *
+ * @param array $payloads
+ * @access public
+ * @return string
+ */
+ public function offsetRequest($payloads)
+ {
+ if (!isset($payloads['data'])) {
+ throw new \Kafka\Exception\Protocol('given offset data invalid. `data` is undefined.');
+ }
+
+ if (!isset($payloads['replica_id'])) {
+ $payloads['replica_id'] = -1;
+ }
+
+ $header = self::requestHeader('kafka-php', 0, self::OFFSET_REQUEST);
+ $data = self::pack(self::BIT_B32, $payloads['replica_id']);
+ $data .= self::encodeArray($payloads['data'], array(__CLASS__, '_encodeOffsetTopic'));
+ $data = self::encodeString($header . $data, self::PACK_INT32);
+
+ return $this->stream->write($data);
+ }
+
+ // }}}
+ // {{{ public function commitOffsetRequest()
+
+ /**
+ * build consumer commit offset request
+ *
+ * @param array $payloads
+ * @access public
+ * @return string
+ */
+ public function commitOffsetRequest($payloads)
+ {
+ if (!isset($payloads['data'])) {
+ throw new \Kafka\Exception\Protocol('given commit offset data invalid. `data` is undefined.');
+ }
+
+ if (!isset($payloads['group_id'])) {
+ throw new \Kafka\Exception\Protocol('given commit offset data invalid. `group_id` is undefined.');
+ }
+
+ $header = self::requestHeader('kafka-php', 0, self::OFFSET_COMMIT_REQUEST);
+ $data = self::encodeString($payloads['group_id'], self::PACK_INT16);
+ $data .= self::encodeArray($payloads['data'], array(__CLASS__, '_encodeCommitOffset'));
+ $data = self::encodeString($header . $data, self::PACK_INT32);
+
+ return $this->stream->write($data);
+ }
+
+ // }}}
+ // {{{ public function fetchOffsetRequest()
+
+ /**
+ * build consumer fetch offset request
+ *
+ * @param array $payloads
+ * @access public
+ * @return string
+ */
+ public function fetchOffsetRequest($payloads)
+ {
+ if (!isset($payloads['data'])) {
+ throw new \Kafka\Exception\Protocol('given fetch offset data invalid. `data` is undefined.');
+ }
+
+ if (!isset($payloads['group_id'])) {
+ throw new \Kafka\Exception\Protocol('given fetch offset data invalid. `group_id` is undefined.');
+ }
+
+ $header = self::requestHeader('kafka-php', 0, self::OFFSET_FETCH_REQUEST);
+ $data = self::encodeString($payloads['group_id'], self::PACK_INT16);
+ $data .= self::encodeArray($payloads['data'], array(__CLASS__, '_encodeFetchOffset'));
+ $data = self::encodeString($header . $data, self::PACK_INT32);
+
+ return $this->stream->write($data);
+ }
+
+ // }}}
+ // {{{ public static function encodeString()
+
+ /**
+ * encode pack string type
+ *
+ * @param string $string
+ * @param int $bytes self::PACK_INT32: int32 big endian order. self::PACK_INT16: int16 big endian order.
+ * @static
+ * @access public
+ * @return string
+ */
+ public static function encodeString($string, $bytes, $compression = self::COMPRESSION_NONE)
+ {
+ $packLen = ($bytes == self::PACK_INT32) ? self::BIT_B32 : self::BIT_B16;
+ switch ($compression) {
+ case self::COMPRESSION_NONE:
+ break;
+ case self::COMPRESSION_GZIP:
+ $string = gzencode($string);
+ break;
+ case self::COMPRESSION_SNAPPY:
+ throw new \Kafka\Exception\NotSupported('SNAPPY compression not yet implemented');
+ default:
+ throw new \Kafka\Exception\NotSupported('Unknown compression flag: ' . $compression);
+ }
+ return self::pack($packLen, strlen($string)) . $string;
+ }
+
+ // }}}
+ // {{{ public static function encodeArray()
+
+ /**
+ * encode key array
+ *
+ * @param array $array
+ * @param Callable $func
+ * @static
+ * @access public
+ * @return string
+ */
+ public static function encodeArray(array $array, $func, $options = null)
+ {
+ if (!is_callable($func, false)) {
+ throw new \Kafka\Exception\Protocol('Encode array failed, given function is not callable.');
+ }
+
+ $arrayCount = count($array);
+
+ $body = '';
+ foreach ($array as $value) {
+ if (!is_null($options)) {
+ $body .= call_user_func($func, $value, $options);
+ } else {
+ $body .= call_user_func($func, $value);
+ }
+ }
+
+ return self::pack(self::BIT_B32, $arrayCount) . $body;
+ }
+
+ // }}}
+ // {{{ public static function encodeMessageSet()
+
+ /**
+ * encode message set
+ * N.B., MessageSets are not preceded by an int32 like other array elements
+ * in the protocol.
+ *
+ * @param array $messages
+ * @static
+ * @access public
+ * @return string
+ */
+ public static function encodeMessageSet($messages, $compression = self::COMPRESSION_NONE)
+ {
+ if (!is_array($messages)) {
+ $messages = array($messages);
+ }
+
+ $data = '';
+ foreach ($messages as $message) {
+ $tmpMessage = self::_encodeMessage($message, $compression);
+
+ // int64 -- message offset Message
+ $data .= self::pack(self::BIT_B64, 0) . self::encodeString($tmpMessage, self::PACK_INT32);
+ }
+ return $data;
+ }
+
+ // }}}
+ // {{{ public static function requestHeader()
+
+ /**
+ * get request header
+ *
+ * @param string $clientId
+ * @param integer $correlationId
+ * @param integer $apiKey
+ * @static
+ * @access public
+ * @return void
+ */
+ public static function requestHeader($clientId, $correlationId, $apiKey)
+ {
+ // int16 -- apiKey int16 -- apiVersion int32 correlationId
+ $binData = self::pack(self::BIT_B16, $apiKey);
+ $binData .= self::pack(self::BIT_B16, self::API_VERSION);
+ $binData .= self::pack(self::BIT_B32, $correlationId);
+
+ // concat client id
+ $binData .= self::encodeString($clientId, self::PACK_INT16);
+
+ return $binData;
+ }
+
+ // }}}
+ // {{{ protected static function _encodeMessage()
+
+ /**
+ * encode signal message
+ *
+ * @param string $message
+ * @static
+ * @access protected
+ * @return string
+ */
+ protected static function _encodeMessage($message, $compression = self::COMPRESSION_NONE)
+ {
+ // int8 -- magic int8 -- attribute
+ $data = self::pack(self::BIT_B8, self::MESSAGE_MAGIC);
+ $data .= self::pack(self::BIT_B8, $compression);
+
+ // message key
+ $data .= self::encodeString('', self::PACK_INT32);
+
+ // message value
+ $data .= self::encodeString($message, self::PACK_INT32, $compression);
+
+ $crc = crc32($data);
+
+ // int32 -- crc code string data
+ $message = self::pack(self::BIT_B32, $crc) . $data;
+
+ return $message;
+ }
+
+ // }}}
+ // {{{ protected static function _encodeProcudePartion()
+
+ /**
+ * encode signal part
+ *
+ * @param partions
+ * @static
+ * @access protected
+ * @return string
+ */
+ protected static function _encodeProcudePartion($values, $compression)
+ {
+ if (!isset($values['partition_id'])) {
+ throw new \Kafka\Exception\Protocol('given produce data invalid. `partition_id` is undefined.');
+ }
+
+ if (!isset($values['messages']) || empty($values['messages'])) {
+ throw new \Kafka\Exception\Protocol('given produce data invalid. `messages` is undefined.');
+ }
+
+ $data = self::pack(self::BIT_B32, $values['partition_id']);
+ $data .= self::encodeString(self::encodeMessageSet($values['messages'], $compression), self::PACK_INT32);
+
+ return $data;
+ }
+
+ // }}}
+ // {{{ protected static function _encodeProcudeTopic()
+
+ /**
+ * encode signal topic
+ *
+ * @param partions
+ * @static
+ * @access protected
+ * @return string
+ */
+ protected static function _encodeProcudeTopic($values, $compression)
+ {
+ if (!isset($values['topic_name'])) {
+ throw new \Kafka\Exception\Protocol('given produce data invalid. `topic_name` is undefined.');
+ }
+
+ if (!isset($values['partitions']) || empty($values['partitions'])) {
+ throw new \Kafka\Exception\Protocol('given produce data invalid. `partitions` is undefined.');
+ }
+
+ $topic = self::encodeString($values['topic_name'], self::PACK_INT16);
+ $partitions = self::encodeArray($values['partitions'], array(__CLASS__, '_encodeProcudePartion'), $compression);
+
+ return $topic . $partitions;
+ }
+
+ // }}}
+ // {{{ protected static function _encodeFetchPartion()
+
+ /**
+ * encode signal part
+ *
+ * @param partions
+ * @static
+ * @access protected
+ * @return string
+ */
+ protected static function _encodeFetchPartion($values)
+ {
+ if (!isset($values['partition_id'])) {
+ throw new \Kafka\Exception\Protocol('given fetch data invalid. `partition_id` is undefined.');
+ }
+
+ if (!isset($values['offset'])) {
+ $values['offset'] = 0;
+ }
+
+ if (!isset($values['max_bytes'])) {
+ $values['max_bytes'] = 100 * 1024 * 1024;
+ }
+
+ $data = self::pack(self::BIT_B32, $values['partition_id']);
+ $data .= self::pack(self::BIT_B64, $values['offset']);
+ $data .= self::pack(self::BIT_B32, $values['max_bytes']);
+
+ return $data;
+ }
+
+ // }}}
+ // {{{ protected static function _encodeFetchTopic()
+
+ /**
+ * encode signal topic
+ *
+ * @param partions
+ * @static
+ * @access protected
+ * @return string
+ */
+ protected static function _encodeFetchTopic($values)
+ {
+ if (!isset($values['topic_name'])) {
+ throw new \Kafka\Exception\Protocol('given fetch data invalid. `topic_name` is undefined.');
+ }
+
+ if (!isset($values['partitions']) || empty($values['partitions'])) {
+ throw new \Kafka\Exception\Protocol('given fetch data invalid. `partitions` is undefined.');
+ }
+
+ $topic = self::encodeString($values['topic_name'], self::PACK_INT16);
+ $partitions = self::encodeArray($values['partitions'], array(__CLASS__, '_encodeFetchPartion'));
+
+ return $topic . $partitions;
+ }
+
+ // }}}
+ // {{{ protected static function _encodeOffsetPartion()
+
+ /**
+ * encode signal part
+ *
+ * @param partions
+ * @static
+ * @access protected
+ * @return string
+ */
+ protected static function _encodeOffsetPartion($values)
+ {
+ if (!isset($values['partition_id'])) {
+ throw new \Kafka\Exception\Protocol('given offset data invalid. `partition_id` is undefined.');
+ }
+
+ if (!isset($values['time'])) {
+ $values['time'] = -1; // -1
+ }
+
+ if (!isset($values['max_offset'])) {
+ $values['max_offset'] = 100000;
+ }
+
+ $data = self::pack(self::BIT_B32, $values['partition_id']);
+ $data .= self::pack(self::BIT_B64, $values['time']);
+ $data .= self::pack(self::BIT_B32, $values['max_offset']);
+
+ return $data;
+ }
+
+ // }}}
+ // {{{ protected static function _encodeOffsetTopic()
+
+ /**
+ * encode signal topic
+ *
+ * @param partions
+ * @static
+ * @access protected
+ * @return string
+ */
+ protected static function _encodeOffsetTopic($values)
+ {
+ if (!isset($values['topic_name'])) {
+ throw new \Kafka\Exception\Protocol('given offset data invalid. `topic_name` is undefined.');
+ }
+
+ if (!isset($values['partitions']) || empty($values['partitions'])) {
+ throw new \Kafka\Exception\Protocol('given offset data invalid. `partitions` is undefined.');
+ }
+
+ $topic = self::encodeString($values['topic_name'], self::PACK_INT16);
+ $partitions = self::encodeArray($values['partitions'], array(__CLASS__, '_encodeOffsetPartion'));
+
+ return $topic . $partitions;
+ }
+
+ // }}}
+ // {{{ protected static function _encodeCommitOffsetPartion()
+
+ /**
+ * encode signal part
+ *
+ * @param partions
+ * @static
+ * @access protected
+ * @return string
+ */
+ protected static function _encodeCommitOffsetPartion($values)
+ {
+ if (!isset($values['partition_id'])) {
+ throw new \Kafka\Exception\Protocol('given commit offset data invalid. `partition_id` is undefined.');
+ }
+
+ if (!isset($values['offset'])) {
+ throw new \Kafka\Exception\Protocol('given commit offset data invalid. `offset` is undefined.');
+ }
+
+ if (!isset($values['time'])) {
+ $values['time'] = -1;
+ }
+
+ if (!isset($values['metadata'])) {
+ $values['metadata'] = 'm';
+ }
+
+ $data = self::pack(self::BIT_B32, $values['partition_id']);
+ $data .= self::pack(self::BIT_B64, $values['offset']);
+ $data .= self::pack(self::BIT_B64, $values['time']);
+ $data .= self::encodeString($values['metadata'], self::PACK_INT16);
+
+ return $data;
+ }
+
+ // }}}
+ // {{{ protected static function _encodeCommitOffset()
+
+ /**
+ * encode signal topic
+ *
+ * @param partions
+ * @static
+ * @access protected
+ * @return string
+ */
+ protected static function _encodeCommitOffset($values)
+ {
+ if (!isset($values['topic_name'])) {
+ throw new \Kafka\Exception\Protocol('given commit offset data invalid. `topic_name` is undefined.');
+ }
+
+ if (!isset($values['partitions']) || empty($values['partitions'])) {
+ throw new \Kafka\Exception\Protocol('given commit offset data invalid. `partitions` is undefined.');
+ }
+
+ $topic = self::encodeString($values['topic_name'], self::PACK_INT16);
+ $partitions = self::encodeArray($values['partitions'], array(__CLASS__, '_encodeCommitOffsetPartion'));
+
+ return $topic . $partitions;
+ }
+
+ // }}}
+ // {{{ protected static function _encodeFetchOffsetPartion()
+
+ /**
+ * encode signal part
+ *
+ * @param partions
+ * @static
+ * @access protected
+ * @return string
+ */
+ protected static function _encodeFetchOffsetPartion($values)
+ {
+ if (!isset($values['partition_id'])) {
+ throw new \Kafka\Exception\Protocol('given fetch offset data invalid. `partition_id` is undefined.');
+ }
+
+ $data = self::pack(self::BIT_B32, $values['partition_id']);
+
+ return $data;
+ }
+
+ // }}}
+ // {{{ protected static function _encodeFetchOffset()
+
+ /**
+ * encode signal topic
+ *
+ * @param partions
+ * @static
+ * @access protected
+ * @return string
+ */
+ protected static function _encodeFetchOffset($values)
+ {
+ if (!isset($values['topic_name'])) {
+ throw new \Kafka\Exception\Protocol('given fetch offset data invalid. `topic_name` is undefined.');
+ }
+
+ if (!isset($values['partitions']) || empty($values['partitions'])) {
+ throw new \Kafka\Exception\Protocol('given fetch offset data invalid. `partitions` is undefined.');
+ }
+
+ $topic = self::encodeString($values['topic_name'], self::PACK_INT16);
+ $partitions = self::encodeArray($values['partitions'], array(__CLASS__, '_encodeFetchOffsetPartion'));
+
+ return $topic . $partitions;
+ }
+
+ // }}}
+ // }}}
+}
diff --git a/vendor/nmred/kafka-php/src/Kafka/Protocol/Fetch/Helper/CommitOffset.php b/vendor/nmred/kafka-php/src/Kafka/Protocol/Fetch/Helper/CommitOffset.php
new file mode 100644
index 00000000..8424cf78
--- /dev/null
+++ b/vendor/nmred/kafka-php/src/Kafka/Protocol/Fetch/Helper/CommitOffset.php
@@ -0,0 +1,119 @@
+<?php
+/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4 foldmethod=marker: */
+// +---------------------------------------------------------------------------
+// | SWAN [ $_SWANBR_SLOGAN_$ ]
+// +---------------------------------------------------------------------------
+// | Copyright $_SWANBR_COPYRIGHT_$
+// +---------------------------------------------------------------------------
+// | Version $_SWANBR_VERSION_$
+// +---------------------------------------------------------------------------
+// | Licensed ( $_SWANBR_LICENSED_URL_$ )
+// +---------------------------------------------------------------------------
+// | $_SWANBR_WEB_DOMAIN_$
+// +---------------------------------------------------------------------------
+
+namespace Kafka\Protocol\Fetch\Helper;
+
+/**
++------------------------------------------------------------------------------
+* Kafka protocol since Kafka v0.8
++------------------------------------------------------------------------------
+*
+* @package
+* @version $_SWANBR_VERSION_$
+* @copyright Copyleft
+* @author $_SWANBR_AUTHOR_$
++------------------------------------------------------------------------------
+*/
+
+class CommitOffset extends HelperAbstract
+{
+ // {{{ members
+
+ /**
+ * consumer group
+ *
+ * @var string
+ * @access protected
+ */
+ protected $group = '';
+
+ // }}}
+ // {{{ functions
+ // {{{ public function __construct()
+
+ /**
+ * __construct
+ *
+ * @access public
+ * @return void
+ */
+ public function __construct($client)
+ {
+ $this->client = $client;
+ }
+
+ // }}}
+ // {{{ public function setGroup()
+
+ /**
+ * set consumer group
+ *
+ * @access public
+ * @return void
+ */
+ public function setGroup($group)
+ {
+ $this->group = $group;
+ }
+
+ // }}}
+ // {{{ public function onStreamEof()
+
+ /**
+ * on stream eof call
+ *
+ * @param string $streamKey
+ * @access public
+ * @return void
+ */
+ public function onStreamEof($streamKey)
+ {
+ }
+
+ // }}}
+ // {{{ public function onTopicEof()
+
+ /**
+ * on topic eof call
+ *
+ * @param string $topicName
+ * @access public
+ * @return void
+ */
+ public function onTopicEof($topicName)
+ {
+ }
+
+ // }}}
+ // {{{ public function onPartitionEof()
+
+ /**
+ * on partition eof call
+ *
+ * @param \Kafka\Protocol\Fetch\Partition $partition
+ * @access public
+ * @return void
+ */
+ public function onPartitionEof($partition)
+ {
+ $partitionId = $partition->key();
+ $topicName = $partition->getTopicName();
+ $offset = $partition->getMessageOffset();
+ $offsetObject = new \Kafka\Offset($this->client, $this->group, $topicName, $partitionId);
+ $offsetObject->setOffset($offset);
+ }
+
+ // }}}
+ // }}}
+}
diff --git a/vendor/nmred/kafka-php/src/Kafka/Protocol/Fetch/Helper/Consumer.php b/vendor/nmred/kafka-php/src/Kafka/Protocol/Fetch/Helper/Consumer.php
new file mode 100644
index 00000000..acf0223e
--- /dev/null
+++ b/vendor/nmred/kafka-php/src/Kafka/Protocol/Fetch/Helper/Consumer.php
@@ -0,0 +1,39 @@
+<?php
+namespace Kafka\Protocol\Fetch\Helper;
+/**
+ * Description of Consumer
+ *
+ * @author daniel
+ */
+class Consumer extends HelperAbstract
+{
+ protected $consumer;
+
+ protected $offsetStrategy;
+
+
+ public function __construct(\Kafka\Consumer $consumer)
+ {
+ $this->consumer = $consumer;
+ }
+
+
+ public function onPartitionEof($partition)
+ {
+ $partitionId = $partition->key();
+ $topicName = $partition->getTopicName();
+ $offset = $partition->getMessageOffset();
+ $this->consumer->setFromOffset(true);
+ $this->consumer->setPartition($topicName, $partitionId, ($offset +1));
+ }
+
+ public function onStreamEof($streamKey)
+ {
+
+ }
+
+ public function onTopicEof($topicName)
+ {
+
+ }
+}
diff --git a/vendor/nmred/kafka-php/src/Kafka/Protocol/Fetch/Helper/FreeStream.php b/vendor/nmred/kafka-php/src/Kafka/Protocol/Fetch/Helper/FreeStream.php
new file mode 100644
index 00000000..bba38dd6
--- /dev/null
+++ b/vendor/nmred/kafka-php/src/Kafka/Protocol/Fetch/Helper/FreeStream.php
@@ -0,0 +1,117 @@
+<?php
+/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4 foldmethod=marker: */
+// +---------------------------------------------------------------------------
+// | SWAN [ $_SWANBR_SLOGAN_$ ]
+// +---------------------------------------------------------------------------
+// | Copyright $_SWANBR_COPYRIGHT_$
+// +---------------------------------------------------------------------------
+// | Version $_SWANBR_VERSION_$
+// +---------------------------------------------------------------------------
+// | Licensed ( $_SWANBR_LICENSED_URL_$ )
+// +---------------------------------------------------------------------------
+// | $_SWANBR_WEB_DOMAIN_$
+// +---------------------------------------------------------------------------
+
+namespace Kafka\Protocol\Fetch\Helper;
+
+/**
++------------------------------------------------------------------------------
+* Kafka protocol since Kafka v0.8
++------------------------------------------------------------------------------
+*
+* @package
+* @version $_SWANBR_VERSION_$
+* @copyright Copyleft
+* @author $_SWANBR_AUTHOR_$
++------------------------------------------------------------------------------
+*/
+
+class FreeStream extends HelperAbstract
+{
+ // {{{ members
+
+ /**
+ * streams
+ *
+ * @var array
+ * @access protected
+ */
+ protected $streams = array();
+
+ // }}}
+ // {{{ functions
+ // {{{ public function __construct()
+
+ /**
+ * __construct
+ *
+ * @access public
+ * @return void
+ */
+ public function __construct($client)
+ {
+ $this->client = $client;
+ }
+
+ // }}}
+ // {{{ public function setStreams()
+
+ /**
+ * set streams
+ *
+ * @access public
+ * @return void
+ */
+ public function setStreams($streams)
+ {
+ $this->streams = $streams;
+ }
+
+ // }}}
+ // {{{ public function onStreamEof()
+
+ /**
+ * on stream eof call
+ *
+ * @param string $streamKey
+ * @access public
+ * @return void
+ */
+ public function onStreamEof($streamKey)
+ {
+ if (isset($this->streams[$streamKey])) {
+ $this->client->freeStream($streamKey);
+ }
+ }
+
+ // }}}
+ // {{{ public function onTopicEof()
+
+ /**
+ * on topic eof call
+ *
+ * @param string $topicName
+ * @access public
+ * @return void
+ */
+ public function onTopicEof($topicName)
+ {
+ }
+
+ // }}}
+ // {{{ public function onPartitionEof()
+
+ /**
+ * on partition eof call
+ *
+ * @param \Kafka\Protocol\Fetch\Partition $partition
+ * @access public
+ * @return void
+ */
+ public function onPartitionEof($partition)
+ {
+ }
+
+ // }}}
+ // }}}
+}
diff --git a/vendor/nmred/kafka-php/src/Kafka/Protocol/Fetch/Helper/Helper.php b/vendor/nmred/kafka-php/src/Kafka/Protocol/Fetch/Helper/Helper.php
new file mode 100644
index 00000000..4ec23926
--- /dev/null
+++ b/vendor/nmred/kafka-php/src/Kafka/Protocol/Fetch/Helper/Helper.php
@@ -0,0 +1,160 @@
+<?php
+/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4 foldmethod=marker: */
+// +---------------------------------------------------------------------------
+// | SWAN [ $_SWANBR_SLOGAN_$ ]
+// +---------------------------------------------------------------------------
+// | Copyright $_SWANBR_COPYRIGHT_$
+// +---------------------------------------------------------------------------
+// | Version $_SWANBR_VERSION_$
+// +---------------------------------------------------------------------------
+// | Licensed ( $_SWANBR_LICENSED_URL_$ )
+// +---------------------------------------------------------------------------
+// | $_SWANBR_WEB_DOMAIN_$
+// +---------------------------------------------------------------------------
+
+namespace Kafka\Protocol\Fetch\Helper;
+
+/**
++------------------------------------------------------------------------------
+* Kafka protocol since Kafka v0.8
++------------------------------------------------------------------------------
+*
+* @package
+* @version $_SWANBR_VERSION_$
+* @copyright Copyleft
+* @author $_SWANBR_AUTHOR_$
++------------------------------------------------------------------------------
+*/
+
+class Helper
+{
+ // {{{ members
+
+ /**
+ * helper object
+ */
+ private static $helpers = array();
+
+ // }}}
+ // {{{ functions
+ // {{{ public staitc function registerHelper()
+
+ /**
+ * register helper
+ *
+ * @param string $key
+ * @param \Kafka\Protocol\Fetch\Helper\HelperAbstract $helper
+ * @static
+ * @access public
+ * @return void
+ */
+ public static function registerHelper($key, $helper = null)
+ {
+ if (is_null($helper)) {
+ $className = '\\Kafka\\Protocol\\Fetch\\Helper\\' . $key;
+ if (!class_exists($className)) {
+ throw new \Kafka\Exception('helper is not exists.');
+ }
+ $helper = new $className();
+ }
+
+ if ($helper instanceof \Kafka\Protocol\Fetch\Helper\HelperAbstract) {
+ self::$helpers[$key] = $helper;
+ } else {
+ throw new \Kafka\Exception('this helper not instance of `\Kafka\Protocol\Fetch\Helper\HelperAbstract`');
+ }
+ }
+
+ // }}}
+ // {{{ public staitc function unRegisterHelper()
+
+ /**
+ * unregister helper
+ *
+ * @param string $key
+ * @static
+ * @access public
+ * @return void
+ */
+ public static function unRegisterHelper($key)
+ {
+ if (isset(self::$helpers[$key])) {
+ unset(self::$helpers[$key]);
+ }
+ }
+
+ // }}}
+ // {{{ public static function onStreamEof()
+
+ /**
+ * on stream eof call
+ *
+ * @param string $streamKey
+ * @static
+ * @access public
+ * @return void
+ */
+ public static function onStreamEof($streamKey)
+ {
+ if (empty(self::$helpers)) {
+ return false;
+ }
+
+ foreach (self::$helpers as $key => $helper) {
+ if (method_exists($helper, 'onStreamEof')) {
+ $helper->onStreamEof($streamKey);
+ }
+ }
+ }
+
+ // }}}
+ // {{{ public static function onTopicEof()
+
+ /**
+ * on topic eof call
+ *
+ * @param string $topicName
+ * @static
+ * @access public
+ * @return void
+ */
+ public static function onTopicEof($topicName)
+ {
+ if (empty(self::$helpers)) {
+ return false;
+ }
+
+ foreach (self::$helpers as $key => $helper) {
+ if (method_exists($helper, 'onTopicEof')) {
+ $helper->onStreamEof($topicName);
+ }
+ }
+ }
+
+ // }}}
+ // {{{ public static function onPartitionEof()
+
+ /**
+ * on partition eof call
+ *
+ * @param \Kafka\Protocol\Fetch\Partition $partition
+ * @static
+ * @access public
+ * @return void
+ */
+ public static function onPartitionEof($partition)
+ {
+ if (empty(self::$helpers)) {
+ return false;
+ }
+
+ foreach (self::$helpers as $key => $helper) {
+ if (method_exists($helper, 'onPartitionEof')) {
+ $helper->onPartitionEof($partition);
+ }
+ }
+ }
+
+ // }}}
+ // }}}
+}
diff --git a/vendor/nmred/kafka-php/src/Kafka/Protocol/Fetch/Helper/HelperAbstract.php b/vendor/nmred/kafka-php/src/Kafka/Protocol/Fetch/Helper/HelperAbstract.php
new file mode 100644
index 00000000..476f3da1
--- /dev/null
+++ b/vendor/nmred/kafka-php/src/Kafka/Protocol/Fetch/Helper/HelperAbstract.php
@@ -0,0 +1,71 @@
+<?php
+/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4 foldmethod=marker: */
+// +---------------------------------------------------------------------------
+// | SWAN [ $_SWANBR_SLOGAN_$ ]
+// +---------------------------------------------------------------------------
+// | Copyright $_SWANBR_COPYRIGHT_$
+// +---------------------------------------------------------------------------
+// | Version $_SWANBR_VERSION_$
+// +---------------------------------------------------------------------------
+// | Licensed ( $_SWANBR_LICENSED_URL_$ )
+// +---------------------------------------------------------------------------
+// | $_SWANBR_WEB_DOMAIN_$
+// +---------------------------------------------------------------------------
+
+namespace Kafka\Protocol\Fetch\Helper;
+
+/**
++------------------------------------------------------------------------------
+* Kafka protocol since Kafka v0.8
++------------------------------------------------------------------------------
+*
+* @package
+* @version $_SWANBR_VERSION_$
+* @copyright Copyleft
+* @author $_SWANBR_AUTHOR_$
++------------------------------------------------------------------------------
+*/
+
+abstract class HelperAbstract
+{
+ // {{{ members
+ // }}}
+ // {{{ functions
+ // {{{ abstract public function onStreamEof()
+
+ /**
+ * on stream eof
+ *
+ * @param string $streamKey
+ * @access public
+ * @return void
+ */
+ abstract public function onStreamEof($streamKey);
+
+ // }}}
+ // {{{ abstract public function onTopicEof()
+
+ /**
+ * on topic eof
+ *
+ * @param string $topicName
+ * @access public
+ * @return void
+ */
+ abstract public function onTopicEof($topicName);
+
+ // }}}
+ // {{{ abstract public function onPartitionEof()
+
+ /**
+ * on partition eof
+ *
+ * @param \Kafka\Protocol\Fetch\Partition $partition
+ * @access public
+ * @return void
+ */
+ abstract public function onPartitionEof($partition);
+
+ // }}}
+ // }}}
+}
diff --git a/vendor/nmred/kafka-php/src/Kafka/Protocol/Fetch/Message.php b/vendor/nmred/kafka-php/src/Kafka/Protocol/Fetch/Message.php
new file mode 100644
index 00000000..42d7da1d
--- /dev/null
+++ b/vendor/nmred/kafka-php/src/Kafka/Protocol/Fetch/Message.php
@@ -0,0 +1,175 @@
+<?php
+/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4 foldmethod=marker: */
+// +---------------------------------------------------------------------------
+// | SWAN [ $_SWANBR_SLOGAN_$ ]
+// +---------------------------------------------------------------------------
+// | Copyright $_SWANBR_COPYRIGHT_$
+// +---------------------------------------------------------------------------
+// | Version $_SWANBR_VERSION_$
+// +---------------------------------------------------------------------------
+// | Licensed ( $_SWANBR_LICENSED_URL_$ )
+// +---------------------------------------------------------------------------
+// | $_SWANBR_WEB_DOMAIN_$
+// +---------------------------------------------------------------------------
+
+namespace Kafka\Protocol\Fetch;
+
+use \Kafka\Protocol\Decoder;
+
+/**
++------------------------------------------------------------------------------
+* Kafka protocol since Kafka v0.8
++------------------------------------------------------------------------------
+*
+* @package
+* @version $_SWANBR_VERSION_$
+* @copyright Copyleft
+* @author $_SWANBR_AUTHOR_$
++------------------------------------------------------------------------------
+*/
+
+class Message
+{
+ // {{{ members
+
+ /**
+ * init read bytes
+ *
+ * @var float
+ * @access private
+ */
+ private $initOffset = 0;
+
+ /**
+ * validByteCount
+ *
+ * @var float
+ * @access private
+ */
+ private $validByteCount = 0;
+
+ /**
+ * crc32 code
+ *
+ * @var float
+ * @access private
+ */
+ private $crc = 0;
+
+ /**
+ * This is a version id used to allow backwards compatible evolution of the
+ * message binary format.
+ *
+ * @var float
+ * @access private
+ */
+ private $magic = 0;
+
+ /**
+ * The lowest 2 bits contain the compression codec used for the message. The
+ * other bits should be set to 0.
+ *
+ * @var float
+ * @access private
+ */
+ private $attribute = 0;
+
+ /**
+ * message key
+ *
+ * @var string
+ * @access private
+ */
+ private $key = '';
+
+ /**
+ * message value
+ *
+ * @var string
+ * @access private
+ */
+ private $value = '';
+
+ // }}}
+ // {{{ functions
+ // {{{ public function __construct()
+
+ /**
+ * __construct
+ *
+ * @param string(raw) $msg
+ * @access public
+ * @return void
+ */
+ public function __construct($msg)
+ {
+ $offset = 0;
+ $crc = Decoder::unpack(Decoder::BIT_B32, substr($msg, $offset, 4));
+ $offset += 4;
+ $this->crc = array_shift($crc);
+ $magic = Decoder::unpack(Decoder::BIT_B8, substr($msg, $offset, 1));
+ $this->magic = array_shift($magic);
+ $offset += 1;
+ $attr = Decoder::unpack(Decoder::BIT_B8, substr($msg, $offset, 1));
+ $this->attribute = array_shift($attr);
+ $offset += 1;
+ $keyLen = Decoder::unpack(Decoder::BIT_B32, substr($msg, $offset, 4));
+ $keyLen = array_shift($keyLen);
+ $offset += 4;
+ if ($keyLen > 0 && $keyLen != 0xFFFFFFFF) {
+ $this->key = substr($msg, $offset, $keyLen);
+ $offset += $keyLen;
+ }
+ $messageSize = Decoder::unpack(Decoder::BIT_B32, substr($msg, $offset, 4));
+ $messageSize = array_shift($messageSize);
+ $offset += 4;
+ if ($messageSize) {
+ $this->value = substr($msg, $offset, $messageSize);
+ }
+ }
+
+ // }}}
+ // {{{ public function getMessage()
+
+ /**
+ * get message data
+ *
+ * @access public
+ * @return string (raw)
+ */
+ public function getMessage()
+ {
+ return $this->value;
+ }
+
+ // }}}
+ // {{{ public function getMessageKey()
+
+ /**
+ * get message key
+ *
+ * @access public
+ * @return string (raw)
+ */
+ public function getMessageKey()
+ {
+ return $this->key;
+ }
+
+ // }}}
+ // {{{ public function __toString()
+
+ /**
+ * __toString
+ *
+ * @access public
+ * @return void
+ */
+ public function __toString()
+ {
+ return $this->value;
+ }
+
+ // }}}
+ // }}}
+}
diff --git a/vendor/nmred/kafka-php/src/Kafka/Protocol/Fetch/MessageSet.php b/vendor/nmred/kafka-php/src/Kafka/Protocol/Fetch/MessageSet.php
new file mode 100644
index 00000000..50413b67
--- /dev/null
+++ b/vendor/nmred/kafka-php/src/Kafka/Protocol/Fetch/MessageSet.php
@@ -0,0 +1,269 @@
+<?php
+/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4 foldmethod=marker: */
+// +---------------------------------------------------------------------------
+// | SWAN [ $_SWANBR_SLOGAN_$ ]
+// +---------------------------------------------------------------------------
+// | Copyright $_SWANBR_COPYRIGHT_$
+// +---------------------------------------------------------------------------
+// | Version $_SWANBR_VERSION_$
+// +---------------------------------------------------------------------------
+// | Licensed ( $_SWANBR_LICENSED_URL_$ )
+// +---------------------------------------------------------------------------
+// | $_SWANBR_WEB_DOMAIN_$
+// +---------------------------------------------------------------------------
+
+namespace Kafka\Protocol\Fetch;
+
+use \Kafka\Protocol\Decoder;
+
+/**
++------------------------------------------------------------------------------
+* Kafka protocol since Kafka v0.8
++------------------------------------------------------------------------------
+*
+* @package
+* @version $_SWANBR_VERSION_$
+* @copyright Copyleft
+* @author $_SWANBR_AUTHOR_$
++------------------------------------------------------------------------------
+*/
+
+class MessageSet implements \Iterator
+{
+ // {{{ members
+
+ /**
+ * kafka socket object
+ *
+ * @var mixed
+ * @access private
+ */
+ private $stream = null;
+
+ /**
+ * messageSet size
+ *
+ * @var float
+ * @access private
+ */
+ private $messageSetSize = 0;
+
+ /**
+ * validByteCount
+ *
+ * @var float
+ * @access private
+ */
+ private $validByteCount = 0;
+
+ /**
+ * messageSet offset
+ *
+ * @var float
+ * @access private
+ */
+ private $offset = 0;
+
+ /**
+ * valid
+ *
+ * @var mixed
+ * @access private
+ */
+ private $valid = false;
+
+ /**
+ * partition object
+ *
+ * @var \Kafka\Protocol\Fetch\Partition
+ * @access private
+ */
+ private $partition = null;
+
+ /**
+ * request fetch context
+ *
+ * @var array
+ */
+ private $context = array();
+
+ // }}}
+ // {{{ functions
+ // {{{ public function __construct()
+
+ /**
+ * __construct
+ *
+ * @param \Kafka\Socket $stream
+ * @param int $initOffset
+ * @access public
+ * @return void
+ */
+ public function __construct(\Kafka\Protocol\Fetch\Partition $partition, $context = array())
+ {
+ $this->stream = $partition->getStream();
+ $this->partition = $partition;
+ $this->context = $context;
+ $this->messageSetSize = $this->getMessageSetSize();
+ \Kafka\Log::log("messageSetSize: {$this->messageSetSize}", LOG_INFO);
+ }
+
+ // }}}
+ // {{{ public function current()
+
+ /**
+ * current
+ *
+ * @access public
+ * @return void
+ */
+ public function current()
+ {
+ return $this->current;
+ }
+
+ // }}}
+ // {{{ public function key()
+
+ /**
+ * key
+ *
+ * @access public
+ * @return void
+ */
+ public function key()
+ {
+ return $this->validByteCount;
+ }
+
+ // }}}
+ // {{{ public function rewind()
+
+ /**
+ * implements Iterator function
+ *
+ * @access public
+ * @return integer
+ */
+ public function rewind()
+ {
+ $this->valid = $this->loadNextMessage();
+ }
+
+ // }}}
+ // {{{ public function valid()
+
+ /**
+ * implements Iterator function
+ *
+ * @access public
+ * @return integer
+ */
+ public function valid()
+ {
+ if (!$this->valid) {
+ $this->partition->setMessageOffset($this->offset);
+
+ // one partition iterator end
+ \Kafka\Protocol\Fetch\Helper\Helper::onPartitionEof($this->partition);
+ }
+
+ return $this->valid;
+ }
+
+ // }}}
+ // {{{ public function next()
+
+ /**
+ * implements Iterator function
+ *
+ * @access public
+ * @return integer
+ */
+ public function next()
+ {
+ $this->valid = $this->loadNextMessage();
+ }
+
+ // }}}
+ // {{{ protected function getMessageSetSize()
+
+ /**
+ * get message set size
+ *
+ * @access protected
+ * @return integer
+ */
+ protected function getMessageSetSize()
+ {
+ // read message size
+ $data = $this->stream->read(4, true);
+ $data = Decoder::unpack(Decoder::BIT_B32, $data);
+ $size = array_shift($data);
+ if ($size <= 0) {
+ throw new \Kafka\Exception\OutOfRange($size . ' is not a valid message size');
+ }
+
+ return $size;
+ }
+
+ // }}}
+ // {{{ public function loadNextMessage()
+
+ /**
+ * load next message
+ *
+ * @access public
+ * @return void
+ */
+ public function loadNextMessage()
+ {
+ if ($this->validByteCount >= $this->messageSetSize) {
+ return false;
+ }
+
+ try {
+ if ($this->validByteCount + 12 > $this->messageSetSize) {
+ // read socket buffer dirty data
+ $this->stream->read($this->messageSetSize - $this->validByteCount);
+ return false;
+ }
+ $offset = $this->stream->read(8, true);
+ $this->offset = \Kafka\Protocol\Decoder::unpack(Decoder::BIT_B64, $offset);
+ $messageSize = $this->stream->read(4, true);
+ $messageSize = Decoder::unpack(Decoder::BIT_B32, $messageSize);
+ $messageSize = array_shift($messageSize);
+ $this->validByteCount += 12;
+ if (($this->validByteCount + $messageSize) > $this->messageSetSize) {
+ // read socket buffer dirty data
+ $this->stream->read($this->messageSetSize - $this->validByteCount);
+ return false;
+ }
+ $msg = $this->stream->read($messageSize, true);
+ $this->current = new Message($msg);
+ } catch (\Kafka\Exception $e) {
+ \Kafka\Log::log("already fetch: {$this->validByteCount}, {$e->getMessage()}", LOG_INFO);
+ return false;
+ }
+
+ $this->validByteCount += $messageSize;
+
+ return true;
+ }
+
+ // }}}
+ // {{{ public function messageOffset()
+
+ /**
+ * current message offset in producer
+ *
+ * @return void
+ */
+ public function messageOffset()
+ {
+ return $this->offset;
+ }
+
+ // }}}
+ // }}}
+}
diff --git a/vendor/nmred/kafka-php/src/Kafka/Protocol/Fetch/Partition.php b/vendor/nmred/kafka-php/src/Kafka/Protocol/Fetch/Partition.php
new file mode 100644
index 00000000..9f8578d5
--- /dev/null
+++ b/vendor/nmred/kafka-php/src/Kafka/Protocol/Fetch/Partition.php
@@ -0,0 +1,375 @@
+<?php
+/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4 foldmethod=marker: */
+// +---------------------------------------------------------------------------
+// | SWAN [ $_SWANBR_SLOGAN_$ ]
+// +---------------------------------------------------------------------------
+// | Copyright $_SWANBR_COPYRIGHT_$
+// +---------------------------------------------------------------------------
+// | Version $_SWANBR_VERSION_$
+// +---------------------------------------------------------------------------
+// | Licensed ( $_SWANBR_LICENSED_URL_$ )
+// +---------------------------------------------------------------------------
+// | $_SWANBR_WEB_DOMAIN_$
+// +---------------------------------------------------------------------------
+
+namespace Kafka\Protocol\Fetch;
+
+use \Kafka\Protocol\Decoder;
+
+/**
++------------------------------------------------------------------------------
+* Kafka protocol since Kafka v0.8
++------------------------------------------------------------------------------
+*
+* @package
+* @version $_SWANBR_VERSION_$
+* @copyright Copyleft
+* @author $_SWANBR_AUTHOR_$
++------------------------------------------------------------------------------
+*/
+
+class Partition implements \Iterator, \Countable
+{
+ // {{{ members
+
+ /**
+ * kafka socket object
+ *
+ * @var mixed
+ * @access private
+ */
+ private $stream = null;
+
+ /**
+ * validCount
+ *
+ * @var float
+ * @access private
+ */
+ private $validCount = 0;
+
+ /**
+ * partitions count
+ *
+ * @var float
+ * @access private
+ */
+ private $partitionCount = false;
+
+ /**
+ * current topic
+ *
+ * @var mixed
+ * @access private
+ */
+ private $current = null;
+
+ /**
+ * current iterator key
+ * partition id
+ *
+ * @var string
+ * @access private
+ */
+ private $key = null;
+
+ /**
+ * partition errCode
+ *
+ * @var float
+ * @access private
+ */
+ private $errCode = 0;
+
+ /**
+ * partition offset
+ *
+ * @var float
+ * @access private
+ */
+ private $offset = 0;
+
+ /**
+ * partition current fetch offset
+ *
+ * @var float
+ * @access private
+ */
+ private $currentOffset = 0;
+
+ /**
+ * valid
+ *
+ * @var mixed
+ * @access private
+ */
+ private $valid = false;
+
+ /**
+ * cuerrent topic name
+ *
+ * @var string
+ * @access private
+ */
+ private $topicName = '';
+
+ /**
+ * request fetch context
+ *
+ * @var array
+ */
+ private $context = array();
+
+ // }}}
+ // {{{ functions
+ // {{{ public function __construct()
+
+ /**
+ * __construct
+ *
+ * @param \Kafka\Protocol\Fetch\Topic $topic
+ * @param int $initOffset
+ * @access public
+ * @return void
+ */
+ public function __construct(\Kafka\Protocol\Fetch\Topic $topic, $context = array())
+ {
+ $this->stream = $topic->getStream();
+ $this->topicName = $topic->key();
+ $this->context = $context;
+ $this->partitionCount = $this->getPartitionCount();
+ }
+
+ // }}}
+ // {{{ public function current()
+
+ /**
+ * current
+ *
+ * @access public
+ * @return void
+ */
+ public function current()
+ {
+ return $this->current;
+ }
+
+ // }}}
+ // {{{ public function key()
+
+ /**
+ * key
+ *
+ * @access public
+ * @return void
+ */
+ public function key()
+ {
+ return $this->key;
+ }
+
+ // }}}
+ // {{{ public function rewind()
+
+ /**
+ * implements Iterator function
+ *
+ * @access public
+ * @return integer
+ */
+ public function rewind()
+ {
+ $this->valid = $this->loadNextPartition();
+ }
+
+ // }}}
+ // {{{ public function valid()
+
+ /**
+ * implements Iterator function
+ *
+ * @access public
+ * @return integer
+ */
+ public function valid()
+ {
+ return $this->valid && $this->validCount <= $this->partitionCount;
+ }
+
+ // }}}
+ // {{{ public function next()
+
+ /**
+ * implements Iterator function
+ *
+ * @access public
+ * @return integer
+ */
+ public function next()
+ {
+ $this->valid = $this->loadNextPartition();
+ }
+
+ // }}}
+ // {{{ public function count()
+
+ /**
+ * implements Countable function
+ *
+ * @access public
+ * @return integer
+ */
+ public function count()
+ {
+ return $this->partitionCount;
+ }
+
+ // }}}
+ // {{{ public function getErrCode()
+
+ /**
+ * get partition errcode
+ *
+ * @access public
+ * @return void
+ */
+ public function getErrCode()
+ {
+ return $this->errCode;
+ }
+
+ // }}}
+ // {{{ public function getHighOffset()
+
+ /**
+ * get partition high offset
+ *
+ * @access public
+ * @return void
+ */
+ public function getHighOffset()
+ {
+ return $this->offset;
+ }
+
+ // }}}
+ // {{{ public function getTopicName()
+
+ /**
+ * get partition topic name
+ *
+ * @access public
+ * @return void
+ */
+ public function getTopicName()
+ {
+ return $this->topicName;
+ }
+
+ // }}}
+ // {{{ public function getStream()
+
+ /**
+ * get current stream
+ *
+ * @access public
+ * @return \Kafka\Socket
+ */
+ public function getStream()
+ {
+ return $this->stream;
+ }
+
+ // }}}
+ // {{{ protected function getPartitionCount()
+
+ /**
+ * get message size
+ * only use to object init
+ *
+ * @access protected
+ * @return integer
+ */
+ protected function getPartitionCount()
+ {
+ // read topic count
+ $data = $this->stream->read(4, true);
+ $data = Decoder::unpack(Decoder::BIT_B32, $data);
+ $count = array_shift($data);
+ if ($count <= 0) {
+ throw new \Kafka\Exception\OutOfRange($size . ' is not a valid partition count');
+ }
+
+ return $count;
+ }
+
+ // }}}
+ // {{{ public function loadNextPartition()
+
+ /**
+ * load next partition
+ *
+ * @access public
+ * @return void
+ */
+ public function loadNextPartition()
+ {
+ if ($this->validCount >= $this->partitionCount) {
+ return false;
+ }
+
+ try {
+ $partitionId = $this->stream->read(4, true);
+ $partitionId = Decoder::unpack(Decoder::BIT_B32, $partitionId);
+ $partitionId = array_shift($partitionId);
+ \Kafka\Log::log("kafka client:fetch partition:" . $partitionId, LOG_INFO);
+
+ $errCode = $this->stream->read(2, true);
+ $errCode = Decoder::unpack(Decoder::BIT_B16, $errCode);
+ $this->errCode = array_shift($errCode);
+ if ($this->errCode != 0) {
+ throw new \Kafka\Exception(\Kafka\Protocol\Decoder::getError($this->errCode));
+ }
+ $offset = $this->stream->read(8, true);
+ $this->offset = \Kafka\Protocol\Decoder::unpack(Decoder::BIT_B64, $offset);
+
+ $this->key = $partitionId;
+ $this->current = new MessageSet($this, $this->context);
+ } catch (\Kafka\Exception $e) {
+ return false;
+ }
+
+ $this->validCount++;
+ return true;
+ }
+
+ // }}}
+ // {{{ public function setMessageOffset()
+
+ /**
+ * set messageSet fetch offset current
+ *
+ * @param intger $offset
+ * @return void
+ */
+ public function setMessageOffset($offset)
+ {
+ $this->currentOffset = $offset;
+ }
+
+ // }}}
+ // {{{ public function getMessageOffset()
+
+ /**
+ * get messageSet fetch offset current
+ *
+ * @return int
+ */
+ public function getMessageOffset()
+ {
+ return $this->currentOffset;
+ }
+
+ // }}}
+ // }}}
+}
diff --git a/vendor/nmred/kafka-php/src/Kafka/Protocol/Fetch/Topic.php b/vendor/nmred/kafka-php/src/Kafka/Protocol/Fetch/Topic.php
new file mode 100644
index 00000000..500e6b1f
--- /dev/null
+++ b/vendor/nmred/kafka-php/src/Kafka/Protocol/Fetch/Topic.php
@@ -0,0 +1,345 @@
+<?php
+/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4 foldmethod=marker: */
+// +---------------------------------------------------------------------------
+// | SWAN [ $_SWANBR_SLOGAN_$ ]
+// +---------------------------------------------------------------------------
+// | Copyright $_SWANBR_COPYRIGHT_$
+// +---------------------------------------------------------------------------
+// | Version $_SWANBR_VERSION_$
+// +---------------------------------------------------------------------------
+// | Licensed ( $_SWANBR_LICENSED_URL_$ )
+// +---------------------------------------------------------------------------
+// | $_SWANBR_WEB_DOMAIN_$
+// +---------------------------------------------------------------------------
+
+namespace Kafka\Protocol\Fetch;
+
+use \Kafka\Protocol\Decoder;
+
+/**
++------------------------------------------------------------------------------
+* Kafka protocol since Kafka v0.8
++------------------------------------------------------------------------------
+*
+* @package
+* @version $_SWANBR_VERSION_$
+* @copyright Copyleft
+* @author $_SWANBR_AUTHOR_$
++------------------------------------------------------------------------------
+*/
+
+class Topic implements \Iterator, \Countable
+{
+ // {{{ members
+
+ /**
+ * kafka socket object
+ *
+ * @var array
+ * @access private
+ */
+ private $streams = array();
+
+ /**
+ * each topic count
+ *
+ * @var array
+ * @access private
+ */
+ private $topicCounts = array();
+
+ /**
+ * current iterator stream
+ *
+ * @var mixed
+ * @access private
+ */
+ private $currentStreamKey = 0;
+
+ /**
+ * current lock key
+ *
+ * @var string
+ * @access private
+ */
+ private $currentStreamLockKey = '';
+
+ /**
+ * currentStreamCount
+ *
+ * @var float
+ * @access private
+ */
+ private $currentStreamCount = 0;
+
+ /**
+ * validCount
+ *
+ * @var float
+ * @access private
+ */
+ private $validCount = 0;
+
+ /**
+ * topic count
+ *
+ * @var float
+ * @access private
+ */
+ private $topicCount = false;
+
+ /**
+ * current topic
+ *
+ * @var mixed
+ * @access private
+ */
+ private $current = null;
+
+ /**
+ * current iterator key
+ * topic name
+ *
+ * @var string
+ * @access private
+ */
+ private $key = null;
+
+ /**
+ * valid
+ *
+ * @var mixed
+ * @access private
+ */
+ private $valid = false;
+
+ /**
+ * request fetch context
+ *
+ * @var array
+ */
+ private $context = array();
+
+ // }}}
+ // {{{ functions
+ // {{{ public function __construct()
+
+ /**
+ * __construct
+ *
+ * @param \Kafka\Socket $stream
+ * @param int $initOffset
+ * @access public
+ * @return void
+ */
+ public function __construct($streams, $context = array())
+ {
+ if (!is_array($streams)) {
+ $streams = array($streams);
+ }
+ $this->streams = $streams;
+ $topicInfos = array();
+ foreach ($context as $values) {
+ if (!isset($values['data'])) {
+ continue;
+ }
+
+ foreach ($values['data'] as $value) {
+ if (!isset($value['topic_name']) || !isset($value['partitions'])) {
+ continue;
+ }
+
+ $topicName = $value['topic_name'];
+ foreach ($value['partitions'] as $part) {
+ $topicInfos[$topicName][$part['partition_id']] = array(
+ 'offset' => $part['offset'],
+ );
+ }
+ }
+ }
+ $this->context = $topicInfos;
+ $this->topicCount = $this->getTopicCount();
+ }
+
+ // }}}
+ // {{{ public function current()
+
+ /**
+ * current
+ *
+ * @access public
+ * @return void
+ */
+ public function current()
+ {
+ return $this->current;
+ }
+
+ // }}}
+ // {{{ public function key()
+
+ /**
+ * key
+ *
+ * @access public
+ * @return void
+ */
+ public function key()
+ {
+ return $this->key;
+ }
+
+ // }}}
+ // {{{ public function rewind()
+
+ /**
+ * implements Iterator function
+ *
+ * @access public
+ * @return integer
+ */
+ public function rewind()
+ {
+ $this->valid = $this->loadNextTopic();
+ }
+
+ // }}}
+ // {{{ public function valid()
+
+ /**
+ * implements Iterator function
+ *
+ * @access public
+ * @return integer
+ */
+ public function valid()
+ {
+ return $this->valid;
+ }
+
+ // }}}
+ // {{{ public function next()
+
+ /**
+ * implements Iterator function
+ *
+ * @access public
+ * @return integer
+ */
+ public function next()
+ {
+ $this->valid = $this->loadNextTopic();
+ }
+
+ // }}}
+ // {{{ public function count()
+
+ /**
+ * implements Countable function
+ *
+ * @access public
+ * @return integer
+ */
+ public function count()
+ {
+ return $this->topicCount;
+ }
+
+ // }}}
+ // {{{ protected function getTopicCount()
+
+ /**
+ * get message size
+ * only use to object init
+ *
+ * @access protected
+ * @return integer
+ */
+ protected function getTopicCount()
+ {
+ $count = 0;
+ foreach (array_values($this->streams) as $key => $stream) {
+ // read topic count
+ $stream->read(8, true);
+ $data = $stream->read(4, true);
+ $data = Decoder::unpack(Decoder::BIT_B32, $data);
+ $topicCount = array_shift($data);
+ $count += $topicCount;
+ $this->topicCounts[$key] = $topicCount;
+ if ($count <= 0) {
+ throw new \Kafka\Exception\OutOfRange($count . ' is not a valid topic count');
+ }
+ }
+
+ return $count;
+ }
+
+ // }}}
+ // {{{ public function loadNextTopic()
+
+ /**
+ * load next topic
+ *
+ * @access public
+ * @return void
+ */
+ public function loadNextTopic()
+ {
+ if ($this->validCount >= $this->topicCount) {
+ \Kafka\Protocol\Fetch\Helper\Helper::onStreamEof($this->currentStreamLockKey);
+ return false;
+ }
+
+ if ($this->currentStreamCount >= $this->topicCounts[$this->currentStreamKey]) {
+ \Kafka\Protocol\Fetch\Helper\Helper::onStreamEof($this->currentStreamLockKey);
+ $this->currentStreamKey++;
+ }
+
+ $lockKeys = array_keys($this->streams);
+ $streams = array_values($this->streams);
+ if (!isset($streams[$this->currentStreamKey])) {
+ return false;
+ }
+
+ $stream = $streams[$this->currentStreamKey];
+ $this->currentStreamLockKey = $lockKeys[$this->currentStreamKey];
+
+ try {
+ $topicLen = $stream->read(2, true);
+ $topicLen = Decoder::unpack(Decoder::BIT_B16, $topicLen);
+ $topicLen = array_shift($topicLen);
+ if ($topicLen <= 0) {
+ return false;
+ }
+
+ // topic name
+ $this->key = $stream->read($topicLen, true);
+ $this->current = new Partition($this, $this->context);
+ } catch (\Kafka\Exception $e) {
+ return false;
+ }
+
+ $this->validCount++;
+ $this->currentStreamCount++;
+
+ return true;
+ }
+
+ // }}}
+ // {{{ public function getStream()
+
+ /**
+ * get current stream
+ *
+ * @access public
+ * @return \Kafka\Socket
+ */
+ public function getStream()
+ {
+ $streams = array_values($this->streams);
+ return $streams[$this->currentStreamKey];
+ }
+
+ // }}}
+ // }}}
+}
diff --git a/vendor/nmred/kafka-php/src/Kafka/Protocol/Protocol.php b/vendor/nmred/kafka-php/src/Kafka/Protocol/Protocol.php
new file mode 100644
index 00000000..a31067b5
--- /dev/null
+++ b/vendor/nmred/kafka-php/src/Kafka/Protocol/Protocol.php
@@ -0,0 +1,230 @@
+<?php
+/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4 foldmethod=marker: */
+// +---------------------------------------------------------------------------
+// | SWAN [ $_SWANBR_SLOGAN_$ ]
+// +---------------------------------------------------------------------------
+// | Copyright $_SWANBR_COPYRIGHT_$
+// +---------------------------------------------------------------------------
+// | Version $_SWANBR_VERSION_$
+// +---------------------------------------------------------------------------
+// | Licensed ( $_SWANBR_LICENSED_URL_$ )
+// +---------------------------------------------------------------------------
+// | $_SWANBR_WEB_DOMAIN_$
+// +---------------------------------------------------------------------------
+
+namespace Kafka\Protocol;
+
+/**
++------------------------------------------------------------------------------
+* Kafka protocol since Kafka v0.8
++------------------------------------------------------------------------------
+*
+* @package
+* @version $_SWANBR_VERSION_$
+* @copyright Copyleft
+* @author $_SWANBR_AUTHOR_$
++------------------------------------------------------------------------------
+*/
+
+abstract class Protocol
+{
+ // {{{ consts
+
+ /**
+ * Kafka server protocol version
+ */
+ const API_VERSION = 0;
+
+ /**
+ * use encode message, This is a version id used to allow backwards
+ * compatible evolution of the message binary format.
+ */
+ const MESSAGE_MAGIC = 0;
+
+ /**
+ * message no compression
+ */
+ const COMPRESSION_NONE = 0;
+
+ /**
+ * Message using gzip compression
+ */
+ const COMPRESSION_GZIP = 1;
+
+ /**
+ * Message using Snappy compression
+ */
+ const COMPRESSION_SNAPPY = 2;
+
+ /**
+ * pack int32 type
+ */
+ const PACK_INT32 = 0;
+
+ /**
+ * pack int16 type
+ */
+ const PACK_INT16 = 1;
+
+ /**
+ * protocol request code
+ */
+ const PRODUCE_REQUEST = 0;
+ const FETCH_REQUEST = 1;
+ const OFFSET_REQUEST = 2;
+ const METADATA_REQUEST = 3;
+ const OFFSET_COMMIT_REQUEST = 8;
+ const OFFSET_FETCH_REQUEST = 9;
+ const CONSUMER_METADATA_REQUEST = 10;
+
+ // unpack/pack bit
+ const BIT_B64 = 'N2';
+ const BIT_B32 = 'N';
+ const BIT_B16 = 'n';
+ const BIT_B8 = 'C';
+
+ // }}}
+ // {{{ members
+
+ /**
+ * stream
+ *
+ * @var mixed
+ * @access protected
+ */
+ protected $stream = null;
+
+ // }}}
+ // {{{ functions
+ // {{{ public function __construct()
+
+ /**
+ * __construct
+ *
+ * @param \Kafka\Socket $stream
+ * @access public
+ * @return void
+ */
+ public function __construct(\Kafka\Socket $stream)
+ {
+ $this->stream = $stream;
+ }
+
+ // }}}
+ // {{{ public static function Khex2bin()
+
+ /**
+ * hex to bin
+ *
+ * @param string $string
+ * @static
+ * @access protected
+ * @return string (raw)
+ */
+ public static function Khex2bin($string)
+ {
+ if (function_exists('\hex2bin')) {
+ return \hex2bin($string);
+ } else {
+ $bin = '';
+ $len = strlen($string);
+ for ($i = 0; $i < $len; $i += 2) {
+ $bin .= pack('H*', substr($string, $i, 2));
+ }
+
+ return $bin;
+ }
+ }
+
+ // }}}
+ // {{{ public static function unpack()
+
+ /**
+ * Unpack a bit integer as big endian long
+ *
+ * @static
+ * @access public
+ * @return integer
+ */
+ public static function unpack($type, $bytes)
+ {
+ self::checkLen($type, $bytes);
+ if ($type == self::BIT_B64) {
+ $set = unpack($type, $bytes);
+ $original = ($set[1] & 0xFFFFFFFF) << 32 | ($set[2] & 0xFFFFFFFF);
+ return $original;
+ } else {
+ return unpack($type, $bytes);
+ }
+ }
+
+ // }}}
+ // {{{ public static function pack()
+
+ /**
+ * pack a bit integer as big endian long
+ *
+ * @static
+ * @access public
+ * @return integer
+ */
+ public static function pack($type, $data)
+ {
+ if ($type == self::BIT_B64) {
+ if ($data == -1) { // -1L
+ $data = self::Khex2bin('ffffffffffffffff');
+ } elseif ($data == -2) { // -2L
+ $data = self::Khex2bin('fffffffffffffffe');
+ } else {
+ $left = 0xffffffff00000000;
+ $right = 0x00000000ffffffff;
+
+ $l = ($data & $left) >> 32;
+ $r = $data & $right;
+ $data = pack($type, $l, $r);
+ }
+ } else {
+ $data = pack($type, $data);
+ }
+
+ return $data;
+ }
+
+ // }}}
+ // {{{ protected static function checkLen()
+
+ /**
+ * check unpack bit is valid
+ *
+ * @param string $type
+ * @param string(raw) $bytes
+ * @static
+ * @access protected
+ * @return void
+ */
+ protected static function checkLen($type, $bytes)
+ {
+ $len = 0;
+ switch($type) {
+ case self::BIT_B64:
+ $len = 8;
+ break;
+ case self::BIT_B32:
+ $len = 4;
+ break;
+ case self::BIT_B16:
+ $len = 2;
+ break;
+ case self::BIT_B8:
+ $len = 1;
+ break;
+ }
+
+ if (strlen($bytes) != $len) {
+ throw new \Kafka\Exception\Protocol('unpack failed. string(raw) length is ' . strlen($bytes) . ' , TO ' . $type);
+ }
+ }
+
+ // }}}
+ // }}}
+}
diff --git a/vendor/nmred/kafka-php/src/Kafka/Socket.php b/vendor/nmred/kafka-php/src/Kafka/Socket.php
new file mode 100644
index 00000000..be7321f3
--- /dev/null
+++ b/vendor/nmred/kafka-php/src/Kafka/Socket.php
@@ -0,0 +1,365 @@
+<?php
+/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4 foldmethod=marker: */
+// +---------------------------------------------------------------------------
+// | SWAN [ $_SWANBR_SLOGAN_$ ]
+// +---------------------------------------------------------------------------
+// | Copyright $_SWANBR_COPYRIGHT_$
+// +---------------------------------------------------------------------------
+// | Version $_SWANBR_VERSION_$
+// +---------------------------------------------------------------------------
+// | Licensed ( $_SWANBR_LICENSED_URL_$ )
+// +---------------------------------------------------------------------------
+// | $_SWANBR_WEB_DOMAIN_$
+// +---------------------------------------------------------------------------
+
+namespace Kafka;
+
+/**
++------------------------------------------------------------------------------
+* Kafka protocol since Kafka v0.8
++------------------------------------------------------------------------------
+*
+* @package
+* @version $_SWANBR_VERSION_$
+* @copyright Copyleft
+* @author $_SWANBR_AUTHOR_$
++------------------------------------------------------------------------------
+*/
+
+class Socket
+{
+ // {{{ consts
+
+ const READ_MAX_LEN = 5242880; // read socket max length 5MB
+
+ // }}}
+ // {{{ members
+
+ /**
+ * Send timeout in seconds.
+ *
+ * @var float
+ * @access private
+ */
+ private $sendTimeoutSec = 0;
+
+ /**
+ * Send timeout in microseconds.
+ *
+ * @var float
+ * @access private
+ */
+ private $sendTimeoutUsec = 100000;
+
+ /**
+ * Recv timeout in seconds
+ *
+ * @var float
+ * @access private
+ */
+ private $recvTimeoutSec = 0;
+
+ /**
+ * Recv timeout in microseconds
+ *
+ * @var float
+ * @access private
+ */
+ private $recvTimeoutUsec = 750000;
+
+ /**
+ * Stream resource
+ *
+ * @var mixed
+ * @access private
+ */
+ private $stream = null;
+
+ /**
+ * Socket host
+ *
+ * @var mixed
+ * @access private
+ */
+ private $host = null;
+
+ /**
+ * Socket port
+ *
+ * @var mixed
+ * @access private
+ */
+ private $port = -1;
+
+ // }}}
+ // {{{ functions
+ // {{{ public function __construct()
+
+ /**
+ * __construct
+ *
+ * @access public
+ * @return void
+ */
+ public function __construct($host, $port, $recvTimeoutSec = 0, $recvTimeoutUsec = 750000, $sendTimeoutSec = 0, $sendTimeoutUsec = 100000)
+ {
+ $this->host = $host;
+ $this->port = $port;
+ $this->setRecvTimeoutSec($recvTimeoutSec);
+ $this->setRecvTimeoutUsec($recvTimeoutUsec);
+ $this->setSendTimeoutSec($sendTimeoutSec);
+ $this->setSendTimeoutUsec($sendTimeoutUsec);
+ }
+
+ /**
+ * @param float $sendTimeoutSec
+ */
+ public function setSendTimeoutSec($sendTimeoutSec)
+ {
+ $this->sendTimeoutSec = $sendTimeoutSec;
+ }
+
+ /**
+ * @param float $sendTimeoutUsec
+ */
+ public function setSendTimeoutUsec($sendTimeoutUsec)
+ {
+ $this->sendTimeoutUsec = $sendTimeoutUsec;
+ }
+
+ /**
+ * @param float $recvTimeoutSec
+ */
+ public function setRecvTimeoutSec($recvTimeoutSec)
+ {
+ $this->recvTimeoutSec = $recvTimeoutSec;
+ }
+
+ /**
+ * @param float $recvTimeoutUsec
+ */
+ public function setRecvTimeoutUsec($recvTimeoutUsec)
+ {
+ $this->recvTimeoutUsec = $recvTimeoutUsec;
+ }
+
+
+
+ // }}}
+ // {{{ public static function createFromStream()
+
+ /**
+ * Optional method to set the internal stream handle
+ *
+ * @static
+ * @access public
+ * @return void
+ */
+ public static function createFromStream($stream)
+ {
+ $socket = new self('localhost', 0);
+ $socket->setStream($stream);
+ return $socket;
+ }
+
+ // }}}
+ // {{{ public function setStream()
+
+ /**
+ * Optional method to set the internal stream handle
+ *
+ * @param mixed $stream
+ * @access public
+ * @return void
+ */
+ public function setStream($stream)
+ {
+ $this->stream = $stream;
+ }
+
+ // }}}
+ // {{{ public function connect()
+
+ /**
+ * Connects the socket
+ *
+ * @access public
+ * @return void
+ */
+ public function connect()
+ {
+ if (is_resource($this->stream)) {
+ return false;
+ }
+
+ if (empty($this->host)) {
+ throw new \Kafka\Exception('Cannot open null host.');
+ }
+ if ($this->port <= 0) {
+ throw new \Kafka\Exception('Cannot open without port.');
+ }
+
+ $this->stream = @fsockopen(
+ $this->host,
+ $this->port,
+ $errno,
+ $errstr,
+ $this->sendTimeoutSec + ($this->sendTimeoutUsec / 1000000)
+ );
+
+ if ($this->stream == false) {
+ $error = 'Could not connect to '
+ . $this->host . ':' . $this->port
+ . ' ('.$errstr.' ['.$errno.'])';
+ throw new \Kafka\Exception\SocketConnect($error);
+ }
+
+ stream_set_blocking($this->stream, 0);
+ }
+
+ // }}}
+ // {{{ public function close()
+
+ /**
+ * close the socket
+ *
+ * @access public
+ * @return void
+ */
+ public function close()
+ {
+ if (is_resource($this->stream)) {
+ fclose($this->stream);
+ }
+ }
+
+ // }}}
+ // {{{ public function read()
+
+ /**
+ * Read from the socket at most $len bytes.
+ *
+ * This method will not wait for all the requested data, it will return as
+ * soon as any data is received.
+ *
+ * @param integer $len Maximum number of bytes to read.
+ * @param boolean $verifyExactLength Throw an exception if the number of read bytes is less than $len
+ *
+ * @return string Binary data
+ * @throws Kafka_Exception_Socket
+ */
+ public function read($len, $verifyExactLength = false)
+ {
+ if ($len > self::READ_MAX_LEN) {
+ throw new \Kafka\Exception\SocketEOF('Could not read '.$len.' bytes from stream, length too longer.');
+ }
+
+ $null = null;
+ $read = array($this->stream);
+ $readable = @stream_select($read, $null, $null, $this->recvTimeoutSec, $this->recvTimeoutUsec);
+ if ($readable > 0) {
+ $remainingBytes = $len;
+ $data = $chunk = '';
+ while ($remainingBytes > 0) {
+ $chunk = fread($this->stream, $remainingBytes);
+ if ($chunk === false) {
+ $this->close();
+ throw new \Kafka\Exception\SocketEOF('Could not read '.$len.' bytes from stream (no data)');
+ }
+ if (strlen($chunk) === 0) {
+ // Zero bytes because of EOF?
+ if (feof($this->stream)) {
+ $this->close();
+ throw new \Kafka\Exception\SocketEOF('Unexpected EOF while reading '.$len.' bytes from stream (no data)');
+ }
+ // Otherwise wait for bytes
+ $readable = @stream_select($read, $null, $null, $this->recvTimeoutSec, $this->recvTimeoutUsec);
+ if ($readable !== 1) {
+ throw new \Kafka\Exception\SocketTimeout('Timed out reading socket while reading ' . $len . ' bytes with ' . $remainingBytes . ' bytes to go');
+ }
+ continue; // attempt another read
+ }
+ $data .= $chunk;
+ $remainingBytes -= strlen($chunk);
+ }
+ if ($len === $remainingBytes || ($verifyExactLength && $len !== strlen($data))) {
+ // couldn't read anything at all OR reached EOF sooner than expected
+ $this->close();
+ throw new \Kafka\Exception\SocketEOF('Read ' . strlen($data) . ' bytes instead of the requested ' . $len . ' bytes');
+ }
+
+ return $data;
+ }
+ if (false !== $readable) {
+ $res = stream_get_meta_data($this->stream);
+ if (!empty($res['timed_out'])) {
+ $this->close();
+ throw new \Kafka\Exception\SocketTimeout('Timed out reading '.$len.' bytes from stream');
+ }
+ }
+ $this->close();
+ throw new \Kafka\Exception\SocketEOF('Could not read '.$len.' bytes from stream (not readable)');
+
+ }
+
+ // }}}
+ // {{{ public function write()
+
+ /**
+ * Write to the socket.
+ *
+ * @param string $buf The data to write
+ *
+ * @return integer
+ * @throws Kafka_Exception_Socket
+ */
+ public function write($buf)
+ {
+ $null = null;
+ $write = array($this->stream);
+
+ // fwrite to a socket may be partial, so loop until we
+ // are done with the entire buffer
+ $written = 0;
+ $buflen = strlen($buf);
+ while ( $written < $buflen ) {
+ // wait for stream to become available for writing
+ $writable = stream_select($null, $write, $null, $this->sendTimeoutSec, $this->sendTimeoutUsec);
+ if ($writable > 0) {
+ // write remaining buffer bytes to stream
+ $wrote = fwrite($this->stream, substr($buf, $written));
+ if ($wrote === -1 || $wrote === false) {
+ throw new \Kafka\Exception\Socket('Could not write ' . strlen($buf) . ' bytes to stream, completed writing only ' . $written . ' bytes');
+ }
+ $written += $wrote;
+ continue;
+ }
+ if (false !== $writable) {
+ $res = stream_get_meta_data($this->stream);
+ if (!empty($res['timed_out'])) {
+ throw new \Kafka\Exception\SocketTimeout('Timed out writing ' . strlen($buf) . ' bytes to stream after writing ' . $written . ' bytes');
+ }
+ }
+ throw new \Kafka\Exception\Socket('Could not write ' . strlen($buf) . ' bytes to stream');
+ }
+ return $written;
+ }
+
+ // }}}
+ // {{{ public function rewind()
+
+ /**
+ * Rewind the stream
+ *
+ * @return void
+ */
+ public function rewind()
+ {
+ if (is_resource($this->stream)) {
+ rewind($this->stream);
+ }
+ }
+
+ // }}}
+ // }}}
+}
diff --git a/vendor/nmred/kafka-php/src/Kafka/ZooKeeper.php b/vendor/nmred/kafka-php/src/Kafka/ZooKeeper.php
new file mode 100644
index 00000000..f48b5cb9
--- /dev/null
+++ b/vendor/nmred/kafka-php/src/Kafka/ZooKeeper.php
@@ -0,0 +1,364 @@
+<?php
+/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4 foldmethod=marker: */
+// +---------------------------------------------------------------------------
+// | SWAN [ $_SWANBR_SLOGAN_$ ]
+// +---------------------------------------------------------------------------
+// | Copyright $_SWANBR_COPYRIGHT_$
+// +---------------------------------------------------------------------------
+// | Version $_SWANBR_VERSION_$
+// +---------------------------------------------------------------------------
+// | Licensed ( $_SWANBR_LICENSED_URL_$ )
+// +---------------------------------------------------------------------------
+// | $_SWANBR_WEB_DOMAIN_$
+// +---------------------------------------------------------------------------
+
+namespace Kafka;
+
+/**
++------------------------------------------------------------------------------
+* Kafka protocol since Kafka v0.8
++------------------------------------------------------------------------------
+*
+* @package
+* @version $_SWANBR_VERSION_$
+* @copyright Copyleft
+* @author $_SWANBR_AUTHOR_$
++------------------------------------------------------------------------------
+*/
+
+class ZooKeeper implements \Kafka\ClusterMetaData
+{
+ // {{{ consts
+
+ /**
+ * get all broker
+ */
+ const BROKER_PATH = '/brokers/ids';
+
+ /**
+ * get broker detail
+ */
+ const BROKER_DETAIL_PATH = '/brokers/ids/%d';
+
+ /**
+ * get topic detail
+ */
+ const TOPIC_PATCH = '/brokers/topics/%s';
+
+ /**
+ * get partition state
+ */
+ const PARTITION_STATE = '/brokers/topics/%s/partitions/%d/state';
+
+ /**
+ * register consumer
+ */
+ const REG_CONSUMER = '/consumers/%s/ids/%s';
+
+ /**
+ * list consumer
+ */
+ const LIST_CONSUMER = '/consumers/%s/ids';
+
+ /**
+ * partition owner
+ */
+ const PARTITION_OWNER = '/consumers/%s/owners/%s/%d';
+
+ // }}}
+ // {{{ members
+
+ /**
+ * zookeeper
+ *
+ * @var mixed
+ * @access private
+ */
+ private $zookeeper = null;
+
+ // }}}
+ // {{{ functions
+ // {{{ public function __construct()
+
+ /**
+ * __construct
+ *
+ * @access public
+ * @return void
+ */
+ public function __construct($hostList, $timeout = null)
+ {
+ if (!is_null($timeout) && is_numeric($timeout)) {
+ $this->zookeeper = new \ZooKeeper($hostList, null, $timeout);
+ } else {
+ $this->zookeeper = new \ZooKeeper($hostList);
+ }
+ }
+
+ // }}}
+ // {{{ public function listBrokers()
+
+ /**
+ * get broker list using zookeeper
+ *
+ * @access public
+ * @return array
+ */
+ public function listBrokers()
+ {
+ $result = array();
+ $lists = $this->zookeeper->getChildren(self::BROKER_PATH);
+ if (!empty($lists)) {
+ foreach ($lists as $brokerId) {
+ $brokerDetail = $this->getBrokerDetail($brokerId);
+ if (!$brokerDetail) {
+ continue;
+ }
+ $result[$brokerId] = $brokerDetail;
+ }
+ }
+
+ return $result;
+ }
+
+ // }}}
+ // {{{ public function getBrokerDetail()
+
+ /**
+ * get broker detail
+ *
+ * @param integer $brokerId
+ * @access public
+ * @return void
+ */
+ public function getBrokerDetail($brokerId)
+ {
+ $result = array();
+ $path = sprintf(self::BROKER_DETAIL_PATH, (int) $brokerId);
+ if ($this->zookeeper->exists($path)) {
+ $result = $this->zookeeper->get($path);
+ if (!$result) {
+ return false;
+ }
+
+ $result = json_decode($result, true);
+ }
+
+ return $result;
+ }
+
+ // }}}
+ // {{{ public function getTopicDetail()
+
+ /**
+ * get topic detail
+ *
+ * @param string $topicName
+ * @access public
+ * @return void
+ */
+ public function getTopicDetail($topicName)
+ {
+ $result = array();
+ $path = sprintf(self::TOPIC_PATCH, (string) $topicName);
+ if ($this->zookeeper->exists($path)) {
+ $result = $this->zookeeper->get($path);
+ if (!$result) {
+ return false;
+ }
+ $result = json_decode($result, true);
+ }
+
+ return $result;
+ }
+
+ // }}}
+ // {{{ public function getPartitionState()
+
+ /**
+ * get partition state
+ *
+ * @param string $topicName
+ * @param integer $partitionId
+ * @access public
+ * @return void
+ */
+ public function getPartitionState($topicName, $partitionId = 0)
+ {
+ $result = array();
+ $path = sprintf(self::PARTITION_STATE, (string) $topicName, (int) $partitionId);
+ if ($this->zookeeper->exists($path)) {
+ $result = $this->zookeeper->get($path);
+ if (!$result) {
+ return false;
+ }
+ $result = json_decode($result, true);
+ }
+
+ return $result;
+ }
+
+ // }}}
+ // {{{ public function registerConsumer()
+
+ /**
+ * register consumer
+ *
+ * @param string $topicName
+ * @param integer $partitionId
+ * @access public
+ * @return void
+ */
+ public function registerConsumer($groupId, $consumerId, $topics = array())
+ {
+ if (empty($topics)) {
+ return true;
+ }
+
+ $path = sprintf(self::REG_CONSUMER, (string) $groupId, (string) $consumerId);
+ $subData = array();
+ foreach ($topics as $topic) {
+ $subData[$topic] = 1;
+ }
+ $data = array(
+ 'version' => '1',
+ 'pattern' => 'white_list',
+ 'subscription' => $subData,
+ );
+ if (!$this->zookeeper->exists($path)) {
+ $this->makeZkPath($path);
+ $this->makeZkNode($path, json_encode($data));
+ } else {
+ $this->zookeeper->set($path, json_encode($data));
+ }
+ }
+
+ // }}}
+ // {{{ public function listConsumer()
+
+ /**
+ * list consumer
+ *
+ * @param string $groupId
+ * @access public
+ * @return void
+ */
+ public function listConsumer($groupId)
+ {
+ $path = sprintf(self::LIST_CONSUMER, (string) $groupId);
+ if (!$this->zookeeper->exists($path)) {
+ return array();
+ } else {
+ return $this->zookeeper->getChildren($path);
+ }
+ }
+
+ // }}}
+ // {{{ public function getConsumersPerTopic()
+
+ /**
+ * get consumer per topic
+ *
+ * @param string $groupId
+ * @access public
+ * @return array
+ */
+ public function getConsumersPerTopic($groupId)
+ {
+ $consumers = $this->listConsumer($groupId);
+ if (empty($consumers)) {
+ return array();
+ }
+
+ $topics = array();
+ foreach ($consumers as $consumerId) {
+ $path = sprintf(self::REG_CONSUMER, (string) $groupId, (string) $consumerId);
+ if (!$this->zookeeper->exists($path)) {
+ continue;
+ }
+
+ $info = $this->zookeeper->get($path);
+ $info = json_decode($info, true);
+ $subTopic = isset($info['subscription']) ? $info['subscription'] : array();
+ foreach ($subTopic as $topic => $num) {
+ $topics[$topic] = $consumerId;
+ }
+ }
+
+ return $topics;
+ }
+
+ // }}}
+ // {{{ public function addPartitionOwner()
+
+ /**
+ * add partition owner
+ *
+ * @param string $groupId
+ * @param string $topicName
+ * @param integer $partitionId
+ * @param string $consumerId
+ * @access public
+ * @return void
+ */
+ public function addPartitionOwner($groupId, $topicName, $partitionId, $consumerId)
+ {
+ $path = sprintf(self::PARTITION_OWNER, (string) $groupId, $topicName, (string) $partitionId);
+ if (!$this->zookeeper->exists($path)) {
+ $this->makeZkPath($path);
+ $this->makeZkNode($path, $consumerId);
+ } else {
+ $this->zookeeper->set($path, $consumerId);
+ }
+ }
+
+ // }}}
+ // {{{ protected function makeZkPath()
+
+ /**
+ * Equivalent of "mkdir -p" on ZooKeeper
+ *
+ * @param string $path The path to the node
+ * @param mixed $value The value to assign to each new node along the path
+ *
+ * @return bool
+ */
+ protected function makeZkPath($path, $value = 0)
+ {
+ $parts = explode('/', $path);
+ $parts = array_filter($parts);
+ $subpath = '';
+ while (count($parts) > 1) {
+ $subpath .= '/' . array_shift($parts);
+ if (!$this->zookeeper->exists($subpath)) {
+ $this->makeZkNode($subpath, $value);
+ }
+ }
+ }
+
+ // }}}
+ // {{{ protected function makeZkNode()
+
+ /**
+ * Create a node on ZooKeeper at the given path
+ *
+ * @param string $path The path to the node
+ * @param mixed $value The value to assign to the new node
+ *
+ * @return bool
+ */
+ protected function makeZkNode($path, $value)
+ {
+ $params = array(
+ array(
+ 'perms' => \Zookeeper::PERM_ALL,
+ 'scheme' => 'world',
+ 'id' => 'anyone',
+ )
+ );
+ return $this->zookeeper->create($path, $value, $params);
+ }
+
+ // }}}
+ // }}}
+}
diff --git a/vendor/oojs/oojs-ui/.csscomb.json b/vendor/oojs/oojs-ui/.csscomb.json
deleted file mode 100644
index c4e215ec..00000000
--- a/vendor/oojs/oojs-ui/.csscomb.json
+++ /dev/null
@@ -1,24 +0,0 @@
-{
- "remove-empty-rulesets": true,
- "always-semicolon": true,
- "color-case": "lower",
- "block-indent": "\t",
- "color-shorthand": false,
- "element-case": "lower",
- "eof-newline": true,
- "leading-zero": true,
- "quotes": "double",
- "space-before-colon": "",
- "space-after-colon": " ",
- "space-before-combinator": " ",
- "space-after-combinator": " ",
- "space-between-declarations": "\n",
- "space-before-opening-brace": " ",
- "space-after-opening-brace": "\n",
- "space-after-selector-delimiter": "\n",
- "space-before-selector-delimiter": "",
- "space-before-closing-brace": "\n",
- "strip-spaces": true,
- "unitless-zero": true,
- "vendor-prefix-align": true
-}
diff --git a/vendor/oojs/oojs-ui/.csslintrc b/vendor/oojs/oojs-ui/.csslintrc
deleted file mode 100644
index e777c7f3..00000000
--- a/vendor/oojs/oojs-ui/.csslintrc
+++ /dev/null
@@ -1,11 +0,0 @@
-{
- "adjoining-classes": false,
- "box-model": false,
- "box-sizing": false,
- "fallback-colors": false,
- "important": false,
- "outline-none": false,
- "qualified-headings": false,
- "universal-selector": false,
- "unqualified-attributes": false
-}
diff --git a/vendor/oojs/oojs-ui/.npmignore b/vendor/oojs/oojs-ui/.npmignore
deleted file mode 100644
index 67aebbfc..00000000
--- a/vendor/oojs/oojs-ui/.npmignore
+++ /dev/null
@@ -1,2 +0,0 @@
-/docs
-vendor
diff --git a/vendor/oojs/oojs-ui/AUTHORS.txt b/vendor/oojs/oojs-ui/AUTHORS.txt
index 6813d169..cc0970df 100644
--- a/vendor/oojs/oojs-ui/AUTHORS.txt
+++ b/vendor/oojs/oojs-ui/AUTHORS.txt
@@ -2,7 +2,7 @@ Principal Authors (major contributors, alphabetically)
Bartosz Dziewoński <matma.rex@gmail.com>
Ed Sanders <esanders@wikimedia.org>
-James D. Forrester <jforrester@wikimedia.org>
+James D. Forrester <jforrester@wikimedia.org>
Kirsten Menger-Anderson <kmenger@wikimedia.org>
Roan Kattouw <roan@wikimedia.org>
Rob Moen <rmoen@wikimedia.org>
@@ -24,6 +24,7 @@ Juliusz Gonera <jgonera@wikimedia.org>
Kunal Mehta <legoktm@gmail.com>
Kyle Florence <kflorence@wikia-inc.com>
May Tee-Galloway <mgalloway@wikimedia.org>
+Mr. Stradivarius <misterstrad@gmail.com>
Moriel Schottlender <moriel@gmail.com>
Niklas Laxström <nlaxstrom@wikimedia.org>
Ricordisamoa <ricordisamoa@openmailbox.org>
diff --git a/vendor/oojs/oojs-ui/Doxyfile b/vendor/oojs/oojs-ui/Doxyfile
deleted file mode 100644
index cf831926..00000000
--- a/vendor/oojs/oojs-ui/Doxyfile
+++ /dev/null
@@ -1,33 +0,0 @@
-# Configuration file for Doxygen
-
-PROJECT_NAME = OOjs UI
-PROJECT_BRIEF = Object-Oriented JavaScript – User Interface
-
-OUTPUT_DIRECTORY = docs
-HTML_OUTPUT = php
-
-JAVADOC_AUTOBRIEF = YES
-QT_AUTOBRIEF = YES
-
-WARN_NO_PARAMDOC = YES
-
-INPUT = README.md php/
-FILE_PATTERNS = *.php
-RECURSIVE = YES
-# Requires doxygen 1.8.3+
-USE_MDFILE_AS_MAINPAGE = README.md
-
-HTML_DYNAMIC_SECTIONS = YES
-GENERATE_TREEVIEW = YES
-TREEVIEW_WIDTH = 250
-
-GENERATE_LATEX = NO
-
-HAVE_DOT = YES
-DOT_FONTNAME = Helvetica
-DOT_FONTSIZE = 10
-TEMPLATE_RELATIONS = YES
-CALL_GRAPH = NO
-CALLER_GRAPH = NO
-# Makes dot run faster. Requires graphviz >1.8.10
-DOT_MULTI_TARGETS = YES
diff --git a/vendor/oojs/oojs-ui/Gruntfile.js b/vendor/oojs/oojs-ui/Gruntfile.js
deleted file mode 100644
index 0aa41e42..00000000
--- a/vendor/oojs/oojs-ui/Gruntfile.js
+++ /dev/null
@@ -1,401 +0,0 @@
-/*!
- * Grunt file
- */
-
-/*jshint node:true */
-module.exports = function ( grunt ) {
- grunt.loadNpmTasks( 'grunt-banana-checker' );
- grunt.loadNpmTasks( 'grunt-contrib-clean' );
- grunt.loadNpmTasks( 'grunt-contrib-concat-sourcemaps' );
- grunt.loadNpmTasks( 'grunt-contrib-copy' );
- grunt.loadNpmTasks( 'grunt-contrib-csslint' );
- grunt.loadNpmTasks( 'grunt-contrib-cssmin' );
- grunt.loadNpmTasks( 'grunt-contrib-jshint' );
- grunt.loadNpmTasks( 'grunt-contrib-less' );
- grunt.loadNpmTasks( 'grunt-contrib-uglify' );
- grunt.loadNpmTasks( 'grunt-contrib-watch' );
- grunt.loadNpmTasks( 'grunt-csscomb' );
- grunt.loadNpmTasks( 'grunt-exec' );
- grunt.loadNpmTasks( 'grunt-file-exists' );
- grunt.loadNpmTasks( 'grunt-cssjanus' );
- grunt.loadNpmTasks( 'grunt-jscs' );
- grunt.loadNpmTasks( 'grunt-karma' );
- grunt.loadNpmTasks( 'grunt-svg2png' );
- grunt.loadTasks( 'build/tasks' );
-
- var modules = grunt.file.readJSON( 'build/modules.json' ),
- pgk = grunt.file.readJSON( 'package.json' ),
- lessFiles = {
- raster: {},
- vector: {},
- mixed: {}
- },
- colorizeSvgFiles = {},
- requiredFiles = modules[ 'oojs-ui' ].scripts.slice(),
- concatCssFiles = {},
- rtlFiles = {},
- minBanner = '/*! OOjs UI v<%= pkg.version %> | http://oojs.mit-license.org */';
-
- ( function () {
- var distFile, target, module, moduleStyleFiles;
- function rtlPath( fileName ) {
- return fileName.replace( /\.(\w+)$/, '.rtl.$1' );
- }
- // Generate all task targets required to process given file into a pair of CSS files (for LTR
- // and RTL), and return file name of LTR file.
- function processFile( fileName ) {
- var lessFileName, cssFileName, theme, path;
- path = require( 'path' );
- if ( path.extname( fileName ) === '.json' ) {
- lessFileName = fileName.replace( /\.json$/, '.less' ).replace( /^src/, 'dist/tmp' );
- theme = path.basename( path.dirname( fileName ) );
-
- colorizeSvgFiles[ fileName.replace( /.+\/(\w+)\/([\w-]+)\.(?:json|less)$/, '$1-$2' ) ] = {
- options: grunt.file.readJSON( fileName ),
- srcDir: 'src/themes/' + theme,
- destDir: 'dist/themes/' + theme,
- // This should not be needed, but our dist directory structure is weird
- cssPrependPath: 'themes/' + theme + '/',
- destLessFile: {
- ltr: lessFileName,
- rtl: rtlPath( lessFileName )
- }
- };
-
- cssFileName = fileName.replace( /\.json$/, '.css' ).replace( /^src/, 'dist/tmp/' + target );
- lessFiles[ target ][ cssFileName ] = [ lessFileName ];
- lessFiles[ target ][ rtlPath( cssFileName ) ] = [ rtlPath( lessFileName ) ];
- } else {
- cssFileName = fileName.replace( /\.less$/, '.css' ).replace( /^src/, 'dist/tmp/' + target );
- lessFiles[ target ][ cssFileName ] = [ fileName ];
- rtlFiles[ rtlPath( cssFileName ) ] = cssFileName;
- }
- return cssFileName;
- }
- for ( module in modules ) {
- if ( modules[ module ].styles ) {
- moduleStyleFiles = modules[ module ].styles;
- for ( target in lessFiles ) {
- requiredFiles.push.apply( requiredFiles, moduleStyleFiles );
-
- distFile = 'dist/' + module + ( target !== 'mixed' ? '.' + target : '' ) + '.css';
-
- concatCssFiles[ distFile ] = moduleStyleFiles.map( processFile );
- concatCssFiles[ rtlPath( distFile ) ] = concatCssFiles[ distFile ].map( rtlPath );
- }
- }
- }
- }() );
-
- function strip( str ) {
- var path = require( 'path' );
- // http://gruntjs.com/configuring-tasks#building-the-files-object-dynamically
- // http://gruntjs.com/api/grunt.file#grunt.file.expandmapping
- return function ( dest, src ) {
- return path.join( dest, src.replace( str, '' ) );
- };
- }
-
- grunt.initConfig( {
- pkg: pgk,
-
- // Build
- clean: {
- build: 'dist/*',
- doc: 'docs/*',
- tmp: 'dist/tmp'
- },
- fileExists: {
- src: requiredFiles
- },
- typos: {
- options: {
- typos: 'build/typos.json'
- },
- src: '{src,php}/**/*.{js,json,less,css}'
- },
- concat: {
- options: {
- banner: grunt.file.read( 'build/banner.txt' )
- },
- js: {
- files: {
- 'dist/oojs-ui.js': modules[ 'oojs-ui' ].scripts,
- 'dist/oojs-ui-apex.js': modules[ 'oojs-ui-apex' ].scripts,
- 'dist/oojs-ui-mediawiki.js': modules[ 'oojs-ui-mediawiki' ].scripts
- }
- },
- css: {
- files: concatCssFiles
- },
- demoCss: {
- options: {
- banner: '/** This file is generated automatically. Do not modify it. */\n\n'
- },
- files: {
- 'demos/styles/demo.rtl.css': 'demos/styles/demo.rtl.css'
- }
- }
- },
-
- // Build – Code
- uglify: {
- options: {
- banner: minBanner,
- sourceMap: true,
- sourceMapIncludeSources: true,
- report: 'gzip'
- },
- js: {
- expand: true,
- src: 'dist/*.js',
- ext: '.min.js',
- extDot: 'last'
- }
- },
-
- // Build – Styling
- less: {
- distRaster: {
- options: {
- ieCompat: true,
- report: 'gzip',
- modifyVars: {
- 'oo-ui-distribution': 'raster',
- 'oo-ui-default-image-ext': 'png'
- }
- },
- files: lessFiles.raster
- },
- distVector: {
- options: {
- ieCompat: false,
- report: 'gzip',
- modifyVars: {
- 'oo-ui-distribution': 'vector',
- 'oo-ui-default-image-ext': 'svg'
- }
- },
- files: lessFiles.vector
- },
- distMixed: {
- options: {
- ieCompat: false,
- report: 'gzip',
- modifyVars: {
- 'oo-ui-distribution': 'mixed',
- 'oo-ui-default-image-ext': 'png'
- }
- },
- files: lessFiles.mixed
- }
- },
- cssjanus: {
- options: {
- generateExactDuplicates: true
- },
- dist: {
- files: rtlFiles
- },
- demoCss: {
- files: {
- 'demos/styles/demo.rtl.css': 'demos/styles/demo.css'
- }
- }
- },
- csscomb: {
- dist: {
- expand: true,
- src: 'dist/*.css'
- }
- },
- copy: {
- imagesCommon: {
- src: 'src/styles/images/*.cur',
- dest: 'dist/images/',
- expand: true,
- flatten: true
- },
- imagesApex: {
- src: 'src/themes/apex/images/**/*.{png,gif}',
- dest: 'dist/themes/apex/images/',
- expand: true,
- rename: strip( 'src/themes/apex/images/' )
- },
- imagesMediaWiki: {
- src: 'src/themes/mediawiki/images/**/*.{png,gif}',
- dest: 'dist/themes/mediawiki/images/',
- expand: true,
- rename: strip( 'src/themes/mediawiki/images/' )
- },
- i18n: {
- src: 'i18n/*.json',
- expand: true,
- dest: 'dist/'
- },
- jsduck: {
- // Don't publish devDependencies
- src: '{dist,node_modules/{' + Object.keys( pgk.dependencies ).join( ',' ) + '}}/**/*',
- dest: 'docs/',
- expand: true
- }
- },
- colorizeSvg: colorizeSvgFiles,
- svg2png: {
- dist: {
- src: 'dist/{images,themes}/**/*.svg'
- }
- },
- cssmin: {
- options: {
- keepSpecialComments: 0,
- banner: minBanner,
- compatibility: 'ie8',
- report: 'gzip'
- },
- dist: {
- expand: true,
- src: 'dist/*.css',
- ext: '.min.css',
- extDot: 'last'
- }
- },
-
- // Lint – Code
- jshint: {
- options: {
- jshintrc: true
- },
- dev: [
- '*.js',
- '{build,demos,src,tests}/**/*.js',
- '!tests/JSPHP.test.js'
- ]
- },
- jscs: {
- dev: [
- '<%= jshint.dev %>',
- '!demos/dist/**'
- ]
- },
-
- // Lint – Styling
- csslint: {
- options: {
- csslintrc: '.csslintrc'
- },
- all: [
- '{demos,src}/**/*.css',
- '!demos/dist/**'
- ]
- },
-
- // Lint – i18n
- banana: {
- all: 'i18n/'
- },
-
- // Test
- exec: {
- rubyTestSuiteGenerator: {
- command: 'ruby bin/testsuitegenerator.rb src php > tests/JSPHP-suite.json'
- },
- phpGenerateJSPHPForKarma: {
- command: 'php ../bin/generate-JSPHP-for-karma.php > JSPHP.test.js',
- cwd: './tests'
- }
- },
- karma: {
- options: {
- frameworks: [ 'qunit' ],
- files: [
- 'node_modules/jquery/dist/jquery.js',
- 'node_modules/oojs/dist/oojs.jquery.js',
- 'dist/oojs-ui.js',
- 'dist/oojs-ui-apex.js',
- 'dist/oojs-ui-mediawiki.js',
- 'tests/QUnit.assert.equalDomElement.js',
- 'tests/**/*.test.js'
- ],
- reporters: [ 'dots' ],
- singleRun: true,
- browserDisconnectTimeout: 5000,
- browserDisconnectTolerance: 2,
- autoWatch: false
- },
- main: {
- browsers: [ 'Chrome' ],
- preprocessors: {
- 'dist/*.js': [ 'coverage' ]
- },
- reporters: [ 'dots', 'coverage' ],
- coverageReporter: { reporters: [
- { type: 'html', dir: 'coverage/' },
- { type: 'text-summary', dir: 'coverage/' }
- ] }
- },
- other: {
- browsers: [ 'Firefox' ]
- }
- },
-
- // Development
- watch: {
- files: [
- '<%= jshint.dev %>',
- '<%= csslint.all %>',
- '{demos,src}/**/*.less',
- '.{csslintrc,jscsrc,jshintignore,jshintrc}'
- ],
- tasks: 'quick-build'
- }
- } );
-
- grunt.registerTask( 'pre-test', function () {
- // Only create Source maps when doing a git-build for testing and local
- // development. Distributions for export should not, as the map would
- // be pointing at "../src".
- grunt.config.set( 'concat.js.options.sourceMap', true );
- grunt.config.set( 'concat.js.options.sourceMapStyle', 'link' );
- } );
-
- grunt.registerTask( 'pre-git-build', function () {
- var done = this.async();
- require( 'child_process' ).exec( 'git rev-parse HEAD', function ( err, stout, stderr ) {
- if ( !stout || err || stderr ) {
- grunt.log.err( err || stderr );
- done( false );
- return;
- }
- grunt.config.set( 'pkg.version', grunt.config( 'pkg.version' ) + '-pre (' + stout.slice( 0, 10 ) + ')' );
- grunt.verbose.writeln( 'Added git HEAD to pgk.version' );
- done();
- } );
- } );
-
- grunt.registerTask( 'build-code', [ 'concat:js', 'uglify' ] );
- grunt.registerTask( 'build-styling', [
- 'colorizeSvg', 'less', 'cssjanus',
- 'concat:css', 'concat:demoCss', 'csscomb', 'cssmin',
- 'copy:imagesCommon', 'copy:imagesApex', 'copy:imagesMediaWiki', 'svg2png'
- ] );
- grunt.registerTask( 'build-i18n', [ 'copy:i18n' ] );
- grunt.registerTask( 'build-tests', [ 'exec:rubyTestSuiteGenerator', 'exec:phpGenerateJSPHPForKarma' ] );
- grunt.registerTask( 'build', [ 'clean:build', 'fileExists', 'typos', 'build-code', 'build-styling', 'build-i18n', 'build-tests', 'clean:tmp' ] );
-
- grunt.registerTask( 'git-build', [ 'pre-git-build', 'build' ] );
-
- // Quickly build a no-frills vector-only ltr-only version for development
- grunt.registerTask( 'quick-build', [
- 'pre-git-build', 'clean:build', 'fileExists', 'typos',
- 'concat:js',
- 'colorizeSvg', 'less:distVector', 'concat:css',
- 'copy:imagesCommon', 'copy:imagesApex', 'copy:imagesMediaWiki',
- 'build-i18n'
- ] );
-
- grunt.registerTask( 'lint', [ 'jshint', 'jscs', 'csslint', 'banana' ] );
- grunt.registerTask( 'test', [ 'lint', 'pre-test', 'git-build', 'karma:main', 'karma:other' ] );
-
- grunt.registerTask( 'default', 'test' );
-};
diff --git a/vendor/oojs/oojs-ui/History.md b/vendor/oojs/oojs-ui/History.md
index 905b6b11..d7d5fbc6 100644
--- a/vendor/oojs/oojs-ui/History.md
+++ b/vendor/oojs/oojs-ui/History.md
@@ -1,10 +1,420 @@
# OOjs UI Release History
+## v0.12.12 / 2015-10-13
+### Features
+* CapsuleMultiSelectWidget: When 'allowArbitrary' is true, don't require 'Enter' to confirm (Bartosz Dziewoński)
+* SelectFileWidget: Add a focus method (Ed Sanders)
+
+### Styles
+* CapsuleMultiSelectWidget: Set 'background-color' rather than 'background' (Bartosz Dziewoński)
+* DropdownWidget: Fix vertical alignment of handle's text (Volker E)
+* MediaWiki theme: Get transitions on ButtonWidget's `:hover` states in sync (Volker E)
+* MediaWiki theme: Unbreak checkbox/radio 'cursor: pointer' (Bartosz Dziewoński)
+* MediaWiki theme: Use inverted icon for 'active' buttons (Ed Sanders)
+
+### Code
+* ButtonElement: Actually use 'active' property and add getter (Ed Sanders)
+* Element: Document $element config option (Thalia)
+* composer.json: Add author names & e-mails (Alangi Derick)
+* demo: Correct some typos (Bartosz Dziewoński)
+
+## v0.12.11 / 2015-10-06
+### Styles
+* MediaWiki theme: Make shadows translucent black instead of light grey (Ed Sanders)
+* MediaWiki theme: Make PHP DropdownInputWidget look closer to JS version (Bartosz Dziewoński)
+
+### Code
+* Follow-up I4acbe69420: BookletLayout: Fix focus of page switching (Ed Sanders)
+* IndexLayout: Fix focus of panel switching (Ed Sanders)
+* TextInputWidget: Remove 'autocomplete' attribute on page navigation (Bartosz Dziewoński)
+* build: Bump es5-shim and various devDependencies to master (James D. Forrester)
+
+## v0.12.10 / 2015-09-29
+### Styles
+* Fix icon/indicator padding on TextInputWidget/SelectFileWidget (Ed Sanders)
+
+### Code
+* CapsuleItemWidget: Remove 'click' event preventing (Bartosz Dziewoński)
+* FloatableElement: Don't try unbinding events before we bind them (Bartosz Dziewoński)
+* SelectWidget: Ensure 'choose' never emits null (Ed Sanders)
+* Remove old textInputWidget-decorated classes (Ed Sanders)
+* build: Upgrade MediaWiki-Codesniffer to 0.4.0 (Kunal Mehta)
+
+## v0.12.9 / 2015-09-22
+### Features
+* BookletLayout, IndexLayout: Make autoFocus and focussing more reliable (Bartosz Dziewoński)
+* CapsuleMultiSelectWidget: Allow using CapsuleItemWidget subclasses (Bartosz Dziewoński)
+* CardLayout: Add a 'label' config option (Ed Sanders)
+* FloatableElement: Introduce mixin (Bartosz Dziewoński)
+* FloatingMenuSelectWidget: Update position of menus within overlay while scrolling (Bartosz Dziewoński)
+* IndexLayout: Add 'expanded' option, passed through to StackLayout (Ed Sanders)
+* MenuLayout: Use child selectors to allow nesting menus (Ed Sanders)
+* Re-attempt I31ab2bace4: Try to stop user from tabbing outside of open dialog box (Ed Sanders)
+
+### Styles
+* SelectFileWidget: Move file type over to the right in secondary text colour (Ed Sanders)
+* Fix focus styles on disabled widgets (Volker E)
+* Apex, MediaWiki themes: Make most borders on table icon thinner (Ed Sanders)
+* Apex, MediaWiki themes: Make picture icon border thinner (Ed Sanders)
+* MediaWiki theme: Alter buttons' padding and position icons absolutely (nirzar)
+* MediaWiki theme: Fix height of IndexLayout tab widget (Ed Sanders)
+* MediaWiki theme: Unify box-shadows for PopupWidget and DropdownWidget (Volker E)
+
+### Code
+* #isFocusableElement: Rewrite for performance and correctness (Ed Sanders)
+* BookletLayout: Remove unnecessary JSHint override (Bartosz Dziewoński)
+* DropdownWidget: Update example doc to show #getMenu usage (Ed Sanders)
+* Follow-up bf1497be: Fix PopupToolGroup use of renamed Clippable property (Ed Sanders)
+* PopupWidget: Add missing `@mixins` doc entry (Bartosz Dziewoński)
+* SelectFileWidget: Fix DOM order of file type label (Ed Sanders)
+* Widget: Fix docs for disable event (Ed Sanders)
+* docs: Remove excess empty lines in comments (Bartosz Dziewoński)
+* docs: Add quotes around PROJECT_BRIEF setting (Timo Tijhof)
+* Update version requirement for mediawiki/at-ease: 1.0.0 → 1.1.0 (Ori Livneh)
+
+## v0.12.8.1 / 2015-09-18 special release
+### Code
+* build: Update version requirement for mediawiki/at-ease: 1.0.0 → 1.1.0 (Ori Livneh)
+
+## v0.12.8 / 2015-09-08
+### Styles
+* SelectFileWidget: Overflow and ellipsis for label (Ed Sanders)
+* Apex theme: Move transition timing to common variables (Prateek Saxena)
+* MediaWiki theme: Move window transition to `@medium-ease` variable (Prateek Saxena)
+* MediaWiki theme: Add missing `width` and `height` attributes to icons (Ed Sanders)
+* Clean up CSS values in .oo-ui-transition calls (Timo Tijhof)
+* Use 'ease' instead of 'ease-in-out' for CSS transitions (Timo Tijhof)
+
+### Code
+* Toolbar: Prevent double initialization (Roan Kattouw)
+* build: Bump grunt-contrib-jshint from 0.11.2 to 0.11.3 to fix upstream issue (James D. Forrester)
+* build: Upgrade grunt-banana-checker to v0.3.0 (James D. Forrester)
+
+## v0.12.7 / 2015-09-01
+### Deprecations
+* [DEPRECATING CHANGE] SelectFileWidget: Re-design to use a clearly clickable button (Ed Sanders)
+
+### Styles
+* FieldLayout: Don't add `margin-bottom` when in a HorizontalLayout (Florian)
+* SelectFileWidget: Use gray for hover and `@progressive-fade` for drop active (Prateek Saxena)
+* Apex, MediaWiki themes: Fix scale of external link icon (Ed Sanders)
+* Apex, MediaWiki themes: Re-crush all SVG files with SVGO (James D. Forrester)
+* Apex, MediaWiki themes: Reduce size of 'close' icon by 1px (Ed Sanders)
+* Apex, MediaWiki themes: Remove Inkscape-ism from SVG files (James D. Forrester)
+* Apex, MediaWiki themes: Standardise XML prolog for SVG files (Bartosz Dziewoński)
+* MediaWiki theme: Fix viewBox of arrow indicators (Ed Sanders)
+* MediaWiki theme: Fix viewBox of several icons (James D. Forrester)
+
+### Code
+* LookupElement: Really disallow editing of `readOnly` TextInputWidgets (Bartosz Dziewoński)
+* SelectFileWidget: Fix drop and drop hover exception in Firefox (Ed Sanders)
+* SelectFileWidget: Improve type checking (Ed Sanders)
+
+## v0.12.6 / 2015-08-25
+### Features
+* AccessKeyedElement: Introduce (Florian)
+* ButtonOptionWidget: Mixin TitledElement (Bartosz Dziewoński)
+* ClippableElement: Allow $clippableContainer to be different from $clippable (Roan Kattouw)
+* Dialog: Listen for Escape key on $element, not document (Roan Kattouw)
+* InputWidget: Add TitledElement and AccessKeyedElement mixins (Florian)
+* PopupWidget: Make it possible to add static footers (Moriel Schottlender)
+* SelectFileWidget: Add drag drop UI as a config (Prateek Saxena)
+* TextInputWidget: Add moveCursorToEnd() (Roan Kattouw)
+
+### Styles
+* MenuToolGroup: Add some missing styles for tools' 'check' icons (Bartosz Dziewoński)
+* PopupWidget: don't apply header styles to footer (Roan Kattouw)
+* SelectFileWidget: Mute the drag and drop design (Ed Sanders)
+* Add colour to neutral state of MW frameless buttons (Ed Sanders)
+* Editing-advanced icon pack: Add 'calendar' (Bartosz Dziewoński)
+
+### Code
+* DropdownInputWidget: Allow users to pass config options to DropdownWidget (Alex Monk)
+* Theme: Add theme classes to $icon and $indicator only (Bartosz Dziewoński)
+* Use OO.ui.debounce() for Element#updateThemeClasses (Roan Kattouw)
+* Document browser-specific code with support comments (Timo Tijhof)
+* Update OOjs to v1.1.9 (James D. Forrester)
+* Fix file permissions (Southparkfan)
+* Fix inArray test in drag handler (Ed Sanders)
+* Prefer ES5 over jQuery methods (Bartosz Dziewoński)
+* build: Enable jscs rule 'requireSpacesInsideBrackets' and make pass (James D. Forrester)
+* build: Enable jscs rule 'requireVarDeclFirst' and make pass (James D. Forrester)
+* build: Make `quick-build` build the 'mixed' distribution (James D. Forrester)
+* build: Update jscs devDependency from 1.8.0 to 2.1.0 (James D. Forrester)
+* build: Update various devDependencies to latest (James D. Forrester)
+* core: Remove spurious "[description]" placeholder from documentation (Timo Tijhof)
+* demos, tests: Use es5-shim for IE8 compatibility (Bartosz Dziewoński)
+* phpcs.xml: Ignore JS demo files in the PHP distribution (James D. Forrester)
+* testsuitegenerator: Do not generate nonsensical tests for 'maxLength' (Bartosz Dziewoński)
+
+## v0.12.5 / 2015-08-18
+### Features
+* CapsuleMultiSelectWidget: Unbreak $overlay config option (Bartosz Dziewoński)
+* FloatingMenuSelectWidget: Introduce, based on TextInputMenuSelectWidget (Bartosz Dziewoński)
+* FieldLayout: Throw an error if no widget is provided (Prateek Saxena)
+* MessageDialog: Focus primary action button when the dialog opens (Prateek Saxena)
+
+### Styles
+* DropdownWidget: Remove additional vertical margin, for consistency (Bartosz Dziewoński)
+* FieldLayout: Correct rendering of multiline messages in MediaWiki theme (Bartosz Dziewoński)
+* Move base icon/indicator styles out of themes (Roan Kattouw)
+* MediaWiki theme: Correct styling of nested buttons (Bartosz Dziewoński)
+
+### Code
+* DropdownWidget: Add $overlay config option (Bartosz Dziewoński)
+* IconElement, IndicatorElement: Apply base styles to the right selector (Bartosz Dziewoński)
+* Add background-repeat: no-repeat; to default icon/indicator styles (Roan Kattouw)
+* Remove redundant background rules for icons/indicators (Roan Kattouw)
+* Revert "TextInputWidget: Update doc'ed requirements for validate function" (Prtksxna)
+* Don't directly use #addEventListener for compatibility with IE 8 (Bartosz Dziewoński)
+* demos: Add a demo of the $overlay config option of various widgets (Bartosz Dziewoński)
+
+## v0.12.4 / 2015-08-13
+### Styles
+* CapsuleMultiSelectWidget: Style tweaks (Ed Sanders)
+
+### Code
+* MenuSelectWidget: Call #updateItemVisibility in more cases (Bartosz Dziewoński)
+* PopupWidget: Remove 'focusout' handling again, limit to CapsuleMultiSelectWidget (Bartosz Dziewoński)
+
+## v0.12.3 / 2015-08-11
+### Deprecations
+* [DEPRECATING CHANGE] TextInputWidget: Add getValidity function, deprecate isValid (Prateek Saxena)
+
+### Features
+* Add OO.ui.isSafeUrl() to make sure url targets are safe client-side (Kunal Mehta)
+* CapsuleMultiSelectWidget: Introduce (Brad Jorsch)
+* FieldLayout: Allow displaying errors or notices next to fields (Bartosz Dziewoński)
+* HorizontalLayout: Introduce (Bartosz Dziewoński)
+* If ProcessDialog#fitLabel is called before dialog is open, defer (Ed Sanders)
+* Mixin TitledElement into DropdownInputWidget and FieldLayout (Florian)
+* Preserve dynamic state of widgets when infusing (Bartosz Dziewoński)
+* TextInputWidget: Don't forget to positionLabel() after it's been unset (Bartosz Dziewoński)
+
+### Styles
+* FieldLayout: Kill 'list-style-image' too for messages list (Bartosz Dziewoński)
+* PopupToolGroup: Handle popup position on very narrow screens (Ed Sanders)
+* ToggleSwitchWidget: Update according to spec (Prateek Saxena)
+* MediaWiki, Apex themes: Fix height of frameless toolbar button (Ed Sanders)
+* Apex theme: Correct disabled iconed button tool's text colour (Ed Sanders)
+* Revert "Dialog: Increase z-index of .oo-ui-dialog to 1000+" (Ed Sanders)
+
+### Code
+* ButtonOptionWidget: Make it more difficult to set an inappropriate 'tabIndex' (Bartosz Dziewoński)
+* TextInputWidget: Update doc'ed requirements for validate function (Prateek Saxena)
+* TextInputWidget: Use getValidity in setValidityFlag (Prateek Saxena)
+* Element: DWIM when repeatedly infusing the same node (Bartosz Dziewoński)
+* Element: Preserve 'classes' config option through infusion (Bartosz Dziewoński)
+* demo: Make compatible with IE 8 (Bartosz Dziewoński)
+* build: Exclude irrelevant files from Composer PHP package (Timo Tijhof)
+* build: Move phpcs config from composer.json to phpcs.xml (Timo Tijhof)
+* build: Output doxygen to "doc" for consistency with other PHP libraries (Kunal Mehta)
+* build: Switch svg2png to personal build which fixes long lines (James D. Forrester)
+* demos, tests: Use `.parent` instead of `.super` (Bartosz Dziewoński)
+* docparser: Add rudimentary error handling (Bartosz Dziewoński)
+* doxygen: Use default directory for HTML_OUTPUT (Kunal Mehta)
+* tests: Twist the time in comparison tests in a different manner (Bartosz Dziewoński)
+* testsuitegenerator: Output the number of generated test cases (Bartosz Dziewoński)
+
+## v0.12.2 / 2015-07-28
+
+### Styles
+* Dialog: Increase z-index of .oo-ui-dialog to 1000+ (Prateek Saxena)
+* MediaWiki theme: Create new 'accessibility' icon pack (Violetto)
+
+### Code
+* SelectWidget: Fix @mixins documentation (Roan Kattouw)
+* Update OOjs to v1.1.8 (James D. Forrester)
+
+## v0.12.1 / 2015-07-22
+
+### Features
+* PendingElement: Make this actually useful (Roan Kattouw)
+* TextInputWidget: Handle required: true better (Bartosz Dziewoński)
+* TextInputWidget: Handle type: 'search' better (Bartosz Dziewoński)
+
+### Styles
+* PanelLayout: Add some vertical margin when 'padded' and 'framed' (Bartosz Dziewoński)
+* MediaWiki, Apex themes: Add 'clear' indicator (Bartosz Dziewoński)
+* MediaWiki theme: Align colour of toolbar and dropdown buttons (Prateek Saxena)
+
+### Code
+* Window: Compute directionality only when needed (Roan Kattouw)
+* Standardise some common comments (Bartosz Dziewoński)
+* build: Add clean:demos task (Bartosz Dziewoński)
+* build: Add clean:tests task (Bartosz Dziewoński)
+* build: Have copyright header reference "OOjs UI" team (Kunal Mehta)
+* build: Use new grunt-tyops package rather than local original (James D. Forrester)
+* Gruntfile: Fix 'pgk' to 'pkg' and add to typos list (James D. Forrester)
+* package.json: Use proper SPDX license notation (Derk-Jan Hartman)
+
+## v0.12.0 / 2015-07-13
+### Breaking changes
+* [BREAKING CHANGE] SearchWidget: Remove deprecated event re-emission (Ed Sanders)
+
+### Features
+* Allow infusion of widgets in other namespaces (Kunal Mehta)
+* Only allow construction of classes that extend OO.ui.Element in infusion (Kunal Mehta)
+* ButtonInputWidget: Disable generating `<label>` elements (Bartosz Dziewoński)
+* FieldLayout: Support HTML help messages through HtmlSnippet (Kunal Mehta)
+* RadioSelectWidget: Improve accessibility (Bartosz Dziewoński)
+* SelectWidget: Call #chooseItem instead of #selectItem when enter is pressed (Ed Sanders)
+
+### Styles
+* MediaWiki, Apex themes: Add a 'notice' icon, same as the 'alert' indicator (James D. Forrester)
+* MediaWiki, Apex themes: Re-crush with svgo 0.5.3 (James D. Forrester)
+* PopupWidget: Use child selectors to apply rules correctly (Ed Sanders)
+* TextInputWidget: Use 'text' cursor for icon/indicator rather than 'pointer' (Bartosz Dziewoński)
+* Set Scots to use bold-b and italic-i (baud/italeec) (Ed Sanders)
+
+### Code
+* ClippableElement: Fix horizontal clipping in nested scrollable elements (Roan Kattouw)
+* ClippableElement: Only call reconsiderScrollbars() if we actually *stopped* clipping (Roan Kattouw)
+* Follow-up 3ddb3603: unbreak nesting of autosizing or labeled TextInputWidgets (Roan Kattouw)
+* InputWidget: Add additional `<span/>` only for subclasses that need it (Bartosz Dziewoński)
+* LookupElement: Disallow editing of readOnly TextInputWidgets (Bartosz Dziewoński)
+* History: Re-write into new B/D/F/S/C format and clean up (James D. Forrester)
+* build: Don't run phpcs over demos/php (Kunal Mehta)
+* build: Update development dependencies (James D. Forrester)
+* build: Update watch rules (Kunal Mehta)
+
+## v0.11.8 / 2015-07-07
+### Features
+* DropdownInputWidget, RadioSelectInputWidget: Consistently call `#cleanUpValue` (Bartosz Dziewoński)
+* TextInputWidget: Allow setting the HTML autocomplete attribute (Florian)
+* TextInputWidget: Support `rows` option when in multiline mode (Kunal Mehta)
+* Make scroll into view work in scrollable divs in Firefox (Roan Kattouw)
+
+### Styles
+* MediaWiki theme: Remove support for frameless primary buttons (Bartosz Dziewoński)
+
+### Code
+* Use at-ease instead of PHP's @ (Kunal Mehta)
+* Use composer's autoloader in exec:phpGenerateJSPHPForKarma (Kunal Mehta)
+* build: Don't lint demos/{dist,node_modules,vendor} (Kunal Mehta)
+* build: Build demos as part of `grunt build` too (Kunal Mehta)
+* build: Build demos as part of `grunt quick-build` (Kunal Mehta)
+* build: Only build test files (`build-tests` task) when going to run tests (Bartosz Dziewoński)
+* demos: Make self-contained in demos/ directory (Kunal Mehta)
+* tests: Provide better output when running infusion test under Karma (Bartosz Dziewoński)
+
+## v0.11.7 / 2015-07-01
+### Features
+* Element.php: Strip all namespaces from infused PHP widgets (Kunal Mehta)
+* OptionWidget: Explicitly set aria-selected to `false` on init (Bartosz Dziewoński)
+
+### Styles
+* MediaWiki theme: Add support for frameless primary buttons (Ed Sanders)
+* MediaWiki theme: Align and center the advanced icon (Roan Kattouw)
+* MediaWiki, Apex themes: Fix styling for frameless process dialog actions (Ed Sanders)
+
+### Code
+* Element.php: Add test case to verify class name in infused widgets (Kunal Mehta)
+* Element.php: Only variables may be passed by reference (Kunal Mehta)
+* Theme.php: Actually make abstract in PHP (Kunal Mehta)
+* Theme.php: Add missing doc comments (Kunal Mehta)
+* documentation: Use bold in comments instead of h4 (Ed Sanders)
+
+## v0.11.6 / 2015-06-23
+### Features
+* NumberInputWidget: Don't use `Math.sign()` (Brad Jorsch)
+* SelectWidget: Fix invalid escape sequence `\s` (Roan Kattouw)
+
+### Styles
+* DropdownWidget: Add white background in MediaWiki theme (Prateek Saxena)
+* SelectFileWidget: Add white background in MediaWiki theme (Prateek Saxena)
+* MediaWiki theme: Add constructive variants for star and unStar icons (Roan Kattouw)
+* MediaWiki theme: Add invert variant to all icons (Roan Kattouw)
+* MediaWiki theme: Add progressive variant to ongoingConversation icon (Stephane Bisson)
+
+### Code
+* Use `.parent` instead of `.super` (Stephane Bisson)
+* build: Updating development dependencies (Kunal Mehta)
+
+## v0.11.5 / 2015-06-16
+### Features
+* ButtonInputWidget: Render frameless button correctly (Bartosz Dziewoński)
+* ComboBoxWidget: Add a getter method for text inputs (Mr. Stradivarius)
+* FieldsetLayout: Make rule for disabled label color more precise (Bartosz Dziewoński)
+* MenuSelectWidget: Explain what the widget config option is for (Roan Kattouw)
+* RadioSelectInputWidget: Unbreak form submission in JS version (Bartosz Dziewoński)
+
+### Styles
+* MediaWiki theme: Add destructive variant to check icon (Matthew Flaschen)
+* MediaWiki, Apex themes: Add ongoingConversation icon (Matthew Flaschen)
+
+### Code
+* build: Configure jsonlint (Kunal Mehta)
+
+## v0.11.4 / 2015-06-09
+### Deprecations
+* [DEPRECATING CHANGE] Introduce oo.ui.mixin namespace for mixins, and put them src/mixins (C. Scott Ananian)
+
+### Features
+* ActionFieldLayout: Add PHP version (Bartosz Dziewoński)
+* ButtonWidget: Fix not having tabindex updated when enabled/disabled (Brad Jorsch)
+* ClippableElement: Fix behavior of clippables in nested scrollables (Bartosz Dziewoński)
+* ClippableElement: Fix behavior of long clippables (Bartosz Dziewoński)
+* Dialog: Label in aria terms (Prateek Saxena)
+* DropdownWidget: Adjust height to other widgets (Bartosz Dziewoński)
+* DropdownWidget: Blank widget when no item is selected (Brad Jorsch)
+* Element#reconsiderScrollbars: Preserve scroll position (Bartosz Dziewoński)
+* GroupElement: pass correct event name to disconnect() from aggregate() (Roan Kattouw)
+* NumberInputWidget: Create, for numeric input (Brad Jorsch)
+* NumberInputWidget: Use keydown, not keypress (Brad Jorsch)
+* ProcessDialog: Don't center the title label if there's not enough space (Bartosz Dziewoński)
+* RadioOptionWidget: Control focus more strictly (Bartosz Dziewoński)
+* RadioSelectInputWidget: Create (Bartosz Dziewoński)
+* SelectFileWidget: Create (Brad Jorsch)
+* SelectWidget: Listen to keypresses and jump to matching items (Brad Jorsch)
+* TextInputWidget: Adjust height to other widgets (Bartosz Dziewoński)
+* Widget: Add `#supportsSimpleLabel` static property to control <label> usage (Bartosz Dziewoński)
+* Window: Clear margins for actions in horizontal/vertical groups (Ed Sanders)
+* `OOUI\Tag`: Avoid 'Potentially unsafe "href" attribute value' exceptions for relative URLs (Bartosz Dziewoński)
+
+### Styles
+* MessageDialog: Remove unintentional action button margin (Bartosz Dziewoński)
+* styles: Change gradient mixin syntax to W3C standards' syntax (Volker E)
+* styles: Remove obsolete "-ms-linear-gradient" declaration (Volker E)
+* Apex theme: Use matching 'lock' and 'unLock' icons (Bartosz Dziewoński)
+* MediaWiki and Apex themes: Force background color of <select> to white (Ed Sanders)
+* MediaWiki and Apex themes: Re-crush SVG files (James D. Forrester)
+
+### Code
+* ActionFieldLayout: Dead code removal and cleanup (Bartosz Dziewoński)
+* BarToolGroup: Add description and example (Kirsten Menger-Anderson)
+* ButtonInputWidget and TextInputWidget: Document and enforce allowed types (Bartosz Dziewoński)
+* DropdownInputWidget: Tweak documentation (Bartosz Dziewoński)
+* InputWidget#getInputElement: Mark as `@protected`, not `@private` (Bartosz Dziewoński)
+* ListToolGroup: Add description and example (Kirsten Menger-Anderson)
+* MenuToolGroup: Add description, example and mark private method (Kirsten Menger-Anderson)
+* PendingElement: Add description (Kirsten Menger-Anderson)
+* PopupTool: Add description and example (Kirsten Menger-Anderson)
+* PopupToolGroup: Add description and mark protected methods (Kirsten Menger-Anderson)
+* Tool: Add description (Kirsten Menger-Anderson)
+* ToolFactory: Add description (Kirsten Menger-Anderson)
+* ToolGroup: Add description and mark protected methods (Kirsten Menger-Anderson)
+* ToolGroupFactory: Add description (Kirsten Menger-Anderson)
+* ToolGroupTool: Add description and example (Kirsten Menger-Anderson)
+* Toolbar: Add description (Kirsten Menger-Anderson)
+* `OOUI\Element::mixins`: Improve doc comment (Kunal Mehta)
+* `OOUI\Tag`: Add basic phpunit tests (Kunal Mehta)
+* build: Update MediaWiki codesniffer to 0.2.0 (Kunal Mehta)
+* build: Updating development dependencies (James D. Forrester)
+* demo: Add 'layout' variable to the consoles (Bartosz Dziewoński)
+* demo: Link JS and PHP demos (Bartosz Dziewoński)
+* docs: Update name of upstream OOjs project in jsduck documentation (C. Scott Ananian)
+* mailmap: Add an additional e-mail for Bartosz per request (James D. Forrester)
+* test: Use -p option to phpcs instead of -v (Kunal Mehta)
+
## v0.11.3 / 2015-05-12
+### Features
* BarToolGroup: Don't use "pointer" cursor for disabled tools in enabled toolgroups (Bartosz Dziewoński)
* Tool: Support icon+label in bar tool groups (Bartosz Dziewoński)
* ToolGroupTool: Correct opacity of disabled nested tool group handle (Bartosz Dziewoński)
* ToolGroupTool: Synchronize inner ToolGroup disabledness state (Bartosz Dziewoński)
+
+### Styles
* MediaWiki theme: Add a powerful default text color for tools (Trevor Parscal)
* MediaWiki theme: Adjust quotes icon to match other icons (nirzar)
* MediaWiki theme: Give names to some more toolbar colours (Bartosz Dziewoński)
@@ -15,33 +425,36 @@
* MediaWiki theme: Update button specification (nirzar)
## v0.11.2 / 2015-05-11
+### Features
* Don't select lookup items on initialize (Ed Sanders)
* ListToolGroup, MenuToolGroup: Set accelTooltips = false (Bartosz Dziewoński)
* PopupWidget: Add setAlignment (Moriel Schottlender)
-* SelectWidget: Mark as @abstract, which it is (Bartosz Dziewoński)
* Simplify default action prevention in buttons and forms (Bartosz Dziewoński)
-* TabOptionWidget: Fix disabled styles to not react to hover/select (Ed Sanders)
* TextInputWidget: Allow override of #setValidityFlag (Ed Sanders)
* TextInputWidget: Use aria-required along with the required attribute (Prateek Saxena)
+
+### Styles
+* TabOptionWidget: Fix disabled styles to not react to hover/select (Ed Sanders)
* Toolbar: Fix shadow styling (Bartosz Dziewoński)
-* Toolbar: Move some tweaks from demo to actual implementation (Bartosz Dziewoński)
* Toolbar: Remove some useless code from the example (Bartosz Dziewoński)
* Toolbar: Rework example and add 'menu' tool group example (Bartosz Dziewoński)
* MediaWiki theme: Change highlight color for selected menu option (nirzar)
* MediaWiki theme: Polish the toolbar design (nirzar)
* MediaWiki theme: Remove accidentally duplicated styles for SelectWidget (Bartosz Dziewoński)
+### Code
+* SelectWidget: Mark as @abstract, which it is (Bartosz Dziewoński)
+* Toolbar: Move some tweaks from demo to actual implementation (Bartosz Dziewoński)
+
## v0.11.1 / 2015-05-04
+### Features
* Add IndexLayout (Trevor Parscal)
-* CardLayout: Fix typo (Kirsten Menger-Anderson)
-* LabelElement: Document that label config option can take an HtmlSnippet (Roan Kattouw)
-* PopupButtonWidget: Update align config in example (Kirsten Menger-Anderson)
-* Remove GridLayout remnants (Bartosz Dziewoński)
* SelectWidget: Add #selectItemByData method (Moriel Schottlender)
-* TabOptionWidget: Change link to card layout (Kirsten Menger-Anderson)
* TextInputWidget: Annotate input validation with aria-invalid (Prateek Saxena)
* TextInputWidget: Don't set 'invalid' flag on first focus, even if invalid (Bartosz Dziewoński)
* TextInputWidget: Support 'required' config option in PHP (Bartosz Dziewoński)
+
+### Styles
* MediaWiki theme: Add 'destructive' variant to block icon (Moriel Schottlender)
* MediaWiki theme: Better vertical alignment of 'search' icon (Ed Sanders)
* MediaWiki theme: Tweak 'search' icon size (Ed Sanders)
@@ -50,37 +463,63 @@
* MediaWiki theme: radio/checkbox: Use variable for transition time and easing function (Prateek Saxena)
* MediaWiki, Apex themes: Switch icons: clear → cancel, closeInput → clear (Bartosz Dziewoński)
* MediaWiki, Apex themes: Switch over 'magnifyingGlass' icon to be 'search' (James D. Forrester)
+
+### Code
+* CardLayout: Fix typo (Kirsten Menger-Anderson)
+* LabelElement: Document that label config option can take an HtmlSnippet (Roan Kattouw)
+* PopupButtonWidget: Update align config in example (Kirsten Menger-Anderson)
+* Remove GridLayout remnants (Bartosz Dziewoński)
+* TabOptionWidget: Change link to card layout (Kirsten Menger-Anderson)
* build: Add clean:doc task (Bartosz Dziewoński)
* build: Bump grunt-jscs to latest version (James D. Forrester)
* core: Add OO.ui.debounce() utility (Roan Kattouw)
* demo: Add icons with variants to icons demo (Bartosz Dziewoński)
## v0.11.0 / 2015-04-29
+### Breaking changes
* [BREAKING CHANGE] Do not set font-size: 0.8em anywhere in the library (Bartosz Dziewoński)
+### Deprecations
* [DEPRECATING CHANGE] Create rtl-ready alignments in PopupWidget (Moriel Schottlender)
+### Features
* MediaWiki theme: Adding variants to several icons (Moriel Schottlender)
* TextInputWidget: Allow functions to be passed as 'validate' config option (Bartosz Dziewoński)
+
+### Styles
* TextInputWidget: Styles for 'invalid' flag (Bartosz Dziewoński)
+
+### Code
* Update OOjs to v1.1.7 (James D. Forrester)
* Update jQuery from v1.11.1 to v1.11.3 (James D. Forrester)
* build: Use jquery and oojs from npm instead of embedded lib (Timo Tijhof)
## v0.10.1 / 2015-04-27
-* Correct 'tabindex' attribute setting (Bartosz Dziewoński)
+### Features
+* Correct `tabindex` attribute setting (Bartosz Dziewoński)
* Make toolbars keyboard-accessible (Bartosz Dziewoński)
+
+### Code
* ToggleButtonWidget: Unbreak horizontal alignment (Bartosz Dziewoński)
## v0.10.0 / 2015-04-22
-* [BREAKING CHANGE] ButtonWidget: remove deprecated nofollow option alias (C. Scott Ananian)
+### Breaking changes
+* [BREAKING CHANGE] ButtonWidget: remove deprecated `nofollow` option alias (C. Scott Ananian)
* [BREAKING CHANGE] Convert ToggleWidget from a mixin to an abstract class (Bartosz Dziewoński)
* [BREAKING CHANGE] MenuLayout: Reimplement without inline styles (Bartosz Dziewoński)
+### Deprecations
+
+### Features
* BarToolGroup: Allow tools with labels instead of icons (Bartosz Dziewoński)
* BookletLayout: Find first focusable element and add focusable utility (Moriel Schottlender)
-* ButtonInputWidget: Don't double-mixin FlaggedElement (Bartosz Dziewoński)
* ButtonWidget: Remove href to make unclickable when disabled (Bartosz Dziewoński)
+
+### Styles
+* MediaWiki, Apex themes: Add viewCompact, viewDetails, visionSimulator icons (Mun May Tee)
+
+### Code
+* ButtonInputWidget: Don't double-mixin FlaggedElement (Bartosz Dziewoński)
* ButtonWidget: Remove pointless #isHyperlink property (Bartosz Dziewoński)
* FormLayout: Better document how this works with InputWidgets (Bartosz Dziewoński)
* MenuLayout: Add example (Kirsten Menger-Anderson)
@@ -88,577 +527,704 @@
* PHP: More useful debugging information on unsafe tag attributes (Chad Horohoe)
* SelectWidget#getTargetItem: Simplify (Ed Sanders)
* Toolbar: Add example (Bartosz Dziewoński)
-* themes: Add viewCompact, viewDetails, visionSimulator icons for iconography page (Mun May Tee)
* demo: Remove VisualEditor references from toolbar demo, use generic icons (Ed Sanders)
* demo: Remove outline controls from outlined BookletLayout demo (Bartosz Dziewoński)
* demo: Simplify ButtonGroupWidget and ButtonSelectWidget examples (Bartosz Dziewoński)
## v0.9.8 / 2015-04-12
-* Apex, MediaWiki: Correct or delete unused SVG files (James D. Forrester)
-* Apex theme: Correctly position popups in RTL; follows-up v0.9.5 (Moriel Schottlender)
+### Features
* BookletLayout: Allow focus on any item (Moriel Schottlender)
+
+### Styles
+* Apex theme: Correctly position popups in RTL; follows-up v0.9.5 (Moriel Schottlender)
+* Apex, MediaWiki themes: Correct or delete unused SVG files (James D. Forrester)
+
+### Code
* Error: Add description (Kirsten Menger-Anderson)
-* Move coverage output from "/dist/coverage" to "/coverage" (Timo Tijhof)
-* ProcessDialog: Remove stray 'this.$' from documentation code example (Roan Kattouw)
+* ProcessDialog: Remove stray `this.$` from documentation code example (Roan Kattouw)
* ProgressBarWidget: Remove spurious styles from CSS output (Bartosz Dziewoński)
+
* build: Add explicit dependency upon grunt-cli (Kunal Mehta)
+* build: Move coverage output from "/dist/coverage" to "/coverage" (Timo Tijhof)
* build: Run lint before build in grunt-test (Timo Tijhof)
* colorize-svg: Generate language-specific rules for images even if equal to default ones (Bartosz Dziewoński)
* colorize-svg: Sprinkle `/* @noflip */` on language-specific rules (Bartosz Dziewoński)
* demo: Change html dir property when direction changes (Moriel Schottlender)
## v0.9.7 / 2015-04-03
+### Code
* build: Generate correct paths to fallback images (Bartosz Dziewoński)
## v0.9.5 / 2015-04-02
+### Deprecations
* [DEPRECATING CHANGE] Deprecate search widget event re-emission (Ed Sanders)
-* ActionFieldLayout: Add description and example (Kirsten Menger-Anderson)
-* Add vertical spacing to RadioSelectWidget in MW theme (Ed Sanders)
-* Allow rejecting Process with single Error (Matthew Flaschen)
-* Apex theme: Tweak 'check.svg' syntax (Bartosz Dziewoński)
-* Balance padding now that focus highlight is balanced (Ed Sanders)
-* BookletLayout: Add description and example (Kirsten Menger-Anderson)
-* Bring in remaining VisualEditor icons for Apex and MediaWiki themes (James D. Forrester)
-* Choose can't emit with a null item (Ed Sanders)
+### Features
+* Process: Allow rejecting with single Error (Matthew Flaschen)
* Correctly position popups in RTL (Moriel Schottlender)
-* Fix opacity of icons/indicators in disabled DecoratedOptionWidget (Ed Sanders)
-* IconWidget: Mix in FlaggedElement (Bartosz Dziewoński)
-* Increase specificity of ButtonElement icon and indicator styles (Bartosz Dziewoński)
-* Make colorize-svg.js actually work more often (Bartosz Dziewoński)
+
+### Styles
+* ButtonElement: Increase specificity of icon and indicator styles (Bartosz Dziewoński)
+* DecoratedOptionWidget: Fix opacity of icons/indicators when disabled (Ed Sanders)
+
+* Balance padding now that focus highlight is balanced (Ed Sanders)
+* Remove line height reset for windows (Ed Sanders)
+* Restore font family definitions to form elements (Ed Sanders)
+
+* Apex theme: Tweak `check.svg` syntax (Bartosz Dziewoński)
+* MediaWiki, Apex themes: Bring in remaining VisualEditor icons (James D. Forrester)
+* MediaWiki, Apex themes: Provide an RTL variant for the help icon (James D. Forrester)
+* MediaWiki theme: Add vertical spacing to RadioSelectWidget (Ed Sanders)
* MediaWiki theme: Allow intention flags for non-buttons (Andrew Garrett)
* MediaWiki theme: Fix icon opacity for disabled ButtonOptionWidgets (Bartosz Dziewoński)
+* MediaWiki theme: Revert "Syncing some button styles with MediaWiki UI" (Bartosz Dziewoński)
* MediaWiki theme: Use checkbox icon per mockups (Bartosz Dziewoński)
-* MediaWiki, Apex: Provide an RTL variant for the help icon (James D. Forrester)
+
+### Code
+* ActionFieldLayout: Add description and example (Kirsten Menger-Anderson)
+* BookletLayout: Add description and example (Kirsten Menger-Anderson)
+* IconWidget: Mix in FlaggedElement (Bartosz Dziewoński)
* MenuLayout: Correct documentation (Bartosz Dziewoński)
* OutlineOption: Add description (Kirsten Menger-Anderson)
* PageLayout: Add description (Kirsten Menger-Anderson)
* Process: Add description (Kirsten Menger-Anderson)
-* Properly support LTR/RTL icon versions in colorize-svg.js (Bartosz Dziewoński)
-* Refactor icon handling again (Bartosz Dziewoński)
-* Remove line height reset for windows (Ed Sanders)
-* Restore font family definitions to form elements (Ed Sanders)
-* Revert "Button styles between OOJS and MW" (Bartosz Dziewoński)
* StackLayout: Add description and example (Kirsten Menger-Anderson)
+* Choose can't emit with a null item (Ed Sanders)
+* Refactor icon handling again (Bartosz Dziewoński)
* build: Add a 'generated automatically' banner to demo.rtl.css (Bartosz Dziewoński)
* build: Generate prettier task names for 'colorizeSvg' (Bartosz Dziewoński)
* build: Have separate 'cssjanus' target for demo.rtl.css (Bartosz Dziewoński)
+* build: Make colorize-svg.js actually work more often (Bartosz Dziewoński)
+* build: Properly support LTR/RTL icon versions in colorize-svg.js (Bartosz Dziewoński)
* build: Simplify 'fileExists' task configuration (Bartosz Dziewoński)
* build: Support (poorly) per-language icon versions in colorize-svg.js (Bartosz Dziewoński)
* build: Update grunt-banana-checker to v0.2.1 (James D. Forrester)
## v0.9.4 / 2015-03-25
+### Breaking changes
+
+### Deprecations
+
+### Features
+* ProcessDialog#executeAction: Don't eat parent's return value (Roan Kattouw)
+* Compensate for loss of margin when opening modals (Ed Sanders)
+* Make outline controls' abilities configurable (Trevor Parscal)
+
+### Styles
+* MediaWiki theme: Reduce thickness of toolbar border (Ed Sanders)
+
+### Code
* ButtonElement: Clarify description (Kirsten Menger-Anderson)
* ButtonElement: Disable line wrapping on buttons (Ed Sanders)
-* Compensate for loss of margin when opening modals (Ed Sanders)
* FieldLayout: Clarify description and mark private methods (Kirsten Menger-Anderson)
* FieldsetLayout: Add description and example (Kirsten Menger-Anderson)
* FormLayout: Add description, example, and mark private method (Kirsten Menger-Anderson)
* Layout: Add description (Kirsten Menger-Anderson)
* LookupElement: Add description and mark private and protected methods (Kirsten Menger-Anderson)
* LookupElement: Fix typo in docs (Bartosz Dziewoński)
-* Make outline controls abilities configurable (Trevor Parscal)
* MenuLayout: Reorder styles (Bartosz Dziewoński)
* MenuSectionOptionWidget: Add description and example (Kirsten Menger-Anderson)
-* ProcessDialog#executeAction: Don't eat parent's return value (Roan Kattouw)
* PanelLayout: Add description and example (Kirsten Menger-Anderson)
-* Reduce thickness of toolbar border in MediaWiki (Ed Sanders)
* SearchWidget: Add description and mark private methods (Kirsten Menger-Anderson)
* TabIndexElement: Mark private method (Kirsten Menger-Anderson)
## v0.9.3 / 2015-03-19
-* Add .mailmap file (Roan Kattouw)
-* Add Kirsten to AUTHORS.txt (Roan Kattouw)
+### Features
+* LookupElement: Add optional config field for suggestions when empty (Matthew Flaschen)
+* ProcessDialog: send an array to showErrors in failed executeAction (Moriel Schottlender)
+
+### Code
* Dialog: Fix links to static properties (Kirsten Menger-Anderson)
* DraggableGroupElement: Clarify description and mark private methods (Kirsten Menger-Anderson)
-* Fix code style in @examples (Ed Sanders)
+* Fix code style in `@examples` (Ed Sanders)
* FlaggedElement: Add example and clarify description (Kirsten Menger-Anderson)
* GroupElement: Clarify description (Kirsten Menger-Anderson)
* IndicatorElement: Clarify description (Kirsten Menger-Anderson)
-* LookupElement: Add optional config field for suggestions when empty (Matthew Flaschen)
* MenuSelectWidget: Clarify description (Kirsten Menger-Anderson)
-* ProcessDialog: send an array to showErrors in failed executeAction (Moriel Schottlender)
* TabIndexedElement: Clarify description (Kirsten Menger-Anderson)
* TitledElement: Clarify description (Kirsten Menger-Anderson)
-* Update OOjs to v1.1.6 (James D. Forrester)
* Widget: Clarify description (Kirsten Menger-Anderson)
* Window: Clarify description of setDimensions method (Kirsten Menger-Anderson)
* WindowManager: Clarify description and mark private methods (Kirsten Menger-Anderson)
+* Update OOjs to v1.1.6 (James D. Forrester)
+* Add .mailmap file (Roan Kattouw)
+* Add Kirsten to AUTHORS.txt (Roan Kattouw)
* demo: Add one more toolbars demo (Bartosz Dziewoński)
## v0.9.2 / 2015-03-12
-* Toolbar: Be less aggressive with 'white-space: nowrap' (Bartosz Dziewoński)
+### Styles
+* Toolbar: Be less aggressive with `white-space: nowrap` (Bartosz Dziewoński)
+
+### Code
* Window: Revert changes from 521061dd (Bartosz Dziewoński)
## v0.9.1 / 2015-03-11
-* Syncing some button styles with MediaWiki UI (kaldari)
-* MediaWiki Theme: Add the progressive variant to the check icon (Prateek Saxena)
-* demo: Fix typo in toolbars demo (Bartosz Dziewoński)
+### Features
+* PanelLayout: Add `framed` config option (Bartosz Dziewoński)
* TextInputWidget: Use MutationObserver for #onElementAttach support (Bartosz Dziewoński)
-* TextInputWidget: Adjust size and label on first focus, too (Bartosz Dziewoński)
-* jsduck: Add MouseEvent and KeyboardEvent to externals (Timo Tijhof)
-* jsduck: Set --processes=0 to fix warnings-exit-nonzero (Timo Tijhof)
+* Only prevent default for handled keypresses (Brad Jorsch)
+
+### Styles
+* Toolbar: Tighten whitespace on narrow displays (Bartosz Dziewoński)
+* MediaWiki theme: Add the progressive variant to the check icon (Prateek Saxena)
+* MediaWiki theme: Add warning variant to icon set (Mark Holmquist)
+* MediaWiki theme: Add "Wikicon" icons (Mun May Tee)
+* MediaWiki theme: Synchronise button styles between OOJS and MW (nirzar)
+* MediaWiki theme: Syncing some button styles with MediaWiki UI (kaldari)
+* MediaWiki theme: textInputWidget: Update focus state (Prateek Saxena)
+
+### Code
+* ActionSet: Add description for events and clarify method descriptions (Kirsten Menger-Anderson)
+* ActionSet: Clarify description (Kirsten Menger-Anderson)
+* ActionWidget: Clarify description and mark private method (Kirsten Menger-Anderson)
+* ActionWidget: Fix bad copy-paste in documentation (Bartosz Dziewoński)
+* ButtonElement: Use #setButtonElement correctly (Bartosz Dziewoński)
+* ButtonInputWidget: Clarify description of configs and methods (Kirsten Menger-Anderson)
* Dialog: Mark private methods and add description of methods and configs (Kirsten Menger-Anderson)
-* ProcessDialog: Add description and example and mark private methods (Kirsten Menger-Anderson)
+* InputWidget: Clarify description (Kirsten Menger-Anderson)
* MessageDialog: Add description, example, and mark private methods (Kirsten Menger-Anderson)
-* build: Remove obsolete 'build' task from grunt-doc (Timo Tijhof)
-* build: Move pre/post 'doc' task into package.json (Timo Tijhof)
-* Remove remnants of window isolation (Bartosz Dziewoński)
-* demo: Simplify @media styles (Bartosz Dziewoński)
-* PanelLayout: Add 'framed' config option (Bartosz Dziewoński)
+* OutlineControlsWidget: Add description (Kirsten Menger-Anderson)
+* OutlineSelectWidget: Add description (Kirsten Menger-Anderson)
+* ProcessDialog: Add description and example and mark private methods (Kirsten Menger-Anderson)
* TextInputMenuSelectWidget: Add description and mark private methods (Kirsten Menger-Anderson)
-* Toolbar: Tighten whitespace on narrow displays (Bartosz Dziewoński)
-* demo: Use popup with head in the toolbars demo (Bartosz Dziewoński)
-* Remove half-baked touch event handling (Bartosz Dziewoński)
-* ButtonElement: Use #setButtonElement correctly (Bartosz Dziewoński)
+* TextInputWidget: Adjust size and label on first focus, too (Bartosz Dziewoński)
+* Window: Clarify descriptions of methods and configs (Kirsten Menger-Anderson)
* WindowManager: Documentation typo (Ed Sanders)
-* ButtonInputWidget: Clarify description of configs and methods (Kirsten Menger-Anderson)
* Icon width should only be applied if there is an icon (Moriel Schottlender)
-* package.json: Bump grunt-svg2png to 0.2.7 (Bartosz Dziewoński)
-* Add warning variant to MediaWiki set (Mark Holmquist)
-* Button styles between OOJS and MW (nirzar)
+* Remove half-baked touch event handling (Bartosz Dziewoński)
+* Remove remnants of window isolation (Bartosz Dziewoński)
* AUTHORS: Add Derk-Jan Hartman (Derk-Jan Hartman)
-* ActionSet: Add description for events and clarify method descriptions (Kirsten Menger-Anderson)
-* demo: Load styles before building demo widgets (not asynchronously) (Bartosz Dziewoński)
-* ActionWidget: Fix bad copy-paste in documentation (Bartosz Dziewoński)
-* Window: Clarify descriptions of methods and configs (Kirsten Menger-Anderson)
-* OutlineSelectWidget: Add description (Kirsten Menger-Anderson)
-* OutlineControlsWidget: Add description (Kirsten Menger-Anderson)
-* MediaWiki Theme: Add "Wikicon" icons (James D. Forrester)
-* build: Set 'generateExactDuplicates: true' for CSSJanus (Bartosz Dziewoński)
* build: Implement basic image flipping support in colorize-svg (Bartosz Dziewoński)
-* ActionWidget: Clarify description and mark private method (Kirsten Menger-Anderson)
-* ActionSet: Clarify description (Kirsten Menger-Anderson)
-* InputWidget: Clarify description (Kirsten Menger-Anderson)
-* MediaWiki Theme: textInputWidget: Update focus state (Prateek Saxena)
-* Only prevent default for handled keypresses (Brad Jorsch)
+* build: Move pre/post 'doc' task into package.json (Timo Tijhof)
+* build: Remove obsolete 'build' task from grunt-doc (Timo Tijhof)
+* build: Set 'generateExactDuplicates: true' for CSSJanus (Bartosz Dziewoński)
+* demo: Fix typo in toolbars demo (Bartosz Dziewoński)
+* demo: Load styles before building demo widgets (not asynchronously) (Bartosz Dziewoński)
+* demo: Simplify `@media` styles (Bartosz Dziewoński)
+* demo: Use popup with head in the toolbars demo (Bartosz Dziewoński)
+* jsduck: Add MouseEvent and KeyboardEvent to externals (Timo Tijhof)
+* jsduck: Set --processes=0 to fix warnings-exit-nonzero (Timo Tijhof)
+* package.json: Bump grunt-svg2png to 0.2.7 (Bartosz Dziewoński)
## v0.9.0 / 2015-03-04
+### Breaking changes
* [BREAKING CHANGE] Remove innerOverlay (Ed Sanders)
-* [BREAKING CHANGE] TextInputWidget: Remove 'icon' and 'indicator' events (Bartosz Dziewoński)
+* [BREAKING CHANGE] TextInputWidget: Remove `icon` and `indicator` events (Bartosz Dziewoński)
* [BREAKING CHANGE] Remove deprecated LookupInputWidget (Bartosz Dziewoński)
* [BREAKING CHANGE] Remove deprecated GridLayout (Bartosz Dziewoński)
-* Only modify body class when first/last window opens/closes (Ed Sanders)
-* InputWidget: Focus checkboxes and radios, too, when the label is clicked (Bartosz Dziewoński)
+### Features
* Move `OO.ui.infuse` to `OO.ui.Element.static.infuse`. (C. Scott Ananian)
-* Don't call LabelElement constructor twice for ActionFieldLayouts (Roan Kattouw)
-* PopupElement: Add description (Kirsten Menger-Anderson)
+* Fake toolbar group nesting (Bartosz Dziewoński)
+* Infer retry button action flags from symbolic name (Trevor Parscal)
+* InputWidget: Focus checkboxes and radios, too, when the label is clicked (Bartosz Dziewoński)
+* ProcessDialog: Dismiss errors on teardown (Moriel Schottlender)
+
+### Styles
* Make icon and indicator container sizes consistent (Ed Sanders)
-* SelectWidget: Marked protected methods and clarified choose/press descriptions (Kirsten Menger-Anderson)
-* demo: Call Toolbar#initialize in toolbar demo (Bartosz Dziewoński)
-* demo: Add PopupTool to toolbar demo (Bartosz Dziewoński)
+* Restore previous toolbar items margins and padding (Bartosz Dziewoński)
+* Use the correct color for gray buttons (Prateek Saxena)
+
+### Code
+* CheckboxInputWidget: Add description and example (Kirsten Menger-Anderson)
+* ComboBoxWidget: Add description, example, and mark private methods (Kirsten Menger-Anderson)
+* DecoratedOptionWidget: Add description and example (Kirsten Menger-Anderson)
+* DropdownInputWidget: Add description, example, and mark private method (Kirsten Menger-Anderson)
+* FieldLayout: Fix display of documentation's bulleted list (Kirsten Menger-Anderson)
+* GroupWidget and ItemWidget: Mark `private` (Kirsten Menger-Anderson)
+* IndicatorWidget: Add description and example (Kirsten Menger-Anderson)
+* LabelElement: Don't call constructor twice for ActionFieldLayouts (Roan Kattouw)
+* LabelWidget: Add description, example, and mark private method (Kirsten Menger-Anderson)
+* PopupElement: Add description (Kirsten Menger-Anderson)
* PopupTool: Tool constructor takes a toolGroup, not a toolbar (Bartosz Dziewoński)
-* Infer retry button action flags from symbolic name (Trevor Parscal)
-* Revert "Unbreak form submission in JavaScript" (Bartosz Dziewoński)
* PopupWidget: Add description, example, and mark private methods (Kirsten Menger-Anderson)
-* ToggleButtonWidget: Add description, example, and mark private method (Kirsten Menger-Anderson)
-* ToggleWidget: Add description (Kirsten Menger-Anderson)
-* ToggleSwitchWidget: Add description, example, and mark private methods (Kirsten Menger-Anderson)
-* build: Add disconnect tolerance to karma config (James D. Forrester)
+* PopupWidget: Add keydown listener and hide popup on ESC (Prateek Saxena)
* ProgressBar: Add description and example (Kirsten Menger-Anderson)
-* CheckboxInputWidget: Add description and example (Kirsten Menger-Anderson)
-* Use the correct color for gray buttons (Prateek Saxena)
* RadioInputWidget: Add description and example (Kirsten Menger-Anderson)
+* SelectWidget: Add example and link to decorated option widget (Kirsten Menger-Anderson)
+* SelectWidget: Marked protected methods and clarified choose/press descriptions (Kirsten Menger-Anderson)
+* TextInputWidget: Add description, example, and mark private methods (Kirsten Menger-Anderson)
+* ToggleButtonWidget: Add description, example, and mark private method (Kirsten Menger-Anderson)
+* ToggleSwitchWidget: Add description, example, and mark private methods (Kirsten Menger-Anderson)
+* ToggleWidget: Add description (Kirsten Menger-Anderson)
* Fix invalid use of border shorthand syntax (Timo Tijhof)
-* Restore previous toolbar items margins and padding (Bartosz Dziewoński)
-* ProcessDialog: Dismiss errors on teardown (Moriel Schottlender)
-* build: Remove footer override from jsduck (Timo Tijhof)
-* FieldLayout: Fix display of bulleted list (Kirsten Menger-Anderson)
+* Only modify body class when first/last window opens/closes (Ed Sanders)
* Use only two variables each for each semantic color (Prateek Saxena)
-* tests: Run JS/PHP tests for widgets with required parameters, too (Bartosz Dziewoński)
-* TextInputWidget: Add description, example, and mark private methods (Kirsten Menger-Anderson)
+* build: Add disconnect tolerance to karma config (James D. Forrester)
+* build: Remove footer override from jsduck (Timo Tijhof)
+* demo: Add PopupTool to toolbar demo (Bartosz Dziewoński)
+* demo: Call Toolbar#initialize in toolbar demo (Bartosz Dziewoński)
* tests: Add infusion tests (Bartosz Dziewoński)
-* PopupWidget: Add keydown listener and hide popup on ESC (Prateek Saxena)
-* DropdownInputWidget: Add description, example, and mark private method (Kirsten Menger-Anderson)
-* ComboBoxWidget: Add description, example, and mark private methods (Kirsten Menger-Anderson)
-* DecoratedOptionWidget: Add description and example (Kirsten Menger-Anderson)
-* SelectWidget: Add example and link to decorated option widget (Kirsten Menger-Anderson)
-* GroupWidget and ItemWidget: Mark private (Kirsten Menger-Anderson)
-* Fake toolbar group nesting (Bartosz Dziewoński)
-* LabelWidget: Add description, example, and mark private method (Kirsten Menger-Anderson)
-* IndicatorWidget: Add description and example (Kirsten Menger-Anderson)
+* tests: Run JS/PHP tests for widgets with required parameters, too (Bartosz Dziewoński)
## v0.8.3 / 2015-02-26
+### Features
* Revert "Unbreak form submission in JavaScript" (Bartosz Dziewoński)
## v0.8.2 / 2015-02-26
-* testsuitegenerator: Exclude 'text' parameter from tests, like 'content' (Bartosz Dziewoński)
+### Features
* PHP TitledElement: Actually set $this->title (Bartosz Dziewoński)
-* PHP PanelLayout: Fix getConfig() for 'expanded' config option (Bartosz Dziewoński)
-* WindowManager: Don't pass 'this' to window factory method (Bartosz Dziewoński)
+* PHP PanelLayout: Fix getConfig() for `expanded` config option (Bartosz Dziewoński)
+
+### Code
+* testsuitegenerator: Exclude 'text' parameter from tests, like 'content' (Bartosz Dziewoński)
+* WindowManager: Don't pass `this` to window factory method (Bartosz Dziewoński)
## v0.8.1 / 2015-02-25
+### Deprecations
* [DEPRECATING CHANGE] Rename setPosition to setLabelPosition (Ed Sanders)
+### Features
+* Allow passing positional parameters inside the config object (Bartosz Dziewoński)
+* ComboBox: Use combobox role (Derk-Jan Hartman)
* Element.php: Add "data" property (C. Scott Ananian)
* Element.php: Add "text" configuration option (C. Scott Ananian)
-* Work around Safari 8 misrendering checkboxes in SVG-only distribution (Bartosz Dziewoński)
+* Element: Add `content` config option, matching PHP side. (C. Scott Ananian)
+* FormLayout: Allow adding child layouts via config (Bartosz Dziewoński)
+* Implement OO.ui.infuse to reconstitute PHP widgets in client-side JS (C. Scott Ananian)
+* Serialize PHP widget state into data-ooui attribute (C. Scott Ananian)
* TextInputWidget: Fix appearance of icons and labels when disabled (Ed Sanders)
-* Remove '$: this.$' from code examples (Bartosz Dziewoński)
-* Prefer OO.isPlainObject to $.isPlainObject (Bartosz Dziewoński)
-* Error: Fix function name (Bartosz Dziewoński)
-* build: Use grunt-contrib-copy instead of custom 'copy' task (Timo Tijhof)
+* Unbreak form submission in JavaScript (Bartosz Dziewoński)
+
+### Styles
+* Set proper spacing between interleaved FieldsetLayouts and FormLayouts (Bartosz Dziewoński)
+* MediaWiki theme: Drop unnecessary pseudo-element of CheckboxInputWidget (Timo Tijhof)
+* MediaWiki theme: Drop unnecessary pseudo-element of RadioInputWidget (Timo Tijhof)
+* MediaWiki theme: Simplify spacing of checkboxes/radios in FieldLayouts (Bartosz Dziewoński)
+
+### Code
+* ButtonOptionWidget: Add description (Kirsten Menger-Anderson)
+* ButtonSelectWidget: Add description and example (Kirsten Menger-Anderson)
+* DraggableElement: Mark private methods and add description to events (Kirsten Menger-Anderson)
* Element.php: Tweak docs (Bartosz Dziewoński)
-* docparser.rb: Ruby 1.9.3 compatibility (Bartosz Dziewoński)
-* Move toggle() from Widget to Element (Moriel Schottlender)
-* build: Include 'lib' and 'dist' in jsduck output (Timo Tijhof)
+* Element: Add description for configs and static property (Kirsten Menger-Anderson)
+* Error: Fix function name (Bartosz Dziewoński)
* Fix typo: contian → contain (Bartosz Dziewoński)
-* MediaWiki Theme: Drop unnecessary pseudo-element of CheckboxInputWidget (Timo Tijhof)
-* MediaWiki Theme: Drop unnecessary pseudo-element of RadioInputWidget (Timo Tijhof)
-* MediaWiki theme: Simplify spacing of checkboxes/radios in FieldLayouts (Bartosz Dziewoński)
-* Add disabled RadioInputWidget to demo (Bartosz Dziewoński)
-* RadioOptionWidget: Make disabling single options work (Bartosz Dziewoński)
-* composer.json: Add description field (Kunal Mehta)
+* FlaggedElement: Add description of event and config option (Kirsten Menger-Anderson)
+* Follow-up bade83bfdfc: actually remove ../ (Roan Kattouw)
* IconElement: Add description for config options (Kirsten Menger-Anderson)
+* IconElement: Add description of methods (Kirsten Menger-Anderson)
* IndicatorElement: Add description for configs and static properties (Kirsten Menger-Anderson)
-* DraggableElement: Mark private methods and add description to events (Kirsten Menger-Anderson)
-* Element: Add description for configs and static property (Kirsten Menger-Anderson)
* LabelElement: Add description, config description, static property description (Kirsten Menger-Anderson)
-* TitledElement: Add description and config and static descriptions (Kirsten Menger-Anderson)
-* ComboBox: Use combobox role (Derk-Jan Hartman)
-* IconElement: Add description of methods (Kirsten Menger-Anderson)
-* Follow-up bade83bfdfc: actually remove ../ (Roan Kattouw)
-* Remove loop length check (Ed Sanders)
-* PopupButtonWidget: Add description and example and mark private method (Kirsten Menger-Anderson)
-* FlaggedElement: Add description of event and config option (Kirsten Menger-Anderson)
-* Unbreak docparser.rb (Bartosz Dziewoński)
-* Allow passing positional parameters inside the config object (Bartosz Dziewoński)
-* Run JS/PHP comparison tests using karma (Bartosz Dziewoński)
-* test: Reduce timeout in Process test from 100 to 10 (Timo Tijhof)
+* MenuOptionWidget: Add description (Kirsten Menger-Anderson)
+* MenuSelectWidget: Add description and mark protected method (Kirsten Menger-Anderson)
+* Move toggle() from Widget to Element (Moriel Schottlender)
* OptionWidget: Add description and descriptions of methods (Kirsten Menger-Anderson)
-* FormLayout: Allow adding child layouts via config (Bartosz Dziewoński)
-* Teach docparser about @member, @see, and PHP pass-by-reference (&$foo). (C. Scott Ananian)
-* Element: Add `content` config option, matching PHP side. (C. Scott Ananian)
-* SelectWidget: Add description for config, methods, events (Kirsten Menger-Anderson)
-* Serialize PHP widget state into data-ooui attribute (C. Scott Ananian)
-* Implement OO.ui.infuse to reconstitute PHP widgets in client-side JS (C. Scott Ananian)
-* ButtonSelectWidget: Add description and example (Kirsten Menger-Anderson)
+* PopupButtonWidget: Add description and example and mark private method (Kirsten Menger-Anderson)
+* Prefer OO.isPlainObject to $.isPlainObject (Bartosz Dziewoński)
* RadioOptionWidget: Add description (Kirsten Menger-Anderson)
-* ButtonOptionWidget: Add description (Kirsten Menger-Anderson)
+* RadioOptionWidget: Make disabling single options work (Bartosz Dziewoński)
* RadioSelectWidget: Add description and example (Kirsten Menger-Anderson)
-* Set proper spacing between interleaved FieldsetLayouts and FormLayouts (Bartosz Dziewoński)
-* MenuOptionWidget: Add description (Kirsten Menger-Anderson)
-* Unbreak form submission in JavaScript (Bartosz Dziewoński)
-* MenuSelectWidget: Add description and mark protected method (Kirsten Menger-Anderson)
+* Remove '$: this.$' from code examples (Bartosz Dziewoński)
+* Remove loop length check (Ed Sanders)
+* SelectWidget: Add description for config, methods, events (Kirsten Menger-Anderson)
* TabIndexelement: Add description, example, and mark private method (Kirsten Menger-Anderson)
-* Add "composer test" command to lint PHP files and run phpcs (Kunal Mehta)
+* TitledElement: Add description and config and static descriptions (Kirsten Menger-Anderson)
* Update OOjs to v1.1.5 (James D. Forrester)
-
+* Work around Safari 8 mis-rendering checkboxes in SVG-only distribution (Bartosz Dziewoński)
+* build: Give docparser.rb Ruby 1.9.3 compatibility (Bartosz Dziewoński)
+* build: Include 'lib' and 'dist' in jsduck output (Timo Tijhof)
+* build: Teach docparser about `@member`, `@see`, and PHP pass-by-reference (`&$foo`). (C. Scott Ananian)
+* build: Unbreak docparser.rb (Bartosz Dziewoński)
+* build: Use grunt-contrib-copy instead of custom 'copy' task (Timo Tijhof)
+* composer.json: Add description field (Kunal Mehta)
+* demo: Add disabled RadioInputWidget to demo (Bartosz Dziewoński)
+* tests: Add "composer test" command to lint PHP files and run phpcs (Kunal Mehta)
+* tests: Reduce timeout in Process test from 100 to 10 (Timo Tijhof)
+* tests: Run JS/PHP comparison tests using karma (Bartosz Dziewoński)
## v0.8.0 / 2015-02-18
+### Breaking changes
* [BREAKING CHANGE] Make default distribution provide SVG with PNG fallback (Bartosz Dziewoński)
-* [DEPRECATING CHANGE] TextInputWidget: Deprecate 'icon' and 'indicator' events (Bartosz Dziewoński)
+### Deprecations
+* [DEPRECATING CHANGE] ButtonWidget: Rename nofollow config option to noFollow (C. Scott Ananian)
+* [DEPRECATING CHANGE] TextInputWidget: Deprecate `icon` and `indicator` events (Bartosz Dziewoński)
-* ButtonElement: add protected to event handlers (Kirsten Menger-Anderson)
-* docs: Make @example documentation tag work (Roan Kattouw)
-* TextInputWidget: Hide mixin components when unused (Ed Sanders)
-* DropdownWidget: Simplify redundant code (Bartosz Dziewoński)
-* Update PHP widgets for accessibility-related changes in JS widgets (Bartosz Dziewoński)
+### Features
* TabIndexedElement: Allow tabIndex property to be null (C. Scott Ananian)
-* ButtonElement: Add description (Kirsten Menger-Anderson)
+* TextInputWidget: Allow maxLength of 0 in JS (matching PHP) (Bartosz Dziewoński)
+
+### Styles
+* MediaWiki theme: Add focus state for frameless button (Prateek Saxena)
+* MediaWiki theme: Fix border width for frameless buttons' focus state (Prateek Saxena)
+* MediaWiki theme: Resynchronize PHP with JS (Bartosz Dziewoński)
+* MediaWiki theme: Use white icons for disabled buttons (Bartosz Dziewoński)
+
+### Code
+* ActionSet: Add `@private` to onActionChange method (Kirsten Menger-Anderson)
+* ActionSet: Add description and example (Kirsten Menger-Anderson)
+* ActionSet: Add description for specialFlags property (Kirsten Menger-Anderson)
+* ActionWidget: Add description (Kirsten Menger-Anderson)
* Add missing ButtonInputWidget.less and corresponding mixin (Bartosz Dziewoński)
-* Various fixes to the PHP implementation (C. Scott Ananian)
-* Use Array.isArray instead of $.isArray (C. Scott Ananian)
-* TextInputWidget: Use margins for moving the label (Ed Sanders)
-* DraggableGroupElement: Add description (Kirsten Menger-Anderson)
-* demo: Add horizontal alignment test (Bartosz Dziewoński)
-* build: Pass RuboCop, customize settings (Bartosz Dziewoński)
-* Widget: Add description (Kirsten Menger-Anderson)
+* ButtonElement: Add description (Kirsten Menger-Anderson)
+* ButtonElement: add `protected` to event handlers (Kirsten Menger-Anderson)
+* ButtonGroupWidget: Add description and example (Kirsten Menger-Anderson)
* ButtonInputWidget: Add description and example (Kirsten Menger-Anderson)
+* ButtonWidget: Add example and link (Kirsten Menger-Anderson)
* Dialog: Add description and example (Kirsten Menger-Anderson)
* DraggableElement: Add description (Kirsten Menger-Anderson)
-* docparser: Add support for 'protected' methods (Bartosz Dziewoński)
-* testsuitegenerator: Only test every pair of config options rather than every triple (Bartosz Dziewoński)
-* TextInputWidget: Don't add label position classes when there's no label (Bartosz Dziewoński)
-* Update JS/PHP comparison test suite (Bartosz Dziewoński)
-* tests: Fix the check for properties (Bartosz Dziewoński)
-* TextInputWidget: Add missing LabelElement mixin documentation (Ed Sanders)
-* Follow-up c762da42: fix ProcessDialog error handling (Roan Kattouw)
-* MediaWiki Theme: Add focus state for frameless button (Prateek Saxena)
-* TextInputWidget: Allow maxLength of 0 in JS (matching PHP) (Bartosz Dziewoński)
-* TextInputWidget: Only put $label in the DOM if needed (Bartosz Dziewoński)
-* MediaWiki Theme: Use white icons for disabled buttons (Bartosz Dziewoński)
-* Follow-up 6a6bb90ab: Update CSS file path in eg-iframe.html (Roan Kattouw)
+* DraggableGroupElement: Add description (Kirsten Menger-Anderson)
+* DropdownWidget: Add `@private` to private methods (Kirsten Menger-Anderson)
+* DropdownWidget: Add description and example (Kirsten Menger-Anderson)
+* DropdownWidget: Simplify redundant code (Bartosz Dziewoński)
* Element: Add description (Kirsten Menger-Anderson)
-* PHP: Remove redundant documentation for getInputElement() (Bartosz Dziewoński)
-* Some documentation tweaks (Bartosz Dziewoński)
* FieldLayout: Add description (Kirsten Menger-Anderson)
* FieldLayout: Clean up and remove lies (Bartosz Dziewoński)
* FlaggedElement: Add description (Kirsten Menger-Anderson)
-* PHP demo: Correct path to CSS files (Bartosz Dziewoński)
-* MediaWikiTheme: Resynchronize PHP with JS (Bartosz Dziewoński)
-* ButtonWidget: Rename nofollow config option to noFollow (C. Scott Ananian)
+* Follow-up 6a6bb90ab: Update CSS file path in eg-iframe.html (Roan Kattouw)
+* Follow-up c762da42: fix ProcessDialog error handling (Roan Kattouw)
* GroupElement: Add description (Kirsten Menger-Anderson)
* IconElement: Add description (Kirsten Menger-Anderson)
+* IconElement: Add description and fix display of static properties (Kirsten Menger-Anderson)
* IconWidget: Add description and example (Kirsten Menger-Anderson)
* IndicatorElement: Add description (Kirsten Menger-Anderson)
* InputWidget: Add description (Kirsten Menger-Anderson)
+* PHP: Remove redundant documentation for getInputElement() (Bartosz Dziewoński)
+* Refactor keyboard accessibility of SelectWidgets (Bartosz Dziewoński)
* SelectWidget: Add description (Kirsten Menger-Anderson)
-* MediaWiki Theme: Fix border width for frameless buttons' focus state (Prateek Saxena)
+* Some documentation tweaks (Bartosz Dziewoński)
+* TextInputWidget: Add missing LabelElement mixin documentation (Ed Sanders)
+* TextInputWidget: Don't add label position classes when there's no label (Bartosz Dziewoński)
+* TextInputWidget: Hide mixin components when unused (Ed Sanders)
+* TextInputWidget: Only put $label in the DOM if needed (Bartosz Dziewoński)
+* TextInputWidget: Use margins for moving the label (Ed Sanders)
+* Update PHP widgets for accessibility-related changes in JS widgets (Bartosz Dziewoński)
+* Use Array.isArray instead of $.isArray (C. Scott Ananian)
+* Various fixes to the PHP implementation (C. Scott Ananian)
+* Widget: Add description (Kirsten Menger-Anderson)
* Window: Add description (Kirsten Menger-Anderson)
* WindowManager: Add description (Kirsten Menger-Anderson)
-* ButtonGroupWidget: Add description and example (Kirsten Menger-Anderson)
-* DropdownWidget: Add @private to private methods (Kirsten Menger-Anderson)
-* Refactor keyboard accessibility of SelectWidgets (Bartosz Dziewoński)
-* ActionSet: Add description and example (Kirsten Menger-Anderson)
-* ActionSet: Add @private to onActionChange method (Kirsten Menger-Anderson)
-* ActionWidget: Add description (Kirsten Menger-Anderson)
-* ActionSet: Add description for specialFlags property (Kirsten Menger-Anderson)
-* DropdownWidget: Add description and example (Kirsten Menger-Anderson)
-* ButtonWidget: Add example and link (Kirsten Menger-Anderson)
-* IconElement: Add description and fix display of static properties (Kirsten Menger-Anderson)
-
+* build: Pass RuboCop, customize settings (Bartosz Dziewoński)
+* demo: Add horizontal alignment test (Bartosz Dziewoński)
+* PHP demo: Correct path to CSS files (Bartosz Dziewoński)
+* tests: Update JS/PHP comparison test suite (Bartosz Dziewoński)
+* docparser: Add support for `protected` methods (Bartosz Dziewoński)
+* docs: Make `@example` documentation tag work (Roan Kattouw)
+* tests: Fix the check for properties (Bartosz Dziewoński)
+* testsuitegenerator: Only test every pair of config options rather than every triple (Bartosz Dziewoński)
## v0.7.0 / 2015-02-11
+### Breaking changes
* [BREAKING CHANGE] Remove window isolation (Trevor Parscal)
+### Deprecations
* [DEPRECATING CHANGE] GridLayout should no longer be used, instead use MenuLayout (Bartosz Dziewoński)
+### Features
+* ButtonWidget: Add `nofollow` option (C. Scott Ananian)
+* ButtonWidget: Better handle non-string parameters in setHref/setTarget (C. Scott Ananian)
+* PopupWidget: Set $clippable only once, correctly (Bartosz Dziewoński)
+* SelectWidget: `listbox` wrapper role, `aria-selected` state on contents (Derk-Jan Hartman)
+* TabIndexedElement: Actually allow tabIndex of -1 (Bartosz Dziewoński)
+* TextInputWidget: Add required attribute on the basis of required config (Prateek Saxena)
+* TextInputWidget: Use aria-hidden for extra autosize textarea (Prateek Saxena)
+* ToggleSwitchWidget: Accessibility improvements (Bartosz Dziewoński)
+
+### Styles
+* FieldsetLayout: Tweak positioning of help icon (Bartosz Dziewoński)
* Fade in window frames separately from window overlays (Ed Sanders)
-* Fix initialisation of window visible (Ed Sanders)
-* SelectWidget: 'listbox' wrapper role, 'aria-selected' state on contents (Derk-Jan Hartman)
-* Cleanup unreachable code from DraggableGroupElement (Moriel Schottlender)
+* MediaWiki theme: Consistent toggle button `active` state (Bartosz Dziewoński)
+* MediaWiki theme: Correct flagged primary button text color when pressed (Bartosz Dziewoński)
+* MediaWiki theme: Fix background color for disabled buttons (Prateek Saxena)
+* MediaWiki theme: Fix non-clickability of radios and checkboxes (Bartosz Dziewoński)
+* MediaWiki theme: Rename `@active` to `@pressed` in button mixins (Prateek Saxena)
+* MediaWiki theme: Rename `@highlight` to `@active` (Prateek Saxena)
+* MediaWiki theme: Rename active-* variables to pressed-* (Prateek Saxena)
+* MediaWiki theme: Use darker color for frameless buttons (Prateek Saxena)
+* MediaWiki theme: Use distribution's image type for backgrounds (Bartosz Dziewoński)
+
+### Code
+* ButtonWidget: Add documentation (Kirsten Menger-Anderson)
+* {Checkbox,Radio}InputWidget: Add missing configuration initialization (Bartosz Dziewoński)
+* DraggableGroupElement: Cleanup unreachable code (Moriel Schottlender)
+* DraggableGroupElement: Make sure it supports button widgets (Moriel Schottlender)
* DraggableGroupElement: Unset dragged item when dropped (Moriel Schottlender)
-* Remove inline spacing from ButtonWidget (Roan Kattouw)
-* Make sure DraggableGroupElement supports button widgets (Moriel Schottlender)
-* demo: Use properties instead of attributes for <link> (Timo Tijhof)
-* Revert "Remove inline spacing from ButtonWidget" (Bartosz Dziewoński)
-* ToggleSwitchWidget: Accessibility improvements (Bartosz Dziewoński)
-* TextInputWidget: Add required attribute on the basis of required config (Prateek Saxena)
-* DropdownInputWidget: Fix undefined variable in PHP (Bartosz Dziewoński)
-* PHP demo: Just echo the autoload error message, don't trigger_error() (Bartosz Dziewoński)
-* demo: Stop inline consoles from generating white space (Bartosz Dziewoński)
-* demo: Reorder widgets into somewhat logical groupings (Bartosz Dziewoński)
-* demo: Add button style showcase from PHP demo (Bartosz Dziewoński)
-* PHP demo: Resynchronize with JS demo (Bartosz Dziewoński)
-* Stop treating ApexTheme class unfairly and make it proper (Bartosz Dziewoński)
-* PHP demo: Add Vector/Raster and MediaWiki/Apex controls (Bartosz Dziewoński)
* Delete unused src/themes/apex/{raster,vector}.less (Bartosz Dziewoński)
-* {Checkbox,Radio}InputWidget: Add missing configuration initialization (Bartosz Dziewoński)
-* MediaWiki theme: Use distribution's image type for backgrounds (Bartosz Dziewoński)
-* tests: Just echo the autoload error message, don't trigger_error() (Bartosz Dziewoński)
-* MediaWiki theme: Fix non-clickability of radios and checkboxes (Bartosz Dziewoński)
+* DropdownInputWidget: Fix undefined variable in PHP (Bartosz Dziewoński)
+* DropdownWidget, ComboBoxWidget: Make keyboard-accessible (Bartosz Dziewoński)
+* Fix initialisation of window visible (Ed Sanders)
* Fix text input auto-height calculation (Ed Sanders)
-* MediaWiki theme: Consistent toggle button 'active' state (Bartosz Dziewoński)
-* RadioOptionWidget: Make it a <label/> (Bartosz Dziewoński)
-* MediaWiki theme: Correct flagged primary button text color when pressed (Bartosz Dziewoński)
-* FieldsetLayout: Tweak positioning of help icon (Bartosz Dziewoński)
-* TextInputWidget: Use aria-hidden for extra autosize textarea (Prateek Saxena)
+* ListToolGroup: Remove hack for jQuery's .show()/.hide() (Bartosz Dziewoński)
+* MenuSelectWidget: Codify current behavior of Tab closing the menu (Bartosz Dziewoński)
+* MenuSelectWidget: Don't clobber other events when unbinding (Bartosz Dziewoński)
+* MenuSelectWidget: Remove dead code (Bartosz Dziewoński)
+* OptionWidgets: Make better use of `scrollIntoViewOnSelect` (Bartosz Dziewoński)
+* PopupElement: Correct documentation (Bartosz Dziewoński)
+* RadioOptionWidget: Make it a `<label />` (Bartosz Dziewoński)
* Refactor clickability of buttons (Bartosz Dziewoński)
-* Remove usage of this.$ and config.$ (Trevor Parscal)
+* Remove usage of `this.$` and `config.$` (Trevor Parscal)
+* Stop treating ApexTheme class unfairly and make it proper (Bartosz Dziewoński)
+* TextInputMenuSelectWidget: Correct documentation (Bartosz Dziewoński)
* build: Bump various devDependencies (James D. Forrester)
+* demo: Add button style showcase from PHP demo (Bartosz Dziewoński)
+* demo: Reorder widgets into somewhat logical groupings (Bartosz Dziewoński)
+* demo: Stop inline consoles from generating white space (Bartosz Dziewoński)
+* demo: Use properties instead of attributes for <link> (Timo Tijhof)
+* PHP demo: Add Vector/Raster and MediaWiki/Apex controls (Bartosz Dziewoński)
+* PHP demo: Just echo the autoload error message, don't trigger_error() (Bartosz Dziewoński)
+* PHP demo: Resynchronize with JS demo (Bartosz Dziewoński)
* History: Fix date typos (James D. Forrester)
-* TabIndexedElement: Actually allow tabIndex of -1 (Bartosz Dziewoński)
-* ListToolGroup: Remove hack for jQuery's .show()/.hide() (Bartosz Dziewoński)
-* PopupWidget: Set $clippable only once, correctly (Bartosz Dziewoński)
-* TextInputMenuSelectWidget: Correct documentation (Bartosz Dziewoński)
-* PopupElement: Correct documentation (Bartosz Dziewoński)
-* MediaWiki Theme: Rename @active to @pressed in button mixins (Prateek Saxena)
+* tests: Just echo the autoload error message, don't trigger_error() (Bartosz Dziewoński)
* tools.less: Use distribution's image type and path for background (Prateek Saxena)
-* MediaWiki Theme: Fix background color for disabled buttons (Prateek Saxena)
-* MenuSelectWidget: Don't clobber other events when unbinding (Bartosz Dziewoński)
-* MenuSelectWidget: Codify current behavior of Tab closing the menu (Bartosz Dziewoński)
-* DropdownWidget, ComboBoxWidget: Make keyboard-accessible (Bartosz Dziewoński)
-* MenuSelectWidget: Remove dead code (Bartosz Dziewoński)
-* MediaWiki Theme: Rename active-* variables to pressed-* (Prateek Saxena)
-* ButtonWidget: Better handle non-string parameters in setHref/setTarget (C. Scott Ananian)
-* Make better use of 'scrollIntoViewOnSelect' in OptionWidgets (Bartosz Dziewoński)
-* ButtonWidget: Add "nofollow" option (C. Scott Ananian)
-* MediaWiki Theme: Rename @highlight to @active (Prateek Saxena)
-* MediaWiki Theme: Use darker color for frameless buttons (Prateek Saxena)
-* ButtonWidget: Add documentation (Kirsten Menger-Anderson)
## v0.6.6 / 2015-02-04
+### Features
+* BookletLayout#toggleOutline: Fix to use MenuLayout method (Ed Sanders)
+* Remove disabled elements from keyboard navigation flow (Derk-Jan Hartman)
* TextInputWidget: Mostly revert "Don't try adjusting size when detached" (Bartosz Dziewoński)
+* Use CSS overriding trick to support RTL in menu layouts (Ed Sanders)
+
+### Styles
+* Use standard border colours for progress bars (Ed Sanders)
+
+### Code
* Use css class instead of jQuery .show()/hide()/toggle() (Moriel Schottlender)
* build: Use karma to v0.12.31 (Timo Tijhof)
-* Use standard border colours for progress bars (Ed Sanders)
-* Remove disabled elements from keyboard navigation flow (Derk-Jan Hartman)
-* Fix BookletLayout#toggleOutline to use MenuLayout method (Ed Sanders)
-* Use CSS overriding trick to support RTL in menu layouts (Ed Sanders)
## v0.6.5 / 2015-02-01
-* Make BookletLayout inherit from MenuLayout instead of embedding a GridLayout (Ed Sanders)
+### Code
* ButtonElement: Unbreak 'pressed' state (Bartosz Dziewoński)
+* Make BookletLayout inherit from MenuLayout instead of embedding a GridLayout (Ed Sanders)
## v0.6.4 / 2015-01-30
+### Features
+* Add inline labels to text widgets (Ed Sanders)
+* BookletLayout: Make sure there is a page before focusing (Moriel Schottlender)
+* DropdownInputWidget: Introduce (Bartosz Dziewoński)
* InputWidget: Resynchronize our internal .value with DOM .value in #getValue (eranroz)
-* demo: Remove nonexistent 'align' config option for a DropdownWidget (Bartosz Dziewoński)
-* MediaWiki theme: Reduce size of checkboxes and radio buttons by 20% (Ed Sanders)
-* MediaWiki theme: Remove SearchWidget's border now dialogs have outline (Ed Sanders)
-* TextInputWidget: Accept 'maxLength' configuration option (Bartosz Dziewoński)
-* MediaWiki Theme: Adjust ButtonSelectWidget, ButtonGroupWidget highlights (Prateek Saxena)
-* Update OOjs to v1.1.4 and switch to the jQuery-optimised version (James D. Forrester)
-* build: Bump devDependencies and fix up (James D. Forrester)
* Seriously work around the Chromium scrollbar bug for good this time (Bartosz Dziewoński)
-* Introduce and use TabIndexedElement (Bartosz Dziewoński)
-* AUTHORS: Update for the last six months' work (James D. Forrester)
-* Set input direction in html prop rather than css rule (Moriel Schottlender)
-* Introduce DropdownInputWidget (Bartosz Dziewoński)
-* Remove the 'flash' feature from MenuSelectWidget and OptionWidget (Bartosz Dziewoński)
-* InputWidget: Clarify documentation of #getInputElement (Bartosz Dziewoński)
-* Make sure there is a page before focusing in BookletLayout (Moriel Schottlender)
-* Provide default margins for buttons and other widgets (Bartosz Dziewoński)
+* TabIndexedElement: Introduce and use (Bartosz Dziewoński)
+* TextInputWidget: Accept `maxLength` configuration option (Bartosz Dziewoński)
+* MenuLayout: Introduce (Ed Sanders)
+* Window#updateSize: Add simpler API (Ed Sanders)
+
+### Styles
+* ActionFieldLayout: Add `nowrap` to the button (Moriel Schottlender)
+* FieldsetLayout: Add help icon (Moriel Schottlender)
+* Fix opening/closing animation on windows (Roan Kattouw)
* OptionWidget: Unbreak 'pressed' state (Bartosz Dziewoński)
-* TextInputWidget: Remove superfluous role=textbox (Derk-Jan Hartman)
+* Provide default margins for buttons and other widgets (Bartosz Dziewoński)
+* MenuSelectWidget and OptionWidget: Remove the 'flash' feature (Bartosz Dziewoński)
+* MediaWiki theme: Adjust ButtonSelectWidget, ButtonGroupWidget highlights (Prateek Saxena)
+* MediaWiki theme: Adjust MenuOptionWidget selected state (Bartosz Dziewoński)
+* MediaWiki theme: Fix background issues with disabled buttons (Roan Kattouw)
+* MediaWiki theme: Reduce size of checkboxes and radio buttons by 20% (Ed Sanders)
+* MediaWiki theme: Remove SearchWidget's border now dialogs have outline (Ed Sanders)
* MediaWiki theme: Tweak some more border-radii (Bartosz Dziewoński)
-* Widget: Set aria-disabled too in #setDisabled (Derk-Jan Hartman)
-* Twiddle things (Ed Sanders)
-* Add help icon for FieldsetLayout (Moriel Schottlender)
-* PopupButtonWidget: Set aria-haspopup to true (Prateek Saxena)
-* ToggleButtonWidget: Set aria-pressed when changing value (Derk-Jan Hartman)
-* ActionFieldLayout: Add 'nowrap' to the button (Moriel Schottlender)
-* demo: Have multiline text in multiline widgets (Bartosz Dziewoński)
-* Add inline labels to text widgets (Ed Sanders)
-* TextInputWidget: Don't try adjusting size when detached (Bartosz Dziewoński)
-* MediaWiki Theme: Adjust MenuOptionWidget selected state (Bartosz Dziewoński)
-* ToggleWidget: Use aria-checked (Prateek Saxena)
* MediaWiki theme: Unbreak disabled buttons (Bartosz Dziewoński)
-* MediaWiki theme: Fix background issues with disabled buttons (Roan Kattouw)
+
+### Code
* ButtonOptionWidget: Add the TabIndexedElement mixin (Derk-Jan Hartman)
+* InputWidget: Clarify documentation of #getInputElement (Bartosz Dziewoński)
+* PopupButtonWidget: Set aria-haspopup to true (Prateek Saxena)
* Remove labelPosition check (Ed Sanders)
-* Fix opening/closing animation on windows (Roan Kattouw)
-* Add MenuLayout (Ed Sanders)
-* Add simpler window#updateSize API (Ed Sanders)
+* Set input direction in html prop rather than css rule (Moriel Schottlender)
+* TextInputWidget: Don't try adjusting size when detached (Bartosz Dziewoński)
+* TextInputWidget: Remove superfluous role=textbox (Derk-Jan Hartman)
+* ToggleButtonWidget: Set aria-pressed when changing value (Derk-Jan Hartman)
+* ToggleWidget: Use aria-checked (Prateek Saxena)
+* Twiddle things (Ed Sanders)
+* Update OOjs to v1.1.4 and switch to the jQuery-optimised version (James D. Forrester)
+* Widget: Set aria-disabled too in #setDisabled (Derk-Jan Hartman)
+* AUTHORS: Update for the last six months' work (James D. Forrester)
+* build: Bump devDependencies and fix up (James D. Forrester)
+* demo: Have multiline text in multiline widgets (Bartosz Dziewoński)
+* demo: Remove nonexistent 'align' config option for a DropdownWidget (Bartosz Dziewoński)
## v0.6.3 / 2015-01-14
+### Deprecations
* [DEPRECATING CHANGE] LookupInputWidget should no longer be used, instead use LookupElement
-* MediaWiki Theme: Adjust toolbar popups' border and shadows (Bartosz Dziewoński)
-* MediaWiki Theme: Don't use 'box-shadow' to produce thin grey lines in dialogs (Bartosz Dziewoński)
-* demo: Switch the default theme from 'Apex' to 'MediaWiki' (Ricordisamoa)
-* Toolbar: Update #initialize docs (Bartosz Dziewoński)
+### Features
* Add an ActionFieldLayout (Moriel Schottlender)
+* Replace old&busted LookupInputWidget with new&hot LookupElement (Bartosz Dziewoński)
+
+### Styles
* dialog: Provide a 'larger' size for things for which 'large' isn't enough (James D. Forrester)
* Synchronize ComboBoxWidget and DropdownWidget styles (Bartosz Dziewoński)
-* Replace old&busted LookupInputWidget with new&hot LookupElement (Bartosz Dziewoński)
+* MediaWiki theme: Adjust toolbar popups' border and shadows (Bartosz Dziewoński)
+* MediaWiki theme: Don't use 'box-shadow' to produce thin grey lines in dialogs (Bartosz Dziewoński)
+
+### Code
+* Toolbar: Update #initialize docs (Bartosz Dziewoński)
+* demo: Switch the default theme from 'Apex' to 'MediaWiki' (Ricordisamoa)
## v0.6.2 / 2015-01-09
-* WindowManager#removeWindows: Documentation fix (Ed Sanders)
+### Features
* Clear windows when destroying window manager (Ed Sanders)
-* MediaWiki theme: Slightly reduce size of indicator arrows (Ed Sanders)
-* MediaWiki Theme: Remove text-shadow on button (Prateek Saxena)
-* MediaWiki Theme: Fix focus state for buttons (Prateek Saxena)
-* MediaWiki Theme: Fix disabled state of buttons (Prateek Saxena)
-* MediaWiki Theme: Fix overlap between hover and active states (Prateek Saxena)
-* Make @anchor-size a less variable and calculate borders from it (Ed Sanders)
-* PHP LabelElement: Actually allow non-plaintext labels (Bartosz Dziewoński)
-* MediaWiki Theme: Add state change transition to checkbox (Prateek Saxena)
-* Synchronize @abstract class annotations between PHP and JS (Bartosz Dziewoński)
-* Add 'lock' icon (Trevor Parscal)
-* Don't test abstract classes (Bartosz Dziewoński)
* Element: Add support for 'id' config option (Bartosz Dziewoński)
-* testsuitegenerator.rb: Handle inheritance chains (Bartosz Dziewoński)
* TextInputWidget: Add support for 'autofocus' config option (Bartosz Dziewoński)
+
+### Styles
+* Add 'lock' icon (Trevor Parscal)
+* Make `@anchor-size` a LESS variable and calculate borders from it (Ed Sanders)
+* MediaWiki theme: Slightly reduce size of indicator arrows (Ed Sanders)
+* MediaWiki theme: Remove text-shadow on button (Prateek Saxena)
+* MediaWiki theme: Fix focus state for buttons (Prateek Saxena)
+* MediaWiki theme: Add state change transition to checkbox (Prateek Saxena)
+* MediaWiki theme: Fix disabled state of buttons (Prateek Saxena)
+* MediaWiki theme: Fix overlap between hover and active states (Prateek Saxena)
+
+### Code
+* Don't test abstract classes (Bartosz Dziewoński)
+* PHP LabelElement: Actually allow non-plaintext labels (Bartosz Dziewoński)
+* Synchronize `@abstract` class annotations between PHP and JS (Bartosz Dziewoński)
+* WindowManager#removeWindows: Documentation fix (Ed Sanders)
* tests: Don't overwrite 'id' attribute (Bartosz Dziewoński)
+* testsuitegenerator.rb: Handle inheritance chains (Bartosz Dziewoński)
## v0.6.1 / 2015-01-05
-* Remove use of Math.round() for offset and position pixel values (Bartosz Dziewoński)
-* Update JSPHP-suite.json (Bartosz Dziewoński)
-* ButtonElement: Inherit all 'font' styles, not only 'font-family' (Bartosz Dziewoński)
+### Styles
* FieldsetLayout: Shrink size of label and bump the weight to compensate (James D. Forrester)
+
+### Code
+* Remove use of `Math.round()` for offset and position pixel values (Bartosz Dziewoński)
+* ButtonElement: Inherit all 'font' styles, not only 'font-family' (Bartosz Dziewoński)
* IndicatorElement: Fix 'indicatorTitle' config option (Bartosz Dziewoński)
-* Error: Unmark as @abstract (Bartosz Dziewoński)
+* Error: Unmark as `@abstract` (Bartosz Dziewoński)
+* JSPHP-suite.json: Update (Bartosz Dziewoński)
* build: Update various devDependencies (James D. Forrester)
* readme: Update badges (Timo Tijhof)
* readme: No need to put the same heading in twice (James D. Forrester)
## v0.6.0 / 2014-12-16
+### Breaking changes
* [BREAKING CHANGE] PopupToolGroup and friends: Pay off technical debt (Bartosz Dziewoński)
-* ButtonGroupWidget: Remove weird margin-bottom: -1px; from theme styles (Bartosz Dziewoński)
+
+### Features
* Prevent parent window scroll in modal mode using overflow hidden (Ed Sanders)
-* MediaWiki theme: RadioInputWidget tweaks (Bartosz Dziewoński)
* ClippableElement: Handle clipping with left edge (Bartosz Dziewoński)
+
+### Styles
+* ButtonGroupWidget: Remove weird margin-bottom: -1px; from theme styles (Bartosz Dziewoński)
+* MediaWiki theme: RadioInputWidget tweaks (Bartosz Dziewoński)
+
+### Code
* Sprinkle some child selectors around in BookletLayout styles (Roan Kattouw)
## v0.5.0 / 2014-12-12
+### Breaking changes
* [BREAKING CHANGE] FieldLayout: Handle 'inline' alignment better (Bartosz Dziewoński)
* [BREAKING CHANGE] Split primary flag into primary and progressive (Trevor Parscal)
* [BREAKING CHANGE] CheckboxInputWidget: Allow setting HTML 'value' attribute (Bartosz Dziewoński)
-* MediaWiki theme: checkbox: Fix states according to spec (Prateek Saxena)
-* MediaWiki theme: Add radio buttons (Prateek Saxena)
-* MediaWiki theme: Use gray instead of blue for select and highlight (Trevor Parscal)
-* MediaWiki theme: Copy .theme-oo-ui-outline{Controls,Option}Widget from Apex (Bartosz Dziewoński)
-* MediaWiki theme: Add thematic border to the bottom of toolbars (Bartosz Dziewoński)
-* MediaWiki theme: Extract @active-color variable (Bartosz Dziewoński)
-* MediaWiki theme: Add hover state to listToolGroup (Trevor Parscal)
-* MediaWiki theme: Add state transition to radio buttons (Prateek Saxena)
-* MediaWiki theme: Make button sizes match Apex (Trevor Parscal)
-* MediaWiki theme: Improve search widget styling (Trevor Parscal)
-* build: Use String#slice instead of discouraged String#substr (Timo Tijhof)
+
+### Features
* Element.getClosestScrollableContainer: Use 'body' or 'documentElement' based on browser (Prateek Saxena)
-* testsuitegenerator: Actually filter out non-unique combinations (Bartosz Dziewoński)
-* Fix primary button description text (Niklas Laxström)
* Give non-isolated windows a tabIndex for selection holding (Ed Sanders)
* Call .off() correctly in setButtonElement() (Roan Kattouw)
-* RadioInputWidget: Remove documentation lies (Bartosz Dziewoński)
-* Don't set line-height of unset button labels (Bartosz Dziewoński)
-* Temporarily remove position:absolute on body when resizing (Ed Sanders)
-* Kill the escape keydown event after handling a window close (Ed Sanders)
-* PopupWidget: Remove box-shadow rule that generates invisible shadow (Bartosz Dziewoński)
-* ClippableElement: 7 is a better number than 10 (Bartosz Dziewoński)
+
+### Styles
* FieldLayout: In styles, don't assume that label is given (Bartosz Dziewoński)
+* PopupWidget: Remove box-shadow rule that generates invisible shadow (Bartosz Dziewoński)
* TextInputWidget: Set vertical-align: middle, like buttons (Bartosz Dziewoński)
+* MediaWiki theme: Add hover state to listToolGroup (Trevor Parscal)
+* MediaWiki theme: Add radio buttons (Prateek Saxena)
+* MediaWiki theme: Add state transition to radio buttons (Prateek Saxena)
+* MediaWiki theme: Add thematic border to the bottom of toolbars (Bartosz Dziewoński)
+* MediaWiki theme: Copy .theme-oo-ui-outline{Controls,Option}Widget from Apex (Bartosz Dziewoński)
+* MediaWiki theme: Extract @active-color variable (Bartosz Dziewoński)
+* MediaWiki theme: Improve search widget styling (Trevor Parscal)
+* MediaWiki theme: Make button sizes match Apex (Trevor Parscal)
+* MediaWiki theme: Use gray instead of blue for select and highlight (Trevor Parscal)
+* MediaWiki theme: checkbox: Fix states according to spec (Prateek Saxena)
+
+### Code
+* Account for <html> rather than <body> being the scrollable root in Chrome (Bartosz Dziewoński)
+* ClippableElement: 7 is a better number than 10 (Bartosz Dziewoński)
+* Don't set line-height of unset button labels (Bartosz Dziewoński)
* FieldLayout: Synchronise PHP with JS (Bartosz Dziewoński)
* FieldLayout: Use <label> for this.$body, not this.$element (Bartosz Dziewoński)
-* Account for <html> rather than <body> being the scrollable root in Chrome (Bartosz Dziewoński)
+* Fix primary button description text (Niklas Laxström)
* GridLayout: Don't round to 1% (Bartosz Dziewoński)
+* Kill the escape keydown event after handling a window close (Ed Sanders)
+* RadioInputWidget: Remove documentation lies (Bartosz Dziewoński)
+* Temporarily remove position:absolute on body when resizing (Ed Sanders)
+* build: Use String#slice instead of discouraged String#substr (Timo Tijhof)
+* testsuitegenerator: Actually filter out non-unique combinations (Bartosz Dziewoński)
* README.md: Drop localisation update auto-commits from release notes (James D. Forrester)
* README.md: Point to Phabricator, not Bugzilla (James D. Forrester)
## v0.4.0 / 2014-12-05
+### Breaking changes
* [BREAKING CHANGE] Remove deprecated Element#onDOMEvent and #offDOMEvent (Bartosz Dziewoński)
* [BREAKING CHANGE] Make a number of Element getters static (Bartosz Dziewoński)
* [BREAKING CHANGE] Rename BookletLayout#getPageName → #getCurrentPageName (Bartosz Dziewoński)
-* demo: Don't put buttons in a FieldsetLayout without FieldLayouts around them (Bartosz Dziewoński)
+
+### Features
* IconElement: Add missing #getIconTitle (Bartosz Dziewoński)
-* SelectWidget: Rewrite #getRelativeSelectableItem (Bartosz Dziewoński)
+
+### Styles
* Follow-up I859ff276e: Add cursor files to repo (Trevor Parscal)
+### Code
+* SelectWidget: Rewrite #getRelativeSelectableItem (Bartosz Dziewoński)
+* demo: Don't put buttons in a FieldsetLayout without FieldLayouts around them (Bartosz Dziewoński)
+
## v0.3.0 / 2014-12-04
+### Breaking changes
* [BREAKING CHANGE] ButtonWidget: Don't default 'target' to 'blank' (Bartosz Dziewoński)
+
+### Features
* InputWidget: Update DOM value before firing 'change' event (Bartosz Dziewoński)
-* TextInputWidget: Reuse a single clone instead of appending and removing new ones (Prateek Saxena)
-* build: Have grunt watch run 'quick-build' instead of 'build' (Prateek Saxena)
-* MediaWiki Theme: Reduce indentation in theme-oo-ui-checkboxInputWidget (Prateek Saxena)
+
+### Styles
+* MediaWiki theme: Reduce indentation in theme-oo-ui-checkboxInputWidget (Prateek Saxena)
+
+### Code
* Adding DraggableGroupElement and DraggableElement mixins (Moriel Schottlender)
* Remove window even if closing promise rejects (Ed Sanders)
+* TextInputWidget: Reuse a single clone instead of appending and removing new ones (Prateek Saxena)
* Fix lies in documentation (Trevor Parscal)
+* build: Have grunt watch run 'quick-build' instead of 'build' (Prateek Saxena)
## v0.2.4 / 2014-12-02
+### Features
+* MessageDialog: Fit actions again when the dialog is resized (Bartosz Dziewoński)
+* Window: Avoid height flickering when resizing dialogs (Bartosz Dziewoński)
+
+### Code
* TextInputWidget: Use .css( propertyName, value ) instead of .css( properties) for single property (Prateek Saxena)
* TextInputWidget: Stop adjustSize if the value of the textarea is the same (Prateek Saxena)
-* Window: Avoid height flickering when resizing dialogs (Bartosz Dziewoński)
-* MessageDialog: Fit actions again when the dialog is resized (Bartosz Dziewoński)
## v0.2.3 / 2014-11-26
+### Features
+* BookletLayout: Make #focus not crash when there are zero pages or when there is no outline (Roan Kattouw)
* Dialog: Only handle escape events when open (Alex Monk)
* Pass original event with TextInputWidget#enter (Ed Sanders)
-* Add missing documentation to ToolFactory (Ed Sanders)
-* BookletLayout: Make #focus not crash when there are zero pages or when there is no outline (Roan Kattouw)
-* Window: Disable transitions when changing window height to calculate content height (Bartosz Dziewoński)
* MessageDialog: Add Firefox hack for scrollbars when sizing dialogs (Bartosz Dziewoński)
+* MessageDialog: Actually correctly calculate and set height (Bartosz Dziewoński)
+* Window: Disable transitions when changing window height to calculate content height (Bartosz Dziewoński)
+
+### Code
+* Add missing documentation to ToolFactory (Ed Sanders)
* Fix RadioOptionWidget demos (Trevor Parscal)
* RadioOptionWidget: Remove lies from documentation (Trevor Parscal)
* RadioOptionWidget: Increase rule specificity to match OptionWidget (Bartosz Dziewoński)
-* MessageDialog: Actually correctly calculate and set height (Bartosz Dziewoński)
## v0.2.2 / 2014-11-25
-* LabelWidget: Add missing documentation for input configuration option (Ed Sanders)
+### Features
* MessageDialog: Fit actions after updating window size, not before (Bartosz Dziewoński)
-* MessageDialog: Use the right superclass (Bartosz Dziewoński)
* ProcessDialog, MessageDialog: Support iconed actions (Bartosz Dziewoński)
+
+### Styles
* Remove padding from undecorated option widgets (Ed Sanders)
+
+### Code
+* LabelWidget: Add missing documentation for input configuration option (Ed Sanders)
+* MessageDialog: Use the right superclass (Bartosz Dziewoński)
* build: Add .npmignore (Timo Tijhof)
## v0.2.1 / 2014-11-24
-* Start the window opening transition before ready, not after (Roan Kattouw)
+
+### Features
* Add focus method to BookletLayout (Roan Kattouw)
-* Add missing History.md file now we're a proper repo (James D. Forrester)
-* README.md: Update introduction, badges, advice (James D. Forrester)
+* Start the window opening transition before ready, not after (Roan Kattouw)
+
+### Code
* LabelElement: Kill inline styles (Bartosz Dziewoński)
+* Add missing History.md file now we're a proper repo (James D. Forrester)
+* readme: Update introduction, badges, advice (James D. Forrester)
* composer: Rename package to 'oojs-ui' and require php 5.3.3 (Timo Tijhof)
## v0.2.0 / 2014-11-17
diff --git a/vendor/oojs/oojs-ui/LICENSE-MIT b/vendor/oojs/oojs-ui/LICENSE-MIT
index 1eef0125..d3b0f35e 100644
--- a/vendor/oojs/oojs-ui/LICENSE-MIT
+++ b/vendor/oojs/oojs-ui/LICENSE-MIT
@@ -1,4 +1,4 @@
-Copyright 2011-2015 OOjs Team and other contributors.
+Copyright 2011-2015 OOjs UI Team and other contributors.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
diff --git a/vendor/oojs/oojs-ui/README.md b/vendor/oojs/oojs-ui/README.md
index e537752e..0c0e427a 100644
--- a/vendor/oojs/oojs-ui/README.md
+++ b/vendor/oojs/oojs-ui/README.md
@@ -23,6 +23,8 @@ If you don't want to use npm, you can:
1. You can now copy the distribution files from the dist directory into your project.
+1. You can see a suite of demos in `/demos` by executing:<br/>`$ npm run-script demos`
+
Versioning
----------
@@ -52,14 +54,20 @@ $ git remote update
$ git checkout -B release -t origin/master
# Ensure tests pass
-$ npm install && npm test
+$ npm install && composer update && npm test
# Avoid using "npm version patch" because that creates
# both a commit and a tag, and we shouldn't tag until after
# the commit is merged.
# Update release notes
-# Copy the resulting list into a new section on History.md
+# Copy the resulting list into a new section at the top of History.md and edit
+# into five sub-sections, in order:
+# * Breaking changes
+# * Deprecations
+# * Features
+# * Styles
+# * Code
$ git log --format='* %s (%aN)' --no-merges --reverse v$(node -e 'console.log(require("./package.json").version);')...HEAD | grep -v "Localisation updates from" | sort
$ edit History.md
diff --git a/vendor/oojs/oojs-ui/bin/docparser.rb b/vendor/oojs/oojs-ui/bin/docparser.rb
index 9f58549b..64bbf81e 100644
--- a/vendor/oojs/oojs-ui/bin/docparser.rb
+++ b/vendor/oojs/oojs-ui/bin/docparser.rb
@@ -1,6 +1,12 @@
require 'pp'
require 'json'
+$bad_input = false
+def bad_input file, text
+ $bad_input = true
+ $stderr.puts "#{file}: unrecognized input: #{text}"
+end
+
def parse_dir dirname
Dir.entries(dirname).map{|filename|
if filename == '.' || filename == '..'
@@ -63,13 +69,13 @@ def parse_file filename
ignore = false
comment, code_line = d.split '*/'
- comment.split("\n").each{|c|
- next if c.strip == '/**'
- c.sub!(/^[ \t]*\*[ \t]?/, '') # strip leading *
+ comment.split("\n").each{|comment_line|
+ next if comment_line.strip == '/**'
+ comment_line.sub!(/^[ \t]*\*[ \t]?/, '') # strip leading '*' and whitespace
- m = c.match(/^@(\w+)[ \t]*(.*)/)
- unless m
- previous_item[:description] << c + "\n"
+ m = comment_line.match(/^@(\w+)[ \t]*(.*)/)
+ if !m
+ previous_item[:description] << comment_line + "\n"
next
end
@@ -93,11 +99,13 @@ def parse_file filename
when 'property', 'var'
kind = :property
m = content.match(/^\{?(.+?)\}?( .+)?$/)
- if m.captures
- type, description = m.captures
- data[:type] = type
- data[:description] = description if description
+ if !m
+ bad_input filename, comment_line
+ next
end
+ type, description = m.captures
+ data[:type] = type
+ data[:description] = description if description
when 'event'
kind = :event
data[:name] = content.strip
@@ -124,20 +132,28 @@ def parse_file filename
end
end
when 'cfg' # JS only
- type, name, default, description = content.match(/^\{(.+?)\} \[?([\w.$]+?)(?:=(.+?))?\]?( .+)?$/).captures
+ m = content.match(/^\{(.+?)\} \[?([\w.$]+?)(?:=(.+?))?\]?( .+)?$/)
+ if !m
+ bad_input filename, comment_line
+ next
+ end
+ type, name, default, description = m.captures
data[:config] << {name: name, type: cleanup_class_name(type), description: description || '', default: default}
previous_item = data[:config][-1]
when 'return'
case filetype
when :js
- type, description = content.match(/^\{(.+?)\}( .+)?$/).captures
- data[:return] = {type: cleanup_class_name(type), description: description || ''}
- previous_item = data[:return]
+ m = content.match(/^\{(.+?)\}( .+)?$/)
when :php
- type, description = content.match(/^(\S+)( .+)?$/).captures
- data[:return] = {type: cleanup_class_name(type), description: description || ''}
- previous_item = data[:return]
+ m = content.match(/^(\S+)( .+)?$/)
+ end
+ if !m
+ bad_input filename, comment_line
+ next
end
+ type, description = m.captures
+ data[:return] = {type: cleanup_class_name(type), description: description || ''}
+ previous_item = data[:return]
when 'private'
data[:visibility] = :private
when 'protected'
@@ -153,7 +169,8 @@ def parse_file filename
'see'
# skip
else
- fail "unrecognized keyword: #{keyword}"
+ bad_input filename, comment_line
+ next
end
}
@@ -163,6 +180,10 @@ def parse_file filename
case filetype
when :js
m = code_line.match(/(?:(static|prototype)\.)?(\w+) =/)
+ if !m
+ bad_input filename, code_line.strip
+ next
+ end
kind_, name = m.captures
data[:static] = true if kind_ == 'static'
kind = {'static' => :property, 'prototype' => :method}[ kind_.strip ] if kind_ && !kind
@@ -175,6 +196,10 @@ def parse_file filename
(\w+)
(?:\sextends\s(\w+))?
/x)
+ if !m
+ bad_input filename, code_line.strip
+ next
+ end
visibility, static, kind_, name, parent = m.captures
kind = {'$' => :property, 'function' => :method, 'class' => :class}[ kind_.strip ]
data[:visibility] = {'private' => :private, 'protected' => :protected, 'public' => :public}[ visibility ] || :public
@@ -223,10 +248,15 @@ end
def parse_any_path path
if File.directory? path
- parse_dir path
+ result = parse_dir path
else
- parse_file path
+ result = parse_file path
+ end
+ if $bad_input
+ $stderr.puts 'Unrecognized inputs encountered, stopping.'
+ exit 1
end
+ result
end
if __FILE__ == $PROGRAM_NAME
diff --git a/vendor/oojs/oojs-ui/bin/generate-JSPHP-for-karma.php b/vendor/oojs/oojs-ui/bin/generate-JSPHP-for-karma.php
index 445da65c..2cee51e6 100644
--- a/vendor/oojs/oojs-ui/bin/generate-JSPHP-for-karma.php
+++ b/vendor/oojs/oojs-ui/bin/generate-JSPHP-for-karma.php
@@ -1,26 +1,20 @@
<?php
-// Quick and dirty autoloader to make it possible to run without Composer.
-spl_autoload_register( function ( $class ) {
- $class = preg_replace( '/^OOUI\\\\/', '', $class );
- foreach ( array( 'elements', 'layouts', 'themes', 'widgets', '.' ) as $dir ) {
- $path = "../php/$dir/$class.php";
- if ( file_exists( $path ) ) {
- require_once $path;
- return;
- }
- }
-} );
+require_once __DIR__ . '/../vendor/autoload.php';
-$testSuiteJSON = file_get_contents( 'JSPHP-suite.json' );
+$testSuiteJSON = file_get_contents( __DIR__ . '/../tests/JSPHP-suite.json' );
$testSuite = json_decode( $testSuiteJSON, true );
$testSuiteOutput = array();
+// @codingStandardsIgnoreStart
function new_OOUI( $class, $config = array() ) {
+ // @codingStandardsIgnoreEnd
$class = "OOUI\\" . $class;
return new $class( $config );
}
+// @codingStandardsIgnoreStart
function unstub( &$value ) {
+ // @codingStandardsIgnoreEnd
if ( is_string( $value ) && substr( $value, 0, 13 ) === '_placeholder_' ) {
$value = json_decode( substr( $value, 13 ), true );
array_walk_recursive( $value['config'], 'unstub' );
@@ -47,4 +41,4 @@ $testSuiteOutputJSON = json_encode( $testSuiteOutput, JSON_PRETTY_PRINT );
echo "var testSuiteConfigs = $testSuiteJSON;\n\n";
echo "var testSuitePHPOutput = $testSuiteOutputJSON;\n\n";
-echo file_get_contents( 'JSPHP.test.karma.js' );
+echo file_get_contents( __DIR__ . '/../tests/JSPHP.test.karma.js' );
diff --git a/vendor/oojs/oojs-ui/bin/testsuitegenerator.rb b/vendor/oojs/oojs-ui/bin/testsuitegenerator.rb
index 28ab1a85..48ba012c 100644
--- a/vendor/oojs/oojs-ui/bin/testsuitegenerator.rb
+++ b/vendor/oojs/oojs-ui/bin/testsuitegenerator.rb
@@ -18,7 +18,7 @@ else
.reject{|c| c[:abstract] } # can't test abstract classes
.reject{|c| !c[:parent] || c[:parent] == 'ElementMixin' || c[:parent] == 'Theme' } # can't test abstract
.reject{|c| %w[Element Widget Layout Theme].include? c[:name] } # no toplevel
- .reject{|c| c[:name] == 'DropdownInputWidget' } # different PHP and JS implementations
+ .reject{|c| %w[DropdownInputWidget RadioSelectInputWidget].include? c[:name] } # different PHP and JS implementations
# values to test for each type
expandos = {
@@ -31,10 +31,13 @@ else
# values to test for names
sensible_values = {
'href' => ['http://example.com/'],
- ['TextInputWidget', 'type'] => %w[text password],
- ['ButtonInputWidget', 'type'] => %w[button input],
+ ['TextInputWidget', 'type'] => %w[text password foo],
+ ['ButtonInputWidget', 'type'] => %w[button submit foo],
['FieldLayout', 'help'] => true, # different PHP and JS implementations
+ ['ActionFieldLayout', 'help'] => true, # different PHP and JS implementations
['FieldsetLayout', 'help'] => true, # different PHP and JS implementations
+ ['FieldLayout', 'errors'] => expandos['string'].map{|v| [v] }, # treat as string[]
+ ['FieldLayout', 'notices'] => expandos['string'].map{|v| [v] }, # treat as string[]
'type' => %w[text button],
'method' => %w[GET POST],
'action' => [],
@@ -44,6 +47,7 @@ else
'name' => true,
'autofocus' => true, # usually makes no sense in JS
'tabIndex' => [-1, 0, 100],
+ 'maxLength' => [100],
'icon' => ['picture'],
'indicator' => ['down'],
'flags' => %w[constructive],
@@ -140,7 +144,9 @@ else
end
end
+ $stderr.puts "Generated #{tests.length} test cases."
tests = tests.group_by{|t| t[:class] }
+ $stderr.puts tests.map{|class_name, class_tests| "* #{class_name}: #{class_tests.length}" }
puts JSON.pretty_generate tests
end
diff --git a/vendor/oojs/oojs-ui/build/banner.txt b/vendor/oojs/oojs-ui/build/banner.txt
deleted file mode 100644
index f6926e8f..00000000
--- a/vendor/oojs/oojs-ui/build/banner.txt
+++ /dev/null
@@ -1,10 +0,0 @@
-/*!
- * OOjs UI v<%= pkg.version %>
- * https://www.mediawiki.org/wiki/OOjs_UI
- *
- * Copyright 2011–<%= grunt.template.today("yyyy") %> OOjs Team and other contributors.
- * Released under the MIT license
- * http://oojs.mit-license.org
- *
- * Date: <%= grunt.template.today("isoUtcDateTime") %>
- */
diff --git a/vendor/oojs/oojs-ui/build/modules.json b/vendor/oojs/oojs-ui/build/modules.json
deleted file mode 100644
index 5aa773ff..00000000
--- a/vendor/oojs/oojs-ui/build/modules.json
+++ /dev/null
@@ -1,240 +0,0 @@
-{
- "oojs-ui": {
- "scripts": [
- "src/intro.js.txt",
- "src/core.js",
-
- "src/elements/PendingElement.js",
-
- "src/ActionSet.js",
- "src/Element.js",
- "src/Layout.js",
- "src/Widget.js",
- "src/Window.js",
- "src/Dialog.js",
- "src/WindowManager.js",
- "src/Error.js",
- "src/HtmlSnippet.js",
- "src/Process.js",
- "src/ToolFactory.js",
- "src/ToolGroupFactory.js",
- "src/Theme.js",
-
- "src/elements/TabIndexedElement.js",
- "src/elements/ButtonElement.js",
- "src/elements/GroupElement.js",
- "src/elements/DraggableElement.js",
- "src/elements/DraggableGroupElement.js",
- "src/elements/IconElement.js",
- "src/elements/IndicatorElement.js",
- "src/elements/LabelElement.js",
- "src/elements/LookupElement.js",
- "src/elements/PopupElement.js",
- "src/elements/FlaggedElement.js",
- "src/elements/TitledElement.js",
- "src/elements/ClippableElement.js",
-
- "src/Tool.js",
- "src/Toolbar.js",
- "src/ToolGroup.js",
-
- "src/dialogs/MessageDialog.js",
- "src/dialogs/ProcessDialog.js",
-
- "src/layouts/FieldLayout.js",
- "src/layouts/ActionFieldLayout.js",
- "src/layouts/FieldsetLayout.js",
- "src/layouts/FormLayout.js",
- "src/layouts/MenuLayout.js",
- "src/layouts/BookletLayout.js",
- "src/layouts/IndexLayout.js",
- "src/layouts/PanelLayout.js",
- "src/layouts/CardLayout.js",
- "src/layouts/PageLayout.js",
- "src/layouts/StackLayout.js",
-
- "src/toolgroups/BarToolGroup.js",
- "src/toolgroups/PopupToolGroup.js",
- "src/toolgroups/ListToolGroup.js",
- "src/toolgroups/MenuToolGroup.js",
-
- "src/tools/PopupTool.js",
- "src/tools/ToolGroupTool.js",
-
- "src/widgets/GroupWidget.js",
- "src/widgets/ItemWidget.js",
- "src/widgets/OutlineControlsWidget.js",
- "src/widgets/ToggleWidget.js",
-
- "src/widgets/ButtonGroupWidget.js",
- "src/widgets/ButtonWidget.js",
- "src/widgets/ActionWidget.js",
- "src/widgets/PopupButtonWidget.js",
- "src/widgets/ToggleButtonWidget.js",
- "src/widgets/DropdownWidget.js",
- "src/widgets/IconWidget.js",
- "src/widgets/IndicatorWidget.js",
- "src/widgets/InputWidget.js",
- "src/widgets/ButtonInputWidget.js",
- "src/widgets/CheckboxInputWidget.js",
- "src/widgets/DropdownInputWidget.js",
- "src/widgets/RadioInputWidget.js",
- "src/widgets/TextInputWidget.js",
- "src/widgets/ComboBoxWidget.js",
- "src/widgets/LabelWidget.js",
- "src/widgets/OptionWidget.js",
- "src/widgets/DecoratedOptionWidget.js",
- "src/widgets/ButtonOptionWidget.js",
- "src/widgets/RadioOptionWidget.js",
- "src/widgets/MenuOptionWidget.js",
- "src/widgets/MenuSectionOptionWidget.js",
- "src/widgets/OutlineOptionWidget.js",
- "src/widgets/TabOptionWidget.js",
- "src/widgets/PopupWidget.js",
- "src/widgets/ProgressBarWidget.js",
- "src/widgets/SearchWidget.js",
- "src/widgets/SelectWidget.js",
- "src/widgets/ButtonSelectWidget.js",
- "src/widgets/RadioSelectWidget.js",
- "src/widgets/MenuSelectWidget.js",
- "src/widgets/TextInputMenuSelectWidget.js",
- "src/widgets/OutlineSelectWidget.js",
- "src/widgets/TabSelectWidget.js",
- "src/widgets/ToggleSwitchWidget.js",
-
- "src/outro.js.txt"
- ]
- },
- "oojs-ui-apex": {
- "scripts": [
- "src/themes/apex/ApexTheme.js"
- ],
- "styles": [
- "src/themes/apex/core.less",
- "src/themes/apex/icons.json",
- "src/themes/apex/indicators.json",
- "src/themes/apex/textures.json"
- ]
- },
- "oojs-ui-apex-noimages": {
- "styles": [
- "src/themes/apex/core.less"
- ]
- },
- "oojs-ui-apex-icons-movement": {
- "styles": [
- "src/themes/apex/icons-movement.json"
- ]
- },
- "oojs-ui-apex-icons-moderation": {
- "styles": [
- "src/themes/apex/icons-moderation.json"
- ]
- },
- "oojs-ui-apex-icons-editing-core": {
- "styles": [
- "src/themes/apex/icons-editing-core.json"
- ]
- },
- "oojs-ui-apex-icons-editing-styling": {
- "styles": [
- "src/themes/apex/icons-editing-styling.json"
- ]
- },
- "oojs-ui-apex-icons-editing-list": {
- "styles": [
- "src/themes/apex/icons-editing-list.json"
- ]
- },
- "oojs-ui-apex-icons-editing-advanced": {
- "styles": [
- "src/themes/apex/icons-editing-advanced.json"
- ]
- },
- "oojs-ui-mediawiki": {
- "scripts": [
- "src/themes/mediawiki/MediaWikiTheme.js"
- ],
- "styles": [
- "src/themes/mediawiki/core.less",
- "src/themes/mediawiki/icons.json",
- "src/themes/mediawiki/indicators.json",
- "src/themes/mediawiki/textures.json"
- ]
- },
- "oojs-ui-mediawiki-noimages": {
- "styles": [
- "src/themes/mediawiki/core.less"
- ]
- },
- "oojs-ui-mediawiki-icons-movement": {
- "styles": [
- "src/themes/mediawiki/icons-movement.json"
- ]
- },
- "oojs-ui-mediawiki-icons-content": {
- "styles": [
- "src/themes/mediawiki/icons-content.json"
- ]
- },
- "oojs-ui-mediawiki-icons-alerts": {
- "styles": [
- "src/themes/mediawiki/icons-alerts.json"
- ]
- },
- "oojs-ui-mediawiki-icons-interactions": {
- "styles": [
- "src/themes/mediawiki/icons-interactions.json"
- ]
- },
- "oojs-ui-mediawiki-icons-moderation": {
- "styles": [
- "src/themes/mediawiki/icons-moderation.json"
- ]
- },
- "oojs-ui-mediawiki-icons-editing-core": {
- "styles": [
- "src/themes/mediawiki/icons-editing-core.json"
- ]
- },
- "oojs-ui-mediawiki-icons-editing-styling": {
- "styles": [
- "src/themes/mediawiki/icons-editing-styling.json"
- ]
- },
- "oojs-ui-mediawiki-icons-editing-list": {
- "styles": [
- "src/themes/mediawiki/icons-editing-list.json"
- ]
- },
- "oojs-ui-mediawiki-icons-editing-advanced": {
- "styles": [
- "src/themes/mediawiki/icons-editing-advanced.json"
- ]
- },
- "oojs-ui-mediawiki-icons-media": {
- "styles": [
- "src/themes/mediawiki/icons-media.json"
- ]
- },
- "oojs-ui-mediawiki-icons-location": {
- "styles": [
- "src/themes/mediawiki/icons-location.json"
- ]
- },
- "oojs-ui-mediawiki-icons-user": {
- "styles": [
- "src/themes/mediawiki/icons-user.json"
- ]
- },
- "oojs-ui-mediawiki-icons-layout": {
- "styles": [
- "src/themes/mediawiki/icons-layout.json"
- ]
- },
- "oojs-ui-mediawiki-icons-wikimedia": {
- "styles": [
- "src/themes/mediawiki/icons-wikimedia.json"
- ]
- }
-}
diff --git a/vendor/oojs/oojs-ui/build/tasks/colorize-svg.js b/vendor/oojs/oojs-ui/build/tasks/colorize-svg.js
deleted file mode 100644
index 0eb421f3..00000000
--- a/vendor/oojs/oojs-ui/build/tasks/colorize-svg.js
+++ /dev/null
@@ -1,538 +0,0 @@
-/*!
- * Colorize SVG files.
- *
- * The task currently doesn't use the standard file specifying methods with this.filesSrc.
- * An option to do it may be added in the future.
- */
-
-/*jshint node:true */
-
-var Q = require( 'q' ),
- path = require( 'path' ),
- asyncTask = require( 'grunt-promise-q' );
-
-module.exports = function ( grunt ) {
-
- asyncTask.registerMulti(
- grunt,
- 'colorizeSvg',
- 'Generate colored variants of SVG images',
- function () {
- var
- data = this.data,
- options = this.options(),
- source = new Source(
- data.srcDir,
- options.images,
- options.variants,
- {
- intro: options.intro,
- prefix: options.prefix,
- cssPrependPath: data.cssPrependPath,
- selectorWithoutVariant: options.selectorWithoutVariant || options.selector,
- selectorWithVariant: options.selectorWithVariant || options.selector
- }
- );
-
- return source.getImageList().generate(
- new Destination(
- data.destDir,
- data.destLessFile || {
- ltr: path.join( data.destDir, 'images.less' ),
- rtl: path.join( data.destDir, 'images.rtl.less' )
- }
- )
- ).then( function ( totalFiles ) {
- grunt.log.writeln( 'Created ' + totalFiles + ' SVG files.' );
- } );
- }
- );
-
- /* Classes */
-
- /**
- * Image source.
- *
- * @class
- *
- * @constructor
- * @param {string} path Directory containing source images
- * @param {Object} images Lists of image configurations
- * @param {Object} [variants] List of variant configurations, keyed by variant name
- * @param {Object} [options] Additional options
- */
- function Source( path, images, variants, options ) {
- this.path = path;
- this.images = images;
- this.variants = variants || {};
- this.options = options || {};
- }
-
- /**
- * Get the path to source images directory.
- *
- * @return {string} Path
- */
- Source.prototype.getPath = function () {
- return this.path;
- };
-
- /**
- * Get image list.
- *
- * @return ImageList Image list
- */
- Source.prototype.getImageList = function () {
- return new ImageList(
- this.path,
- new VariantList( this.variants ),
- this.options,
- this.images
- );
- };
-
- /**
- * Destination for images.
- *
- * @class
- *
- * @constructor
- * @param {string} path Image path
- * @param {Object} stylesheetPath Stylesheet file path
- * @param {string} stylesheetPath.ltr Stylesheet file path, left-to-right
- * @param {string} stylesheetPath.rtl Stylesheet file path, right-to-left
- */
- function Destination( path, stylesheetPath ) {
- this.path = path;
- this.stylesheetPath = stylesheetPath;
- }
-
- /**
- * Get image destination directory.
- *
- * @return {string} Destination path
- */
- Destination.prototype.getPath = function () {
- return this.path;
- };
-
- /**
- * Get path to file of generated Less stylesheet.
- *
- * @param {string} textDirection Text direction to get stylesheet path for, 'ltr' or 'rtl'
- * @return {string} Destination path
- */
- Destination.prototype.getStylesheetPath = function ( textDirection ) {
- return this.stylesheetPath[ textDirection ];
- };
-
- /**
- * Source image.
- *
- * @class
- *
- * @constructor
- * @param {Object} list Image list
- * @param {string} name Image name
- * @param {Object} data Image options
- */
- function Image( list, name, data ) {
- this.list = list;
- this.name = name;
- this.file = data.file;
- this.variantNames = ( data.variants || [] )
- .concat( this.list.getVariants().getGlobalVariantNames() )
- .filter( function ( variant, index, variants ) {
- return variants.indexOf( variant ) === index;
- } );
- }
-
- /**
- * Generate CSS and images.
- *
- * @param {Destination} destination Destination
- * @return {Q.Promise}
- */
- Image.prototype.generate = function ( destination ) {
- // TODO Make configurable
- function getDeclarations( primary ) {
- // If 'primary' is not a SVG file, 'fallback' and 'primary' are intentionally the same
- var fallback = primary.replace( /\.svg$/, '.png' );
- return '.oo-ui-background-image-svg2(' +
- '\'' + ( cssPrependPath || '' ) + primary + '\', ' +
- '\'' + ( cssPrependPath || '' ) + fallback + '\'' +
- ')';
- }
- function variantizeFileName( fileName, variantName ) {
- if ( variantName ) {
- return fileName.replace( /\.(\w+)$/, '-' + variantName + '.$1' );
- }
- return fileName;
- }
-
- var selector, declarations, direction, lang, langSelector,
- deferred = Q.defer(),
- file = typeof this.file === 'string' ?
- { ltr: this.file, rtl: this.file } :
- { ltr: this.file.ltr || this.file.default, rtl: this.file.rtl || this.file.default },
- moreLangs = this.file.lang || {},
- name = this.name,
- sourcePath = this.list.getPath(),
- destinationPath = destination.getPath(),
- variants = this.list.getVariants(),
- cssClassPrefix = this.list.getCssClassPrefix(),
- cssSelectors = this.list.getCssSelectors(),
- cssPrependPath = this.list.options.cssPrependPath,
- originalSvg = {},
- rules = {
- ltr: [],
- rtl: []
- },
- files = {},
- uncolorizableImages = [],
- unknownVariants = [];
-
- // Expand shorthands:
- // { "en,de,fr": "foo.svg" } → { "en": "foo.svg", "de": "foo.svg", "fr": "foo.svg" }
- moreLangs = Object.keys( moreLangs ).reduce( function ( langs, langList ) {
- langList.split( ',' ).forEach( function ( lang ) {
- langs[ lang ] = moreLangs[ langList ];
- } );
- return langs;
- }, {} );
-
- // Original
- selector = cssSelectors.selectorWithoutVariant
- .replace( /{prefix}/g, cssClassPrefix )
- .replace( /{name}/g, name )
- .replace( /{variant}/g, '' );
-
- for ( direction in file ) {
- declarations = getDeclarations( file[ direction ] );
- rules[ direction ].push( selector + ' {\n\t' + declarations + '\n}' );
-
- originalSvg[ direction ] = grunt.file.read(
- path.join( sourcePath, file[ direction ] )
- );
- files[ path.join( destinationPath, file[ direction ] ) ] = originalSvg[ direction ];
-
- for ( lang in moreLangs ) {
- // This will not work for selectors ending in a pseudo-element.
- langSelector = ':lang(' + lang + ')';
- declarations = getDeclarations( moreLangs[ lang ] );
- rules[ direction ].push(
- '/* @noflip */\n' +
- selector.replace( /,|$/g, langSelector + '$&' ) +
- ' {\n\t' + declarations + '\n}'
- );
-
- originalSvg[ 'lang-' + lang ] = grunt.file.read(
- path.join( sourcePath, moreLangs[ lang ] )
- );
- files[ path.join( destinationPath, moreLangs[ lang ] ) ] = originalSvg[ 'lang-' + lang ];
- }
- }
-
- // Variants
- this.variantNames.forEach( function ( variantName ) {
- var variantSvg, destinationFilePath,
- variant = variants.getVariant( variantName );
-
- if ( variant === undefined ) {
- unknownVariants.push( variantName );
- return;
- }
-
- selector = cssSelectors.selectorWithVariant
- .replace( /{prefix}/g, cssClassPrefix )
- .replace( /{name}/g, name )
- .replace( /{variant}/g, variantName );
-
- for ( direction in file ) {
- declarations = getDeclarations( variantizeFileName( file[ direction ], variantName ) );
- rules[ direction ].push( selector + ' {\n\t' + declarations + '\n}' );
-
- // TODO: Do this in a safer and more clever way
- variantSvg = originalSvg[ direction ].replace(
- /<svg[^>]*>/, '$&<style>* { fill: ' + variant.getColor() + ' }</style>'
- );
-
- if ( originalSvg[ direction ] === variantSvg ) {
- uncolorizableImages.push( file[ direction ] );
- continue;
- }
-
- destinationFilePath = path.join(
- destinationPath,
- variantizeFileName( file[ direction ], variantName )
- );
- files[ destinationFilePath ] = variantSvg;
-
- for ( lang in moreLangs ) {
- langSelector = ':lang(' + lang + ')';
- declarations = getDeclarations( variantizeFileName( moreLangs[ lang ], variantName ) );
- rules[ direction ].push(
- '/* @noflip */\n' +
- selector.replace( /,|$/g, langSelector + '$&' ) +
- ' {\n\t' + declarations + '\n}'
- );
-
- variantSvg = originalSvg[ 'lang-' + lang ].replace(
- /<svg[^>]*>/, '$&<style>* { fill: ' + variant.getColor() + ' }</style>'
- );
-
- if ( originalSvg[ 'lang-' + lang ] === variantSvg ) {
- uncolorizableImages.push( moreLangs[ lang ] );
- continue;
- }
-
- destinationFilePath = path.join(
- destinationPath,
- variantizeFileName( moreLangs[ lang ], variantName )
- );
- files[ destinationFilePath ] = variantSvg;
- }
- }
- } );
-
- if ( unknownVariants.length || uncolorizableImages.length ) {
- if ( unknownVariants.length ) {
- grunt.log.error(
- unknownVariants.length +
- ' unknown variants requested: ' +
- unknownVariants.join( ', ' )
- );
- }
- if ( uncolorizableImages.length ) {
- grunt.log.error(
- uncolorizableImages.length +
- ' invalid source images: ' +
- uncolorizableImages.join( ', ' )
- );
- }
- deferred.reject( 'Failed to generate some images' );
- } else {
- deferred.resolve( {
- rules: rules,
- files: files
- } );
- }
-
- return deferred.promise;
- };
-
- /**
- * List of source images.
- *
- * @class
- *
- * @constructor
- * @param {string} path Images path
- * @param {VariantList} variants Variants list
- * @param {Object} options Additional options
- * @param {Object} data List of image configurations keyed by name
- */
- function ImageList( path, variants, options, data ) {
- var key;
-
- this.list = {};
- this.path = path;
- this.variants = variants;
- this.options = options;
-
- for ( key in data ) {
- this.list[ key ] = new Image( this, key, data[ key ] );
- }
- }
-
- /**
- * Get image path.
- *
- * @return {string} Image path
- */
- ImageList.prototype.getPath = function () {
- return this.path;
- };
-
- /**
- * Get image variants.
- *
- * @return {VariantsList} Image variants
- */
- ImageList.prototype.getVariants = function () {
- return this.variants;
- };
-
- /**
- * Get CSS class prefix.
- *
- * @return {string} CSS class prefix
- */
- ImageList.prototype.getCssClassPrefix = function () {
- return this.options.prefix || '';
- };
-
- /**
- * Get CSS selectors.
- *
- * @return {Object.<string, string>} CSS selectors
- */
- ImageList.prototype.getCssSelectors = function () {
- return {
- selectorWithoutVariant: this.options.selectorWithoutVariant || '.{prefix}-{name}',
- selectorWithVariant: this.options.selectorWithVariant || '.{prefix}-{name}-{variant}'
- };
- };
-
- /**
- * Get CSS file intro.
- *
- * @return {string} CSS file intro
- */
- ImageList.prototype.getCssIntro = function () {
- return this.options.intro || '';
- };
-
- /**
- * Get number of images in list.
- *
- * @return {number} List length
- */
- ImageList.prototype.getLength = function () {
- return Object.keys( this.list ).length;
- };
-
- /**
- * Generate images and CSS.
- *
- * @param {Destination} destination Destination
- * @return {Q.Promise} Promise resolved with number of generated SVG files
- */
- ImageList.prototype.generate = function ( destination ) {
- var list = this.list,
- intro = this.getCssIntro();
- return Q.all( Object.keys( this.list ).map( function ( key ) {
- return list[ key ].generate( destination );
- } ) ).then( function ( data ) {
- var textDirection, stylesheetPath, destinationFilePath, dataFormat;
- dataFormat = {
- files: {},
- rules: {
- ltr: [],
- rtl: []
- }
- };
-
- data = data.reduce( function ( a, b ) {
- for ( destinationFilePath in b.files ) {
- // This de-duplicates the entries, as the same file can be used by many Images
- a.files[ destinationFilePath ] = b.files[ destinationFilePath ];
- }
- a.rules.ltr = a.rules.ltr.concat( b.rules.ltr );
- a.rules.rtl = a.rules.rtl.concat( b.rules.rtl );
- return a;
- }, dataFormat );
-
- for ( textDirection in data.rules ) {
- stylesheetPath = destination.getStylesheetPath( textDirection );
- grunt.file.write(
- stylesheetPath,
- intro + '\n' + data.rules[ textDirection ].join( '\n' )
- );
- grunt.log.writeln( 'Created "' + stylesheetPath + '".' );
- }
- for ( destinationFilePath in data.files ) {
- grunt.file.write( destinationFilePath, data.files[ destinationFilePath ] );
- }
-
- return Object.keys( data.files ).length;
- } );
- };
-
- /**
- * Image variant.
- *
- * @class
- *
- * @constructor
- * @param {VariantList} list Variant list
- * @param {string} name Variant name
- * @param {Object} data Variant options
- */
- function Variant( list, name, data ) {
- // Properties
- this.list = list;
- this.name = name;
- this.color = data.color;
- this.global = data.global;
- }
-
- /**
- * Check if variant is global.
- *
- * @return {boolean} Variant is global
- */
- Variant.prototype.isGlobal = function () {
- return this.global;
- };
-
- /**
- * Get variant color.
- *
- * @return {string} CSS color expression
- */
- Variant.prototype.getColor = function () {
- return this.color;
- };
-
- /**
- * List of variants.
- *
- * @class
- *
- * @constructor
- * @param {Object} list List of variant configurations keyed by name
- */
- function VariantList( data ) {
- var key;
-
- this.list = {};
- this.globals = [];
-
- for ( key in data ) {
- this.list[ key ] = new Variant( this, key, data[ key ] );
- if ( this.list[ key ].isGlobal() ) {
- this.globals.push( key );
- }
- }
- }
-
- /**
- * Get names of global variants.
- *
- * @return {string[]} Global variant names
- */
- VariantList.prototype.getGlobalVariantNames = function () {
- return this.globals;
- };
-
- /**
- * Get variant by name.
- *
- * @param {string} name Variant name
- * @return {Variant|undefined} Variant with matching name, or undefined of none exists.
- */
- VariantList.prototype.getVariant = function ( name ) {
- return this.list[ name ];
- };
-
- /**
- * Get number of variants in list.
- *
- * @return {number} List length
- */
- VariantList.prototype.getLength = function () {
- return Object.keys( this.list ).length;
- };
-
-};
diff --git a/vendor/oojs/oojs-ui/build/tasks/typos.js b/vendor/oojs/oojs-ui/build/tasks/typos.js
deleted file mode 100644
index 6c0bb4ee..00000000
--- a/vendor/oojs/oojs-ui/build/tasks/typos.js
+++ /dev/null
@@ -1,89 +0,0 @@
-/*!
- * Check files from 'src' for typos; fail if any are found.
- */
-
-/*jshint node:true */
-module.exports = function ( grunt ) {
-
- grunt.registerMultiTask( 'typos', function () {
- var typosData, typosCSRegExp, typosCIRegExp, file,
- options = this.options( {
- typos: 'typos.json'
- } ),
- files = this.filesSrc,
- fileCount = files.length,
- typosJSON = grunt.file.read( options.typos ),
- typoCount = 0,
- ok = true;
-
- try {
- typosData = JSON.parse( typosJSON );
- } catch ( e ) {
- grunt.log.error( 'Could not parse ' + options.typos + ': ' + e );
- }
-
- typosData.caseSensitive = typosData.caseSensitive || [];
- typosData.caseInsensitive = typosData.caseInsensitive || [];
-
- typoCount += typosData.caseSensitive.length + typosData.caseInsensitive.length;
-
- function patternMap( typo ) {
- return typo[ 0 ];
- }
-
- if ( typosData.caseSensitive.length ) {
- typosCSRegExp = new RegExp(
- '(' + typosData.caseSensitive.map( patternMap ).join( '|' ) + ')', 'g'
- );
- }
-
- if ( typosData.caseInsensitive.length ) {
- typosCIRegExp = new RegExp(
- '(' + typosData.caseInsensitive.map( patternMap ).join( '|' ) + ')', 'gi'
- );
- }
-
- function findTypo( line, lineNumber, filepath, typos, flags ) {
- // Check each pattern to find the replacement
- typos.forEach( function ( typo ) {
- var replace,
- pattern = new RegExp( typo[ 0 ], flags ),
- matches = line.match( pattern );
-
- if ( matches ) {
- ok = false;
- replace = matches[ 0 ].replace( pattern, typo[ 1 ], flags );
- grunt.log.error(
- 'File "' + filepath + '" contains typo "' + matches[ 0 ] + '" on line ' + lineNumber +
- ', did you mean "' + replace + '"?'
- );
- }
- } );
- }
-
- files.forEach( function ( filepath ) {
- if ( grunt.file.isDir( filepath ) ) {
- fileCount--;
- return;
- }
- file = grunt.file.read( filepath );
- file.split( '\n' ).forEach( function ( line, lineNumber ) {
- // Check for any typos on the line with group expressions
- if ( typosCSRegExp && typosCSRegExp.test( line ) ) {
- findTypo( line, lineNumber, filepath, typosData.caseSensitive, 'g' );
- }
- if ( typosCIRegExp && typosCIRegExp.test( line ) ) {
- findTypo( line, lineNumber, filepath, typosData.caseInsensitive, 'gi' );
- }
- } );
- } );
-
- if ( !ok ) {
- return false;
- }
-
- grunt.log.ok( 'No typos found; ' +
- fileCount + ' file' + ( fileCount !== 1 ? 's' : '' ) + ' checked for ' +
- typoCount + ' typo' + ( typoCount !== 1 ? 's' : '' ) + '.' );
- } );
-};
diff --git a/vendor/oojs/oojs-ui/build/typos.json b/vendor/oojs/oojs-ui/build/typos.json
deleted file mode 100644
index 5916d77e..00000000
--- a/vendor/oojs/oojs-ui/build/typos.json
+++ /dev/null
@@ -1,17 +0,0 @@
-{
- "caseSensitive": [
- [ "@returns", "@return" ]
- ],
- "caseInsensitive": [
- [ "paralell", "parallel" ],
- [ "properites", "properties" ],
- [ "visiblit(ies|y)", "visibilit$1" ],
- [ "movablilties", "movabilities" ],
- [ "inpsect(ors?|ion)", "inspect$1" ],
- [ "\bteh\b", "the" ],
- [ "intialization", "initialization" ],
- [ "durring", "during" ],
- [ "contian", "contain" ],
- [ "occured", "occurred" ]
- ]
-}
diff --git a/vendor/oojs/oojs-ui/composer.json b/vendor/oojs/oojs-ui/composer.json
deleted file mode 100644
index 0907de12..00000000
--- a/vendor/oojs/oojs-ui/composer.json
+++ /dev/null
@@ -1,24 +0,0 @@
-{
- "name": "oojs/oojs-ui",
- "description": "Provides library of common widgets, layouts, and windows.",
- "homepage": "https://www.mediawiki.org/wiki/OOjs_UI",
- "license": "MIT",
- "require": {
- "php": ">=5.3.3"
- },
- "require-dev": {
- "jakub-onderka/php-parallel-lint": "0.8.*",
- "mediawiki/mediawiki-codesniffer": "0.1.0",
- "squizlabs/php_codesniffer": "2.1.*"
- },
- "autoload": {
- "classmap": ["php/"]
- },
- "scripts": {
- "test": [
- "parallel-lint . --exclude vendor",
- "phpcs $PHPCS_ARGS --standard=vendor/mediawiki/mediawiki-codesniffer/MediaWiki --ignore=vendor --extensions=php,php5,inc -v ."
- ]
- }
-}
-
diff --git a/vendor/oojs/oojs-ui/demos/demo.js b/vendor/oojs/oojs-ui/demos/demo.js
index a1d39314..b0ff06d2 100644
--- a/vendor/oojs/oojs-ui/demos/demo.js
+++ b/vendor/oojs/oojs-ui/demos/demo.js
@@ -6,13 +6,12 @@
*/
OO.ui.Demo = function OoUiDemo() {
// Parent
- OO.ui.Demo.super.call( this );
+ OO.ui.Demo.parent.call( this );
// Normalization
this.normalizeHash();
// Properties
- this.stylesheetLinks = this.getStylesheetLinks();
this.mode = this.getCurrentMode();
this.$menu = $( '<div>' );
this.pageDropdown = new OO.ui.DropdownWidget( {
@@ -40,6 +39,16 @@ OO.ui.Demo = function OoUiDemo() {
new OO.ui.ButtonOptionWidget( { data: 'ltr', label: 'LTR' } ),
new OO.ui.ButtonOptionWidget( { data: 'rtl', label: 'RTL' } )
] );
+ this.jsPhpSelect = new OO.ui.ButtonGroupWidget().addItems( [
+ new OO.ui.ButtonWidget( { label: 'JS' } ).setActive( true ),
+ new OO.ui.ButtonWidget( {
+ label: 'PHP',
+ href: 'widgets.php' +
+ '?theme=' + this.mode.theme +
+ '&graphic=' + this.mode.graphics +
+ '&direction=' + this.mode.direction
+ } )
+ ] );
// Events
this.pageMenu.on( 'choose', OO.ui.bind( this.onModeChange, this ) );
@@ -58,7 +67,8 @@ OO.ui.Demo = function OoUiDemo() {
this.pageDropdown.$element,
this.themeSelect.$element,
this.graphicsSelect.$element,
- this.directionSelect.$element
+ this.directionSelect.$element,
+ this.jsPhpSelect.$element
);
this.$element
.addClass( 'oo-ui-demo' )
@@ -66,7 +76,7 @@ OO.ui.Demo = function OoUiDemo() {
$( 'body' ).addClass( 'oo-ui-' + this.mode.direction );
// Correctly apply direction to the <html> tags as well
$( 'html' ).attr( 'dir', this.mode.direction );
- $( 'head' ).append( this.stylesheetLinks );
+ this.stylesheetLinks = this.addStylesheetLinks( $( 'head' ) );
OO.ui.theme = new ( this.constructor.static.themes[ this.mode.theme ].theme )();
};
@@ -113,6 +123,7 @@ OO.ui.Demo.static.themes = {
'-icons-location',
'-icons-user',
'-icons-layout',
+ '-icons-accessibility',
'-icons-wikimedia'
],
theme: OO.ui.MediaWikiTheme
@@ -188,7 +199,7 @@ OO.ui.Demo.static.defaultTheme = 'mediawiki';
* @static
* @property {string}
*/
-OO.ui.Demo.static.defaultGraphics = 'vector';
+OO.ui.Demo.static.defaultGraphics = 'mixed';
/**
* Default page.
@@ -207,8 +218,8 @@ OO.ui.Demo.static.defaultDirection = 'ltr';
*/
OO.ui.Demo.prototype.initialize = function () {
var demo = this,
- promises = $( this.stylesheetLinks ).map( function () {
- return $( this ).data( 'load-promise' );
+ promises = this.stylesheetLinks.map( function ( el ) {
+ return $( el ).data( 'load-promise' );
} );
$.when.apply( $, promises )
.done( function () {
@@ -309,11 +320,12 @@ OO.ui.Demo.prototype.getCurrentMode = function () {
};
/**
- * Get link elements for the current mode.
+ * Get and insert link elements for the current mode.
*
+ * @param {jQuery} $where Node to insert the links into
* @return {HTMLElement[]} List of link elements
*/
-OO.ui.Demo.prototype.getStylesheetLinks = function () {
+OO.ui.Demo.prototype.addStylesheetLinks = function ( $where ) {
var i, len, links, fragments,
factors = this.getFactors(),
theme = this.getCurrentFactorValues()[ 1 ],
@@ -326,9 +338,9 @@ OO.ui.Demo.prototype.getStylesheetLinks = function () {
} );
// Theme styles
- urls.push( '../dist/oojs-ui' + fragments.slice( 1 ).join( '' ) + '.css' );
+ urls.push( 'dist/oojs-ui' + fragments.slice( 1 ).join( '' ) + '.css' );
for ( i = 0, len = suffixes.length; i < len; i++ ) {
- urls.push( '../dist/oojs-ui' + fragments[1] + suffixes[i] + fragments.slice( 2 ).join( '' ) + '.css' );
+ urls.push( 'dist/oojs-ui' + fragments[ 1 ] + suffixes[ i ] + fragments.slice( 2 ).join( '' ) + '.css' );
}
// Demo styles
@@ -345,6 +357,8 @@ OO.ui.Demo.prototype.getStylesheetLinks = function () {
load: deferred.resolve,
error: deferred.reject
} );
+ // Insert into DOM before setting 'href' for IE 8 compatibility
+ $where.append( $link );
link.rel = 'stylesheet';
link.href = url;
return link;
@@ -383,12 +397,12 @@ OO.ui.Demo.prototype.destroy = function () {
/**
* Build a console for interacting with an element.
*
- * @param {OO.ui.Element} item
- * @param {string} key Variable name for item
- * @param {string} [item.label=""]
+ * @param {OO.ui.Layout} item
+ * @param {string} layout Variable name for layout
+ * @param {string} widget Variable name for layout's field widget
* @return {jQuery} Console interface element
*/
-OO.ui.Demo.prototype.buildConsole = function ( item, key ) {
+OO.ui.Demo.prototype.buildConsole = function ( item, layout, widget ) {
var $toggle, $log, $label, $input, $submit, $console, $form,
console = window.console;
@@ -399,8 +413,8 @@ OO.ui.Demo.prototype.buildConsole = function ( item, key ) {
str = 'return ' + str;
}
try {
- func = new Function( key, 'item', str );
- ret = { value: func( item, item ) };
+ func = new Function( layout, widget, 'item', str );
+ ret = { value: func( item, item.fieldWidget, item.fieldWidget ) };
} catch ( error ) {
ret = {
value: undefined,
@@ -460,8 +474,9 @@ OO.ui.Demo.prototype.buildConsole = function ( item, key ) {
if ( $input.is( ':visible' ) ) {
$input[ 0 ].focus();
if ( console && console.log ) {
- window[ key ] = item;
- console.log( '[demo]', 'Global ' + key + ' has been set' );
+ window[ layout ] = item;
+ window[ widget ] = item.fieldWidget;
+ console.log( '[demo]', 'Globals ' + layout + ', ' + widget + ' have been set' );
console.log( '[demo]', item );
}
}
@@ -475,7 +490,7 @@ OO.ui.Demo.prototype.buildConsole = function ( item, key ) {
$input = $( '<input>' )
.addClass( 'oo-ui-demo-console-input' )
- .prop( 'placeholder', '... (predefined: ' + key + ')' );
+ .prop( 'placeholder', '... (predefined: ' + layout + ', ' + widget + ')' );
$submit = $( '<div>' )
.addClass( 'oo-ui-demo-console-submit' )
diff --git a/vendor/oojs/oojs-ui/demos/index.html b/vendor/oojs/oojs-ui/demos/index.html
index 35ccc69a..13f8d48e 100644
--- a/vendor/oojs/oojs-ui/demos/index.html
+++ b/vendor/oojs/oojs-ui/demos/index.html
@@ -7,11 +7,12 @@
<meta name="viewport" content="width=device-width, user-scalable=no">
</head>
<body>
- <script src="../node_modules/jquery/dist/jquery.js"></script>
- <script src="../node_modules/oojs/dist/oojs.jquery.js"></script>
- <script src="../dist/oojs-ui.js"></script>
- <script src="../dist/oojs-ui-apex.js"></script>
- <script src="../dist/oojs-ui-mediawiki.js"></script>
+ <script src="node_modules/jquery/dist/jquery.js"></script>
+ <script src="node_modules/es5-shim/es5-shim.js"></script>
+ <script src="node_modules/oojs/dist/oojs.jquery.js"></script>
+ <script src="dist/oojs-ui.js"></script>
+ <script src="dist/oojs-ui-apex.js"></script>
+ <script src="dist/oojs-ui-mediawiki.js"></script>
<script src="demo.js"></script>
<script src="pages/dialogs.js"></script>
<script src="pages/icons.js"></script>
diff --git a/vendor/oojs/oojs-ui/demos/infusion.js b/vendor/oojs/oojs-ui/demos/infusion.js
index 4fa0f64a..ea927ea5 100644
--- a/vendor/oojs/oojs-ui/demos/infusion.js
+++ b/vendor/oojs/oojs-ui/demos/infusion.js
@@ -1,19 +1,19 @@
// Demonstrate JavaScript 'infusion' of PHP-generated widgets.
// Used by widgets.php.
-var $menu, themeButtons, themes;
+var infuseButton;
// Helper function to get high resolution profiling data, where available.
function now() {
- /* global performance */
+ /*global performance */
return ( typeof performance !== 'undefined' ) ? performance.now() :
Date.now ? Date.now() : new Date().getTime();
}
// Add a button to infuse everything!
-// (You wouldn't typically do this: you'd only infuse those objects which
-// you needed to attach client-side behaviors to. But our theme-setting
-// code needs a list of all widgets, and it's a good overall test.)
+// (You wouldn't typically do this: you'd only infuse those objects which you needed to attach
+// client-side behaviors to, or where the JS implementation provides additional features over PHP,
+// like DropdownInputWidget. We do it here because it's a good overall test.)
function infuseAll() {
var start, end, all;
start = now();
@@ -22,45 +22,13 @@ function infuseAll() {
} );
end = now();
window.console.log( 'Infusion time: ' + ( end - start ) );
- return all;
+ infuseButton.setDisabled( true );
}
-$menu = $( '.oo-ui-demo-menu' );
-$menu.append(
- new OO.ui.ButtonGroupWidget().addItems( [
- new OO.ui.ButtonWidget( { label: 'Infuse' } )
- .on( 'click', infuseAll )
- ] ).$element );
-// Hook up the theme switch buttons.
-// This is more like a typical use case: we are just infusing specific
-// named UI elements.
-themeButtons = [
- // If you're lazy, you can just use OO.ui.infuse. But if you name the
- // Element type you're expecting, you can get some type checking.
- OO.ui.ButtonWidget.static.infuse( 'theme-mediawiki' ),
- OO.ui.ButtonWidget.static.infuse( 'theme-apex' )
-];
-themes = {
- mediawiki: new OO.ui.MediaWikiTheme(),
- apex: new OO.ui.ApexTheme()
-};
-function updateTheme( theme ) {
- OO.ui.theme = themes[theme];
- $.each( infuseAll(), function ( _, el ) {
- // FIXME: this isn't really supported, but it makes a neat demo.
- OO.ui.theme.updateElementClasses( el );
- } );
- // A bit of a hack, but it will do for a demo.
- $( 'link[rel="stylesheet"][title="theme"]' ).attr(
- 'href',
- '../dist/oojs-ui-' + theme + '.vector.css'
- );
-}
-// This is another more typical usage: we take the existing server-side
-// buttons and replace the href with a JS click handler.
-$.each( themeButtons, function ( _, b ) {
- // Get rid of the old server-side click handling.
- b.setHref( null );
- // Add new client-side click handling.
- b.on( 'click', function () { updateTheme( b.getData() ); } );
-} );
+// More typical usage: we take the existing server-side
+// button group and do things to it, here adding a new button.
+infuseButton = new OO.ui.ButtonWidget( { label: 'Infuse' } )
+ .on( 'click', infuseAll );
+
+OO.ui.ButtonGroupWidget.static.infuse( 'oo-ui-demo-menu-infuse' )
+ .addItems( [ infuseButton ] );
diff --git a/vendor/oojs/oojs-ui/demos/pages/dialogs.js b/vendor/oojs/oojs-ui/demos/pages/dialogs.js
index 6e9da3f8..ff3b0bbd 100644
--- a/vendor/oojs/oojs-ui/demos/pages/dialogs.js
+++ b/vendor/oojs/oojs-ui/demos/pages/dialogs.js
@@ -6,7 +6,7 @@ OO.ui.Demo.static.pages.dialogs = function ( demo ) {
windowManager = new OO.ui.WindowManager();
function SimpleDialog( config ) {
- SimpleDialog.super.call( this, config );
+ SimpleDialog.parent.call( this, config );
}
OO.inheritClass( SimpleDialog, OO.ui.Dialog );
SimpleDialog.static.title = 'Simple dialog';
@@ -14,7 +14,7 @@ OO.ui.Demo.static.pages.dialogs = function ( demo ) {
var closeButton,
dialog = this;
- SimpleDialog.super.prototype.initialize.apply( this, arguments );
+ SimpleDialog.parent.prototype.initialize.apply( this, arguments );
this.content = new OO.ui.PanelLayout( { padded: true, expanded: false } );
this.content.$element.append( '<p>Dialog content</p>' );
@@ -33,16 +33,17 @@ OO.ui.Demo.static.pages.dialogs = function ( demo ) {
};
function ProcessDialog( config ) {
- ProcessDialog.super.call( this, config );
+ ProcessDialog.parent.call( this, config );
}
OO.inheritClass( ProcessDialog, OO.ui.ProcessDialog );
ProcessDialog.static.title = 'Process dialog';
ProcessDialog.static.actions = [
{ action: 'save', label: 'Done', flags: [ 'primary', 'progressive' ] },
- { action: 'cancel', label: 'Cancel', flags: 'safe' }
+ { action: 'cancel', label: 'Cancel', flags: 'safe' },
+ { action: 'other', label: 'Other', flags: 'other' }
];
ProcessDialog.prototype.initialize = function () {
- ProcessDialog.super.prototype.initialize.apply( this, arguments );
+ ProcessDialog.parent.prototype.initialize.apply( this, arguments );
this.content = new OO.ui.PanelLayout( { padded: true, expanded: false } );
this.content.$element.append( '<p>Dialog content</p>' );
this.$body.append( this.content.$element );
@@ -54,23 +55,32 @@ OO.ui.Demo.static.pages.dialogs = function ( demo ) {
dialog.close( { action: action } );
} );
}
- return ProcessDialog.super.prototype.getActionProcess.call( this, action );
+ return ProcessDialog.parent.prototype.getActionProcess.call( this, action );
};
ProcessDialog.prototype.getBodyHeight = function () {
return this.content.$element.outerHeight( true );
};
+ function FramelessProcessDialog( config ) {
+ FramelessProcessDialog.parent.call( this, config );
+ }
+ OO.inheritClass( FramelessProcessDialog, ProcessDialog );
+ FramelessProcessDialog.static.actions = OO.copy( FramelessProcessDialog.static.actions );
+ FramelessProcessDialog.static.actions.forEach( function ( action ) {
+ action.framed = false;
+ } );
+
function SearchWidgetDialog( config ) {
- SearchWidgetDialog.super.call( this, config );
+ SearchWidgetDialog.parent.call( this, config );
this.broken = false;
}
OO.inheritClass( SearchWidgetDialog, OO.ui.ProcessDialog );
SearchWidgetDialog.static.title = 'Search widget dialog';
SearchWidgetDialog.prototype.initialize = function () {
- SearchWidgetDialog.super.prototype.initialize.apply( this, arguments );
- var i,
- items = [],
- searchWidget = new OO.ui.SearchWidget();
+ var i, items, searchWidget;
+ SearchWidgetDialog.parent.prototype.initialize.apply( this, arguments );
+ items = [];
+ searchWidget = new OO.ui.SearchWidget();
for ( i = 1; i <= 20; i++ ) {
items.push( new OO.ui.OptionWidget( { data: i, label: 'Item ' + i } ) );
}
@@ -92,7 +102,7 @@ OO.ui.Demo.static.pages.dialogs = function ( demo ) {
};
function BrokenDialog( config ) {
- BrokenDialog.super.call( this, config );
+ BrokenDialog.parent.call( this, config );
this.broken = false;
}
OO.inheritClass( BrokenDialog, OO.ui.ProcessDialog );
@@ -106,7 +116,7 @@ OO.ui.Demo.static.pages.dialogs = function ( demo ) {
return 250;
};
BrokenDialog.prototype.initialize = function () {
- BrokenDialog.super.prototype.initialize.apply( this, arguments );
+ BrokenDialog.parent.prototype.initialize.apply( this, arguments );
this.content = new OO.ui.PanelLayout( { padded: true } );
this.fieldset = new OO.ui.FieldsetLayout( {
label: 'Dialog with error handling', icon: 'alert'
@@ -120,13 +130,13 @@ OO.ui.Demo.static.pages.dialogs = function ( demo ) {
this.$body.append( this.content.$element );
};
BrokenDialog.prototype.getSetupProcess = function ( data ) {
- return BrokenDialog.super.prototype.getSetupProcess.call( this, data )
+ return BrokenDialog.parent.prototype.getSetupProcess.call( this, data )
.next( function () {
this.broken = true;
}, this );
};
BrokenDialog.prototype.getActionProcess = function ( action ) {
- return BrokenDialog.super.prototype.getActionProcess.call( this, action )
+ return BrokenDialog.parent.prototype.getActionProcess.call( this, action )
.next( function () {
return 1000;
}, this )
@@ -147,20 +157,22 @@ OO.ui.Demo.static.pages.dialogs = function ( demo ) {
// Return a promise to remaing pending while closing
return closing;
}
- return BrokenDialog.super.prototype.getActionProcess.call( this, action );
+ return BrokenDialog.parent.prototype.getActionProcess.call( this, action );
}, this );
};
function SamplePage( name, config ) {
- config = $.extend( { label: 'Sample page', icon: 'Sample icon' }, config );
+ config = $.extend( { label: 'Sample page' }, config );
OO.ui.PageLayout.call( this, name, config );
this.label = config.label;
this.icon = config.icon;
- this.$element.text( this.label );
+ if ( this.$element.is( ':empty' ) ) {
+ this.$element.text( this.label );
+ }
}
OO.inheritClass( SamplePage, OO.ui.PageLayout );
SamplePage.prototype.setupOutlineItem = function ( outlineItem ) {
- SamplePage.super.prototype.setupOutlineItem.call( this, outlineItem );
+ SamplePage.parent.prototype.setupOutlineItem.call( this, outlineItem );
this.outlineItem
.setMovable( true )
.setRemovable( true )
@@ -169,7 +181,7 @@ OO.ui.Demo.static.pages.dialogs = function ( demo ) {
};
function BookletDialog( config ) {
- BookletDialog.super.call( this, config );
+ BookletDialog.parent.call( this, config );
}
OO.inheritClass( BookletDialog, OO.ui.ProcessDialog );
BookletDialog.static.title = 'Booklet dialog';
@@ -181,9 +193,10 @@ OO.ui.Demo.static.pages.dialogs = function ( demo ) {
return 250;
};
BookletDialog.prototype.initialize = function () {
- BookletDialog.super.prototype.initialize.apply( this, arguments );
+ var dialog;
+ BookletDialog.parent.prototype.initialize.apply( this, arguments );
- var dialog = this;
+ dialog = this;
function changePage( direction ) {
var pageIndex = dialog.pages.indexOf( dialog.bookletLayout.getCurrentPage() );
@@ -232,14 +245,14 @@ OO.ui.Demo.static.pages.dialogs = function ( demo ) {
this.close( { action: action } );
}, this );
}
- return BookletDialog.super.prototype.getActionProcess.call( this, action );
+ return BookletDialog.parent.prototype.getActionProcess.call( this, action );
};
BookletDialog.prototype.onBookletLayoutSet = function ( page ) {
page.$element.append( this.navigationField.$element );
};
function OutlinedBookletDialog( config ) {
- OutlinedBookletDialog.super.call( this, config );
+ OutlinedBookletDialog.parent.call( this, config );
}
OO.inheritClass( OutlinedBookletDialog, OO.ui.ProcessDialog );
OutlinedBookletDialog.static.title = 'Booklet dialog';
@@ -251,7 +264,7 @@ OO.ui.Demo.static.pages.dialogs = function ( demo ) {
return 250;
};
OutlinedBookletDialog.prototype.initialize = function () {
- OutlinedBookletDialog.super.prototype.initialize.apply( this, arguments );
+ OutlinedBookletDialog.parent.prototype.initialize.apply( this, arguments );
this.bookletLayout = new OO.ui.BookletLayout( {
outlined: true
} );
@@ -273,32 +286,26 @@ OO.ui.Demo.static.pages.dialogs = function ( demo ) {
this.close( { action: action } );
}, this );
}
- return OutlinedBookletDialog.super.prototype.getActionProcess.call( this, action );
+ return OutlinedBookletDialog.parent.prototype.getActionProcess.call( this, action );
};
OutlinedBookletDialog.prototype.onBookletLayoutSet = function ( page ) {
this.setSize( page.getName() );
};
OutlinedBookletDialog.prototype.getSetupProcess = function ( data ) {
- return OutlinedBookletDialog.super.prototype.getSetupProcess.call( this, data )
+ return OutlinedBookletDialog.parent.prototype.getSetupProcess.call( this, data )
.next( function () {
this.bookletLayout.setPage( this.getSize() );
}, this );
};
function SampleCard( name, config ) {
- config = $.extend( { label: 'Sample card' }, config );
OO.ui.CardLayout.call( this, name, config );
- this.label = config.label;
this.$element.text( this.label );
}
OO.inheritClass( SampleCard, OO.ui.CardLayout );
- SampleCard.prototype.setupTabItem = function ( tabItem ) {
- SampleCard.super.prototype.setupTabItem.call( this, tabItem );
- this.tabItem.setLabel( this.label );
- };
function IndexedDialog( config ) {
- IndexedDialog.super.call( this, config );
+ IndexedDialog.parent.call( this, config );
}
OO.inheritClass( IndexedDialog, OO.ui.ProcessDialog );
IndexedDialog.static.title = 'Index dialog';
@@ -310,7 +317,7 @@ OO.ui.Demo.static.pages.dialogs = function ( demo ) {
return 250;
};
IndexedDialog.prototype.initialize = function () {
- IndexedDialog.super.prototype.initialize.apply( this, arguments );
+ IndexedDialog.parent.prototype.initialize.apply( this, arguments );
this.indexLayout = new OO.ui.IndexLayout();
this.cards = [
new SampleCard( 'first', { label: 'One' } ),
@@ -330,11 +337,11 @@ OO.ui.Demo.static.pages.dialogs = function ( demo ) {
this.close( { action: action } );
}, this );
}
- return IndexedDialog.super.prototype.getActionProcess.call( this, action );
+ return IndexedDialog.parent.prototype.getActionProcess.call( this, action );
};
function MenuDialog( config ) {
- MenuDialog.super.call( this, config );
+ MenuDialog.parent.call( this, config );
}
OO.inheritClass( MenuDialog, OO.ui.ProcessDialog );
MenuDialog.static.title = 'Menu dialog';
@@ -346,47 +353,49 @@ OO.ui.Demo.static.pages.dialogs = function ( demo ) {
return 350;
};
MenuDialog.prototype.initialize = function () {
- MenuDialog.super.prototype.initialize.apply( this, arguments );
- var menuLayout = new OO.ui.MenuLayout(),
- positionField = new OO.ui.FieldLayout(
- new OO.ui.ButtonSelectWidget( {
- items: [
- new OO.ui.ButtonOptionWidget( {
- data: 'before',
- label: 'Before'
- } ),
- new OO.ui.ButtonOptionWidget( {
- data: 'after',
- label: 'After'
- } ),
- new OO.ui.ButtonOptionWidget( {
- data: 'top',
- label: 'Top'
- } ),
- new OO.ui.ButtonOptionWidget( {
- data: 'bottom',
- label: 'Bottom'
- } )
- ]
- } ).on( 'select', function ( item ) {
- menuLayout.setMenuPosition( item.getData() );
- } ),
- {
- label: 'Menu position',
- align: 'top'
- }
- ),
- showField = new OO.ui.FieldLayout(
- new OO.ui.ToggleSwitchWidget( { value: true } ).on( 'change', function ( value ) {
- menuLayout.toggleMenu( value );
- } ),
- {
- label: 'Show menu',
- align: 'top'
- }
- ),
- menuPanel = new OO.ui.PanelLayout( { padded: true, expanded: true, scrollable: true } ),
- contentPanel = new OO.ui.PanelLayout( { padded: true, expanded: true, scrollable: true } );
+ var menuLayout, positionField, showField, menuPanel, contentPanel;
+ MenuDialog.parent.prototype.initialize.apply( this, arguments );
+
+ menuLayout = new OO.ui.MenuLayout();
+ positionField = new OO.ui.FieldLayout(
+ new OO.ui.ButtonSelectWidget( {
+ items: [
+ new OO.ui.ButtonOptionWidget( {
+ data: 'before',
+ label: 'Before'
+ } ),
+ new OO.ui.ButtonOptionWidget( {
+ data: 'after',
+ label: 'After'
+ } ),
+ new OO.ui.ButtonOptionWidget( {
+ data: 'top',
+ label: 'Top'
+ } ),
+ new OO.ui.ButtonOptionWidget( {
+ data: 'bottom',
+ label: 'Bottom'
+ } )
+ ]
+ } ).on( 'select', function ( item ) {
+ menuLayout.setMenuPosition( item.getData() );
+ } ),
+ {
+ label: 'Menu position',
+ align: 'top'
+ }
+ );
+ showField = new OO.ui.FieldLayout(
+ new OO.ui.ToggleSwitchWidget( { value: true } ).on( 'change', function ( value ) {
+ menuLayout.toggleMenu( value );
+ } ),
+ {
+ label: 'Show menu',
+ align: 'top'
+ }
+ );
+ menuPanel = new OO.ui.PanelLayout( { padded: true, expanded: true, scrollable: true } );
+ contentPanel = new OO.ui.PanelLayout( { padded: true, expanded: true, scrollable: true } );
menuLayout.$menu.append(
menuPanel.$element.append( 'Menu panel' )
@@ -406,7 +415,144 @@ OO.ui.Demo.static.pages.dialogs = function ( demo ) {
this.close( { action: action } );
}, this );
}
- return MenuDialog.super.prototype.getActionProcess.call( this, action );
+ return MenuDialog.parent.prototype.getActionProcess.call( this, action );
+ };
+
+ function ExampleLookupTextInputWidget( config ) {
+ config = config || {};
+ this.items = config.items || [];
+ OO.ui.TextInputWidget.call( this, config );
+ OO.ui.mixin.LookupElement.call( this, config );
+ }
+ OO.inheritClass( ExampleLookupTextInputWidget, OO.ui.TextInputWidget );
+ OO.mixinClass( ExampleLookupTextInputWidget, OO.ui.mixin.LookupElement );
+ ExampleLookupTextInputWidget.prototype.getLookupRequest = function () {
+ return $.Deferred().resolve( [] ).promise( { abort: function () {} } );
+ };
+ ExampleLookupTextInputWidget.prototype.getLookupCacheDataFromResponse = function () {
+ return [];
+ };
+ ExampleLookupTextInputWidget.prototype.getLookupMenuOptionsFromData = function () {
+ return this.items;
+ };
+
+ function DialogWithDropdowns( config ) {
+ DialogWithDropdowns.parent.call( this, config );
+ }
+ OO.inheritClass( DialogWithDropdowns, OO.ui.ProcessDialog );
+ DialogWithDropdowns.static.title = 'Dialog with dropdowns ($overlay test)';
+ DialogWithDropdowns.static.actions = [
+ { action: 'save', label: 'Done', flags: [ 'primary', 'progressive' ] },
+ { action: 'cancel', label: 'Cancel', flags: 'safe' }
+ ];
+ DialogWithDropdowns.prototype.getBodyHeight = function () {
+ return 250;
+ };
+ DialogWithDropdowns.prototype.initialize = function () {
+ var $spacer = $( '<div>' ).height( 150 );
+ DialogWithDropdowns.parent.prototype.initialize.apply( this, arguments );
+ this.bookletLayout = new OO.ui.BookletLayout( {
+ outlined: true
+ } );
+ this.pages = [
+ new SamplePage( 'info', {
+ label: 'Information',
+ icon: 'info',
+ content: [
+ 'This is a test of various kinds of dropdown menus and their $overlay config option. ',
+ 'Entries without any icon use a correctly set $overlay and their menus should be able to extend outside of this small dialog. ',
+ 'Entries with the ', new OO.ui.IconWidget( { icon: 'alert' } ), ' icon do not, and their menus should be clipped to the dialog\'s boundaries. ',
+ 'All dropdown menus should stick to the widget proper, even when scrolling while the menu is open.'
+ ]
+ } ),
+ new SamplePage( 'dropdown', {
+ label: 'DropdownWidget',
+ content: [ $spacer.clone(), new OO.ui.DropdownWidget( {
+ $overlay: this.$overlay,
+ menu: {
+ items: this.makeItems()
+ }
+ } ), $spacer.clone() ]
+ } ),
+ new SamplePage( 'dropdown2', {
+ label: 'DropdownWidget',
+ icon: 'alert',
+ content: [ $spacer.clone(), new OO.ui.DropdownWidget( {
+ menu: {
+ items: this.makeItems()
+ }
+ } ), $spacer.clone() ]
+ } ),
+ new SamplePage( 'combobox', {
+ label: 'ComboBoxWidget',
+ content: [ $spacer.clone(), new OO.ui.ComboBoxWidget( {
+ $overlay: this.$overlay,
+ menu: {
+ items: this.makeItems()
+ }
+ } ), $spacer.clone() ]
+ } ),
+ new SamplePage( 'combobox2', {
+ label: 'ComboBoxWidget',
+ icon: 'alert',
+ content: [ $spacer.clone(), new OO.ui.ComboBoxWidget( {
+ menu: {
+ items: this.makeItems()
+ }
+ } ), $spacer.clone() ]
+ } ),
+ new SamplePage( 'lookup', {
+ label: 'LookupElement',
+ content: [ $spacer.clone(), new ExampleLookupTextInputWidget( {
+ $overlay: this.$overlay,
+ items: this.makeItems()
+ } ), $spacer.clone() ]
+ } ),
+ new SamplePage( 'lookup2', {
+ label: 'LookupElement',
+ icon: 'alert',
+ content: [ $spacer.clone(), new ExampleLookupTextInputWidget( {
+ items: this.makeItems()
+ } ), $spacer.clone() ]
+ } ),
+ new SamplePage( 'capsule', {
+ label: 'CapsuleMultiSelectWidget',
+ content: [ $spacer.clone(), new OO.ui.CapsuleMultiSelectWidget( {
+ $overlay: this.$overlay,
+ menu: {
+ items: this.makeItems()
+ }
+ } ), $spacer.clone() ]
+ } ),
+ new SamplePage( 'capsule2', {
+ label: 'CapsuleMultiSelectWidget',
+ icon: 'alert',
+ content: [ $spacer.clone(), new OO.ui.CapsuleMultiSelectWidget( {
+ menu: {
+ items: this.makeItems()
+ }
+ } ), $spacer.clone() ]
+ } )
+ ];
+ this.bookletLayout.addPages( this.pages );
+ this.$body.append( this.bookletLayout.$element );
+ };
+ DialogWithDropdowns.prototype.makeItems = function () {
+ return [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 ].map( function ( val ) {
+ return new OO.ui.MenuOptionWidget( {
+ data: val,
+ label: String( val )
+ } );
+ } );
+ };
+
+ DialogWithDropdowns.prototype.getActionProcess = function ( action ) {
+ if ( action ) {
+ return new OO.ui.Process( function () {
+ this.close( { action: action } );
+ }, this );
+ }
+ return DialogWithDropdowns.parent.prototype.getActionProcess.call( this, action );
};
config = [
@@ -451,6 +597,13 @@ OO.ui.Demo.static.pages.dialogs = function ( demo ) {
}
},
{
+ name: 'Process dialog (frameless buttons)',
+ dialogClass: FramelessProcessDialog,
+ config: {
+ size: 'medium'
+ }
+ },
+ {
name: 'Process dialog (full)',
dialogClass: ProcessDialog,
config: {
@@ -500,6 +653,13 @@ OO.ui.Demo.static.pages.dialogs = function ( demo ) {
}
},
{
+ name: 'Dialog with dropdowns ($overlay test)',
+ dialogClass: DialogWithDropdowns,
+ config: {
+ size: 'large'
+ }
+ },
+ {
name: 'Message dialog (generic)',
dialogClass: OO.ui.MessageDialog,
data: {
diff --git a/vendor/oojs/oojs-ui/demos/pages/icons.js b/vendor/oojs/oojs-ui/demos/pages/icons.js
index aec2204c..ffc5112e 100644
--- a/vendor/oojs/oojs-ui/demos/pages/icons.js
+++ b/vendor/oojs/oojs-ui/demos/pages/icons.js
@@ -19,6 +19,7 @@ OO.ui.Demo.static.pages.icons = function ( demo ) {
'info',
'menu',
'next',
+ 'notice',
'picture',
'previous',
'redo',
@@ -88,6 +89,7 @@ OO.ui.Demo.static.pages.icons = function ( demo ) {
'flag',
'flagUndo',
'lock',
+ 'ongoingConversation',
'star',
'trash',
'trashUndo',
@@ -126,6 +128,7 @@ OO.ui.Demo.static.pages.icons = function ( demo ) {
'alignCentre',
'alignLeft',
'alignRight',
+ 'calendar',
'find',
'insert',
'layout',
@@ -176,7 +179,15 @@ OO.ui.Demo.static.pages.icons = function ( demo ) {
'stripeSummary',
'stripeToC',
'viewCompact',
- 'viewDetails',
+ 'viewDetails'
+ ],
+ accessibility: [
+ 'bright',
+ 'halfBright',
+ 'notBright',
+ 'moon',
+ 'largerText',
+ 'smallerText',
'visionSimulator'
],
wikimedia: [
@@ -187,6 +198,7 @@ OO.ui.Demo.static.pages.icons = function ( demo ) {
},
indicators = [
'alert',
+ 'clear',
'down',
'next',
'previous',
@@ -290,6 +302,6 @@ OO.ui.Demo.static.pages.icons = function ( demo ) {
.append(
selector.$element,
indicatorsFieldset.$element,
- iconsFieldsets.map( function ( item ) { return item.$element[0]; } )
+ iconsFieldsets.map( function ( item ) { return item.$element[ 0 ]; } )
) );
};
diff --git a/vendor/oojs/oojs-ui/demos/pages/toolbars.js b/vendor/oojs/oojs-ui/demos/pages/toolbars.js
index 550d8128..b729e364 100644
--- a/vendor/oojs/oojs-ui/demos/pages/toolbars.js
+++ b/vendor/oojs/oojs-ui/demos/pages/toolbars.js
@@ -1,5 +1,6 @@
OO.ui.Demo.static.pages.toolbars = function ( demo ) {
- var i, toolGroups, saveButton, actionButton, actionButtonDisabled, PopupTool, ToolGroupTool,
+ var i, toolGroups, saveButton, deleteButton, actionButton, actionButtonDisabled, PopupTool, ToolGroupTool,
+ setDisabled = function () { this.setDisabled( true ); },
$demo = demo.$element,
$containers = $(),
toolFactories = [],
@@ -26,7 +27,7 @@ OO.ui.Demo.static.pages.toolbars = function ( demo ) {
function createTool( toolbar, group, name, icon, title, init, onSelect, displayBothIconAndLabel ) {
var Tool = function () {
- Tool.super.apply( this, arguments );
+ Tool.parent.apply( this, arguments );
this.toggled = false;
if ( init ) {
init.call( this );
@@ -64,7 +65,7 @@ OO.ui.Demo.static.pages.toolbars = function ( demo ) {
function createDisabledToolGroup( parent, name ) {
var DisabledToolGroup = function () {
- DisabledToolGroup.super.apply( this, arguments );
+ DisabledToolGroup.parent.apply( this, arguments );
this.setDisabled( true );
};
@@ -210,6 +211,10 @@ OO.ui.Demo.static.pages.toolbars = function ( demo ) {
include: [ { group: 'cite' } ]
},
{
+ type: 'bar',
+ include: [ { group: 'citeDisabled' } ]
+ },
+ {
type: 'list',
indicator: 'down',
label: 'Insert',
@@ -218,13 +223,14 @@ OO.ui.Demo.static.pages.toolbars = function ( demo ) {
] );
saveButton = new OO.ui.ButtonWidget( { label: 'Save', flags: [ 'progressive', 'primary' ] } );
+ deleteButton = new OO.ui.ButtonWidget( { label: 'Delete', flags: [ 'destructive' ] } );
actionButton = new OO.ui.ButtonWidget( { label: 'Action' } );
actionButtonDisabled = new OO.ui.ButtonWidget( { label: 'Disabled', disabled: true } );
toolbars[ 1 ].$actions
.append( actionButton.$element, actionButtonDisabled.$element );
toolbars[ 3 ].$actions
- .append( toolbars[ 2 ].$element, saveButton.$element );
+ .append( toolbars[ 2 ].$element, deleteButton.$element, saveButton.$element );
for ( i = 0; i < toolbars.length; i++ ) {
toolbars[ i ].emit( 'updateState' );
@@ -233,7 +239,7 @@ OO.ui.Demo.static.pages.toolbars = function ( demo ) {
toolGroups = {
barTools: [
[ 'barTool', 'picture', 'Basic tool in bar' ],
- [ 'disabledBarTool', 'picture', 'Basic tool in bar disabled', function () { this.setDisabled( true ); } ]
+ [ 'disabledBarTool', 'picture', 'Basic tool in bar disabled', setDisabled ]
],
disabledBarTools: [
@@ -243,7 +249,7 @@ OO.ui.Demo.static.pages.toolbars = function ( demo ) {
listTools: [
[ 'listTool', 'picture', 'First basic tool in list' ],
[ 'listTool1', 'picture', 'Basic tool in list' ],
- [ 'listTool3', 'picture', 'Basic disabled tool in list', function () { this.setDisabled( true ); } ],
+ [ 'listTool3', 'picture', 'Basic disabled tool in list', setDisabled ],
[ 'listTool6', 'picture', 'A final tool' ]
],
@@ -262,12 +268,12 @@ OO.ui.Demo.static.pages.toolbars = function ( demo ) {
],
autoDisableListTools: [
- [ 'autoDisableListTool', 'picture', 'Click to disable this tool', null, function () { this.setDisabled( true ); } ]
+ [ 'autoDisableListTool', 'picture', 'Click to disable this tool', null, setDisabled ]
],
menuTools: [
[ 'menuTool', 'picture', 'Basic tool' ],
- [ 'disabledMenuTool', 'picture', 'Basic tool disabled', function () { this.setDisabled( true ); } ]
+ [ 'disabledMenuTool', 'picture', 'Basic tool disabled', setDisabled ]
],
disabledMenuTools: [
@@ -290,6 +296,10 @@ OO.ui.Demo.static.pages.toolbars = function ( demo ) {
cite: [
[ 'citeTool', 'citeArticle', 'Cite', null, null, true ]
+ ],
+
+ citeDisabled: [
+ [ 'citeToolDisabled', 'citeArticle', 'Cite', setDisabled, null, true ]
]
};
@@ -306,6 +316,7 @@ OO.ui.Demo.static.pages.toolbars = function ( demo ) {
createToolGroup( 3, 'history' );
createToolGroup( 3, 'link' );
createToolGroup( 3, 'cite' );
+ createToolGroup( 3, 'citeDisabled' );
createToolGroup( 3, 'menuTools' );
createToolGroup( 3, 'listTools' );
createToolGroup( 3, 'moreListTools' );
diff --git a/vendor/oojs/oojs-ui/demos/pages/widgets.js b/vendor/oojs/oojs-ui/demos/pages/widgets.js
index 52c6ee87..dd4be8c4 100644
--- a/vendor/oojs/oojs-ui/demos/pages/widgets.js
+++ b/vendor/oojs/oojs-ui/demos/pages/widgets.js
@@ -1,5 +1,6 @@
OO.ui.Demo.static.pages.widgets = function ( demo ) {
- var styles, states, buttonStyleShowcaseWidget, horizontalAlignmentWidget, fieldsets,
+ var styles, states, buttonStyleShowcaseWidget, fieldsets,
+ capsuleWithPopup, capsulePopupWidget,
$demo = demo.$element;
/**
@@ -11,21 +12,21 @@ OO.ui.Demo.static.pages.widgets = function ( demo ) {
config = config || {};
// Parent constructor
- DragDropGroupWidget.super.call( this, config );
+ DragDropGroupWidget.parent.call( this, config );
// Mixin constructors
- OO.ui.DraggableGroupElement.call( this, $.extend( {}, config, { $group: this.$element } ) );
+ OO.ui.mixin.DraggableGroupElement.call( this, $.extend( {}, config, { $group: this.$element } ) );
// Respond to reorder event
this.connect( this, { reorder: 'onReorder' } );
}
/* Setup */
OO.inheritClass( DragDropGroupWidget, OO.ui.Widget );
- OO.mixinClass( DragDropGroupWidget, OO.ui.DraggableGroupElement );
+ OO.mixinClass( DragDropGroupWidget, OO.ui.mixin.DraggableGroupElement );
/**
* Respond to order event
- * @param {OO.ui.DraggableElement} item Reordered item
+ * @param {OO.ui.mixin.DraggableElement} item Reordered item
* @param {number} newIndex New index
*/
DragDropGroupWidget.prototype.onReorder = function ( item, newIndex ) {
@@ -41,28 +42,28 @@ OO.ui.Demo.static.pages.widgets = function ( demo ) {
config = config || {};
// Parent constructor
- DragDropItemWidget.super.call( this, config );
+ DragDropItemWidget.parent.call( this, config );
// Mixin constructors
- OO.ui.DraggableElement.call( this, config );
+ OO.ui.mixin.DraggableElement.call( this, config );
}
/* Setup */
OO.inheritClass( DragDropItemWidget, OO.ui.OptionWidget );
- OO.mixinClass( DragDropItemWidget, OO.ui.DraggableElement );
+ OO.mixinClass( DragDropItemWidget, OO.ui.mixin.DraggableElement );
/**
* Demo for LookupElement.
* @extends OO.ui.TextInputWidget
- * @mixins OO.ui.LookupElement
+ * @mixins OO.ui.mixin.LookupElement
*/
function NumberLookupTextInputWidget() {
// Parent constructor
OO.ui.TextInputWidget.call( this, { validate: 'integer' } );
// Mixin constructors
- OO.ui.LookupElement.call( this );
+ OO.ui.mixin.LookupElement.call( this );
}
OO.inheritClass( NumberLookupTextInputWidget, OO.ui.TextInputWidget );
- OO.mixinClass( NumberLookupTextInputWidget, OO.ui.LookupElement );
+ OO.mixinClass( NumberLookupTextInputWidget, OO.ui.mixin.LookupElement );
/**
* @inheritdoc
@@ -113,6 +114,33 @@ OO.ui.Demo.static.pages.widgets = function ( demo ) {
return items;
};
+ function UnsupportedSelectFileWidget() {
+ // Parent constructor
+ UnsupportedSelectFileWidget.parent.apply( this, arguments );
+ }
+ OO.inheritClass( UnsupportedSelectFileWidget, OO.ui.SelectFileWidget );
+ UnsupportedSelectFileWidget.static.isSupported = function () {
+ return false;
+ };
+
+ capsulePopupWidget = new OO.ui.NumberInputWidget( {
+ isInteger: true
+ } );
+ capsulePopupWidget.connect( capsulePopupWidget, {
+ enter: function () {
+ if ( !isNaN( this.getNumericValue() ) ) {
+ capsuleWithPopup.addItemsFromData( [ this.getNumericValue() ] );
+ this.setValue( '' );
+ }
+ return false;
+ }
+ } );
+ capsulePopupWidget.$element.css( 'vertical-align', 'middle' );
+ capsuleWithPopup = new OO.ui.CapsuleMultiSelectWidget( {
+ allowArbitrary: true,
+ popup: { $content: capsulePopupWidget.$element }
+ } );
+
styles = [
{},
{
@@ -182,28 +210,6 @@ OO.ui.Demo.static.pages.widgets = function ( demo ) {
buttonStyleShowcaseWidget.$element.append( $( '<br>' ) );
} );
- horizontalAlignmentWidget = new OO.ui.Widget( {
- classes: [ 'oo-ui-demo-horizontal-alignment' ]
- } );
- horizontalAlignmentWidget.$element.append(
- new OO.ui.ButtonWidget( { label: 'Button' } ).$element,
- new OO.ui.ButtonGroupWidget( { items: [
- new OO.ui.ToggleButtonWidget( { label: 'A' } ),
- new OO.ui.ToggleButtonWidget( { label: 'B' } )
- ] } ).$element,
- new OO.ui.ButtonInputWidget( { label: 'ButtonInput' } ).$element,
- new OO.ui.TextInputWidget( { value: 'TextInput' } ).$element,
- new OO.ui.DropdownInputWidget( { options: [
- {
- label: 'DropdownInput',
- data: null
- }
- ] } ).$element,
- new OO.ui.CheckboxInputWidget( { selected: true } ).$element,
- new OO.ui.RadioInputWidget( { selected: true } ).$element,
- new OO.ui.LabelWidget( { label: 'Label' } ).$element
- );
-
fieldsets = [
new OO.ui.FieldsetLayout( {
label: 'Simple buttons',
@@ -487,6 +493,16 @@ OO.ui.Demo.static.pages.widgets = function ( demo ) {
label: 'ButtonWidget (frameless, indicator)\u200E',
align: 'top'
}
+ ),
+ new OO.ui.FieldLayout(
+ new OO.ui.ButtonWidget( {
+ label: 'AccessKeyed',
+ accessKey: 'k'
+ } ),
+ {
+ label: 'ButtonWidget (with accesskey k)\u200E',
+ align: 'top'
+ }
)
]
} ),
@@ -656,15 +672,15 @@ OO.ui.Demo.static.pages.widgets = function ( demo ) {
new OO.ui.RadioSelectWidget( {
items: [
new OO.ui.RadioOptionWidget( {
- data: 'Cat',
+ data: 'cat',
label: 'Cat'
} ),
new OO.ui.RadioOptionWidget( {
- data: 'Dog',
+ data: 'dog',
label: 'Dog'
} ),
new OO.ui.RadioOptionWidget( {
- data: 'Goldfish',
+ data: 'goldfish',
label: 'Goldfish',
disabled: true
} )
@@ -676,6 +692,50 @@ OO.ui.Demo.static.pages.widgets = function ( demo ) {
}
),
new OO.ui.FieldLayout(
+ new OO.ui.RadioSelectInputWidget( {
+ value: 'dog',
+ options: [
+ {
+ data: 'cat',
+ label: 'Cat'
+ },
+ {
+ data: 'dog',
+ label: 'Dog'
+ },
+ {
+ data: 'goldfish',
+ label: 'Goldfish'
+ }
+ ]
+ } ),
+ {
+ align: 'top',
+ label: 'RadioSelectInputWidget'
+ }
+ ),
+ new OO.ui.FieldLayout(
+ new OO.ui.NumberInputWidget(),
+ {
+ label: 'NumberInputWidget',
+ align: 'top'
+ }
+ ),
+ new OO.ui.FieldLayout(
+ new OO.ui.NumberInputWidget( { min: 1, max: 5, isInteger: true } ),
+ {
+ label: 'NumberInputWidget (1–5, ints only)',
+ align: 'top'
+ }
+ ),
+ new OO.ui.FieldLayout(
+ new OO.ui.NumberInputWidget( { min: 0, max: 1, step: 0.1, pageStep: 0.25 } ),
+ {
+ label: 'NumberInputWidget (0–1, step by .1, page by .25)',
+ align: 'top'
+ }
+ ),
+ new OO.ui.FieldLayout(
new OO.ui.ToggleSwitchWidget(),
{
label: 'ToggleSwitchWidget',
@@ -733,12 +793,11 @@ OO.ui.Demo.static.pages.widgets = function ( demo ) {
),
new OO.ui.FieldLayout(
new OO.ui.TextInputWidget( {
- indicator: 'required',
required: true,
validate: 'non-empty'
} ),
{
- label: 'TextInputWidget (indicator, required)\u200E',
+ label: 'TextInputWidget (required)\u200E',
align: 'top'
}
),
@@ -761,6 +820,13 @@ OO.ui.Demo.static.pages.widgets = function ( demo ) {
}
),
new OO.ui.FieldLayout(
+ new OO.ui.TextInputWidget( { type: 'search' } ),
+ {
+ label: 'TextInputWidget (type=search)\u200E',
+ align: 'top'
+ }
+ ),
+ new OO.ui.FieldLayout(
new OO.ui.TextInputWidget( {
value: 'Readonly',
readOnly: true
@@ -783,6 +849,17 @@ OO.ui.Demo.static.pages.widgets = function ( demo ) {
new OO.ui.FieldLayout(
new OO.ui.TextInputWidget( {
multiline: true,
+ rows: 15,
+ value: 'Multiline\nMultiline'
+ } ),
+ {
+ label: 'TextInputWidget (multiline, rows=15)\u200E',
+ align: 'top'
+ }
+ ),
+ new OO.ui.FieldLayout(
+ new OO.ui.TextInputWidget( {
+ multiline: true,
autosize: true,
value: 'Autosize\nAutosize\nAutosize\nAutosize'
} ),
@@ -793,6 +870,18 @@ OO.ui.Demo.static.pages.widgets = function ( demo ) {
),
new OO.ui.FieldLayout(
new OO.ui.TextInputWidget( {
+ multiline: true,
+ rows: 10,
+ autosize: true,
+ value: 'Autosize\nAutosize\nAutosize\nAutosize'
+ } ),
+ {
+ label: 'TextInputWidget (autosize, rows=10)\u200E',
+ align: 'top'
+ }
+ ),
+ new OO.ui.FieldLayout(
+ new OO.ui.TextInputWidget( {
icon: 'tag',
indicator: 'alert',
value: 'Text input with label',
@@ -817,6 +906,94 @@ OO.ui.Demo.static.pages.widgets = function ( demo ) {
}
),
new OO.ui.FieldLayout(
+ new OO.ui.TextInputWidget( {
+ value: 'Title attribute',
+ title: 'Title attribute with more information about me.'
+ } ),
+ {
+ label: 'TextInputWidget (with title)\u200E',
+ align: 'top'
+ }
+ ),
+ new OO.ui.FieldLayout(
+ new OO.ui.TextInputWidget( {
+ value: 'Accesskey A',
+ accessKey: 'a'
+ } ),
+ {
+ label: 'TextInputWidget (with Accesskey)\u200E',
+ align: 'top'
+ }
+ ),
+ new OO.ui.FieldLayout(
+ new OO.ui.SelectFileWidget( {} ),
+ {
+ label: 'SelectFileWidget\u200E',
+ align: 'top'
+ }
+ ),
+ new OO.ui.FieldLayout(
+ new OO.ui.SelectFileWidget( { accept: [ 'image/png', 'image/jpeg' ] } ),
+ {
+ label: 'SelectFileWidget (accept PNG and JPEG)\u200E',
+ align: 'top'
+ }
+ ),
+ new OO.ui.FieldLayout(
+ new OO.ui.SelectFileWidget( {
+ icon: 'tag',
+ indicator: 'required'
+ } ),
+ {
+ label: 'SelectFileWidget (icon, indicator)\u200E',
+ align: 'top'
+ }
+ ),
+ new OO.ui.FieldLayout(
+ new OO.ui.SelectFileWidget( {
+ icon: 'tag',
+ indicator: 'required',
+ disabled: true
+ } ),
+ {
+ label: 'SelectFileWidget (disabled)\u200E',
+ align: 'top'
+ }
+ ),
+ new OO.ui.FieldLayout(
+ new UnsupportedSelectFileWidget(),
+ {
+ label: 'SelectFileWidget (no browser support)\u200E',
+ align: 'top'
+ }
+ ),
+ new OO.ui.FieldLayout(
+ new OO.ui.SelectFileWidget( { showDropTarget: true } ),
+ {
+ label: 'SelectFileWidget (with drop target)\u200E',
+ align: 'top'
+ }
+ ),
+ new OO.ui.FieldLayout(
+ new OO.ui.SelectFileWidget( {
+ showDropTarget: true,
+ disabled: true
+ } ),
+ {
+ label: 'SelectFileWidget (with drop target, disabled)\u200E',
+ align: 'top'
+ }
+ ),
+ new OO.ui.FieldLayout(
+ new UnsupportedSelectFileWidget( {
+ showDropTarget: true
+ } ),
+ {
+ label: 'SelectFileWidget (with drop target, no browser support)\u200E',
+ align: 'top'
+ }
+ ),
+ new OO.ui.FieldLayout(
new OO.ui.DropdownWidget( {
label: 'Select one',
menu: {
@@ -933,7 +1110,8 @@ OO.ui.Demo.static.pages.widgets = function ( demo ) {
label: 'Third'
}
],
- value: 'b'
+ value: 'b',
+ title: 'Select an item'
} ),
{
label: 'DropdownInputWidget',
@@ -983,6 +1161,89 @@ OO.ui.Demo.static.pages.widgets = function ( demo ) {
}
),
new OO.ui.FieldLayout(
+ new OO.ui.CapsuleMultiSelectWidget( {
+ menu: {
+ items: [
+ new OO.ui.MenuOptionWidget( { data: 'abc', label: 'Label for abc' } ),
+ new OO.ui.MenuOptionWidget( { data: 'asd', label: 'Label for asd' } ),
+ new OO.ui.MenuOptionWidget( { data: 'jkl', label: 'Label for jkl' } ),
+ new OO.ui.MenuOptionWidget( { data: 'jjj', label: 'Label for jjj' } ),
+ new OO.ui.MenuOptionWidget( { data: 'zxc', label: 'Label for zxc' } ),
+ new OO.ui.MenuOptionWidget( { data: 'vbn', label: 'Label for vbn' } )
+ ]
+ }
+ } ),
+ {
+ label: 'CapsuleMultiSelectWidget',
+ align: 'top'
+ }
+ ),
+ new OO.ui.FieldLayout(
+ new OO.ui.CapsuleMultiSelectWidget( {
+ allowArbitrary: true,
+ icon: 'tag',
+ indicator: 'required',
+ menu: {
+ items: [
+ new OO.ui.MenuOptionWidget( { data: 'abc', label: 'Label for abc' } ),
+ new OO.ui.MenuOptionWidget( { data: 'asd', label: 'Label for asd' } ),
+ new OO.ui.MenuOptionWidget( { data: 'jkl', label: 'Label for jkl' } ),
+ new OO.ui.MenuOptionWidget( { data: 'jjj', label: 'Label for jjj' } ),
+ new OO.ui.MenuOptionWidget( { data: 'zxc', label: 'Label for zxc' } ),
+ new OO.ui.MenuOptionWidget( { data: 'vbn', label: 'Label for vbn' } )
+ ]
+ }
+ } ),
+ {
+ label: 'CapsuleMultiSelectWidget (icon, indicator, arbitrary values allowed)',
+ align: 'top'
+ }
+ ),
+ new OO.ui.FieldLayout(
+ new OO.ui.CapsuleMultiSelectWidget( {
+ disabled: true,
+ icon: 'tag',
+ indicator: 'required',
+ values: [ 'jkl', 'zxc' ],
+ menu: {
+ items: [
+ new OO.ui.MenuOptionWidget( { data: 'abc', label: 'Label for abc' } ),
+ new OO.ui.MenuOptionWidget( { data: 'asd', label: 'Label for asd' } ),
+ new OO.ui.MenuOptionWidget( { data: 'jkl', label: 'Label for jkl' } ),
+ new OO.ui.MenuOptionWidget( { data: 'jjj', label: 'Label for jjj' } ),
+ new OO.ui.MenuOptionWidget( { data: 'zxc', label: 'Label for zxc' } ),
+ new OO.ui.MenuOptionWidget( { data: 'vbn', label: 'Label for vbn' } )
+ ]
+ }
+ } ),
+ {
+ label: 'CapsuleMultiSelectWidget (disabled)\u200E',
+ align: 'top'
+ }
+ ),
+ new OO.ui.FieldLayout(
+ new OO.ui.CapsuleMultiSelectWidget( {
+ menu: {
+ items: [
+ new OO.ui.MenuOptionWidget( { data: 'abc', label: 'Label for abc' } ),
+ new OO.ui.MenuOptionWidget( { data: 'asd', label: 'Label for asd' } ),
+ new OO.ui.MenuOptionWidget( { data: 'jkl', label: 'Label for jkl' } )
+ ]
+ }
+ } ).addItemsFromData( [ 'abc', 'asd' ] ),
+ {
+ label: 'CapsuleMultiSelectWidget (initially selected)\u200E',
+ align: 'top'
+ }
+ ),
+ new OO.ui.FieldLayout(
+ capsuleWithPopup,
+ {
+ label: 'CapsuleMultiSelectWidget with NumberInputWidget popup\u200E',
+ align: 'top'
+ }
+ ),
+ new OO.ui.FieldLayout(
new OO.ui.ButtonInputWidget( {
label: 'Submit the form',
type: 'submit'
@@ -1002,14 +1263,58 @@ OO.ui.Demo.static.pages.widgets = function ( demo ) {
align: 'top',
label: 'ButtonInputWidget (using <input/>)\u200E'
}
+ ),
+ new OO.ui.FieldLayout(
+ new OO.ui.ButtonInputWidget( {
+ framed: false,
+ label: 'Submit the form',
+ type: 'submit'
+ } ),
+ {
+ align: 'top',
+ label: 'ButtonInputWidget (frameless)\u200E'
+ }
+ ),
+ new OO.ui.FieldLayout(
+ new OO.ui.ButtonInputWidget( {
+ framed: false,
+ label: 'Submit the form',
+ type: 'submit',
+ useInputTag: true
+ } ),
+ {
+ align: 'top',
+ label: 'ButtonInputWidget (frameless, using <input/>)\u200E'
+ }
)
]
} ),
new OO.ui.FieldsetLayout( {
- label: 'Horizontal alignment',
+ label: 'HorizontalLayout',
items: [
new OO.ui.FieldLayout(
- horizontalAlignmentWidget,
+ new OO.ui.Widget( {
+ content: [ new OO.ui.HorizontalLayout( {
+ items: [
+ new OO.ui.ButtonWidget( { label: 'Button' } ),
+ new OO.ui.ButtonGroupWidget( { items: [
+ new OO.ui.ToggleButtonWidget( { label: 'A' } ),
+ new OO.ui.ToggleButtonWidget( { label: 'B' } )
+ ] } ),
+ new OO.ui.ButtonInputWidget( { label: 'ButtonInput' } ),
+ new OO.ui.TextInputWidget( { value: 'TextInput' } ),
+ new OO.ui.DropdownInputWidget( { options: [
+ {
+ label: 'DropdownInput',
+ data: null
+ }
+ ] } ),
+ new OO.ui.CheckboxInputWidget( { selected: true } ),
+ new OO.ui.RadioInputWidget( { selected: true } ),
+ new OO.ui.LabelWidget( { label: 'Label' } )
+ ]
+ } ) ]
+ } ),
{
label: 'Multiple widgets shown as a single line, ' +
'as used in compact forms or in parts of a bigger widget.',
@@ -1230,6 +1535,24 @@ OO.ui.Demo.static.pages.widgets = function ( demo ) {
),
new OO.ui.FieldLayout(
new OO.ui.PopupButtonWidget( {
+ icon: 'info',
+ framed: false,
+ popup: {
+ head: true,
+ label: 'More information',
+ $content: $( '<p>Extra information here.</p><ul><li>Item one</li><li>Item two</li><li>Item three</li><li>Item four</li></ul><p>Even more information here which might well be clipped off the visible area.</p>' ),
+ $footer: $( '<p>And maybe a footer whilst we\'re at it?</p>' ),
+ padded: true,
+ align: 'forwards'
+ }
+ } ),
+ {
+ label: 'PopupButtonWidget (frameless, with popup head and footer, align: forwards)\u200E',
+ align: 'top'
+ }
+ ),
+ new OO.ui.FieldLayout(
+ new OO.ui.PopupButtonWidget( {
icon: 'menu',
label: 'Options',
popup: {
@@ -1286,8 +1609,28 @@ OO.ui.Demo.static.pages.widgets = function ( demo ) {
align: 'top'
}
),
+ new OO.ui.FieldLayout(
+ new OO.ui.ButtonWidget( {
+ label: 'Button'
+ } ),
+ {
+ label: 'FieldLayout with HTML help',
+ help: new OO.ui.HtmlSnippet( '<b>Bold text</b> is helpful!' ),
+ align: 'top'
+ }
+ ),
+ new OO.ui.FieldLayout(
+ new OO.ui.ButtonWidget( {
+ label: 'Button'
+ } ),
+ {
+ label: 'FieldLayout with title',
+ title: 'Field title text',
+ align: 'top'
+ }
+ ),
new OO.ui.ActionFieldLayout(
- new OO.ui.TextInputWidget( {} ),
+ new OO.ui.TextInputWidget(),
new OO.ui.ButtonWidget( {
label: 'Button'
} ),
@@ -1297,7 +1640,7 @@ OO.ui.Demo.static.pages.widgets = function ( demo ) {
}
),
new OO.ui.ActionFieldLayout(
- new OO.ui.TextInputWidget( {} ),
+ new OO.ui.TextInputWidget(),
new OO.ui.ButtonWidget( {
label: 'Button'
} ),
@@ -1307,7 +1650,7 @@ OO.ui.Demo.static.pages.widgets = function ( demo ) {
}
),
new OO.ui.ActionFieldLayout(
- new OO.ui.TextInputWidget( {} ),
+ new OO.ui.TextInputWidget(),
new OO.ui.ButtonWidget( {
label: 'Button'
} ),
@@ -1317,7 +1660,7 @@ OO.ui.Demo.static.pages.widgets = function ( demo ) {
}
),
new OO.ui.ActionFieldLayout(
- new OO.ui.TextInputWidget( {} ),
+ new OO.ui.TextInputWidget(),
new OO.ui.ButtonWidget( {
label: 'Button'
} ),
@@ -1327,7 +1670,7 @@ OO.ui.Demo.static.pages.widgets = function ( demo ) {
}
),
new OO.ui.ActionFieldLayout(
- new OO.ui.TextInputWidget( {} ),
+ new OO.ui.TextInputWidget(),
new OO.ui.ButtonWidget( {
label: 'Button'
} ),
@@ -1339,7 +1682,7 @@ OO.ui.Demo.static.pages.widgets = function ( demo ) {
}
),
new OO.ui.ActionFieldLayout(
- new OO.ui.TextInputWidget( {} ),
+ new OO.ui.TextInputWidget(),
new OO.ui.ButtonWidget( {
label: 'Button'
} ),
@@ -1347,6 +1690,37 @@ OO.ui.Demo.static.pages.widgets = function ( demo ) {
label: $( '<i>' ).text( 'ActionFieldLayout aligned top with rich text label' ),
align: 'top'
}
+ ),
+ new OO.ui.FieldLayout(
+ new OO.ui.TextInputWidget( {
+ value: ''
+ } ),
+ {
+ label: 'FieldLayout with notice',
+ notices: [ 'Please input a number.' ],
+ align: 'top'
+ }
+ ),
+ new OO.ui.FieldLayout(
+ new OO.ui.TextInputWidget( {
+ value: 'Foo'
+ } ),
+ {
+ label: 'FieldLayout with error message',
+ errors: [ 'The value must be a number.' ],
+ align: 'top'
+ }
+ ),
+ new OO.ui.FieldLayout(
+ new OO.ui.TextInputWidget( {
+ value: 'Foo'
+ } ),
+ {
+ label: 'FieldLayout with notice and error message',
+ notices: [ 'Please input a number.' ],
+ errors: [ 'The value must be a number.' ],
+ align: 'top'
+ }
)
]
} ),
@@ -1408,7 +1782,7 @@ OO.ui.Demo.static.pages.widgets = function ( demo ) {
$.each( fieldsets, function ( i, fieldsetLayout ) {
$.each( fieldsetLayout.getItems(), function ( j, fieldLayout ) {
fieldLayout.$element.append(
- demo.buildConsole( fieldLayout.fieldWidget, 'widget' )
+ demo.buildConsole( fieldLayout, 'layout', 'widget' )
);
} );
} );
diff --git a/vendor/oojs/oojs-ui/demos/styles/demo.css b/vendor/oojs/oojs-ui/demos/styles/demo.css
index 1c8d6139..9d6bad42 100644
--- a/vendor/oojs/oojs-ui/demos/styles/demo.css
+++ b/vendor/oojs/oojs-ui/demos/styles/demo.css
@@ -91,16 +91,8 @@ body {
/* Widgets demo */
-.oo-ui-demo-horizontal-alignment > .oo-ui-checkboxInputWidget,
-.oo-ui-demo-horizontal-alignment > .oo-ui-radioInputWidget,
-.oo-ui-demo-horizontal-alignment > .oo-ui-buttonInputWidget,
-.oo-ui-demo-horizontal-alignment > .oo-ui-textInputWidget,
-.oo-ui-demo-horizontal-alignment > .oo-ui-dropdownInputWidget {
- display: inline-block;
-}
-
-.oo-ui-demo-horizontal-alignment > .oo-ui-textInputWidget,
-.oo-ui-demo-horizontal-alignment > .oo-ui-dropdownInputWidget {
+.oo-ui-horizontalLayout > .oo-ui-textInputWidget,
+.oo-ui-horizontalLayout > .oo-ui-dropdownInputWidget {
max-width: 10em;
}
diff --git a/vendor/oojs/oojs-ui/demos/widgets.php b/vendor/oojs/oojs-ui/demos/widgets.php
index 494a7ac1..191e1def 100644
--- a/vendor/oojs/oojs-ui/demos/widgets.php
+++ b/vendor/oojs/oojs-ui/demos/widgets.php
@@ -1,5 +1,5 @@
<?php
- $autoload = '../vendor/autoload.php';
+ $autoload = __DIR__ . '/vendor/autoload.php';
if ( !file_exists( $autoload ) ) {
echo '<h1>Did you forget to run <code>composer install</code>?</h1>';
exit();
@@ -16,7 +16,7 @@
'raster' => '.raster',
);
$graphic = ( isset( $_GET['graphic'] ) && isset( $graphicSuffixMap[ $_GET['graphic'] ] ) )
- ? $_GET['graphic'] : 'vector';
+ ? $_GET['graphic'] : 'mixed';
$graphicSuffix = $graphicSuffixMap[ $graphic ];
$direction = ( isset( $_GET['direction'] ) && $_GET['direction'] === 'rtl' ) ? 'rtl' : 'ltr';
@@ -35,7 +35,7 @@
<head>
<meta charset="UTF-8">
<title>OOjs UI Widget Demo</title>
- <link rel="stylesheet" href="../dist/<?php echo $styleFileName; ?>" title="theme">
+ <link rel="stylesheet" href="dist/<?php echo $styleFileName; ?>">
<link rel="stylesheet" href="styles/demo<?php echo $directionSuffix; ?>.css">
</head>
<body class="oo-ui-<?php echo $direction; ?>">
@@ -46,15 +46,11 @@
'infusable' => true,
'items' => array(
new OOUI\ButtonWidget( array(
- 'id' => 'theme-mediawiki',
'label' => 'MediaWiki',
- 'data' => 'mediawiki',
'href' => '?' . http_build_query( array_merge( $query, array( 'theme' => 'mediawiki' ) ) ),
) ),
new OOUI\ButtonWidget( array(
- 'id' => 'theme-apex',
'label' => 'Apex',
- 'data' => 'apex',
'href' => '?' . http_build_query( array_merge( $query, array( 'theme' => 'apex' ) ) ),
) ),
)
@@ -89,6 +85,20 @@
) ),
)
) );
+ echo new OOUI\ButtonGroupWidget( array(
+ 'infusable' => true,
+ 'id' => 'oo-ui-demo-menu-infuse',
+ 'items' => array(
+ new OOUI\ButtonWidget( array(
+ 'label' => 'JS',
+ 'href' => ".#widgets-$theme-$graphic-$direction",
+ ) ),
+ new OOUI\ButtonWidget( array(
+ 'label' => 'PHP',
+ 'href' => '?' . http_build_query( $query ),
+ ) ),
+ )
+ ) );
?>
</div>
<?php
@@ -168,30 +178,6 @@
$buttonStyleShowcaseWidget->appendContent( new OOUI\HtmlSnippet( '<br />' ) );
}
- $horizontalAlignmentWidget = new OOUI\Widget( array(
- 'classes' => array( 'oo-ui-demo-horizontal-alignment' )
- ) );
- # Adding content after the fact does not play well with
- # infusability. We should be using a proper Layout here.
- $horizontalAlignmentWidget->appendContent(
- new OOUI\ButtonWidget( array( 'label' => 'Button' ) ),
- new OOUI\ButtonGroupWidget( array( 'items' => array(
- new OOUI\ButtonWidget( array( 'label' => 'A' ) ),
- new OOUI\ButtonWidget( array( 'label' => 'B' ) )
- ) ) ),
- new OOUI\ButtonInputWidget( array( 'label' => 'ButtonInput' ) ),
- new OOUI\TextInputWidget( array( 'value' => 'TextInput' ) ),
- new OOUI\DropdownInputWidget( array( 'options' => array(
- array(
- 'label' => 'DropdownInput',
- 'data' => null
- )
- ) ) ),
- new OOUI\CheckboxInputWidget( array( 'selected' => true ) ),
- new OOUI\RadioInputWidget( array( 'selected' => true ) ),
- new OOUI\LabelWidget( array( 'label' => 'Label' ) )
- );
-
$demoContainer->appendContent( new OOUI\FieldsetLayout( array(
'infusable' => true,
'label' => 'Simple buttons',
@@ -420,6 +406,16 @@
'label' => "ButtonWidget (frameless, constructive, disabled)\xE2\x80\x8E",
'align' => 'top'
)
+ ),
+ new OOUI\FieldLayout(
+ new OOUI\ButtonWidget( array(
+ 'label' => 'AccessKeyed',
+ 'accessKey' => 'k',
+ ) ),
+ array(
+ 'label' => "ButtonWidget (with accesskey k)\xE2\x80\x8E",
+ 'align' => 'top'
+ )
)
)
) ) );
@@ -525,6 +521,29 @@
)
),
new OOUI\FieldLayout(
+ new OOUI\RadioSelectInputWidget( array(
+ 'value' => 'dog',
+ 'options' => array(
+ array(
+ 'data' => 'cat',
+ 'label' => 'Cat'
+ ),
+ array(
+ 'data' => 'dog',
+ 'label' => 'Dog'
+ ),
+ array(
+ 'data' => 'goldfish',
+ 'label' => 'Goldfish'
+ ),
+ )
+ ) ),
+ array(
+ 'align' => 'top',
+ 'label' => 'RadioSelectInputWidget',
+ )
+ ),
+ new OOUI\FieldLayout(
new OOUI\TextInputWidget( array( 'value' => 'Text input' ) ),
array(
'label' => "TextInputWidget\xE2\x80\x8E",
@@ -540,11 +559,10 @@
),
new OOUI\FieldLayout(
new OOUI\TextInputWidget( array(
- 'indicator' => 'required',
'required' => true
) ),
array(
- 'label' => "TextInputWidget (indicator, required)\xE2\x80\x8E",
+ 'label' => "TextInputWidget (required)\xE2\x80\x8E",
'align' => 'top'
)
),
@@ -556,6 +574,13 @@
)
),
new OOUI\FieldLayout(
+ new OOUI\TextInputWidget( array( 'type' => 'search' ) ),
+ array(
+ 'label' => "TextInputWidget (type=search)\xE2\x80\x8E",
+ 'align' => 'top'
+ )
+ ),
+ new OOUI\FieldLayout(
new OOUI\TextInputWidget( array(
'value' => 'Readonly',
'readOnly' => true
@@ -577,6 +602,26 @@
),
new OOUI\FieldLayout(
new OOUI\TextInputWidget( array(
+ 'value' => 'Accesskey A',
+ 'accessKey' => 'a'
+ ) ),
+ array(
+ 'label' => "TextInputWidget (with Accesskey)\xE2\x80\x8E",
+ 'align' => 'top'
+ )
+ ),
+ new OOUI\FieldLayout(
+ new OOUI\TextInputWidget( array(
+ 'value' => 'Title attribute',
+ 'title' => 'Title attribute with more information about me.'
+ ) ),
+ array(
+ 'label' => "TextInputWidget (with title)\xE2\x80\x8E",
+ 'align' => 'top'
+ )
+ ),
+ new OOUI\FieldLayout(
+ new OOUI\TextInputWidget( array(
'multiline' => true,
'value' => "Multiline\nMultiline"
) ),
@@ -586,6 +631,17 @@
)
),
new OOUI\FieldLayout(
+ new OOUI\TextInputWidget( array(
+ 'multiline' => true,
+ 'rows' => 15,
+ 'value' => "Multiline\nMultiline"
+ ) ),
+ array(
+ 'label' => "TextInputWidget (multiline, rows=15)\xE2\x80\x8E",
+ 'align' => 'top'
+ )
+ ),
+ new OOUI\FieldLayout(
new OOUI\DropdownInputWidget( array(
'options' => array(
array(
@@ -601,7 +657,8 @@
'label' => 'Third'
)
),
- 'value' => 'b'
+ 'value' => 'b',
+ 'title' => 'Select an item'
) ),
array(
'label' => 'DropdownInputWidget',
@@ -631,26 +688,44 @@
)
)
) ) );
- # Again, $horizontalAlignmentWidget is not infusable because
- # it manually added content after creation. If we embed it
- # in an infusable FieldsetLayout, it will (recursively) be made
- # infusable. So protect the widget by wrapping it in a
- # <div> Tag.
- $wrappedFieldLayout = new OOUI\Tag( 'div' );
- $wrappedFieldLayout->appendContent(
- new OOUI\FieldLayout(
- $horizontalAlignmentWidget,
- array(
- 'label' => 'Multiple widgets shown as a single line, ' .
- 'as used in compact forms or in parts of a bigger widget.',
- 'align' => 'top'
- )
- )
- );
+ // We can't make the outer FieldsetLayout infusable, because the Widget in its FieldLayout
+ // is added with 'content', which is not preserved after infusion. But we need the Widget
+ // to wrap the HorizontalLayout. Need to think about this at some point.
$demoContainer->appendContent( new OOUI\FieldsetLayout( array(
- 'infusable' => true,
- 'label' => 'Horizontal alignment',
- 'items' => array( $wrappedFieldLayout ),
+ 'infusable' => false,
+ 'label' => 'HorizontalLayout',
+ 'items' => array(
+ new OOUI\FieldLayout(
+ new OOUI\Widget( array(
+ 'content' => new OOUI\HorizontalLayout( array(
+ 'infusable' => true,
+ 'items' => array(
+ new OOUI\ButtonWidget( array( 'label' => 'Button' ) ),
+ new OOUI\ButtonGroupWidget( array( 'items' => array(
+ new OOUI\ButtonWidget( array( 'label' => 'A' ) ),
+ new OOUI\ButtonWidget( array( 'label' => 'B' ) )
+ ) ) ),
+ new OOUI\ButtonInputWidget( array( 'label' => 'ButtonInput' ) ),
+ new OOUI\TextInputWidget( array( 'value' => 'TextInput' ) ),
+ new OOUI\DropdownInputWidget( array( 'options' => array(
+ array(
+ 'label' => 'DropdownInput',
+ 'data' => null
+ )
+ ) ) ),
+ new OOUI\CheckboxInputWidget( array( 'selected' => true ) ),
+ new OOUI\RadioInputWidget( array( 'selected' => true ) ),
+ new OOUI\LabelWidget( array( 'label' => 'Label' ) )
+ ),
+ ) ),
+ ) ),
+ array(
+ 'label' => 'Multiple widgets shown as a single line, ' .
+ 'as used in compact forms or in parts of a bigger widget.',
+ 'align' => 'top'
+ )
+ ),
+ ),
) ) );
$demoContainer->appendContent( new OOUI\FieldsetLayout( array(
'infusable' => true,
@@ -755,7 +830,121 @@
"in, duo ex inimicus perpetua complectitur, mel periculis similique at.\xE2\x80\x8E",
'align' => 'top'
)
- )
+ ),
+ new OOUI\FieldLayout(
+ new OOUI\ButtonWidget( array(
+ 'label' => 'Button'
+ ) ),
+ array(
+ 'label' => 'FieldLayout with HTML help',
+ 'help' => new OOUI\HtmlSnippet( '<b>Bold text</b> is helpful!' ),
+ 'align' => 'top'
+ )
+ ),
+ new OOUI\FieldLayout(
+ new OOUI\ButtonWidget( array(
+ 'label' => 'Button'
+ ) ),
+ array(
+ 'label' => 'FieldLayout with title',
+ 'title' => 'Field title text',
+ 'align' => 'top'
+ )
+ ),
+ new OOUI\ActionFieldLayout(
+ new OOUI\TextInputWidget(),
+ new OOUI\ButtonWidget( array(
+ 'label' => 'Button'
+ ) ),
+ array(
+ 'label' => 'ActionFieldLayout aligned left',
+ 'align' => 'left'
+ )
+ ),
+ new OOUI\ActionFieldLayout(
+ new OOUI\TextInputWidget(),
+ new OOUI\ButtonWidget( array(
+ 'label' => 'Button'
+ ) ),
+ array(
+ 'label' => 'ActionFieldLayout aligned inline',
+ 'align' => 'inline'
+ )
+ ),
+ new OOUI\ActionFieldLayout(
+ new OOUI\TextInputWidget(),
+ new OOUI\ButtonWidget( array(
+ 'label' => 'Button'
+ ) ),
+ array(
+ 'label' => 'ActionFieldLayout aligned right',
+ 'align' => 'right'
+ )
+ ),
+ new OOUI\ActionFieldLayout(
+ new OOUI\TextInputWidget(),
+ new OOUI\ButtonWidget( array(
+ 'label' => 'Button'
+ ) ),
+ array(
+ 'label' => 'ActionFieldLayout aligned top',
+ 'align' => 'top'
+ )
+ ),
+ new OOUI\ActionFieldLayout(
+ new OOUI\TextInputWidget(),
+ new OOUI\ButtonWidget( array(
+ 'label' => 'Button'
+ ) ),
+ array(
+ 'label' => 'ActionFieldLayout aligned top with help',
+ 'help' => 'I am an additional, helpful information. Lorem ipsum dolor sit amet, cibo pri ' .
+ "in, duo ex inimicus perpetua complectitur, mel periculis similique at.\xE2\x80\x8E",
+ 'align' => 'top'
+ )
+ ),
+ new OOUI\ActionFieldLayout(
+ new OOUI\TextInputWidget(),
+ new OOUI\ButtonWidget( array(
+ 'label' => 'Button'
+ ) ),
+ array(
+ 'label' =>
+ new OOUI\HtmlSnippet( '<i>ActionFieldLayout aligned top with rich text label</i>' ),
+ 'align' => 'top'
+ )
+ ),
+ new OOUI\FieldLayout(
+ new OOUI\TextInputWidget( array(
+ 'value' => ''
+ ) ),
+ array(
+ 'label' => 'FieldLayout with notice',
+ 'notices' => array( 'Please input a number.' ),
+ 'align' => 'top'
+ )
+ ),
+ new OOUI\FieldLayout(
+ new OOUI\TextInputWidget( array(
+ 'value' => 'Foo'
+ ) ),
+ array(
+ 'label' => 'FieldLayout with error message',
+ 'errors' => array( 'The value must be a number.' ),
+ 'align' => 'top'
+ )
+ ),
+ new OOUI\FieldLayout(
+ new OOUI\TextInputWidget( array(
+ 'value' => 'Foo'
+ ) ),
+ array(
+ 'label' => 'FieldLayout with notice and error message',
+ 'notices' => array( 'Please input a number.' ),
+ 'errors' => array( 'The value must be a number.' ),
+ 'align' => 'top'
+ )
+ ),
)
) ) );
@@ -820,11 +1009,11 @@
</div>
<!-- Demonstrate JavaScript "infusion" of PHP widgets -->
- <script src="../node_modules/jquery/dist/jquery.js"></script>
- <script src="../node_modules/oojs/dist/oojs.jquery.js"></script>
- <script src="../dist/oojs-ui.js"></script>
- <script src="../dist/oojs-ui-apex.js"></script>
- <script src="../dist/oojs-ui-mediawiki.js"></script>
- <script src="./infusion.js"></script>
+ <script src="node_modules/jquery/dist/jquery.js"></script>
+ <script src="node_modules/es5-shim/es5-shim.js"></script>
+ <script src="node_modules/oojs/dist/oojs.jquery.js"></script>
+ <script src="dist/oojs-ui.js"></script>
+ <script src="dist/oojs-ui-<?php echo $theme; ?>.js"></script>
+ <script src="infusion.js"></script>
</body>
</html>
diff --git a/vendor/oojs/oojs-ui/i18n/af.json b/vendor/oojs/oojs-ui/i18n/af.json
index 6f79e370..67ec517d 100644
--- a/vendor/oojs/oojs-ui/i18n/af.json
+++ b/vendor/oojs/oojs-ui/i18n/af.json
@@ -1,7 +1,8 @@
{
"@metadata": {
"authors": [
- "Naudefj"
+ "Naudefj",
+ "Fwolff"
]
},
"ooui-outline-control-move-down": "Skuif item af",
@@ -15,5 +16,8 @@
"ooui-dialog-process-error": "Iets het verkeerd gegaan",
"ooui-dialog-process-dismiss": "Sluit",
"ooui-dialog-process-retry": "Probeer weer",
- "ooui-dialog-process-continue": "Gaan voort"
+ "ooui-dialog-process-continue": "Gaan voort",
+ "ooui-selectfile-button-select": "Kies 'n lêer",
+ "ooui-selectfile-placeholder": "Geen lêer is gekies nie",
+ "ooui-selectfile-dragdrop-placeholder": "Laat val die lêer hier"
}
diff --git a/vendor/oojs/oojs-ui/i18n/ar.json b/vendor/oojs/oojs-ui/i18n/ar.json
index 058a1491..610e1eee 100644
--- a/vendor/oojs/oojs-ui/i18n/ar.json
+++ b/vendor/oojs/oojs-ui/i18n/ar.json
@@ -10,7 +10,9 @@
"زكريا",
"مشعل الحربي",
"ترجمان05",
- "Abanima"
+ "Abanima",
+ "محمد أحمد عبد الفتاح",
+ "Hiba Alshawi"
]
},
"ooui-outline-control-move-down": "انقل العنصر للأسفل",
@@ -24,5 +26,9 @@
"ooui-dialog-process-error": "حدث خطأ",
"ooui-dialog-process-dismiss": "أغلق",
"ooui-dialog-process-retry": "حاول مرة أخرى",
- "ooui-dialog-process-continue": "استمر"
+ "ooui-dialog-process-continue": "استمر",
+ "ooui-selectfile-button-select": "أختر ملف",
+ "ooui-selectfile-not-supported": "تحديد الملفات غير مدعوم",
+ "ooui-selectfile-placeholder": "لم يختر أي ملف",
+ "ooui-selectfile-dragdrop-placeholder": "ترك ملف هنا"
}
diff --git a/vendor/oojs/oojs-ui/i18n/arq.json b/vendor/oojs/oojs-ui/i18n/arq.json
index 80987818..61eb3844 100644
--- a/vendor/oojs/oojs-ui/i18n/arq.json
+++ b/vendor/oojs/oojs-ui/i18n/arq.json
@@ -8,9 +8,14 @@
"ooui-outline-control-move-up": "طلع الشيئ للفوق",
"ooui-outline-control-remove": "أمحي العنصر",
"ooui-toolbar-more": "زيادة",
+ "ooui-toolgroup-expand": "زيادة",
+ "ooui-toolgroup-collapse": "قليل",
"ooui-dialog-message-accept": "مليح",
"ooui-dialog-message-reject": "رجَع",
"ooui-dialog-process-error": "حاجه ما خدمتش مليح",
"ooui-dialog-process-dismiss": "أرفضها",
- "ooui-dialog-process-retry": "عاود جرب"
+ "ooui-dialog-process-retry": "عاود جرب",
+ "ooui-dialog-process-continue": "واصل",
+ "ooui-selectfile-not-supported": "تحديد الفيشيات ما هوش محدد",
+ "ooui-selectfile-placeholder": "ما اختاريتش حتا ملف"
}
diff --git a/vendor/oojs/oojs-ui/i18n/as.json b/vendor/oojs/oojs-ui/i18n/as.json
new file mode 100644
index 00000000..50532809
--- /dev/null
+++ b/vendor/oojs/oojs-ui/i18n/as.json
@@ -0,0 +1,25 @@
+{
+ "@metadata": {
+ "authors": [
+ "Gitartha.bordoloi",
+ "Dibya Dutta",
+ "IKHazarika"
+ ]
+ },
+ "ooui-outline-control-move-down": "সমল তললৈ স্থানান্তৰ কৰক",
+ "ooui-outline-control-move-up": "সমল ওপৰলৈ স্থানান্তৰ কৰক",
+ "ooui-outline-control-remove": "সমল আঁতৰাওক",
+ "ooui-toolbar-more": "অধিক",
+ "ooui-toolgroup-expand": "অধিক",
+ "ooui-toolgroup-collapse": "কম দেখাওক",
+ "ooui-dialog-message-accept": "শুদ্ধ",
+ "ooui-dialog-message-reject": "বাতিল কৰক",
+ "ooui-dialog-process-error": "কিবা ত্ৰুটি হৈছে",
+ "ooui-dialog-process-dismiss": "বাতিল",
+ "ooui-dialog-process-retry": "পুনৰ চেষ্টা কৰক",
+ "ooui-dialog-process-continue": "অব্যাহত ৰাখক",
+ "ooui-selectfile-button-select": "ফাইল নিৰ্বাচন কৰক",
+ "ooui-selectfile-not-supported": "নথি নিৰ্বাচন সমৰ্থন কৰা নাই",
+ "ooui-selectfile-placeholder": "কোনো নথি নিৰ্বাচিত কৰা হোৱা নাই",
+ "ooui-selectfile-dragdrop-placeholder": "ইয়াত ফাইল এৰক"
+}
diff --git a/vendor/oojs/oojs-ui/i18n/ast.json b/vendor/oojs/oojs-ui/i18n/ast.json
index 87d7688a..11761c6c 100644
--- a/vendor/oojs/oojs-ui/i18n/ast.json
+++ b/vendor/oojs/oojs-ui/i18n/ast.json
@@ -10,9 +10,16 @@
"ooui-outline-control-move-up": "Mover arriba l'elementu",
"ooui-outline-control-remove": "Desaniciar elementu",
"ooui-toolbar-more": "Más",
+ "ooui-toolgroup-expand": "Más",
+ "ooui-toolgroup-collapse": "Menos",
"ooui-dialog-message-accept": "Aceutar",
"ooui-dialog-message-reject": "Encaboxar",
"ooui-dialog-process-error": "Daqué funcionó mal",
"ooui-dialog-process-dismiss": "Descartar",
- "ooui-dialog-process-retry": "Vuelvi a intentalo"
+ "ooui-dialog-process-retry": "Vuelvi a intentalo",
+ "ooui-dialog-process-continue": "Siguir",
+ "ooui-selectfile-button-select": "Seleicionar un ficheru",
+ "ooui-selectfile-not-supported": "Nun hai encontu pa la seleición de ficheros",
+ "ooui-selectfile-placeholder": "Nun se seleicionó nengún ficheru",
+ "ooui-selectfile-dragdrop-placeholder": "Soltar el ficheru equí"
}
diff --git a/vendor/oojs/oojs-ui/i18n/be-tarask.json b/vendor/oojs/oojs-ui/i18n/be-tarask.json
index c5475f85..3548239a 100644
--- a/vendor/oojs/oojs-ui/i18n/be-tarask.json
+++ b/vendor/oojs/oojs-ui/i18n/be-tarask.json
@@ -4,10 +4,23 @@
"EugeneZelenko",
"Wizardist",
"Чаховіч Уладзіслаў",
- "Zedlik"
+ "Zedlik",
+ "Red Winged Duck",
+ "Renessaince"
]
},
- "ooui-outline-control-move-down": "Перасунуць ніжэй",
- "ooui-outline-control-move-up": "Перасунуць вышэй",
- "ooui-toolbar-more": "Болей"
+ "ooui-outline-control-move-down": "Перасунуць элемэнт ніжэй",
+ "ooui-outline-control-move-up": "Перасунуць элемэнт вышэй",
+ "ooui-outline-control-remove": "Выдаліць пункт",
+ "ooui-toolbar-more": "Болей",
+ "ooui-toolgroup-expand": "Болей",
+ "ooui-toolgroup-collapse": "Меней",
+ "ooui-dialog-message-accept": "Добра",
+ "ooui-dialog-message-reject": "Скасаваць",
+ "ooui-dialog-process-error": "Нешта пайшло ня так",
+ "ooui-dialog-process-dismiss": "Прапусьціць",
+ "ooui-dialog-process-retry": "Паспрабаваць зноў",
+ "ooui-dialog-process-continue": "Працягваць",
+ "ooui-selectfile-not-supported": "Выбар файлу не падтрымліваецца",
+ "ooui-selectfile-placeholder": "Ніводзін файл не абраны"
}
diff --git a/vendor/oojs/oojs-ui/i18n/be.json b/vendor/oojs/oojs-ui/i18n/be.json
index fb0f6880..7db7547b 100644
--- a/vendor/oojs/oojs-ui/i18n/be.json
+++ b/vendor/oojs/oojs-ui/i18n/be.json
@@ -2,9 +2,22 @@
"@metadata": {
"authors": [
"Чаховіч Уладзіслаў",
- "Artificial123"
+ "Artificial123",
+ "Goshaproject"
]
},
+ "ooui-outline-control-move-down": "Перамясціць элемент ўніз",
+ "ooui-outline-control-move-up": "Перамясціць элемент уверх",
+ "ooui-outline-control-remove": "Выдаліць элемент",
+ "ooui-toolbar-more": "Яшчэ",
+ "ooui-toolgroup-expand": "Яшчэ",
+ "ooui-toolgroup-collapse": "Менш",
"ooui-dialog-message-accept": "ОК",
- "ooui-dialog-message-reject": "Адмяніць"
+ "ooui-dialog-message-reject": "Адмяніць",
+ "ooui-dialog-process-error": "Штось пайшло не так…",
+ "ooui-dialog-process-dismiss": "Прапусціць",
+ "ooui-dialog-process-retry": "Паспрабаваць яшчэ раз",
+ "ooui-dialog-process-continue": "Працягнуць",
+ "ooui-selectfile-not-supported": "Выбраны файл не падтрымліваецца",
+ "ooui-selectfile-placeholder": "Файл не выбраны"
}
diff --git a/vendor/oojs/oojs-ui/i18n/bg.json b/vendor/oojs/oojs-ui/i18n/bg.json
index 02d95b52..dce3593c 100644
--- a/vendor/oojs/oojs-ui/i18n/bg.json
+++ b/vendor/oojs/oojs-ui/i18n/bg.json
@@ -4,9 +4,18 @@
"DCLXVI",
"Hristofor.mirchev",
"පසිඳු කාවින්ද",
- "Mitzev"
+ "Mitzev",
+ "Aquilax"
]
},
"ooui-outline-control-remove": "Премахване на обекта",
- "ooui-toolbar-more": "Още"
+ "ooui-toolbar-more": "Още",
+ "ooui-toolgroup-expand": "Още",
+ "ooui-toolgroup-collapse": "По-малко",
+ "ooui-dialog-message-accept": "OK",
+ "ooui-dialog-message-reject": "Отказ",
+ "ooui-dialog-process-error": "Нещо се обърка",
+ "ooui-dialog-process-dismiss": "Затвори",
+ "ooui-dialog-process-retry": "Опитайте отново",
+ "ooui-dialog-process-continue": "Продължаване"
}
diff --git a/vendor/oojs/oojs-ui/i18n/bn.json b/vendor/oojs/oojs-ui/i18n/bn.json
index 1cfa6c45..02d57e0c 100644
--- a/vendor/oojs/oojs-ui/i18n/bn.json
+++ b/vendor/oojs/oojs-ui/i18n/bn.json
@@ -8,7 +8,8 @@
"Runab",
"Sayak Sarkar",
"Aftabuzzaman",
- "RYasmeen (WMF)"
+ "RYasmeen (WMF)",
+ "NahidSultan"
]
},
"ooui-outline-control-move-down": "আইটেম নিচে স্থানান্তর",
@@ -22,5 +23,9 @@
"ooui-dialog-process-error": "কিছু একটায় ত্রুটি হয়েছে",
"ooui-dialog-process-dismiss": "বাতিল করুন",
"ooui-dialog-process-retry": "আবার চেষ্টা করুন",
- "ooui-dialog-process-continue": "অগ্রসর হোন"
+ "ooui-dialog-process-continue": "অগ্রসর হোন",
+ "ooui-selectfile-button-select": "একটি ফাইল নির্বাচন করুন",
+ "ooui-selectfile-not-supported": "চিত্র নির্বাচন সমর্থন করছে না।",
+ "ooui-selectfile-placeholder": " কোন চিত্র নির্বাচিত হয়নি।",
+ "ooui-selectfile-dragdrop-placeholder": "এখানে ফাইল ছাড়ুন"
}
diff --git a/vendor/oojs/oojs-ui/i18n/bs.json b/vendor/oojs/oojs-ui/i18n/bs.json
index 130bd8e5..d6f61ae5 100644
--- a/vendor/oojs/oojs-ui/i18n/bs.json
+++ b/vendor/oojs/oojs-ui/i18n/bs.json
@@ -1,10 +1,11 @@
{
"@metadata": {
"authors": [
- "DzWiki"
+ "DzWiki",
+ "Semso98"
]
},
- "ooui-outline-control-move-down": "Premjesti stavku dole",
+ "ooui-outline-control-move-down": "Premjesti stavku dolje",
"ooui-outline-control-move-up": "Premjesti stavku gore",
"ooui-outline-control-remove": "Ukloni stavku",
"ooui-toolbar-more": "Više",
diff --git a/vendor/oojs/oojs-ui/i18n/ca.json b/vendor/oojs/oojs-ui/i18n/ca.json
index ce3afa43..3077b605 100644
--- a/vendor/oojs/oojs-ui/i18n/ca.json
+++ b/vendor/oojs/oojs-ui/i18n/ca.json
@@ -10,7 +10,10 @@
"Vriullop",
"Toniher",
"Edustus",
- "Davidpar"
+ "Davidpar",
+ "Maceleiro",
+ "Kippelboy",
+ "Macofe"
]
},
"ooui-outline-control-move-down": "Baixa l'element",
@@ -24,5 +27,9 @@
"ooui-dialog-process-error": "Alguna cosa no ha funcionat",
"ooui-dialog-process-dismiss": "Descarta",
"ooui-dialog-process-retry": "Torneu-ho a provar",
- "ooui-dialog-process-continue": "Continua"
+ "ooui-dialog-process-continue": "Continua",
+ "ooui-selectfile-button-select": "Seleccioneu un fitxer",
+ "ooui-selectfile-not-supported": "El tipus de fitxer no és compatible",
+ "ooui-selectfile-placeholder": "No s'ha seleccionat cap fitxer",
+ "ooui-selectfile-dragdrop-placeholder": "Deixeu-hi anar el fitxer (o feu clic a navega)"
}
diff --git a/vendor/oojs/oojs-ui/i18n/ckb.json b/vendor/oojs/oojs-ui/i18n/ckb.json
index 0c66619d..d2a998c0 100644
--- a/vendor/oojs/oojs-ui/i18n/ckb.json
+++ b/vendor/oojs/oojs-ui/i18n/ckb.json
@@ -3,9 +3,18 @@
"authors": [
"Calak",
"Muhammed taha",
- "Serwan"
+ "Serwan",
+ "Pirehelokan"
]
},
+ "ooui-toolbar-more": "زیاتر",
+ "ooui-toolgroup-expand": "زیاتر",
+ "ooui-toolgroup-collapse": "کەمتر",
"ooui-dialog-message-accept": "باشە",
- "ooui-dialog-message-reject": "پاشگەزبوونەوە"
+ "ooui-dialog-message-reject": "پاشگەزبوونەوە",
+ "ooui-dialog-process-error": "ھەڵەیەک ڕووی داوە",
+ "ooui-dialog-process-dismiss": "لێگەڕان",
+ "ooui-dialog-process-retry": "دیسان ھەوڵ بدە",
+ "ooui-dialog-process-continue": "درێژە بدە",
+ "ooui-selectfile-placeholder": "ھیچ فایلێک ھەڵنەبژێراوە"
}
diff --git a/vendor/oojs/oojs-ui/i18n/cs.json b/vendor/oojs/oojs-ui/i18n/cs.json
index 1db9aed5..0d86aa64 100644
--- a/vendor/oojs/oojs-ui/i18n/cs.json
+++ b/vendor/oojs/oojs-ui/i18n/cs.json
@@ -25,5 +25,7 @@
"ooui-dialog-process-error": "Něco se pokazilo",
"ooui-dialog-process-dismiss": "Zavřít",
"ooui-dialog-process-retry": "Zkusit znovu",
- "ooui-dialog-process-continue": "Pokračovat"
+ "ooui-dialog-process-continue": "Pokračovat",
+ "ooui-selectfile-not-supported": "Výběr souboru není podporován",
+ "ooui-selectfile-placeholder": "Nebyl vybrán žádný soubor"
}
diff --git a/vendor/oojs/oojs-ui/i18n/cu.json b/vendor/oojs/oojs-ui/i18n/cu.json
index aa916af0..d627de06 100644
--- a/vendor/oojs/oojs-ui/i18n/cu.json
+++ b/vendor/oojs/oojs-ui/i18n/cu.json
@@ -5,5 +5,6 @@
]
},
"ooui-toolbar-more": "вѧщє",
- "ooui-toolgroup-expand": "вѧщє"
+ "ooui-toolgroup-expand": "вѧщє",
+ "ooui-dialog-process-error": "нѣчьто ꙁълѣ сѧ авило"
}
diff --git a/vendor/oojs/oojs-ui/i18n/da.json b/vendor/oojs/oojs-ui/i18n/da.json
index 0b847be1..30e3efae 100644
--- a/vendor/oojs/oojs-ui/i18n/da.json
+++ b/vendor/oojs/oojs-ui/i18n/da.json
@@ -7,10 +7,13 @@
"Laketown",
"Palnatoke",
"Simeondahl",
- "Tehnix"
+ "Tehnix",
+ "Macofe"
]
},
"ooui-outline-control-move-down": "Flyt ned",
"ooui-outline-control-move-up": "Flyt op",
- "ooui-toolbar-more": "Mere"
+ "ooui-toolbar-more": "Mere",
+ "ooui-toolgroup-expand": "Mere",
+ "ooui-dialog-process-continue": "Fortsæt"
}
diff --git a/vendor/oojs/oojs-ui/i18n/de.json b/vendor/oojs/oojs-ui/i18n/de.json
index 15624fd4..b48dfb5e 100644
--- a/vendor/oojs/oojs-ui/i18n/de.json
+++ b/vendor/oojs/oojs-ui/i18n/de.json
@@ -24,5 +24,9 @@
"ooui-dialog-process-error": "Etwas ist schief gelaufen",
"ooui-dialog-process-dismiss": "Ausblenden",
"ooui-dialog-process-retry": "Erneut versuchen",
- "ooui-dialog-process-continue": "Fortfahren"
+ "ooui-dialog-process-continue": "Fortfahren",
+ "ooui-selectfile-button-select": "Eine Datei auswählen",
+ "ooui-selectfile-not-supported": "Die Dateiauswahl wird nicht unterstützt",
+ "ooui-selectfile-placeholder": "Keine Datei ausgewählt",
+ "ooui-selectfile-dragdrop-placeholder": "Dateien hier ablegen"
}
diff --git a/vendor/oojs/oojs-ui/i18n/dty.json b/vendor/oojs/oojs-ui/i18n/dty.json
new file mode 100644
index 00000000..21742b69
--- /dev/null
+++ b/vendor/oojs/oojs-ui/i18n/dty.json
@@ -0,0 +1,18 @@
+{
+ "@metadata": {
+ "authors": [
+ "जनक राज भट्ट"
+ ]
+ },
+ "ooui-outline-control-move-down": "वस्तुलाई तल साददे",
+ "ooui-outline-control-move-up": "वस्तुलाई मथि साददे",
+ "ooui-outline-control-remove": "वस्तुलाई हटुन्या",
+ "ooui-toolbar-more": "झिक्क",
+ "ooui-toolgroup-expand": "झिक्क",
+ "ooui-toolgroup-collapse": "थोका",
+ "ooui-dialog-message-accept": "हुन्छ",
+ "ooui-dialog-message-reject": "रद्द",
+ "ooui-dialog-process-dismiss": "खारेज गद्दे",
+ "ooui-dialog-process-retry": "दोसरया प्रयास गर",
+ "ooui-dialog-process-continue": "जारी राख्या"
+}
diff --git a/vendor/oojs/oojs-ui/i18n/el.json b/vendor/oojs/oojs-ui/i18n/el.json
index 6fb7dbad..85384179 100644
--- a/vendor/oojs/oojs-ui/i18n/el.json
+++ b/vendor/oojs/oojs-ui/i18n/el.json
@@ -8,7 +8,8 @@
"Geraki",
"Glavkos",
"Nikosguard",
- "Tifa93"
+ "Tifa93",
+ "Stam.nikos"
]
},
"ooui-outline-control-move-down": "Μετακίνηση στοιχείου προς τα κάτω",
@@ -22,5 +23,8 @@
"ooui-dialog-process-error": "Κάτι πήγε στραβά",
"ooui-dialog-process-dismiss": "Απόρριψη",
"ooui-dialog-process-retry": "Δοκιμάστε ξανά",
- "ooui-dialog-process-continue": "Συνέχεια"
+ "ooui-dialog-process-continue": "Συνέχεια",
+ "ooui-selectfile-not-supported": "Επιλογή αρχείου δεν υποστηρίζεται",
+ "ooui-selectfile-placeholder": "Κανένα αρχείο δεν είναι επιλεγμένο",
+ "ooui-selectfile-dragdrop-placeholder": "Σύρετε το αρχείο εδώ"
}
diff --git a/vendor/oojs/oojs-ui/i18n/en-ca.json b/vendor/oojs/oojs-ui/i18n/en-ca.json
new file mode 100644
index 00000000..1a8e31be
--- /dev/null
+++ b/vendor/oojs/oojs-ui/i18n/en-ca.json
@@ -0,0 +1,22 @@
+{
+ "@metadata": {
+ "authors": [
+ "Skyllful"
+ ]
+ },
+ "ooui-outline-control-move-down": "Move item down",
+ "ooui-outline-control-move-up": "Move item up",
+ "ooui-outline-control-remove": "Remove item",
+ "ooui-toolbar-more": "More",
+ "ooui-toolgroup-expand": "More",
+ "ooui-toolgroup-collapse": "Less",
+ "ooui-dialog-message-accept": "OK",
+ "ooui-dialog-message-reject": "Cancel",
+ "ooui-dialog-process-error": "Something went wrong",
+ "ooui-dialog-process-dismiss": "Dismiss",
+ "ooui-dialog-process-retry": "Try again",
+ "ooui-dialog-process-continue": "Continue",
+ "ooui-selectfile-not-supported": "File(s) not supported",
+ "ooui-selectfile-placeholder": "No file selected",
+ "ooui-selectfile-dragdrop-placeholder": "Drop file here (or click to browse your computer)"
+}
diff --git a/vendor/oojs/oojs-ui/i18n/en.json b/vendor/oojs/oojs-ui/i18n/en.json
index 1db3fd85..be008321 100644
--- a/vendor/oojs/oojs-ui/i18n/en.json
+++ b/vendor/oojs/oojs-ui/i18n/en.json
@@ -27,5 +27,9 @@
"ooui-dialog-process-error": "Something went wrong",
"ooui-dialog-process-dismiss": "Dismiss",
"ooui-dialog-process-retry": "Try again",
- "ooui-dialog-process-continue": "Continue"
+ "ooui-dialog-process-continue": "Continue",
+ "ooui-selectfile-button-select": "Select a file",
+ "ooui-selectfile-not-supported": "File selection is not supported",
+ "ooui-selectfile-placeholder": "No file is selected",
+ "ooui-selectfile-dragdrop-placeholder": "Drop file here"
}
diff --git a/vendor/oojs/oojs-ui/i18n/eo.json b/vendor/oojs/oojs-ui/i18n/eo.json
index 8d9714c6..e7895650 100644
--- a/vendor/oojs/oojs-ui/i18n/eo.json
+++ b/vendor/oojs/oojs-ui/i18n/eo.json
@@ -4,10 +4,23 @@
"Happy5214",
"KuboF",
"Shirayuki",
- "Yekrats"
+ "Yekrats",
+ "Kvardek du"
]
},
"ooui-outline-control-move-down": "Movi eron suben",
"ooui-outline-control-move-up": "Movi eron supren",
- "ooui-toolbar-more": "Pli"
+ "ooui-outline-control-remove": "Forigi eron",
+ "ooui-toolbar-more": "Pli",
+ "ooui-toolgroup-expand": "Pli",
+ "ooui-toolgroup-collapse": "Mapli",
+ "ooui-dialog-message-accept": "Bone",
+ "ooui-dialog-message-reject": "Nuligi",
+ "ooui-dialog-process-error": "Io rompiĝis",
+ "ooui-dialog-process-dismiss": "Elimini",
+ "ooui-dialog-process-retry": "Reprovi",
+ "ooui-dialog-process-continue": "Daŭrigi",
+ "ooui-selectfile-button-select": "Elekti dosieron",
+ "ooui-selectfile-not-supported": "Dosieroselekto ne estas subtenata.",
+ "ooui-selectfile-placeholder": "Vi ne selektis dosieron"
}
diff --git a/vendor/oojs/oojs-ui/i18n/es.json b/vendor/oojs/oojs-ui/i18n/es.json
index 915791e6..fa11a362 100644
--- a/vendor/oojs/oojs-ui/i18n/es.json
+++ b/vendor/oojs/oojs-ui/i18n/es.json
@@ -29,5 +29,9 @@
"ooui-dialog-process-error": "Algo salió mal",
"ooui-dialog-process-dismiss": "Descartar",
"ooui-dialog-process-retry": "Intentar de nuevo",
- "ooui-dialog-process-continue": "Continuar"
+ "ooui-dialog-process-continue": "Continuar",
+ "ooui-selectfile-button-select": "Selecciona un archivo",
+ "ooui-selectfile-not-supported": "No se admite la selección de archivos",
+ "ooui-selectfile-placeholder": "Ningún archivo seleccionado",
+ "ooui-selectfile-dragdrop-placeholder": "Suelta el archivo aquí"
}
diff --git a/vendor/oojs/oojs-ui/i18n/et.json b/vendor/oojs/oojs-ui/i18n/et.json
index 6a212b6b..59b7ccd9 100644
--- a/vendor/oojs/oojs-ui/i18n/et.json
+++ b/vendor/oojs/oojs-ui/i18n/et.json
@@ -2,7 +2,8 @@
"@metadata": {
"authors": [
"Avjoska",
- "Pikne"
+ "Pikne",
+ "Suwa"
]
},
"ooui-outline-control-move-down": "Liiguta üksust allapoole",
@@ -16,5 +17,9 @@
"ooui-dialog-process-error": "Midagi läks valesti",
"ooui-dialog-process-dismiss": "Hülga",
"ooui-dialog-process-retry": "Proovi uuesti",
- "ooui-dialog-process-continue": "Jätka"
+ "ooui-dialog-process-continue": "Jätka",
+ "ooui-selectfile-button-select": "Vali fail",
+ "ooui-selectfile-not-supported": "Faili valiku tugi puudub",
+ "ooui-selectfile-placeholder": "Faili ei ole valitud",
+ "ooui-selectfile-dragdrop-placeholder": "Lohista fail siia"
}
diff --git a/vendor/oojs/oojs-ui/i18n/eu.json b/vendor/oojs/oojs-ui/i18n/eu.json
index e947582d..e5073251 100644
--- a/vendor/oojs/oojs-ui/i18n/eu.json
+++ b/vendor/oojs/oojs-ui/i18n/eu.json
@@ -4,17 +4,23 @@
"An13sa",
"Unai Fdz. de Betoño",
"Xabier Armendaritz",
- "Subi"
+ "Subi",
+ "Sator"
]
},
"ooui-outline-control-move-down": "Mugitu itema beherantz",
"ooui-outline-control-move-up": "Mugitu itema gorantz",
+ "ooui-outline-control-remove": "Elementua kendu",
"ooui-toolbar-more": "Gehiago",
"ooui-toolgroup-expand": "Gehiago",
"ooui-toolgroup-collapse": "Gutxiago",
"ooui-dialog-message-accept": "Ados",
"ooui-dialog-message-reject": "Utzi",
"ooui-dialog-process-error": "Zerbaitek huts egin du",
+ "ooui-dialog-process-dismiss": "Utzi",
"ooui-dialog-process-retry": "Saiatu berriro",
- "ooui-dialog-process-continue": "Jarraitu"
+ "ooui-dialog-process-continue": "Jarraitu",
+ "ooui-selectfile-button-select": "Fitxategi bat aukeratu",
+ "ooui-selectfile-not-supported": "Fitxategi aukeraketa ez da onartzen",
+ "ooui-selectfile-placeholder": "Ez da fitxategirik hautatu"
}
diff --git a/vendor/oojs/oojs-ui/i18n/fa.json b/vendor/oojs/oojs-ui/i18n/fa.json
index 7cfcfa21..0375c8eb 100644
--- a/vendor/oojs/oojs-ui/i18n/fa.json
+++ b/vendor/oojs/oojs-ui/i18n/fa.json
@@ -11,7 +11,10 @@
"Taha",
"درفش کاویانی",
"Armin1392",
- "Alirezaaa"
+ "Alirezaaa",
+ "Leyth",
+ "الناز",
+ "فلورانس"
]
},
"ooui-outline-control-move-down": "انتقال مورد به پایین",
@@ -23,7 +26,11 @@
"ooui-dialog-message-accept": "تأیید",
"ooui-dialog-message-reject": "لغو",
"ooui-dialog-process-error": "مشکلی وجود دارد",
- "ooui-dialog-process-dismiss": "نپذیرفتن",
- "ooui-dialog-process-retry": "دوباره امتحان کن",
- "ooui-dialog-process-continue": "ادامه"
+ "ooui-dialog-process-dismiss": "رد",
+ "ooui-dialog-process-retry": "دوباره امتحان کنید",
+ "ooui-dialog-process-continue": "ادامه",
+ "ooui-selectfile-button-select": "یک فایل انتخاب کنید",
+ "ooui-selectfile-not-supported": "انتخاب پرونده پشتیبانی نمی‌شود",
+ "ooui-selectfile-placeholder": "هیچ پرونده‌ای انتخاب نشده است",
+ "ooui-selectfile-dragdrop-placeholder": "فایل را اینجا رها کنید"
}
diff --git a/vendor/oojs/oojs-ui/i18n/fi.json b/vendor/oojs/oojs-ui/i18n/fi.json
index 3fb4110c..bdf015f9 100644
--- a/vendor/oojs/oojs-ui/i18n/fi.json
+++ b/vendor/oojs/oojs-ui/i18n/fi.json
@@ -13,19 +13,23 @@
"Silvonen",
"Skalman",
"Stryn",
- "VezonThunder"
+ "VezonThunder",
+ "Alluk."
]
},
"ooui-outline-control-move-down": "Siirrä kohdetta alaspäin",
"ooui-outline-control-move-up": "Siirrä kohdetta ylöspäin",
"ooui-outline-control-remove": "Poista kohde",
"ooui-toolbar-more": "Lisää",
- "ooui-toolgroup-expand": "Enemmän",
- "ooui-toolgroup-collapse": "Vähemmän",
+ "ooui-toolgroup-expand": "Näytä lisää",
+ "ooui-toolgroup-collapse": "Näytä vähemmän",
"ooui-dialog-message-accept": "OK",
- "ooui-dialog-message-reject": "Peruuta",
+ "ooui-dialog-message-reject": "Peru",
"ooui-dialog-process-error": "Jokin meni pieleen",
"ooui-dialog-process-dismiss": "Hylkää",
"ooui-dialog-process-retry": "Yritä uudelleen",
- "ooui-dialog-process-continue": "Jatka"
+ "ooui-dialog-process-continue": "Jatka",
+ "ooui-selectfile-not-supported": "Tiedoston valitsemista ei tueta",
+ "ooui-selectfile-placeholder": "Tiedostoa ei ole valittu",
+ "ooui-selectfile-dragdrop-placeholder": "Pudota tiedosto (tai selaa tiedostoja napsauttamalla)"
}
diff --git a/vendor/oojs/oojs-ui/i18n/fr.json b/vendor/oojs/oojs-ui/i18n/fr.json
index 9144cb01..92015a4f 100644
--- a/vendor/oojs/oojs-ui/i18n/fr.json
+++ b/vendor/oojs/oojs-ui/i18n/fr.json
@@ -27,19 +27,25 @@
"Verdy p",
"Wyz",
"SnowedEarth",
- "Jdforrester"
+ "Jdforrester",
+ "Wladek92",
+ "Harmonia Amanda"
]
},
- "ooui-outline-control-move-down": "Faire descendre l’élément",
- "ooui-outline-control-move-up": "Faire monter l’élément",
+ "ooui-outline-control-move-down": "Descendre l’élément",
+ "ooui-outline-control-move-up": "Monter l’élément",
"ooui-outline-control-remove": "Supprimer l’élément",
"ooui-toolbar-more": "Plus",
"ooui-toolgroup-expand": "Plus",
"ooui-toolgroup-collapse": "Moins",
"ooui-dialog-message-accept": "OK",
"ooui-dialog-message-reject": "Annuler",
- "ooui-dialog-process-error": "Quelque chose a mal tourné",
+ "ooui-dialog-process-error": "Quelque chose s'est mal passé",
"ooui-dialog-process-dismiss": "Rejeter",
- "ooui-dialog-process-retry": "Réessayez",
- "ooui-dialog-process-continue": "Continuer"
+ "ooui-dialog-process-retry": "Réessayer",
+ "ooui-dialog-process-continue": "Continuer",
+ "ooui-selectfile-button-select": "Sélectionner un fichier",
+ "ooui-selectfile-not-supported": "La sélection de fichier n’est pas prise en charge",
+ "ooui-selectfile-placeholder": "Aucun fichier sélectionné",
+ "ooui-selectfile-dragdrop-placeholder": "Déposer le fichier ici"
}
diff --git a/vendor/oojs/oojs-ui/i18n/gl.json b/vendor/oojs/oojs-ui/i18n/gl.json
index a4339f47..4cb28399 100644
--- a/vendor/oojs/oojs-ui/i18n/gl.json
+++ b/vendor/oojs/oojs-ui/i18n/gl.json
@@ -18,5 +18,9 @@
"ooui-dialog-process-error": "Algo foi mal",
"ooui-dialog-process-dismiss": "Agochar",
"ooui-dialog-process-retry": "Inténteo de novo",
- "ooui-dialog-process-continue": "Continuar"
+ "ooui-dialog-process-continue": "Continuar",
+ "ooui-selectfile-button-select": "Seleccionar un ficheiro",
+ "ooui-selectfile-not-supported": "Non está soportada a selección de ficheiros",
+ "ooui-selectfile-placeholder": "Non se seleccionou ningún ficheiro",
+ "ooui-selectfile-dragdrop-placeholder": "Solte un ficheiro aquí"
}
diff --git a/vendor/oojs/oojs-ui/i18n/glk.json b/vendor/oojs/oojs-ui/i18n/glk.json
new file mode 100644
index 00000000..9b15046f
--- /dev/null
+++ b/vendor/oojs/oojs-ui/i18n/glk.json
@@ -0,0 +1,23 @@
+{
+ "@metadata": {
+ "authors": [
+ "V6rg"
+ ]
+ },
+ "ooui-outline-control-move-down": "مأسمکه جابجا بۊکۊن جير",
+ "ooui-outline-control-move-up": "مأسمکه جابجا بۊکۊن جؤر",
+ "ooui-outline-control-remove": "مأسمکه حذفأکۊن",
+ "ooui-toolbar-more": "ويشتر",
+ "ooui-toolgroup-expand": "ويشتر",
+ "ooui-toolgroup-collapse": "کمتر",
+ "ooui-dialog-message-accept": "خؤ",
+ "ooui-dialog-message-reject": "لغو",
+ "ooui-dialog-process-error": "ىک مؤشکلي هنأ",
+ "ooui-dialog-process-dismiss": "وأبدي",
+ "ooui-dialog-process-retry": "هنده حقسأى بۊکۊنين",
+ "ooui-dialog-process-continue": "سره",
+ "ooui-selectfile-button-select": "ىکته فاىله دؤجين بۊکۊنين",
+ "ooui-selectfile-not-supported": "نشأنهىکته فاىله دؤجين گۊدن",
+ "ooui-selectfile-placeholder": "هيچ فاىلي دؤجين نۊبؤ",
+ "ooui-selectfile-dragdrop-placeholder": "فاىله ائره فدي"
+}
diff --git a/vendor/oojs/oojs-ui/i18n/gu.json b/vendor/oojs/oojs-ui/i18n/gu.json
index 2d8315bf..5c48b9ef 100644
--- a/vendor/oojs/oojs-ui/i18n/gu.json
+++ b/vendor/oojs/oojs-ui/i18n/gu.json
@@ -3,15 +3,23 @@
"authors": [
"Ashok modhvadia",
"KartikMistry",
- "The Discoverer"
+ "The Discoverer",
+ "NehalDaveND",
+ "Dsvyas"
]
},
"ooui-outline-control-move-down": "વસ્તુ નીચે ખસેડો",
"ooui-outline-control-move-up": "વસ્તુ ઉપર ખસેડો",
"ooui-outline-control-remove": "વસ્તુ હટાવો",
"ooui-toolbar-more": "વધુ",
+ "ooui-toolgroup-expand": "વધુ",
+ "ooui-toolgroup-collapse": "ઓછા",
"ooui-dialog-message-accept": "બરાબર",
"ooui-dialog-message-reject": "રદ કરો",
"ooui-dialog-process-error": "કંઇક ગરબડ થઇ",
- "ooui-dialog-process-retry": "ફરી પ્રયત્ન કરો"
+ "ooui-dialog-process-dismiss": "વિસર્જન",
+ "ooui-dialog-process-retry": "ફરી પ્રયત્ન કરો",
+ "ooui-dialog-process-continue": "ચાલુ રાખો",
+ "ooui-selectfile-not-supported": "ફાઇલ પસંદગીની જોગવાઈ નથી",
+ "ooui-selectfile-placeholder": "કોઇ ફાઇલ પસંદ નથી કરાઈ"
}
diff --git a/vendor/oojs/oojs-ui/i18n/he.json b/vendor/oojs/oojs-ui/i18n/he.json
index cadc416c..650d67dd 100644
--- a/vendor/oojs/oojs-ui/i18n/he.json
+++ b/vendor/oojs/oojs-ui/i18n/he.json
@@ -26,5 +26,9 @@
"ooui-dialog-process-error": "משהו השתבש",
"ooui-dialog-process-dismiss": "לוותר",
"ooui-dialog-process-retry": "לנסות שוב",
- "ooui-dialog-process-continue": "המשך"
+ "ooui-dialog-process-continue": "המשך",
+ "ooui-selectfile-button-select": "נא לבחור קובץ",
+ "ooui-selectfile-not-supported": "בחירת קבצים אינה נתמכת",
+ "ooui-selectfile-placeholder": "לא נבחר שום קובץ",
+ "ooui-selectfile-dragdrop-placeholder": "נא לשחרר את הקובץ כאן"
}
diff --git a/vendor/oojs/oojs-ui/i18n/hi.json b/vendor/oojs/oojs-ui/i18n/hi.json
index ce86aaab..573096f3 100644
--- a/vendor/oojs/oojs-ui/i18n/hi.json
+++ b/vendor/oojs/oojs-ui/i18n/hi.json
@@ -6,7 +6,8 @@
"Rajesh",
"Siddhartha Ghai",
"Goelujjwal",
- "Ankita-ks"
+ "Ankita-ks",
+ "Param Mudgal"
]
},
"ooui-outline-control-move-down": "प्रविष्टि नीचे ले जाएँ",
@@ -20,5 +21,7 @@
"ooui-dialog-process-error": "कुछ गलत हुअा है",
"ooui-dialog-process-dismiss": "ख़ारिज करें",
"ooui-dialog-process-retry": "पुनः प्रयास करें",
- "ooui-dialog-process-continue": "जारी रखें"
+ "ooui-dialog-process-continue": "जारी रखें",
+ "ooui-selectfile-not-supported": "फ़ाइल का चयन समर्थित नहीं है",
+ "ooui-selectfile-placeholder": "कोई फाइल चुनी नही गई हेै"
}
diff --git a/vendor/oojs/oojs-ui/i18n/hrx.json b/vendor/oojs/oojs-ui/i18n/hrx.json
new file mode 100644
index 00000000..1534af76
--- /dev/null
+++ b/vendor/oojs/oojs-ui/i18n/hrx.json
@@ -0,0 +1,12 @@
+{
+ "@metadata": {
+ "authors": [
+ "Midnight Gambler"
+ ]
+ },
+ "ooui-toolbar-more": "Meahr",
+ "ooui-toolgroup-expand": "Meahr",
+ "ooui-dialog-message-accept": "OK",
+ "ooui-dialog-message-reject": "Abbreche",
+ "ooui-dialog-process-dismiss": "Ausblenne"
+}
diff --git a/vendor/oojs/oojs-ui/i18n/hu-formal.json b/vendor/oojs/oojs-ui/i18n/hu-formal.json
new file mode 100644
index 00000000..34aa0ae6
--- /dev/null
+++ b/vendor/oojs/oojs-ui/i18n/hu-formal.json
@@ -0,0 +1,21 @@
+{
+ "@metadata": {
+ "authors": [
+ "Misibacsi"
+ ]
+ },
+ "ooui-outline-control-move-down": "Elem mozgatása lefelé",
+ "ooui-outline-control-move-up": "Elem mozgatása felfelé",
+ "ooui-outline-control-remove": "Elem eltávolítása",
+ "ooui-toolbar-more": "Tovább...",
+ "ooui-toolgroup-expand": "Tovább",
+ "ooui-toolgroup-collapse": "Kevesebb",
+ "ooui-dialog-message-accept": "Rendben",
+ "ooui-dialog-message-reject": "Mégse",
+ "ooui-dialog-process-error": "Valami elromlott.",
+ "ooui-dialog-process-dismiss": "Mégse",
+ "ooui-dialog-process-retry": "Próbálja újra",
+ "ooui-dialog-process-continue": "Folytatás",
+ "ooui-selectfile-not-supported": "A fájl kiválasztása nincs támogatva",
+ "ooui-selectfile-placeholder": "Nincs fájl kiválasztva"
+}
diff --git a/vendor/oojs/oojs-ui/i18n/hu.json b/vendor/oojs/oojs-ui/i18n/hu.json
index d50e62da..acd9d3b5 100644
--- a/vendor/oojs/oojs-ui/i18n/hu.json
+++ b/vendor/oojs/oojs-ui/i18n/hu.json
@@ -6,18 +6,22 @@
"Misibacsi",
"ViDam",
"Tacsipacsi",
- "Csega"
+ "Csega",
+ "Kishajnalka"
]
},
"ooui-outline-control-move-down": "Elem mozgatása lefelé",
"ooui-outline-control-move-up": "Elem mozgatása felfelé",
"ooui-outline-control-remove": "Elem eltávolítása",
- "ooui-toolbar-more": "Tovább...",
+ "ooui-toolbar-more": "Több",
"ooui-toolgroup-expand": "Több",
"ooui-toolgroup-collapse": "Kevesebb",
"ooui-dialog-message-accept": "OK",
"ooui-dialog-message-reject": "Mégse",
+ "ooui-dialog-process-error": "Valami elromlott",
"ooui-dialog-process-dismiss": "Elrejt",
"ooui-dialog-process-retry": "Próbáld újra",
- "ooui-dialog-process-continue": "Folytatás"
+ "ooui-dialog-process-continue": "Folytatás",
+ "ooui-selectfile-not-supported": "A fájl kiválasztása nincs támogatva",
+ "ooui-selectfile-placeholder": "Nincs fájl kiválasztva"
}
diff --git a/vendor/oojs/oojs-ui/i18n/hy.json b/vendor/oojs/oojs-ui/i18n/hy.json
index 2aaf4e46..c2b45a8b 100644
--- a/vendor/oojs/oojs-ui/i18n/hy.json
+++ b/vendor/oojs/oojs-ui/i18n/hy.json
@@ -3,7 +3,8 @@
"authors": [
"Vacio",
"Xelgen",
- "Դավիթ Սարոյան"
+ "Դավիթ Սարոյան",
+ "Vahe Gharakhanyan"
]
},
"ooui-outline-control-move-down": "Իջեցնել կետը",
@@ -17,5 +18,7 @@
"ooui-dialog-process-error": "Ինչ-որ սխալ է տեղի ունեցել",
"ooui-dialog-process-dismiss": "Փակել",
"ooui-dialog-process-retry": "Կրկին փորձել",
- "ooui-dialog-process-continue": "Շարունակել"
+ "ooui-dialog-process-continue": "Շարունակել",
+ "ooui-selectfile-not-supported": "Ֆայլի ընտրությունը չի պաշտպանվում",
+ "ooui-selectfile-placeholder": "Ֆայլն ընտրված չէ"
}
diff --git a/vendor/oojs/oojs-ui/i18n/ia.json b/vendor/oojs/oojs-ui/i18n/ia.json
index b374b6f6..ceb27c9f 100644
--- a/vendor/oojs/oojs-ui/i18n/ia.json
+++ b/vendor/oojs/oojs-ui/i18n/ia.json
@@ -8,9 +8,16 @@
"ooui-outline-control-move-up": "Displaciar elemento in alto",
"ooui-outline-control-remove": "Remover elemento",
"ooui-toolbar-more": "Plus",
+ "ooui-toolgroup-expand": "Plus",
+ "ooui-toolgroup-collapse": "Minus",
"ooui-dialog-message-accept": "OK",
"ooui-dialog-message-reject": "Cancellar",
"ooui-dialog-process-error": "Qualcosa ha vadite mal",
"ooui-dialog-process-dismiss": "Clauder",
- "ooui-dialog-process-retry": "Reprobar"
+ "ooui-dialog-process-retry": "Reprobar",
+ "ooui-dialog-process-continue": "Continuar",
+ "ooui-selectfile-button-select": "Selige un file",
+ "ooui-selectfile-not-supported": "Le selection de files non es supportate",
+ "ooui-selectfile-placeholder": "Nulle file es seligite",
+ "ooui-selectfile-dragdrop-placeholder": "Depone file hic"
}
diff --git a/vendor/oojs/oojs-ui/i18n/id.json b/vendor/oojs/oojs-ui/i18n/id.json
index bd65e71a..400a4325 100644
--- a/vendor/oojs/oojs-ui/i18n/id.json
+++ b/vendor/oojs/oojs-ui/i18n/id.json
@@ -22,5 +22,7 @@
"ooui-dialog-process-error": "Ada yang tidak beres",
"ooui-dialog-process-dismiss": "Tutup",
"ooui-dialog-process-retry": "Coba lagi",
- "ooui-dialog-process-continue": "Lanjutkan"
+ "ooui-dialog-process-continue": "Lanjutkan",
+ "ooui-selectfile-not-supported": "Peilihan berkas tidak didukung",
+ "ooui-selectfile-placeholder": "Tidak ada berkas yang terpilih"
}
diff --git a/vendor/oojs/oojs-ui/i18n/ilo.json b/vendor/oojs/oojs-ui/i18n/ilo.json
index b37beae1..287c86d6 100644
--- a/vendor/oojs/oojs-ui/i18n/ilo.json
+++ b/vendor/oojs/oojs-ui/i18n/ilo.json
@@ -15,5 +15,7 @@
"ooui-dialog-process-error": "Adda madi a napasamak",
"ooui-dialog-process-dismiss": "Pugsayen",
"ooui-dialog-process-retry": "Padasen manen",
- "ooui-dialog-process-continue": "Agtuloy"
+ "ooui-dialog-process-continue": "Agtuloy",
+ "ooui-selectfile-not-supported": "Saan a masuportaran ti panagpili ti papeles",
+ "ooui-selectfile-placeholder": "Awan ti napili a papeles"
}
diff --git a/vendor/oojs/oojs-ui/i18n/is.json b/vendor/oojs/oojs-ui/i18n/is.json
index 3a4e1454..574c5927 100644
--- a/vendor/oojs/oojs-ui/i18n/is.json
+++ b/vendor/oojs/oojs-ui/i18n/is.json
@@ -16,5 +16,9 @@
"ooui-dialog-process-error": "Eitthvað mistókst",
"ooui-dialog-process-dismiss": "Loka",
"ooui-dialog-process-retry": "Reyna aftur",
- "ooui-dialog-process-continue": "Halda áfram"
+ "ooui-dialog-process-continue": "Halda áfram",
+ "ooui-selectfile-button-select": "Velja skrá",
+ "ooui-selectfile-not-supported": "Skráar val er ekki stutt.",
+ "ooui-selectfile-placeholder": "Engin skrá er valin",
+ "ooui-selectfile-dragdrop-placeholder": "Slepptu skránni hérna"
}
diff --git a/vendor/oojs/oojs-ui/i18n/it.json b/vendor/oojs/oojs-ui/i18n/it.json
index 0ff8af8f..68a25b5d 100644
--- a/vendor/oojs/oojs-ui/i18n/it.json
+++ b/vendor/oojs/oojs-ui/i18n/it.json
@@ -12,19 +12,26 @@
"Minerva Titani",
"Raoli",
"Una giornata uggiosa '94",
- "Ontsed"
+ "Ontsed",
+ "Alexmar983",
+ "Nemo bis",
+ "Jdforrester"
]
},
"ooui-outline-control-move-down": "Sposta in basso",
"ooui-outline-control-move-up": "Sposta in alto",
"ooui-outline-control-remove": "Rimuovi elemento",
"ooui-toolbar-more": "Altro",
- "ooui-toolgroup-expand": "Più",
+ "ooui-toolgroup-expand": "Altro",
"ooui-toolgroup-collapse": "Meno",
"ooui-dialog-message-accept": "OK",
"ooui-dialog-message-reject": "Annulla",
"ooui-dialog-process-error": "Qualcosa è andato storto",
"ooui-dialog-process-dismiss": "Nascondi",
"ooui-dialog-process-retry": "Riprova",
- "ooui-dialog-process-continue": "Continua"
+ "ooui-dialog-process-continue": "Continua",
+ "ooui-selectfile-button-select": "Seleziona un file",
+ "ooui-selectfile-not-supported": "La selezione del file non è supportata",
+ "ooui-selectfile-placeholder": "Nessun file è selezionato",
+ "ooui-selectfile-dragdrop-placeholder": "Posiziona i files qui"
}
diff --git a/vendor/oojs/oojs-ui/i18n/ja.json b/vendor/oojs/oojs-ui/i18n/ja.json
index ec86124e..d0df0274 100644
--- a/vendor/oojs/oojs-ui/i18n/ja.json
+++ b/vendor/oojs/oojs-ui/i18n/ja.json
@@ -6,7 +6,8 @@
"Penn Station",
"Shirayuki",
"Takot",
- "Los688"
+ "Los688",
+ "Sujiniku"
]
},
"ooui-outline-control-move-down": "項目を下に移動させる",
@@ -20,5 +21,9 @@
"ooui-dialog-process-error": "エラーが発生しました…",
"ooui-dialog-process-dismiss": "閉じる",
"ooui-dialog-process-retry": "もう一度お試しください",
- "ooui-dialog-process-continue": "続行"
+ "ooui-dialog-process-continue": "続行",
+ "ooui-selectfile-button-select": "ファイルを選択",
+ "ooui-selectfile-not-supported": "ファイルの選択はサポートされていません",
+ "ooui-selectfile-placeholder": "ファイルが選択されていません",
+ "ooui-selectfile-dragdrop-placeholder": "ファイルをここにドロップ"
}
diff --git a/vendor/oojs/oojs-ui/i18n/jv.json b/vendor/oojs/oojs-ui/i18n/jv.json
index 8827af38..677b1c3d 100644
--- a/vendor/oojs/oojs-ui/i18n/jv.json
+++ b/vendor/oojs/oojs-ui/i18n/jv.json
@@ -3,8 +3,22 @@
"authors": [
"Gleki",
"NoiX180",
- "Pras"
+ "Pras",
+ "Jadinegara"
]
},
- "ooui-outline-control-move-down": "Pindhahaken butir mangandhap"
+ "ooui-outline-control-move-down": "Pindhahaken butir mangandhap",
+ "ooui-outline-control-move-up": "Pindhah kara mêndhuwur",
+ "ooui-outline-control-remove": "Busak kara",
+ "ooui-toolbar-more": "Mênèh",
+ "ooui-toolgroup-expand": "Mênèh",
+ "ooui-toolgroup-collapse": "Suda",
+ "ooui-dialog-message-accept": "Oké",
+ "ooui-dialog-message-reject": "Batal",
+ "ooui-dialog-process-error": "Ana sing klèru",
+ "ooui-dialog-process-dismiss": "Tutup",
+ "ooui-dialog-process-retry": "Jajal manèh",
+ "ooui-dialog-process-continue": "Tutug",
+ "ooui-selectfile-not-supported": "Pilihan bêrkas ora disokong",
+ "ooui-selectfile-placeholder": "Ora ana bêrkas sing kapilih"
}
diff --git a/vendor/oojs/oojs-ui/i18n/ka.json b/vendor/oojs/oojs-ui/i18n/ka.json
index 60ef661b..f1a1a473 100644
--- a/vendor/oojs/oojs-ui/i18n/ka.json
+++ b/vendor/oojs/oojs-ui/i18n/ka.json
@@ -22,5 +22,7 @@
"ooui-dialog-process-error": "მოხდა რაღაც შეცდომა",
"ooui-dialog-process-dismiss": "დამალვა",
"ooui-dialog-process-retry": "კიდევ სცადეთ",
- "ooui-dialog-process-continue": "გაგრძელება"
+ "ooui-dialog-process-continue": "გაგრძელება",
+ "ooui-selectfile-not-supported": "ფაილის არჩევა არ არის მხარდაჭერილი",
+ "ooui-selectfile-placeholder": "ფაილი არ არის არჩეული"
}
diff --git a/vendor/oojs/oojs-ui/i18n/km.json b/vendor/oojs/oojs-ui/i18n/km.json
index c0d72c4f..e64889f4 100644
--- a/vendor/oojs/oojs-ui/i18n/km.json
+++ b/vendor/oojs/oojs-ui/i18n/km.json
@@ -1,11 +1,24 @@
{
"@metadata": {
"authors": [
- "Sovichet"
+ "Sovichet",
+ "គីមស៊្រុន"
]
},
- "ooui-outline-control-move-down": "រុញ​ទៅ​ក្រោម",
- "ooui-outline-control-move-up": "រុញ​ទៅ​លើ",
- "ooui-outline-control-remove": "ដក​វត្ថុ​ចេញ",
- "ooui-toolbar-more": "បន្ថែម"
+ "ooui-outline-control-move-down": "រុញ​ធាតុទៅ​ក្រោម",
+ "ooui-outline-control-move-up": "រុញធាតុទៅ​លើ",
+ "ooui-outline-control-remove": "ដកធាតុចេញ",
+ "ooui-toolbar-more": "បន្ថែមទៀត",
+ "ooui-toolgroup-expand": "មើលច្រើន",
+ "ooui-toolgroup-collapse": "មើលតិច",
+ "ooui-dialog-message-accept": "យល់ព្រម",
+ "ooui-dialog-message-reject": "បោះបង់",
+ "ooui-dialog-process-error": "មានបញ្ហាអ្វីមួយ",
+ "ooui-dialog-process-dismiss": "បិទ",
+ "ooui-dialog-process-retry": "ព្យាយាមម្ដងទៀត",
+ "ooui-dialog-process-continue": "បន្ត",
+ "ooui-selectfile-button-select": "ជ្រើសរើសឯកសារ",
+ "ooui-selectfile-not-supported": "ការជ្រើសរើសឯកសារមិនអាចប្រើបានទេ",
+ "ooui-selectfile-placeholder": "គ្មានឯកសារណាមួយត្រូវបានជ្រើសរើស",
+ "ooui-selectfile-dragdrop-placeholder": "ទម្លាក់ឯកសារនៅទីនេះ"
}
diff --git a/vendor/oojs/oojs-ui/i18n/ko.json b/vendor/oojs/oojs-ui/i18n/ko.json
index 196dc2c3..38944173 100644
--- a/vendor/oojs/oojs-ui/i18n/ko.json
+++ b/vendor/oojs/oojs-ui/i18n/ko.json
@@ -9,17 +9,24 @@
"고기랑",
"Ryuch",
"Revi",
- "Infinity"
+ "Infinity",
+ "Hwangjy9"
]
},
"ooui-outline-control-move-down": "항목을 아래로 옮기기",
"ooui-outline-control-move-up": "항목을 위로 옮기기",
- "ooui-outline-control-remove": "항목 지우기",
+ "ooui-outline-control-remove": "항목 제거",
"ooui-toolbar-more": "더 보기",
"ooui-toolgroup-expand": "더 보기",
+ "ooui-toolgroup-collapse": "덜 보기",
"ooui-dialog-message-accept": "확인",
"ooui-dialog-message-reject": "취소",
"ooui-dialog-process-error": "무언가가 잘못되었습니다",
"ooui-dialog-process-dismiss": "숨기기",
- "ooui-dialog-process-retry": "다시 시도하세요"
+ "ooui-dialog-process-retry": "다시 시도하세요",
+ "ooui-dialog-process-continue": "계속",
+ "ooui-selectfile-button-select": "파일을 선택하세요",
+ "ooui-selectfile-not-supported": "파일 선택은 지원하지 않습니다",
+ "ooui-selectfile-placeholder": "선택한 파일 없음",
+ "ooui-selectfile-dragdrop-placeholder": "여기에 파일을 놓으세요"
}
diff --git a/vendor/oojs/oojs-ui/i18n/krc.json b/vendor/oojs/oojs-ui/i18n/krc.json
index ef92e49f..d4068c87 100644
--- a/vendor/oojs/oojs-ui/i18n/krc.json
+++ b/vendor/oojs/oojs-ui/i18n/krc.json
@@ -15,5 +15,7 @@
"ooui-dialog-process-error": "Не эсе да табсыз кетди",
"ooui-dialog-process-dismiss": "Джаб",
"ooui-dialog-process-retry": "Энтда сынаб кёр",
- "ooui-dialog-process-continue": "Бардыр"
+ "ooui-dialog-process-continue": "Бардыр",
+ "ooui-selectfile-not-supported": "Файл сайлау тутулмайды",
+ "ooui-selectfile-placeholder": "Бир файл да сайланмагъанды"
}
diff --git a/vendor/oojs/oojs-ui/i18n/krl.json b/vendor/oojs/oojs-ui/i18n/krl.json
new file mode 100644
index 00000000..6ff25ebe
--- /dev/null
+++ b/vendor/oojs/oojs-ui/i18n/krl.json
@@ -0,0 +1,10 @@
+{
+ "@metadata": {
+ "authors": [
+ "Mashoi7"
+ ]
+ },
+ "ooui-toolbar-more": "Enämpi",
+ "ooui-toolgroup-expand": "Enämpi",
+ "ooui-toolgroup-collapse": "Vähempi"
+}
diff --git a/vendor/oojs/oojs-ui/i18n/ksh.json b/vendor/oojs/oojs-ui/i18n/ksh.json
index c975e825..f99c29fd 100644
--- a/vendor/oojs/oojs-ui/i18n/ksh.json
+++ b/vendor/oojs/oojs-ui/i18n/ksh.json
@@ -15,5 +15,8 @@
"ooui-dialog-process-error": "Öhnsjädd es scheif jejange",
"ooui-dialog-process-dismiss": "Maach fott, ha_sch jelässe",
"ooui-dialog-process-retry": "Norr_ens versöhke",
- "ooui-dialog-process-continue": "Wigger maache"
+ "ooui-dialog-process-continue": "Wigger maache",
+ "ooui-selectfile-button-select": "Söhg en Dattei uß",
+ "ooui-selectfile-not-supported": "Mer ogerschtözze et Datteij_Ußwähle nit.",
+ "ooui-selectfile-placeholder": "Kein Dattei es ußjewählt"
}
diff --git a/vendor/oojs/oojs-ui/i18n/ku-latn.json b/vendor/oojs/oojs-ui/i18n/ku-latn.json
index be9a8abd..94b46873 100644
--- a/vendor/oojs/oojs-ui/i18n/ku-latn.json
+++ b/vendor/oojs/oojs-ui/i18n/ku-latn.json
@@ -1,13 +1,16 @@
{
"@metadata": {
"authors": [
- "George Animal"
+ "George Animal",
+ "Bikarhêner"
]
},
+ "ooui-toolbar-more": "Bêhtir",
"ooui-toolgroup-expand": "Bêhtir",
"ooui-toolgroup-collapse": "Kêmtir",
"ooui-dialog-message-accept": "Baş e",
"ooui-dialog-message-reject": "Betal bike",
"ooui-dialog-process-retry": "Dîsa hewl bide",
- "ooui-dialog-process-continue": "Bidomîne"
+ "ooui-dialog-process-continue": "Bidomîne",
+ "ooui-selectfile-placeholder": "Ti dosye nehatiye hilbijartin"
}
diff --git a/vendor/oojs/oojs-ui/i18n/la.json b/vendor/oojs/oojs-ui/i18n/la.json
new file mode 100644
index 00000000..7a9b2d23
--- /dev/null
+++ b/vendor/oojs/oojs-ui/i18n/la.json
@@ -0,0 +1,15 @@
+{
+ "@metadata": {
+ "authors": [
+ "Jdforrester"
+ ]
+ },
+ "ooui-toolbar-more": "Plus",
+ "ooui-toolgroup-expand": "Plus",
+ "ooui-toolgroup-collapse": "Paucior",
+ "ooui-dialog-message-accept": "Assentior",
+ "ooui-dialog-message-reject": "Dimittere",
+ "ooui-dialog-process-dismiss": "Dimittere",
+ "ooui-dialog-process-retry": "Retemptare",
+ "ooui-dialog-process-continue": "Pergere"
+}
diff --git a/vendor/oojs/oojs-ui/i18n/lb.json b/vendor/oojs/oojs-ui/i18n/lb.json
index 119d1be9..39bc6701 100644
--- a/vendor/oojs/oojs-ui/i18n/lb.json
+++ b/vendor/oojs/oojs-ui/i18n/lb.json
@@ -21,5 +21,8 @@
"ooui-dialog-process-error": "Et ass eppes schif gaang",
"ooui-dialog-process-dismiss": "Verwerfen",
"ooui-dialog-process-retry": "Nach eng Kéier probéieren",
- "ooui-dialog-process-continue": "Virufueren"
+ "ooui-dialog-process-continue": "Virufueren",
+ "ooui-selectfile-button-select": "E Fichier eraussichen",
+ "ooui-selectfile-placeholder": "Et ass kee Fichier erausgesicht",
+ "ooui-selectfile-dragdrop-placeholder": "Fichier hei ofleeën"
}
diff --git a/vendor/oojs/oojs-ui/i18n/li.json b/vendor/oojs/oojs-ui/i18n/li.json
new file mode 100644
index 00000000..f05a9571
--- /dev/null
+++ b/vendor/oojs/oojs-ui/i18n/li.json
@@ -0,0 +1,21 @@
+{
+ "@metadata": {
+ "authors": [
+ "Pahles"
+ ]
+ },
+ "ooui-outline-control-move-down": "Item nao ónger verplaatse",
+ "ooui-outline-control-move-up": "Item nao bove verplaetse",
+ "ooui-outline-control-remove": "Item ewegsjaffe",
+ "ooui-toolbar-more": "Mieë",
+ "ooui-toolgroup-expand": "Mieë",
+ "ooui-toolgroup-collapse": "Minder",
+ "ooui-dialog-message-accept": "Ok",
+ "ooui-dialog-message-reject": "Aafbraeke",
+ "ooui-dialog-process-error": "Dao is get misgegange",
+ "ooui-dialog-process-dismiss": "Sjlete",
+ "ooui-dialog-process-retry": "Perbeer obbenuujts",
+ "ooui-dialog-process-continue": "Doorgaon",
+ "ooui-selectfile-not-supported": "Selektie van 'n besjtandj waert neet óngersteund",
+ "ooui-selectfile-placeholder": "Dao is gein besjtandj geselekteerd"
+}
diff --git a/vendor/oojs/oojs-ui/i18n/lt.json b/vendor/oojs/oojs-ui/i18n/lt.json
index ecd06a8a..fbd22d0f 100644
--- a/vendor/oojs/oojs-ui/i18n/lt.json
+++ b/vendor/oojs/oojs-ui/i18n/lt.json
@@ -3,8 +3,24 @@
"authors": [
"Audriusa",
"Eitvys200",
- "Mantak111"
+ "Mantak111",
+ "Albertas"
]
},
- "ooui-outline-control-remove": "Šalinti elementus"
+ "ooui-outline-control-move-down": "Perkelti elementą žemyn",
+ "ooui-outline-control-move-up": "Perkelti elementą aukštyn",
+ "ooui-outline-control-remove": "Šalinti elementus",
+ "ooui-toolbar-more": "Daugiau",
+ "ooui-toolgroup-expand": "Daugiau",
+ "ooui-toolgroup-collapse": "Mažiau",
+ "ooui-dialog-message-accept": "Gerai",
+ "ooui-dialog-message-reject": "Atšaukti",
+ "ooui-dialog-process-error": "Kažkas nutiko ne taip",
+ "ooui-dialog-process-dismiss": "Paslėpti",
+ "ooui-dialog-process-retry": "Bandykite dar kartą",
+ "ooui-dialog-process-continue": "Tęsti",
+ "ooui-selectfile-button-select": "Pasirinkti failą",
+ "ooui-selectfile-not-supported": "Failų pasirinkimas nepalaikomas",
+ "ooui-selectfile-placeholder": "Nėra pasirinktų failų",
+ "ooui-selectfile-dragdrop-placeholder": "Atitempkite failą čia"
}
diff --git a/vendor/oojs/oojs-ui/i18n/luz.json b/vendor/oojs/oojs-ui/i18n/luz.json
new file mode 100644
index 00000000..d48a9dfa
--- /dev/null
+++ b/vendor/oojs/oojs-ui/i18n/luz.json
@@ -0,0 +1,21 @@
+{
+ "@metadata": {
+ "authors": [
+ "علی ساکی لرستانی"
+ ]
+ },
+ "ooui-outline-control-move-down": "انتقال مورد وه دومن",
+ "ooui-outline-control-move-up": "انتقال مورد وه بالا",
+ "ooui-outline-control-remove": "حذف مورد",
+ "ooui-toolbar-more": "هنی",
+ "ooui-toolgroup-expand": "هنی",
+ "ooui-toolgroup-collapse": "کم تر",
+ "ooui-dialog-message-accept": "خووه",
+ "ooui-dialog-message-reject": "لغو",
+ "ooui-dialog-process-error": "یه چیایی اشتباه ویده",
+ "ooui-dialog-process-dismiss": "منفصل کردن",
+ "ooui-dialog-process-retry": "دوباره تلاش کردن",
+ "ooui-dialog-process-continue": "ادامه دائن",
+ "ooui-selectfile-not-supported": "فایل انتخابی پشتیبانی نوابیه",
+ "ooui-selectfile-placeholder": "فایلی انتخاب نوابیه"
+}
diff --git a/vendor/oojs/oojs-ui/i18n/mk.json b/vendor/oojs/oojs-ui/i18n/mk.json
index 7962336c..46f37fe8 100644
--- a/vendor/oojs/oojs-ui/i18n/mk.json
+++ b/vendor/oojs/oojs-ui/i18n/mk.json
@@ -17,5 +17,9 @@
"ooui-dialog-process-error": "Нешто не е во ред",
"ooui-dialog-process-dismiss": "Тргни",
"ooui-dialog-process-retry": "Обиди се пак",
- "ooui-dialog-process-continue": "Продолжи"
+ "ooui-dialog-process-continue": "Продолжи",
+ "ooui-selectfile-button-select": "Одберете податотека",
+ "ooui-selectfile-not-supported": "Изборот на податотеки не е поддржан",
+ "ooui-selectfile-placeholder": "Немате одбрано податотека",
+ "ooui-selectfile-dragdrop-placeholder": "Тука пуштете ја податотеката"
}
diff --git a/vendor/oojs/oojs-ui/i18n/ml.json b/vendor/oojs/oojs-ui/i18n/ml.json
index 0ce0c3fd..9649b2eb 100644
--- a/vendor/oojs/oojs-ui/i18n/ml.json
+++ b/vendor/oojs/oojs-ui/i18n/ml.json
@@ -4,10 +4,24 @@
"Kavya Manohar",
"Praveenp",
"Santhosh.thottingal",
- "Vssun"
+ "Vssun",
+ "Ranjithsiji"
]
},
"ooui-outline-control-move-down": "ഇനം താഴേയ്ക്ക് മാറ്റുക",
"ooui-outline-control-move-up": "ഇനം മുകളിലേയ്ക്ക് മാറ്റുക",
- "ooui-toolbar-more": "കൂടുതൽ"
+ "ooui-outline-control-remove": "ഇനം നീക്കംചെയ്യുക",
+ "ooui-toolbar-more": "കൂടുതൽ",
+ "ooui-toolgroup-expand": "കൂടുതൽ",
+ "ooui-toolgroup-collapse": "കുറച്ച്",
+ "ooui-dialog-message-accept": "ശരി",
+ "ooui-dialog-message-reject": "റദ്ദാക്കുക",
+ "ooui-dialog-process-error": "എന്തോ പ്രശ്നമുണ്ടായി",
+ "ooui-dialog-process-dismiss": "ഒഴിവാക്കുക",
+ "ooui-dialog-process-retry": "വീണ്ടും ശ്രമിക്കുക",
+ "ooui-dialog-process-continue": "തുടരുക",
+ "ooui-selectfile-button-select": "പ്രമാണം തിരഞ്ഞെടുക്കുക",
+ "ooui-selectfile-not-supported": "പ്രമാണം തിരഞ്ഞെടുക്കൽ പിന്തുണയ്ക്കുന്നില്ല",
+ "ooui-selectfile-placeholder": "പ്രമാണങ്ങൾ ഒന്നും തിരഞ്ഞെടുത്തിട്ടില്ല",
+ "ooui-selectfile-dragdrop-placeholder": "പ്രമാണം ഇവിടെ ഇടുക"
}
diff --git a/vendor/oojs/oojs-ui/i18n/mr.json b/vendor/oojs/oojs-ui/i18n/mr.json
index 70061907..15a5de39 100644
--- a/vendor/oojs/oojs-ui/i18n/mr.json
+++ b/vendor/oojs/oojs-ui/i18n/mr.json
@@ -6,10 +6,17 @@
"Praju23",
"V.narsikar",
"Ydyashad",
- "संतोष दहिवळ"
+ "संतोष दहिवळ",
+ "NehalDaveND",
+ "Sau6402"
]
},
"ooui-outline-control-move-down": "घटक (आयटम) खाली सरकवा",
"ooui-outline-control-move-up": "घटक (आयटम) वर सरकवा",
- "ooui-toolbar-more": "अधिक"
+ "ooui-toolbar-more": "अधिक",
+ "ooui-toolgroup-expand": "अधिक",
+ "ooui-dialog-message-accept": "ठिक आहे",
+ "ooui-dialog-message-reject": "रद्द करा",
+ "ooui-dialog-process-dismiss": "रद्द करा",
+ "ooui-dialog-process-continue": "चालू ठेवा"
}
diff --git a/vendor/oojs/oojs-ui/i18n/ms.json b/vendor/oojs/oojs-ui/i18n/ms.json
index 823d4936..19ce1c2f 100644
--- a/vendor/oojs/oojs-ui/i18n/ms.json
+++ b/vendor/oojs/oojs-ui/i18n/ms.json
@@ -3,15 +3,22 @@
"authors": [
"Anakmalaysia",
"Aurora",
- "Pizza1016"
+ "Pizza1016",
+ "Karmadunya9-"
]
},
"ooui-outline-control-move-down": "Alihkan perkara ke bawah",
"ooui-outline-control-move-up": "Alihkan perkara ke atas",
"ooui-outline-control-remove": "Buang perkara",
"ooui-toolbar-more": "Selebihnya",
+ "ooui-toolgroup-expand": "Selengkapnya",
+ "ooui-toolgroup-collapse": "Secukupnya",
+ "ooui-dialog-message-accept": "OK",
"ooui-dialog-message-reject": "Batal",
"ooui-dialog-process-error": "Ada masalah",
"ooui-dialog-process-dismiss": "Singkir",
- "ooui-dialog-process-retry": "Cuba lagi"
+ "ooui-dialog-process-retry": "Cuba lagi",
+ "ooui-dialog-process-continue": "Teruskan",
+ "ooui-selectfile-not-supported": "Pilihan fail tidak disokong",
+ "ooui-selectfile-placeholder": "Tiada fail yang dipilih"
}
diff --git a/vendor/oojs/oojs-ui/i18n/nap.json b/vendor/oojs/oojs-ui/i18n/nap.json
index 91660373..b7e37b49 100644
--- a/vendor/oojs/oojs-ui/i18n/nap.json
+++ b/vendor/oojs/oojs-ui/i18n/nap.json
@@ -3,8 +3,25 @@
"authors": [
"Chelin",
"Chrisportelli",
- "PiRSquared17"
+ "PiRSquared17",
+ "C.R.",
+ "Candalua"
]
},
- "ooui-toolbar-more": "Atro"
+ "ooui-outline-control-move-down": "Mòve abbascio",
+ "ooui-outline-control-move-up": "Mòve ncoppa",
+ "ooui-outline-control-remove": "Leva elemento",
+ "ooui-toolbar-more": "Atro",
+ "ooui-toolgroup-expand": "Cchiù",
+ "ooui-toolgroup-collapse": "Meno",
+ "ooui-dialog-message-accept": "OK",
+ "ooui-dialog-message-reject": "Scancella",
+ "ooui-dialog-process-error": "Cocchosa è ghiuta malamente",
+ "ooui-dialog-process-dismiss": "Passa 'a vacca",
+ "ooui-dialog-process-retry": "Prova n'ata vota",
+ "ooui-dialog-process-continue": "Continua",
+ "ooui-selectfile-button-select": "Sceglie nu file",
+ "ooui-selectfile-not-supported": "Filtro 'e selezione nun suppurtato",
+ "ooui-selectfile-placeholder": "Nun s'è scigliuto nisciuno file",
+ "ooui-selectfile-dragdrop-placeholder": "Lassa 'o file ccà"
}
diff --git a/vendor/oojs/oojs-ui/i18n/nb.json b/vendor/oojs/oojs-ui/i18n/nb.json
index 9e773924..d3fad8dc 100644
--- a/vendor/oojs/oojs-ui/i18n/nb.json
+++ b/vendor/oojs/oojs-ui/i18n/nb.json
@@ -21,5 +21,9 @@
"ooui-dialog-process-error": "Noe gikk galt",
"ooui-dialog-process-dismiss": "Lukk",
"ooui-dialog-process-retry": "Prøv igjen",
- "ooui-dialog-process-continue": "Fortsett"
+ "ooui-dialog-process-continue": "Fortsett",
+ "ooui-selectfile-button-select": "Velg en fil",
+ "ooui-selectfile-not-supported": "Filvalg er ikke støttet",
+ "ooui-selectfile-placeholder": "Ingen fil er valgt",
+ "ooui-selectfile-dragdrop-placeholder": "Slipp fil her"
}
diff --git a/vendor/oojs/oojs-ui/i18n/nl.json b/vendor/oojs/oojs-ui/i18n/nl.json
index 7c7b1767..515eadab 100644
--- a/vendor/oojs/oojs-ui/i18n/nl.json
+++ b/vendor/oojs/oojs-ui/i18n/nl.json
@@ -31,5 +31,7 @@
"ooui-dialog-process-error": "Er is iets misgegaan",
"ooui-dialog-process-dismiss": "Sluiten",
"ooui-dialog-process-retry": "Opnieuw proberen",
- "ooui-dialog-process-continue": "Doorgaan"
+ "ooui-dialog-process-continue": "Doorgaan",
+ "ooui-selectfile-not-supported": "Selectie van een bestand wordt niet ondersteund",
+ "ooui-selectfile-placeholder": "Er is geen bestand geselecteerd"
}
diff --git a/vendor/oojs/oojs-ui/i18n/oc.json b/vendor/oojs/oojs-ui/i18n/oc.json
index 4d35b6c9..bccd615f 100644
--- a/vendor/oojs/oojs-ui/i18n/oc.json
+++ b/vendor/oojs/oojs-ui/i18n/oc.json
@@ -9,5 +9,12 @@
"ooui-outline-control-move-up": "Far montar l’element",
"ooui-outline-control-remove": "Suprimir l’element",
"ooui-toolbar-more": "Mai",
- "ooui-dialog-message-reject": "Anullar"
+ "ooui-toolgroup-expand": "Mai",
+ "ooui-toolgroup-collapse": "Mens",
+ "ooui-dialog-message-accept": "D'acòrdi",
+ "ooui-dialog-message-reject": "Anullar",
+ "ooui-dialog-process-dismiss": "Regetar",
+ "ooui-dialog-process-retry": "Ensajatz tornamai",
+ "ooui-dialog-process-continue": "Contunhar",
+ "ooui-selectfile-placeholder": "Cap de fichièr pas seleccionat"
}
diff --git a/vendor/oojs/oojs-ui/i18n/olo.json b/vendor/oojs/oojs-ui/i18n/olo.json
new file mode 100644
index 00000000..1dc994eb
--- /dev/null
+++ b/vendor/oojs/oojs-ui/i18n/olo.json
@@ -0,0 +1,23 @@
+{
+ "@metadata": {
+ "authors": [
+ "Mashoi7"
+ ]
+ },
+ "ooui-outline-control-move-down": "Siirrä kohteh alah",
+ "ooui-outline-control-move-up": "Siirrä kohteh yläh",
+ "ooui-outline-control-remove": "Ota kohteh iäre",
+ "ooui-toolbar-more": "Enämbi",
+ "ooui-toolgroup-expand": "Enämbi",
+ "ooui-toolgroup-collapse": "Vähembi",
+ "ooui-dialog-message-accept": "OK",
+ "ooui-dialog-message-reject": "Hylgiä",
+ "ooui-dialog-process-error": "Mitah haireh rodih",
+ "ooui-dialog-process-dismiss": "Hylgiä",
+ "ooui-dialog-process-retry": "Opi vie",
+ "ooui-dialog-process-continue": "Jatka",
+ "ooui-selectfile-button-select": "Valliče failu",
+ "ooui-selectfile-not-supported": "Failan valličendua ei tuveta",
+ "ooui-selectfile-placeholder": "Failua ei ole vallittu",
+ "ooui-selectfile-dragdrop-placeholder": "Kirvota failu täh"
+}
diff --git a/vendor/oojs/oojs-ui/i18n/om.json b/vendor/oojs/oojs-ui/i18n/om.json
index ecf95971..a61083b3 100644
--- a/vendor/oojs/oojs-ui/i18n/om.json
+++ b/vendor/oojs/oojs-ui/i18n/om.json
@@ -16,5 +16,7 @@
"ooui-dialog-process-error": "Dogoggorri wayii ummameera",
"ooui-dialog-process-dismiss": "Didi",
"ooui-dialog-process-retry": "Itti deebi'ii yaali",
- "ooui-dialog-process-continue": "Itti fufi"
+ "ooui-dialog-process-continue": "Itti fufi",
+ "ooui-selectfile-not-supported": "Faayilii filachuun hin danda'amu.",
+ "ooui-selectfile-placeholder": "Faayiliin wayiiyyuu hin filatamne"
}
diff --git a/vendor/oojs/oojs-ui/i18n/or.json b/vendor/oojs/oojs-ui/i18n/or.json
index dde49bf1..7d96dcb7 100644
--- a/vendor/oojs/oojs-ui/i18n/or.json
+++ b/vendor/oojs/oojs-ui/i18n/or.json
@@ -3,7 +3,8 @@
"authors": [
"Odisha1",
"Psubhashish",
- "ଶିତିକଣ୍ଠ ଦାଶ"
+ "ଶିତିକଣ୍ଠ ଦାଶ",
+ "Jnanaranjan Sahu"
]
},
"ooui-outline-control-move-down": "ବସ୍ତୁଟିକୁ ତଳକୁ ଘୁଞ୍ଚାନ୍ତୁ",
@@ -17,5 +18,7 @@
"ooui-dialog-process-error": "ଅସୁବିଧାଟିଏ ଘଟିଲା",
"ooui-dialog-process-dismiss": "ଖାରଜ",
"ooui-dialog-process-retry": "ଆଉ ଥରେ ଚେଷ୍ଟା କରନ୍ତୁ",
- "ooui-dialog-process-continue": "ଚାଲୁରଖିବେ"
+ "ooui-dialog-process-continue": "ଚାଲୁରଖିବେ",
+ "ooui-selectfile-not-supported": "ଫାଇଲ ବାଛିବା ସୁବିଧା ନାହିଁ",
+ "ooui-selectfile-placeholder": "କୌଣସି ଫାଇଲ ବଛାଯାଇନାହିଁ"
}
diff --git a/vendor/oojs/oojs-ui/i18n/pa.json b/vendor/oojs/oojs-ui/i18n/pa.json
index 8c7a1e7c..a69d76f9 100644
--- a/vendor/oojs/oojs-ui/i18n/pa.json
+++ b/vendor/oojs/oojs-ui/i18n/pa.json
@@ -10,13 +10,18 @@
},
"ooui-outline-control-move-down": "ਨੀਚੇ ਲੈਕੇ ਜਾਓ",
"ooui-outline-control-move-up": "ਉੱਤੇ ਲੈਕੇ ਜਾਓ",
+ "ooui-outline-control-remove": "ਆਈਟਮ ਹਟਾਓ",
"ooui-toolbar-more": "ਹੋਰ",
"ooui-toolgroup-expand": "ਹੋਰ",
- "ooui-toolgroup-collapse": "ਥੋੜੇ",
+ "ooui-toolgroup-collapse": "ਥੋੜ੍ਹੇ",
"ooui-dialog-message-accept": "ਠੀਕ ਹੈ",
"ooui-dialog-message-reject": "ਰੱਦ ਕਰੋ",
"ooui-dialog-process-error": "ਕੁਝ ਗਲਤ ਹੋ ਗਿਆ",
"ooui-dialog-process-dismiss": "ਰੱਦ ਕਰੋ",
"ooui-dialog-process-retry": "ਦੁਬਾਰਾ ਕੋਸ਼ਿਸ਼ ਕਰੋ",
- "ooui-dialog-process-continue": "ਜਾਰੀ ਰੱਖੋ"
+ "ooui-dialog-process-continue": "ਜਾਰੀ ਰੱਖੋ",
+ "ooui-selectfile-button-select": "ਫ਼ਾਈਲ ਚੁਣੋ",
+ "ooui-selectfile-not-supported": "ਚੁਣੀ ਗਈ ਫ਼ਾਈਲ ਖੋਲੀ ਨਹੀਂ ਜਾ ਸਕਦੀ",
+ "ooui-selectfile-placeholder": "ਕੋਈ ਫ਼ਾਈਲ ਚੁਣੀ ਨਹੀਂ ਗਈ",
+ "ooui-selectfile-dragdrop-placeholder": "ਫ਼ਾਈਲ ਇੱਥੇ ਸਿੱਟੋ"
}
diff --git a/vendor/oojs/oojs-ui/i18n/pl.json b/vendor/oojs/oojs-ui/i18n/pl.json
index fbd0c8cc..9ceb96fd 100644
--- a/vendor/oojs/oojs-ui/i18n/pl.json
+++ b/vendor/oojs/oojs-ui/i18n/pl.json
@@ -16,7 +16,8 @@
"Jacenty359",
"Matik7",
"Gloria sah",
- "Andrzej aa"
+ "Andrzej aa",
+ "The Polish"
]
},
"ooui-outline-control-move-down": "Przenieś niżej",
@@ -28,7 +29,11 @@
"ooui-dialog-message-accept": "OK",
"ooui-dialog-message-reject": "Anuluj",
"ooui-dialog-process-error": "Coś poszło nie tak",
- "ooui-dialog-process-dismiss": "Ukryj",
+ "ooui-dialog-process-dismiss": "Powrót",
"ooui-dialog-process-retry": "Spróbuj ponownie",
- "ooui-dialog-process-continue": "Kontynuuj"
+ "ooui-dialog-process-continue": "Kontynuuj",
+ "ooui-selectfile-button-select": "Wybierz plik",
+ "ooui-selectfile-not-supported": "Wybór pliku nie jest obsługiwany",
+ "ooui-selectfile-placeholder": "Nie wybrano pliku",
+ "ooui-selectfile-dragdrop-placeholder": "Umieść plik tutaj"
}
diff --git a/vendor/oojs/oojs-ui/i18n/pms.json b/vendor/oojs/oojs-ui/i18n/pms.json
index b8fd3a58..c8b5bc7e 100644
--- a/vendor/oojs/oojs-ui/i18n/pms.json
+++ b/vendor/oojs/oojs-ui/i18n/pms.json
@@ -8,5 +8,16 @@
},
"ooui-outline-control-move-down": "Fé calé giù l'element",
"ooui-outline-control-move-up": "Fé monté l'element",
- "ooui-toolbar-more": "Ëd pi"
+ "ooui-outline-control-remove": "Gavé j'element",
+ "ooui-toolbar-more": "Ëd pi",
+ "ooui-toolgroup-expand": "Pi",
+ "ooui-toolgroup-collapse": "Men",
+ "ooui-dialog-message-accept": "Va bin",
+ "ooui-dialog-message-reject": "Scancelé",
+ "ooui-dialog-process-error": "Quaicòs a l'é andà mal",
+ "ooui-dialog-process-dismiss": "Stërmé",
+ "ooui-dialog-process-retry": "Preuva torna",
+ "ooui-dialog-process-continue": "Continua",
+ "ooui-selectfile-not-supported": "La selession d'archivi a l'é nen mantnùa",
+ "ooui-selectfile-placeholder": "Gnun archivi selessionà"
}
diff --git a/vendor/oojs/oojs-ui/i18n/ps.json b/vendor/oojs/oojs-ui/i18n/ps.json
index ebffe539..228291ac 100644
--- a/vendor/oojs/oojs-ui/i18n/ps.json
+++ b/vendor/oojs/oojs-ui/i18n/ps.json
@@ -14,5 +14,9 @@
"ooui-dialog-message-reject": "ناگارل",
"ooui-dialog-process-error": "يوه ستونزه رامنځ ته شوه",
"ooui-dialog-process-dismiss": "تړل",
- "ooui-dialog-process-retry": "بيا هڅه"
+ "ooui-dialog-process-retry": "بيا هڅه",
+ "ooui-dialog-process-continue": "پرله پورې",
+ "ooui-selectfile-button-select": "يوه دوتنه وټاکئ",
+ "ooui-selectfile-not-supported": "د دوتنې د ټاکنې ملاتړ نه دی شوی",
+ "ooui-selectfile-placeholder": "کومه دوتنه نه ده ټاکل شوې"
}
diff --git a/vendor/oojs/oojs-ui/i18n/pt-br.json b/vendor/oojs/oojs-ui/i18n/pt-br.json
index 94ea0895..bcc31e09 100644
--- a/vendor/oojs/oojs-ui/i18n/pt-br.json
+++ b/vendor/oojs/oojs-ui/i18n/pt-br.json
@@ -9,10 +9,23 @@
"Jaideraf",
"Luckas",
"OTAVIO1981",
- 555
+ 555,
+ "TheEduGobi",
+ "TheGabrielZaum"
]
},
"ooui-outline-control-move-down": "Mover item para baixo",
"ooui-outline-control-move-up": "Mover item para cima",
- "ooui-toolbar-more": "Mais"
+ "ooui-outline-control-remove": "Remover item",
+ "ooui-toolbar-more": "Mais",
+ "ooui-toolgroup-expand": "Mais",
+ "ooui-toolgroup-collapse": "Menos",
+ "ooui-dialog-message-accept": "OK",
+ "ooui-dialog-message-reject": "Cancelar",
+ "ooui-dialog-process-error": "Algo deu errado",
+ "ooui-dialog-process-dismiss": "Dispensar",
+ "ooui-dialog-process-retry": "Tentar novamente",
+ "ooui-dialog-process-continue": "Continuar",
+ "ooui-selectfile-not-supported": "O selecionamento de arquivos não é suportado",
+ "ooui-selectfile-placeholder": "Nenhum arquivo selecionado"
}
diff --git a/vendor/oojs/oojs-ui/i18n/pt.json b/vendor/oojs/oojs-ui/i18n/pt.json
index 7b3176fb..8d9071a7 100644
--- a/vendor/oojs/oojs-ui/i18n/pt.json
+++ b/vendor/oojs/oojs-ui/i18n/pt.json
@@ -10,7 +10,8 @@
"Jdforrester",
"Luckas",
"Vitorvicentevalente",
- "SandroHc"
+ "SandroHc",
+ "Jkb8"
]
},
"ooui-outline-control-move-down": "Mover item para baixo",
@@ -24,5 +25,8 @@
"ooui-dialog-process-error": "Algo correu mal",
"ooui-dialog-process-dismiss": "Ignorar",
"ooui-dialog-process-retry": "Tentar novamente",
- "ooui-dialog-process-continue": "Continuar"
+ "ooui-dialog-process-continue": "Continuar",
+ "ooui-selectfile-not-supported": "A seleção de ficheiros não é suportada",
+ "ooui-selectfile-placeholder": "Nenhum ficheiro selecionado",
+ "ooui-selectfile-dragdrop-placeholder": "Soltar ficheiro aqui"
}
diff --git a/vendor/oojs/oojs-ui/i18n/qqq.json b/vendor/oojs/oojs-ui/i18n/qqq.json
index c1b794ab..1a096efc 100644
--- a/vendor/oojs/oojs-ui/i18n/qqq.json
+++ b/vendor/oojs/oojs-ui/i18n/qqq.json
@@ -31,5 +31,9 @@
"ooui-dialog-process-error": "Title for process dialog error description",
"ooui-dialog-process-dismiss": "Label for process dialog dismiss error button, visible when describing errors\n{{Identical|Dismiss}}",
"ooui-dialog-process-retry": "Label for process dialog retry action button, visible when describing recoverable errors\n{{Identical|Try again}}",
- "ooui-dialog-process-continue": "Label for process dialog retry action button, visible when describing only warnings\n{{Identical|Continue}}"
+ "ooui-dialog-process-continue": "Label for process dialog retry action button, visible when describing only warnings\n{{Identical|Continue}}",
+ "ooui-selectfile-button-select": "Label for the file selection widget's select file button",
+ "ooui-selectfile-not-supported": "Label for the file selection widget if file selection is not supported",
+ "ooui-selectfile-placeholder": "Label for the file selection widget when no file is currently selected",
+ "ooui-selectfile-dragdrop-placeholder": "Label for the file selection widget's drop target"
}
diff --git a/vendor/oojs/oojs-ui/i18n/ro.json b/vendor/oojs/oojs-ui/i18n/ro.json
index 258f3e74..69daa180 100644
--- a/vendor/oojs/oojs-ui/i18n/ro.json
+++ b/vendor/oojs/oojs-ui/i18n/ro.json
@@ -19,5 +19,9 @@
"ooui-dialog-process-error": "Ceva nu a funcționat",
"ooui-dialog-process-dismiss": "Renunțare",
"ooui-dialog-process-retry": "Reîncearcă",
- "ooui-dialog-process-continue": "Continuă"
+ "ooui-dialog-process-continue": "Continuă",
+ "ooui-selectfile-button-select": "Alege un fișier",
+ "ooui-selectfile-not-supported": "Selecția de fișiere nu este acceptată",
+ "ooui-selectfile-placeholder": "Niciun fișier selectat",
+ "ooui-selectfile-dragdrop-placeholder": "Trageți fișierul aici"
}
diff --git a/vendor/oojs/oojs-ui/i18n/roa-tara.json b/vendor/oojs/oojs-ui/i18n/roa-tara.json
index f6f422a2..73a5a6c1 100644
--- a/vendor/oojs/oojs-ui/i18n/roa-tara.json
+++ b/vendor/oojs/oojs-ui/i18n/roa-tara.json
@@ -15,5 +15,9 @@
"ooui-dialog-process-error": "Quacche cose ha sciute stuèrte",
"ooui-dialog-process-dismiss": "Scitte",
"ooui-dialog-process-retry": "Pruève arrete",
- "ooui-dialog-process-continue": "Condinue"
+ "ooui-dialog-process-continue": "Condinue",
+ "ooui-selectfile-button-select": "Scacchie 'nu file",
+ "ooui-selectfile-not-supported": "'U scacchiamende d'u file non g'è supportate",
+ "ooui-selectfile-placeholder": "Nisciune file scacchiate",
+ "ooui-selectfile-dragdrop-placeholder": "Scitte 'u file aqquà"
}
diff --git a/vendor/oojs/oojs-ui/i18n/ru.json b/vendor/oojs/oojs-ui/i18n/ru.json
index 129dd6a2..6c62d360 100644
--- a/vendor/oojs/oojs-ui/i18n/ru.json
+++ b/vendor/oojs/oojs-ui/i18n/ru.json
@@ -16,7 +16,8 @@
"Sunpriat",
"Yury Katkov",
"Умар",
- "Камалист"
+ "Камалист",
+ "Meshkov.a"
]
},
"ooui-outline-control-move-down": "Переместить элемент вниз",
@@ -30,5 +31,9 @@
"ooui-dialog-process-error": "Что-то пошло не так",
"ooui-dialog-process-dismiss": "Закрыть",
"ooui-dialog-process-retry": "Попробовать ещё раз",
- "ooui-dialog-process-continue": "Продолжить"
+ "ooui-dialog-process-continue": "Продолжить",
+ "ooui-selectfile-button-select": "Выберите файл",
+ "ooui-selectfile-not-supported": "Выбор файла не поддерживается",
+ "ooui-selectfile-placeholder": "Не выбран файл",
+ "ooui-selectfile-dragdrop-placeholder": "Перетащите файл сюда"
}
diff --git a/vendor/oojs/oojs-ui/i18n/sa.json b/vendor/oojs/oojs-ui/i18n/sa.json
new file mode 100644
index 00000000..49f038c7
--- /dev/null
+++ b/vendor/oojs/oojs-ui/i18n/sa.json
@@ -0,0 +1,14 @@
+{
+ "@metadata": {
+ "authors": [
+ "NehalDaveND"
+ ]
+ },
+ "ooui-outline-control-remove": "वस्तु निष्कास्यताम्",
+ "ooui-toolbar-more": "अधिकम्",
+ "ooui-toolgroup-expand": "अधिकम्",
+ "ooui-dialog-message-accept": "अस्तु",
+ "ooui-dialog-message-reject": "निरस्यताम्",
+ "ooui-dialog-process-retry": "पुनः चेष्ट्यताम्",
+ "ooui-dialog-process-continue": "निरन्तरम्"
+}
diff --git a/vendor/oojs/oojs-ui/i18n/sah.json b/vendor/oojs/oojs-ui/i18n/sah.json
index 85a94cd5..1e1b05d1 100644
--- a/vendor/oojs/oojs-ui/i18n/sah.json
+++ b/vendor/oojs/oojs-ui/i18n/sah.json
@@ -4,5 +4,19 @@
"Gazeb",
"HalanTul"
]
- }
+ },
+ "ooui-outline-control-move-down": "Аллара түһэрэн биэр",
+ "ooui-outline-control-move-up": "Үөһэ таһааран биэр",
+ "ooui-outline-control-remove": "Сот",
+ "ooui-toolbar-more": "Эбии",
+ "ooui-toolgroup-expand": "Эбии",
+ "ooui-toolgroup-collapse": "Кыччат",
+ "ooui-dialog-message-accept": "Сөп",
+ "ooui-dialog-message-reject": "Салҕаама",
+ "ooui-dialog-process-error": "Туга эрэ сатаммата",
+ "ooui-dialog-process-dismiss": "Сап",
+ "ooui-dialog-process-retry": "Хатылаан көр",
+ "ooui-dialog-process-continue": "Салгыы",
+ "ooui-selectfile-not-supported": "Билэни талыы өйөммөт",
+ "ooui-selectfile-placeholder": "Биир да билэ талыллыбатах"
}
diff --git a/vendor/oojs/oojs-ui/i18n/sco.json b/vendor/oojs/oojs-ui/i18n/sco.json
index 0a26a5c8..794d71f7 100644
--- a/vendor/oojs/oojs-ui/i18n/sco.json
+++ b/vendor/oojs/oojs-ui/i18n/sco.json
@@ -1,11 +1,22 @@
{
"@metadata": {
"authors": [
- "John Reid"
+ "John Reid",
+ "Foxj"
]
},
"ooui-outline-control-move-down": "Muiv eetem doon",
"ooui-outline-control-move-up": "Muiv eetem up",
"ooui-outline-control-remove": "Remuiv eetem",
- "ooui-toolbar-more": "Mair"
+ "ooui-toolbar-more": "Mair",
+ "ooui-toolgroup-expand": "Mair",
+ "ooui-toolgroup-collapse": "Less",
+ "ooui-dialog-message-accept": "OK",
+ "ooui-dialog-message-reject": "Cancel",
+ "ooui-dialog-process-error": "Sommit went wrang",
+ "ooui-dialog-process-dismiss": "Close",
+ "ooui-dialog-process-retry": "Hae aniter gae",
+ "ooui-dialog-process-continue": "Conteena",
+ "ooui-selectfile-not-supported": "Cannae pick ony files",
+ "ooui-selectfile-placeholder": "Nae file selectit"
}
diff --git a/vendor/oojs/oojs-ui/i18n/sh.json b/vendor/oojs/oojs-ui/i18n/sh.json
index b40fa04e..db6fa3c4 100644
--- a/vendor/oojs/oojs-ui/i18n/sh.json
+++ b/vendor/oojs/oojs-ui/i18n/sh.json
@@ -5,5 +5,17 @@
]
},
"ooui-outline-control-move-down": "Pomakni stavku dolje",
- "ooui-outline-control-move-up": "Pomakni stavku gore"
+ "ooui-outline-control-move-up": "Premjesti stavku gore",
+ "ooui-outline-control-remove": "Ukloni stavku",
+ "ooui-toolbar-more": "Više",
+ "ooui-toolgroup-expand": "Više",
+ "ooui-toolgroup-collapse": "Manje",
+ "ooui-dialog-message-accept": "U redu",
+ "ooui-dialog-message-reject": "Otkaži",
+ "ooui-dialog-process-error": "Nešto je pošlo naopako",
+ "ooui-dialog-process-dismiss": "Odbaci",
+ "ooui-dialog-process-retry": "Pokušajte ponovo",
+ "ooui-dialog-process-continue": "Nastavi",
+ "ooui-selectfile-not-supported": "Izbor datoteke nije podržan",
+ "ooui-selectfile-placeholder": "Nijedna datoteka nije odabrana"
}
diff --git a/vendor/oojs/oojs-ui/i18n/sk.json b/vendor/oojs/oojs-ui/i18n/sk.json
index c8246da9..fa658889 100644
--- a/vendor/oojs/oojs-ui/i18n/sk.json
+++ b/vendor/oojs/oojs-ui/i18n/sk.json
@@ -2,11 +2,21 @@
"@metadata": {
"authors": [
"Mimarik",
- "Teslaton"
+ "Teslaton",
+ "Kusavica"
]
},
"ooui-outline-control-move-down": "Posunúť položku nadol",
"ooui-outline-control-move-up": "Posunúť položku nahor",
"ooui-outline-control-remove": "Odstrániť položku",
- "ooui-toolbar-more": "Viac"
+ "ooui-toolbar-more": "Viac",
+ "ooui-toolgroup-expand": "Viac",
+ "ooui-toolgroup-collapse": "Menej",
+ "ooui-dialog-message-accept": "OK",
+ "ooui-dialog-message-reject": "Zrušiť",
+ "ooui-dialog-process-error": "Niečo sa pokazilo",
+ "ooui-dialog-process-dismiss": "Zrušiť",
+ "ooui-dialog-process-retry": "Skúsiť znova",
+ "ooui-dialog-process-continue": "Pokračovať",
+ "ooui-selectfile-placeholder": "Nie je vybraný žiadny súbor"
}
diff --git a/vendor/oojs/oojs-ui/i18n/sl.json b/vendor/oojs/oojs-ui/i18n/sl.json
index a40728ad..e113671c 100644
--- a/vendor/oojs/oojs-ui/i18n/sl.json
+++ b/vendor/oojs/oojs-ui/i18n/sl.json
@@ -18,5 +18,7 @@
"ooui-dialog-process-error": "Nekaj je šlo narobe",
"ooui-dialog-process-dismiss": "Skrij",
"ooui-dialog-process-retry": "Poskusi znova",
- "ooui-dialog-process-continue": "Nadaljuj"
+ "ooui-dialog-process-continue": "Nadaljuj",
+ "ooui-selectfile-not-supported": "Izbira datoteke ni podprta",
+ "ooui-selectfile-placeholder": "Nobena datoteka ni izbrana"
}
diff --git a/vendor/oojs/oojs-ui/i18n/sq.json b/vendor/oojs/oojs-ui/i18n/sq.json
index ec180199..4bf5dac9 100644
--- a/vendor/oojs/oojs-ui/i18n/sq.json
+++ b/vendor/oojs/oojs-ui/i18n/sq.json
@@ -5,15 +5,22 @@
"Kushtrim",
"Elioqoshi",
"GretaDoci",
- "Gertakapllani"
+ "Gertakapllani",
+ "Techlik"
]
},
"ooui-outline-control-move-down": "Zhvendose artikullin më poshtë",
"ooui-outline-control-move-up": "Zhvendose artikullin më lart",
"ooui-outline-control-remove": "Hiq artikullin",
"ooui-toolbar-more": "Më tepër...",
+ "ooui-toolgroup-expand": "Më tepër...",
+ "ooui-toolgroup-collapse": "Më pak",
"ooui-dialog-message-accept": "Në rregull",
"ooui-dialog-message-reject": "Anullo",
"ooui-dialog-process-error": "Diçka shkoi keq",
- "ooui-dialog-process-retry": "Provo përsëri"
+ "ooui-dialog-process-dismiss": "Largoje",
+ "ooui-dialog-process-retry": "Provo përsëri",
+ "ooui-dialog-process-continue": "Vazhdo",
+ "ooui-selectfile-not-supported": "Skedari i përzgjedhur nuk përkrahet",
+ "ooui-selectfile-placeholder": "Nuk është zgjedhur asnjë skedar"
}
diff --git a/vendor/oojs/oojs-ui/i18n/sr-ec.json b/vendor/oojs/oojs-ui/i18n/sr-ec.json
index c827554e..de52812e 100644
--- a/vendor/oojs/oojs-ui/i18n/sr-ec.json
+++ b/vendor/oojs/oojs-ui/i18n/sr-ec.json
@@ -17,5 +17,7 @@
"ooui-dialog-process-error": "Нешто је пошло наопако",
"ooui-dialog-process-dismiss": "Одбаци",
"ooui-dialog-process-retry": "Покушај поново",
- "ooui-dialog-process-continue": "Настави"
+ "ooui-dialog-process-continue": "Настави",
+ "ooui-selectfile-button-select": "Изабери датотеку",
+ "ooui-selectfile-placeholder": "Није изабрана ниједна датотека"
}
diff --git a/vendor/oojs/oojs-ui/i18n/su.json b/vendor/oojs/oojs-ui/i18n/su.json
new file mode 100644
index 00000000..a8cf762e
--- /dev/null
+++ b/vendor/oojs/oojs-ui/i18n/su.json
@@ -0,0 +1,21 @@
+{
+ "@metadata": {
+ "authors": [
+ "Kandar"
+ ]
+ },
+ "ooui-outline-control-move-down": "Pindahkeun ka handap",
+ "ooui-outline-control-move-up": "Pindahkeun ka luhur",
+ "ooui-outline-control-remove": "Hapus",
+ "ooui-toolbar-more": "Lobaan",
+ "ooui-toolgroup-expand": "Lobaan",
+ "ooui-toolgroup-collapse": "Saeutikan",
+ "ooui-dialog-message-accept": "Heug",
+ "ooui-dialog-message-reject": "Bolay",
+ "ooui-dialog-process-error": "Aya nu teu bener",
+ "ooui-dialog-process-dismiss": "Tutup",
+ "ooui-dialog-process-retry": "Cobaan deui",
+ "ooui-dialog-process-continue": "Teruskeun",
+ "ooui-selectfile-not-supported": "Pamilihan berkas teu dirojong",
+ "ooui-selectfile-placeholder": "Taya berkas anu dipilih"
+}
diff --git a/vendor/oojs/oojs-ui/i18n/sv.json b/vendor/oojs/oojs-ui/i18n/sv.json
index d499427c..3ffbc489 100644
--- a/vendor/oojs/oojs-ui/i18n/sv.json
+++ b/vendor/oojs/oojs-ui/i18n/sv.json
@@ -11,7 +11,8 @@
"Sendelbach",
"Skalman",
"WikiPhoenix",
- "Lokal Profil"
+ "Lokal Profil",
+ "Warrakkk"
]
},
"ooui-outline-control-move-down": "Flytta ned objekt",
@@ -25,5 +26,9 @@
"ooui-dialog-process-error": "Något gick fel",
"ooui-dialog-process-dismiss": "Stäng",
"ooui-dialog-process-retry": "Försök igen",
- "ooui-dialog-process-continue": "Fortsätt"
+ "ooui-dialog-process-continue": "Fortsätt",
+ "ooui-selectfile-button-select": "Välj en fil",
+ "ooui-selectfile-not-supported": "Filval stöds inte",
+ "ooui-selectfile-placeholder": "Ingen fil är vald",
+ "ooui-selectfile-dragdrop-placeholder": "Släpp filen här"
}
diff --git a/vendor/oojs/oojs-ui/i18n/ta.json b/vendor/oojs/oojs-ui/i18n/ta.json
index 122d4a27..6e7b2494 100644
--- a/vendor/oojs/oojs-ui/i18n/ta.json
+++ b/vendor/oojs/oojs-ui/i18n/ta.json
@@ -5,9 +5,22 @@
"Sank",
"Shanmugamp7",
"மதனாஹரன்",
- "ElangoRamanujam"
+ "ElangoRamanujam",
+ "Info-farmer"
]
},
+ "ooui-outline-control-move-down": "உருப்படியை கீழிடு",
+ "ooui-outline-control-move-up": "உருப்படியை மேலிடு",
+ "ooui-outline-control-remove": "உருப்படியை நீக்கு",
+ "ooui-toolbar-more": "மேலும்",
"ooui-toolgroup-expand": "மேலும்",
- "ooui-dialog-process-continue": "தொடரவும்"
+ "ooui-toolgroup-collapse": "குறைவாக",
+ "ooui-dialog-message-accept": "சரி",
+ "ooui-dialog-message-reject": "கைவிடுக",
+ "ooui-dialog-process-error": "ஏதோ தவறாகியுள்ளது",
+ "ooui-dialog-process-dismiss": "அகற்று",
+ "ooui-dialog-process-retry": "மீண்டும் முயல்க",
+ "ooui-dialog-process-continue": "தொடரவும்",
+ "ooui-selectfile-not-supported": "கோப்புத்தேர்வு ஆதரவாக இல்லை",
+ "ooui-selectfile-placeholder": "எக்கோப்பும் தெரிவாகவில்லை"
}
diff --git a/vendor/oojs/oojs-ui/i18n/te.json b/vendor/oojs/oojs-ui/i18n/te.json
index d4868706..957b0d0f 100644
--- a/vendor/oojs/oojs-ui/i18n/te.json
+++ b/vendor/oojs/oojs-ui/i18n/te.json
@@ -9,5 +9,14 @@
"Visdaviva",
"மதனாஹரன்"
]
- }
+ },
+ "ooui-toolbar-more": "మరిన్ని",
+ "ooui-toolgroup-expand": "మరిన్ని",
+ "ooui-toolgroup-collapse": "కొన్ని",
+ "ooui-dialog-message-accept": "సరే",
+ "ooui-dialog-message-reject": "రద్దుచేయి",
+ "ooui-dialog-process-error": "ఏదో పొరపాటు జరిగింది",
+ "ooui-dialog-process-dismiss": "రద్దుచేయి",
+ "ooui-dialog-process-retry": "మళ్ళీ ప్రయత్నించు",
+ "ooui-dialog-process-continue": "కొనసాగించు"
}
diff --git a/vendor/oojs/oojs-ui/i18n/tl.json b/vendor/oojs/oojs-ui/i18n/tl.json
index b3a9f246..c0dbd5fd 100644
--- a/vendor/oojs/oojs-ui/i18n/tl.json
+++ b/vendor/oojs/oojs-ui/i18n/tl.json
@@ -2,13 +2,22 @@
"@metadata": {
"authors": [
"AnakngAraw",
- "Sky Harbor"
+ "Sky Harbor",
+ "Jewel457"
]
},
"ooui-outline-control-move-down": "Ilipat ang aytem pababa",
"ooui-outline-control-move-up": "Ilipat ang aytem pataas",
"ooui-outline-control-remove": "Tanggalin ang aytem",
"ooui-toolbar-more": "Marami pa",
+ "ooui-toolgroup-expand": "Maraming iba pa",
+ "ooui-toolgroup-collapse": "Kakaunti",
"ooui-dialog-message-accept": "Sige",
- "ooui-dialog-message-reject": "Huwag ituloy"
+ "ooui-dialog-message-reject": "Huwag ituloy",
+ "ooui-dialog-process-error": "May pagkakamali",
+ "ooui-dialog-process-dismiss": "Isa-isantabi",
+ "ooui-dialog-process-retry": "Subuking muli",
+ "ooui-dialog-process-continue": "Magpatuloy",
+ "ooui-selectfile-not-supported": "Ang pagpili ng file ay hindi kinakatigan",
+ "ooui-selectfile-placeholder": "Walang piniling file"
}
diff --git a/vendor/oojs/oojs-ui/i18n/uk.json b/vendor/oojs/oojs-ui/i18n/uk.json
index 0197a4ce..a38afbfd 100644
--- a/vendor/oojs/oojs-ui/i18n/uk.json
+++ b/vendor/oojs/oojs-ui/i18n/uk.json
@@ -15,7 +15,9 @@
"Tel'et",
"Tifinaghes",
"Ата",
- "Piramidion"
+ "Piramidion",
+ "A1",
+ "Dars"
]
},
"ooui-outline-control-move-down": "Перемістити елемент униз",
@@ -29,5 +31,9 @@
"ooui-dialog-process-error": "Щось пішло не так",
"ooui-dialog-process-dismiss": "Приховати",
"ooui-dialog-process-retry": "Спробуйте ще раз",
- "ooui-dialog-process-continue": "Продовжити"
+ "ooui-dialog-process-continue": "Продовжити",
+ "ooui-selectfile-button-select": "Оберіть файл",
+ "ooui-selectfile-not-supported": "Вибір файлу не підтримується",
+ "ooui-selectfile-placeholder": "Жодного файлу не вибрано",
+ "ooui-selectfile-dragdrop-placeholder": "Помістіть файл сюди"
}
diff --git a/vendor/oojs/oojs-ui/i18n/vec.json b/vendor/oojs/oojs-ui/i18n/vec.json
index 4de584bf..ddd27c5e 100644
--- a/vendor/oojs/oojs-ui/i18n/vec.json
+++ b/vendor/oojs/oojs-ui/i18n/vec.json
@@ -9,5 +9,14 @@
"ooui-outline-control-move-down": "Sposta in baso",
"ooui-outline-control-move-up": "Sposta in sima",
"ooui-toolbar-more": "Altro",
- "ooui-dialog-message-accept": "Va ben"
+ "ooui-toolgroup-expand": "Piassè",
+ "ooui-toolgroup-collapse": "Manco",
+ "ooui-dialog-message-accept": "Va ben",
+ "ooui-dialog-message-reject": "Fa gnente",
+ "ooui-dialog-process-error": "Xe 'ndà storto calcossa",
+ "ooui-dialog-process-dismiss": "Scondi",
+ "ooui-dialog-process-retry": "Proa da novo",
+ "ooui-dialog-process-continue": "Và vanti",
+ "ooui-selectfile-button-select": "Siegli un file",
+ "ooui-selectfile-dragdrop-placeholder": "Mola zo el file chì rento"
}
diff --git a/vendor/oojs/oojs-ui/i18n/vi.json b/vendor/oojs/oojs-ui/i18n/vi.json
index d5c1e364..fd630814 100644
--- a/vendor/oojs/oojs-ui/i18n/vi.json
+++ b/vendor/oojs/oojs-ui/i18n/vi.json
@@ -4,19 +4,24 @@
"Cheers!",
"Jdforrester",
"Minh Nguyen",
- "Max20091"
+ "Max20091",
+ "Anh88"
]
},
"ooui-outline-control-move-down": "Chuyển mục xuống",
"ooui-outline-control-move-up": "Chuyển mục lên",
- "ooui-outline-control-remove": "Xóa khoản",
+ "ooui-outline-control-remove": "Xóa mục",
"ooui-toolbar-more": "Thêm",
"ooui-toolgroup-expand": "Mở rộng",
"ooui-toolgroup-collapse": "Rút gọn",
"ooui-dialog-message-accept": "OK",
"ooui-dialog-message-reject": "Hủy bỏ",
- "ooui-dialog-process-error": "Đã bị trục trặc",
+ "ooui-dialog-process-error": "Có thứ gì đó bị lỗi",
"ooui-dialog-process-dismiss": "Bỏ qua",
"ooui-dialog-process-retry": "Thử lại",
- "ooui-dialog-process-continue": "Tiếp tục"
+ "ooui-dialog-process-continue": "Tiếp tục",
+ "ooui-selectfile-button-select": "Chọn tập tin",
+ "ooui-selectfile-not-supported": "Không hỗ trợ việc chọn tập tin",
+ "ooui-selectfile-placeholder": "Không có tập tin nào được chọn",
+ "ooui-selectfile-dragdrop-placeholder": "Thả tập tin vào đây"
}
diff --git a/vendor/oojs/oojs-ui/i18n/xmf.json b/vendor/oojs/oojs-ui/i18n/xmf.json
new file mode 100644
index 00000000..f5bfa2c6
--- /dev/null
+++ b/vendor/oojs/oojs-ui/i18n/xmf.json
@@ -0,0 +1,19 @@
+{
+ "@metadata": {
+ "authors": [
+ "David1010"
+ ]
+ },
+ "ooui-outline-control-move-down": "ელემენტის ქვემოთ გადატანა",
+ "ooui-outline-control-move-up": "ელემენტის ზემოთ გადატანა",
+ "ooui-outline-control-remove": "ელემენტის წაშლა",
+ "ooui-toolbar-more": "უმოსი",
+ "ooui-toolgroup-expand": "უმოსი",
+ "ooui-toolgroup-collapse": "რამდენიმე",
+ "ooui-dialog-message-accept": "ჯგირი",
+ "ooui-dialog-message-reject": "გოუქვაფა",
+ "ooui-dialog-process-error": "მოხდა რაღაც შეცდომა",
+ "ooui-dialog-process-dismiss": "დამალვა",
+ "ooui-dialog-process-retry": "კიდევ სცადეთ",
+ "ooui-dialog-process-continue": "გაგრძელება"
+}
diff --git a/vendor/oojs/oojs-ui/i18n/yi.json b/vendor/oojs/oojs-ui/i18n/yi.json
index a850fce2..f206a723 100644
--- a/vendor/oojs/oojs-ui/i18n/yi.json
+++ b/vendor/oojs/oojs-ui/i18n/yi.json
@@ -10,9 +10,14 @@
"ooui-outline-control-move-up": "רוקן עלעמענט ארויף",
"ooui-outline-control-remove": "אַראָפנעמען איינס",
"ooui-toolbar-more": "נאך",
+ "ooui-toolgroup-expand": "נאך",
+ "ooui-toolgroup-collapse": "ווייניגער",
"ooui-dialog-message-accept": "יאָ",
"ooui-dialog-message-reject": "אַנולירן",
"ooui-dialog-process-error": "עפעס איז דורכגעפאלן",
"ooui-dialog-process-dismiss": "צומאַכן",
- "ooui-dialog-process-retry": "פרובירט נאכאמאל"
+ "ooui-dialog-process-retry": "פרובירט נאכאמאל",
+ "ooui-dialog-process-continue": "פֿארזעצן",
+ "ooui-selectfile-not-supported": "טעקע אויסווייל נישט געשטיצט",
+ "ooui-selectfile-placeholder": "קיין טעקע נישט אויסגעוויילט"
}
diff --git a/vendor/oojs/oojs-ui/i18n/yue.json b/vendor/oojs/oojs-ui/i18n/yue.json
index 81ad9a95..629528de 100644
--- a/vendor/oojs/oojs-ui/i18n/yue.json
+++ b/vendor/oojs/oojs-ui/i18n/yue.json
@@ -1,16 +1,26 @@
{
"@metadata": {
"authors": [
- "Deryck Chan"
+ "Deryck Chan",
+ "William915",
+ "Shinjiman",
+ "Ktchankt"
]
},
"ooui-outline-control-move-down": "向下搬",
"ooui-outline-control-move-up": "向上搬",
"ooui-outline-control-remove": "拎走",
- "ooui-toolbar-more": "仲有...",
+ "ooui-toolbar-more": "仲有",
+ "ooui-toolgroup-expand": "更多",
+ "ooui-toolgroup-collapse": "少啲",
"ooui-dialog-message-accept": "好",
"ooui-dialog-message-reject": "取消",
"ooui-dialog-process-error": "唔對路",
"ooui-dialog-process-dismiss": "閂咗佢",
- "ooui-dialog-process-retry": "再試過"
+ "ooui-dialog-process-retry": "再試過",
+ "ooui-dialog-process-continue": "繼續",
+ "ooui-selectfile-button-select": "揀檔案",
+ "ooui-selectfile-not-supported": "未有文件選擇功能",
+ "ooui-selectfile-placeholder": "無揀到文件",
+ "ooui-selectfile-dragdrop-placeholder": "放檔案響度"
}
diff --git a/vendor/oojs/oojs-ui/i18n/zh-hans.json b/vendor/oojs/oojs-ui/i18n/zh-hans.json
index ed2f61e4..9934d9d0 100644
--- a/vendor/oojs/oojs-ui/i18n/zh-hans.json
+++ b/vendor/oojs/oojs-ui/i18n/zh-hans.json
@@ -16,19 +16,24 @@
"Yfdyh000",
"Zhangjintao",
"乌拉跨氪",
- "Great Brightstar"
+ "Great Brightstar",
+ "Nbdd0121"
]
},
- "ooui-outline-control-move-down": "项目下移",
- "ooui-outline-control-move-up": "项目上移",
+ "ooui-outline-control-move-down": "向下移动一项",
+ "ooui-outline-control-move-up": "向上移动一项",
"ooui-outline-control-remove": "移除项目",
"ooui-toolbar-more": "更多",
"ooui-toolgroup-expand": "更多",
"ooui-toolgroup-collapse": "更少",
"ooui-dialog-message-accept": "确定",
"ooui-dialog-message-reject": "取消",
- "ooui-dialog-process-error": "发生一些错误",
- "ooui-dialog-process-dismiss": "解除",
+ "ooui-dialog-process-error": "发生了一些错误",
+ "ooui-dialog-process-dismiss": "关闭",
"ooui-dialog-process-retry": "重试",
- "ooui-dialog-process-continue": "继续"
+ "ooui-dialog-process-continue": "继续",
+ "ooui-selectfile-button-select": "选择一个文件",
+ "ooui-selectfile-not-supported": "文件选择不受支持",
+ "ooui-selectfile-placeholder": "没有选定文件",
+ "ooui-selectfile-dragdrop-placeholder": "将文件拖动至此"
}
diff --git a/vendor/oojs/oojs-ui/i18n/zh-hant.json b/vendor/oojs/oojs-ui/i18n/zh-hant.json
index 3fd8d361..f70efe19 100644
--- a/vendor/oojs/oojs-ui/i18n/zh-hant.json
+++ b/vendor/oojs/oojs-ui/i18n/zh-hant.json
@@ -14,7 +14,8 @@
"Spring Roll Conan",
"Waihorace",
"Cwlin0416",
- "LNDDYL"
+ "LNDDYL",
+ "Shangkuanlc"
]
},
"ooui-outline-control-move-down": "項目下移",
@@ -28,5 +29,9 @@
"ooui-dialog-process-error": "發生不明錯誤",
"ooui-dialog-process-dismiss": "關閉",
"ooui-dialog-process-retry": "再試一次",
- "ooui-dialog-process-continue": "繼續"
+ "ooui-dialog-process-continue": "繼續",
+ "ooui-selectfile-button-select": "選擇一個檔案",
+ "ooui-selectfile-not-supported": "無法支援所選擇的檔案",
+ "ooui-selectfile-placeholder": "未選擇檔案",
+ "ooui-selectfile-dragdrop-placeholder": "拖曳檔案到此處"
}
diff --git a/vendor/oojs/oojs-ui/jsduck.categories.json b/vendor/oojs/oojs-ui/jsduck.categories.json
deleted file mode 100644
index c079f073..00000000
--- a/vendor/oojs/oojs-ui/jsduck.categories.json
+++ /dev/null
@@ -1,80 +0,0 @@
-[
- {
- "name": "OOjs UI",
- "groups": [
- {
- "name": "General",
- "classes": [
- "OO.ui",
- "OO.ui.Element",
- "OO.ui.HtmlSnippet",
- "OO.ui.Toolbar",
- "OO.ui.Window",
- "OO.ui.Dialog",
- "OO.ui.WindowManager",
- "OO.ui.Process",
- "OO.ui.Error",
- "OO.ui.ActionSet"
- ]
- },
- {
- "name": "Factories",
- "classes": ["OO.ui.*Factory"]
- },
- {
- "name": "Tools",
- "classes": ["OO.ui.*Tool"]
- },
- {
- "name": "Elements",
- "classes": ["OO.ui.*Element"]
- },
- {
- "name": "Layouts",
- "classes": ["OO.ui.*Layout"]
- },
- {
- "name": "Tool groups",
- "classes": ["OO.ui.*ToolGroup"]
- },
- {
- "name": "Widgets",
- "classes": ["OO.ui.*Widget"]
- },
- {
- "name": "Dialogs",
- "classes": ["OO.ui.*Dialog"]
- },
- {
- "name": "Themes",
- "classes": ["OO.ui.*Theme"]
- }
- ]
- },
- {
- "name": "Upstream",
- "groups": [
- {
- "name": "OOJS",
- "classes": ["OO", "OO.EventEmitter", "OO.Factory", "OO.Registry"]
- },
- {
- "name": "jQuery",
- "classes": ["jQuery", "jQuery.Event", "jQuery.Promise", "jQuery.Deferred", "jQuery.jqXHR"]
- },
- {
- "name": "JavaScript",
- "classes": [
- "Array",
- "Boolean",
- "Date",
- "Function",
- "Number",
- "Object",
- "RegExp",
- "String"
- ]
- }
- ]
- }
-]
diff --git a/vendor/oojs/oojs-ui/jsduck.eg-iframe.html b/vendor/oojs/oojs-ui/jsduck.eg-iframe.html
deleted file mode 100644
index bd9c9dde..00000000
--- a/vendor/oojs/oojs-ui/jsduck.eg-iframe.html
+++ /dev/null
@@ -1,33 +0,0 @@
-<!DOCTYPE html>
-<html lang="en" dir="ltr">
-<head>
- <meta charset="UTF-8">
- <title>OOjs UI example</title>
- <!-- Prevent scaling on mobile devices which cause problems with dialog sizing -->
- <meta name="viewport" content="width=device-width, user-scalable=no">
- <style>
- body {
- font-size: 0.8em;
- font-family: sans-serif;
- }
- </style>
- <link rel="stylesheet" href="dist/oojs-ui-apex.css">
-</head>
-<body>
- <script src="node_modules/jquery/dist/jquery.js"></script>
- <script src="node_modules/oojs/dist/oojs.jquery.js"></script>
- <script src="dist/oojs-ui.js"></script>
- <script src="dist/oojs-ui-apex.js"></script>
- <script>
- function loadInlineExample( code, options, callback ) {
- try {
- eval( code );
- callback && callback( true );
- } catch (e) {
- document.body.appendChild( document.createTextNode( e ) );
- callback && callback( false, e );
- }
- }
- </script>
-</body>
-</html>
diff --git a/vendor/oojs/oojs-ui/jsduck.external.js b/vendor/oojs/oojs-ui/jsduck.external.js
deleted file mode 100644
index 655c043f..00000000
--- a/vendor/oojs/oojs-ui/jsduck.external.js
+++ /dev/null
@@ -1,26 +0,0 @@
-/**
- * @class jQuery
- * <http://api.jquery.com/>
- */
-
-/**
- * @class jQuery.Event
- * <http://api.jquery.com/Types/#Event>
- */
-
-/**
- * @class jQuery.Promise
- * <http://api.jquery.com/Types/#Promise>
- */
-
-/**
- * @class jQuery.Deferred
- * @mixins jQuery.Promise
- * <http://api.jquery.com/jQuery.Deferred/>
- */
-
-/**
- * @class jQuery.jqXHR
- * @alternateClassName jqXHR
- * <http://api.jquery.com/Types/#jqXHR>
- */
diff --git a/vendor/oojs/oojs-ui/jsduck.json b/vendor/oojs/oojs-ui/jsduck.json
deleted file mode 100644
index 918b5702..00000000
--- a/vendor/oojs/oojs-ui/jsduck.json
+++ /dev/null
@@ -1,16 +0,0 @@
-{
- "--title": "OOjs UI - Documentation",
- "--output": "docs",
- "--categories": "./jsduck.categories.json",
- "--eg-iframe": "./jsduck.eg-iframe.html",
- "--processes": "0",
- "--warnings-exit-nonzero": true,
- "--builtin-classes": true,
- "--external": "HTMLDocument,Window,MouseEvent,KeyboardEvent",
- "--warnings": ["-nodoc(class,public)"],
- "--": [
- "jsduck.external.js",
- "node_modules/oojs/dist/oojs.jquery.js",
- "src"
- ]
-}
diff --git a/vendor/oojs/oojs-ui/php/Element.php b/vendor/oojs/oojs-ui/php/Element.php
index eaa8c825..a7bd683a 100644
--- a/vendor/oojs/oojs-ui/php/Element.php
+++ b/vendor/oojs/oojs-ui/php/Element.php
@@ -9,7 +9,7 @@ namespace OOUI;
*/
class Element extends Tag {
- /* Static properties */
+ /* Static Properties */
/**
* HTML tag name.
@@ -29,7 +29,7 @@ class Element extends Tag {
*/
public static $defaultDir = 'ltr';
- /* Members */
+ /* Properties */
/**
* Element data.
@@ -39,9 +39,17 @@ class Element extends Tag {
protected $data = null;
/**
+ * CSS classes explicitly configured for this element (as opposed to #$classes, which contains all
+ * classes for this element).
+ *
+ * @var string[]
+ */
+ protected $ownClasses = array();
+
+ /**
* Mixins.
*
- * @var array List mixed in objects.
+ * @var ElementMixin[] List mixed in objects.
*/
protected $mixins = array();
@@ -69,7 +77,8 @@ class Element extends Tag {
$this->setData( $config['data'] );
}
if ( isset( $config['classes'] ) && is_array( $config['classes'] ) ) {
- $this->addClasses( $config['classes'] );
+ $this->ownClasses = $config['classes'];
+ $this->addClasses( $this->ownClasses );
}
if ( isset( $config['id'] ) ) {
$this->setAttributes( array( 'id' => $config['id'] ) );
@@ -121,7 +130,7 @@ class Element extends Tag {
* @return Tag|null Target property or null if not found
*/
public function __get( $name ) {
- // Search mixins for methods
+ // Search mixins for the property
foreach ( $this->mixins as $mixin ) {
if ( isset( $mixin::$targetPropertyName ) && $mixin::$targetPropertyName === $name ) {
return $mixin->target;
@@ -133,6 +142,22 @@ class Element extends Tag {
}
/**
+ * Check for existence of a mixed-in target property.
+ *
+ * @param string $name Property name
+ * @return bool Whether property exists
+ */
+ public function __isset( $name ) {
+ // Search mixins for the property
+ foreach ( $this->mixins as $mixin ) {
+ if ( isset( $mixin::$targetPropertyName ) && $mixin::$targetPropertyName === $name ) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
* Get the HTML tag name.
*
* Override this method to base the result on instance information.
@@ -220,6 +245,9 @@ class Element extends Tag {
if ( $this->data !== null ) {
$config['data'] = $this->data;
}
+ if ( $this->ownClasses !== array() ) {
+ $config['classes'] = $this->ownClasses;
+ }
return $config;
}
@@ -247,10 +275,18 @@ class Element extends Tag {
};
array_walk_recursive( $config, $replaceElements );
// Set '_' last to ensure that subclasses can't accidentally step on it.
- $config['_'] = preg_replace( '/^OOUI\\\\/', '', get_class( $this ) );
+ $config['_'] = $this->getJavaScriptClassName();
return $config;
}
+ /**
+ * The class name of the JavaScript version of this widget
+ * @return string
+ */
+ protected function getJavaScriptClassName() {
+ return str_replace( 'OOUI\\', 'OO.ui.', get_class( $this ) );
+ }
+
protected function getGeneratedAttributes() {
$attributesArray = parent::getGeneratedAttributes();
// Add `data-ooui` attribute from serialized config array.
diff --git a/vendor/oojs/oojs-ui/php/HtmlSnippet.php b/vendor/oojs/oojs-ui/php/HtmlSnippet.php
index e0889fca..adde8286 100644
--- a/vendor/oojs/oojs-ui/php/HtmlSnippet.php
+++ b/vendor/oojs/oojs-ui/php/HtmlSnippet.php
@@ -7,7 +7,7 @@ namespace OOUI;
*/
class HtmlSnippet {
- /* Members */
+ /* Properties */
/**
* HTML snippet this instance represents.
diff --git a/vendor/oojs/oojs-ui/php/Tag.php b/vendor/oojs/oojs-ui/php/Tag.php
index da8c2bfa..e5fa9df6 100644
--- a/vendor/oojs/oojs-ui/php/Tag.php
+++ b/vendor/oojs/oojs-ui/php/Tag.php
@@ -4,7 +4,7 @@ namespace OOUI;
class Tag {
- /* Members */
+ /* Properties */
/**
* Tag name for this instance.
@@ -296,23 +296,27 @@ class Tag {
// reasons to ever use 'javascript:' URLs anyway.
$protocolWhitelist = array(
// Sourced from MediaWiki's $wgUrlProtocols
+ // Keep in sync with OO.ui.isSafeUrl
'bitcoin', 'ftp', 'ftps', 'geo', 'git', 'gopher', 'http', 'https', 'irc', 'ircs',
'magnet', 'mailto', 'mms', 'news', 'nntp', 'redis', 'sftp', 'sip', 'sips', 'sms', 'ssh',
'svn', 'tel', 'telnet', 'urn', 'worldwind', 'xmpp',
+ '(protocol-relative)', '(relative)',
);
// Protocol-relative URLs are handled really badly by parse_url()
if ( substr( $value, 0, 2 ) === '//' ) {
- $url = "http:$value";
+ $scheme = '(protocol-relative)';
} else {
- $url = $value;
+ // Must suppress warnings when the value is not a valid URL. parse_url() returns false then.
+ \MediaWiki\suppressWarnings();
+ $scheme = parse_url( $value, PHP_URL_SCHEME );
+ \MediaWiki\restoreWarnings();
+ if ( $scheme === null || ( !$scheme && substr( $value, 0, 1 ) === '/' ) ) {
+ $scheme = '(relative)';
+ }
}
- // Must suppress warnings when the value is not a valid URL. parse_url() returns false then.
- // @codingStandardsIgnoreStart
- $scheme = @parse_url( $url, PHP_URL_SCHEME );
- // @codingStandardsIgnoreEnd
- if ( !( $scheme === null || in_array( strtolower( $scheme ), $protocolWhitelist ) ) ) {
+ if ( !in_array( strtolower( $scheme ), $protocolWhitelist ) ) {
throw new Exception( "Potentially unsafe '$key' attribute value. " .
"Scheme: '$scheme'; value: '$value'." );
}
diff --git a/vendor/oojs/oojs-ui/php/Theme.php b/vendor/oojs/oojs-ui/php/Theme.php
index d36b6d82..7f8eea36 100644
--- a/vendor/oojs/oojs-ui/php/Theme.php
+++ b/vendor/oojs/oojs-ui/php/Theme.php
@@ -7,18 +7,25 @@ namespace OOUI;
*
* @abstract
*/
-class Theme {
+abstract class Theme {
- /* Members */
+ /* Properties */
private static $singleton;
/* Static Methods */
- public static function setSingleton( Theme $theme ) {
+ /**
+ * @param Theme|null $theme
+ */
+ public static function setSingleton( Theme $theme = null ) {
self::$singleton = $theme;
}
+ /**
+ * @return Theme
+ * @throws Exception
+ */
public static function singleton() {
if ( !self::$singleton ) {
throw new Exception( __METHOD__ . ' was called with no singleton theme set.' );
@@ -51,8 +58,15 @@ class Theme {
public function updateElementClasses( Element $element ) {
$classes = $this->getElementClasses( $element );
- $element
- ->removeClasses( $classes['off'] )
- ->addClasses( $classes['on'] );
+ if ( isset( $element->icon ) ) {
+ $element->icon
+ ->removeClasses( $classes['off'] )
+ ->addClasses( $classes['on'] );
+ }
+ if ( isset( $element->indicator ) ) {
+ $element->indicator
+ ->removeClasses( $classes['off'] )
+ ->addClasses( $classes['on'] );
+ }
}
}
diff --git a/vendor/oojs/oojs-ui/php/Widget.php b/vendor/oojs/oojs-ui/php/Widget.php
index 04152aa5..7828a82e 100644
--- a/vendor/oojs/oojs-ui/php/Widget.php
+++ b/vendor/oojs/oojs-ui/php/Widget.php
@@ -9,6 +9,16 @@ namespace OOUI;
*/
class Widget extends Element {
+ /* Static Properties */
+
+ /**
+ * Whether this widget will behave reasonably when wrapped in a HTML `<label>`. If this is true,
+ * wrappers such as FieldLayout may use a `<label>`.
+ *
+ * @var boolean
+ */
+ public static $supportsSimpleLabel = false;
+
/* Properties */
/**
diff --git a/vendor/oojs/oojs-ui/php/elements/ButtonElement.php b/vendor/oojs/oojs-ui/php/elements/ButtonElement.php
deleted file mode 100644
index f9acf2d8..00000000
--- a/vendor/oojs/oojs-ui/php/elements/ButtonElement.php
+++ /dev/null
@@ -1,102 +0,0 @@
-<?php
-
-namespace OOUI;
-
-/**
- * Element with a button.
- *
- * Buttons are used for controls which can be clicked. They can be configured to use tab indexing
- * and access keys for accessibility purposes.
- *
- * @abstract
- */
-class ButtonElement extends ElementMixin {
- /**
- * Button is framed.
- *
- * @var boolean
- */
- protected $framed = false;
-
- /**
- * Button's access key.
- *
- * @var string
- */
- protected $accessKey = null;
-
- public static $targetPropertyName = 'button';
-
- /**
- * @param Element $element Element being mixed into
- * @param array $config Configuration options
- * @param boolean $config['framed'] Render button with a frame (default: true)
- * @param string $config['accessKey'] Button's access key
- */
- public function __construct( Element $element, array $config = array() ) {
- // Parent constructor
- $target = isset( $config['button'] ) ? $config['button'] : new Tag( 'a' );
- parent::__construct( $element, $target, $config );
-
- // Initialization
- $this->element->addClasses( array( 'oo-ui-buttonElement' ) );
- $this->target->addClasses( array( 'oo-ui-buttonElement-button' ) );
- $this->toggleFramed( isset( $config['framed'] ) ? $config['framed'] : true );
- $this->setAccessKey( isset( $config['accessKey'] ) ? $config['accessKey'] : null );
- $this->target->setAttributes( array(
- 'role' => 'button',
- ) );
- }
-
- /**
- * Toggle frame.
- *
- * @param boolean $framed Make button framed, omit to toggle
- * @chainable
- */
- public function toggleFramed( $framed = null ) {
- $this->framed = $framed !== null ? !!$framed : !$this->framed;
- $this->element->toggleClasses( array( 'oo-ui-buttonElement-framed' ), $this->framed );
- $this->element->toggleClasses( array( 'oo-ui-buttonElement-frameless' ), !$this->framed );
- }
-
- /**
- * Check if button has a frame.
- *
- * @return boolean Button is framed
- */
- public function isFramed() {
- return $this->framed;
- }
-
- /**
- * Set access key.
- *
- * @param string $accessKey Button's access key, use empty string to remove
- * @chainable
- */
- public function setAccessKey( $accessKey ) {
- $accessKey = is_string( $accessKey ) && strlen( $accessKey ) ? $accessKey : null;
-
- if ( $this->accessKey !== $accessKey ) {
- if ( $accessKey !== null ) {
- $this->target->setAttributes( array( 'accesskey' => $accessKey ) );
- } else {
- $this->target->removeAttributes( array( 'accesskey' ) );
- }
- $this->accessKey = $accessKey;
- }
-
- return $this;
- }
-
- public function getConfig( &$config ) {
- if ( $this->framed !== true ) {
- $config['framed'] = $this->framed;
- }
- if ( $this->accessKey !== null ) {
- $config['accessKey'] = $this->accessKey;
- }
- return parent::getConfig( $config );
- }
-}
diff --git a/vendor/oojs/oojs-ui/php/layouts/ActionFieldLayout.php b/vendor/oojs/oojs-ui/php/layouts/ActionFieldLayout.php
new file mode 100644
index 00000000..bf908184
--- /dev/null
+++ b/vendor/oojs/oojs-ui/php/layouts/ActionFieldLayout.php
@@ -0,0 +1,55 @@
+<?php
+
+namespace OOUI;
+
+/**
+ * Layout made of a field, button and optional label.
+ */
+class ActionFieldLayout extends FieldLayout {
+
+ /**
+ * Button widget to be laid out.
+ *
+ * @var Widget
+ */
+ protected $buttonWidget;
+
+ /**
+ * @param Widget $fieldWidget Field widget
+ * @param ButtonWidget $buttonWidget Field widget
+ * @param array $config Configuration options
+ */
+ public function __construct( $fieldWidget, $buttonWidget = false, array $config = array() ) {
+ // Allow passing positional parameters inside the config array
+ if ( is_array( $fieldWidget ) && isset( $fieldWidget['fieldWidget'] ) ) {
+ $config = $fieldWidget;
+ $fieldWidget = $config['fieldWidget'];
+ $buttonWidget = $config['buttonWidget'];
+ }
+
+ // Parent constructor
+ parent::__construct( $fieldWidget, $config );
+
+ // Properties
+ $this->buttonWidget = $buttonWidget;
+ $this->button = new Tag( 'div' );
+ $this->input = new Tag( 'div' );
+
+ // Initialization
+ $this->addClasses( array( 'oo-ui-actionFieldLayout' ) );
+ $this->button
+ ->addClasses( array( 'oo-ui-actionFieldLayout-button' ) )
+ ->appendContent( $this->buttonWidget );
+ $this->input
+ ->addClasses( array( 'oo-ui-actionFieldLayout-input' ) )
+ ->appendContent( $this->fieldWidget );
+ $this->field
+ ->clearContent()
+ ->appendContent( $this->input, $this->button );
+ }
+
+ public function getConfig( &$config ) {
+ $config['buttonWidget'] = $this->buttonWidget;
+ return parent::getConfig( $config );
+ }
+}
diff --git a/vendor/oojs/oojs-ui/php/layouts/FieldLayout.php b/vendor/oojs/oojs-ui/php/layouts/FieldLayout.php
index ef0d4c6c..bfa25afe 100644
--- a/vendor/oojs/oojs-ui/php/layouts/FieldLayout.php
+++ b/vendor/oojs/oojs-ui/php/layouts/FieldLayout.php
@@ -31,14 +31,37 @@ class FieldLayout extends Layout {
*/
protected $fieldWidget;
- private $field, $body, $help;
+ /**
+ * Error messages.
+ *
+ * @var array
+ */
+ protected $errors;
+
+ /**
+ * Notice messages.
+ *
+ * @var array
+ */
+ protected $notices;
+
+ /**
+ * @var ButtonWidget|string
+ */
+ protected $help;
+
+ protected $field, $body, $messages;
/**
* @param Widget $fieldWidget Field widget
* @param array $config Configuration options
* @param string $config['align'] Alignment mode, either 'left', 'right', 'top' or 'inline'
* (default: 'left')
- * @param string $config['help'] Explanatory text shown as a '?' icon.
+ * @param array $config['errors'] Error messages about the widget, as strings or HtmlSnippet
+ * instances.
+ * @param array $config['notices'] Notices about the widget, as strings or HtmlSnippet instances.
+ * @param string|HtmlSnippet $config['help'] Explanatory text shown as a '?' icon.
+ * @throws Exception An exception is thrown if no widget is specified
*/
public function __construct( $fieldWidget, array $config = array() ) {
// Allow passing positional parameters inside the config array
@@ -47,7 +70,12 @@ class FieldLayout extends Layout {
$fieldWidget = $config['fieldWidget'];
}
- $hasInputWidget = $fieldWidget instanceof InputWidget;
+ // Make sure we have required constructor arguments
+ if ( $fieldWidget === null ) {
+ throw new Exception( 'Widget not found' );
+ }
+
+ $hasInputWidget = $fieldWidget::$supportsSimpleLabel;
// Config initialization
$config = array_merge( array( 'align' => 'left' ), $config );
@@ -57,7 +85,10 @@ class FieldLayout extends Layout {
// Properties
$this->fieldWidget = $fieldWidget;
+ $this->errors = isset( $config['errors'] ) ? $config['errors'] : array();
+ $this->notices = isset( $config['notices'] ) ? $config['notices'] : array();
$this->field = new Tag( 'div' );
+ $this->messages = new Tag( 'ul' );
$this->body = new Tag( $hasInputWidget ? 'label' : 'div' );
if ( isset( $config['help'] ) ) {
$this->help = new ButtonWidget( array(
@@ -72,21 +103,55 @@ class FieldLayout extends Layout {
// Mixins
$this->mixin( new LabelElement( $this, $config ) );
+ $this->mixin( new TitledElement( $this,
+ array_merge( $config, array( 'titled' => $this->label ) ) ) );
// Initialization
$this
->addClasses( array( 'oo-ui-fieldLayout' ) )
->appendContent( $this->help, $this->body );
+ if ( count( $this->errors ) || count( $this->notices ) ) {
+ $this->appendContent( $this->messages );
+ }
$this->body->addClasses( array( 'oo-ui-fieldLayout-body' ) );
+ $this->messages->addClasses( array( 'oo-ui-fieldLayout-messages' ) );
$this->field
->addClasses( array( 'oo-ui-fieldLayout-field' ) )
->toggleClasses( array( 'oo-ui-fieldLayout-disable' ), $this->fieldWidget->isDisabled() )
->appendContent( $this->fieldWidget );
+ foreach ( $this->notices as $text ) {
+ $this->messages->appendContent( $this->makeMessage( 'notice', $text ) );
+ }
+ foreach ( $this->errors as $text ) {
+ $this->messages->appendContent( $this->makeMessage( 'error', $text ) );
+ }
+
$this->setAlignment( $config['align'] );
}
/**
+ * @param string $kind 'error' or 'notice'
+ * @param string|HtmlSnippet $text
+ * @return Tag
+ */
+ private function makeMessage( $kind, $text ) {
+ $listItem = new Tag( 'li' );
+ if ( $kind === 'error' ) {
+ $icon = new IconWidget( array( 'icon' => 'alert', 'flags' => array( 'warning' ) ) );
+ } elseif ( $kind === 'notice' ) {
+ $icon = new IconWidget( array( 'icon' => 'info' ) );
+ } else {
+ $icon = null;
+ }
+ $message = new LabelWidget( array( 'label' => $text ) );
+ $listItem
+ ->appendContent( $icon, $message )
+ ->addClasses( array( "oo-ui-fieldLayout-messages-$kind" ) );
+ return $listItem;
+ }
+
+ /**
* Get the field.
*
* @return Widget Field widget
@@ -132,6 +197,8 @@ class FieldLayout extends Layout {
public function getConfig( &$config ) {
$config['fieldWidget'] = $this->fieldWidget;
$config['align'] = $this->align;
+ $config['errors'] = $this->errors;
+ $config['notices'] = $this->notices;
if ( $this->help !== '' ) {
$config['help'] = $this->help->getTitle();
}
diff --git a/vendor/oojs/oojs-ui/php/layouts/FormLayout.php b/vendor/oojs/oojs-ui/php/layouts/FormLayout.php
index ebeb89de..eadf2750 100644
--- a/vendor/oojs/oojs-ui/php/layouts/FormLayout.php
+++ b/vendor/oojs/oojs-ui/php/layouts/FormLayout.php
@@ -7,7 +7,7 @@ namespace OOUI;
*/
class FormLayout extends Layout {
- /* Static properties */
+ /* Static Properties */
public static $tagName = 'form';
diff --git a/vendor/oojs/oojs-ui/php/layouts/HorizontalLayout.php b/vendor/oojs/oojs-ui/php/layouts/HorizontalLayout.php
new file mode 100644
index 00000000..d4acb216
--- /dev/null
+++ b/vendor/oojs/oojs-ui/php/layouts/HorizontalLayout.php
@@ -0,0 +1,27 @@
+<?php
+
+namespace OOUI;
+
+/**
+ * HorizontalLayout arranges its contents in a single line (using `display: inline-block` for its
+ * items), with small margins between them.
+ */
+class HorizontalLayout extends Layout {
+ /**
+ * @param array $config Configuration options
+ * @param Widget[]|Layout[] $config['items'] Widgets or other layouts to add to the layout.
+ */
+ public function __construct( array $config = array() ) {
+ // Parent constructor
+ parent::__construct( $config );
+
+ // Mixins
+ $this->mixin( new GroupElement( $this, array_merge( $config, array( 'group' => $this ) ) ) );
+
+ // Initialization
+ $this->addClasses( array( 'oo-ui-horizontalLayout' ) );
+ if ( isset( $config['items'] ) ) {
+ $this->addItems( $config['items'] );
+ }
+ }
+}
diff --git a/vendor/oojs/oojs-ui/php/mixins/AccessKeyedElement.php b/vendor/oojs/oojs-ui/php/mixins/AccessKeyedElement.php
new file mode 100644
index 00000000..eb4b79ea
--- /dev/null
+++ b/vendor/oojs/oojs-ui/php/mixins/AccessKeyedElement.php
@@ -0,0 +1,76 @@
+<?php
+
+namespace OOUI;
+
+/**
+ * Element with an accesskey.
+ *
+ * Accesskeys allow an user to go to a specific element by using
+ * a shortcut combination of a browser specific keys + the key
+ * set to the field.
+ *
+ * @abstract
+ */
+class AccessKeyedElement extends ElementMixin {
+ /**
+ * Accesskey
+ *
+ * @var string
+ */
+ protected $accessKey = null;
+
+ public static $targetPropertyName = 'accessKeyed';
+
+ /**
+ * @param Element $element Element being mixed into
+ * @param array $config Configuration options
+ * @param string $config['accessKey'] AccessKey. If not provided, no accesskey will be added
+ */
+ public function __construct( Element $element, array $config = array() ) {
+ // Parent constructor
+ $target = isset( $config['accessKeyed'] ) ? $config['accessKeyed'] : $element;
+ parent::__construct( $element, $target, $config );
+
+ // Initialization
+ $this->setAccessKey(
+ isset( $config['accessKey'] ) ? $config['accessKey'] : null
+ );
+ }
+
+ /**
+ * Set access key.
+ *
+ * @param string $accessKey Tag's access key, use empty string to remove
+ * @chainable
+ */
+ public function setAccessKey( $accessKey ) {
+ $accessKey = is_string( $accessKey ) && strlen( $accessKey ) ? $accessKey : null;
+
+ if ( $this->accessKey !== $accessKey ) {
+ if ( $accessKey !== null ) {
+ $this->target->setAttributes( array( 'accesskey' => $accessKey ) );
+ } else {
+ $this->target->removeAttributes( array( 'accesskey' ) );
+ }
+ $this->accessKey = $accessKey;
+ }
+
+ return $this;
+ }
+
+ /**
+ * Get AccessKey.
+ *
+ * @return string Accesskey string
+ */
+ public function getAccessKey() {
+ return $this->accessKey;
+ }
+
+ public function getConfig( &$config ) {
+ if ( $this->accessKey !== null ) {
+ $config['accessKey'] = $this->accessKey;
+ }
+ return parent::getConfig( $config );
+ }
+}
diff --git a/vendor/oojs/oojs-ui/php/mixins/ButtonElement.php b/vendor/oojs/oojs-ui/php/mixins/ButtonElement.php
new file mode 100644
index 00000000..b09c7941
--- /dev/null
+++ b/vendor/oojs/oojs-ui/php/mixins/ButtonElement.php
@@ -0,0 +1,69 @@
+<?php
+
+namespace OOUI;
+
+/**
+ * Element with a button.
+ *
+ * Buttons are used for controls which can be clicked. They can be configured to use tab indexing
+ * and access keys for accessibility purposes.
+ *
+ * @abstract
+ */
+class ButtonElement extends ElementMixin {
+ /**
+ * Button is framed.
+ *
+ * @var boolean
+ */
+ protected $framed = false;
+
+ public static $targetPropertyName = 'button';
+
+ /**
+ * @param Element $element Element being mixed into
+ * @param array $config Configuration options
+ * @param boolean $config['framed'] Render button with a frame (default: true)
+ */
+ public function __construct( Element $element, array $config = array() ) {
+ // Parent constructor
+ $target = isset( $config['button'] ) ? $config['button'] : new Tag( 'a' );
+ parent::__construct( $element, $target, $config );
+
+ // Initialization
+ $this->element->addClasses( array( 'oo-ui-buttonElement' ) );
+ $this->target->addClasses( array( 'oo-ui-buttonElement-button' ) );
+ $this->toggleFramed( isset( $config['framed'] ) ? $config['framed'] : true );
+ $this->target->setAttributes( array(
+ 'role' => 'button',
+ ) );
+ }
+
+ /**
+ * Toggle frame.
+ *
+ * @param boolean $framed Make button framed, omit to toggle
+ * @chainable
+ */
+ public function toggleFramed( $framed = null ) {
+ $this->framed = $framed !== null ? !!$framed : !$this->framed;
+ $this->element->toggleClasses( array( 'oo-ui-buttonElement-framed' ), $this->framed );
+ $this->element->toggleClasses( array( 'oo-ui-buttonElement-frameless' ), !$this->framed );
+ }
+
+ /**
+ * Check if button has a frame.
+ *
+ * @return boolean Button is framed
+ */
+ public function isFramed() {
+ return $this->framed;
+ }
+
+ public function getConfig( &$config ) {
+ if ( $this->framed !== true ) {
+ $config['framed'] = $this->framed;
+ }
+ return parent::getConfig( $config );
+ }
+}
diff --git a/vendor/oojs/oojs-ui/php/elements/FlaggedElement.php b/vendor/oojs/oojs-ui/php/mixins/FlaggedElement.php
index bd5dc80d..bd5dc80d 100644
--- a/vendor/oojs/oojs-ui/php/elements/FlaggedElement.php
+++ b/vendor/oojs/oojs-ui/php/mixins/FlaggedElement.php
diff --git a/vendor/oojs/oojs-ui/php/elements/GroupElement.php b/vendor/oojs/oojs-ui/php/mixins/GroupElement.php
index 93d3c7a1..93d3c7a1 100644
--- a/vendor/oojs/oojs-ui/php/elements/GroupElement.php
+++ b/vendor/oojs/oojs-ui/php/mixins/GroupElement.php
diff --git a/vendor/oojs/oojs-ui/php/elements/IconElement.php b/vendor/oojs/oojs-ui/php/mixins/IconElement.php
index b6d27376..b6d27376 100644
--- a/vendor/oojs/oojs-ui/php/elements/IconElement.php
+++ b/vendor/oojs/oojs-ui/php/mixins/IconElement.php
diff --git a/vendor/oojs/oojs-ui/php/elements/IndicatorElement.php b/vendor/oojs/oojs-ui/php/mixins/IndicatorElement.php
index 56238b6c..56238b6c 100644
--- a/vendor/oojs/oojs-ui/php/elements/IndicatorElement.php
+++ b/vendor/oojs/oojs-ui/php/mixins/IndicatorElement.php
diff --git a/vendor/oojs/oojs-ui/php/elements/LabelElement.php b/vendor/oojs/oojs-ui/php/mixins/LabelElement.php
index d5cf7bee..d5cf7bee 100644
--- a/vendor/oojs/oojs-ui/php/elements/LabelElement.php
+++ b/vendor/oojs/oojs-ui/php/mixins/LabelElement.php
diff --git a/vendor/oojs/oojs-ui/php/elements/TabIndexedElement.php b/vendor/oojs/oojs-ui/php/mixins/TabIndexedElement.php
index 223b5371..223b5371 100644
--- a/vendor/oojs/oojs-ui/php/elements/TabIndexedElement.php
+++ b/vendor/oojs/oojs-ui/php/mixins/TabIndexedElement.php
diff --git a/vendor/oojs/oojs-ui/php/elements/TitledElement.php b/vendor/oojs/oojs-ui/php/mixins/TitledElement.php
index 5f1317c4..5f1317c4 100644
--- a/vendor/oojs/oojs-ui/php/elements/TitledElement.php
+++ b/vendor/oojs/oojs-ui/php/mixins/TitledElement.php
diff --git a/vendor/oojs/oojs-ui/php/widgets/ButtonInputWidget.php b/vendor/oojs/oojs-ui/php/widgets/ButtonInputWidget.php
index b3bcb63b..00c17912 100644
--- a/vendor/oojs/oojs-ui/php/widgets/ButtonInputWidget.php
+++ b/vendor/oojs/oojs-ui/php/widgets/ButtonInputWidget.php
@@ -6,6 +6,15 @@ namespace OOUI;
* A button that is an input widget. Intended to be used within a FormLayout.
*/
class ButtonInputWidget extends InputWidget {
+
+ /* Static Properties */
+
+ /**
+ * Disable generating `<label>` elements for buttons. One would very rarely need additional label
+ * for a button, and it's already a big clickable target, and it causes unexpected rendering.
+ */
+ public static $supportsSimpleLabel = false;
+
/* Properties */
/**
@@ -60,8 +69,11 @@ class ButtonInputWidget extends InputWidget {
}
protected function getInputElement( $config ) {
+ $type = in_array( $config['type'], array( 'button', 'submit', 'reset' ) ) ?
+ $config['type'] :
+ 'button';
$input = new Tag( $config['useInputTag'] ? 'input' : 'button' );
- $input->setAttributes( array( 'type' => $config['type'] ) );
+ $input->setAttributes( array( 'type' => $type ) );
return $input;
}
diff --git a/vendor/oojs/oojs-ui/php/widgets/ButtonWidget.php b/vendor/oojs/oojs-ui/php/widgets/ButtonWidget.php
index f26608b1..976ac6c2 100644
--- a/vendor/oojs/oojs-ui/php/widgets/ButtonWidget.php
+++ b/vendor/oojs/oojs-ui/php/widgets/ButtonWidget.php
@@ -50,6 +50,8 @@ class ButtonWidget extends Widget {
$this->mixin( new FlaggedElement( $this, $config ) );
$this->mixin( new TabIndexedElement( $this,
array_merge( $config, array( 'tabIndexed' => $this->button ) ) ) );
+ $this->mixin( new AccessKeyedElement( $this,
+ array_merge( $config, array( 'accessKeyed' => $this->button ) ) ) );
// Initialization
$this->button->appendContent( $this->icon, $this->label, $this->indicator );
diff --git a/vendor/oojs/oojs-ui/php/widgets/CheckboxInputWidget.php b/vendor/oojs/oojs-ui/php/widgets/CheckboxInputWidget.php
index bda09c66..5d180d58 100644
--- a/vendor/oojs/oojs-ui/php/widgets/CheckboxInputWidget.php
+++ b/vendor/oojs/oojs-ui/php/widgets/CheckboxInputWidget.php
@@ -27,6 +27,8 @@ class CheckboxInputWidget extends InputWidget {
// Initialization
$this->addClasses( array( 'oo-ui-checkboxInputWidget' ) );
+ // Required for pretty styling in MediaWiki theme
+ $this->appendContent( new Tag( 'span' ) );
$this->setSelected( isset( $config['selected'] ) ? $config['selected'] : false );
}
diff --git a/vendor/oojs/oojs-ui/php/widgets/DropdownInputWidget.php b/vendor/oojs/oojs-ui/php/widgets/DropdownInputWidget.php
index ae541a66..f8ea48a3 100644
--- a/vendor/oojs/oojs-ui/php/widgets/DropdownInputWidget.php
+++ b/vendor/oojs/oojs-ui/php/widgets/DropdownInputWidget.php
@@ -23,6 +23,10 @@ class DropdownInputWidget extends InputWidget {
// Parent constructor
parent::__construct( $config );
+ // Mixins
+ $this->mixin( new TitledElement( $this,
+ array_merge( $config, array( 'titled' => $this->input ) ) ) );
+
// Initialization
$this->setOptions( isset( $config['options'] ) ? $config['options'] : array() );
$this->addClasses( array( 'oo-ui-dropdownInputWidget' ) );
@@ -60,11 +64,12 @@ class DropdownInputWidget extends InputWidget {
// Rebuild the dropdown menu
$this->input->clearContent();
foreach ( $options as $opt ) {
+ $optValue = $this->cleanUpValue( $opt['data'] );
$option = new Tag( 'option' );
- $option->setAttributes( array( 'value' => $opt['data'] ) );
- $option->appendContent( isset( $opt['label'] ) ? $opt['label'] : $opt['data'] );
+ $option->setAttributes( array( 'value' => $optValue ) );
+ $option->appendContent( isset( $opt['label'] ) ? $opt['label'] : $optValue );
- if ( $value === $opt['data'] ) {
+ if ( $value === $optValue ) {
$isValueAvailable = true;
}
diff --git a/vendor/oojs/oojs-ui/php/widgets/IconWidget.php b/vendor/oojs/oojs-ui/php/widgets/IconWidget.php
index f8273f37..d752ddc8 100644
--- a/vendor/oojs/oojs-ui/php/widgets/IconWidget.php
+++ b/vendor/oojs/oojs-ui/php/widgets/IconWidget.php
@@ -9,7 +9,7 @@ namespace OOUI;
*/
class IconWidget extends Widget {
- /* Static properties */
+ /* Static Properties */
public static $tagName = 'span';
diff --git a/vendor/oojs/oojs-ui/php/widgets/IndicatorWidget.php b/vendor/oojs/oojs-ui/php/widgets/IndicatorWidget.php
index 01f2055d..b933a309 100644
--- a/vendor/oojs/oojs-ui/php/widgets/IndicatorWidget.php
+++ b/vendor/oojs/oojs-ui/php/widgets/IndicatorWidget.php
@@ -9,7 +9,7 @@ namespace OOUI;
*/
class IndicatorWidget extends Widget {
- /* Static properties */
+ /* Static Properties */
public static $tagName = 'span';
diff --git a/vendor/oojs/oojs-ui/php/widgets/InputWidget.php b/vendor/oojs/oojs-ui/php/widgets/InputWidget.php
index 234d3145..24f5a51c 100644
--- a/vendor/oojs/oojs-ui/php/widgets/InputWidget.php
+++ b/vendor/oojs/oojs-ui/php/widgets/InputWidget.php
@@ -9,6 +9,10 @@ namespace OOUI;
*/
class InputWidget extends Widget {
+ /* Static Properties */
+
+ public static $supportsSimpleLabel = true;
+
/* Properties */
/**
@@ -42,6 +46,10 @@ class InputWidget extends Widget {
array_merge( $config, array( 'flagged' => $this ) ) ) );
$this->mixin( new TabIndexedElement( $this,
array_merge( $config, array( 'tabIndexed' => $this->input ) ) ) );
+ $this->mixin( new TitledElement( $this,
+ array_merge( $config, array( 'titled' => $this->input ) ) ) );
+ $this->mixin( new AccessKeyedElement( $this,
+ array_merge( $config, array( 'accessKeyed' => $this->input ) ) ) );
// Initialization
if ( isset( $config['name'] ) ) {
@@ -53,7 +61,7 @@ class InputWidget extends Widget {
$this
->addClasses( array( 'oo-ui-inputWidget' ) )
->appendContent( $this->input );
- $this->appendContent( new Tag( 'span' ) );
+ $this->input->addClasses( array( 'oo-ui-inputWidget-input' ) );
$this->setValue( isset( $config['value'] ) ? $config['value'] : null );
}
diff --git a/vendor/oojs/oojs-ui/php/widgets/LabelWidget.php b/vendor/oojs/oojs-ui/php/widgets/LabelWidget.php
index b59a5f25..8945b15f 100644
--- a/vendor/oojs/oojs-ui/php/widgets/LabelWidget.php
+++ b/vendor/oojs/oojs-ui/php/widgets/LabelWidget.php
@@ -7,7 +7,7 @@ namespace OOUI;
*/
class LabelWidget extends Widget {
- /* Static properties */
+ /* Static Properties */
public static $tagName = 'span';
diff --git a/vendor/oojs/oojs-ui/php/widgets/RadioInputWidget.php b/vendor/oojs/oojs-ui/php/widgets/RadioInputWidget.php
index 26da29d0..69fd0a8e 100644
--- a/vendor/oojs/oojs-ui/php/widgets/RadioInputWidget.php
+++ b/vendor/oojs/oojs-ui/php/widgets/RadioInputWidget.php
@@ -18,6 +18,8 @@ class RadioInputWidget extends InputWidget {
// Initialization
$this->addClasses( array( 'oo-ui-radioInputWidget' ) );
+ // Required for pretty styling in MediaWiki theme
+ $this->appendContent( new Tag( 'span' ) );
$this->setSelected( isset( $config['selected'] ) ? $config['selected'] : false );
}
diff --git a/vendor/oojs/oojs-ui/php/widgets/RadioSelectInputWidget.php b/vendor/oojs/oojs-ui/php/widgets/RadioSelectInputWidget.php
new file mode 100644
index 00000000..912c6917
--- /dev/null
+++ b/vendor/oojs/oojs-ui/php/widgets/RadioSelectInputWidget.php
@@ -0,0 +1,127 @@
+<?php
+
+namespace OOUI;
+
+/**
+ * Multiple radio buttons input widget. Intended to be used within a OO.ui.FormLayout.
+ */
+class RadioSelectInputWidget extends InputWidget {
+
+ /* Static Properties */
+
+ public static $supportsSimpleLabel = false;
+
+ /* Properties */
+
+ /**
+ * @var string|null
+ */
+ protected $name = null;
+
+ /**
+ * @var FieldLayout[]
+ */
+ protected $fields = array();
+
+ /**
+ * @param array $config Configuration options
+ * @param array[] $config['options'] Array of menu options in the format
+ * `array( 'data' => …, 'label' => … )`
+ */
+ public function __construct( array $config = array() ) {
+ // Parent constructor
+ parent::__construct( $config );
+
+ if ( isset( $config['name'] ) ) {
+ $this->name = $config['name'];
+ }
+
+ // Initialization
+ $this->setOptions( isset( $config['options'] ) ? $config['options'] : array() );
+ $this->addClasses( array( 'oo-ui-radioSelectInputWidget' ) );
+ }
+
+ protected function getInputElement( $config ) {
+ // Actually unused
+ return new Tag( 'div' );
+ }
+
+ public function setValue( $value ) {
+ $this->value = $this->cleanUpValue( $value );
+ foreach ( $this->fields as &$field ) {
+ $field->getField()->setSelected( $field->getField()->getValue() === $this->value );
+ }
+ return $this;
+ }
+
+ /**
+ * Set the options available for this input.
+ *
+ * @param array[] $options Array of menu options in the format
+ * `array( 'data' => …, 'label' => … )`
+ * @chainable
+ */
+ public function setOptions( $options ) {
+ $value = $this->getValue();
+ $isValueAvailable = false;
+ $this->fields = array();
+
+ // Rebuild the radio buttons
+ $this->clearContent();
+ // Need a unique name, otherwise more than one radio will be selectable
+ $name = $this->name ?: 'oo-ui-radioSelectInputWidget' . mt_rand();
+ foreach ( $options as $opt ) {
+ $optValue = $this->cleanUpValue( $opt['data'] );
+ $field = new FieldLayout(
+ new RadioInputWidget( array(
+ 'name' => $name,
+ 'value' => $optValue,
+ 'disabled' => $this->isDisabled(),
+ ) ),
+ array(
+ 'label' => isset( $opt['label'] ) ? $opt['label'] : $optValue,
+ 'align' => 'inline',
+ )
+ );
+
+ if ( $value === $optValue ) {
+ $isValueAvailable = true;
+ }
+
+ $this->fields[] = $field;
+ $this->appendContent( $field );
+ }
+
+ // Restore the previous value, or reset to something sensible
+ if ( $isValueAvailable ) {
+ // Previous value is still available
+ $this->setValue( $value );
+ } else {
+ // No longer valid, reset
+ if ( count( $options ) ) {
+ $this->setValue( $options[0]['data'] );
+ }
+ }
+
+ return $this;
+ }
+
+ public function setDisabled( $state ) {
+ parent::setDisabled( $state );
+ foreach ( $this->fields as $field ) {
+ $field->getField()->setDisabled( $this->isDisabled() );
+ }
+ return $this;
+ }
+
+ public function getConfig( &$config ) {
+ $o = array();
+ foreach ( $this->fields as $field ) {
+ $label = $field->getLabel();
+ $data = $field->getField()->getValue();
+ $o[] = array( 'data' => $data, 'label' => $label );
+ }
+ $config['options'] = $o;
+ return parent::getConfig( $config );
+ }
+}
diff --git a/vendor/oojs/oojs-ui/php/widgets/TextInputWidget.php b/vendor/oojs/oojs-ui/php/widgets/TextInputWidget.php
index a5f31f74..210729fd 100644
--- a/vendor/oojs/oojs-ui/php/widgets/TextInputWidget.php
+++ b/vendor/oojs/oojs-ui/php/widgets/TextInputWidget.php
@@ -10,6 +10,13 @@ class TextInputWidget extends InputWidget {
/* Properties */
/**
+ * Input field type.
+ *
+ * @var string
+ */
+ protected $type = null;
+
+ /**
* Prevent changes.
*
* @var boolean
@@ -25,27 +32,49 @@ class TextInputWidget extends InputWidget {
/**
* @param array $config Configuration options
- * @param string $config['type'] HTML tag `type` attribute (default: 'text')
+ * @param string $config['type'] HTML tag `type` attribute: 'text', 'password', 'search', 'email'
+ * or 'url'. Ignored if `multiline` is true. (default: 'text')
+ *
+ * Some values of `type` result in additional behaviors:
+ * - `search`: implies `icon: 'search'` and `indicator: 'clear'`; when clicked, the indicator
+ * empties the text field
* @param string $config['placeholder'] Placeholder text
* @param boolean $config['autofocus'] Ask the browser to focus this widget, using the 'autofocus'
* HTML attribute (default: false)
* @param boolean $config['readOnly'] Prevent changes (default: false)
* @param number $config['maxLength'] Maximum allowed number of characters to input
* @param boolean $config['multiline'] Allow multiple lines of text (default: false)
- * @param boolean $config['required'] Mark the field as required (default: false)
+ * @param int $config['rows'] If multiline, number of visible lines in textarea
+ * @param boolean $config['required'] Mark the field as required.
+ * Implies `indicator: 'required'`. (default: false)
+ * @param boolean $config['autocomplete'] If the field should support autocomplete
+ * or not (default: true)
*/
public function __construct( array $config = array() ) {
// Config initialization
$config = array_merge( array(
+ 'type' => 'text',
'readOnly' => false,
'autofocus' => false,
'required' => false,
+ 'autocomplete' => true,
), $config );
+ if ( $config['type'] === 'search' ) {
+ if ( !array_key_exists( 'icon', $config ) ) {
+ $config['icon'] = 'search';
+ }
+ }
+ if ( $config['required'] ) {
+ if ( !array_key_exists( 'indicator', $config ) ) {
+ $config['indicator'] = 'required';
+ }
+ }
// Parent constructor
parent::__construct( $config );
// Properties
+ $this->type = $this->getSaneType( $config );
$this->multiline = isset( $config['multiline'] ) ? (bool)$config['multiline'] : false;
// Mixins
@@ -54,7 +83,7 @@ class TextInputWidget extends InputWidget {
// Initialization
$this
- ->addClasses( array( 'oo-ui-textInputWidget' ) )
+ ->addClasses( array( 'oo-ui-textInputWidget', 'oo-ui-textInputWidget-type-' . $this->type ) )
->appendContent( $this->icon, $this->indicator );
$this->setReadOnly( $config['readOnly'] );
if ( isset( $config['placeholder'] ) ) {
@@ -69,6 +98,12 @@ class TextInputWidget extends InputWidget {
if ( $config['required'] ) {
$this->input->setAttributes( array( 'required' => 'required', 'aria-required' => 'true' ) );
}
+ if ( !$config['autocomplete'] ) {
+ $this->input->setAttributes( array( 'autocomplete' => 'off' ) );
+ }
+ if ( $this->multiline && isset( $config['rows'] ) ) {
+ $this->input->setAttributes( array( 'rows' => $config['rows'] ) );
+ }
}
/**
@@ -101,13 +136,23 @@ class TextInputWidget extends InputWidget {
if ( isset( $config['multiline'] ) && $config['multiline'] ) {
return new Tag( 'textarea' );
} else {
- $type = isset( $config['type'] ) ? $config['type'] : 'text';
$input = new Tag( 'input' );
- $input->setAttributes( array( 'type' => $type ) );
+ $input->setAttributes( array( 'type' => $this->getSaneType( $config ) ) );
return $input;
}
}
+ private function getSaneType( $config ) {
+ if ( isset( $config['multiline'] ) && $config['multiline'] ) {
+ return 'multiline';
+ } else {
+ $type = in_array( $config['type'], array( 'text', 'password', 'search', 'email', 'url' ) ) ?
+ $config['type'] :
+ 'text';
+ return $type;
+ }
+ }
+
/**
* Check if input supports multiple lines.
*
@@ -120,6 +165,10 @@ class TextInputWidget extends InputWidget {
public function getConfig( &$config ) {
if ( $this->isMultiline() ) {
$config['multiline'] = true;
+ $rows = $this->input->getAttribute( 'rows' );
+ if ( $rows !== null ) {
+ $config['rows'] = $rows;
+ }
} else {
$type = $this->input->getAttribute( 'type' );
if ( $type !== 'text' ) {
@@ -146,6 +195,10 @@ class TextInputWidget extends InputWidget {
if ( ( $required !== null ) || ( $ariarequired !== null ) ) {
$config['required'] = true;
}
+ $autocomplete = $this->input->getAttribute( 'autocomplete' );
+ if ( $autocomplete !== null ) {
+ $config['autocomplete'] = false;
+ }
return parent::getConfig( $config );
}
}
diff --git a/vendor/oojs/oojs-ui/src/ActionSet.js b/vendor/oojs/oojs-ui/src/ActionSet.js
deleted file mode 100644
index 875ca605..00000000
--- a/vendor/oojs/oojs-ui/src/ActionSet.js
+++ /dev/null
@@ -1,504 +0,0 @@
-/**
- * ActionSets manage the behavior of the {@link OO.ui.ActionWidget action widgets} that comprise them.
- * Actions can be made available for specific contexts (modes) and circumstances
- * (abilities). Action sets are primarily used with {@link OO.ui.Dialog Dialogs}.
- *
- * ActionSets contain two types of actions:
- *
- * - Special: Special actions are the first visible actions with special flags, such as 'safe' and 'primary', the default special flags. Additional special flags can be configured in subclasses with the static #specialFlags property.
- * - Other: Other actions include all non-special visible actions.
- *
- * Please see the [OOjs UI documentation on MediaWiki][1] for more information.
- *
- * @example
- * // Example: An action set used in a process dialog
- * function MyProcessDialog( config ) {
- * MyProcessDialog.super.call( this, config );
- * }
- * OO.inheritClass( MyProcessDialog, OO.ui.ProcessDialog );
- * MyProcessDialog.static.title = 'An action set in a process dialog';
- * // An action set that uses modes ('edit' and 'help' mode, in this example).
- * MyProcessDialog.static.actions = [
- * { action: 'continue', modes: 'edit', label: 'Continue', flags: [ 'primary', 'constructive' ] },
- * { action: 'help', modes: 'edit', label: 'Help' },
- * { modes: 'edit', label: 'Cancel', flags: 'safe' },
- * { action: 'back', modes: 'help', label: 'Back', flags: 'safe' }
- * ];
- *
- * MyProcessDialog.prototype.initialize = function () {
- * MyProcessDialog.super.prototype.initialize.apply( this, arguments );
- * this.panel1 = new OO.ui.PanelLayout( { padded: true, expanded: false } );
- * this.panel1.$element.append( '<p>This dialog uses an action set (continue, help, cancel, back) configured with modes. This is edit mode. Click \'help\' to see help mode.</p>' );
- * this.panel2 = new OO.ui.PanelLayout( { padded: true, expanded: false } );
- * this.panel2.$element.append( '<p>This is help mode. Only the \'back\' action widget is configured to be visible here. Click \'back\' to return to \'edit\' mode.</p>' );
- * this.stackLayout = new OO.ui.StackLayout( {
- * items: [ this.panel1, this.panel2 ]
- * } );
- * this.$body.append( this.stackLayout.$element );
- * };
- * MyProcessDialog.prototype.getSetupProcess = function ( data ) {
- * return MyProcessDialog.super.prototype.getSetupProcess.call( this, data )
- * .next( function () {
- * this.actions.setMode( 'edit' );
- * }, this );
- * };
- * MyProcessDialog.prototype.getActionProcess = function ( action ) {
- * if ( action === 'help' ) {
- * this.actions.setMode( 'help' );
- * this.stackLayout.setItem( this.panel2 );
- * } else if ( action === 'back' ) {
- * this.actions.setMode( 'edit' );
- * this.stackLayout.setItem( this.panel1 );
- * } else if ( action === 'continue' ) {
- * var dialog = this;
- * return new OO.ui.Process( function () {
- * dialog.close();
- * } );
- * }
- * return MyProcessDialog.super.prototype.getActionProcess.call( this, action );
- * };
- * MyProcessDialog.prototype.getBodyHeight = function () {
- * return this.panel1.$element.outerHeight( true );
- * };
- * var windowManager = new OO.ui.WindowManager();
- * $( 'body' ).append( windowManager.$element );
- * var dialog = new MyProcessDialog( {
- * size: 'medium'
- * } );
- * windowManager.addWindows( [ dialog ] );
- * windowManager.openWindow( dialog );
- *
- * [1]: https://www.mediawiki.org/wiki/OOjs_UI/Windows/Process_Dialogs#Action_sets
- *
- * @abstract
- * @class
- * @mixins OO.EventEmitter
- *
- * @constructor
- * @param {Object} [config] Configuration options
- */
-OO.ui.ActionSet = function OoUiActionSet( config ) {
- // Configuration initialization
- config = config || {};
-
- // Mixin constructors
- OO.EventEmitter.call( this );
-
- // Properties
- this.list = [];
- this.categories = {
- actions: 'getAction',
- flags: 'getFlags',
- modes: 'getModes'
- };
- this.categorized = {};
- this.special = {};
- this.others = [];
- this.organized = false;
- this.changing = false;
- this.changed = false;
-};
-
-/* Setup */
-
-OO.mixinClass( OO.ui.ActionSet, OO.EventEmitter );
-
-/* Static Properties */
-
-/**
- * Symbolic name of the flags used to identify special actions. Special actions are displayed in the
- * header of a {@link OO.ui.ProcessDialog process dialog}.
- * See the [OOjs UI documentation on MediaWiki][2] for more information and examples.
- *
- * [2]:https://www.mediawiki.org/wiki/OOjs_UI/Windows/Process_Dialogs
- *
- * @abstract
- * @static
- * @inheritable
- * @property {string}
- */
-OO.ui.ActionSet.static.specialFlags = [ 'safe', 'primary' ];
-
-/* Events */
-
-/**
- * @event click
- *
- * A 'click' event is emitted when an action is clicked.
- *
- * @param {OO.ui.ActionWidget} action Action that was clicked
- */
-
-/**
- * @event resize
- *
- * A 'resize' event is emitted when an action widget is resized.
- *
- * @param {OO.ui.ActionWidget} action Action that was resized
- */
-
-/**
- * @event add
- *
- * An 'add' event is emitted when actions are {@link #method-add added} to the action set.
- *
- * @param {OO.ui.ActionWidget[]} added Actions added
- */
-
-/**
- * @event remove
- *
- * A 'remove' event is emitted when actions are {@link #method-remove removed}
- * or {@link #clear cleared}.
- *
- * @param {OO.ui.ActionWidget[]} added Actions removed
- */
-
-/**
- * @event change
- *
- * A 'change' event is emitted when actions are {@link #method-add added}, {@link #clear cleared},
- * or {@link #method-remove removed} from the action set or when the {@link #setMode mode} is changed.
- *
- */
-
-/* Methods */
-
-/**
- * Handle action change events.
- *
- * @private
- * @fires change
- */
-OO.ui.ActionSet.prototype.onActionChange = function () {
- this.organized = false;
- if ( this.changing ) {
- this.changed = true;
- } else {
- this.emit( 'change' );
- }
-};
-
-/**
- * Check if an action is one of the special actions.
- *
- * @param {OO.ui.ActionWidget} action Action to check
- * @return {boolean} Action is special
- */
-OO.ui.ActionSet.prototype.isSpecial = function ( action ) {
- var flag;
-
- for ( flag in this.special ) {
- if ( action === this.special[ flag ] ) {
- return true;
- }
- }
-
- return false;
-};
-
-/**
- * Get action widgets based on the specified filter: ‘actions’, ‘flags’, ‘modes’, ‘visible’,
- * or ‘disabled’.
- *
- * @param {Object} [filters] Filters to use, omit to get all actions
- * @param {string|string[]} [filters.actions] Actions that action widgets must have
- * @param {string|string[]} [filters.flags] Flags that action widgets must have (e.g., 'safe')
- * @param {string|string[]} [filters.modes] Modes that action widgets must have
- * @param {boolean} [filters.visible] Action widgets must be visible
- * @param {boolean} [filters.disabled] Action widgets must be disabled
- * @return {OO.ui.ActionWidget[]} Action widgets matching all criteria
- */
-OO.ui.ActionSet.prototype.get = function ( filters ) {
- var i, len, list, category, actions, index, match, matches;
-
- if ( filters ) {
- this.organize();
-
- // Collect category candidates
- matches = [];
- for ( category in this.categorized ) {
- list = filters[ category ];
- if ( list ) {
- if ( !Array.isArray( list ) ) {
- list = [ list ];
- }
- for ( i = 0, len = list.length; i < len; i++ ) {
- actions = this.categorized[ category ][ list[ i ] ];
- if ( Array.isArray( actions ) ) {
- matches.push.apply( matches, actions );
- }
- }
- }
- }
- // Remove by boolean filters
- for ( i = 0, len = matches.length; i < len; i++ ) {
- match = matches[ i ];
- if (
- ( filters.visible !== undefined && match.isVisible() !== filters.visible ) ||
- ( filters.disabled !== undefined && match.isDisabled() !== filters.disabled )
- ) {
- matches.splice( i, 1 );
- len--;
- i--;
- }
- }
- // Remove duplicates
- for ( i = 0, len = matches.length; i < len; i++ ) {
- match = matches[ i ];
- index = matches.lastIndexOf( match );
- while ( index !== i ) {
- matches.splice( index, 1 );
- len--;
- index = matches.lastIndexOf( match );
- }
- }
- return matches;
- }
- return this.list.slice();
-};
-
-/**
- * Get 'special' actions.
- *
- * Special actions are the first visible action widgets with special flags, such as 'safe' and 'primary'.
- * Special flags can be configured in subclasses by changing the static #specialFlags property.
- *
- * @return {OO.ui.ActionWidget[]|null} 'Special' action widgets.
- */
-OO.ui.ActionSet.prototype.getSpecial = function () {
- this.organize();
- return $.extend( {}, this.special );
-};
-
-/**
- * Get 'other' actions.
- *
- * Other actions include all non-special visible action widgets.
- *
- * @return {OO.ui.ActionWidget[]} 'Other' action widgets
- */
-OO.ui.ActionSet.prototype.getOthers = function () {
- this.organize();
- return this.others.slice();
-};
-
-/**
- * Set the mode (e.g., ‘edit’ or ‘view’). Only {@link OO.ui.ActionWidget#modes actions} configured
- * to be available in the specified mode will be made visible. All other actions will be hidden.
- *
- * @param {string} mode The mode. Only actions configured to be available in the specified
- * mode will be made visible.
- * @chainable
- * @fires toggle
- * @fires change
- */
-OO.ui.ActionSet.prototype.setMode = function ( mode ) {
- var i, len, action;
-
- this.changing = true;
- for ( i = 0, len = this.list.length; i < len; i++ ) {
- action = this.list[ i ];
- action.toggle( action.hasMode( mode ) );
- }
-
- this.organized = false;
- this.changing = false;
- this.emit( 'change' );
-
- return this;
-};
-
-/**
- * Set the abilities of the specified actions.
- *
- * Action widgets that are configured with the specified actions will be enabled
- * or disabled based on the boolean values specified in the `actions`
- * parameter.
- *
- * @param {Object.<string,boolean>} actions A list keyed by action name with boolean
- * values that indicate whether or not the action should be enabled.
- * @chainable
- */
-OO.ui.ActionSet.prototype.setAbilities = function ( actions ) {
- var i, len, action, item;
-
- for ( i = 0, len = this.list.length; i < len; i++ ) {
- item = this.list[ i ];
- action = item.getAction();
- if ( actions[ action ] !== undefined ) {
- item.setDisabled( !actions[ action ] );
- }
- }
-
- return this;
-};
-
-/**
- * Executes a function once per action.
- *
- * When making changes to multiple actions, use this method instead of iterating over the actions
- * manually to defer emitting a #change event until after all actions have been changed.
- *
- * @param {Object|null} actions Filters to use to determine which actions to iterate over; see #get
- * @param {Function} callback Callback to run for each action; callback is invoked with three
- * arguments: the action, the action's index, the list of actions being iterated over
- * @chainable
- */
-OO.ui.ActionSet.prototype.forEach = function ( filter, callback ) {
- this.changed = false;
- this.changing = true;
- this.get( filter ).forEach( callback );
- this.changing = false;
- if ( this.changed ) {
- this.emit( 'change' );
- }
-
- return this;
-};
-
-/**
- * Add action widgets to the action set.
- *
- * @param {OO.ui.ActionWidget[]} actions Action widgets to add
- * @chainable
- * @fires add
- * @fires change
- */
-OO.ui.ActionSet.prototype.add = function ( actions ) {
- var i, len, action;
-
- this.changing = true;
- for ( i = 0, len = actions.length; i < len; i++ ) {
- action = actions[ i ];
- action.connect( this, {
- click: [ 'emit', 'click', action ],
- resize: [ 'emit', 'resize', action ],
- toggle: [ 'onActionChange' ]
- } );
- this.list.push( action );
- }
- this.organized = false;
- this.emit( 'add', actions );
- this.changing = false;
- this.emit( 'change' );
-
- return this;
-};
-
-/**
- * Remove action widgets from the set.
- *
- * To remove all actions, you may wish to use the #clear method instead.
- *
- * @param {OO.ui.ActionWidget[]} actions Action widgets to remove
- * @chainable
- * @fires remove
- * @fires change
- */
-OO.ui.ActionSet.prototype.remove = function ( actions ) {
- var i, len, index, action;
-
- this.changing = true;
- for ( i = 0, len = actions.length; i < len; i++ ) {
- action = actions[ i ];
- index = this.list.indexOf( action );
- if ( index !== -1 ) {
- action.disconnect( this );
- this.list.splice( index, 1 );
- }
- }
- this.organized = false;
- this.emit( 'remove', actions );
- this.changing = false;
- this.emit( 'change' );
-
- return this;
-};
-
-/**
- * Remove all action widets from the set.
- *
- * To remove only specified actions, use the {@link #method-remove remove} method instead.
- *
- * @chainable
- * @fires remove
- * @fires change
- */
-OO.ui.ActionSet.prototype.clear = function () {
- var i, len, action,
- removed = this.list.slice();
-
- this.changing = true;
- for ( i = 0, len = this.list.length; i < len; i++ ) {
- action = this.list[ i ];
- action.disconnect( this );
- }
-
- this.list = [];
-
- this.organized = false;
- this.emit( 'remove', removed );
- this.changing = false;
- this.emit( 'change' );
-
- return this;
-};
-
-/**
- * Organize actions.
- *
- * This is called whenever organized information is requested. It will only reorganize the actions
- * if something has changed since the last time it ran.
- *
- * @private
- * @chainable
- */
-OO.ui.ActionSet.prototype.organize = function () {
- var i, iLen, j, jLen, flag, action, category, list, item, special,
- specialFlags = this.constructor.static.specialFlags;
-
- if ( !this.organized ) {
- this.categorized = {};
- this.special = {};
- this.others = [];
- for ( i = 0, iLen = this.list.length; i < iLen; i++ ) {
- action = this.list[ i ];
- if ( action.isVisible() ) {
- // Populate categories
- for ( category in this.categories ) {
- if ( !this.categorized[ category ] ) {
- this.categorized[ category ] = {};
- }
- list = action[ this.categories[ category ] ]();
- if ( !Array.isArray( list ) ) {
- list = [ list ];
- }
- for ( j = 0, jLen = list.length; j < jLen; j++ ) {
- item = list[ j ];
- if ( !this.categorized[ category ][ item ] ) {
- this.categorized[ category ][ item ] = [];
- }
- this.categorized[ category ][ item ].push( action );
- }
- }
- // Populate special/others
- special = false;
- for ( j = 0, jLen = specialFlags.length; j < jLen; j++ ) {
- flag = specialFlags[ j ];
- if ( !this.special[ flag ] && action.hasFlag( flag ) ) {
- this.special[ flag ] = action;
- special = true;
- break;
- }
- }
- if ( !special ) {
- this.others.push( action );
- }
- }
- }
- this.organized = true;
- }
-
- return this;
-};
diff --git a/vendor/oojs/oojs-ui/src/Dialog.js b/vendor/oojs/oojs-ui/src/Dialog.js
deleted file mode 100644
index 33226038..00000000
--- a/vendor/oojs/oojs-ui/src/Dialog.js
+++ /dev/null
@@ -1,323 +0,0 @@
-/**
- * The Dialog class serves as the base class for the other types of dialogs.
- * Unless extended to include controls, the rendered dialog box is a simple window
- * that users can close by hitting the ‘Esc’ key. Dialog windows are used with OO.ui.WindowManager,
- * which opens, closes, and controls the presentation of the window. See the
- * [OOjs UI documentation on MediaWiki] [1] for more information.
- *
- * @example
- * // A simple dialog window.
- * function MyDialog( config ) {
- * MyDialog.super.call( this, config );
- * }
- * OO.inheritClass( MyDialog, OO.ui.Dialog );
- * MyDialog.prototype.initialize = function () {
- * MyDialog.super.prototype.initialize.call( this );
- * this.content = new OO.ui.PanelLayout( { padded: true, expanded: false } );
- * this.content.$element.append( '<p>A simple dialog window. Press \'Esc\' to close.</p>' );
- * this.$body.append( this.content.$element );
- * };
- * MyDialog.prototype.getBodyHeight = function () {
- * return this.content.$element.outerHeight( true );
- * };
- * var myDialog = new MyDialog( {
- * size: 'medium'
- * } );
- * // Create and append a window manager, which opens and closes the window.
- * var windowManager = new OO.ui.WindowManager();
- * $( 'body' ).append( windowManager.$element );
- * windowManager.addWindows( [ myDialog ] );
- * // Open the window!
- * windowManager.openWindow( myDialog );
- *
- * [1]: https://www.mediawiki.org/wiki/OOjs_UI/Windows/Dialogs
- *
- * @abstract
- * @class
- * @extends OO.ui.Window
- * @mixins OO.ui.PendingElement
- *
- * @constructor
- * @param {Object} [config] Configuration options
- */
-OO.ui.Dialog = function OoUiDialog( config ) {
- // Parent constructor
- OO.ui.Dialog.super.call( this, config );
-
- // Mixin constructors
- OO.ui.PendingElement.call( this );
-
- // Properties
- this.actions = new OO.ui.ActionSet();
- this.attachedActions = [];
- this.currentAction = null;
- this.onDocumentKeyDownHandler = this.onDocumentKeyDown.bind( this );
-
- // Events
- this.actions.connect( this, {
- click: 'onActionClick',
- resize: 'onActionResize',
- change: 'onActionsChange'
- } );
-
- // Initialization
- this.$element
- .addClass( 'oo-ui-dialog' )
- .attr( 'role', 'dialog' );
-};
-
-/* Setup */
-
-OO.inheritClass( OO.ui.Dialog, OO.ui.Window );
-OO.mixinClass( OO.ui.Dialog, OO.ui.PendingElement );
-
-/* Static Properties */
-
-/**
- * Symbolic name of dialog.
- *
- * The dialog class must have a symbolic name in order to be registered with OO.Factory.
- * Please see the [OOjs UI documentation on MediaWiki] [3] for more information.
- *
- * [3]: https://www.mediawiki.org/wiki/OOjs_UI/Windows/Window_managers
- *
- * @abstract
- * @static
- * @inheritable
- * @property {string}
- */
-OO.ui.Dialog.static.name = '';
-
-/**
- * The dialog title.
- *
- * The title can be specified as a plaintext string, a {@link OO.ui.LabelElement Label} node, or a function
- * that will produce a Label node or string. The title can also be specified with data passed to the
- * constructor (see #getSetupProcess). In this case, the static value will be overriden.
- *
- * @abstract
- * @static
- * @inheritable
- * @property {jQuery|string|Function}
- */
-OO.ui.Dialog.static.title = '';
-
-/**
- * An array of configured {@link OO.ui.ActionWidget action widgets}.
- *
- * Actions can also be specified with data passed to the constructor (see #getSetupProcess). In this case, the static
- * value will be overriden.
- *
- * [2]: https://www.mediawiki.org/wiki/OOjs_UI/Windows/Process_Dialogs#Action_sets
- *
- * @static
- * @inheritable
- * @property {Object[]}
- */
-OO.ui.Dialog.static.actions = [];
-
-/**
- * Close the dialog when the 'Esc' key is pressed.
- *
- * @static
- * @abstract
- * @inheritable
- * @property {boolean}
- */
-OO.ui.Dialog.static.escapable = true;
-
-/* Methods */
-
-/**
- * Handle frame document key down events.
- *
- * @private
- * @param {jQuery.Event} e Key down event
- */
-OO.ui.Dialog.prototype.onDocumentKeyDown = function ( e ) {
- if ( e.which === OO.ui.Keys.ESCAPE ) {
- this.close();
- e.preventDefault();
- e.stopPropagation();
- }
-};
-
-/**
- * Handle action resized events.
- *
- * @private
- * @param {OO.ui.ActionWidget} action Action that was resized
- */
-OO.ui.Dialog.prototype.onActionResize = function () {
- // Override in subclass
-};
-
-/**
- * Handle action click events.
- *
- * @private
- * @param {OO.ui.ActionWidget} action Action that was clicked
- */
-OO.ui.Dialog.prototype.onActionClick = function ( action ) {
- if ( !this.isPending() ) {
- this.executeAction( action.getAction() );
- }
-};
-
-/**
- * Handle actions change event.
- *
- * @private
- */
-OO.ui.Dialog.prototype.onActionsChange = function () {
- this.detachActions();
- if ( !this.isClosing() ) {
- this.attachActions();
- }
-};
-
-/**
- * Get the set of actions used by the dialog.
- *
- * @return {OO.ui.ActionSet}
- */
-OO.ui.Dialog.prototype.getActions = function () {
- return this.actions;
-};
-
-/**
- * Get a process for taking action.
- *
- * When you override this method, you can create a new OO.ui.Process and return it, or add additional
- * accept steps to the process the parent method provides using the {@link OO.ui.Process#first 'first'}
- * and {@link OO.ui.Process#next 'next'} methods of OO.ui.Process.
- *
- * @abstract
- * @param {string} [action] Symbolic name of action
- * @return {OO.ui.Process} Action process
- */
-OO.ui.Dialog.prototype.getActionProcess = function ( action ) {
- return new OO.ui.Process()
- .next( function () {
- if ( !action ) {
- // An empty action always closes the dialog without data, which should always be
- // safe and make no changes
- this.close();
- }
- }, this );
-};
-
-/**
- * @inheritdoc
- *
- * @param {Object} [data] Dialog opening data
- * @param {jQuery|string|Function|null} [data.title] Dialog title, omit to use
- * the {@link #static-title static title}
- * @param {Object[]} [data.actions] List of configuration options for each
- * {@link OO.ui.ActionWidget action widget}, omit to use {@link #static-actions static actions}.
- */
-OO.ui.Dialog.prototype.getSetupProcess = function ( data ) {
- data = data || {};
-
- // Parent method
- return OO.ui.Dialog.super.prototype.getSetupProcess.call( this, data )
- .next( function () {
- var config = this.constructor.static,
- actions = data.actions !== undefined ? data.actions : config.actions;
-
- this.title.setLabel(
- data.title !== undefined ? data.title : this.constructor.static.title
- );
- this.actions.add( this.getActionWidgets( actions ) );
-
- if ( this.constructor.static.escapable ) {
- this.$document.on( 'keydown', this.onDocumentKeyDownHandler );
- }
- }, this );
-};
-
-/**
- * @inheritdoc
- */
-OO.ui.Dialog.prototype.getTeardownProcess = function ( data ) {
- // Parent method
- return OO.ui.Dialog.super.prototype.getTeardownProcess.call( this, data )
- .first( function () {
- if ( this.constructor.static.escapable ) {
- this.$document.off( 'keydown', this.onDocumentKeyDownHandler );
- }
-
- this.actions.clear();
- this.currentAction = null;
- }, this );
-};
-
-/**
- * @inheritdoc
- */
-OO.ui.Dialog.prototype.initialize = function () {
- // Parent method
- OO.ui.Dialog.super.prototype.initialize.call( this );
-
- // Properties
- this.title = new OO.ui.LabelWidget();
-
- // Initialization
- this.$content.addClass( 'oo-ui-dialog-content' );
- this.setPendingElement( this.$head );
-};
-
-/**
- * Get action widgets from a list of configs
- *
- * @param {Object[]} actions Action widget configs
- * @return {OO.ui.ActionWidget[]} Action widgets
- */
-OO.ui.Dialog.prototype.getActionWidgets = function ( actions ) {
- var i, len, widgets = [];
- for ( i = 0, len = actions.length; i < len; i++ ) {
- widgets.push(
- new OO.ui.ActionWidget( actions[ i ] )
- );
- }
- return widgets;
-};
-
-/**
- * Attach action actions.
- *
- * @protected
- */
-OO.ui.Dialog.prototype.attachActions = function () {
- // Remember the list of potentially attached actions
- this.attachedActions = this.actions.get();
-};
-
-/**
- * Detach action actions.
- *
- * @protected
- * @chainable
- */
-OO.ui.Dialog.prototype.detachActions = function () {
- var i, len;
-
- // Detach all actions that may have been previously attached
- for ( i = 0, len = this.attachedActions.length; i < len; i++ ) {
- this.attachedActions[ i ].$element.detach();
- }
- this.attachedActions = [];
-};
-
-/**
- * Execute an action.
- *
- * @param {string} action Symbolic name of action to execute
- * @return {jQuery.Promise} Promise resolved when action completes, rejected if it fails
- */
-OO.ui.Dialog.prototype.executeAction = function ( action ) {
- this.pushPending();
- this.currentAction = action;
- return this.getActionProcess( action ).execute()
- .always( this.popPending.bind( this ) );
-};
diff --git a/vendor/oojs/oojs-ui/src/Element.js b/vendor/oojs/oojs-ui/src/Element.js
deleted file mode 100644
index 127eb503..00000000
--- a/vendor/oojs/oojs-ui/src/Element.js
+++ /dev/null
@@ -1,748 +0,0 @@
-/**
- * Each Element represents a rendering in the DOM—a button or an icon, for example, or anything
- * that is visible to a user. Unlike {@link OO.ui.Widget widgets}, plain elements usually do not have events
- * connected to them and can't be interacted with.
- *
- * @abstract
- * @class
- *
- * @constructor
- * @param {Object} [config] Configuration options
- * @cfg {string[]} [classes] The names of the CSS classes to apply to the element. CSS styles are added
- * to the top level (e.g., the outermost div) of the element. See the [OOjs UI documentation on MediaWiki][2]
- * for an example.
- * [2]: https://www.mediawiki.org/wiki/OOjs_UI/Widgets/Buttons_and_Switches#cssExample
- * @cfg {string} [id] The HTML id attribute used in the rendered tag.
- * @cfg {string} [text] Text to insert
- * @cfg {Array} [content] An array of content elements to append (after #text).
- * Strings will be html-escaped; use an OO.ui.HtmlSnippet to append raw HTML.
- * Instances of OO.ui.Element will have their $element appended.
- * @cfg {jQuery} [$content] Content elements to append (after #text)
- * @cfg {Mixed} [data] Custom data of any type or combination of types (e.g., string, number, array, object).
- * Data can also be specified with the #setData method.
- */
-OO.ui.Element = function OoUiElement( config ) {
- // Configuration initialization
- config = config || {};
-
- // Properties
- this.$ = $;
- this.visible = true;
- this.data = config.data;
- this.$element = config.$element ||
- $( document.createElement( this.getTagName() ) );
- this.elementGroup = null;
- this.debouncedUpdateThemeClassesHandler = this.debouncedUpdateThemeClasses.bind( this );
- this.updateThemeClassesPending = false;
-
- // Initialization
- if ( Array.isArray( config.classes ) ) {
- this.$element.addClass( config.classes.join( ' ' ) );
- }
- if ( config.id ) {
- this.$element.attr( 'id', config.id );
- }
- if ( config.text ) {
- this.$element.text( config.text );
- }
- if ( config.content ) {
- // The `content` property treats plain strings as text; use an
- // HtmlSnippet to append HTML content. `OO.ui.Element`s get their
- // appropriate $element appended.
- this.$element.append( config.content.map( function ( v ) {
- if ( typeof v === 'string' ) {
- // Escape string so it is properly represented in HTML.
- return document.createTextNode( v );
- } else if ( v instanceof OO.ui.HtmlSnippet ) {
- // Bypass escaping.
- return v.toString();
- } else if ( v instanceof OO.ui.Element ) {
- return v.$element;
- }
- return v;
- } ) );
- }
- if ( config.$content ) {
- // The `$content` property treats plain strings as HTML.
- this.$element.append( config.$content );
- }
-};
-
-/* Setup */
-
-OO.initClass( OO.ui.Element );
-
-/* Static Properties */
-
-/**
- * The name of the HTML tag used by the element.
- *
- * The static value may be ignored if the #getTagName method is overridden.
- *
- * @static
- * @inheritable
- * @property {string}
- */
-OO.ui.Element.static.tagName = 'div';
-
-/* Static Methods */
-
-/**
- * Reconstitute a JavaScript object corresponding to a widget created
- * by the PHP implementation.
- *
- * @param {string|HTMLElement|jQuery} idOrNode
- * A DOM id (if a string) or node for the widget to infuse.
- * @return {OO.ui.Element}
- * The `OO.ui.Element` corresponding to this (infusable) document node.
- * For `Tag` objects emitted on the HTML side (used occasionally for content)
- * the value returned is a newly-created Element wrapping around the existing
- * DOM node.
- */
-OO.ui.Element.static.infuse = function ( idOrNode ) {
- var obj = OO.ui.Element.static.unsafeInfuse( idOrNode, true );
- // Verify that the type matches up.
- // FIXME: uncomment after T89721 is fixed (see T90929)
- /*
- if ( !( obj instanceof this['class'] ) ) {
- throw new Error( 'Infusion type mismatch!' );
- }
- */
- return obj;
-};
-
-/**
- * Implementation helper for `infuse`; skips the type check and has an
- * extra property so that only the top-level invocation touches the DOM.
- * @private
- * @param {string|HTMLElement|jQuery} idOrNode
- * @param {boolean} top True only for top-level invocation.
- * @return {OO.ui.Element}
- */
-OO.ui.Element.static.unsafeInfuse = function ( idOrNode, top ) {
- // look for a cached result of a previous infusion.
- var id, $elem, data, cls, obj;
- if ( typeof idOrNode === 'string' ) {
- id = idOrNode;
- $elem = $( document.getElementById( id ) );
- } else {
- $elem = $( idOrNode );
- id = $elem.attr( 'id' );
- }
- data = $elem.data( 'ooui-infused' );
- if ( data ) {
- // cached!
- if ( data === true ) {
- throw new Error( 'Circular dependency! ' + id );
- }
- return data;
- }
- if ( !$elem.length ) {
- throw new Error( 'Widget not found: ' + id );
- }
- data = $elem.attr( 'data-ooui' );
- if ( !data ) {
- throw new Error( 'No infusion data found: ' + id );
- }
- try {
- data = $.parseJSON( data );
- } catch ( _ ) {
- data = null;
- }
- if ( !( data && data._ ) ) {
- throw new Error( 'No valid infusion data found: ' + id );
- }
- if ( data._ === 'Tag' ) {
- // Special case: this is a raw Tag; wrap existing node, don't rebuild.
- return new OO.ui.Element( { $element: $elem } );
- }
- cls = OO.ui[data._];
- if ( !cls ) {
- throw new Error( 'Unknown widget type: ' + id );
- }
- $elem.data( 'ooui-infused', true ); // prevent loops
- data.id = id; // implicit
- data = OO.copy( data, null, function deserialize( value ) {
- if ( OO.isPlainObject( value ) ) {
- if ( value.tag ) {
- return OO.ui.Element.static.unsafeInfuse( value.tag, false );
- }
- if ( value.html ) {
- return new OO.ui.HtmlSnippet( value.html );
- }
- }
- } );
- // jscs:disable requireCapitalizedConstructors
- obj = new cls( data ); // rebuild widget
- // now replace old DOM with this new DOM.
- if ( top ) {
- $elem.replaceWith( obj.$element );
- }
- obj.$element.data( 'ooui-infused', obj );
- // set the 'data-ooui' attribute so we can identify infused widgets
- obj.$element.attr( 'data-ooui', '' );
- return obj;
-};
-
-/**
- * Get a jQuery function within a specific document.
- *
- * @static
- * @param {jQuery|HTMLElement|HTMLDocument|Window} context Context to bind the function to
- * @param {jQuery} [$iframe] HTML iframe element that contains the document, omit if document is
- * not in an iframe
- * @return {Function} Bound jQuery function
- */
-OO.ui.Element.static.getJQuery = function ( context, $iframe ) {
- function wrapper( selector ) {
- return $( selector, wrapper.context );
- }
-
- wrapper.context = this.getDocument( context );
-
- if ( $iframe ) {
- wrapper.$iframe = $iframe;
- }
-
- return wrapper;
-};
-
-/**
- * Get the document of an element.
- *
- * @static
- * @param {jQuery|HTMLElement|HTMLDocument|Window} obj Object to get the document for
- * @return {HTMLDocument|null} Document object
- */
-OO.ui.Element.static.getDocument = function ( obj ) {
- // jQuery - selections created "offscreen" won't have a context, so .context isn't reliable
- return ( obj[ 0 ] && obj[ 0 ].ownerDocument ) ||
- // Empty jQuery selections might have a context
- obj.context ||
- // HTMLElement
- obj.ownerDocument ||
- // Window
- obj.document ||
- // HTMLDocument
- ( obj.nodeType === 9 && obj ) ||
- null;
-};
-
-/**
- * Get the window of an element or document.
- *
- * @static
- * @param {jQuery|HTMLElement|HTMLDocument|Window} obj Context to get the window for
- * @return {Window} Window object
- */
-OO.ui.Element.static.getWindow = function ( obj ) {
- var doc = this.getDocument( obj );
- return doc.parentWindow || doc.defaultView;
-};
-
-/**
- * Get the direction of an element or document.
- *
- * @static
- * @param {jQuery|HTMLElement|HTMLDocument|Window} obj Context to get the direction for
- * @return {string} Text direction, either 'ltr' or 'rtl'
- */
-OO.ui.Element.static.getDir = function ( obj ) {
- var isDoc, isWin;
-
- if ( obj instanceof jQuery ) {
- obj = obj[ 0 ];
- }
- isDoc = obj.nodeType === 9;
- isWin = obj.document !== undefined;
- if ( isDoc || isWin ) {
- if ( isWin ) {
- obj = obj.document;
- }
- obj = obj.body;
- }
- return $( obj ).css( 'direction' );
-};
-
-/**
- * Get the offset between two frames.
- *
- * TODO: Make this function not use recursion.
- *
- * @static
- * @param {Window} from Window of the child frame
- * @param {Window} [to=window] Window of the parent frame
- * @param {Object} [offset] Offset to start with, used internally
- * @return {Object} Offset object, containing left and top properties
- */
-OO.ui.Element.static.getFrameOffset = function ( from, to, offset ) {
- var i, len, frames, frame, rect;
-
- if ( !to ) {
- to = window;
- }
- if ( !offset ) {
- offset = { top: 0, left: 0 };
- }
- if ( from.parent === from ) {
- return offset;
- }
-
- // Get iframe element
- frames = from.parent.document.getElementsByTagName( 'iframe' );
- for ( i = 0, len = frames.length; i < len; i++ ) {
- if ( frames[ i ].contentWindow === from ) {
- frame = frames[ i ];
- break;
- }
- }
-
- // Recursively accumulate offset values
- if ( frame ) {
- rect = frame.getBoundingClientRect();
- offset.left += rect.left;
- offset.top += rect.top;
- if ( from !== to ) {
- this.getFrameOffset( from.parent, offset );
- }
- }
- return offset;
-};
-
-/**
- * Get the offset between two elements.
- *
- * The two elements may be in a different frame, but in that case the frame $element is in must
- * be contained in the frame $anchor is in.
- *
- * @static
- * @param {jQuery} $element Element whose position to get
- * @param {jQuery} $anchor Element to get $element's position relative to
- * @return {Object} Translated position coordinates, containing top and left properties
- */
-OO.ui.Element.static.getRelativePosition = function ( $element, $anchor ) {
- var iframe, iframePos,
- pos = $element.offset(),
- anchorPos = $anchor.offset(),
- elementDocument = this.getDocument( $element ),
- anchorDocument = this.getDocument( $anchor );
-
- // If $element isn't in the same document as $anchor, traverse up
- while ( elementDocument !== anchorDocument ) {
- iframe = elementDocument.defaultView.frameElement;
- if ( !iframe ) {
- throw new Error( '$element frame is not contained in $anchor frame' );
- }
- iframePos = $( iframe ).offset();
- pos.left += iframePos.left;
- pos.top += iframePos.top;
- elementDocument = iframe.ownerDocument;
- }
- pos.left -= anchorPos.left;
- pos.top -= anchorPos.top;
- return pos;
-};
-
-/**
- * Get element border sizes.
- *
- * @static
- * @param {HTMLElement} el Element to measure
- * @return {Object} Dimensions object with `top`, `left`, `bottom` and `right` properties
- */
-OO.ui.Element.static.getBorders = function ( el ) {
- var doc = el.ownerDocument,
- win = doc.parentWindow || doc.defaultView,
- style = win && win.getComputedStyle ?
- win.getComputedStyle( el, null ) :
- el.currentStyle,
- $el = $( el ),
- top = parseFloat( style ? style.borderTopWidth : $el.css( 'borderTopWidth' ) ) || 0,
- left = parseFloat( style ? style.borderLeftWidth : $el.css( 'borderLeftWidth' ) ) || 0,
- bottom = parseFloat( style ? style.borderBottomWidth : $el.css( 'borderBottomWidth' ) ) || 0,
- right = parseFloat( style ? style.borderRightWidth : $el.css( 'borderRightWidth' ) ) || 0;
-
- return {
- top: top,
- left: left,
- bottom: bottom,
- right: right
- };
-};
-
-/**
- * Get dimensions of an element or window.
- *
- * @static
- * @param {HTMLElement|Window} el Element to measure
- * @return {Object} Dimensions object with `borders`, `scroll`, `scrollbar` and `rect` properties
- */
-OO.ui.Element.static.getDimensions = function ( el ) {
- var $el, $win,
- doc = el.ownerDocument || el.document,
- win = doc.parentWindow || doc.defaultView;
-
- if ( win === el || el === doc.documentElement ) {
- $win = $( win );
- return {
- borders: { top: 0, left: 0, bottom: 0, right: 0 },
- scroll: {
- top: $win.scrollTop(),
- left: $win.scrollLeft()
- },
- scrollbar: { right: 0, bottom: 0 },
- rect: {
- top: 0,
- left: 0,
- bottom: $win.innerHeight(),
- right: $win.innerWidth()
- }
- };
- } else {
- $el = $( el );
- return {
- borders: this.getBorders( el ),
- scroll: {
- top: $el.scrollTop(),
- left: $el.scrollLeft()
- },
- scrollbar: {
- right: $el.innerWidth() - el.clientWidth,
- bottom: $el.innerHeight() - el.clientHeight
- },
- rect: el.getBoundingClientRect()
- };
- }
-};
-
-/**
- * Get scrollable object parent
- *
- * documentElement can't be used to get or set the scrollTop
- * property on Blink. Changing and testing its value lets us
- * use 'body' or 'documentElement' based on what is working.
- *
- * https://code.google.com/p/chromium/issues/detail?id=303131
- *
- * @static
- * @param {HTMLElement} el Element to find scrollable parent for
- * @return {HTMLElement} Scrollable parent
- */
-OO.ui.Element.static.getRootScrollableElement = function ( el ) {
- var scrollTop, body;
-
- if ( OO.ui.scrollableElement === undefined ) {
- body = el.ownerDocument.body;
- scrollTop = body.scrollTop;
- body.scrollTop = 1;
-
- if ( body.scrollTop === 1 ) {
- body.scrollTop = scrollTop;
- OO.ui.scrollableElement = 'body';
- } else {
- OO.ui.scrollableElement = 'documentElement';
- }
- }
-
- return el.ownerDocument[ OO.ui.scrollableElement ];
-};
-
-/**
- * Get closest scrollable container.
- *
- * Traverses up until either a scrollable element or the root is reached, in which case the window
- * will be returned.
- *
- * @static
- * @param {HTMLElement} el Element to find scrollable container for
- * @param {string} [dimension] Dimension of scrolling to look for; `x`, `y` or omit for either
- * @return {HTMLElement} Closest scrollable container
- */
-OO.ui.Element.static.getClosestScrollableContainer = function ( el, dimension ) {
- var i, val,
- props = [ 'overflow' ],
- $parent = $( el ).parent();
-
- if ( dimension === 'x' || dimension === 'y' ) {
- props.push( 'overflow-' + dimension );
- }
-
- while ( $parent.length ) {
- if ( $parent[ 0 ] === this.getRootScrollableElement( el ) ) {
- return $parent[ 0 ];
- }
- i = props.length;
- while ( i-- ) {
- val = $parent.css( props[ i ] );
- if ( val === 'auto' || val === 'scroll' ) {
- return $parent[ 0 ];
- }
- }
- $parent = $parent.parent();
- }
- return this.getDocument( el ).body;
-};
-
-/**
- * Scroll element into view.
- *
- * @static
- * @param {HTMLElement} el Element to scroll into view
- * @param {Object} [config] Configuration options
- * @param {string} [config.duration] jQuery animation duration value
- * @param {string} [config.direction] Scroll in only one direction, e.g. 'x' or 'y', omit
- * to scroll in both directions
- * @param {Function} [config.complete] Function to call when scrolling completes
- */
-OO.ui.Element.static.scrollIntoView = function ( el, config ) {
- // Configuration initialization
- config = config || {};
-
- var rel, anim = {},
- callback = typeof config.complete === 'function' && config.complete,
- sc = this.getClosestScrollableContainer( el, config.direction ),
- $sc = $( sc ),
- eld = this.getDimensions( el ),
- scd = this.getDimensions( sc ),
- $win = $( this.getWindow( el ) );
-
- // Compute the distances between the edges of el and the edges of the scroll viewport
- if ( $sc.is( 'html, body' ) ) {
- // If the scrollable container is the root, this is easy
- rel = {
- top: eld.rect.top,
- bottom: $win.innerHeight() - eld.rect.bottom,
- left: eld.rect.left,
- right: $win.innerWidth() - eld.rect.right
- };
- } else {
- // Otherwise, we have to subtract el's coordinates from sc's coordinates
- rel = {
- top: eld.rect.top - ( scd.rect.top + scd.borders.top ),
- bottom: scd.rect.bottom - scd.borders.bottom - scd.scrollbar.bottom - eld.rect.bottom,
- left: eld.rect.left - ( scd.rect.left + scd.borders.left ),
- right: scd.rect.right - scd.borders.right - scd.scrollbar.right - eld.rect.right
- };
- }
-
- if ( !config.direction || config.direction === 'y' ) {
- if ( rel.top < 0 ) {
- anim.scrollTop = scd.scroll.top + rel.top;
- } else if ( rel.top > 0 && rel.bottom < 0 ) {
- anim.scrollTop = scd.scroll.top + Math.min( rel.top, -rel.bottom );
- }
- }
- if ( !config.direction || config.direction === 'x' ) {
- if ( rel.left < 0 ) {
- anim.scrollLeft = scd.scroll.left + rel.left;
- } else if ( rel.left > 0 && rel.right < 0 ) {
- anim.scrollLeft = scd.scroll.left + Math.min( rel.left, -rel.right );
- }
- }
- if ( !$.isEmptyObject( anim ) ) {
- $sc.stop( true ).animate( anim, config.duration || 'fast' );
- if ( callback ) {
- $sc.queue( function ( next ) {
- callback();
- next();
- } );
- }
- } else {
- if ( callback ) {
- callback();
- }
- }
-};
-
-/**
- * Force the browser to reconsider whether it really needs to render scrollbars inside the element
- * and reserve space for them, because it probably doesn't.
- *
- * Workaround primarily for <https://code.google.com/p/chromium/issues/detail?id=387290>, but also
- * similar bugs in other browsers. "Just" forcing a reflow is not sufficient in all cases, we need
- * to first actually detach (or hide, but detaching is simpler) all children, *then* force a reflow,
- * and then reattach (or show) them back.
- *
- * @static
- * @param {HTMLElement} el Element to reconsider the scrollbars on
- */
-OO.ui.Element.static.reconsiderScrollbars = function ( el ) {
- var i, len, nodes = [];
- // Detach all children
- while ( el.firstChild ) {
- nodes.push( el.firstChild );
- el.removeChild( el.firstChild );
- }
- // Force reflow
- void el.offsetHeight;
- // Reattach all children
- for ( i = 0, len = nodes.length; i < len; i++ ) {
- el.appendChild( nodes[ i ] );
- }
-};
-
-/* Methods */
-
-/**
- * Toggle visibility of an element.
- *
- * @param {boolean} [show] Make element visible, omit to toggle visibility
- * @fires visible
- * @chainable
- */
-OO.ui.Element.prototype.toggle = function ( show ) {
- show = show === undefined ? !this.visible : !!show;
-
- if ( show !== this.isVisible() ) {
- this.visible = show;
- this.$element.toggleClass( 'oo-ui-element-hidden', !this.visible );
- this.emit( 'toggle', show );
- }
-
- return this;
-};
-
-/**
- * Check if element is visible.
- *
- * @return {boolean} element is visible
- */
-OO.ui.Element.prototype.isVisible = function () {
- return this.visible;
-};
-
-/**
- * Get element data.
- *
- * @return {Mixed} Element data
- */
-OO.ui.Element.prototype.getData = function () {
- return this.data;
-};
-
-/**
- * Set element data.
- *
- * @param {Mixed} Element data
- * @chainable
- */
-OO.ui.Element.prototype.setData = function ( data ) {
- this.data = data;
- return this;
-};
-
-/**
- * Check if element supports one or more methods.
- *
- * @param {string|string[]} methods Method or list of methods to check
- * @return {boolean} All methods are supported
- */
-OO.ui.Element.prototype.supports = function ( methods ) {
- var i, len,
- support = 0;
-
- methods = Array.isArray( methods ) ? methods : [ methods ];
- for ( i = 0, len = methods.length; i < len; i++ ) {
- if ( $.isFunction( this[ methods[ i ] ] ) ) {
- support++;
- }
- }
-
- return methods.length === support;
-};
-
-/**
- * Update the theme-provided classes.
- *
- * @localdoc This is called in element mixins and widget classes any time state changes.
- * Updating is debounced, minimizing overhead of changing multiple attributes and
- * guaranteeing that theme updates do not occur within an element's constructor
- */
-OO.ui.Element.prototype.updateThemeClasses = function () {
- if ( !this.updateThemeClassesPending ) {
- this.updateThemeClassesPending = true;
- setTimeout( this.debouncedUpdateThemeClassesHandler );
- }
-};
-
-/**
- * @private
- */
-OO.ui.Element.prototype.debouncedUpdateThemeClasses = function () {
- OO.ui.theme.updateElementClasses( this );
- this.updateThemeClassesPending = false;
-};
-
-/**
- * Get the HTML tag name.
- *
- * Override this method to base the result on instance information.
- *
- * @return {string} HTML tag name
- */
-OO.ui.Element.prototype.getTagName = function () {
- return this.constructor.static.tagName;
-};
-
-/**
- * Check if the element is attached to the DOM
- * @return {boolean} The element is attached to the DOM
- */
-OO.ui.Element.prototype.isElementAttached = function () {
- return $.contains( this.getElementDocument(), this.$element[ 0 ] );
-};
-
-/**
- * Get the DOM document.
- *
- * @return {HTMLDocument} Document object
- */
-OO.ui.Element.prototype.getElementDocument = function () {
- // Don't cache this in other ways either because subclasses could can change this.$element
- return OO.ui.Element.static.getDocument( this.$element );
-};
-
-/**
- * Get the DOM window.
- *
- * @return {Window} Window object
- */
-OO.ui.Element.prototype.getElementWindow = function () {
- return OO.ui.Element.static.getWindow( this.$element );
-};
-
-/**
- * Get closest scrollable container.
- */
-OO.ui.Element.prototype.getClosestScrollableElementContainer = function () {
- return OO.ui.Element.static.getClosestScrollableContainer( this.$element[ 0 ] );
-};
-
-/**
- * Get group element is in.
- *
- * @return {OO.ui.GroupElement|null} Group element, null if none
- */
-OO.ui.Element.prototype.getElementGroup = function () {
- return this.elementGroup;
-};
-
-/**
- * Set group element is in.
- *
- * @param {OO.ui.GroupElement|null} group Group element, null if none
- * @chainable
- */
-OO.ui.Element.prototype.setElementGroup = function ( group ) {
- this.elementGroup = group;
- return this;
-};
-
-/**
- * Scroll element into view.
- *
- * @param {Object} [config] Configuration options
- */
-OO.ui.Element.prototype.scrollElementIntoView = function ( config ) {
- return OO.ui.Element.static.scrollIntoView( this.$element[ 0 ], config );
-};
diff --git a/vendor/oojs/oojs-ui/src/Error.js b/vendor/oojs/oojs-ui/src/Error.js
deleted file mode 100644
index af87b722..00000000
--- a/vendor/oojs/oojs-ui/src/Error.js
+++ /dev/null
@@ -1,91 +0,0 @@
-/**
- * Errors contain a required message (either a string or jQuery selection) that is used to describe what went wrong
- * in a {@link OO.ui.Process process}. The error's #recoverable and #warning configurations are used to customize the
- * appearance and functionality of the error interface.
- *
- * The basic error interface contains a formatted error message as well as two buttons: 'Dismiss' and 'Try again' (i.e., the error
- * is 'recoverable' by default). If the error is not recoverable, the 'Try again' button will not be rendered and the widget
- * that initiated the failed process will be disabled.
- *
- * If the error is a warning, the error interface will include a 'Dismiss' and a 'Continue' button, which will try the
- * process again.
- *
- * For an example of error interfaces, please see the [OOjs UI documentation on MediaWiki][1].
- *
- * [1]: https://www.mediawiki.org/wiki/OOjs_UI/Windows/Process_Dialogs#Processes_and_errors
- *
- * @class
- *
- * @constructor
- * @param {string|jQuery} message Description of error
- * @param {Object} [config] Configuration options
- * @cfg {boolean} [recoverable=true] Error is recoverable.
- * By default, errors are recoverable, and users can try the process again.
- * @cfg {boolean} [warning=false] Error is a warning.
- * If the error is a warning, the error interface will include a
- * 'Dismiss' and a 'Continue' button. It is the responsibility of the developer to ensure that the warning
- * is not triggered a second time if the user chooses to continue.
- */
-OO.ui.Error = function OoUiError( message, config ) {
- // Allow passing positional parameters inside the config object
- if ( OO.isPlainObject( message ) && config === undefined ) {
- config = message;
- message = config.message;
- }
-
- // Configuration initialization
- config = config || {};
-
- // Properties
- this.message = message instanceof jQuery ? message : String( message );
- this.recoverable = config.recoverable === undefined || !!config.recoverable;
- this.warning = !!config.warning;
-};
-
-/* Setup */
-
-OO.initClass( OO.ui.Error );
-
-/* Methods */
-
-/**
- * Check if the error is recoverable.
- *
- * If the error is recoverable, users are able to try the process again.
- *
- * @return {boolean} Error is recoverable
- */
-OO.ui.Error.prototype.isRecoverable = function () {
- return this.recoverable;
-};
-
-/**
- * Check if the error is a warning.
- *
- * If the error is a warning, the error interface will include a 'Dismiss' and a 'Continue' button.
- *
- * @return {boolean} Error is warning
- */
-OO.ui.Error.prototype.isWarning = function () {
- return this.warning;
-};
-
-/**
- * Get error message as DOM nodes.
- *
- * @return {jQuery} Error message in DOM nodes
- */
-OO.ui.Error.prototype.getMessage = function () {
- return this.message instanceof jQuery ?
- this.message.clone() :
- $( '<div>' ).text( this.message ).contents();
-};
-
-/**
- * Get the error message text.
- *
- * @return {string} Error message
- */
-OO.ui.Error.prototype.getMessageText = function () {
- return this.message instanceof jQuery ? this.message.text() : this.message;
-};
diff --git a/vendor/oojs/oojs-ui/src/HtmlSnippet.js b/vendor/oojs/oojs-ui/src/HtmlSnippet.js
deleted file mode 100644
index b9c5c314..00000000
--- a/vendor/oojs/oojs-ui/src/HtmlSnippet.js
+++ /dev/null
@@ -1,29 +0,0 @@
-/**
- * Wraps an HTML snippet for use with configuration values which default
- * to strings. This bypasses the default html-escaping done to string
- * values.
- *
- * @class
- *
- * @constructor
- * @param {string} [content] HTML content
- */
-OO.ui.HtmlSnippet = function OoUiHtmlSnippet( content ) {
- // Properties
- this.content = content;
-};
-
-/* Setup */
-
-OO.initClass( OO.ui.HtmlSnippet );
-
-/* Methods */
-
-/**
- * Render into HTML.
- *
- * @return {string} Unchanged HTML snippet.
- */
-OO.ui.HtmlSnippet.prototype.toString = function () {
- return this.content;
-};
diff --git a/vendor/oojs/oojs-ui/src/Layout.js b/vendor/oojs/oojs-ui/src/Layout.js
deleted file mode 100644
index d0c368f5..00000000
--- a/vendor/oojs/oojs-ui/src/Layout.js
+++ /dev/null
@@ -1,33 +0,0 @@
-/**
- * Layouts are containers for elements and are used to arrange other widgets of arbitrary type in a way
- * that is centrally controlled and can be updated dynamically. Layouts can be, and usually are, combined.
- * See {@link OO.ui.FieldsetLayout FieldsetLayout}, {@link OO.ui.FieldLayout FieldLayout}, {@link OO.ui.FormLayout FormLayout},
- * {@link OO.ui.PanelLayout PanelLayout}, {@link OO.ui.StackLayout StackLayout}, {@link OO.ui.PageLayout PageLayout},
- * and {@link OO.ui.BookletLayout BookletLayout} for more information and examples.
- *
- * @abstract
- * @class
- * @extends OO.ui.Element
- * @mixins OO.EventEmitter
- *
- * @constructor
- * @param {Object} [config] Configuration options
- */
-OO.ui.Layout = function OoUiLayout( config ) {
- // Configuration initialization
- config = config || {};
-
- // Parent constructor
- OO.ui.Layout.super.call( this, config );
-
- // Mixin constructors
- OO.EventEmitter.call( this );
-
- // Initialization
- this.$element.addClass( 'oo-ui-layout' );
-};
-
-/* Setup */
-
-OO.inheritClass( OO.ui.Layout, OO.ui.Element );
-OO.mixinClass( OO.ui.Layout, OO.EventEmitter );
diff --git a/vendor/oojs/oojs-ui/src/Process.js b/vendor/oojs/oojs-ui/src/Process.js
deleted file mode 100644
index 649ffb99..00000000
--- a/vendor/oojs/oojs-ui/src/Process.js
+++ /dev/null
@@ -1,166 +0,0 @@
-/**
- * A Process is a list of steps that are called in sequence. The step can be a number, a jQuery promise,
- * or a function:
- *
- * - **number**: the process will wait for the specified number of milliseconds before proceeding.
- * - **promise**: the process will continue to the next step when the promise is successfully resolved
- * or stop if the promise is rejected.
- * - **function**: the process will execute the function. The process will stop if the function returns
- * either a boolean `false` or a promise that is rejected; if the function returns a number, the process
- * will wait for that number of milliseconds before proceeding.
- *
- * If the process fails, an {@link OO.ui.Error error} is generated. Depending on how the error is
- * configured, users can dismiss the error and try the process again, or not. If a process is stopped,
- * its remaining steps will not be performed.
- *
- * @class
- *
- * @constructor
- * @param {number|jQuery.Promise|Function} step Number of miliseconds to wait before proceeding, promise
- * that must be resolved before proceeding, or a function to execute. See #createStep for more information. see #createStep for more information
- * @param {Object} [context=null] Execution context of the function. The context is ignored if the step is
- * a number or promise.
- * @return {Object} Step object, with `callback` and `context` properties
- */
-OO.ui.Process = function ( step, context ) {
- // Properties
- this.steps = [];
-
- // Initialization
- if ( step !== undefined ) {
- this.next( step, context );
- }
-};
-
-/* Setup */
-
-OO.initClass( OO.ui.Process );
-
-/* Methods */
-
-/**
- * Start the process.
- *
- * @return {jQuery.Promise} Promise that is resolved when all steps have successfully completed.
- * If any of the steps return a promise that is rejected or a boolean false, this promise is rejected
- * and any remaining steps are not performed.
- */
-OO.ui.Process.prototype.execute = function () {
- var i, len, promise;
-
- /**
- * Continue execution.
- *
- * @ignore
- * @param {Array} step A function and the context it should be called in
- * @return {Function} Function that continues the process
- */
- function proceed( step ) {
- return function () {
- // Execute step in the correct context
- var deferred,
- result = step.callback.call( step.context );
-
- if ( result === false ) {
- // Use rejected promise for boolean false results
- return $.Deferred().reject( [] ).promise();
- }
- if ( typeof result === 'number' ) {
- if ( result < 0 ) {
- throw new Error( 'Cannot go back in time: flux capacitor is out of service' );
- }
- // Use a delayed promise for numbers, expecting them to be in milliseconds
- deferred = $.Deferred();
- setTimeout( deferred.resolve, result );
- return deferred.promise();
- }
- if ( result instanceof OO.ui.Error ) {
- // Use rejected promise for error
- return $.Deferred().reject( [ result ] ).promise();
- }
- if ( Array.isArray( result ) && result.length && result[ 0 ] instanceof OO.ui.Error ) {
- // Use rejected promise for list of errors
- return $.Deferred().reject( result ).promise();
- }
- // Duck-type the object to see if it can produce a promise
- if ( result && $.isFunction( result.promise ) ) {
- // Use a promise generated from the result
- return result.promise();
- }
- // Use resolved promise for other results
- return $.Deferred().resolve().promise();
- };
- }
-
- if ( this.steps.length ) {
- // Generate a chain reaction of promises
- promise = proceed( this.steps[ 0 ] )();
- for ( i = 1, len = this.steps.length; i < len; i++ ) {
- promise = promise.then( proceed( this.steps[ i ] ) );
- }
- } else {
- promise = $.Deferred().resolve().promise();
- }
-
- return promise;
-};
-
-/**
- * Create a process step.
- *
- * @private
- * @param {number|jQuery.Promise|Function} step
- *
- * - Number of milliseconds to wait before proceeding
- * - Promise that must be resolved before proceeding
- * - Function to execute
- * - If the function returns a boolean false the process will stop
- * - If the function returns a promise, the process will continue to the next
- * step when the promise is resolved or stop if the promise is rejected
- * - If the function returns a number, the process will wait for that number of
- * milliseconds before proceeding
- * @param {Object} [context=null] Execution context of the function. The context is
- * ignored if the step is a number or promise.
- * @return {Object} Step object, with `callback` and `context` properties
- */
-OO.ui.Process.prototype.createStep = function ( step, context ) {
- if ( typeof step === 'number' || $.isFunction( step.promise ) ) {
- return {
- callback: function () {
- return step;
- },
- context: null
- };
- }
- if ( $.isFunction( step ) ) {
- return {
- callback: step,
- context: context
- };
- }
- throw new Error( 'Cannot create process step: number, promise or function expected' );
-};
-
-/**
- * Add step to the beginning of the process.
- *
- * @inheritdoc #createStep
- * @return {OO.ui.Process} this
- * @chainable
- */
-OO.ui.Process.prototype.first = function ( step, context ) {
- this.steps.unshift( this.createStep( step, context ) );
- return this;
-};
-
-/**
- * Add step to the end of the process.
- *
- * @inheritdoc #createStep
- * @return {OO.ui.Process} this
- * @chainable
- */
-OO.ui.Process.prototype.next = function ( step, context ) {
- this.steps.push( this.createStep( step, context ) );
- return this;
-};
diff --git a/vendor/oojs/oojs-ui/src/Theme.js b/vendor/oojs/oojs-ui/src/Theme.js
deleted file mode 100644
index 92de72ed..00000000
--- a/vendor/oojs/oojs-ui/src/Theme.js
+++ /dev/null
@@ -1,48 +0,0 @@
-/**
- * Theme logic.
- *
- * @abstract
- * @class
- *
- * @constructor
- * @param {Object} [config] Configuration options
- */
-OO.ui.Theme = function OoUiTheme( config ) {
- // Configuration initialization
- config = config || {};
-};
-
-/* Setup */
-
-OO.initClass( OO.ui.Theme );
-
-/* Methods */
-
-/**
- * Get a list of classes to be applied to a widget.
- *
- * The 'on' and 'off' lists combined MUST contain keys for all classes the theme adds or removes,
- * otherwise state transitions will not work properly.
- *
- * @param {OO.ui.Element} element Element for which to get classes
- * @return {Object.<string,string[]>} Categorized class names with `on` and `off` lists
- */
-OO.ui.Theme.prototype.getElementClasses = function ( /* element */ ) {
- return { on: [], off: [] };
-};
-
-/**
- * Update CSS classes provided by the theme.
- *
- * For elements with theme logic hooks, this should be called any time there's a state change.
- *
- * @param {OO.ui.Element} element Element for which to update classes
- * @return {Object.<string,string[]>} Categorized class names with `on` and `off` lists
- */
-OO.ui.Theme.prototype.updateElementClasses = function ( element ) {
- var classes = this.getElementClasses( element );
-
- element.$element
- .removeClass( classes.off.join( ' ' ) )
- .addClass( classes.on.join( ' ' ) );
-};
diff --git a/vendor/oojs/oojs-ui/src/Tool.js b/vendor/oojs/oojs-ui/src/Tool.js
deleted file mode 100644
index 603c0639..00000000
--- a/vendor/oojs/oojs-ui/src/Tool.js
+++ /dev/null
@@ -1,279 +0,0 @@
-/**
- * Generic toolbar tool.
- *
- * @abstract
- * @class
- * @extends OO.ui.Widget
- * @mixins OO.ui.IconElement
- * @mixins OO.ui.FlaggedElement
- * @mixins OO.ui.TabIndexedElement
- *
- * @constructor
- * @param {OO.ui.ToolGroup} toolGroup
- * @param {Object} [config] Configuration options
- * @cfg {string|Function} [title] Title text or a function that returns text
- */
-OO.ui.Tool = function OoUiTool( toolGroup, config ) {
- // Allow passing positional parameters inside the config object
- if ( OO.isPlainObject( toolGroup ) && config === undefined ) {
- config = toolGroup;
- toolGroup = config.toolGroup;
- }
-
- // Configuration initialization
- config = config || {};
-
- // Parent constructor
- OO.ui.Tool.super.call( this, config );
-
- // Properties
- this.toolGroup = toolGroup;
- this.toolbar = this.toolGroup.getToolbar();
- this.active = false;
- this.$title = $( '<span>' );
- this.$accel = $( '<span>' );
- this.$link = $( '<a>' );
- this.title = null;
-
- // Mixin constructors
- OO.ui.IconElement.call( this, config );
- OO.ui.FlaggedElement.call( this, config );
- OO.ui.TabIndexedElement.call( this, $.extend( {}, config, { $tabIndexed: this.$link } ) );
-
- // Events
- this.toolbar.connect( this, { updateState: 'onUpdateState' } );
-
- // Initialization
- this.$title.addClass( 'oo-ui-tool-title' );
- this.$accel
- .addClass( 'oo-ui-tool-accel' )
- .prop( {
- // This may need to be changed if the key names are ever localized,
- // but for now they are essentially written in English
- dir: 'ltr',
- lang: 'en'
- } );
- this.$link
- .addClass( 'oo-ui-tool-link' )
- .append( this.$icon, this.$title, this.$accel )
- .attr( 'role', 'button' );
- this.$element
- .data( 'oo-ui-tool', this )
- .addClass(
- 'oo-ui-tool ' + 'oo-ui-tool-name-' +
- this.constructor.static.name.replace( /^([^\/]+)\/([^\/]+).*$/, '$1-$2' )
- )
- .toggleClass( 'oo-ui-tool-with-label', this.constructor.static.displayBothIconAndLabel )
- .append( this.$link );
- this.setTitle( config.title || this.constructor.static.title );
-};
-
-/* Setup */
-
-OO.inheritClass( OO.ui.Tool, OO.ui.Widget );
-OO.mixinClass( OO.ui.Tool, OO.ui.IconElement );
-OO.mixinClass( OO.ui.Tool, OO.ui.FlaggedElement );
-OO.mixinClass( OO.ui.Tool, OO.ui.TabIndexedElement );
-
-/* Events */
-
-/**
- * @event select
- */
-
-/* Static Properties */
-
-/**
- * @static
- * @inheritdoc
- */
-OO.ui.Tool.static.tagName = 'span';
-
-/**
- * Symbolic name of tool.
- *
- * @abstract
- * @static
- * @inheritable
- * @property {string}
- */
-OO.ui.Tool.static.name = '';
-
-/**
- * Tool group.
- *
- * @abstract
- * @static
- * @inheritable
- * @property {string}
- */
-OO.ui.Tool.static.group = '';
-
-/**
- * Tool title.
- *
- * Title is used as a tooltip when the tool is part of a bar tool group, or a label when the tool
- * is part of a list or menu tool group. If a trigger is associated with an action by the same name
- * as the tool, a description of its keyboard shortcut for the appropriate platform will be
- * appended to the title if the tool is part of a bar tool group.
- *
- * @abstract
- * @static
- * @inheritable
- * @property {string|Function} Title text or a function that returns text
- */
-OO.ui.Tool.static.title = '';
-
-/**
- * Whether this tool should be displayed with both title and label when used in a bar tool group.
- * Normally only the icon is displayed, or only the label if no icon is given.
- *
- * @static
- * @inheritable
- * @property {boolean}
- */
-OO.ui.Tool.static.displayBothIconAndLabel = false;
-
-/**
- * Tool can be automatically added to catch-all groups.
- *
- * @static
- * @inheritable
- * @property {boolean}
- */
-OO.ui.Tool.static.autoAddToCatchall = true;
-
-/**
- * Tool can be automatically added to named groups.
- *
- * @static
- * @property {boolean}
- * @inheritable
- */
-OO.ui.Tool.static.autoAddToGroup = true;
-
-/**
- * Check if this tool is compatible with given data.
- *
- * @static
- * @inheritable
- * @param {Mixed} data Data to check
- * @return {boolean} Tool can be used with data
- */
-OO.ui.Tool.static.isCompatibleWith = function () {
- return false;
-};
-
-/* Methods */
-
-/**
- * Handle the toolbar state being updated.
- *
- * This is an abstract method that must be overridden in a concrete subclass.
- *
- * @abstract
- */
-OO.ui.Tool.prototype.onUpdateState = function () {
- throw new Error(
- 'OO.ui.Tool.onUpdateState not implemented in this subclass:' + this.constructor
- );
-};
-
-/**
- * Handle the tool being selected.
- *
- * This is an abstract method that must be overridden in a concrete subclass.
- *
- * @abstract
- */
-OO.ui.Tool.prototype.onSelect = function () {
- throw new Error(
- 'OO.ui.Tool.onSelect not implemented in this subclass:' + this.constructor
- );
-};
-
-/**
- * Check if the button is active.
- *
- * @return {boolean} Button is active
- */
-OO.ui.Tool.prototype.isActive = function () {
- return this.active;
-};
-
-/**
- * Make the button appear active or inactive.
- *
- * @param {boolean} state Make button appear active
- */
-OO.ui.Tool.prototype.setActive = function ( state ) {
- this.active = !!state;
- if ( this.active ) {
- this.$element.addClass( 'oo-ui-tool-active' );
- } else {
- this.$element.removeClass( 'oo-ui-tool-active' );
- }
-};
-
-/**
- * Get the tool title.
- *
- * @param {string|Function} title Title text or a function that returns text
- * @chainable
- */
-OO.ui.Tool.prototype.setTitle = function ( title ) {
- this.title = OO.ui.resolveMsg( title );
- this.updateTitle();
- return this;
-};
-
-/**
- * Get the tool title.
- *
- * @return {string} Title text
- */
-OO.ui.Tool.prototype.getTitle = function () {
- return this.title;
-};
-
-/**
- * Get the tool's symbolic name.
- *
- * @return {string} Symbolic name of tool
- */
-OO.ui.Tool.prototype.getName = function () {
- return this.constructor.static.name;
-};
-
-/**
- * Update the title.
- */
-OO.ui.Tool.prototype.updateTitle = function () {
- var titleTooltips = this.toolGroup.constructor.static.titleTooltips,
- accelTooltips = this.toolGroup.constructor.static.accelTooltips,
- accel = this.toolbar.getToolAccelerator( this.constructor.static.name ),
- tooltipParts = [];
-
- this.$title.text( this.title );
- this.$accel.text( accel );
-
- if ( titleTooltips && typeof this.title === 'string' && this.title.length ) {
- tooltipParts.push( this.title );
- }
- if ( accelTooltips && typeof accel === 'string' && accel.length ) {
- tooltipParts.push( accel );
- }
- if ( tooltipParts.length ) {
- this.$link.attr( 'title', tooltipParts.join( ' ' ) );
- } else {
- this.$link.removeAttr( 'title' );
- }
-};
-
-/**
- * Destroy tool.
- */
-OO.ui.Tool.prototype.destroy = function () {
- this.toolbar.disconnect( this );
- this.$element.remove();
-};
diff --git a/vendor/oojs/oojs-ui/src/ToolFactory.js b/vendor/oojs/oojs-ui/src/ToolFactory.js
deleted file mode 100644
index aada2e9b..00000000
--- a/vendor/oojs/oojs-ui/src/ToolFactory.js
+++ /dev/null
@@ -1,120 +0,0 @@
-/**
- * Factory for tools.
- *
- * @class
- * @extends OO.Factory
- * @constructor
- */
-OO.ui.ToolFactory = function OoUiToolFactory() {
- // Parent constructor
- OO.ui.ToolFactory.super.call( this );
-};
-
-/* Setup */
-
-OO.inheritClass( OO.ui.ToolFactory, OO.Factory );
-
-/* Methods */
-
-/**
- * Get tools from the factory
- *
- * @param {Array} include Included tools
- * @param {Array} exclude Excluded tools
- * @param {Array} promote Promoted tools
- * @param {Array} demote Demoted tools
- * @return {string[]} List of tools
- */
-OO.ui.ToolFactory.prototype.getTools = function ( include, exclude, promote, demote ) {
- var i, len, included, promoted, demoted,
- auto = [],
- used = {};
-
- // Collect included and not excluded tools
- included = OO.simpleArrayDifference( this.extract( include ), this.extract( exclude ) );
-
- // Promotion
- promoted = this.extract( promote, used );
- demoted = this.extract( demote, used );
-
- // Auto
- for ( i = 0, len = included.length; i < len; i++ ) {
- if ( !used[ included[ i ] ] ) {
- auto.push( included[ i ] );
- }
- }
-
- return promoted.concat( auto ).concat( demoted );
-};
-
-/**
- * Get a flat list of names from a list of names or groups.
- *
- * Tools can be specified in the following ways:
- *
- * - A specific tool: `{ name: 'tool-name' }` or `'tool-name'`
- * - All tools in a group: `{ group: 'group-name' }`
- * - All tools: `'*'`
- *
- * @private
- * @param {Array|string} collection List of tools
- * @param {Object} [used] Object with names that should be skipped as properties; extracted
- * names will be added as properties
- * @return {string[]} List of extracted names
- */
-OO.ui.ToolFactory.prototype.extract = function ( collection, used ) {
- var i, len, item, name, tool,
- names = [];
-
- if ( collection === '*' ) {
- for ( name in this.registry ) {
- tool = this.registry[ name ];
- if (
- // Only add tools by group name when auto-add is enabled
- tool.static.autoAddToCatchall &&
- // Exclude already used tools
- ( !used || !used[ name ] )
- ) {
- names.push( name );
- if ( used ) {
- used[ name ] = true;
- }
- }
- }
- } else if ( Array.isArray( collection ) ) {
- for ( i = 0, len = collection.length; i < len; i++ ) {
- item = collection[ i ];
- // Allow plain strings as shorthand for named tools
- if ( typeof item === 'string' ) {
- item = { name: item };
- }
- if ( OO.isPlainObject( item ) ) {
- if ( item.group ) {
- for ( name in this.registry ) {
- tool = this.registry[ name ];
- if (
- // Include tools with matching group
- tool.static.group === item.group &&
- // Only add tools by group name when auto-add is enabled
- tool.static.autoAddToGroup &&
- // Exclude already used tools
- ( !used || !used[ name ] )
- ) {
- names.push( name );
- if ( used ) {
- used[ name ] = true;
- }
- }
- }
- // Include tools with matching name and exclude already used tools
- } else if ( item.name && ( !used || !used[ item.name ] ) ) {
- names.push( item.name );
- if ( used ) {
- used[ item.name ] = true;
- }
- }
- }
- }
- }
- return names;
-};
diff --git a/vendor/oojs/oojs-ui/src/ToolGroup.js b/vendor/oojs/oojs-ui/src/ToolGroup.js
deleted file mode 100644
index eab3cea4..00000000
--- a/vendor/oojs/oojs-ui/src/ToolGroup.js
+++ /dev/null
@@ -1,338 +0,0 @@
-/**
- * Collection of tools.
- *
- * Tools can be specified in the following ways:
- *
- * - A specific tool: `{ name: 'tool-name' }` or `'tool-name'`
- * - All tools in a group: `{ group: 'group-name' }`
- * - All tools: `'*'`
- *
- * @abstract
- * @class
- * @extends OO.ui.Widget
- * @mixins OO.ui.GroupElement
- *
- * @constructor
- * @param {OO.ui.Toolbar} toolbar
- * @param {Object} [config] Configuration options
- * @cfg {Array|string} [include=[]] List of tools to include
- * @cfg {Array|string} [exclude=[]] List of tools to exclude
- * @cfg {Array|string} [promote=[]] List of tools to promote to the beginning
- * @cfg {Array|string} [demote=[]] List of tools to demote to the end
- */
-OO.ui.ToolGroup = function OoUiToolGroup( toolbar, config ) {
- // Allow passing positional parameters inside the config object
- if ( OO.isPlainObject( toolbar ) && config === undefined ) {
- config = toolbar;
- toolbar = config.toolbar;
- }
-
- // Configuration initialization
- config = config || {};
-
- // Parent constructor
- OO.ui.ToolGroup.super.call( this, config );
-
- // Mixin constructors
- OO.ui.GroupElement.call( this, config );
-
- // Properties
- this.toolbar = toolbar;
- this.tools = {};
- this.pressed = null;
- this.autoDisabled = false;
- this.include = config.include || [];
- this.exclude = config.exclude || [];
- this.promote = config.promote || [];
- this.demote = config.demote || [];
- this.onCapturedMouseKeyUpHandler = this.onCapturedMouseKeyUp.bind( this );
-
- // Events
- this.$element.on( {
- mousedown: this.onMouseKeyDown.bind( this ),
- mouseup: this.onMouseKeyUp.bind( this ),
- keydown: this.onMouseKeyDown.bind( this ),
- keyup: this.onMouseKeyUp.bind( this ),
- focus: this.onMouseOverFocus.bind( this ),
- blur: this.onMouseOutBlur.bind( this ),
- mouseover: this.onMouseOverFocus.bind( this ),
- mouseout: this.onMouseOutBlur.bind( this )
- } );
- this.toolbar.getToolFactory().connect( this, { register: 'onToolFactoryRegister' } );
- this.aggregate( { disable: 'itemDisable' } );
- this.connect( this, { itemDisable: 'updateDisabled' } );
-
- // Initialization
- this.$group.addClass( 'oo-ui-toolGroup-tools' );
- this.$element
- .addClass( 'oo-ui-toolGroup' )
- .append( this.$group );
- this.populate();
-};
-
-/* Setup */
-
-OO.inheritClass( OO.ui.ToolGroup, OO.ui.Widget );
-OO.mixinClass( OO.ui.ToolGroup, OO.ui.GroupElement );
-
-/* Events */
-
-/**
- * @event update
- */
-
-/* Static Properties */
-
-/**
- * Show labels in tooltips.
- *
- * @static
- * @inheritable
- * @property {boolean}
- */
-OO.ui.ToolGroup.static.titleTooltips = false;
-
-/**
- * Show acceleration labels in tooltips.
- *
- * @static
- * @inheritable
- * @property {boolean}
- */
-OO.ui.ToolGroup.static.accelTooltips = false;
-
-/**
- * Automatically disable the toolgroup when all tools are disabled
- *
- * @static
- * @inheritable
- * @property {boolean}
- */
-OO.ui.ToolGroup.static.autoDisable = true;
-
-/* Methods */
-
-/**
- * @inheritdoc
- */
-OO.ui.ToolGroup.prototype.isDisabled = function () {
- return this.autoDisabled || OO.ui.ToolGroup.super.prototype.isDisabled.apply( this, arguments );
-};
-
-/**
- * @inheritdoc
- */
-OO.ui.ToolGroup.prototype.updateDisabled = function () {
- var i, item, allDisabled = true;
-
- if ( this.constructor.static.autoDisable ) {
- for ( i = this.items.length - 1; i >= 0; i-- ) {
- item = this.items[ i ];
- if ( !item.isDisabled() ) {
- allDisabled = false;
- break;
- }
- }
- this.autoDisabled = allDisabled;
- }
- OO.ui.ToolGroup.super.prototype.updateDisabled.apply( this, arguments );
-};
-
-/**
- * Handle mouse down and key down events.
- *
- * @param {jQuery.Event} e Mouse down or key down event
- */
-OO.ui.ToolGroup.prototype.onMouseKeyDown = function ( e ) {
- if (
- !this.isDisabled() &&
- ( e.which === 1 || e.which === OO.ui.Keys.SPACE || e.which === OO.ui.Keys.ENTER )
- ) {
- this.pressed = this.getTargetTool( e );
- if ( this.pressed ) {
- this.pressed.setActive( true );
- this.getElementDocument().addEventListener( 'mouseup', this.onCapturedMouseKeyUpHandler, true );
- this.getElementDocument().addEventListener( 'keyup', this.onCapturedMouseKeyUpHandler, true );
- }
- return false;
- }
-};
-
-/**
- * Handle captured mouse up and key up events.
- *
- * @param {Event} e Mouse up or key up event
- */
-OO.ui.ToolGroup.prototype.onCapturedMouseKeyUp = function ( e ) {
- this.getElementDocument().removeEventListener( 'mouseup', this.onCapturedMouseKeyUpHandler, true );
- this.getElementDocument().removeEventListener( 'keyup', this.onCapturedMouseKeyUpHandler, true );
- // onMouseKeyUp may be called a second time, depending on where the mouse is when the button is
- // released, but since `this.pressed` will no longer be true, the second call will be ignored.
- this.onMouseKeyUp( e );
-};
-
-/**
- * Handle mouse up and key up events.
- *
- * @param {jQuery.Event} e Mouse up or key up event
- */
-OO.ui.ToolGroup.prototype.onMouseKeyUp = function ( e ) {
- var tool = this.getTargetTool( e );
-
- if (
- !this.isDisabled() && this.pressed && this.pressed === tool &&
- ( e.which === 1 || e.which === OO.ui.Keys.SPACE || e.which === OO.ui.Keys.ENTER )
- ) {
- this.pressed.onSelect();
- this.pressed = null;
- return false;
- }
-
- this.pressed = null;
-};
-
-/**
- * Handle mouse over and focus events.
- *
- * @param {jQuery.Event} e Mouse over or focus event
- */
-OO.ui.ToolGroup.prototype.onMouseOverFocus = function ( e ) {
- var tool = this.getTargetTool( e );
-
- if ( this.pressed && this.pressed === tool ) {
- this.pressed.setActive( true );
- }
-};
-
-/**
- * Handle mouse out and blur events.
- *
- * @param {jQuery.Event} e Mouse out or blur event
- */
-OO.ui.ToolGroup.prototype.onMouseOutBlur = function ( e ) {
- var tool = this.getTargetTool( e );
-
- if ( this.pressed && this.pressed === tool ) {
- this.pressed.setActive( false );
- }
-};
-
-/**
- * Get the closest tool to a jQuery.Event.
- *
- * Only tool links are considered, which prevents other elements in the tool such as popups from
- * triggering tool group interactions.
- *
- * @private
- * @param {jQuery.Event} e
- * @return {OO.ui.Tool|null} Tool, `null` if none was found
- */
-OO.ui.ToolGroup.prototype.getTargetTool = function ( e ) {
- var tool,
- $item = $( e.target ).closest( '.oo-ui-tool-link' );
-
- if ( $item.length ) {
- tool = $item.parent().data( 'oo-ui-tool' );
- }
-
- return tool && !tool.isDisabled() ? tool : null;
-};
-
-/**
- * Handle tool registry register events.
- *
- * If a tool is registered after the group is created, we must repopulate the list to account for:
- *
- * - a tool being added that may be included
- * - a tool already included being overridden
- *
- * @param {string} name Symbolic name of tool
- */
-OO.ui.ToolGroup.prototype.onToolFactoryRegister = function () {
- this.populate();
-};
-
-/**
- * Get the toolbar this group is in.
- *
- * @return {OO.ui.Toolbar} Toolbar of group
- */
-OO.ui.ToolGroup.prototype.getToolbar = function () {
- return this.toolbar;
-};
-
-/**
- * Add and remove tools based on configuration.
- */
-OO.ui.ToolGroup.prototype.populate = function () {
- var i, len, name, tool,
- toolFactory = this.toolbar.getToolFactory(),
- names = {},
- add = [],
- remove = [],
- list = this.toolbar.getToolFactory().getTools(
- this.include, this.exclude, this.promote, this.demote
- );
-
- // Build a list of needed tools
- for ( i = 0, len = list.length; i < len; i++ ) {
- name = list[ i ];
- if (
- // Tool exists
- toolFactory.lookup( name ) &&
- // Tool is available or is already in this group
- ( this.toolbar.isToolAvailable( name ) || this.tools[ name ] )
- ) {
- // Hack to prevent infinite recursion via ToolGroupTool. We need to reserve the tool before
- // creating it, but we can't call reserveTool() yet because we haven't created the tool.
- this.toolbar.tools[ name ] = true;
- tool = this.tools[ name ];
- if ( !tool ) {
- // Auto-initialize tools on first use
- this.tools[ name ] = tool = toolFactory.create( name, this );
- tool.updateTitle();
- }
- this.toolbar.reserveTool( tool );
- add.push( tool );
- names[ name ] = true;
- }
- }
- // Remove tools that are no longer needed
- for ( name in this.tools ) {
- if ( !names[ name ] ) {
- this.tools[ name ].destroy();
- this.toolbar.releaseTool( this.tools[ name ] );
- remove.push( this.tools[ name ] );
- delete this.tools[ name ];
- }
- }
- if ( remove.length ) {
- this.removeItems( remove );
- }
- // Update emptiness state
- if ( add.length ) {
- this.$element.removeClass( 'oo-ui-toolGroup-empty' );
- } else {
- this.$element.addClass( 'oo-ui-toolGroup-empty' );
- }
- // Re-add tools (moving existing ones to new locations)
- this.addItems( add );
- // Disabled state may depend on items
- this.updateDisabled();
-};
-
-/**
- * Destroy tool group.
- */
-OO.ui.ToolGroup.prototype.destroy = function () {
- var name;
-
- this.clearItems();
- this.toolbar.getToolFactory().disconnect( this );
- for ( name in this.tools ) {
- this.toolbar.releaseTool( this.tools[ name ] );
- this.tools[ name ].disconnect( this ).destroy();
- delete this.tools[ name ];
- }
- this.$element.remove();
-};
diff --git a/vendor/oojs/oojs-ui/src/ToolGroupFactory.js b/vendor/oojs/oojs-ui/src/ToolGroupFactory.js
deleted file mode 100644
index 109b86e8..00000000
--- a/vendor/oojs/oojs-ui/src/ToolGroupFactory.js
+++ /dev/null
@@ -1,38 +0,0 @@
-/**
- * Factory for tool groups.
- *
- * @class
- * @extends OO.Factory
- * @constructor
- */
-OO.ui.ToolGroupFactory = function OoUiToolGroupFactory() {
- // Parent constructor
- OO.Factory.call( this );
-
- var i, l,
- defaultClasses = this.constructor.static.getDefaultClasses();
-
- // Register default toolgroups
- for ( i = 0, l = defaultClasses.length; i < l; i++ ) {
- this.register( defaultClasses[ i ] );
- }
-};
-
-/* Setup */
-
-OO.inheritClass( OO.ui.ToolGroupFactory, OO.Factory );
-
-/* Static Methods */
-
-/**
- * Get a default set of classes to be registered on construction
- *
- * @return {Function[]} Default classes
- */
-OO.ui.ToolGroupFactory.static.getDefaultClasses = function () {
- return [
- OO.ui.BarToolGroup,
- OO.ui.ListToolGroup,
- OO.ui.MenuToolGroup
- ];
-};
diff --git a/vendor/oojs/oojs-ui/src/Toolbar.js b/vendor/oojs/oojs-ui/src/Toolbar.js
deleted file mode 100644
index f52fbffe..00000000
--- a/vendor/oojs/oojs-ui/src/Toolbar.js
+++ /dev/null
@@ -1,481 +0,0 @@
-/**
- * Collection of tool groups.
- *
- * The following is a minimal example using several tools and tool groups.
- *
- * @example
- * // Create the toolbar
- * var toolFactory = new OO.ui.ToolFactory();
- * var toolGroupFactory = new OO.ui.ToolGroupFactory();
- * var toolbar = new OO.ui.Toolbar( toolFactory, toolGroupFactory );
- *
- * // We will be placing status text in this element when tools are used
- * var $area = $( '<p>' ).text( 'Toolbar example' );
- *
- * // Define the tools that we're going to place in our toolbar
- *
- * // Create a class inheriting from OO.ui.Tool
- * function PictureTool() {
- * PictureTool.super.apply( this, arguments );
- * }
- * OO.inheritClass( PictureTool, OO.ui.Tool );
- * // Each tool must have a 'name' (used as an internal identifier, see later) and at least one
- * // of 'icon' and 'title' (displayed icon and text).
- * PictureTool.static.name = 'picture';
- * PictureTool.static.icon = 'picture';
- * PictureTool.static.title = 'Insert picture';
- * // Defines the action that will happen when this tool is selected (clicked).
- * PictureTool.prototype.onSelect = function () {
- * $area.text( 'Picture tool clicked!' );
- * // Never display this tool as "active" (selected).
- * this.setActive( false );
- * };
- * // Make this tool available in our toolFactory and thus our toolbar
- * toolFactory.register( PictureTool );
- *
- * // Register two more tools, nothing interesting here
- * function SettingsTool() {
- * SettingsTool.super.apply( this, arguments );
- * }
- * OO.inheritClass( SettingsTool, OO.ui.Tool );
- * SettingsTool.static.name = 'settings';
- * SettingsTool.static.icon = 'settings';
- * SettingsTool.static.title = 'Change settings';
- * SettingsTool.prototype.onSelect = function () {
- * $area.text( 'Settings tool clicked!' );
- * this.setActive( false );
- * };
- * toolFactory.register( SettingsTool );
- *
- * // Register two more tools, nothing interesting here
- * function StuffTool() {
- * StuffTool.super.apply( this, arguments );
- * }
- * OO.inheritClass( StuffTool, OO.ui.Tool );
- * StuffTool.static.name = 'stuff';
- * StuffTool.static.icon = 'ellipsis';
- * StuffTool.static.title = 'More stuff';
- * StuffTool.prototype.onSelect = function () {
- * $area.text( 'More stuff tool clicked!' );
- * this.setActive( false );
- * };
- * toolFactory.register( StuffTool );
- *
- * // This is a PopupTool. Rather than having a custom 'onSelect' action, it will display a
- * // little popup window (a PopupWidget).
- * function HelpTool( toolGroup, config ) {
- * OO.ui.PopupTool.call( this, toolGroup, $.extend( { popup: {
- * padded: true,
- * label: 'Help',
- * head: true
- * } }, config ) );
- * this.popup.$body.append( '<p>I am helpful!</p>' );
- * }
- * OO.inheritClass( HelpTool, OO.ui.PopupTool );
- * HelpTool.static.name = 'help';
- * HelpTool.static.icon = 'help';
- * HelpTool.static.title = 'Help';
- * toolFactory.register( HelpTool );
- *
- * // Finally define which tools and in what order appear in the toolbar. Each tool may only be
- * // used once (but not all defined tools must be used).
- * toolbar.setup( [
- * {
- * // 'bar' tool groups display tools' icons only, side-by-side.
- * type: 'bar',
- * include: [ 'picture', 'help' ]
- * },
- * {
- * // 'list' tool groups display both the titles and icons, in a dropdown list.
- * type: 'list',
- * indicator: 'down',
- * label: 'More',
- * include: [ 'settings', 'stuff' ]
- * }
- * // Note how the tools themselves are toolgroup-agnostic - the same tool can be displayed
- * // either in a 'list' or a 'bar'. There is a 'menu' tool group too, not showcased here,
- * // since it's more complicated to use. (See the next example snippet on this page.)
- * ] );
- *
- * // Create some UI around the toolbar and place it in the document
- * var frame = new OO.ui.PanelLayout( {
- * expanded: false,
- * framed: true
- * } );
- * var contentFrame = new OO.ui.PanelLayout( {
- * expanded: false,
- * padded: true
- * } );
- * frame.$element.append(
- * toolbar.$element,
- * contentFrame.$element.append( $area )
- * );
- * $( 'body' ).append( frame.$element );
- *
- * // Here is where the toolbar is actually built. This must be done after inserting it into the
- * // document.
- * toolbar.initialize();
- *
- * The following example extends the previous one to illustrate 'menu' tool groups and the usage of
- * 'updateState' event.
- *
- * @example
- * // Create the toolbar
- * var toolFactory = new OO.ui.ToolFactory();
- * var toolGroupFactory = new OO.ui.ToolGroupFactory();
- * var toolbar = new OO.ui.Toolbar( toolFactory, toolGroupFactory );
- *
- * // We will be placing status text in this element when tools are used
- * var $area = $( '<p>' ).text( 'Toolbar example' );
- *
- * // Define the tools that we're going to place in our toolbar
- *
- * // Create a class inheriting from OO.ui.Tool
- * function PictureTool() {
- * PictureTool.super.apply( this, arguments );
- * }
- * OO.inheritClass( PictureTool, OO.ui.Tool );
- * // Each tool must have a 'name' (used as an internal identifier, see later) and at least one
- * // of 'icon' and 'title' (displayed icon and text).
- * PictureTool.static.name = 'picture';
- * PictureTool.static.icon = 'picture';
- * PictureTool.static.title = 'Insert picture';
- * // Defines the action that will happen when this tool is selected (clicked).
- * PictureTool.prototype.onSelect = function () {
- * $area.text( 'Picture tool clicked!' );
- * // Never display this tool as "active" (selected).
- * this.setActive( false );
- * };
- * // The toolbar can be synchronized with the state of some external stuff, like a text
- * // editor's editing area, highlighting the tools (e.g. a 'bold' tool would be shown as active
- * // when the text cursor was inside bolded text). Here we simply disable this feature.
- * PictureTool.prototype.onUpdateState = function () {
- * };
- * // Make this tool available in our toolFactory and thus our toolbar
- * toolFactory.register( PictureTool );
- *
- * // Register two more tools, nothing interesting here
- * function SettingsTool() {
- * SettingsTool.super.apply( this, arguments );
- * this.reallyActive = false;
- * }
- * OO.inheritClass( SettingsTool, OO.ui.Tool );
- * SettingsTool.static.name = 'settings';
- * SettingsTool.static.icon = 'settings';
- * SettingsTool.static.title = 'Change settings';
- * SettingsTool.prototype.onSelect = function () {
- * $area.text( 'Settings tool clicked!' );
- * // Toggle the active state on each click
- * this.reallyActive = !this.reallyActive;
- * this.setActive( this.reallyActive );
- * // To update the menu label
- * this.toolbar.emit( 'updateState' );
- * };
- * SettingsTool.prototype.onUpdateState = function () {
- * };
- * toolFactory.register( SettingsTool );
- *
- * // Register two more tools, nothing interesting here
- * function StuffTool() {
- * StuffTool.super.apply( this, arguments );
- * this.reallyActive = false;
- * }
- * OO.inheritClass( StuffTool, OO.ui.Tool );
- * StuffTool.static.name = 'stuff';
- * StuffTool.static.icon = 'ellipsis';
- * StuffTool.static.title = 'More stuff';
- * StuffTool.prototype.onSelect = function () {
- * $area.text( 'More stuff tool clicked!' );
- * // Toggle the active state on each click
- * this.reallyActive = !this.reallyActive;
- * this.setActive( this.reallyActive );
- * // To update the menu label
- * this.toolbar.emit( 'updateState' );
- * };
- * StuffTool.prototype.onUpdateState = function () {
- * };
- * toolFactory.register( StuffTool );
- *
- * // This is a PopupTool. Rather than having a custom 'onSelect' action, it will display a
- * // little popup window (a PopupWidget). 'onUpdateState' is also already implemented.
- * function HelpTool( toolGroup, config ) {
- * OO.ui.PopupTool.call( this, toolGroup, $.extend( { popup: {
- * padded: true,
- * label: 'Help',
- * head: true
- * } }, config ) );
- * this.popup.$body.append( '<p>I am helpful!</p>' );
- * }
- * OO.inheritClass( HelpTool, OO.ui.PopupTool );
- * HelpTool.static.name = 'help';
- * HelpTool.static.icon = 'help';
- * HelpTool.static.title = 'Help';
- * toolFactory.register( HelpTool );
- *
- * // Finally define which tools and in what order appear in the toolbar. Each tool may only be
- * // used once (but not all defined tools must be used).
- * toolbar.setup( [
- * {
- * // 'bar' tool groups display tools' icons only, side-by-side.
- * type: 'bar',
- * include: [ 'picture', 'help' ]
- * },
- * {
- * // 'menu' tool groups display both the titles and icons, in a dropdown menu.
- * // Menu label indicates which items are selected.
- * type: 'menu',
- * indicator: 'down',
- * include: [ 'settings', 'stuff' ]
- * }
- * ] );
- *
- * // Create some UI around the toolbar and place it in the document
- * var frame = new OO.ui.PanelLayout( {
- * expanded: false,
- * framed: true
- * } );
- * var contentFrame = new OO.ui.PanelLayout( {
- * expanded: false,
- * padded: true
- * } );
- * frame.$element.append(
- * toolbar.$element,
- * contentFrame.$element.append( $area )
- * );
- * $( 'body' ).append( frame.$element );
- *
- * // Here is where the toolbar is actually built. This must be done after inserting it into the
- * // document.
- * toolbar.initialize();
- * toolbar.emit( 'updateState' );
- *
- * @class
- * @extends OO.ui.Element
- * @mixins OO.EventEmitter
- * @mixins OO.ui.GroupElement
- *
- * @constructor
- * @param {OO.ui.ToolFactory} toolFactory Factory for creating tools
- * @param {OO.ui.ToolGroupFactory} toolGroupFactory Factory for creating tool groups
- * @param {Object} [config] Configuration options
- * @cfg {boolean} [actions] Add an actions section opposite to the tools
- * @cfg {boolean} [shadow] Add a shadow below the toolbar
- */
-OO.ui.Toolbar = function OoUiToolbar( toolFactory, toolGroupFactory, config ) {
- // Allow passing positional parameters inside the config object
- if ( OO.isPlainObject( toolFactory ) && config === undefined ) {
- config = toolFactory;
- toolFactory = config.toolFactory;
- toolGroupFactory = config.toolGroupFactory;
- }
-
- // Configuration initialization
- config = config || {};
-
- // Parent constructor
- OO.ui.Toolbar.super.call( this, config );
-
- // Mixin constructors
- OO.EventEmitter.call( this );
- OO.ui.GroupElement.call( this, config );
-
- // Properties
- this.toolFactory = toolFactory;
- this.toolGroupFactory = toolGroupFactory;
- this.groups = [];
- this.tools = {};
- this.$bar = $( '<div>' );
- this.$actions = $( '<div>' );
- this.initialized = false;
- this.onWindowResizeHandler = this.onWindowResize.bind( this );
-
- // Events
- this.$element
- .add( this.$bar ).add( this.$group ).add( this.$actions )
- .on( 'mousedown keydown', this.onPointerDown.bind( this ) );
-
- // Initialization
- this.$group.addClass( 'oo-ui-toolbar-tools' );
- if ( config.actions ) {
- this.$bar.append( this.$actions.addClass( 'oo-ui-toolbar-actions' ) );
- }
- this.$bar
- .addClass( 'oo-ui-toolbar-bar' )
- .append( this.$group, '<div style="clear:both"></div>' );
- if ( config.shadow ) {
- this.$bar.append( '<div class="oo-ui-toolbar-shadow"></div>' );
- }
- this.$element.addClass( 'oo-ui-toolbar' ).append( this.$bar );
-};
-
-/* Setup */
-
-OO.inheritClass( OO.ui.Toolbar, OO.ui.Element );
-OO.mixinClass( OO.ui.Toolbar, OO.EventEmitter );
-OO.mixinClass( OO.ui.Toolbar, OO.ui.GroupElement );
-
-/* Methods */
-
-/**
- * Get the tool factory.
- *
- * @return {OO.ui.ToolFactory} Tool factory
- */
-OO.ui.Toolbar.prototype.getToolFactory = function () {
- return this.toolFactory;
-};
-
-/**
- * Get the tool group factory.
- *
- * @return {OO.Factory} Tool group factory
- */
-OO.ui.Toolbar.prototype.getToolGroupFactory = function () {
- return this.toolGroupFactory;
-};
-
-/**
- * Handles mouse down events.
- *
- * @param {jQuery.Event} e Mouse down event
- */
-OO.ui.Toolbar.prototype.onPointerDown = function ( e ) {
- var $closestWidgetToEvent = $( e.target ).closest( '.oo-ui-widget' ),
- $closestWidgetToToolbar = this.$element.closest( '.oo-ui-widget' );
- if ( !$closestWidgetToEvent.length || $closestWidgetToEvent[ 0 ] === $closestWidgetToToolbar[ 0 ] ) {
- return false;
- }
-};
-
-/**
- * Handle window resize event.
- *
- * @private
- * @param {jQuery.Event} e Window resize event
- */
-OO.ui.Toolbar.prototype.onWindowResize = function () {
- this.$element.toggleClass(
- 'oo-ui-toolbar-narrow',
- this.$bar.width() <= this.narrowThreshold
- );
-};
-
-/**
- * Sets up handles and preloads required information for the toolbar to work.
- * This must be called after it is attached to a visible document and before doing anything else.
- */
-OO.ui.Toolbar.prototype.initialize = function () {
- this.initialized = true;
- this.narrowThreshold = this.$group.width() + this.$actions.width();
- $( this.getElementWindow() ).on( 'resize', this.onWindowResizeHandler );
- this.onWindowResize();
-};
-
-/**
- * Setup toolbar.
- *
- * Tools can be specified in the following ways:
- *
- * - A specific tool: `{ name: 'tool-name' }` or `'tool-name'`
- * - All tools in a group: `{ group: 'group-name' }`
- * - All tools: `'*'` - Using this will make the group a list with a "More" label by default
- *
- * @param {Object.<string,Array>} groups List of tool group configurations
- * @param {Array|string} [groups.include] Tools to include
- * @param {Array|string} [groups.exclude] Tools to exclude
- * @param {Array|string} [groups.promote] Tools to promote to the beginning
- * @param {Array|string} [groups.demote] Tools to demote to the end
- */
-OO.ui.Toolbar.prototype.setup = function ( groups ) {
- var i, len, type, group,
- items = [],
- defaultType = 'bar';
-
- // Cleanup previous groups
- this.reset();
-
- // Build out new groups
- for ( i = 0, len = groups.length; i < len; i++ ) {
- group = groups[ i ];
- if ( group.include === '*' ) {
- // Apply defaults to catch-all groups
- if ( group.type === undefined ) {
- group.type = 'list';
- }
- if ( group.label === undefined ) {
- group.label = OO.ui.msg( 'ooui-toolbar-more' );
- }
- }
- // Check type has been registered
- type = this.getToolGroupFactory().lookup( group.type ) ? group.type : defaultType;
- items.push(
- this.getToolGroupFactory().create( type, this, group )
- );
- }
- this.addItems( items );
-};
-
-/**
- * Remove all tools and groups from the toolbar.
- */
-OO.ui.Toolbar.prototype.reset = function () {
- var i, len;
-
- this.groups = [];
- this.tools = {};
- for ( i = 0, len = this.items.length; i < len; i++ ) {
- this.items[ i ].destroy();
- }
- this.clearItems();
-};
-
-/**
- * Destroys toolbar, removing event handlers and DOM elements.
- *
- * Call this whenever you are done using a toolbar.
- */
-OO.ui.Toolbar.prototype.destroy = function () {
- $( this.getElementWindow() ).off( 'resize', this.onWindowResizeHandler );
- this.reset();
- this.$element.remove();
-};
-
-/**
- * Check if tool has not been used yet.
- *
- * @param {string} name Symbolic name of tool
- * @return {boolean} Tool is available
- */
-OO.ui.Toolbar.prototype.isToolAvailable = function ( name ) {
- return !this.tools[ name ];
-};
-
-/**
- * Prevent tool from being used again.
- *
- * @param {OO.ui.Tool} tool Tool to reserve
- */
-OO.ui.Toolbar.prototype.reserveTool = function ( tool ) {
- this.tools[ tool.getName() ] = tool;
-};
-
-/**
- * Allow tool to be used again.
- *
- * @param {OO.ui.Tool} tool Tool to release
- */
-OO.ui.Toolbar.prototype.releaseTool = function ( tool ) {
- delete this.tools[ tool.getName() ];
-};
-
-/**
- * Get accelerator label for tool.
- *
- * This is a stub that should be overridden to provide access to accelerator information.
- *
- * @param {string} name Symbolic name of tool
- * @return {string|undefined} Tool accelerator label if available
- */
-OO.ui.Toolbar.prototype.getToolAccelerator = function () {
- return undefined;
-};
diff --git a/vendor/oojs/oojs-ui/src/Widget.js b/vendor/oojs/oojs-ui/src/Widget.js
deleted file mode 100644
index 4929e055..00000000
--- a/vendor/oojs/oojs-ui/src/Widget.js
+++ /dev/null
@@ -1,102 +0,0 @@
-/**
- * Widgets are compositions of one or more OOjs UI elements that users can both view
- * and interact with. All widgets can be configured and modified via a standard API,
- * and their state can change dynamically according to a model.
- *
- * @abstract
- * @class
- * @extends OO.ui.Element
- * @mixins OO.EventEmitter
- *
- * @constructor
- * @param {Object} [config] Configuration options
- * @cfg {boolean} [disabled=false] Disable the widget. Disabled widgets cannot be used and their
- * appearance reflects this state.
- */
-OO.ui.Widget = function OoUiWidget( config ) {
- // Initialize config
- config = $.extend( { disabled: false }, config );
-
- // Parent constructor
- OO.ui.Widget.super.call( this, config );
-
- // Mixin constructors
- OO.EventEmitter.call( this );
-
- // Properties
- this.disabled = null;
- this.wasDisabled = null;
-
- // Initialization
- this.$element.addClass( 'oo-ui-widget' );
- this.setDisabled( !!config.disabled );
-};
-
-/* Setup */
-
-OO.inheritClass( OO.ui.Widget, OO.ui.Element );
-OO.mixinClass( OO.ui.Widget, OO.EventEmitter );
-
-/* Events */
-
-/**
- * @event disable
- *
- * A 'disable' event is emitted when a widget is disabled.
- *
- * @param {boolean} disabled Widget is disabled
- */
-
-/**
- * @event toggle
- *
- * A 'toggle' event is emitted when the visibility of the widget changes.
- *
- * @param {boolean} visible Widget is visible
- */
-
-/* Methods */
-
-/**
- * Check if the widget is disabled.
- *
- * @return {boolean} Widget is disabled
- */
-OO.ui.Widget.prototype.isDisabled = function () {
- return this.disabled;
-};
-
-/**
- * Set the 'disabled' state of the widget.
- *
- * When a widget is disabled, it cannot be used and its appearance is updated to reflect this state.
- *
- * @param {boolean} disabled Disable widget
- * @chainable
- */
-OO.ui.Widget.prototype.setDisabled = function ( disabled ) {
- var isDisabled;
-
- this.disabled = !!disabled;
- isDisabled = this.isDisabled();
- if ( isDisabled !== this.wasDisabled ) {
- this.$element.toggleClass( 'oo-ui-widget-disabled', isDisabled );
- this.$element.toggleClass( 'oo-ui-widget-enabled', !isDisabled );
- this.$element.attr( 'aria-disabled', isDisabled.toString() );
- this.emit( 'disable', isDisabled );
- this.updateThemeClasses();
- }
- this.wasDisabled = isDisabled;
-
- return this;
-};
-
-/**
- * Update the disabled state, in case of changes in parent widget.
- *
- * @chainable
- */
-OO.ui.Widget.prototype.updateDisabled = function () {
- this.setDisabled( this.disabled );
- return this;
-};
diff --git a/vendor/oojs/oojs-ui/src/Window.js b/vendor/oojs/oojs-ui/src/Window.js
deleted file mode 100644
index c3c2e51d..00000000
--- a/vendor/oojs/oojs-ui/src/Window.js
+++ /dev/null
@@ -1,628 +0,0 @@
-/**
- * A window is a container for elements that are in a child frame. They are used with
- * a window manager (OO.ui.WindowManager), which is used to open and close the window and control
- * its presentation. The size of a window is specified using a symbolic name (e.g., ‘small’, ‘medium’,
- * ‘large’), which is interpreted by the window manager. If the requested size is not recognized,
- * the window manager will choose a sensible fallback.
- *
- * The lifecycle of a window has three primary stages (opening, opened, and closing) in which
- * different processes are executed:
- *
- * **opening**: The opening stage begins when the window manager's {@link OO.ui.WindowManager#openWindow
- * openWindow} or the window's {@link #open open} methods are used, and the window manager begins to open
- * the window.
- *
- * - {@link #getSetupProcess} method is called and its result executed
- * - {@link #getReadyProcess} method is called and its result executed
- *
- * **opened**: The window is now open
- *
- * **closing**: The closing stage begins when the window manager's
- * {@link OO.ui.WindowManager#closeWindow closeWindow}
- * or the window's {@link #close} methods are used, and the window manager begins to close the window.
- *
- * - {@link #getHoldProcess} method is called and its result executed
- * - {@link #getTeardownProcess} method is called and its result executed. The window is now closed
- *
- * Each of the window's processes (setup, ready, hold, and teardown) can be extended in subclasses
- * by overriding the window's #getSetupProcess, #getReadyProcess, #getHoldProcess and #getTeardownProcess
- * methods. Note that each {@link OO.ui.Process process} is executed in series, so asynchronous
- * processing can complete. Always assume window processes are executed asynchronously.
- *
- * For more information, please see the [OOjs UI documentation on MediaWiki] [1].
- *
- * [1]: https://www.mediawiki.org/wiki/OOjs_UI/Windows
- *
- * @abstract
- * @class
- * @extends OO.ui.Element
- * @mixins OO.EventEmitter
- *
- * @constructor
- * @param {Object} [config] Configuration options
- * @cfg {string} [size] Symbolic name of the dialog size: `small`, `medium`, `large`, `larger` or
- * `full`. If omitted, the value of the {@link #static-size static size} property will be used.
- */
-OO.ui.Window = function OoUiWindow( config ) {
- // Configuration initialization
- config = config || {};
-
- // Parent constructor
- OO.ui.Window.super.call( this, config );
-
- // Mixin constructors
- OO.EventEmitter.call( this );
-
- // Properties
- this.manager = null;
- this.size = config.size || this.constructor.static.size;
- this.$frame = $( '<div>' );
- this.$overlay = $( '<div>' );
- this.$content = $( '<div>' );
-
- // Initialization
- this.$overlay.addClass( 'oo-ui-window-overlay' );
- this.$content
- .addClass( 'oo-ui-window-content' )
- .attr( 'tabindex', 0 );
- this.$frame
- .addClass( 'oo-ui-window-frame' )
- .append( this.$content );
-
- this.$element
- .addClass( 'oo-ui-window' )
- .append( this.$frame, this.$overlay );
-
- // Initially hidden - using #toggle may cause errors if subclasses override toggle with methods
- // that reference properties not initialized at that time of parent class construction
- // TODO: Find a better way to handle post-constructor setup
- this.visible = false;
- this.$element.addClass( 'oo-ui-element-hidden' );
-};
-
-/* Setup */
-
-OO.inheritClass( OO.ui.Window, OO.ui.Element );
-OO.mixinClass( OO.ui.Window, OO.EventEmitter );
-
-/* Static Properties */
-
-/**
- * Symbolic name of the window size: `small`, `medium`, `large`, `larger` or `full`.
- *
- * The static size is used if no #size is configured during construction.
- *
- * @static
- * @inheritable
- * @property {string}
- */
-OO.ui.Window.static.size = 'medium';
-
-/* Methods */
-
-/**
- * Handle mouse down events.
- *
- * @private
- * @param {jQuery.Event} e Mouse down event
- */
-OO.ui.Window.prototype.onMouseDown = function ( e ) {
- // Prevent clicking on the click-block from stealing focus
- if ( e.target === this.$element[ 0 ] ) {
- return false;
- }
-};
-
-/**
- * Check if the window has been initialized.
- *
- * Initialization occurs when a window is added to a manager.
- *
- * @return {boolean} Window has been initialized
- */
-OO.ui.Window.prototype.isInitialized = function () {
- return !!this.manager;
-};
-
-/**
- * Check if the window is visible.
- *
- * @return {boolean} Window is visible
- */
-OO.ui.Window.prototype.isVisible = function () {
- return this.visible;
-};
-
-/**
- * Check if the window is opening.
- *
- * This method is a wrapper around the window manager's {@link OO.ui.WindowManager#isOpening isOpening}
- * method.
- *
- * @return {boolean} Window is opening
- */
-OO.ui.Window.prototype.isOpening = function () {
- return this.manager.isOpening( this );
-};
-
-/**
- * Check if the window is closing.
- *
- * This method is a wrapper around the window manager's {@link OO.ui.WindowManager#isClosing isClosing} method.
- *
- * @return {boolean} Window is closing
- */
-OO.ui.Window.prototype.isClosing = function () {
- return this.manager.isClosing( this );
-};
-
-/**
- * Check if the window is opened.
- *
- * This method is a wrapper around the window manager's {@link OO.ui.WindowManager#isOpened isOpened} method.
- *
- * @return {boolean} Window is opened
- */
-OO.ui.Window.prototype.isOpened = function () {
- return this.manager.isOpened( this );
-};
-
-/**
- * Get the window manager.
- *
- * All windows must be attached to a window manager, which is used to open
- * and close the window and control its presentation.
- *
- * @return {OO.ui.WindowManager} Manager of window
- */
-OO.ui.Window.prototype.getManager = function () {
- return this.manager;
-};
-
-/**
- * Get the symbolic name of the window size (e.g., `small` or `medium`).
- *
- * @return {string} Symbolic name of the size: `small`, `medium`, `large`, `larger`, `full`
- */
-OO.ui.Window.prototype.getSize = function () {
- return this.size;
-};
-
-/**
- * Disable transitions on window's frame for the duration of the callback function, then enable them
- * back.
- *
- * @private
- * @param {Function} callback Function to call while transitions are disabled
- */
-OO.ui.Window.prototype.withoutSizeTransitions = function ( callback ) {
- // Temporarily resize the frame so getBodyHeight() can use scrollHeight measurements.
- // Disable transitions first, otherwise we'll get values from when the window was animating.
- var oldTransition,
- styleObj = this.$frame[ 0 ].style;
- oldTransition = styleObj.transition || styleObj.OTransition || styleObj.MsTransition ||
- styleObj.MozTransition || styleObj.WebkitTransition;
- styleObj.transition = styleObj.OTransition = styleObj.MsTransition =
- styleObj.MozTransition = styleObj.WebkitTransition = 'none';
- callback();
- // Force reflow to make sure the style changes done inside callback really are not transitioned
- this.$frame.height();
- styleObj.transition = styleObj.OTransition = styleObj.MsTransition =
- styleObj.MozTransition = styleObj.WebkitTransition = oldTransition;
-};
-
-/**
- * Get the height of the full window contents (i.e., the window head, body and foot together).
- *
- * What consistitutes the head, body, and foot varies depending on the window type.
- * A {@link OO.ui.MessageDialog message dialog} displays a title and message in its body,
- * and any actions in the foot. A {@link OO.ui.ProcessDialog process dialog} displays a title
- * and special actions in the head, and dialog content in the body.
- *
- * To get just the height of the dialog body, use the #getBodyHeight method.
- *
- * @return {number} The height of the window contents (the dialog head, body and foot) in pixels
- */
-OO.ui.Window.prototype.getContentHeight = function () {
- var bodyHeight,
- win = this,
- bodyStyleObj = this.$body[ 0 ].style,
- frameStyleObj = this.$frame[ 0 ].style;
-
- // Temporarily resize the frame so getBodyHeight() can use scrollHeight measurements.
- // Disable transitions first, otherwise we'll get values from when the window was animating.
- this.withoutSizeTransitions( function () {
- var oldHeight = frameStyleObj.height,
- oldPosition = bodyStyleObj.position;
- frameStyleObj.height = '1px';
- // Force body to resize to new width
- bodyStyleObj.position = 'relative';
- bodyHeight = win.getBodyHeight();
- frameStyleObj.height = oldHeight;
- bodyStyleObj.position = oldPosition;
- } );
-
- return (
- // Add buffer for border
- ( this.$frame.outerHeight() - this.$frame.innerHeight() ) +
- // Use combined heights of children
- ( this.$head.outerHeight( true ) + bodyHeight + this.$foot.outerHeight( true ) )
- );
-};
-
-/**
- * Get the height of the window body.
- *
- * To get the height of the full window contents (the window body, head, and foot together),
- * use #getContentHeight.
- *
- * When this function is called, the window will temporarily have been resized
- * to height=1px, so .scrollHeight measurements can be taken accurately.
- *
- * @return {number} Height of the window body in pixels
- */
-OO.ui.Window.prototype.getBodyHeight = function () {
- return this.$body[ 0 ].scrollHeight;
-};
-
-/**
- * Get the directionality of the frame (right-to-left or left-to-right).
- *
- * @return {string} Directionality: `'ltr'` or `'rtl'`
- */
-OO.ui.Window.prototype.getDir = function () {
- return this.dir;
-};
-
-/**
- * Get the 'setup' process.
- *
- * The setup process is used to set up a window for use in a particular context,
- * based on the `data` argument. This method is called during the opening phase of the window’s
- * lifecycle.
- *
- * Override this method to add additional steps to the ‘setup’ process the parent method provides
- * using the {@link OO.ui.Process#first first} and {@link OO.ui.Process#next next} methods
- * of OO.ui.Process.
- *
- * To add window content that persists between openings, you may wish to use the #initialize method
- * instead.
- *
- * @abstract
- * @param {Object} [data] Window opening data
- * @return {OO.ui.Process} Setup process
- */
-OO.ui.Window.prototype.getSetupProcess = function () {
- return new OO.ui.Process();
-};
-
-/**
- * Get the ‘ready’ process.
- *
- * The ready process is used to ready a window for use in a particular
- * context, based on the `data` argument. This method is called during the opening phase of
- * the window’s lifecycle, after the window has been {@link #getSetupProcess setup}.
- *
- * Override this method to add additional steps to the ‘ready’ process the parent method
- * provides using the {@link OO.ui.Process#first first} and {@link OO.ui.Process#next next}
- * methods of OO.ui.Process.
- *
- * @abstract
- * @param {Object} [data] Window opening data
- * @return {OO.ui.Process} Ready process
- */
-OO.ui.Window.prototype.getReadyProcess = function () {
- return new OO.ui.Process();
-};
-
-/**
- * Get the 'hold' process.
- *
- * The hold proccess is used to keep a window from being used in a particular context,
- * based on the `data` argument. This method is called during the closing phase of the window’s
- * lifecycle.
- *
- * Override this method to add additional steps to the 'hold' process the parent method provides
- * using the {@link OO.ui.Process#first first} and {@link OO.ui.Process#next next} methods
- * of OO.ui.Process.
- *
- * @abstract
- * @param {Object} [data] Window closing data
- * @return {OO.ui.Process} Hold process
- */
-OO.ui.Window.prototype.getHoldProcess = function () {
- return new OO.ui.Process();
-};
-
-/**
- * Get the ‘teardown’ process.
- *
- * The teardown process is used to teardown a window after use. During teardown,
- * user interactions within the window are conveyed and the window is closed, based on the `data`
- * argument. This method is called during the closing phase of the window’s lifecycle.
- *
- * Override this method to add additional steps to the ‘teardown’ process the parent method provides
- * using the {@link OO.ui.Process#first first} and {@link OO.ui.Process#next next} methods
- * of OO.ui.Process.
- *
- * @abstract
- * @param {Object} [data] Window closing data
- * @return {OO.ui.Process} Teardown process
- */
-OO.ui.Window.prototype.getTeardownProcess = function () {
- return new OO.ui.Process();
-};
-
-/**
- * Set the window manager.
- *
- * This will cause the window to initialize. Calling it more than once will cause an error.
- *
- * @param {OO.ui.WindowManager} manager Manager for this window
- * @throws {Error} An error is thrown if the method is called more than once
- * @chainable
- */
-OO.ui.Window.prototype.setManager = function ( manager ) {
- if ( this.manager ) {
- throw new Error( 'Cannot set window manager, window already has a manager' );
- }
-
- this.manager = manager;
- this.initialize();
-
- return this;
-};
-
-/**
- * Set the window size by symbolic name (e.g., 'small' or 'medium')
- *
- * @param {string} size Symbolic name of size: `small`, `medium`, `large`, `larger` or
- * `full`
- * @chainable
- */
-OO.ui.Window.prototype.setSize = function ( size ) {
- this.size = size;
- this.updateSize();
- return this;
-};
-
-/**
- * Update the window size.
- *
- * @throws {Error} An error is thrown if the window is not attached to a window manager
- * @chainable
- */
-OO.ui.Window.prototype.updateSize = function () {
- if ( !this.manager ) {
- throw new Error( 'Cannot update window size, must be attached to a manager' );
- }
-
- this.manager.updateWindowSize( this );
-
- return this;
-};
-
-/**
- * Set window dimensions. This method is called by the {@link OO.ui.WindowManager window manager}
- * when the window is opening. In general, setDimensions should not be called directly.
- *
- * To set the size of the window, use the #setSize method.
- *
- * @param {Object} dim CSS dimension properties
- * @param {string|number} [dim.width] Width
- * @param {string|number} [dim.minWidth] Minimum width
- * @param {string|number} [dim.maxWidth] Maximum width
- * @param {string|number} [dim.width] Height, omit to set based on height of contents
- * @param {string|number} [dim.minWidth] Minimum height
- * @param {string|number} [dim.maxWidth] Maximum height
- * @chainable
- */
-OO.ui.Window.prototype.setDimensions = function ( dim ) {
- var height,
- win = this,
- styleObj = this.$frame[ 0 ].style;
-
- // Calculate the height we need to set using the correct width
- if ( dim.height === undefined ) {
- this.withoutSizeTransitions( function () {
- var oldWidth = styleObj.width;
- win.$frame.css( 'width', dim.width || '' );
- height = win.getContentHeight();
- styleObj.width = oldWidth;
- } );
- } else {
- height = dim.height;
- }
-
- this.$frame.css( {
- width: dim.width || '',
- minWidth: dim.minWidth || '',
- maxWidth: dim.maxWidth || '',
- height: height || '',
- minHeight: dim.minHeight || '',
- maxHeight: dim.maxHeight || ''
- } );
-
- return this;
-};
-
-/**
- * Initialize window contents.
- *
- * Before the window is opened for the first time, #initialize is called so that content that
- * persists between openings can be added to the window.
- *
- * To set up a window with new content each time the window opens, use #getSetupProcess.
- *
- * @throws {Error} An error is thrown if the window is not attached to a window manager
- * @chainable
- */
-OO.ui.Window.prototype.initialize = function () {
- if ( !this.manager ) {
- throw new Error( 'Cannot initialize window, must be attached to a manager' );
- }
-
- // Properties
- this.$head = $( '<div>' );
- this.$body = $( '<div>' );
- this.$foot = $( '<div>' );
- this.dir = OO.ui.Element.static.getDir( this.$content ) || 'ltr';
- this.$document = $( this.getElementDocument() );
-
- // Events
- this.$element.on( 'mousedown', this.onMouseDown.bind( this ) );
-
- // Initialization
- this.$head.addClass( 'oo-ui-window-head' );
- this.$body.addClass( 'oo-ui-window-body' );
- this.$foot.addClass( 'oo-ui-window-foot' );
- this.$content.append( this.$head, this.$body, this.$foot );
-
- return this;
-};
-
-/**
- * Open the window.
- *
- * This method is a wrapper around a call to the window manager’s {@link OO.ui.WindowManager#openWindow openWindow}
- * method, which returns a promise resolved when the window is done opening.
- *
- * To customize the window each time it opens, use #getSetupProcess or #getReadyProcess.
- *
- * @param {Object} [data] Window opening data
- * @return {jQuery.Promise} Promise resolved with a value when the window is opened, or rejected
- * if the window fails to open. When the promise is resolved successfully, the first argument of the
- * value is a new promise, which is resolved when the window begins closing.
- * @throws {Error} An error is thrown if the window is not attached to a window manager
- */
-OO.ui.Window.prototype.open = function ( data ) {
- if ( !this.manager ) {
- throw new Error( 'Cannot open window, must be attached to a manager' );
- }
-
- return this.manager.openWindow( this, data );
-};
-
-/**
- * Close the window.
- *
- * This method is a wrapper around a call to the window
- * manager’s {@link OO.ui.WindowManager#closeWindow closeWindow} method,
- * which returns a closing promise resolved when the window is done closing.
- *
- * The window's #getHoldProcess and #getTeardownProcess methods are called during the closing
- * phase of the window’s lifecycle and can be used to specify closing behavior each time
- * the window closes.
- *
- * @param {Object} [data] Window closing data
- * @return {jQuery.Promise} Promise resolved when window is closed
- * @throws {Error} An error is thrown if the window is not attached to a window manager
- */
-OO.ui.Window.prototype.close = function ( data ) {
- if ( !this.manager ) {
- throw new Error( 'Cannot close window, must be attached to a manager' );
- }
-
- return this.manager.closeWindow( this, data );
-};
-
-/**
- * Setup window.
- *
- * This is called by OO.ui.WindowManager during window opening, and should not be called directly
- * by other systems.
- *
- * @param {Object} [data] Window opening data
- * @return {jQuery.Promise} Promise resolved when window is setup
- */
-OO.ui.Window.prototype.setup = function ( data ) {
- var win = this,
- deferred = $.Deferred();
-
- this.toggle( true );
-
- this.getSetupProcess( data ).execute().done( function () {
- // Force redraw by asking the browser to measure the elements' widths
- win.$element.addClass( 'oo-ui-window-active oo-ui-window-setup' ).width();
- win.$content.addClass( 'oo-ui-window-content-setup' ).width();
- deferred.resolve();
- } );
-
- return deferred.promise();
-};
-
-/**
- * Ready window.
- *
- * This is called by OO.ui.WindowManager during window opening, and should not be called directly
- * by other systems.
- *
- * @param {Object} [data] Window opening data
- * @return {jQuery.Promise} Promise resolved when window is ready
- */
-OO.ui.Window.prototype.ready = function ( data ) {
- var win = this,
- deferred = $.Deferred();
-
- this.$content.focus();
- this.getReadyProcess( data ).execute().done( function () {
- // Force redraw by asking the browser to measure the elements' widths
- win.$element.addClass( 'oo-ui-window-ready' ).width();
- win.$content.addClass( 'oo-ui-window-content-ready' ).width();
- deferred.resolve();
- } );
-
- return deferred.promise();
-};
-
-/**
- * Hold window.
- *
- * This is called by OO.ui.WindowManager during window closing, and should not be called directly
- * by other systems.
- *
- * @param {Object} [data] Window closing data
- * @return {jQuery.Promise} Promise resolved when window is held
- */
-OO.ui.Window.prototype.hold = function ( data ) {
- var win = this,
- deferred = $.Deferred();
-
- this.getHoldProcess( data ).execute().done( function () {
- // Get the focused element within the window's content
- var $focus = win.$content.find( OO.ui.Element.static.getDocument( win.$content ).activeElement );
-
- // Blur the focused element
- if ( $focus.length ) {
- $focus[ 0 ].blur();
- }
-
- // Force redraw by asking the browser to measure the elements' widths
- win.$element.removeClass( 'oo-ui-window-ready' ).width();
- win.$content.removeClass( 'oo-ui-window-content-ready' ).width();
- deferred.resolve();
- } );
-
- return deferred.promise();
-};
-
-/**
- * Teardown window.
- *
- * This is called by OO.ui.WindowManager during window closing, and should not be called directly
- * by other systems.
- *
- * @param {Object} [data] Window closing data
- * @return {jQuery.Promise} Promise resolved when window is torn down
- */
-OO.ui.Window.prototype.teardown = function ( data ) {
- var win = this;
-
- return this.getTeardownProcess( data ).execute()
- .done( function () {
- // Force redraw by asking the browser to measure the elements' widths
- win.$element.removeClass( 'oo-ui-window-active oo-ui-window-setup' ).width();
- win.$content.removeClass( 'oo-ui-window-content-setup' ).width();
- win.toggle( false );
- } );
-};
diff --git a/vendor/oojs/oojs-ui/src/WindowManager.js b/vendor/oojs/oojs-ui/src/WindowManager.js
deleted file mode 100644
index 4731011a..00000000
--- a/vendor/oojs/oojs-ui/src/WindowManager.js
+++ /dev/null
@@ -1,675 +0,0 @@
-/**
- * Window managers are used to open and close {@link OO.ui.Window windows} and control their presentation.
- * Managed windows are mutually exclusive. If a new window is opened while a current window is opening
- * or is opened, the current window will be closed and any ongoing {@link OO.ui.Process process} will be cancelled. Windows
- * themselves are persistent and—rather than being torn down when closed—can be repopulated with the
- * pertinent data and reused.
- *
- * Over the lifecycle of a window, the window manager makes available three promises: `opening`,
- * `opened`, and `closing`, which represent the primary stages of the cycle:
- *
- * **Opening**: the opening stage begins when the window manager’s #openWindow or a window’s
- * {@link OO.ui.Window#open open} method is used, and the window manager begins to open the window.
- *
- * - an `opening` event is emitted with an `opening` promise
- * - the #getSetupDelay method is called and the returned value is used to time a pause in execution before
- * the window’s {@link OO.ui.Window#getSetupProcess getSetupProcess} method is called on the
- * window and its result executed
- * - a `setup` progress notification is emitted from the `opening` promise
- * - the #getReadyDelay method is called the returned value is used to time a pause in execution before
- * the window’s {@link OO.ui.Window#getReadyProcess getReadyProcess} method is called on the
- * window and its result executed
- * - a `ready` progress notification is emitted from the `opening` promise
- * - the `opening` promise is resolved with an `opened` promise
- *
- * **Opened**: the window is now open.
- *
- * **Closing**: the closing stage begins when the window manager's #closeWindow or the
- * window's {@link OO.ui.Window#close close} methods is used, and the window manager begins
- * to close the window.
- *
- * - the `opened` promise is resolved with `closing` promise and a `closing` event is emitted
- * - the #getHoldDelay method is called and the returned value is used to time a pause in execution before
- * the window's {@link OO.ui.Window#getHoldProcess getHoldProces} method is called on the
- * window and its result executed
- * - a `hold` progress notification is emitted from the `closing` promise
- * - the #getTeardownDelay() method is called and the returned value is used to time a pause in execution before
- * the window's {@link OO.ui.Window#getTeardownProcess getTeardownProcess} method is called on the
- * window and its result executed
- * - a `teardown` progress notification is emitted from the `closing` promise
- * - the `closing` promise is resolved. The window is now closed
- *
- * See the [OOjs UI documentation on MediaWiki][1] for more information.
- *
- * [1]: https://www.mediawiki.org/wiki/OOjs_UI/Windows/Window_managers
- *
- * @class
- * @extends OO.ui.Element
- * @mixins OO.EventEmitter
- *
- * @constructor
- * @param {Object} [config] Configuration options
- * @cfg {OO.Factory} [factory] Window factory to use for automatic instantiation
- * Note that window classes that are instantiated with a factory must have
- * a {@link OO.ui.Dialog#static-name static name} property that specifies a symbolic name.
- * @cfg {boolean} [modal=true] Prevent interaction outside the dialog
- */
-OO.ui.WindowManager = function OoUiWindowManager( config ) {
- // Configuration initialization
- config = config || {};
-
- // Parent constructor
- OO.ui.WindowManager.super.call( this, config );
-
- // Mixin constructors
- OO.EventEmitter.call( this );
-
- // Properties
- this.factory = config.factory;
- this.modal = config.modal === undefined || !!config.modal;
- this.windows = {};
- this.opening = null;
- this.opened = null;
- this.closing = null;
- this.preparingToOpen = null;
- this.preparingToClose = null;
- this.currentWindow = null;
- this.globalEvents = false;
- this.$ariaHidden = null;
- this.onWindowResizeTimeout = null;
- this.onWindowResizeHandler = this.onWindowResize.bind( this );
- this.afterWindowResizeHandler = this.afterWindowResize.bind( this );
-
- // Initialization
- this.$element
- .addClass( 'oo-ui-windowManager' )
- .toggleClass( 'oo-ui-windowManager-modal', this.modal );
-};
-
-/* Setup */
-
-OO.inheritClass( OO.ui.WindowManager, OO.ui.Element );
-OO.mixinClass( OO.ui.WindowManager, OO.EventEmitter );
-
-/* Events */
-
-/**
- * An 'opening' event is emitted when the window begins to be opened.
- *
- * @event opening
- * @param {OO.ui.Window} win Window that's being opened
- * @param {jQuery.Promise} opening An `opening` promise resolved with a value when the window is opened successfully.
- * When the `opening` promise is resolved, the first argument of the value is an 'opened' promise, the second argument
- * is the opening data. The `opening` promise emits `setup` and `ready` notifications when those processes are complete.
- * @param {Object} data Window opening data
- */
-
-/**
- * A 'closing' event is emitted when the window begins to be closed.
- *
- * @event closing
- * @param {OO.ui.Window} win Window that's being closed
- * @param {jQuery.Promise} closing A `closing` promise is resolved with a value when the window
- * is closed successfully. The promise emits `hold` and `teardown` notifications when those
- * processes are complete. When the `closing` promise is resolved, the first argument of its value
- * is the closing data.
- * @param {Object} data Window closing data
- */
-
-/**
- * A 'resize' event is emitted when a window is resized.
- *
- * @event resize
- * @param {OO.ui.Window} win Window that was resized
- */
-
-/* Static Properties */
-
-/**
- * Map of the symbolic name of each window size and its CSS properties.
- *
- * @static
- * @inheritable
- * @property {Object}
- */
-OO.ui.WindowManager.static.sizes = {
- small: {
- width: 300
- },
- medium: {
- width: 500
- },
- large: {
- width: 700
- },
- larger: {
- width: 900
- },
- full: {
- // These can be non-numeric because they are never used in calculations
- width: '100%',
- height: '100%'
- }
-};
-
-/**
- * Symbolic name of the default window size.
- *
- * The default size is used if the window's requested size is not recognized.
- *
- * @static
- * @inheritable
- * @property {string}
- */
-OO.ui.WindowManager.static.defaultSize = 'medium';
-
-/* Methods */
-
-/**
- * Handle window resize events.
- *
- * @private
- * @param {jQuery.Event} e Window resize event
- */
-OO.ui.WindowManager.prototype.onWindowResize = function () {
- clearTimeout( this.onWindowResizeTimeout );
- this.onWindowResizeTimeout = setTimeout( this.afterWindowResizeHandler, 200 );
-};
-
-/**
- * Handle window resize events.
- *
- * @private
- * @param {jQuery.Event} e Window resize event
- */
-OO.ui.WindowManager.prototype.afterWindowResize = function () {
- if ( this.currentWindow ) {
- this.updateWindowSize( this.currentWindow );
- }
-};
-
-/**
- * Check if window is opening.
- *
- * @return {boolean} Window is opening
- */
-OO.ui.WindowManager.prototype.isOpening = function ( win ) {
- return win === this.currentWindow && !!this.opening && this.opening.state() === 'pending';
-};
-
-/**
- * Check if window is closing.
- *
- * @return {boolean} Window is closing
- */
-OO.ui.WindowManager.prototype.isClosing = function ( win ) {
- return win === this.currentWindow && !!this.closing && this.closing.state() === 'pending';
-};
-
-/**
- * Check if window is opened.
- *
- * @return {boolean} Window is opened
- */
-OO.ui.WindowManager.prototype.isOpened = function ( win ) {
- return win === this.currentWindow && !!this.opened && this.opened.state() === 'pending';
-};
-
-/**
- * Check if a window is being managed.
- *
- * @param {OO.ui.Window} win Window to check
- * @return {boolean} Window is being managed
- */
-OO.ui.WindowManager.prototype.hasWindow = function ( win ) {
- var name;
-
- for ( name in this.windows ) {
- if ( this.windows[ name ] === win ) {
- return true;
- }
- }
-
- return false;
-};
-
-/**
- * Get the number of milliseconds to wait after opening begins before executing the ‘setup’ process.
- *
- * @param {OO.ui.Window} win Window being opened
- * @param {Object} [data] Window opening data
- * @return {number} Milliseconds to wait
- */
-OO.ui.WindowManager.prototype.getSetupDelay = function () {
- return 0;
-};
-
-/**
- * Get the number of milliseconds to wait after setup has finished before executing the ‘ready’ process.
- *
- * @param {OO.ui.Window} win Window being opened
- * @param {Object} [data] Window opening data
- * @return {number} Milliseconds to wait
- */
-OO.ui.WindowManager.prototype.getReadyDelay = function () {
- return 0;
-};
-
-/**
- * Get the number of milliseconds to wait after closing has begun before executing the 'hold' process.
- *
- * @param {OO.ui.Window} win Window being closed
- * @param {Object} [data] Window closing data
- * @return {number} Milliseconds to wait
- */
-OO.ui.WindowManager.prototype.getHoldDelay = function () {
- return 0;
-};
-
-/**
- * Get the number of milliseconds to wait after the ‘hold’ process has finished before
- * executing the ‘teardown’ process.
- *
- * @param {OO.ui.Window} win Window being closed
- * @param {Object} [data] Window closing data
- * @return {number} Milliseconds to wait
- */
-OO.ui.WindowManager.prototype.getTeardownDelay = function () {
- return this.modal ? 250 : 0;
-};
-
-/**
- * Get a window by its symbolic name.
- *
- * If the window is not yet instantiated and its symbolic name is recognized by a factory, it will be
- * instantiated and added to the window manager automatically. Please see the [OOjs UI documentation on MediaWiki][3]
- * for more information about using factories.
- * [3]: https://www.mediawiki.org/wiki/OOjs_UI/Windows/Window_managers
- *
- * @param {string} name Symbolic name of the window
- * @return {jQuery.Promise} Promise resolved with matching window, or rejected with an OO.ui.Error
- * @throws {Error} An error is thrown if the symbolic name is not recognized by the factory.
- * @throws {Error} An error is thrown if the named window is not recognized as a managed window.
- */
-OO.ui.WindowManager.prototype.getWindow = function ( name ) {
- var deferred = $.Deferred(),
- win = this.windows[ name ];
-
- if ( !( win instanceof OO.ui.Window ) ) {
- if ( this.factory ) {
- if ( !this.factory.lookup( name ) ) {
- deferred.reject( new OO.ui.Error(
- 'Cannot auto-instantiate window: symbolic name is unrecognized by the factory'
- ) );
- } else {
- win = this.factory.create( name );
- this.addWindows( [ win ] );
- deferred.resolve( win );
- }
- } else {
- deferred.reject( new OO.ui.Error(
- 'Cannot get unmanaged window: symbolic name unrecognized as a managed window'
- ) );
- }
- } else {
- deferred.resolve( win );
- }
-
- return deferred.promise();
-};
-
-/**
- * Get current window.
- *
- * @return {OO.ui.Window|null} Currently opening/opened/closing window
- */
-OO.ui.WindowManager.prototype.getCurrentWindow = function () {
- return this.currentWindow;
-};
-
-/**
- * Open a window.
- *
- * @param {OO.ui.Window|string} win Window object or symbolic name of window to open
- * @param {Object} [data] Window opening data
- * @return {jQuery.Promise} An `opening` promise resolved when the window is done opening.
- * See {@link #event-opening 'opening' event} for more information about `opening` promises.
- * @fires opening
- */
-OO.ui.WindowManager.prototype.openWindow = function ( win, data ) {
- var manager = this,
- opening = $.Deferred();
-
- // Argument handling
- if ( typeof win === 'string' ) {
- return this.getWindow( win ).then( function ( win ) {
- return manager.openWindow( win, data );
- } );
- }
-
- // Error handling
- if ( !this.hasWindow( win ) ) {
- opening.reject( new OO.ui.Error(
- 'Cannot open window: window is not attached to manager'
- ) );
- } else if ( this.preparingToOpen || this.opening || this.opened ) {
- opening.reject( new OO.ui.Error(
- 'Cannot open window: another window is opening or open'
- ) );
- }
-
- // Window opening
- if ( opening.state() !== 'rejected' ) {
- // If a window is currently closing, wait for it to complete
- this.preparingToOpen = $.when( this.closing );
- // Ensure handlers get called after preparingToOpen is set
- this.preparingToOpen.done( function () {
- if ( manager.modal ) {
- manager.toggleGlobalEvents( true );
- manager.toggleAriaIsolation( true );
- }
- manager.currentWindow = win;
- manager.opening = opening;
- manager.preparingToOpen = null;
- manager.emit( 'opening', win, opening, data );
- setTimeout( function () {
- win.setup( data ).then( function () {
- manager.updateWindowSize( win );
- manager.opening.notify( { state: 'setup' } );
- setTimeout( function () {
- win.ready( data ).then( function () {
- manager.opening.notify( { state: 'ready' } );
- manager.opening = null;
- manager.opened = $.Deferred();
- opening.resolve( manager.opened.promise(), data );
- } );
- }, manager.getReadyDelay() );
- } );
- }, manager.getSetupDelay() );
- } );
- }
-
- return opening.promise();
-};
-
-/**
- * Close a window.
- *
- * @param {OO.ui.Window|string} win Window object or symbolic name of window to close
- * @param {Object} [data] Window closing data
- * @return {jQuery.Promise} A `closing` promise resolved when the window is done closing.
- * See {@link #event-closing 'closing' event} for more information about closing promises.
- * @throws {Error} An error is thrown if the window is not managed by the window manager.
- * @fires closing
- */
-OO.ui.WindowManager.prototype.closeWindow = function ( win, data ) {
- var manager = this,
- closing = $.Deferred(),
- opened;
-
- // Argument handling
- if ( typeof win === 'string' ) {
- win = this.windows[ win ];
- } else if ( !this.hasWindow( win ) ) {
- win = null;
- }
-
- // Error handling
- if ( !win ) {
- closing.reject( new OO.ui.Error(
- 'Cannot close window: window is not attached to manager'
- ) );
- } else if ( win !== this.currentWindow ) {
- closing.reject( new OO.ui.Error(
- 'Cannot close window: window already closed with different data'
- ) );
- } else if ( this.preparingToClose || this.closing ) {
- closing.reject( new OO.ui.Error(
- 'Cannot close window: window already closing with different data'
- ) );
- }
-
- // Window closing
- if ( closing.state() !== 'rejected' ) {
- // If the window is currently opening, close it when it's done
- this.preparingToClose = $.when( this.opening );
- // Ensure handlers get called after preparingToClose is set
- this.preparingToClose.done( function () {
- manager.closing = closing;
- manager.preparingToClose = null;
- manager.emit( 'closing', win, closing, data );
- opened = manager.opened;
- manager.opened = null;
- opened.resolve( closing.promise(), data );
- setTimeout( function () {
- win.hold( data ).then( function () {
- closing.notify( { state: 'hold' } );
- setTimeout( function () {
- win.teardown( data ).then( function () {
- closing.notify( { state: 'teardown' } );
- if ( manager.modal ) {
- manager.toggleGlobalEvents( false );
- manager.toggleAriaIsolation( false );
- }
- manager.closing = null;
- manager.currentWindow = null;
- closing.resolve( data );
- } );
- }, manager.getTeardownDelay() );
- } );
- }, manager.getHoldDelay() );
- } );
- }
-
- return closing.promise();
-};
-
-/**
- * Add windows to the window manager.
- *
- * Windows can be added by reference, symbolic name, or explicitly defined symbolic names.
- * See the [OOjs ui documentation on MediaWiki] [2] for examples.
- * [2]: https://www.mediawiki.org/wiki/OOjs_UI/Windows/Window_managers
- *
- * @param {Object.<string,OO.ui.Window>|OO.ui.Window[]} windows An array of window objects specified
- * by reference, symbolic name, or explicitly defined symbolic names.
- * @throws {Error} An error is thrown if a window is added by symbolic name, but has neither an
- * explicit nor a statically configured symbolic name.
- */
-OO.ui.WindowManager.prototype.addWindows = function ( windows ) {
- var i, len, win, name, list;
-
- if ( Array.isArray( windows ) ) {
- // Convert to map of windows by looking up symbolic names from static configuration
- list = {};
- for ( i = 0, len = windows.length; i < len; i++ ) {
- name = windows[ i ].constructor.static.name;
- if ( typeof name !== 'string' ) {
- throw new Error( 'Cannot add window' );
- }
- list[ name ] = windows[ i ];
- }
- } else if ( OO.isPlainObject( windows ) ) {
- list = windows;
- }
-
- // Add windows
- for ( name in list ) {
- win = list[ name ];
- this.windows[ name ] = win.toggle( false );
- this.$element.append( win.$element );
- win.setManager( this );
- }
-};
-
-/**
- * Remove the specified windows from the windows manager.
- *
- * Windows will be closed before they are removed. If you wish to remove all windows, you may wish to use
- * the #clearWindows method instead. If you no longer need the window manager and want to ensure that it no
- * longer listens to events, use the #destroy method.
- *
- * @param {string[]} names Symbolic names of windows to remove
- * @return {jQuery.Promise} Promise resolved when window is closed and removed
- * @throws {Error} An error is thrown if the named windows are not managed by the window manager.
- */
-OO.ui.WindowManager.prototype.removeWindows = function ( names ) {
- var i, len, win, name, cleanupWindow,
- manager = this,
- promises = [],
- cleanup = function ( name, win ) {
- delete manager.windows[ name ];
- win.$element.detach();
- };
-
- for ( i = 0, len = names.length; i < len; i++ ) {
- name = names[ i ];
- win = this.windows[ name ];
- if ( !win ) {
- throw new Error( 'Cannot remove window' );
- }
- cleanupWindow = cleanup.bind( null, name, win );
- promises.push( this.closeWindow( name ).then( cleanupWindow, cleanupWindow ) );
- }
-
- return $.when.apply( $, promises );
-};
-
-/**
- * Remove all windows from the window manager.
- *
- * Windows will be closed before they are removed. Note that the window manager, though not in use, will still
- * listen to events. If the window manager will not be used again, you may wish to use the #destroy method instead.
- * To remove just a subset of windows, use the #removeWindows method.
- *
- * @return {jQuery.Promise} Promise resolved when all windows are closed and removed
- */
-OO.ui.WindowManager.prototype.clearWindows = function () {
- return this.removeWindows( Object.keys( this.windows ) );
-};
-
-/**
- * Set dialog size. In general, this method should not be called directly.
- *
- * Fullscreen mode will be used if the dialog is too wide to fit in the screen.
- *
- * @chainable
- */
-OO.ui.WindowManager.prototype.updateWindowSize = function ( win ) {
- // Bypass for non-current, and thus invisible, windows
- if ( win !== this.currentWindow ) {
- return;
- }
-
- var viewport = OO.ui.Element.static.getDimensions( win.getElementWindow() ),
- sizes = this.constructor.static.sizes,
- size = win.getSize();
-
- if ( !sizes[ size ] ) {
- size = this.constructor.static.defaultSize;
- }
- if ( size !== 'full' && viewport.rect.right - viewport.rect.left < sizes[ size ].width ) {
- size = 'full';
- }
-
- this.$element.toggleClass( 'oo-ui-windowManager-fullscreen', size === 'full' );
- this.$element.toggleClass( 'oo-ui-windowManager-floating', size !== 'full' );
- win.setDimensions( sizes[ size ] );
-
- this.emit( 'resize', win );
-
- return this;
-};
-
-/**
- * Bind or unbind global events for scrolling.
- *
- * @private
- * @param {boolean} [on] Bind global events
- * @chainable
- */
-OO.ui.WindowManager.prototype.toggleGlobalEvents = function ( on ) {
- on = on === undefined ? !!this.globalEvents : !!on;
-
- var scrollWidth, bodyMargin,
- $body = $( this.getElementDocument().body ),
- // We could have multiple window managers open so only modify
- // the body css at the bottom of the stack
- stackDepth = $body.data( 'windowManagerGlobalEvents' ) || 0 ;
-
- if ( on ) {
- if ( !this.globalEvents ) {
- $( this.getElementWindow() ).on( {
- // Start listening for top-level window dimension changes
- 'orientationchange resize': this.onWindowResizeHandler
- } );
- if ( stackDepth === 0 ) {
- scrollWidth = window.innerWidth - document.documentElement.clientWidth;
- bodyMargin = parseFloat( $body.css( 'margin-right' ) ) || 0;
- $body.css( {
- overflow: 'hidden',
- 'margin-right': bodyMargin + scrollWidth
- } );
- }
- stackDepth++;
- this.globalEvents = true;
- }
- } else if ( this.globalEvents ) {
- $( this.getElementWindow() ).off( {
- // Stop listening for top-level window dimension changes
- 'orientationchange resize': this.onWindowResizeHandler
- } );
- stackDepth--;
- if ( stackDepth === 0 ) {
- $body.css( {
- overflow: '',
- 'margin-right': ''
- } );
- }
- this.globalEvents = false;
- }
- $body.data( 'windowManagerGlobalEvents', stackDepth );
-
- return this;
-};
-
-/**
- * Toggle screen reader visibility of content other than the window manager.
- *
- * @private
- * @param {boolean} [isolate] Make only the window manager visible to screen readers
- * @chainable
- */
-OO.ui.WindowManager.prototype.toggleAriaIsolation = function ( isolate ) {
- isolate = isolate === undefined ? !this.$ariaHidden : !!isolate;
-
- if ( isolate ) {
- if ( !this.$ariaHidden ) {
- // Hide everything other than the window manager from screen readers
- this.$ariaHidden = $( 'body' )
- .children()
- .not( this.$element.parentsUntil( 'body' ).last() )
- .attr( 'aria-hidden', '' );
- }
- } else if ( this.$ariaHidden ) {
- // Restore screen reader visibility
- this.$ariaHidden.removeAttr( 'aria-hidden' );
- this.$ariaHidden = null;
- }
-
- return this;
-};
-
-/**
- * Destroy the window manager.
- *
- * Destroying the window manager ensures that it will no longer listen to events. If you would like to
- * continue using the window manager, but wish to remove all windows from it, use the #clearWindows method
- * instead.
- */
-OO.ui.WindowManager.prototype.destroy = function () {
- this.toggleGlobalEvents( false );
- this.toggleAriaIsolation( false );
- this.clearWindows();
- this.$element.remove();
-};
diff --git a/vendor/oojs/oojs-ui/src/core.js b/vendor/oojs/oojs-ui/src/core.js
deleted file mode 100644
index 1331f5cc..00000000
--- a/vendor/oojs/oojs-ui/src/core.js
+++ /dev/null
@@ -1,286 +0,0 @@
-/**
- * Namespace for all classes, static methods and static properties.
- *
- * @class
- * @singleton
- */
-OO.ui = {};
-
-OO.ui.bind = $.proxy;
-
-/**
- * @property {Object}
- */
-OO.ui.Keys = {
- UNDEFINED: 0,
- BACKSPACE: 8,
- DELETE: 46,
- LEFT: 37,
- RIGHT: 39,
- UP: 38,
- DOWN: 40,
- ENTER: 13,
- END: 35,
- HOME: 36,
- TAB: 9,
- PAGEUP: 33,
- PAGEDOWN: 34,
- ESCAPE: 27,
- SHIFT: 16,
- SPACE: 32
-};
-
-/**
- * Check if an element is focusable.
- * Inspired from :focusable in jQueryUI v1.11.4 - 2015-04-14
- *
- * @param {jQuery} element Element to test
- * @return {Boolean} [description]
- */
-OO.ui.isFocusableElement = function ( $element ) {
- var node = $element[0],
- nodeName = node.nodeName.toLowerCase(),
- // Check if the element have tabindex set
- isInElementGroup = /^(input|select|textarea|button|object)$/.test( nodeName ),
- // Check if the element is a link with href or if it has tabindex
- isOtherElement = (
- ( nodeName === 'a' && node.href ) ||
- !isNaN( $element.attr( 'tabindex' ) )
- ),
- // Check if the element is visible
- isVisible = (
- // This is quicker than calling $element.is( ':visible' )
- $.expr.filters.visible( node ) &&
- // Check that all parents are visible
- !$element.parents().addBack().filter( function () {
- return $.css( this, 'visibility' ) === 'hidden';
- } ).length
- );
-
- return (
- ( isInElementGroup ? !node.disabled : isOtherElement ) &&
- isVisible
- );
-};
-
-/**
- * Get the user's language and any fallback languages.
- *
- * These language codes are used to localize user interface elements in the user's language.
- *
- * In environments that provide a localization system, this function should be overridden to
- * return the user's language(s). The default implementation returns English (en) only.
- *
- * @return {string[]} Language codes, in descending order of priority
- */
-OO.ui.getUserLanguages = function () {
- return [ 'en' ];
-};
-
-/**
- * Get a value in an object keyed by language code.
- *
- * @param {Object.<string,Mixed>} obj Object keyed by language code
- * @param {string|null} [lang] Language code, if omitted or null defaults to any user language
- * @param {string} [fallback] Fallback code, used if no matching language can be found
- * @return {Mixed} Local value
- */
-OO.ui.getLocalValue = function ( obj, lang, fallback ) {
- var i, len, langs;
-
- // Requested language
- if ( obj[ lang ] ) {
- return obj[ lang ];
- }
- // Known user language
- langs = OO.ui.getUserLanguages();
- for ( i = 0, len = langs.length; i < len; i++ ) {
- lang = langs[ i ];
- if ( obj[ lang ] ) {
- return obj[ lang ];
- }
- }
- // Fallback language
- if ( obj[ fallback ] ) {
- return obj[ fallback ];
- }
- // First existing language
- for ( lang in obj ) {
- return obj[ lang ];
- }
-
- return undefined;
-};
-
-/**
- * Check if a node is contained within another node
- *
- * Similar to jQuery#contains except a list of containers can be supplied
- * and a boolean argument allows you to include the container in the match list
- *
- * @param {HTMLElement|HTMLElement[]} containers Container node(s) to search in
- * @param {HTMLElement} contained Node to find
- * @param {boolean} [matchContainers] Include the container(s) in the list of nodes to match, otherwise only match descendants
- * @return {boolean} The node is in the list of target nodes
- */
-OO.ui.contains = function ( containers, contained, matchContainers ) {
- var i;
- if ( !Array.isArray( containers ) ) {
- containers = [ containers ];
- }
- for ( i = containers.length - 1; i >= 0; i-- ) {
- if ( ( matchContainers && contained === containers[ i ] ) || $.contains( containers[ i ], contained ) ) {
- return true;
- }
- }
- return false;
-};
-
-/**
- * Return a function, that, as long as it continues to be invoked, will not
- * be triggered. The function will be called after it stops being called for
- * N milliseconds. If `immediate` is passed, trigger the function on the
- * leading edge, instead of the trailing.
- *
- * Ported from: http://underscorejs.org/underscore.js
- *
- * @param {Function} func
- * @param {number} wait
- * @param {boolean} immediate
- * @return {Function}
- */
-OO.ui.debounce = function ( func, wait, immediate ) {
- var timeout;
- return function () {
- var context = this,
- args = arguments,
- later = function () {
- timeout = null;
- if ( !immediate ) {
- func.apply( context, args );
- }
- };
- if ( immediate && !timeout ) {
- func.apply( context, args );
- }
- clearTimeout( timeout );
- timeout = setTimeout( later, wait );
- };
-};
-
-/**
- * Reconstitute a JavaScript object corresponding to a widget created by
- * the PHP implementation.
- *
- * This is an alias for `OO.ui.Element.static.infuse()`.
- *
- * @param {string|HTMLElement|jQuery} idOrNode
- * A DOM id (if a string) or node for the widget to infuse.
- * @return {OO.ui.Element}
- * The `OO.ui.Element` corresponding to this (infusable) document node.
- */
-OO.ui.infuse = function ( idOrNode ) {
- return OO.ui.Element.static.infuse( idOrNode );
-};
-
-( function () {
- /**
- * Message store for the default implementation of OO.ui.msg
- *
- * Environments that provide a localization system should not use this, but should override
- * OO.ui.msg altogether.
- *
- * @private
- */
- var messages = {
- // Tool tip for a button that moves items in a list down one place
- 'ooui-outline-control-move-down': 'Move item down',
- // Tool tip for a button that moves items in a list up one place
- 'ooui-outline-control-move-up': 'Move item up',
- // Tool tip for a button that removes items from a list
- 'ooui-outline-control-remove': 'Remove item',
- // Label for the toolbar group that contains a list of all other available tools
- 'ooui-toolbar-more': 'More',
- // Label for the fake tool that expands the full list of tools in a toolbar group
- 'ooui-toolgroup-expand': 'More',
- // Label for the fake tool that collapses the full list of tools in a toolbar group
- 'ooui-toolgroup-collapse': 'Fewer',
- // Default label for the accept button of a confirmation dialog
- 'ooui-dialog-message-accept': 'OK',
- // Default label for the reject button of a confirmation dialog
- 'ooui-dialog-message-reject': 'Cancel',
- // Title for process dialog error description
- 'ooui-dialog-process-error': 'Something went wrong',
- // Label for process dialog dismiss error button, visible when describing errors
- 'ooui-dialog-process-dismiss': 'Dismiss',
- // Label for process dialog retry action button, visible when describing only recoverable errors
- 'ooui-dialog-process-retry': 'Try again',
- // Label for process dialog retry action button, visible when describing only warnings
- 'ooui-dialog-process-continue': 'Continue'
- };
-
- /**
- * Get a localized message.
- *
- * In environments that provide a localization system, this function should be overridden to
- * return the message translated in the user's language. The default implementation always returns
- * English messages.
- *
- * After the message key, message parameters may optionally be passed. In the default implementation,
- * any occurrences of $1 are replaced with the first parameter, $2 with the second parameter, etc.
- * Alternative implementations of OO.ui.msg may use any substitution system they like, as long as
- * they support unnamed, ordered message parameters.
- *
- * @abstract
- * @param {string} key Message key
- * @param {Mixed...} [params] Message parameters
- * @return {string} Translated message with parameters substituted
- */
- OO.ui.msg = function ( key ) {
- var message = messages[ key ],
- params = Array.prototype.slice.call( arguments, 1 );
- if ( typeof message === 'string' ) {
- // Perform $1 substitution
- message = message.replace( /\$(\d+)/g, function ( unused, n ) {
- var i = parseInt( n, 10 );
- return params[ i - 1 ] !== undefined ? params[ i - 1 ] : '$' + n;
- } );
- } else {
- // Return placeholder if message not found
- message = '[' + key + ']';
- }
- return message;
- };
-
- /**
- * Package a message and arguments for deferred resolution.
- *
- * Use this when you are statically specifying a message and the message may not yet be present.
- *
- * @param {string} key Message key
- * @param {Mixed...} [params] Message parameters
- * @return {Function} Function that returns the resolved message when executed
- */
- OO.ui.deferMsg = function () {
- var args = arguments;
- return function () {
- return OO.ui.msg.apply( OO.ui, args );
- };
- };
-
- /**
- * Resolve a message.
- *
- * If the message is a function it will be executed, otherwise it will pass through directly.
- *
- * @param {Function|string} msg Deferred message, or message text
- * @return {string} Resolved message
- */
- OO.ui.resolveMsg = function ( msg ) {
- if ( $.isFunction( msg ) ) {
- return msg();
- }
- return msg;
- };
-
-} )();
diff --git a/vendor/oojs/oojs-ui/src/dialogs/MessageDialog.js b/vendor/oojs/oojs-ui/src/dialogs/MessageDialog.js
deleted file mode 100644
index 4ec12615..00000000
--- a/vendor/oojs/oojs-ui/src/dialogs/MessageDialog.js
+++ /dev/null
@@ -1,325 +0,0 @@
-/**
- * MessageDialogs display a confirmation or alert message. By default, the rendered dialog box
- * consists of a header that contains the dialog title, a body with the message, and a footer that
- * contains any {@link OO.ui.ActionWidget action widgets}. The MessageDialog class is the only type
- * of {@link OO.ui.Dialog dialog} that is usually instantiated directly.
- *
- * There are two basic types of message dialogs, confirmation and alert:
- *
- * - **confirmation**: the dialog title describes what a progressive action will do and the message provides
- * more details about the consequences.
- * - **alert**: the dialog title describes which event occurred and the message provides more information
- * about why the event occurred.
- *
- * The MessageDialog class specifies two actions: ‘accept’, the primary
- * action (e.g., ‘ok’) and ‘reject,’ the safe action (e.g., ‘cancel’). Both will close the window,
- * passing along the selected action.
- *
- * For more information and examples, please see the [OOjs UI documentation on MediaWiki][1].
- *
- * @example
- * // Example: Creating and opening a message dialog window.
- * var messageDialog = new OO.ui.MessageDialog();
- *
- * // Create and append a window manager.
- * var windowManager = new OO.ui.WindowManager();
- * $( 'body' ).append( windowManager.$element );
- * windowManager.addWindows( [ messageDialog ] );
- * // Open the window.
- * windowManager.openWindow( messageDialog, {
- * title: 'Basic message dialog',
- * message: 'This is the message'
- * } );
- *
- * [1]: https://www.mediawiki.org/wiki/OOjs_UI/Windows/Message_Dialogs
- *
- * @class
- * @extends OO.ui.Dialog
- *
- * @constructor
- * @param {Object} [config] Configuration options
- */
-OO.ui.MessageDialog = function OoUiMessageDialog( config ) {
- // Parent constructor
- OO.ui.MessageDialog.super.call( this, config );
-
- // Properties
- this.verticalActionLayout = null;
-
- // Initialization
- this.$element.addClass( 'oo-ui-messageDialog' );
-};
-
-/* Inheritance */
-
-OO.inheritClass( OO.ui.MessageDialog, OO.ui.Dialog );
-
-/* Static Properties */
-
-OO.ui.MessageDialog.static.name = 'message';
-
-OO.ui.MessageDialog.static.size = 'small';
-
-OO.ui.MessageDialog.static.verbose = false;
-
-/**
- * Dialog title.
- *
- * The title of a confirmation dialog describes what a progressive action will do. The
- * title of an alert dialog describes which event occurred.
- *
- * @static
- * @inheritable
- * @property {jQuery|string|Function|null}
- */
-OO.ui.MessageDialog.static.title = null;
-
-/**
- * The message displayed in the dialog body.
- *
- * A confirmation message describes the consequences of a progressive action. An alert
- * message describes why an event occurred.
- *
- * @static
- * @inheritable
- * @property {jQuery|string|Function|null}
- */
-OO.ui.MessageDialog.static.message = null;
-
-OO.ui.MessageDialog.static.actions = [
- { action: 'accept', label: OO.ui.deferMsg( 'ooui-dialog-message-accept' ), flags: 'primary' },
- { action: 'reject', label: OO.ui.deferMsg( 'ooui-dialog-message-reject' ), flags: 'safe' }
-];
-
-/* Methods */
-
-/**
- * @inheritdoc
- */
-OO.ui.MessageDialog.prototype.setManager = function ( manager ) {
- OO.ui.MessageDialog.super.prototype.setManager.call( this, manager );
-
- // Events
- this.manager.connect( this, {
- resize: 'onResize'
- } );
-
- return this;
-};
-
-/**
- * @inheritdoc
- */
-OO.ui.MessageDialog.prototype.onActionResize = function ( action ) {
- this.fitActions();
- return OO.ui.MessageDialog.super.prototype.onActionResize.call( this, action );
-};
-
-/**
- * Handle window resized events.
- *
- * @private
- */
-OO.ui.MessageDialog.prototype.onResize = function () {
- var dialog = this;
- dialog.fitActions();
- // Wait for CSS transition to finish and do it again :(
- setTimeout( function () {
- dialog.fitActions();
- }, 300 );
-};
-
-/**
- * Toggle action layout between vertical and horizontal.
- *
- *
- * @private
- * @param {boolean} [value] Layout actions vertically, omit to toggle
- * @chainable
- */
-OO.ui.MessageDialog.prototype.toggleVerticalActionLayout = function ( value ) {
- value = value === undefined ? !this.verticalActionLayout : !!value;
-
- if ( value !== this.verticalActionLayout ) {
- this.verticalActionLayout = value;
- this.$actions
- .toggleClass( 'oo-ui-messageDialog-actions-vertical', value )
- .toggleClass( 'oo-ui-messageDialog-actions-horizontal', !value );
- }
-
- return this;
-};
-
-/**
- * @inheritdoc
- */
-OO.ui.MessageDialog.prototype.getActionProcess = function ( action ) {
- if ( action ) {
- return new OO.ui.Process( function () {
- this.close( { action: action } );
- }, this );
- }
- return OO.ui.MessageDialog.super.prototype.getActionProcess.call( this, action );
-};
-
-/**
- * @inheritdoc
- *
- * @param {Object} [data] Dialog opening data
- * @param {jQuery|string|Function|null} [data.title] Description of the action being confirmed
- * @param {jQuery|string|Function|null} [data.message] Description of the action's consequence
- * @param {boolean} [data.verbose] Message is verbose and should be styled as a long message
- * @param {Object[]} [data.actions] List of OO.ui.ActionOptionWidget configuration options for each
- * action item
- */
-OO.ui.MessageDialog.prototype.getSetupProcess = function ( data ) {
- data = data || {};
-
- // Parent method
- return OO.ui.MessageDialog.super.prototype.getSetupProcess.call( this, data )
- .next( function () {
- this.title.setLabel(
- data.title !== undefined ? data.title : this.constructor.static.title
- );
- this.message.setLabel(
- data.message !== undefined ? data.message : this.constructor.static.message
- );
- this.message.$element.toggleClass(
- 'oo-ui-messageDialog-message-verbose',
- data.verbose !== undefined ? data.verbose : this.constructor.static.verbose
- );
- }, this );
-};
-
-/**
- * @inheritdoc
- */
-OO.ui.MessageDialog.prototype.getBodyHeight = function () {
- var bodyHeight, oldOverflow,
- $scrollable = this.container.$element;
-
- oldOverflow = $scrollable[ 0 ].style.overflow;
- $scrollable[ 0 ].style.overflow = 'hidden';
-
- OO.ui.Element.static.reconsiderScrollbars( $scrollable[ 0 ] );
-
- bodyHeight = this.text.$element.outerHeight( true );
- $scrollable[ 0 ].style.overflow = oldOverflow;
-
- return bodyHeight;
-};
-
-/**
- * @inheritdoc
- */
-OO.ui.MessageDialog.prototype.setDimensions = function ( dim ) {
- var $scrollable = this.container.$element;
- OO.ui.MessageDialog.super.prototype.setDimensions.call( this, dim );
-
- // Twiddle the overflow property, otherwise an unnecessary scrollbar will be produced.
- // Need to do it after transition completes (250ms), add 50ms just in case.
- setTimeout( function () {
- var oldOverflow = $scrollable[ 0 ].style.overflow;
- $scrollable[ 0 ].style.overflow = 'hidden';
-
- OO.ui.Element.static.reconsiderScrollbars( $scrollable[ 0 ] );
-
- $scrollable[ 0 ].style.overflow = oldOverflow;
- }, 300 );
-
- return this;
-};
-
-/**
- * @inheritdoc
- */
-OO.ui.MessageDialog.prototype.initialize = function () {
- // Parent method
- OO.ui.MessageDialog.super.prototype.initialize.call( this );
-
- // Properties
- this.$actions = $( '<div>' );
- this.container = new OO.ui.PanelLayout( {
- scrollable: true, classes: [ 'oo-ui-messageDialog-container' ]
- } );
- this.text = new OO.ui.PanelLayout( {
- padded: true, expanded: false, classes: [ 'oo-ui-messageDialog-text' ]
- } );
- this.message = new OO.ui.LabelWidget( {
- classes: [ 'oo-ui-messageDialog-message' ]
- } );
-
- // Initialization
- this.title.$element.addClass( 'oo-ui-messageDialog-title' );
- this.$content.addClass( 'oo-ui-messageDialog-content' );
- this.container.$element.append( this.text.$element );
- this.text.$element.append( this.title.$element, this.message.$element );
- this.$body.append( this.container.$element );
- this.$actions.addClass( 'oo-ui-messageDialog-actions' );
- this.$foot.append( this.$actions );
-};
-
-/**
- * @inheritdoc
- */
-OO.ui.MessageDialog.prototype.attachActions = function () {
- var i, len, other, special, others;
-
- // Parent method
- OO.ui.MessageDialog.super.prototype.attachActions.call( this );
-
- special = this.actions.getSpecial();
- others = this.actions.getOthers();
- if ( special.safe ) {
- this.$actions.append( special.safe.$element );
- special.safe.toggleFramed( false );
- }
- if ( others.length ) {
- for ( i = 0, len = others.length; i < len; i++ ) {
- other = others[ i ];
- this.$actions.append( other.$element );
- other.toggleFramed( false );
- }
- }
- if ( special.primary ) {
- this.$actions.append( special.primary.$element );
- special.primary.toggleFramed( false );
- }
-
- if ( !this.isOpening() ) {
- // If the dialog is currently opening, this will be called automatically soon.
- // This also calls #fitActions.
- this.updateSize();
- }
-};
-
-/**
- * Fit action actions into columns or rows.
- *
- * Columns will be used if all labels can fit without overflow, otherwise rows will be used.
- *
- * @private
- */
-OO.ui.MessageDialog.prototype.fitActions = function () {
- var i, len, action,
- previous = this.verticalActionLayout,
- actions = this.actions.get();
-
- // Detect clipping
- this.toggleVerticalActionLayout( false );
- for ( i = 0, len = actions.length; i < len; i++ ) {
- action = actions[ i ];
- if ( action.$element.innerWidth() < action.$label.outerWidth( true ) ) {
- this.toggleVerticalActionLayout( true );
- break;
- }
- }
-
- // Move the body out of the way of the foot
- this.$body.css( 'bottom', this.$foot.outerHeight( true ) );
-
- if ( this.verticalActionLayout !== previous ) {
- // We changed the layout, window height might need to be updated.
- this.updateSize();
- }
-};
diff --git a/vendor/oojs/oojs-ui/src/dialogs/ProcessDialog.js b/vendor/oojs/oojs-ui/src/dialogs/ProcessDialog.js
deleted file mode 100644
index d8f7c137..00000000
--- a/vendor/oojs/oojs-ui/src/dialogs/ProcessDialog.js
+++ /dev/null
@@ -1,296 +0,0 @@
-/**
- * ProcessDialog windows encapsulate a {@link OO.ui.Process process} and all of the code necessary
- * to complete it. If the process terminates with an error, a customizable {@link OO.ui.Error error
- * interface} alerts users to the trouble, permitting the user to dismiss the error and try again when
- * relevant. The ProcessDialog class is always extended and customized with the actions and content
- * required for each process.
- *
- * The process dialog box consists of a header that visually represents the ‘working’ state of long
- * processes with an animation. The header contains the dialog title as well as
- * two {@link OO.ui.ActionWidget action widgets}: a ‘safe’ action on the left (e.g., ‘Cancel’) and
- * a ‘primary’ action on the right (e.g., ‘Done’).
- *
- * Like other windows, the process dialog is managed by a {@link OO.ui.WindowManager window manager}.
- * Please see the [OOjs UI documentation on MediaWiki][1] for more information and examples.
- *
- * @example
- * // Example: Creating and opening a process dialog window.
- * function MyProcessDialog( config ) {
- * MyProcessDialog.super.call( this, config );
- * }
- * OO.inheritClass( MyProcessDialog, OO.ui.ProcessDialog );
- *
- * MyProcessDialog.static.title = 'Process dialog';
- * MyProcessDialog.static.actions = [
- * { action: 'save', label: 'Done', flags: 'primary' },
- * { label: 'Cancel', flags: 'safe' }
- * ];
- *
- * MyProcessDialog.prototype.initialize = function () {
- * MyProcessDialog.super.prototype.initialize.apply( this, arguments );
- * this.content = new OO.ui.PanelLayout( { padded: true, expanded: false } );
- * this.content.$element.append( '<p>This is a process dialog window. The header contains the title and two buttons: \'Cancel\' (a safe action) on the left and \'Done\' (a primary action) on the right.</p>' );
- * this.$body.append( this.content.$element );
- * };
- * MyProcessDialog.prototype.getActionProcess = function ( action ) {
- * var dialog = this;
- * if ( action ) {
- * return new OO.ui.Process( function () {
- * dialog.close( { action: action } );
- * } );
- * }
- * return MyProcessDialog.super.prototype.getActionProcess.call( this, action );
- * };
- *
- * var windowManager = new OO.ui.WindowManager();
- * $( 'body' ).append( windowManager.$element );
- *
- * var dialog = new MyProcessDialog();
- * windowManager.addWindows( [ dialog ] );
- * windowManager.openWindow( dialog );
- *
- * [1]: https://www.mediawiki.org/wiki/OOjs_UI/Windows/Process_Dialogs
- *
- * @abstract
- * @class
- * @extends OO.ui.Dialog
- *
- * @constructor
- * @param {Object} [config] Configuration options
- */
-OO.ui.ProcessDialog = function OoUiProcessDialog( config ) {
- // Parent constructor
- OO.ui.ProcessDialog.super.call( this, config );
-
- // Initialization
- this.$element.addClass( 'oo-ui-processDialog' );
-};
-
-/* Setup */
-
-OO.inheritClass( OO.ui.ProcessDialog, OO.ui.Dialog );
-
-/* Methods */
-
-/**
- * Handle dismiss button click events.
- *
- * Hides errors.
- *
- * @private
- */
-OO.ui.ProcessDialog.prototype.onDismissErrorButtonClick = function () {
- this.hideErrors();
-};
-
-/**
- * Handle retry button click events.
- *
- * Hides errors and then tries again.
- *
- * @private
- */
-OO.ui.ProcessDialog.prototype.onRetryButtonClick = function () {
- this.hideErrors();
- this.executeAction( this.currentAction );
-};
-
-/**
- * @inheritdoc
- */
-OO.ui.ProcessDialog.prototype.onActionResize = function ( action ) {
- if ( this.actions.isSpecial( action ) ) {
- this.fitLabel();
- }
- return OO.ui.ProcessDialog.super.prototype.onActionResize.call( this, action );
-};
-
-/**
- * @inheritdoc
- */
-OO.ui.ProcessDialog.prototype.initialize = function () {
- // Parent method
- OO.ui.ProcessDialog.super.prototype.initialize.call( this );
-
- // Properties
- this.$navigation = $( '<div>' );
- this.$location = $( '<div>' );
- this.$safeActions = $( '<div>' );
- this.$primaryActions = $( '<div>' );
- this.$otherActions = $( '<div>' );
- this.dismissButton = new OO.ui.ButtonWidget( {
- label: OO.ui.msg( 'ooui-dialog-process-dismiss' )
- } );
- this.retryButton = new OO.ui.ButtonWidget();
- this.$errors = $( '<div>' );
- this.$errorsTitle = $( '<div>' );
-
- // Events
- this.dismissButton.connect( this, { click: 'onDismissErrorButtonClick' } );
- this.retryButton.connect( this, { click: 'onRetryButtonClick' } );
-
- // Initialization
- this.title.$element.addClass( 'oo-ui-processDialog-title' );
- this.$location
- .append( this.title.$element )
- .addClass( 'oo-ui-processDialog-location' );
- this.$safeActions.addClass( 'oo-ui-processDialog-actions-safe' );
- this.$primaryActions.addClass( 'oo-ui-processDialog-actions-primary' );
- this.$otherActions.addClass( 'oo-ui-processDialog-actions-other' );
- this.$errorsTitle
- .addClass( 'oo-ui-processDialog-errors-title' )
- .text( OO.ui.msg( 'ooui-dialog-process-error' ) );
- this.$errors
- .addClass( 'oo-ui-processDialog-errors oo-ui-element-hidden' )
- .append( this.$errorsTitle, this.dismissButton.$element, this.retryButton.$element );
- this.$content
- .addClass( 'oo-ui-processDialog-content' )
- .append( this.$errors );
- this.$navigation
- .addClass( 'oo-ui-processDialog-navigation' )
- .append( this.$safeActions, this.$location, this.$primaryActions );
- this.$head.append( this.$navigation );
- this.$foot.append( this.$otherActions );
-};
-
-/**
- * @inheritdoc
- */
-OO.ui.ProcessDialog.prototype.getActionWidgets = function ( actions ) {
- var i, len, widgets = [];
- for ( i = 0, len = actions.length; i < len; i++ ) {
- widgets.push(
- new OO.ui.ActionWidget( $.extend( { framed: true }, actions[ i ] ) )
- );
- }
- return widgets;
-};
-
-/**
- * @inheritdoc
- */
-OO.ui.ProcessDialog.prototype.attachActions = function () {
- var i, len, other, special, others;
-
- // Parent method
- OO.ui.ProcessDialog.super.prototype.attachActions.call( this );
-
- special = this.actions.getSpecial();
- others = this.actions.getOthers();
- if ( special.primary ) {
- this.$primaryActions.append( special.primary.$element );
- }
- for ( i = 0, len = others.length; i < len; i++ ) {
- other = others[ i ];
- this.$otherActions.append( other.$element );
- }
- if ( special.safe ) {
- this.$safeActions.append( special.safe.$element );
- }
-
- this.fitLabel();
- this.$body.css( 'bottom', this.$foot.outerHeight( true ) );
-};
-
-/**
- * @inheritdoc
- */
-OO.ui.ProcessDialog.prototype.executeAction = function ( action ) {
- var process = this;
- return OO.ui.ProcessDialog.super.prototype.executeAction.call( this, action )
- .fail( function ( errors ) {
- process.showErrors( errors || [] );
- } );
-};
-
-/**
- * Fit label between actions.
- *
- * @private
- * @chainable
- */
-OO.ui.ProcessDialog.prototype.fitLabel = function () {
- var width = Math.max(
- this.$safeActions.is( ':visible' ) ? this.$safeActions.width() : 0,
- this.$primaryActions.is( ':visible' ) ? this.$primaryActions.width() : 0
- );
- this.$location.css( { paddingLeft: width, paddingRight: width } );
-
- return this;
-};
-
-/**
- * Handle errors that occurred during accept or reject processes.
- *
- * @private
- * @param {OO.ui.Error[]|OO.ui.Error} errors Errors to be handled
- */
-OO.ui.ProcessDialog.prototype.showErrors = function ( errors ) {
- var i, len, $item, actions,
- items = [],
- abilities = {},
- recoverable = true,
- warning = false;
-
- if ( errors instanceof OO.ui.Error ) {
- errors = [ errors ];
- }
-
- for ( i = 0, len = errors.length; i < len; i++ ) {
- if ( !errors[ i ].isRecoverable() ) {
- recoverable = false;
- }
- if ( errors[ i ].isWarning() ) {
- warning = true;
- }
- $item = $( '<div>' )
- .addClass( 'oo-ui-processDialog-error' )
- .append( errors[ i ].getMessage() );
- items.push( $item[ 0 ] );
- }
- this.$errorItems = $( items );
- if ( recoverable ) {
- abilities[this.currentAction] = true;
- // Copy the flags from the first matching action
- actions = this.actions.get( { actions: this.currentAction } );
- if ( actions.length ) {
- this.retryButton.clearFlags().setFlags( actions[0].getFlags() );
- }
- } else {
- abilities[this.currentAction] = false;
- this.actions.setAbilities( abilities );
- }
- if ( warning ) {
- this.retryButton.setLabel( OO.ui.msg( 'ooui-dialog-process-continue' ) );
- } else {
- this.retryButton.setLabel( OO.ui.msg( 'ooui-dialog-process-retry' ) );
- }
- this.retryButton.toggle( recoverable );
- this.$errorsTitle.after( this.$errorItems );
- this.$errors.removeClass( 'oo-ui-element-hidden' ).scrollTop( 0 );
-};
-
-/**
- * Hide errors.
- *
- * @private
- */
-OO.ui.ProcessDialog.prototype.hideErrors = function () {
- this.$errors.addClass( 'oo-ui-element-hidden' );
- if ( this.$errorItems ) {
- this.$errorItems.remove();
- this.$errorItems = null;
- }
-};
-
-/**
- * @inheritdoc
- */
-OO.ui.ProcessDialog.prototype.getTeardownProcess = function ( data ) {
- // Parent method
- return OO.ui.ProcessDialog.super.prototype.getTeardownProcess.call( this, data )
- .first( function () {
- // Make sure to hide errors
- this.hideErrors();
- }, this );
-};
diff --git a/vendor/oojs/oojs-ui/src/elements/ButtonElement.js b/vendor/oojs/oojs-ui/src/elements/ButtonElement.js
deleted file mode 100644
index 6d338ed7..00000000
--- a/vendor/oojs/oojs-ui/src/elements/ButtonElement.js
+++ /dev/null
@@ -1,263 +0,0 @@
-/**
- * ButtonElement is often mixed into other classes to generate a button, which is a clickable
- * interface element that can be configured with access keys for accessibility.
- * See the [OOjs UI documentation on MediaWiki] [1] for examples.
- *
- * [1]: https://www.mediawiki.org/wiki/OOjs_UI/Widgets/Buttons_and_Switches#Buttons
- * @abstract
- * @class
- *
- * @constructor
- * @param {Object} [config] Configuration options
- * @cfg {jQuery} [$button] The button element created by the class.
- * If this configuration is omitted, the button element will use a generated `<a>`.
- * @cfg {boolean} [framed=true] Render the button with a frame
- * @cfg {string} [accessKey] Button's access key
- */
-OO.ui.ButtonElement = function OoUiButtonElement( config ) {
- // Configuration initialization
- config = config || {};
-
- // Properties
- this.$button = null;
- this.framed = null;
- this.accessKey = null;
- this.active = false;
- this.onMouseUpHandler = this.onMouseUp.bind( this );
- this.onMouseDownHandler = this.onMouseDown.bind( this );
- this.onKeyDownHandler = this.onKeyDown.bind( this );
- this.onKeyUpHandler = this.onKeyUp.bind( this );
- this.onClickHandler = this.onClick.bind( this );
- this.onKeyPressHandler = this.onKeyPress.bind( this );
-
- // Initialization
- this.$element.addClass( 'oo-ui-buttonElement' );
- this.toggleFramed( config.framed === undefined || config.framed );
- this.setAccessKey( config.accessKey );
- this.setButtonElement( config.$button || $( '<a>' ) );
-};
-
-/* Setup */
-
-OO.initClass( OO.ui.ButtonElement );
-
-/* Static Properties */
-
-/**
- * Cancel mouse down events.
- *
- * This property is usually set to `true` to prevent the focus from changing when the button is clicked.
- * Classes such as {@link OO.ui.DraggableElement DraggableElement} and {@link OO.ui.ButtonOptionWidget ButtonOptionWidget}
- * use a value of `false` so that dragging behavior is possible and mousedown events can be handled by a
- * parent widget.
- *
- * @static
- * @inheritable
- * @property {boolean}
- */
-OO.ui.ButtonElement.static.cancelButtonMouseDownEvents = true;
-
-/* Events */
-
-/**
- * A 'click' event is emitted when the button element is clicked.
- *
- * @event click
- */
-
-/* Methods */
-
-/**
- * Set the button element.
- *
- * This method is used to retarget a button mixin so that its functionality applies to
- * the specified button element instead of the one created by the class. If a button element
- * is already set, the method will remove the mixin’s effect on that element.
- *
- * @param {jQuery} $button Element to use as button
- */
-OO.ui.ButtonElement.prototype.setButtonElement = function ( $button ) {
- if ( this.$button ) {
- this.$button
- .removeClass( 'oo-ui-buttonElement-button' )
- .removeAttr( 'role accesskey' )
- .off( {
- mousedown: this.onMouseDownHandler,
- keydown: this.onKeyDownHandler,
- click: this.onClickHandler,
- keypress: this.onKeyPressHandler
- } );
- }
-
- this.$button = $button
- .addClass( 'oo-ui-buttonElement-button' )
- .attr( { role: 'button', accesskey: this.accessKey } )
- .on( {
- mousedown: this.onMouseDownHandler,
- keydown: this.onKeyDownHandler,
- click: this.onClickHandler,
- keypress: this.onKeyPressHandler
- } );
-};
-
-/**
- * Handles mouse down events.
- *
- * @protected
- * @param {jQuery.Event} e Mouse down event
- */
-OO.ui.ButtonElement.prototype.onMouseDown = function ( e ) {
- if ( this.isDisabled() || e.which !== 1 ) {
- return;
- }
- this.$element.addClass( 'oo-ui-buttonElement-pressed' );
- // Run the mouseup handler no matter where the mouse is when the button is let go, so we can
- // reliably remove the pressed class
- this.getElementDocument().addEventListener( 'mouseup', this.onMouseUpHandler, true );
- // Prevent change of focus unless specifically configured otherwise
- if ( this.constructor.static.cancelButtonMouseDownEvents ) {
- return false;
- }
-};
-
-/**
- * Handles mouse up events.
- *
- * @protected
- * @param {jQuery.Event} e Mouse up event
- */
-OO.ui.ButtonElement.prototype.onMouseUp = function ( e ) {
- if ( this.isDisabled() || e.which !== 1 ) {
- return;
- }
- this.$element.removeClass( 'oo-ui-buttonElement-pressed' );
- // Stop listening for mouseup, since we only needed this once
- this.getElementDocument().removeEventListener( 'mouseup', this.onMouseUpHandler, true );
-};
-
-/**
- * Handles mouse click events.
- *
- * @protected
- * @param {jQuery.Event} e Mouse click event
- * @fires click
- */
-OO.ui.ButtonElement.prototype.onClick = function ( e ) {
- if ( !this.isDisabled() && e.which === 1 ) {
- if ( this.emit( 'click' ) ) {
- return false;
- }
- }
-};
-
-/**
- * Handles key down events.
- *
- * @protected
- * @param {jQuery.Event} e Key down event
- */
-OO.ui.ButtonElement.prototype.onKeyDown = function ( e ) {
- if ( this.isDisabled() || ( e.which !== OO.ui.Keys.SPACE && e.which !== OO.ui.Keys.ENTER ) ) {
- return;
- }
- this.$element.addClass( 'oo-ui-buttonElement-pressed' );
- // Run the keyup handler no matter where the key is when the button is let go, so we can
- // reliably remove the pressed class
- this.getElementDocument().addEventListener( 'keyup', this.onKeyUpHandler, true );
-};
-
-/**
- * Handles key up events.
- *
- * @protected
- * @param {jQuery.Event} e Key up event
- */
-OO.ui.ButtonElement.prototype.onKeyUp = function ( e ) {
- if ( this.isDisabled() || ( e.which !== OO.ui.Keys.SPACE && e.which !== OO.ui.Keys.ENTER ) ) {
- return;
- }
- this.$element.removeClass( 'oo-ui-buttonElement-pressed' );
- // Stop listening for keyup, since we only needed this once
- this.getElementDocument().removeEventListener( 'keyup', this.onKeyUpHandler, true );
-};
-
-/**
- * Handles key press events.
- *
- * @protected
- * @param {jQuery.Event} e Key press event
- * @fires click
- */
-OO.ui.ButtonElement.prototype.onKeyPress = function ( e ) {
- if ( !this.isDisabled() && ( e.which === OO.ui.Keys.SPACE || e.which === OO.ui.Keys.ENTER ) ) {
- if ( this.emit( 'click' ) ) {
- return false;
- }
- }
-};
-
-/**
- * Check if button has a frame.
- *
- * @return {boolean} Button is framed
- */
-OO.ui.ButtonElement.prototype.isFramed = function () {
- return this.framed;
-};
-
-/**
- * Render the button with or without a frame. Omit the `framed` parameter to toggle the button frame on and off.
- *
- * @param {boolean} [framed] Make button framed, omit to toggle
- * @chainable
- */
-OO.ui.ButtonElement.prototype.toggleFramed = function ( framed ) {
- framed = framed === undefined ? !this.framed : !!framed;
- if ( framed !== this.framed ) {
- this.framed = framed;
- this.$element
- .toggleClass( 'oo-ui-buttonElement-frameless', !framed )
- .toggleClass( 'oo-ui-buttonElement-framed', framed );
- this.updateThemeClasses();
- }
-
- return this;
-};
-
-/**
- * Set the button's access key.
- *
- * @param {string} accessKey Button's access key, use empty string to remove
- * @chainable
- */
-OO.ui.ButtonElement.prototype.setAccessKey = function ( accessKey ) {
- accessKey = typeof accessKey === 'string' && accessKey.length ? accessKey : null;
-
- if ( this.accessKey !== accessKey ) {
- if ( this.$button ) {
- if ( accessKey !== null ) {
- this.$button.attr( 'accesskey', accessKey );
- } else {
- this.$button.removeAttr( 'accesskey' );
- }
- }
- this.accessKey = accessKey;
- }
-
- return this;
-};
-
-/**
- * Set the button to its 'active' state.
- *
- * The active state occurs when a {@link OO.ui.ButtonOptionWidget ButtonOptionWidget} or
- * a {@link OO.ui.ToggleButtonWidget ToggleButtonWidget} is pressed. This method does nothing
- * for other button types.
- *
- * @param {boolean} [value] Make button active
- * @chainable
- */
-OO.ui.ButtonElement.prototype.setActive = function ( value ) {
- this.$element.toggleClass( 'oo-ui-buttonElement-active', !!value );
- return this;
-};
diff --git a/vendor/oojs/oojs-ui/src/elements/ClippableElement.js b/vendor/oojs/oojs-ui/src/elements/ClippableElement.js
deleted file mode 100644
index 33b0b234..00000000
--- a/vendor/oojs/oojs-ui/src/elements/ClippableElement.js
+++ /dev/null
@@ -1,205 +0,0 @@
-/**
- * Element that can be automatically clipped to visible boundaries.
- *
- * Whenever the element's natural height changes, you have to call
- * #clip to make sure it's still clipping correctly.
- *
- * @abstract
- * @class
- *
- * @constructor
- * @param {Object} [config] Configuration options
- * @cfg {jQuery} [$clippable] Nodes to clip, assigned to #$clippable, omit to use #$element
- */
-OO.ui.ClippableElement = function OoUiClippableElement( config ) {
- // Configuration initialization
- config = config || {};
-
- // Properties
- this.$clippable = null;
- this.clipping = false;
- this.clippedHorizontally = false;
- this.clippedVertically = false;
- this.$clippableContainer = null;
- this.$clippableScroller = null;
- this.$clippableWindow = null;
- this.idealWidth = null;
- this.idealHeight = null;
- this.onClippableContainerScrollHandler = this.clip.bind( this );
- this.onClippableWindowResizeHandler = this.clip.bind( this );
-
- // Initialization
- this.setClippableElement( config.$clippable || this.$element );
-};
-
-/* Methods */
-
-/**
- * Set clippable element.
- *
- * If an element is already set, it will be cleaned up before setting up the new element.
- *
- * @param {jQuery} $clippable Element to make clippable
- */
-OO.ui.ClippableElement.prototype.setClippableElement = function ( $clippable ) {
- if ( this.$clippable ) {
- this.$clippable.removeClass( 'oo-ui-clippableElement-clippable' );
- this.$clippable.css( { width: '', height: '', overflowX: '', overflowY: '' } );
- OO.ui.Element.static.reconsiderScrollbars( this.$clippable[ 0 ] );
- }
-
- this.$clippable = $clippable.addClass( 'oo-ui-clippableElement-clippable' );
- this.clip();
-};
-
-/**
- * Toggle clipping.
- *
- * Do not turn clipping on until after the element is attached to the DOM and visible.
- *
- * @param {boolean} [clipping] Enable clipping, omit to toggle
- * @chainable
- */
-OO.ui.ClippableElement.prototype.toggleClipping = function ( clipping ) {
- clipping = clipping === undefined ? !this.clipping : !!clipping;
-
- if ( this.clipping !== clipping ) {
- this.clipping = clipping;
- if ( clipping ) {
- this.$clippableContainer = $( this.getClosestScrollableElementContainer() );
- // If the clippable container is the root, we have to listen to scroll events and check
- // jQuery.scrollTop on the window because of browser inconsistencies
- this.$clippableScroller = this.$clippableContainer.is( 'html, body' ) ?
- $( OO.ui.Element.static.getWindow( this.$clippableContainer ) ) :
- this.$clippableContainer;
- this.$clippableScroller.on( 'scroll', this.onClippableContainerScrollHandler );
- this.$clippableWindow = $( this.getElementWindow() )
- .on( 'resize', this.onClippableWindowResizeHandler );
- // Initial clip after visible
- this.clip();
- } else {
- this.$clippable.css( { width: '', height: '', overflowX: '', overflowY: '' } );
- OO.ui.Element.static.reconsiderScrollbars( this.$clippable[ 0 ] );
-
- this.$clippableContainer = null;
- this.$clippableScroller.off( 'scroll', this.onClippableContainerScrollHandler );
- this.$clippableScroller = null;
- this.$clippableWindow.off( 'resize', this.onClippableWindowResizeHandler );
- this.$clippableWindow = null;
- }
- }
-
- return this;
-};
-
-/**
- * Check if the element will be clipped to fit the visible area of the nearest scrollable container.
- *
- * @return {boolean} Element will be clipped to the visible area
- */
-OO.ui.ClippableElement.prototype.isClipping = function () {
- return this.clipping;
-};
-
-/**
- * Check if the bottom or right of the element is being clipped by the nearest scrollable container.
- *
- * @return {boolean} Part of the element is being clipped
- */
-OO.ui.ClippableElement.prototype.isClipped = function () {
- return this.clippedHorizontally || this.clippedVertically;
-};
-
-/**
- * Check if the right of the element is being clipped by the nearest scrollable container.
- *
- * @return {boolean} Part of the element is being clipped
- */
-OO.ui.ClippableElement.prototype.isClippedHorizontally = function () {
- return this.clippedHorizontally;
-};
-
-/**
- * Check if the bottom of the element is being clipped by the nearest scrollable container.
- *
- * @return {boolean} Part of the element is being clipped
- */
-OO.ui.ClippableElement.prototype.isClippedVertically = function () {
- return this.clippedVertically;
-};
-
-/**
- * Set the ideal size. These are the dimensions the element will have when it's not being clipped.
- *
- * @param {number|string} [width] Width as a number of pixels or CSS string with unit suffix
- * @param {number|string} [height] Height as a number of pixels or CSS string with unit suffix
- */
-OO.ui.ClippableElement.prototype.setIdealSize = function ( width, height ) {
- this.idealWidth = width;
- this.idealHeight = height;
-
- if ( !this.clipping ) {
- // Update dimensions
- this.$clippable.css( { width: width, height: height } );
- }
- // While clipping, idealWidth and idealHeight are not considered
-};
-
-/**
- * Clip element to visible boundaries and allow scrolling when needed. Call this method when
- * the element's natural height changes.
- *
- * Element will be clipped the bottom or right of the element is within 10px of the edge of, or
- * overlapped by, the visible area of the nearest scrollable container.
- *
- * @chainable
- */
-OO.ui.ClippableElement.prototype.clip = function () {
- if ( !this.clipping ) {
- // this.$clippableContainer and this.$clippableWindow are null, so the below will fail
- return this;
- }
-
- var buffer = 7, // Chosen by fair dice roll
- cOffset = this.$clippable.offset(),
- $container = this.$clippableContainer.is( 'html, body' ) ?
- this.$clippableWindow : this.$clippableContainer,
- ccOffset = $container.offset() || { top: 0, left: 0 },
- ccHeight = $container.innerHeight() - buffer,
- ccWidth = $container.innerWidth() - buffer,
- cHeight = this.$clippable.outerHeight() + buffer,
- cWidth = this.$clippable.outerWidth() + buffer,
- scrollTop = this.$clippableScroller.scrollTop(),
- scrollLeft = this.$clippableScroller.scrollLeft(),
- desiredWidth = cOffset.left < 0 ?
- cWidth + cOffset.left :
- ( ccOffset.left + scrollLeft + ccWidth ) - cOffset.left,
- desiredHeight = cOffset.top < 0 ?
- cHeight + cOffset.top :
- ( ccOffset.top + scrollTop + ccHeight ) - cOffset.top,
- naturalWidth = this.$clippable.prop( 'scrollWidth' ),
- naturalHeight = this.$clippable.prop( 'scrollHeight' ),
- clipWidth = desiredWidth < naturalWidth,
- clipHeight = desiredHeight < naturalHeight;
-
- if ( clipWidth ) {
- this.$clippable.css( { overflowX: 'scroll', width: desiredWidth } );
- } else {
- this.$clippable.css( { width: this.idealWidth || '', overflowX: '' } );
- }
- if ( clipHeight ) {
- this.$clippable.css( { overflowY: 'scroll', height: desiredHeight } );
- } else {
- this.$clippable.css( { height: this.idealHeight || '', overflowY: '' } );
- }
-
- // If we stopped clipping in at least one of the dimensions
- if ( !clipWidth || !clipHeight ) {
- OO.ui.Element.static.reconsiderScrollbars( this.$clippable[ 0 ] );
- }
-
- this.clippedHorizontally = clipWidth;
- this.clippedVertically = clipHeight;
-
- return this;
-};
diff --git a/vendor/oojs/oojs-ui/src/elements/DraggableElement.js b/vendor/oojs/oojs-ui/src/elements/DraggableElement.js
deleted file mode 100644
index 9ae4d5bb..00000000
--- a/vendor/oojs/oojs-ui/src/elements/DraggableElement.js
+++ /dev/null
@@ -1,142 +0,0 @@
-/**
- * DraggableElement is a mixin class used to create elements that can be clicked
- * and dragged by a mouse to a new position within a group. This class must be used
- * in conjunction with OO.ui.DraggableGroupElement, which provides a container for
- * the draggable elements.
- *
- * @abstract
- * @class
- *
- * @constructor
- */
-OO.ui.DraggableElement = function OoUiDraggableElement() {
- // Properties
- this.index = null;
-
- // Initialize and events
- this.$element
- .attr( 'draggable', true )
- .addClass( 'oo-ui-draggableElement' )
- .on( {
- dragstart: this.onDragStart.bind( this ),
- dragover: this.onDragOver.bind( this ),
- dragend: this.onDragEnd.bind( this ),
- drop: this.onDrop.bind( this )
- } );
-};
-
-OO.initClass( OO.ui.DraggableElement );
-
-/* Events */
-
-/**
- * @event dragstart
- *
- * A dragstart event is emitted when the user clicks and begins dragging an item.
- * @param {OO.ui.DraggableElement} item The item the user has clicked and is dragging with the mouse.
- */
-
-/**
- * @event dragend
- * A dragend event is emitted when the user drags an item and releases the mouse,
- * thus terminating the drag operation.
- */
-
-/**
- * @event drop
- * A drop event is emitted when the user drags an item and then releases the mouse button
- * over a valid target.
- */
-
-/* Static Properties */
-
-/**
- * @inheritdoc OO.ui.ButtonElement
- */
-OO.ui.DraggableElement.static.cancelButtonMouseDownEvents = false;
-
-/* Methods */
-
-/**
- * Respond to dragstart event.
- *
- * @private
- * @param {jQuery.Event} event jQuery event
- * @fires dragstart
- */
-OO.ui.DraggableElement.prototype.onDragStart = function ( e ) {
- var dataTransfer = e.originalEvent.dataTransfer;
- // Define drop effect
- dataTransfer.dropEffect = 'none';
- dataTransfer.effectAllowed = 'move';
- // We must set up a dataTransfer data property or Firefox seems to
- // ignore the fact the element is draggable.
- try {
- dataTransfer.setData( 'application-x/OOjs-UI-draggable', this.getIndex() );
- } catch ( err ) {
- // The above is only for firefox. No need to set a catch clause
- // if it fails, move on.
- }
- // Add dragging class
- this.$element.addClass( 'oo-ui-draggableElement-dragging' );
- // Emit event
- this.emit( 'dragstart', this );
- return true;
-};
-
-/**
- * Respond to dragend event.
- *
- * @private
- * @fires dragend
- */
-OO.ui.DraggableElement.prototype.onDragEnd = function () {
- this.$element.removeClass( 'oo-ui-draggableElement-dragging' );
- this.emit( 'dragend' );
-};
-
-/**
- * Handle drop event.
- *
- * @private
- * @param {jQuery.Event} event jQuery event
- * @fires drop
- */
-OO.ui.DraggableElement.prototype.onDrop = function ( e ) {
- e.preventDefault();
- this.emit( 'drop', e );
-};
-
-/**
- * In order for drag/drop to work, the dragover event must
- * return false and stop propogation.
- *
- * @private
- */
-OO.ui.DraggableElement.prototype.onDragOver = function ( e ) {
- e.preventDefault();
-};
-
-/**
- * Set item index.
- * Store it in the DOM so we can access from the widget drag event
- *
- * @private
- * @param {number} Item index
- */
-OO.ui.DraggableElement.prototype.setIndex = function ( index ) {
- if ( this.index !== index ) {
- this.index = index;
- this.$element.data( 'index', index );
- }
-};
-
-/**
- * Get item index
- *
- * @private
- * @return {number} Item index
- */
-OO.ui.DraggableElement.prototype.getIndex = function () {
- return this.index;
-};
diff --git a/vendor/oojs/oojs-ui/src/elements/DraggableGroupElement.js b/vendor/oojs/oojs-ui/src/elements/DraggableGroupElement.js
deleted file mode 100644
index 134e2953..00000000
--- a/vendor/oojs/oojs-ui/src/elements/DraggableGroupElement.js
+++ /dev/null
@@ -1,261 +0,0 @@
-/**
- * DraggableGroupElement is a mixin class used to create a group element to
- * contain draggable elements, which are items that can be clicked and dragged by a mouse.
- * The class is used with OO.ui.DraggableElement.
- *
- * @abstract
- * @class
- * @mixins OO.ui.GroupElement
- *
- * @constructor
- * @param {Object} [config] Configuration options
- * @cfg {string} [orientation] Item orientation: 'horizontal' or 'vertical'. The orientation
- * should match the layout of the items. Items displayed in a single row
- * or in several rows should use horizontal orientation. The vertical orientation should only be
- * used when the items are displayed in a single column. Defaults to 'vertical'
- */
-OO.ui.DraggableGroupElement = function OoUiDraggableGroupElement( config ) {
- // Configuration initialization
- config = config || {};
-
- // Parent constructor
- OO.ui.GroupElement.call( this, config );
-
- // Properties
- this.orientation = config.orientation || 'vertical';
- this.dragItem = null;
- this.itemDragOver = null;
- this.itemKeys = {};
- this.sideInsertion = '';
-
- // Events
- this.aggregate( {
- dragstart: 'itemDragStart',
- dragend: 'itemDragEnd',
- drop: 'itemDrop'
- } );
- this.connect( this, {
- itemDragStart: 'onItemDragStart',
- itemDrop: 'onItemDrop',
- itemDragEnd: 'onItemDragEnd'
- } );
- this.$element.on( {
- dragover: $.proxy( this.onDragOver, this ),
- dragleave: $.proxy( this.onDragLeave, this )
- } );
-
- // Initialize
- if ( Array.isArray( config.items ) ) {
- this.addItems( config.items );
- }
- this.$placeholder = $( '<div>' )
- .addClass( 'oo-ui-draggableGroupElement-placeholder' );
- this.$element
- .addClass( 'oo-ui-draggableGroupElement' )
- .append( this.$status )
- .toggleClass( 'oo-ui-draggableGroupElement-horizontal', this.orientation === 'horizontal' )
- .prepend( this.$placeholder );
-};
-
-/* Setup */
-OO.mixinClass( OO.ui.DraggableGroupElement, OO.ui.GroupElement );
-
-/* Events */
-
-/**
- * A 'reorder' event is emitted when the order of items in the group changes.
- *
- * @event reorder
- * @param {OO.ui.DraggableElement} item Reordered item
- * @param {number} [newIndex] New index for the item
- */
-
-/* Methods */
-
-/**
- * Respond to item drag start event
- *
- * @private
- * @param {OO.ui.DraggableElement} item Dragged item
- */
-OO.ui.DraggableGroupElement.prototype.onItemDragStart = function ( item ) {
- var i, len;
-
- // Map the index of each object
- for ( i = 0, len = this.items.length; i < len; i++ ) {
- this.items[ i ].setIndex( i );
- }
-
- if ( this.orientation === 'horizontal' ) {
- // Set the height of the indicator
- this.$placeholder.css( {
- height: item.$element.outerHeight(),
- width: 2
- } );
- } else {
- // Set the width of the indicator
- this.$placeholder.css( {
- height: 2,
- width: item.$element.outerWidth()
- } );
- }
- this.setDragItem( item );
-};
-
-/**
- * Respond to item drag end event
- *
- * @private
- */
-OO.ui.DraggableGroupElement.prototype.onItemDragEnd = function () {
- this.unsetDragItem();
- return false;
-};
-
-/**
- * Handle drop event and switch the order of the items accordingly
- *
- * @private
- * @param {OO.ui.DraggableElement} item Dropped item
- * @fires reorder
- */
-OO.ui.DraggableGroupElement.prototype.onItemDrop = function ( item ) {
- var toIndex = item.getIndex();
- // Check if the dropped item is from the current group
- // TODO: Figure out a way to configure a list of legally droppable
- // elements even if they are not yet in the list
- if ( this.getDragItem() ) {
- // If the insertion point is 'after', the insertion index
- // is shifted to the right (or to the left in RTL, hence 'after')
- if ( this.sideInsertion === 'after' ) {
- toIndex++;
- }
- // Emit change event
- this.emit( 'reorder', this.getDragItem(), toIndex );
- }
- this.unsetDragItem();
- // Return false to prevent propogation
- return false;
-};
-
-/**
- * Handle dragleave event.
- *
- * @private
- */
-OO.ui.DraggableGroupElement.prototype.onDragLeave = function () {
- // This means the item was dragged outside the widget
- this.$placeholder
- .css( 'left', 0 )
- .addClass( 'oo-ui-element-hidden' );
-};
-
-/**
- * Respond to dragover event
- *
- * @private
- * @param {jQuery.Event} event Event details
- */
-OO.ui.DraggableGroupElement.prototype.onDragOver = function ( e ) {
- var dragOverObj, $optionWidget, itemOffset, itemMidpoint, itemBoundingRect,
- itemSize, cssOutput, dragPosition, itemIndex, itemPosition,
- clientX = e.originalEvent.clientX,
- clientY = e.originalEvent.clientY;
-
- // Get the OptionWidget item we are dragging over
- dragOverObj = this.getElementDocument().elementFromPoint( clientX, clientY );
- $optionWidget = $( dragOverObj ).closest( '.oo-ui-draggableElement' );
- if ( $optionWidget[ 0 ] ) {
- itemOffset = $optionWidget.offset();
- itemBoundingRect = $optionWidget[ 0 ].getBoundingClientRect();
- itemPosition = $optionWidget.position();
- itemIndex = $optionWidget.data( 'index' );
- }
-
- if (
- itemOffset &&
- this.isDragging() &&
- itemIndex !== this.getDragItem().getIndex()
- ) {
- if ( this.orientation === 'horizontal' ) {
- // Calculate where the mouse is relative to the item width
- itemSize = itemBoundingRect.width;
- itemMidpoint = itemBoundingRect.left + itemSize / 2;
- dragPosition = clientX;
- // Which side of the item we hover over will dictate
- // where the placeholder will appear, on the left or
- // on the right
- cssOutput = {
- left: dragPosition < itemMidpoint ? itemPosition.left : itemPosition.left + itemSize,
- top: itemPosition.top
- };
- } else {
- // Calculate where the mouse is relative to the item height
- itemSize = itemBoundingRect.height;
- itemMidpoint = itemBoundingRect.top + itemSize / 2;
- dragPosition = clientY;
- // Which side of the item we hover over will dictate
- // where the placeholder will appear, on the top or
- // on the bottom
- cssOutput = {
- top: dragPosition < itemMidpoint ? itemPosition.top : itemPosition.top + itemSize,
- left: itemPosition.left
- };
- }
- // Store whether we are before or after an item to rearrange
- // For horizontal layout, we need to account for RTL, as this is flipped
- if ( this.orientation === 'horizontal' && this.$element.css( 'direction' ) === 'rtl' ) {
- this.sideInsertion = dragPosition < itemMidpoint ? 'after' : 'before';
- } else {
- this.sideInsertion = dragPosition < itemMidpoint ? 'before' : 'after';
- }
- // Add drop indicator between objects
- this.$placeholder
- .css( cssOutput )
- .removeClass( 'oo-ui-element-hidden' );
- } else {
- // This means the item was dragged outside the widget
- this.$placeholder
- .css( 'left', 0 )
- .addClass( 'oo-ui-element-hidden' );
- }
- // Prevent default
- e.preventDefault();
-};
-
-/**
- * Set a dragged item
- *
- * @param {OO.ui.DraggableElement} item Dragged item
- */
-OO.ui.DraggableGroupElement.prototype.setDragItem = function ( item ) {
- this.dragItem = item;
-};
-
-/**
- * Unset the current dragged item
- */
-OO.ui.DraggableGroupElement.prototype.unsetDragItem = function () {
- this.dragItem = null;
- this.itemDragOver = null;
- this.$placeholder.addClass( 'oo-ui-element-hidden' );
- this.sideInsertion = '';
-};
-
-/**
- * Get the item that is currently being dragged.
- *
- * @return {OO.ui.DraggableElement|null} The currently dragged item, or `null` if no item is being dragged
- */
-OO.ui.DraggableGroupElement.prototype.getDragItem = function () {
- return this.dragItem;
-};
-
-/**
- * Check if an item in the group is currently being dragged.
- *
- * @return {Boolean} Item is being dragged
- */
-OO.ui.DraggableGroupElement.prototype.isDragging = function () {
- return this.getDragItem() !== null;
-};
diff --git a/vendor/oojs/oojs-ui/src/elements/FlaggedElement.js b/vendor/oojs/oojs-ui/src/elements/FlaggedElement.js
deleted file mode 100644
index 7050f696..00000000
--- a/vendor/oojs/oojs-ui/src/elements/FlaggedElement.js
+++ /dev/null
@@ -1,209 +0,0 @@
-/**
- * The FlaggedElement class is an attribute mixin, meaning that it is used to add
- * additional functionality to an element created by another class. The class provides
- * a ‘flags’ property assigned the name (or an array of names) of styling flags,
- * which are used to customize the look and feel of a widget to better describe its
- * importance and functionality.
- *
- * The library currently contains the following styling flags for general use:
- *
- * - **progressive**: Progressive styling is applied to convey that the widget will move the user forward in a process.
- * - **destructive**: Destructive styling is applied to convey that the widget will remove something.
- * - **constructive**: Constructive styling is applied to convey that the widget will create something.
- *
- * The flags affect the appearance of the buttons:
- *
- * @example
- * // FlaggedElement is mixed into ButtonWidget to provide styling flags
- * var button1 = new OO.ui.ButtonWidget( {
- * label: 'Constructive',
- * flags: 'constructive'
- * } );
- * var button2 = new OO.ui.ButtonWidget( {
- * label: 'Destructive',
- * flags: 'destructive'
- * } );
- * var button3 = new OO.ui.ButtonWidget( {
- * label: 'Progressive',
- * flags: 'progressive'
- * } );
- * $( 'body' ).append( button1.$element, button2.$element, button3.$element );
- *
- * {@link OO.ui.ActionWidget ActionWidgets}, which are a special kind of button that execute an action, use these flags: **primary** and **safe**.
- * Please see the [OOjs UI documentation on MediaWiki] [1] for more information.
- *
- * [1]: https://www.mediawiki.org/wiki/OOjs_UI/Elements/Flagged
- *
- * @abstract
- * @class
- *
- * @constructor
- * @param {Object} [config] Configuration options
- * @cfg {string|string[]} [flags] The name or names of the flags (e.g., 'constructive' or 'primary') to apply.
- * Please see the [OOjs UI documentation on MediaWiki] [2] for more information about available flags.
- * [2]: https://www.mediawiki.org/wiki/OOjs_UI/Elements/Flagged
- * @cfg {jQuery} [$flagged] The flagged element. By default,
- * the flagged functionality is applied to the element created by the class ($element).
- * If a different element is specified, the flagged functionality will be applied to it instead.
- */
-OO.ui.FlaggedElement = function OoUiFlaggedElement( config ) {
- // Configuration initialization
- config = config || {};
-
- // Properties
- this.flags = {};
- this.$flagged = null;
-
- // Initialization
- this.setFlags( config.flags );
- this.setFlaggedElement( config.$flagged || this.$element );
-};
-
-/* Events */
-
-/**
- * @event flag
- * A flag event is emitted when the #clearFlags or #setFlags methods are used. The `changes`
- * parameter contains the name of each modified flag and indicates whether it was
- * added or removed.
- *
- * @param {Object.<string,boolean>} changes Object keyed by flag name. A Boolean `true` indicates
- * that the flag was added, `false` that the flag was removed.
- */
-
-/* Methods */
-
-/**
- * Set the flagged element.
- *
- * This method is used to retarget a flagged mixin so that its functionality applies to the specified element.
- * If an element is already set, the method will remove the mixin’s effect on that element.
- *
- * @param {jQuery} $flagged Element that should be flagged
- */
-OO.ui.FlaggedElement.prototype.setFlaggedElement = function ( $flagged ) {
- var classNames = Object.keys( this.flags ).map( function ( flag ) {
- return 'oo-ui-flaggedElement-' + flag;
- } ).join( ' ' );
-
- if ( this.$flagged ) {
- this.$flagged.removeClass( classNames );
- }
-
- this.$flagged = $flagged.addClass( classNames );
-};
-
-/**
- * Check if the specified flag is set.
- *
- * @param {string} flag Name of flag
- * @return {boolean} The flag is set
- */
-OO.ui.FlaggedElement.prototype.hasFlag = function ( flag ) {
- return flag in this.flags;
-};
-
-/**
- * Get the names of all flags set.
- *
- * @return {string[]} Flag names
- */
-OO.ui.FlaggedElement.prototype.getFlags = function () {
- return Object.keys( this.flags );
-};
-
-/**
- * Clear all flags.
- *
- * @chainable
- * @fires flag
- */
-OO.ui.FlaggedElement.prototype.clearFlags = function () {
- var flag, className,
- changes = {},
- remove = [],
- classPrefix = 'oo-ui-flaggedElement-';
-
- for ( flag in this.flags ) {
- className = classPrefix + flag;
- changes[ flag ] = false;
- delete this.flags[ flag ];
- remove.push( className );
- }
-
- if ( this.$flagged ) {
- this.$flagged.removeClass( remove.join( ' ' ) );
- }
-
- this.updateThemeClasses();
- this.emit( 'flag', changes );
-
- return this;
-};
-
-/**
- * Add one or more flags.
- *
- * @param {string|string[]|Object.<string, boolean>} flags A flag name, an array of flag names,
- * or an object keyed by flag name with a boolean value that indicates whether the flag should
- * be added (`true`) or removed (`false`).
- * @chainable
- * @fires flag
- */
-OO.ui.FlaggedElement.prototype.setFlags = function ( flags ) {
- var i, len, flag, className,
- changes = {},
- add = [],
- remove = [],
- classPrefix = 'oo-ui-flaggedElement-';
-
- if ( typeof flags === 'string' ) {
- className = classPrefix + flags;
- // Set
- if ( !this.flags[ flags ] ) {
- this.flags[ flags ] = true;
- add.push( className );
- }
- } else if ( Array.isArray( flags ) ) {
- for ( i = 0, len = flags.length; i < len; i++ ) {
- flag = flags[ i ];
- className = classPrefix + flag;
- // Set
- if ( !this.flags[ flag ] ) {
- changes[ flag ] = true;
- this.flags[ flag ] = true;
- add.push( className );
- }
- }
- } else if ( OO.isPlainObject( flags ) ) {
- for ( flag in flags ) {
- className = classPrefix + flag;
- if ( flags[ flag ] ) {
- // Set
- if ( !this.flags[ flag ] ) {
- changes[ flag ] = true;
- this.flags[ flag ] = true;
- add.push( className );
- }
- } else {
- // Remove
- if ( this.flags[ flag ] ) {
- changes[ flag ] = false;
- delete this.flags[ flag ];
- remove.push( className );
- }
- }
- }
- }
-
- if ( this.$flagged ) {
- this.$flagged
- .addClass( add.join( ' ' ) )
- .removeClass( remove.join( ' ' ) );
- }
-
- this.updateThemeClasses();
- this.emit( 'flag', changes );
-
- return this;
-};
diff --git a/vendor/oojs/oojs-ui/src/elements/GroupElement.js b/vendor/oojs/oojs-ui/src/elements/GroupElement.js
deleted file mode 100644
index 51cf5d25..00000000
--- a/vendor/oojs/oojs-ui/src/elements/GroupElement.js
+++ /dev/null
@@ -1,290 +0,0 @@
-/**
- * Any OOjs UI widget that contains other widgets (such as {@link OO.ui.ButtonWidget buttons} or
- * {@link OO.ui.OptionWidget options}) mixes in GroupElement. Adding, removing, and clearing
- * items from the group is done through the interface the class provides.
- * For more information, please see the [OOjs UI documentation on MediaWiki] [1].
- *
- * [1]: https://www.mediawiki.org/wiki/OOjs_UI/Elements/Groups
- *
- * @abstract
- * @class
- *
- * @constructor
- * @param {Object} [config] Configuration options
- * @cfg {jQuery} [$group] The container element created by the class. If this configuration
- * is omitted, the group element will use a generated `<div>`.
- */
-OO.ui.GroupElement = function OoUiGroupElement( config ) {
- // Configuration initialization
- config = config || {};
-
- // Properties
- this.$group = null;
- this.items = [];
- this.aggregateItemEvents = {};
-
- // Initialization
- this.setGroupElement( config.$group || $( '<div>' ) );
-};
-
-/* Methods */
-
-/**
- * Set the group element.
- *
- * If an element is already set, items will be moved to the new element.
- *
- * @param {jQuery} $group Element to use as group
- */
-OO.ui.GroupElement.prototype.setGroupElement = function ( $group ) {
- var i, len;
-
- this.$group = $group;
- for ( i = 0, len = this.items.length; i < len; i++ ) {
- this.$group.append( this.items[ i ].$element );
- }
-};
-
-/**
- * Check if a group contains no items.
- *
- * @return {boolean} Group is empty
- */
-OO.ui.GroupElement.prototype.isEmpty = function () {
- return !this.items.length;
-};
-
-/**
- * Get all items in the group.
- *
- * The method returns an array of item references (e.g., [button1, button2, button3]) and is useful
- * when synchronizing groups of items, or whenever the references are required (e.g., when removing items
- * from a group).
- *
- * @return {OO.ui.Element[]} An array of items.
- */
-OO.ui.GroupElement.prototype.getItems = function () {
- return this.items.slice( 0 );
-};
-
-/**
- * Get an item by its data.
- *
- * Only the first item with matching data will be returned. To return all matching items,
- * use the #getItemsFromData method.
- *
- * @param {Object} data Item data to search for
- * @return {OO.ui.Element|null} Item with equivalent data, `null` if none exists
- */
-OO.ui.GroupElement.prototype.getItemFromData = function ( data ) {
- var i, len, item,
- hash = OO.getHash( data );
-
- for ( i = 0, len = this.items.length; i < len; i++ ) {
- item = this.items[ i ];
- if ( hash === OO.getHash( item.getData() ) ) {
- return item;
- }
- }
-
- return null;
-};
-
-/**
- * Get items by their data.
- *
- * All items with matching data will be returned. To return only the first match, use the #getItemFromData method instead.
- *
- * @param {Object} data Item data to search for
- * @return {OO.ui.Element[]} Items with equivalent data
- */
-OO.ui.GroupElement.prototype.getItemsFromData = function ( data ) {
- var i, len, item,
- hash = OO.getHash( data ),
- items = [];
-
- for ( i = 0, len = this.items.length; i < len; i++ ) {
- item = this.items[ i ];
- if ( hash === OO.getHash( item.getData() ) ) {
- items.push( item );
- }
- }
-
- return items;
-};
-
-/**
- * Aggregate the events emitted by the group.
- *
- * When events are aggregated, the group will listen to all contained items for the event,
- * and then emit the event under a new name. The new event will contain an additional leading
- * parameter containing the item that emitted the original event. Other arguments emitted from
- * the original event are passed through.
- *
- * @param {Object.<string,string|null>} events An object keyed by the name of the event that should be
- * aggregated (e.g., ‘click’) and the value of the new name to use (e.g., ‘groupClick’).
- * A `null` value will remove aggregated events.
-
- * @throws {Error} An error is thrown if aggregation already exists.
- */
-OO.ui.GroupElement.prototype.aggregate = function ( events ) {
- var i, len, item, add, remove, itemEvent, groupEvent;
-
- for ( itemEvent in events ) {
- groupEvent = events[ itemEvent ];
-
- // Remove existing aggregated event
- if ( Object.prototype.hasOwnProperty.call( this.aggregateItemEvents, itemEvent ) ) {
- // Don't allow duplicate aggregations
- if ( groupEvent ) {
- throw new Error( 'Duplicate item event aggregation for ' + itemEvent );
- }
- // Remove event aggregation from existing items
- for ( i = 0, len = this.items.length; i < len; i++ ) {
- item = this.items[ i ];
- if ( item.connect && item.disconnect ) {
- remove = {};
- remove[ itemEvent ] = [ 'emit', groupEvent, item ];
- item.disconnect( this, remove );
- }
- }
- // Prevent future items from aggregating event
- delete this.aggregateItemEvents[ itemEvent ];
- }
-
- // Add new aggregate event
- if ( groupEvent ) {
- // Make future items aggregate event
- this.aggregateItemEvents[ itemEvent ] = groupEvent;
- // Add event aggregation to existing items
- for ( i = 0, len = this.items.length; i < len; i++ ) {
- item = this.items[ i ];
- if ( item.connect && item.disconnect ) {
- add = {};
- add[ itemEvent ] = [ 'emit', groupEvent, item ];
- item.connect( this, add );
- }
- }
- }
- }
-};
-
-/**
- * Add items to the group.
- *
- * Items will be added to the end of the group array unless the optional `index` parameter specifies
- * a different insertion point. Adding an existing item will move it to the end of the array or the point specified by the `index`.
- *
- * @param {OO.ui.Element[]} items An array of items to add to the group
- * @param {number} [index] Index of the insertion point
- * @chainable
- */
-OO.ui.GroupElement.prototype.addItems = function ( items, index ) {
- var i, len, item, event, events, currentIndex,
- itemElements = [];
-
- for ( i = 0, len = items.length; i < len; i++ ) {
- item = items[ i ];
-
- // Check if item exists then remove it first, effectively "moving" it
- currentIndex = $.inArray( item, this.items );
- if ( currentIndex >= 0 ) {
- this.removeItems( [ item ] );
- // Adjust index to compensate for removal
- if ( currentIndex < index ) {
- index--;
- }
- }
- // Add the item
- if ( item.connect && item.disconnect && !$.isEmptyObject( this.aggregateItemEvents ) ) {
- events = {};
- for ( event in this.aggregateItemEvents ) {
- events[ event ] = [ 'emit', this.aggregateItemEvents[ event ], item ];
- }
- item.connect( this, events );
- }
- item.setElementGroup( this );
- itemElements.push( item.$element.get( 0 ) );
- }
-
- if ( index === undefined || index < 0 || index >= this.items.length ) {
- this.$group.append( itemElements );
- this.items.push.apply( this.items, items );
- } else if ( index === 0 ) {
- this.$group.prepend( itemElements );
- this.items.unshift.apply( this.items, items );
- } else {
- this.items[ index ].$element.before( itemElements );
- this.items.splice.apply( this.items, [ index, 0 ].concat( items ) );
- }
-
- return this;
-};
-
-/**
- * Remove the specified items from a group.
- *
- * Removed items are detached (not removed) from the DOM so that they may be reused.
- * To remove all items from a group, you may wish to use the #clearItems method instead.
- *
- * @param {OO.ui.Element[]} items An array of items to remove
- * @chainable
- */
-OO.ui.GroupElement.prototype.removeItems = function ( items ) {
- var i, len, item, index, remove, itemEvent;
-
- // Remove specific items
- for ( i = 0, len = items.length; i < len; i++ ) {
- item = items[ i ];
- index = $.inArray( item, this.items );
- if ( index !== -1 ) {
- if (
- item.connect && item.disconnect &&
- !$.isEmptyObject( this.aggregateItemEvents )
- ) {
- remove = {};
- if ( Object.prototype.hasOwnProperty.call( this.aggregateItemEvents, itemEvent ) ) {
- remove[ itemEvent ] = [ 'emit', this.aggregateItemEvents[ itemEvent ], item ];
- }
- item.disconnect( this, remove );
- }
- item.setElementGroup( null );
- this.items.splice( index, 1 );
- item.$element.detach();
- }
- }
-
- return this;
-};
-
-/**
- * Clear all items from the group.
- *
- * Cleared items are detached from the DOM, not removed, so that they may be reused.
- * To remove only a subset of items from a group, use the #removeItems method.
- *
- * @chainable
- */
-OO.ui.GroupElement.prototype.clearItems = function () {
- var i, len, item, remove, itemEvent;
-
- // Remove all items
- for ( i = 0, len = this.items.length; i < len; i++ ) {
- item = this.items[ i ];
- if (
- item.connect && item.disconnect &&
- !$.isEmptyObject( this.aggregateItemEvents )
- ) {
- remove = {};
- if ( Object.prototype.hasOwnProperty.call( this.aggregateItemEvents, itemEvent ) ) {
- remove[ itemEvent ] = [ 'emit', this.aggregateItemEvents[ itemEvent ], item ];
- }
- item.disconnect( this, remove );
- }
- item.setElementGroup( null );
- item.$element.detach();
- }
-
- this.items = [];
- return this;
-};
diff --git a/vendor/oojs/oojs-ui/src/elements/IconElement.js b/vendor/oojs/oojs-ui/src/elements/IconElement.js
deleted file mode 100644
index e3cf2f2a..00000000
--- a/vendor/oojs/oojs-ui/src/elements/IconElement.js
+++ /dev/null
@@ -1,187 +0,0 @@
-/**
- * IconElement is often mixed into other classes to generate an icon.
- * Icons are graphics, about the size of normal text. They are used to aid the user
- * in locating a control or to convey information in a space-efficient way. See the
- * [OOjs UI documentation on MediaWiki] [1] for a list of icons
- * included in the library.
- *
- * [1]: https://www.mediawiki.org/wiki/OOjs_UI/Widgets/Icons,_Indicators,_and_Labels#Icons
- *
- * @abstract
- * @class
- *
- * @constructor
- * @param {Object} [config] Configuration options
- * @cfg {jQuery} [$icon] The icon element created by the class. If this configuration is omitted,
- * the icon element will use a generated `<span>`. To use a different HTML tag, or to specify that
- * the icon element be set to an existing icon instead of the one generated by this class, set a
- * value using a jQuery selection. For example:
- *
- * // Use a <div> tag instead of a <span>
- * $icon: $("<div>")
- * // Use an existing icon element instead of the one generated by the class
- * $icon: this.$element
- * // Use an icon element from a child widget
- * $icon: this.childwidget.$element
- * @cfg {Object|string} [icon=''] The symbolic name of the icon (e.g., ‘remove’ or ‘menu’), or a map of
- * symbolic names. A map is used for i18n purposes and contains a `default` icon
- * name and additional names keyed by language code. The `default` name is used when no icon is keyed
- * by the user's language.
- *
- * Example of an i18n map:
- *
- * { default: 'bold-a', en: 'bold-b', de: 'bold-f' }
- * See the [OOjs UI documentation on MediaWiki] [2] for a list of icons included in the library.
- * [2]: https://www.mediawiki.org/wiki/OOjs_UI/Widgets/Icons,_Indicators,_and_Labels#Icons
- * @cfg {string|Function} [iconTitle] A text string used as the icon title, or a function that returns title
- * text. The icon title is displayed when users move the mouse over the icon.
- */
-OO.ui.IconElement = function OoUiIconElement( config ) {
- // Configuration initialization
- config = config || {};
-
- // Properties
- this.$icon = null;
- this.icon = null;
- this.iconTitle = null;
-
- // Initialization
- this.setIcon( config.icon || this.constructor.static.icon );
- this.setIconTitle( config.iconTitle || this.constructor.static.iconTitle );
- this.setIconElement( config.$icon || $( '<span>' ) );
-};
-
-/* Setup */
-
-OO.initClass( OO.ui.IconElement );
-
-/* Static Properties */
-
-/**
- * The symbolic name of the icon (e.g., ‘remove’ or ‘menu’), or a map of symbolic names. A map is used
- * for i18n purposes and contains a `default` icon name and additional names keyed by
- * language code. The `default` name is used when no icon is keyed by the user's language.
- *
- * Example of an i18n map:
- *
- * { default: 'bold-a', en: 'bold-b', de: 'bold-f' }
- *
- * Note: the static property will be overridden if the #icon configuration is used.
- *
- * @static
- * @inheritable
- * @property {Object|string}
- */
-OO.ui.IconElement.static.icon = null;
-
-/**
- * The icon title, displayed when users move the mouse over the icon. The value can be text, a
- * function that returns title text, or `null` for no title.
- *
- * The static property will be overridden if the #iconTitle configuration is used.
- *
- * @static
- * @inheritable
- * @property {string|Function|null}
- */
-OO.ui.IconElement.static.iconTitle = null;
-
-/* Methods */
-
-/**
- * Set the icon element. This method is used to retarget an icon mixin so that its functionality
- * applies to the specified icon element instead of the one created by the class. If an icon
- * element is already set, the mixin’s effect on that element is removed. Generated CSS classes
- * and mixin methods will no longer affect the element.
- *
- * @param {jQuery} $icon Element to use as icon
- */
-OO.ui.IconElement.prototype.setIconElement = function ( $icon ) {
- if ( this.$icon ) {
- this.$icon
- .removeClass( 'oo-ui-iconElement-icon oo-ui-icon-' + this.icon )
- .removeAttr( 'title' );
- }
-
- this.$icon = $icon
- .addClass( 'oo-ui-iconElement-icon' )
- .toggleClass( 'oo-ui-icon-' + this.icon, !!this.icon );
- if ( this.iconTitle !== null ) {
- this.$icon.attr( 'title', this.iconTitle );
- }
-};
-
-/**
- * Set icon by symbolic name (e.g., ‘remove’ or ‘menu’). Use `null` to remove an icon.
- * The icon parameter can also be set to a map of icon names. See the #icon config setting
- * for an example.
- *
- * @param {Object|string|null} icon A symbolic icon name, a {@link #icon map of icon names} keyed
- * by language code, or `null` to remove the icon.
- * @chainable
- */
-OO.ui.IconElement.prototype.setIcon = function ( icon ) {
- icon = OO.isPlainObject( icon ) ? OO.ui.getLocalValue( icon, null, 'default' ) : icon;
- icon = typeof icon === 'string' && icon.trim().length ? icon.trim() : null;
-
- if ( this.icon !== icon ) {
- if ( this.$icon ) {
- if ( this.icon !== null ) {
- this.$icon.removeClass( 'oo-ui-icon-' + this.icon );
- }
- if ( icon !== null ) {
- this.$icon.addClass( 'oo-ui-icon-' + icon );
- }
- }
- this.icon = icon;
- }
-
- this.$element.toggleClass( 'oo-ui-iconElement', !!this.icon );
- this.updateThemeClasses();
-
- return this;
-};
-
-/**
- * Set the icon title. Use `null` to remove the title.
- *
- * @param {string|Function|null} iconTitle A text string used as the icon title,
- * a function that returns title text, or `null` for no title.
- * @chainable
- */
-OO.ui.IconElement.prototype.setIconTitle = function ( iconTitle ) {
- iconTitle = typeof iconTitle === 'function' ||
- ( typeof iconTitle === 'string' && iconTitle.length ) ?
- OO.ui.resolveMsg( iconTitle ) : null;
-
- if ( this.iconTitle !== iconTitle ) {
- this.iconTitle = iconTitle;
- if ( this.$icon ) {
- if ( this.iconTitle !== null ) {
- this.$icon.attr( 'title', iconTitle );
- } else {
- this.$icon.removeAttr( 'title' );
- }
- }
- }
-
- return this;
-};
-
-/**
- * Get the symbolic name of the icon.
- *
- * @return {string} Icon name
- */
-OO.ui.IconElement.prototype.getIcon = function () {
- return this.icon;
-};
-
-/**
- * Get the icon title. The title text is displayed when a user moves the mouse over the icon.
- *
- * @return {string} Icon title text
- */
-OO.ui.IconElement.prototype.getIconTitle = function () {
- return this.iconTitle;
-};
diff --git a/vendor/oojs/oojs-ui/src/elements/IndicatorElement.js b/vendor/oojs/oojs-ui/src/elements/IndicatorElement.js
deleted file mode 100644
index 5c6294d2..00000000
--- a/vendor/oojs/oojs-ui/src/elements/IndicatorElement.js
+++ /dev/null
@@ -1,168 +0,0 @@
-/**
- * IndicatorElement is often mixed into other classes to generate an indicator.
- * Indicators are small graphics that are generally used in two ways:
- *
- * - To draw attention to the status of an item. For example, an indicator might be
- * used to show that an item in a list has errors that need to be resolved.
- * - To clarify the function of a control that acts in an exceptional way (a button
- * that opens a menu instead of performing an action directly, for example).
- *
- * For a list of indicators included in the library, please see the
- * [OOjs UI documentation on MediaWiki] [1].
- *
- * [1]: https://www.mediawiki.org/wiki/OOjs_UI/Widgets/Icons,_Indicators,_and_Labels#Indicators
- *
- * @abstract
- * @class
- *
- * @constructor
- * @param {Object} [config] Configuration options
- * @cfg {jQuery} [$indicator] The indicator element created by the class. If this
- * configuration is omitted, the indicator element will use a generated `<span>`.
- * @cfg {string} [indicator] Symbolic name of the indicator (e.g., ‘alert’ or ‘down’).
- * See the [OOjs UI documentation on MediaWiki][2] for a list of indicators included
- * in the library.
- * [2]: https://www.mediawiki.org/wiki/OOjs_UI/Widgets/Icons,_Indicators,_and_Labels#Indicators
- * @cfg {string|Function} [indicatorTitle] A text string used as the indicator title,
- * or a function that returns title text. The indicator title is displayed when users move
- * the mouse over the indicator.
- */
-OO.ui.IndicatorElement = function OoUiIndicatorElement( config ) {
- // Configuration initialization
- config = config || {};
-
- // Properties
- this.$indicator = null;
- this.indicator = null;
- this.indicatorTitle = null;
-
- // Initialization
- this.setIndicator( config.indicator || this.constructor.static.indicator );
- this.setIndicatorTitle( config.indicatorTitle || this.constructor.static.indicatorTitle );
- this.setIndicatorElement( config.$indicator || $( '<span>' ) );
-};
-
-/* Setup */
-
-OO.initClass( OO.ui.IndicatorElement );
-
-/* Static Properties */
-
-/**
- * Symbolic name of the indicator (e.g., ‘alert’ or ‘down’).
- * The static property will be overridden if the #indicator configuration is used.
- *
- * @static
- * @inheritable
- * @property {string|null}
- */
-OO.ui.IndicatorElement.static.indicator = null;
-
-/**
- * A text string used as the indicator title, a function that returns title text, or `null`
- * for no title. The static property will be overridden if the #indicatorTitle configuration is used.
- *
- * @static
- * @inheritable
- * @property {string|Function|null}
- */
-OO.ui.IndicatorElement.static.indicatorTitle = null;
-
-/* Methods */
-
-/**
- * Set the indicator element.
- *
- * If an element is already set, it will be cleaned up before setting up the new element.
- *
- * @param {jQuery} $indicator Element to use as indicator
- */
-OO.ui.IndicatorElement.prototype.setIndicatorElement = function ( $indicator ) {
- if ( this.$indicator ) {
- this.$indicator
- .removeClass( 'oo-ui-indicatorElement-indicator oo-ui-indicator-' + this.indicator )
- .removeAttr( 'title' );
- }
-
- this.$indicator = $indicator
- .addClass( 'oo-ui-indicatorElement-indicator' )
- .toggleClass( 'oo-ui-indicator-' + this.indicator, !!this.indicator );
- if ( this.indicatorTitle !== null ) {
- this.$indicator.attr( 'title', this.indicatorTitle );
- }
-};
-
-/**
- * Set the indicator by its symbolic name: ‘alert’, ‘down’, ‘next’, ‘previous’, ‘required’, ‘up’. Use `null` to remove the indicator.
- *
- * @param {string|null} indicator Symbolic name of indicator, or `null` for no indicator
- * @chainable
- */
-OO.ui.IndicatorElement.prototype.setIndicator = function ( indicator ) {
- indicator = typeof indicator === 'string' && indicator.length ? indicator.trim() : null;
-
- if ( this.indicator !== indicator ) {
- if ( this.$indicator ) {
- if ( this.indicator !== null ) {
- this.$indicator.removeClass( 'oo-ui-indicator-' + this.indicator );
- }
- if ( indicator !== null ) {
- this.$indicator.addClass( 'oo-ui-indicator-' + indicator );
- }
- }
- this.indicator = indicator;
- }
-
- this.$element.toggleClass( 'oo-ui-indicatorElement', !!this.indicator );
- this.updateThemeClasses();
-
- return this;
-};
-
-/**
- * Set the indicator title.
- *
- * The title is displayed when a user moves the mouse over the indicator.
- *
- * @param {string|Function|null} indicator Indicator title text, a function that returns text, or
- * `null` for no indicator title
- * @chainable
- */
-OO.ui.IndicatorElement.prototype.setIndicatorTitle = function ( indicatorTitle ) {
- indicatorTitle = typeof indicatorTitle === 'function' ||
- ( typeof indicatorTitle === 'string' && indicatorTitle.length ) ?
- OO.ui.resolveMsg( indicatorTitle ) : null;
-
- if ( this.indicatorTitle !== indicatorTitle ) {
- this.indicatorTitle = indicatorTitle;
- if ( this.$indicator ) {
- if ( this.indicatorTitle !== null ) {
- this.$indicator.attr( 'title', indicatorTitle );
- } else {
- this.$indicator.removeAttr( 'title' );
- }
- }
- }
-
- return this;
-};
-
-/**
- * Get the symbolic name of the indicator (e.g., ‘alert’ or ‘down’).
- *
- * @return {string} Symbolic name of indicator
- */
-OO.ui.IndicatorElement.prototype.getIndicator = function () {
- return this.indicator;
-};
-
-/**
- * Get the indicator title.
- *
- * The title is displayed when a user moves the mouse over the indicator.
- *
- * @return {string} Indicator title text
- */
-OO.ui.IndicatorElement.prototype.getIndicatorTitle = function () {
- return this.indicatorTitle;
-};
diff --git a/vendor/oojs/oojs-ui/src/elements/LabelElement.js b/vendor/oojs/oojs-ui/src/elements/LabelElement.js
deleted file mode 100644
index 674fa73a..00000000
--- a/vendor/oojs/oojs-ui/src/elements/LabelElement.js
+++ /dev/null
@@ -1,152 +0,0 @@
-/**
- * LabelElement is often mixed into other classes to generate a label, which
- * helps identify the function of an interface element.
- * See the [OOjs UI documentation on MediaWiki] [1] for more information.
- *
- * [1]: https://www.mediawiki.org/wiki/OOjs_UI/Widgets/Icons,_Indicators,_and_Labels#Labels
- *
- * @abstract
- * @class
- *
- * @constructor
- * @param {Object} [config] Configuration options
- * @cfg {jQuery} [$label] The label element created by the class. If this
- * configuration is omitted, the label element will use a generated `<span>`.
- * @cfg {jQuery|string|Function|OO.ui.HtmlSnippet} [label] The label text. The label can be specified
- * as a plaintext string, a jQuery selection of elements, or a function that will produce a string
- * in the future. See the [OOjs UI documentation on MediaWiki] [2] for examples.
- * [2]: https://www.mediawiki.org/wiki/OOjs_UI/Widgets/Icons,_Indicators,_and_Labels#Labels
- * @cfg {boolean} [autoFitLabel=true] Fit the label to the width of the parent element.
- * The label will be truncated to fit if necessary.
- */
-OO.ui.LabelElement = function OoUiLabelElement( config ) {
- // Configuration initialization
- config = config || {};
-
- // Properties
- this.$label = null;
- this.label = null;
- this.autoFitLabel = config.autoFitLabel === undefined || !!config.autoFitLabel;
-
- // Initialization
- this.setLabel( config.label || this.constructor.static.label );
- this.setLabelElement( config.$label || $( '<span>' ) );
-};
-
-/* Setup */
-
-OO.initClass( OO.ui.LabelElement );
-
-/* Events */
-
-/**
- * @event labelChange
- * @param {string} value
- */
-
-/* Static Properties */
-
-/**
- * The label text. The label can be specified as a plaintext string, a function that will
- * produce a string in the future, or `null` for no label. The static value will
- * be overridden if a label is specified with the #label config option.
- *
- * @static
- * @inheritable
- * @property {string|Function|null}
- */
-OO.ui.LabelElement.static.label = null;
-
-/* Methods */
-
-/**
- * Set the label element.
- *
- * If an element is already set, it will be cleaned up before setting up the new element.
- *
- * @param {jQuery} $label Element to use as label
- */
-OO.ui.LabelElement.prototype.setLabelElement = function ( $label ) {
- if ( this.$label ) {
- this.$label.removeClass( 'oo-ui-labelElement-label' ).empty();
- }
-
- this.$label = $label.addClass( 'oo-ui-labelElement-label' );
- this.setLabelContent( this.label );
-};
-
-/**
- * Set the label.
- *
- * An empty string will result in the label being hidden. A string containing only whitespace will
- * be converted to a single `&nbsp;`.
- *
- * @param {jQuery|string|OO.ui.HtmlSnippet|Function|null} label Label nodes; text; a function that returns nodes or
- * text; or null for no label
- * @chainable
- */
-OO.ui.LabelElement.prototype.setLabel = function ( label ) {
- label = typeof label === 'function' ? OO.ui.resolveMsg( label ) : label;
- label = ( ( typeof label === 'string' && label.length ) || label instanceof jQuery || label instanceof OO.ui.HtmlSnippet ) ? label : null;
-
- this.$element.toggleClass( 'oo-ui-labelElement', !!label );
-
- if ( this.label !== label ) {
- if ( this.$label ) {
- this.setLabelContent( label );
- }
- this.label = label;
- this.emit( 'labelChange' );
- }
-
- return this;
-};
-
-/**
- * Get the label.
- *
- * @return {jQuery|string|Function|null} Label nodes; text; a function that returns nodes or
- * text; or null for no label
- */
-OO.ui.LabelElement.prototype.getLabel = function () {
- return this.label;
-};
-
-/**
- * Fit the label.
- *
- * @chainable
- */
-OO.ui.LabelElement.prototype.fitLabel = function () {
- if ( this.$label && this.$label.autoEllipsis && this.autoFitLabel ) {
- this.$label.autoEllipsis( { hasSpan: false, tooltip: true } );
- }
-
- return this;
-};
-
-/**
- * Set the content of the label.
- *
- * Do not call this method until after the label element has been set by #setLabelElement.
- *
- * @private
- * @param {jQuery|string|Function|null} label Label nodes; text; a function that returns nodes or
- * text; or null for no label
- */
-OO.ui.LabelElement.prototype.setLabelContent = function ( label ) {
- if ( typeof label === 'string' ) {
- if ( label.match( /^\s*$/ ) ) {
- // Convert whitespace only string to a single non-breaking space
- this.$label.html( '&nbsp;' );
- } else {
- this.$label.text( label );
- }
- } else if ( label instanceof OO.ui.HtmlSnippet ) {
- this.$label.html( label.toString() );
- } else if ( label instanceof jQuery ) {
- this.$label.empty().append( label );
- } else {
- this.$label.empty();
- }
-};
diff --git a/vendor/oojs/oojs-ui/src/elements/LookupElement.js b/vendor/oojs/oojs-ui/src/elements/LookupElement.js
deleted file mode 100644
index b79f02a9..00000000
--- a/vendor/oojs/oojs-ui/src/elements/LookupElement.js
+++ /dev/null
@@ -1,352 +0,0 @@
-/**
- * LookupElement is a mixin that creates a {@link OO.ui.TextInputMenuSelectWidget menu} of suggested values for
- * a {@link OO.ui.TextInputWidget text input widget}. Suggested values are based on the characters the user types
- * into the text input field and, in general, the menu is only displayed when the user types. If a suggested value is chosen
- * from the lookup menu, that value becomes the value of the input field.
- *
- * Note that a new menu of suggested items is displayed when a value is chosen from the lookup menu. If this is
- * not the desired behavior, disable lookup menus with the #setLookupsDisabled method, then set the value, then
- * re-enable lookups.
- *
- * See the [OOjs UI demos][1] for an example.
- *
- * [1]: https://tools.wmflabs.org/oojs-ui/oojs-ui/demos/index.html#widgets-apex-vector-ltr
- *
- * @class
- * @abstract
- *
- * @constructor
- * @param {Object} [config] Configuration options
- * @cfg {jQuery} [$overlay] Overlay for the lookup menu; defaults to relative positioning
- * @cfg {jQuery} [$container=this.$element] The container element. The lookup menu is rendered beneath the specified element.
- * @cfg {boolean} [allowSuggestionsWhenEmpty=false] Request and display a lookup menu when the text input is empty.
- * By default, the lookup menu is not generated and displayed until the user begins to type.
- */
-OO.ui.LookupElement = function OoUiLookupElement( config ) {
- // Configuration initialization
- config = config || {};
-
- // Properties
- this.$overlay = config.$overlay || this.$element;
- this.lookupMenu = new OO.ui.TextInputMenuSelectWidget( this, {
- widget: this,
- input: this,
- $container: config.$container
- } );
-
- this.allowSuggestionsWhenEmpty = config.allowSuggestionsWhenEmpty || false;
-
- this.lookupCache = {};
- this.lookupQuery = null;
- this.lookupRequest = null;
- this.lookupsDisabled = false;
- this.lookupInputFocused = false;
-
- // Events
- this.$input.on( {
- focus: this.onLookupInputFocus.bind( this ),
- blur: this.onLookupInputBlur.bind( this ),
- mousedown: this.onLookupInputMouseDown.bind( this )
- } );
- this.connect( this, { change: 'onLookupInputChange' } );
- this.lookupMenu.connect( this, {
- toggle: 'onLookupMenuToggle',
- choose: 'onLookupMenuItemChoose'
- } );
-
- // Initialization
- this.$element.addClass( 'oo-ui-lookupElement' );
- this.lookupMenu.$element.addClass( 'oo-ui-lookupElement-menu' );
- this.$overlay.append( this.lookupMenu.$element );
-};
-
-/* Methods */
-
-/**
- * Handle input focus event.
- *
- * @protected
- * @param {jQuery.Event} e Input focus event
- */
-OO.ui.LookupElement.prototype.onLookupInputFocus = function () {
- this.lookupInputFocused = true;
- this.populateLookupMenu();
-};
-
-/**
- * Handle input blur event.
- *
- * @protected
- * @param {jQuery.Event} e Input blur event
- */
-OO.ui.LookupElement.prototype.onLookupInputBlur = function () {
- this.closeLookupMenu();
- this.lookupInputFocused = false;
-};
-
-/**
- * Handle input mouse down event.
- *
- * @protected
- * @param {jQuery.Event} e Input mouse down event
- */
-OO.ui.LookupElement.prototype.onLookupInputMouseDown = function () {
- // Only open the menu if the input was already focused.
- // This way we allow the user to open the menu again after closing it with Esc
- // by clicking in the input. Opening (and populating) the menu when initially
- // clicking into the input is handled by the focus handler.
- if ( this.lookupInputFocused && !this.lookupMenu.isVisible() ) {
- this.populateLookupMenu();
- }
-};
-
-/**
- * Handle input change event.
- *
- * @protected
- * @param {string} value New input value
- */
-OO.ui.LookupElement.prototype.onLookupInputChange = function () {
- if ( this.lookupInputFocused ) {
- this.populateLookupMenu();
- }
-};
-
-/**
- * Handle the lookup menu being shown/hidden.
- *
- * @protected
- * @param {boolean} visible Whether the lookup menu is now visible.
- */
-OO.ui.LookupElement.prototype.onLookupMenuToggle = function ( visible ) {
- if ( !visible ) {
- // When the menu is hidden, abort any active request and clear the menu.
- // This has to be done here in addition to closeLookupMenu(), because
- // MenuSelectWidget will close itself when the user presses Esc.
- this.abortLookupRequest();
- this.lookupMenu.clearItems();
- }
-};
-
-/**
- * Handle menu item 'choose' event, updating the text input value to the value of the clicked item.
- *
- * @protected
- * @param {OO.ui.MenuOptionWidget} item Selected item
- */
-OO.ui.LookupElement.prototype.onLookupMenuItemChoose = function ( item ) {
- this.setValue( item.getData() );
-};
-
-/**
- * Get lookup menu.
- *
- * @private
- * @return {OO.ui.TextInputMenuSelectWidget}
- */
-OO.ui.LookupElement.prototype.getLookupMenu = function () {
- return this.lookupMenu;
-};
-
-/**
- * Disable or re-enable lookups.
- *
- * When lookups are disabled, calls to #populateLookupMenu will be ignored.
- *
- * @param {boolean} disabled Disable lookups
- */
-OO.ui.LookupElement.prototype.setLookupsDisabled = function ( disabled ) {
- this.lookupsDisabled = !!disabled;
-};
-
-/**
- * Open the menu. If there are no entries in the menu, this does nothing.
- *
- * @private
- * @chainable
- */
-OO.ui.LookupElement.prototype.openLookupMenu = function () {
- if ( !this.lookupMenu.isEmpty() ) {
- this.lookupMenu.toggle( true );
- }
- return this;
-};
-
-/**
- * Close the menu, empty it, and abort any pending request.
- *
- * @private
- * @chainable
- */
-OO.ui.LookupElement.prototype.closeLookupMenu = function () {
- this.lookupMenu.toggle( false );
- this.abortLookupRequest();
- this.lookupMenu.clearItems();
- return this;
-};
-
-/**
- * Request menu items based on the input's current value, and when they arrive,
- * populate the menu with these items and show the menu.
- *
- * If lookups have been disabled with #setLookupsDisabled, this function does nothing.
- *
- * @private
- * @chainable
- */
-OO.ui.LookupElement.prototype.populateLookupMenu = function () {
- var widget = this,
- value = this.getValue();
-
- if ( this.lookupsDisabled ) {
- return;
- }
-
- // If the input is empty, clear the menu, unless suggestions when empty are allowed.
- if ( !this.allowSuggestionsWhenEmpty && value === '' ) {
- this.closeLookupMenu();
- // Skip population if there is already a request pending for the current value
- } else if ( value !== this.lookupQuery ) {
- this.getLookupMenuItems()
- .done( function ( items ) {
- widget.lookupMenu.clearItems();
- if ( items.length ) {
- widget.lookupMenu
- .addItems( items )
- .toggle( true );
- widget.initializeLookupMenuSelection();
- } else {
- widget.lookupMenu.toggle( false );
- }
- } )
- .fail( function () {
- widget.lookupMenu.clearItems();
- } );
- }
-
- return this;
-};
-
-/**
- * Highlight the first selectable item in the menu.
- *
- * @private
- * @chainable
- */
-OO.ui.LookupElement.prototype.initializeLookupMenuSelection = function () {
- if ( !this.lookupMenu.getSelectedItem() ) {
- this.lookupMenu.highlightItem( this.lookupMenu.getFirstSelectableItem() );
- }
-};
-
-/**
- * Get lookup menu items for the current query.
- *
- * @private
- * @return {jQuery.Promise} Promise object which will be passed menu items as the first argument of
- * the done event. If the request was aborted to make way for a subsequent request, this promise
- * will not be rejected: it will remain pending forever.
- */
-OO.ui.LookupElement.prototype.getLookupMenuItems = function () {
- var widget = this,
- value = this.getValue(),
- deferred = $.Deferred(),
- ourRequest;
-
- this.abortLookupRequest();
- if ( Object.prototype.hasOwnProperty.call( this.lookupCache, value ) ) {
- deferred.resolve( this.getLookupMenuOptionsFromData( this.lookupCache[ value ] ) );
- } else {
- this.pushPending();
- this.lookupQuery = value;
- ourRequest = this.lookupRequest = this.getLookupRequest();
- ourRequest
- .always( function () {
- // We need to pop pending even if this is an old request, otherwise
- // the widget will remain pending forever.
- // TODO: this assumes that an aborted request will fail or succeed soon after
- // being aborted, or at least eventually. It would be nice if we could popPending()
- // at abort time, but only if we knew that we hadn't already called popPending()
- // for that request.
- widget.popPending();
- } )
- .done( function ( response ) {
- // If this is an old request (and aborting it somehow caused it to still succeed),
- // ignore its success completely
- if ( ourRequest === widget.lookupRequest ) {
- widget.lookupQuery = null;
- widget.lookupRequest = null;
- widget.lookupCache[ value ] = widget.getLookupCacheDataFromResponse( response );
- deferred.resolve( widget.getLookupMenuOptionsFromData( widget.lookupCache[ value ] ) );
- }
- } )
- .fail( function () {
- // If this is an old request (or a request failing because it's being aborted),
- // ignore its failure completely
- if ( ourRequest === widget.lookupRequest ) {
- widget.lookupQuery = null;
- widget.lookupRequest = null;
- deferred.reject();
- }
- } );
- }
- return deferred.promise();
-};
-
-/**
- * Abort the currently pending lookup request, if any.
- *
- * @private
- */
-OO.ui.LookupElement.prototype.abortLookupRequest = function () {
- var oldRequest = this.lookupRequest;
- if ( oldRequest ) {
- // First unset this.lookupRequest to the fail handler will notice
- // that the request is no longer current
- this.lookupRequest = null;
- this.lookupQuery = null;
- oldRequest.abort();
- }
-};
-
-/**
- * Get a new request object of the current lookup query value.
- *
- * @protected
- * @abstract
- * @return {jQuery.Promise} jQuery AJAX object, or promise object with an .abort() method
- */
-OO.ui.LookupElement.prototype.getLookupRequest = function () {
- // Stub, implemented in subclass
- return null;
-};
-
-/**
- * Pre-process data returned by the request from #getLookupRequest.
- *
- * The return value of this function will be cached, and any further queries for the given value
- * will use the cache rather than doing API requests.
- *
- * @protected
- * @abstract
- * @param {Mixed} response Response from server
- * @return {Mixed} Cached result data
- */
-OO.ui.LookupElement.prototype.getLookupCacheDataFromResponse = function () {
- // Stub, implemented in subclass
- return [];
-};
-
-/**
- * Get a list of menu option widgets from the (possibly cached) data returned by
- * #getLookupCacheDataFromResponse.
- *
- * @protected
- * @abstract
- * @param {Mixed} data Cached result data, usually an array
- * @return {OO.ui.MenuOptionWidget[]} Menu items
- */
-OO.ui.LookupElement.prototype.getLookupMenuOptionsFromData = function () {
- // Stub, implemented in subclass
- return [];
-};
diff --git a/vendor/oojs/oojs-ui/src/elements/PendingElement.js b/vendor/oojs/oojs-ui/src/elements/PendingElement.js
deleted file mode 100644
index c5f71d54..00000000
--- a/vendor/oojs/oojs-ui/src/elements/PendingElement.js
+++ /dev/null
@@ -1,84 +0,0 @@
-/**
- * Element that can be marked as pending.
- *
- * @abstract
- * @class
- *
- * @constructor
- * @param {Object} [config] Configuration options
- * @cfg {jQuery} [$pending] Element to mark as pending, defaults to this.$element
- */
-OO.ui.PendingElement = function OoUiPendingElement( config ) {
- // Configuration initialization
- config = config || {};
-
- // Properties
- this.pending = 0;
- this.$pending = null;
-
- // Initialisation
- this.setPendingElement( config.$pending || this.$element );
-};
-
-/* Setup */
-
-OO.initClass( OO.ui.PendingElement );
-
-/* Methods */
-
-/**
- * Set the pending element (and clean up any existing one).
- *
- * @param {jQuery} $pending The element to set to pending.
- */
-OO.ui.PendingElement.prototype.setPendingElement = function ( $pending ) {
- if ( this.$pending ) {
- this.$pending.removeClass( 'oo-ui-pendingElement-pending' );
- }
-
- this.$pending = $pending;
- if ( this.pending > 0 ) {
- this.$pending.addClass( 'oo-ui-pendingElement-pending' );
- }
-};
-
-/**
- * Check if input is pending.
- *
- * @return {boolean}
- */
-OO.ui.PendingElement.prototype.isPending = function () {
- return !!this.pending;
-};
-
-/**
- * Increase the pending stack.
- *
- * @chainable
- */
-OO.ui.PendingElement.prototype.pushPending = function () {
- if ( this.pending === 0 ) {
- this.$pending.addClass( 'oo-ui-pendingElement-pending' );
- this.updateThemeClasses();
- }
- this.pending++;
-
- return this;
-};
-
-/**
- * Reduce the pending stack.
- *
- * Clamped at zero.
- *
- * @chainable
- */
-OO.ui.PendingElement.prototype.popPending = function () {
- if ( this.pending === 1 ) {
- this.$pending.removeClass( 'oo-ui-pendingElement-pending' );
- this.updateThemeClasses();
- }
- this.pending = Math.max( 0, this.pending - 1 );
-
- return this;
-};
diff --git a/vendor/oojs/oojs-ui/src/elements/PopupElement.js b/vendor/oojs/oojs-ui/src/elements/PopupElement.js
deleted file mode 100644
index 099e94b7..00000000
--- a/vendor/oojs/oojs-ui/src/elements/PopupElement.js
+++ /dev/null
@@ -1,36 +0,0 @@
-/**
- * PopupElement is mixed into other classes to generate a {@link OO.ui.PopupWidget popup widget}.
- * A popup is a container for content. It is overlaid and positioned absolutely. By default, each
- * popup has an anchor, which is an arrow-like protrusion that points toward the popup’s origin.
- * See {@link OO.ui.PopupWidget PopupWidget} for an example.
- *
- * @abstract
- * @class
- *
- * @constructor
- * @param {Object} [config] Configuration options
- * @cfg {Object} [popup] Configuration to pass to popup
- * @cfg {boolean} [popup.autoClose=true] Popup auto-closes when it loses focus
- */
-OO.ui.PopupElement = function OoUiPopupElement( config ) {
- // Configuration initialization
- config = config || {};
-
- // Properties
- this.popup = new OO.ui.PopupWidget( $.extend(
- { autoClose: true },
- config.popup,
- { $autoCloseIgnore: this.$element }
- ) );
-};
-
-/* Methods */
-
-/**
- * Get popup.
- *
- * @return {OO.ui.PopupWidget} Popup widget
- */
-OO.ui.PopupElement.prototype.getPopup = function () {
- return this.popup;
-};
diff --git a/vendor/oojs/oojs-ui/src/elements/TabIndexedElement.js b/vendor/oojs/oojs-ui/src/elements/TabIndexedElement.js
deleted file mode 100644
index 5c2151a0..00000000
--- a/vendor/oojs/oojs-ui/src/elements/TabIndexedElement.js
+++ /dev/null
@@ -1,138 +0,0 @@
-/**
- * The TabIndexedElement class is an attribute mixin used to add additional functionality to an
- * element created by another class. The mixin provides a ‘tabIndex’ property, which specifies the
- * order in which users will navigate through the focusable elements via the "tab" key.
- *
- * @example
- * // TabIndexedElement is mixed into the ButtonWidget class
- * // to provide a tabIndex property.
- * var button1 = new OO.ui.ButtonWidget( {
- * label: 'fourth',
- * tabIndex: 4
- * } );
- * var button2 = new OO.ui.ButtonWidget( {
- * label: 'second',
- * tabIndex: 2
- * } );
- * var button3 = new OO.ui.ButtonWidget( {
- * label: 'third',
- * tabIndex: 3
- * } );
- * var button4 = new OO.ui.ButtonWidget( {
- * label: 'first',
- * tabIndex: 1
- * } );
- * $( 'body' ).append( button1.$element, button2.$element, button3.$element, button4.$element );
- *
- * @abstract
- * @class
- *
- * @constructor
- * @param {Object} [config] Configuration options
- * @cfg {jQuery} [$tabIndexed] The element that should use the tabindex functionality. By default,
- * the functionality is applied to the element created by the class ($element). If a different element is specified, the tabindex
- * functionality will be applied to it instead.
- * @cfg {number|null} [tabIndex=0] Number that specifies the element’s position in the tab-navigation
- * order (e.g., 1 for the first focusable element). Use 0 to use the default navigation order; use -1
- * to remove the element from the tab-navigation flow.
- */
-OO.ui.TabIndexedElement = function OoUiTabIndexedElement( config ) {
- // Configuration initialization
- config = $.extend( { tabIndex: 0 }, config );
-
- // Properties
- this.$tabIndexed = null;
- this.tabIndex = null;
-
- // Events
- this.connect( this, { disable: 'onDisable' } );
-
- // Initialization
- this.setTabIndex( config.tabIndex );
- this.setTabIndexedElement( config.$tabIndexed || this.$element );
-};
-
-/* Setup */
-
-OO.initClass( OO.ui.TabIndexedElement );
-
-/* Methods */
-
-/**
- * Set the element that should use the tabindex functionality.
- *
- * This method is used to retarget a tabindex mixin so that its functionality applies
- * to the specified element. If an element is currently using the functionality, the mixin’s
- * effect on that element is removed before the new element is set up.
- *
- * @param {jQuery} $tabIndexed Element that should use the tabindex functionality
- * @chainable
- */
-OO.ui.TabIndexedElement.prototype.setTabIndexedElement = function ( $tabIndexed ) {
- var tabIndex = this.tabIndex;
- // Remove attributes from old $tabIndexed
- this.setTabIndex( null );
- // Force update of new $tabIndexed
- this.$tabIndexed = $tabIndexed;
- this.tabIndex = tabIndex;
- return this.updateTabIndex();
-};
-
-/**
- * Set the value of the tabindex.
- *
- * @param {number|null} tabIndex Tabindex value, or `null` for no tabindex
- * @chainable
- */
-OO.ui.TabIndexedElement.prototype.setTabIndex = function ( tabIndex ) {
- tabIndex = typeof tabIndex === 'number' ? tabIndex : null;
-
- if ( this.tabIndex !== tabIndex ) {
- this.tabIndex = tabIndex;
- this.updateTabIndex();
- }
-
- return this;
-};
-
-/**
- * Update the `tabindex` attribute, in case of changes to tab index or
- * disabled state.
- *
- * @private
- * @chainable
- */
-OO.ui.TabIndexedElement.prototype.updateTabIndex = function () {
- if ( this.$tabIndexed ) {
- if ( this.tabIndex !== null ) {
- // Do not index over disabled elements
- this.$tabIndexed.attr( {
- tabindex: this.isDisabled() ? -1 : this.tabIndex,
- // ChromeVox and NVDA do not seem to inherit this from parent elements
- 'aria-disabled': this.isDisabled().toString()
- } );
- } else {
- this.$tabIndexed.removeAttr( 'tabindex aria-disabled' );
- }
- }
- return this;
-};
-
-/**
- * Handle disable events.
- *
- * @private
- * @param {boolean} disabled Element is disabled
- */
-OO.ui.TabIndexedElement.prototype.onDisable = function () {
- this.updateTabIndex();
-};
-
-/**
- * Get the value of the tabindex.
- *
- * @return {number|null} Tabindex value
- */
-OO.ui.TabIndexedElement.prototype.getTabIndex = function () {
- return this.tabIndex;
-};
diff --git a/vendor/oojs/oojs-ui/src/elements/TitledElement.js b/vendor/oojs/oojs-ui/src/elements/TitledElement.js
deleted file mode 100644
index 905ec019..00000000
--- a/vendor/oojs/oojs-ui/src/elements/TitledElement.js
+++ /dev/null
@@ -1,106 +0,0 @@
-/**
- * TitledElement is mixed into other classes to provide a `title` attribute.
- * Titles are rendered by the browser and are made visible when the user moves
- * the mouse over the element. Titles are not visible on touch devices.
- *
- * @example
- * // TitledElement provides a 'title' attribute to the
- * // ButtonWidget class
- * var button = new OO.ui.ButtonWidget( {
- * label: 'Button with Title',
- * title: 'I am a button'
- * } );
- * $( 'body' ).append( button.$element );
- *
- * @abstract
- * @class
- *
- * @constructor
- * @param {Object} [config] Configuration options
- * @cfg {jQuery} [$titled] The element to which the `title` attribute is applied.
- * If this config is omitted, the title functionality is applied to $element, the
- * element created by the class.
- * @cfg {string|Function} [title] The title text or a function that returns text. If
- * this config is omitted, the value of the {@link #static-title static title} property is used.
- */
-OO.ui.TitledElement = function OoUiTitledElement( config ) {
- // Configuration initialization
- config = config || {};
-
- // Properties
- this.$titled = null;
- this.title = null;
-
- // Initialization
- this.setTitle( config.title || this.constructor.static.title );
- this.setTitledElement( config.$titled || this.$element );
-};
-
-/* Setup */
-
-OO.initClass( OO.ui.TitledElement );
-
-/* Static Properties */
-
-/**
- * The title text, a function that returns text, or `null` for no title. The value of the static property
- * is overridden if the #title config option is used.
- *
- * @static
- * @inheritable
- * @property {string|Function|null}
- */
-OO.ui.TitledElement.static.title = null;
-
-/* Methods */
-
-/**
- * Set the titled element.
- *
- * This method is used to retarget a titledElement mixin so that its functionality applies to the specified element.
- * If an element is already set, the mixin’s effect on that element is removed before the new element is set up.
- *
- * @param {jQuery} $titled Element that should use the 'titled' functionality
- */
-OO.ui.TitledElement.prototype.setTitledElement = function ( $titled ) {
- if ( this.$titled ) {
- this.$titled.removeAttr( 'title' );
- }
-
- this.$titled = $titled;
- if ( this.title ) {
- this.$titled.attr( 'title', this.title );
- }
-};
-
-/**
- * Set title.
- *
- * @param {string|Function|null} title Title text, a function that returns text, or `null` for no title
- * @chainable
- */
-OO.ui.TitledElement.prototype.setTitle = function ( title ) {
- title = typeof title === 'string' ? OO.ui.resolveMsg( title ) : null;
-
- if ( this.title !== title ) {
- if ( this.$titled ) {
- if ( title !== null ) {
- this.$titled.attr( 'title', title );
- } else {
- this.$titled.removeAttr( 'title' );
- }
- }
- this.title = title;
- }
-
- return this;
-};
-
-/**
- * Get title.
- *
- * @return {string} Title string
- */
-OO.ui.TitledElement.prototype.getTitle = function () {
- return this.title;
-};
diff --git a/vendor/oojs/oojs-ui/src/intro.js.txt b/vendor/oojs/oojs-ui/src/intro.js.txt
deleted file mode 100644
index 31f545ca..00000000
--- a/vendor/oojs/oojs-ui/src/intro.js.txt
+++ /dev/null
@@ -1,3 +0,0 @@
-( function ( OO ) {
-
-'use strict';
diff --git a/vendor/oojs/oojs-ui/src/layouts/ActionFieldLayout.js b/vendor/oojs/oojs-ui/src/layouts/ActionFieldLayout.js
deleted file mode 100644
index 59640ed9..00000000
--- a/vendor/oojs/oojs-ui/src/layouts/ActionFieldLayout.js
+++ /dev/null
@@ -1,81 +0,0 @@
-/**
- * ActionFieldLayouts are used with OO.ui.FieldsetLayout. The layout consists of a field-widget, a button,
- * and an optional label and/or help text. The field-widget (e.g., a {@link OO.ui.TextInputWidget TextInputWidget}),
- * is required and is specified before any optional configuration settings.
- *
- * Labels can be aligned in one of four ways:
- *
- * - **left**: The label is placed before the field-widget and aligned with the left margin.
- * A left-alignment is used for forms with many fields.
- * - **right**: The label is placed before the field-widget and aligned to the right margin.
- * A right-alignment is used for long but familiar forms which users tab through,
- * verifying the current field with a quick glance at the label.
- * - **top**: The label is placed above the field-widget. A top-alignment is used for brief forms
- * that users fill out from top to bottom.
- * - **inline**: The label is placed after the field-widget and aligned to the left.
- * An inline-alignment is best used with checkboxes or radio buttons.
- *
- * Help text is accessed via a help icon that appears in the upper right corner of the rendered field layout when help
- * text is specified.
- *
- * @example
- * // Example of an ActionFieldLayout
- * var actionFieldLayout = new OO.ui.ActionFieldLayout(
- * new OO.ui.TextInputWidget( {
- * placeholder: 'Field widget'
- * } ),
- * new OO.ui.ButtonWidget( {
- * label: 'Button'
- * } ),
- * {
- * label: 'An ActionFieldLayout. This label is aligned top',
- * align: 'top',
- * help: 'This is help text'
- * }
- * );
- *
- * $( 'body' ).append( actionFieldLayout.$element );
- *
- *
- * @class
- * @extends OO.ui.FieldLayout
- *
- * @constructor
- * @param {OO.ui.Widget} fieldWidget Field widget
- * @param {OO.ui.ButtonWidget} buttonWidget Button widget
- * @param {Object} [config] Configuration options
- * @cfg {string} [align='left'] Alignment of the label: 'left', 'right', 'top' or 'inline'
- * @cfg {string} [help] Help text. When help text is specified, a help icon will appear in the
- * upper-right corner of the rendered field.
- */
-OO.ui.ActionFieldLayout = function OoUiActionFieldLayout( fieldWidget, buttonWidget, config ) {
- // Allow passing positional parameters inside the config object
- if ( OO.isPlainObject( fieldWidget ) && config === undefined ) {
- config = fieldWidget;
- fieldWidget = config.fieldWidget;
- buttonWidget = config.buttonWidget;
- }
-
- // Configuration initialization
- config = $.extend( { align: 'left' }, config );
-
- // Parent constructor
- OO.ui.ActionFieldLayout.super.call( this, fieldWidget, config );
-
- // Properties
- this.fieldWidget = fieldWidget;
- this.buttonWidget = buttonWidget;
- this.$button = $( '<div>' )
- .addClass( 'oo-ui-actionFieldLayout-button' )
- .append( this.buttonWidget.$element );
- this.$input = $( '<div>' )
- .addClass( 'oo-ui-actionFieldLayout-input' )
- .append( this.fieldWidget.$element );
- this.$field
- .addClass( 'oo-ui-actionFieldLayout' )
- .append( this.$input, this.$button );
-};
-
-/* Setup */
-
-OO.inheritClass( OO.ui.ActionFieldLayout, OO.ui.FieldLayout );
diff --git a/vendor/oojs/oojs-ui/src/layouts/BookletLayout.js b/vendor/oojs/oojs-ui/src/layouts/BookletLayout.js
deleted file mode 100644
index eebf57d6..00000000
--- a/vendor/oojs/oojs-ui/src/layouts/BookletLayout.js
+++ /dev/null
@@ -1,542 +0,0 @@
-/**
- * BookletLayouts contain {@link OO.ui.PageLayout page layouts} as well as
- * an {@link OO.ui.OutlineSelectWidget outline} that allows users to easily navigate
- * through the pages and select which one to display. By default, only one page is
- * displayed at a time and the outline is hidden. When a user navigates to a new page,
- * the booklet layout automatically focuses on the first focusable element, unless the
- * default setting is changed. Optionally, booklets can be configured to show
- * {@link OO.ui.OutlineControlsWidget controls} for adding, moving, and removing items.
- *
- * @example
- * // Example of a BookletLayout that contains two PageLayouts.
- *
- * function PageOneLayout( name, config ) {
- * PageOneLayout.super.call( this, name, config );
- * this.$element.append( '<p>First page</p><p>(This booklet has an outline, displayed on the left)</p>' );
- * }
- * OO.inheritClass( PageOneLayout, OO.ui.PageLayout );
- * PageOneLayout.prototype.setupOutlineItem = function () {
- * this.outlineItem.setLabel( 'Page One' );
- * };
- *
- * function PageTwoLayout( name, config ) {
- * PageTwoLayout.super.call( this, name, config );
- * this.$element.append( '<p>Second page</p>' );
- * }
- * OO.inheritClass( PageTwoLayout, OO.ui.PageLayout );
- * PageTwoLayout.prototype.setupOutlineItem = function () {
- * this.outlineItem.setLabel( 'Page Two' );
- * };
- *
- * var page1 = new PageOneLayout( 'one' ),
- * page2 = new PageTwoLayout( 'two' );
- *
- * var booklet = new OO.ui.BookletLayout( {
- * outlined: true
- * } );
- *
- * booklet.addPages ( [ page1, page2 ] );
- * $( 'body' ).append( booklet.$element );
- *
- * @class
- * @extends OO.ui.MenuLayout
- *
- * @constructor
- * @param {Object} [config] Configuration options
- * @cfg {boolean} [continuous=false] Show all pages, one after another
- * @cfg {boolean} [autoFocus=true] Focus on the first focusable element when a new page is displayed.
- * @cfg {boolean} [outlined=false] Show the outline. The outline is used to navigate through the pages of the booklet.
- * @cfg {boolean} [editable=false] Show controls for adding, removing and reordering pages
- */
-OO.ui.BookletLayout = function OoUiBookletLayout( config ) {
- // Configuration initialization
- config = config || {};
-
- // Parent constructor
- OO.ui.BookletLayout.super.call( this, config );
-
- // Properties
- this.currentPageName = null;
- this.pages = {};
- this.ignoreFocus = false;
- this.stackLayout = new OO.ui.StackLayout( { continuous: !!config.continuous } );
- this.$content.append( this.stackLayout.$element );
- this.autoFocus = config.autoFocus === undefined || !!config.autoFocus;
- this.outlineVisible = false;
- this.outlined = !!config.outlined;
- if ( this.outlined ) {
- this.editable = !!config.editable;
- this.outlineControlsWidget = null;
- this.outlineSelectWidget = new OO.ui.OutlineSelectWidget();
- this.outlinePanel = new OO.ui.PanelLayout( { scrollable: true } );
- this.$menu.append( this.outlinePanel.$element );
- this.outlineVisible = true;
- if ( this.editable ) {
- this.outlineControlsWidget = new OO.ui.OutlineControlsWidget(
- this.outlineSelectWidget
- );
- }
- }
- this.toggleMenu( this.outlined );
-
- // Events
- this.stackLayout.connect( this, { set: 'onStackLayoutSet' } );
- if ( this.outlined ) {
- this.outlineSelectWidget.connect( this, { select: 'onOutlineSelectWidgetSelect' } );
- }
- if ( this.autoFocus ) {
- // Event 'focus' does not bubble, but 'focusin' does
- this.stackLayout.$element.on( 'focusin', this.onStackLayoutFocus.bind( this ) );
- }
-
- // Initialization
- this.$element.addClass( 'oo-ui-bookletLayout' );
- this.stackLayout.$element.addClass( 'oo-ui-bookletLayout-stackLayout' );
- if ( this.outlined ) {
- this.outlinePanel.$element
- .addClass( 'oo-ui-bookletLayout-outlinePanel' )
- .append( this.outlineSelectWidget.$element );
- if ( this.editable ) {
- this.outlinePanel.$element
- .addClass( 'oo-ui-bookletLayout-outlinePanel-editable' )
- .append( this.outlineControlsWidget.$element );
- }
- }
-};
-
-/* Setup */
-
-OO.inheritClass( OO.ui.BookletLayout, OO.ui.MenuLayout );
-
-/* Events */
-
-/**
- * A 'set' event is emitted when a page is {@link #setPage set} to be displayed by the booklet layout.
- * @event set
- * @param {OO.ui.PageLayout} page Current page
- */
-
-/**
- * An 'add' event is emitted when pages are {@link #addPages added} to the booklet layout.
- *
- * @event add
- * @param {OO.ui.PageLayout[]} page Added pages
- * @param {number} index Index pages were added at
- */
-
-/**
- * A 'remove' event is emitted when pages are {@link #clearPages cleared} or
- * {@link #removePages removed} from the booklet.
- *
- * @event remove
- * @param {OO.ui.PageLayout[]} pages Removed pages
- */
-
-/* Methods */
-
-/**
- * Handle stack layout focus.
- *
- * @private
- * @param {jQuery.Event} e Focusin event
- */
-OO.ui.BookletLayout.prototype.onStackLayoutFocus = function ( e ) {
- var name, $target;
-
- // Find the page that an element was focused within
- $target = $( e.target ).closest( '.oo-ui-pageLayout' );
- for ( name in this.pages ) {
- // Check for page match, exclude current page to find only page changes
- if ( this.pages[ name ].$element[ 0 ] === $target[ 0 ] && name !== this.currentPageName ) {
- this.setPage( name );
- break;
- }
- }
-};
-
-/**
- * Handle stack layout set events.
- *
- * @private
- * @param {OO.ui.PanelLayout|null} page The page panel that is now the current panel
- */
-OO.ui.BookletLayout.prototype.onStackLayoutSet = function ( page ) {
- var layout = this;
- if ( page ) {
- page.scrollElementIntoView( { complete: function () {
- if ( layout.autoFocus ) {
- layout.focus();
- }
- } } );
- }
-};
-
-/**
- * Focus the first input in the current page.
- *
- * If no page is selected, the first selectable page will be selected.
- * If the focus is already in an element on the current page, nothing will happen.
- * @param {number} [itemIndex] A specific item to focus on
- */
-OO.ui.BookletLayout.prototype.focus = function ( itemIndex ) {
- var $input, page,
- items = this.stackLayout.getItems();
-
- if ( itemIndex !== undefined && items[ itemIndex ] ) {
- page = items[ itemIndex ];
- } else {
- page = this.stackLayout.getCurrentItem();
- }
-
- if ( !page && this.outlined ) {
- this.selectFirstSelectablePage();
- page = this.stackLayout.getCurrentItem();
- }
- if ( !page ) {
- return;
- }
- // Only change the focus if is not already in the current page
- if ( !page.$element.find( ':focus' ).length ) {
- $input = page.$element.find( ':input:first' );
- if ( $input.length ) {
- $input[ 0 ].focus();
- }
- }
-};
-
-/**
- * Find the first focusable input in the booklet layout and focus
- * on it.
- */
-OO.ui.BookletLayout.prototype.focusFirstFocusable = function () {
- var i, len,
- found = false,
- items = this.stackLayout.getItems(),
- checkAndFocus = function () {
- if ( OO.ui.isFocusableElement( $( this ) ) ) {
- $( this ).focus();
- found = true;
- return false;
- }
- };
-
- for ( i = 0, len = items.length; i < len; i++ ) {
- if ( found ) {
- break;
- }
- // Find all potentially focusable elements in the item
- // and check if they are focusable
- items[i].$element
- .find( 'input, select, textarea, button, object' )
- /* jshint loopfunc:true */
- .each( checkAndFocus );
- }
-};
-
-/**
- * Handle outline widget select events.
- *
- * @private
- * @param {OO.ui.OptionWidget|null} item Selected item
- */
-OO.ui.BookletLayout.prototype.onOutlineSelectWidgetSelect = function ( item ) {
- if ( item ) {
- this.setPage( item.getData() );
- }
-};
-
-/**
- * Check if booklet has an outline.
- *
- * @return {boolean} Booklet has an outline
- */
-OO.ui.BookletLayout.prototype.isOutlined = function () {
- return this.outlined;
-};
-
-/**
- * Check if booklet has editing controls.
- *
- * @return {boolean} Booklet is editable
- */
-OO.ui.BookletLayout.prototype.isEditable = function () {
- return this.editable;
-};
-
-/**
- * Check if booklet has a visible outline.
- *
- * @return {boolean} Outline is visible
- */
-OO.ui.BookletLayout.prototype.isOutlineVisible = function () {
- return this.outlined && this.outlineVisible;
-};
-
-/**
- * Hide or show the outline.
- *
- * @param {boolean} [show] Show outline, omit to invert current state
- * @chainable
- */
-OO.ui.BookletLayout.prototype.toggleOutline = function ( show ) {
- if ( this.outlined ) {
- show = show === undefined ? !this.outlineVisible : !!show;
- this.outlineVisible = show;
- this.toggleMenu( show );
- }
-
- return this;
-};
-
-/**
- * Get the page closest to the specified page.
- *
- * @param {OO.ui.PageLayout} page Page to use as a reference point
- * @return {OO.ui.PageLayout|null} Page closest to the specified page
- */
-OO.ui.BookletLayout.prototype.getClosestPage = function ( page ) {
- var next, prev, level,
- pages = this.stackLayout.getItems(),
- index = $.inArray( page, pages );
-
- if ( index !== -1 ) {
- next = pages[ index + 1 ];
- prev = pages[ index - 1 ];
- // Prefer adjacent pages at the same level
- if ( this.outlined ) {
- level = this.outlineSelectWidget.getItemFromData( page.getName() ).getLevel();
- if (
- prev &&
- level === this.outlineSelectWidget.getItemFromData( prev.getName() ).getLevel()
- ) {
- return prev;
- }
- if (
- next &&
- level === this.outlineSelectWidget.getItemFromData( next.getName() ).getLevel()
- ) {
- return next;
- }
- }
- }
- return prev || next || null;
-};
-
-/**
- * Get the outline widget.
- *
- * If the booklet is not outlined, the method will return `null`.
- *
- * @return {OO.ui.OutlineSelectWidget|null} Outline widget, or null if the booklet is not outlined
- */
-OO.ui.BookletLayout.prototype.getOutline = function () {
- return this.outlineSelectWidget;
-};
-
-/**
- * Get the outline controls widget.
- *
- * If the outline is not editable, the method will return `null`.
- *
- * @return {OO.ui.OutlineControlsWidget|null} The outline controls widget.
- */
-OO.ui.BookletLayout.prototype.getOutlineControls = function () {
- return this.outlineControlsWidget;
-};
-
-/**
- * Get a page by its symbolic name.
- *
- * @param {string} name Symbolic name of page
- * @return {OO.ui.PageLayout|undefined} Page, if found
- */
-OO.ui.BookletLayout.prototype.getPage = function ( name ) {
- return this.pages[ name ];
-};
-
-/**
- * Get the current page.
- *
- * @return {OO.ui.PageLayout|undefined} Current page, if found
- */
-OO.ui.BookletLayout.prototype.getCurrentPage = function () {
- var name = this.getCurrentPageName();
- return name ? this.getPage( name ) : undefined;
-};
-
-/**
- * Get the symbolic name of the current page.
- *
- * @return {string|null} Symbolic name of the current page
- */
-OO.ui.BookletLayout.prototype.getCurrentPageName = function () {
- return this.currentPageName;
-};
-
-/**
- * Add pages to the booklet layout
- *
- * When pages are added with the same names as existing pages, the existing pages will be
- * automatically removed before the new pages are added.
- *
- * @param {OO.ui.PageLayout[]} pages Pages to add
- * @param {number} index Index of the insertion point
- * @fires add
- * @chainable
- */
-OO.ui.BookletLayout.prototype.addPages = function ( pages, index ) {
- var i, len, name, page, item, currentIndex,
- stackLayoutPages = this.stackLayout.getItems(),
- remove = [],
- items = [];
-
- // Remove pages with same names
- for ( i = 0, len = pages.length; i < len; i++ ) {
- page = pages[ i ];
- name = page.getName();
-
- if ( Object.prototype.hasOwnProperty.call( this.pages, name ) ) {
- // Correct the insertion index
- currentIndex = $.inArray( this.pages[ name ], stackLayoutPages );
- if ( currentIndex !== -1 && currentIndex + 1 < index ) {
- index--;
- }
- remove.push( this.pages[ name ] );
- }
- }
- if ( remove.length ) {
- this.removePages( remove );
- }
-
- // Add new pages
- for ( i = 0, len = pages.length; i < len; i++ ) {
- page = pages[ i ];
- name = page.getName();
- this.pages[ page.getName() ] = page;
- if ( this.outlined ) {
- item = new OO.ui.OutlineOptionWidget( { data: name } );
- page.setOutlineItem( item );
- items.push( item );
- }
- }
-
- if ( this.outlined && items.length ) {
- this.outlineSelectWidget.addItems( items, index );
- this.selectFirstSelectablePage();
- }
- this.stackLayout.addItems( pages, index );
- this.emit( 'add', pages, index );
-
- return this;
-};
-
-/**
- * Remove the specified pages from the booklet layout.
- *
- * To remove all pages from the booklet, you may wish to use the #clearPages method instead.
- *
- * @param {OO.ui.PageLayout[]} pages An array of pages to remove
- * @fires remove
- * @chainable
- */
-OO.ui.BookletLayout.prototype.removePages = function ( pages ) {
- var i, len, name, page,
- items = [];
-
- for ( i = 0, len = pages.length; i < len; i++ ) {
- page = pages[ i ];
- name = page.getName();
- delete this.pages[ name ];
- if ( this.outlined ) {
- items.push( this.outlineSelectWidget.getItemFromData( name ) );
- page.setOutlineItem( null );
- }
- }
- if ( this.outlined && items.length ) {
- this.outlineSelectWidget.removeItems( items );
- this.selectFirstSelectablePage();
- }
- this.stackLayout.removeItems( pages );
- this.emit( 'remove', pages );
-
- return this;
-};
-
-/**
- * Clear all pages from the booklet layout.
- *
- * To remove only a subset of pages from the booklet, use the #removePages method.
- *
- * @fires remove
- * @chainable
- */
-OO.ui.BookletLayout.prototype.clearPages = function () {
- var i, len,
- pages = this.stackLayout.getItems();
-
- this.pages = {};
- this.currentPageName = null;
- if ( this.outlined ) {
- this.outlineSelectWidget.clearItems();
- for ( i = 0, len = pages.length; i < len; i++ ) {
- pages[ i ].setOutlineItem( null );
- }
- }
- this.stackLayout.clearItems();
-
- this.emit( 'remove', pages );
-
- return this;
-};
-
-/**
- * Set the current page by symbolic name.
- *
- * @fires set
- * @param {string} name Symbolic name of page
- */
-OO.ui.BookletLayout.prototype.setPage = function ( name ) {
- var selectedItem,
- $focused,
- page = this.pages[ name ];
-
- if ( name !== this.currentPageName ) {
- if ( this.outlined ) {
- selectedItem = this.outlineSelectWidget.getSelectedItem();
- if ( selectedItem && selectedItem.getData() !== name ) {
- this.outlineSelectWidget.selectItemByData( name );
- }
- }
- if ( page ) {
- if ( this.currentPageName && this.pages[ this.currentPageName ] ) {
- this.pages[ this.currentPageName ].setActive( false );
- // Blur anything focused if the next page doesn't have anything focusable - this
- // is not needed if the next page has something focusable because once it is focused
- // this blur happens automatically
- if ( this.autoFocus && !page.$element.find( ':input' ).length ) {
- $focused = this.pages[ this.currentPageName ].$element.find( ':focus' );
- if ( $focused.length ) {
- $focused[ 0 ].blur();
- }
- }
- }
- this.currentPageName = name;
- this.stackLayout.setItem( page );
- page.setActive( true );
- this.emit( 'set', page );
- }
- }
-};
-
-/**
- * Select the first selectable page.
- *
- * @chainable
- */
-OO.ui.BookletLayout.prototype.selectFirstSelectablePage = function () {
- if ( !this.outlineSelectWidget.getSelectedItem() ) {
- this.outlineSelectWidget.selectItem( this.outlineSelectWidget.getFirstSelectableItem() );
- }
-
- return this;
-};
diff --git a/vendor/oojs/oojs-ui/src/layouts/CardLayout.js b/vendor/oojs/oojs-ui/src/layouts/CardLayout.js
deleted file mode 100644
index 353aedc9..00000000
--- a/vendor/oojs/oojs-ui/src/layouts/CardLayout.js
+++ /dev/null
@@ -1,138 +0,0 @@
-/**
- * CardLayouts are used within {@link OO.ui.IndexLayout index layouts} to create cards that users can select and display
- * from the index's optional {@link OO.ui.TabSelectWidget tab} navigation. Cards are usually not instantiated directly,
- * rather extended to include the required content and functionality.
- *
- * Each card must have a unique symbolic name, which is passed to the constructor. In addition, the card's tab
- * item is customized (with a label) using the #setupTabItem method. See
- * {@link OO.ui.IndexLayout IndexLayout} for an example.
- *
- * @class
- * @extends OO.ui.PanelLayout
- *
- * @constructor
- * @param {string} name Unique symbolic name of card
- * @param {Object} [config] Configuration options
- */
-OO.ui.CardLayout = function OoUiCardLayout( name, config ) {
- // Allow passing positional parameters inside the config object
- if ( OO.isPlainObject( name ) && config === undefined ) {
- config = name;
- name = config.name;
- }
-
- // Configuration initialization
- config = $.extend( { scrollable: true }, config );
-
- // Parent constructor
- OO.ui.CardLayout.super.call( this, config );
-
- // Properties
- this.name = name;
- this.tabItem = null;
- this.active = false;
-
- // Initialization
- this.$element.addClass( 'oo-ui-cardLayout' );
-};
-
-/* Setup */
-
-OO.inheritClass( OO.ui.CardLayout, OO.ui.PanelLayout );
-
-/* Events */
-
-/**
- * An 'active' event is emitted when the card becomes active. Cards become active when they are
- * shown in a index layout that is configured to display only one card at a time.
- *
- * @event active
- * @param {boolean} active Card is active
- */
-
-/* Methods */
-
-/**
- * Get the symbolic name of the card.
- *
- * @return {string} Symbolic name of card
- */
-OO.ui.CardLayout.prototype.getName = function () {
- return this.name;
-};
-
-/**
- * Check if card is active.
- *
- * Cards become active when they are shown in a {@link OO.ui.IndexLayout index layout} that is configured to display
- * only one card at a time. Additional CSS is applied to the card's tab item to reflect the active state.
- *
- * @return {boolean} Card is active
- */
-OO.ui.CardLayout.prototype.isActive = function () {
- return this.active;
-};
-
-/**
- * Get tab item.
- *
- * The tab item allows users to access the card from the index's tab
- * navigation. The tab item itself can be customized (with a label, level, etc.) using the #setupTabItem method.
- *
- * @return {OO.ui.TabOptionWidget|null} Tab option widget
- */
-OO.ui.CardLayout.prototype.getTabItem = function () {
- return this.tabItem;
-};
-
-/**
- * Set or unset the tab item.
- *
- * Specify a {@link OO.ui.TabOptionWidget tab option} to set it,
- * or `null` to clear the tab item. To customize the tab item itself (e.g., to set a label or tab
- * level), use #setupTabItem instead of this method.
- *
- * @param {OO.ui.TabOptionWidget|null} tabItem Tab option widget, null to clear
- * @chainable
- */
-OO.ui.CardLayout.prototype.setTabItem = function ( tabItem ) {
- this.tabItem = tabItem || null;
- if ( tabItem ) {
- this.setupTabItem();
- }
- return this;
-};
-
-/**
- * Set up the tab item.
- *
- * Use this method to customize the tab item (e.g., to add a label or tab level). To set or unset
- * the tab item itself (with a {@link OO.ui.TabOptionWidget tab option} or `null`), use
- * the #setTabItem method instead.
- *
- * @param {OO.ui.TabOptionWidget} tabItem Tab option widget to set up
- * @chainable
- */
-OO.ui.CardLayout.prototype.setupTabItem = function () {
- return this;
-};
-
-/**
- * Set the card to its 'active' state.
- *
- * Cards become active when they are shown in a index layout that is configured to display only one card at a time. Additional
- * CSS is applied to the tab item to reflect the card's active state. Outside of the index
- * context, setting the active state on a card does nothing.
- *
- * @param {boolean} value Card is active
- * @fires active
- */
-OO.ui.CardLayout.prototype.setActive = function ( active ) {
- active = !!active;
-
- if ( active !== this.active ) {
- this.active = active;
- this.$element.toggleClass( 'oo-ui-cardLayout-active', this.active );
- this.emit( 'active', this.active );
- }
-};
diff --git a/vendor/oojs/oojs-ui/src/layouts/FieldLayout.js b/vendor/oojs/oojs-ui/src/layouts/FieldLayout.js
deleted file mode 100644
index 86385741..00000000
--- a/vendor/oojs/oojs-ui/src/layouts/FieldLayout.js
+++ /dev/null
@@ -1,160 +0,0 @@
-/**
- * FieldLayouts are used with OO.ui.FieldsetLayout. Each FieldLayout requires a field-widget,
- * which is a widget that is specified by reference before any optional configuration settings.
- *
- * Field layouts can be configured with help text and/or labels. Labels are aligned in one of four ways:
- *
- * - **left**: The label is placed before the field-widget and aligned with the left margin.
- * A left-alignment is used for forms with many fields.
- * - **right**: The label is placed before the field-widget and aligned to the right margin.
- * A right-alignment is used for long but familiar forms which users tab through,
- * verifying the current field with a quick glance at the label.
- * - **top**: The label is placed above the field-widget. A top-alignment is used for brief forms
- * that users fill out from top to bottom.
- * - **inline**: The label is placed after the field-widget and aligned to the left.
- * An inline-alignment is best used with checkboxes or radio buttons.
- *
- * Help text is accessed via a help icon that appears in the upper right corner of the rendered field layout.
- * Please see the [OOjs UI documentation on MediaWiki] [1] for examples and more information.
- *
- * [1]: https://www.mediawiki.org/wiki/OOjs_UI/Layouts/Fields_and_Fieldsets
- * @class
- * @extends OO.ui.Layout
- * @mixins OO.ui.LabelElement
- *
- * @constructor
- * @param {OO.ui.Widget} fieldWidget Field widget
- * @param {Object} [config] Configuration options
- * @cfg {string} [align='left'] Alignment of the label: 'left', 'right', 'top' or 'inline'
- * @cfg {string} [help] Help text. When help text is specified, a help icon will appear
- * in the upper-right corner of the rendered field.
- */
-OO.ui.FieldLayout = function OoUiFieldLayout( fieldWidget, config ) {
- // Allow passing positional parameters inside the config object
- if ( OO.isPlainObject( fieldWidget ) && config === undefined ) {
- config = fieldWidget;
- fieldWidget = config.fieldWidget;
- }
-
- var hasInputWidget = fieldWidget instanceof OO.ui.InputWidget;
-
- // Configuration initialization
- config = $.extend( { align: 'left' }, config );
-
- // Parent constructor
- OO.ui.FieldLayout.super.call( this, config );
-
- // Mixin constructors
- OO.ui.LabelElement.call( this, config );
-
- // Properties
- this.fieldWidget = fieldWidget;
- this.$field = $( '<div>' );
- this.$body = $( '<' + ( hasInputWidget ? 'label' : 'div' ) + '>' );
- this.align = null;
- if ( config.help ) {
- this.popupButtonWidget = new OO.ui.PopupButtonWidget( {
- classes: [ 'oo-ui-fieldLayout-help' ],
- framed: false,
- icon: 'info'
- } );
-
- this.popupButtonWidget.getPopup().$body.append(
- $( '<div>' )
- .text( config.help )
- .addClass( 'oo-ui-fieldLayout-help-content' )
- );
- this.$help = this.popupButtonWidget.$element;
- } else {
- this.$help = $( [] );
- }
-
- // Events
- if ( hasInputWidget ) {
- this.$label.on( 'click', this.onLabelClick.bind( this ) );
- }
- this.fieldWidget.connect( this, { disable: 'onFieldDisable' } );
-
- // Initialization
- this.$element
- .addClass( 'oo-ui-fieldLayout' )
- .append( this.$help, this.$body );
- this.$body.addClass( 'oo-ui-fieldLayout-body' );
- this.$field
- .addClass( 'oo-ui-fieldLayout-field' )
- .toggleClass( 'oo-ui-fieldLayout-disable', this.fieldWidget.isDisabled() )
- .append( this.fieldWidget.$element );
-
- this.setAlignment( config.align );
-};
-
-/* Setup */
-
-OO.inheritClass( OO.ui.FieldLayout, OO.ui.Layout );
-OO.mixinClass( OO.ui.FieldLayout, OO.ui.LabelElement );
-
-/* Methods */
-
-/**
- * Handle field disable events.
- *
- * @private
- * @param {boolean} value Field is disabled
- */
-OO.ui.FieldLayout.prototype.onFieldDisable = function ( value ) {
- this.$element.toggleClass( 'oo-ui-fieldLayout-disabled', value );
-};
-
-/**
- * Handle label mouse click events.
- *
- * @private
- * @param {jQuery.Event} e Mouse click event
- */
-OO.ui.FieldLayout.prototype.onLabelClick = function () {
- this.fieldWidget.simulateLabelClick();
- return false;
-};
-
-/**
- * Get the widget contained by the field.
- *
- * @return {OO.ui.Widget} Field widget
- */
-OO.ui.FieldLayout.prototype.getField = function () {
- return this.fieldWidget;
-};
-
-/**
- * Set the field alignment mode.
- *
- * @private
- * @param {string} value Alignment mode, either 'left', 'right', 'top' or 'inline'
- * @chainable
- */
-OO.ui.FieldLayout.prototype.setAlignment = function ( value ) {
- if ( value !== this.align ) {
- // Default to 'left'
- if ( [ 'left', 'right', 'top', 'inline' ].indexOf( value ) === -1 ) {
- value = 'left';
- }
- // Reorder elements
- if ( value === 'inline' ) {
- this.$body.append( this.$field, this.$label );
- } else {
- this.$body.append( this.$label, this.$field );
- }
- // Set classes. The following classes can be used here:
- // * oo-ui-fieldLayout-align-left
- // * oo-ui-fieldLayout-align-right
- // * oo-ui-fieldLayout-align-top
- // * oo-ui-fieldLayout-align-inline
- if ( this.align ) {
- this.$element.removeClass( 'oo-ui-fieldLayout-align-' + this.align );
- }
- this.$element.addClass( 'oo-ui-fieldLayout-align-' + value );
- this.align = value;
- }
-
- return this;
-};
diff --git a/vendor/oojs/oojs-ui/src/layouts/FieldsetLayout.js b/vendor/oojs/oojs-ui/src/layouts/FieldsetLayout.js
deleted file mode 100644
index 1a21e8e1..00000000
--- a/vendor/oojs/oojs-ui/src/layouts/FieldsetLayout.js
+++ /dev/null
@@ -1,86 +0,0 @@
-/**
- * FieldsetLayouts are composed of one or more {@link OO.ui.FieldLayout FieldLayouts},
- * which each contain an individual widget and, optionally, a label. Each Fieldset can be
- * configured with a label as well. For more information and examples,
- * please see the [OOjs UI documentation on MediaWiki][1].
- *
- * @example
- * // Example of a fieldset layout
- * var input1 = new OO.ui.TextInputWidget( {
- * placeholder: 'A text input field'
- * } );
- *
- * var input2 = new OO.ui.TextInputWidget( {
- * placeholder: 'A text input field'
- * } );
- *
- * var fieldset = new OO.ui.FieldsetLayout( {
- * label: 'Example of a fieldset layout'
- * } );
- *
- * fieldset.addItems( [
- * new OO.ui.FieldLayout( input1, {
- * label: 'Field One'
- * } ),
- * new OO.ui.FieldLayout( input2, {
- * label: 'Field Two'
- * } )
- * ] );
- * $( 'body' ).append( fieldset.$element );
- *
- * [1]: https://www.mediawiki.org/wiki/OOjs_UI/Layouts/Fields_and_Fieldsets
- *
- * @class
- * @extends OO.ui.Layout
- * @mixins OO.ui.IconElement
- * @mixins OO.ui.LabelElement
- * @mixins OO.ui.GroupElement
- *
- * @constructor
- * @param {Object} [config] Configuration options
- * @cfg {OO.ui.FieldLayout[]} [items] An array of fields to add to the fieldset. See OO.ui.FieldLayout for more information about fields.
- */
-OO.ui.FieldsetLayout = function OoUiFieldsetLayout( config ) {
- // Configuration initialization
- config = config || {};
-
- // Parent constructor
- OO.ui.FieldsetLayout.super.call( this, config );
-
- // Mixin constructors
- OO.ui.IconElement.call( this, config );
- OO.ui.LabelElement.call( this, config );
- OO.ui.GroupElement.call( this, config );
-
- if ( config.help ) {
- this.popupButtonWidget = new OO.ui.PopupButtonWidget( {
- classes: [ 'oo-ui-fieldsetLayout-help' ],
- framed: false,
- icon: 'info'
- } );
-
- this.popupButtonWidget.getPopup().$body.append(
- $( '<div>' )
- .text( config.help )
- .addClass( 'oo-ui-fieldsetLayout-help-content' )
- );
- this.$help = this.popupButtonWidget.$element;
- } else {
- this.$help = $( [] );
- }
-
- // Initialization
- this.$element
- .addClass( 'oo-ui-fieldsetLayout' )
- .prepend( this.$help, this.$icon, this.$label, this.$group );
- if ( Array.isArray( config.items ) ) {
- this.addItems( config.items );
- }
-};
-
-/* Setup */
-
-OO.inheritClass( OO.ui.FieldsetLayout, OO.ui.Layout );
-OO.mixinClass( OO.ui.FieldsetLayout, OO.ui.IconElement );
-OO.mixinClass( OO.ui.FieldsetLayout, OO.ui.LabelElement );
-OO.mixinClass( OO.ui.FieldsetLayout, OO.ui.GroupElement );
diff --git a/vendor/oojs/oojs-ui/src/layouts/FormLayout.js b/vendor/oojs/oojs-ui/src/layouts/FormLayout.js
deleted file mode 100644
index a131c169..00000000
--- a/vendor/oojs/oojs-ui/src/layouts/FormLayout.js
+++ /dev/null
@@ -1,119 +0,0 @@
-/**
- * FormLayouts are used to wrap {@link OO.ui.FieldsetLayout FieldsetLayouts} when you intend to use browser-based
- * form submission for the fields instead of handling them in JavaScript. Form layouts can be configured with an
- * HTML form action, an encoding type, and a method using the #action, #enctype, and #method configs, respectively.
- * See the [OOjs UI documentation on MediaWiki] [1] for more information and examples.
- *
- * Only widgets from the {@link OO.ui.InputWidget InputWidget} family support form submission. It
- * includes standard form elements like {@link OO.ui.CheckboxInputWidget checkboxes}, {@link
- * OO.ui.RadioInputWidget radio buttons} and {@link OO.ui.TextInputWidget text fields}, as well as
- * some fancier controls. Some controls have both regular and InputWidget variants, for example
- * OO.ui.DropdownWidget and OO.ui.DropdownInputWidget – only the latter support form submission and
- * often have simplified APIs to match the capabilities of HTML forms.
- * See the [OOjs UI Inputs documentation on MediaWiki] [2] for more information about InputWidgets.
- *
- * [1]: https://www.mediawiki.org/wiki/OOjs_UI/Layouts/Forms
- * [2]: https://www.mediawiki.org/wiki/OOjs_UI/Widgets/Inputs
- *
- * @example
- * // Example of a form layout that wraps a fieldset layout
- * var input1 = new OO.ui.TextInputWidget( {
- * placeholder: 'Username'
- * } );
- * var input2 = new OO.ui.TextInputWidget( {
- * placeholder: 'Password',
- * type: 'password'
- * } );
- * var submit = new OO.ui.ButtonInputWidget( {
- * label: 'Submit'
- * } );
- *
- * var fieldset = new OO.ui.FieldsetLayout( {
- * label: 'A form layout'
- * } );
- * fieldset.addItems( [
- * new OO.ui.FieldLayout( input1, {
- * label: 'Username',
- * align: 'top'
- * } ),
- * new OO.ui.FieldLayout( input2, {
- * label: 'Password',
- * align: 'top'
- * } ),
- * new OO.ui.FieldLayout( submit )
- * ] );
- * var form = new OO.ui.FormLayout( {
- * items: [ fieldset ],
- * action: '/api/formhandler',
- * method: 'get'
- * } )
- * $( 'body' ).append( form.$element );
- *
- * @class
- * @extends OO.ui.Layout
- * @mixins OO.ui.GroupElement
- *
- * @constructor
- * @param {Object} [config] Configuration options
- * @cfg {string} [method] HTML form `method` attribute
- * @cfg {string} [action] HTML form `action` attribute
- * @cfg {string} [enctype] HTML form `enctype` attribute
- * @cfg {OO.ui.FieldsetLayout[]} [items] Fieldset layouts to add to the form layout.
- */
-OO.ui.FormLayout = function OoUiFormLayout( config ) {
- // Configuration initialization
- config = config || {};
-
- // Parent constructor
- OO.ui.FormLayout.super.call( this, config );
-
- // Mixin constructors
- OO.ui.GroupElement.call( this, $.extend( {}, config, { $group: this.$element } ) );
-
- // Events
- this.$element.on( 'submit', this.onFormSubmit.bind( this ) );
-
- // Initialization
- this.$element
- .addClass( 'oo-ui-formLayout' )
- .attr( {
- method: config.method,
- action: config.action,
- enctype: config.enctype
- } );
- if ( Array.isArray( config.items ) ) {
- this.addItems( config.items );
- }
-};
-
-/* Setup */
-
-OO.inheritClass( OO.ui.FormLayout, OO.ui.Layout );
-OO.mixinClass( OO.ui.FormLayout, OO.ui.GroupElement );
-
-/* Events */
-
-/**
- * A 'submit' event is emitted when the form is submitted.
- *
- * @event submit
- */
-
-/* Static Properties */
-
-OO.ui.FormLayout.static.tagName = 'form';
-
-/* Methods */
-
-/**
- * Handle form submit events.
- *
- * @private
- * @param {jQuery.Event} e Submit event
- * @fires submit
- */
-OO.ui.FormLayout.prototype.onFormSubmit = function () {
- if ( this.emit( 'submit' ) ) {
- return false;
- }
-};
diff --git a/vendor/oojs/oojs-ui/src/layouts/IndexLayout.js b/vendor/oojs/oojs-ui/src/layouts/IndexLayout.js
deleted file mode 100644
index 4cda00a9..00000000
--- a/vendor/oojs/oojs-ui/src/layouts/IndexLayout.js
+++ /dev/null
@@ -1,452 +0,0 @@
-/**
- * IndexLayouts contain {@link OO.ui.CardLayout card layouts} as well as
- * {@link OO.ui.TabSelectWidget tabs} that allow users to easily navigate through the cards and
- * select which one to display. By default, only one card is displayed at a time. When a user
- * navigates to a new card, the index layout automatically focuses on the first focusable element,
- * unless the default setting is changed.
- *
- * TODO: This class is similar to BookletLayout, we may want to refactor to reduce duplication
- *
- * @example
- * // Example of a IndexLayout that contains two CardLayouts.
- *
- * function CardOneLayout( name, config ) {
- * CardOneLayout.super.call( this, name, config );
- * this.$element.append( '<p>First card</p>' );
- * }
- * OO.inheritClass( CardOneLayout, OO.ui.CardLayout );
- * CardOneLayout.prototype.setupTabItem = function () {
- * this.tabItem.setLabel( 'Card One' );
- * };
- *
- * function CardTwoLayout( name, config ) {
- * CardTwoLayout.super.call( this, name, config );
- * this.$element.append( '<p>Second card</p>' );
- * }
- * OO.inheritClass( CardTwoLayout, OO.ui.CardLayout );
- * CardTwoLayout.prototype.setupTabItem = function () {
- * this.tabItem.setLabel( 'Card Two' );
- * };
- *
- * var card1 = new CardOneLayout( 'one' ),
- * card2 = new CardTwoLayout( 'two' );
- *
- * var index = new OO.ui.IndexLayout();
- *
- * index.addCards ( [ card1, card2 ] );
- * $( 'body' ).append( index.$element );
- *
- * @class
- * @extends OO.ui.MenuLayout
- *
- * @constructor
- * @param {Object} [config] Configuration options
- * @cfg {boolean} [continuous=false] Show all cards, one after another
- * @cfg {boolean} [autoFocus=true] Focus on the first focusable element when a new card is displayed.
- */
-OO.ui.IndexLayout = function OoUiIndexLayout( config ) {
- // Configuration initialization
- config = $.extend( {}, config, { menuPosition: 'top' } );
-
- // Parent constructor
- OO.ui.IndexLayout.super.call( this, config );
-
- // Properties
- this.currentCardName = null;
- this.cards = {};
- this.ignoreFocus = false;
- this.stackLayout = new OO.ui.StackLayout( { continuous: !!config.continuous } );
- this.$content.append( this.stackLayout.$element );
- this.autoFocus = config.autoFocus === undefined || !!config.autoFocus;
-
- this.tabSelectWidget = new OO.ui.TabSelectWidget();
- this.tabPanel = new OO.ui.PanelLayout();
- this.$menu.append( this.tabPanel.$element );
-
- this.toggleMenu( true );
-
- // Events
- this.stackLayout.connect( this, { set: 'onStackLayoutSet' } );
- this.tabSelectWidget.connect( this, { select: 'onTabSelectWidgetSelect' } );
- if ( this.autoFocus ) {
- // Event 'focus' does not bubble, but 'focusin' does
- this.stackLayout.$element.on( 'focusin', this.onStackLayoutFocus.bind( this ) );
- }
-
- // Initialization
- this.$element.addClass( 'oo-ui-indexLayout' );
- this.stackLayout.$element.addClass( 'oo-ui-indexLayout-stackLayout' );
- this.tabPanel.$element
- .addClass( 'oo-ui-indexLayout-tabPanel' )
- .append( this.tabSelectWidget.$element );
-};
-
-/* Setup */
-
-OO.inheritClass( OO.ui.IndexLayout, OO.ui.MenuLayout );
-
-/* Events */
-
-/**
- * A 'set' event is emitted when a card is {@link #setCard set} to be displayed by the index layout.
- * @event set
- * @param {OO.ui.CardLayout} card Current card
- */
-
-/**
- * An 'add' event is emitted when cards are {@link #addCards added} to the index layout.
- *
- * @event add
- * @param {OO.ui.CardLayout[]} card Added cards
- * @param {number} index Index cards were added at
- */
-
-/**
- * A 'remove' event is emitted when cards are {@link #clearCards cleared} or
- * {@link #removeCards removed} from the index.
- *
- * @event remove
- * @param {OO.ui.CardLayout[]} cards Removed cards
- */
-
-/* Methods */
-
-/**
- * Handle stack layout focus.
- *
- * @private
- * @param {jQuery.Event} e Focusin event
- */
-OO.ui.IndexLayout.prototype.onStackLayoutFocus = function ( e ) {
- var name, $target;
-
- // Find the card that an element was focused within
- $target = $( e.target ).closest( '.oo-ui-cardLayout' );
- for ( name in this.cards ) {
- // Check for card match, exclude current card to find only card changes
- if ( this.cards[ name ].$element[ 0 ] === $target[ 0 ] && name !== this.currentCardName ) {
- this.setCard( name );
- break;
- }
- }
-};
-
-/**
- * Handle stack layout set events.
- *
- * @private
- * @param {OO.ui.PanelLayout|null} card The card panel that is now the current panel
- */
-OO.ui.IndexLayout.prototype.onStackLayoutSet = function ( card ) {
- var layout = this;
- if ( card ) {
- card.scrollElementIntoView( { complete: function () {
- if ( layout.autoFocus ) {
- layout.focus();
- }
- } } );
- }
-};
-
-/**
- * Focus the first input in the current card.
- *
- * If no card is selected, the first selectable card will be selected.
- * If the focus is already in an element on the current card, nothing will happen.
- * @param {number} [itemIndex] A specific item to focus on
- */
-OO.ui.IndexLayout.prototype.focus = function ( itemIndex ) {
- var $input, card,
- items = this.stackLayout.getItems();
-
- if ( itemIndex !== undefined && items[ itemIndex ] ) {
- card = items[ itemIndex ];
- } else {
- card = this.stackLayout.getCurrentItem();
- }
-
- if ( !card ) {
- this.selectFirstSelectableCard();
- card = this.stackLayout.getCurrentItem();
- }
- if ( !card ) {
- return;
- }
- // Only change the focus if is not already in the current card
- if ( !card.$element.find( ':focus' ).length ) {
- $input = card.$element.find( ':input:first' );
- if ( $input.length ) {
- $input[ 0 ].focus();
- }
- }
-};
-
-/**
- * Find the first focusable input in the index layout and focus
- * on it.
- */
-OO.ui.IndexLayout.prototype.focusFirstFocusable = function () {
- var i, len,
- found = false,
- items = this.stackLayout.getItems(),
- checkAndFocus = function () {
- if ( OO.ui.isFocusableElement( $( this ) ) ) {
- $( this ).focus();
- found = true;
- return false;
- }
- };
-
- for ( i = 0, len = items.length; i < len; i++ ) {
- if ( found ) {
- break;
- }
- // Find all potentially focusable elements in the item
- // and check if they are focusable
- items[i].$element
- .find( 'input, select, textarea, button, object' )
- .each( checkAndFocus );
- }
-};
-
-/**
- * Handle tab widget select events.
- *
- * @private
- * @param {OO.ui.OptionWidget|null} item Selected item
- */
-OO.ui.IndexLayout.prototype.onTabSelectWidgetSelect = function ( item ) {
- if ( item ) {
- this.setCard( item.getData() );
- }
-};
-
-/**
- * Get the card closest to the specified card.
- *
- * @param {OO.ui.CardLayout} card Card to use as a reference point
- * @return {OO.ui.CardLayout|null} Card closest to the specified card
- */
-OO.ui.IndexLayout.prototype.getClosestCard = function ( card ) {
- var next, prev, level,
- cards = this.stackLayout.getItems(),
- index = $.inArray( card, cards );
-
- if ( index !== -1 ) {
- next = cards[ index + 1 ];
- prev = cards[ index - 1 ];
- // Prefer adjacent cards at the same level
- level = this.tabSelectWidget.getItemFromData( card.getName() ).getLevel();
- if (
- prev &&
- level === this.tabSelectWidget.getItemFromData( prev.getName() ).getLevel()
- ) {
- return prev;
- }
- if (
- next &&
- level === this.tabSelectWidget.getItemFromData( next.getName() ).getLevel()
- ) {
- return next;
- }
- }
- return prev || next || null;
-};
-
-/**
- * Get the tabs widget.
- *
- * @return {OO.ui.TabSelectWidget} Tabs widget
- */
-OO.ui.IndexLayout.prototype.getTabs = function () {
- return this.tabSelectWidget;
-};
-
-/**
- * Get a card by its symbolic name.
- *
- * @param {string} name Symbolic name of card
- * @return {OO.ui.CardLayout|undefined} Card, if found
- */
-OO.ui.IndexLayout.prototype.getCard = function ( name ) {
- return this.cards[ name ];
-};
-
-/**
- * Get the current card.
- *
- * @return {OO.ui.CardLayout|undefined} Current card, if found
- */
-OO.ui.IndexLayout.prototype.getCurrentCard = function () {
- var name = this.getCurrentCardName();
- return name ? this.getCard( name ) : undefined;
-};
-
-/**
- * Get the symbolic name of the current card.
- *
- * @return {string|null} Symbolic name of the current card
- */
-OO.ui.IndexLayout.prototype.getCurrentCardName = function () {
- return this.currentCardName;
-};
-
-/**
- * Add cards to the index layout
- *
- * When cards are added with the same names as existing cards, the existing cards will be
- * automatically removed before the new cards are added.
- *
- * @param {OO.ui.CardLayout[]} cards Cards to add
- * @param {number} index Index of the insertion point
- * @fires add
- * @chainable
- */
-OO.ui.IndexLayout.prototype.addCards = function ( cards, index ) {
- var i, len, name, card, item, currentIndex,
- stackLayoutCards = this.stackLayout.getItems(),
- remove = [],
- items = [];
-
- // Remove cards with same names
- for ( i = 0, len = cards.length; i < len; i++ ) {
- card = cards[ i ];
- name = card.getName();
-
- if ( Object.prototype.hasOwnProperty.call( this.cards, name ) ) {
- // Correct the insertion index
- currentIndex = $.inArray( this.cards[ name ], stackLayoutCards );
- if ( currentIndex !== -1 && currentIndex + 1 < index ) {
- index--;
- }
- remove.push( this.cards[ name ] );
- }
- }
- if ( remove.length ) {
- this.removeCards( remove );
- }
-
- // Add new cards
- for ( i = 0, len = cards.length; i < len; i++ ) {
- card = cards[ i ];
- name = card.getName();
- this.cards[ card.getName() ] = card;
- item = new OO.ui.TabOptionWidget( { data: name } );
- card.setTabItem( item );
- items.push( item );
- }
-
- if ( items.length ) {
- this.tabSelectWidget.addItems( items, index );
- this.selectFirstSelectableCard();
- }
- this.stackLayout.addItems( cards, index );
- this.emit( 'add', cards, index );
-
- return this;
-};
-
-/**
- * Remove the specified cards from the index layout.
- *
- * To remove all cards from the index, you may wish to use the #clearCards method instead.
- *
- * @param {OO.ui.CardLayout[]} cards An array of cards to remove
- * @fires remove
- * @chainable
- */
-OO.ui.IndexLayout.prototype.removeCards = function ( cards ) {
- var i, len, name, card,
- items = [];
-
- for ( i = 0, len = cards.length; i < len; i++ ) {
- card = cards[ i ];
- name = card.getName();
- delete this.cards[ name ];
- items.push( this.tabSelectWidget.getItemFromData( name ) );
- card.setTabItem( null );
- }
- if ( items.length ) {
- this.tabSelectWidget.removeItems( items );
- this.selectFirstSelectableCard();
- }
- this.stackLayout.removeItems( cards );
- this.emit( 'remove', cards );
-
- return this;
-};
-
-/**
- * Clear all cards from the index layout.
- *
- * To remove only a subset of cards from the index, use the #removeCards method.
- *
- * @fires remove
- * @chainable
- */
-OO.ui.IndexLayout.prototype.clearCards = function () {
- var i, len,
- cards = this.stackLayout.getItems();
-
- this.cards = {};
- this.currentCardName = null;
- this.tabSelectWidget.clearItems();
- for ( i = 0, len = cards.length; i < len; i++ ) {
- cards[ i ].setTabItem( null );
- }
- this.stackLayout.clearItems();
-
- this.emit( 'remove', cards );
-
- return this;
-};
-
-/**
- * Set the current card by symbolic name.
- *
- * @fires set
- * @param {string} name Symbolic name of card
- */
-OO.ui.IndexLayout.prototype.setCard = function ( name ) {
- var selectedItem,
- $focused,
- card = this.cards[ name ];
-
- if ( name !== this.currentCardName ) {
- selectedItem = this.tabSelectWidget.getSelectedItem();
- if ( selectedItem && selectedItem.getData() !== name ) {
- this.tabSelectWidget.selectItemByData( name );
- }
- if ( card ) {
- if ( this.currentCardName && this.cards[ this.currentCardName ] ) {
- this.cards[ this.currentCardName ].setActive( false );
- // Blur anything focused if the next card doesn't have anything focusable - this
- // is not needed if the next card has something focusable because once it is focused
- // this blur happens automatically
- if ( this.autoFocus && !card.$element.find( ':input' ).length ) {
- $focused = this.cards[ this.currentCardName ].$element.find( ':focus' );
- if ( $focused.length ) {
- $focused[ 0 ].blur();
- }
- }
- }
- this.currentCardName = name;
- this.stackLayout.setItem( card );
- card.setActive( true );
- this.emit( 'set', card );
- }
- }
-};
-
-/**
- * Select the first selectable card.
- *
- * @chainable
- */
-OO.ui.IndexLayout.prototype.selectFirstSelectableCard = function () {
- if ( !this.tabSelectWidget.getSelectedItem() ) {
- this.tabSelectWidget.selectItem( this.tabSelectWidget.getFirstSelectableItem() );
- }
-
- return this;
-};
diff --git a/vendor/oojs/oojs-ui/src/layouts/MenuLayout.js b/vendor/oojs/oojs-ui/src/layouts/MenuLayout.js
deleted file mode 100644
index 53937cc7..00000000
--- a/vendor/oojs/oojs-ui/src/layouts/MenuLayout.js
+++ /dev/null
@@ -1,156 +0,0 @@
-/**
- * MenuLayouts combine a menu and a content {@link OO.ui.PanelLayout panel}. The menu is positioned relative to the content (after, before, top, or bottom)
- * and its size is customized with the #menuSize config. The content area will fill all remaining space.
- *
- * @example
- * var menuLayout = new OO.ui.MenuLayout( {
- * position: 'top'
- * } ),
- * menuPanel = new OO.ui.PanelLayout( { padded: true, expanded: true, scrollable: true } ),
- * contentPanel = new OO.ui.PanelLayout( { padded: true, expanded: true, scrollable: true } ),
- * select = new OO.ui.SelectWidget( {
- * items: [
- * new OO.ui.OptionWidget( {
- * data: 'before',
- * label: 'Before',
- * } ),
- * new OO.ui.OptionWidget( {
- * data: 'after',
- * label: 'After',
- * } ),
- * new OO.ui.OptionWidget( {
- * data: 'top',
- * label: 'Top',
- * } ),
- * new OO.ui.OptionWidget( {
- * data: 'bottom',
- * label: 'Bottom',
- * } )
- * ]
- * } ).on( 'select', function ( item ) {
- * menuLayout.setMenuPosition( item.getData() );
- * } );
- *
- * menuLayout.$menu.append(
- * menuPanel.$element.append( '<b>Menu panel</b>', select.$element )
- * );
- * menuLayout.$content.append(
- * contentPanel.$element.append( '<b>Content panel</b>', '<p>Note that the menu is positioned relative to the content panel: top, bottom, after, before.</p>')
- * );
- * $( 'body' ).append( menuLayout.$element );
- *
- * If menu size needs to be overridden, it can be accomplished using CSS similar to the snippet
- * below. MenuLayout's CSS will override the appropriate values with 'auto' or '0' to display the
- * menu correctly. If `menuPosition` is known beforehand, CSS rules corresponding to other positions
- * may be omitted.
- *
- * .oo-ui-menuLayout-menu {
- * height: 200px;
- * width: 200px;
- * }
- * .oo-ui-menuLayout-content {
- * top: 200px;
- * left: 200px;
- * right: 200px;
- * bottom: 200px;
- * }
- *
- * @class
- * @extends OO.ui.Layout
- *
- * @constructor
- * @param {Object} [config] Configuration options
- * @cfg {boolean} [showMenu=true] Show menu
- * @cfg {string} [menuPosition='before'] Position of menu: `top`, `after`, `bottom` or `before`
- */
-OO.ui.MenuLayout = function OoUiMenuLayout( config ) {
- // Configuration initialization
- config = $.extend( {
- showMenu: true,
- menuPosition: 'before'
- }, config );
-
- // Parent constructor
- OO.ui.MenuLayout.super.call( this, config );
-
- /**
- * Menu DOM node
- *
- * @property {jQuery}
- */
- this.$menu = $( '<div>' );
- /**
- * Content DOM node
- *
- * @property {jQuery}
- */
- this.$content = $( '<div>' );
-
- // Initialization
- this.$menu
- .addClass( 'oo-ui-menuLayout-menu' );
- this.$content.addClass( 'oo-ui-menuLayout-content' );
- this.$element
- .addClass( 'oo-ui-menuLayout' )
- .append( this.$content, this.$menu );
- this.setMenuPosition( config.menuPosition );
- this.toggleMenu( config.showMenu );
-};
-
-/* Setup */
-
-OO.inheritClass( OO.ui.MenuLayout, OO.ui.Layout );
-
-/* Methods */
-
-/**
- * Toggle menu.
- *
- * @param {boolean} showMenu Show menu, omit to toggle
- * @chainable
- */
-OO.ui.MenuLayout.prototype.toggleMenu = function ( showMenu ) {
- showMenu = showMenu === undefined ? !this.showMenu : !!showMenu;
-
- if ( this.showMenu !== showMenu ) {
- this.showMenu = showMenu;
- this.$element
- .toggleClass( 'oo-ui-menuLayout-showMenu', this.showMenu )
- .toggleClass( 'oo-ui-menuLayout-hideMenu', !this.showMenu );
- }
-
- return this;
-};
-
-/**
- * Check if menu is visible
- *
- * @return {boolean} Menu is visible
- */
-OO.ui.MenuLayout.prototype.isMenuVisible = function () {
- return this.showMenu;
-};
-
-/**
- * Set menu position.
- *
- * @param {string} position Position of menu, either `top`, `after`, `bottom` or `before`
- * @throws {Error} If position value is not supported
- * @chainable
- */
-OO.ui.MenuLayout.prototype.setMenuPosition = function ( position ) {
- this.$element.removeClass( 'oo-ui-menuLayout-' + this.menuPosition );
- this.menuPosition = position;
- this.$element.addClass( 'oo-ui-menuLayout-' + position );
-
- return this;
-};
-
-/**
- * Get menu position.
- *
- * @return {string} Menu position
- */
-OO.ui.MenuLayout.prototype.getMenuPosition = function () {
- return this.menuPosition;
-};
diff --git a/vendor/oojs/oojs-ui/src/layouts/PageLayout.js b/vendor/oojs/oojs-ui/src/layouts/PageLayout.js
deleted file mode 100644
index 4753b7db..00000000
--- a/vendor/oojs/oojs-ui/src/layouts/PageLayout.js
+++ /dev/null
@@ -1,138 +0,0 @@
-/**
- * PageLayouts are used within {@link OO.ui.BookletLayout booklet layouts} to create pages that users can select and display
- * from the booklet's optional {@link OO.ui.OutlineSelectWidget outline} navigation. Pages are usually not instantiated directly,
- * rather extended to include the required content and functionality.
- *
- * Each page must have a unique symbolic name, which is passed to the constructor. In addition, the page's outline
- * item is customized (with a label, outline level, etc.) using the #setupOutlineItem method. See
- * {@link OO.ui.BookletLayout BookletLayout} for an example.
- *
- * @class
- * @extends OO.ui.PanelLayout
- *
- * @constructor
- * @param {string} name Unique symbolic name of page
- * @param {Object} [config] Configuration options
- */
-OO.ui.PageLayout = function OoUiPageLayout( name, config ) {
- // Allow passing positional parameters inside the config object
- if ( OO.isPlainObject( name ) && config === undefined ) {
- config = name;
- name = config.name;
- }
-
- // Configuration initialization
- config = $.extend( { scrollable: true }, config );
-
- // Parent constructor
- OO.ui.PageLayout.super.call( this, config );
-
- // Properties
- this.name = name;
- this.outlineItem = null;
- this.active = false;
-
- // Initialization
- this.$element.addClass( 'oo-ui-pageLayout' );
-};
-
-/* Setup */
-
-OO.inheritClass( OO.ui.PageLayout, OO.ui.PanelLayout );
-
-/* Events */
-
-/**
- * An 'active' event is emitted when the page becomes active. Pages become active when they are
- * shown in a booklet layout that is configured to display only one page at a time.
- *
- * @event active
- * @param {boolean} active Page is active
- */
-
-/* Methods */
-
-/**
- * Get the symbolic name of the page.
- *
- * @return {string} Symbolic name of page
- */
-OO.ui.PageLayout.prototype.getName = function () {
- return this.name;
-};
-
-/**
- * Check if page is active.
- *
- * Pages become active when they are shown in a {@link OO.ui.BookletLayout booklet layout} that is configured to display
- * only one page at a time. Additional CSS is applied to the page's outline item to reflect the active state.
- *
- * @return {boolean} Page is active
- */
-OO.ui.PageLayout.prototype.isActive = function () {
- return this.active;
-};
-
-/**
- * Get outline item.
- *
- * The outline item allows users to access the page from the booklet's outline
- * navigation. The outline item itself can be customized (with a label, level, etc.) using the #setupOutlineItem method.
- *
- * @return {OO.ui.OutlineOptionWidget|null} Outline option widget
- */
-OO.ui.PageLayout.prototype.getOutlineItem = function () {
- return this.outlineItem;
-};
-
-/**
- * Set or unset the outline item.
- *
- * Specify an {@link OO.ui.OutlineOptionWidget outline option} to set it,
- * or `null` to clear the outline item. To customize the outline item itself (e.g., to set a label or outline
- * level), use #setupOutlineItem instead of this method.
- *
- * @param {OO.ui.OutlineOptionWidget|null} outlineItem Outline option widget, null to clear
- * @chainable
- */
-OO.ui.PageLayout.prototype.setOutlineItem = function ( outlineItem ) {
- this.outlineItem = outlineItem || null;
- if ( outlineItem ) {
- this.setupOutlineItem();
- }
- return this;
-};
-
-/**
- * Set up the outline item.
- *
- * Use this method to customize the outline item (e.g., to add a label or outline level). To set or unset
- * the outline item itself (with an {@link OO.ui.OutlineOptionWidget outline option} or `null`), use
- * the #setOutlineItem method instead.
- *
- * @param {OO.ui.OutlineOptionWidget} outlineItem Outline option widget to set up
- * @chainable
- */
-OO.ui.PageLayout.prototype.setupOutlineItem = function () {
- return this;
-};
-
-/**
- * Set the page to its 'active' state.
- *
- * Pages become active when they are shown in a booklet layout that is configured to display only one page at a time. Additional
- * CSS is applied to the outline item to reflect the page's active state. Outside of the booklet
- * context, setting the active state on a page does nothing.
- *
- * @param {boolean} value Page is active
- * @fires active
- */
-OO.ui.PageLayout.prototype.setActive = function ( active ) {
- active = !!active;
-
- if ( active !== this.active ) {
- this.active = active;
- this.$element.toggleClass( 'oo-ui-pageLayout-active', active );
- this.emit( 'active', this.active );
- }
-};
diff --git a/vendor/oojs/oojs-ui/src/layouts/PanelLayout.js b/vendor/oojs/oojs-ui/src/layouts/PanelLayout.js
deleted file mode 100644
index 9183f597..00000000
--- a/vendor/oojs/oojs-ui/src/layouts/PanelLayout.js
+++ /dev/null
@@ -1,55 +0,0 @@
-/**
- * PanelLayouts expand to cover the entire area of their parent. They can be configured with scrolling, padding,
- * and a frame, and are often used together with {@link OO.ui.StackLayout StackLayouts}.
- *
- * @example
- * // Example of a panel layout
- * var panel = new OO.ui.PanelLayout( {
- * expanded: false,
- * framed: true,
- * padded: true,
- * $content: $( '<p>A panel layout with padding and a frame.</p>' )
- * } );
- * $( 'body' ).append( panel.$element );
- *
- * @class
- * @extends OO.ui.Layout
- *
- * @constructor
- * @param {Object} [config] Configuration options
- * @cfg {boolean} [scrollable=false] Allow vertical scrolling
- * @cfg {boolean} [padded=false] Add padding between the content and the edges of the panel.
- * @cfg {boolean} [expanded=true] Expand the panel to fill the entire parent element.
- * @cfg {boolean} [framed=false] Render the panel with a frame to visually separate it from outside content.
- */
-OO.ui.PanelLayout = function OoUiPanelLayout( config ) {
- // Configuration initialization
- config = $.extend( {
- scrollable: false,
- padded: false,
- expanded: true,
- framed: false
- }, config );
-
- // Parent constructor
- OO.ui.PanelLayout.super.call( this, config );
-
- // Initialization
- this.$element.addClass( 'oo-ui-panelLayout' );
- if ( config.scrollable ) {
- this.$element.addClass( 'oo-ui-panelLayout-scrollable' );
- }
- if ( config.padded ) {
- this.$element.addClass( 'oo-ui-panelLayout-padded' );
- }
- if ( config.expanded ) {
- this.$element.addClass( 'oo-ui-panelLayout-expanded' );
- }
- if ( config.framed ) {
- this.$element.addClass( 'oo-ui-panelLayout-framed' );
- }
-};
-
-/* Setup */
-
-OO.inheritClass( OO.ui.PanelLayout, OO.ui.Layout );
diff --git a/vendor/oojs/oojs-ui/src/layouts/StackLayout.js b/vendor/oojs/oojs-ui/src/layouts/StackLayout.js
deleted file mode 100644
index 58f35d31..00000000
--- a/vendor/oojs/oojs-ui/src/layouts/StackLayout.js
+++ /dev/null
@@ -1,214 +0,0 @@
-/**
- * StackLayouts contain a series of {@link OO.ui.PanelLayout panel layouts}. By default, only one panel is displayed
- * at a time, though the stack layout can also be configured to show all contained panels, one after another,
- * by setting the #continuous option to 'true'.
- *
- * @example
- * // A stack layout with two panels, configured to be displayed continously
- * var myStack = new OO.ui.StackLayout( {
- * items: [
- * new OO.ui.PanelLayout( {
- * $content: $( '<p>Panel One</p>' ),
- * padded: true,
- * framed: true
- * } ),
- * new OO.ui.PanelLayout( {
- * $content: $( '<p>Panel Two</p>' ),
- * padded: true,
- * framed: true
- * } )
- * ],
- * continuous: true
- * } );
- * $( 'body' ).append( myStack.$element );
- *
- * @class
- * @extends OO.ui.PanelLayout
- * @mixins OO.ui.GroupElement
- *
- * @constructor
- * @param {Object} [config] Configuration options
- * @cfg {boolean} [continuous=false] Show all panels, one after another. By default, only one panel is displayed at a time.
- * @cfg {OO.ui.Layout[]} [items] Panel layouts to add to the stack layout.
- */
-OO.ui.StackLayout = function OoUiStackLayout( config ) {
- // Configuration initialization
- config = $.extend( { scrollable: true }, config );
-
- // Parent constructor
- OO.ui.StackLayout.super.call( this, config );
-
- // Mixin constructors
- OO.ui.GroupElement.call( this, $.extend( {}, config, { $group: this.$element } ) );
-
- // Properties
- this.currentItem = null;
- this.continuous = !!config.continuous;
-
- // Initialization
- this.$element.addClass( 'oo-ui-stackLayout' );
- if ( this.continuous ) {
- this.$element.addClass( 'oo-ui-stackLayout-continuous' );
- }
- if ( Array.isArray( config.items ) ) {
- this.addItems( config.items );
- }
-};
-
-/* Setup */
-
-OO.inheritClass( OO.ui.StackLayout, OO.ui.PanelLayout );
-OO.mixinClass( OO.ui.StackLayout, OO.ui.GroupElement );
-
-/* Events */
-
-/**
- * A 'set' event is emitted when panels are {@link #addItems added}, {@link #removeItems removed},
- * {@link #clearItems cleared} or {@link #setItem displayed}.
- *
- * @event set
- * @param {OO.ui.Layout|null} item Current panel or `null` if no panel is shown
- */
-
-/* Methods */
-
-/**
- * Get the current panel.
- *
- * @return {OO.ui.Layout|null}
- */
-OO.ui.StackLayout.prototype.getCurrentItem = function () {
- return this.currentItem;
-};
-
-/**
- * Unset the current item.
- *
- * @private
- * @param {OO.ui.StackLayout} layout
- * @fires set
- */
-OO.ui.StackLayout.prototype.unsetCurrentItem = function () {
- var prevItem = this.currentItem;
- if ( prevItem === null ) {
- return;
- }
-
- this.currentItem = null;
- this.emit( 'set', null );
-};
-
-/**
- * Add panel layouts to the stack layout.
- *
- * Panels will be added to the end of the stack layout array unless the optional index parameter specifies a different
- * insertion point. Adding a panel that is already in the stack will move it to the end of the array or the point specified
- * by the index.
- *
- * @param {OO.ui.Layout[]} items Panels to add
- * @param {number} [index] Index of the insertion point
- * @chainable
- */
-OO.ui.StackLayout.prototype.addItems = function ( items, index ) {
- // Update the visibility
- this.updateHiddenState( items, this.currentItem );
-
- // Mixin method
- OO.ui.GroupElement.prototype.addItems.call( this, items, index );
-
- if ( !this.currentItem && items.length ) {
- this.setItem( items[ 0 ] );
- }
-
- return this;
-};
-
-/**
- * Remove the specified panels from the stack layout.
- *
- * Removed panels are detached from the DOM, not removed, so that they may be reused. To remove all panels,
- * you may wish to use the #clearItems method instead.
- *
- * @param {OO.ui.Layout[]} items Panels to remove
- * @chainable
- * @fires set
- */
-OO.ui.StackLayout.prototype.removeItems = function ( items ) {
- // Mixin method
- OO.ui.GroupElement.prototype.removeItems.call( this, items );
-
- if ( $.inArray( this.currentItem, items ) !== -1 ) {
- if ( this.items.length ) {
- this.setItem( this.items[ 0 ] );
- } else {
- this.unsetCurrentItem();
- }
- }
-
- return this;
-};
-
-/**
- * Clear all panels from the stack layout.
- *
- * Cleared panels are detached from the DOM, not removed, so that they may be reused. To remove only
- * a subset of panels, use the #removeItems method.
- *
- * @chainable
- * @fires set
- */
-OO.ui.StackLayout.prototype.clearItems = function () {
- this.unsetCurrentItem();
- OO.ui.GroupElement.prototype.clearItems.call( this );
-
- return this;
-};
-
-/**
- * Show the specified panel.
- *
- * If another panel is currently displayed, it will be hidden.
- *
- * @param {OO.ui.Layout} item Panel to show
- * @chainable
- * @fires set
- */
-OO.ui.StackLayout.prototype.setItem = function ( item ) {
- if ( item !== this.currentItem ) {
- this.updateHiddenState( this.items, item );
-
- if ( $.inArray( item, this.items ) !== -1 ) {
- this.currentItem = item;
- this.emit( 'set', item );
- } else {
- this.unsetCurrentItem();
- }
- }
-
- return this;
-};
-
-/**
- * Update the visibility of all items in case of non-continuous view.
- *
- * Ensure all items are hidden except for the selected one.
- * This method does nothing when the stack is continuous.
- *
- * @private
- * @param {OO.ui.Layout[]} items Item list iterate over
- * @param {OO.ui.Layout} [selectedItem] Selected item to show
- */
-OO.ui.StackLayout.prototype.updateHiddenState = function ( items, selectedItem ) {
- var i, len;
-
- if ( !this.continuous ) {
- for ( i = 0, len = items.length; i < len; i++ ) {
- if ( !selectedItem || selectedItem !== items[ i ] ) {
- items[ i ].$element.addClass( 'oo-ui-element-hidden' );
- }
- }
- if ( selectedItem ) {
- selectedItem.$element.removeClass( 'oo-ui-element-hidden' );
- }
- }
-};
diff --git a/vendor/oojs/oojs-ui/src/outro.js.txt b/vendor/oojs/oojs-ui/src/outro.js.txt
deleted file mode 100644
index 4cc1e390..00000000
--- a/vendor/oojs/oojs-ui/src/outro.js.txt
+++ /dev/null
@@ -1 +0,0 @@
-}( OO ) );
diff --git a/vendor/oojs/oojs-ui/src/styles/Dialog.less b/vendor/oojs/oojs-ui/src/styles/Dialog.less
deleted file mode 100644
index 391cefda..00000000
--- a/vendor/oojs/oojs-ui/src/styles/Dialog.less
+++ /dev/null
@@ -1,35 +0,0 @@
-@import 'common';
-
-.oo-ui-dialog {
- &-content {
- > .oo-ui-window {
- &-head,
- &-body,
- &-foot {
- position: absolute;
- left: 0;
- right: 0;
- overflow: hidden;
- .oo-ui-box-sizing(border-box);
- }
-
- &-head {
- z-index: 1;
- top: 0;
- }
-
- &-body {
- z-index: 2;
- top: 0;
- bottom: 0;
- }
-
- &-foot {
- z-index: 1;
- bottom: 0;
- }
- }
- }
-
- .theme-oo-ui-dialog();
-}
diff --git a/vendor/oojs/oojs-ui/src/styles/Element.less b/vendor/oojs/oojs-ui/src/styles/Element.less
deleted file mode 100644
index f8f3389f..00000000
--- a/vendor/oojs/oojs-ui/src/styles/Element.less
+++ /dev/null
@@ -1,9 +0,0 @@
-@import 'common';
-
-.oo-ui-element {
- &-hidden {
- display: none !important;
- }
-
- .theme-oo-ui-element();
-}
diff --git a/vendor/oojs/oojs-ui/src/styles/Layout.less b/vendor/oojs/oojs-ui/src/styles/Layout.less
deleted file mode 100644
index d1ed2f7e..00000000
--- a/vendor/oojs/oojs-ui/src/styles/Layout.less
+++ /dev/null
@@ -1,5 +0,0 @@
-@import 'common';
-
-.oo-ui-layout {
- .theme-oo-ui-layout();
-}
diff --git a/vendor/oojs/oojs-ui/src/styles/Tool.less b/vendor/oojs/oojs-ui/src/styles/Tool.less
deleted file mode 100644
index 86cf6c38..00000000
--- a/vendor/oojs/oojs-ui/src/styles/Tool.less
+++ /dev/null
@@ -1,5 +0,0 @@
-@import 'common';
-
-.oo-ui-tool {
- .theme-oo-ui-tool();
-}
diff --git a/vendor/oojs/oojs-ui/src/styles/ToolGroup.less b/vendor/oojs/oojs-ui/src/styles/ToolGroup.less
deleted file mode 100644
index 4ba55ea3..00000000
--- a/vendor/oojs/oojs-ui/src/styles/ToolGroup.less
+++ /dev/null
@@ -1,21 +0,0 @@
-@import 'common';
-
-.oo-ui-toolGroup {
- display: inline-block;
- vertical-align: middle;
-
- &-empty {
- display: none;
- }
-
- .oo-ui-tool-link {
- text-decoration: none;
-
- .oo-ui-iconElement-icon {
- background-position: center center;
- background-repeat: no-repeat;
- }
- }
-
- .theme-oo-ui-toolGroup();
-}
diff --git a/vendor/oojs/oojs-ui/src/styles/Toolbar.less b/vendor/oojs/oojs-ui/src/styles/Toolbar.less
deleted file mode 100644
index 42eeeaa5..00000000
--- a/vendor/oojs/oojs-ui/src/styles/Toolbar.less
+++ /dev/null
@@ -1,52 +0,0 @@
-@import 'common';
-
-.oo-ui-toolbar {
- clear: both;
-
- &-bar {
- line-height: 1em;
- position: relative;
- }
-
- &-actions {
- float: right;
-
- .oo-ui-toolbar {
- display: inline-block;
- }
- }
-
- &-tools {
- display: inline;
- white-space: nowrap;
-
- .oo-ui-toolbar-narrow & {
- white-space: normal;
- }
-
- // Tools like PopupToolGroup can have a lot of content, which should be wrapped normally
- .oo-ui-tool {
- white-space: normal;
- }
- }
-
- &-tools,
- &-actions,
- &-shadow {
- .oo-ui-unselectable();
- }
-
- &-actions .oo-ui-popupWidget {
- .oo-ui-selectable();
- }
-
- &-shadow {
- background-position: left top;
- background-repeat: repeat-x;
- position: absolute;
- width: 100%;
- pointer-events: none;
- }
-
- .theme-oo-ui-toolbar();
-}
diff --git a/vendor/oojs/oojs-ui/src/styles/Widget.less b/vendor/oojs/oojs-ui/src/styles/Widget.less
deleted file mode 100644
index 107bc424..00000000
--- a/vendor/oojs/oojs-ui/src/styles/Widget.less
+++ /dev/null
@@ -1,5 +0,0 @@
-@import 'common';
-
-.oo-ui-widget {
- .theme-oo-ui-widget();
-}
diff --git a/vendor/oojs/oojs-ui/src/styles/Window.less b/vendor/oojs/oojs-ui/src/styles/Window.less
deleted file mode 100644
index 34064684..00000000
--- a/vendor/oojs/oojs-ui/src/styles/Window.less
+++ /dev/null
@@ -1,32 +0,0 @@
-@import 'common';
-
-.oo-ui-window {
- &-frame {
- .oo-ui-box-sizing(border-box);
- }
-
- // Content div takes focus when opened, so hide outline
- &-content:focus {
- outline: none;
- }
-
- &-head,
- &-foot {
- .oo-ui-unselectable();
- }
-
- &-body {
- margin: 0;
- padding: 0;
- background: none;
- }
-
- &-overlay {
- position: absolute;
- top: 0;
- /* @noflip */
- left: 0;
- }
-
- .theme-oo-ui-window();
-}
diff --git a/vendor/oojs/oojs-ui/src/styles/WindowManager.less b/vendor/oojs/oojs-ui/src/styles/WindowManager.less
deleted file mode 100644
index bd1e2ab1..00000000
--- a/vendor/oojs/oojs-ui/src/styles/WindowManager.less
+++ /dev/null
@@ -1,39 +0,0 @@
-@import 'common';
-
-.oo-ui-windowManager {
- &-modal > .oo-ui-dialog {
- position: fixed;
- width: 0;
- height: 0;
- overflow: hidden;
-
- &.oo-ui-window-active {
- width: auto;
- height: auto;
- top: 0;
- right: 0;
- bottom: 0;
- left: 0;
- padding: 1em;
- }
-
- &.oo-ui-window-setup > .oo-ui-window-frame {
- position: absolute;
- right: 0;
- left: 0;
- margin: auto;
- overflow: hidden;
- max-width: 100%;
- max-height: 100%;
- }
- }
-
- &-fullscreen > .oo-ui-dialog > .oo-ui-window-frame {
- width: 100%;
- height: 100%;
- top: 0;
- bottom: 0;
- }
-
- .theme-oo-ui-windowManager();
-}
diff --git a/vendor/oojs/oojs-ui/src/styles/common.less b/vendor/oojs/oojs-ui/src/styles/common.less
deleted file mode 100644
index 9663580f..00000000
--- a/vendor/oojs/oojs-ui/src/styles/common.less
+++ /dev/null
@@ -1,102 +0,0 @@
-@import 'theme';
-
-// Variables
-
-// @oo-ui-default-image-ext set during build
-// @oo-ui-distribution set during build
-@oo-ui-default-image-path: 'images';
-
-// Mixins
-
-.oo-ui-background-image( @url ) {
- background-image: e('/* @embed */') url(~'@{url}');
-}
-
-.oo-ui-background-image-svg2( @svg, @fallback ) when ( @oo-ui-distribution = mixed ) {
- background-image: url(@fallback);
- background-image: -webkit-linear-gradient(transparent, transparent), e('/* @embed */') url(@svg);
- background-image: linear-gradient(transparent, transparent), e('/* @embed */') url(@svg);
- background-image: -o-linear-gradient(transparent, transparent), url(@fallback);
-}
-.oo-ui-background-image-svg2( @svg, @fallback ) when ( @oo-ui-distribution = vector ) {
- .oo-ui-background-image(@svg);
-}
-.oo-ui-background-image-svg2( @svg, @fallback ) when ( @oo-ui-distribution = raster ) {
- .oo-ui-background-image(@fallback);
-}
-
-.oo-ui-background-image-svg( @url-without-extension ) {
- @svg: '@{url-without-extension}.svg';
- @fallback: '@{url-without-extension}.@{oo-ui-default-image-ext}';
- .oo-ui-background-image-svg2(@svg, @fallback);
-}
-
-.oo-ui-force-webkit-gpu() {
- -webkit-transform: translate3d(0, 0, 0);
-}
-
-.oo-ui-animation( @value1, @value2: X, ... ) {
- @value: ~`"@{arguments}".replace(/[\[\]]|\,\sX/g, '')`;
- -webkit-animation: @value;
- -moz-animation: @value;
- -ms-animation: @value;
- -o-animation: @value;
- animation: @value;
-}
-
-.oo-ui-transition( @value1, @value2: X, ... ) {
- @value: ~`"@{arguments}".replace(/[\[\]]|\,\sX/g, '')`;
- -webkit-transition: @value;
- -moz-transition: @value;
- -ms-transition: @value;
- -o-transition: @value;
- transition: @value;
-}
-
-.oo-ui-transform( @string ) {
- -webkit-transform: @string;
- -moz-transform: @string;
- -ms-transform: @string;
- -o-transform: @string;
- transform: @string;
-}
-
-.oo-ui-box-sizing( @type: border-box ) {
- -webkit-box-sizing: @type;
- -moz-box-sizing: @type;
- box-sizing: @type;
-}
-
-.oo-ui-vertical-gradient( @start: #EEE, @stop: #FFF ) {
- background: mix(@start, @stop, 50%);
- filter: e(%("progid:DXImageTransform.Microsoft.gradient(GradientType=0, startColorstr='%d', endColorstr='%d')", @start, @stop));
- background-image: -webkit-gradient(linear, right top, right bottom, color-stop(0%, @start), color-stop(100%, @stop));
- background-image: -webkit-linear-gradient(top, @start 0%, @stop 100%);
- background-image: -moz-linear-gradient(top, @start 0%, @stop 100%);
- background-image: -ms-linear-gradient(top, @start 0%, @stop 100%);
- background-image: -o-linear-gradient(top, @start 0%, @stop 100%);
- background-image: linear-gradient(top, @start 0%, @stop 100%);
-}
-
-.oo-ui-unselectable() {
- -webkit-touch-callout: none;
- -webkit-user-select: none;
- -moz-user-select: none;
- -ms-user-select: none;
- user-select: none;
-}
-
-.oo-ui-selectable() {
- -webkit-touch-callout: default;
- -webkit-user-select: all;
- -moz-user-select: all;
- -ms-user-select: all;
- user-select: all;
-}
-
-.oo-ui-inline-spacing( @spacing, @cancelled-spacing: 0 ) {
- margin-right: @spacing;
- &:last-child {
- margin-right: @cancelled-spacing;
- }
-}
diff --git a/vendor/oojs/oojs-ui/src/styles/core.less b/vendor/oojs/oojs-ui/src/styles/core.less
deleted file mode 100644
index fc1c91f8..00000000
--- a/vendor/oojs/oojs-ui/src/styles/core.less
+++ /dev/null
@@ -1,114 +0,0 @@
-//
-// Base styles.
-//
-// Themes should include this file after defining their variables and mixins.
-//
-
-@import 'common';
-
-/* @noflip */
-.oo-ui-rtl {
- direction: rtl;
-}
-
-/* @noflip */
-.oo-ui-ltr {
- direction: ltr;
-}
-
-@import 'Element.less';
-@import 'elements/ButtonElement.less';
-@import 'elements/ClippableElement.less';
-@import 'elements/FlaggedElement.less';
-@import 'elements/DraggableElement.less';
-@import 'elements/DraggableGroupElement.less';
-@import 'elements/GroupElement.less';
-@import 'elements/IconElement.less';
-@import 'elements/IndicatorElement.less';
-@import 'elements/LabelElement.less';
-@import 'elements/LookupElement.less';
-@import 'elements/PopupElement.less';
-@import 'elements/TabIndexedElement.less';
-@import 'elements/TitledElement.less';
-
-@import 'Layout.less';
-@import 'layouts/BookletLayout.less';
-@import 'layouts/IndexLayout.less';
-@import 'layouts/FieldLayout.less';
-@import 'layouts/ActionFieldLayout.less';
-@import 'layouts/FieldsetLayout.less';
-@import 'layouts/FormLayout.less';
-@import 'layouts/MenuLayout.less';
-@import 'layouts/PanelLayout.less';
-@import 'layouts/CardLayout.less';
-@import 'layouts/PageLayout.less';
-@import 'layouts/StackLayout.less';
-
-@import 'Tool.less';
-@import 'tools/PopupTool.less';
-@import 'tools/ToolGroupTool.less';
-
-@import 'ToolGroup.less';
-@import 'toolgroups/BarToolGroup.less';
-@import 'toolgroups/PopupToolGroup.less';
-@import 'toolgroups/ListToolGroup.less';
-@import 'toolgroups/MenuToolGroup.less';
-
-@import 'Toolbar.less';
-
-@import 'Widget.less';
-@import 'widgets/SelectWidget.less';
-@import 'widgets/OptionWidget.less';
-@import 'widgets/DecoratedOptionWidget.less';
-@import 'widgets/ButtonSelectWidget.less';
-@import 'widgets/RadioSelectWidget.less';
-@import 'widgets/ButtonOptionWidget.less';
-@import 'widgets/RadioOptionWidget.less';
-
-@import 'widgets/LabelWidget.less';
-@import 'widgets/IconWidget.less';
-@import 'widgets/IndicatorWidget.less';
-
-@import 'widgets/ButtonWidget.less';
-@import 'widgets/ButtonGroupWidget.less';
-
-@import 'widgets/ToggleWidget.less';
-@import 'widgets/ToggleButtonWidget.less';
-@import 'widgets/ToggleSwitchWidget.less';
-
-@import 'widgets/ProgressBarWidget.less';
-
-@import 'widgets/ActionWidget.less';
-
-@import 'widgets/PopupWidget.less';
-@import 'widgets/PopupButtonWidget.less';
-
-@import 'widgets/InputWidget.less';
-@import 'widgets/ButtonInputWidget.less';
-@import 'widgets/CheckboxInputWidget.less';
-@import 'widgets/DropdownInputWidget.less';
-@import 'widgets/RadioInputWidget.less';
-@import 'widgets/TextInputWidget.less';
-
-@import 'widgets/MenuSelectWidget.less';
-@import 'widgets/MenuOptionWidget.less';
-@import 'widgets/MenuSectionOptionWidget.less';
-@import 'widgets/TextInputMenuSelectWidget.less';
-@import 'widgets/DropdownWidget.less';
-
-@import 'widgets/OutlineSelectWidget.less';
-@import 'widgets/OutlineOptionWidget.less';
-@import 'widgets/OutlineControlsWidget.less';
-
-@import 'widgets/TabSelectWidget.less';
-@import 'widgets/TabOptionWidget.less';
-
-@import 'widgets/ComboBoxWidget.less';
-@import 'widgets/SearchWidget.less';
-
-@import 'Window.less';
-@import 'Dialog.less';
-@import 'dialogs/MessageDialog.less';
-@import 'dialogs/ProcessDialog.less';
-
-@import 'WindowManager.less';
diff --git a/vendor/oojs/oojs-ui/src/styles/dialogs/MessageDialog.less b/vendor/oojs/oojs-ui/src/styles/dialogs/MessageDialog.less
deleted file mode 100644
index e50029f9..00000000
--- a/vendor/oojs/oojs-ui/src/styles/dialogs/MessageDialog.less
+++ /dev/null
@@ -1,45 +0,0 @@
-@import '../common';
-
-.oo-ui-messageDialog {
- &-actions {
- &-horizontal {
- display: table;
- table-layout: fixed;
- width: 100%;
-
- .oo-ui-actionWidget {
- display: table-cell;
- width: 1%;
- }
- }
-
- &-vertical {
- display: block;
-
- .oo-ui-actionWidget {
- display: block;
- overflow: hidden;
- text-overflow: ellipsis;
- }
- }
-
- .oo-ui-actionWidget {
- position: relative;
- text-align: center;
-
- .oo-ui-buttonElement-button {
- display: block;
- }
-
- .oo-ui-labelElement-label {
- position: relative;
- top: auto;
- bottom: auto;
- display: inline;
- white-space: nowrap;
- }
- }
- }
-
- .theme-oo-ui-messageDialog();
-}
diff --git a/vendor/oojs/oojs-ui/src/styles/dialogs/ProcessDialog.less b/vendor/oojs/oojs-ui/src/styles/dialogs/ProcessDialog.less
deleted file mode 100644
index 379588ae..00000000
--- a/vendor/oojs/oojs-ui/src/styles/dialogs/ProcessDialog.less
+++ /dev/null
@@ -1,52 +0,0 @@
-@import '../common';
-
-.oo-ui-processDialog {
- &-location {
- overflow: hidden;
- text-overflow: ellipsis;
- white-space: nowrap;
- }
-
- &-title {
- display: inline;
- padding: 0;
- }
-
- &-actions {
- &-safe,
- &-primary,
- &-other {
- .oo-ui-actionWidget {
- white-space: nowrap;
- }
- }
-
- &-safe,
- &-primary {
- position: absolute;
- top: 0;
- bottom: 0;
- }
-
- &-safe {
- left: 0;
- }
-
- &-primary {
- right: 0;
- }
- }
-
- &-errors {
- position: absolute;
- top: 0;
- left: 0;
- right: 0;
- bottom: 0;
- z-index: 2;
- overflow-x: hidden;
- overflow-y: auto;
- }
-
- .theme-oo-ui-processDialog();
-}
diff --git a/vendor/oojs/oojs-ui/src/styles/elements/ButtonElement.less b/vendor/oojs/oojs-ui/src/styles/elements/ButtonElement.less
deleted file mode 100644
index 248772e5..00000000
--- a/vendor/oojs/oojs-ui/src/styles/elements/ButtonElement.less
+++ /dev/null
@@ -1,62 +0,0 @@
-@import '../common';
-
-.oo-ui-buttonElement {
- > .oo-ui-buttonElement-button {
- cursor: pointer;
- display: inline-block;
- vertical-align: middle;
- font: inherit;
- white-space: nowrap;
- .oo-ui-unselectable();
-
- > .oo-ui-iconElement-icon,
- > .oo-ui-indicatorElement-indicator {
- display: none;
- }
- }
-
- &.oo-ui-widget-disabled > .oo-ui-buttonElement-button {
- cursor: default;
- }
-
- &.oo-ui-indicatorElement > .oo-ui-buttonElement-button > .oo-ui-indicatorElement-indicator,
- &.oo-ui-iconElement > .oo-ui-buttonElement-button > .oo-ui-iconElement-icon {
- display: inline-block;
- vertical-align: middle;
- background-position: center center;
- background-repeat: no-repeat;
- }
-
- &-frameless {
- display: inline-block;
- position: relative;
-
- &.oo-ui-labelElement > .oo-ui-buttonElement-button > .oo-ui-labelElement-label {
- display: inline-block;
- vertical-align: middle;
- }
- }
-
- &-framed {
- > .oo-ui-buttonElement-button {
- display: inline-block;
- vertical-align: top;
- text-align: center;
- }
-
- &.oo-ui-labelElement > .oo-ui-buttonElement-button > .oo-ui-labelElement-label {
- display: inline-block;
- vertical-align: middle;
- }
-
- &.oo-ui-widget-disabled {
- > .oo-ui-buttonElement-button,
- &.oo-ui-buttonElement-active > .oo-ui-buttonElement-button,
- &.oo-ui-buttonElement-pressed > .oo-ui-buttonElement-button {
- cursor: default;
- }
- }
- }
-
- .theme-oo-ui-buttonElement();
-}
diff --git a/vendor/oojs/oojs-ui/src/styles/elements/ClippableElement.less b/vendor/oojs/oojs-ui/src/styles/elements/ClippableElement.less
deleted file mode 100644
index 2a661e93..00000000
--- a/vendor/oojs/oojs-ui/src/styles/elements/ClippableElement.less
+++ /dev/null
@@ -1,7 +0,0 @@
-@import '../common';
-
-.oo-ui-clippableElement-clippable {
- .oo-ui-box-sizing(border-box);
-
- .theme-oo-ui-clippableElement();
-}
diff --git a/vendor/oojs/oojs-ui/src/styles/elements/DraggableElement.less b/vendor/oojs/oojs-ui/src/styles/elements/DraggableElement.less
deleted file mode 100644
index 3f382766..00000000
--- a/vendor/oojs/oojs-ui/src/styles/elements/DraggableElement.less
+++ /dev/null
@@ -1,22 +0,0 @@
-@import '../common';
-
-.oo-ui-draggableElement {
- cursor: -webkit-grab -moz-grab, url(images/grab.cur), move;
-
- &-dragging {
- cursor: -webkit-grabbing -moz-grabbing, url(images/grabbing.cur), move;
- background: rgba( 0, 0, 0, 0.2 );
- opacity: 0.4;
- }
-
- /*
- * HACK: In order to style horizontally, we must override
- * OO.ui.OptionWidget's display rule that is currently set
- * to be 'block'
- */
- .oo-ui-draggableGroupElement-horizontal &.oo-ui-optionWidget {
- display: inline-block;
- }
-
- .theme-oo-ui-draggableElement();
-}
diff --git a/vendor/oojs/oojs-ui/src/styles/elements/DraggableGroupElement.less b/vendor/oojs/oojs-ui/src/styles/elements/DraggableGroupElement.less
deleted file mode 100644
index 07e08594..00000000
--- a/vendor/oojs/oojs-ui/src/styles/elements/DraggableGroupElement.less
+++ /dev/null
@@ -1,11 +0,0 @@
-@import '../common';
-
-.oo-ui-draggableGroupElement {
- &-placeholder {
- position: absolute;
- display: block;
- background: rgba( 0, 0, 0, 0.4 );
- }
-
- .theme-oo-ui-draggableGroupElement();
-}
diff --git a/vendor/oojs/oojs-ui/src/styles/elements/FlaggedElement.less b/vendor/oojs/oojs-ui/src/styles/elements/FlaggedElement.less
deleted file mode 100644
index 6e9202e9..00000000
--- a/vendor/oojs/oojs-ui/src/styles/elements/FlaggedElement.less
+++ /dev/null
@@ -1,5 +0,0 @@
-@import '../common';
-
-.oo-ui-flaggedElement {
- .theme-oo-ui-flaggedElement();
-}
diff --git a/vendor/oojs/oojs-ui/src/styles/elements/GroupElement.less b/vendor/oojs/oojs-ui/src/styles/elements/GroupElement.less
deleted file mode 100644
index 159d32cc..00000000
--- a/vendor/oojs/oojs-ui/src/styles/elements/GroupElement.less
+++ /dev/null
@@ -1,5 +0,0 @@
-@import '../common';
-
-.oo-ui-groupElement {
- .theme-oo-ui-groupElement();
-}
diff --git a/vendor/oojs/oojs-ui/src/styles/elements/IconElement.less b/vendor/oojs/oojs-ui/src/styles/elements/IconElement.less
deleted file mode 100644
index 5d90fda6..00000000
--- a/vendor/oojs/oojs-ui/src/styles/elements/IconElement.less
+++ /dev/null
@@ -1,5 +0,0 @@
-@import '../common';
-
-.oo-ui-iconElement {
- .theme-oo-ui-iconElement();
-}
diff --git a/vendor/oojs/oojs-ui/src/styles/elements/IndicatorElement.less b/vendor/oojs/oojs-ui/src/styles/elements/IndicatorElement.less
deleted file mode 100644
index d400803c..00000000
--- a/vendor/oojs/oojs-ui/src/styles/elements/IndicatorElement.less
+++ /dev/null
@@ -1,5 +0,0 @@
-@import '../common';
-
-.oo-ui-indicatorElement {
- .theme-oo-ui-indicatorElement();
-}
diff --git a/vendor/oojs/oojs-ui/src/styles/elements/LabelElement.less b/vendor/oojs/oojs-ui/src/styles/elements/LabelElement.less
deleted file mode 100644
index c47ecdc4..00000000
--- a/vendor/oojs/oojs-ui/src/styles/elements/LabelElement.less
+++ /dev/null
@@ -1,5 +0,0 @@
-@import '../common';
-
-.oo-ui-labelElement {
- .theme-oo-ui-labelElement();
-}
diff --git a/vendor/oojs/oojs-ui/src/styles/elements/LookupElement.less b/vendor/oojs/oojs-ui/src/styles/elements/LookupElement.less
deleted file mode 100644
index 0ab29f72..00000000
--- a/vendor/oojs/oojs-ui/src/styles/elements/LookupElement.less
+++ /dev/null
@@ -1,10 +0,0 @@
-@import '../common';
-
-.oo-ui-lookupElement {
- > .oo-ui-menuSelectWidget {
- z-index: 1;
- width: 100%;
- }
-
- .theme-oo-ui-lookupElement();
-}
diff --git a/vendor/oojs/oojs-ui/src/styles/elements/PopupElement.less b/vendor/oojs/oojs-ui/src/styles/elements/PopupElement.less
deleted file mode 100644
index 12b80daf..00000000
--- a/vendor/oojs/oojs-ui/src/styles/elements/PopupElement.less
+++ /dev/null
@@ -1,5 +0,0 @@
-@import '../common';
-
-.oo-ui-popupElement {
- .theme-oo-ui-popupElement();
-}
diff --git a/vendor/oojs/oojs-ui/src/styles/elements/TabIndexedElement.less b/vendor/oojs/oojs-ui/src/styles/elements/TabIndexedElement.less
deleted file mode 100644
index f894d369..00000000
--- a/vendor/oojs/oojs-ui/src/styles/elements/TabIndexedElement.less
+++ /dev/null
@@ -1,5 +0,0 @@
-@import '../common';
-
-.oo-ui-tabIndexedElement {
- .theme-oo-ui-tabIndexedElement();
-}
diff --git a/vendor/oojs/oojs-ui/src/styles/elements/TitledElement.less b/vendor/oojs/oojs-ui/src/styles/elements/TitledElement.less
deleted file mode 100644
index f8a15b68..00000000
--- a/vendor/oojs/oojs-ui/src/styles/elements/TitledElement.less
+++ /dev/null
@@ -1,5 +0,0 @@
-@import '../common';
-
-.oo-ui-titledElement {
- .theme-oo-ui-titledElement();
-}
diff --git a/vendor/oojs/oojs-ui/src/styles/images/grab.cur b/vendor/oojs/oojs-ui/src/styles/images/grab.cur
deleted file mode 100644
index fba3ddc8..00000000
--- a/vendor/oojs/oojs-ui/src/styles/images/grab.cur
+++ /dev/null
Binary files differ
diff --git a/vendor/oojs/oojs-ui/src/styles/images/grabbing.cur b/vendor/oojs/oojs-ui/src/styles/images/grabbing.cur
deleted file mode 100644
index 41aaa62a..00000000
--- a/vendor/oojs/oojs-ui/src/styles/images/grabbing.cur
+++ /dev/null
Binary files differ
diff --git a/vendor/oojs/oojs-ui/src/styles/layouts/ActionFieldLayout.less b/vendor/oojs/oojs-ui/src/styles/layouts/ActionFieldLayout.less
deleted file mode 100644
index 2d4c2a66..00000000
--- a/vendor/oojs/oojs-ui/src/styles/layouts/ActionFieldLayout.less
+++ /dev/null
@@ -1,26 +0,0 @@
-@import '../common';
-
-.oo-ui-actionFieldLayout {
- &-field {
- display: table;
- table-layout: fixed;
- width: 100%;
- }
-
- &-input,
- &-button {
- display: table-cell;
- vertical-align: middle;
- }
-
- &-input {
- padding-right: 1em;
- }
-
- &-button {
- width: 1%;
- white-space: nowrap;
- }
-
- .theme-oo-ui-actionFieldLayout();
-}
diff --git a/vendor/oojs/oojs-ui/src/styles/layouts/BookletLayout.less b/vendor/oojs/oojs-ui/src/styles/layouts/BookletLayout.less
deleted file mode 100644
index b31cb6d7..00000000
--- a/vendor/oojs/oojs-ui/src/styles/layouts/BookletLayout.less
+++ /dev/null
@@ -1,43 +0,0 @@
-@import '../common';
-
-.oo-ui-bookletLayout {
- &-stackLayout {
- &.oo-ui-stackLayout-continuous > .oo-ui-panelLayout-scrollable {
- overflow-y: hidden;
- }
-
- > .oo-ui-panelLayout {
- width: 100%;
-
- .oo-ui-box-sizing(border-box);
-
- &-scrollable {
- overflow-y: auto;
- }
-
- &-padded {
- padding: 2em;
- }
- }
- }
-
- &-outlinePanel {
- &-editable > .oo-ui-outlineSelectWidget {
- position: absolute;
- top: 0;
- left: 0;
- right: 0;
- bottom: 3em;
- overflow-y: auto;
- }
-
- > .oo-ui-outlineControlsWidget {
- position: absolute;
- bottom: 0;
- left: 0;
- right: 0;
- }
- }
-
- .theme-oo-ui-bookletLayout();
-}
diff --git a/vendor/oojs/oojs-ui/src/styles/layouts/CardLayout.less b/vendor/oojs/oojs-ui/src/styles/layouts/CardLayout.less
deleted file mode 100644
index 4fdb20b2..00000000
--- a/vendor/oojs/oojs-ui/src/styles/layouts/CardLayout.less
+++ /dev/null
@@ -1,5 +0,0 @@
-@import '../common';
-
-.oo-ui-cardLayout {
- .theme-oo-ui-cardLayout();
-}
diff --git a/vendor/oojs/oojs-ui/src/styles/layouts/FieldLayout.less b/vendor/oojs/oojs-ui/src/styles/layouts/FieldLayout.less
deleted file mode 100644
index 799f9f4b..00000000
--- a/vendor/oojs/oojs-ui/src/styles/layouts/FieldLayout.less
+++ /dev/null
@@ -1,59 +0,0 @@
-@import '../common';
-
-.oo-ui-fieldLayout {
- display: block;
-
- &:before,
- &:after {
- content: " ";
- display: table;
- }
-
- &:after {
- clear: both;
- }
-
- &.oo-ui-fieldLayout-align-left,
- &.oo-ui-fieldLayout-align-right {
- > .oo-ui-fieldLayout-body {
- > .oo-ui-labelElement-label,
- > .oo-ui-fieldLayout-field {
- display: block;
- float: left;
- }
- }
- }
-
- &.oo-ui-fieldLayout-align-right > .oo-ui-fieldLayout-body > .oo-ui-labelElement-label {
- text-align: right;
- }
-
- &.oo-ui-fieldLayout-align-inline > .oo-ui-fieldLayout-body {
- display: table;
-
- > .oo-ui-labelElement-label,
- > .oo-ui-fieldLayout-field {
- display: table-cell;
- vertical-align: middle;
- }
- }
-
- &.oo-ui-labelElement.oo-ui-fieldLayout-align-top > .oo-ui-fieldLayout-body > .oo-ui-labelElement-label {
- display: inline-block;
- }
-
- > .oo-ui-fieldLayout-help {
- float: right;
-
- > .oo-ui-popupWidget > .oo-ui-popupWidget-popup {
- z-index: 1;
- }
-
- .oo-ui-fieldLayout-help-content {
- padding: 0.5em 0.75em;
- line-height: 1.5em;
- }
- }
-
- .theme-oo-ui-fieldLayout();
-}
diff --git a/vendor/oojs/oojs-ui/src/styles/layouts/FieldsetLayout.less b/vendor/oojs/oojs-ui/src/styles/layouts/FieldsetLayout.less
deleted file mode 100644
index 726b9310..00000000
--- a/vendor/oojs/oojs-ui/src/styles/layouts/FieldsetLayout.less
+++ /dev/null
@@ -1,31 +0,0 @@
-@import '../common';
-
-.oo-ui-fieldsetLayout {
- position: relative;
-
- &.oo-ui-iconElement > .oo-ui-iconElement-icon {
- display: block;
- position: absolute;
- background-position: center center;
- background-repeat: no-repeat;
- }
-
- &.oo-ui-labelElement > .oo-ui-labelElement-label {
- display: inline-block;
- }
-
- > .oo-ui-fieldsetLayout-help {
- float: right;
-
- > .oo-ui-popupWidget > .oo-ui-popupWidget-popup {
- z-index: 1;
- }
-
- .oo-ui-fieldsetLayout-help-content {
- padding: 0.5em 0.75em;
- line-height: 1.5em;
- }
- }
-
- .theme-oo-ui-fieldsetLayout();
-}
diff --git a/vendor/oojs/oojs-ui/src/styles/layouts/FormLayout.less b/vendor/oojs/oojs-ui/src/styles/layouts/FormLayout.less
deleted file mode 100644
index 7354e4bd..00000000
--- a/vendor/oojs/oojs-ui/src/styles/layouts/FormLayout.less
+++ /dev/null
@@ -1,5 +0,0 @@
-@import '../common';
-
-.oo-ui-formLayout {
- .theme-oo-ui-formLayout();
-}
diff --git a/vendor/oojs/oojs-ui/src/styles/layouts/IndexLayout.less b/vendor/oojs/oojs-ui/src/styles/layouts/IndexLayout.less
deleted file mode 100644
index 63f3f146..00000000
--- a/vendor/oojs/oojs-ui/src/styles/layouts/IndexLayout.less
+++ /dev/null
@@ -1,13 +0,0 @@
-@import '../common';
-
-.oo-ui-indexLayout {
- > .oo-ui-menuLayout-menu {
- height: 3em;
- }
-
- > .oo-ui-menuLayout-content {
- top: 3em;
- }
-
- .theme-oo-ui-indexLayout();
-}
diff --git a/vendor/oojs/oojs-ui/src/styles/layouts/MenuLayout.less b/vendor/oojs/oojs-ui/src/styles/layouts/MenuLayout.less
deleted file mode 100644
index c5080e2b..00000000
--- a/vendor/oojs/oojs-ui/src/styles/layouts/MenuLayout.less
+++ /dev/null
@@ -1,108 +0,0 @@
-@import '../common';
-
-.oo-ui-menuLayout {
- position: absolute;
- top: 0;
- left: 0;
- right: 0;
- bottom: 0;
-
- &-menu,
- &-content {
- position: absolute;
- .oo-ui-transition(all ease-in-out 200ms);
- }
-
- // These are overridden with 'auto' or '0' later
- &-menu {
- height: 18em;
- width: 18em;
- }
-
- // These are overridden with 'auto' or '0' later
- &-content {
- top: 18em;
- left: 18em;
- right: 18em;
- bottom: 18em;
- }
-
- &.oo-ui-menuLayout-hideMenu {
- .oo-ui-menuLayout-menu {
- width: 0 !important;
- height: 0 !important;
- overflow: hidden;
- }
-
- .oo-ui-menuLayout-content {
- top: 0 !important;
- left: 0 !important;
- right: 0 !important;
- bottom: 0 !important;
- }
- }
-
- &.oo-ui-menuLayout-showMenu {
- &.oo-ui-menuLayout-top {
- .oo-ui-menuLayout-menu {
- width: auto !important;
- left: 0;
- top: 0;
- right: 0;
- }
-
- .oo-ui-menuLayout-content {
- right: 0 !important;
- bottom: 0 !important;
- left: 0 !important;
- }
- }
-
- &.oo-ui-menuLayout-after {
- .oo-ui-menuLayout-menu {
- height: auto !important;
- top: 0;
- right: 0;
- bottom: 0;
- }
-
- .oo-ui-menuLayout-content {
- bottom: 0 !important;
- left: 0 !important;
- top: 0 !important;
- }
- }
-
- &.oo-ui-menuLayout-bottom {
- .oo-ui-menuLayout-menu {
- width: auto !important;
- right: 0;
- bottom: 0;
- left: 0;
- }
-
- .oo-ui-menuLayout-content {
- left: 0 !important;
- top: 0 !important;
- right: 0 !important;
- }
- }
-
- &.oo-ui-menuLayout-before {
- .oo-ui-menuLayout-menu {
- height: auto !important;
- bottom: 0;
- left: 0;
- top: 0;
- }
-
- .oo-ui-menuLayout-content {
- top: 0 !important;
- right: 0 !important;
- bottom: 0 !important;
- }
- }
- }
-
- .theme-oo-ui-menuLayout();
-}
diff --git a/vendor/oojs/oojs-ui/src/styles/layouts/PageLayout.less b/vendor/oojs/oojs-ui/src/styles/layouts/PageLayout.less
deleted file mode 100644
index 91aa4571..00000000
--- a/vendor/oojs/oojs-ui/src/styles/layouts/PageLayout.less
+++ /dev/null
@@ -1,5 +0,0 @@
-@import '../common';
-
-.oo-ui-pageLayout {
- .theme-oo-ui-pageLayout();
-}
diff --git a/vendor/oojs/oojs-ui/src/styles/layouts/PanelLayout.less b/vendor/oojs/oojs-ui/src/styles/layouts/PanelLayout.less
deleted file mode 100644
index ed488ed7..00000000
--- a/vendor/oojs/oojs-ui/src/styles/layouts/PanelLayout.less
+++ /dev/null
@@ -1,19 +0,0 @@
-@import '../common';
-
-.oo-ui-panelLayout {
- position: relative;
-
- &-scrollable {
- overflow-y: auto;
- }
-
- &-expanded {
- position: absolute;
- top: 0;
- left: 0;
- right: 0;
- bottom: 0;
- }
-
- .theme-oo-ui-panelLayout();
-}
diff --git a/vendor/oojs/oojs-ui/src/styles/layouts/StackLayout.less b/vendor/oojs/oojs-ui/src/styles/layouts/StackLayout.less
deleted file mode 100644
index 6dd4fa79..00000000
--- a/vendor/oojs/oojs-ui/src/styles/layouts/StackLayout.less
+++ /dev/null
@@ -1,10 +0,0 @@
-@import '../common';
-
-.oo-ui-stackLayout {
- &-continuous > .oo-ui-panelLayout {
- display: block;
- position: relative;
- }
-
- .theme-oo-ui-stackLayout();
-}
diff --git a/vendor/oojs/oojs-ui/src/styles/theme.less b/vendor/oojs/oojs-ui/src/styles/theme.less
deleted file mode 100644
index 2cd4c0e3..00000000
--- a/vendor/oojs/oojs-ui/src/styles/theme.less
+++ /dev/null
@@ -1,91 +0,0 @@
-//
-// Blank theme mixins.
-//
-// Base styles invoke these mixins at the end of their definitions. Override these mixins to add
-// additional rules to the base styles.
-//
-
-.theme-oo-ui-layout () {}
-.theme-oo-ui-element () {}
-.theme-oo-ui-widget () {}
-.theme-oo-ui-window () {}
-.theme-oo-ui-dialog () {}
-.theme-oo-ui-windowManager () {}
-
-.theme-oo-ui-buttonElement () {}
-.theme-oo-ui-clippableElement () {}
-.theme-oo-ui-draggableElement () {}
-.theme-oo-ui-flaggedElement () {}
-.theme-oo-ui-groupElement () {}
-.theme-oo-ui-draggableGroupElement () {}
-.theme-oo-ui-iconElement () {}
-.theme-oo-ui-indicatorElement () {}
-.theme-oo-ui-labelElement () {}
-.theme-oo-ui-lookupElement () {}
-.theme-oo-ui-popupElement () {}
-.theme-oo-ui-tabIndexedElement () {}
-.theme-oo-ui-titledElement () {}
-
-.theme-oo-ui-tool () {}
-.theme-oo-ui-toolbar () {}
-.theme-oo-ui-toolGroup () {}
-.theme-oo-ui-messageDialog () {}
-.theme-oo-ui-processDialog () {}
-
-.theme-oo-ui-bookletLayout () {}
-.theme-oo-ui-indexLayout () {}
-.theme-oo-ui-fieldLayout () {}
-.theme-oo-ui-actionFieldLayout () {}
-.theme-oo-ui-fieldsetLayout () {}
-.theme-oo-ui-formLayout () {}
-.theme-oo-ui-menuLayout () {}
-.theme-oo-ui-panelLayout () {}
-.theme-oo-ui-cardLayout () {}
-.theme-oo-ui-pageLayout () {}
-.theme-oo-ui-stackLayout () {}
-
-.theme-oo-ui-barToolGroup () {}
-.theme-oo-ui-popupToolGroup () {}
-.theme-oo-ui-listToolGroup () {}
-.theme-oo-ui-menuToolGroup () {}
-
-.theme-oo-ui-popupTool () {}
-.theme-oo-ui-toolGroupTool () {}
-
-.theme-oo-ui-outlineControlsWidget () {}
-.theme-oo-ui-toggleWidget () {}
-
-.theme-oo-ui-buttonGroupWidget () {}
-.theme-oo-ui-buttonWidget () {}
-.theme-oo-ui-actionWidget () {}
-.theme-oo-ui-popupButtonWidget () {}
-.theme-oo-ui-toggleButtonWidget () {}
-.theme-oo-ui-iconWidget () {}
-.theme-oo-ui-indicatorWidget () {}
-.theme-oo-ui-dropdownWidget () {}
-.theme-oo-ui-inputWidget () {}
-.theme-oo-ui-buttonInputWidget () {}
-.theme-oo-ui-checkboxInputWidget () {}
-.theme-oo-ui-dropdownInputWidget () {}
-.theme-oo-ui-radioInputWidget () {}
-.theme-oo-ui-textInputWidget () {}
-.theme-oo-ui-comboBoxWidget () {}
-.theme-oo-ui-labelWidget () {}
-.theme-oo-ui-optionWidget () {}
-.theme-oo-ui-decoratedOptionWidget () {}
-.theme-oo-ui-buttonOptionWidget () {}
-.theme-oo-ui-radioOptionWidget () {}
-.theme-oo-ui-menuOptionWidget () {}
-.theme-oo-ui-menuSectionOptionWidget () {}
-.theme-oo-ui-outlineOptionWidget () {}
-.theme-oo-ui-tabOptionWidget () {}
-.theme-oo-ui-popupWidget () {}
-.theme-oo-ui-searchWidget () {}
-.theme-oo-ui-selectWidget () {}
-.theme-oo-ui-buttonSelectWidget () {}
-.theme-oo-ui-radioSelectWidget () {}
-.theme-oo-ui-menuSelectWidget () {}
-.theme-oo-ui-textInputMenuSelectWidget () {}
-.theme-oo-ui-outlineSelectWidget () {}
-.theme-oo-ui-tabSelectWidget () {}
-.theme-oo-ui-toggleSwitchWidget () {}
diff --git a/vendor/oojs/oojs-ui/src/styles/toolgroups/BarToolGroup.less b/vendor/oojs/oojs-ui/src/styles/toolgroups/BarToolGroup.less
deleted file mode 100644
index 44c3bb8c..00000000
--- a/vendor/oojs/oojs-ui/src/styles/toolgroups/BarToolGroup.less
+++ /dev/null
@@ -1,51 +0,0 @@
-@import '../common';
-
-.oo-ui-barToolGroup {
- > .oo-ui-iconElement-icon,
- > .oo-ui-labelElement-label {
- display: none;
- }
-
- &.oo-ui-widget-enabled > .oo-ui-toolGroup-tools > .oo-ui-tool {
- > .oo-ui-tool-link {
- cursor: pointer;
- }
- }
-
- > .oo-ui-toolGroup-tools > .oo-ui-tool {
- display: inline-block;
- position: relative;
- vertical-align: top;
-
- > .oo-ui-tool-link {
- display: block;
-
- .oo-ui-tool-accel {
- display: none;
- }
- }
-
- &.oo-ui-iconElement > .oo-ui-tool-link {
- .oo-ui-iconElement-icon {
- display: inline-block;
- vertical-align: top;
- }
-
- .oo-ui-tool-title {
- display: none;
- }
- }
-
- &.oo-ui-iconElement.oo-ui-tool-with-label > .oo-ui-tool-link {
- .oo-ui-tool-title {
- display: inline;
- }
- }
-
- &.oo-ui-widget-disabled > .oo-ui-tool-link {
- cursor: default;
- }
- }
-
- .theme-oo-ui-barToolGroup();
-}
diff --git a/vendor/oojs/oojs-ui/src/styles/toolgroups/ListToolGroup.less b/vendor/oojs/oojs-ui/src/styles/toolgroups/ListToolGroup.less
deleted file mode 100644
index f3c745a3..00000000
--- a/vendor/oojs/oojs-ui/src/styles/toolgroups/ListToolGroup.less
+++ /dev/null
@@ -1,21 +0,0 @@
-@import '../common';
-
-.oo-ui-listToolGroup {
- .oo-ui-tool {
- display: block;
-
- .oo-ui-box-sizing(border-box);
-
- &-link {
- cursor: pointer;
- }
-
- &.oo-ui-widget-disabled {
- .oo-ui-tool-link {
- cursor: default;
- }
- }
- }
-
- .theme-oo-ui-listToolGroup();
-}
diff --git a/vendor/oojs/oojs-ui/src/styles/toolgroups/MenuToolGroup.less b/vendor/oojs/oojs-ui/src/styles/toolgroups/MenuToolGroup.less
deleted file mode 100644
index cfbbe0b6..00000000
--- a/vendor/oojs/oojs-ui/src/styles/toolgroups/MenuToolGroup.less
+++ /dev/null
@@ -1,19 +0,0 @@
-@import '../common';
-
-.oo-ui-menuToolGroup {
- .oo-ui-tool {
- display: block;
-
- &-link {
- cursor: pointer;
- }
-
- &.oo-ui-widget-disabled {
- .oo-ui-tool-link {
- cursor: default;
- }
- }
- }
-
- .theme-oo-ui-menuToolGroup();
-}
diff --git a/vendor/oojs/oojs-ui/src/styles/toolgroups/PopupToolGroup.less b/vendor/oojs/oojs-ui/src/styles/toolgroups/PopupToolGroup.less
deleted file mode 100644
index 1b54bea5..00000000
--- a/vendor/oojs/oojs-ui/src/styles/toolgroups/PopupToolGroup.less
+++ /dev/null
@@ -1,73 +0,0 @@
-@import '../common';
-
-.oo-ui-popupToolGroup {
- position: relative;
-
- &-handle {
- display: block;
- cursor: pointer;
-
- .oo-ui-indicatorElement-indicator,
- .oo-ui-iconElement-icon {
- position: absolute;
- background-position: center center;
- background-repeat: no-repeat;
- }
- }
-
- &.oo-ui-widget-disabled {
- .oo-ui-popupToolGroup-handle {
- cursor: default;
- }
- }
-
- .oo-ui-toolGroup-tools {
- display: none;
- position: absolute;
- z-index: 4;
-
- .oo-ui-iconElement-icon {
- background-repeat: no-repeat;
- background-position: center center;
- }
- }
-
- &-active.oo-ui-widget-enabled {
- > .oo-ui-toolGroup-tools {
- display: block;
- }
- }
-
- &-left > .oo-ui-toolGroup-tools {
- left: 0;
- }
-
- &-right > .oo-ui-toolGroup-tools {
- right: 0;
- }
-
- .oo-ui-tool-link {
- display: table;
- width: 100%;
- vertical-align: middle;
- white-space: nowrap;
-
- .oo-ui-iconElement-icon,
- .oo-ui-tool-accel,
- .oo-ui-tool-title {
- display: table-cell;
- vertical-align: middle;
- }
-
- .oo-ui-tool-accel {
- text-align: right;
- }
-
- .oo-ui-tool-accel:not(:empty) {
- // Push away from tool's title
- padding-left: 3em;
- }
- }
-
- .theme-oo-ui-popupToolGroup();
-}
diff --git a/vendor/oojs/oojs-ui/src/styles/tools/PopupTool.less b/vendor/oojs/oojs-ui/src/styles/tools/PopupTool.less
deleted file mode 100644
index df90302b..00000000
--- a/vendor/oojs/oojs-ui/src/styles/tools/PopupTool.less
+++ /dev/null
@@ -1,12 +0,0 @@
-@import '../common';
-
-.oo-ui-popupTool {
- .oo-ui-popupWidget {
- &-popup,
- &-anchor {
- z-index: 4;
- }
- }
-
- .theme-oo-ui-popupTool();
-}
diff --git a/vendor/oojs/oojs-ui/src/styles/tools/ToolGroupTool.less b/vendor/oojs/oojs-ui/src/styles/tools/ToolGroupTool.less
deleted file mode 100644
index 753d4e8a..00000000
--- a/vendor/oojs/oojs-ui/src/styles/tools/ToolGroupTool.less
+++ /dev/null
@@ -1,5 +0,0 @@
-@import '../common';
-
-.oo-ui-toolGroupTool {
- .theme-oo-ui-toolGroupTool();
-}
diff --git a/vendor/oojs/oojs-ui/src/styles/widgets/ActionWidget.less b/vendor/oojs/oojs-ui/src/styles/widgets/ActionWidget.less
deleted file mode 100644
index 39ed296f..00000000
--- a/vendor/oojs/oojs-ui/src/styles/widgets/ActionWidget.less
+++ /dev/null
@@ -1,5 +0,0 @@
-@import '../common';
-
-.oo-ui-actionWidget {
- .theme-oo-ui-actionWidget();
-}
diff --git a/vendor/oojs/oojs-ui/src/styles/widgets/ButtonGroupWidget.less b/vendor/oojs/oojs-ui/src/styles/widgets/ButtonGroupWidget.less
deleted file mode 100644
index eee220d4..00000000
--- a/vendor/oojs/oojs-ui/src/styles/widgets/ButtonGroupWidget.less
+++ /dev/null
@@ -1,5 +0,0 @@
-@import '../common';
-
-.oo-ui-buttonGroupWidget {
- .theme-oo-ui-buttonGroupWidget();
-}
diff --git a/vendor/oojs/oojs-ui/src/styles/widgets/ButtonInputWidget.less b/vendor/oojs/oojs-ui/src/styles/widgets/ButtonInputWidget.less
deleted file mode 100644
index 5de860eb..00000000
--- a/vendor/oojs/oojs-ui/src/styles/widgets/ButtonInputWidget.less
+++ /dev/null
@@ -1,8 +0,0 @@
-@import '../common';
-
-.oo-ui-buttonInputWidget {
- display: inline-block;
- vertical-align: middle;
-
- .theme-oo-ui-buttonInputWidget();
-}
diff --git a/vendor/oojs/oojs-ui/src/styles/widgets/ButtonOptionWidget.less b/vendor/oojs/oojs-ui/src/styles/widgets/ButtonOptionWidget.less
deleted file mode 100644
index fe214090..00000000
--- a/vendor/oojs/oojs-ui/src/styles/widgets/ButtonOptionWidget.less
+++ /dev/null
@@ -1,18 +0,0 @@
-@import '../common';
-
-.oo-ui-buttonOptionWidget {
- display: inline-block;
-
- .oo-ui-buttonElement-button {
- position: relative;
- }
-
- &.oo-ui-iconElement .oo-ui-iconElement-icon,
- &.oo-ui-indicatorElement .oo-ui-indicatorElement-indicator {
- position: static;
- display: inline-block;
- vertical-align: middle;
- }
-
- .theme-oo-ui-buttonOptionWidget();
-}
diff --git a/vendor/oojs/oojs-ui/src/styles/widgets/ButtonSelectWidget.less b/vendor/oojs/oojs-ui/src/styles/widgets/ButtonSelectWidget.less
deleted file mode 100644
index d0430db5..00000000
--- a/vendor/oojs/oojs-ui/src/styles/widgets/ButtonSelectWidget.less
+++ /dev/null
@@ -1,8 +0,0 @@
-@import '../common';
-
-.oo-ui-buttonSelectWidget {
- display: inline-block;
- white-space: nowrap;
-
- .theme-oo-ui-buttonSelectWidget();
-}
diff --git a/vendor/oojs/oojs-ui/src/styles/widgets/ButtonWidget.less b/vendor/oojs/oojs-ui/src/styles/widgets/ButtonWidget.less
deleted file mode 100644
index c33149f2..00000000
--- a/vendor/oojs/oojs-ui/src/styles/widgets/ButtonWidget.less
+++ /dev/null
@@ -1,8 +0,0 @@
-@import '../common';
-
-.oo-ui-buttonWidget {
- display: inline-block;
- vertical-align: middle;
-
- .theme-oo-ui-buttonWidget();
-}
diff --git a/vendor/oojs/oojs-ui/src/styles/widgets/CheckboxInputWidget.less b/vendor/oojs/oojs-ui/src/styles/widgets/CheckboxInputWidget.less
deleted file mode 100644
index 608c9a6b..00000000
--- a/vendor/oojs/oojs-ui/src/styles/widgets/CheckboxInputWidget.less
+++ /dev/null
@@ -1,5 +0,0 @@
-@import '../common';
-
-.oo-ui-checkboxInputWidget {
- .theme-oo-ui-checkboxInputWidget();
-}
diff --git a/vendor/oojs/oojs-ui/src/styles/widgets/ComboBoxWidget.less b/vendor/oojs/oojs-ui/src/styles/widgets/ComboBoxWidget.less
deleted file mode 100644
index 1b393c5b..00000000
--- a/vendor/oojs/oojs-ui/src/styles/widgets/ComboBoxWidget.less
+++ /dev/null
@@ -1,13 +0,0 @@
-@import '../common';
-
-.oo-ui-comboBoxWidget {
- display: inline-block;
- position: relative;
-
- > .oo-ui-menuSelectWidget {
- z-index: 1;
- width: 100%;
- }
-
- .theme-oo-ui-comboBoxWidget();
-}
diff --git a/vendor/oojs/oojs-ui/src/styles/widgets/DecoratedOptionWidget.less b/vendor/oojs/oojs-ui/src/styles/widgets/DecoratedOptionWidget.less
deleted file mode 100644
index a31d0670..00000000
--- a/vendor/oojs/oojs-ui/src/styles/widgets/DecoratedOptionWidget.less
+++ /dev/null
@@ -1,12 +0,0 @@
-@import '../common';
-
-.oo-ui-decoratedOptionWidget {
- .oo-ui-iconElement-icon,
- .oo-ui-indicatorElement-indicator {
- position: absolute;
- background-repeat: no-repeat;
- background-position: center center;
- }
-
- .theme-oo-ui-decoratedOptionWidget();
-}
diff --git a/vendor/oojs/oojs-ui/src/styles/widgets/DropdownInputWidget.less b/vendor/oojs/oojs-ui/src/styles/widgets/DropdownInputWidget.less
deleted file mode 100644
index 8b7bb7cf..00000000
--- a/vendor/oojs/oojs-ui/src/styles/widgets/DropdownInputWidget.less
+++ /dev/null
@@ -1,17 +0,0 @@
-@import '../common';
-
-.oo-ui-dropdownInputWidget {
- position: relative;
- // Necessary for proper alignment when used with display: inline-block
- vertical-align: middle;
- .oo-ui-box-sizing(border-box);
-
- select {
- display: inline-block;
- width: 100%;
- resize: none;
- .oo-ui-box-sizing(border-box);
- }
-
- .theme-oo-ui-dropdownInputWidget();
-}
diff --git a/vendor/oojs/oojs-ui/src/styles/widgets/DropdownWidget.less b/vendor/oojs/oojs-ui/src/styles/widgets/DropdownWidget.less
deleted file mode 100644
index d934cd4b..00000000
--- a/vendor/oojs/oojs-ui/src/styles/widgets/DropdownWidget.less
+++ /dev/null
@@ -1,33 +0,0 @@
-@import '../common';
-
-.oo-ui-dropdownWidget {
- display: inline-block;
- position: relative;
-
- &-handle {
- width: 100%;
- display: inline-block;
- cursor: pointer;
-
- .oo-ui-unselectable();
- .oo-ui-box-sizing(border-box);
-
- .oo-ui-indicatorElement-indicator,
- .oo-ui-iconElement-icon {
- position: absolute;
- background-position: center center;
- background-repeat: no-repeat;
- }
- }
-
- > .oo-ui-menuSelectWidget {
- z-index: 1;
- width: 100%;
- }
-
- &.oo-ui-widget-disabled .oo-ui-dropdownWidget-handle {
- cursor: default;
- }
-
- .theme-oo-ui-dropdownWidget();
-}
diff --git a/vendor/oojs/oojs-ui/src/styles/widgets/IconWidget.less b/vendor/oojs/oojs-ui/src/styles/widgets/IconWidget.less
deleted file mode 100644
index 03f6ab79..00000000
--- a/vendor/oojs/oojs-ui/src/styles/widgets/IconWidget.less
+++ /dev/null
@@ -1,10 +0,0 @@
-@import '../common';
-
-.oo-ui-iconWidget {
- display: inline-block;
- vertical-align: middle;
- background-position: center center;
- background-repeat: no-repeat;
-
- .theme-oo-ui-iconWidget();
-}
diff --git a/vendor/oojs/oojs-ui/src/styles/widgets/IndicatorWidget.less b/vendor/oojs/oojs-ui/src/styles/widgets/IndicatorWidget.less
deleted file mode 100644
index c1b00458..00000000
--- a/vendor/oojs/oojs-ui/src/styles/widgets/IndicatorWidget.less
+++ /dev/null
@@ -1,10 +0,0 @@
-@import '../common';
-
-.oo-ui-indicatorWidget {
- display: inline-block;
- vertical-align: middle;
- background-position: center center;
- background-repeat: no-repeat;
-
- .theme-oo-ui-indicatorWidget();
-}
diff --git a/vendor/oojs/oojs-ui/src/styles/widgets/InputWidget.less b/vendor/oojs/oojs-ui/src/styles/widgets/InputWidget.less
deleted file mode 100644
index 93628830..00000000
--- a/vendor/oojs/oojs-ui/src/styles/widgets/InputWidget.less
+++ /dev/null
@@ -1,5 +0,0 @@
-@import '../common';
-
-.oo-ui-inputWidget {
- .theme-oo-ui-inputWidget();
-}
diff --git a/vendor/oojs/oojs-ui/src/styles/widgets/LabelWidget.less b/vendor/oojs/oojs-ui/src/styles/widgets/LabelWidget.less
deleted file mode 100644
index cddd1a0a..00000000
--- a/vendor/oojs/oojs-ui/src/styles/widgets/LabelWidget.less
+++ /dev/null
@@ -1,7 +0,0 @@
-@import '../common';
-
-.oo-ui-labelWidget {
- display: inline-block;
-
- .theme-oo-ui-labelWidget();
-}
diff --git a/vendor/oojs/oojs-ui/src/styles/widgets/MenuOptionWidget.less b/vendor/oojs/oojs-ui/src/styles/widgets/MenuOptionWidget.less
deleted file mode 100644
index f7f9f7a4..00000000
--- a/vendor/oojs/oojs-ui/src/styles/widgets/MenuOptionWidget.less
+++ /dev/null
@@ -1,21 +0,0 @@
-@import '../common';
-
-.oo-ui-menuOptionWidget {
- position: relative;
-
- .oo-ui-iconElement-icon {
- display: none;
- }
-
- &.oo-ui-optionWidget {
- &-selected {
- background-color: transparent;
-
- .oo-ui-iconElement-icon {
- display: block;
- }
- }
- }
-
- .theme-oo-ui-menuOptionWidget();
-}
diff --git a/vendor/oojs/oojs-ui/src/styles/widgets/MenuSectionOptionWidget.less b/vendor/oojs/oojs-ui/src/styles/widgets/MenuSectionOptionWidget.less
deleted file mode 100644
index f670f7f5..00000000
--- a/vendor/oojs/oojs-ui/src/styles/widgets/MenuSectionOptionWidget.less
+++ /dev/null
@@ -1,8 +0,0 @@
-@import '../common';
-
-.oo-ui-menuSectionOptionWidget {
- cursor: default;
-
- .theme-oo-ui-menuSectionOptionWidget();
-}
-
diff --git a/vendor/oojs/oojs-ui/src/styles/widgets/MenuSelectWidget.less b/vendor/oojs/oojs-ui/src/styles/widgets/MenuSelectWidget.less
deleted file mode 100644
index 0585469f..00000000
--- a/vendor/oojs/oojs-ui/src/styles/widgets/MenuSelectWidget.less
+++ /dev/null
@@ -1,15 +0,0 @@
-@import '../common';
-
-.oo-ui-menuSelectWidget {
- position: absolute;
-
- input {
- position: absolute;
- width: 0;
- height: 0;
- overflow: hidden;
- opacity: 0;
- }
-
- .theme-oo-ui-menuSelectWidget();
-}
diff --git a/vendor/oojs/oojs-ui/src/styles/widgets/OptionWidget.less b/vendor/oojs/oojs-ui/src/styles/widgets/OptionWidget.less
deleted file mode 100644
index 8543fc74..00000000
--- a/vendor/oojs/oojs-ui/src/styles/widgets/OptionWidget.less
+++ /dev/null
@@ -1,20 +0,0 @@
-@import '../common';
-
-.oo-ui-optionWidget {
- position: relative;
- display: block;
- cursor: pointer;
-
- &.oo-ui-widget-disabled {
- cursor: default;
- }
-
- &.oo-ui-labelElement .oo-ui-labelElement-label {
- display: block;
- white-space: nowrap;
- text-overflow: ellipsis;
- overflow: hidden;
- }
-
- .theme-oo-ui-optionWidget();
-}
diff --git a/vendor/oojs/oojs-ui/src/styles/widgets/OutlineControlsWidget.less b/vendor/oojs/oojs-ui/src/styles/widgets/OutlineControlsWidget.less
deleted file mode 100644
index 97d4e1d7..00000000
--- a/vendor/oojs/oojs-ui/src/styles/widgets/OutlineControlsWidget.less
+++ /dev/null
@@ -1,32 +0,0 @@
-@import '../common';
-
-.oo-ui-outlineControlsWidget {
- &-items,
- &-movers {
- float: left;
- .oo-ui-box-sizing(border-box);
- }
-
- > .oo-ui-iconElement-icon {
- float: left;
- background-position: right center;
- background-repeat: no-repeat;
- }
-
- &-items {
- float: left;
-
- .oo-ui-buttonWidget {
- float: left;
- }
- }
- &-movers {
- float: right;
-
- .oo-ui-buttonWidget {
- float: right;
- }
- }
-
- .theme-oo-ui-outlineControlsWidget();
-}
diff --git a/vendor/oojs/oojs-ui/src/styles/widgets/OutlineOptionWidget.less b/vendor/oojs/oojs-ui/src/styles/widgets/OutlineOptionWidget.less
deleted file mode 100644
index 6558c652..00000000
--- a/vendor/oojs/oojs-ui/src/styles/widgets/OutlineOptionWidget.less
+++ /dev/null
@@ -1,9 +0,0 @@
-@import '../common';
-
-.oo-ui-outlineOptionWidget {
- position: relative;
- cursor: pointer;
- .oo-ui-unselectable();
-
- .theme-oo-ui-outlineOptionWidget();
-}
diff --git a/vendor/oojs/oojs-ui/src/styles/widgets/OutlineSelectWidget.less b/vendor/oojs/oojs-ui/src/styles/widgets/OutlineSelectWidget.less
deleted file mode 100644
index 65fc621b..00000000
--- a/vendor/oojs/oojs-ui/src/styles/widgets/OutlineSelectWidget.less
+++ /dev/null
@@ -1,5 +0,0 @@
-@import '../common';
-
-.oo-ui-outlineSelectWidget {
- .theme-oo-ui-outlineSelectWidget();
-}
diff --git a/vendor/oojs/oojs-ui/src/styles/widgets/PopupButtonWidget.less b/vendor/oojs/oojs-ui/src/styles/widgets/PopupButtonWidget.less
deleted file mode 100644
index 805239ed..00000000
--- a/vendor/oojs/oojs-ui/src/styles/widgets/PopupButtonWidget.less
+++ /dev/null
@@ -1,12 +0,0 @@
-@import '../common';
-
-.oo-ui-popupButtonWidget {
- position: relative;
-
- .oo-ui-popupWidget {
- position: absolute;
- cursor: auto;
- }
-
- .theme-oo-ui-popupButtonWidget();
-}
diff --git a/vendor/oojs/oojs-ui/src/styles/widgets/PopupWidget.less b/vendor/oojs/oojs-ui/src/styles/widgets/PopupWidget.less
deleted file mode 100644
index d8fdd40c..00000000
--- a/vendor/oojs/oojs-ui/src/styles/widgets/PopupWidget.less
+++ /dev/null
@@ -1,49 +0,0 @@
-@import '../common';
-
-.oo-ui-popupWidget {
- position: absolute;
- /* @noflip */
- left: 0;
-
- &-popup {
- position: relative;
- overflow: hidden;
- z-index: 1;
- }
-
- &-anchor {
- display: none;
- z-index: 1;
- }
-
- &-anchored {
- .oo-ui-popupWidget-anchor {
- display: block;
- position: absolute;
- top: 0;
- /* @noflip */
- left: 0;
- background-repeat: no-repeat;
- }
- }
-
- &-head {
- .oo-ui-unselectable();
-
- .oo-ui-buttonWidget {
- float: right;
- }
-
- .oo-ui-labelElement-label {
- float: left;
- cursor: default;
- }
- }
-
- &-body {
- clear: both;
- overflow: hidden;
- }
-
- .theme-oo-ui-popupWidget();
-}
diff --git a/vendor/oojs/oojs-ui/src/styles/widgets/ProgressBarWidget.less b/vendor/oojs/oojs-ui/src/styles/widgets/ProgressBarWidget.less
deleted file mode 100644
index 82993fc1..00000000
--- a/vendor/oojs/oojs-ui/src/styles/widgets/ProgressBarWidget.less
+++ /dev/null
@@ -1,5 +0,0 @@
-@import '../common';
-
-.oo-ui-progressBarWidget {
- .theme-oo-ui-progressBarWidget();
-}
diff --git a/vendor/oojs/oojs-ui/src/styles/widgets/RadioInputWidget.less b/vendor/oojs/oojs-ui/src/styles/widgets/RadioInputWidget.less
deleted file mode 100644
index 7b75f871..00000000
--- a/vendor/oojs/oojs-ui/src/styles/widgets/RadioInputWidget.less
+++ /dev/null
@@ -1,5 +0,0 @@
-@import '../common';
-
-.oo-ui-radioInputWidget {
- .theme-oo-ui-radioInputWidget();
-}
diff --git a/vendor/oojs/oojs-ui/src/styles/widgets/RadioOptionWidget.less b/vendor/oojs/oojs-ui/src/styles/widgets/RadioOptionWidget.less
deleted file mode 100644
index 9a83997a..00000000
--- a/vendor/oojs/oojs-ui/src/styles/widgets/RadioOptionWidget.less
+++ /dev/null
@@ -1,13 +0,0 @@
-@import '../common';
-
-.oo-ui-radioOptionWidget {
- cursor: default;
-
- .oo-ui-radioInputWidget,
- &.oo-ui-labelElement .oo-ui-labelElement-label {
- display: inline-block;
- vertical-align: middle;
- }
-
- .theme-oo-ui-radioOptionWidget();
-}
diff --git a/vendor/oojs/oojs-ui/src/styles/widgets/RadioSelectWidget.less b/vendor/oojs/oojs-ui/src/styles/widgets/RadioSelectWidget.less
deleted file mode 100644
index f6900cb6..00000000
--- a/vendor/oojs/oojs-ui/src/styles/widgets/RadioSelectWidget.less
+++ /dev/null
@@ -1,5 +0,0 @@
-@import '../common';
-
-.oo-ui-radioSelectWidget {
- .theme-oo-ui-radioSelectWidget();
-}
diff --git a/vendor/oojs/oojs-ui/src/styles/widgets/SearchWidget.less b/vendor/oojs/oojs-ui/src/styles/widgets/SearchWidget.less
deleted file mode 100644
index 920beacf..00000000
--- a/vendor/oojs/oojs-ui/src/styles/widgets/SearchWidget.less
+++ /dev/null
@@ -1,25 +0,0 @@
-@import '../common';
-
-.oo-ui-searchWidget {
- &-query {
- position: absolute;
- top: 0;
- left: 0;
- right: 0;
-
- .oo-ui-textInputWidget {
- width: 100%;
- }
- }
-
- &-results {
- position: absolute;
- bottom: 0;
- left: 0;
- right: 0;
- overflow-x: hidden;
- overflow-y: auto;
- }
-
- .theme-oo-ui-searchWidget();
-}
diff --git a/vendor/oojs/oojs-ui/src/styles/widgets/SelectWidget.less b/vendor/oojs/oojs-ui/src/styles/widgets/SelectWidget.less
deleted file mode 100644
index 2ad0b943..00000000
--- a/vendor/oojs/oojs-ui/src/styles/widgets/SelectWidget.less
+++ /dev/null
@@ -1,5 +0,0 @@
-@import '../common';
-
-.oo-ui-selectWidget {
- .theme-oo-ui-selectWidget();
-}
diff --git a/vendor/oojs/oojs-ui/src/styles/widgets/TabOptionWidget.less b/vendor/oojs/oojs-ui/src/styles/widgets/TabOptionWidget.less
deleted file mode 100644
index 0b83154c..00000000
--- a/vendor/oojs/oojs-ui/src/styles/widgets/TabOptionWidget.less
+++ /dev/null
@@ -1,8 +0,0 @@
-@import '../common';
-
-.oo-ui-tabOptionWidget {
- display: inline-block;
- vertical-align: bottom;
-
- .theme-oo-ui-tabOptionWidget();
-}
diff --git a/vendor/oojs/oojs-ui/src/styles/widgets/TabSelectWidget.less b/vendor/oojs/oojs-ui/src/styles/widgets/TabSelectWidget.less
deleted file mode 100644
index b3a57c98..00000000
--- a/vendor/oojs/oojs-ui/src/styles/widgets/TabSelectWidget.less
+++ /dev/null
@@ -1,9 +0,0 @@
-@import '../common';
-
-.oo-ui-tabSelectWidget {
- text-align: left;
- white-space: nowrap;
- overflow: hidden;
-
- .theme-oo-ui-tabSelectWidget();
-}
diff --git a/vendor/oojs/oojs-ui/src/styles/widgets/TextInputMenuSelectWidget.less b/vendor/oojs/oojs-ui/src/styles/widgets/TextInputMenuSelectWidget.less
deleted file mode 100644
index 6edc474b..00000000
--- a/vendor/oojs/oojs-ui/src/styles/widgets/TextInputMenuSelectWidget.less
+++ /dev/null
@@ -1,5 +0,0 @@
-@import '../common';
-
-.oo-ui-textInputMenuSelectWidget {
- .theme-oo-ui-textInputMenuSelectWidget();
-}
diff --git a/vendor/oojs/oojs-ui/src/styles/widgets/TextInputWidget.less b/vendor/oojs/oojs-ui/src/styles/widgets/TextInputWidget.less
deleted file mode 100644
index dd0cdf46..00000000
--- a/vendor/oojs/oojs-ui/src/styles/widgets/TextInputWidget.less
+++ /dev/null
@@ -1,71 +0,0 @@
-@import '../common';
-
-.oo-ui-textInputWidget {
- position: relative;
- // Necessary for proper alignment when used with display: inline-block
- vertical-align: middle;
- .oo-ui-box-sizing(border-box);
-
- input,
- textarea {
- display: inline-block;
- width: 100%;
- resize: none;
- .oo-ui-box-sizing(border-box);
- }
-
- > .oo-ui-iconElement-icon,
- > .oo-ui-indicatorElement-indicator,
- > .oo-ui-labelElement-label {
- display: none;
- }
-
- &.oo-ui-iconElement > .oo-ui-iconElement-icon,
- &.oo-ui-indicatorElement > .oo-ui-indicatorElement-indicator {
- display: block;
- position: absolute;
- top: 0;
- height: 100%;
- background-repeat: no-repeat;
-
- .oo-ui-unselectable();
- }
-
- &.oo-ui-widget-enabled {
- > .oo-ui-iconElement-icon,
- > .oo-ui-indicatorElement-indicator {
- cursor: pointer;
- }
- }
-
- &.oo-ui-labelElement > .oo-ui-labelElement-label {
- display: block;
- }
-
- > .oo-ui-iconElement-icon {
- left: 0;
- }
-
- > .oo-ui-indicatorElement-indicator {
- right: 0;
- }
-
- > .oo-ui-labelElement-label {
- position: absolute;
- top: 0;
- }
-
- &-labelPosition-after {
- > .oo-ui-labelElement-label {
- right: 0
- }
- }
-
- &-labelPosition-before {
- > .oo-ui-labelElement-label {
- left: 0
- }
- }
-
- .theme-oo-ui-textInputWidget();
-}
diff --git a/vendor/oojs/oojs-ui/src/styles/widgets/ToggleButtonWidget.less b/vendor/oojs/oojs-ui/src/styles/widgets/ToggleButtonWidget.less
deleted file mode 100644
index 5441e4e8..00000000
--- a/vendor/oojs/oojs-ui/src/styles/widgets/ToggleButtonWidget.less
+++ /dev/null
@@ -1,8 +0,0 @@
-@import '../common';
-
-.oo-ui-toggleButtonWidget {
- display: inline-block;
- vertical-align: middle;
-
- .theme-oo-ui-toggleButtonWidget();
-}
diff --git a/vendor/oojs/oojs-ui/src/styles/widgets/ToggleSwitchWidget.less b/vendor/oojs/oojs-ui/src/styles/widgets/ToggleSwitchWidget.less
deleted file mode 100644
index f030cf66..00000000
--- a/vendor/oojs/oojs-ui/src/styles/widgets/ToggleSwitchWidget.less
+++ /dev/null
@@ -1,41 +0,0 @@
-@import '../common';
-
-.oo-ui-toggleSwitchWidget {
- position: relative;
- display: inline-block;
- vertical-align: middle;
- overflow: hidden;
- cursor: pointer;
-
- .oo-ui-box-sizing(border-box);
- .oo-ui-transform(translateZ(0px));
-
- &.oo-ui-widget-disabled {
- cursor: default;
- }
-
- &-grip {
- position: absolute;
- display: block;
-
- .oo-ui-box-sizing(border-box);
- }
-
- .oo-ui-toggleSwitchWidget-glow {
- position: absolute;
- top: 0;
- bottom: 0;
- right: 0;
- left: 0;
-
- .oo-ui-unselectable();
- }
-
- .oo-ui-toggleWidget-off & {
- &-glow {
- display: none;
- }
- }
-
- .theme-oo-ui-toggleSwitchWidget();
-}
diff --git a/vendor/oojs/oojs-ui/src/styles/widgets/ToggleWidget.less b/vendor/oojs/oojs-ui/src/styles/widgets/ToggleWidget.less
deleted file mode 100644
index f51e45b5..00000000
--- a/vendor/oojs/oojs-ui/src/styles/widgets/ToggleWidget.less
+++ /dev/null
@@ -1,5 +0,0 @@
-@import '../common';
-
-.oo-ui-toggleWidget {
- .theme-oo-ui-toggleWidget();
-}
diff --git a/vendor/oojs/oojs-ui/src/themes/apex/ApexTheme.js b/vendor/oojs/oojs-ui/src/themes/apex/ApexTheme.js
deleted file mode 100644
index 157dfb64..00000000
--- a/vendor/oojs/oojs-ui/src/themes/apex/ApexTheme.js
+++ /dev/null
@@ -1,18 +0,0 @@
-/**
- * @class
- * @extends OO.ui.Theme
- *
- * @constructor
- */
-OO.ui.ApexTheme = function OoUiApexTheme() {
- // Parent constructor
- OO.ui.ApexTheme.super.call( this );
-};
-
-/* Setup */
-
-OO.inheritClass( OO.ui.ApexTheme, OO.ui.Theme );
-
-/* Instantiation */
-
-OO.ui.theme = new OO.ui.ApexTheme();
diff --git a/vendor/oojs/oojs-ui/src/themes/apex/common.less b/vendor/oojs/oojs-ui/src/themes/apex/common.less
deleted file mode 100644
index 74dd3a3b..00000000
--- a/vendor/oojs/oojs-ui/src/themes/apex/common.less
+++ /dev/null
@@ -1,27 +0,0 @@
-// Base variables and mixins
-@import '../../styles/common';
-
-// Theme variables
-
-@progressive: #087ecc;
-@constructive: #76ab36;
-@destructive: #d45353;
-
-@progressive-gradient-start: #eaf4fa;
-@progressive-gradient-end: #b0d9ee;
-@progressive-border: #a6cee1;
-@progressive-border-selected: #9dc2d4;
-
-@constructive-gradient-start: #f0fbe1;
-@constructive-gradient-end: #c3e59a;
-@constructive-border: #b8d892;
-@constructive-border-selected: #adcb89;
-
-@oo-ui-default-image-path: 'themes/apex/images';
-
-@icon-size: unit(24 / 16 / 0.8, em);
-@indicator-size: unit(12 / 16 / 0.8, em);
-
-// Theme mixins
-
-// (add mixins here)
diff --git a/vendor/oojs/oojs-ui/src/themes/apex/core.less b/vendor/oojs/oojs-ui/src/themes/apex/core.less
deleted file mode 100644
index 1c83a946..00000000
--- a/vendor/oojs/oojs-ui/src/themes/apex/core.less
+++ /dev/null
@@ -1,12 +0,0 @@
-// Base and theme variables and mixins
-@import 'common';
-
-// Theme rules
-@import 'elements';
-@import 'layouts';
-@import 'tools';
-@import 'widgets';
-@import 'windows';
-
-// Base rules
-@import '../../styles/core';
diff --git a/vendor/oojs/oojs-ui/src/themes/apex/elements.less b/vendor/oojs/oojs-ui/src/themes/apex/elements.less
deleted file mode 100644
index bfd11228..00000000
--- a/vendor/oojs/oojs-ui/src/themes/apex/elements.less
+++ /dev/null
@@ -1,247 +0,0 @@
-@import 'common';
-
-.theme-oo-ui-element () {}
-
-.theme-oo-ui-buttonElement () {
- > .oo-ui-buttonElement-button {
- color: #333;
- }
-
- &.oo-ui-iconElement > .oo-ui-buttonElement-button {
- > .oo-ui-iconElement-icon {
- margin-left: 0;
- }
- }
-
- &.oo-ui-indicatorElement > .oo-ui-buttonElement-button {
- > .oo-ui-indicatorElement-indicator {
- width: @indicator-size;
- height: @indicator-size;
- margin: @indicator-size / 2;
- }
- }
-
- &.oo-ui-iconElement > .oo-ui-buttonElement-button > .oo-ui-indicatorElement-indicator {
- margin-left: @indicator-size / 2;
- }
- &.oo-ui-iconElement > .oo-ui-buttonElement-button > .oo-ui-iconElement-icon {
- width: @icon-size;
- height: @icon-size;
- }
-
- &-frameless {
- > .oo-ui-buttonElement-button {
- > .oo-ui-iconElement-icon {
- /* Don't animate opacities for now, causes wiggling in Chrome (bug 63020) */
- /*.oo-ui-transition(opacity 200ms);*/
- }
-
- &:hover,
- &:focus {
- outline: none;
-
- > .oo-ui-iconElement-icon {
- opacity: 1;
- }
- > .oo-ui-labelElement-label {
- color: #000;
- }
- }
-
- > .oo-ui-labelElement-label {
- color: #333;
- }
- }
-
- &.oo-ui-labelElement {
- > .oo-ui-buttonElement-button {
- > .oo-ui-labelElement-label {
- margin-left: 0.25em;
- }
- }
- }
-
- &.oo-ui-flaggedElement {
- &-progressive > .oo-ui-buttonElement-button > .oo-ui-labelElement-label {
- color: @progressive;
- }
-
- &-constructive > .oo-ui-buttonElement-button > .oo-ui-labelElement-label {
- color: @constructive;
- }
-
- &-destructive > .oo-ui-buttonElement-button > .oo-ui-labelElement-label {
- color: @destructive;
- }
- }
-
- &.oo-ui-widget-disabled > .oo-ui-buttonElement-button {
- > .oo-ui-iconElement-icon {
- opacity: 0.2;
- }
- > .oo-ui-labelElement-label {
- color: #ccc;
- }
- }
- }
-
- &-framed {
- > .oo-ui-buttonElement-button {
- margin: 0.1em 0;
- padding: 0.2em 0.8em;
- border-radius: 0.3em;
- text-shadow: 0 1px 1px rgba(255, 255, 255, 0.5);
- border: 1px #c9c9c9 solid;
- .oo-ui-transition(border-color 100ms ease-in-out);
- .oo-ui-vertical-gradient(#fff, #ddd);
-
- &:hover,
- &:focus {
- border-color: #aaa;
- outline: none;
- }
- }
-
- // Support <input/> from ButtonInputWidget
- > input.oo-ui-buttonElement-button,
- &.oo-ui-labelElement > .oo-ui-buttonElement-button > .oo-ui-labelElement-label {
- line-height: @icon-size;
- }
-
- &.oo-ui-widget-enabled > .oo-ui-buttonElement-button:active,
- &.oo-ui-buttonElement-active > .oo-ui-buttonElement-button,
- &.oo-ui-buttonElement-pressed > .oo-ui-buttonElement-button {
- box-shadow: inset 0 1px 4px 0 rgba(0, 0, 0, 0.07);
- color: black;
- border-color: #c9c9c9;
- .oo-ui-vertical-gradient(#ddd, #fff);
- }
-
- &.oo-ui-iconElement {
- > .oo-ui-buttonElement-button > .oo-ui-iconElement-icon {
- margin-left: -0.5em;
- margin-right: -0.5em;
- }
-
- &.oo-ui-labelElement > .oo-ui-buttonElement-button > .oo-ui-iconElement-icon {
- margin-right: 0.3em;
- }
- }
-
- &.oo-ui-indicatorElement {
- > .oo-ui-buttonElement-button > .oo-ui-indicatorElement-indicator {
- /* -0.5 - 0.475 */
- margin-left: -0.005em;
- margin-right: -0.005em;
- }
-
- &.oo-ui-labelElement > .oo-ui-buttonElement-button > .oo-ui-indicatorElement-indicator,
- &.oo-ui-iconElement:not( .oo-ui-labelElement ) > .oo-ui-buttonElement-button > .oo-ui-indicatorElement-indicator {
- margin-left: @indicator-size / 2;
- margin-right: -0.275em;
- }
- }
-
- &.oo-ui-flaggedElement {
- &-progressive {
- > .oo-ui-buttonElement-button {
- border: 1px solid @progressive-border;
- .oo-ui-vertical-gradient(@progressive-gradient-start, @progressive-gradient-end);
-
- &:hover,
- &:focus {
- border-color: @progressive-border-selected;
- }
- }
-
- &.oo-ui-widget-enabled > .oo-ui-buttonElement-button:active,
- &.oo-ui-buttonElement-active > .oo-ui-buttonElement-button,
- &.oo-ui-buttonElement-pressed > .oo-ui-buttonElement-button {
- border: 1px solid @progressive-border;
- .oo-ui-vertical-gradient(@progressive-gradient-end, @progressive-gradient-start);
- }
- }
-
- &-constructive {
- > .oo-ui-buttonElement-button {
- border: 1px solid @constructive-border;
- .oo-ui-vertical-gradient(@constructive-gradient-start, @constructive-gradient-end);
-
- &:hover,
- &:focus {
- border-color: @constructive-border-selected;
- }
- }
-
- &.oo-ui-widget-enabled > .oo-ui-buttonElement-button:active,
- &.oo-ui-buttonElement-active > .oo-ui-buttonElement-button,
- &.oo-ui-buttonElement-pressed > .oo-ui-buttonElement-button {
- border: 1px solid @constructive-border;
- .oo-ui-vertical-gradient(@constructive-gradient-end, @constructive-gradient-start);
- }
- }
-
- &-destructive > .oo-ui-buttonElement-button {
- color: @destructive;
- }
- }
-
- &.oo-ui-widget-disabled {
- > .oo-ui-buttonElement-button,
- &.oo-ui-buttonElement-active > .oo-ui-buttonElement-button,
- &.oo-ui-buttonElement-pressed > .oo-ui-buttonElement-button {
- opacity: 0.5;
- // Opacity causes 1px measurement errors in Chrome, so force GPU rendering
- .oo-ui-force-webkit-gpu();
- box-shadow: none;
- color: #333;
- background: #eee;
- border-color: #ccc;
-
- &:hover,
- &:focus {
- border-color: #ccc;
- box-shadow: none;
- }
- }
- }
- }
-}
-
-.theme-oo-ui-clippableElement () {}
-
-.theme-oo-ui-flaggedElement () {}
-
-.theme-oo-ui-draggableElement () {}
-
-.theme-oo-ui-groupElement () {}
-
-.theme-oo-ui-draggableGroupElement () {}
-
-.theme-oo-ui-iconElement () {
- .oo-ui-iconElement-icon,
- &.oo-ui-iconElement-icon {
- opacity: 0.8;
- background-size: contain;
- background-position: center center;
- }
-}
-
-.theme-oo-ui-indicatorElement () {
- .oo-ui-indicatorElement-indicator,
- &.oo-ui-indicatorElement-indicator {
- opacity: 0.8;
- background-size: contain;
- background-position: center center;
- }
-}
-
-.theme-oo-ui-labelElement () {}
-
-.theme-oo-ui-lookupElement () {}
-
-.theme-oo-ui-popupElement () {}
-
-.theme-oo-ui-tabIndexedElement () {}
-
-.theme-oo-ui-titledElement () {}
diff --git a/vendor/oojs/oojs-ui/src/themes/apex/icons-editing-advanced.json b/vendor/oojs/oojs-ui/src/themes/apex/icons-editing-advanced.json
deleted file mode 100644
index 8fdc5051..00000000
--- a/vendor/oojs/oojs-ui/src/themes/apex/icons-editing-advanced.json
+++ /dev/null
@@ -1,75 +0,0 @@
-{
- "prefix": "oo-ui-icon",
- "intro": "@import '../../../../src/styles/common';",
- "images": {
- "alignCentre": { "file": "images/icons/align-center.svg" },
- "alignLeft": { "file": "images/icons/align-float-left.svg" },
- "alignRight": { "file": "images/icons/align-float-right.svg" },
- "find": { "file": {
- "ltr": "images/icons/find-ltr.svg",
- "rtl": "images/icons/find-rtl.svg"
- } },
- "insert": { "file": "images/icons/insert.svg" },
- "layout": { "file": {
- "ltr": "images/icons/layout-ltr.svg",
- "rtl": "images/icons/layout-rtl.svg"
- } },
- "newline": { "file": {
- "ltr": "images/icons/newline-ltr.svg",
- "rtl": "images/icons/newline-rtl.svg"
- } },
- "redirect": { "file": {
- "ltr": "images/icons/redirect-ltr.svg",
- "rtl": "images/icons/redirect-rtl.svg"
- } },
- "noWikiText": { "file": {
- "ltr": "images/icons/noWikiText-ltr.svg",
- "rtl": "images/icons/noWikiText-rtl.svg"
- } },
- "outline": { "file": {
- "ltr": "images/icons/outline-ltr.svg",
- "rtl": "images/icons/outline-rtl.svg"
- } },
- "puzzle": { "file": {
- "ltr": "images/icons/puzzle-ltr.svg",
- "rtl": "images/icons/puzzle-rtl.svg"
- } },
- "quotes": { "file": {
- "ltr": "images/icons/quotes-ltr.svg",
- "rtl": "images/icons/quotes-rtl.svg"
- } },
- "quotesAdd": { "file": {
- "ltr": "images/icons/quotesAdd-ltr.svg",
- "rtl": "images/icons/quotesAdd-rtl.svg"
- } },
- "redirect": { "file": {
- "ltr": "images/icons/redirect-ltr.svg",
- "rtl": "images/icons/redirect-rtl.svg"
- } },
- "searchCaseSensitive": { "file": "images/icons/case-sensitive.svg" },
- "searchRegularExpression": { "file": "images/icons/regular-expression.svg" },
- "specialCharacter": { "file": "images/icons/specialCharacter.svg" },
- "table": { "file": "images/icons/table.svg" },
- "tableAddColumnAfter": { "file": {
- "ltr": "images/icons/table-insert-column-rtl.svg",
- "rtl": "images/icons/table-insert-column-ltr.svg"
- } },
- "tableAddColumnBefore": { "file": {
- "ltr": "images/icons/table-insert-column-ltr.svg",
- "rtl": "images/icons/table-insert-column-rtl.svg"
- } },
- "tableAddRowAfter": { "file": "images/icons/table-insert-row-after.svg" },
- "tableAddRowBefore": { "file": "images/icons/table-insert-row-before.svg" },
- "tableCaption": { "file": "images/icons/table-caption.svg" },
- "tableMergeCells": { "file": "images/icons/table-merge-cells.svg" },
- "templateAdd": { "file": {
- "ltr": "images/icons/templateAdd-ltr.svg",
- "rtl": "images/icons/templateAdd-rtl.svg"
- } },
- "translation": { "file": {
- "ltr": "images/icons/translation-ltr.svg",
- "rtl": "images/icons/translation-rtl.svg"
- } },
- "wikiText": { "file": "images/icons/wikiText.svg" }
- }
-}
diff --git a/vendor/oojs/oojs-ui/src/themes/apex/icons-editing-core.json b/vendor/oojs/oojs-ui/src/themes/apex/icons-editing-core.json
deleted file mode 100644
index 95e8358e..00000000
--- a/vendor/oojs/oojs-ui/src/themes/apex/icons-editing-core.json
+++ /dev/null
@@ -1,24 +0,0 @@
-{
- "prefix": "oo-ui-icon",
- "intro": "@import '../../../../src/styles/common';",
- "images": {
- "edit": { "file": {
- "ltr": "images/icons/edit-ltr.svg",
- "rtl": "images/icons/edit-rtl.svg"
- } },
- "editLock": { "file": {
- "ltr": "images/icons/editLock-ltr.svg",
- "rtl": "images/icons/editLock-rtl.svg"
- } },
- "editUndo": { "file": {
- "ltr": "images/icons/editUndo-ltr.svg",
- "rtl": "images/icons/editUndo-rtl.svg"
- } },
- "link": { "file": "images/icons/link.svg" },
- "linkExternal": { "file": {
- "ltr": "images/icons/external-link-ltr.svg",
- "rtl": "images/icons/external-link-rtl.svg"
- } },
- "linkSecure": { "file": "images/icons/secure-link.svg" }
- }
-}
diff --git a/vendor/oojs/oojs-ui/src/themes/apex/icons-editing-list.json b/vendor/oojs/oojs-ui/src/themes/apex/icons-editing-list.json
deleted file mode 100644
index 490f8faf..00000000
--- a/vendor/oojs/oojs-ui/src/themes/apex/icons-editing-list.json
+++ /dev/null
@@ -1,22 +0,0 @@
-{
- "prefix": "oo-ui-icon",
- "intro": "@import '../../../../src/styles/common';",
- "images": {
- "indent": { "file": {
- "ltr": "images/icons/indent-ltr.svg",
- "rtl": "images/icons/indent-rtl.svg"
- } },
- "listBullet": { "file": {
- "ltr": "images/icons/listBullet-ltr.svg",
- "rtl": "images/icons/listBullet-rtl.svg"
- } },
- "listNumbered": { "file": {
- "ltr": "images/icons/listNumbered-ltr.svg",
- "rtl": "images/icons/listNumbered-rtl.svg"
- } },
- "outdent": { "file": {
- "ltr": "images/icons/outdent-ltr.svg",
- "rtl": "images/icons/outdent-rtl.svg"
- } }
- }
-}
diff --git a/vendor/oojs/oojs-ui/src/themes/apex/icons-editing-styling.json b/vendor/oojs/oojs-ui/src/themes/apex/icons-editing-styling.json
deleted file mode 100644
index 65fbc218..00000000
--- a/vendor/oojs/oojs-ui/src/themes/apex/icons-editing-styling.json
+++ /dev/null
@@ -1,72 +0,0 @@
-{
- "prefix": "oo-ui-icon",
- "intro": "@import '../../../../src/styles/common';",
- "images": {
- "bigger": { "file": {
- "ltr": "images/icons/bigger-ltr.svg",
- "rtl": "images/icons/bigger-rtl.svg"
- } },
- "smaller": { "file": {
- "ltr": "images/icons/smaller-ltr.svg",
- "rtl": "images/icons/smaller-rtl.svg"
- } },
- "subscript": { "file": {
- "ltr": "images/icons/subscript-ltr.svg",
- "rtl": "images/icons/subscript-rtl.svg"
- } },
- "superscript": { "file": {
- "ltr": "images/icons/superscript-ltr.svg",
- "rtl": "images/icons/superscript-rtl.svg"
- } },
- "bold": { "file": {
- "default": "images/icons/bold-a.svg",
- "lang": {
- "ar": "images/icons/bold-arab-ain.svg",
- "be": "images/icons/bold-cyrl-te.svg",
- "cs,en,he,ml,pl": "images/icons/bold-b.svg",
- "da,de,hu,ksh,nn,no,sv": "images/icons/bold-f.svg",
- "es,gl,pt": "images/icons/bold-n.svg",
- "eu,fi": "images/icons/bold-l.svg",
- "fa": "images/icons/bold-arab-dad.svg",
- "fr,it": "images/icons/bold-g.svg",
- "hy": "images/icons/bold-armn-to.svg",
- "ka": "images/icons/bold-geor-man.svg",
- "ky,ru": "images/icons/bold-cyrl-zhe.svg",
- "nl": "images/icons/bold-v.svg",
- "os": "images/icons/bold-cyrl-be.svg"
- }
- } },
- "italic": { "file": {
- "default": "images/icons/italic-a.svg",
- "lang": {
- "ar": "images/icons/italic-arab-meem.svg",
- "cs,en,fr,he,ml,pl,pt": "images/icons/italic-i.svg",
- "be,da,de,fi,ky,nn,no,os,sv,ru": "images/icons/italic-k.svg",
- "es,gl,it,nl": "images/icons/italic-c.svg",
- "eu": "images/icons/italic-e.svg",
- "fa": "images/icons/italic-arab-keheh-jeem.svg",
- "hu": "images/icons/italic-d.svg",
- "hy": "images/icons/italic-armn-sha.svg",
- "ksh": "images/icons/italic-s.svg",
- "ka": "images/icons/italic-geor-kan.svg"
- }
- } },
- "strikethrough": { "file": {
- "default": "images/icons/strikethrough-a.svg",
- "lang": {
- "en": "images/icons/strikethrough-s.svg",
- "fi": "images/icons/strikethrough-y.svg"
- }
- } },
- "underline": { "file": {
- "default": "images/icons/underline-a.svg",
- "lang": {
- "en": "images/icons/underline-u.svg"
- }
- } },
- "textLanguage": { "file": "images/icons/language.svg" },
- "textDirLTR": { "file": "images/icons/text-dir-lefttoright.svg" },
- "textDirRTL": { "file": "images/icons/text-dir-righttoleft.svg" },
- "textStyle": { "file": "images/icons/text-style.svg" }
- }
-}
diff --git a/vendor/oojs/oojs-ui/src/themes/apex/icons-moderation.json b/vendor/oojs/oojs-ui/src/themes/apex/icons-moderation.json
deleted file mode 100644
index f904cc26..00000000
--- a/vendor/oojs/oojs-ui/src/themes/apex/icons-moderation.json
+++ /dev/null
@@ -1,33 +0,0 @@
-{
- "prefix": "oo-ui-icon",
- "intro": "@import '../../../../src/styles/common';",
- "images": {
- "block": { "file": "images/icons/block.svg" },
- "blockUndo": { "file": {
- "ltr": "images/icons/blockUndo-ltr.svg",
- "rtl": "images/icons/blockUndo-rtl.svg"
- } },
- "flag": { "file": {
- "ltr": "images/icons/flag-ltr.svg",
- "rtl": "images/icons/flag-rtl.svg"
- } },
- "flagUndo": { "file": {
- "ltr": "images/icons/flagUndo-ltr.svg",
- "rtl": "images/icons/flagUndo-rtl.svg"
- } },
- "lock": { "file": "images/icons/lock.svg" },
- "star": { "file": "images/icons/star.svg" },
- "trash": { "file": "images/icons/trash.svg" },
- "trashUndo": { "file": {
- "ltr": "images/icons/trashUndo-ltr.svg",
- "rtl": "images/icons/trashUndo-rtl.svg"
- } },
- "unLock": { "file": {
- "ltr": "images/icons/unLock-ltr.svg",
- "rtl": "images/icons/unLock-rtl.svg"
- } },
- "unStar": { "file": "images/icons/unStar.svg" }
-
-
- }
-}
diff --git a/vendor/oojs/oojs-ui/src/themes/apex/icons-movement.json b/vendor/oojs/oojs-ui/src/themes/apex/icons-movement.json
deleted file mode 100644
index 9aa1b809..00000000
--- a/vendor/oojs/oojs-ui/src/themes/apex/icons-movement.json
+++ /dev/null
@@ -1,27 +0,0 @@
-{
- "prefix": "oo-ui-icon",
- "intro": "@import '../../../../src/styles/common';",
- "images": {
- "arrowNext": { "file": {
- "ltr": "images/icons/arrow-ltr.svg",
- "rtl": "images/icons/arrow-rtl.svg"
- } },
- "arrowLast": { "file": {
- "ltr": "images/icons/arrow-rtl.svg",
- "rtl": "images/icons/arrow-ltr.svg"
- } },
- "caretNext": { "file": {
- "ltr": "images/icons/caret-rtl.svg",
- "rtl": "images/icons/caret-ltr.svg"
- } },
- "caretLast": { "file": {
- "ltr": "images/icons/caret-ltr.svg",
- "rtl": "images/icons/caret-rtl.svg"
- } },
- "caretDown": { "file": "images/icons/caretDown.svg" },
- "caretUp": { "file": "images/icons/caretUp.svg" },
- "downTriangle": { "file": "images/icons/downTriangle.svg" },
- "move": { "file": "images/icons/move.svg" },
- "upTriangle": { "file": "images/icons/upTriangle.svg" }
- }
-}
diff --git a/vendor/oojs/oojs-ui/src/themes/apex/icons.json b/vendor/oojs/oojs-ui/src/themes/apex/icons.json
deleted file mode 100644
index 9372363f..00000000
--- a/vendor/oojs/oojs-ui/src/themes/apex/icons.json
+++ /dev/null
@@ -1,50 +0,0 @@
-{
- "prefix": "oo-ui-icon",
- "intro": "@import '../../../../src/styles/common';",
- "images": {
- "circle": { "file": "images/icons/circle.svg" },
- "add": { "file": "images/icons/add.svg" },
- "advanced": { "file": "images/icons/advanced.svg" },
- "cancel": { "file": "images/icons/cancel.svg" },
- "alert": { "file": "images/icons/alert.svg" },
- "check": { "file": "images/icons/check.svg" },
- "close": { "file": "images/icons/close.svg" },
- "code": { "file": "images/icons/code.svg" },
- "collapse": { "file": "images/icons/collapse.svg" },
- "comment": { "file": "images/icons/comment.svg" },
- "ellipsis": { "file": "images/icons/ellipsis.svg" },
- "expand": { "file": "images/icons/expand.svg" },
- "help": { "file": {
- "ltr": "images/icons/help-ltr.svg",
- "rtl": "images/icons/help-rtl.svg",
- "lang": {
- "he,yi": "images/icons/help-ltr.svg"
- }
- } },
- "history": { "file": "images/icons/history.svg" },
- "info": { "file": "images/icons/info.svg" },
- "menu": { "file": "images/icons/menu.svg" },
- "next": { "file": {
- "ltr": "images/icons/move-ltr.svg",
- "rtl": "images/icons/move-rtl.svg"
- } },
- "picture": { "file": "images/icons/picture.svg" },
- "previous": { "file": {
- "ltr": "images/icons/move-rtl.svg",
- "rtl": "images/icons/move-ltr.svg"
- } },
- "redo": { "file": {
- "ltr": "images/icons/arched-arrow-ltr.svg",
- "rtl": "images/icons/arched-arrow-rtl.svg"
- } },
- "remove": { "file": "images/icons/remove.svg" },
- "search": { "file": "images/icons/search.svg" },
- "settings": { "file": "images/icons/settings.svg" },
- "tag": { "file": "images/icons/tag.svg" },
- "undo": { "file": {
- "ltr": "images/icons/arched-arrow-rtl.svg",
- "rtl": "images/icons/arched-arrow-ltr.svg"
- } },
- "window": { "file": "images/icons/window.svg" }
- }
-}
diff --git a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/add.svg b/vendor/oojs/oojs-ui/src/themes/apex/images/icons/add.svg
deleted file mode 100644
index 29e5dba8..00000000
--- a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/add.svg
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="add">
- <path id="plus" d="M13 8h-2v3h-3v2h3v3h2v-3h3v-2h-3z"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/advanced.svg b/vendor/oojs/oojs-ui/src/themes/apex/images/icons/advanced.svg
deleted file mode 100644
index 201b4d73..00000000
--- a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/advanced.svg
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="settings">
- <path id="gear" d="M20.869 13.476c.079-.482.131-.972.131-1.476s-.052-.994-.131-1.476l-2.463-.259c-.149-.556-.367-1.082-.648-1.57l1.558-1.924c-.576-.806-1.281-1.511-2.087-2.087l-1.924 1.558c-.488-.281-1.015-.499-1.57-.648l-.259-2.463c-.482-.079-.972-.131-1.476-.131s-.994.052-1.476.131l-.259 2.463c-.555.149-1.081.367-1.57.648l-1.924-1.557c-.805.576-1.51 1.281-2.086 2.086l1.558 1.924c-.281.488-.499 1.015-.648 1.57l-2.463.259c-.08.482-.132.972-.132 1.476s.052.994.131 1.476l2.463.259c.149.556.367 1.082.648 1.57l-1.558 1.924c.576.806 1.281 1.511 2.087 2.087l1.924-1.558c.488.281 1.015.499 1.57.648l.259 2.463c.482.079.972.131 1.476.131s.994-.052 1.476-.131l.259-2.463c.556-.149 1.082-.367 1.57-.648l1.924 1.558c.806-.576 1.511-1.281 2.087-2.087l-1.558-1.924c.281-.488.499-1.015.648-1.57l2.463-.259zm-8.869 2.522c-2.209 0-3.998-1.789-3.998-3.998s1.789-3.998 3.998-3.998 3.998 1.789 3.998 3.998-1.789 3.998-3.998 3.998z"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/alert.svg b/vendor/oojs/oojs-ui/src/themes/apex/images/icons/alert.svg
deleted file mode 100644
index f0c65224..00000000
--- a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/alert.svg
+++ /dev/null
@@ -1,8 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="alert">
- <path id="point" d="M11 16h2v2h-2z"/>
- <path id="stroke" d="M13.516 10h-3l.484 5h2z"/>
- <path id="triangle" d="M12.017 5.974l7.519 13.026h-15.04l7.521-13.026m0-2.474c-.544 0-1.088.357-1.5 1.071l-7.985 13.831c-.825 1.429-.15 2.598 1.5 2.598h15.968c1.65 0 2.325-1.169 1.5-2.599l-7.983-13.829c-.413-.715-.956-1.072-1.5-1.072z"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/align-center.svg b/vendor/oojs/oojs-ui/src/themes/apex/images/icons/align-center.svg
deleted file mode 100644
index 887c2f66..00000000
--- a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/align-center.svg
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="align-center">
- <path d="M9 9h6c.554 0 1 .446 1 1v5c0 .554-.446 1-1 1h-6c-.554 0-1-.446-1-1v-5c0-.554.446-1 1-1zM3.5 18h17c.277 0 .5.223.5.5s-.223.5-.5.5h-17c-.277 0-.5-.223-.5-.5s.223-.5.5-.5zM3.5 6h17c.277 0 .5.223.5.5s-.223.5-.5.5h-17c-.277 0-.5-.223-.5-.5s.223-.5.5-.5z"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/align-float-left.svg b/vendor/oojs/oojs-ui/src/themes/apex/images/icons/align-float-left.svg
deleted file mode 100644
index ce9761e2..00000000
--- a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/align-float-left.svg
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="align-float-left">
- <path d="M4 9h6c.554 0 1 .446 1 1v5c0 .554-.446 1-1 1h-6c-.554 0-1-.446-1-1v-5c0-.554.446-1 1-1zM13.5 9h7c.277 0 .5.223.5.5s-.223.5-.5.5h-7c-.277 0-.5-.223-.5-.5s.223-.5.5-.5zM13.5 12h7c.277 0 .5.223.5.5s-.223.5-.5.5h-7c-.277 0-.5-.223-.5-.5s.223-.5.5-.5zM13.5 15h7c.277 0 .5.223.5.5s-.223.5-.5.5h-7c-.277 0-.5-.223-.5-.5s.223-.5.5-.5zM3.5 6h17c.277 0 .5.223.5.5s-.223.5-.5.5h-17c-.277 0-.5-.223-.5-.5s.223-.5.5-.5zM3.5 18h17c.277 0 .5.223.5.5s-.223.5-.5.5h-17c-.277 0-.5-.223-.5-.5s.223-.5.5-.5z"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/align-float-right.svg b/vendor/oojs/oojs-ui/src/themes/apex/images/icons/align-float-right.svg
deleted file mode 100644
index 557692ae..00000000
--- a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/align-float-right.svg
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="align-float-right">
- <path d="M20 9h-6c-.554 0-1 .446-1 1v5c0 .554.446 1 1 1h6c.554 0 1-.446 1-1v-5c0-.554-.446-1-1-1zM10.5 9h-7c-.277 0-.5.223-.5.5s.223.5.5.5h7c.277 0 .5-.223.5-.5s-.223-.5-.5-.5zM10.5 12h-7c-.277 0-.5.223-.5.5s.223.5.5.5h7c.277 0 .5-.223.5-.5s-.223-.5-.5-.5zM10.5 15h-7c-.277 0-.5.223-.5.5s.223.5.5.5h7c.277 0 .5-.223.5-.5s-.223-.5-.5-.5zM20.5 6h-17c-.277 0-.5.223-.5.5s.223.5.5.5h17c.277 0 .5-.223.5-.5s-.223-.5-.5-.5zM20.5 18h-17c-.277 0-.5.223-.5.5s.223.5.5.5h17c.277 0 .5-.223.5-.5s-.223-.5-.5-.5z"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/arched-arrow-ltr.svg b/vendor/oojs/oojs-ui/src/themes/apex/images/icons/arched-arrow-ltr.svg
deleted file mode 100644
index 8a670ef2..00000000
--- a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/arched-arrow-ltr.svg
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="arched-arrow-ltr">
- <path id="arrow" d="M19.925 14.937l-2.391-6.901-1.48 2.329c-.964-.845-2.699-1.85-5.513-1.823-4.887.046-6.524 4.244-6.524 4.244s2.753-2.639 6.925-1.949c1.729.286 3.007 1.206 3.675 1.791l-1.474 2.319 6.782-.01z"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/arched-arrow-rtl.svg b/vendor/oojs/oojs-ui/src/themes/apex/images/icons/arched-arrow-rtl.svg
deleted file mode 100644
index 01fc216b..00000000
--- a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/arched-arrow-rtl.svg
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="arched-arrow-rtl">
- <path id="arrow" d="M13.401 8.542c-2.814-.027-4.549.978-5.513 1.823l-1.48-2.329-2.391 6.901 6.782.009-1.474-2.319c.668-.584 1.945-1.504 3.675-1.791 4.172-.69 6.925 1.949 6.925 1.949s-1.637-4.197-6.524-4.243z"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/arrow-ltr.svg b/vendor/oojs/oojs-ui/src/themes/apex/images/icons/arrow-ltr.svg
deleted file mode 100644
index b07621e8..00000000
--- a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/arrow-ltr.svg
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="g4">
- <path d="M16 12h-10c-1.7 0-3 1.3-3 3h13v3l5-4.5-5-4.5v3z" id="path6"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/arrow-rtl.svg b/vendor/oojs/oojs-ui/src/themes/apex/images/icons/arrow-rtl.svg
deleted file mode 100644
index a0189283..00000000
--- a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/arrow-rtl.svg
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g>
- <path d="M8 12h10c1.7 0 3 1.3 3 3h-13v3l-5-4.5 5-4.5v3z"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/bigger-ltr.svg b/vendor/oojs/oojs-ui/src/themes/apex/images/icons/bigger-ltr.svg
deleted file mode 100644
index 94ec6704..00000000
--- a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/bigger-ltr.svg
+++ /dev/null
@@ -1,7 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <path d="M12.666 6h-1.372l-4.48 12h1.705l1.494-4h3.999l1.508 4h1.666l-4.52-12zm-2.28 7l1.617-4.333 1.634 4.333h-3.251z" id="a"/>
- <g id="up">
- <path id="arrow" d="M15.5 9h7l-3.5-6z"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/bigger-rtl.svg b/vendor/oojs/oojs-ui/src/themes/apex/images/icons/bigger-rtl.svg
deleted file mode 100644
index b2a6c139..00000000
--- a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/bigger-rtl.svg
+++ /dev/null
@@ -1,7 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <path d="M12.666 6h-1.372l-4.48 12H8.52l1.493-4h4l1.507 4h1.666l-4.52-12zm-2.28 7l1.617-4.333L13.637 13h-3.25z" id="a"/>
- <g id="up">
- <path id="arrow" d="M1.5 9h7L5 3z"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/block.svg b/vendor/oojs/oojs-ui/src/themes/apex/images/icons/block.svg
deleted file mode 100644
index 0ddd1d47..00000000
--- a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/block.svg
+++ /dev/null
@@ -1,4 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <path d="M12 4c-4.4 0-8 3.6-8 8s3.6 8 8 8 8-3.6 8-8-3.6-8-8-8zm5 9h-10v-2h10v2z" id="path4"/>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/blockUndo-ltr.svg b/vendor/oojs/oojs-ui/src/themes/apex/images/icons/blockUndo-ltr.svg
deleted file mode 100644
index 3d9cfd7d..00000000
--- a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/blockUndo-ltr.svg
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="g66">
- <path d="M17 11v2h-2l3.6 3.6c.9-1.3 1.4-2.9 1.4-4.6 0-4.4-3.6-8-8-8-1.7 0-3.3.5-4.6 1.4l5.6 5.6h4zm-13-7l-1 1 2.4 2.4c-.9 1.3-1.4 2.9-1.4 4.6 0 4.4 3.6 8 8 8 1.7 0 3.3-.5 4.6-1.4l2.4 2.4 1-1-16-16zm3 9v-2h2l2 2h-4z" id="path68"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/blockUndo-rtl.svg b/vendor/oojs/oojs-ui/src/themes/apex/images/icons/blockUndo-rtl.svg
deleted file mode 100644
index 8f807596..00000000
--- a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/blockUndo-rtl.svg
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="g66">
- <path d="M7 11v2h2l-3.6 3.6c-.9-1.3-1.4-2.9-1.4-4.6 0-4.4 3.6-8 8-8 1.7 0 3.3.5 4.6 1.4l-5.6 5.6h-4zm13-7l1 1-2.4 2.4c.9 1.3 1.4 2.9 1.4 4.6 0 4.4-3.6 8-8 8-1.7 0-3.3-.5-4.6-1.4l-2.4 2.4-1-1 16-16zm-3 9v-2h-2l-2 2h4z" id="path68"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/bold-a.svg b/vendor/oojs/oojs-ui/src/themes/apex/images/icons/bold-a.svg
deleted file mode 100644
index 4b828779..00000000
--- a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/bold-a.svg
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="bold-a">
- <path d="M16 18h3l-5-12h-3l-5 12h3l1.25-3h4.5l1.25 3zm-4.917-5l1.417-3.4 1.417 3.4h-2.834z"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/bold-arab-ain.svg b/vendor/oojs/oojs-ui/src/themes/apex/images/icons/bold-arab-ain.svg
deleted file mode 100644
index f96cebce..00000000
--- a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/bold-arab-ain.svg
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="bold-arab-ain">
- <path id="arab-ain" d="M9.337 13.616c0 1.349 1.386 2.101 4.159 2.258l2.187-.029.318.044c-.03.127-.251.345-.665.652l-.089.066c-1.236.929-2.423 1.393-3.56 1.393-1.143 0-2.046-.33-2.711-.99-.65-.66-.975-1.559-.975-2.698.005-1.354.566-2.573 1.684-3.658v-.044l-.606-.55c-.148-.181-.222-.391-.222-.63 0-.489.239-1.109.717-1.862.65-1.046 1.303-1.566 1.958-1.561.886.005 1.618.42 2.194 1.246.325.479-.03.552-1.064.22-.842-.327-1.527-.051-2.054.828l.015.073 1.123.865.052.007c1.404-.498 2.418-.74 3.043-.726-.059.117-.14.362-.244.733-.103.357-.204.684-.303.982l-.126.374-.384.051c-1.743.239-2.992.716-3.745 1.429-.463.464-.697.973-.702 1.525"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/bold-arab-dad.svg b/vendor/oojs/oojs-ui/src/themes/apex/images/icons/bold-arab-dad.svg
deleted file mode 100644
index f04c6aad..00000000
--- a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/bold-arab-dad.svg
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="bold-arab-dad">
- <path id="arab-dad" d="M16.411 8.232l-1.676-.665.694-1.567 1.688.64-.707 1.592m.775 3.078c-.509-.286-1-.427-1.476-.423-.471 0-.982.205-1.532.616l-.506.379.006.025c1.084.066 1.934.099 2.551.099h.313c.567-.021.992-.064 1.276-.131-.067-.17-.275-.359-.625-.566h-.006m-6.803 3.296c-.017-.904-.329-1.87-.938-2.898l1.294-1.729.119.149c.267.336.504.924.713 1.766l.063.05c.496-.008.942-.17 1.338-.485v-.006l1.732-1.53c.679-.601 1.282-.902 1.807-.902.383.004.848.195 1.394.572.55.377.884.696 1 .958.063.149.094.386.094.709 0 .696-.11 1.229-.331 1.598-.192.311-.473.555-.844.734-.438.207-1.549.311-3.333.311-.8 0-1.795-.021-2.983-.062l-.144.429c-.254.672-.463 1.113-.625 1.324-.725.937-1.786 1.405-3.183 1.405-1.705-.008-2.557-.922-2.557-2.742.004-.941.279-1.814.825-2.618.15-.216.298-.367.444-.454.225-.133.288-.091.188.124-.396.862-.596 1.548-.6 2.058.008 1.177.752 1.768 2.232 1.772 1.038-.004 1.803-.182 2.295-.535"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/bold-armn-to.svg b/vendor/oojs/oojs-ui/src/themes/apex/images/icons/bold-armn-to.svg
deleted file mode 100644
index 4dbec6d9..00000000
--- a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/bold-armn-to.svg
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="bold-armn-to">
- <path id="armn-to" d="M13.86 16.257c.124 0 .254-.026.39-.078.135-.058.257-.15.367-.274.114-.13.205-.302.273-.516.073-.213.11-.48.11-.797V13h-1.14c-.14 0-.284.026-.43.078-.14.047-.27.133-.383.258-.11.125-.2.294-.274.508-.067.213-.1.487-.1.82 0 .34.035.47.108.695.08.218.175.395.29.53.12.136.247.232.383.29.14.05.276.077.406.077m-2.97-7.84c-.37.082-.695.247-.976.45-.28.198-.505.47-.672.813-.16.343-.242.78-.242 1.312V18H6v-7.188c0-.776.15-1.455.453-2.04.302-.587.714-1.077 1.234-1.467.52-.39 1.13-.685 1.83-.883.697-.198 1.44-.297 2.225-.297.526 0 1.04.044 1.54.133.504.088.98.22 1.43.398.447.172.858.388 1.233.65.375.26.698.564.97.913.275.348.49.738.64 1.17.15.433.226 1.094.226 1.61h1.353v2.04H17.78v1.6c0 .58-.103 1.092-.31 1.54-.21.442-.49.815-.845 1.117-.35.302-.834.53-1.297.687-.464.15-.953.226-1.47.226-.51 0-.996-.078-1.46-.234-.464-.156-.87-.39-1.22-.703-.348-.313-.626-.703-.835-1.172-.203-.473-.304-1.028-.304-1.663s.105-1.182.32-1.64c.213-.46.497-.685.85-.977.355-.297.76-.513 1.22-.648.458-.14.935-.21 1.43-.21h1.132c-.01-.49-.04-1.043-.242-1.36-.198-.323-.453-.58-.766-.766-.312-.193-.598-.332-.984-.426-.374-.09-.577-.094-1.1-.094-.52 0-.64.02-1.01.102z"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/bold-b.svg b/vendor/oojs/oojs-ui/src/themes/apex/images/icons/bold-b.svg
deleted file mode 100644
index 4f648203..00000000
--- a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/bold-b.svg
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="bold-b">
- <path id="b" d="M7 18h6c2 0 4-1 4-3 0-1.064.011-1.975-1.989-3 2-.975 1.989-1.935 1.989-3 0-2-2-3-4-3h-6v12zm7-8c0 1.001 0 1-2 1h-2v-3h2c2 0 2 0 2 1v1zm-2 6h-2v-3h2c2 0 2 0 2 1v1s0 1-2 1z"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/bold-cyrl-be.svg b/vendor/oojs/oojs-ui/src/themes/apex/images/icons/bold-cyrl-be.svg
deleted file mode 100644
index 279466d4..00000000
--- a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/bold-cyrl-be.svg
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="bold-cyrl-be">
- <path id="cyrl-be" d="M7 6h9v2h-6v3h2.649c.893 0 1.633.109 2.22.327.588.218 1.088.622 1.502 1.211.419.589.629 1.187.629 1.978 0 .813-.21 1.398-.629 1.977-.419.578-.898.974-1.437 1.187-.533.213-1.295.319-2.286.319h-5.649m4.767-2c.751 0 1.279-.049 1.584-.12.305-.076.569-.246.792-.508.229-.262.343-.473.343-.855 0-.557-.199-.868-.596-1.119-.392-.256-1.064-.398-2.016-.398h-1.873v3"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/bold-cyrl-te.svg b/vendor/oojs/oojs-ui/src/themes/apex/images/icons/bold-cyrl-te.svg
deleted file mode 100644
index fdeeb6c5..00000000
--- a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/bold-cyrl-te.svg
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="bold-cyrl-te">
- <path id="te" d="M11 18v-10h-4v-2h11v2h-4v10"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/bold-cyrl-zhe.svg b/vendor/oojs/oojs-ui/src/themes/apex/images/icons/bold-cyrl-zhe.svg
deleted file mode 100644
index 5996c813..00000000
--- a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/bold-cyrl-zhe.svg
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="bold-cyrl-zhe">
- <path id="cyrl-zhe" d="M13 6v5.154c.328-.033.537-.181.705-.447.168-.266.401-.873.698-1.821.39-1.241.789-2.033 1.197-2.374.403-.336 1.075-.504 2.014-.504l.386-.008v1.78l-.386-.008c-.399 0-.691.062-.878.187-.186.119-.337.304-.452.553-.115.249-.286.762-.512 1.537-.12.412-.25.756-.392 1.033-.137.276-.383.537-.738.78.439.157.8.466 1.084.927.288.455.603 1.103.944 1.943l1.33 3.268h-2.314l-1.17-3.081-.113-.252-.239-.561c-.248-.569-.452-.932-.612-1.089-.16-.157-.317-.236-.552-.236v5.22h-2v-5.22c-.226 0-.382.076-.546.228-.164.152-.368.518-.612 1.098l-.246.561-.113.252-1.17 3.081h-2.314l1.33-3.268c.328-.808.636-1.447.924-1.919.293-.477.663-.794 1.11-.951-.355-.244-.603-.501-.745-.772-.137-.276-.268-.623-.392-1.041-.222-.759-.39-1.266-.505-1.52-.111-.255-.261-.444-.452-.569-.186-.125-.492-.187-.917-.187l-.352.008v-1.78l.386.008c.953 0 1.631.171 2.034.512.399.347.791 1.136 1.177 2.366.301.954.534 1.564.698 1.829.168.26.377.406.705.439v-5.154"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/bold-f.svg b/vendor/oojs/oojs-ui/src/themes/apex/images/icons/bold-f.svg
deleted file mode 100644
index 357d2e5d..00000000
--- a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/bold-f.svg
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="bold-f">
- <path id="f" d="M16 8v-2h-8v12h3v-5h4v-2h-4v-3z"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/bold-g.svg b/vendor/oojs/oojs-ui/src/themes/apex/images/icons/bold-g.svg
deleted file mode 100644
index e032542e..00000000
--- a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/bold-g.svg
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="bold-g">
- <path id="g" d="M12 14v-2h5v4.203c-.497.475-1.22.894-2.166 1.259-.941.359-1.896.538-2.864.538-1.23 0-2.303-.253-3.217-.76-.915-.512-1.602-1.24-2.062-2.185-.46-.95-.69-1.982-.69-3.095 0-1.208.257-2.282.77-3.222.513-.939 1.265-1.66 2.255-2.161.754-.385 1.693-.578 2.816-.578 1.46 0 2.6.303 3.418.91.824.602 1.353 1.435 1.589 2.501l-2.359.435c-.166-.57-.479-1.018-.939-1.346-.455-.332-1.024-.499-1.709-.499-1.038 0-1.864.325-2.479.974-.61.649-.915 1.612-.915 2.889 0 1.377.31 2.412.931 3.103.62.686 1.433 1.029 2.439 1.029.497 0 .995-.095 1.492-.285.503-.195 1.332-.571 1.691-.845v-.867"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/bold-geor-man.svg b/vendor/oojs/oojs-ui/src/themes/apex/images/icons/bold-geor-man.svg
deleted file mode 100644
index b211bf7a..00000000
--- a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/bold-geor-man.svg
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="bold-geor-man">
- <path id="geor-man" d="M13.832 14.061c0-1.715-.394-2.573-1.182-2.573-.868 0-1.302.779-1.302 2.338-.01 1.624.421 2.436 1.295 2.436.793 0 1.189-.734 1.189-2.201m2.168 0c0 2.626-1.116 3.939-3.349 3.939-2.434 0-3.651-1.386-3.651-4.159 0-2.738 1.217-4.106 3.651-4.106.841 0 1.182.63 1.182.63v-1.579c0-.789-.449-1.184-1.347-1.184-.572 0-.858.374-.858 1.123h-2.341c.005-1.817 1.064-2.725 3.176-2.725 2.368 0 3.548.946 3.538 2.839"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/bold-l.svg b/vendor/oojs/oojs-ui/src/themes/apex/images/icons/bold-l.svg
deleted file mode 100644
index 16797938..00000000
--- a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/bold-l.svg
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="bold-l">
- <path id="l" d="M8 18v-12h3v10h5v2"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/bold-n.svg b/vendor/oojs/oojs-ui/src/themes/apex/images/icons/bold-n.svg
deleted file mode 100644
index 73ad019a..00000000
--- a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/bold-n.svg
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="bold-n">
- <path id="n" d="M7 18v-12h3l4 8v-8h3v12h-3l-4-8v8h-3"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/bold-v.svg b/vendor/oojs/oojs-ui/src/themes/apex/images/icons/bold-v.svg
deleted file mode 100644
index 146943a5..00000000
--- a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/bold-v.svg
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="bold-v">
- <path id="v" d="M10.5 18l-4.5-12h3l3 8 3-8h3l-4.5 12"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/cancel.svg b/vendor/oojs/oojs-ui/src/themes/apex/images/icons/cancel.svg
deleted file mode 100644
index bfc1b44b..00000000
--- a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/cancel.svg
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="cancel">
- <path id="circle-with-strike" d="M11.999 5.022c-3.853 0-6.977 3.124-6.977 6.978 0 3.853 3.124 6.978 6.977 6.978 3.854 0 6.979-3.125 6.979-6.978 0-3.854-3.125-6.978-6.979-6.978zm-5.113 6.978c0-1.092.572-3.25.93-2.929l7.113 7.113c.488.525-1.837.931-2.93.931-2.825-.001-5.113-2.291-5.113-5.115zm9.298 2.929l-7.114-7.113c-.445-.483 1.837-.931 2.929-.931 2.827 0 5.115 2.289 5.115 5.114 0 1.093-.364 3.543-.93 2.93z"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/caret-ltr.svg b/vendor/oojs/oojs-ui/src/themes/apex/images/icons/caret-ltr.svg
deleted file mode 100644
index f31ec095..00000000
--- a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/caret-ltr.svg
+++ /dev/null
@@ -1,4 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <path d="M7 13.1l8.9 8.9c.8-.8.8-2 0-2.8l-6.1-6.1 6-6.1c.8-.8.8-2 0-2.8l-8.8 8.9z"/>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/caret-rtl.svg b/vendor/oojs/oojs-ui/src/themes/apex/images/icons/caret-rtl.svg
deleted file mode 100644
index 02b4e387..00000000
--- a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/caret-rtl.svg
+++ /dev/null
@@ -1,4 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <path d="M16.5 13.1l-8.9 8.9c-.8-.8-.8-2 0-2.8l6.1-6.1-6-6.1c-.8-.8-.8-2 0-2.8l8.8 8.9z" id="path108"/>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/caretDown.svg b/vendor/oojs/oojs-ui/src/themes/apex/images/icons/caretDown.svg
deleted file mode 100644
index a04ca572..00000000
--- a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/caretDown.svg
+++ /dev/null
@@ -1,4 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <path d="M12 16l8.9-8.9c-.8-.8-2-.8-2.8 0l-6.1 6.1-6.1-6c-.8-.8-2-.8-2.8 0l8.9 8.8z" id="path4"/>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/caretUp.svg b/vendor/oojs/oojs-ui/src/themes/apex/images/icons/caretUp.svg
deleted file mode 100644
index d0e0c283..00000000
--- a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/caretUp.svg
+++ /dev/null
@@ -1,4 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <path d="M12 6.5l8.9 8.9c-.8.8-2 .8-2.8 0l-6.1-6.1-6.1 6c-.8.8-2 .8-2.8 0l8.9-8.8z" id="path4"/>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/case-sensitive.svg b/vendor/oojs/oojs-ui/src/themes/apex/images/icons/case-sensitive.svg
deleted file mode 100644
index 824790c5..00000000
--- a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/case-sensitive.svg
+++ /dev/null
@@ -1,7 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="regular-expression">
- <path id="upper-case" d="M 7.53125,7 4,17 l 2.0625,0 0.71875,-2.40625 3.625,0 L 11.125,17 13.1875,17 9.65625,7 7.53125,7 z M 8.59375,8.53125 9.9375,13 7.25,13 8.59375,8.53125 z" />
- <path id="lower-case" d="m 18.548697,17 -0.183254,-1.035072 -0.05451,0 c -0.349771,0.440361 -0.710892,0.746796 -1.083366,0.919307 -0.367941,0.167972 -0.849436,0.251959 -1.444489,0.251959 -0.564328,0 -0.954665,-0.20883 -1.377109,-0.626492 -0.417903,-0.417659 -0.626854,-1.012371 -0.626853,-1.784137 -1e-6,-0.80808 0.281628,-1.402791 0.844889,-1.784137 0.567801,-0.385878 1.193222,-0.607062 2.208372,-0.640111 l 1.321843,-0.04086 0,-0.333674 c 0,-0.771759 -0.395195,-1.15764 -1.185571,-1.157647 -0.608688,7e-6 -1.324118,0.183867 -2.146293,0.551584 L 14.134181,9.9184512 c 0.876685,-0.4585114 1.848761,-0.6877705 2.916233,-0.6877783 1.022038,7.8e-6 1.586855,0.2224573 2.131951,0.6673492 C 19.727448,10.342928 20,11.019356 20,11.927309 l 0,5.073215 -1.451303,0 m -0.394476,-3.527417 -0.804008,0.02724 c -0.604145,0.01816 -1.053844,0.127119 -1.349098,0.326866 -0.29526,0.199753 -0.442889,0.503919 -0.442886,0.912498 -3e-6,0.585634 0.336136,0.878451 1.008417,0.878449 0.481492,2e-6 0.865326,-0.138462 1.151503,-0.415391 0.29071,-0.276925 0.436067,-0.644648 0.436072,-1.103169 l 0,-0.626491" />
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/check.svg b/vendor/oojs/oojs-ui/src/themes/apex/images/icons/check.svg
deleted file mode 100644
index 03e36607..00000000
--- a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/check.svg
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="check">
- <path d="M7.105 13.473l1.422-1.423 1.901 1.902 4.81-6.952 1.657 1.148-6.26 8.852z"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/circle.svg b/vendor/oojs/oojs-ui/src/themes/apex/images/icons/circle.svg
deleted file mode 100644
index 436259e5..00000000
--- a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/circle.svg
+++ /dev/null
@@ -1,2 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><circle cx="12" cy="12" r="6"></circle></svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/close.svg b/vendor/oojs/oojs-ui/src/themes/apex/images/icons/close.svg
deleted file mode 100644
index 1345e867..00000000
--- a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/close.svg
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="close">
- <path id="x" d="M18.717 6.697l-1.414-1.414-5.303 5.303-5.303-5.303-1.414 1.414 5.303 5.303-5.303 5.303 1.414 1.414 5.303-5.303 5.303 5.303 1.414-1.414-5.303-5.303z"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/code.svg b/vendor/oojs/oojs-ui/src/themes/apex/images/icons/code.svg
deleted file mode 100644
index 32f140d9..00000000
--- a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/code.svg
+++ /dev/null
@@ -1,7 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="24" height="24" viewBox="0 0 24 24">
- <g id="code">
- <path id="left-bracket" d="M4 12v-1h1c1 0 1 0 1-1v-2.386c0-.514.024-.896.073-1.142.054-.252.139-.463.257-.633.204-.279.473-.475.808-.584.335-.115.872-.255 1.835-.255h1.027v1h-.752c-.457 0-.77.191-.936.408-.167.215-.312.445-.312 1.068v1.857c0 .729-.041 1.18-.244 1.493-.2.307-.562.529-1.09.667.535.155.9.385 1.096.688.199.303.238.757.238 1.484v1.862c0 .619.145.848.312 1.062.166.22.479.407.936.407l.752.004v1h-1.027c-.963 0-1.5-.133-1.835-.248-.335-.109-.604-.307-.808-.591-.118-.165-.203-.374-.257-.625-.049-.253-.073-.636-.073-1.149v-2.387c0-1 0-1-1-1h-1z"/>
- <use transform="matrix(-1 0 0 1 24 0)" id="right-bracket" width="24" height="24" xlink:href="#left-bracket"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/collapse.svg b/vendor/oojs/oojs-ui/src/themes/apex/images/icons/collapse.svg
deleted file mode 100644
index 55aa8f8f..00000000
--- a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/collapse.svg
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="collapse">
- <path id="arrow" d="M6.697 15.714l5.303-5.302 5.303 5.302 1.414-1.414-6.717-6.717-6.717 6.717z"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/comment.svg b/vendor/oojs/oojs-ui/src/themes/apex/images/icons/comment.svg
deleted file mode 100644
index 0ae7e63f..00000000
--- a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/comment.svg
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="comment">
- <path id="speech-bubble" d="M15 6h-6c-1.657 0-3 1.344-3 3v4c0 1.656 1.343 3 3 3v3l3-3h3c1.657 0 3-1.344 3-3v-4c0-1.656-1.343-3-3-3z"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/downTriangle.svg b/vendor/oojs/oojs-ui/src/themes/apex/images/icons/downTriangle.svg
deleted file mode 100644
index 7bc1c228..00000000
--- a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/downTriangle.svg
+++ /dev/null
@@ -1,4 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <path d="M12 18l8-10h-16z"/>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/edit-ltr.svg b/vendor/oojs/oojs-ui/src/themes/apex/images/icons/edit-ltr.svg
deleted file mode 100644
index 3972e070..00000000
--- a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/edit-ltr.svg
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="Layer_3">
- <path d="M17 2l-12 12-1 5 5-1 12-12c0-2-2-4-4-4zm-9.8 13.5c-.3-.3-.7-.6-1-.8 2.3-2.3 11.3-11.4 11.3-11.4.4.1.7.3 1 .7l-11.3 11.5z"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/edit-rtl.svg b/vendor/oojs/oojs-ui/src/themes/apex/images/icons/edit-rtl.svg
deleted file mode 100644
index 978b2fd1..00000000
--- a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/edit-rtl.svg
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="Layer_3">
- <path d="M8 2l12 12 1 5-5-1-12-12c0-2 2-4 4-4zm9.8 13.5c.3-.3.7-.6 1-.8-2.3-2.3-11.3-11.4-11.3-11.4-.4.1-.7.3-1 .7l11.3 11.5z" id="path173"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/editLock-ltr.svg b/vendor/oojs/oojs-ui/src/themes/apex/images/icons/editLock-ltr.svg
deleted file mode 100644
index 7e376824..00000000
--- a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/editLock-ltr.svg
+++ /dev/null
@@ -1,8 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="Layer_2">
- <g id="g184">
- <path d="M21 4v-1s0-3-3-3-3 3-3 3v1h-1v6h8v-6zm-1.5 0h-3v-1s0-1.5 1.5-1.5c1.48.06 1.5 1.5 1.5 1.5zm-6.5 5.6l-6.8 6.9c-.3-.3-.7-.6-1-.8 1.4-1.4 5-5 7.8-7.9v-1.8l-9 9-1 5 5-1 8-8h-3z" id="path186"/>
- </g>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/editLock-rtl.svg b/vendor/oojs/oojs-ui/src/themes/apex/images/icons/editLock-rtl.svg
deleted file mode 100644
index 0b4751d2..00000000
--- a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/editLock-rtl.svg
+++ /dev/null
@@ -1,8 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="Layer_2">
- <g id="g184">
- <path d="M4 4v-1s0-3 3-3 3 3 3 3v1h1v6h-8v-6zm1.5 0h3v-1s0-1.5-1.5-1.5c-1.48.06-1.5 1.5-1.5 1.5zm6.5 5.6l6.8 6.9c.3-.3.7-.6 1-.8-1.4-1.4-5-5-7.8-7.9v-1.8l9 9 1 5-5-1-8-8h3z" id="path186"/>
- </g>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/editUndo-ltr.svg b/vendor/oojs/oojs-ui/src/themes/apex/images/icons/editUndo-ltr.svg
deleted file mode 100644
index f346874e..00000000
--- a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/editUndo-ltr.svg
+++ /dev/null
@@ -1,11 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="g196">
- <g id="g198">
- <path d="M14.9 2.8c.9 0 1.8.2 2.7.6.9.4 1.6.9 1.9 1.6-2.8.1-5 1.1-6.6 3.1l1.3 2-6.7-.3.5-6.8 1.7 2c1.8-1.5 3.5-2.2 5.2-2.2z" id="path200"/>
- </g>
- </g>
- <g id="g204">
- <path d="M15.2 11.1l-2.6-.1-5.4 5.5c-.3-.3-.7-.6-1-.8.9-.9 2.8-2.8 4.7-4.8h-1.8l-4.1 4.1-1 5 5-1 7.8-7.8-1.6-.1zm5.4-5.1c-1.7 0-3.2.5-4.4 1.4l-.9.9.8 1.3.9 1.4 4-4c0-.3-.1-.7-.2-1h-.2z" id="path206"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/editUndo-rtl.svg b/vendor/oojs/oojs-ui/src/themes/apex/images/icons/editUndo-rtl.svg
deleted file mode 100644
index 5b59d452..00000000
--- a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/editUndo-rtl.svg
+++ /dev/null
@@ -1,11 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="g196">
- <g id="g198">
- <path d="M10.1 2.8c-.9 0-1.8.2-2.7.6-.9.4-1.6.9-1.9 1.6 2.8.1 5 1.1 6.6 3.1l-1.3 2 6.7-.3-.5-6.8-1.7 2c-1.8-1.5-3.5-2.2-5.2-2.2z" id="path200"/>
- </g>
- </g>
- <g id="g204">
- <path d="M9.8 11.1l2.6-.1 5.4 5.5c.3-.3.7-.6 1-.8-.9-.9-2.8-2.8-4.7-4.8h1.8l4.1 4.1 1 5-5-1-7.8-7.8 1.6-.1zm-5.4-5.1c1.7 0 3.2.5 4.4 1.4l.9.9-.8 1.3-.9 1.4-4-4c0-.3.1-.7.2-1h.2z" id="path206"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/ellipsis.svg b/vendor/oojs/oojs-ui/src/themes/apex/images/icons/ellipsis.svg
deleted file mode 100644
index dd36a30d..00000000
--- a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/ellipsis.svg
+++ /dev/null
@@ -1,14 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g>
- <g>
- <path d="M8 13c0 .6-.2 1-.6 1.4-.4.4-.9.6-1.4.6-.6 0-1-.2-1.4-.6-.4-.4-.6-.9-.6-1.4s.2-1 .6-1.4c.4-.4.9-.6 1.4-.6s1 .2 1.4.6c.4.4.6.9.6 1.4z"/>
- </g>
- <g>
- <path d="M14 13c0 .6-.2 1-.6 1.4-.4.4-.9.6-1.4.6-.6 0-1-.2-1.4-.6-.4-.4-.6-.9-.6-1.4s.2-1 .6-1.4c.4-.4.9-.6 1.4-.6s1 .2 1.4.6c.4.4.6.9.6 1.4z"/>
- </g>
- <g>
- <path d="M20 13c0 .6-.2 1-.6 1.4-.4.4-.9.6-1.4.6-.6 0-1-.2-1.4-.6-.4-.4-.6-.9-.6-1.4s.2-1 .6-1.4c.4-.4.9-.6 1.4-.6s1 .2 1.4.6c.4.4.6.9.6 1.4z"/>
- </g>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/expand.svg b/vendor/oojs/oojs-ui/src/themes/apex/images/icons/expand.svg
deleted file mode 100644
index 7666b41d..00000000
--- a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/expand.svg
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="expand">
- <path id="arrow" d="M17.303 8.283l-5.303 5.303-5.303-5.303-1.414 1.414 6.717 6.717 6.717-6.717z"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/external-link-ltr.svg b/vendor/oojs/oojs-ui/src/themes/apex/images/icons/external-link-ltr.svg
deleted file mode 100644
index 827bc1b1..00000000
--- a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/external-link-ltr.svg
+++ /dev/null
@@ -1,7 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 12 12">
- <g id="external">
- <path id="box" d="M2 2h3v1h-2v6h6v-2h1v3h-8z"/>
- <path id="arrow" d="M6.211 2h3.789v3.789l-1.421-1.421-2.132 2.132-.947-.947 2.132-2.132z"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/external-link-rtl.svg b/vendor/oojs/oojs-ui/src/themes/apex/images/icons/external-link-rtl.svg
deleted file mode 100644
index c375ca0f..00000000
--- a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/external-link-rtl.svg
+++ /dev/null
@@ -1,7 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 12 12">
- <g id="external">
- <path id="box" d="M7 3h2v6h-6v-2h-1v3h8v-8h-3z"/>
- <path id="arrow" d="M2 5.789l1.421-1.421 2.132 2.132.947-.947-2.132-2.132 1.421-1.421h-3.789z"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/find-ltr.svg b/vendor/oojs/oojs-ui/src/themes/apex/images/icons/find-ltr.svg
deleted file mode 100644
index f8578cf8..00000000
--- a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/find-ltr.svg
+++ /dev/null
@@ -1,7 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="find">
- <path id="magnifying-glass" d="m 13.65625,11 c -1.921,0 -3.5,1.54775 -3.5,3.46875 0,1.92 1.579,3.5 3.5,3.5 0.749,0 1.432,-0.25225 2,-0.65625 l 0.09375,0.15625 2.375,2.375 c 0.19,0.189 0.53425,0.15325 0.78125,-0.09375 0.247,-0.247 0.314,-0.59125 0.125,-0.78125 l -2.375,-2.375 L 16.46875,16.5 C 16.87175,15.934 17.125,15.21775 17.125,14.46875 17.124,12.54875 15.57525,11 13.65625,11 z m 0,1.65625 c 1.011306,0 1.8125,0.801194 1.8125,1.8125 0,1.011306 -0.801194,1.84375 -1.8125,1.84375 -1.011306,0 -1.84375,-0.832444 -1.84375,-1.84375 0,-1.011306 0.832444,-1.8125 1.84375,-1.8125 z" />
- <path id="text" d="M 6,5 6,7 16,7 16,5 6,5 z m 0,3 0,2 11,0 0,-2 -11,0 z m 0,3 0,2 3.53125,0 c 0.2825289,-0.797203 0.786096,-1.486208 1.4375,-2 L 6,11 z m 0,3 0,2 3.53125,0 C 9.3537004,15.520243 9.25,15.010236 9.25,14.46875 9.25,14.309811 9.2962033,14.154621 9.3125,14 L 6,14 z" />
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/find-rtl.svg b/vendor/oojs/oojs-ui/src/themes/apex/images/icons/find-rtl.svg
deleted file mode 100644
index 2a1e9c6f..00000000
--- a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/find-rtl.svg
+++ /dev/null
@@ -1,7 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="find">
- <path id="magnifying-glass" d="m 11.343828,11.000025 c 1.921,0 3.5,1.54775 3.5,3.46875 0,1.92 -1.579,3.5 -3.5,3.5 -0.749,0 -1.432,-0.25225 -2,-0.65625 l -0.09375,0.15625 -2.375,2.375 c -0.19,0.189 -0.53425,0.15325 -0.78125,-0.09375 -0.247,-0.247 -0.314,-0.59125 -0.125,-0.78125 l 2.375,-2.375 0.1875,-0.09375 c -0.403,-0.566 -0.65625,-1.28225 -0.65625,-2.03125 10e-4,-1.92 1.54975,-3.46875 3.46875,-3.46875 z m 0,1.65625 c -1.011306,0 -1.8125,0.801194 -1.8125,1.8125 0,1.011306 0.801194,1.84375 1.8125,1.84375 1.011306,0 1.84375,-0.832444 1.84375,-1.84375 0,-1.011306 -0.832444,-1.8125 -1.84375,-1.8125 z" />
- <path id="text" d="M 19,5 19,7 9,7 9,5 z m 0,3 0,2 -11,0 0,-2 z m 0,3 0,2 -3.53125,0 c -0.282529,-0.797203 -0.786096,-1.486208 -1.4375,-2 z m 0,3 0,2 -3.53125,0 C 15.6463,15.520243 15.75,15.010236 15.75,14.46875 15.75,14.309811 15.703797,14.154621 15.6875,14 z" />
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/flag-ltr.svg b/vendor/oojs/oojs-ui/src/themes/apex/images/icons/flag-ltr.svg
deleted file mode 100644
index 6e81d2bc..00000000
--- a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/flag-ltr.svg
+++ /dev/null
@@ -1,4 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <path d="M14 6.5v-1.5c-1.4-1.5-5.2-1.2-6 0v-1h-1v15h1v-7c.8-.8 3.4-.9 5-.5v1.5c1.2 1.5 4.3 1.2 5 0v-7c-.7.7-2.7.9-4 .5z" id="path216"/>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/flag-rtl.svg b/vendor/oojs/oojs-ui/src/themes/apex/images/icons/flag-rtl.svg
deleted file mode 100644
index 4b743aac..00000000
--- a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/flag-rtl.svg
+++ /dev/null
@@ -1,4 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <path d="M11 6.5v-1.5c1.4-1.5 5.2-1.2 6 0v-1h1v15h-1v-7c-.8-.8-3.4-.9-5-.5v1.5c-1.2 1.5-4.3 1.2-5 0v-7c.7.7 2.7.9 4 .5z" id="path216"/>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/flagUndo-ltr.svg b/vendor/oojs/oojs-ui/src/themes/apex/images/icons/flagUndo-ltr.svg
deleted file mode 100644
index 49cdb7a2..00000000
--- a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/flagUndo-ltr.svg
+++ /dev/null
@@ -1,16 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="g2990">
- <g id="Layer_1">
- <path id="path227" d="M14 6.5v-1.5c-1.4-1.5-5.2-1.2-6 0v-1h-1v15h1v-7c.8-.8 3.4-.9 5-.5v1.5c1.2 1.5 4.3 1.2 5 0v-7c-.7.7-2.7.9-4 .5z"/>
- </g>
- <g id="Layer_2">
- <g id="g230">
- <path id="path232" d="M17.997 1.989l.99.99-15.98 15.98-.99-.99z"/>
- </g>
- <g id="g234">
- <path id="path236" d="M16.999 1.016l.99.99-15.98 15.98-.99-.99z" fill="#fff"/>
- </g>
- </g>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/flagUndo-rtl.svg b/vendor/oojs/oojs-ui/src/themes/apex/images/icons/flagUndo-rtl.svg
deleted file mode 100644
index e470de42..00000000
--- a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/flagUndo-rtl.svg
+++ /dev/null
@@ -1,16 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="g2990">
- <g id="Layer_1">
- <path id="path227" d="M11 6.5v-1.5c1.4-1.5 5.2-1.2 6 0v-1h1v15h-1v-7c-.8-.8-3.4-.9-5-.5v1.5c-1.2 1.5-4.3 1.2-5 0v-7c.7.7 2.7.9 4 .5z"/>
- </g>
- <g id="Layer_2">
- <g id="g230">
- <path id="path232" d="M7.003 1.989l-.99.99 15.98 15.98.99-.99z"/>
- </g>
- <g id="g234">
- <path id="path236" d="M8.001 1.016l-.99.99 15.98 15.98.99-.99z" fill="#fff"/>
- </g>
- </g>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/help-ltr.svg b/vendor/oojs/oojs-ui/src/themes/apex/images/icons/help-ltr.svg
deleted file mode 100644
index bb2545c5..00000000
--- a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/help-ltr.svg
+++ /dev/null
@@ -1,10 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="help">
- <path id="circle" d="M12.001 2.085c-5.478 0-9.916 4.438-9.916 9.916 0 5.476 4.438 9.914 9.916 9.914 5.476 0 9.914-4.438 9.914-9.914 0-5.478-4.438-9.916-9.914-9.916zm.001 18c-4.465 0-8.084-3.619-8.084-8.083 0-4.465 3.619-8.084 8.084-8.084 4.464 0 8.083 3.619 8.083 8.084 0 4.464-3.619 8.083-8.083 8.083z"/>
- <g id="question-mark">
- <path id="top" d="M11.766 6.688c-2.5 0-3.219 2.188-3.219 2.188l1.411.854s.298-.791.901-1.229c.516-.375 1.625-.625 2.219.125.701.885-.17 1.587-1.078 2.719-.953 1.186-1 3.655-1 3.655h1.969s.135-2.318 1.041-3.381c.603-.707 1.443-1.338 1.443-2.494s-1.187-2.437-3.687-2.437z"/>
- <path id="bottom" d="M11 16h2v2h-2z"/>
- </g>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/help-rtl.svg b/vendor/oojs/oojs-ui/src/themes/apex/images/icons/help-rtl.svg
deleted file mode 100644
index 99c7f842..00000000
--- a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/help-rtl.svg
+++ /dev/null
@@ -1,10 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="help">
- <path id="circle" d="M11.999 2.085c5.478 0 9.916 4.438 9.916 9.916 0 5.476-4.438 9.914-9.916 9.914-5.476 0-9.914-4.438-9.914-9.914 0-5.478 4.438-9.916 9.914-9.916zm-.001 18c4.465 0 8.084-3.619 8.084-8.083 0-4.465-3.619-8.084-8.084-8.084-4.464 0-8.083 3.619-8.083 8.084 0 4.464 3.619 8.083 8.083 8.083z"/>
- <g id="question-mark">
- <path id="top" d="M12.234 6.688c2.5 0 3.219 2.188 3.219 2.188l-1.411.854s-.298-.791-.901-1.229c-.516-.375-1.625-.625-2.219.125-.701.885.17 1.587 1.078 2.719.953 1.186 1 3.655 1 3.655h-1.969s-.135-2.318-1.041-3.381c-.603-.707-1.443-1.338-1.443-2.494 0-1.156 1.187-2.437 3.687-2.437z"/>
- <path id="bottom" d="M13 16h-2v2h2z"/>
- </g>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/history.svg b/vendor/oojs/oojs-ui/src/themes/apex/images/icons/history.svg
deleted file mode 100644
index 35f15afe..00000000
--- a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/history.svg
+++ /dev/null
@@ -1,7 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="history">
- <path id="clock-hands" d="M17.26 15.076s-2.385-1.935-4.005-3.062c.72-2.397 1.702-6.559 1.702-6.559s-4.35 5.363-4.877 6.699c-.463 1.168 1.459 2.209 2.346 1.678 1.9.551 4.834 1.244 4.834 1.244z"/>
- <path id="arrow" d="M12.086 2.085c-5.478 0-9.916 4.438-9.916 9.916 0 1.783.476 3.454 1.301 4.898l-2.223 2.04h5.688v-5.219l-2.066 1.896c-.55-1.088-.866-2.312-.866-3.615 0-4.465 3.619-8.084 8.084-8.084 4.464 0 8.083 3.619 8.083 8.084 0 4.464-3.619 8.083-8.083 8.083-1.145 0-2.228-.247-3.213-.678l-.833 1.634c1.235.557 2.602.874 4.045.874 5.476 0 9.914-4.438 9.914-9.914-.001-5.477-4.439-9.915-9.915-9.915z"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/indent-ltr.svg b/vendor/oojs/oojs-ui/src/themes/apex/images/icons/indent-ltr.svg
deleted file mode 100644
index e95d40d8..00000000
--- a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/indent-ltr.svg
+++ /dev/null
@@ -1,9 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="indent-list-ltr">
- <path id="arrow" d="M5 15.079l4.794-3.527-4.704-3.599-.01 2.047h-2.08v3h2z"/>
- <path id="bottom_line" d="M20 17h-16c-.553 0-1 .447-1 1v1c0 .553.447 1 1 1h16c.553 0 1-.447 1-1v-1c0-.553-.447-1-1-1z"/>
- <path id="middle_line" d="M20 10h-7c-.553 0-1 .447-1 1v1c0 .553.447 1 1 1h7c.553 0 1-.447 1-1v-1c0-.553-.447-1-1-1z"/>
- <path id="top_line" d="M20 3h-16c-.553 0-1 .447-1 1v1c0 .553.447 1 1 1h16c.553 0 1-.447 1-1v-1c0-.553-.447-1-1-1z"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/indent-rtl.svg b/vendor/oojs/oojs-ui/src/themes/apex/images/icons/indent-rtl.svg
deleted file mode 100644
index cca3ad31..00000000
--- a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/indent-rtl.svg
+++ /dev/null
@@ -1,9 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="indent-list-rtl">
- <path id="arrow" d="M19 15.079l-4.794-3.527 4.704-3.599.01 2.047h2.08v3h-2z"/>
- <path id="bottom_line" d="M4 17h16c.553 0 1 .447 1 1v1c0 .553-.447 1-1 1h-16c-.553 0-1-.447-1-1v-1c0-.553.447-1 1-1z"/>
- <path id="middle_line" d="M4 10h7c.553 0 1 .447 1 1v1c0 .553-.447 1-1 1h-7c-.553 0-1-.447-1-1v-1c0-.553.447-1 1-1z"/>
- <path id="top_line_5_" d="M4 3h16c.553 0 1 .447 1 1v1c0 .553-.447 1-1 1h-16c-.553 0-1-.447-1-1v-1c0-.553.447-1 1-1z"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/info.svg b/vendor/oojs/oojs-ui/src/themes/apex/images/icons/info.svg
deleted file mode 100644
index 9c0d1cbc..00000000
--- a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/info.svg
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0, 0, 24, 24">
- <g id="info">
- <path id="circled-i" d="M11.499 17c-3.036 0-5.499-2.464-5.499-5.5 0-3.037 2.462-5.5 5.499-5.5 3.037 0 5.501 2.462 5.501 5.5 0 3.036-2.464 5.5-5.501 5.5zm.002-12c-3.591 0-6.501 2.91-6.501 6.5s2.91 6.5 6.501 6.5c3.588 0 6.499-2.911 6.499-6.5s-2.911-6.5-6.499-6.5zM12 10v4h1v1h-3v-1h1v-3h-1v-1zM11 8h1v1h-1z"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/insert.svg b/vendor/oojs/oojs-ui/src/themes/apex/images/icons/insert.svg
deleted file mode 100644
index 0833f84f..00000000
--- a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/insert.svg
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="insert">
- <path d="M13 5h-2v6h-6v2h6v6h2v-6h6v-2h-6z" id="plus"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/italic-a.svg b/vendor/oojs/oojs-ui/src/themes/apex/images/icons/italic-a.svg
deleted file mode 100644
index a0e66bff..00000000
--- a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/italic-a.svg
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="italic-a">
- <path id="a" d="M14.667 6h-1.372l-7 12h1.705l2.333-4h4l.667 4h1.667l-2-12zm-3.75 7l2.527-4.333.723 4.333h-3.25z"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/italic-arab-keheh-jeem.svg b/vendor/oojs/oojs-ui/src/themes/apex/images/icons/italic-arab-keheh-jeem.svg
deleted file mode 100644
index d4bff1be..00000000
--- a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/italic-arab-keheh-jeem.svg
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="italic-arab-keheh-jeem">
- <path id="arab-keheh-jeem" d="M18.125 5.844c-1.695.555-3.297 1.162-4.594 1.938-.49.299-.774.712-.875 1.125-.064.263-.035.572.063.781.189.405.539.574.844.813l.094-.125.531.625c.14.164.343.513.469.938.137.463.08.725 0 1.125h-3.438c-.338 0-.592.007-.766-.02-.339-.053-.256-.208-.234-.34.332-.127.564-.173.938-.141.29-.494.593-.885.906-1.313-.98.037-1.878.015-2.688-.094-.346-.047-.698-.186-1.094-.156-.357.026-.768.239-1.031.719-.246.448-.434.839-.656 1.281l.75-.469c.23-.142.484-.227.719-.219.157.005.275.054.406.094-.231.205-.509.402-.719.563-.301.26-.702.688-.906 1-.403.615-.694 1.084-.875 1.781-.179.689.004 1.339.469 1.75.426.376.846.519 1.281.563.65.065 1.205.093 2-.188.657-.231 1.021-.553 1.5-.969-.883.11-1.817.089-2.531.031-.871-.07-1.268-.384-1.469-.594-.271-.283-.307-.64-.156-1.219.036-.141.097-.323.25-.531.168-.228.364-.435.594-.656.451-.436 1.011-.737 1.461-.938-.045.206-.107.443-.055.688.049.229.248.379.438.469.259.122.506.155.688.156 1.421.011 2.862 0 4.281 0 .247 0 .452-.163.594-.375.139-.208.249-.481.344-.844.131-.499.094-1.062-.094-1.625-.182-.543-.418-1.009-.719-1.406-.335-.443-.674-.829-1-1.219 1.257-.815 2.716-1.239 3.969-1.688.121-.452.224-.926.313-1.313zm-9.469 8.438c-.262.394-.584.691-.875 1 .375.286.748.556 1.094.813.335-.303.626-.674.875-.969-.39-.268-.771-.588-1.094-.844z"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/italic-arab-meem.svg b/vendor/oojs/oojs-ui/src/themes/apex/images/icons/italic-arab-meem.svg
deleted file mode 100644
index bfbc9bf5..00000000
--- a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/italic-arab-meem.svg
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="italic-arab-meem">
- <path id="arab-meem" d="M16 9.729l-.93 2.19h-4.663c-.479 0-.857.122-1.135.367l-.061.11c-.184 2.016-.502 3.558-.955 4.627-.272.641-.633 1.252-1.082 1.833-.177.226-.219.186-.126-.119l.142-.504.17-.669.234-.87.002-.009.202-1.045.258-1.411.353-1.906c.191-.312.424-.638.699-.98.276-.342.589-.706.94-1.09.129-.092.697-.18 1.705-.266 1.05-.086 1.638-.183 1.765-.293l.065-.128c.007-.11-.011-.241-.054-.394-.043-.153-.12-.327-.231-.522-.22-.428-.438-.641-.654-.641-.294 0-.915.269-1.864.806-.359.208-.376.125-.051-.247 1.558-1.71 2.708-2.566 3.45-2.566.383 0 .671.131.863.394.135.195.25.599.344 1.21l.203 1.2c.106.586.242.895.409.925"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/italic-armn-sha.svg b/vendor/oojs/oojs-ui/src/themes/apex/images/icons/italic-armn-sha.svg
deleted file mode 100644
index 63de0f6c..00000000
--- a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/italic-armn-sha.svg
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="italic-armn-sha">
- <path id="armn-sha" d="M11.564 7.678c-.268-.13-.578-.22-.93-.268-.35-.047-.75-.07-1.197-.07h-1.11L8.586 6h1.724c.558 0 1.042.032 1.45.095.416.063.794.173 1.136.33l4.483 2.033-.324 1.67-2.624-1.165c-.126-.058-.27-.103-.433-.134-.164-.038-.356-.057-.576-.057-.583 0-1.137.095-1.663.284-.524.19-1 .46-1.425.812-.42.35-.777.78-1.072 1.283-.294.504-.504 1.074-.63 1.71-.242 1.255-.152 2.21.268 2.868.426.652 1.19.978 2.294.978.55 0 1.045-.08 1.48-.237.437-.156.815-.377 1.136-.66.326-.29.59-.633.796-1.033.21-.4.362-.84.457-1.323l.11-.56h1.6l-.12.59c-.13.674-.356 1.288-.676 1.845-.32.55-.725 1.026-1.214 1.425-.488.394-1.053.7-1.694.922-.642.215-1.343.323-2.105.323-.767 0-1.434-.113-2-.34-.568-.225-1.025-.553-1.372-.984-.347-.436-.573-.97-.678-1.607-.105-.637-.078-1.364.08-2.184.125-.66.346-1.273.66-1.835.316-.567.697-1.066 1.144-1.496.445-.436.944-.794 1.496-1.072.55-.284 1.13-.475 1.733-.575l-.466-.23"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/italic-c.svg b/vendor/oojs/oojs-ui/src/themes/apex/images/icons/italic-c.svg
deleted file mode 100644
index b468deac..00000000
--- a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/italic-c.svg
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="italic-c">
- <path id="c" d="M15.008 13.718l1.481.214c-.468 1.34-1.15 2.354-2.046 3.04-.896.686-1.901 1.029-3.015 1.029-1.359 0-2.438-.43-3.237-1.29-.794-.86-1.191-2.092-1.191-3.697 0-2.09.606-3.818 1.817-5.185 1.079-1.219 2.42-1.828 4.023-1.828 1.186 0 2.145.33 2.878.989.738.66 1.165 1.546 1.282 2.66l-1.397.135c-.148-.839-.453-1.464-.916-1.876-.458-.417-1.051-.625-1.779-.625-1.369 0-2.476.631-3.321 1.892-.733 1.087-1.099 2.377-1.099 3.871 0 1.193.282 2.103.847 2.731.565.628 1.3.942 2.206.942.774 0 1.473-.261 2.099-.784.626-.522 1.081-1.261 1.366-2.216"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/italic-d.svg b/vendor/oojs/oojs-ui/src/themes/apex/images/icons/italic-d.svg
deleted file mode 100644
index 92a834d9..00000000
--- a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/italic-d.svg
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="italic-d">
- <path id="d" d="M7 18l2.462-12h3.557c.853 0 1.505.063 1.955.188.644.169 1.194.472 1.65.909.456.431.799.971 1.03 1.621.231.649.346 1.378.346 2.186 0 .966-.145 1.847-.435 2.644-.284.791-.66 1.49-1.127 2.095-.461.6-.947 1.072-1.456 1.416-.504.338-1.102.589-1.794.753-.526.126-1.172.188-1.939.188h-4.249m1.859-1.359h1.867c.842 0 1.591-.079 2.245-.237.408-.098.756-.243 1.046-.434.381-.246.727-.57 1.038-.974.408-.535.732-1.143.974-1.825.247-.688.37-1.468.37-2.341 0-.971-.166-1.716-.499-2.235-.333-.524-.756-.87-1.271-1.04-.381-.126-.974-.188-1.778-.188h-1.85l-1.907 9.274"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/italic-e.svg b/vendor/oojs/oojs-ui/src/themes/apex/images/icons/italic-e.svg
deleted file mode 100644
index 66a5ef5d..00000000
--- a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/italic-e.svg
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="italic-e">
- <path id="e" d="M7 18l2.474-12h8.526l-.282 1.367h-6.947l-.75 3.633h6.09l-.282 1.367h-6.09l-.877 4.274h7.438l-.282 1.359h-9.018"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/italic-geor-kan.svg b/vendor/oojs/oojs-ui/src/themes/apex/images/icons/italic-geor-kan.svg
deleted file mode 100644
index 3398904d..00000000
--- a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/italic-geor-kan.svg
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="italic-geor-kan">
- <path id="geor-kan" d="M15.057 14.663c-.441 2.225-1.834 3.337-4.178 3.337-1.919 0-2.879-.787-2.879-2.36 0-.298.036-.624.108-.977.083-.431.245-.836.488-1.217l1.241.605-.207.613c-.055.259-.083.497-.083.712 0 .972.521 1.458 1.564 1.458 1.307 0 2.101-.723 2.383-2.17l.058-.331c.044-.221.066-.425.066-.613 0-.928-.546-1.391-1.638-1.391h-1.117l.248-1.259h1.117c1.202-.005 1.908-.552 2.118-1.64.039-.182.058-.356.058-.522 0-1.143-.899-1.714-2.697-1.714l.232-1.193c2.708 0 4.062.875 4.062 2.625 0 .248-.028.516-.083.803-.204 1.093-1.051 1.825-2.54 2.195l-.033.166c1.23.199 1.845.823 1.845 1.872 0 .21-.025.433-.074.671l-.058.331"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/italic-i.svg b/vendor/oojs/oojs-ui/src/themes/apex/images/icons/italic-i.svg
deleted file mode 100644
index 93bec5a6..00000000
--- a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/italic-i.svg
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="italic-i">
- <path id="i" d="M12.5 17.999l.249-.994h-1.5l2.509-10.037h1.5l.242-.967h-5l-.242.967h1.5l-2.509 10.037h-1.5l-.249.994z"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/italic-k.svg b/vendor/oojs/oojs-ui/src/themes/apex/images/icons/italic-k.svg
deleted file mode 100644
index d4831549..00000000
--- a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/italic-k.svg
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="italic-k">
- <path id="k" d="M12.018 10.652l4.982-4.652h-2l-5.309 5.234 1.309-5.234h-1.5l-3 12h1.5l1.173-4.693 1.54-1.438c.287 4.131 3.287 6.131 3.287 6.131h2s-4-2-3.982-7.348z"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/italic-s.svg b/vendor/oojs/oojs-ui/src/themes/apex/images/icons/italic-s.svg
deleted file mode 100644
index 4f6364cb..00000000
--- a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/italic-s.svg
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="italic-s">
- <path id="s" d="M16.474 6.589l-.302 1.526c-.522-.279-1.041-.488-1.557-.628-.511-.145-1.007-.217-1.487-.217-.935 0-1.679.204-2.231.612-.553.408-.829.95-.829 1.627 0 .372.101.658.302.86.207.196.733.408 1.58.635l.937.232c1.059.274 1.795.622 2.208 1.046.413.418.62 1.007.62 1.766 0 1.167-.46 2.117-1.379 2.851-.914.733-2.12 1.1-3.618 1.1-.615 0-1.232-.062-1.852-.186-.62-.119-1.242-.302-1.867-.55l.318-1.611c.573.356 1.147.625 1.72.806.578.181 1.154.271 1.728.271.976 0 1.759-.217 2.347-.651.589-.434.883-.999.883-1.697 0-.465-.119-.816-.356-1.054-.232-.243-.736-.462-1.511-.658l-.937-.24c-1.069-.279-1.8-.599-2.192-.961-.387-.367-.581-.878-.581-1.534 0-1.152.442-2.094 1.325-2.828.888-.739 2.043-1.108 3.463-1.108.553 0 1.1.049 1.642.147.542.098 1.085.245 1.627.442"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/language.svg b/vendor/oojs/oojs-ui/src/themes/apex/images/icons/language.svg
deleted file mode 100644
index 081e49a1..00000000
--- a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/language.svg
+++ /dev/null
@@ -1,7 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="language">
- <path id="japanese" d="M17.533 9.81l.271-.59 1.041.407-.18.363c.661.271 1.101.468 1.312.589.331.211.618.514.86.905.211.393.316.846.316 1.358 0 .786-.302 1.479-.905 2.083-.604.634-1.66 1.057-3.169 1.268-.121-.361-.258-.679-.408-.95.965-.151 1.645-.333 2.037-.545.454-.21.785-.481.998-.813.21-.303.314-.663.314-1.087 0-.482-.136-.905-.407-1.269-.331-.331-.8-.589-1.402-.77-.333.634-.649 1.117-.951 1.449-.242.332-.694.906-1.358 1.721.09.393.181.709.272.951l-1.042.362-.091-.498c-.423.361-.801.617-1.133.77-.361.15-.664.226-.905.226-.303 0-.574-.136-.814-.407-.243-.301-.362-.68-.362-1.132 0-.604.136-1.147.407-1.63.241-.453.603-.89 1.086-1.313.272-.241.725-.528 1.359-.86 0-.271.03-.799.09-1.585-.514.03-.921.045-1.222.045-.393 0-.711-.015-.951-.045l-.046-1.041c.725.091 1.494.135 2.31.135 0-.149.075-.738.227-1.766l1.177.183c-.151.542-.256 1.041-.316 1.493.242-.029.543-.075.906-.136.362-.061.573-.091.634-.091s.648-.15 1.766-.453l.046 1.041c-.967.243-2.145.439-3.532.591-.062.663-.092 1.086-.092 1.266.663-.151 1.284-.225 1.857-.225zm-2.672 3.893c-.061-.481-.136-1.252-.227-2.31-.573.424-1.041.86-1.403 1.313-.303.423-.452.875-.452 1.358 0 .241.044.438.136.588.09.092.195.137.316.137.363.001.907-.361 1.63-1.086zm.771-2.763c0 .483.029 1.088.09 1.811.604-.905 1.057-1.599 1.359-2.082-.574.06-1.058.151-1.449.271z"/>
- <path id="english" d="M9.497 15.981h1.851l-3.084-8.949h-1.85l-3.081 8.949h1.85l.557-1.981h3.209l.548 1.981zm-3.489-3.377l1.331-3.782 1.344 3.782h-2.675z"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/layout-ltr.svg b/vendor/oojs/oojs-ui/src/themes/apex/images/icons/layout-ltr.svg
deleted file mode 100644
index 47e71b39..00000000
--- a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/layout-ltr.svg
+++ /dev/null
@@ -1,7 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="layout-ltr">
- <path id="text" d="M5 19v-14h6v8h8v6h-14z"/>
- <path id="float" d="M13 5v6h6v-6h-6zm5 5h-4v-4h4v4z"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/layout-rtl.svg b/vendor/oojs/oojs-ui/src/themes/apex/images/icons/layout-rtl.svg
deleted file mode 100644
index fe9ee617..00000000
--- a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/layout-rtl.svg
+++ /dev/null
@@ -1,7 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="layout-rtl">
- <path id="text" d="M5 19v-6h8v-8h6v14h-14z"/>
- <path id="float" d="M5 5v6h6v-6h-6zm1 1h4v4h-4v-4z"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/link.svg b/vendor/oojs/oojs-ui/src/themes/apex/images/icons/link.svg
deleted file mode 100644
index dbae3414..00000000
--- a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/link.svg
+++ /dev/null
@@ -1,8 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="link">
- <path id="right" d="M19.188 12.001c0 1.1-.891 2.015-1.988 2.015l-4.195-.015c.538 1.088.963 1.999 1.997 1.999h3c1.656 0 2.998-2.343 2.998-4s-1.342-4-2.998-4h-3c-1.034 0-1.459.911-1.998 1.999l4.195-.015c1.098 0 1.989.917 1.989 2.017z"/>
- <path id="center" d="M8 12c0 .535.42 1 .938 1h6.109c.518 0 .938-.465.938-1 0-.534-.42-1-.938-1h-6.109c-.518 0-.938.466-.938 1z"/>
- <path id="left" d="M4.816 11.999c0-1.1.891-2.015 1.988-2.015l4.196.015c-.539-1.088-.964-1.999-1.998-1.999h-3c-1.656 0-2.998 2.343-2.998 4s1.342 4 2.998 4h3c1.034 0 1.459-.911 1.998-1.999l-4.195.015c-1.098 0-1.989-.917-1.989-2.017z"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/listBullet-ltr.svg b/vendor/oojs/oojs-ui/src/themes/apex/images/icons/listBullet-ltr.svg
deleted file mode 100644
index 5a43f5ce..00000000
--- a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/listBullet-ltr.svg
+++ /dev/null
@@ -1,11 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="bullet-list-ltr">
- <path id="bottom_dot" d="M5 10h-1c-.552 0-1 .447-1 1v1c0 .553.448 1 1 1h1c.552 0 1-.447 1-1v-1c0-.553-.448-1-1-1z"/>
- <path id="middle_dot" d="M5 17h-1c-.552 0-1 .447-1 1v1c0 .553.448 1 1 1h1c.552 0 1-.447 1-1v-1c0-.553-.448-1-1-1z"/>
- <path id="top_dot" d="M5 3h-1c-.552 0-1 .447-1 1v1c0 .553.448 1 1 1h1c.552 0 1-.447 1-1v-1c0-.553-.448-1-1-1z"/>
- <path id="bottom_line" d="M20 17h-11c-.552 0-1 .447-1 1v1c0 .553.448 1 1 1h11c.552 0 1-.447 1-1v-1c0-.553-.448-1-1-1z"/>
- <path id="middle_line" d="M20 10h-11c-.552 0-1 .447-1 1v1c0 .553.448 1 1 1h11c.552 0 1-.447 1-1v-1c0-.553-.448-1-1-1z"/>
- <path id="top_line" d="M20 3h-11c-.552 0-1 .447-1 1v1c0 .553.448 1 1 1h11c.552 0 1-.447 1-1v-1c0-.553-.448-1-1-1z"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/listBullet-rtl.svg b/vendor/oojs/oojs-ui/src/themes/apex/images/icons/listBullet-rtl.svg
deleted file mode 100644
index fb6e9569..00000000
--- a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/listBullet-rtl.svg
+++ /dev/null
@@ -1,11 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="bullet-list-rtl">
- <path id="bottom_dot_1_" d="M19 10h1c.552 0 1 .447 1 1v1c0 .553-.448 1-1 1h-1c-.552 0-1-.447-1-1v-1c0-.553.448-1 1-1z"/>
- <path id="middle_dot_1_" d="M19 17h1c.552 0 1 .447 1 1v1c0 .553-.448 1-1 1h-1c-.552 0-1-.447-1-1v-1c0-.553.448-1 1-1z"/>
- <path id="top_dot_1_" d="M19 3h1c.552 0 1 .447 1 1v1c0 .553-.448 1-1 1h-1c-.552 0-1-.447-1-1v-1c0-.553.448-1 1-1z"/>
- <path id="bottom_line_7_" d="M4 17h11c.552 0 1 .447 1 1v1c0 .553-.448 1-1 1h-11c-.552 0-1-.447-1-1v-1c0-.553.448-1 1-1z"/>
- <path id="middle_line_7_" d="M4 10h11c.552 0 1 .447 1 1v1c0 .553-.448 1-1 1h-11c-.552 0-1-.447-1-1v-1c0-.553.448-1 1-1z"/>
- <path id="top_line_7_" d="M4 3h11c.552 0 1 .447 1 1v1c0 .553-.448 1-1 1h-11c-.552 0-1-.447-1-1v-1c0-.553.448-1 1-1z"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/listNumbered-ltr.svg b/vendor/oojs/oojs-ui/src/themes/apex/images/icons/listNumbered-ltr.svg
deleted file mode 100644
index e929dae0..00000000
--- a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/listNumbered-ltr.svg
+++ /dev/null
@@ -1,11 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="number-list-ltr">
- <path id="bottom_dot" d="M3 16v1h1.993l.03 1h-1.023v1h1v1h-2v1h2.023l.977-1.002v-1l-.955-.531.955-.5v-.969l-1.007-.998z"/>
- <path id="middle_dot" d="M3 9v1h2.117l-2.117 2.187v1.811l3-.062v-.936h-2.118l2.118-2.188v-1.032l-.668-.78z"/>
- <path id="top_dot" d="M4.993 2h-.648l-1.327 1.391.031.609h1.025l-.068 2h-1.006v1h3v-1h-1.037z"/>
- <path id="bottom_line" d="M20.002 17h-11.002c-.553 0-1 .447-1 1v1c0 .553.447 1 1 1h11.002c.551 0 .998-.447.998-1v-1c0-.553-.447-1-.998-1z"/>
- <path id="middle_line" d="M20.002 10h-11.002c-.553 0-1 .447-1 1v1c0 .553.447 1 1 1h11.002c.551 0 .998-.447.998-1v-1c0-.553-.447-1-.998-1z"/>
- <path id="top_line" d="M20.002 3h-11.002c-.553 0-1 .447-1 1v1c0 .553.447 1 1 1h11.002c.551 0 .998-.447.998-1v-1c0-.553-.447-1-.998-1z"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/listNumbered-rtl.svg b/vendor/oojs/oojs-ui/src/themes/apex/images/icons/listNumbered-rtl.svg
deleted file mode 100644
index bbfa92f4..00000000
--- a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/listNumbered-rtl.svg
+++ /dev/null
@@ -1,11 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="number-list-rtl">
- <path id="bottom_dot" d="M18 16v1h1.993l.03 1h-1.023v1h1v1h-2v1h2.023l.977-1.002v-1l-.956-.531.956-.5v-.969l-1.007-.998z"/>
- <path id="middle_dot" d="M18 9v1h2.116l-2.116 2.187v1.811l3-.062v-.936h-2.118l2.118-2.188v-1.032l-.669-.78z"/>
- <path id="top_dot" d="M19.993 2h-.648l-1.328 1.391.031.609h1.026l-.069 2h-1.005v1h3v-1h-1.038z"/>
- <path id="bottom_line" d="M3.999 17h11.002c.552 0 .999.447.999 1v1c0 .553-.447 1-.999 1h-11.002c-.552 0-.999-.447-.999-1v-1c0-.553.447-1 .999-1z"/>
- <path id="middle_line" d="M3.999 10h11.002c.552 0 .999.447.999 1v1c0 .553-.447 1-.999 1h-11.002c-.552 0-.999-.447-.999-1v-1c0-.553.447-1 .999-1z"/>
- <path id="top_line" d="M3.999 3h11.002c.552 0 .999.447.999 1v1c0 .553-.447 1-.999 1h-11.002c-.552 0-.999-.447-.999-1v-1c0-.553.447-1 .999-1z"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/lock.svg b/vendor/oojs/oojs-ui/src/themes/apex/images/icons/lock.svg
deleted file mode 100644
index 76328f37..00000000
--- a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/lock.svg
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="lock">
- <path d="M12 6c-2.21 0-4 1.79-4 4v1H7v7h10v-7h-1v-1c0-2.21-1.79-4-4-4zm0 2c1.105 0 2 .895 2 2v1h-4v-1c0-1.105.895-2 2-2z"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/menu.svg b/vendor/oojs/oojs-ui/src/themes/apex/images/icons/menu.svg
deleted file mode 100644
index 50ac8a39..00000000
--- a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/menu.svg
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="menu">
- <path id="lines" d="M6 15h12c.553 0 1 .447 1 1v1c0 .553-.447 1-1 1h-12c-.553 0-1-.447-1-1v-1c0-.553.447-1 1-1zm-1-4v1c0 .553.447 1 1 1h12c.553 0 1-.447 1-1v-1c0-.553-.447-1-1-1h-12c-.553 0-1 .447-1 1zm0-5v1c0 .553.447 1 1 1h12c.553 0 1-.447 1-1v-1c0-.553-.447-1-1-1h-12c-.553 0-1 .447-1 1z"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/move-ltr.svg b/vendor/oojs/oojs-ui/src/themes/apex/images/icons/move-ltr.svg
deleted file mode 100644
index 51e6611a..00000000
--- a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/move-ltr.svg
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="move-ltr">
- <path id="arrow" d="M8.935 7.181l5.302 5.302-5.302 5.303 1.414 1.414 6.716-6.717-6.716-6.716z"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/move-rtl.svg b/vendor/oojs/oojs-ui/src/themes/apex/images/icons/move-rtl.svg
deleted file mode 100644
index bcee09d9..00000000
--- a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/move-rtl.svg
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="move-rtl">
- <path id="arrow" d="M15.065 17.786l-5.302-5.303 5.302-5.302-1.414-1.414-6.716 6.716 6.716 6.717z"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/move.svg b/vendor/oojs/oojs-ui/src/themes/apex/images/icons/move.svg
deleted file mode 100644
index 9063bd48..00000000
--- a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/move.svg
+++ /dev/null
@@ -1,4 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <path d="M20 11l-4-3v2h-3v-3h2l-3-4-3 4h2v3h-3v-2l-4 3 4 3v-2h3v3h-2l3 4 3-4h-2v-3h3v2z"/>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/newline-ltr.svg b/vendor/oojs/oojs-ui/src/themes/apex/images/icons/newline-ltr.svg
deleted file mode 100644
index dad5f51c..00000000
--- a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/newline-ltr.svg
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="line_return">
- <path d="M17.8 5.7c-.5 0-.9.2-1.2.5s-.5.7-.5 1.2v4.3h-5.1v-4l-6 5.5 6 5.5v-4h8v-9h-1.2z"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/newline-rtl.svg b/vendor/oojs/oojs-ui/src/themes/apex/images/icons/newline-rtl.svg
deleted file mode 100644
index fd758cc6..00000000
--- a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/newline-rtl.svg
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="line_return">
- <path d="M6.2 5.7c.5 0 .9.2 1.2.5.3.3.5.7.5 1.2v4.3H13v-4l6 5.5-6 5.5v-4H5v-9h1.2z"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/noWikiText-ltr.svg b/vendor/oojs/oojs-ui/src/themes/apex/images/icons/noWikiText-ltr.svg
deleted file mode 100644
index 601428e2..00000000
--- a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/noWikiText-ltr.svg
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g>
- <path d="M16 14l2 2v-11h-4v2h2zm0 2l-7-7-2-2-1-1-1-1-3-3-1 1 2 2h-1v14h4v-2h-2v-10h1l2 2v10h4v-2h-2v-6l6 6h-1v2h3l4 4 1-1-4-4zm-5-9v-2h-4l2 2zm8-2v2h2v10h-2l2 2h2v-14z"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/noWikiText-rtl.svg b/vendor/oojs/oojs-ui/src/themes/apex/images/icons/noWikiText-rtl.svg
deleted file mode 100644
index 31785a3c..00000000
--- a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/noWikiText-rtl.svg
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="g484">
- <path d="M8 14l-2 2v-11h4v2h-2zm0 2l7-7 2-2 1-1 1-1 3-3 1 1-2 2h1v14h-4v-2h2v-10h-1l-2 2v10h-4v-2h2v-6l-6 6h1v2h-3l-4 4-1-1 4-4zm5-9v-2h4l-2 2zm-8-2v2h-2v10h2l-2 2h-2v-14z" id="path486"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/outdent-ltr.svg b/vendor/oojs/oojs-ui/src/themes/apex/images/icons/outdent-ltr.svg
deleted file mode 100644
index 344b7617..00000000
--- a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/outdent-ltr.svg
+++ /dev/null
@@ -1,9 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="outdent-list-ltr">
- <path id="arrow" d="M8 13h2v-3h-2.052l-.031-2.06-4.712 3.585 4.795 3.554z"/>
- <path id="bottom_line" d="M20 17h-16c-.553 0-1 .447-1 1v1c0 .553.447 1 1 1h16c.553 0 1-.447 1-1v-1c0-.553-.447-1-1-1z"/>
- <path id="middle_line" d="M20 10h-7c-.553 0-1 .447-1 1v1c0 .553.447 1 1 1h7c.553 0 1-.447 1-1v-1c0-.553-.447-1-1-1z"/>
- <path id="top_line" d="M20 3h-16c-.553 0-1 .447-1 1v1c0 .553.447 1 1 1h16c.553 0 1-.447 1-1v-1c0-.553-.447-1-1-1z"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/outdent-rtl.svg b/vendor/oojs/oojs-ui/src/themes/apex/images/icons/outdent-rtl.svg
deleted file mode 100644
index 31e92c51..00000000
--- a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/outdent-rtl.svg
+++ /dev/null
@@ -1,9 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="outdent-list-rtl">
- <path id="arrow" d="M16 13h-2v-3h2.052l.031-2.06 4.712 3.585-4.795 3.554z"/>
- <path id="bottom_line" d="M4 17h16c.553 0 1 .447 1 1v1c0 .553-.447 1-1 1h-16c-.553 0-1-.447-1-1v-1c0-.553.447-1 1-1z"/>
- <path id="middle_line" d="M4 10h7c.553 0 1 .447 1 1v1c0 .553-.447 1-1 1h-7c-.553 0-1-.447-1-1v-1c0-.553.447-1 1-1z"/>
- <path id="top_line" d="M4 3h16c.553 0 1 .447 1 1v1c0 .553-.447 1-1 1h-16c-.553 0-1-.447-1-1v-1c0-.553.447-1 1-1z"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/outline-ltr.svg b/vendor/oojs/oojs-ui/src/themes/apex/images/icons/outline-ltr.svg
deleted file mode 100644
index 9c0ea598..00000000
--- a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/outline-ltr.svg
+++ /dev/null
@@ -1,7 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="outline-ltr">
- <path id="text" d="M5 13h14v6h-14v-6z"/>
- <path id="float" d="M5 5v6h6v-6h-6zm5 5h-4v-4h4v4z"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/outline-rtl.svg b/vendor/oojs/oojs-ui/src/themes/apex/images/icons/outline-rtl.svg
deleted file mode 100644
index 2a3428e9..00000000
--- a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/outline-rtl.svg
+++ /dev/null
@@ -1,7 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="outline-rtl">
- <path id="text" d="M19 19h-14v-6h14v6z"/>
- <path id="float" d="M13 5v6h6v-6h-6zm1 1h4v4h-4v-4z"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/picture.svg b/vendor/oojs/oojs-ui/src/themes/apex/images/icons/picture.svg
deleted file mode 100644
index 7400bca9..00000000
--- a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/picture.svg
+++ /dev/null
@@ -1,8 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="picture">
- <path id="frame" d="M18 4h-12c-2-.007-3 .993-3 2.993l.014 9.007c-.014 2 .986 2.988 2.986 3h12c2-.012 2.994-1 3-3.006v-9.001c-.006-2-1-3-3-2.993zm1 13h-14v-11h14v11z"/>
- <path id="mountains" d="M6 13.5l3.5-3.5 2.328 2.312-1.312 1.094.875 1.032 4.109-3.438 2.5 2v3h-12z"/>
- <path id="sky" d="M6 12l3.516-4.156 3.046 3.172 2.938-2.016 2.5 2v-4h-12z"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/puzzle-ltr.svg b/vendor/oojs/oojs-ui/src/themes/apex/images/icons/puzzle-ltr.svg
deleted file mode 100644
index 97b77bb4..00000000
--- a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/puzzle-ltr.svg
+++ /dev/null
@@ -1,4 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <path d="M18 9.9c-.7 0-1.4.3-1.8.9v-4.8h-4c.2-.4.4-.8.4-1.2 0-1.2-1-2.2-2.2-2.2-1.3-.1-2.3.9-2.3 2.2 0 .4.2.8.4 1.2h-4.4v3.6l.6-.1c1.4 0 2.5 1.1 2.5 2.5s-1.1 2.5-2.5 2.5c-.2 0-.4 0-.6-.1v3.6h4.9c-.5.4-.9 1-.9 1.8 0 1.2 1 2.2 2.3 2.2 1.2 0 2.2-1 2.2-2.2 0-.7-.3-1.4-.9-1.8h4.5v-4.5c.4.5 1 .9 1.8.9 1.2 0 2.2-1 2.2-2.2 0-1.3-1-2.3-2.2-2.3z" id="path542"/>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/puzzle-rtl.svg b/vendor/oojs/oojs-ui/src/themes/apex/images/icons/puzzle-rtl.svg
deleted file mode 100644
index 0ad5f375..00000000
--- a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/puzzle-rtl.svg
+++ /dev/null
@@ -1,4 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <path d="M6.3 9.9c.7 0 1.4.3 1.8.9v-4.8h4c-.2-.4-.4-.8-.4-1.2 0-1.2 1-2.2 2.2-2.2 1.3-.1 2.3.9 2.3 2.2 0 .4-.2.8-.4 1.2h4.4v3.6l-.6-.1c-1.4 0-2.5 1.1-2.5 2.5s1.1 2.5 2.5 2.5c.2 0 .4 0 .6-.1v3.6h-4.9c.5.4.9 1 .9 1.8 0 1.2-1 2.2-2.3 2.2-1.2 0-2.2-1-2.2-2.2 0-.7.3-1.4.9-1.8h-4.5v-4.5c-.4.5-1 .9-1.8.9-1.2 0-2.2-1-2.2-2.2 0-1.3 1-2.3 2.2-2.3z" id="path542"/>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/quotes-ltr.svg b/vendor/oojs/oojs-ui/src/themes/apex/images/icons/quotes-ltr.svg
deleted file mode 100644
index dc1c06f0..00000000
--- a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/quotes-ltr.svg
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g>
- <path d="M19.9 8.7c.3-.1.6-.3.8-.6s.3-.7.3-1.1v-1c-1.3.2-1.9.2-3.3.8-.9.5-1.6 1.1-2.2 1.8s-2.5 3.4-2.5 7.4v4h6c1.1 0 2-.9 2-2v-6h-4s.1-.9.8-1.8c.6-.7 1.3-1.2 2.1-1.5zm-14.4-.1c-.6.7-2.5 3.4-2.5 7.4v4h6c1.1 0 2-.9 2-2v-6h-4s.1-.9.8-1.8c.6-.7 1.3-1.2 2.1-1.5.3-.1.6-.3.8-.6s.3-.7.3-1.1v-1c-1.3.2-1.9.2-3.3.8-.8.5-1.6 1.1-2.2 1.8z"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/quotes-rtl.svg b/vendor/oojs/oojs-ui/src/themes/apex/images/icons/quotes-rtl.svg
deleted file mode 100644
index 3a8b7012..00000000
--- a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/quotes-rtl.svg
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="g552">
- <path d="M4.1 8.7c-.3-.1-.6-.3-.8-.6-.2-.3-.3-.7-.3-1.1v-1c1.3.2 1.9.2 3.3.8.9.5 1.6 1.1 2.2 1.8.6.7 2.5 3.4 2.5 7.4v4h-6c-1.1 0-2-.9-2-2v-6h4s-.1-.9-.8-1.8c-.6-.7-1.3-1.2-2.1-1.5zm14.4-.1c.6.7 2.5 3.4 2.5 7.4v4h-6c-1.1 0-2-.9-2-2v-6h4s-.1-.9-.8-1.8c-.6-.7-1.3-1.2-2.1-1.5-.3-.1-.6-.3-.8-.6-.2-.3-.3-.7-.3-1.1v-1c1.3.2 1.9.2 3.3.8.8.5 1.6 1.1 2.2 1.8z" id="path554"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/quotesAdd-ltr.svg b/vendor/oojs/oojs-ui/src/themes/apex/images/icons/quotesAdd-ltr.svg
deleted file mode 100644
index 24fca8f5..00000000
--- a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/quotesAdd-ltr.svg
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="g4">
- <path d="M3.5 8.6c-.6.7-2.5 3.4-2.5 7.4v4h6c1.1 0 2-.9 2-2v-6h-4s.1-.9.8-1.8c.6-.7 1.3-1.2 2.1-1.5.3-.1.6-.3.8-.6.2-.3.3-.7.3-1.1v-1c-1.3.2-1.9.2-3.3.8-.8.5-1.6 1.1-2.2 1.8zm15.5-3.6v-4h-2v4h-4v2h4v4h2v-4h4v-2zm-4 7s.1-.9.8-1.8l.2-.2v-2h-1.9l-.6.6c-.6.7-2.5 3.4-2.5 7.4v4h6c1.1 0 2-.9 2-2v-6h-4z" id="path6"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/quotesAdd-rtl.svg b/vendor/oojs/oojs-ui/src/themes/apex/images/icons/quotesAdd-rtl.svg
deleted file mode 100644
index 736f2a6d..00000000
--- a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/quotesAdd-rtl.svg
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="g4">
- <path d="M20.5 8.6c.6.7 2.5 3.4 2.5 7.4v4h-6c-1.1 0-2-.9-2-2v-6h4s-.1-.9-.8-1.8c-.6-.7-1.3-1.2-2.1-1.5-.3-.1-.6-.3-.8-.6-.2-.3-.3-.7-.3-1.1v-1c1.3.2 1.9.2 3.3.8.8.5 1.6 1.1 2.2 1.8zm-15.5-3.6v-4h2v4h4v2h-4v4h-2v-4h-4v-2zm4 7s-.1-.9-.8-1.8l-.2-.2v-2h1.9l.6.6c.6.7 2.5 3.4 2.5 7.4v4h-6c-1.1 0-2-.9-2-2v-6h4z" id="path6"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/redirect-ltr.svg b/vendor/oojs/oojs-ui/src/themes/apex/images/icons/redirect-ltr.svg
deleted file mode 100644
index 884d40df..00000000
--- a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/redirect-ltr.svg
+++ /dev/null
@@ -1,8 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="create_redirect">
- <g>
- <path d="M17.7 2.4c-.3-.3-.7-.4-1.2-.4h-12.1v16.2c0 .5.1.8.4 1.1s.7.7 1.2.7h10.2c-.6-.2-1.2-.5-1.9-1-.4-.3-.8-.6-1.2-1l-.5-.6h-6.2v-1.4h5.4s-.4-1.5-.4-2h-5v-1h9v1c.4.1 1.1.1 1.5.1.4 0 .7 0 1.1-.1v-10.5c.1-.5-.1-.9-.3-1.1zm-5.2 1.6h3v4.5h-3v-4.5zm-6.1 0h4v1.6h-4v-1.6zm0 3h4v1.5h-4v-1.5zm0 3h9v1.5h-9v-1.5zm12.7 3.1l4.9 3.8-4.9 4.8v-2.2c-1.7 0-2.9-.2-4.3-1.2-1.2-.8-2.5-2.6-2.3-4.1 1.4 1 2.9 1.5 4.4 1.5.7 0 1.4-.1 2.1-.3l.1-2.3"/>
- </g>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/redirect-rtl.svg b/vendor/oojs/oojs-ui/src/themes/apex/images/icons/redirect-rtl.svg
deleted file mode 100644
index a07e8364..00000000
--- a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/redirect-rtl.svg
+++ /dev/null
@@ -1,9 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="create_redirect">
- <g id="g3264">
- <path d="M6.3 2.4c.3-.3.7-.4 1.2-.4h12.1v16.2c0 .5-.1.8-.4 1.1-.3.3-.7.7-1.2.7h-10.2c.6-.2 1.2-.5 1.9-1 .4-.3.8-.6 1.2-1l.5-.6h6.2v-1.4h-5.4s.4-1.5.4-2h5v-1h-9v1c-.4.1-1.1.1-1.5.1-.4 0-.7 0-1.1-.1v-10.5c-.1-.5.1-.9.3-1.1zm5.2 1.6h-3v4.5h3v-4.5zm6.1 0h-4v1.6h4v-1.6zm0 3h-4v1.5h4v-1.5zm0 3h-9v1.5h9v-1.5z" id="path3266"/>
- <path d="M4.9 13.1l-4.9 3.8 4.9 4.8v-2.2c1.7 0 2.9-.2 4.3-1.2 1.2-.8 2.5-2.6 2.3-4.1-1.4 1-2.9 1.5-4.4 1.5-.7 0-1.4-.1-2.1-.3l-.1-2.3" id="path3268"/>
- </g>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/regular-expression.svg b/vendor/oojs/oojs-ui/src/themes/apex/images/icons/regular-expression.svg
deleted file mode 100644
index 7b672618..00000000
--- a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/regular-expression.svg
+++ /dev/null
@@ -1,9 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="regular-expression">
- <path id="left-bracket" d="m 3,12.044797 c -5e-7,-0.989171 0.150394,-1.914889 0.451184,-2.7771612 C 3.7558785,8.4053812 4.1933899,7.6495032 4.7637193,7 L 6.2286026,7 C 5.6778034,7.7204251 5.261777,8.511764 4.9805221,9.3740188 4.6992623,10.236291 4.5586337,11.122815 4.5586357,12.033598 c -2e-6,0.914522 0.1425798,1.799179 0.427746,2.653974 C 5.2754491,15.538635 5.6856161,16.309444 6.2168835,17 L 4.7637193,17 C 4.1894835,16.365435 3.7519721,15.624488 3.451184,14.777158 3.150394,13.929828 3,13.019042 3,12.044797" />
- <path id="dot" d="m 10,16 c 0,0.552285 -0.4477153,1 -1,1 -0.5522847,0 -1,-0.447715 -1,-1 0,-0.552285 0.4477153,-1 1,-1 0.5522847,0 1,0.447715 1,1 z" />
- <path id="star" d="m 14.250652,7.0127142 -0.240235,2.15625 2.185547,-0.609375 0.193359,1.4765618 -1.992187,0.140625 1.306641,1.740234 -1.330079,0.708985 -0.914062,-1.833985 -0.802734,1.822266 -1.382813,-0.697266 1.294922,-1.740234 -1.980469,-0.152343 0.228516,-1.4648438 2.138672,0.609375 -0.240235,-2.15625 1.535157,0" />
- <path id="right-bracket" d="m 21,12.044797 c -3e-6,0.981711 -0.152351,1.896229 -0.457043,2.743558 C 20.241767,15.635686 19.806209,16.3729 19.235883,17 l -1.453164,0 c 0.527356,-0.686824 0.93557,-1.455766 1.224642,-2.306829 0.289069,-0.854795 0.433604,-1.741318 0.433606,-2.659573 -2e-6,-0.910783 -0.140631,-1.797307 -0.421886,-2.6595792 C 18.737821,8.511764 18.321795,7.7204251 17.771,7 l 1.464883,0 c 0.574232,0.653236 1.011744,1.4128466 1.312536,2.2788341 0.300785,0.8622719 0.45118,1.7842569 0.451183,2.7659629" />
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/remove.svg b/vendor/oojs/oojs-ui/src/themes/apex/images/icons/remove.svg
deleted file mode 100644
index 6ad79174..00000000
--- a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/remove.svg
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="remove">
- <path id="trash-can" d="M12 10h-1v6h1v-6zm-2 0h-1v6h1v-6zm4 0h-1v6h1v-6zm0-4v-1h-5v1h-3v3h1v7.966l1 1.031v-.074.077h6.984l.016-.018v.015l1-1.031v-7.966h1v-3h-3zm1 11h-7v-8h7v8zm1-9h-9v-1h9v1z"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/search.svg b/vendor/oojs/oojs-ui/src/themes/apex/images/icons/search.svg
deleted file mode 100644
index 208d44b3..00000000
--- a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/search.svg
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="search">
- <path id="search" d="M16.021 15.96l-2.374-2.375-.169-.099c.403-.566.643-1.26.643-2.009-.001-1.92-1.558-3.477-3.477-3.477-1.921 0-3.478 1.557-3.478 3.478 0 1.92 1.557 3.477 3.478 3.477.749 0 1.442-.239 2.01-.643l.098.169 2.375 2.374c.19.189.543.143.79-.104s.293-.601.104-.791zm-5.377-2.27c-1.221 0-2.213-.991-2.213-2.213 0-1.221.992-2.213 2.213-2.213 1.222 0 2.213.992 2.213 2.213-.001 1.222-.992 2.213-2.213 2.213z"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/secure-link.svg b/vendor/oojs/oojs-ui/src/themes/apex/images/icons/secure-link.svg
deleted file mode 100644
index a9c7d276..00000000
--- a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/secure-link.svg
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 12 12">
- <g id="secure">
- <path id="lock" d="M8 5h.019v-.997c.001-.057.004-1.409-.832-2.255-.434-.438-.998-.66-1.679-.66s-1.245.222-1.678.659c-.837.847-.833 2.199-.832 2.251v1.002h.002c-.553 0-1 .447-1 1v3c0 .553.447 1 1 1h5c.553 0 1-.447 1-1v-3c0-.553-.447-1-1-1zm-4.002 0v-1.007c0-.01.005-.999.543-1.543.482-.485 1.449-.487 1.932-.002.544.546.546 1.536.546 1.55v1.002h-3.021z"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/settings.svg b/vendor/oojs/oojs-ui/src/themes/apex/images/icons/settings.svg
deleted file mode 100644
index 9fa0a4b3..00000000
--- a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/settings.svg
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0, 0, 24, 24">
- <g id="settings">
- <path id="gear" d="M3 4h3v2h-3zM12 4h9v2h-9zM8 3h2c.552 0 1 .448 1 1v2c0 .552-.448 1-1 1h-2c-.552 0-1-.448-1-1v-2c0-.552.448-1 1-1zM3 11h9v2h-9zM18 11h3v2h-3zM14 10h2c.552 0 1 .448 1 1v2c0 .552-.448 1-1 1h-2c-.552 0-1-.448-1-1v-2c0-.552.448-1 1-1zM3 18h6v2h-6zM15 18h6v2h-6zM11 17h2c.552 0 1 .448 1 1v2c0 .552-.448 1-1 1h-2c-.552 0-1-.448-1-1v-2c0-.552.448-1 1-1z"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/smaller-ltr.svg b/vendor/oojs/oojs-ui/src/themes/apex/images/icons/smaller-ltr.svg
deleted file mode 100644
index e8b427b1..00000000
--- a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/smaller-ltr.svg
+++ /dev/null
@@ -1,7 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <path id="a" d="M12.666 6h-1.372l-4.48 12H8.52l1.493-4h4l1.507 4h1.666l-4.52-12zm-2.28 7l1.617-4.333L13.637 13h-3.25z"/>
- <g id="down">
- <path id="arrow" d="M22 3l-3.5 6L15 3z"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/smaller-rtl.svg b/vendor/oojs/oojs-ui/src/themes/apex/images/icons/smaller-rtl.svg
deleted file mode 100644
index e5e95196..00000000
--- a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/smaller-rtl.svg
+++ /dev/null
@@ -1,7 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <path id="a" d="M12.666 6h-1.372l-4.48 12H8.52l1.493-4h4l1.507 4h1.666l-4.52-12zm-2.28 7l1.617-4.333L13.637 13h-3.25z"/>
- <g id="down">
- <path id="arrow" d="M9 3L5.5 9 2 3z"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/specialCharacter.svg b/vendor/oojs/oojs-ui/src/themes/apex/images/icons/specialCharacter.svg
deleted file mode 100644
index 4d601281..00000000
--- a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/specialCharacter.svg
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="special-character">
- <path id="omega" d="M12 6.708c-.794 0-1.368.103-1.894.31-.525.207-.944.496-1.255.867-.311.366-.531.808-.66 1.327-.128.513-.192 1.08-.192 1.699 0 .513.058 1 .174 1.46.122.46.311.87.568 1.23.629.863 1.155 1.139 2.011 1.363l.247 3.035h-5v-3h.605l.531 1.354.394.053.605.044.751.035.456.009h.66l-.092-.894c-.629-.094-.811-.268-1.336-.522-.525-.26-.98-.59-1.365-.991-.379-.401-.675-.867-.889-1.398-.214-.537-.321-1.13-.321-1.779 0-.82.131-1.537.394-2.15.269-.619.656-1.133 1.163-1.54.507-.407 1.133-.711 1.878-.912.745-.206 1.6-.31 2.565-.31.959 0 1.811.103 2.556.31.751.201 1.38.504 1.887.912.507.407.892.92 1.154 1.54.269.614.403 1.33.403 2.15 0 .649-.107 1.242-.321 1.779-.214.531-.513.997-.898 1.398-.379.401-.831.732-1.356.991-.525.254-.707.428-1.336.522l-.092.894h.66l.447-.009.751-.035.605-.044.403-.053.531-1.354h.605v3h-5l.247-3.035c1.066-.11 1.337-.696 2.002-1.363.263-.36.452-.77.568-1.23.122-.46.183-.947.183-1.46 0-.619-.064-1.186-.192-1.699-.128-.519-.348-.962-.66-1.327-.311-.372-.73-.661-1.255-.867-.525-.206-1.1-.31-1.894-.31"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/star.svg b/vendor/oojs/oojs-ui/src/themes/apex/images/icons/star.svg
deleted file mode 100644
index ea8c26c6..00000000
--- a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/star.svg
+++ /dev/null
@@ -1,4 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <path d="M12 7.4l1.7 3.6 4 .5-2.7 2.8.5 3.9-3.5-1.7-3.6 1.7.6-3.9-2.8-2.8 3.9-.5 1.9-3.6m0-3.4l-2.8 5.6-6.2.9 4.5 4.4-1.1 6.1 5.6-3 5.5 3-1-6.2 4.5-4.4-6.3-.9-2.7-5.5z"/>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/strikethrough-a.svg b/vendor/oojs/oojs-ui/src/themes/apex/images/icons/strikethrough-a.svg
deleted file mode 100644
index 480189f5..00000000
--- a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/strikethrough-a.svg
+++ /dev/null
@@ -1,7 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="strikethrough-a">
- <path id="strikethrough" d="M6 11h12v1h-12v-1z"/>
- <path id="a" d="M12.666 6h-1.372l-4.48 12h1.705l1.494-4h3.999l1.508 4h1.666l-4.52-12zm-2.28 7l1.617-4.333 1.634 4.333h-3.251z"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/strikethrough-s.svg b/vendor/oojs/oojs-ui/src/themes/apex/images/icons/strikethrough-s.svg
deleted file mode 100644
index d57b652f..00000000
--- a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/strikethrough-s.svg
+++ /dev/null
@@ -1,7 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="strikethrough-s">
- <path id="strikethrough" d="M6 12h12v1h-12v-1z"/>
- <path id="s" d="M12.094 6c-1.133 0-2.076.287-2.75.9-.67.613-1 1.49-1 2.52 0 .889.221 1.602.719 2.13.498.528 1.279.91 2.312 1.14l.812.182v-.03c.656.147 1.128.375 1.375.63.252.256.375.607.375 1.11 0 .573-.172.97-.531 1.26-.358.291-.894.45-1.625.45-.477 0-.969-.074-1.469-.24-.502-.166-1.031-.417-1.562-.75l-.375-.238v2.158l.156.062c.58.237 1.143.417 1.688.54.549.121 1.07.18 1.562.18 1.286 0 2.297-.293 3-.9.709-.605 1.062-1.486 1.062-2.608 0-.943-.256-1.726-.781-2.312-.521-.592-1.305-1-2.344-1.229l-.812-.181c-.716-.148-1.204-.352-1.406-.539-.205-.203-.312-.485-.312-.935 0-.533.162-.899.5-1.17.342-.271.836-.42 1.531-.42.395 0 .818.052 1.25.181.433.127.908.333 1.406.6l.375.18v-2.041s-1.188-.383-1.688-.479c-.499-.098-.984-.151-1.468-.151z"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/strikethrough-y.svg b/vendor/oojs/oojs-ui/src/themes/apex/images/icons/strikethrough-y.svg
deleted file mode 100644
index 8409dc15..00000000
--- a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/strikethrough-y.svg
+++ /dev/null
@@ -1,7 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="strikethrough-y">
- <path id="strikethrough" d="M6 11h12v1h-12v-1z"/>
- <path id="a" d="M7 6h1.724l3.288 4.935 3.264-4.935h1.724l-4.194 6.285v5.715h-1.612v-5.715l-4.194-6.285"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/subscript-ltr.svg b/vendor/oojs/oojs-ui/src/themes/apex/images/icons/subscript-ltr.svg
deleted file mode 100644
index b7507daf..00000000
--- a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/subscript-ltr.svg
+++ /dev/null
@@ -1,5 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <path id="x" d="M14 9l-2.354 3.406L14 16h-1.2L11 13.25 9.2 16H8l2.403-3.662L8 9h1.188l1.857 2.494L12.797 9H14z"/>
- <path d="M18 13l-1 1v3l1 1h-1l-.527-.46L16 18h-1l1-1v-3l-1-1h1l.485.497L17 13z"/>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/subscript-rtl.svg b/vendor/oojs/oojs-ui/src/themes/apex/images/icons/subscript-rtl.svg
deleted file mode 100644
index 9fe5325f..00000000
--- a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/subscript-rtl.svg
+++ /dev/null
@@ -1,5 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <path id="x" d="M12 9l2.354 3.406L12 16h1.2l1.8-2.75L16.8 16H18l-2.403-3.662L18 9h-1.188l-1.857 2.494L13.203 9H12z"/>
- <path d="M8 13l1 1v3l-1 1h1l.527-.46L10 18h1l-1-1v-3l1-1h-1l-.485.497L9 13z"/>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/superscript-ltr.svg b/vendor/oojs/oojs-ui/src/themes/apex/images/icons/superscript-ltr.svg
deleted file mode 100644
index 39f30a76..00000000
--- a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/superscript-ltr.svg
+++ /dev/null
@@ -1,5 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <path id="x" d="M14 9l-2.354 3.406L14 16h-1.2L11 13.25 9.2 16H8l2.403-3.662L8 9h1.188l1.857 2.494L12.797 9H14z"/>
- <path d="M18 7l-1 1v3l1 1h-1l-.527-.46L16 12h-1l1-1V8l-1-1h1l.485.497L17 7z"/>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/superscript-rtl.svg b/vendor/oojs/oojs-ui/src/themes/apex/images/icons/superscript-rtl.svg
deleted file mode 100644
index eabab21c..00000000
--- a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/superscript-rtl.svg
+++ /dev/null
@@ -1,5 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <path id="x" d="M12 9l2.354 3.406L12 16h1.2l1.8-2.75L16.8 16H18l-2.403-3.662L18 9h-1.188l-1.857 2.494L13.203 9H12z"/>
- <path d="M8 7l1 1v3l-1 1h1l.527-.46L10 12h1l-1-1V8l1-1h-1l-.485.497L9 7z"/>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/table-caption.svg b/vendor/oojs/oojs-ui/src/themes/apex/images/icons/table-caption.svg
deleted file mode 100644
index 15bb06a6..00000000
--- a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/table-caption.svg
+++ /dev/null
@@ -1,7 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="table-caption">
- <path id="caption" d="M6 6h12v3H6z"/>
- <path id="table" d="M4 10v7h16v-7H4zm1 1h4v2H5v-2zm5 0h4v2h-4v-2zm5 0h4v2h-4v-2zM5 14h4v2H5v-2zm5 0h4v2h-4v-2zm5 0h4v2h-4v-2z"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/table-insert-column-ltr.svg b/vendor/oojs/oojs-ui/src/themes/apex/images/icons/table-insert-column-ltr.svg
deleted file mode 100644
index 798ee4a1..00000000
--- a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/table-insert-column-ltr.svg
+++ /dev/null
@@ -1,11 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="table-insert-column-ltr">
- <path
- d="m 13,9 -2,0 0,2 -2,0 0,2 2,0 0,2 2,0 0,-2 2,0 0,-2 -2,0 z"
- id="plus" />
- <path
- d="m 5,5 2,0 0,14 -2,0 z"
- id="column" />
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/table-insert-column-rtl.svg b/vendor/oojs/oojs-ui/src/themes/apex/images/icons/table-insert-column-rtl.svg
deleted file mode 100644
index dfa33a08..00000000
--- a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/table-insert-column-rtl.svg
+++ /dev/null
@@ -1,11 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="table-insert-column-rtl">
- <path
- d="m 13,9 -2,0 0,2 -2,0 0,2 2,0 0,2 2,0 0,-2 2,0 0,-2 -2,0 z"
- id="plus" />
- <path
- d="m 17,5 2,0 0,14 -2,0 z"
- id="column" />
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/table-insert-row-after.svg b/vendor/oojs/oojs-ui/src/themes/apex/images/icons/table-insert-row-after.svg
deleted file mode 100644
index 91d06644..00000000
--- a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/table-insert-row-after.svg
+++ /dev/null
@@ -1,11 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="table-insert-row-after">
- <path
- d="m 13,9 -2,0 0,2 -2,0 0,2 2,0 0,2 2,0 0,-2 2,0 0,-2 -2,0 z"
- id="plus" />
- <path
- d="m 5,17 14,0 0,2 -14,0 z"
- id="row" />
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/table-insert-row-before.svg b/vendor/oojs/oojs-ui/src/themes/apex/images/icons/table-insert-row-before.svg
deleted file mode 100644
index 4b71f2a8..00000000
--- a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/table-insert-row-before.svg
+++ /dev/null
@@ -1,11 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="table-insert-row-before">
- <path
- d="m 13,9 -2,0 0,2 -2,0 0,2 2,0 0,2 2,0 0,-2 2,0 0,-2 -2,0 z"
- id="plus" />
- <path
- d="m 5,5 14,0 0,2 -14,0 z"
- id="row" />
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/table-merge-cells.svg b/vendor/oojs/oojs-ui/src/themes/apex/images/icons/table-merge-cells.svg
deleted file mode 100644
index 6a8b77d8..00000000
--- a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/table-merge-cells.svg
+++ /dev/null
@@ -1,10 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="24" height="24" viewBox="0 0 24 24">
- <g id="table-merge-cells">
- <g id="merge-cell-left">
- <path id="cell-border" d="m 4,7 0,9 7,0 0,-3 -1,0.834 L 10,15 5,15 5,8 10,8 10,9.167 11,10 11,7 z" />
- <path id="arrow" d="m 8,9 0,2 -2,0 0,1 2,0 0,2 3,-2.5 z" />
- </g>
- <use id="merge-cell-right" xlink:href="#merge-cell-left" transform="matrix(-1,0,0,1,24,0)" />
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/table.svg b/vendor/oojs/oojs-ui/src/themes/apex/images/icons/table.svg
deleted file mode 100644
index 1ba8c440..00000000
--- a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/table.svg
+++ /dev/null
@@ -1,7 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
-
- <g id="table-insert">
- <path id="table" d="M4 5v13h16v-13zm2 2h5v4h-5zm7 0h5v4h-5zm-7 5h5v4h-5zm7 0h5v4h-5z"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/tag.svg b/vendor/oojs/oojs-ui/src/themes/apex/images/icons/tag.svg
deleted file mode 100644
index 534824c8..00000000
--- a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/tag.svg
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="tag">
- <path d="M18.748 11.717c.389.389.389 1.025 0 1.414l-4.949 4.95c-.389.389-1.025.389-1.414 0l-6.01-6.01c-.389-.389-.707-1.157-.707-1.707l-.001-4.364c0-.55.45-1 1-1h4.364c.55 0 1.318.318 1.707.707l6.01 6.01zm-10.644-4.261c-.579.576-.578 1.514-.001 2.093.578.577 1.516.577 2.095.001.576-.578.576-1.517 0-2.095-.581-.576-1.518-.577-2.094.001z"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/templateAdd-ltr.svg b/vendor/oojs/oojs-ui/src/themes/apex/images/icons/templateAdd-ltr.svg
deleted file mode 100644
index 6b594b29..00000000
--- a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/templateAdd-ltr.svg
+++ /dev/null
@@ -1,7 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g>
- <path d="M24 6h-4v-4h-2v4h-4v2h4v4h2v-4h4z"/>
- </g>
- <path d="M19 13v7h-16c-1.1 0-2-.9-2-2v-11h12v-1h-13v12c0 1.7 1.3 3 3 3h17v-8h-1z"/>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/templateAdd-rtl.svg b/vendor/oojs/oojs-ui/src/themes/apex/images/icons/templateAdd-rtl.svg
deleted file mode 100644
index 36b25a3e..00000000
--- a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/templateAdd-rtl.svg
+++ /dev/null
@@ -1,7 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="g690">
- <path d="M0 6h4v-4h2v4h4v2h-4v4h-2v-4h-4z" id="path692"/>
- </g>
- <path d="M5 13v7h16c1.1 0 2-.9 2-2v-11h-12v-1h13v12c0 1.7-1.3 3-3 3h-17v-8h1z" id="path694"/>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/text-dir-lefttoright.svg b/vendor/oojs/oojs-ui/src/themes/apex/images/icons/text-dir-lefttoright.svg
deleted file mode 100644
index 62526a03..00000000
--- a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/text-dir-lefttoright.svg
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="text-dir-ltr">
- <path d="M7 7h-2v-1h2l.469.5.531-.5h2v1h-2v10h2v1h-2l-.5-.531-.5.531h-2v-1h2zM13.976 16v-2h-2.976v-4h2.976v-1.956l6.024 3.978z"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/text-dir-righttoleft.svg b/vendor/oojs/oojs-ui/src/themes/apex/images/icons/text-dir-righttoleft.svg
deleted file mode 100644
index 913bbfd6..00000000
--- a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/text-dir-righttoleft.svg
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="text-dir-rtl">
- <path d="M17 17h2v1h-2l-.469-.5-.531.5h-2v-1h2v-10h-2v-1h2l.5.531.5-.531h2v1h-2zM10.024 8v2h2.976v4h-2.976v1.956l-6.024-3.978z"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/text-style.svg b/vendor/oojs/oojs-ui/src/themes/apex/images/icons/text-style.svg
deleted file mode 100644
index 0198c355..00000000
--- a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/text-style.svg
+++ /dev/null
@@ -1,7 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="text-style">
- <path id="a" d="M15.296 18h2.789l-1.14-12h-2.789l-8.156 12h2.789l2.039-3h4.183l.285 3zm-3.109-5l2.311-3.4.323 3.4h-2.634z"/>
- <path id="underline" d="M6 19h12v1h-12v-1z"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/translation-ltr.svg b/vendor/oojs/oojs-ui/src/themes/apex/images/icons/translation-ltr.svg
deleted file mode 100644
index 7740e43e..00000000
--- a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/translation-ltr.svg
+++ /dev/null
@@ -1,4 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <path d="M11.1 13.1c-1.8-2.1-2.7-4.3-3-5.1h4.7l.7-2h-5.5v-3h-2v3h-5v2h5c-.2.9-1.3 4.8-5.1 7.6l1.2 1.6c2.7-2 4.3-4.5 5.1-6.4.7 1.3 1.7 3 3.2 4.5l.7-2.2zm1.4 6.9l1.3-4h5.3l1.3 4h2.2l-4.6-14h-3l-4.7 14h2.2zm4-12l2 6h-4l2-6z"/>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/translation-rtl.svg b/vendor/oojs/oojs-ui/src/themes/apex/images/icons/translation-rtl.svg
deleted file mode 100644
index c78e6222..00000000
--- a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/translation-rtl.svg
+++ /dev/null
@@ -1,4 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <path d="M12.4 13.1c1.8-2.1 2.7-4.3 3-5.1h-4.7l-.7-2h5.5v-3h2v3h5v2h-5c.2.9 1.3 4.8 5.1 7.6l-1.2 1.6c-2.7-2-4.3-4.5-5.1-6.4-.7 1.3-1.7 3-3.2 4.5l-.7-2.2zm-1.4 6.9l-1.3-4h-5.3l-1.3 4h-2.2l4.6-14h3l4.7 14h-2.2zm-4-12l-2 6h4l-2-6z" id="path704"/>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/trash.svg b/vendor/oojs/oojs-ui/src/themes/apex/images/icons/trash.svg
deleted file mode 100644
index f5914312..00000000
--- a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/trash.svg
+++ /dev/null
@@ -1,4 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <path d="M6 8c0-1.1.9-2 2-2h2l1-1h2l1 1h2c1.1 0 2 .9 2 2h-12zm1 1h10l-1 11h-8z"/>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/trashUndo-ltr.svg b/vendor/oojs/oojs-ui/src/themes/apex/images/icons/trashUndo-ltr.svg
deleted file mode 100644
index 0731f056..00000000
--- a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/trashUndo-ltr.svg
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g>
- <path d="M20.5 20.5l-15.5-15.5-1 1 3 3 1 11h8l.2-1.8 3.3 3.3zm-3.5-11.5h-6l5.5 5.5zm1-1c0-1.1-.9-2-2-2h-2l-1-1h-2l-1 1h-2l2 2h8z"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/trashUndo-rtl.svg b/vendor/oojs/oojs-ui/src/themes/apex/images/icons/trashUndo-rtl.svg
deleted file mode 100644
index 2a92cbef..00000000
--- a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/trashUndo-rtl.svg
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="g714">
- <path d="M4 20.5l15.5-15.5 1 1-3 3-1 11h-8l-.2-1.8-3.3 3.3zm3.5-11.5h6l-5.5 5.5zm-1-1c0-1.1.9-2 2-2h2l1-1h2l1 1h2l-2 2h-8z" id="path716"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/unLock-ltr.svg b/vendor/oojs/oojs-ui/src/themes/apex/images/icons/unLock-ltr.svg
deleted file mode 100644
index 66c024a9..00000000
--- a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/unLock-ltr.svg
+++ /dev/null
@@ -1,4 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <path d="M12 9v-2s0-5-4.5-5-4.5 5-4.5 5h2s0-3 2.5-3 2.5 3 2.5 3v2h-3v7c0 1.7 1.3 3 3 3h10v-10z" id="path726"/>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/unLock-rtl.svg b/vendor/oojs/oojs-ui/src/themes/apex/images/icons/unLock-rtl.svg
deleted file mode 100644
index 07cecbfe..00000000
--- a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/unLock-rtl.svg
+++ /dev/null
@@ -1,4 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <path d="M11 9v-2s0-5 4.5-5 4.5 5 4.5 5h-2s0-3-2.5-3-2.5 3-2.5 3v2h3v7c0 1.7-1.3 3-3 3h-10v-10z" id="path726"/>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/unStar.svg b/vendor/oojs/oojs-ui/src/themes/apex/images/icons/unStar.svg
deleted file mode 100644
index 724d1901..00000000
--- a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/unStar.svg
+++ /dev/null
@@ -1,4 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <path d="M21 11l-6-1-3-6-3 6-6 1 4 4-1 6 6-3 6 3-1-6 4-4z"/>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/underline-a.svg b/vendor/oojs/oojs-ui/src/themes/apex/images/icons/underline-a.svg
deleted file mode 100644
index dd6dde36..00000000
--- a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/underline-a.svg
+++ /dev/null
@@ -1,7 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="underline-a">
- <path id="a" d="M14.424 16h2.076l-3.463-10h-2.077l-3.46 10h2.077l.627-2h3.604l.616 2zm-3.921-3.623l1.496-4.379 1.511 4.379h-3z"/>
- <path id="underline" d="M7 17h10v1h-10v-1z"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/underline-u.svg b/vendor/oojs/oojs-ui/src/themes/apex/images/icons/underline-u.svg
deleted file mode 100644
index fbd7c147..00000000
--- a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/underline-u.svg
+++ /dev/null
@@ -1,7 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="underline-u">
- <path id="u" d="M8 6h2v5.959c-.104 1.707.695 2.002 2 2.041 1.777.062 2.002-.879 2-2.041v-5.959h2v6.123c0 1.279-.338 2.245-1.016 2.898-.672.651-1.666.979-2.98.979-1.32 0-2.319-.326-2.996-.979-.672-.653-1.008-1.619-1.008-2.898v-6.123"/>
- <path id="underline" d="M7 17h10v1h-10v-1z"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/upTriangle.svg b/vendor/oojs/oojs-ui/src/themes/apex/images/icons/upTriangle.svg
deleted file mode 100644
index 9e5e72f6..00000000
--- a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/upTriangle.svg
+++ /dev/null
@@ -1,4 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <path d="M12 8l8 10h-16z"/>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/wikiText.svg b/vendor/oojs/oojs-ui/src/themes/apex/images/icons/wikiText.svg
deleted file mode 100644
index eebd9b1a..00000000
--- a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/wikiText.svg
+++ /dev/null
@@ -1,15 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g>
- <path d="M23 5h-4v2h2v10h-2v2h4z"/>
- </g>
- <g>
- <path d="M18 5h-4v2h2v10h-2v2h4z"/>
- </g>
- <g>
- <path d="M2 5h4v2h-2v10h2v2h-4z"/>
- </g>
- <g>
- <path d="M7 5h4v2h-2v10h2v2h-4z"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/window.svg b/vendor/oojs/oojs-ui/src/themes/apex/images/icons/window.svg
deleted file mode 100644
index cd3b76c2..00000000
--- a/vendor/oojs/oojs-ui/src/themes/apex/images/icons/window.svg
+++ /dev/null
@@ -1,7 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="window">
- <path id="title" d="M7 10h10v1h-10z"/>
- <path id="frame" d="M16 19h-8c-2.206 0-4-1.794-4-4v-6c0-2.206 1.794-4 4-4h8c2.206 0 4 1.794 4 4v6c0 2.206-1.794 4-4 4zm-8-12c-1.103 0-2 .897-2 2v6c0 1.103.897 2 2 2h8c1.103 0 2-.897 2-2v-6c0-1.103-.897-2-2-2h-8z"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/apex/images/indicators/alert.svg b/vendor/oojs/oojs-ui/src/themes/apex/images/indicators/alert.svg
deleted file mode 100644
index d9dc6a87..00000000
--- a/vendor/oojs/oojs-ui/src/themes/apex/images/indicators/alert.svg
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 12 12">
- <g id="alert">
- <path d="M6 12c-3.314 0-6-2.686-6-6s2.686-6 6-6 6 2.686 6 6-2.686 6-6 6zm-1-5h2v-5h-2zm0 3h2v-2h-2z"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/apex/images/indicators/arrow-down.svg b/vendor/oojs/oojs-ui/src/themes/apex/images/indicators/arrow-down.svg
deleted file mode 100644
index bfa8ef0b..00000000
--- a/vendor/oojs/oojs-ui/src/themes/apex/images/indicators/arrow-down.svg
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 12 12">
- <g id="down">
- <path id="arrow" d="M2 3l3.5 6 3.5-6z"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/apex/images/indicators/arrow-ltr.svg b/vendor/oojs/oojs-ui/src/themes/apex/images/indicators/arrow-ltr.svg
deleted file mode 100644
index aeca27a9..00000000
--- a/vendor/oojs/oojs-ui/src/themes/apex/images/indicators/arrow-ltr.svg
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 12 12">
- <g id="ltr">
- <path id="arrow" d="M3 9v-7l6 3.5z"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/apex/images/indicators/arrow-rtl.svg b/vendor/oojs/oojs-ui/src/themes/apex/images/indicators/arrow-rtl.svg
deleted file mode 100644
index eba00995..00000000
--- a/vendor/oojs/oojs-ui/src/themes/apex/images/indicators/arrow-rtl.svg
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 12 12">
- <g id="rtl">
- <path id="arrow" d="M3 5.5l6 3.5v-7z"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/apex/images/indicators/arrow-up.svg b/vendor/oojs/oojs-ui/src/themes/apex/images/indicators/arrow-up.svg
deleted file mode 100644
index 4b01bb02..00000000
--- a/vendor/oojs/oojs-ui/src/themes/apex/images/indicators/arrow-up.svg
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 12 12">
- <g id="up">
- <path id="arrow" d="M5.5 2l-3.5 6h7z"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/apex/images/indicators/required.svg b/vendor/oojs/oojs-ui/src/themes/apex/images/indicators/required.svg
deleted file mode 100644
index 969fa2d8..00000000
--- a/vendor/oojs/oojs-ui/src/themes/apex/images/indicators/required.svg
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 12 12">
- <g id="required">
- <path d="M5 1h2v10h-2zM9.83 2.634l1 1.732-8.66 5-1-1.732zM1.17 4.366l1-1.732 8.66 5-1 1.732z"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/apex/images/indicators/search-ltr.svg b/vendor/oojs/oojs-ui/src/themes/apex/images/indicators/search-ltr.svg
deleted file mode 100644
index 266349ed..00000000
--- a/vendor/oojs/oojs-ui/src/themes/apex/images/indicators/search-ltr.svg
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 12 12">
- <g id="search">
- <path id="path3051" d="M10.369 9.474l-2.374-2.375-.169-.099c.403-.566.643-1.26.643-2.009-.001-1.92-1.558-3.477-3.477-3.477-1.921 0-3.478 1.557-3.478 3.478 0 1.92 1.557 3.477 3.478 3.477.749 0 1.442-.239 2.01-.643l.098.169 2.375 2.374c.19.189.543.143.79-.104s.293-.601.104-.791zm-5.377-2.27c-1.221 0-2.213-.991-2.213-2.213 0-1.221.992-2.213 2.213-2.213 1.222 0 2.213.992 2.213 2.213-.001 1.222-.992 2.213-2.213 2.213z"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/apex/images/indicators/search-rtl.svg b/vendor/oojs/oojs-ui/src/themes/apex/images/indicators/search-rtl.svg
deleted file mode 100644
index 5368fd7c..00000000
--- a/vendor/oojs/oojs-ui/src/themes/apex/images/indicators/search-rtl.svg
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 12 12">
- <g id="search">
- <path id="path3051" d="M1.631 9.474l2.374-2.375.169-.099c-.403-.566-.643-1.26-.643-2.009.001-1.92 1.558-3.477 3.477-3.477 1.921 0 3.478 1.557 3.478 3.478 0 1.92-1.557 3.477-3.478 3.477-.749 0-1.442-.239-2.01-.643l-.098.169-2.375 2.374c-.19.189-.543.143-.79-.104s-.293-.601-.104-.791zm5.377-2.27c1.221 0 2.213-.991 2.213-2.213 0-1.221-.992-2.213-2.213-2.213-1.222 0-2.213.992-2.213 2.213.001 1.222.992 2.213 2.213 2.213z"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/apex/images/textures/pending.gif b/vendor/oojs/oojs-ui/src/themes/apex/images/textures/pending.gif
deleted file mode 100644
index 1194eed2..00000000
--- a/vendor/oojs/oojs-ui/src/themes/apex/images/textures/pending.gif
+++ /dev/null
Binary files differ
diff --git a/vendor/oojs/oojs-ui/src/themes/apex/images/textures/transparency.svg b/vendor/oojs/oojs-ui/src/themes/apex/images/textures/transparency.svg
deleted file mode 100644
index 63a0b57c..00000000
--- a/vendor/oojs/oojs-ui/src/themes/apex/images/textures/transparency.svg
+++ /dev/null
@@ -1,10 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
-<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0" y="0" width="16" height="16" viewBox="0, 0, 16, 16">
- <g id="transparency">
- <path d="M0,0 L8,0 L8,8 L0,8 z" fill="#CCCCCC"/>
- <path d="M8,8 L16,8 L16,16 L8,16 z" fill="#CCCCCC"/>
- <path d="M8,0 L16,0 L16,8 L8,8 z" fill="#FFFFFF"/>
- <path d="M0,8 L8,8 L8,16 L0,16 z" fill="#FFFFFF"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/apex/images/toolbar-shadow.png b/vendor/oojs/oojs-ui/src/themes/apex/images/toolbar-shadow.png
deleted file mode 100644
index 97e8d13d..00000000
--- a/vendor/oojs/oojs-ui/src/themes/apex/images/toolbar-shadow.png
+++ /dev/null
Binary files differ
diff --git a/vendor/oojs/oojs-ui/src/themes/apex/indicators.json b/vendor/oojs/oojs-ui/src/themes/apex/indicators.json
deleted file mode 100644
index 0a9d1d26..00000000
--- a/vendor/oojs/oojs-ui/src/themes/apex/indicators.json
+++ /dev/null
@@ -1,22 +0,0 @@
-{
- "prefix": "oo-ui-indicator",
- "intro": "@import '../../../../src/styles/common';",
- "images": {
- "alert": { "file": "images/indicators/alert.svg" },
- "up": { "file": "images/indicators/arrow-up.svg" },
- "down": { "file": "images/indicators/arrow-down.svg" },
- "next": { "file": {
- "ltr": "images/indicators/arrow-ltr.svg",
- "rtl": "images/indicators/arrow-rtl.svg"
- } },
- "previous": { "file": {
- "ltr": "images/indicators/arrow-rtl.svg",
- "rtl": "images/indicators/arrow-ltr.svg"
- } },
- "required": { "file": "images/indicators/required.svg" },
- "search": { "file": {
- "ltr": "images/indicators/search-ltr.svg",
- "rtl": "images/indicators/search-rtl.svg"
- } }
- }
-}
diff --git a/vendor/oojs/oojs-ui/src/themes/apex/layouts.less b/vendor/oojs/oojs-ui/src/themes/apex/layouts.less
deleted file mode 100644
index b86aa010..00000000
--- a/vendor/oojs/oojs-ui/src/themes/apex/layouts.less
+++ /dev/null
@@ -1,135 +0,0 @@
-@import 'common';
-
-.theme-oo-ui-layout () {}
-
-.theme-oo-ui-bookletLayout () {
- &-stackLayout {
- > .oo-ui-panelLayout {
- padding: 1.5em;
- }
- }
-
- &-outlinePanel {
- border-right: 1px solid #ddd;
-
- > .oo-ui-outlineControlsWidget {
- box-shadow: 0 0 0.25em rgba(0,0,0,0.25);
- }
- }
-}
-
-.theme-oo-ui-indexLayout () {
- &-stackLayout {
- > .oo-ui-panelLayout {
- padding: 1.5em;
- }
- }
-}
-
-.theme-oo-ui-fieldLayout () {
- margin-bottom: 1em;
-
- &:last-child {
- margin-bottom: 0;
- }
-
- &.oo-ui-fieldLayout-align-left,
- &.oo-ui-fieldLayout-align-right {
- &.oo-ui-labelElement > .oo-ui-fieldLayout-body > .oo-ui-labelElement-label {
- padding-top: 0.5em;
- margin-right: 5%;
- width: 35%;
- }
-
- > .oo-ui-fieldLayout-body > .oo-ui-fieldLayout-field {
- width: 60%;
- }
- }
-
- &.oo-ui-fieldLayout-align-inline {
- &.oo-ui-labelElement > .oo-ui-fieldLayout-body > .oo-ui-labelElement-label {
- padding: 0.5em;
- }
-
- > .oo-ui-fieldLayout-body > .oo-ui-fieldLayout-field {
- padding: 0.5em 0;
- }
- }
-
- &.oo-ui-fieldLayout-align-top {
- &.oo-ui-labelElement > .oo-ui-fieldLayout-body > .oo-ui-labelElement-label {
- padding: 0.5em 0;
- }
- }
-
- > .oo-ui-popupButtonWidget {
- .oo-ui-inline-spacing(0);
- margin-top: 0.25em;
- }
-
- &-disabled .oo-ui-labelElement-label {
- color: #ccc;
- }
-}
-
-.theme-oo-ui-actionFieldLayout () {}
-
-.theme-oo-ui-fieldsetLayout () {
- margin: 0;
- padding: 0;
- border: none;
-
- + .oo-ui-fieldsetLayout,
- + .oo-ui-formLayout {
- margin-top: 2em;
- }
-
- > .oo-ui-labelElement-label {
- font-size: 1.1em;
- margin-bottom: 0.5em;
- padding: 0.25em 0;
- font-weight: bold;
- }
-
- &.oo-ui-iconElement > .oo-ui-labelElement-label {
- padding-left: 2em;
- line-height: 1.8em;
- }
-
- &.oo-ui-iconElement > .oo-ui-iconElement-icon {
- left: 0;
- top: 0.25em;
- width: @icon-size;
- height: @icon-size;
- }
-
- > .oo-ui-popupButtonWidget {
- .oo-ui-inline-spacing(0);
- }
-}
-
-.theme-oo-ui-formLayout () {
- + .oo-ui-fieldsetLayout,
- + .oo-ui-formLayout {
- margin-top: 2em;
- }
-}
-
-.theme-oo-ui-menuLayout () {}
-
-.theme-oo-ui-panelLayout () {
- &-padded {
- padding: 1.25em;
- }
-
- &-framed {
- border-radius: 0.5em;
- box-shadow: 0 0.25em 1em rgba(0, 0, 0, 0.25);
- }
-}
-
-.theme-oo-ui-cardLayout () {}
-
-.theme-oo-ui-pageLayout () {}
-
-.theme-oo-ui-stackLayout () {}
diff --git a/vendor/oojs/oojs-ui/src/themes/apex/textures.json b/vendor/oojs/oojs-ui/src/themes/apex/textures.json
deleted file mode 100644
index e90730ab..00000000
--- a/vendor/oojs/oojs-ui/src/themes/apex/textures.json
+++ /dev/null
@@ -1,8 +0,0 @@
-{
- "prefix": "oo-ui-texture",
- "intro": "@import '../../../../src/styles/common';",
- "images": {
- "pending": { "file": "images/textures/pending.gif" },
- "transparency": { "file": "images/textures/transparency.svg" }
- }
-}
diff --git a/vendor/oojs/oojs-ui/src/themes/apex/tools.less b/vendor/oojs/oojs-ui/src/themes/apex/tools.less
deleted file mode 100644
index 913bb516..00000000
--- a/vendor/oojs/oojs-ui/src/themes/apex/tools.less
+++ /dev/null
@@ -1,422 +0,0 @@
-@import 'common';
-
-.theme-oo-ui-toolbar () {
- &-bar {
- border-bottom: 1px solid #ccc;
- .oo-ui-vertical-gradient(#fff, #F1F7FB);
-
- .oo-ui-toolbar-bar {
- border: none;
- background: none;
- }
- }
-
- &-actions {
- > .oo-ui-buttonElement {
- margin-top: 0.4em;
- margin-bottom: 0.4em;
- }
-
- > .oo-ui-buttonElement:last-child {
- margin-right: 0.5em;
- }
- }
-
- &-shadow {
- .oo-ui-background-image('@{oo-ui-default-image-path}/toolbar-shadow.png');
- bottom: -9px;
- height: 9px;
- opacity: 0.5;
- .oo-ui-transition(opacity 500ms ease-in-out);
- }
-}
-
-.theme-oo-ui-tool () {}
-
-.theme-oo-ui-popupTool () {
- .oo-ui-popupWidget {
- /* @noflip */
- margin-left: 1.25em;
- }
-}
-
-.theme-oo-ui-toolGroupTool () {
- > .oo-ui-popupToolGroup {
- border: 0;
- border-radius: 0;
- margin: 0;
- }
-
- // Like .oo-ui-tool in barToolGroup
- &:first-child > .oo-ui-popupToolGroup {
- border-top-left-radius: 0.3125em;
- border-bottom-left-radius: 0.3125em;
- }
-
- &:last-child > .oo-ui-popupToolGroup {
- border-top-right-radius: 0.3125em;
- border-bottom-right-radius: 0.3125em;
- }
-
- // Like .oo-ui-tool-link in barToolGroup
- > .oo-ui-popupToolGroup > .oo-ui-popupToolGroup-handle {
- height: 1.875em;
- padding: 0.3125em;
-
- .oo-ui-iconElement-icon {
- height: 1.875em;
- width: 1.875em;
- }
- }
-
- > .oo-ui-popupToolGroup.oo-ui-labelElement > .oo-ui-popupToolGroup-handle {
- .oo-ui-labelElement-label {
- line-height: 2.1em; // 0.5em less
- }
- }
-}
-
-.theme-oo-ui-toolGroup () {
- margin: 0.375em;
- border-radius: 0.3125em;
- border: 1px solid transparent;
- .oo-ui-transition(border-color 300ms ease-in-out);
-
- .oo-ui-toolbar-narrow & {
- + .oo-ui-toolGroup {
- margin-left: 0;
- }
- }
-
- &.oo-ui-widget-enabled {
- &:hover {
- border-color: rgba(0,0,0,0.1);
- }
-
- .oo-ui-tool-link .oo-ui-tool-title {
- color: #000;
- }
- }
-}
-
-.theme-oo-ui-barToolGroup () {
- > .oo-ui-toolGroup-tools > .oo-ui-tool {
- margin: -1px 0 -1px -1px;
- border: 1px solid transparent;
-
- &:first-child {
- border-top-left-radius: 0.3125em;
- border-bottom-left-radius: 0.3125em;
- }
-
- &:last-child {
- margin-right: -1px;
- border-top-right-radius: 0.3125em;
- border-bottom-right-radius: 0.3125em;
- }
-
- > .oo-ui-tool-link {
- height: 1.875em;
- padding: 0.3125em;
-
- .oo-ui-iconElement-icon {
- height: 1.875em;
- width: 1.875em;
- }
-
- .oo-ui-tool-title {
- line-height: 2.1em; // 0.5em less
- }
- }
- }
-
- &.oo-ui-widget-enabled > .oo-ui-toolGroup-tools > .oo-ui-tool {
- &.oo-ui-widget-enabled:hover {
- border-color: rgba(0,0,0,0.2);
- }
-
- &.oo-ui-tool-active {
- &.oo-ui-widget-enabled {
- border-color: rgba(0,0,0,0.2);
- box-shadow: inset 0 0.0875em 0.0875em 0 rgba(0, 0, 0, 0.07);
- .oo-ui-vertical-gradient(#F1F7FB, #fff);
- }
-
- &.oo-ui-widget-enabled + .oo-ui-tool-active.oo-ui-widget-enabled {
- border-left-color: rgba(0,0,0,0.1);
- }
- }
-
- &.oo-ui-widget-disabled > .oo-ui-tool-link {
- .oo-ui-iconElement-icon {
- opacity: 0.2;
- }
- }
-
- &.oo-ui-widget-enabled {
- &:hover > .oo-ui-tool-link .oo-ui-iconElement-icon {
- opacity: 1;
- }
- }
- }
-
- &.oo-ui-widget-disabled > .oo-ui-toolGroup-tools > .oo-ui-tool {
- > .oo-ui-tool-link {
- .oo-ui-iconElement-icon {
- opacity: 0.2;
- }
- }
- }
-}
-
-.theme-oo-ui-popupToolGroup () {
- height: 2.5em;
- min-width: 2.5em;
-
- .oo-ui-toolbar-narrow & {
- min-width: 1.875em;
- }
-
- &.oo-ui-iconElement {
- min-width: 3.125em;
-
- .oo-ui-toolbar-narrow & {
- min-width: 2.5em;
- }
- }
-
- &.oo-ui-indicatorElement.oo-ui-iconElement {
- min-width: 4.375em;
-
- .oo-ui-toolbar-narrow & {
- min-width: 3.75em;
- }
- }
-
- &.oo-ui-labelElement {
- .oo-ui-popupToolGroup-handle .oo-ui-labelElement-label {
- line-height: 2.6em;
- margin: 0 1em;
-
- .oo-ui-toolbar-narrow & {
- margin: 0 0.5em;
- }
- }
-
- &.oo-ui-iconElement .oo-ui-popupToolGroup-handle .oo-ui-labelElement-label {
- margin-left: 3em;
-
- .oo-ui-toolbar-narrow & {
- margin-left: 2.5em;
- }
- }
-
- &.oo-ui-indicatorElement .oo-ui-popupToolGroup-handle .oo-ui-labelElement-label {
- margin-right: 2.25em;
-
- .oo-ui-toolbar-narrow & {
- margin-right: 1.75em;
- }
- }
- }
-
- &-handle {
- .oo-ui-indicatorElement-indicator {
- width: 0.9375em;
- height: 0.9375em;
- margin: 0.78125em;
- top: 0;
- right: 0;
-
- .oo-ui-toolbar-narrow & {
- right: -0.3125em;
- }
- }
- .oo-ui-iconElement-icon {
- width: 1.875em;
- height: 1.875em;
- margin: 0.3125em;
- top: 0;
- left: 0.3125em;
-
- .oo-ui-toolbar-narrow & {
- left: 0;
- }
- }
- }
-
- &-header {
- line-height: 2.6em;
- margin: 0 0.6em;
- font-weight: bold;
- }
-
- &-active.oo-ui-widget-enabled {
- border-bottom-left-radius: 0;
- border-bottom-right-radius: 0;
- box-shadow: inset 0 0.0875em 0.0875em 0 rgba(0, 0, 0, 0.07);
-
- .oo-ui-vertical-gradient(#F1F7FB, #fff);
- }
-
- .oo-ui-toolGroup-tools {
- top: 2.5em;
- margin: 0 -1px;
- border: 1px solid #ccc;
- background-color: white;
- box-shadow: 0 0.3125em 1.25em rgba(0,0,0,0.25);
- }
-
- .oo-ui-tool-link {
- padding: 0.3125em 0 0.3125em 0.3125em;
-
- .oo-ui-iconElement-icon {
- height: 1.875em;
- width: 1.875em;
- min-width: 1.875em;
- }
-
- .oo-ui-tool-title {
- padding-left: 0.5em;
- }
-
- .oo-ui-tool-accel,
- .oo-ui-tool-title {
- line-height: 2em;
- }
-
- .oo-ui-tool-accel {
- color: #888;
- }
- }
-}
-
-.theme-oo-ui-listToolGroup () {
- .oo-ui-toolGroup-tools {
- padding: 0.3125em;
- }
-
- &.oo-ui-popupToolGroup-active {
- border-color: rgba(0,0,0,0.2);
- }
-
- .oo-ui-tool {
- border: 1px solid transparent;
- margin: -1px 0;
- padding: 0 0.625em 0 0;
-
- &-active {
- &.oo-ui-widget-enabled {
- border-color: rgba(0,0,0,0.1);
- box-shadow: inset 0 0.0875em 0.0875em 0 rgba(0, 0, 0, 0.07);
- .oo-ui-vertical-gradient(#F1F7FB, #fff);
-
- + .oo-ui-tool-active.oo-ui-widget-enabled {
- border-top-color: rgba(0,0,0,0.1);
- }
- &:hover {
- border-color: rgba(0,0,0,0.2);
- }
- }
- }
-
- &.oo-ui-widget-enabled {
- &:hover {
- border-color: rgba(0,0,0,0.2);
- }
- &:hover .oo-ui-tool-link .oo-ui-iconElement-icon {
- opacity: 1;
- }
- }
-
- &.oo-ui-widget-disabled {
- .oo-ui-tool-link {
- .oo-ui-tool-title {
- color: #ccc;
- }
-
- .oo-ui-tool-accel {
- color: #ddd;
- }
-
- .oo-ui-iconElement-icon {
- opacity: 0.2;
- }
- }
- }
- }
-
- &.oo-ui-widget-disabled {
- color: #ccc;
- .oo-ui-indicatorElement-indicator,
- .oo-ui-iconElement-icon {
- opacity: 0.2;
- }
- }
-}
-
-.theme-oo-ui-menuToolGroup () {
- border-color: rgba(0,0,0,0.1);
-
- .oo-ui-popupToolGroup-handle {
- min-width: 10em;
-
- .oo-ui-toolbar-narrow & {
- min-width: 8.125em;
- }
- }
-
- .oo-ui-toolGroup-tools {
- padding: 0.3125em 0 0.3125em 0;
- }
-
- &.oo-ui-widget-enabled {
- &:hover {
- border-color: rgba(0,0,0,0.2);
- }
- }
-
- &.oo-ui-popupToolGroup-active {
- border-color: rgba(0,0,0,0.25);
- }
-
- .oo-ui-tool {
- padding: 0 1.25em 0 0.3125em;
-
- &-link {
- .oo-ui-iconElement-icon {
- background-image: none;
- }
- }
-
- &-active .oo-ui-tool-link .oo-ui-iconElement-icon {
- .oo-ui-background-image-svg('@{oo-ui-default-image-path}/icons/check');
- }
-
- &.oo-ui-widget-enabled {
- &:hover {
- background-color: #e1f3ff;
- }
- }
-
- &.oo-ui-widget-disabled {
- .oo-ui-tool-link .oo-ui-tool-title {
- color: #ccc;
- }
-
- .oo-ui-tool-link .oo-ui-iconElement-icon {
- opacity: 0.2;
- }
- }
- }
-
- &.oo-ui-widget-disabled {
- color: #ccc;
- border-color: rgba(0,0,0,0.05);
-
- .oo-ui-indicatorElement-indicator,
- .oo-ui-iconElement-icon {
- opacity: 0.2;
- }
- }
-}
diff --git a/vendor/oojs/oojs-ui/src/themes/apex/widgets.less b/vendor/oojs/oojs-ui/src/themes/apex/widgets.less
deleted file mode 100644
index f415b6dd..00000000
--- a/vendor/oojs/oojs-ui/src/themes/apex/widgets.less
+++ /dev/null
@@ -1,797 +0,0 @@
-@import 'common';
-
-.theme-oo-ui-widget () {}
-
-.theme-oo-ui-outlineControlsWidget () {
- height: 3em;
- background-color: #fff;
-
- &-items,
- &-movers {
- height: 2em;
- margin: 0.5em 0.5em 0.5em 0;
- padding: 0;
- }
-
- > .oo-ui-iconElement-icon {
- width: 1.5em;
- height: 2em;
- margin: 0.5em 0 0.5em 0.5em;
- opacity: 0.2;
- }
-}
-
-.theme-oo-ui-toggleWidget () {}
-
-.theme-oo-ui-buttonGroupWidget () {
- display: inline-block;
- white-space: nowrap;
- border-radius: 0.3em;
-
- .oo-ui-inline-spacing(0.5em);
- .oo-ui-buttonElement {
- .oo-ui-inline-spacing(0);
- }
-
- .oo-ui-buttonElement-framed {
- .oo-ui-buttonElement-button {
- border-radius: 0;
- margin-left: -1px;
- }
-
- &:first-child .oo-ui-buttonElement-button {
- border-bottom-left-radius: 0.3em;
- border-top-left-radius: 0.3em;
- margin-left: 0;
- }
-
- &:last-child .oo-ui-buttonElement-button {
- border-bottom-right-radius: 0.3em;
- border-top-right-radius: 0.3em;
- }
- }
-}
-
-.theme-oo-ui-buttonWidget () {
- .oo-ui-inline-spacing(0.5em);
-}
-
-.theme-oo-ui-actionWidget () {
- &.oo-ui-pendingElement-pending {
- .oo-ui-background-image('@{oo-ui-default-image-path}/textures/pending.gif');
- }
-}
-
-.theme-oo-ui-popupButtonWidget () {
- &.oo-ui-buttonElement-frameless > .oo-ui-popupWidget {
- // Compensate for icon being inset
- /* @noflip */
- left: 1em;
- }
-
- &.oo-ui-buttonElement-framed > .oo-ui-popupWidget {
- // Compensate for icon being inset
- /* @noflip */
- left: 1.25em;
- }
-}
-
-.theme-oo-ui-toggleButtonWidget () {
- .oo-ui-inline-spacing(0.5em);
-}
-
-.theme-oo-ui-iconWidget () {
- line-height: 2.5em;
- height: @icon-size;
- width: @icon-size;
-
- &.oo-ui-widget-disabled {
- opacity: 0.2;
- }
-}
-
-.theme-oo-ui-indicatorWidget () {
- line-height: 2.5em;
- height: @indicator-size;
- width: @indicator-size;
- margin: @indicator-size / 2;
-
- &.oo-ui-widget-disabled {
- opacity: 0.2;
- }
-}
-
-.theme-oo-ui-dropdownWidget () {
- margin: 0.25em 0;
- width: 100%;
- max-width: 50em;
-
- .oo-ui-inline-spacing(0.5em);
-
- &-handle {
- height: 2.5em;
- border: 1px solid rgba(0,0,0,0.1);
- border-radius: 0.25em;
-
- &:hover {
- border-color: rgba(0,0,0,0.2);
- }
-
- .oo-ui-indicatorElement-indicator {
- right: 0;
- }
-
- .oo-ui-iconElement-icon {
- left: 0.25em;
- }
-
- .oo-ui-labelElement-label {
- line-height: 2.5em;
- margin: 0 0.5em;
- }
-
- .oo-ui-indicatorElement-indicator {
- top: 0;
- width: @indicator-size;
- height: @indicator-size;
- margin: 0.775em;
- }
-
- .oo-ui-iconElement-icon {
- top: 0;
- width: @icon-size;
- height: @icon-size;
- margin: 0.3em;
- }
- }
-
- &.oo-ui-widget-disabled {
- .oo-ui-dropdownWidget-handle {
- color: #ccc;
- text-shadow: 0 1px 1px #fff;
- border-color: #ddd;
- background-color: #f3f3f3;
- }
- .oo-ui-indicatorElement-indicator {
- opacity: 0.2;
- }
- }
-
- &.oo-ui-iconElement .oo-ui-dropdownWidget-handle .oo-ui-labelElement-label {
- margin-left: 3em;
- }
-
- &.oo-ui-indicatorElement .oo-ui-dropdownWidget-handle .oo-ui-labelElement-label {
- margin-right: 2em;
- }
-}
-
-.theme-oo-ui-inputWidget () {
- .oo-ui-inline-spacing(0.5em);
-}
-
-.theme-oo-ui-buttonInputWidget () {}
-
-.theme-oo-ui-checkboxInputWidget () {}
-
-.theme-oo-ui-dropdownInputWidget () {
- width: 100%;
- max-width: 50em;
-
- select {
- height: 2.5em;
- padding: 0.5em;
- font-size: inherit;
- font-family: inherit;
- border: 1px solid rgba(0,0,0,0.1);
- border-radius: 0.25em;
- }
-
- &.oo-ui-widget-enabled {
- select:hover,
- select:focus {
- border-color: rgba(0,0,0,0.2);
- outline: none;
- }
- }
-
- &.oo-ui-widget-disabled {
- select {
- color: #ccc;
- border-color: #ddd;
- background-color: #f3f3f3;
- }
- }
-}
-
-.theme-oo-ui-radioInputWidget () {}
-
-.theme-oo-ui-textInputWidget () {
- width: 100%;
- max-width: 50em;
-
- input,
- textarea {
- padding: 0.5em;
- font-size: inherit;
- font-family: inherit;
- background-color: #fff;
- color: black;
- border: 1px solid #ccc;
- box-shadow: 0 0 0 white, inset 0 0.1em 0.2em #ddd;
- border-radius: 0.25em;
- .oo-ui-transition(border-color 200ms, box-shadow 200ms);
- }
-
- &-decorated {
- input,
- textarea {
- padding-left: 2em;
- }
- }
-
- &-icon {
- width: 2em;
- }
-
- &.oo-ui-widget-enabled {
- input:focus,
- textarea:focus {
- outline: none;
- border-color: #a7dcff;
- box-shadow: 0 0 0.3em #a7dcff, 0 0 0 white;
- }
-
- input[readonly],
- textarea[readonly] {
- color: #777;
- }
-
- &.oo-ui-flaggedElement-invalid {
- input,
- textarea {
- background-color: #fdd;
- }
- }
- }
-
- &.oo-ui-widget-disabled {
- input,
- textarea {
- color: #ccc;
- text-shadow: 0 1px 1px #fff;
- border-color: #ddd;
- background-color: #f3f3f3;
- }
- .oo-ui-iconElement-icon,
- .oo-ui-indicatorElement-indicator {
- opacity: 0.2;
- }
- .oo-ui-labelElement-label {
- color: #ddd;
- text-shadow: 0 1px 1px #fff;
- }
- }
-
- &.oo-ui-pendingElement-pending {
- input,
- textarea {
- background-color: transparent;
- .oo-ui-background-image('@{oo-ui-default-image-path}/textures/pending.gif');
- }
- }
-
- &.oo-ui-iconElement {
- input,
- textarea {
- padding-left: 2em;
- }
-
- .oo-ui-iconElement-icon {
- width: @icon-size;
- margin-left: 0.1em;
- }
- }
-
- &.oo-ui-indicatorElement {
- input,
- textarea {
- padding-right: 1.5em;
- }
-
- .oo-ui-indicatorElement-indicator {
- width: @indicator-size;
- margin-right: 0.775em;
- }
- }
-
- > .oo-ui-labelElement-label {
- padding: 0.4em;
- line-height: 1.5em;
- color: #888;
- }
-
- &-labelPosition-after {
- &.oo-ui-indicatorElement > .oo-ui-labelElement-label {
- margin-right: 1.6em;
- }
- }
-
- &-labelPosition-before {
- &.oo-ui-iconElement > .oo-ui-labelElement-label {
- margin-left: 2.1em;
- }
- }
-}
-
-.theme-oo-ui-comboBoxWidget () {
- width: 100%;
- max-width: 50em;
-
- .oo-ui-inline-spacing(0.5em);
-
- &-handle {
- border: 1px solid rgba(0,0,0,0.1);
- border-radius: 0.25em;
-
- &:hover {
- border-color: rgba(0,0,0,0.2);
- }
- }
-
- &.oo-ui-widget-disabled,
- &-empty {
- .oo-ui-textInputWidget.oo-ui-indicatorElement {
- .oo-ui-indicatorElement-indicator {
- cursor: default;
- opacity: 0.2;
- }
- }
- }
-
- > .oo-ui-selectWidget {
- margin-top: -3px
- }
-}
-
-.theme-oo-ui-labelWidget () {
- padding: 0.5em 0;
-}
-
-.theme-oo-ui-optionWidget () {
- padding: 0.25em 0.5em;
- border: none;
-
- &-highlighted {
- background-color: #e1f3ff;
- }
-
- .oo-ui-labelElement-label {
- line-height: 1.5em;
- }
-
- .oo-ui-selectWidget-depressed &-selected {
- background-color: #a7dcff;
- }
-
- .oo-ui-selectWidget-pressed &-pressed,
- .oo-ui-selectWidget-pressed &-pressed&-highlighted,
- .oo-ui-selectWidget-pressed &-pressed&-highlighted&-selected {
- background-color: #a7dcff;
- }
-
- &.oo-ui-widget-disabled {
- color: #ccc;
- }
-}
-
-.theme-oo-ui-decoratedOptionWidget () {
- padding: 0.5em 2em 0.5em 3em;
-
- &.oo-ui-iconElement .oo-ui-iconElement-icon,
- &.oo-ui-indicatorElement .oo-ui-indicatorElement-indicator {
- top: 0;
- height: 100%;
- }
-
- &.oo-ui-iconElement .oo-ui-iconElement-icon {
- width: @icon-size;
- left: 0.5em;
- }
-
- &.oo-ui-indicatorElement .oo-ui-indicatorElement-indicator {
- width: @indicator-size;
- right: 0.5em;
- }
-
- &.oo-ui-widget-disabled {
- .oo-ui-iconElement-icon,
- .oo-ui-indicatorElement-indicator {
- opacity: 0.2;
- }
- }
-}
-
-.theme-oo-ui-buttonOptionWidget () {
- padding: 0;
- background-color: transparent;
-
- .oo-ui-buttonElement-button {
- height: @icon-size;
- }
-
- &.oo-ui-iconElement .oo-ui-iconElement-icon {
- margin-top: 0;
- }
-
- &.oo-ui-optionWidget-selected,
- &.oo-ui-optionWidget-pressed,
- &.oo-ui-optionWidget-highlighted {
- background-color: transparent;
- }
-}
-
-.theme-oo-ui-radioOptionWidget () {
- padding: 0;
- background-color: transparent;
-
- &.oo-ui-optionWidget-selected,
- &.oo-ui-optionWidget-pressed,
- &.oo-ui-optionWidget-highlighted {
- background-color: transparent;
- }
-
- &.oo-ui-labelElement .oo-ui-labelElement-label {
- padding-left: 0.5em;
- }
-
- .oo-ui-radioInputWidget {
- margin-right: 0;
- }
-}
-
-.theme-oo-ui-menuOptionWidget () {
- &.oo-ui-optionWidget {
- &-selected {
- background-color: transparent;
- }
- &-highlighted,
- &-highlighted.oo-ui-optionWidget-selected {
- background-color: #e1f3ff;
- }
- }
-}
-
-.theme-oo-ui-menuSectionOptionWidget () {
- padding: 0.33em 0.75em;
- color: #888;
-}
-
-.theme-oo-ui-outlineOptionWidget () {
- font-size: 1.1em;
- padding: 0.75em;
-
- &.oo-ui-indicatorElement .oo-ui-labelElement-label {
- padding-right: 1.5em;
- }
-
- &.oo-ui-indicatorElement .oo-ui-indicatorElement-indicator {
- opacity: 0.5;
- }
-
- &-level-0 {
- padding-left: 3.5em;
-
- .oo-ui-iconElement-icon {
- left: 1em;
- }
- }
- &-level-1 {
- padding-left: 5em;
-
- .oo-ui-iconElement-icon {
- left: 2.5em;
- }
- }
-
- &-level-2 {
- padding-left: 6.5em;
-
- .oo-ui-iconElement-icon {
- left: 4em;
- }
- }
-
- .oo-ui-selectWidget-depressed &.oo-ui-optionWidget-selected {
- background-color: #a7dcff;
- text-shadow: 0 1px 1px rgba(255,255,255,0.5);
- }
-
- &.oo-ui-flaggedElement-important {
- font-weight: bold;
- }
-
- &.oo-ui-flaggedElement-placeholder {
- font-style: italic;
- }
-
- &.oo-ui-flaggedElement-empty {
- .oo-ui-iconElement-icon {
- opacity: 0.5;
- }
- .oo-ui-labelElement-label {
- color: #777;
- }
- }
-}
-
-.theme-oo-ui-tabOptionWidget () {
- padding: 0.5em 1em;
- margin: 0.5em 0 0 0.75em;
- border: 1px solid transparent;
- border-bottom: none;
- border-top-left-radius: 0.5em;
- border-top-right-radius: 0.5em;
-
- &.oo-ui-indicatorElement .oo-ui-labelElement-label {
- padding-right: 1.5em;
- }
-
- &.oo-ui-indicatorElement .oo-ui-indicatorElement-indicator {
- opacity: 0.5;
- }
-
- .oo-ui-selectWidget-pressed &.oo-ui-optionWidget-pressed {
- background-color: transparent;
- }
-
- &.oo-ui-widget-enabled {
- &:hover {
- background-color: rgba(255, 255, 255, 0.2);
- border-color: #ddd;
- }
-
- &:active {
- background-color: #fff;
- border-color: #ddd;
- }
- }
-
- .oo-ui-selectWidget-pressed &.oo-ui-optionWidget-selected,
- .oo-ui-selectWidget-depressed &.oo-ui-optionWidget-selected,
- &.oo-ui-optionWidget-selected:hover {
- background-color: #fff;
- border-color: #ddd;
- }
-}
-
-.theme-oo-ui-popupWidget () {
- &-popup {
- border: 1px solid #ccc;
- border-radius: 0.25em;
- background-color: #fff;
- box-shadow: 0 0.15em 0.5em 0 rgba(0, 0, 0, 0.2);
- }
-
- @anchor-size: 6px;
-
- &-anchored {
- .oo-ui-popupWidget-popup {
- margin-top: @anchor-size;
- }
-
- .oo-ui-popupWidget-anchor:before,
- .oo-ui-popupWidget-anchor:after {
- content: "";
- position: absolute;
- width: 0;
- height: 0;
- border-style: solid;
- border-color: transparent;
- border-top: 0;
- }
-
- .oo-ui-popupWidget-anchor:before {
- bottom: -@anchor-size - 1px;
- left: -@anchor-size;
- border-bottom-color: #aaa;
- border-width: @anchor-size + 1px;
- }
-
- .oo-ui-popupWidget-anchor:after {
- bottom: -@anchor-size - 1px;
- left: -@anchor-size + 1px;
- border-bottom-color: #fff;
- border-width: @anchor-size;
- }
- }
-
- &-transitioning .oo-ui-popupWidget-popup {
- .oo-ui-transition(
- width 100ms ease-in-out, height 100ms ease-in-out, left 100ms ease-in-out
- );
- }
-
- &-head {
- height: 2.5em;
-
- .oo-ui-buttonWidget {
- margin: 0.25em;
- }
-
- .oo-ui-labelElement-label {
- margin: 0.75em 1em;
- }
- }
-
- &-body-padded {
- padding: 0 1em;
- }
-}
-
-.theme-oo-ui-searchWidget () {
- &-query {
- height: 4em;
- padding: 0 1em;
- box-shadow: 0 0 0.5em rgba(0,0,0,0.2);
-
- .oo-ui-textInputWidget {
- margin: 0.75em 0;
- }
- }
-
- &-results {
- top: 4em;
- padding: 1em;
- line-height: 0;
- }
-}
-
-.theme-oo-ui-selectWidget () {}
-
-.theme-oo-ui-buttonSelectWidget () {
- border-radius: 0.3em;
-
- .oo-ui-inline-spacing(0.5em);
-
- .oo-ui-buttonOptionWidget {
- .oo-ui-buttonElement-button {
- border-radius: 0;
- margin-left: -1px;
- }
-
- &:first-child .oo-ui-buttonElement-button {
- border-bottom-left-radius: 0.3em;
- border-top-left-radius: 0.3em;
- margin-left: 0;
- }
-
- &:last-child .oo-ui-buttonElement-button {
- border-bottom-right-radius: 0.3em;
- border-top-right-radius: 0.3em;
- }
- }
-}
-
-.theme-oo-ui-radioSelectWidget () {
- padding: 0.75em 0 0.5em 0;
-}
-
-.theme-oo-ui-menuSelectWidget () {
- background: #fff;
- margin-top: -1px;
- border: 1px solid #ccc;
- border-radius: 0 0 0.25em 0.25em;
- box-shadow: 0 0.15em 1em 0 rgba(0, 0, 0, 0.2);
-}
-
-.theme-oo-ui-textInputMenuSelectWidget () {}
-
-.theme-oo-ui-outlineSelectWidget () {}
-
-.theme-oo-ui-tabSelectWidget () {
- background-color: #eee;
- box-shadow: inset 0 -0.015em 0.1em rgba(0, 0, 0, 0.1);
-}
-
-.theme-oo-ui-toggleSwitchWidget () {
- @travelDistance: 2em;
- height: 2em;
- width: @travelDistance + 2em;
- border-radius: 1em;
- box-shadow: 0 0 0 white, inset 0 0.1em 0.2em #ddd;
- border: 1px solid #ccc;
-
- .oo-ui-inline-spacing(0.5em);
-
- .oo-ui-vertical-gradient(#ddd, #fff);
-
- &.oo-ui-widget-disabled {
- opacity: 0.5;
- }
-
- &-grip {
- top: 0.25em;
- left: 0.25em;
- width: 1.5em;
- height: 1.5em;
- margin-top: -1px;
- border-radius: 1em;
- box-shadow: 0 0.1em 0.25em rgba(0, 0, 0, 0.1);
- border: 1px #c9c9c9 solid;
-
- .oo-ui-transition(left 200ms ease-in-out, margin-left 200ms ease-in-out);
- .oo-ui-vertical-gradient(#fff, #ddd);
- }
-
- &.oo-ui-widget-enabled {
- &:hover,
- &:hover .oo-ui-toggleSwitchWidget-grip {
- border-color: #aaa;
- }
- }
-
- .oo-ui-toggleSwitchWidget-glow {
- border-radius: 1em;
- box-shadow: inset 0 1px 4px 0 rgba(0, 0, 0, 0.07);
-
- .oo-ui-transition(opacity 200ms ease-in-out);
- .oo-ui-vertical-gradient(#b0d9ee, #eaf4fa);
- }
-
- .oo-ui-toggleWidget-on & {
- &-glow {
- opacity: 1;
- }
- &-grip {
- left: @travelDistance + 0.25em;
- margin-left: -2px;
- }
- }
-
- .oo-ui-toggleWidget-off & {
- &-glow {
- display: block;
- opacity: 0;
- }
- &-grip {
- left: 0.25em;
- margin-left: 0;
- }
- }
-}
-
-.theme-oo-ui-progressBarWidget () {
- max-width: 50em;
- border: 1px solid #ccc;
- border-radius: 0.25em;
- overflow: hidden;
-
- &-bar {
- height: 1em;
- border-right: 1px solid #ccc;
- .oo-ui-transition(width 200ms, margin-left 200ms);
- .oo-ui-vertical-gradient(@progressive-gradient-start, @progressive-gradient-end);
- }
- &-indeterminate {
- .oo-ui-progressBarWidget-bar {
- .oo-ui-animation(oo-ui-progressBarWidget-slide 2s infinite linear);
- width: 40%;
- margin-left: -10%;
- border-left: 1px solid @progressive-border;
- }
- }
- &.oo-ui-widget-disabled {
- opacity: 0.6;
- }
-}
-
-.oo-ui-progressBarWidget-slide-frames () {
- from { margin-left: -40%; }
- to { margin-left: 100%; }
-}
-@-webkit-keyframes oo-ui-progressBarWidget-slide { .oo-ui-progressBarWidget-slide-frames }
-@-moz-keyframes oo-ui-progressBarWidget-slide { .oo-ui-progressBarWidget-slide-frames }
-@-ms-keyframes oo-ui-progressBarWidget-slide { .oo-ui-progressBarWidget-slide-frames }
-@-o-keyframes oo-ui-progressBarWidget-slide { .oo-ui-progressBarWidget-slide-frames }
-@keyframes oo-ui-progressBarWidget-slide { .oo-ui-progressBarWidget-slide-frames }
diff --git a/vendor/oojs/oojs-ui/src/themes/apex/windows.less b/vendor/oojs/oojs-ui/src/themes/apex/windows.less
deleted file mode 100644
index 0048c7ff..00000000
--- a/vendor/oojs/oojs-ui/src/themes/apex/windows.less
+++ /dev/null
@@ -1,307 +0,0 @@
-@import 'common';
-
-.theme-oo-ui-window () {
- background-color: transparent;
- background-image: none;
-}
-
-.theme-oo-ui-dialog () {
- &-content > .oo-ui-window-body {
- box-shadow: 0 0 0.66em rgba(0,0,0,0.25);
- }
-}
-
-.theme-oo-ui-messageDialog () {
- &-content {
- .oo-ui-window-body {
- box-shadow: 0 0 0.33em rgba(0,0,0,0.33);
- }
- }
-
- &-title,
- &-message {
- display: block;
- text-align: center;
- padding-top: 0.5em;
- }
-
- &-title {
- font-size: 1.5em;
- line-height: 1em;
- color: #000;
- }
-
- &-message {
- font-size: 0.9em;
- line-height: 1.25em;
- color: #666;
-
- &-verbose {
- font-size: 1.1em;
- line-height: 1.5em;
- text-align: left;
- }
- }
-
- &-actions {
- &-horizontal {
- .oo-ui-actionWidget {
- border-right: 1px solid #e5e5e5;
-
- &:last-child {
- border-right-width: 0;
- }
- }
- }
-
- &-vertical {
- .oo-ui-actionWidget {
- border-bottom: 1px solid #e5e5e5;
-
- &:last-child {
- border-bottom-width: 0;
- }
- }
- }
-
- .oo-ui-actionWidget {
- height: 3.4em;
-
- &.oo-ui-labelElement .oo-ui-labelElement-label {
- text-align: center;
- line-height: 3.4em;
- padding: 0 2em;
- }
-
- &:hover {
- background-color: rgba(0,0,0,0.05);
- }
-
- &:active {
- background-color: rgba(0,0,0,0.1);
- }
-
- &.oo-ui-flaggedElement {
- &-progressive {
- &:hover {
- background-color: rgba(8,126,204,0.05);
- }
-
- &:active {
- background-color: rgba(8,126,204,0.1);
- }
-
- .oo-ui-labelElement-label {
- font-weight: bold;
- }
- }
-
- &-constructive {
- &:hover {
- background-color: rgba(118,171,54,0.05);
- }
-
- &:active {
- background-color: rgba(118,171,54,0.1);
- }
- }
-
- &-destructive {
- &:hover {
- background-color: rgba(212,83,83,0.05);
- }
-
- &:active {
- background-color: rgba(212,83,83,0.1);
- }
- }
- }
- }
- }
-}
-
-.theme-oo-ui-processDialog () {
- &-content {
- .oo-ui-window-head {
- height: 3.4em;
-
- &.oo-ui-pendingElement-pending {
- .oo-ui-background-image('@{oo-ui-default-image-path}/textures/pending.gif');
- }
- }
-
- .oo-ui-window-body {
- top: 3.4em;
- box-shadow: 0 0 0.33em rgba(0,0,0,0.33);
- }
- }
-
- &-navigation {
- position: relative;
- height: 3.4em;
- padding: 0 1em;
- }
-
- &-location {
- padding: 0.75em 0;
- height: @icon-size;
- cursor: default;
- text-align: center;
- }
-
- &-title {
- font-weight: bold;
- line-height: @icon-size;
- }
-
- &-actions {
- &-safe,
- &-primary,
- &-other {
- .oo-ui-actionWidget {
- .oo-ui-buttonElement-button {
- min-width: @icon-size;
- min-height: @icon-size;
- }
-
- .oo-ui-labelElement-label {
- line-height: @icon-size;
- }
-
- &.oo-ui-iconElement .oo-ui-iconElement-icon {
- margin-top: -0.125em;
- }
-
- &.oo-ui-buttonElement-framed {
- margin: 0.75em 0 0.75em 0.75em;
- .oo-ui-buttonElement-button {
- padding: 0 1em;
- vertical-align: middle;
- }
- }
- }
- }
-
- &-safe,
- &-primary {
- .oo-ui-actionWidget {
- &:hover {
- background-color: rgba(0,0,0,0.05);
- }
-
- &:active {
- background-color: rgba(0,0,0,0.1);
- }
-
- &.oo-ui-buttonElement-framed {
- margin: 0.75em;
- .oo-ui-buttonElement-button {
- /* Adjust for border so text aligns with title */
- margin: -1px;
- }
- }
-
- &.oo-ui-flaggedElement {
- &-progressive {
- &:hover {
- background-color: rgba(8,126,204,0.05);
- }
-
- &:active {
- background-color: rgba(8,126,204,0.1);
- }
-
- .oo-ui-labelElement-label {
- font-weight: bold;
- }
- }
-
- &-constructive {
- &:hover {
- background-color: rgba(118,171,54,0.05);
- }
-
- &:active {
- background-color: rgba(118,171,54,0.1);
- }
- }
-
- &-destructive {
- &:hover {
- background-color: rgba(212,83,83,0.05);
- }
-
- &:active {
- background-color: rgba(212,83,83,0.1);
- }
- }
- }
- }
- }
- }
-
- > .oo-ui-window-frame {
- min-height: 5em;
- }
-
- &-errors {
- background-color: rgba(255,255,255,0.9);
- padding: 3em 3em 1.5em 3em;
- text-align: center;
-
- .oo-ui-buttonWidget {
- margin: 2em 1em 2em 1em;
- }
-
- &-title {
- font-size: 1.5em;
- color: #000;
- margin-bottom: 2em;
- }
- }
-
- &-error {
- text-align: left;
- margin: 1em;
- padding: 1em;
- border: 1px solid #ff9e9e;
- background-color: #fff7f7;
- border-radius: 0.25em;
- }
-}
-
-.theme-oo-ui-windowManager () {
- &-modal > .oo-ui-dialog {
- background-color: rgba(255,255,255,0.5);
- opacity: 0;
-
- .oo-ui-transition(opacity 250ms ease-in-out);
-
- > .oo-ui-window-frame {
- top: 1em;
- bottom: 1em;
- background-color: #fff;
-
- opacity: 0;
- .oo-ui-transform(scale(0.5));
- .oo-ui-transition(all 250ms ease-in-out);
- }
-
- &.oo-ui-window-ready {
- /* Fade window overlay */
- opacity: 1;
-
- > .oo-ui-window-frame {
- /* Fade frame */
- opacity: 1;
- .oo-ui-transform(scale(1));
- }
- }
- }
-
- &-modal&-floating > .oo-ui-dialog > .oo-ui-window-frame {
- border: 1px solid #ccc;
- border-radius: 0.5em;
- box-shadow: 0 0.2em 1em rgba(0, 0, 0, 0.3);
- }
-}
diff --git a/vendor/oojs/oojs-ui/src/themes/blank/BlankTheme.js b/vendor/oojs/oojs-ui/src/themes/blank/BlankTheme.js
deleted file mode 100644
index 208b6a9c..00000000
--- a/vendor/oojs/oojs-ui/src/themes/blank/BlankTheme.js
+++ /dev/null
@@ -1,32 +0,0 @@
-/**
- * @class
- * @extends {OO.ui.Theme}
- *
- * @constructor
- */
-OO.ui.BlankTheme = function OoUiBlankTheme() {
- // Parent constructor
- OO.ui.BlankTheme.super.call( this );
-};
-
-/* Setup */
-
-OO.inheritClass( OO.ui.BlankTheme, OO.ui.Theme );
-
-/* Methods */
-
-/**
- * @inheritdoc
- */
-OO.ui.BlankTheme.prototype.getElementClasses = function ( element ) {
- // Parent method
- var classes = OO.ui.BlankTheme.super.prototype.getElementClasses.call( this, element );
-
- // Add classes to classes.on or classes.off
-
- return classes;
-};
-
-/* Instantiation */
-
-OO.ui.theme = new OO.ui.BlankTheme();
diff --git a/vendor/oojs/oojs-ui/src/themes/blank/common.less b/vendor/oojs/oojs-ui/src/themes/blank/common.less
deleted file mode 100644
index f9ec869a..00000000
--- a/vendor/oojs/oojs-ui/src/themes/blank/common.less
+++ /dev/null
@@ -1,10 +0,0 @@
-// Base variables and mixins
-@import '../../styles/common';
-
-// Theme variables
-
-@oo-ui-default-image-path: 'themes/blank/images';
-
-// Theme mixins
-
-// (add mixins here)
diff --git a/vendor/oojs/oojs-ui/src/themes/blank/core.less b/vendor/oojs/oojs-ui/src/themes/blank/core.less
deleted file mode 100644
index 1c83a946..00000000
--- a/vendor/oojs/oojs-ui/src/themes/blank/core.less
+++ /dev/null
@@ -1,12 +0,0 @@
-// Base and theme variables and mixins
-@import 'common';
-
-// Theme rules
-@import 'elements';
-@import 'layouts';
-@import 'tools';
-@import 'widgets';
-@import 'windows';
-
-// Base rules
-@import '../../styles/core';
diff --git a/vendor/oojs/oojs-ui/src/themes/blank/elements.less b/vendor/oojs/oojs-ui/src/themes/blank/elements.less
deleted file mode 100644
index 89b96648..00000000
--- a/vendor/oojs/oojs-ui/src/themes/blank/elements.less
+++ /dev/null
@@ -1,29 +0,0 @@
-@import 'common';
-
-.theme-oo-ui-element () {}
-
-.theme-oo-ui-buttonElement () {}
-
-.theme-oo-ui-clippableElement () {}
-
-.theme-oo-ui-draggableElement () {}
-
-.theme-oo-ui-flaggedElement () {}
-
-.theme-oo-ui-groupElement () {}
-
-.theme-oo-ui-draggableGroupElement () {}
-
-.theme-oo-ui-iconElement () {}
-
-.theme-oo-ui-indicatorElement () {}
-
-.theme-oo-ui-labelElement () {}
-
-.theme-oo-ui-lookupElement () {}
-
-.theme-oo-ui-popupElement () {}
-
-.theme-oo-ui-tabIndexedElement () {}
-
-.theme-oo-ui-titledElement () {}
diff --git a/vendor/oojs/oojs-ui/src/themes/blank/images/icons/README.txt b/vendor/oojs/oojs-ui/src/themes/blank/images/icons/README.txt
deleted file mode 100644
index 129fbed2..00000000
--- a/vendor/oojs/oojs-ui/src/themes/blank/images/icons/README.txt
+++ /dev/null
@@ -1 +0,0 @@
-Remove this file and add icon images here \ No newline at end of file
diff --git a/vendor/oojs/oojs-ui/src/themes/blank/images/indicators/README.txt b/vendor/oojs/oojs-ui/src/themes/blank/images/indicators/README.txt
deleted file mode 100644
index 9ff30ec2..00000000
--- a/vendor/oojs/oojs-ui/src/themes/blank/images/indicators/README.txt
+++ /dev/null
@@ -1 +0,0 @@
-Remove this file and add indicator images here \ No newline at end of file
diff --git a/vendor/oojs/oojs-ui/src/themes/blank/images/textures/README.txt b/vendor/oojs/oojs-ui/src/themes/blank/images/textures/README.txt
deleted file mode 100644
index 6ca283de..00000000
--- a/vendor/oojs/oojs-ui/src/themes/blank/images/textures/README.txt
+++ /dev/null
@@ -1 +0,0 @@
-Remove this file and add texture images here \ No newline at end of file
diff --git a/vendor/oojs/oojs-ui/src/themes/blank/layouts.less b/vendor/oojs/oojs-ui/src/themes/blank/layouts.less
deleted file mode 100644
index 93f677c7..00000000
--- a/vendor/oojs/oojs-ui/src/themes/blank/layouts.less
+++ /dev/null
@@ -1,26 +0,0 @@
-@import 'common';
-
-.theme-oo-ui-layout () {}
-
-.theme-oo-ui-bookletLayout () {}
-
-.theme-oo-ui-indexLayout () {}
-
-.theme-oo-ui-fieldLayout () {}
-
-.theme-oo-ui-actionFieldLayout () {}
-
-.theme-oo-ui-fieldsetLayout () {}
-
-.theme-oo-ui-formLayout () {}
-
-.theme-oo-ui-menuLayout () {}
-
-.theme-oo-ui-panelLayout () {}
-
-.theme-oo-ui-cardLayout () {}
-
-.theme-oo-ui-pageLayout () {}
-
-.theme-oo-ui-stackLayout () {}
-
diff --git a/vendor/oojs/oojs-ui/src/themes/blank/tools.less b/vendor/oojs/oojs-ui/src/themes/blank/tools.less
deleted file mode 100644
index 923b0ad6..00000000
--- a/vendor/oojs/oojs-ui/src/themes/blank/tools.less
+++ /dev/null
@@ -1,20 +0,0 @@
-@import 'common';
-
-.theme-oo-ui-toolbar () {}
-
-.theme-oo-ui-tool () {}
-
-.theme-oo-ui-popupTool () {}
-
-.theme-oo-ui-toolGroupTool () {}
-
-.theme-oo-ui-toolGroup () {}
-
-.theme-oo-ui-barToolGroup () {}
-
-.theme-oo-ui-popupToolGroup () {}
-
-.theme-oo-ui-listToolGroup () {}
-
-.theme-oo-ui-menuToolGroup () {}
-
diff --git a/vendor/oojs/oojs-ui/src/themes/blank/widgets.less b/vendor/oojs/oojs-ui/src/themes/blank/widgets.less
deleted file mode 100644
index 68c64cd8..00000000
--- a/vendor/oojs/oojs-ui/src/themes/blank/widgets.less
+++ /dev/null
@@ -1,77 +0,0 @@
-@import 'common';
-
-.theme-oo-ui-widget () {}
-
-.theme-oo-ui-outlineControlsWidget () {}
-
-.theme-oo-ui-toggleWidget () {}
-
-.theme-oo-ui-buttonGroupWidget () {}
-
-.theme-oo-ui-buttonWidget () {}
-
-.theme-oo-ui-actionWidget () {}
-
-.theme-oo-ui-popupButtonWidget () {}
-
-.theme-oo-ui-toggleButtonWidget () {}
-
-.theme-oo-ui-iconWidget () {}
-
-.theme-oo-ui-indicatorWidget () {}
-
-.theme-oo-ui-dropdownWidget () {}
-
-.theme-oo-ui-inputWidget () {}
-
-.theme-oo-ui-buttonInputWidget () {}
-
-.theme-oo-ui-checkboxInputWidget () {}
-
-.theme-oo-ui-dropdownInputWidget () {}
-
-.theme-oo-ui-radioInputWidget () {}
-
-.theme-oo-ui-textInputWidget () {}
-
-.theme-oo-ui-comboBoxWidget () {}
-
-.theme-oo-ui-labelWidget () {}
-
-.theme-oo-ui-optionWidget () {}
-
-.theme-oo-ui-decoratedOptionWidget () {}
-
-.theme-oo-ui-buttonOptionWidget () {}
-
-.theme-oo-ui-radioOptionWidget () {}
-
-.theme-oo-ui-menuOptionWidget () {}
-
-.theme-oo-ui-menuSectionOptionWidget () {}
-
-.theme-oo-ui-outlineOptionWidget () {}
-
-.theme-oo-ui-tabOptionWidget () {}
-
-.theme-oo-ui-popupWidget () {}
-
-.theme-oo-ui-searchWidget () {}
-
-.theme-oo-ui-selectWidget () {}
-
-.theme-oo-ui-buttonSelectWidget () {}
-
-.theme-oo-ui-radioSelectWidget () {}
-
-.theme-oo-ui-menuSelectWidget () {}
-
-.theme-oo-ui-textInputMenuSelectWidget () {}
-
-.theme-oo-ui-outlineSelectWidget () {}
-
-.theme-oo-ui-tabSelectWidget () {}
-
-.theme-oo-ui-toggleSwitchWidget () {}
-
-.theme-oo-ui-progressBarWidget () {}
diff --git a/vendor/oojs/oojs-ui/src/themes/blank/windows.less b/vendor/oojs/oojs-ui/src/themes/blank/windows.less
deleted file mode 100644
index 35c0b40a..00000000
--- a/vendor/oojs/oojs-ui/src/themes/blank/windows.less
+++ /dev/null
@@ -1,11 +0,0 @@
-@import 'common';
-
-.theme-oo-ui-window () {}
-
-.theme-oo-ui-dialog () {}
-
-.theme-oo-ui-messageDialog () {}
-
-.theme-oo-ui-processDialog () {}
-
-.theme-oo-ui-windowManager () {}
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/MediaWikiTheme.js b/vendor/oojs/oojs-ui/src/themes/mediawiki/MediaWikiTheme.js
deleted file mode 100644
index be2371bd..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/MediaWikiTheme.js
+++ /dev/null
@@ -1,56 +0,0 @@
-/**
- * @class
- * @extends OO.ui.Theme
- *
- * @constructor
- */
-OO.ui.MediaWikiTheme = function OoUiMediaWikiTheme() {
- // Parent constructor
- OO.ui.MediaWikiTheme.super.call( this );
-};
-
-/* Setup */
-
-OO.inheritClass( OO.ui.MediaWikiTheme, OO.ui.Theme );
-
-/* Methods */
-
-/**
- * @inheritdoc
- */
-OO.ui.MediaWikiTheme.prototype.getElementClasses = function ( element ) {
- // Parent method
- var variant,
- variants = {
- warning: false,
- invert: false,
- progressive: false,
- constructive: false,
- destructive: false
- },
- // Parent method
- classes = OO.ui.MediaWikiTheme.super.prototype.getElementClasses.call( this, element ),
- isFramed;
-
- if ( element.supports( [ 'hasFlag' ] ) ) {
- isFramed = element.supports( [ 'isFramed' ] ) && element.isFramed();
- if ( isFramed && ( element.isDisabled() || element.hasFlag( 'primary' ) ) ) {
- variants.invert = true;
- } else {
- variants.progressive = element.hasFlag( 'progressive' );
- variants.constructive = element.hasFlag( 'constructive' );
- variants.destructive = element.hasFlag( 'destructive' );
- variants.warning = element.hasFlag( 'warning' );
- }
- }
-
- for ( variant in variants ) {
- classes[ variants[ variant ] ? 'on' : 'off' ].push( 'oo-ui-image-' + variant );
- }
-
- return classes;
-};
-
-/* Instantiation */
-
-OO.ui.theme = new OO.ui.MediaWikiTheme();
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/common.less b/vendor/oojs/oojs-ui/src/themes/mediawiki/common.less
deleted file mode 100644
index ab63c022..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/common.less
+++ /dev/null
@@ -1,69 +0,0 @@
-// Base variables and mixins
-@import '../../styles/common';
-
-// Theme variables
-
-@active: #999;
-@background: #ffffff;
-
-@select: #d8e6fe;
-
-@progressive: #347bff;
-@progressive-hover: #2962CC;
-@progressive-selected: #1F4999;
-@progressive-fade: rgba(52,123,255,0.1);
-
-@constructive: #00af89;
-@constructive-hover: #008064;
-@constructive-selected: #005946;
-@constructive-fade: rgba(0,171,137,0.1);
-
-@destructive: #d11d13;
-@destructive-hover: #8C130D;
-@destructive-selected: #73100A;
-@destructive-fade: rgba(209,29,19,0.1);
-
-@text: #555555;
-@pressed-text: #444444;
-@pressed-color: #d0d0d0; // Used for borders and backgrounds
-@disabled-text: #cccccc;
-@disabled-framed-text: #ffffff;
-@disabled-background: #dddddd;
-
-@neutral-button-border: 1px solid #cdcdcd;
-
-@oo-ui-default-image-path: 'themes/mediawiki/images';
-
-@input-border-color: #777;
-@input-active-color: #ddd;
-@input-disabled-color: #eee;
-@input-hover-border-bottom-width: 3px;
-@input-focus-border-width: 2px;
-@input-size: 1.6em;
-@border-radius: 2px;
-
-@icon-size: unit(24 / 16 / 0.8, em);
-@indicator-size: unit(12 / 16 / 0.8, em);
-
-// Theme animation variables
-@quick-ease: 0.1s ease-in-out;
-@medium-ease-out-back: 0.2s cubic-bezier(0.175, 0.885, 0.32, 1.275);
-@medium-ease-out-sine: 0.2s cubic-bezier(0.39, 0.575, 0.565, 1);
-
-// Theme mixins
-
-// Workaround for Safari 8 bug. Combining a selector like `input[type="checkbox"]:checked + span`
-// with transition on background-size, background-color, and a single background-image using SVG
-// causes the selector to sometimes not be applied. (T89309)
-//
-// * Syntax mimics the core mixin .oo-ui-background-image-svg().
-// * No-op in distributions other than 'vector'.
-// * Using -webkit- prefix to limit this stupidity from impacting other browsers. Alas, some
-// non-Safari ones also parse the -webkit- prefix (Chrome, Opera).
-// * We take the payload size hit of the unnecessary /* @embed */ hint across the board. It should
-// be mostly mitigated by using gzip compression.
-// * Upstream bug report: https://bugs.webkit.org/show_bug.cgi?id=141789
-.oo-ui-background-image-safari( @url-without-extension ) when ( @oo-ui-distribution = vector ) {
- @svg: '@{url-without-extension}.svg';
- background-image: -webkit-linear-gradient(transparent, transparent), e('/* @embed */') url(@svg);
-}
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/core.less b/vendor/oojs/oojs-ui/src/themes/mediawiki/core.less
deleted file mode 100644
index 1c83a946..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/core.less
+++ /dev/null
@@ -1,12 +0,0 @@
-// Base and theme variables and mixins
-@import 'common';
-
-// Theme rules
-@import 'elements';
-@import 'layouts';
-@import 'tools';
-@import 'widgets';
-@import 'windows';
-
-// Base rules
-@import '../../styles/core';
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/elements.less b/vendor/oojs/oojs-ui/src/themes/mediawiki/elements.less
deleted file mode 100644
index 535c0251..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/elements.less
+++ /dev/null
@@ -1,319 +0,0 @@
-@import 'common';
-
-.theme-oo-ui-element () {}
-
-.theme-oo-ui-buttonElement () {
- > .oo-ui-buttonElement-button {
- font-weight: bold;
- }
-
- &.oo-ui-iconElement > .oo-ui-buttonElement-button {
- > .oo-ui-iconElement-icon {
- margin-left: 0;
- }
- }
-
- &.oo-ui-indicatorElement > .oo-ui-buttonElement-button {
- > .oo-ui-indicatorElement-indicator {
- width: @indicator-size;
- height: @indicator-size;
- margin: @indicator-size / 2;
- }
- }
-
- &.oo-ui-iconElement > .oo-ui-buttonElement-button > .oo-ui-indicatorElement-indicator {
- margin-left: @indicator-size / 2;
- }
- &.oo-ui-iconElement > .oo-ui-buttonElement-button > .oo-ui-iconElement-icon {
- width: @icon-size;
- height: @icon-size;
- }
-
- &-frameless {
- > .oo-ui-buttonElement-button {
- &:focus {
- box-shadow: inset 0 0 0 1px rgba(0,0,0,0.2), 0 0 0 1px rgba(0,0,0,0.2);
- outline: none;
- }
-
- .oo-ui-indicatorElement-indicator {
- margin-right: 0em;
- }
- }
-
- &.oo-ui-labelElement {
- > .oo-ui-buttonElement-button {
- > .oo-ui-labelElement-label {
- margin-left: 0.25em;
- margin-right: 0.25em;
- }
- }
- }
-
- &.oo-ui-widget-enabled {
- > .oo-ui-buttonElement-button > .oo-ui-labelElement-label {
- color: @text;
- }
-
- &.oo-ui-buttonElement-pressed > .oo-ui-buttonElement-button > .oo-ui-labelElement-label {
- color: @pressed-text;
- }
-
- &.oo-ui-flaggedElement {
- &-progressive {
- .mediawiki-frameless-button-colored(@progressive, @progressive-selected);
- }
-
- &-constructive {
- .mediawiki-frameless-button-colored(@constructive, @constructive-selected);
- }
-
- &-destructive {
- .mediawiki-frameless-button-colored(@destructive, @destructive-selected);
- }
- }
- }
-
- &.oo-ui-widget-disabled > .oo-ui-buttonElement-button {
- color: @disabled-text;
-
- > .oo-ui-iconElement-icon,
- > .oo-ui-indicatorElement-indicator {
- opacity: 0.2;
- }
- }
- }
-
- &-framed {
- > .oo-ui-buttonElement-button {
- margin: 0.1em 0;
- padding: 0.2em 0.8em;
- border-radius: @border-radius;
-
- &:hover,
- &:focus {
- outline: none;
- }
-
- .oo-ui-transition(
- background @quick-ease,
- color @quick-ease,
- box-shadow @quick-ease
- );
- }
-
- // Support <input/> from ButtonInputWidget
- > input.oo-ui-buttonElement-button,
- &.oo-ui-labelElement > .oo-ui-buttonElement-button > .oo-ui-labelElement-label {
- line-height: @icon-size;
- }
-
- &.oo-ui-iconElement {
- > .oo-ui-buttonElement-button > .oo-ui-iconElement-icon {
- margin-left: -0.5em;
- margin-right: -0.5em;
- }
-
- &.oo-ui-labelElement > .oo-ui-buttonElement-button > .oo-ui-iconElement-icon {
- margin-right: 0.3em;
- }
- }
-
- &.oo-ui-indicatorElement {
- > .oo-ui-buttonElement-button > .oo-ui-indicatorElement-indicator {
- /* -0.5 - 0.475 */
- margin-left: -0.005em;
- margin-right: -0.005em;
- }
-
- &.oo-ui-labelElement > .oo-ui-buttonElement-button > .oo-ui-indicatorElement-indicator,
- &.oo-ui-iconElement:not( .oo-ui-labelElement ) > .oo-ui-buttonElement-button > .oo-ui-indicatorElement-indicator {
- margin-left: @indicator-size / 2;
- margin-right: -0.275em;
- }
- }
-
- &.oo-ui-widget-disabled > .oo-ui-buttonElement-button {
- color: @disabled-framed-text;
- background: @disabled-background;
- border: 1px solid @disabled-background;
- }
-
- &.oo-ui-widget-enabled {
- > .oo-ui-buttonElement-button {
- color: @text;
- background-color: @background;
- border: @neutral-button-border;
-
- &:hover {
- background-color: darken(@background,8%);
- }
-
- &:focus {
- box-shadow: inset 0 0 0 1px rgba(0,0,0,0.2);
- }
- }
-
- & > .oo-ui-buttonElement-button:active,
- &.oo-ui-buttonElement-pressed > .oo-ui-buttonElement-button {
- background-color: darken(@background,15%);
- border-color: darken(@background,15%);
- box-shadow: none;
- }
-
- &.oo-ui-buttonElement-active > .oo-ui-buttonElement-button {
- background-color: @active;
- color: #fff;
- }
-
- &.oo-ui-flaggedElement {
- &-progressive {
- .mediawiki-framed-button-colored(@progressive, @progressive-fade, @progressive-selected);
- }
-
- &-constructive {
- .mediawiki-framed-button-colored(@constructive, @constructive-fade, @constructive-selected);
- }
-
- &-destructive {
- .mediawiki-framed-button-colored(@destructive, @destructive-fade, @destructive-selected);
- }
- }
- &.oo-ui-flaggedElement-primary.oo-ui-flaggedElement {
- &-progressive {
- .mediawiki-framed-primary-button-colored(@progressive, @progressive-hover, @progressive-selected);
- }
-
- &-constructive {
- .mediawiki-framed-primary-button-colored(@constructive, @constructive-hover, @constructive-selected);
- }
-
- &-destructive {
- .mediawiki-framed-primary-button-colored(@destructive, @destructive-hover, @destructive-selected);
- }
- }
- }
- }
-}
-
-.mediawiki-frameless-button-colored( @neutral, @pressed ) {
- > .oo-ui-buttonElement-button {
- &:hover,
- &:focus {
- > .oo-ui-labelElement-label {
- color: @neutral;
- }
- }
-
- > .oo-ui-labelElement-label {
- color: #777777;
- }
- }
-
- &.oo-ui-widget-enabled {
- & > .oo-ui-buttonElement-button:active > .oo-ui-labelElement-label,
- &.oo-ui-buttonElement-pressed > .oo-ui-buttonElement-button > .oo-ui-labelElement-label {
- color: @pressed;
- box-shadow: none;
- }
- }
-}
-
-.mediawiki-framed-button-colored( @neutral, @hover, @pressed ) {
- > .oo-ui-buttonElement-button {
- color: @neutral;
-
- &:hover {
- background-color: @hover;
- border-color: fade(@pressed,50%);
- }
-
- &:focus {
- box-shadow: inset 0 0 0 1px @pressed;
- border-color: @pressed;
- }
- }
-
- &.oo-ui-widget-enabled {
- .oo-ui-buttonElement-button:active,
- &.oo-ui-buttonElement-pressed > .oo-ui-buttonElement-button {
- color: @pressed;
- border-color: @pressed;
- box-shadow: none;
- }
-
- &.oo-ui-buttonElement-active > .oo-ui-buttonElement-button {
- background-color: @active;
- color: #fff;
- }
- }
-}
-
-.mediawiki-framed-primary-button-colored( @neutral, @hover, @pressed ) {
- > .oo-ui-buttonElement-button {
- color: @background;
- background-color: @neutral;
- border-color: @neutral;
-
- &:hover {
- background: @hover;
- border-color: @hover;
- }
-
- &:focus {
- box-shadow: inset 0 0 0 1px @background;
- border-color: @neutral;
- }
- }
-
- &.oo-ui-widget-enabled {
- .oo-ui-buttonElement-button:active,
- &.oo-ui-buttonElement-pressed > .oo-ui-buttonElement-button {
- color: @background;
- background-color: @pressed;
- border-color: @pressed;
- box-shadow: none;
- }
-
- &.oo-ui-buttonElement-active > .oo-ui-buttonElement-button {
- background-color: @active;
- color: #fff;
- }
- }
-}
-
-.theme-oo-ui-clippableElement () {}
-
-.theme-oo-ui-flaggedElement () {}
-
-.theme-oo-ui-draggableElement () {}
-
-.theme-oo-ui-groupElement () {}
-
-.theme-oo-ui-draggableGroupElement () {}
-
-.theme-oo-ui-iconElement () {
- .oo-ui-iconElement-icon,
- &.oo-ui-iconElement-icon {
- background-size: contain;
- background-position: center center;
- }
-}
-
-.theme-oo-ui-indicatorElement () {
- .oo-ui-indicatorElement-indicator,
- &.oo-ui-indicatorElement-indicator {
- background-size: contain;
- background-position: center center;
- }
-}
-
-.theme-oo-ui-labelElement () {}
-
-.theme-oo-ui-lookupElement () {}
-
-.theme-oo-ui-popupElement () {}
-
-.theme-oo-ui-tabIndexedElement () {}
-
-.theme-oo-ui-titledElement () {}
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/icons-alerts.json b/vendor/oojs/oojs-ui/src/themes/mediawiki/icons-alerts.json
deleted file mode 100644
index 5fbf34d0..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/icons-alerts.json
+++ /dev/null
@@ -1,33 +0,0 @@
-{
- "prefix": "oo-ui-icon",
- "intro": "@import '../../../../src/styles/common';",
- "images": {
- "bell": { "file": "images/icons/bell.svg" },
- "bellOn": { "file": {
- "ltr": "images/icons/bellOn-ltr.svg",
- "rtl": "images/icons/bellOn-rtl.svg"
- } },
- "eye": { "file": "images/icons/eye.svg" },
- "eyeClosed": { "file": "images/icons/eyeClosed.svg" },
- "message": { "file": {
- "ltr": "images/icons/message-ltr.svg",
- "rtl": "images/icons/message-rtl.svg"
- } },
- "signature": { "file": {
- "ltr": "images/icons/signature-ltr.svg",
- "rtl": "images/icons/signature-rtl.svg"
- } },
- "speechBubble": { "file": {
- "ltr": "images/icons/speechBubble-ltr.svg",
- "rtl": "images/icons/speechBubble-rtl.svg"
- } },
- "speechBubbleAdd": { "file": {
- "ltr": "images/icons/speechBubbleAdd-ltr.svg",
- "rtl": "images/icons/speechBubbleAdd-rtl.svg"
- } },
- "speechBubbles": { "file": {
- "ltr": "images/icons/speechBubbles-ltr.svg",
- "rtl": "images/icons/speechBubbles-rtl.svg"
- } }
- }
-}
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/icons-content.json b/vendor/oojs/oojs-ui/src/themes/mediawiki/icons-content.json
deleted file mode 100644
index 29681c0e..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/icons-content.json
+++ /dev/null
@@ -1,50 +0,0 @@
-{
- "prefix": "oo-ui-icon",
- "intro": "@import '../../../../src/styles/common';",
- "images": {
- "article": { "file": {
- "ltr": "images/icons/article-ltr.svg",
- "rtl": "images/icons/article-rtl.svg"
- } },
- "articleCheck": { "file": {
- "ltr": "images/icons/articleCheck-ltr.svg",
- "rtl": "images/icons/articleCheck-rtl.svg"
- } },
- "articleSearch": { "file": {
- "ltr": "images/icons/articleSearch-ltr.svg",
- "rtl": "images/icons/articleSearch-rtl.svg"
- } },
- "book": { "file": {
- "ltr": "images/icons/book-ltr.svg",
- "rtl": "images/icons/book-rtl.svg"
- } },
- "citeArticle": { "file": {
- "ltr": "images/icons/citeArticle-ltr.svg",
- "rtl": "images/icons/citeArticle-rtl.svg"
- } },
- "die": { "file": {
- "ltr": "images/icons/die-ltr.svg",
- "rtl": "images/icons/die-rtl.svg"
- } },
- "download": { "file": {
- "ltr": "images/icons/download-ltr.svg",
- "rtl": "images/icons/download-rtl.svg"
- } },
- "folderPlaceholder": { "file": {
- "ltr": "images/icons/folderPlaceholder-ltr.svg",
- "rtl": "images/icons/folderPlaceholder-rtl.svg"
- } },
- "journal": { "file": {
- "ltr": "images/icons/journal-ltr.svg",
- "rtl": "images/icons/journal-rtl.svg"
- } },
- "newspaper": { "file": {
- "ltr": "images/icons/newspaper-ltr.svg",
- "rtl": "images/icons/newspaper-rtl.svg"
- } },
- "upload": { "file": {
- "ltr": "images/icons/upload-ltr.svg",
- "rtl": "images/icons/upload-rtl.svg"
- } }
- }
-}
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/icons-editing-advanced.json b/vendor/oojs/oojs-ui/src/themes/mediawiki/icons-editing-advanced.json
deleted file mode 100644
index 8fdc5051..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/icons-editing-advanced.json
+++ /dev/null
@@ -1,75 +0,0 @@
-{
- "prefix": "oo-ui-icon",
- "intro": "@import '../../../../src/styles/common';",
- "images": {
- "alignCentre": { "file": "images/icons/align-center.svg" },
- "alignLeft": { "file": "images/icons/align-float-left.svg" },
- "alignRight": { "file": "images/icons/align-float-right.svg" },
- "find": { "file": {
- "ltr": "images/icons/find-ltr.svg",
- "rtl": "images/icons/find-rtl.svg"
- } },
- "insert": { "file": "images/icons/insert.svg" },
- "layout": { "file": {
- "ltr": "images/icons/layout-ltr.svg",
- "rtl": "images/icons/layout-rtl.svg"
- } },
- "newline": { "file": {
- "ltr": "images/icons/newline-ltr.svg",
- "rtl": "images/icons/newline-rtl.svg"
- } },
- "redirect": { "file": {
- "ltr": "images/icons/redirect-ltr.svg",
- "rtl": "images/icons/redirect-rtl.svg"
- } },
- "noWikiText": { "file": {
- "ltr": "images/icons/noWikiText-ltr.svg",
- "rtl": "images/icons/noWikiText-rtl.svg"
- } },
- "outline": { "file": {
- "ltr": "images/icons/outline-ltr.svg",
- "rtl": "images/icons/outline-rtl.svg"
- } },
- "puzzle": { "file": {
- "ltr": "images/icons/puzzle-ltr.svg",
- "rtl": "images/icons/puzzle-rtl.svg"
- } },
- "quotes": { "file": {
- "ltr": "images/icons/quotes-ltr.svg",
- "rtl": "images/icons/quotes-rtl.svg"
- } },
- "quotesAdd": { "file": {
- "ltr": "images/icons/quotesAdd-ltr.svg",
- "rtl": "images/icons/quotesAdd-rtl.svg"
- } },
- "redirect": { "file": {
- "ltr": "images/icons/redirect-ltr.svg",
- "rtl": "images/icons/redirect-rtl.svg"
- } },
- "searchCaseSensitive": { "file": "images/icons/case-sensitive.svg" },
- "searchRegularExpression": { "file": "images/icons/regular-expression.svg" },
- "specialCharacter": { "file": "images/icons/specialCharacter.svg" },
- "table": { "file": "images/icons/table.svg" },
- "tableAddColumnAfter": { "file": {
- "ltr": "images/icons/table-insert-column-rtl.svg",
- "rtl": "images/icons/table-insert-column-ltr.svg"
- } },
- "tableAddColumnBefore": { "file": {
- "ltr": "images/icons/table-insert-column-ltr.svg",
- "rtl": "images/icons/table-insert-column-rtl.svg"
- } },
- "tableAddRowAfter": { "file": "images/icons/table-insert-row-after.svg" },
- "tableAddRowBefore": { "file": "images/icons/table-insert-row-before.svg" },
- "tableCaption": { "file": "images/icons/table-caption.svg" },
- "tableMergeCells": { "file": "images/icons/table-merge-cells.svg" },
- "templateAdd": { "file": {
- "ltr": "images/icons/templateAdd-ltr.svg",
- "rtl": "images/icons/templateAdd-rtl.svg"
- } },
- "translation": { "file": {
- "ltr": "images/icons/translation-ltr.svg",
- "rtl": "images/icons/translation-rtl.svg"
- } },
- "wikiText": { "file": "images/icons/wikiText.svg" }
- }
-}
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/icons-editing-core.json b/vendor/oojs/oojs-ui/src/themes/mediawiki/icons-editing-core.json
deleted file mode 100644
index 3bacb605..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/icons-editing-core.json
+++ /dev/null
@@ -1,45 +0,0 @@
-{
- "prefix": "oo-ui-icon",
- "intro": "@import '../../../../src/styles/common';",
- "variants": {
- "invert": {
- "color": "#FFFFFF",
- "global": true
- },
- "progressive": {
- "color": "#347BFF"
- },
- "constructive": {
- "color": "#00AF89"
- },
- "destructive": {
- "color": "#D11D13"
- },
- "warning": {
- "color": "#FF5D00"
- }
- },
- "images": {
- "edit": { "file": {
- "ltr": "images/icons/edit-ltr.svg",
- "rtl": "images/icons/edit-rtl.svg"
- }, "variants": [ "progressive" ] },
- "editLock": { "file": {
- "ltr": "images/icons/editLock-ltr.svg",
- "rtl": "images/icons/editLock-rtl.svg"
- } },
- "editUndo": { "file": {
- "ltr": "images/icons/editUndo-ltr.svg",
- "rtl": "images/icons/editUndo-rtl.svg"
- } },
- "link": { "file": {
- "ltr": "images/icons/link-ltr.svg",
- "rtl": "images/icons/link-rtl.svg"
- } },
- "linkExternal": { "file": {
- "ltr": "images/icons/external-link-ltr.svg",
- "rtl": "images/icons/external-link-rtl.svg"
- } },
- "linkSecure": { "file": "images/icons/secure-link.svg" }
- }
-}
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/icons-editing-list.json b/vendor/oojs/oojs-ui/src/themes/mediawiki/icons-editing-list.json
deleted file mode 100644
index 490f8faf..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/icons-editing-list.json
+++ /dev/null
@@ -1,22 +0,0 @@
-{
- "prefix": "oo-ui-icon",
- "intro": "@import '../../../../src/styles/common';",
- "images": {
- "indent": { "file": {
- "ltr": "images/icons/indent-ltr.svg",
- "rtl": "images/icons/indent-rtl.svg"
- } },
- "listBullet": { "file": {
- "ltr": "images/icons/listBullet-ltr.svg",
- "rtl": "images/icons/listBullet-rtl.svg"
- } },
- "listNumbered": { "file": {
- "ltr": "images/icons/listNumbered-ltr.svg",
- "rtl": "images/icons/listNumbered-rtl.svg"
- } },
- "outdent": { "file": {
- "ltr": "images/icons/outdent-ltr.svg",
- "rtl": "images/icons/outdent-rtl.svg"
- } }
- }
-}
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/icons-editing-styling.json b/vendor/oojs/oojs-ui/src/themes/mediawiki/icons-editing-styling.json
deleted file mode 100644
index 65fbc218..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/icons-editing-styling.json
+++ /dev/null
@@ -1,72 +0,0 @@
-{
- "prefix": "oo-ui-icon",
- "intro": "@import '../../../../src/styles/common';",
- "images": {
- "bigger": { "file": {
- "ltr": "images/icons/bigger-ltr.svg",
- "rtl": "images/icons/bigger-rtl.svg"
- } },
- "smaller": { "file": {
- "ltr": "images/icons/smaller-ltr.svg",
- "rtl": "images/icons/smaller-rtl.svg"
- } },
- "subscript": { "file": {
- "ltr": "images/icons/subscript-ltr.svg",
- "rtl": "images/icons/subscript-rtl.svg"
- } },
- "superscript": { "file": {
- "ltr": "images/icons/superscript-ltr.svg",
- "rtl": "images/icons/superscript-rtl.svg"
- } },
- "bold": { "file": {
- "default": "images/icons/bold-a.svg",
- "lang": {
- "ar": "images/icons/bold-arab-ain.svg",
- "be": "images/icons/bold-cyrl-te.svg",
- "cs,en,he,ml,pl": "images/icons/bold-b.svg",
- "da,de,hu,ksh,nn,no,sv": "images/icons/bold-f.svg",
- "es,gl,pt": "images/icons/bold-n.svg",
- "eu,fi": "images/icons/bold-l.svg",
- "fa": "images/icons/bold-arab-dad.svg",
- "fr,it": "images/icons/bold-g.svg",
- "hy": "images/icons/bold-armn-to.svg",
- "ka": "images/icons/bold-geor-man.svg",
- "ky,ru": "images/icons/bold-cyrl-zhe.svg",
- "nl": "images/icons/bold-v.svg",
- "os": "images/icons/bold-cyrl-be.svg"
- }
- } },
- "italic": { "file": {
- "default": "images/icons/italic-a.svg",
- "lang": {
- "ar": "images/icons/italic-arab-meem.svg",
- "cs,en,fr,he,ml,pl,pt": "images/icons/italic-i.svg",
- "be,da,de,fi,ky,nn,no,os,sv,ru": "images/icons/italic-k.svg",
- "es,gl,it,nl": "images/icons/italic-c.svg",
- "eu": "images/icons/italic-e.svg",
- "fa": "images/icons/italic-arab-keheh-jeem.svg",
- "hu": "images/icons/italic-d.svg",
- "hy": "images/icons/italic-armn-sha.svg",
- "ksh": "images/icons/italic-s.svg",
- "ka": "images/icons/italic-geor-kan.svg"
- }
- } },
- "strikethrough": { "file": {
- "default": "images/icons/strikethrough-a.svg",
- "lang": {
- "en": "images/icons/strikethrough-s.svg",
- "fi": "images/icons/strikethrough-y.svg"
- }
- } },
- "underline": { "file": {
- "default": "images/icons/underline-a.svg",
- "lang": {
- "en": "images/icons/underline-u.svg"
- }
- } },
- "textLanguage": { "file": "images/icons/language.svg" },
- "textDirLTR": { "file": "images/icons/text-dir-lefttoright.svg" },
- "textDirRTL": { "file": "images/icons/text-dir-righttoleft.svg" },
- "textStyle": { "file": "images/icons/text-style.svg" }
- }
-}
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/icons-interactions.json b/vendor/oojs/oojs-ui/src/themes/mediawiki/icons-interactions.json
deleted file mode 100644
index 497a3014..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/icons-interactions.json
+++ /dev/null
@@ -1,52 +0,0 @@
-{
- "prefix": "oo-ui-icon",
- "intro": "@import '../../../../src/styles/common';",
- "images": {
- "beta": { "file": "images/icons/beta.svg" },
- "betaLaunch": { "file": "images/icons/betaLaunch.svg" },
- "bookmark": { "file": {
- "ltr": "images/icons/bookmark-ltr.svg",
- "rtl": "images/icons/bookmark-rtl.svg"
- } },
- "browser": { "file": {
- "ltr": "images/icons/browser-ltr.svg",
- "rtl": "images/icons/browser-rtl.svg"
- } },
- "clear": { "file": "images/icons/clear.svg" },
- "clock": { "file": "images/icons/clock.svg" },
- "funnel": { "file": {
- "ltr": "images/icons/funnel-ltr.svg",
- "rtl": "images/icons/funnel-rtl.svg"
- } },
- "heart": { "file": "images/icons/heart.svg" },
- "key": { "file": {
- "ltr": "images/icons/key-ltr.svg",
- "rtl": "images/icons/key-rtl.svg"
- } },
- "keyboard": { "file": {
- "ltr": "images/icons/keyboard-ltr.svg",
- "rtl": "images/icons/keyboard-rtl.svg"
- } },
- "logOut": { "file": {
- "ltr": "images/icons/logOut-ltr.svg",
- "rtl": "images/icons/logOut-rtl.svg"
- } },
- "newWindow": { "file": {
- "ltr": "images/icons/newWindow-ltr.svg",
- "rtl": "images/icons/newWindow-rtl.svg"
- } },
- "printer": { "file": {
- "ltr": "images/icons/printer-ltr.svg",
- "rtl": "images/icons/printer-rtl.svg"
- } },
- "ribbonPrize": { "file": "images/icons/ribbonPrize.svg" },
- "sun": { "file": {
- "ltr": "images/icons/sun-ltr.svg",
- "rtl": "images/icons/sun-rtl.svg"
- } },
- "watchlist": { "file": {
- "ltr": "images/icons/watchlist-ltr.svg",
- "rtl": "images/icons/watchlist-rtl.svg"
- } }
- }
-}
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/icons-layout.json b/vendor/oojs/oojs-ui/src/themes/mediawiki/icons-layout.json
deleted file mode 100644
index ae6b09d7..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/icons-layout.json
+++ /dev/null
@@ -1,43 +0,0 @@
-{
- "prefix": "oo-ui-icon",
- "intro": "@import '../../../../src/styles/common';",
- "variants": {
- "invert": {
- "color": "#FFFFFF",
- "global": true
- },
- "progressive": {
- "color": "#347BFF"
- },
- "constructive": {
- "color": "#00AF89"
- },
- "destructive": {
- "color": "#D11D13"
- },
- "warning": {
- "color": "#FF5D00"
- }
- },
- "images": {
- "stripeFlow": { "file": {
- "ltr": "images/icons/stripeFlow-ltr.svg",
- "rtl": "images/icons/stripeFlow-rtl.svg"
- } },
- "stripeSideMenu": { "file": "images/icons/stripeSideMenu.svg" },
- "stripeSummary": { "file": {
- "ltr": "images/icons/stripeSummary-ltr.svg",
- "rtl": "images/icons/stripeSummary-rtl.svg"
- } },
- "stripeToC": { "file": {
- "ltr": "images/icons/stripeToC-ltr.svg",
- "rtl": "images/icons/stripeToC-rtl.svg"
- }, "variants": [ "progressive" ] },
- "viewCompact": { "file": "images/icons/viewCompact.svg" },
- "viewDetails": { "file": {
- "ltr": "images/icons/viewDetails-ltr.svg",
- "rtl": "images/icons/viewDetails-rtl.svg"
- } },
- "visionSimulator": { "file": "images/icons/visionSimulator.svg" }
- }
-}
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/icons-location.json b/vendor/oojs/oojs-ui/src/themes/mediawiki/icons-location.json
deleted file mode 100644
index 9eec19ba..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/icons-location.json
+++ /dev/null
@@ -1,19 +0,0 @@
-{
- "prefix": "oo-ui-icon",
- "intro": "@import '../../../../src/styles/common';",
- "images": {
- "map": { "file": {
- "ltr": "images/icons/map-ltr.svg",
- "rtl": "images/icons/map-rtl.svg"
- } },
- "mapPin": { "file": "images/icons/mapPin.svg" },
- "mapPinAdd": { "file": {
- "ltr": "images/icons/mapPinAdd-ltr.svg",
- "rtl": "images/icons/mapPinAdd-rtl.svg"
- } },
- "wikitrail": { "file": {
- "ltr": "images/icons/wikitrail-ltr.svg",
- "rtl": "images/icons/wikitrail-rtl.svg"
- } }
- }
-}
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/icons-media.json b/vendor/oojs/oojs-ui/src/themes/mediawiki/icons-media.json
deleted file mode 100644
index 960079b4..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/icons-media.json
+++ /dev/null
@@ -1,27 +0,0 @@
-{
- "prefix": "oo-ui-icon",
- "intro": "@import '../../../../src/styles/common';",
- "images": {
- "image": { "file": {
- "ltr": "images/icons/image-ltr.svg",
- "rtl": "images/icons/image-rtl.svg"
- } },
- "imageAdd": { "file": {
- "ltr": "images/icons/imageAdd-ltr.svg",
- "rtl": "images/icons/imageAdd-rtl.svg"
- } },
- "imageLock": { "file": {
- "ltr": "images/icons/imageLock-ltr.svg",
- "rtl": "images/icons/imageLock-rtl.svg"
- } },
- "photoGallery": { "file": {
- "ltr": "images/icons/photoGallery-ltr.svg",
- "rtl": "images/icons/photoGallery-rtl.svg"
- } },
- "play": { "file": {
- "ltr": "images/icons/play-ltr.svg",
- "rtl": "images/icons/play-rtl.svg"
- } },
- "stop": { "file": "images/icons/stop.svg" }
- }
-}
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/icons-moderation.json b/vendor/oojs/oojs-ui/src/themes/mediawiki/icons-moderation.json
deleted file mode 100644
index 1f12f2ae..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/icons-moderation.json
+++ /dev/null
@@ -1,52 +0,0 @@
-{
- "prefix": "oo-ui-icon",
- "intro": "@import '../../../../src/styles/common';",
- "variants": {
- "invert": {
- "color": "#FFFFFF",
- "global": true
- },
- "progressive": {
- "color": "#347BFF"
- },
- "constructive": {
- "color": "#00AF89"
- },
- "destructive": {
- "color": "#D11D13"
- },
- "warning": {
- "color": "#FF5D00"
- }
- },
- "images": {
- "block": { "file": "images/icons/block.svg", "variants": [ "destructive" ] },
- "blockUndo": { "file": {
- "ltr": "images/icons/blockUndo-ltr.svg",
- "rtl": "images/icons/blockUndo-rtl.svg"
- } },
- "flag": { "file": {
- "ltr": "images/icons/flag-ltr.svg",
- "rtl": "images/icons/flag-rtl.svg"
- } },
- "flagUndo": { "file": {
- "ltr": "images/icons/flagUndo-ltr.svg",
- "rtl": "images/icons/flagUndo-rtl.svg"
- } },
- "lock": { "file": {
- "ltr": "images/icons/lock-ltr.svg",
- "rtl": "images/icons/lock-rtl.svg"
- }, "variants": [ "destructive" ] },
- "star": { "file": "images/icons/star.svg" },
- "trash": { "file": "images/icons/trash.svg" },
- "trashUndo": { "file": {
- "ltr": "images/icons/trashUndo-ltr.svg",
- "rtl": "images/icons/trashUndo-rtl.svg"
- } },
- "unLock": { "file": {
- "ltr": "images/icons/unLock-ltr.svg",
- "rtl": "images/icons/unLock-rtl.svg"
- }, "variants": [ "destructive" ] },
- "unStar": { "file": "images/icons/unStar.svg" }
- }
-}
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/icons-movement.json b/vendor/oojs/oojs-ui/src/themes/mediawiki/icons-movement.json
deleted file mode 100644
index 9aa1b809..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/icons-movement.json
+++ /dev/null
@@ -1,27 +0,0 @@
-{
- "prefix": "oo-ui-icon",
- "intro": "@import '../../../../src/styles/common';",
- "images": {
- "arrowNext": { "file": {
- "ltr": "images/icons/arrow-ltr.svg",
- "rtl": "images/icons/arrow-rtl.svg"
- } },
- "arrowLast": { "file": {
- "ltr": "images/icons/arrow-rtl.svg",
- "rtl": "images/icons/arrow-ltr.svg"
- } },
- "caretNext": { "file": {
- "ltr": "images/icons/caret-rtl.svg",
- "rtl": "images/icons/caret-ltr.svg"
- } },
- "caretLast": { "file": {
- "ltr": "images/icons/caret-ltr.svg",
- "rtl": "images/icons/caret-rtl.svg"
- } },
- "caretDown": { "file": "images/icons/caretDown.svg" },
- "caretUp": { "file": "images/icons/caretUp.svg" },
- "downTriangle": { "file": "images/icons/downTriangle.svg" },
- "move": { "file": "images/icons/move.svg" },
- "upTriangle": { "file": "images/icons/upTriangle.svg" }
- }
-}
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/icons-user.json b/vendor/oojs/oojs-ui/src/themes/mediawiki/icons-user.json
deleted file mode 100644
index 2bda5753..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/icons-user.json
+++ /dev/null
@@ -1,19 +0,0 @@
-{
- "prefix": "oo-ui-icon",
- "intro": "@import '../../../../src/styles/common';",
- "images": {
- "userActive": { "file": {
- "ltr": "images/icons/userActive-ltr.svg",
- "rtl": "images/icons/userActive-rtl.svg"
- } },
- "userAvatar": { "file": "images/icons/userAvatar.svg" },
- "userInactive": { "file": {
- "ltr": "images/icons/userInactive-ltr.svg",
- "rtl": "images/icons/userInactive-rtl.svg"
- } },
- "userTalk": { "file": {
- "ltr": "images/icons/userTalk-ltr.svg",
- "rtl": "images/icons/userTalk-rtl.svg"
- } }
- }
-}
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/icons-wikimedia.json b/vendor/oojs/oojs-ui/src/themes/mediawiki/icons-wikimedia.json
deleted file mode 100644
index fd13c95d..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/icons-wikimedia.json
+++ /dev/null
@@ -1,9 +0,0 @@
-{
- "prefix": "oo-ui-icon",
- "intro": "@import '../../../../src/styles/common';",
- "images": {
- "logoCC": { "file": "images/icons/logo-cc.svg" },
- "logoWikimediaCommons": { "file": "images/icons/logo-wikimediaCommons.svg" },
- "logoWikipedia": { "file": "images/icons/logo-wikipedia.svg" }
- }
-}
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/icons.json b/vendor/oojs/oojs-ui/src/themes/mediawiki/icons.json
deleted file mode 100644
index d385eb11..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/icons.json
+++ /dev/null
@@ -1,75 +0,0 @@
-{
- "selectorWithoutVariant": ".oo-ui-icon-{name}",
- "selectorWithVariant": ".oo-ui-image-{variant} .oo-ui-icon-{name}, .oo-ui-image-{variant}.oo-ui-icon-{name}",
- "intro": "@import '../../../../src/styles/common';",
- "variants": {
- "invert": {
- "color": "#FFFFFF",
- "global": true
- },
- "progressive": {
- "color": "#347BFF"
- },
- "constructive": {
- "color": "#00AF89"
- },
- "destructive": {
- "color": "#D11D13"
- },
- "warning": {
- "color": "#FF5D00"
- }
- },
- "images": {
- "add": { "file": "images/icons/add.svg", "variants": [ "constructive" ] },
- "advanced": { "file": "images/icons/advanced.svg" },
- "alert": { "file": "images/icons/alert.svg", "variants": [ "warning" ] },
- "cancel": { "file": "images/icons/cancel.svg" },
- "check": { "file": "images/icons/check.svg", "variants": [ "constructive", "progressive" ] },
- "circle": { "file": "images/icons/circle.svg", "variants": [ "constructive" ] },
- "close": { "file": {
- "ltr": "images/icons/close-ltr.svg",
- "rtl": "images/icons/close-rtl.svg"
- } },
- "code": { "file": "images/icons/code.svg" },
- "collapse": { "file": "images/icons/collapse.svg" },
- "comment": { "file": "images/icons/comment.svg" },
- "ellipsis": { "file": "images/icons/ellipsis.svg" },
- "expand": { "file": "images/icons/expand.svg" },
- "help": { "file": {
- "ltr": "images/icons/help-ltr.svg",
- "rtl": "images/icons/help-rtl.svg",
- "lang": {
- "he,yi": "images/icons/help-ltr.svg"
- }
- } },
- "history": { "file": "images/icons/history.svg" },
- "info": { "file": "images/icons/info.svg" },
- "menu": { "file": "images/icons/menu.svg" },
- "next": { "file": {
- "ltr": "images/icons/move-ltr.svg",
- "rtl": "images/icons/move-rtl.svg"
- } },
- "picture": { "file": "images/icons/picture.svg" },
- "previous": { "file": {
- "ltr": "images/icons/move-rtl.svg",
- "rtl": "images/icons/move-ltr.svg"
- } },
- "redo": { "file": {
- "ltr": "images/icons/arched-arrow-ltr.svg",
- "rtl": "images/icons/arched-arrow-rtl.svg"
- } },
- "remove": { "file": "images/icons/remove.svg", "variants": [ "destructive" ] },
- "search": { "file": {
- "ltr": "images/icons/search-ltr.svg",
- "rtl": "images/icons/search-rtl.svg"
- } },
- "settings": { "file": "images/icons/settings.svg" },
- "tag": { "file": "images/icons/tag.svg", "variants": [ "destructive", "warning", "constructive", "progressive" ] },
- "undo": { "file": {
- "ltr": "images/icons/arched-arrow-rtl.svg",
- "rtl": "images/icons/arched-arrow-ltr.svg"
- } },
- "window": { "file": "images/icons/window.svg" }
- }
-}
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/add.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/add.svg
deleted file mode 100644
index 29e5dba8..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/add.svg
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="add">
- <path id="plus" d="M13 8h-2v3h-3v2h3v3h2v-3h3v-2h-3z"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/advanced.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/advanced.svg
deleted file mode 100644
index b4629bf9..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/advanced.svg
+++ /dev/null
@@ -1,4 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <path d="M20 14.5v-2.9l-1.8-.3c-.1-.4-.3-.8-.6-1.4l1.1-1.5-2.1-2.1-1.5 1.1c-.5-.3-1-.5-1.4-.6l-.2-1.8h-2.9l-.3 1.8c-.5.1-.9.3-1.4.6l-1.5-1.1-2.1 2.1 1 1.5c-.3.5-.4.9-.6 1.4l-1.7.2v2.9l1.8.3c.1.5.3.9.6 1.4l-1 1.5 2.1 2.1 1.5-1c.4.2.9.4 1.4.6l.3 1.8h3l.3-1.8c.5-.1.9-.3 1.4-.6l1.5 1.1 2.1-2.1-1.1-1.5c.3-.5.5-1 .6-1.4l1.5-.3zm-8 1.5c-1.7 0-3-1.3-3-3s1.3-3 3-3 3 1.3 3 3-1.3 3-3 3z"/>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/alert.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/alert.svg
deleted file mode 100644
index f0c65224..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/alert.svg
+++ /dev/null
@@ -1,8 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="alert">
- <path id="point" d="M11 16h2v2h-2z"/>
- <path id="stroke" d="M13.516 10h-3l.484 5h2z"/>
- <path id="triangle" d="M12.017 5.974l7.519 13.026h-15.04l7.521-13.026m0-2.474c-.544 0-1.088.357-1.5 1.071l-7.985 13.831c-.825 1.429-.15 2.598 1.5 2.598h15.968c1.65 0 2.325-1.169 1.5-2.599l-7.983-13.829c-.413-.715-.956-1.072-1.5-1.072z"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/align-center.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/align-center.svg
deleted file mode 100644
index 887c2f66..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/align-center.svg
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="align-center">
- <path d="M9 9h6c.554 0 1 .446 1 1v5c0 .554-.446 1-1 1h-6c-.554 0-1-.446-1-1v-5c0-.554.446-1 1-1zM3.5 18h17c.277 0 .5.223.5.5s-.223.5-.5.5h-17c-.277 0-.5-.223-.5-.5s.223-.5.5-.5zM3.5 6h17c.277 0 .5.223.5.5s-.223.5-.5.5h-17c-.277 0-.5-.223-.5-.5s.223-.5.5-.5z"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/align-float-left.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/align-float-left.svg
deleted file mode 100644
index ce9761e2..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/align-float-left.svg
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="align-float-left">
- <path d="M4 9h6c.554 0 1 .446 1 1v5c0 .554-.446 1-1 1h-6c-.554 0-1-.446-1-1v-5c0-.554.446-1 1-1zM13.5 9h7c.277 0 .5.223.5.5s-.223.5-.5.5h-7c-.277 0-.5-.223-.5-.5s.223-.5.5-.5zM13.5 12h7c.277 0 .5.223.5.5s-.223.5-.5.5h-7c-.277 0-.5-.223-.5-.5s.223-.5.5-.5zM13.5 15h7c.277 0 .5.223.5.5s-.223.5-.5.5h-7c-.277 0-.5-.223-.5-.5s.223-.5.5-.5zM3.5 6h17c.277 0 .5.223.5.5s-.223.5-.5.5h-17c-.277 0-.5-.223-.5-.5s.223-.5.5-.5zM3.5 18h17c.277 0 .5.223.5.5s-.223.5-.5.5h-17c-.277 0-.5-.223-.5-.5s.223-.5.5-.5z"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/align-float-right.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/align-float-right.svg
deleted file mode 100644
index 557692ae..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/align-float-right.svg
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="align-float-right">
- <path d="M20 9h-6c-.554 0-1 .446-1 1v5c0 .554.446 1 1 1h6c.554 0 1-.446 1-1v-5c0-.554-.446-1-1-1zM10.5 9h-7c-.277 0-.5.223-.5.5s.223.5.5.5h7c.277 0 .5-.223.5-.5s-.223-.5-.5-.5zM10.5 12h-7c-.277 0-.5.223-.5.5s.223.5.5.5h7c.277 0 .5-.223.5-.5s-.223-.5-.5-.5zM10.5 15h-7c-.277 0-.5.223-.5.5s.223.5.5.5h7c.277 0 .5-.223.5-.5s-.223-.5-.5-.5zM20.5 6h-17c-.277 0-.5.223-.5.5s.223.5.5.5h17c.277 0 .5-.223.5-.5s-.223-.5-.5-.5zM20.5 18h-17c-.277 0-.5.223-.5.5s.223.5.5.5h17c.277 0 .5-.223.5-.5s-.223-.5-.5-.5z"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/arched-arrow-ltr.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/arched-arrow-ltr.svg
deleted file mode 100644
index 049f21e2..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/arched-arrow-ltr.svg
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Generator: Adobe Illustrator 18.1.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
-<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
- viewBox="-487 489 24 24" enable-background="new -487 489 24 24" xml:space="preserve">
-<path d="M-472.8,494.7l6.3,5.7l-6.3,5.7v-3.8h-1.3c-3.2,0-6.3,1.3-7.6,3.8c0-4.7,2.8-7.6,7.9-7.6h0.9V494.7z"/>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/arched-arrow-rtl.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/arched-arrow-rtl.svg
deleted file mode 100644
index 20875f34..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/arched-arrow-rtl.svg
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Generator: Adobe Illustrator 18.1.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
-<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
- viewBox="-487 489 24 24" enable-background="new -487 489 24 24" xml:space="preserve">
-<path d="M-476.3,494.7l-6.3,5.7l6.3,5.7v-3.8h1.3c3.2,0,6.3,1.3,7.6,3.8c0-4.7-2.8-7.6-7.9-7.6h-0.9V494.7z"/>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/arrow-ltr.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/arrow-ltr.svg
deleted file mode 100644
index b07621e8..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/arrow-ltr.svg
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="g4">
- <path d="M16 12h-10c-1.7 0-3 1.3-3 3h13v3l5-4.5-5-4.5v3z" id="path6"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/arrow-rtl.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/arrow-rtl.svg
deleted file mode 100644
index a0189283..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/arrow-rtl.svg
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g>
- <path d="M8 12h10c1.7 0 3 1.3 3 3h-13v3l-5-4.5 5-4.5v3z"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/article-ltr.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/article-ltr.svg
deleted file mode 100644
index b719946d..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/article-ltr.svg
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g>
- <path d="M12 10h4v-5h-4v5zm-5 2h9v-1h-9v1zm0 2h9v-1h-9v1zm0 2h9v-1h-9v1zm4-9h-4v1h4v-1zm0 2h-4v1h4v-1zm0-4h-4v1h4v-1zm-6-2h13v16h-10c-1.7 0-3-1.3-3-3v-13z"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/article-rtl.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/article-rtl.svg
deleted file mode 100644
index f14dfbda..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/article-rtl.svg
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="g16">
- <path d="M11 10h-4v-5h4v5zm5 2h-9v-1h9v1zm0 2h-9v-1h9v1zm0 2h-9v-1h9v1zm-4-9h4v1h-4v-1zm0 2h4v1h-4v-1zm0-4h4v1h-4v-1zm6-2h-13v16h10c1.7 0 3-1.3 3-3v-13z" id="path18"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/articleCheck-ltr.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/articleCheck-ltr.svg
deleted file mode 100644
index 77119710..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/articleCheck-ltr.svg
+++ /dev/null
@@ -1,9 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g>
- <g>
- <path d="M21 11l-6 7-4-4-1 1 5 5 7-8z"/>
- </g>
- <path d="M17 14v-11h-13v13c0 1.7 1.3 3 3 3h5l-3-3h-3v-1h2.6l1-1h-3.6v-1h9v1h-2l1 1h2l1-1zm-11-9h4v1h-4v-1zm0 2h4v1h-4v-1zm0 2h4v1h-4v-1zm9 3h-9v-1h9v1zm-4-2v-5h4v5h-4z"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/articleCheck-rtl.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/articleCheck-rtl.svg
deleted file mode 100644
index 771b3ffb..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/articleCheck-rtl.svg
+++ /dev/null
@@ -1,9 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="g28">
- <g id="g30">
- <path d="M5 11l6 7 4-4 1 1-5 5-7-8z" id="path32"/>
- </g>
- <path d="M9 14v-11h13v13c0 1.7-1.3 3-3 3h-5l3-3h3v-1h-2.6l-1-1h3.6v-1h-9v1h2l-1 1h-2l-1-1zm11-9h-4v1h4v-1zm0 2h-4v1h4v-1zm0 2h-4v1h4v-1zm-9 3h9v-1h-9v1zm4-2v-5h-4v5h4z" id="path34"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/articleSearch-ltr.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/articleSearch-ltr.svg
deleted file mode 100644
index e54c0c4a..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/articleSearch-ltr.svg
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g>
- <path d="M19.1 18.5c.6-.7.9-1.5.9-2.5 0-2.2-1.8-4-4-4s-4 1.8-4 4 1.8 4 4 4c.7 0 1.3-.1 1.8-.4l2.7 2.7 1.1-1.1-2.5-2.7zm-3.1-.3c-1.2 0-2.2-1-2.2-2.3 0-1.2 1-2.2 2.2-2.2 1.2 0 2.3 1 2.3 2.2-.1 1.3-1.1 2.3-2.3 2.3zm-4.2-5.2c.3-.4.6-.7 1-1h-5.8v-1h9s1.2 0 2 .6v-8.6h-13v13c0 1.7 1.3 3 3 3h3.8c-.6-.8-1-1.9-1-3h-3.8v-1h3.9l.3-1h-4.2v-1h4.8zm.2-8h4v5h-4v-5zm-5 0h4v1h-4v-1zm0 2h4v1h-4v-1zm0 2h4v1h-4v-1z"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/articleSearch-rtl.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/articleSearch-rtl.svg
deleted file mode 100644
index 31134f1c..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/articleSearch-rtl.svg
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="g44">
- <path d="M7.5 18.5c-.6-.7-.9-1.5-.9-2.5 0-2.2 1.8-4 4-4s4 1.8 4 4-1.8 4-4 4c-.7 0-1.3-.1-1.8-.4l-2.7 2.7-1.1-1.1 2.5-2.7zm3.1-.3c1.2 0 2.2-1 2.2-2.3 0-1.2-1-2.2-2.2-2.2-1.2 0-2.3 1-2.3 2.2.1 1.3 1.1 2.3 2.3 2.3zm4.2-5.2c-.3-.4-.6-.7-1-1h5.8v-1h-9s-1.2 0-2 .6v-8.6h13v13c0 1.7-1.3 3-3 3h-3.8c.6-.8 1-1.9 1-3h3.8v-1h-3.9l-.3-1h4.2v-1h-4.8zm-.2-8h-4v5h4v-5zm5 0h-4v1h4v-1zm0 2h-4v1h4v-1zm0 2h-4v1h4v-1z" id="path46"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/bell.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/bell.svg
deleted file mode 100644
index df08800f..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/bell.svg
+++ /dev/null
@@ -1,4 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <path d="M17.5 14v-5c0-3-2.3-5-5.5-5s-5.5 2-5.5 5v5c0 2 0 3-2 3v1h15v-1c-2 0-2-1-2-3zm-5.5 6h-3c0 1 1.6 2 3 2s3-1 3-2h-3z"/>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/bellOn-ltr.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/bellOn-ltr.svg
deleted file mode 100644
index f419e79f..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/bellOn-ltr.svg
+++ /dev/null
@@ -1,4 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <path d="M17.8 14.7l1.7-4.7c1-2.8-.5-5.5-3.5-6.6s-5.9 0-6.9 2.8l-1.7 4.7c-.7 1.9-1 2.8-2.9 2.1l-.3 1 14.1 5.1.3-.9c-1.9-.7-1.5-1.6-.8-3.5zm-5.8 5.1l-2.8-1c-.3.9.8 2.4 2.1 2.9s3.2.1 3.5-.9l-2.8-1z"/>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/bellOn-rtl.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/bellOn-rtl.svg
deleted file mode 100644
index e4c3a3fa..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/bellOn-rtl.svg
+++ /dev/null
@@ -1,4 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <path d="M6.209 14.7l-1.7-4.7c-1-2.8.5-5.5 3.5-6.6 3-1.1 5.9 0 6.9 2.8l1.7 4.7c.7 1.9 1 2.8 2.9 2.1l.3 1-14.1 5.1-.3-.9c1.9-.7 1.5-1.6.8-3.5zm5.8 5.1l2.8-1c.3.9-.8 2.4-2.1 2.9s-3.2.1-3.5-.9l2.8-1z" id="path56"/>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/beta.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/beta.svg
deleted file mode 100644
index 51a5c782..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/beta.svg
+++ /dev/null
@@ -1,4 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <path d="M12 4c-4.4 0-8 3.6-8 8s3.6 8 8 8 8-3.6 8-8-3.6-8-8-8zm4 12l-3-2-1 4-1-4-3 2 2-3-4-1 4-1-2-3 3 2 1-4 1 4 3-2-2 3 4 1-4 1 2 3z"/>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/betaLaunch.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/betaLaunch.svg
deleted file mode 100644
index a693b59b..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/betaLaunch.svg
+++ /dev/null
@@ -1,4 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <path d="M15.3 14.7c.8-3.8-.6-10.7-3.3-10.7-2.7 0-4.2 6.7-3.4 10.5l-1.6 3.5h2.7l.3 1h4c.2-.3.1-.5.3-1h2.7l-1.7-3.3zm-3.3-4.7c-.8 0-1.5-.7-1.5-1.5s.7-1.5 1.5-1.5 1.5.7 1.5 1.5-.7 1.5-1.5 1.5zm2 10c0 1.1-2 2-2 2s-2-.9-2-2"/>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/bigger-ltr.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/bigger-ltr.svg
deleted file mode 100644
index 94ec6704..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/bigger-ltr.svg
+++ /dev/null
@@ -1,7 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <path d="M12.666 6h-1.372l-4.48 12h1.705l1.494-4h3.999l1.508 4h1.666l-4.52-12zm-2.28 7l1.617-4.333 1.634 4.333h-3.251z" id="a"/>
- <g id="up">
- <path id="arrow" d="M15.5 9h7l-3.5-6z"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/bigger-rtl.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/bigger-rtl.svg
deleted file mode 100644
index b2a6c139..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/bigger-rtl.svg
+++ /dev/null
@@ -1,7 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <path d="M12.666 6h-1.372l-4.48 12H8.52l1.493-4h4l1.507 4h1.666l-4.52-12zm-2.28 7l1.617-4.333L13.637 13h-3.25z" id="a"/>
- <g id="up">
- <path id="arrow" d="M1.5 9h7L5 3z"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/block.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/block.svg
deleted file mode 100644
index 0ddd1d47..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/block.svg
+++ /dev/null
@@ -1,4 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <path d="M12 4c-4.4 0-8 3.6-8 8s3.6 8 8 8 8-3.6 8-8-3.6-8-8-8zm5 9h-10v-2h10v2z" id="path4"/>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/blockUndo-ltr.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/blockUndo-ltr.svg
deleted file mode 100644
index 3d9cfd7d..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/blockUndo-ltr.svg
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="g66">
- <path d="M17 11v2h-2l3.6 3.6c.9-1.3 1.4-2.9 1.4-4.6 0-4.4-3.6-8-8-8-1.7 0-3.3.5-4.6 1.4l5.6 5.6h4zm-13-7l-1 1 2.4 2.4c-.9 1.3-1.4 2.9-1.4 4.6 0 4.4 3.6 8 8 8 1.7 0 3.3-.5 4.6-1.4l2.4 2.4 1-1-16-16zm3 9v-2h2l2 2h-4z" id="path68"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/blockUndo-rtl.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/blockUndo-rtl.svg
deleted file mode 100644
index 8f807596..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/blockUndo-rtl.svg
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="g66">
- <path d="M7 11v2h2l-3.6 3.6c-.9-1.3-1.4-2.9-1.4-4.6 0-4.4 3.6-8 8-8 1.7 0 3.3.5 4.6 1.4l-5.6 5.6h-4zm13-7l1 1-2.4 2.4c.9 1.3 1.4 2.9 1.4 4.6 0 4.4-3.6 8-8 8-1.7 0-3.3-.5-4.6-1.4l-2.4 2.4-1-1 16-16zm-3 9v-2h-2l-2 2h4z" id="path68"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/bold-a.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/bold-a.svg
deleted file mode 100644
index 4b828779..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/bold-a.svg
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="bold-a">
- <path d="M16 18h3l-5-12h-3l-5 12h3l1.25-3h4.5l1.25 3zm-4.917-5l1.417-3.4 1.417 3.4h-2.834z"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/bold-arab-ain.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/bold-arab-ain.svg
deleted file mode 100644
index f96cebce..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/bold-arab-ain.svg
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="bold-arab-ain">
- <path id="arab-ain" d="M9.337 13.616c0 1.349 1.386 2.101 4.159 2.258l2.187-.029.318.044c-.03.127-.251.345-.665.652l-.089.066c-1.236.929-2.423 1.393-3.56 1.393-1.143 0-2.046-.33-2.711-.99-.65-.66-.975-1.559-.975-2.698.005-1.354.566-2.573 1.684-3.658v-.044l-.606-.55c-.148-.181-.222-.391-.222-.63 0-.489.239-1.109.717-1.862.65-1.046 1.303-1.566 1.958-1.561.886.005 1.618.42 2.194 1.246.325.479-.03.552-1.064.22-.842-.327-1.527-.051-2.054.828l.015.073 1.123.865.052.007c1.404-.498 2.418-.74 3.043-.726-.059.117-.14.362-.244.733-.103.357-.204.684-.303.982l-.126.374-.384.051c-1.743.239-2.992.716-3.745 1.429-.463.464-.697.973-.702 1.525"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/bold-arab-dad.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/bold-arab-dad.svg
deleted file mode 100644
index f04c6aad..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/bold-arab-dad.svg
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="bold-arab-dad">
- <path id="arab-dad" d="M16.411 8.232l-1.676-.665.694-1.567 1.688.64-.707 1.592m.775 3.078c-.509-.286-1-.427-1.476-.423-.471 0-.982.205-1.532.616l-.506.379.006.025c1.084.066 1.934.099 2.551.099h.313c.567-.021.992-.064 1.276-.131-.067-.17-.275-.359-.625-.566h-.006m-6.803 3.296c-.017-.904-.329-1.87-.938-2.898l1.294-1.729.119.149c.267.336.504.924.713 1.766l.063.05c.496-.008.942-.17 1.338-.485v-.006l1.732-1.53c.679-.601 1.282-.902 1.807-.902.383.004.848.195 1.394.572.55.377.884.696 1 .958.063.149.094.386.094.709 0 .696-.11 1.229-.331 1.598-.192.311-.473.555-.844.734-.438.207-1.549.311-3.333.311-.8 0-1.795-.021-2.983-.062l-.144.429c-.254.672-.463 1.113-.625 1.324-.725.937-1.786 1.405-3.183 1.405-1.705-.008-2.557-.922-2.557-2.742.004-.941.279-1.814.825-2.618.15-.216.298-.367.444-.454.225-.133.288-.091.188.124-.396.862-.596 1.548-.6 2.058.008 1.177.752 1.768 2.232 1.772 1.038-.004 1.803-.182 2.295-.535"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/bold-armn-to.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/bold-armn-to.svg
deleted file mode 100644
index 4dbec6d9..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/bold-armn-to.svg
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="bold-armn-to">
- <path id="armn-to" d="M13.86 16.257c.124 0 .254-.026.39-.078.135-.058.257-.15.367-.274.114-.13.205-.302.273-.516.073-.213.11-.48.11-.797V13h-1.14c-.14 0-.284.026-.43.078-.14.047-.27.133-.383.258-.11.125-.2.294-.274.508-.067.213-.1.487-.1.82 0 .34.035.47.108.695.08.218.175.395.29.53.12.136.247.232.383.29.14.05.276.077.406.077m-2.97-7.84c-.37.082-.695.247-.976.45-.28.198-.505.47-.672.813-.16.343-.242.78-.242 1.312V18H6v-7.188c0-.776.15-1.455.453-2.04.302-.587.714-1.077 1.234-1.467.52-.39 1.13-.685 1.83-.883.697-.198 1.44-.297 2.225-.297.526 0 1.04.044 1.54.133.504.088.98.22 1.43.398.447.172.858.388 1.233.65.375.26.698.564.97.913.275.348.49.738.64 1.17.15.433.226 1.094.226 1.61h1.353v2.04H17.78v1.6c0 .58-.103 1.092-.31 1.54-.21.442-.49.815-.845 1.117-.35.302-.834.53-1.297.687-.464.15-.953.226-1.47.226-.51 0-.996-.078-1.46-.234-.464-.156-.87-.39-1.22-.703-.348-.313-.626-.703-.835-1.172-.203-.473-.304-1.028-.304-1.663s.105-1.182.32-1.64c.213-.46.497-.685.85-.977.355-.297.76-.513 1.22-.648.458-.14.935-.21 1.43-.21h1.132c-.01-.49-.04-1.043-.242-1.36-.198-.323-.453-.58-.766-.766-.312-.193-.598-.332-.984-.426-.374-.09-.577-.094-1.1-.094-.52 0-.64.02-1.01.102z"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/bold-b.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/bold-b.svg
deleted file mode 100644
index 4f648203..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/bold-b.svg
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="bold-b">
- <path id="b" d="M7 18h6c2 0 4-1 4-3 0-1.064.011-1.975-1.989-3 2-.975 1.989-1.935 1.989-3 0-2-2-3-4-3h-6v12zm7-8c0 1.001 0 1-2 1h-2v-3h2c2 0 2 0 2 1v1zm-2 6h-2v-3h2c2 0 2 0 2 1v1s0 1-2 1z"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/bold-cyrl-be.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/bold-cyrl-be.svg
deleted file mode 100644
index 279466d4..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/bold-cyrl-be.svg
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="bold-cyrl-be">
- <path id="cyrl-be" d="M7 6h9v2h-6v3h2.649c.893 0 1.633.109 2.22.327.588.218 1.088.622 1.502 1.211.419.589.629 1.187.629 1.978 0 .813-.21 1.398-.629 1.977-.419.578-.898.974-1.437 1.187-.533.213-1.295.319-2.286.319h-5.649m4.767-2c.751 0 1.279-.049 1.584-.12.305-.076.569-.246.792-.508.229-.262.343-.473.343-.855 0-.557-.199-.868-.596-1.119-.392-.256-1.064-.398-2.016-.398h-1.873v3"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/bold-cyrl-te.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/bold-cyrl-te.svg
deleted file mode 100644
index fdeeb6c5..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/bold-cyrl-te.svg
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="bold-cyrl-te">
- <path id="te" d="M11 18v-10h-4v-2h11v2h-4v10"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/bold-cyrl-zhe.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/bold-cyrl-zhe.svg
deleted file mode 100644
index 5996c813..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/bold-cyrl-zhe.svg
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="bold-cyrl-zhe">
- <path id="cyrl-zhe" d="M13 6v5.154c.328-.033.537-.181.705-.447.168-.266.401-.873.698-1.821.39-1.241.789-2.033 1.197-2.374.403-.336 1.075-.504 2.014-.504l.386-.008v1.78l-.386-.008c-.399 0-.691.062-.878.187-.186.119-.337.304-.452.553-.115.249-.286.762-.512 1.537-.12.412-.25.756-.392 1.033-.137.276-.383.537-.738.78.439.157.8.466 1.084.927.288.455.603 1.103.944 1.943l1.33 3.268h-2.314l-1.17-3.081-.113-.252-.239-.561c-.248-.569-.452-.932-.612-1.089-.16-.157-.317-.236-.552-.236v5.22h-2v-5.22c-.226 0-.382.076-.546.228-.164.152-.368.518-.612 1.098l-.246.561-.113.252-1.17 3.081h-2.314l1.33-3.268c.328-.808.636-1.447.924-1.919.293-.477.663-.794 1.11-.951-.355-.244-.603-.501-.745-.772-.137-.276-.268-.623-.392-1.041-.222-.759-.39-1.266-.505-1.52-.111-.255-.261-.444-.452-.569-.186-.125-.492-.187-.917-.187l-.352.008v-1.78l.386.008c.953 0 1.631.171 2.034.512.399.347.791 1.136 1.177 2.366.301.954.534 1.564.698 1.829.168.26.377.406.705.439v-5.154"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/bold-f.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/bold-f.svg
deleted file mode 100644
index 357d2e5d..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/bold-f.svg
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="bold-f">
- <path id="f" d="M16 8v-2h-8v12h3v-5h4v-2h-4v-3z"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/bold-g.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/bold-g.svg
deleted file mode 100644
index e032542e..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/bold-g.svg
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="bold-g">
- <path id="g" d="M12 14v-2h5v4.203c-.497.475-1.22.894-2.166 1.259-.941.359-1.896.538-2.864.538-1.23 0-2.303-.253-3.217-.76-.915-.512-1.602-1.24-2.062-2.185-.46-.95-.69-1.982-.69-3.095 0-1.208.257-2.282.77-3.222.513-.939 1.265-1.66 2.255-2.161.754-.385 1.693-.578 2.816-.578 1.46 0 2.6.303 3.418.91.824.602 1.353 1.435 1.589 2.501l-2.359.435c-.166-.57-.479-1.018-.939-1.346-.455-.332-1.024-.499-1.709-.499-1.038 0-1.864.325-2.479.974-.61.649-.915 1.612-.915 2.889 0 1.377.31 2.412.931 3.103.62.686 1.433 1.029 2.439 1.029.497 0 .995-.095 1.492-.285.503-.195 1.332-.571 1.691-.845v-.867"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/bold-geor-man.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/bold-geor-man.svg
deleted file mode 100644
index b211bf7a..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/bold-geor-man.svg
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="bold-geor-man">
- <path id="geor-man" d="M13.832 14.061c0-1.715-.394-2.573-1.182-2.573-.868 0-1.302.779-1.302 2.338-.01 1.624.421 2.436 1.295 2.436.793 0 1.189-.734 1.189-2.201m2.168 0c0 2.626-1.116 3.939-3.349 3.939-2.434 0-3.651-1.386-3.651-4.159 0-2.738 1.217-4.106 3.651-4.106.841 0 1.182.63 1.182.63v-1.579c0-.789-.449-1.184-1.347-1.184-.572 0-.858.374-.858 1.123h-2.341c.005-1.817 1.064-2.725 3.176-2.725 2.368 0 3.548.946 3.538 2.839"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/bold-l.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/bold-l.svg
deleted file mode 100644
index 16797938..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/bold-l.svg
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="bold-l">
- <path id="l" d="M8 18v-12h3v10h5v2"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/bold-n.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/bold-n.svg
deleted file mode 100644
index 73ad019a..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/bold-n.svg
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="bold-n">
- <path id="n" d="M7 18v-12h3l4 8v-8h3v12h-3l-4-8v8h-3"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/bold-v.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/bold-v.svg
deleted file mode 100644
index 146943a5..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/bold-v.svg
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="bold-v">
- <path id="v" d="M10.5 18l-4.5-12h3l3 8 3-8h3l-4.5 12"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/book-ltr.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/book-ltr.svg
deleted file mode 100644
index 7a058ed3..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/book-ltr.svg
+++ /dev/null
@@ -1,4 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <path d="M15 7c-1.7 0-3 1.3-3 3 0-1.7-1.3-3-3-3h-6v13h6c1.7 0 3 1 3 2 0-1 1.3-2 3-2h6v-13h-6zm5 12h-5c-1.7 0-2 .4-2 .4v-8.9c0-1.4 1.1-2.5 2.5-2.5h4.5v11z"/>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/book-rtl.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/book-rtl.svg
deleted file mode 100644
index 6ae47ec5..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/book-rtl.svg
+++ /dev/null
@@ -1,4 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <path d="M9 7c1.7 0 3 1.3 3 3 0-1.7 1.3-3 3-3h6v13h-6c-1.7 0-3 1-3 2 0-1-1.3-2-3-2h-6v-13h6zm-5 12h5c1.7 0 2 .4 2 .4v-8.9c0-1.4-1.1-2.5-2.5-2.5h-4.5v11z" id="path78"/>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/bookmark-ltr.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/bookmark-ltr.svg
deleted file mode 100644
index d803d6be..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/bookmark-ltr.svg
+++ /dev/null
@@ -1,4 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <path d="M15 5h-7c-1.1 0-2 .9-2 2v3h3v11l4-3 4 3v-14c0-1.1-.9-2-2-2zm-6 4h-2v-2c0-.6.4-1 1-1h1v3z"/>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/bookmark-rtl.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/bookmark-rtl.svg
deleted file mode 100644
index 744d0f4e..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/bookmark-rtl.svg
+++ /dev/null
@@ -1,4 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <path d="M8 5h7c1.1 0 2 .9 2 2v3h-3v11l-4-3-4 3v-14c0-1.1.9-2 2-2zm6 4h2v-2c0-.6-.4-1-1-1h-1v3z" id="path88"/>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/browser-ltr.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/browser-ltr.svg
deleted file mode 100644
index 7bd04250..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/browser-ltr.svg
+++ /dev/null
@@ -1,4 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <path d="M3 6v11c0 1.7 1.3 3 3 3h15v-14h-18zm2.5 1c.8 0 1.5.7 1.5 1.5s-.7 1.5-1.5 1.5-1.5-.7-1.5-1.5.7-1.5 1.5-1.5zm14.5 12h-14c-1.1 0-2-.9-2-2v-6h16v8z"/>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/browser-rtl.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/browser-rtl.svg
deleted file mode 100644
index 84b18dae..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/browser-rtl.svg
+++ /dev/null
@@ -1,4 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <path d="M21 6v11c0 1.7-1.3 3-3 3h-15v-14h18zm-2.5 1c-.8 0-1.5.7-1.5 1.5s.7 1.5 1.5 1.5 1.5-.7 1.5-1.5-.7-1.5-1.5-1.5zm-14.5 12h14c1.1 0 2-.9 2-2v-6h-16v8z" id="path98"/>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/cancel.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/cancel.svg
deleted file mode 100644
index bfc1b44b..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/cancel.svg
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="cancel">
- <path id="circle-with-strike" d="M11.999 5.022c-3.853 0-6.977 3.124-6.977 6.978 0 3.853 3.124 6.978 6.977 6.978 3.854 0 6.979-3.125 6.979-6.978 0-3.854-3.125-6.978-6.979-6.978zm-5.113 6.978c0-1.092.572-3.25.93-2.929l7.113 7.113c.488.525-1.837.931-2.93.931-2.825-.001-5.113-2.291-5.113-5.115zm9.298 2.929l-7.114-7.113c-.445-.483 1.837-.931 2.929-.931 2.827 0 5.115 2.289 5.115 5.114 0 1.093-.364 3.543-.93 2.93z"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/caret-ltr.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/caret-ltr.svg
deleted file mode 100644
index f31ec095..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/caret-ltr.svg
+++ /dev/null
@@ -1,4 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <path d="M7 13.1l8.9 8.9c.8-.8.8-2 0-2.8l-6.1-6.1 6-6.1c.8-.8.8-2 0-2.8l-8.8 8.9z"/>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/caret-rtl.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/caret-rtl.svg
deleted file mode 100644
index 02b4e387..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/caret-rtl.svg
+++ /dev/null
@@ -1,4 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <path d="M16.5 13.1l-8.9 8.9c-.8-.8-.8-2 0-2.8l6.1-6.1-6-6.1c-.8-.8-.8-2 0-2.8l8.8 8.9z" id="path108"/>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/caretDown.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/caretDown.svg
deleted file mode 100644
index a04ca572..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/caretDown.svg
+++ /dev/null
@@ -1,4 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <path d="M12 16l8.9-8.9c-.8-.8-2-.8-2.8 0l-6.1 6.1-6.1-6c-.8-.8-2-.8-2.8 0l8.9 8.8z" id="path4"/>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/caretUp.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/caretUp.svg
deleted file mode 100644
index d0e0c283..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/caretUp.svg
+++ /dev/null
@@ -1,4 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <path d="M12 6.5l8.9 8.9c-.8.8-2 .8-2.8 0l-6.1-6.1-6.1 6c-.8.8-2 .8-2.8 0l8.9-8.8z" id="path4"/>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/case-sensitive.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/case-sensitive.svg
deleted file mode 100644
index 824790c5..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/case-sensitive.svg
+++ /dev/null
@@ -1,7 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="regular-expression">
- <path id="upper-case" d="M 7.53125,7 4,17 l 2.0625,0 0.71875,-2.40625 3.625,0 L 11.125,17 13.1875,17 9.65625,7 7.53125,7 z M 8.59375,8.53125 9.9375,13 7.25,13 8.59375,8.53125 z" />
- <path id="lower-case" d="m 18.548697,17 -0.183254,-1.035072 -0.05451,0 c -0.349771,0.440361 -0.710892,0.746796 -1.083366,0.919307 -0.367941,0.167972 -0.849436,0.251959 -1.444489,0.251959 -0.564328,0 -0.954665,-0.20883 -1.377109,-0.626492 -0.417903,-0.417659 -0.626854,-1.012371 -0.626853,-1.784137 -1e-6,-0.80808 0.281628,-1.402791 0.844889,-1.784137 0.567801,-0.385878 1.193222,-0.607062 2.208372,-0.640111 l 1.321843,-0.04086 0,-0.333674 c 0,-0.771759 -0.395195,-1.15764 -1.185571,-1.157647 -0.608688,7e-6 -1.324118,0.183867 -2.146293,0.551584 L 14.134181,9.9184512 c 0.876685,-0.4585114 1.848761,-0.6877705 2.916233,-0.6877783 1.022038,7.8e-6 1.586855,0.2224573 2.131951,0.6673492 C 19.727448,10.342928 20,11.019356 20,11.927309 l 0,5.073215 -1.451303,0 m -0.394476,-3.527417 -0.804008,0.02724 c -0.604145,0.01816 -1.053844,0.127119 -1.349098,0.326866 -0.29526,0.199753 -0.442889,0.503919 -0.442886,0.912498 -3e-6,0.585634 0.336136,0.878451 1.008417,0.878449 0.481492,2e-6 0.865326,-0.138462 1.151503,-0.415391 0.29071,-0.276925 0.436067,-0.644648 0.436072,-1.103169 l 0,-0.626491" />
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/check.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/check.svg
deleted file mode 100644
index cf7858ba..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/check.svg
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="check">
- <path d="M17 7.5L9.5 15 6 11.5 4.5 13l5 5L20 7.5c-.706-.706-2.294-.706-3 0z"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/circle.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/circle.svg
deleted file mode 100644
index 436259e5..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/circle.svg
+++ /dev/null
@@ -1,2 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><circle cx="12" cy="12" r="6"></circle></svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/citeArticle-ltr.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/citeArticle-ltr.svg
deleted file mode 100644
index 28ba0cb5..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/citeArticle-ltr.svg
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g>
- <path d="M7 12h9v-1h-9v1zm0 2h9v-1h-9v1zm0 2h9v-1h-9v1zm4-9h-4v1h4v-1zm0 2h-4v1h4v-1zm0-4h-4v1h4v-1zm5-2h2v16h-10c-1.7 0-3-1.3-3-3v-13h8v7l1.5-2 1.5 2v-7z"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/citeArticle-rtl.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/citeArticle-rtl.svg
deleted file mode 100644
index 7625307c..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/citeArticle-rtl.svg
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="g128">
- <path d="M16 12h-9v-1h9v1zm0 2h-9v-1h9v1zm0 2h-9v-1h9v1zm-4-9h4v1h-4v-1zm0 2h4v1h-4v-1zm0-4h4v1h-4v-1zm-5-2h-2v16h10c1.7 0 3-1.3 3-3v-13h-8v7l-1.5-2-1.5 2v-7z" id="path130"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/clear.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/clear.svg
deleted file mode 100644
index 55a26c97..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/clear.svg
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="clear">
- <path id="circle-with-cross" d="M12 5c-4.4 0-8 3.6-8 8s3.6 8 8 8 8-3.6 8-8-3.6-8-8-8zm4 11l-1 1-3-3-3 3-1-1 3-3-3-3 1-1 3 3 3-3 1 1-3 3 3 3z"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/clock.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/clock.svg
deleted file mode 100644
index 1cf72670..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/clock.svg
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g>
- <path d="M12 5c-4.4 0-8 3.6-8 8s3.6 8 8 8 8-3.6 8-8-3.6-8-8-8zm3 12l-4-3v-6h2v5l1.7 1.2c1.3.9 1 1.9.3 2.8z"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/close-ltr.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/close-ltr.svg
deleted file mode 100644
index 4f0f64ec..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/close-ltr.svg
+++ /dev/null
@@ -1,4 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <path d="M18.4 8.1c.8-.8.8-2 0-2.8l-6.4 6.5-5.6-5.6-1.4 1.4 5.6 5.6-5 5c-.8.8-.8 2 0 2.8l6.4-6.4 5.6 5.6 1.4-1.4-5.6-5.6 5-5.1z"/>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/close-rtl.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/close-rtl.svg
deleted file mode 100644
index d9829d0e..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/close-rtl.svg
+++ /dev/null
@@ -1,4 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <path d="M5.6 8.1c-.8-.8-.8-2 0-2.8l6.4 6.5 5.6-5.6 1.4 1.4-5.6 5.6 5 5c.8.8.8 2 0 2.8l-6.4-6.4-5.6 5.6-1.4-1.4 5.6-5.6-5-5.1z" id="path140"/>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/code.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/code.svg
deleted file mode 100644
index 32f140d9..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/code.svg
+++ /dev/null
@@ -1,7 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="24" height="24" viewBox="0 0 24 24">
- <g id="code">
- <path id="left-bracket" d="M4 12v-1h1c1 0 1 0 1-1v-2.386c0-.514.024-.896.073-1.142.054-.252.139-.463.257-.633.204-.279.473-.475.808-.584.335-.115.872-.255 1.835-.255h1.027v1h-.752c-.457 0-.77.191-.936.408-.167.215-.312.445-.312 1.068v1.857c0 .729-.041 1.18-.244 1.493-.2.307-.562.529-1.09.667.535.155.9.385 1.096.688.199.303.238.757.238 1.484v1.862c0 .619.145.848.312 1.062.166.22.479.407.936.407l.752.004v1h-1.027c-.963 0-1.5-.133-1.835-.248-.335-.109-.604-.307-.808-.591-.118-.165-.203-.374-.257-.625-.049-.253-.073-.636-.073-1.149v-2.387c0-1 0-1-1-1h-1z"/>
- <use transform="matrix(-1 0 0 1 24 0)" id="right-bracket" width="24" height="24" xlink:href="#left-bracket"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/collapse.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/collapse.svg
deleted file mode 100644
index 55aa8f8f..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/collapse.svg
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="collapse">
- <path id="arrow" d="M6.697 15.714l5.303-5.302 5.303 5.302 1.414-1.414-6.717-6.717-6.717 6.717z"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/comment.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/comment.svg
deleted file mode 100644
index 0ae7e63f..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/comment.svg
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="comment">
- <path id="speech-bubble" d="M15 6h-6c-1.657 0-3 1.344-3 3v4c0 1.656 1.343 3 3 3v3l3-3h3c1.657 0 3-1.344 3-3v-4c0-1.656-1.343-3-3-3z"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/die-ltr.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/die-ltr.svg
deleted file mode 100644
index eb4c360d..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/die-ltr.svg
+++ /dev/null
@@ -1,4 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <path d="M16 5h-12v12c0 1.6 1.3 3 3 3h12v-12c0-1.7-1.4-3-3-3zm-8.5 12c-.8 0-1.5-.7-1.5-1.5s.7-1.5 1.5-1.5 1.5.7 1.5 1.5-.7 1.5-1.5 1.5zm0-6c-.8 0-1.5-.7-1.5-1.5s.7-1.5 1.5-1.5 1.5.7 1.5 1.5-.7 1.5-1.5 1.5zm4 3c-.8 0-1.5-.7-1.5-1.5s.7-1.5 1.5-1.5 1.5.7 1.5 1.5-.7 1.5-1.5 1.5zm4 3c-.8 0-1.5-.7-1.5-1.5s.7-1.5 1.5-1.5 1.5.7 1.5 1.5-.7 1.5-1.5 1.5zm0-6c-.8 0-1.5-.7-1.5-1.5s.7-1.5 1.5-1.5 1.5.7 1.5 1.5-.7 1.5-1.5 1.5z"/>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/die-rtl.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/die-rtl.svg
deleted file mode 100644
index e929fdb1..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/die-rtl.svg
+++ /dev/null
@@ -1,4 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <path d="M7 5h12v12c0 1.6-1.3 3-3 3h-12v-12c0-1.7 1.4-3 3-3zm8.5 12c.8 0 1.5-.7 1.5-1.5s-.7-1.5-1.5-1.5-1.5.7-1.5 1.5.7 1.5 1.5 1.5zm0-6c.8 0 1.5-.7 1.5-1.5s-.7-1.5-1.5-1.5-1.5.7-1.5 1.5.7 1.5 1.5 1.5zm-4 3c.8 0 1.5-.7 1.5-1.5s-.7-1.5-1.5-1.5-1.5.7-1.5 1.5.7 1.5 1.5 1.5zm-4 3c.8 0 1.5-.7 1.5-1.5s-.7-1.5-1.5-1.5-1.5.7-1.5 1.5.7 1.5 1.5 1.5zm0-6c.8 0 1.5-.7 1.5-1.5s-.7-1.5-1.5-1.5-1.5.7-1.5 1.5.7 1.5 1.5 1.5z" id="path150"/>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/downTriangle.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/downTriangle.svg
deleted file mode 100644
index 7bc1c228..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/downTriangle.svg
+++ /dev/null
@@ -1,4 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <path d="M12 18l8-10h-16z"/>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/download-ltr.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/download-ltr.svg
deleted file mode 100644
index d0d5bb5b..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/download-ltr.svg
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g>
- <path d="M16 11h-3v-7c-1.7 0-3 1.3-3 3v4h-3l4.5 5 4.5-5zm1 2v5h-10c-.6 0-1-.4-1-1v-4h-2v4c0 1.9 1.3 3 3 3h12v-7h-2z"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/download-rtl.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/download-rtl.svg
deleted file mode 100644
index 9abb2ae4..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/download-rtl.svg
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="g160">
- <path d="M7 11h3v-7c1.7 0 3 1.3 3 3v4h3l-4.5 5-4.5-5zm-1 2v5h10c.6 0 1-.4 1-1v-4h2v4c0 1.9-1.3 3-3 3h-12v-7h2z" id="path162"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/edit-ltr.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/edit-ltr.svg
deleted file mode 100644
index 3972e070..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/edit-ltr.svg
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="Layer_3">
- <path d="M17 2l-12 12-1 5 5-1 12-12c0-2-2-4-4-4zm-9.8 13.5c-.3-.3-.7-.6-1-.8 2.3-2.3 11.3-11.4 11.3-11.4.4.1.7.3 1 .7l-11.3 11.5z"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/edit-rtl.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/edit-rtl.svg
deleted file mode 100644
index 978b2fd1..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/edit-rtl.svg
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="Layer_3">
- <path d="M8 2l12 12 1 5-5-1-12-12c0-2 2-4 4-4zm9.8 13.5c.3-.3.7-.6 1-.8-2.3-2.3-11.3-11.4-11.3-11.4-.4.1-.7.3-1 .7l11.3 11.5z" id="path173"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/editLock-ltr.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/editLock-ltr.svg
deleted file mode 100644
index 7e376824..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/editLock-ltr.svg
+++ /dev/null
@@ -1,8 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="Layer_2">
- <g id="g184">
- <path d="M21 4v-1s0-3-3-3-3 3-3 3v1h-1v6h8v-6zm-1.5 0h-3v-1s0-1.5 1.5-1.5c1.48.06 1.5 1.5 1.5 1.5zm-6.5 5.6l-6.8 6.9c-.3-.3-.7-.6-1-.8 1.4-1.4 5-5 7.8-7.9v-1.8l-9 9-1 5 5-1 8-8h-3z" id="path186"/>
- </g>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/editLock-rtl.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/editLock-rtl.svg
deleted file mode 100644
index 0b4751d2..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/editLock-rtl.svg
+++ /dev/null
@@ -1,8 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="Layer_2">
- <g id="g184">
- <path d="M4 4v-1s0-3 3-3 3 3 3 3v1h1v6h-8v-6zm1.5 0h3v-1s0-1.5-1.5-1.5c-1.48.06-1.5 1.5-1.5 1.5zm6.5 5.6l6.8 6.9c.3-.3.7-.6 1-.8-1.4-1.4-5-5-7.8-7.9v-1.8l9 9 1 5-5-1-8-8h3z" id="path186"/>
- </g>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/editUndo-ltr.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/editUndo-ltr.svg
deleted file mode 100644
index f346874e..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/editUndo-ltr.svg
+++ /dev/null
@@ -1,11 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="g196">
- <g id="g198">
- <path d="M14.9 2.8c.9 0 1.8.2 2.7.6.9.4 1.6.9 1.9 1.6-2.8.1-5 1.1-6.6 3.1l1.3 2-6.7-.3.5-6.8 1.7 2c1.8-1.5 3.5-2.2 5.2-2.2z" id="path200"/>
- </g>
- </g>
- <g id="g204">
- <path d="M15.2 11.1l-2.6-.1-5.4 5.5c-.3-.3-.7-.6-1-.8.9-.9 2.8-2.8 4.7-4.8h-1.8l-4.1 4.1-1 5 5-1 7.8-7.8-1.6-.1zm5.4-5.1c-1.7 0-3.2.5-4.4 1.4l-.9.9.8 1.3.9 1.4 4-4c0-.3-.1-.7-.2-1h-.2z" id="path206"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/editUndo-rtl.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/editUndo-rtl.svg
deleted file mode 100644
index 5b59d452..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/editUndo-rtl.svg
+++ /dev/null
@@ -1,11 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="g196">
- <g id="g198">
- <path d="M10.1 2.8c-.9 0-1.8.2-2.7.6-.9.4-1.6.9-1.9 1.6 2.8.1 5 1.1 6.6 3.1l-1.3 2 6.7-.3-.5-6.8-1.7 2c-1.8-1.5-3.5-2.2-5.2-2.2z" id="path200"/>
- </g>
- </g>
- <g id="g204">
- <path d="M9.8 11.1l2.6-.1 5.4 5.5c.3-.3.7-.6 1-.8-.9-.9-2.8-2.8-4.7-4.8h1.8l4.1 4.1 1 5-5-1-7.8-7.8 1.6-.1zm-5.4-5.1c1.7 0 3.2.5 4.4 1.4l.9.9-.8 1.3-.9 1.4-4-4c0-.3.1-.7.2-1h.2z" id="path206"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/ellipsis.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/ellipsis.svg
deleted file mode 100644
index dd36a30d..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/ellipsis.svg
+++ /dev/null
@@ -1,14 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g>
- <g>
- <path d="M8 13c0 .6-.2 1-.6 1.4-.4.4-.9.6-1.4.6-.6 0-1-.2-1.4-.6-.4-.4-.6-.9-.6-1.4s.2-1 .6-1.4c.4-.4.9-.6 1.4-.6s1 .2 1.4.6c.4.4.6.9.6 1.4z"/>
- </g>
- <g>
- <path d="M14 13c0 .6-.2 1-.6 1.4-.4.4-.9.6-1.4.6-.6 0-1-.2-1.4-.6-.4-.4-.6-.9-.6-1.4s.2-1 .6-1.4c.4-.4.9-.6 1.4-.6s1 .2 1.4.6c.4.4.6.9.6 1.4z"/>
- </g>
- <g>
- <path d="M20 13c0 .6-.2 1-.6 1.4-.4.4-.9.6-1.4.6-.6 0-1-.2-1.4-.6-.4-.4-.6-.9-.6-1.4s.2-1 .6-1.4c.4-.4.9-.6 1.4-.6s1 .2 1.4.6c.4.4.6.9.6 1.4z"/>
- </g>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/expand.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/expand.svg
deleted file mode 100644
index 7666b41d..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/expand.svg
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="expand">
- <path id="arrow" d="M17.303 8.283l-5.303 5.303-5.303-5.303-1.414 1.414 6.717 6.717 6.717-6.717z"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/external-link-ltr.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/external-link-ltr.svg
deleted file mode 100644
index 827bc1b1..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/external-link-ltr.svg
+++ /dev/null
@@ -1,7 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 12 12">
- <g id="external">
- <path id="box" d="M2 2h3v1h-2v6h6v-2h1v3h-8z"/>
- <path id="arrow" d="M6.211 2h3.789v3.789l-1.421-1.421-2.132 2.132-.947-.947 2.132-2.132z"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/external-link-rtl.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/external-link-rtl.svg
deleted file mode 100644
index c375ca0f..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/external-link-rtl.svg
+++ /dev/null
@@ -1,7 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 12 12">
- <g id="external">
- <path id="box" d="M7 3h2v6h-6v-2h-1v3h8v-8h-3z"/>
- <path id="arrow" d="M2 5.789l1.421-1.421 2.132 2.132.947-.947-2.132-2.132 1.421-1.421h-3.789z"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/eye.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/eye.svg
deleted file mode 100644
index fa3bc3c1..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/eye.svg
+++ /dev/null
@@ -1,7 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="g4">
- <path d="M12 8c-5 0-11 6-11 6s6 6 11 6 11-6 11-6-6-6-11-6zm0 10c-2.2 0-4-1.8-4-4s1.8-4 4-4 4 1.8 4 4-1.8 4-4 4z" id="path6"/>
- <circle cx="12" cy="14" r="2" id="circle8"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/eyeClosed.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/eyeClosed.svg
deleted file mode 100644
index fa1167df..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/eyeClosed.svg
+++ /dev/null
@@ -1,4 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <path d="M19.4 12.7c.7-.8 1.2-1.7 1.4-2.7h-1.6c-.9 2.5-3.9 4.4-7.7 4.6h-.1c-3.7-.2-6.8-2.1-7.7-4.6h-1.5c.2 1 .8 1.9 1.4 2.7l-2 2 .7.7 2-2c.8.6 1.7 1.2 2.7 1.7l-1 2.8.9.3 1-2.8c1 .3 2 .6 3.1.6v3h1v-3c1.1-.1 2.2-.3 3.1-.6l1 2.8.9-.3-1-2.8c1-.4 1.9-1 2.6-1.7l2 2 .7-.7-1.9-2z"/>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/find-ltr.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/find-ltr.svg
deleted file mode 100644
index f8578cf8..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/find-ltr.svg
+++ /dev/null
@@ -1,7 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="find">
- <path id="magnifying-glass" d="m 13.65625,11 c -1.921,0 -3.5,1.54775 -3.5,3.46875 0,1.92 1.579,3.5 3.5,3.5 0.749,0 1.432,-0.25225 2,-0.65625 l 0.09375,0.15625 2.375,2.375 c 0.19,0.189 0.53425,0.15325 0.78125,-0.09375 0.247,-0.247 0.314,-0.59125 0.125,-0.78125 l -2.375,-2.375 L 16.46875,16.5 C 16.87175,15.934 17.125,15.21775 17.125,14.46875 17.124,12.54875 15.57525,11 13.65625,11 z m 0,1.65625 c 1.011306,0 1.8125,0.801194 1.8125,1.8125 0,1.011306 -0.801194,1.84375 -1.8125,1.84375 -1.011306,0 -1.84375,-0.832444 -1.84375,-1.84375 0,-1.011306 0.832444,-1.8125 1.84375,-1.8125 z" />
- <path id="text" d="M 6,5 6,7 16,7 16,5 6,5 z m 0,3 0,2 11,0 0,-2 -11,0 z m 0,3 0,2 3.53125,0 c 0.2825289,-0.797203 0.786096,-1.486208 1.4375,-2 L 6,11 z m 0,3 0,2 3.53125,0 C 9.3537004,15.520243 9.25,15.010236 9.25,14.46875 9.25,14.309811 9.2962033,14.154621 9.3125,14 L 6,14 z" />
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/find-rtl.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/find-rtl.svg
deleted file mode 100644
index 2a1e9c6f..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/find-rtl.svg
+++ /dev/null
@@ -1,7 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="find">
- <path id="magnifying-glass" d="m 11.343828,11.000025 c 1.921,0 3.5,1.54775 3.5,3.46875 0,1.92 -1.579,3.5 -3.5,3.5 -0.749,0 -1.432,-0.25225 -2,-0.65625 l -0.09375,0.15625 -2.375,2.375 c -0.19,0.189 -0.53425,0.15325 -0.78125,-0.09375 -0.247,-0.247 -0.314,-0.59125 -0.125,-0.78125 l 2.375,-2.375 0.1875,-0.09375 c -0.403,-0.566 -0.65625,-1.28225 -0.65625,-2.03125 10e-4,-1.92 1.54975,-3.46875 3.46875,-3.46875 z m 0,1.65625 c -1.011306,0 -1.8125,0.801194 -1.8125,1.8125 0,1.011306 0.801194,1.84375 1.8125,1.84375 1.011306,0 1.84375,-0.832444 1.84375,-1.84375 0,-1.011306 -0.832444,-1.8125 -1.84375,-1.8125 z" />
- <path id="text" d="M 19,5 19,7 9,7 9,5 z m 0,3 0,2 -11,0 0,-2 z m 0,3 0,2 -3.53125,0 c -0.282529,-0.797203 -0.786096,-1.486208 -1.4375,-2 z m 0,3 0,2 -3.53125,0 C 15.6463,15.520243 15.75,15.010236 15.75,14.46875 15.75,14.309811 15.703797,14.154621 15.6875,14 z" />
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/flag-ltr.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/flag-ltr.svg
deleted file mode 100644
index 6e81d2bc..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/flag-ltr.svg
+++ /dev/null
@@ -1,4 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <path d="M14 6.5v-1.5c-1.4-1.5-5.2-1.2-6 0v-1h-1v15h1v-7c.8-.8 3.4-.9 5-.5v1.5c1.2 1.5 4.3 1.2 5 0v-7c-.7.7-2.7.9-4 .5z" id="path216"/>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/flag-rtl.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/flag-rtl.svg
deleted file mode 100644
index 4b743aac..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/flag-rtl.svg
+++ /dev/null
@@ -1,4 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <path d="M11 6.5v-1.5c1.4-1.5 5.2-1.2 6 0v-1h1v15h-1v-7c-.8-.8-3.4-.9-5-.5v1.5c-1.2 1.5-4.3 1.2-5 0v-7c.7.7 2.7.9 4 .5z" id="path216"/>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/flagUndo-ltr.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/flagUndo-ltr.svg
deleted file mode 100644
index 49cdb7a2..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/flagUndo-ltr.svg
+++ /dev/null
@@ -1,16 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="g2990">
- <g id="Layer_1">
- <path id="path227" d="M14 6.5v-1.5c-1.4-1.5-5.2-1.2-6 0v-1h-1v15h1v-7c.8-.8 3.4-.9 5-.5v1.5c1.2 1.5 4.3 1.2 5 0v-7c-.7.7-2.7.9-4 .5z"/>
- </g>
- <g id="Layer_2">
- <g id="g230">
- <path id="path232" d="M17.997 1.989l.99.99-15.98 15.98-.99-.99z"/>
- </g>
- <g id="g234">
- <path id="path236" d="M16.999 1.016l.99.99-15.98 15.98-.99-.99z" fill="#fff"/>
- </g>
- </g>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/flagUndo-rtl.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/flagUndo-rtl.svg
deleted file mode 100644
index e470de42..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/flagUndo-rtl.svg
+++ /dev/null
@@ -1,16 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="g2990">
- <g id="Layer_1">
- <path id="path227" d="M11 6.5v-1.5c1.4-1.5 5.2-1.2 6 0v-1h1v15h-1v-7c-.8-.8-3.4-.9-5-.5v1.5c-1.2 1.5-4.3 1.2-5 0v-7c.7.7 2.7.9 4 .5z"/>
- </g>
- <g id="Layer_2">
- <g id="g230">
- <path id="path232" d="M7.003 1.989l-.99.99 15.98 15.98.99-.99z"/>
- </g>
- <g id="g234">
- <path id="path236" d="M8.001 1.016l-.99.99 15.98 15.98.99-.99z" fill="#fff"/>
- </g>
- </g>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/folderPlaceholder-ltr.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/folderPlaceholder-ltr.svg
deleted file mode 100644
index 63e0b1aa..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/folderPlaceholder-ltr.svg
+++ /dev/null
@@ -1,4 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <path d="M2 5v15h20v-15h-20zm15 11h-9c-.6 0-1-.4-1-1v-6h3l2 1h5v6z"/>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/folderPlaceholder-rtl.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/folderPlaceholder-rtl.svg
deleted file mode 100644
index 25bec742..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/folderPlaceholder-rtl.svg
+++ /dev/null
@@ -1,4 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <path d="M22 5v15h-20v-15h20zm-15 11h9c.6 0 1-.4 1-1v-6h-3l-2 1h-5v6z" id="path246"/>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/funnel-ltr.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/funnel-ltr.svg
deleted file mode 100644
index 191584eb..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/funnel-ltr.svg
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g>
- <path d="M11 13l-6-7h15l-6 7v7c-1.7 0-3-1.3-3-3v-4z"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/funnel-rtl.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/funnel-rtl.svg
deleted file mode 100644
index 45f2f642..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/funnel-rtl.svg
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="g256">
- <path d="M14 13l6-7h-15l6 7v7c1.7 0 3-1.3 3-3v-4z" id="path258"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/heart.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/heart.svg
deleted file mode 100644
index 6433201a..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/heart.svg
+++ /dev/null
@@ -1,4 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <path d="M15 7c-2 0-3 2-3 2s-1-2-3-2c-2.5 0-4 2-4 4 0 4 5 5 7 8 2-3 7-4 7-8 0-2-1.5-4-4-4z"/>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/help-ltr.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/help-ltr.svg
deleted file mode 100644
index bb2545c5..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/help-ltr.svg
+++ /dev/null
@@ -1,10 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="help">
- <path id="circle" d="M12.001 2.085c-5.478 0-9.916 4.438-9.916 9.916 0 5.476 4.438 9.914 9.916 9.914 5.476 0 9.914-4.438 9.914-9.914 0-5.478-4.438-9.916-9.914-9.916zm.001 18c-4.465 0-8.084-3.619-8.084-8.083 0-4.465 3.619-8.084 8.084-8.084 4.464 0 8.083 3.619 8.083 8.084 0 4.464-3.619 8.083-8.083 8.083z"/>
- <g id="question-mark">
- <path id="top" d="M11.766 6.688c-2.5 0-3.219 2.188-3.219 2.188l1.411.854s.298-.791.901-1.229c.516-.375 1.625-.625 2.219.125.701.885-.17 1.587-1.078 2.719-.953 1.186-1 3.655-1 3.655h1.969s.135-2.318 1.041-3.381c.603-.707 1.443-1.338 1.443-2.494s-1.187-2.437-3.687-2.437z"/>
- <path id="bottom" d="M11 16h2v2h-2z"/>
- </g>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/help-rtl.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/help-rtl.svg
deleted file mode 100644
index 99c7f842..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/help-rtl.svg
+++ /dev/null
@@ -1,10 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="help">
- <path id="circle" d="M11.999 2.085c5.478 0 9.916 4.438 9.916 9.916 0 5.476-4.438 9.914-9.916 9.914-5.476 0-9.914-4.438-9.914-9.914 0-5.478 4.438-9.916 9.914-9.916zm-.001 18c4.465 0 8.084-3.619 8.084-8.083 0-4.465-3.619-8.084-8.084-8.084-4.464 0-8.083 3.619-8.083 8.084 0 4.464 3.619 8.083 8.083 8.083z"/>
- <g id="question-mark">
- <path id="top" d="M12.234 6.688c2.5 0 3.219 2.188 3.219 2.188l-1.411.854s-.298-.791-.901-1.229c-.516-.375-1.625-.625-2.219.125-.701.885.17 1.587 1.078 2.719.953 1.186 1 3.655 1 3.655h-1.969s-.135-2.318-1.041-3.381c-.603-.707-1.443-1.338-1.443-2.494 0-1.156 1.187-2.437 3.687-2.437z"/>
- <path id="bottom" d="M13 16h-2v2h2z"/>
- </g>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/history.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/history.svg
deleted file mode 100644
index 35f15afe..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/history.svg
+++ /dev/null
@@ -1,7 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="history">
- <path id="clock-hands" d="M17.26 15.076s-2.385-1.935-4.005-3.062c.72-2.397 1.702-6.559 1.702-6.559s-4.35 5.363-4.877 6.699c-.463 1.168 1.459 2.209 2.346 1.678 1.9.551 4.834 1.244 4.834 1.244z"/>
- <path id="arrow" d="M12.086 2.085c-5.478 0-9.916 4.438-9.916 9.916 0 1.783.476 3.454 1.301 4.898l-2.223 2.04h5.688v-5.219l-2.066 1.896c-.55-1.088-.866-2.312-.866-3.615 0-4.465 3.619-8.084 8.084-8.084 4.464 0 8.083 3.619 8.083 8.084 0 4.464-3.619 8.083-8.083 8.083-1.145 0-2.228-.247-3.213-.678l-.833 1.634c1.235.557 2.602.874 4.045.874 5.476 0 9.914-4.438 9.914-9.914-.001-5.477-4.439-9.915-9.915-9.915z"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/image-ltr.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/image-ltr.svg
deleted file mode 100644
index bebe0a9e..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/image-ltr.svg
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g>
- <path d="M20 18l-4-4-2 2-4-4-2 1-4 5h16zm2-13v15h-20v-15h20z"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/image-rtl.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/image-rtl.svg
deleted file mode 100644
index 88e0e3c0..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/image-rtl.svg
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="g278">
- <path d="M4 18l4-4 2 2 4-4 2 1 4 5h-16zm-2-13v15h20v-15h-20z" id="path280"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/imageAdd-ltr.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/imageAdd-ltr.svg
deleted file mode 100644
index 300e4b15..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/imageAdd-ltr.svg
+++ /dev/null
@@ -1,7 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <path d="M17 12v-4h-4v-3h-13v15h20v-8h-3zm-15 6l4-5 2-1 4 4 2-2 4 4h-16z"/>
- <g>
- <path d="M24 5h-4v-4h-2v4h-4v2h4v4h2v-4h4z"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/imageAdd-rtl.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/imageAdd-rtl.svg
deleted file mode 100644
index 70e32486..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/imageAdd-rtl.svg
+++ /dev/null
@@ -1,7 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <path d="M7 12v-4h4v-3h13v15h-20v-8h3zm15 6l-4-5-2-1-4 4-2-2-4 4h16z" id="path290"/>
- <g id="g292">
- <path d="M0 5h4v-4h2v4h4v2h-4v4h-2v-4h-4z" id="path294"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/imageLock-ltr.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/imageLock-ltr.svg
deleted file mode 100644
index 8cec9f5a..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/imageLock-ltr.svg
+++ /dev/null
@@ -1,4 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <path d="M19.5 4h-3v-1s0-1.5 1.5-1.5c1.5.06 1.5 1.5 1.5 1.5zm1.5 0v-1s0-3-3-3-3 3-3 3v1h-1v6h8v-6zm-8 7v-6h-11v15h20v-9zm-9 7l4-5 2-1 4 4 2-2 4 4z" id="path304"/>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/imageLock-rtl.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/imageLock-rtl.svg
deleted file mode 100644
index 6bb78f71..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/imageLock-rtl.svg
+++ /dev/null
@@ -1,4 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <path d="M4.5 4h3v-1s0-1.5-1.5-1.5c-1.5.06-1.5 1.5-1.5 1.5zm-1.5 0v-1s0-3 3-3 3 3 3 3v1h1v6h-8v-6zm8 7v-6h11v15h-20v-9zm9 7l-4-5-2-1-4 4-2-2-4 4z" id="path304"/>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/indent-ltr.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/indent-ltr.svg
deleted file mode 100644
index ada33959..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/indent-ltr.svg
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g>
- <path d="M10 8h9v2h-9v-2zm0 3h9v2h-9v-2zm0 3h6v2h-6v-2zm11-8h-18v-2h18v2zm0 14h-18v-2h18v2zm-18-12v8l5-4-5-4z"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/indent-rtl.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/indent-rtl.svg
deleted file mode 100644
index 9afedbbd..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/indent-rtl.svg
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="g314">
- <path d="M14 8h-9v2h9v-2zm0 3h-9v2h9v-2zm0 3h-6v2h6v-2zm-11-8h18v-2h-18v2zm0 14h18v-2h-18v2zm18-12v8l-5-4 5-4z" id="path316"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/info.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/info.svg
deleted file mode 100644
index 4bdefd46..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/info.svg
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="info">
- <path id="circled-i" d="M11.499 17c-3.036 0-5.499-2.464-5.499-5.5 0-3.037 2.462-5.5 5.499-5.5 3.037 0 5.501 2.462 5.501 5.5 0 3.036-2.464 5.5-5.501 5.5zm.002-12c-3.591 0-6.501 2.91-6.501 6.5s2.91 6.5 6.501 6.5c3.588 0 6.499-2.911 6.499-6.5s-2.911-6.5-6.499-6.5zM12 10v4h1v1h-3v-1h1v-3h-1v-1zM11 8h1v1h-1z"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/insert.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/insert.svg
deleted file mode 100644
index 0833f84f..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/insert.svg
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="insert">
- <path d="M13 5h-2v6h-6v2h6v6h2v-6h6v-2h-6z" id="plus"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/italic-a.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/italic-a.svg
deleted file mode 100644
index a0e66bff..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/italic-a.svg
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="italic-a">
- <path id="a" d="M14.667 6h-1.372l-7 12h1.705l2.333-4h4l.667 4h1.667l-2-12zm-3.75 7l2.527-4.333.723 4.333h-3.25z"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/italic-arab-keheh-jeem.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/italic-arab-keheh-jeem.svg
deleted file mode 100644
index d4bff1be..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/italic-arab-keheh-jeem.svg
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="italic-arab-keheh-jeem">
- <path id="arab-keheh-jeem" d="M18.125 5.844c-1.695.555-3.297 1.162-4.594 1.938-.49.299-.774.712-.875 1.125-.064.263-.035.572.063.781.189.405.539.574.844.813l.094-.125.531.625c.14.164.343.513.469.938.137.463.08.725 0 1.125h-3.438c-.338 0-.592.007-.766-.02-.339-.053-.256-.208-.234-.34.332-.127.564-.173.938-.141.29-.494.593-.885.906-1.313-.98.037-1.878.015-2.688-.094-.346-.047-.698-.186-1.094-.156-.357.026-.768.239-1.031.719-.246.448-.434.839-.656 1.281l.75-.469c.23-.142.484-.227.719-.219.157.005.275.054.406.094-.231.205-.509.402-.719.563-.301.26-.702.688-.906 1-.403.615-.694 1.084-.875 1.781-.179.689.004 1.339.469 1.75.426.376.846.519 1.281.563.65.065 1.205.093 2-.188.657-.231 1.021-.553 1.5-.969-.883.11-1.817.089-2.531.031-.871-.07-1.268-.384-1.469-.594-.271-.283-.307-.64-.156-1.219.036-.141.097-.323.25-.531.168-.228.364-.435.594-.656.451-.436 1.011-.737 1.461-.938-.045.206-.107.443-.055.688.049.229.248.379.438.469.259.122.506.155.688.156 1.421.011 2.862 0 4.281 0 .247 0 .452-.163.594-.375.139-.208.249-.481.344-.844.131-.499.094-1.062-.094-1.625-.182-.543-.418-1.009-.719-1.406-.335-.443-.674-.829-1-1.219 1.257-.815 2.716-1.239 3.969-1.688.121-.452.224-.926.313-1.313zm-9.469 8.438c-.262.394-.584.691-.875 1 .375.286.748.556 1.094.813.335-.303.626-.674.875-.969-.39-.268-.771-.588-1.094-.844z"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/italic-arab-meem.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/italic-arab-meem.svg
deleted file mode 100644
index bfbc9bf5..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/italic-arab-meem.svg
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="italic-arab-meem">
- <path id="arab-meem" d="M16 9.729l-.93 2.19h-4.663c-.479 0-.857.122-1.135.367l-.061.11c-.184 2.016-.502 3.558-.955 4.627-.272.641-.633 1.252-1.082 1.833-.177.226-.219.186-.126-.119l.142-.504.17-.669.234-.87.002-.009.202-1.045.258-1.411.353-1.906c.191-.312.424-.638.699-.98.276-.342.589-.706.94-1.09.129-.092.697-.18 1.705-.266 1.05-.086 1.638-.183 1.765-.293l.065-.128c.007-.11-.011-.241-.054-.394-.043-.153-.12-.327-.231-.522-.22-.428-.438-.641-.654-.641-.294 0-.915.269-1.864.806-.359.208-.376.125-.051-.247 1.558-1.71 2.708-2.566 3.45-2.566.383 0 .671.131.863.394.135.195.25.599.344 1.21l.203 1.2c.106.586.242.895.409.925"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/italic-armn-sha.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/italic-armn-sha.svg
deleted file mode 100644
index 63de0f6c..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/italic-armn-sha.svg
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="italic-armn-sha">
- <path id="armn-sha" d="M11.564 7.678c-.268-.13-.578-.22-.93-.268-.35-.047-.75-.07-1.197-.07h-1.11L8.586 6h1.724c.558 0 1.042.032 1.45.095.416.063.794.173 1.136.33l4.483 2.033-.324 1.67-2.624-1.165c-.126-.058-.27-.103-.433-.134-.164-.038-.356-.057-.576-.057-.583 0-1.137.095-1.663.284-.524.19-1 .46-1.425.812-.42.35-.777.78-1.072 1.283-.294.504-.504 1.074-.63 1.71-.242 1.255-.152 2.21.268 2.868.426.652 1.19.978 2.294.978.55 0 1.045-.08 1.48-.237.437-.156.815-.377 1.136-.66.326-.29.59-.633.796-1.033.21-.4.362-.84.457-1.323l.11-.56h1.6l-.12.59c-.13.674-.356 1.288-.676 1.845-.32.55-.725 1.026-1.214 1.425-.488.394-1.053.7-1.694.922-.642.215-1.343.323-2.105.323-.767 0-1.434-.113-2-.34-.568-.225-1.025-.553-1.372-.984-.347-.436-.573-.97-.678-1.607-.105-.637-.078-1.364.08-2.184.125-.66.346-1.273.66-1.835.316-.567.697-1.066 1.144-1.496.445-.436.944-.794 1.496-1.072.55-.284 1.13-.475 1.733-.575l-.466-.23"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/italic-c.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/italic-c.svg
deleted file mode 100644
index b468deac..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/italic-c.svg
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="italic-c">
- <path id="c" d="M15.008 13.718l1.481.214c-.468 1.34-1.15 2.354-2.046 3.04-.896.686-1.901 1.029-3.015 1.029-1.359 0-2.438-.43-3.237-1.29-.794-.86-1.191-2.092-1.191-3.697 0-2.09.606-3.818 1.817-5.185 1.079-1.219 2.42-1.828 4.023-1.828 1.186 0 2.145.33 2.878.989.738.66 1.165 1.546 1.282 2.66l-1.397.135c-.148-.839-.453-1.464-.916-1.876-.458-.417-1.051-.625-1.779-.625-1.369 0-2.476.631-3.321 1.892-.733 1.087-1.099 2.377-1.099 3.871 0 1.193.282 2.103.847 2.731.565.628 1.3.942 2.206.942.774 0 1.473-.261 2.099-.784.626-.522 1.081-1.261 1.366-2.216"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/italic-d.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/italic-d.svg
deleted file mode 100644
index 92a834d9..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/italic-d.svg
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="italic-d">
- <path id="d" d="M7 18l2.462-12h3.557c.853 0 1.505.063 1.955.188.644.169 1.194.472 1.65.909.456.431.799.971 1.03 1.621.231.649.346 1.378.346 2.186 0 .966-.145 1.847-.435 2.644-.284.791-.66 1.49-1.127 2.095-.461.6-.947 1.072-1.456 1.416-.504.338-1.102.589-1.794.753-.526.126-1.172.188-1.939.188h-4.249m1.859-1.359h1.867c.842 0 1.591-.079 2.245-.237.408-.098.756-.243 1.046-.434.381-.246.727-.57 1.038-.974.408-.535.732-1.143.974-1.825.247-.688.37-1.468.37-2.341 0-.971-.166-1.716-.499-2.235-.333-.524-.756-.87-1.271-1.04-.381-.126-.974-.188-1.778-.188h-1.85l-1.907 9.274"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/italic-e.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/italic-e.svg
deleted file mode 100644
index 66a5ef5d..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/italic-e.svg
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="italic-e">
- <path id="e" d="M7 18l2.474-12h8.526l-.282 1.367h-6.947l-.75 3.633h6.09l-.282 1.367h-6.09l-.877 4.274h7.438l-.282 1.359h-9.018"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/italic-geor-kan.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/italic-geor-kan.svg
deleted file mode 100644
index 3398904d..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/italic-geor-kan.svg
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="italic-geor-kan">
- <path id="geor-kan" d="M15.057 14.663c-.441 2.225-1.834 3.337-4.178 3.337-1.919 0-2.879-.787-2.879-2.36 0-.298.036-.624.108-.977.083-.431.245-.836.488-1.217l1.241.605-.207.613c-.055.259-.083.497-.083.712 0 .972.521 1.458 1.564 1.458 1.307 0 2.101-.723 2.383-2.17l.058-.331c.044-.221.066-.425.066-.613 0-.928-.546-1.391-1.638-1.391h-1.117l.248-1.259h1.117c1.202-.005 1.908-.552 2.118-1.64.039-.182.058-.356.058-.522 0-1.143-.899-1.714-2.697-1.714l.232-1.193c2.708 0 4.062.875 4.062 2.625 0 .248-.028.516-.083.803-.204 1.093-1.051 1.825-2.54 2.195l-.033.166c1.23.199 1.845.823 1.845 1.872 0 .21-.025.433-.074.671l-.058.331"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/italic-i.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/italic-i.svg
deleted file mode 100644
index 93bec5a6..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/italic-i.svg
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="italic-i">
- <path id="i" d="M12.5 17.999l.249-.994h-1.5l2.509-10.037h1.5l.242-.967h-5l-.242.967h1.5l-2.509 10.037h-1.5l-.249.994z"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/italic-k.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/italic-k.svg
deleted file mode 100644
index d4831549..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/italic-k.svg
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="italic-k">
- <path id="k" d="M12.018 10.652l4.982-4.652h-2l-5.309 5.234 1.309-5.234h-1.5l-3 12h1.5l1.173-4.693 1.54-1.438c.287 4.131 3.287 6.131 3.287 6.131h2s-4-2-3.982-7.348z"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/italic-s.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/italic-s.svg
deleted file mode 100644
index 4f6364cb..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/italic-s.svg
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="italic-s">
- <path id="s" d="M16.474 6.589l-.302 1.526c-.522-.279-1.041-.488-1.557-.628-.511-.145-1.007-.217-1.487-.217-.935 0-1.679.204-2.231.612-.553.408-.829.95-.829 1.627 0 .372.101.658.302.86.207.196.733.408 1.58.635l.937.232c1.059.274 1.795.622 2.208 1.046.413.418.62 1.007.62 1.766 0 1.167-.46 2.117-1.379 2.851-.914.733-2.12 1.1-3.618 1.1-.615 0-1.232-.062-1.852-.186-.62-.119-1.242-.302-1.867-.55l.318-1.611c.573.356 1.147.625 1.72.806.578.181 1.154.271 1.728.271.976 0 1.759-.217 2.347-.651.589-.434.883-.999.883-1.697 0-.465-.119-.816-.356-1.054-.232-.243-.736-.462-1.511-.658l-.937-.24c-1.069-.279-1.8-.599-2.192-.961-.387-.367-.581-.878-.581-1.534 0-1.152.442-2.094 1.325-2.828.888-.739 2.043-1.108 3.463-1.108.553 0 1.1.049 1.642.147.542.098 1.085.245 1.627.442"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/journal-ltr.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/journal-ltr.svg
deleted file mode 100644
index c7e16033..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/journal-ltr.svg
+++ /dev/null
@@ -1,4 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <path d="M16 9v-1h-6v1h6zm-2 2v-1h-4v1h4zm-8-6h1v16h-1v-16zm2 0h10v13c0 1.7-1.3 3-3 3h-7v-16z"/>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/journal-rtl.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/journal-rtl.svg
deleted file mode 100644
index 2d16be37..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/journal-rtl.svg
+++ /dev/null
@@ -1,4 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <path d="M8 9v-1h6v1h-6zm2 2v-1h4v1h-4zm8-6h-1v16h1v-16zm-2 0h-10v13c0 1.7 1.3 3 3 3h7v-16z" id="path326"/>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/key-ltr.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/key-ltr.svg
deleted file mode 100644
index 8dfb89ae..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/key-ltr.svg
+++ /dev/null
@@ -1,4 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <path d="M14.5 4c-3 0-5.5 2.5-5.5 5.5 0 1 .3 1.9.7 2.8l-5.7 5.7v2h4v-2h2v-2h2l1.2-1.2c.4.1.9.2 1.3.2 3 0 5.5-2.5 5.5-5.5s-2.5-5.5-5.5-5.5zm1.5 5c-.8 0-1.5-.7-1.5-1.5s.7-1.5 1.5-1.5 1.5.7 1.5 1.5-.7 1.5-1.5 1.5z"/>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/key-rtl.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/key-rtl.svg
deleted file mode 100644
index 06392874..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/key-rtl.svg
+++ /dev/null
@@ -1,4 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <path d="M9.5 4c3 0 5.5 2.5 5.5 5.5 0 1-.3 1.9-.7 2.8l5.7 5.7v2h-4v-2h-2v-2h-2l-1.2-1.2c-.4.1-.9.2-1.3.2-3 0-5.5-2.5-5.5-5.5s2.5-5.5 5.5-5.5zm-1.5 5c.8 0 1.5-.7 1.5-1.5s-.7-1.5-1.5-1.5-1.5.7-1.5 1.5.7 1.5 1.5 1.5z" id="path336"/>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/keyboard-ltr.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/keyboard-ltr.svg
deleted file mode 100644
index ea5055c8..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/keyboard-ltr.svg
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g>
- <path d="M3 7v9c0 1.7 1.3 3 3 3h15v-12h-18zm8 2h2v2h-2v-2zm0 3h2v2h-2v-2zm-3-3h2v2h-2v-2zm0 3h2v2h-2v-2zm-1 5h-1c-.6 0-1-.4-1-1v-1h2v2zm0-3h-2v-2h2v2zm0-3h-2v-2h2v2zm9 6h-8v-2h8v2zm0-3h-2v-2h2v2zm0-3h-2v-2h2v2zm3 6h-2v-2h2v2zm0-3h-2v-2h2v2zm0-3h-2v-2h2v2z"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/keyboard-rtl.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/keyboard-rtl.svg
deleted file mode 100644
index b35d108d..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/keyboard-rtl.svg
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="g346">
- <path d="M21 7v9c0 1.7-1.3 3-3 3h-15v-12h18zm-8 2h-2v2h2v-2zm0 3h-2v2h2v-2zm3-3h-2v2h2v-2zm0 3h-2v2h2v-2zm1 5h1c.6 0 1-.4 1-1v-1h-2v2zm0-3h2v-2h-2v2zm0-3h2v-2h-2v2zm-9 6h8v-2h-8v2zm0-3h2v-2h-2v2zm0-3h2v-2h-2v2zm-3 6h2v-2h-2v2zm0-3h2v-2h-2v2zm0-3h2v-2h-2v2z" id="path348"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/language.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/language.svg
deleted file mode 100644
index 081e49a1..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/language.svg
+++ /dev/null
@@ -1,7 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="language">
- <path id="japanese" d="M17.533 9.81l.271-.59 1.041.407-.18.363c.661.271 1.101.468 1.312.589.331.211.618.514.86.905.211.393.316.846.316 1.358 0 .786-.302 1.479-.905 2.083-.604.634-1.66 1.057-3.169 1.268-.121-.361-.258-.679-.408-.95.965-.151 1.645-.333 2.037-.545.454-.21.785-.481.998-.813.21-.303.314-.663.314-1.087 0-.482-.136-.905-.407-1.269-.331-.331-.8-.589-1.402-.77-.333.634-.649 1.117-.951 1.449-.242.332-.694.906-1.358 1.721.09.393.181.709.272.951l-1.042.362-.091-.498c-.423.361-.801.617-1.133.77-.361.15-.664.226-.905.226-.303 0-.574-.136-.814-.407-.243-.301-.362-.68-.362-1.132 0-.604.136-1.147.407-1.63.241-.453.603-.89 1.086-1.313.272-.241.725-.528 1.359-.86 0-.271.03-.799.09-1.585-.514.03-.921.045-1.222.045-.393 0-.711-.015-.951-.045l-.046-1.041c.725.091 1.494.135 2.31.135 0-.149.075-.738.227-1.766l1.177.183c-.151.542-.256 1.041-.316 1.493.242-.029.543-.075.906-.136.362-.061.573-.091.634-.091s.648-.15 1.766-.453l.046 1.041c-.967.243-2.145.439-3.532.591-.062.663-.092 1.086-.092 1.266.663-.151 1.284-.225 1.857-.225zm-2.672 3.893c-.061-.481-.136-1.252-.227-2.31-.573.424-1.041.86-1.403 1.313-.303.423-.452.875-.452 1.358 0 .241.044.438.136.588.09.092.195.137.316.137.363.001.907-.361 1.63-1.086zm.771-2.763c0 .483.029 1.088.09 1.811.604-.905 1.057-1.599 1.359-2.082-.574.06-1.058.151-1.449.271z"/>
- <path id="english" d="M9.497 15.981h1.851l-3.084-8.949h-1.85l-3.081 8.949h1.85l.557-1.981h3.209l.548 1.981zm-3.489-3.377l1.331-3.782 1.344 3.782h-2.675z"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/layout-ltr.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/layout-ltr.svg
deleted file mode 100644
index 47e71b39..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/layout-ltr.svg
+++ /dev/null
@@ -1,7 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="layout-ltr">
- <path id="text" d="M5 19v-14h6v8h8v6h-14z"/>
- <path id="float" d="M13 5v6h6v-6h-6zm5 5h-4v-4h4v4z"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/layout-rtl.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/layout-rtl.svg
deleted file mode 100644
index fe9ee617..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/layout-rtl.svg
+++ /dev/null
@@ -1,7 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="layout-rtl">
- <path id="text" d="M5 19v-6h8v-8h6v14h-14z"/>
- <path id="float" d="M5 5v6h6v-6h-6zm1 1h4v4h-4v-4z"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/link-ltr.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/link-ltr.svg
deleted file mode 100644
index 841ba7d4..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/link-ltr.svg
+++ /dev/null
@@ -1,13 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Generator: Adobe Illustrator 18.1.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
-<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
- viewBox="-487 489 24 24" enable-background="new -487 489 24 24" xml:space="preserve">
-<g>
- <path d="M-471.2,493.6c-2.1,0-3.6,1.9-5.1,3.3c0.2,0,0.5-0.1,0.8-0.1c0.5,0,1,0.1,1.5,0.3c0.8-0.8,1.6-1.7,2.8-1.7
- c0.6,0,1.3,0.3,1.8,0.7c1,1,1,2.6,0,3.6l-2.6,2.6c-0.4,0.4-1.2,0.7-1.8,0.7c-1.4,0-2.1-0.9-2.6-2l-1.3,1.3c0.8,1.5,2,2.6,3.8,2.6
- c1.2,0,2.3-0.5,3-1.3l2.6-2.6c0.9-0.9,1.5-2,1.5-3.3C-467,495.5-469,493.6-471.2,493.6z M-475.5,505.7l-0.9,0.9
- c-0.4,0.4-1.2,0.7-1.8,0.7c-0.6,0-1.3-0.3-1.8-0.7c-1-1-1-2.7,0-3.6l2.6-2.6c0.4-0.4,1.2-0.7,1.8-0.7c1.4,0,2.1,1,2.6,2l1.3-1.3
- c-0.8-1.5-2-2.6-3.8-2.6c-1.2,0-2.3,0.5-3,1.3l-2.6,2.6c-1.7,1.7-1.7,4.4,0,6c1.6,1.6,4.4,1.7,5.9,0l1.9-1.9
- c-0.3,0.1-0.6,0.1-0.9,0.1C-474.7,505.9-475.1,505.9-475.5,505.7z"/>
-</g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/link-rtl.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/link-rtl.svg
deleted file mode 100644
index d4c2fd66..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/link-rtl.svg
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="g358">
- <path d="M9.025 3.6c2.1 0 3.6 1.9 5.1 3.3-.2 0-.5-.1-.8-.1-.5 0-1 .1-1.5.3-.8-.8-1.6-1.7-2.8-1.7-.6 0-1.3.3-1.8.7-1 1-1 2.6 0 3.6l2.6 2.6c.4.4 1.2.7 1.8.7 1.4 0 2.1-.9 2.6-2l1.3 1.3c-.8 1.5-2 2.6-3.8 2.6-1.2 0-2.3-.5-3-1.3l-2.6-2.6c-.9-.9-1.5-2-1.5-3.3.2-2.2 2.2-4.1 4.4-4.1zm4.3 12.1l.9.9c.4.4 1.2.7 1.8.7.6 0 1.3-.3 1.8-.7 1-1 1-2.7 0-3.6l-2.6-2.6c-.4-.4-1.2-.7-1.8-.7-1.4 0-2.1 1-2.6 2l-1.3-1.3c.8-1.5 2-2.6 3.8-2.6 1.2 0 2.3.5 3 1.3l2.6 2.6c1.7 1.7 1.7 4.4 0 6-1.6 1.6-4.4 1.7-5.9 0l-1.9-1.9c.3.1.6.1.9.1.5 0 .9 0 1.3-.2z" id="path360"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/listBullet-ltr.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/listBullet-ltr.svg
deleted file mode 100644
index 09a4ff5d..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/listBullet-ltr.svg
+++ /dev/null
@@ -1,4 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <path d="M21 7h-12v-2h12v2zm-14-1c0 1.1-.9 2-2 2s-2-.9-2-2 .9-2 2-2 2 .9 2 2zm14 7h-12v-2h12v2zm-14-1c0 1.1-.9 2-2 2s-2-.9-2-2 .9-2 2-2 2 .9 2 2zm14 7h-12v-2h12v2zm-14-1c0 1.1-.9 2-2 2s-2-.9-2-2 .9-2 2-2 2 .9 2 2z"/>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/listBullet-rtl.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/listBullet-rtl.svg
deleted file mode 100644
index 67b9dfee..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/listBullet-rtl.svg
+++ /dev/null
@@ -1,4 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <path d="M3 7h12v-2h-12v2zm14-1c0 1.1.9 2 2 2s2-.9 2-2-.9-2-2-2-2 .9-2 2zm-14 7h12v-2h-12v2zm14-1c0 1.1.9 2 2 2s2-.9 2-2-.9-2-2-2-2 .9-2 2zm-14 7h12v-2h-12v2zm14-1c0 1.1.9 2 2 2s2-.9 2-2-.9-2-2-2-2 .9-2 2z" id="path370"/>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/listNumbered-ltr.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/listNumbered-ltr.svg
deleted file mode 100644
index 87e8854e..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/listNumbered-ltr.svg
+++ /dev/null
@@ -1,4 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <path d="M21 7h-13v-2h13v2zm0 6h-13v-2h13v2zm0 6h-13v-2h13v2zm-17-15h2v4h-1v-3h-1zm-1 6v-1h3v3h-2v1h2v1h-3v-3h2v-1zm3 10h-3v-1h2v-1h-1v-1h1v-1h-2v-1h3z"/>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/listNumbered-rtl.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/listNumbered-rtl.svg
deleted file mode 100644
index 831a5fb9..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/listNumbered-rtl.svg
+++ /dev/null
@@ -1,4 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <path d="M3 7h13v-2h-13zm0 6h13v-2h-13zm0 6h13v-2h-13zm15-15h2v4h-1v-3h-1zm0 6v-1h3v3h-2v1h2v1h-3v-3h2v-1zm3 10h-3v-1h2v-1h-1v-1h1v-1h-2v-1h3z" id="path380"/>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/lock-ltr.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/lock-ltr.svg
deleted file mode 100644
index 59454922..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/lock-ltr.svg
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="g390">
- <path d="M15 8s0-3-2.5-3-2.5 3-2.5 3v1h5zm2 0v1h2v10h-10c-1.7 0-3-1.3-3-3v-7h2v-1s0-5 4.5-5 4.5 5 4.5 5z" id="path392"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/lock-rtl.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/lock-rtl.svg
deleted file mode 100644
index 0591f661..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/lock-rtl.svg
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="g390">
- <path d="M10 8s0-3 2.5-3 2.5 3 2.5 3v1h-5zm-2 0v1h-2v10h10c1.7 0 3-1.3 3-3v-7h-2v-1s0-5-4.5-5-4.5 5-4.5 5z" id="path392"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/logOut-ltr.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/logOut-ltr.svg
deleted file mode 100644
index 4af765ca..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/logOut-ltr.svg
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g>
- <path d="M15 14v3l5-4.5-5-4.5v3h-7c0 1.7 1.3 3 3 3h4zm-1-9h-10v15h10v-2h-8v-11h8v-2z"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/logOut-rtl.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/logOut-rtl.svg
deleted file mode 100644
index f72c04ad..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/logOut-rtl.svg
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="g402">
- <path d="M9 14v3l-5-4.5 5-4.5v3h7c0 1.7-1.3 3-3 3h-4zm1-9h10v15h-10v-2h8v-11h-8v-2z" id="path404"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/logo-cc.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/logo-cc.svg
deleted file mode 100644
index 124b2101..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/logo-cc.svg
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g>
- <path d="M12 6c-3.9 0-7 3.1-7 7s3.1 7 7 7 7-3.1 7-7-3.1-7-7-7zm0 13c-3.3 0-6-2.7-6-6s2.7-6 6-6 6 2.7 6 6-2.7 6-6 6zm-1.7-4.6c-.7 0-1-.4-1-1.2s.3-1.2 1-1.2c.4 0 .6.2.8.6l.9-.5c-.4-.7-1-1-1.9-1-.6 0-1.1.2-1.5.6s-.6.8-.6 1.5.2 1.2.6 1.6c.4.4.9.6 1.5.6.8 0 1.4-.4 1.9-1.1l-.9-.4c-.2.3-.5.5-.8.5zm4 0c-.7 0-1-.4-1-1.2s.3-1.2 1-1.2c.4 0 .6.2.8.6l.9-.5c-.4-.7-1-1-1.9-1-.6 0-1.1.2-1.5.6s-.6.8-.6 1.5.2 1.2.6 1.6c.4.4.9.6 1.5.6.8 0 1.4-.4 1.9-1.1l-.9-.4c-.2.3-.5.5-.8.5z"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/logo-wikimediaCommons.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/logo-wikimediaCommons.svg
deleted file mode 100644
index 079e1773..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/logo-wikimediaCommons.svg
+++ /dev/null
@@ -1,7 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g>
- <path d="M15.4 7.8c-2-.9-2.3-2.5-2.4-2.8.1.1 2 1 2 1l-3-5-3 5 2-1s0 .8.6 2.1c.8 1.5 2.2 2.2 2.2 2.2s1.6.7 2.2 1.3l-.7.7-.5-.5-.4 1.8 1.8-.4-.5-.5.7-.7c.9 1 1.5 2.3 1.6 3.8h-1v-.8l-1.5 1 1.5 1v-.8h1c-.1 1.5-.6 2.8-1.6 3.8l-.7-.7.5-.5-1.8-.4.4 1.8.5-.5.7.7c-1 .9-2.3 1.5-3.8 1.6v-1h.8l-1-1.5-1 1.5h.8v1c-1.5-.1-2.8-.6-3.8-1.6l.7-.7.5.5.4-1.8-1.8.4.5.5-.7.7c-.9-1-1.5-2.3-1.6-3.8h1v.8l1.5-1-1.5-1v.8h-1c.1-1.5.6-2.8 1.6-3.8l.7.7-.5.5 1.8.4-.4-1.8-.5.5-.7-.7-1.5-1.4c-1.5 1.4-2.5 3.5-2.5 5.8 0 4.4 3.6 8 8 8s8-3.6 8-8c0-3.2-1.9-5.9-4.6-7.2z"/>
- <circle cx="12" cy="15" r="3"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/logo-wikipedia.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/logo-wikipedia.svg
deleted file mode 100644
index 6672d9dc..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/logo-wikipedia.svg
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g>
- <path d="M22.3 6.3c0 .2 0 .3-.1.3-.7.1-1.2.5-1.6 1.1-.1.2-.2.4-.3.7l-4.6 10.1c-.1.2-.2.3-.2.3s-.1.1-.2.1c-.2 0-.4-.1-.5-.4l-2.6-5.5-2.8 5.5c-.1.3-.3.4-.5.4s-.4-.1-.5-.4l-4.3-10.1c-.3-.8-.6-1.2-.8-1.4-.2-.2-.5-.3-1-.4-.1-.1-.1-.2-.1-.3 0-.2 0-.3.1-.3h4.3c.1.1.1.2.1.3 0 .2 0 .3-.1.3-.6.1-1 .2-1.1.4-.1.2 0 .6.3 1.2l3.6 8.2h.1l2.2-4.4-1.7-3.6c-.3-.7-.6-1.2-.8-1.4s-.5-.3-.9-.4c-.1-.1-.1-.2-.1-.3 0-.2 0-.3.1-.3h3.6c.1.1.1.2.1.3 0 .2 0 .3-.1.3-.4.1-.6.2-.6.4s.1.6.4 1.2l1 1.9 1-1.9c.3-.6.5-.9.5-1.1 0-.2 0-.3-.1-.4-.1-.1-.3-.1-.5-.1l-.1-.3c0-.2 0-.3.1-.3h3c.1.1.1.2.1.3 0 .2 0 .3-.1.3-.5.1-.8.2-1.1.5-.3.3-.6.7-.8 1.3l-1.3 2.8 2.5 5.2h.1l3.7-8.1c.3-.5.3-.9.2-1.2-.1-.3-.5-.4-1.1-.5-.1-.1-.1-.2-.1-.3s0-.3.1-.3h3.7c-.2.1-.2.2-.2.3z"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/map-ltr.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/map-ltr.svg
deleted file mode 100644
index 0fc47737..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/map-ltr.svg
+++ /dev/null
@@ -1,4 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <path d="M15 6l-6-2-6 2v15l6-2 6 2 6-2v-15l-6 2zm-6.3 12.1l-4.7 1.5v-12.9l5-1.7v12.9l-.3.2zm11.3.2l-5 1.7v-12.9l.3-.1 4.7-1.6v12.9z"/>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/map-rtl.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/map-rtl.svg
deleted file mode 100644
index b33f1e39..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/map-rtl.svg
+++ /dev/null
@@ -1,4 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <path d="M9 6l6-2 6 2v15l-6-2-6 2-6-2v-15l6 2zm6.3 12.1l4.7 1.5v-12.9l-5-1.7v12.9l.3.2zm-11.3.2l5 1.7v-12.9l-.3-.1-4.7-1.6v12.9z" id="path424"/>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/mapPin.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/mapPin.svg
deleted file mode 100644
index f422c84f..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/mapPin.svg
+++ /dev/null
@@ -1,4 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <path d="M19 12c0-3.9-3.1-7-7-7s-7 3.1-7 7c0 1.4.4 2.6 1.1 3.7l5.9 7.3 5.9-7.3c.7-1.1 1.1-2.3 1.1-3.7zm-7 4c-2.2 0-4-1.8-4-4s1.8-4 4-4 4 1.8 4 4-1.8 4-4 4z" id="path4"/>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/mapPinAdd-ltr.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/mapPinAdd-ltr.svg
deleted file mode 100644
index 9a54eb6a..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/mapPinAdd-ltr.svg
+++ /dev/null
@@ -1,9 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="g434">
- <g id="g436">
- <path d="M24 4h-4v-4h-2v4h-4v2h4v4h2v-4h4z" id="path438"/>
- </g>
- </g>
- <path d="M18 11h-1v-3.9l-.1-.1h-3.9v-1.9c-.3-.1-.7-.1-1-.1-3.9 0-7 3.1-7 7 0 1.4.4 2.6 1.1 3.7l5.9 7.3 5.9-7.3c.7-1.1 1.1-2.3 1.1-3.7 0-.3 0-.7-.1-1h-.9zm-6 5c-2.2 0-4-1.8-4-4s1.8-4 4-4 4 1.8 4 4-1.8 4-4 4z" id="path440"/>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/mapPinAdd-rtl.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/mapPinAdd-rtl.svg
deleted file mode 100644
index d3e152e0..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/mapPinAdd-rtl.svg
+++ /dev/null
@@ -1,9 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="g434">
- <g id="g436">
- <path d="M0 4h4v-4h2v4h4v2h-4v4h-2v-4h-4z" id="path438"/>
- </g>
- </g>
- <path d="M6 11h1v-3.9l.1-.1h3.9v-1.9c.3-.1.7-.1 1-.1 3.9 0 7 3.1 7 7 0 1.4-.4 2.6-1.1 3.7l-5.9 7.3-5.9-7.3c-.7-1.1-1.1-2.3-1.1-3.7 0-.3 0-.7.1-1h.9zm6 5c2.2 0 4-1.8 4-4s-1.8-4-4-4-4 1.8-4 4 1.8 4 4 4z" id="path440"/>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/menu.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/menu.svg
deleted file mode 100644
index 89fd9789..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/menu.svg
+++ /dev/null
@@ -1,10 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Generator: Adobe Illustrator 18.1.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
-<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
- viewBox="-487 489 24 24" enable-background="new -487 489 24 24" xml:space="preserve">
-<g id="menu">
- <path id="lines" d="M-481,505h12c0.6,0,1,0.4,1,1v1c0,0.6-0.4,1-1,1h-12c-0.6,0-1-0.4-1-1v-1C-482,505.4-481.6,505-481,505z
- M-482,501v1c0,0.6,0.4,1,1,1h12c0.6,0,1-0.4,1-1v-1c0-0.6-0.4-1-1-1h-12C-481.6,500-482,500.4-482,501z M-482,496v1
- c0,0.6,0.4,1,1,1h12c0.6,0,1-0.4,1-1v-1c0-0.6-0.4-1-1-1h-12C-481.6,495-482,495.4-482,496z"/>
-</g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/message-ltr.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/message-ltr.svg
deleted file mode 100644
index 3f308ff7..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/message-ltr.svg
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g>
- <path d="M21 9c0-1.7-1.3-3-3-3h-15v3l9 4 9-4zm-18 2v6c0 1.7 1.3 3 3 3h15v-9l-9 4-9-4z"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/message-rtl.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/message-rtl.svg
deleted file mode 100644
index fa61aa18..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/message-rtl.svg
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="g450">
- <path d="M3 9c0-1.7 1.3-3 3-3h15v3l-9 4-9-4zm18 2v6c0 1.7-1.3 3-3 3h-15v-9l9 4 9-4z" id="path452"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/move-ltr.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/move-ltr.svg
deleted file mode 100644
index 51e6611a..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/move-ltr.svg
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="move-ltr">
- <path id="arrow" d="M8.935 7.181l5.302 5.302-5.302 5.303 1.414 1.414 6.716-6.717-6.716-6.716z"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/move-rtl.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/move-rtl.svg
deleted file mode 100644
index bcee09d9..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/move-rtl.svg
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="move-rtl">
- <path id="arrow" d="M15.065 17.786l-5.302-5.303 5.302-5.302-1.414-1.414-6.716 6.716 6.716 6.717z"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/move.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/move.svg
deleted file mode 100644
index 9063bd48..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/move.svg
+++ /dev/null
@@ -1,4 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <path d="M20 11l-4-3v2h-3v-3h2l-3-4-3 4h2v3h-3v-2l-4 3 4 3v-2h3v3h-2l3 4 3-4h-2v-3h3v2z"/>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/newWindow-ltr.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/newWindow-ltr.svg
deleted file mode 100644
index b8ea833e..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/newWindow-ltr.svg
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="g4">
- <path d="M12 5l2.5 2.5-3.5 3.5c-1.2 1.2-1.2 2.8 0 4l5.5-5.5 2.5 2.5v-7h-7zm5 12h-9c-.6 0-1-.4-1-1v-9h3l-2-2h-3v11c0 1.7 1.3 3 3 3h11v-3l-2-2v3z" id="path6"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/newWindow-rtl.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/newWindow-rtl.svg
deleted file mode 100644
index 58a9eeb2..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/newWindow-rtl.svg
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="g462">
- <path d="M12 5l-2.5 2.5 3.5 3.5c1.2 1.2 1.2 2.8 0 4l-5.5-5.5-2.5 2.5v-7h7zm-5 12h9c.6 0 1-.4 1-1v-9h-3l2-2h3v11c0 1.7-1.3 3-3 3h-11v-3l2-2v3z" id="path464"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/newline-ltr.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/newline-ltr.svg
deleted file mode 100644
index dad5f51c..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/newline-ltr.svg
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="line_return">
- <path d="M17.8 5.7c-.5 0-.9.2-1.2.5s-.5.7-.5 1.2v4.3h-5.1v-4l-6 5.5 6 5.5v-4h8v-9h-1.2z"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/newline-rtl.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/newline-rtl.svg
deleted file mode 100644
index fd758cc6..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/newline-rtl.svg
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="line_return">
- <path d="M6.2 5.7c.5 0 .9.2 1.2.5.3.3.5.7.5 1.2v4.3H13v-4l6 5.5-6 5.5v-4H5v-9h1.2z"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/newspaper-ltr.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/newspaper-ltr.svg
deleted file mode 100644
index 46471a33..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/newspaper-ltr.svg
+++ /dev/null
@@ -1,4 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <path d="M6 7v12c-.6 0-1-.4-1-1v-9h-1v9c0 1.1.9 2 2 2h15v-13h-15zm9 11h-7v-1h7v1zm0-2h-7v-1h7v1zm0-2h-7v-1h7v1zm4 4h-3v-5h3v5zm0-7h-11v-2h11v2z"/>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/newspaper-rtl.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/newspaper-rtl.svg
deleted file mode 100644
index 7564dff0..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/newspaper-rtl.svg
+++ /dev/null
@@ -1,4 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <path d="M19 7v12c.6 0 1-.4 1-1v-9h1v9c0 1.1-.9 2-2 2h-15v-13h15zm-9 11h7v-1h-7v1zm0-2h7v-1h-7v1zm0-2h7v-1h-7v1zm-4 4h3v-5h-3v5zm0-7h11v-2h-11v2z" id="path474"/>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/noWikiText-ltr.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/noWikiText-ltr.svg
deleted file mode 100644
index 601428e2..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/noWikiText-ltr.svg
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g>
- <path d="M16 14l2 2v-11h-4v2h2zm0 2l-7-7-2-2-1-1-1-1-3-3-1 1 2 2h-1v14h4v-2h-2v-10h1l2 2v10h4v-2h-2v-6l6 6h-1v2h3l4 4 1-1-4-4zm-5-9v-2h-4l2 2zm8-2v2h2v10h-2l2 2h2v-14z"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/noWikiText-rtl.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/noWikiText-rtl.svg
deleted file mode 100644
index 31785a3c..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/noWikiText-rtl.svg
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="g484">
- <path d="M8 14l-2 2v-11h4v2h-2zm0 2l7-7 2-2 1-1 1-1 3-3 1 1-2 2h1v14h-4v-2h2v-10h-1l-2 2v10h-4v-2h2v-6l-6 6h1v2h-3l-4 4-1-1 4-4zm5-9v-2h4l-2 2zm-8-2v2h-2v10h2l-2 2h-2v-14z" id="path486"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/outdent-ltr.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/outdent-ltr.svg
deleted file mode 100644
index 4264ff08..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/outdent-ltr.svg
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g>
- <path d="M10 8h9v2h-9v-2zm0 3h9v2h-9v-2zm0 3h6v2h-6v-2zm11-8h-18v-2h18v2zm0 14h-18v-2h18v2zm-18-8l5 4v-8l-5 4z"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/outdent-rtl.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/outdent-rtl.svg
deleted file mode 100644
index 2479343e..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/outdent-rtl.svg
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="g496">
- <path d="M14 8h-9v2h9v-2zm0 3h-9v2h9v-2zm0 3h-6v2h6v-2zm-11-8h18v-2h-18v2zm0 14h18v-2h-18v2zm18-8l-5 4v-8l5 4z" id="path498"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/outline-ltr.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/outline-ltr.svg
deleted file mode 100644
index 9c0ea598..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/outline-ltr.svg
+++ /dev/null
@@ -1,7 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="outline-ltr">
- <path id="text" d="M5 13h14v6h-14v-6z"/>
- <path id="float" d="M5 5v6h6v-6h-6zm5 5h-4v-4h4v4z"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/outline-rtl.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/outline-rtl.svg
deleted file mode 100644
index 2a3428e9..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/outline-rtl.svg
+++ /dev/null
@@ -1,7 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="outline-rtl">
- <path id="text" d="M19 19h-14v-6h14v6z"/>
- <path id="float" d="M13 5v6h6v-6h-6zm1 1h4v4h-4v-4z"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/photoGallery-ltr.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/photoGallery-ltr.svg
deleted file mode 100644
index 92fc07ed..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/photoGallery-ltr.svg
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g>
- <path d="M2 3h18v2h-16v12h-2v-14zm13 13l-4-4-4 5h13l-3-3-2 2zm-10-10h17v13h-17v-13z"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/photoGallery-rtl.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/photoGallery-rtl.svg
deleted file mode 100644
index d989d3d4..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/photoGallery-rtl.svg
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="g508">
- <path d="M22 3h-18v2h16v12h2v-14zm-13 13l4-4 4 5h-13l3-3 2 2zm10-10h-17v13h17v-13z" id="path510"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/picture.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/picture.svg
deleted file mode 100644
index 7400bca9..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/picture.svg
+++ /dev/null
@@ -1,8 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="picture">
- <path id="frame" d="M18 4h-12c-2-.007-3 .993-3 2.993l.014 9.007c-.014 2 .986 2.988 2.986 3h12c2-.012 2.994-1 3-3.006v-9.001c-.006-2-1-3-3-2.993zm1 13h-14v-11h14v11z"/>
- <path id="mountains" d="M6 13.5l3.5-3.5 2.328 2.312-1.312 1.094.875 1.032 4.109-3.438 2.5 2v3h-12z"/>
- <path id="sky" d="M6 12l3.516-4.156 3.046 3.172 2.938-2.016 2.5 2v-4h-12z"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/play-ltr.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/play-ltr.svg
deleted file mode 100644
index 5ce95636..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/play-ltr.svg
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g>
- <path d="M12 5c-4.4 0-8 3.6-8 8s3.6 8 8 8 8-3.6 8-8-3.6-8-8-8zm-2 12v-8l6 4-6 4z"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/play-rtl.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/play-rtl.svg
deleted file mode 100644
index 591a5d3a..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/play-rtl.svg
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="g520">
- <path d="M12 5c4.4 0 8 3.6 8 8s-3.6 8-8 8-8-3.6-8-8 3.6-8 8-8zm2 12v-8l-6 4 6 4z" id="path522"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/printer-ltr.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/printer-ltr.svg
deleted file mode 100644
index baae35e9..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/printer-ltr.svg
+++ /dev/null
@@ -1,4 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <path d="M18 8h-1v-4h-10v4h-4v6c0 1.7 1.3 3 3 3h1v3h10v-3h4v-6c0-1.7-1.3-3-3-3zm-10-3h8v3h-8v-3zm8 14h-8v-6h8v6z"/>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/printer-rtl.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/printer-rtl.svg
deleted file mode 100644
index 8294afd5..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/printer-rtl.svg
+++ /dev/null
@@ -1,4 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <path d="M6 8h1v-4h10v4h4v6c0 1.7-1.3 3-3 3h-1v3h-10v-3h-4v-6c0-1.7 1.3-3 3-3zm10-3h-8v3h8v-3zm-8 14h8v-6h-8v6z" id="path532"/>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/puzzle-ltr.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/puzzle-ltr.svg
deleted file mode 100644
index 97b77bb4..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/puzzle-ltr.svg
+++ /dev/null
@@ -1,4 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <path d="M18 9.9c-.7 0-1.4.3-1.8.9v-4.8h-4c.2-.4.4-.8.4-1.2 0-1.2-1-2.2-2.2-2.2-1.3-.1-2.3.9-2.3 2.2 0 .4.2.8.4 1.2h-4.4v3.6l.6-.1c1.4 0 2.5 1.1 2.5 2.5s-1.1 2.5-2.5 2.5c-.2 0-.4 0-.6-.1v3.6h4.9c-.5.4-.9 1-.9 1.8 0 1.2 1 2.2 2.3 2.2 1.2 0 2.2-1 2.2-2.2 0-.7-.3-1.4-.9-1.8h4.5v-4.5c.4.5 1 .9 1.8.9 1.2 0 2.2-1 2.2-2.2 0-1.3-1-2.3-2.2-2.3z" id="path542"/>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/puzzle-rtl.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/puzzle-rtl.svg
deleted file mode 100644
index 0ad5f375..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/puzzle-rtl.svg
+++ /dev/null
@@ -1,4 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <path d="M6.3 9.9c.7 0 1.4.3 1.8.9v-4.8h4c-.2-.4-.4-.8-.4-1.2 0-1.2 1-2.2 2.2-2.2 1.3-.1 2.3.9 2.3 2.2 0 .4-.2.8-.4 1.2h4.4v3.6l-.6-.1c-1.4 0-2.5 1.1-2.5 2.5s1.1 2.5 2.5 2.5c.2 0 .4 0 .6-.1v3.6h-4.9c.5.4.9 1 .9 1.8 0 1.2-1 2.2-2.3 2.2-1.2 0-2.2-1-2.2-2.2 0-.7.3-1.4.9-1.8h-4.5v-4.5c-.4.5-1 .9-1.8.9-1.2 0-2.2-1-2.2-2.2 0-1.3 1-2.3 2.2-2.3z" id="path542"/>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/quotes-ltr.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/quotes-ltr.svg
deleted file mode 100644
index b3b923e5..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/quotes-ltr.svg
+++ /dev/null
@@ -1,11 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Generator: Adobe Illustrator 18.1.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
-<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
- viewBox="-487 489 24 24" enable-background="new -487 489 24 24" xml:space="preserve">
-<g>
- <path d="M-468.9,498.1c0.2-0.1,0.5-0.2,0.6-0.5s0.2-0.5,0.2-0.9V496c-1,0.2-1.5,0.2-2.6,0.6c-0.7,0.4-1.2,0.9-1.7,1.4
- c-0.5,0.5-1.9,2.6-1.9,5.8v3.1h4.7c0.9,0,1.6-0.7,1.6-1.6v-4.7h-3.1c0,0,0.1-0.7,0.6-1.4C-470,498.7-469.5,498.3-468.9,498.1z
- M-480.1,498c-0.5,0.5-1.9,2.9-1.9,6v2.9h4.7c0.9,0,1.6-0.7,1.6-1.6v-4.7h-3.1c0,0,0.1-0.7,0.6-1.4c0.5-0.5,1-0.9,1.6-1.2
- c0.2-0.1,0.5-0.2,0.6-0.5s0.2-0.5,0.2-0.9V496c-1,0.2-1.5,0.2-2.6,0.6C-479,497-479.6,497.5-480.1,498z"/>
-</g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/quotes-rtl.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/quotes-rtl.svg
deleted file mode 100644
index b40a8ac9..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/quotes-rtl.svg
+++ /dev/null
@@ -1,11 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Generator: Adobe Illustrator 18.1.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
-<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
- viewBox="-487 489 24 24" enable-background="new -487 489 24 24" xml:space="preserve">
-<g>
- <path d="M-479.5,499.3c0.5,0.7,0.6,1.4,0.6,1.4h-3.1v4.7c0,0.9,0.7,1.6,1.6,1.6h4.7v-3.1c0-3.1-1.5-5.2-1.9-5.8
- c-0.5-0.5-1-1-1.7-1.4c-1.1-0.5-1.6-0.5-2.6-0.6v0.8c0,0.3,0.1,0.6,0.2,0.9s0.4,0.4,0.6,0.5C-480.5,498.3-480,498.7-479.5,499.3z
- M-471.7,496.6c-1.1-0.5-1.6-0.5-2.6-0.6v0.8c0,0.3,0.1,0.6,0.2,0.9s0.4,0.4,0.6,0.5c0.6,0.2,1.2,0.6,1.6,1.2
- c0.5,0.7,0.6,1.4,0.6,1.4h-3.1v4.7c0,0.9,0.7,1.6,1.6,1.6h4.7V504c0-3.1-1.5-5.4-1.9-6C-470.4,497.5-471,497-471.7,496.6z"/>
-</g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/quotesAdd-ltr.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/quotesAdd-ltr.svg
deleted file mode 100644
index 24fca8f5..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/quotesAdd-ltr.svg
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="g4">
- <path d="M3.5 8.6c-.6.7-2.5 3.4-2.5 7.4v4h6c1.1 0 2-.9 2-2v-6h-4s.1-.9.8-1.8c.6-.7 1.3-1.2 2.1-1.5.3-.1.6-.3.8-.6.2-.3.3-.7.3-1.1v-1c-1.3.2-1.9.2-3.3.8-.8.5-1.6 1.1-2.2 1.8zm15.5-3.6v-4h-2v4h-4v2h4v4h2v-4h4v-2zm-4 7s.1-.9.8-1.8l.2-.2v-2h-1.9l-.6.6c-.6.7-2.5 3.4-2.5 7.4v4h6c1.1 0 2-.9 2-2v-6h-4z" id="path6"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/quotesAdd-rtl.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/quotesAdd-rtl.svg
deleted file mode 100644
index 736f2a6d..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/quotesAdd-rtl.svg
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="g4">
- <path d="M20.5 8.6c.6.7 2.5 3.4 2.5 7.4v4h-6c-1.1 0-2-.9-2-2v-6h4s-.1-.9-.8-1.8c-.6-.7-1.3-1.2-2.1-1.5-.3-.1-.6-.3-.8-.6-.2-.3-.3-.7-.3-1.1v-1c1.3.2 1.9.2 3.3.8.8.5 1.6 1.1 2.2 1.8zm-15.5-3.6v-4h2v4h4v2h-4v4h-2v-4h-4v-2zm4 7s-.1-.9-.8-1.8l-.2-.2v-2h1.9l.6.6c.6.7 2.5 3.4 2.5 7.4v4h-6c-1.1 0-2-.9-2-2v-6h4z" id="path6"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/redirect-ltr.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/redirect-ltr.svg
deleted file mode 100644
index 884d40df..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/redirect-ltr.svg
+++ /dev/null
@@ -1,8 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="create_redirect">
- <g>
- <path d="M17.7 2.4c-.3-.3-.7-.4-1.2-.4h-12.1v16.2c0 .5.1.8.4 1.1s.7.7 1.2.7h10.2c-.6-.2-1.2-.5-1.9-1-.4-.3-.8-.6-1.2-1l-.5-.6h-6.2v-1.4h5.4s-.4-1.5-.4-2h-5v-1h9v1c.4.1 1.1.1 1.5.1.4 0 .7 0 1.1-.1v-10.5c.1-.5-.1-.9-.3-1.1zm-5.2 1.6h3v4.5h-3v-4.5zm-6.1 0h4v1.6h-4v-1.6zm0 3h4v1.5h-4v-1.5zm0 3h9v1.5h-9v-1.5zm12.7 3.1l4.9 3.8-4.9 4.8v-2.2c-1.7 0-2.9-.2-4.3-1.2-1.2-.8-2.5-2.6-2.3-4.1 1.4 1 2.9 1.5 4.4 1.5.7 0 1.4-.1 2.1-.3l.1-2.3"/>
- </g>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/redirect-rtl.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/redirect-rtl.svg
deleted file mode 100644
index a07e8364..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/redirect-rtl.svg
+++ /dev/null
@@ -1,9 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="create_redirect">
- <g id="g3264">
- <path d="M6.3 2.4c.3-.3.7-.4 1.2-.4h12.1v16.2c0 .5-.1.8-.4 1.1-.3.3-.7.7-1.2.7h-10.2c.6-.2 1.2-.5 1.9-1 .4-.3.8-.6 1.2-1l.5-.6h6.2v-1.4h-5.4s.4-1.5.4-2h5v-1h-9v1c-.4.1-1.1.1-1.5.1-.4 0-.7 0-1.1-.1v-10.5c-.1-.5.1-.9.3-1.1zm5.2 1.6h-3v4.5h3v-4.5zm6.1 0h-4v1.6h4v-1.6zm0 3h-4v1.5h4v-1.5zm0 3h-9v1.5h9v-1.5z" id="path3266"/>
- <path d="M4.9 13.1l-4.9 3.8 4.9 4.8v-2.2c1.7 0 2.9-.2 4.3-1.2 1.2-.8 2.5-2.6 2.3-4.1-1.4 1-2.9 1.5-4.4 1.5-.7 0-1.4-.1-2.1-.3l-.1-2.3" id="path3268"/>
- </g>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/regular-expression.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/regular-expression.svg
deleted file mode 100644
index 7b672618..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/regular-expression.svg
+++ /dev/null
@@ -1,9 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="regular-expression">
- <path id="left-bracket" d="m 3,12.044797 c -5e-7,-0.989171 0.150394,-1.914889 0.451184,-2.7771612 C 3.7558785,8.4053812 4.1933899,7.6495032 4.7637193,7 L 6.2286026,7 C 5.6778034,7.7204251 5.261777,8.511764 4.9805221,9.3740188 4.6992623,10.236291 4.5586337,11.122815 4.5586357,12.033598 c -2e-6,0.914522 0.1425798,1.799179 0.427746,2.653974 C 5.2754491,15.538635 5.6856161,16.309444 6.2168835,17 L 4.7637193,17 C 4.1894835,16.365435 3.7519721,15.624488 3.451184,14.777158 3.150394,13.929828 3,13.019042 3,12.044797" />
- <path id="dot" d="m 10,16 c 0,0.552285 -0.4477153,1 -1,1 -0.5522847,0 -1,-0.447715 -1,-1 0,-0.552285 0.4477153,-1 1,-1 0.5522847,0 1,0.447715 1,1 z" />
- <path id="star" d="m 14.250652,7.0127142 -0.240235,2.15625 2.185547,-0.609375 0.193359,1.4765618 -1.992187,0.140625 1.306641,1.740234 -1.330079,0.708985 -0.914062,-1.833985 -0.802734,1.822266 -1.382813,-0.697266 1.294922,-1.740234 -1.980469,-0.152343 0.228516,-1.4648438 2.138672,0.609375 -0.240235,-2.15625 1.535157,0" />
- <path id="right-bracket" d="m 21,12.044797 c -3e-6,0.981711 -0.152351,1.896229 -0.457043,2.743558 C 20.241767,15.635686 19.806209,16.3729 19.235883,17 l -1.453164,0 c 0.527356,-0.686824 0.93557,-1.455766 1.224642,-2.306829 0.289069,-0.854795 0.433604,-1.741318 0.433606,-2.659573 -2e-6,-0.910783 -0.140631,-1.797307 -0.421886,-2.6595792 C 18.737821,8.511764 18.321795,7.7204251 17.771,7 l 1.464883,0 c 0.574232,0.653236 1.011744,1.4128466 1.312536,2.2788341 0.300785,0.8622719 0.45118,1.7842569 0.451183,2.7659629" />
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/remove.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/remove.svg
deleted file mode 100644
index 6ad79174..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/remove.svg
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="remove">
- <path id="trash-can" d="M12 10h-1v6h1v-6zm-2 0h-1v6h1v-6zm4 0h-1v6h1v-6zm0-4v-1h-5v1h-3v3h1v7.966l1 1.031v-.074.077h6.984l.016-.018v.015l1-1.031v-7.966h1v-3h-3zm1 11h-7v-8h7v8zm1-9h-9v-1h9v1z"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/ribbonPrize.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/ribbonPrize.svg
deleted file mode 100644
index 6e4979f8..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/ribbonPrize.svg
+++ /dev/null
@@ -1,9 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="Layer_1">
- <g>
- <circle cx="11.5" cy="8.5" r="2.5"/>
- <path d="M16.3 8.7l.7-.7-.8-.8.4-.8-1.1-.5.1-.9-1.2-.2-.1-.9-1.2.2-.4-.8-1.1.5-.6-.8-.8.8-.9-.4-.5 1.1-.9-.2-.2 1.2-.9.2.2 1.2-.9.4.5 1.1-.6.6.8.8-.4.8 1.1.5-.1.9 1.2.2.1.9 1.2-.2.4.8 1.1-.5.6.8.8-.8.8.4.5-1.1.9.1.2-1.2.9-.1-.2-1.2.8-.4-.4-1zm-4.8 3.3c-1.9 0-3.5-1.6-3.5-3.5s1.6-3.5 3.5-3.5 3.5 1.6 3.5 3.5-1.6 3.5-3.5 3.5zm.5 3l-.7-.7-1.1.6-.4-.7-.8.3v8.5l2.5-3 2.5 3v-8.5l-1-.5z"/>
- </g>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/search-ltr.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/search-ltr.svg
deleted file mode 100644
index cdcbc30d..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/search-ltr.svg
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="search">
- <path id="magnifying-glass" d="M 10.5,4 C 6.9101491,4 4,6.9101491 4,10.5 c 0,3.589851 2.9101491,6.5 6.5,6.5 1.02211,0 1.983324,-0.235899 2.84375,-0.65625 L 16,19 c 1.4,1.4 2.5,1.5 4,0 L 15.5625,14.5625 C 16.462737,13.447115 17,12.044969 17,10.5 17,6.9101491 14.089851,4 10.5,4 z m 0,2 C 12.985281,6 15,8.0147186 15,10.5 15,12.985281 12.985281,15 10.5,15 8.0147186,15 6,12.985281 6,10.5 6,8.0147186 8.0147186,6 10.5,6 z"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/search-rtl.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/search-rtl.svg
deleted file mode 100644
index c6753493..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/search-rtl.svg
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="search">
- <path id="magnifying-glass" d="m 13.5,4 c 3.589851,0 6.5,2.9101491 6.5,6.5 0,3.589851 -2.910149,6.5 -6.5,6.5 -1.02211,0 -1.983324,-0.235899 -2.84375,-0.65625 L 8,19 C 6.6,20.4 5.5,20.5 4,19 L 8.4375,14.5625 C 7.537263,13.447115 7,12.044969 7,10.5 7,6.9101491 9.910149,4 13.5,4 z m 0,2 C 11.014719,6 9,8.0147186 9,10.5 9,12.985281 11.014719,15 13.5,15 15.985281,15 18,12.985281 18,10.5 18,8.0147186 15.985281,6 13.5,6 z"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/secure-link.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/secure-link.svg
deleted file mode 100644
index a9c7d276..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/secure-link.svg
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 12 12">
- <g id="secure">
- <path id="lock" d="M8 5h.019v-.997c.001-.057.004-1.409-.832-2.255-.434-.438-.998-.66-1.679-.66s-1.245.222-1.678.659c-.837.847-.833 2.199-.832 2.251v1.002h.002c-.553 0-1 .447-1 1v3c0 .553.447 1 1 1h5c.553 0 1-.447 1-1v-3c0-.553-.447-1-1-1zm-4.002 0v-1.007c0-.01.005-.999.543-1.543.482-.485 1.449-.487 1.932-.002.544.546.546 1.536.546 1.55v1.002h-3.021z"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/settings.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/settings.svg
deleted file mode 100644
index bcd665ee..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/settings.svg
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="settings">
- <path id="gear" d="M3 4h3v2h-3zM12 4h9v2h-9zM8 3h2c.552 0 1 .448 1 1v2c0 .552-.448 1-1 1h-2c-.552 0-1-.448-1-1v-2c0-.552.448-1 1-1zM3 11h9v2h-9zM18 11h3v2h-3zM14 10h2c.552 0 1 .448 1 1v2c0 .552-.448 1-1 1h-2c-.552 0-1-.448-1-1v-2c0-.552.448-1 1-1zM3 18h6v2h-6zM15 18h6v2h-6zM11 17h2c.552 0 1 .448 1 1v2c0 .552-.448 1-1 1h-2c-.552 0-1-.448-1-1v-2c0-.552.448-1 1-1z"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/signature-ltr.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/signature-ltr.svg
deleted file mode 100644
index 0d495049..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/signature-ltr.svg
+++ /dev/null
@@ -1,4 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <path d="M0 20h24v1h-24v-1zm6-8l-1-1-2 2-2-2-1 1 2 2-2 2 1 1 2-2 2 2 1-1-2-2zm15.6 3.7c-.9-.5-1.9-.5-2.7 0-1.5.9-3.1.4-3.1.4-.4-.2-.8-.4-1.1-.6 2.2-.6 4.4-1.8 6-3.9 1.1-1.2 2.5-3.9.4-6-.7-.7-1.6-1.1-2.7-1-1.4.1-2.8.9-3.9 2.1-.9 1.1-3.1 4.5-2.3 7.5 0 .1 0 .2.1.3-2.3.3-4.2.2-4.4.1v1.5c.7.1 2.7.2 5.1-.2.5.7 1.3 1.2 2.3 1.6.1 0 2.4.8 4.5-.6.5-.3.9-.1 1.1 0 .4.2.7.6.7 1h1.4c0-.8-.6-1.7-1.4-2.2zm-8-1.7c-.5-2.2 1.1-5.1 2-6.2.8-.9 1.8-1.5 2.8-1.6h.1c.6 0 1.1.2 1.5.6 1.6 1.6-.4 3.9-.5 4-1.5 2-3.7 3-5.8 3.5l-.1-.3z"/>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/signature-rtl.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/signature-rtl.svg
deleted file mode 100644
index 6c0ae5e0..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/signature-rtl.svg
+++ /dev/null
@@ -1,4 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <path d="M24 20h-24v1h24v-1zm-6-8l1-1 2 2 2-2 1 1-2 2 2 2-1 1-2-2-2 2-1-1 2-2zm-15.6 3.7c.9-.5 1.9-.5 2.7 0 1.5.9 3.1.4 3.1.4.4-.2.8-.4 1.1-.6-2.2-.6-4.4-1.8-6-3.9-1.1-1.2-2.5-3.9-.4-6 .7-.7 1.6-1.1 2.7-1 1.4.1 2.8.9 3.9 2.1.9 1.1 3.1 4.5 2.3 7.5 0 .1 0 .2-.1.3 2.3.3 4.2.2 4.4.1v1.5c-.7.1-2.7.2-5.1-.2-.5.7-1.3 1.2-2.3 1.6-.1 0-2.4.8-4.5-.6-.5-.3-.9-.1-1.1 0-.4.2-.7.6-.7 1h-1.4c0-.8.6-1.7 1.4-2.2zm8-1.7c.5-2.2-1.1-5.1-2-6.2-.8-.9-1.8-1.5-2.8-1.6h-.1c-.6 0-1.1.2-1.5.6-1.6 1.6.4 3.9.5 4 1.5 2 3.7 3 5.8 3.5l.1-.3z" id="path576"/>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/smaller-ltr.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/smaller-ltr.svg
deleted file mode 100644
index e8b427b1..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/smaller-ltr.svg
+++ /dev/null
@@ -1,7 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <path id="a" d="M12.666 6h-1.372l-4.48 12H8.52l1.493-4h4l1.507 4h1.666l-4.52-12zm-2.28 7l1.617-4.333L13.637 13h-3.25z"/>
- <g id="down">
- <path id="arrow" d="M22 3l-3.5 6L15 3z"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/smaller-rtl.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/smaller-rtl.svg
deleted file mode 100644
index e5e95196..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/smaller-rtl.svg
+++ /dev/null
@@ -1,7 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <path id="a" d="M12.666 6h-1.372l-4.48 12H8.52l1.493-4h4l1.507 4h1.666l-4.52-12zm-2.28 7l1.617-4.333L13.637 13h-3.25z"/>
- <g id="down">
- <path id="arrow" d="M9 3L5.5 9 2 3z"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/specialCharacter.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/specialCharacter.svg
deleted file mode 100644
index 4d601281..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/specialCharacter.svg
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="special-character">
- <path id="omega" d="M12 6.708c-.794 0-1.368.103-1.894.31-.525.207-.944.496-1.255.867-.311.366-.531.808-.66 1.327-.128.513-.192 1.08-.192 1.699 0 .513.058 1 .174 1.46.122.46.311.87.568 1.23.629.863 1.155 1.139 2.011 1.363l.247 3.035h-5v-3h.605l.531 1.354.394.053.605.044.751.035.456.009h.66l-.092-.894c-.629-.094-.811-.268-1.336-.522-.525-.26-.98-.59-1.365-.991-.379-.401-.675-.867-.889-1.398-.214-.537-.321-1.13-.321-1.779 0-.82.131-1.537.394-2.15.269-.619.656-1.133 1.163-1.54.507-.407 1.133-.711 1.878-.912.745-.206 1.6-.31 2.565-.31.959 0 1.811.103 2.556.31.751.201 1.38.504 1.887.912.507.407.892.92 1.154 1.54.269.614.403 1.33.403 2.15 0 .649-.107 1.242-.321 1.779-.214.531-.513.997-.898 1.398-.379.401-.831.732-1.356.991-.525.254-.707.428-1.336.522l-.092.894h.66l.447-.009.751-.035.605-.044.403-.053.531-1.354h.605v3h-5l.247-3.035c1.066-.11 1.337-.696 2.002-1.363.263-.36.452-.77.568-1.23.122-.46.183-.947.183-1.46 0-.619-.064-1.186-.192-1.699-.128-.519-.348-.962-.66-1.327-.311-.372-.73-.661-1.255-.867-.525-.206-1.1-.31-1.894-.31"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/speechBubble-ltr.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/speechBubble-ltr.svg
deleted file mode 100644
index f3fb8b31..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/speechBubble-ltr.svg
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g>
- <path d="M19 20h-17l3-3v-11h17v11c0 1.7-1.3 3-3 3z"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/speechBubble-rtl.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/speechBubble-rtl.svg
deleted file mode 100644
index fd9b7bd9..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/speechBubble-rtl.svg
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="g586">
- <path d="M5 20h17l-3-3v-11h-17v11c0 1.7 1.3 3 3 3z" id="path588"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/speechBubbleAdd-ltr.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/speechBubbleAdd-ltr.svg
deleted file mode 100644
index 333c1e86..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/speechBubbleAdd-ltr.svg
+++ /dev/null
@@ -1,7 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g>
- <path d="M19 20h-17l3-3v-11h17v11c0 1.7-1.3 3-3 3z"/>
- </g>
- <path fill="#fff" d="M13 9h1v7h-1zm-3 3h7v1h-7z"/>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/speechBubbleAdd-rtl.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/speechBubbleAdd-rtl.svg
deleted file mode 100644
index 4e6313f1..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/speechBubbleAdd-rtl.svg
+++ /dev/null
@@ -1,7 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="g598">
- <path d="M5 20h17l-3-3v-11h-17v11c0 1.7 1.3 3 3 3z" id="path600"/>
- </g>
- <path d="M11 9h-1v7h1zm3 3h-7v1h7z" id="path602" fill="#fff"/>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/speechBubbles-ltr.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/speechBubbles-ltr.svg
deleted file mode 100644
index c4b4a2f7..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/speechBubbles-ltr.svg
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g>
- <path d="M20 9v9l2 2h-14v-11h12zm-17-5h12v4h-8v7h-6l2-2v-9z"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/speechBubbles-rtl.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/speechBubbles-rtl.svg
deleted file mode 100644
index c452fbbd..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/speechBubbles-rtl.svg
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="g612">
- <path d="M3 9v9l-2 2h14v-11h-12zm17-5h-12v4h8v7h6l-2-2v-9z" id="path614"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/star.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/star.svg
deleted file mode 100644
index ea8c26c6..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/star.svg
+++ /dev/null
@@ -1,4 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <path d="M12 7.4l1.7 3.6 4 .5-2.7 2.8.5 3.9-3.5-1.7-3.6 1.7.6-3.9-2.8-2.8 3.9-.5 1.9-3.6m0-3.4l-2.8 5.6-6.2.9 4.5 4.4-1.1 6.1 5.6-3 5.5 3-1-6.2 4.5-4.4-6.3-.9-2.7-5.5z"/>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/stop.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/stop.svg
deleted file mode 100644
index 7bd06331..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/stop.svg
+++ /dev/null
@@ -1,4 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <path d="M12 6c3.9 0 7 3.1 7 7s-3.1 7-7 7-7-3.1-7-7 3.1-7 7-7m0-1c-4.4 0-8 3.6-8 8s3.6 8 8 8 8-3.6 8-8-3.6-8-8-8zm-3 5h6v6h-6z"/>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/strikethrough-a.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/strikethrough-a.svg
deleted file mode 100644
index 480189f5..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/strikethrough-a.svg
+++ /dev/null
@@ -1,7 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="strikethrough-a">
- <path id="strikethrough" d="M6 11h12v1h-12v-1z"/>
- <path id="a" d="M12.666 6h-1.372l-4.48 12h1.705l1.494-4h3.999l1.508 4h1.666l-4.52-12zm-2.28 7l1.617-4.333 1.634 4.333h-3.251z"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/strikethrough-s.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/strikethrough-s.svg
deleted file mode 100644
index d57b652f..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/strikethrough-s.svg
+++ /dev/null
@@ -1,7 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="strikethrough-s">
- <path id="strikethrough" d="M6 12h12v1h-12v-1z"/>
- <path id="s" d="M12.094 6c-1.133 0-2.076.287-2.75.9-.67.613-1 1.49-1 2.52 0 .889.221 1.602.719 2.13.498.528 1.279.91 2.312 1.14l.812.182v-.03c.656.147 1.128.375 1.375.63.252.256.375.607.375 1.11 0 .573-.172.97-.531 1.26-.358.291-.894.45-1.625.45-.477 0-.969-.074-1.469-.24-.502-.166-1.031-.417-1.562-.75l-.375-.238v2.158l.156.062c.58.237 1.143.417 1.688.54.549.121 1.07.18 1.562.18 1.286 0 2.297-.293 3-.9.709-.605 1.062-1.486 1.062-2.608 0-.943-.256-1.726-.781-2.312-.521-.592-1.305-1-2.344-1.229l-.812-.181c-.716-.148-1.204-.352-1.406-.539-.205-.203-.312-.485-.312-.935 0-.533.162-.899.5-1.17.342-.271.836-.42 1.531-.42.395 0 .818.052 1.25.181.433.127.908.333 1.406.6l.375.18v-2.041s-1.188-.383-1.688-.479c-.499-.098-.984-.151-1.468-.151z"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/strikethrough-y.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/strikethrough-y.svg
deleted file mode 100644
index 8409dc15..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/strikethrough-y.svg
+++ /dev/null
@@ -1,7 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="strikethrough-y">
- <path id="strikethrough" d="M6 11h12v1h-12v-1z"/>
- <path id="a" d="M7 6h1.724l3.288 4.935 3.264-4.935h1.724l-4.194 6.285v5.715h-1.612v-5.715l-4.194-6.285"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/stripeFlow-ltr.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/stripeFlow-ltr.svg
deleted file mode 100644
index acacc362..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/stripeFlow-ltr.svg
+++ /dev/null
@@ -1,4 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <path d="M4 9h12v2h-12v-2zm0 3h8v2h-8v-2zm0-7h16v3h-16v-3zm16 14h-16v-3h16v3z"/>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/stripeFlow-rtl.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/stripeFlow-rtl.svg
deleted file mode 100644
index c38a283f..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/stripeFlow-rtl.svg
+++ /dev/null
@@ -1,4 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <path d="M20 9h-12v2h12v-2zm0 3h-8v2h8v-2zm0-7h-16v3h16v-3zm-16 14h16v-3h-16v3z" id="path624"/>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/stripeSideMenu.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/stripeSideMenu.svg
deleted file mode 100644
index 47e70d74..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/stripeSideMenu.svg
+++ /dev/null
@@ -1,12 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g>
- <path d="M20 19h-16v-2h16v2z"/>
- </g>
- <g>
- <path d="M20 15h-16v-2h16v2z"/>
- </g>
- <g>
- <path d="M20 11h-16v-2h16v2z"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/stripeSummary-ltr.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/stripeSummary-ltr.svg
deleted file mode 100644
index 7f8822bc..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/stripeSummary-ltr.svg
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g>
- <path d="M20 11h-16v-2h16v2zm-16 1h8v2h-8v-2z"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/stripeSummary-rtl.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/stripeSummary-rtl.svg
deleted file mode 100644
index fcb10bad..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/stripeSummary-rtl.svg
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="g654">
- <path d="M4 11h16v-2h-16v2zm16 1h-8v2h8v-2z" id="path656"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/stripeToC-ltr.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/stripeToC-ltr.svg
deleted file mode 100644
index 76c80d20..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/stripeToC-ltr.svg
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g>
- <path d="M17 13h-13v-3h13v3zm-5 6h-8v-3h8v3zm-8-12v-3h16v3h-16z"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/stripeToC-rtl.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/stripeToC-rtl.svg
deleted file mode 100644
index 308c2e62..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/stripeToC-rtl.svg
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="g666">
- <path d="M7 13h13v-3h-13v3zm5 6h8v-3h-8v3zm8-12v-3h-16v3h16z" id="path668"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/subscript-ltr.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/subscript-ltr.svg
deleted file mode 100644
index b7507daf..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/subscript-ltr.svg
+++ /dev/null
@@ -1,5 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <path id="x" d="M14 9l-2.354 3.406L14 16h-1.2L11 13.25 9.2 16H8l2.403-3.662L8 9h1.188l1.857 2.494L12.797 9H14z"/>
- <path d="M18 13l-1 1v3l1 1h-1l-.527-.46L16 18h-1l1-1v-3l-1-1h1l.485.497L17 13z"/>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/subscript-rtl.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/subscript-rtl.svg
deleted file mode 100644
index 9fe5325f..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/subscript-rtl.svg
+++ /dev/null
@@ -1,5 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <path id="x" d="M12 9l2.354 3.406L12 16h1.2l1.8-2.75L16.8 16H18l-2.403-3.662L18 9h-1.188l-1.857 2.494L13.203 9H12z"/>
- <path d="M8 13l1 1v3l-1 1h1l.527-.46L10 18h1l-1-1v-3l1-1h-1l-.485.497L9 13z"/>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/sun-ltr.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/sun-ltr.svg
deleted file mode 100644
index f1b7caf3..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/sun-ltr.svg
+++ /dev/null
@@ -1,5 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <path d="M18.1 5.1c0 .3-.1.6-.3.9l-1.4 1.4-.9-.8 2.2-2.2c.3.1.4.4.4.7zm-.5 5.3h3.2c0 .3-.1.6-.4.9s-.5.4-.8.4h-2v-1.3zm-6.2-5v-3.2c.3 0 .6.1.9.4s.4.5.4.8v2h-1.3zm6.4 11.7c-.3 0-.6-.1-.8-.3l-1.4-1.4.8-.8 2.2 2.2c-.2.2-.5.3-.8.3zm-11.6-12.2c.3 0 .6.1.8.3l1.4 1.4-.8.9-2.2-2.3c.2-.2.5-.3.8-.3zm5.2 11.7h1.2v3.2c-.3 0-.6-.1-.9-.4s-.4-.5-.4-.8l.1-2zm-7-6.2h2v1.2h-3.2c0-.3.1-.6.4-.9s.5-.3.8-.3zm1.8 5.6l1.4-1.4.8.8-2.2 2.2c-.2-.2-.3-.5-.3-.8s.1-.6.3-.8z"/>
- <circle cx="12" cy="11" r="4"/>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/sun-rtl.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/sun-rtl.svg
deleted file mode 100644
index a625fb90..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/sun-rtl.svg
+++ /dev/null
@@ -1,5 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <path d="M5.9 5.1c0 .3.1.6.3.9l1.4 1.4.9-.8-2.2-2.2c-.3.1-.4.4-.4.7zm.5 5.3h-3.2c0 .3.1.6.4.9.3.3.5.4.8.4h2v-1.3zm6.2-5v-3.2c-.3 0-.6.1-.9.4-.3.3-.4.5-.4.8v2h1.3zm-6.4 11.7c.3 0 .6-.1.8-.3l1.4-1.4-.8-.8-2.2 2.2c.2.2.5.3.8.3zm11.6-12.2c-.3 0-.6.1-.8.3l-1.4 1.4.8.9 2.2-2.3c-.2-.2-.5-.3-.8-.3zm-5.2 11.7h-1.2v3.2c.3 0 .6-.1.9-.4.3-.3.4-.5.4-.8l-.1-2zm7-6.2h-2v1.2h3.2c0-.3-.1-.6-.4-.9-.3-.3-.5-.3-.8-.3zm-1.8 5.6l-1.4-1.4-.8.8 2.2 2.2c.2-.2.3-.5.3-.8 0-.3-.1-.6-.3-.8z" id="path678"/>
- <circle cx="12" cy="11" r="4" id="circle680" transform="matrix(-1 0 0 1 24 0)"/>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/superscript-ltr.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/superscript-ltr.svg
deleted file mode 100644
index 39f30a76..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/superscript-ltr.svg
+++ /dev/null
@@ -1,5 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <path id="x" d="M14 9l-2.354 3.406L14 16h-1.2L11 13.25 9.2 16H8l2.403-3.662L8 9h1.188l1.857 2.494L12.797 9H14z"/>
- <path d="M18 7l-1 1v3l1 1h-1l-.527-.46L16 12h-1l1-1V8l-1-1h1l.485.497L17 7z"/>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/superscript-rtl.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/superscript-rtl.svg
deleted file mode 100644
index eabab21c..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/superscript-rtl.svg
+++ /dev/null
@@ -1,5 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <path id="x" d="M12 9l2.354 3.406L12 16h1.2l1.8-2.75L16.8 16H18l-2.403-3.662L18 9h-1.188l-1.857 2.494L13.203 9H12z"/>
- <path d="M8 7l1 1v3l-1 1h1l.527-.46L10 12h1l-1-1V8l1-1h-1l-.485.497L9 7z"/>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/table-caption.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/table-caption.svg
deleted file mode 100644
index 15bb06a6..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/table-caption.svg
+++ /dev/null
@@ -1,7 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="table-caption">
- <path id="caption" d="M6 6h12v3H6z"/>
- <path id="table" d="M4 10v7h16v-7H4zm1 1h4v2H5v-2zm5 0h4v2h-4v-2zm5 0h4v2h-4v-2zM5 14h4v2H5v-2zm5 0h4v2h-4v-2zm5 0h4v2h-4v-2z"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/table-insert-column-ltr.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/table-insert-column-ltr.svg
deleted file mode 100644
index 798ee4a1..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/table-insert-column-ltr.svg
+++ /dev/null
@@ -1,11 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="table-insert-column-ltr">
- <path
- d="m 13,9 -2,0 0,2 -2,0 0,2 2,0 0,2 2,0 0,-2 2,0 0,-2 -2,0 z"
- id="plus" />
- <path
- d="m 5,5 2,0 0,14 -2,0 z"
- id="column" />
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/table-insert-column-rtl.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/table-insert-column-rtl.svg
deleted file mode 100644
index dfa33a08..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/table-insert-column-rtl.svg
+++ /dev/null
@@ -1,11 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="table-insert-column-rtl">
- <path
- d="m 13,9 -2,0 0,2 -2,0 0,2 2,0 0,2 2,0 0,-2 2,0 0,-2 -2,0 z"
- id="plus" />
- <path
- d="m 17,5 2,0 0,14 -2,0 z"
- id="column" />
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/table-insert-row-after.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/table-insert-row-after.svg
deleted file mode 100644
index 91d06644..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/table-insert-row-after.svg
+++ /dev/null
@@ -1,11 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="table-insert-row-after">
- <path
- d="m 13,9 -2,0 0,2 -2,0 0,2 2,0 0,2 2,0 0,-2 2,0 0,-2 -2,0 z"
- id="plus" />
- <path
- d="m 5,17 14,0 0,2 -14,0 z"
- id="row" />
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/table-insert-row-before.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/table-insert-row-before.svg
deleted file mode 100644
index 4b71f2a8..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/table-insert-row-before.svg
+++ /dev/null
@@ -1,11 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="table-insert-row-before">
- <path
- d="m 13,9 -2,0 0,2 -2,0 0,2 2,0 0,2 2,0 0,-2 2,0 0,-2 -2,0 z"
- id="plus" />
- <path
- d="m 5,5 14,0 0,2 -14,0 z"
- id="row" />
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/table-merge-cells.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/table-merge-cells.svg
deleted file mode 100644
index 6a8b77d8..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/table-merge-cells.svg
+++ /dev/null
@@ -1,10 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="24" height="24" viewBox="0 0 24 24">
- <g id="table-merge-cells">
- <g id="merge-cell-left">
- <path id="cell-border" d="m 4,7 0,9 7,0 0,-3 -1,0.834 L 10,15 5,15 5,8 10,8 10,9.167 11,10 11,7 z" />
- <path id="arrow" d="m 8,9 0,2 -2,0 0,1 2,0 0,2 3,-2.5 z" />
- </g>
- <use id="merge-cell-right" xlink:href="#merge-cell-left" transform="matrix(-1,0,0,1,24,0)" />
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/table.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/table.svg
deleted file mode 100644
index 1ba8c440..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/table.svg
+++ /dev/null
@@ -1,7 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
-
- <g id="table-insert">
- <path id="table" d="M4 5v13h16v-13zm2 2h5v4h-5zm7 0h5v4h-5zm-7 5h5v4h-5zm7 0h5v4h-5z"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/tag.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/tag.svg
deleted file mode 100644
index 534824c8..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/tag.svg
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="tag">
- <path d="M18.748 11.717c.389.389.389 1.025 0 1.414l-4.949 4.95c-.389.389-1.025.389-1.414 0l-6.01-6.01c-.389-.389-.707-1.157-.707-1.707l-.001-4.364c0-.55.45-1 1-1h4.364c.55 0 1.318.318 1.707.707l6.01 6.01zm-10.644-4.261c-.579.576-.578 1.514-.001 2.093.578.577 1.516.577 2.095.001.576-.578.576-1.517 0-2.095-.581-.576-1.518-.577-2.094.001z"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/templateAdd-ltr.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/templateAdd-ltr.svg
deleted file mode 100644
index 6b594b29..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/templateAdd-ltr.svg
+++ /dev/null
@@ -1,7 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g>
- <path d="M24 6h-4v-4h-2v4h-4v2h4v4h2v-4h4z"/>
- </g>
- <path d="M19 13v7h-16c-1.1 0-2-.9-2-2v-11h12v-1h-13v12c0 1.7 1.3 3 3 3h17v-8h-1z"/>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/templateAdd-rtl.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/templateAdd-rtl.svg
deleted file mode 100644
index 36b25a3e..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/templateAdd-rtl.svg
+++ /dev/null
@@ -1,7 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="g690">
- <path d="M0 6h4v-4h2v4h4v2h-4v4h-2v-4h-4z" id="path692"/>
- </g>
- <path d="M5 13v7h16c1.1 0 2-.9 2-2v-11h-12v-1h13v12c0 1.7-1.3 3-3 3h-17v-8h1z" id="path694"/>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/text-dir-lefttoright.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/text-dir-lefttoright.svg
deleted file mode 100644
index 62526a03..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/text-dir-lefttoright.svg
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="text-dir-ltr">
- <path d="M7 7h-2v-1h2l.469.5.531-.5h2v1h-2v10h2v1h-2l-.5-.531-.5.531h-2v-1h2zM13.976 16v-2h-2.976v-4h2.976v-1.956l6.024 3.978z"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/text-dir-righttoleft.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/text-dir-righttoleft.svg
deleted file mode 100644
index 913bbfd6..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/text-dir-righttoleft.svg
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="text-dir-rtl">
- <path d="M17 17h2v1h-2l-.469-.5-.531.5h-2v-1h2v-10h-2v-1h2l.5.531.5-.531h2v1h-2zM10.024 8v2h2.976v4h-2.976v1.956l-6.024-3.978z"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/text-style.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/text-style.svg
deleted file mode 100644
index 0198c355..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/text-style.svg
+++ /dev/null
@@ -1,7 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="text-style">
- <path id="a" d="M15.296 18h2.789l-1.14-12h-2.789l-8.156 12h2.789l2.039-3h4.183l.285 3zm-3.109-5l2.311-3.4.323 3.4h-2.634z"/>
- <path id="underline" d="M6 19h12v1h-12v-1z"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/translation-ltr.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/translation-ltr.svg
deleted file mode 100644
index 7740e43e..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/translation-ltr.svg
+++ /dev/null
@@ -1,4 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <path d="M11.1 13.1c-1.8-2.1-2.7-4.3-3-5.1h4.7l.7-2h-5.5v-3h-2v3h-5v2h5c-.2.9-1.3 4.8-5.1 7.6l1.2 1.6c2.7-2 4.3-4.5 5.1-6.4.7 1.3 1.7 3 3.2 4.5l.7-2.2zm1.4 6.9l1.3-4h5.3l1.3 4h2.2l-4.6-14h-3l-4.7 14h2.2zm4-12l2 6h-4l2-6z"/>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/translation-rtl.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/translation-rtl.svg
deleted file mode 100644
index c78e6222..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/translation-rtl.svg
+++ /dev/null
@@ -1,4 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <path d="M12.4 13.1c1.8-2.1 2.7-4.3 3-5.1h-4.7l-.7-2h5.5v-3h2v3h5v2h-5c.2.9 1.3 4.8 5.1 7.6l-1.2 1.6c-2.7-2-4.3-4.5-5.1-6.4-.7 1.3-1.7 3-3.2 4.5l-.7-2.2zm-1.4 6.9l-1.3-4h-5.3l-1.3 4h-2.2l4.6-14h3l4.7 14h-2.2zm-4-12l-2 6h4l-2-6z" id="path704"/>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/trash.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/trash.svg
deleted file mode 100644
index f5914312..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/trash.svg
+++ /dev/null
@@ -1,4 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <path d="M6 8c0-1.1.9-2 2-2h2l1-1h2l1 1h2c1.1 0 2 .9 2 2h-12zm1 1h10l-1 11h-8z"/>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/trashUndo-ltr.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/trashUndo-ltr.svg
deleted file mode 100644
index 0731f056..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/trashUndo-ltr.svg
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g>
- <path d="M20.5 20.5l-15.5-15.5-1 1 3 3 1 11h8l.2-1.8 3.3 3.3zm-3.5-11.5h-6l5.5 5.5zm1-1c0-1.1-.9-2-2-2h-2l-1-1h-2l-1 1h-2l2 2h8z"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/trashUndo-rtl.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/trashUndo-rtl.svg
deleted file mode 100644
index 2a92cbef..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/trashUndo-rtl.svg
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="g714">
- <path d="M4 20.5l15.5-15.5 1 1-3 3-1 11h-8l-.2-1.8-3.3 3.3zm3.5-11.5h6l-5.5 5.5zm-1-1c0-1.1.9-2 2-2h2l1-1h2l1 1h2l-2 2h-8z" id="path716"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/unLock-ltr.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/unLock-ltr.svg
deleted file mode 100644
index 66c024a9..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/unLock-ltr.svg
+++ /dev/null
@@ -1,4 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <path d="M12 9v-2s0-5-4.5-5-4.5 5-4.5 5h2s0-3 2.5-3 2.5 3 2.5 3v2h-3v7c0 1.7 1.3 3 3 3h10v-10z" id="path726"/>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/unLock-rtl.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/unLock-rtl.svg
deleted file mode 100644
index 07cecbfe..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/unLock-rtl.svg
+++ /dev/null
@@ -1,4 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <path d="M11 9v-2s0-5 4.5-5 4.5 5 4.5 5h-2s0-3-2.5-3-2.5 3-2.5 3v2h3v7c0 1.7-1.3 3-3 3h-10v-10z" id="path726"/>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/unStar.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/unStar.svg
deleted file mode 100644
index 724d1901..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/unStar.svg
+++ /dev/null
@@ -1,4 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <path d="M21 11l-6-1-3-6-3 6-6 1 4 4-1 6 6-3 6 3-1-6 4-4z"/>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/underline-a.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/underline-a.svg
deleted file mode 100644
index dd6dde36..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/underline-a.svg
+++ /dev/null
@@ -1,7 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="underline-a">
- <path id="a" d="M14.424 16h2.076l-3.463-10h-2.077l-3.46 10h2.077l.627-2h3.604l.616 2zm-3.921-3.623l1.496-4.379 1.511 4.379h-3z"/>
- <path id="underline" d="M7 17h10v1h-10v-1z"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/underline-u.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/underline-u.svg
deleted file mode 100644
index fbd7c147..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/underline-u.svg
+++ /dev/null
@@ -1,7 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="underline-u">
- <path id="u" d="M8 6h2v5.959c-.104 1.707.695 2.002 2 2.041 1.777.062 2.002-.879 2-2.041v-5.959h2v6.123c0 1.279-.338 2.245-1.016 2.898-.672.651-1.666.979-2.98.979-1.32 0-2.319-.326-2.996-.979-.672-.653-1.008-1.619-1.008-2.898v-6.123"/>
- <path id="underline" d="M7 17h10v1h-10v-1z"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/upTriangle.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/upTriangle.svg
deleted file mode 100644
index 9e5e72f6..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/upTriangle.svg
+++ /dev/null
@@ -1,4 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <path d="M12 8l8 10h-16z"/>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/upload-ltr.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/upload-ltr.svg
deleted file mode 100644
index 18879e32..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/upload-ltr.svg
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g>
- <path d="M10 13c0 1.7 1.3 3 3 3v-7h3l-4.5-5-4.5 5h3v4zm7 0v5h-10c-.6 0-1-.4-1-1v-4h-2v4c0 1.9 1.3 3 3 3h12v-7h-2z"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/upload-rtl.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/upload-rtl.svg
deleted file mode 100644
index 7a3535ba..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/upload-rtl.svg
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="g736">
- <path d="M13 13c0 1.7-1.3 3-3 3v-7h-3l4.5-5 4.5 5h-3v4zm-7 0v5h10c.6 0 1-.4 1-1v-4h2v4c0 1.9-1.3 3-3 3h-12v-7h2z" id="path738"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/userActive-ltr.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/userActive-ltr.svg
deleted file mode 100644
index 5dcc3179..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/userActive-ltr.svg
+++ /dev/null
@@ -1,4 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <path d="M16 5h-12v12c0 1.7 1.3 3 3 3h12v-12c0-1.7-1.3-3-3-3zm-2 4c.7 0 1.2.6 1.2 1.2s-.6 1.2-1.2 1.2-1.2-.6-1.2-1.2.5-1.2 1.2-1.2zm-5 0c.7 0 1.2.6 1.2 1.2s-.5 1.3-1.2 1.3-1.2-.6-1.2-1.2.5-1.3 1.2-1.3zm7 5.4c0 .2-.1.3-.3.5-.7.6-1.6 1-2.6 1.3s-2.1.2-3.1 0-2-.9-2.7-1.5c-.1-.1-.2-.3-.2-.4s.1-.3.2-.4c.1-.1.3-.2.4-.2.2 0 .3.1.4.2.5.5 1.2.9 2.1 1.1s1.7.2 2.6 0 1.6-.5 2.1-1c.1-.1.3-.2.4-.2s.3.1.5.2.2.2.2.4z"/>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/userActive-rtl.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/userActive-rtl.svg
deleted file mode 100644
index a5e4dc95..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/userActive-rtl.svg
+++ /dev/null
@@ -1,4 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <path d="M7 5h12v12c0 1.7-1.3 3-3 3h-12v-12c0-1.7 1.3-3 3-3zm2 4c-.7 0-1.2.6-1.2 1.2s.6 1.2 1.2 1.2 1.2-.6 1.2-1.2-.5-1.2-1.2-1.2zm5 0c-.7 0-1.2.6-1.2 1.2s.5 1.3 1.2 1.3 1.2-.6 1.2-1.2-.5-1.3-1.2-1.3zm-7 5.4c0 .2.1.3.3.5.7.6 1.6 1 2.6 1.3 1 .3 2.1.2 3.1 0s2-.9 2.7-1.5c.1-.1.2-.3.2-.4 0-.1-.1-.3-.2-.4-.1-.1-.3-.2-.4-.2-.2 0-.3.1-.4.2-.5.5-1.2.9-2.1 1.1-.9.2-1.7.2-2.6 0-.9-.2-1.6-.5-2.1-1-.1-.1-.3-.2-.4-.2-.1 0-.3.1-.5.2s-.2.2-.2.4z" id="path748"/>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/userAvatar.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/userAvatar.svg
deleted file mode 100644
index e9687fa6..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/userAvatar.svg
+++ /dev/null
@@ -1,8 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="g4">
- <g id="g6">
- <path d="M11.5 13c1.7 0 3.5-2 3.5-5 0-.1 0-4-3.5-4s-3.5 3.9-3.5 4c0 3 1.8 5 3.5 5zm3.5-1c-.4.7-1.7 2-3.5 2s-3.2-1.3-3.5-2h-2c-1.1 0-2 .9-2 2v6h15v-6c0-1.1-.9-2-2-2h-2z" id="path8"/>
- </g>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/userInactive-ltr.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/userInactive-ltr.svg
deleted file mode 100644
index bb5b0968..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/userInactive-ltr.svg
+++ /dev/null
@@ -1,4 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <path d="M16 5h-12v12c0 1.7 1.3 3 3 3h12v-12c0-1.7-1.3-3-3-3zm-9.3 5.4c-.5-.4-.7-.8-.7-1.4.6.6 1.5.9 2.5.9s1.9-.3 2.5-.9c0 .6-.2 1-.7 1.4-.5.4-1.1.6-1.8.6s-1.3-.2-1.8-.6zm8.4 4.3c0 .2-.1.3-.3.4-1 .6-2.2.9-3.5.9-1.2 0-2.3-.3-3.3-1-.2-.1-.2-.2-.3-.4s0-.3.1-.5.2-.2.4-.3.3 0 .5.1c.8.5 1.7.8 2.8.8s2-.2 2.8-.7c.1-.1.3-.1.5-.1s.3.1.4.3l-.1.5zm1.2-4.3c-.5.4-1.1.6-1.8.6s-1.3-.2-1.8-.6-.7-.8-.7-1.4c.6.6 1.5.9 2.5.9s1.9-.3 2.5-.9c0 .6-.2 1-.7 1.4z"/>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/userInactive-rtl.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/userInactive-rtl.svg
deleted file mode 100644
index 4a9fd0d7..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/userInactive-rtl.svg
+++ /dev/null
@@ -1,4 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <path d="M7 5h12v12c0 1.7-1.3 3-3 3h-12v-12c0-1.7 1.3-3 3-3zm9.3 5.4c.5-.4.7-.8.7-1.4-.6.6-1.5.9-2.5.9s-1.9-.3-2.5-.9c0 .6.2 1 .7 1.4.5.4 1.1.6 1.8.6s1.3-.2 1.8-.6zm-8.4 4.3c0 .2.1.3.3.4 1 .6 2.2.9 3.5.9 1.2 0 2.3-.3 3.3-1 .2-.1.2-.2.3-.4.1-.2 0-.3-.1-.5s-.2-.2-.4-.3c-.2-.1-.3 0-.5.1-.8.5-1.7.8-2.8.8-1.1 0-2-.2-2.8-.7-.1-.1-.3-.1-.5-.1s-.3.1-.4.3l.1.5zm-1.2-4.3c.5.4 1.1.6 1.8.6s1.3-.2 1.8-.6c.5-.4.7-.8.7-1.4-.6.6-1.5.9-2.5.9s-1.9-.3-2.5-.9c0 .6.2 1 .7 1.4z" id="path758"/>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/userTalk-ltr.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/userTalk-ltr.svg
deleted file mode 100644
index f516539c..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/userTalk-ltr.svg
+++ /dev/null
@@ -1,4 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <path d="M5 6v11l-3 3h17c1.7 0 3-1.3 3-3v-11h-17zm11.2 2.5c.7 0 1.2.6 1.2 1.2s-.5 1.3-1.2 1.3-1.2-.6-1.2-1.2.6-1.3 1.2-1.3zm-5.4 0c.7 0 1.2.6 1.2 1.2s-.6 1.3-1.2 1.3-1.2-.6-1.2-1.2.5-1.3 1.2-1.3zm2.7 8.5c-5.1 0-6-5-6-5s2 1 6 1l6-1s-1 5-6 5z" id="path6"/>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/userTalk-rtl.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/userTalk-rtl.svg
deleted file mode 100644
index 8963fafc..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/userTalk-rtl.svg
+++ /dev/null
@@ -1,4 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <path d="M19 6v11l3 3h-17c-1.7 0-3-1.3-3-3v-11h17zm-11.2 2.5c-.7 0-1.2.6-1.2 1.2s.5 1.3 1.2 1.3 1.2-.6 1.2-1.2-.6-1.3-1.2-1.3zm5.4 0c-.7 0-1.2.6-1.2 1.2s.6 1.3 1.2 1.3 1.2-.6 1.2-1.2-.5-1.3-1.2-1.3zm-2.7 8.5c5.1 0 6-5 6-5s-2 1-6 1l-6-1s1 5 6 5z" id="path770"/>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/viewCompact.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/viewCompact.svg
deleted file mode 100644
index d96a2e3f..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/viewCompact.svg
+++ /dev/null
@@ -1,14 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="viewCompact">
- <circle cx="6" cy="6" r="2"/>
- <circle cx="12" cy="6" r="2"/>
- <circle cx="18" cy="6" r="2"/>
- <circle cx="6" cy="12" r="2"/>
- <circle cx="12" cy="12" r="2"/>
- <circle cx="18" cy="12" r="2"/>
- <circle cx="6" cy="18" r="2"/>
- <circle cx="12" cy="18" r="2"/>
- <circle cx="18" cy="18" r="2"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/viewDetails-ltr.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/viewDetails-ltr.svg
deleted file mode 100644
index 4f5f9b3d..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/viewDetails-ltr.svg
+++ /dev/null
@@ -1,9 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="viewDetails">
- <circle cx="5.5" cy="8.5" r="2.5"/>
- <path d="M10 6h12v1H10zM10 8h9v1h-9zM10 10h4v1h-4z"/>
- <circle cx="5.5" cy="16.5" r="2.5"/>
- <path d="M10 14h12v1H10zM10 16h9v1h-9zM10 18h4v1h-4z"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/viewDetails-rtl.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/viewDetails-rtl.svg
deleted file mode 100644
index f43b05f1..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/viewDetails-rtl.svg
+++ /dev/null
@@ -1,9 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="viewDetails">
- <circle cx="18.5" cy="8.5" r="2.5"/>
- <path d="M14 6H2v1h12zm0 2H5v1h9zm0 2h-4v1h4z"/>
- <circle cx="18.5" cy="16.5" r="2.5"/>
- <path d="M14 14H2v1h12zm0 2H5v1h9zm0 2h-4v1h4z"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/visionSimulator.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/visionSimulator.svg
deleted file mode 100644
index ae6ba27a..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/visionSimulator.svg
+++ /dev/null
@@ -1,4 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <path d="M0 10v8h2.3c.3.6 1 1 1.7 1h4c1.5 0 2.7-.8 3-2h2c.3 1.2 1.5 2 3 2h4c.7 0 1.4 0 1.7-1H24v-8zm10 6c0 1-.4 2-2 2H4c-.6 0-1-.4-1-1v-3c0-.6.4-1 1-1h5c.6 0 1 .4 1 1zm11 1c0 .6-.4 1-1 1h-4c-1.6 0-2-1-2-2v-2c0-.6.4-1 1-1h5c.6 0 1 .4 1 1z"/>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/watchlist-ltr.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/watchlist-ltr.svg
deleted file mode 100644
index 79c7d5ca..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/watchlist-ltr.svg
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g>
- <path d="M13 14h5v1h-5v-1zm0 3h5v-1h-5v1zm0 1h5v1h-5v-1zm-1-5v3l-5 3 1-6-4-3 6-1 2-5s1.9 5 2 5l6 1-4 3h-4z"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/watchlist-rtl.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/watchlist-rtl.svg
deleted file mode 100644
index 6bbc2fa2..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/watchlist-rtl.svg
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="g780">
- <path d="M11 14h-5v1h5v-1zm0 3h-5v-1h5v1zm0 1h-5v1h5v-1zm1-5v3l5 3-1-6 4-3-6-1-2-5s-1.9 5-2 5l-6 1 4 3h4z" id="path782"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/wikiText.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/wikiText.svg
deleted file mode 100644
index eebd9b1a..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/wikiText.svg
+++ /dev/null
@@ -1,15 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g>
- <path d="M23 5h-4v2h2v10h-2v2h4z"/>
- </g>
- <g>
- <path d="M18 5h-4v2h2v10h-2v2h4z"/>
- </g>
- <g>
- <path d="M2 5h4v2h-2v10h2v2h-4z"/>
- </g>
- <g>
- <path d="M7 5h4v2h-2v10h2v2h-4z"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/wikitrail-ltr.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/wikitrail-ltr.svg
deleted file mode 100644
index c606becd..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/wikitrail-ltr.svg
+++ /dev/null
@@ -1,8 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g>
- <path d="M15 9l.7-1.8c.9.4 1.8.7 2.4.9l-.6 1.7v.2l-2.5-1zm-4.3-1.9l.8-1.8c1.2.5 2.6 1.1 3 1.4l-.8 1.8-3-1.4zm-5.9-1c-.8 0-1.4.2-2 .6l-1.1-1.7c.9-.6 1.9-.9 3.1-.9v2zm-4.3.7l1.8.8c-.3.7-.3 1.3-.1 1.8l-1.9.7c-.3-1.2-.3-2.3.2-3.3zm4.2 5.4l-1.3 1.5c-1-1-1.7-1.6-2-2l1.5-1.3c.7.8 1.3 1.4 1.8 1.8zm7.3 4.3c0 1.9-1.6 3.5-3.5 3.5s-3.5-1.6-3.5-3.5 1.6-3.5 3.5-3.5 3.5 1.6 3.5 3.5z"/>
- </g>
- <path d="M24 8l-1-1-1.5 1.5-1.5-1.5-1 1 1.5 1.5-1.5 1.5 1 1 1.5-1.5 1.5 1.5 1-1-1.5-1.5z"/>
- <circle cx="8" cy="5" r="2"/>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/wikitrail-rtl.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/wikitrail-rtl.svg
deleted file mode 100644
index f304f6ed..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/wikitrail-rtl.svg
+++ /dev/null
@@ -1,8 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="g792">
- <path d="M9.095 9l-.7-1.8c-.9.4-1.8.7-2.4.9l.6 1.7v.2l2.5-1zm4.3-1.9l-.8-1.8c-1.2.5-2.6 1.1-3 1.4l.8 1.8 3-1.4zm5.9-1c.8 0 1.4.2 2 .6l1.1-1.7c-.9-.6-1.9-.9-3.1-.9v2zm4.3.7l-1.8.8c.3.7.3 1.3.1 1.8l1.9.7c.3-1.2.3-2.3-.2-3.3zm-4.2 5.4l1.3 1.5c1-1 1.7-1.6 2-2l-1.5-1.3c-.7.8-1.3 1.4-1.8 1.8zm-7.3 4.3c0 1.9 1.6 3.5 3.5 3.5s3.5-1.6 3.5-3.5-1.6-3.5-3.5-3.5-3.5 1.6-3.5 3.5z" id="path794"/>
- </g>
- <path d="M.095 8l1-1 1.5 1.5 1.5-1.5 1 1-1.5 1.5 1.5 1.5-1 1-1.5-1.5-1.5 1.5-1-1 1.5-1.5z" id="path796"/>
- <circle cx="8" cy="5" r="2" id="circle798" transform="matrix(-1 0 0 1 24.095 0)"/>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/window.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/window.svg
deleted file mode 100644
index cd3b76c2..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/icons/window.svg
+++ /dev/null
@@ -1,7 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="window">
- <path id="title" d="M7 10h10v1h-10z"/>
- <path id="frame" d="M16 19h-8c-2.206 0-4-1.794-4-4v-6c0-2.206 1.794-4 4-4h8c2.206 0 4 1.794 4 4v6c0 2.206-1.794 4-4 4zm-8-12c-1.103 0-2 .897-2 2v6c0 1.103.897 2 2 2h8c1.103 0 2-.897 2-2v-6c0-1.103-.897-2-2-2h-8z"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/indicators/alert.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/indicators/alert.svg
deleted file mode 100644
index d9dc6a87..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/indicators/alert.svg
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 12 12">
- <g id="alert">
- <path d="M6 12c-3.314 0-6-2.686-6-6s2.686-6 6-6 6 2.686 6 6-2.686 6-6 6zm-1-5h2v-5h-2zm0 3h2v-2h-2z"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/indicators/arrow-down.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/indicators/arrow-down.svg
deleted file mode 100644
index 17380577..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/indicators/arrow-down.svg
+++ /dev/null
@@ -1,8 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Generator: Adobe Illustrator 18.1.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
-<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
- viewBox="0 0 1000 1000" enable-background="new 0 0 1000 1000" xml:space="preserve">
-<g id="down">
- <path id="arrow" d="M883.3,341H116.7L500,724.3l0,0l0,0L883.3,341"/>
-</g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/indicators/arrow-ltr.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/indicators/arrow-ltr.svg
deleted file mode 100644
index fb366e64..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/indicators/arrow-ltr.svg
+++ /dev/null
@@ -1,8 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Generator: Adobe Illustrator 18.1.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
-<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
- viewBox="-493 495 12 12" enable-background="new -493 495 12 12" xml:space="preserve">
-<g id="ltr">
- <path id="arrow" d="M-489,496v10l5-5h0h0L-489,496"/>
-</g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/indicators/arrow-rtl.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/indicators/arrow-rtl.svg
deleted file mode 100644
index 62b6bb50..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/indicators/arrow-rtl.svg
+++ /dev/null
@@ -1,8 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Generator: Adobe Illustrator 18.1.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
-<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
- viewBox="-493 495 12 12" enable-background="new -493 495 12 12" xml:space="preserve">
-<g id="rtl">
- <path id="arrow" d="M-485,506v-10l-5,5h0h0L-485,506"/>
-</g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/indicators/arrow-up.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/indicators/arrow-up.svg
deleted file mode 100644
index 20e734fb..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/indicators/arrow-up.svg
+++ /dev/null
@@ -1,8 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Generator: Adobe Illustrator 18.1.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
-<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
- viewBox="-493 495 12 12" enable-background="new -493 495 12 12" xml:space="preserve">
-<g id="up">
- <path id="arrow" d="M-492,503h10l-5-5v0v0L-492,503"/>
-</g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/indicators/required.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/indicators/required.svg
deleted file mode 100644
index 969fa2d8..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/indicators/required.svg
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 12 12">
- <g id="required">
- <path d="M5 1h2v10h-2zM9.83 2.634l1 1.732-8.66 5-1-1.732zM1.17 4.366l1-1.732 8.66 5-1 1.732z"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/indicators/search-ltr.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/indicators/search-ltr.svg
deleted file mode 100644
index 266349ed..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/indicators/search-ltr.svg
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 12 12">
- <g id="search">
- <path id="path3051" d="M10.369 9.474l-2.374-2.375-.169-.099c.403-.566.643-1.26.643-2.009-.001-1.92-1.558-3.477-3.477-3.477-1.921 0-3.478 1.557-3.478 3.478 0 1.92 1.557 3.477 3.478 3.477.749 0 1.442-.239 2.01-.643l.098.169 2.375 2.374c.19.189.543.143.79-.104s.293-.601.104-.791zm-5.377-2.27c-1.221 0-2.213-.991-2.213-2.213 0-1.221.992-2.213 2.213-2.213 1.222 0 2.213.992 2.213 2.213-.001 1.222-.992 2.213-2.213 2.213z"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/indicators/search-rtl.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/indicators/search-rtl.svg
deleted file mode 100644
index 5368fd7c..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/indicators/search-rtl.svg
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 12 12">
- <g id="search">
- <path id="path3051" d="M1.631 9.474l2.374-2.375.169-.099c-.403-.566-.643-1.26-.643-2.009.001-1.92 1.558-3.477 3.477-3.477 1.921 0 3.478 1.557 3.478 3.478 0 1.92-1.557 3.477-3.478 3.477-.749 0-1.442-.239-2.01-.643l-.098.169-2.375 2.374c-.19.189-.543.143-.79-.104s-.293-.601-.104-.791zm5.377-2.27c1.221 0 2.213-.991 2.213-2.213 0-1.221-.992-2.213-2.213-2.213-1.222 0-2.213.992-2.213 2.213.001 1.222.992 2.213 2.213 2.213z"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/textures/pending.gif b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/textures/pending.gif
deleted file mode 100644
index 1194eed2..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/textures/pending.gif
+++ /dev/null
Binary files differ
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/textures/transparency.svg b/vendor/oojs/oojs-ui/src/themes/mediawiki/images/textures/transparency.svg
deleted file mode 100644
index 63a0b57c..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/images/textures/transparency.svg
+++ /dev/null
@@ -1,10 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
-<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0" y="0" width="16" height="16" viewBox="0, 0, 16, 16">
- <g id="transparency">
- <path d="M0,0 L8,0 L8,8 L0,8 z" fill="#CCCCCC"/>
- <path d="M8,8 L16,8 L16,16 L8,16 z" fill="#CCCCCC"/>
- <path d="M8,0 L16,0 L16,8 L8,8 z" fill="#FFFFFF"/>
- <path d="M0,8 L8,8 L8,16 L0,16 z" fill="#FFFFFF"/>
- </g>
-</svg>
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/indicators.json b/vendor/oojs/oojs-ui/src/themes/mediawiki/indicators.json
deleted file mode 100644
index d83e57e6..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/indicators.json
+++ /dev/null
@@ -1,29 +0,0 @@
-{
- "selectorWithoutVariant": ".oo-ui-indicator-{name}",
- "selectorWithVariant": ".oo-ui-image-{variant} .oo-ui-indicator-{name}, .oo-ui-image-{variant}.oo-ui-indicator-{name}",
- "intro": "@import '../../../../src/styles/common';",
- "variants": {
- "invert": {
- "color": "#FFFFFF",
- "global": true
- }
- },
- "images": {
- "alert": { "file": "images/indicators/alert.svg" },
- "up": { "file": "images/indicators/arrow-up.svg" },
- "down": { "file": "images/indicators/arrow-down.svg" },
- "next": { "file": {
- "ltr": "images/indicators/arrow-ltr.svg",
- "rtl": "images/indicators/arrow-rtl.svg"
- } },
- "previous": { "file": {
- "ltr": "images/indicators/arrow-rtl.svg",
- "rtl": "images/indicators/arrow-ltr.svg"
- } },
- "required": { "file": "images/indicators/required.svg" },
- "search": { "file": {
- "ltr": "images/indicators/search-ltr.svg",
- "rtl": "images/indicators/search-rtl.svg"
- } }
- }
-}
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/layouts.less b/vendor/oojs/oojs-ui/src/themes/mediawiki/layouts.less
deleted file mode 100644
index c4956f33..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/layouts.less
+++ /dev/null
@@ -1,135 +0,0 @@
-@import 'common';
-
-.theme-oo-ui-layout () {}
-
-.theme-oo-ui-bookletLayout () {
- &-stackLayout {
- > .oo-ui-panelLayout {
- padding: 1.5em;
- }
- }
-
- &-outlinePanel {
- border-right: 1px solid #ddd;
-
- > .oo-ui-outlineControlsWidget {
- box-shadow: 0 0 0.25em rgba(0,0,0,0.25);
- }
- }
-}
-
-.theme-oo-ui-indexLayout () {
- &-stackLayout {
- > .oo-ui-panelLayout {
- padding: 1.5em;
- }
- }
-}
-
-.theme-oo-ui-fieldLayout () {
- margin-bottom: 1em;
-
- &:last-child {
- margin-bottom: 0;
- }
-
- &.oo-ui-fieldLayout-align-left,
- &.oo-ui-fieldLayout-align-right {
- &.oo-ui-labelElement > .oo-ui-fieldLayout-body > .oo-ui-labelElement-label {
- padding-top: 0.5em;
- margin-right: 5%;
- width: 35%;
- }
-
- > .oo-ui-fieldLayout-body > .oo-ui-fieldLayout-field {
- width: 60%;
- }
- }
-
- &.oo-ui-fieldLayout-align-inline {
- &.oo-ui-labelElement > .oo-ui-fieldLayout-body > .oo-ui-labelElement-label {
- padding: 0.5em;
- padding-left: 1em;
- }
-
- > .oo-ui-fieldLayout-body > .oo-ui-fieldLayout-field {
- padding: 0.5em 0;
- }
- }
-
- &.oo-ui-fieldLayout-align-top {
- &.oo-ui-labelElement > .oo-ui-fieldLayout-body > .oo-ui-labelElement-label {
- padding: 0.5em 0;
- }
- }
-
- > .oo-ui-popupButtonWidget {
- .oo-ui-inline-spacing(0);
- margin-top: 0.25em;
- }
-
- &-disabled .oo-ui-labelElement-label {
- color: #ccc;
- }
-}
-
-.theme-oo-ui-actionFieldLayout () {}
-
-.theme-oo-ui-fieldsetLayout () {
- margin: 0;
- padding: 0;
- border: none;
-
- + .oo-ui-fieldsetLayout,
- + .oo-ui-formLayout {
- margin-top: 2em;
- }
-
- > .oo-ui-labelElement-label {
- font-size: 1.1em;
- margin-bottom: 0.5em;
- padding: 0.25em 0;
- font-weight: bold;
- }
-
- &.oo-ui-iconElement > .oo-ui-labelElement-label {
- padding-left: 2em;
- line-height: 1.8em;
- }
-
- &.oo-ui-iconElement > .oo-ui-iconElement-icon {
- left: 0;
- top: 0.25em;
- width: @icon-size;
- height: @icon-size;
- }
-
- > .oo-ui-popupButtonWidget {
- .oo-ui-inline-spacing(0);
- }
-}
-
-.theme-oo-ui-formLayout () {
- + .oo-ui-fieldsetLayout,
- + .oo-ui-formLayout {
- margin-top: 2em;
- }
-}
-
-.theme-oo-ui-menuLayout () {}
-
-.theme-oo-ui-panelLayout () {
- &-padded {
- padding: 1.25em;
- }
-
- &-framed {
- border: 1px solid #aaa;
- border-radius: 0.2em;
- box-shadow: inset 0 -0.2em 0 0 rgba(0,0,0,0.2);
- }
-}
-
-.theme-oo-ui-pageLayout () {}
-
-.theme-oo-ui-stackLayout () {}
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/textures.json b/vendor/oojs/oojs-ui/src/themes/mediawiki/textures.json
deleted file mode 100644
index e90730ab..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/textures.json
+++ /dev/null
@@ -1,8 +0,0 @@
-{
- "prefix": "oo-ui-texture",
- "intro": "@import '../../../../src/styles/common';",
- "images": {
- "pending": { "file": "images/textures/pending.gif" },
- "transparency": { "file": "images/textures/transparency.svg" }
- }
-}
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/tools.less b/vendor/oojs/oojs-ui/src/themes/mediawiki/tools.less
deleted file mode 100644
index fa5d6ddc..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/tools.less
+++ /dev/null
@@ -1,422 +0,0 @@
-@import 'common';
-
-@oo-ui-toolbar-normal: #fff;
-@oo-ui-toolbar-normal-hover: #eee;
-@oo-ui-toolbar-active: #e5e5e5;
-@oo-ui-toolbar-active-hover: #eee;
-@oo-ui-toolbar-pressed: #e7e7e7;
-@oo-ui-toolbar-bar-text: #555;
-@oo-ui-toolbar-dropdown-text: #000;
-
-.theme-oo-ui-toolbar () {
- &-bar {
- border-bottom: 1px solid #ccc;
- background-color: @oo-ui-toolbar-normal;
- box-shadow: 0px 1px 1px rgba(0, 0, 0, 0.1);
- font-weight: 500;
- color: @oo-ui-toolbar-bar-text;
-
- .oo-ui-toolbar-bar {
- border: none;
- background: none;
- box-shadow: none;
- }
- }
-
- &-actions {
- > .oo-ui-buttonElement {
- margin-top: 0.25em;
- margin-bottom: 0.25em;
- }
-
- > .oo-ui-toolbar,
- > .oo-ui-buttonElement:last-child {
- margin-right: 0.5em;
- }
- }
-}
-
-.theme-oo-ui-tool () {}
-
-.theme-oo-ui-popupTool () {
- .oo-ui-popupWidget {
- /* @noflip */
- margin-left: 1.25em;
- }
-}
-
-.theme-oo-ui-toolGroupTool () {
- > .oo-ui-popupToolGroup {
- border: 0;
- border-radius: 0;
- margin: 0;
- }
-
- > .oo-ui-toolGroup {
- border-right: none;
- }
-
- > .oo-ui-popupToolGroup > .oo-ui-popupToolGroup-handle {
- height: 2.5em;
- padding: 0.3125em;
-
- .oo-ui-iconElement-icon {
- height: 2.5em;
- width: 1.875em;
- }
- }
-
- > .oo-ui-popupToolGroup.oo-ui-labelElement > .oo-ui-popupToolGroup-handle {
- .oo-ui-labelElement-label {
- line-height: 2.1em;
- }
- }
-}
-
-.theme-oo-ui-toolGroup () {
- border-radius: 0px;
- border-right: 1px solid #ddd;
-
- .oo-ui-toolbar-narrow & {
- + .oo-ui-toolGroup {
- margin-left: 0;
- }
- }
-
- .oo-ui-toolGroup {
- .oo-ui-widget-enabled {
- border-right: none !important;
- }
- }
-}
-
-.theme-oo-ui-barToolGroup () {
- > .oo-ui-toolGroup-tools > .oo-ui-tool {
- > .oo-ui-tool-link {
- height: 1.875em;
- padding: 0.625em;
-
- .oo-ui-iconElement-icon {
- height: 1.875em;
- width: 1.875em;
- }
-
- .oo-ui-tool-title {
- line-height: 2.1em; // 0.5em less
- padding: 0em 0.4em;
- }
- }
- }
-
- &.oo-ui-widget-enabled > .oo-ui-toolGroup-tools > .oo-ui-tool {
- &.oo-ui-widget-enabled:hover {
- border-color: rgba(0,0,0,0.2);
- background-color: @oo-ui-toolbar-normal-hover;
- }
-
- > a.oo-ui-tool-link .oo-ui-tool-title {
- color: @oo-ui-toolbar-bar-text;
- }
-
- &.oo-ui-tool-active {
- &.oo-ui-widget-enabled {
- border-color: rgba(0,0,0,0.2);
- box-shadow: inset 0 0.07em 0.07em 0 rgba(0, 0, 0, 0.07);
- background-color: @oo-ui-toolbar-active;
- }
-
- &.oo-ui-widget-enabled:hover {
- background-color: @oo-ui-toolbar-active-hover;
- }
-
- &.oo-ui-widget-enabled + .oo-ui-tool-active.oo-ui-widget-enabled {
- border-left-color: rgba(0,0,0,0.1);
- }
- }
-
- &.oo-ui-widget-disabled > .oo-ui-tool-link {
- .oo-ui-tool-title {
- color: #ccc;
- }
-
- .oo-ui-iconElement-icon {
- opacity: 0.2;
- }
- }
-
- &.oo-ui-widget-enabled {
- > .oo-ui-tool-link .oo-ui-iconElement-icon {
- opacity: 0.7;
- }
-
- &:hover > .oo-ui-tool-link .oo-ui-iconElement-icon {
- opacity: 0.9;
- }
- }
-
- &.oo-ui-widget-enabled:active {
- background-color: @oo-ui-toolbar-pressed;
- }
- }
-
- &.oo-ui-widget-disabled > .oo-ui-toolGroup-tools > .oo-ui-tool {
- > a.oo-ui-tool-link {
- .oo-ui-tool-title {
- color: #ccc;
- }
-
- .oo-ui-iconElement-icon {
- opacity: 0.2;
- }
- }
- }
-}
-
-.theme-oo-ui-popupToolGroup () {
- height: 3.125em;
- min-width: 2em;
-
- .oo-ui-toolbar-narrow & {
- min-width: 1.875em;
- }
-
- &.oo-ui-iconElement {
- min-width: 3.125em;
- .oo-ui-toolbar-narrow & {
- min-width: 2.5em;
- }
- }
-
- &.oo-ui-indicatorElement.oo-ui-iconElement {
- min-width: 4.375em;
-
- .oo-ui-toolbar-narrow & {
- min-width: 3.75em;
- }
- }
-
- &.oo-ui-labelElement {
- .oo-ui-popupToolGroup-handle .oo-ui-labelElement-label {
- line-height: 2.6em;
- margin: 0 1em;
-
- .oo-ui-toolbar-narrow & {
- margin: 0 0.5em;
- }
- }
-
- &.oo-ui-iconElement .oo-ui-popupToolGroup-handle .oo-ui-labelElement-label {
- margin-left: 3em;
-
- .oo-ui-toolbar-narrow & {
- margin-left: 2.5em;
- }
- }
-
- &.oo-ui-indicatorElement .oo-ui-popupToolGroup-handle .oo-ui-labelElement-label {
- margin-right: 2em;
-
- .oo-ui-toolbar-narrow & {
- margin-right: 1.75em;
- }
- }
- }
-
- &.oo-ui-widget-enabled &-handle:hover {
- background-color: @oo-ui-toolbar-normal-hover;
- }
-
- &.oo-ui-widget-enabled &-handle:active {
- background-color: @oo-ui-toolbar-active;
- }
-
- &-handle {
- padding: 0.3125em;
- height: 2.5em;
-
- .oo-ui-indicatorElement-indicator {
- width: 0.9375em;
- height: 1.625em;
- margin: 0.78125em 0.5em;
- top: 0;
- right: 0;
- opacity: 0.3;
-
- .oo-ui-toolbar-narrow & {
- right: -0.3125em;
- }
- }
-
- .oo-ui-iconElement-icon {
- width: 1.875em;
- height: 2.6em;
- margin: 0.25em;
- top: 0;
- left: 0.3125em;
- opacity: 0.7;
-
- .oo-ui-toolbar-narrow & {
- left: 0;
- }
- }
- }
-
- &-header {
- line-height: 2.6em;
- margin: 0 0.6em;
- font-weight: bold;
- }
-
- &-active.oo-ui-widget-enabled {
- border-bottom-left-radius: 0;
- border-bottom-right-radius: 0;
- box-shadow: inset 0 0.07em 0.07em 0 rgba(0, 0, 0, 0.07);
- background-color: @oo-ui-toolbar-normal-hover;
- }
-
- .oo-ui-toolGroup-tools {
- top: 3.125em;
- margin: 0 -1px;
- border: 1px solid #ccc;
- background-color: @oo-ui-toolbar-normal;
- box-shadow: 0px 2px 3px rgba(0,0,0,0.2);
- min-width: 16em;
- }
-
- .oo-ui-tool-link {
- padding: 0.4em 0.625em;
- box-sizing: border-box;
-
- .oo-ui-iconElement-icon {
- height: 2.5em;
- width: 1.875em;
- min-width: 1.875em;
- }
-
- .oo-ui-tool-title {
- padding-left: 0.5em;
- color: @oo-ui-toolbar-dropdown-text;
- }
-
- .oo-ui-tool-accel,
- .oo-ui-tool-title {
- line-height: 2em;
- }
-
- .oo-ui-tool-accel {
- color: #888;
- }
- }
-}
-
-.theme-oo-ui-listToolGroup () {
- &.oo-ui-popupToolGroup-active {
- border-color: rgba(0,0,0,0.2);
- }
-
- .oo-ui-tool {
- &.oo-ui-widget-enabled {
- &:hover {
- border-color: rgba(0,0,0,0.2);
- background-color: @oo-ui-toolbar-normal-hover;
- }
-
- &:active {
- background-color: @oo-ui-toolbar-pressed;
- }
-
- &:hover .oo-ui-tool-link .oo-ui-iconElement-icon {
- opacity: 0.9;
- }
- }
-
- &-active {
- &.oo-ui-widget-enabled {
- border-color: rgba(0,0,0,0.1);
- box-shadow: inset 0 0.07em 0.07em 0 rgba(0, 0, 0, 0.07);
- background-color: @oo-ui-toolbar-active;
-
- + .oo-ui-tool-active.oo-ui-widget-enabled {
- border-top-color: rgba(0,0,0,0.1);
- }
-
- &:hover {
- border-color: rgba(0,0,0,0.2);
- background-color: @oo-ui-toolbar-active-hover;
- }
- }
- }
-
- &.oo-ui-widget-disabled {
- .oo-ui-tool-link {
- .oo-ui-tool-title {
- color: #ccc;
- }
-
- .oo-ui-tool-accel {
- color: #ddd;
- }
-
- .oo-ui-iconElement-icon {
- opacity: 0.2;
- }
- }
- }
- }
-
- &.oo-ui-widget-disabled {
- color: #ccc;
-
- .oo-ui-indicatorElement-indicator,
- .oo-ui-iconElement-icon {
- opacity: 0.2;
- }
- }
-}
-
-.theme-oo-ui-menuToolGroup () {
- .oo-ui-popupToolGroup-handle {
- min-width: 10em;
-
- .oo-ui-toolbar-narrow & {
- min-width: 8.125em;
- }
- }
-
- .oo-ui-tool {
- &-link {
- .oo-ui-iconElement-icon {
- background-image: none;
- }
- }
-
- &-active .oo-ui-tool-link .oo-ui-iconElement-icon {
- .oo-ui-background-image-svg('@{oo-ui-default-image-path}/icons/check');
- }
-
- &.oo-ui-widget-enabled {
- &:hover {
- background-color: @oo-ui-toolbar-normal-hover;
- }
- }
-
- &.oo-ui-widget-disabled {
- .oo-ui-tool-link .oo-ui-tool-title {
- color: #ccc;
- }
-
- .oo-ui-tool-link .oo-ui-iconElement-icon {
- opacity: 0.2;
- }
- }
- }
-
- &.oo-ui-widget-disabled {
- color: #ccc;
-
- .oo-ui-indicatorElement-indicator,
- .oo-ui-iconElement-icon {
- opacity: 0.2;
- }
- }
-}
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/widgets.less b/vendor/oojs/oojs-ui/src/themes/mediawiki/widgets.less
deleted file mode 100644
index 2f072878..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/widgets.less
+++ /dev/null
@@ -1,978 +0,0 @@
-@import 'common';
-
-.theme-oo-ui-widget () {}
-
-.theme-oo-ui-outlineControlsWidget () {
- height: 3em;
- background-color: #fff;
-
- &-items,
- &-movers {
- height: 2em;
- margin: 0.5em 0.5em 0.5em 0;
- padding: 0;
- }
-
- > .oo-ui-iconElement-icon {
- width: 1.5em;
- height: 2em;
- margin: 0.5em 0 0.5em 0.5em;
- opacity: 0.2;
- }
-}
-
-.theme-oo-ui-toggleWidget () {}
-
-.theme-oo-ui-buttonGroupWidget () {
- display: inline-block;
- white-space: nowrap;
- border-radius: @border-radius;
-
- .oo-ui-inline-spacing(0.5em);
- .oo-ui-buttonElement {
- .oo-ui-inline-spacing(0);
- }
-
- .oo-ui-buttonElement-framed {
- .oo-ui-buttonElement-button {
- border-radius: 0;
- margin-left: -1px;
- }
-
- &:first-child .oo-ui-buttonElement-button {
- border-bottom-left-radius: @border-radius;
- border-top-left-radius: @border-radius;
- margin-left: 0;
- }
-
- &:last-child .oo-ui-buttonElement-button {
- border-bottom-right-radius: @border-radius;
- border-top-right-radius: @border-radius;
- }
- }
-}
-
-.theme-oo-ui-buttonWidget () {
- .oo-ui-inline-spacing(0.5em);
-}
-
-.theme-oo-ui-actionWidget () {
- &.oo-ui-pendingElement-pending {
- .oo-ui-background-image('@{oo-ui-default-image-path}/textures/pending.gif');
- }
-}
-
-.theme-oo-ui-popupButtonWidget () {
- &.oo-ui-buttonElement-frameless > .oo-ui-popupWidget {
- // Compensate for icon being inset
- /* @noflip */
- left: 1em;
- }
-
- &.oo-ui-buttonElement-framed > .oo-ui-popupWidget {
- // Compensate for icon being inset
- /* @noflip */
- left: 1.75em;
- }
-}
-
-.theme-oo-ui-toggleButtonWidget () {
- .oo-ui-inline-spacing(0.5em);
-}
-
-.theme-oo-ui-iconWidget () {
- line-height: 2.5em;
- height: @icon-size;
- width: @icon-size;
-
- &.oo-ui-widget-disabled {
- opacity: 0.2;
- }
-}
-
-.theme-oo-ui-indicatorWidget () {
- line-height: 2.5em;
- height: @indicator-size;
- width: @indicator-size;
- margin: @indicator-size / 2;
-
- &.oo-ui-widget-disabled {
- opacity: 0.2;
- }
-}
-
-.theme-oo-ui-dropdownWidget () {
- margin: 0.25em 0;
- width: 100%;
- max-width: 50em;
-
- .oo-ui-inline-spacing(0.5em);
-
- &-handle {
- height: 2.5em;
- border: 1px solid #ccc;
- border-radius: 0.1em;
-
- .oo-ui-indicatorElement-indicator {
- right: 0;
- }
-
- .oo-ui-iconElement-icon {
- left: 0.25em;
- }
-
- .oo-ui-labelElement-label {
- line-height: 2.5em;
- margin: 0 1em;
- }
-
- .oo-ui-indicatorElement-indicator {
- top: 0;
- width: @indicator-size;
- height: @indicator-size;
- margin: 0.775em;
- }
-
- .oo-ui-iconElement-icon {
- top: 0;
- width: @icon-size;
- height: @icon-size;
- margin: 0.3em;
- }
- }
-
- &:hover .oo-ui-dropdownWidget-handle {
- border-color: #aaa;
- }
-
- &.oo-ui-widget-disabled {
- .oo-ui-dropdownWidget-handle {
- color: #ccc;
- text-shadow: 0 1px 1px #fff;
- border-color: #ddd;
- background-color: #f3f3f3;
- }
- .oo-ui-indicatorElement-indicator {
- opacity: 0.2;
- }
- }
-
- &.oo-ui-iconElement .oo-ui-dropdownWidget-handle .oo-ui-labelElement-label {
- margin-left: 3em;
- }
-
- &.oo-ui-indicatorElement .oo-ui-dropdownWidget-handle .oo-ui-labelElement-label {
- margin-right: 2em;
- }
-
- .oo-ui-selectWidget {
- border-top-color: #fff;
- }
-}
-
-.theme-oo-ui-inputWidget () {
- .oo-ui-inline-spacing(0.5em);
-}
-
-.theme-oo-ui-buttonInputWidget () {}
-
-.theme-oo-ui-checkboxInputWidget () {
- position: relative;
- line-height: @input-size;
- // Prevent the fake span from jumping to the next line of text
- white-space: nowrap;
-
- * {
- font: inherit;
- vertical-align: middle;
- }
-
- // This input element is visually replaced by the the span that follows
- input[type="checkbox"] {
- // Use opacity so that VoiceOver software can still identify it
- opacity: 0;
- // Render "on top of" the span, so that it's still clickable
- z-index: 1;
- position: relative;
-
- // Having margin would offset the input from where the span is absolutely positioned,
- // making only the overlap region receive events
- margin: 0;
-
- // Ensure the invisible input takes up the required width
- width: @input-size;
- height: @input-size;
-
- // Needed for Firefox mobile (See bug 71750 to workaround default Firefox stylesheet)
- max-width: none;
-
- & + span {
- cursor: pointer;
- .oo-ui-transition(background-size @medium-ease-out-back);
- .oo-ui-box-sizing( border-box );
- position: absolute;
- left: 0;
- border-radius: @border-radius;
- width: @input-size;
- height: @input-size;
- background-color: white;
- border: 1px solid @input-border-color;
- .oo-ui-background-image-svg('@{oo-ui-default-image-path}/icons/check-constructive');
- .oo-ui-background-image-safari('@{oo-ui-default-image-path}/icons/check-constructive');
- background-repeat: no-repeat;
- background-position: center center;
- background-origin: border-box;
- background-size: 0 0;
- }
-
- &:checked + span {
- background-size: 100% 100%;
- }
-
- &:active + span {
- background-color: @input-active-color;
- border-color: @input-active-color;
- }
-
- &:focus + span {
- border-width: @input-focus-border-width;
- }
-
- &:focus:hover + span,
- &:hover + span {
- border-bottom-width: @input-hover-border-bottom-width;
- }
-
- &:disabled + span {
- cursor: default;
- background-color: @input-disabled-color;
- border-color: @input-disabled-color;
- }
-
- &:disabled:checked + span {
- .oo-ui-background-image-svg('@{oo-ui-default-image-path}/icons/check-invert');
- .oo-ui-background-image-safari('@{oo-ui-default-image-path}/icons/check-invert');
- }
- }
-}
-
-.theme-oo-ui-dropdownInputWidget () {
- width: 100%;
- max-width: 50em;
-
- select {
- height: 2.5em;
- padding: 0.5em;
- font-size: inherit;
- font-family: inherit;
- .oo-ui-box-sizing(border-box);
- border: 1px solid #ccc;
- }
-
- &.oo-ui-widget-enabled {
- select:hover,
- select:focus {
- border-color: #aaa;
- outline: none;
- }
- }
-
- &.oo-ui-widget-disabled {
- select {
- color: #ccc;
- border-color: #ddd;
- background-color: #f3f3f3;
- }
- }
-}
-
-.theme-oo-ui-radioInputWidget () {
- position: relative;
- line-height: @input-size;
- // Prevent the fake span from jumping to the next line of text
- white-space: nowrap;
-
- * {
- font: inherit;
- vertical-align: middle;
- }
-
- // This input element is visually replaced by the the span that follows
- input[type="radio"] {
- // Use opacity so that VoiceOver software can still identify it
- opacity: 0;
- // Render "on top of" the span, so that it's still clickable
- z-index: 1;
- position: relative;
-
- // Having margin would offset the input from where the span is absolutely positioned,
- // making only the overlap region receive events
- margin: 0;
-
- // Ensure the invisible input takes up the required width
- width: @input-size;
- height: @input-size;
-
- // Needed for Firefox mobile (See bug 71750 to workaround default Firefox stylesheet)
- max-width: none;
-
- & + span {
- cursor: pointer;
- .oo-ui-transition(background-size @medium-ease-out-back);
- .oo-ui-box-sizing(border-box);
- position: absolute;
- left: 0;
- border-radius: 100%;
- width: @input-size;
- height: @input-size;
- background: white;
- border: 1px solid @input-border-color;
- .oo-ui-background-image-svg('@{oo-ui-default-image-path}/icons/circle-constructive');
- .oo-ui-background-image-safari('@{oo-ui-default-image-path}/icons/circle-constructive');
- background-repeat: no-repeat;
- background-position: center center;
- background-origin: border-box;
- background-size: 0 0;
- }
-
- &:checked + span {
- background-size: 100% 100%;
- }
-
- &:active + span {
- background-color: @input-active-color;
- border-color: @input-active-color;
- }
-
- &:focus + span {
- border-width: @input-focus-border-width;
- }
-
- &:focus:hover + span,
- &:hover + span {
- border-bottom-width: @input-hover-border-bottom-width;
- }
-
- &:disabled + span {
- cursor: default;
- background-color: @input-disabled-color;
- border-color: @input-disabled-color;
- }
-
- &:disabled:checked + span {
- .oo-ui-background-image-svg('@{oo-ui-default-image-path}/icons/circle-invert');
- .oo-ui-background-image-safari('@{oo-ui-default-image-path}/icons/circle-invert');
- }
- }
-}
-
-.theme-oo-ui-textInputWidget () {
- width: 100%;
- max-width: 50em;
-
- input,
- textarea {
- padding: 0.5em;
- margin: 0;
- font-size: inherit;
- font-family: inherit;
- background-color: #fff;
- color: black;
- border: solid 1px #ccc;
- box-shadow: inset 0 0 0 0 @progressive;
- border-radius: 0.1em;
- .oo-ui-transition(box-shadow @quick-ease);
- .oo-ui-box-sizing(border-box);
- }
-
- &-decorated {
- input,
- textarea {
- padding-left: 2em;
- }
- }
-
- &-icon {
- width: 2em;
- }
-
- &.oo-ui-widget-enabled {
- input,
- textarea {
- .oo-ui-transition(
- border @medium-ease-out-sine,
- box-shadow @medium-ease-out-sine
- );
- }
-
- input:focus,
- textarea:focus {
- outline: none;
- border-color: @progressive;
- box-shadow: inset 0 0 0 0.1em @progressive;
- }
-
- input[readonly],
- textarea[readonly] {
- color: #777;
- text-shadow: 0 1px 1px #fff;
-
- &:focus {
- border-color: #ccc;
- box-shadow: inset 0 0 0 0.1em #ccc;
- }
- }
-
- &.oo-ui-flaggedElement-invalid {
- input,
- textarea {
- border-color: red;
- box-shadow: inset 0 0 0 0 red;
- }
-
- input:focus,
- textarea:focus {
- border-color: red;
- box-shadow: inset 0 0 0 0.1em red;
- }
- }
- }
-
- &.oo-ui-widget-disabled {
- input,
- textarea {
- color: #ccc;
- text-shadow: 0 1px 1px #fff;
- border-color: #ddd;
- background-color: #f3f3f3;
- }
- .oo-ui-iconElement-icon,
- .oo-ui-indicatorElement-indicator {
- opacity: 0.2;
- }
- .oo-ui-labelElement-label {
- color: #ddd;
- text-shadow: 0 1px 1px #fff;
- }
- }
-
- &.oo-ui-pendingElement-pending {
- input,
- textarea {
- background-color: transparent;
- .oo-ui-background-image('@{oo-ui-default-image-path}/textures/pending.gif');
- }
- }
-
- &.oo-ui-iconElement {
- input,
- textarea {
- padding-left: 2.75em;
- }
-
- .oo-ui-iconElement-icon {
- left: 0.4em;
- width: @icon-size;
- margin-left: 0.1em;
- height: 100%;
- background-position: right center;
- }
- }
-
- &.oo-ui-indicatorElement {
- input,
- textarea {
- padding-right: @icon-size;
- }
-
- .oo-ui-indicatorElement-indicator {
- width: @indicator-size;
- margin: 0 0.775em;
- height: 100%;
- }
- }
-
- > .oo-ui-labelElement-label {
- padding: 0.4em;
- line-height: 1.5em;
- color: #888;
- }
-
- &-labelPosition-after {
- &.oo-ui-indicatorElement > .oo-ui-labelElement-label {
- margin-right: 2em;
- }
- }
-
- &-labelPosition-before {
- &.oo-ui-iconElement > .oo-ui-labelElement-label {
- margin-left: 2.5em;
- }
- }
-}
-
-.theme-oo-ui-comboBoxWidget () {
- width: 100%;
- max-width: 50em;
-
- .oo-ui-inline-spacing(0.5em);
-
- .oo-ui-textInputWidget {
- input,
- textarea {
- height: 2.35em;
- }
- }
-}
-
-.theme-oo-ui-labelWidget () {}
-
-.theme-oo-ui-optionWidget () {
- padding: 0.25em 0.5em;
- border: none;
-
- &-highlighted {
- background-color: #eee;
- }
-
- .oo-ui-labelElement-label {
- line-height: 1.5em;
- }
-
- .oo-ui-selectWidget-depressed &-selected,
- .oo-ui-selectWidget-pressed &-pressed,
- .oo-ui-selectWidget-pressed &-pressed&-highlighted,
- .oo-ui-selectWidget-pressed &-pressed&-highlighted&-selected {
- background-color: @pressed-color;
- }
-
- &.oo-ui-widget-disabled {
- color: #ccc;
- }
-}
-
-.theme-oo-ui-decoratedOptionWidget () {
- padding: 0.5em 2em 0.5em 3em;
-
- &.oo-ui-iconElement .oo-ui-iconElement-icon,
- &.oo-ui-indicatorElement .oo-ui-indicatorElement-indicator {
- top: 0;
- height: 100%;
- }
-
- &.oo-ui-iconElement .oo-ui-iconElement-icon {
- width: @icon-size;
- left: 0.5em;
- }
-
- &.oo-ui-indicatorElement .oo-ui-indicatorElement-indicator {
- width: @indicator-size;
- right: 0.5em;
- }
-
- &.oo-ui-widget-disabled {
- .oo-ui-iconElement-icon,
- .oo-ui-indicatorElement-indicator {
- opacity: 0.2;
- }
- }
-}
-
-.theme-oo-ui-buttonOptionWidget () {
- padding: 0;
- background-color: transparent;
-
- .oo-ui-buttonElement-button {
- height: @icon-size;
- }
-
- &.oo-ui-iconElement .oo-ui-iconElement-icon {
- margin-top: 0;
- }
-
- &.oo-ui-optionWidget-selected,
- &.oo-ui-optionWidget-pressed,
- &.oo-ui-optionWidget-highlighted {
- background-color: transparent;
- }
-
- // Override DecoratedOptionWidget styles
- &.oo-ui-widget-disabled {
- .oo-ui-iconElement-icon,
- .oo-ui-indicatorElement-indicator {
- opacity: 1;
- }
- }
-}
-
-.theme-oo-ui-radioOptionWidget () {
- padding: 0.25em 0;
- background-color: transparent;
-
- &.oo-ui-optionWidget-selected,
- &.oo-ui-optionWidget-pressed,
- &.oo-ui-optionWidget-highlighted {
- background-color: transparent;
- }
-
- &.oo-ui-labelElement .oo-ui-labelElement-label {
- padding: 0.25em;
- padding-left: 1em;
- }
-
- .oo-ui-radioInputWidget {
- margin-right: 0;
- }
-}
-
-.theme-oo-ui-menuOptionWidget () {
- padding: 0.5em 1em;
-
- &.oo-ui-optionWidget {
- &-selected {
- background-color: @select;
- color: rgba(0,0,0,0.8);
-
- .oo-ui-iconElement-icon {
- display: none;
- }
- }
- &-highlighted {
- background-color: #eee;
- color: black;
- }
- &-selected&-highlighted {
- background-color: @select;
- }
- }
-}
-
-.theme-oo-ui-menuSectionOptionWidget () {
- padding: 0.33em 0.75em;
- color: #888;
-}
-
-.theme-oo-ui-outlineOptionWidget () {
- font-size: 1.1em;
- padding: 0.75em;
-
- &.oo-ui-indicatorElement .oo-ui-labelElement-label {
- padding-right: 1.5em;
- }
-
- &.oo-ui-indicatorElement .oo-ui-indicatorElement-indicator {
- opacity: 0.5;
- }
-
- &-level-0 {
- padding-left: 3.5em;
-
- .oo-ui-iconElement-icon {
- left: 1em;
- }
- }
- &-level-1 {
- padding-left: 5em;
-
- .oo-ui-iconElement-icon {
- left: 2.5em;
- }
- }
-
- &-level-2 {
- padding-left: 6.5em;
-
- .oo-ui-iconElement-icon {
- left: 4em;
- }
- }
-
- .oo-ui-selectWidget-depressed &.oo-ui-optionWidget-selected {
- background-color: @pressed-color;
- text-shadow: 0 1px 1px #fff;
- }
-
- &.oo-ui-flaggedElement-important {
- font-weight: bold;
- }
-
- &.oo-ui-flaggedElement-placeholder {
- font-style: italic;
- }
-
- &.oo-ui-flaggedElement-empty {
- .oo-ui-iconElement-icon {
- opacity: 0.5;
- }
- .oo-ui-labelElement-label {
- color: #777;
- }
- }
-}
-
-.theme-oo-ui-tabOptionWidget () {
- padding: 0.35em 1em;
- margin: 0.5em 0 0 0.75em;
- border: 1px solid transparent;
- border-bottom: none;
- border-top-left-radius: @border-radius;
- border-top-right-radius: @border-radius;
- color: #666;
- font-weight: bold;
-
- &.oo-ui-widget-enabled {
- &:hover {
- background-color: rgba(255, 255, 255, 0.3);
- }
-
- &:active {
- background-color: rgba(255, 255, 255, 0.8);
- }
- }
-
- &.oo-ui-indicatorElement .oo-ui-labelElement-label {
- padding-right: 1.5em;
- }
-
- &.oo-ui-indicatorElement .oo-ui-indicatorElement-indicator {
- opacity: 0.5;
- }
-
- .oo-ui-selectWidget-pressed &.oo-ui-optionWidget-selected,
- .oo-ui-selectWidget-depressed &.oo-ui-optionWidget-selected,
- &.oo-ui-optionWidget-selected:hover {
- background-color: #fff;
- color: #333;
- }
-}
-
-.theme-oo-ui-popupWidget () {
- &-popup {
- border: 1px solid #aaa;
- border-radius: 0.2em;
- background-color: #fff;
- box-shadow: inset 0 -0.2em 0 0 rgba(0, 0, 0, 0.2);
- }
-
- @anchor-size: 9px;
-
- &-anchored {
- .oo-ui-popupWidget-popup {
- margin-top: @anchor-size;
- }
-
- .oo-ui-popupWidget-anchor:before,
- .oo-ui-popupWidget-anchor:after {
- content: "";
- position: absolute;
- width: 0;
- height: 0;
- border-style: solid;
- border-color: transparent;
- border-top: 0;
- }
-
- .oo-ui-popupWidget-anchor:before {
- bottom: -@anchor-size - 1px;
- left: -@anchor-size;
- border-bottom-color: #888;
- border-width: @anchor-size + 1px;
- }
-
- .oo-ui-popupWidget-anchor:after {
- bottom: -@anchor-size - 1px;
- left: -@anchor-size + 1px;
- border-bottom-color: #fff;
- border-width: @anchor-size;
- }
- }
-
- &-transitioning .oo-ui-popupWidget-popup {
- .oo-ui-transition(width @quick-ease, height @quick-ease, left @quick-ease);
- }
-
- &-head {
- height: 2.5em;
-
- .oo-ui-buttonWidget {
- margin: 0.25em;
- }
-
- .oo-ui-labelElement-label {
- margin: 0.75em 1em;
- }
- }
-
- &-body-padded {
- padding: 0 1em;
- }
-}
-
-.theme-oo-ui-searchWidget () {
- &-query {
- height: 4em;
- padding: 0 1em;
- border-bottom: 1px solid #ccc;
-
- .oo-ui-textInputWidget {
- margin: 0.75em 0;
- }
- }
-
- &-results {
- top: 4em;
- padding: 1em;
- line-height: 0;
- }
-}
-
-.theme-oo-ui-selectWidget () {}
-
-.theme-oo-ui-buttonSelectWidget () {
- border-radius: @border-radius;
-
- .oo-ui-inline-spacing(0.5em);
-
- .oo-ui-buttonOptionWidget {
- .oo-ui-buttonElement-button {
- border-radius: 0;
- margin-left: -1px;
- }
-
- &:first-child .oo-ui-buttonElement-button {
- border-bottom-left-radius: @border-radius;
- border-top-left-radius: @border-radius;
- margin-left: 0;
- }
-
- &:last-child .oo-ui-buttonElement-button {
- border-bottom-right-radius: @border-radius;
- border-top-right-radius: @border-radius;
- }
- }
-}
-
-.theme-oo-ui-radioSelectWidget () {}
-
-.theme-oo-ui-menuSelectWidget () {
- background: #fff;
- margin-top: -1px;
- border: 1px solid #aaa;
- border-radius: 0 0 0.2em 0.2em;
- padding-bottom: 0.25em;
- box-shadow: inset 0 -0.2em 0 0 rgba(0, 0, 0, 0.2), 0 0.1em 0 0 rgba(0, 0, 0, 0.2);
-}
-
-.theme-oo-ui-textInputMenuSelectWidget () {}
-
-.theme-oo-ui-outlineSelectWidget () {}
-
-.theme-oo-ui-tabSelectWidget () {
- background-color: #ddd;
-}
-
-.theme-oo-ui-toggleSwitchWidget () {
- @travelDistance: 2em;
- height: 2em;
- width: @travelDistance + 2em;
- border-radius: 1em;
- border: 1px #ddd solid;
-
- .oo-ui-inline-spacing(0.5em);
-
- &-grip {
- top: 0.25em;
- left: 0.25em;
- width: 1.5em;
- height: 1.5em;
- margin-top: -1px;
- border-radius: 1em;
- border: 1px #ddd solid;
- background-color: #f7f7f7;
-
- .oo-ui-transition(left @quick-ease, margin-left @quick-ease);
- }
-
- &-glow {
- border-radius: 1em;
- background-color: #f7f7f7;
-
- .oo-ui-transition(background-color @quick-ease);
- }
-
- &.oo-ui-toggleWidget-on {
- .oo-ui-toggleSwitchWidget-grip {
- left: @travelDistance + 0.25em;
- margin-left: -2px;
- }
- }
-
- &.oo-ui-toggleWidget-off {
- .oo-ui-toggleSwitchWidget-glow {
- display: block;
- }
- .oo-ui-toggleSwitchWidget-grip {
- left: 0.25em;
- margin-left: 0;
- }
- }
-
- &.oo-ui-widget-enabled {
- border: 1px #ccc solid;
-
- &:hover {
- border-color: #aaa;
- }
-
- .oo-ui-toggleSwitchWidget-grip {
- background-color: #fff;
- border-color: #aaa;
- }
-
- &.oo-ui-toggleWidget-on {
- .oo-ui-toggleSwitchWidget-glow {
- background-color: @pressed-color;
- }
- }
-
- &.oo-ui-toggleWidget-off {
- .oo-ui-toggleSwitchWidget-glow {
- background-color: #fff;
- }
- }
- }
-}
-
-.theme-oo-ui-progressBarWidget () {
- max-width: 50em;
- border: 1px solid #ccc;
- border-radius: 0.1em;
- overflow: hidden;
-
- &-bar {
- height: 1em;
- background: #ddd;
- .oo-ui-transition(width 200ms, margin-left 200ms);
- }
- &-indeterminate {
- .oo-ui-progressBarWidget-bar {
- .oo-ui-animation(oo-ui-progressBarWidget-slide 2s infinite linear);
- width: 40%;
- margin-left: -10%;
- border-left-width: 1px;
- }
- }
- &.oo-ui-widget-disabled {
- opacity: 0.6;
- }
-}
-
-.oo-ui-progressBarWidget-slide-frames () {
- from { margin-left: -40%; }
- to { margin-left: 100%; }
-}
-@-webkit-keyframes oo-ui-progressBarWidget-slide { .oo-ui-progressBarWidget-slide-frames }
-@-moz-keyframes oo-ui-progressBarWidget-slide { .oo-ui-progressBarWidget-slide-frames }
-@-ms-keyframes oo-ui-progressBarWidget-slide { .oo-ui-progressBarWidget-slide-frames }
-@-o-keyframes oo-ui-progressBarWidget-slide { .oo-ui-progressBarWidget-slide-frames }
-@keyframes oo-ui-progressBarWidget-slide { .oo-ui-progressBarWidget-slide-frames }
diff --git a/vendor/oojs/oojs-ui/src/themes/mediawiki/windows.less b/vendor/oojs/oojs-ui/src/themes/mediawiki/windows.less
deleted file mode 100644
index 423233ce..00000000
--- a/vendor/oojs/oojs-ui/src/themes/mediawiki/windows.less
+++ /dev/null
@@ -1,300 +0,0 @@
-@import 'common';
-
-.theme-oo-ui-window () {
- background: transparent;
-}
-
-.theme-oo-ui-dialog () {
- &-content > .oo-ui-window-body {
- outline: 1px solid #aaa;
- }
-}
-
-.theme-oo-ui-messageDialog () {
- &-title,
- &-message {
- display: block;
- text-align: center;
- padding-top: 0.5em;
- }
-
- &-title {
- font-size: 1.5em;
- line-height: 1em;
- color: #000;
- }
-
- &-message {
- font-size: 0.9em;
- line-height: 1.25em;
- color: #666;
-
- &-verbose {
- font-size: 1.1em;
- line-height: 1.5em;
- text-align: left;
- }
- }
-
- &-actions {
- &-horizontal {
- .oo-ui-actionWidget {
- border-right: 1px solid #e5e5e5;
-
- &:last-child {
- border-right-width: 0;
- }
- }
- }
-
- &-vertical {
- .oo-ui-actionWidget {
- border-bottom: 1px solid #e5e5e5;
-
- &:last-child {
- border-bottom-width: 0;
- }
- }
- }
-
- .oo-ui-actionWidget {
- height: 3.4em;
-
- &.oo-ui-labelElement .oo-ui-labelElement-label {
- text-align: center;
- line-height: 3.4em;
- padding: 0 2em;
- }
-
- &:hover {
- background-color: rgba(0,0,0,0.05);
- }
-
- &:active {
- background-color: rgba(0,0,0,0.1);
- }
-
- &.oo-ui-flaggedElement {
- &-progressive {
- &:hover {
- background-color: rgba(8,126,204,0.05);
- }
-
- &:active {
- background-color: rgba(8,126,204,0.1);
- }
-
- .oo-ui-labelElement-label {
- font-weight: bold;
- }
- }
-
- &-constructive {
- &:hover {
- background-color: rgba(118,171,54,0.05);
- }
-
- &:active {
- background-color: rgba(118,171,54,0.1);
- }
- }
-
- &-destructive {
- &:hover {
- background-color: rgba(212,83,83,0.05);
- }
-
- &:active {
- background-color: rgba(212,83,83,0.1);
- }
- }
- }
- }
- }
-}
-
-.theme-oo-ui-processDialog () {
- &-content {
- .oo-ui-window-head {
- height: 3.4em;
-
- &.oo-ui-pendingElement-pending {
- .oo-ui-background-image('@{oo-ui-default-image-path}/textures/pending.gif');
- }
- }
-
- .oo-ui-window-body {
- top: 3.4em;
- outline: 1px solid rgba(0,0,0,0.2);
- }
- }
-
- &-navigation {
- position: relative;
- height: 3.4em;
- padding: 0 1em;
- }
-
- &-location {
- padding: 0.75em 0;
- height: @icon-size;
- cursor: default;
- text-align: center;
- }
-
- &-title {
- font-weight: bold;
- line-height: @icon-size;
- }
-
- &-actions {
- &-safe,
- &-primary,
- &-other {
- .oo-ui-actionWidget {
- .oo-ui-buttonElement-button {
- min-width: @icon-size;
- min-height: @icon-size;
- }
-
- .oo-ui-labelElement-label {
- line-height: @icon-size;
- }
-
- &.oo-ui-iconElement .oo-ui-iconElement-icon {
- margin-top: -0.125em;
- }
-
- &.oo-ui-buttonElement-framed {
- margin: 0.75em 0 0.75em 0.75em;
- .oo-ui-buttonElement-button {
- padding: 0 1em;
- vertical-align: middle;
- }
- }
- }
- }
-
- &-safe,
- &-primary {
- .oo-ui-actionWidget {
- &:hover {
- background-color: rgba(0,0,0,0.05);
- }
-
- &:active {
- background-color: rgba(0,0,0,0.1);
- }
-
- &.oo-ui-buttonElement-framed {
- margin: 0.75em;
- .oo-ui-buttonElement-button {
- /* Adjust for border so text aligns with title */
- margin: -1px;
- }
- }
-
- &.oo-ui-flaggedElement {
- &-progressive {
- &:hover {
- background-color: rgba(8,126,204,0.05);
- }
-
- &:active {
- background-color: rgba(8,126,204,0.1);
- }
-
- .oo-ui-labelElement-label {
- font-weight: bold;
- }
- }
-
- &-constructive {
- &:hover {
- background-color: rgba(118,171,54,0.05);
- }
-
- &:active {
- background-color: rgba(118,171,54,0.1);
- }
- }
-
- &-destructive {
- &:hover {
- background-color: rgba(212,83,83,0.05);
- }
-
- &:active {
- background-color: rgba(212,83,83,0.1);
- }
- }
- }
- }
- }
- }
-
- > .oo-ui-window-frame {
- min-height: 5em;
- }
-
- &-errors {
- background-color: rgba(255,255,255,0.9);
- padding: 3em 3em 1.5em 3em;
- text-align: center;
-
- .oo-ui-buttonWidget {
- margin: 2em 1em 2em 1em;
- }
-
- &-title {
- font-size: 1.5em;
- color: #000;
- margin-bottom: 2em;
- }
- }
-
- &-error {
- text-align: left;
- margin: 1em;
- padding: 1em;
- border: 1px solid #ff9e9e;
- background-color: #fff7f7;
- border-radius: 0.25em;
- }
-}
-
-.theme-oo-ui-windowManager () {
- &-modal > .oo-ui-dialog {
- background-color: rgba(255,255,255,0.5);
- opacity: 0;
-
- .oo-ui-transition(opacity 250ms ease-in-out);
-
- > .oo-ui-window-frame {
- top: 1em;
- bottom: 1em;
- background-color: #fff;
-
- opacity: 0;
- .oo-ui-transform(scale(0.5));
- .oo-ui-transition(all 250ms ease-in-out);
- }
-
- &.oo-ui-window-ready {
- /* Fade window overlay */
- opacity: 1;
-
- > .oo-ui-window-frame {
- /* Fade frame */
- opacity: 1;
- .oo-ui-transform(scale(1));
- }
- }
- }
-
- &-modal&-floating > .oo-ui-dialog > .oo-ui-window-frame {
- border: 1px solid #aaa;
- border-radius: 0.2em;
- box-shadow: inset 0 -0.2em 0 0 rgba(0,0,0,0.2);
- }
-}
diff --git a/vendor/oojs/oojs-ui/src/toolgroups/BarToolGroup.js b/vendor/oojs/oojs-ui/src/toolgroups/BarToolGroup.js
deleted file mode 100644
index 038894d6..00000000
--- a/vendor/oojs/oojs-ui/src/toolgroups/BarToolGroup.js
+++ /dev/null
@@ -1,35 +0,0 @@
-/**
- * Horizontal bar layout of tools as icon buttons.
- *
- * @class
- * @extends OO.ui.ToolGroup
- *
- * @constructor
- * @param {OO.ui.Toolbar} toolbar
- * @param {Object} [config] Configuration options
- */
-OO.ui.BarToolGroup = function OoUiBarToolGroup( toolbar, config ) {
- // Allow passing positional parameters inside the config object
- if ( OO.isPlainObject( toolbar ) && config === undefined ) {
- config = toolbar;
- toolbar = config.toolbar;
- }
-
- // Parent constructor
- OO.ui.BarToolGroup.super.call( this, toolbar, config );
-
- // Initialization
- this.$element.addClass( 'oo-ui-barToolGroup' );
-};
-
-/* Setup */
-
-OO.inheritClass( OO.ui.BarToolGroup, OO.ui.ToolGroup );
-
-/* Static Properties */
-
-OO.ui.BarToolGroup.static.titleTooltips = true;
-
-OO.ui.BarToolGroup.static.accelTooltips = true;
-
-OO.ui.BarToolGroup.static.name = 'bar';
diff --git a/vendor/oojs/oojs-ui/src/toolgroups/ListToolGroup.js b/vendor/oojs/oojs-ui/src/toolgroups/ListToolGroup.js
deleted file mode 100644
index e78f507e..00000000
--- a/vendor/oojs/oojs-ui/src/toolgroups/ListToolGroup.js
+++ /dev/null
@@ -1,133 +0,0 @@
-/**
- * Drop down list layout of tools as labeled icon buttons.
- *
- * This layout allows some tools to be collapsible, controlled by a "More" / "Fewer" option at the
- * bottom of the main list. These are not automatically positioned at the bottom of the list; you
- * may want to use the 'promote' and 'demote' configuration options to achieve this.
- *
- * @class
- * @extends OO.ui.PopupToolGroup
- *
- * @constructor
- * @param {OO.ui.Toolbar} toolbar
- * @param {Object} [config] Configuration options
- * @cfg {Array} [allowCollapse] List of tools that can be collapsed. Remaining tools will be always
- * shown.
- * @cfg {Array} [forceExpand] List of tools that *may not* be collapsed. All remaining tools will be
- * allowed to be collapsed.
- * @cfg {boolean} [expanded=false] Whether the collapsible tools are expanded by default
- */
-OO.ui.ListToolGroup = function OoUiListToolGroup( toolbar, config ) {
- // Allow passing positional parameters inside the config object
- if ( OO.isPlainObject( toolbar ) && config === undefined ) {
- config = toolbar;
- toolbar = config.toolbar;
- }
-
- // Configuration initialization
- config = config || {};
-
- // Properties (must be set before parent constructor, which calls #populate)
- this.allowCollapse = config.allowCollapse;
- this.forceExpand = config.forceExpand;
- this.expanded = config.expanded !== undefined ? config.expanded : false;
- this.collapsibleTools = [];
-
- // Parent constructor
- OO.ui.ListToolGroup.super.call( this, toolbar, config );
-
- // Initialization
- this.$element.addClass( 'oo-ui-listToolGroup' );
-};
-
-/* Setup */
-
-OO.inheritClass( OO.ui.ListToolGroup, OO.ui.PopupToolGroup );
-
-/* Static Properties */
-
-OO.ui.ListToolGroup.static.name = 'list';
-
-/* Methods */
-
-/**
- * @inheritdoc
- */
-OO.ui.ListToolGroup.prototype.populate = function () {
- var i, len, allowCollapse = [];
-
- OO.ui.ListToolGroup.super.prototype.populate.call( this );
-
- // Update the list of collapsible tools
- if ( this.allowCollapse !== undefined ) {
- allowCollapse = this.allowCollapse;
- } else if ( this.forceExpand !== undefined ) {
- allowCollapse = OO.simpleArrayDifference( Object.keys( this.tools ), this.forceExpand );
- }
-
- this.collapsibleTools = [];
- for ( i = 0, len = allowCollapse.length; i < len; i++ ) {
- if ( this.tools[ allowCollapse[ i ] ] !== undefined ) {
- this.collapsibleTools.push( this.tools[ allowCollapse[ i ] ] );
- }
- }
-
- // Keep at the end, even when tools are added
- this.$group.append( this.getExpandCollapseTool().$element );
-
- this.getExpandCollapseTool().toggle( this.collapsibleTools.length !== 0 );
- this.updateCollapsibleState();
-};
-
-OO.ui.ListToolGroup.prototype.getExpandCollapseTool = function () {
- if ( this.expandCollapseTool === undefined ) {
- var ExpandCollapseTool = function () {
- ExpandCollapseTool.super.apply( this, arguments );
- };
-
- OO.inheritClass( ExpandCollapseTool, OO.ui.Tool );
-
- ExpandCollapseTool.prototype.onSelect = function () {
- this.toolGroup.expanded = !this.toolGroup.expanded;
- this.toolGroup.updateCollapsibleState();
- this.setActive( false );
- };
- ExpandCollapseTool.prototype.onUpdateState = function () {
- // Do nothing. Tool interface requires an implementation of this function.
- };
-
- ExpandCollapseTool.static.name = 'more-fewer';
-
- this.expandCollapseTool = new ExpandCollapseTool( this );
- }
- return this.expandCollapseTool;
-};
-
-/**
- * @inheritdoc
- */
-OO.ui.ListToolGroup.prototype.onMouseKeyUp = function ( e ) {
- // Do not close the popup when the user wants to show more/fewer tools
- if (
- $( e.target ).closest( '.oo-ui-tool-name-more-fewer' ).length &&
- ( e.which === 1 || e.which === OO.ui.Keys.SPACE || e.which === OO.ui.Keys.ENTER )
- ) {
- // HACK: Prevent the popup list from being hidden. Skip the PopupToolGroup implementation (which
- // hides the popup list when a tool is selected) and call ToolGroup's implementation directly.
- return OO.ui.ListToolGroup.super.super.prototype.onMouseKeyUp.call( this, e );
- } else {
- return OO.ui.ListToolGroup.super.prototype.onMouseKeyUp.call( this, e );
- }
-};
-
-OO.ui.ListToolGroup.prototype.updateCollapsibleState = function () {
- var i, len;
-
- this.getExpandCollapseTool()
- .setIcon( this.expanded ? 'collapse' : 'expand' )
- .setTitle( OO.ui.msg( this.expanded ? 'ooui-toolgroup-collapse' : 'ooui-toolgroup-expand' ) );
-
- for ( i = 0, len = this.collapsibleTools.length; i < len; i++ ) {
- this.collapsibleTools[ i ].toggle( this.expanded );
- }
-};
diff --git a/vendor/oojs/oojs-ui/src/toolgroups/MenuToolGroup.js b/vendor/oojs/oojs-ui/src/toolgroups/MenuToolGroup.js
deleted file mode 100644
index aef69a93..00000000
--- a/vendor/oojs/oojs-ui/src/toolgroups/MenuToolGroup.js
+++ /dev/null
@@ -1,58 +0,0 @@
-/**
- * Drop down menu layout of tools as selectable menu items.
- *
- * @class
- * @extends OO.ui.PopupToolGroup
- *
- * @constructor
- * @param {OO.ui.Toolbar} toolbar
- * @param {Object} [config] Configuration options
- */
-OO.ui.MenuToolGroup = function OoUiMenuToolGroup( toolbar, config ) {
- // Allow passing positional parameters inside the config object
- if ( OO.isPlainObject( toolbar ) && config === undefined ) {
- config = toolbar;
- toolbar = config.toolbar;
- }
-
- // Configuration initialization
- config = config || {};
-
- // Parent constructor
- OO.ui.MenuToolGroup.super.call( this, toolbar, config );
-
- // Events
- this.toolbar.connect( this, { updateState: 'onUpdateState' } );
-
- // Initialization
- this.$element.addClass( 'oo-ui-menuToolGroup' );
-};
-
-/* Setup */
-
-OO.inheritClass( OO.ui.MenuToolGroup, OO.ui.PopupToolGroup );
-
-/* Static Properties */
-
-OO.ui.MenuToolGroup.static.name = 'menu';
-
-/* Methods */
-
-/**
- * Handle the toolbar state being updated.
- *
- * When the state changes, the title of each active item in the menu will be joined together and
- * used as a label for the group. The label will be empty if none of the items are active.
- */
-OO.ui.MenuToolGroup.prototype.onUpdateState = function () {
- var name,
- labelTexts = [];
-
- for ( name in this.tools ) {
- if ( this.tools[ name ].isActive() ) {
- labelTexts.push( this.tools[ name ].getTitle() );
- }
- }
-
- this.setLabel( labelTexts.join( ', ' ) || ' ' );
-};
diff --git a/vendor/oojs/oojs-ui/src/toolgroups/PopupToolGroup.js b/vendor/oojs/oojs-ui/src/toolgroups/PopupToolGroup.js
deleted file mode 100644
index 0fbdf4fc..00000000
--- a/vendor/oojs/oojs-ui/src/toolgroups/PopupToolGroup.js
+++ /dev/null
@@ -1,187 +0,0 @@
-/**
- * Popup list of tools with an icon and optional label.
- *
- * @abstract
- * @class
- * @extends OO.ui.ToolGroup
- * @mixins OO.ui.IconElement
- * @mixins OO.ui.IndicatorElement
- * @mixins OO.ui.LabelElement
- * @mixins OO.ui.TitledElement
- * @mixins OO.ui.ClippableElement
- * @mixins OO.ui.TabIndexedElement
- *
- * @constructor
- * @param {OO.ui.Toolbar} toolbar
- * @param {Object} [config] Configuration options
- * @cfg {string} [header] Text to display at the top of the pop-up
- */
-OO.ui.PopupToolGroup = function OoUiPopupToolGroup( toolbar, config ) {
- // Allow passing positional parameters inside the config object
- if ( OO.isPlainObject( toolbar ) && config === undefined ) {
- config = toolbar;
- toolbar = config.toolbar;
- }
-
- // Configuration initialization
- config = config || {};
-
- // Parent constructor
- OO.ui.PopupToolGroup.super.call( this, toolbar, config );
-
- // Properties
- this.active = false;
- this.dragging = false;
- this.onBlurHandler = this.onBlur.bind( this );
- this.$handle = $( '<span>' );
-
- // Mixin constructors
- OO.ui.IconElement.call( this, config );
- OO.ui.IndicatorElement.call( this, config );
- OO.ui.LabelElement.call( this, config );
- OO.ui.TitledElement.call( this, config );
- OO.ui.ClippableElement.call( this, $.extend( {}, config, { $clippable: this.$group } ) );
- OO.ui.TabIndexedElement.call( this, $.extend( {}, config, { $tabIndexed: this.$handle } ) );
-
- // Events
- this.$handle.on( {
- keydown: this.onHandleMouseKeyDown.bind( this ),
- keyup: this.onHandleMouseKeyUp.bind( this ),
- mousedown: this.onHandleMouseKeyDown.bind( this ),
- mouseup: this.onHandleMouseKeyUp.bind( this )
- } );
-
- // Initialization
- this.$handle
- .addClass( 'oo-ui-popupToolGroup-handle' )
- .append( this.$icon, this.$label, this.$indicator );
- // If the pop-up should have a header, add it to the top of the toolGroup.
- // Note: If this feature is useful for other widgets, we could abstract it into an
- // OO.ui.HeaderedElement mixin constructor.
- if ( config.header !== undefined ) {
- this.$group
- .prepend( $( '<span>' )
- .addClass( 'oo-ui-popupToolGroup-header' )
- .text( config.header )
- );
- }
- this.$element
- .addClass( 'oo-ui-popupToolGroup' )
- .prepend( this.$handle );
-};
-
-/* Setup */
-
-OO.inheritClass( OO.ui.PopupToolGroup, OO.ui.ToolGroup );
-OO.mixinClass( OO.ui.PopupToolGroup, OO.ui.IconElement );
-OO.mixinClass( OO.ui.PopupToolGroup, OO.ui.IndicatorElement );
-OO.mixinClass( OO.ui.PopupToolGroup, OO.ui.LabelElement );
-OO.mixinClass( OO.ui.PopupToolGroup, OO.ui.TitledElement );
-OO.mixinClass( OO.ui.PopupToolGroup, OO.ui.ClippableElement );
-OO.mixinClass( OO.ui.PopupToolGroup, OO.ui.TabIndexedElement );
-
-/* Methods */
-
-/**
- * @inheritdoc
- */
-OO.ui.PopupToolGroup.prototype.setDisabled = function () {
- // Parent method
- OO.ui.PopupToolGroup.super.prototype.setDisabled.apply( this, arguments );
-
- if ( this.isDisabled() && this.isElementAttached() ) {
- this.setActive( false );
- }
-};
-
-/**
- * Handle focus being lost.
- *
- * The event is actually generated from a mouseup/keyup, so it is not a normal blur event object.
- *
- * @param {jQuery.Event} e Mouse up or key up event
- */
-OO.ui.PopupToolGroup.prototype.onBlur = function ( e ) {
- // Only deactivate when clicking outside the dropdown element
- if ( $( e.target ).closest( '.oo-ui-popupToolGroup' )[ 0 ] !== this.$element[ 0 ] ) {
- this.setActive( false );
- }
-};
-
-/**
- * @inheritdoc
- */
-OO.ui.PopupToolGroup.prototype.onMouseKeyUp = function ( e ) {
- // Only close toolgroup when a tool was actually selected
- if (
- !this.isDisabled() && this.pressed && this.pressed === this.getTargetTool( e ) &&
- ( e.which === 1 || e.which === OO.ui.Keys.SPACE || e.which === OO.ui.Keys.ENTER )
- ) {
- this.setActive( false );
- }
- return OO.ui.PopupToolGroup.super.prototype.onMouseKeyUp.call( this, e );
-};
-
-/**
- * Handle mouse up and key up events.
- *
- * @param {jQuery.Event} e Mouse up or key up event
- */
-OO.ui.PopupToolGroup.prototype.onHandleMouseKeyUp = function ( e ) {
- if (
- !this.isDisabled() &&
- ( e.which === 1 || e.which === OO.ui.Keys.SPACE || e.which === OO.ui.Keys.ENTER )
- ) {
- return false;
- }
-};
-
-/**
- * Handle mouse down and key down events.
- *
- * @param {jQuery.Event} e Mouse down or key down event
- */
-OO.ui.PopupToolGroup.prototype.onHandleMouseKeyDown = function ( e ) {
- if (
- !this.isDisabled() &&
- ( e.which === 1 || e.which === OO.ui.Keys.SPACE || e.which === OO.ui.Keys.ENTER )
- ) {
- this.setActive( !this.active );
- return false;
- }
-};
-
-/**
- * Switch into active mode.
- *
- * When active, mouseup events anywhere in the document will trigger deactivation.
- */
-OO.ui.PopupToolGroup.prototype.setActive = function ( value ) {
- value = !!value;
- if ( this.active !== value ) {
- this.active = value;
- if ( value ) {
- this.getElementDocument().addEventListener( 'mouseup', this.onBlurHandler, true );
- this.getElementDocument().addEventListener( 'keyup', this.onBlurHandler, true );
-
- // Try anchoring the popup to the left first
- this.$element.addClass( 'oo-ui-popupToolGroup-active oo-ui-popupToolGroup-left' );
- this.toggleClipping( true );
- if ( this.isClippedHorizontally() ) {
- // Anchoring to the left caused the popup to clip, so anchor it to the right instead
- this.toggleClipping( false );
- this.$element
- .removeClass( 'oo-ui-popupToolGroup-left' )
- .addClass( 'oo-ui-popupToolGroup-right' );
- this.toggleClipping( true );
- }
- } else {
- this.getElementDocument().removeEventListener( 'mouseup', this.onBlurHandler, true );
- this.getElementDocument().removeEventListener( 'keyup', this.onBlurHandler, true );
- this.$element.removeClass(
- 'oo-ui-popupToolGroup-active oo-ui-popupToolGroup-left oo-ui-popupToolGroup-right'
- );
- this.toggleClipping( false );
- }
- }
-};
diff --git a/vendor/oojs/oojs-ui/src/tools/PopupTool.js b/vendor/oojs/oojs-ui/src/tools/PopupTool.js
deleted file mode 100644
index 98f93d75..00000000
--- a/vendor/oojs/oojs-ui/src/tools/PopupTool.js
+++ /dev/null
@@ -1,59 +0,0 @@
-/**
- * Tool that shows a popup when selected.
- *
- * @abstract
- * @class
- * @extends OO.ui.Tool
- * @mixins OO.ui.PopupElement
- *
- * @constructor
- * @param {OO.ui.ToolGroup} toolGroup
- * @param {Object} [config] Configuration options
- */
-OO.ui.PopupTool = function OoUiPopupTool( toolGroup, config ) {
- // Allow passing positional parameters inside the config object
- if ( OO.isPlainObject( toolGroup ) && config === undefined ) {
- config = toolGroup;
- toolGroup = config.toolGroup;
- }
-
- // Parent constructor
- OO.ui.PopupTool.super.call( this, toolGroup, config );
-
- // Mixin constructors
- OO.ui.PopupElement.call( this, config );
-
- // Initialization
- this.$element
- .addClass( 'oo-ui-popupTool' )
- .append( this.popup.$element );
-};
-
-/* Setup */
-
-OO.inheritClass( OO.ui.PopupTool, OO.ui.Tool );
-OO.mixinClass( OO.ui.PopupTool, OO.ui.PopupElement );
-
-/* Methods */
-
-/**
- * Handle the tool being selected.
- *
- * @inheritdoc
- */
-OO.ui.PopupTool.prototype.onSelect = function () {
- if ( !this.isDisabled() ) {
- this.popup.toggle();
- }
- this.setActive( false );
- return false;
-};
-
-/**
- * Handle the toolbar state being updated.
- *
- * @inheritdoc
- */
-OO.ui.PopupTool.prototype.onUpdateState = function () {
- this.setActive( false );
-};
diff --git a/vendor/oojs/oojs-ui/src/tools/ToolGroupTool.js b/vendor/oojs/oojs-ui/src/tools/ToolGroupTool.js
deleted file mode 100644
index b8f70a3a..00000000
--- a/vendor/oojs/oojs-ui/src/tools/ToolGroupTool.js
+++ /dev/null
@@ -1,96 +0,0 @@
-/**
- * Tool that has a tool group inside. This is a bad workaround for the lack of proper hierarchical
- * menus in toolbars (T74159).
- *
- * @abstract
- * @class
- * @extends OO.ui.Tool
- *
- * @constructor
- * @param {OO.ui.ToolGroup} toolGroup
- * @param {Object} [config] Configuration options
- */
-OO.ui.ToolGroupTool = function OoUiToolGroupTool( toolGroup, config ) {
- // Allow passing positional parameters inside the config object
- if ( OO.isPlainObject( toolGroup ) && config === undefined ) {
- config = toolGroup;
- toolGroup = config.toolGroup;
- }
-
- // Parent constructor
- OO.ui.ToolGroupTool.super.call( this, toolGroup, config );
-
- // Properties
- this.innerToolGroup = this.createGroup( this.constructor.static.groupConfig );
-
- // Events
- this.innerToolGroup.connect( this, { disable: 'onToolGroupDisable' } );
-
- // Initialization
- this.$link.remove();
- this.$element
- .addClass( 'oo-ui-toolGroupTool' )
- .append( this.innerToolGroup.$element );
-};
-
-/* Setup */
-
-OO.inheritClass( OO.ui.ToolGroupTool, OO.ui.Tool );
-
-/* Static Properties */
-
-/**
- * Tool group configuration. See OO.ui.Toolbar#setup for the accepted values.
- *
- * @property {Object.<string,Array>}
- */
-OO.ui.ToolGroupTool.static.groupConfig = {};
-
-/* Methods */
-
-/**
- * Handle the tool being selected.
- *
- * @inheritdoc
- */
-OO.ui.ToolGroupTool.prototype.onSelect = function () {
- this.innerToolGroup.setActive( !this.innerToolGroup.active );
- return false;
-};
-
-/**
- * Synchronize disabledness state of the tool with the inner toolgroup.
- *
- * @private
- * @param {boolean} disabled Element is disabled
- */
-OO.ui.ToolGroupTool.prototype.onToolGroupDisable = function ( disabled ) {
- this.setDisabled( disabled );
-};
-
-/**
- * Handle the toolbar state being updated.
- *
- * @inheritdoc
- */
-OO.ui.ToolGroupTool.prototype.onUpdateState = function () {
- this.setActive( false );
-};
-
-/**
- * Build a OO.ui.ToolGroup from the configuration.
- *
- * @param {Object.<string,Array>} group Tool group configuration. See OO.ui.Toolbar#setup for the
- * accepted values.
- * @return {OO.ui.ListToolGroup}
- */
-OO.ui.ToolGroupTool.prototype.createGroup = function ( group ) {
- if ( group.include === '*' ) {
- // Apply defaults to catch-all groups
- if ( group.label === undefined ) {
- group.label = OO.ui.msg( 'ooui-toolbar-more' );
- }
- }
-
- return this.toolbar.getToolGroupFactory().create( 'list', this.toolbar, group );
-};
diff --git a/vendor/oojs/oojs-ui/src/widgets/ActionWidget.js b/vendor/oojs/oojs-ui/src/widgets/ActionWidget.js
deleted file mode 100644
index 789f04f1..00000000
--- a/vendor/oojs/oojs-ui/src/widgets/ActionWidget.js
+++ /dev/null
@@ -1,170 +0,0 @@
-/**
- * An ActionWidget is a {@link OO.ui.ButtonWidget button widget} that executes an action.
- * Action widgets are used with OO.ui.ActionSet, which manages the behavior and availability
- * of the actions.
- *
- * Both actions and action sets are primarily used with {@link OO.ui.Dialog Dialogs}.
- * Please see the [OOjs UI documentation on MediaWiki] [1] for more information
- * and examples.
- *
- * [1]: https://www.mediawiki.org/wiki/OOjs_UI/Windows/Process_Dialogs#Action_sets
- *
- * @class
- * @extends OO.ui.ButtonWidget
- * @mixins OO.ui.PendingElement
- *
- * @constructor
- * @param {Object} [config] Configuration options
- * @cfg {string} [action] Symbolic name of the action (e.g., ‘continue’ or ‘cancel’).
- * @cfg {string[]} [modes] Symbolic names of the modes (e.g., ‘edit’ or ‘read’) in which the action
- * should be made available. See the action set's {@link OO.ui.ActionSet#setMode setMode} method
- * for more information about setting modes.
- * @cfg {boolean} [framed=false] Render the action button with a frame
- */
-OO.ui.ActionWidget = function OoUiActionWidget( config ) {
- // Configuration initialization
- config = $.extend( { framed: false }, config );
-
- // Parent constructor
- OO.ui.ActionWidget.super.call( this, config );
-
- // Mixin constructors
- OO.ui.PendingElement.call( this, config );
-
- // Properties
- this.action = config.action || '';
- this.modes = config.modes || [];
- this.width = 0;
- this.height = 0;
-
- // Initialization
- this.$element.addClass( 'oo-ui-actionWidget' );
-};
-
-/* Setup */
-
-OO.inheritClass( OO.ui.ActionWidget, OO.ui.ButtonWidget );
-OO.mixinClass( OO.ui.ActionWidget, OO.ui.PendingElement );
-
-/* Events */
-
-/**
- * A resize event is emitted when the size of the widget changes.
- *
- * @event resize
- */
-
-/* Methods */
-
-/**
- * Check if the action is configured to be available in the specified `mode`.
- *
- * @param {string} mode Name of mode
- * @return {boolean} The action is configured with the mode
- */
-OO.ui.ActionWidget.prototype.hasMode = function ( mode ) {
- return this.modes.indexOf( mode ) !== -1;
-};
-
-/**
- * Get the symbolic name of the action (e.g., ‘continue’ or ‘cancel’).
- *
- * @return {string}
- */
-OO.ui.ActionWidget.prototype.getAction = function () {
- return this.action;
-};
-
-/**
- * Get the symbolic name of the mode or modes for which the action is configured to be available.
- *
- * The current mode is set with the action set's {@link OO.ui.ActionSet#setMode setMode} method.
- * Only actions that are configured to be avaiable in the current mode will be visible. All other actions
- * are hidden.
- *
- * @return {string[]}
- */
-OO.ui.ActionWidget.prototype.getModes = function () {
- return this.modes.slice();
-};
-
-/**
- * Emit a resize event if the size has changed.
- *
- * @private
- * @chainable
- */
-OO.ui.ActionWidget.prototype.propagateResize = function () {
- var width, height;
-
- if ( this.isElementAttached() ) {
- width = this.$element.width();
- height = this.$element.height();
-
- if ( width !== this.width || height !== this.height ) {
- this.width = width;
- this.height = height;
- this.emit( 'resize' );
- }
- }
-
- return this;
-};
-
-/**
- * @inheritdoc
- */
-OO.ui.ActionWidget.prototype.setIcon = function () {
- // Mixin method
- OO.ui.IconElement.prototype.setIcon.apply( this, arguments );
- this.propagateResize();
-
- return this;
-};
-
-/**
- * @inheritdoc
- */
-OO.ui.ActionWidget.prototype.setLabel = function () {
- // Mixin method
- OO.ui.LabelElement.prototype.setLabel.apply( this, arguments );
- this.propagateResize();
-
- return this;
-};
-
-/**
- * @inheritdoc
- */
-OO.ui.ActionWidget.prototype.setFlags = function () {
- // Mixin method
- OO.ui.FlaggedElement.prototype.setFlags.apply( this, arguments );
- this.propagateResize();
-
- return this;
-};
-
-/**
- * @inheritdoc
- */
-OO.ui.ActionWidget.prototype.clearFlags = function () {
- // Mixin method
- OO.ui.FlaggedElement.prototype.clearFlags.apply( this, arguments );
- this.propagateResize();
-
- return this;
-};
-
-/**
- * Toggle the visibility of the action button.
- *
- * @param {boolean} [show] Show button, omit to toggle visibility
- * @chainable
- */
-OO.ui.ActionWidget.prototype.toggle = function () {
- // Parent method
- OO.ui.ActionWidget.super.prototype.toggle.apply( this, arguments );
- this.propagateResize();
-
- return this;
-};
diff --git a/vendor/oojs/oojs-ui/src/widgets/ButtonGroupWidget.js b/vendor/oojs/oojs-ui/src/widgets/ButtonGroupWidget.js
deleted file mode 100644
index f1388ab8..00000000
--- a/vendor/oojs/oojs-ui/src/widgets/ButtonGroupWidget.js
+++ /dev/null
@@ -1,53 +0,0 @@
-/**
- * A ButtonGroupWidget groups related buttons and is used together with OO.ui.ButtonWidget and
- * its subclasses. Each button in a group is addressed by a unique reference. Buttons can be added,
- * removed, and cleared from the group.
- *
- * @example
- * // Example: A ButtonGroupWidget with two buttons
- * var button1 = new OO.ui.PopupButtonWidget( {
- * label: 'Select a category',
- * icon: 'menu',
- * popup: {
- * $content: $( '<p>List of categories...</p>' ),
- * padded: true,
- * align: 'left'
- * }
- * } );
- * var button2 = new OO.ui.ButtonWidget( {
- * label: 'Add item'
- * });
- * var buttonGroup = new OO.ui.ButtonGroupWidget( {
- * items: [button1, button2]
- * } );
- * $( 'body' ).append( buttonGroup.$element );
- *
- * @class
- * @extends OO.ui.Widget
- * @mixins OO.ui.GroupElement
- *
- * @constructor
- * @param {Object} [config] Configuration options
- * @cfg {OO.ui.ButtonWidget[]} [items] Buttons to add
- */
-OO.ui.ButtonGroupWidget = function OoUiButtonGroupWidget( config ) {
- // Configuration initialization
- config = config || {};
-
- // Parent constructor
- OO.ui.ButtonGroupWidget.super.call( this, config );
-
- // Mixin constructors
- OO.ui.GroupElement.call( this, $.extend( {}, config, { $group: this.$element } ) );
-
- // Initialization
- this.$element.addClass( 'oo-ui-buttonGroupWidget' );
- if ( Array.isArray( config.items ) ) {
- this.addItems( config.items );
- }
-};
-
-/* Setup */
-
-OO.inheritClass( OO.ui.ButtonGroupWidget, OO.ui.Widget );
-OO.mixinClass( OO.ui.ButtonGroupWidget, OO.ui.GroupElement );
diff --git a/vendor/oojs/oojs-ui/src/widgets/ButtonInputWidget.js b/vendor/oojs/oojs-ui/src/widgets/ButtonInputWidget.js
deleted file mode 100644
index 1d4d97fe..00000000
--- a/vendor/oojs/oojs-ui/src/widgets/ButtonInputWidget.js
+++ /dev/null
@@ -1,121 +0,0 @@
-/**
- * ButtonInputWidget is used to submit HTML forms and is intended to be used within
- * a OO.ui.FormLayout. If you do not need the button to work with HTML forms, you probably
- * want to use OO.ui.ButtonWidget instead. Button input widgets can be rendered as either an
- * HTML `<button/>` (the default) or an HTML `<input/>` tags. See the
- * [OOjs UI documentation on MediaWiki] [1] for more information.
- *
- * @example
- * // A ButtonInputWidget rendered as an HTML button, the default.
- * var button = new OO.ui.ButtonInputWidget( {
- * label: 'Input button',
- * icon: 'check',
- * value: 'check'
- * } );
- * $( 'body' ).append( button.$element );
- *
- * [1]: https://www.mediawiki.org/wiki/OOjs_UI/Widgets/Inputs#Button_inputs
- *
- * @class
- * @extends OO.ui.InputWidget
- * @mixins OO.ui.ButtonElement
- * @mixins OO.ui.IconElement
- * @mixins OO.ui.IndicatorElement
- * @mixins OO.ui.LabelElement
- * @mixins OO.ui.TitledElement
- *
- * @constructor
- * @param {Object} [config] Configuration options
- * @cfg {string} [type='button'] The value of the HTML `'type'` attribute: 'button', 'submit' or 'reset'.
- * @cfg {boolean} [useInputTag=false] Use an `<input/>` tag instead of a `<button/>` tag, the default.
- * Widgets configured to be an `<input/>` do not support {@link #icon icons} and {@link #indicator indicators},
- * non-plaintext {@link #label labels}, or {@link #value values}. In general, useInputTag should only
- * be set to `true` when there’s need to support IE6 in a form with multiple buttons.
- */
-OO.ui.ButtonInputWidget = function OoUiButtonInputWidget( config ) {
- // Configuration initialization
- config = $.extend( { type: 'button', useInputTag: false }, config );
-
- // Properties (must be set before parent constructor, which calls #setValue)
- this.useInputTag = config.useInputTag;
-
- // Parent constructor
- OO.ui.ButtonInputWidget.super.call( this, config );
-
- // Mixin constructors
- OO.ui.ButtonElement.call( this, $.extend( {}, config, { $button: this.$input } ) );
- OO.ui.IconElement.call( this, config );
- OO.ui.IndicatorElement.call( this, config );
- OO.ui.LabelElement.call( this, config );
- OO.ui.TitledElement.call( this, $.extend( {}, config, { $titled: this.$input } ) );
-
- // Initialization
- if ( !config.useInputTag ) {
- this.$input.append( this.$icon, this.$label, this.$indicator );
- }
- this.$element.addClass( 'oo-ui-buttonInputWidget' );
-};
-
-/* Setup */
-
-OO.inheritClass( OO.ui.ButtonInputWidget, OO.ui.InputWidget );
-OO.mixinClass( OO.ui.ButtonInputWidget, OO.ui.ButtonElement );
-OO.mixinClass( OO.ui.ButtonInputWidget, OO.ui.IconElement );
-OO.mixinClass( OO.ui.ButtonInputWidget, OO.ui.IndicatorElement );
-OO.mixinClass( OO.ui.ButtonInputWidget, OO.ui.LabelElement );
-OO.mixinClass( OO.ui.ButtonInputWidget, OO.ui.TitledElement );
-
-/* Methods */
-
-/**
- * @inheritdoc
- * @private
- */
-OO.ui.ButtonInputWidget.prototype.getInputElement = function ( config ) {
- var html = '<' + ( config.useInputTag ? 'input' : 'button' ) + ' type="' + config.type + '">';
- return $( html );
-};
-
-/**
- * Set label value.
- *
- * If #useInputTag is `true`, the label is set as the `value` of the `<input/>` tag.
- *
- * @param {jQuery|string|Function|null} label Label nodes, text, a function that returns nodes or
- * text, or `null` for no label
- * @chainable
- */
-OO.ui.ButtonInputWidget.prototype.setLabel = function ( label ) {
- OO.ui.LabelElement.prototype.setLabel.call( this, label );
-
- if ( this.useInputTag ) {
- if ( typeof label === 'function' ) {
- label = OO.ui.resolveMsg( label );
- }
- if ( label instanceof jQuery ) {
- label = label.text();
- }
- if ( !label ) {
- label = '';
- }
- this.$input.val( label );
- }
-
- return this;
-};
-
-/**
- * Set the value of the input.
- *
- * This method is disabled for button inputs configured as {@link #useInputTag <input/> tags}, as
- * they do not support {@link #value values}.
- *
- * @param {string} value New value
- * @chainable
- */
-OO.ui.ButtonInputWidget.prototype.setValue = function ( value ) {
- if ( !this.useInputTag ) {
- OO.ui.ButtonInputWidget.super.prototype.setValue.call( this, value );
- }
- return this;
-};
diff --git a/vendor/oojs/oojs-ui/src/widgets/ButtonOptionWidget.js b/vendor/oojs/oojs-ui/src/widgets/ButtonOptionWidget.js
deleted file mode 100644
index 7758c949..00000000
--- a/vendor/oojs/oojs-ui/src/widgets/ButtonOptionWidget.js
+++ /dev/null
@@ -1,60 +0,0 @@
-/**
- * ButtonOptionWidget is a special type of {@link OO.ui.ButtonElement button element} that
- * can be selected and configured with data. The class is
- * used with OO.ui.ButtonSelectWidget to create a selection of button options. Please see the
- * [OOjs UI documentation on MediaWiki] [1] for more information.
- *
- * [1]: https://www.mediawiki.org/wiki/OOjs_UI/Widgets/Selects_and_Options#Button_selects_and_options
- *
- * @class
- * @extends OO.ui.DecoratedOptionWidget
- * @mixins OO.ui.ButtonElement
- * @mixins OO.ui.TabIndexedElement
- *
- * @constructor
- * @param {Object} [config] Configuration options
- */
-OO.ui.ButtonOptionWidget = function OoUiButtonOptionWidget( config ) {
- // Configuration initialization
- config = $.extend( { tabIndex: -1 }, config );
-
- // Parent constructor
- OO.ui.ButtonOptionWidget.super.call( this, config );
-
- // Mixin constructors
- OO.ui.ButtonElement.call( this, config );
- OO.ui.TabIndexedElement.call( this, $.extend( {}, config, { $tabIndexed: this.$button } ) );
-
- // Initialization
- this.$element.addClass( 'oo-ui-buttonOptionWidget' );
- this.$button.append( this.$element.contents() );
- this.$element.append( this.$button );
-};
-
-/* Setup */
-
-OO.inheritClass( OO.ui.ButtonOptionWidget, OO.ui.DecoratedOptionWidget );
-OO.mixinClass( OO.ui.ButtonOptionWidget, OO.ui.ButtonElement );
-OO.mixinClass( OO.ui.ButtonOptionWidget, OO.ui.TabIndexedElement );
-
-/* Static Properties */
-
-// Allow button mouse down events to pass through so they can be handled by the parent select widget
-OO.ui.ButtonOptionWidget.static.cancelButtonMouseDownEvents = false;
-
-OO.ui.ButtonOptionWidget.static.highlightable = false;
-
-/* Methods */
-
-/**
- * @inheritdoc
- */
-OO.ui.ButtonOptionWidget.prototype.setSelected = function ( state ) {
- OO.ui.ButtonOptionWidget.super.prototype.setSelected.call( this, state );
-
- if ( this.constructor.static.selectable ) {
- this.setActive( state );
- }
-
- return this;
-};
diff --git a/vendor/oojs/oojs-ui/src/widgets/ButtonSelectWidget.js b/vendor/oojs/oojs-ui/src/widgets/ButtonSelectWidget.js
deleted file mode 100644
index 18177761..00000000
--- a/vendor/oojs/oojs-ui/src/widgets/ButtonSelectWidget.js
+++ /dev/null
@@ -1,62 +0,0 @@
-/**
- * ButtonSelectWidget is a {@link OO.ui.SelectWidget select widget} that contains
- * button options and is used together with
- * OO.ui.ButtonOptionWidget. The ButtonSelectWidget provides an interface for
- * highlighting, choosing, and selecting mutually exclusive options. Please see
- * the [OOjs UI documentation on MediaWiki] [1] for more information.
- *
- * @example
- * // Example: A ButtonSelectWidget that contains three ButtonOptionWidgets
- * var option1 = new OO.ui.ButtonOptionWidget( {
- * data: 1,
- * label: 'Option 1',
- * title: 'Button option 1'
- * } );
- *
- * var option2 = new OO.ui.ButtonOptionWidget( {
- * data: 2,
- * label: 'Option 2',
- * title: 'Button option 2'
- * } );
- *
- * var option3 = new OO.ui.ButtonOptionWidget( {
- * data: 3,
- * label: 'Option 3',
- * title: 'Button option 3'
- * } );
- *
- * var buttonSelect=new OO.ui.ButtonSelectWidget( {
- * items: [ option1, option2, option3 ]
- * } );
- * $( 'body' ).append( buttonSelect.$element );
- *
- * [1]: https://www.mediawiki.org/wiki/OOjs_UI/Widgets/Selects_and_Options
- *
- * @class
- * @extends OO.ui.SelectWidget
- * @mixins OO.ui.TabIndexedElement
- *
- * @constructor
- * @param {Object} [config] Configuration options
- */
-OO.ui.ButtonSelectWidget = function OoUiButtonSelectWidget( config ) {
- // Parent constructor
- OO.ui.ButtonSelectWidget.super.call( this, config );
-
- // Mixin constructors
- OO.ui.TabIndexedElement.call( this, config );
-
- // Events
- this.$element.on( {
- focus: this.bindKeyDownListener.bind( this ),
- blur: this.unbindKeyDownListener.bind( this )
- } );
-
- // Initialization
- this.$element.addClass( 'oo-ui-buttonSelectWidget' );
-};
-
-/* Setup */
-
-OO.inheritClass( OO.ui.ButtonSelectWidget, OO.ui.SelectWidget );
-OO.mixinClass( OO.ui.ButtonSelectWidget, OO.ui.TabIndexedElement );
diff --git a/vendor/oojs/oojs-ui/src/widgets/ButtonWidget.js b/vendor/oojs/oojs-ui/src/widgets/ButtonWidget.js
deleted file mode 100644
index 474fafed..00000000
--- a/vendor/oojs/oojs-ui/src/widgets/ButtonWidget.js
+++ /dev/null
@@ -1,215 +0,0 @@
-/**
- * ButtonWidget is a generic widget for buttons. A wide variety of looks,
- * feels, and functionality can be customized via the class’s configuration options
- * and methods. Please see the [OOjs UI documentation on MediaWiki] [1] for more information
- * and examples.
- *
- * [1]: https://www.mediawiki.org/wiki/OOjs_UI/Widgets/Buttons_and_Switches
- *
- * @example
- * // A button widget
- * var button = new OO.ui.ButtonWidget( {
- * label: 'Button with Icon',
- * icon: 'remove',
- * iconTitle: 'Remove'
- * } );
- * $( 'body' ).append( button.$element );
- *
- * NOTE: HTML form buttons should use the OO.ui.ButtonInputWidget class.
- *
- * @class
- * @extends OO.ui.Widget
- * @mixins OO.ui.ButtonElement
- * @mixins OO.ui.IconElement
- * @mixins OO.ui.IndicatorElement
- * @mixins OO.ui.LabelElement
- * @mixins OO.ui.TitledElement
- * @mixins OO.ui.FlaggedElement
- * @mixins OO.ui.TabIndexedElement
- *
- * @constructor
- * @param {Object} [config] Configuration options
- * @cfg {string} [href] Hyperlink to visit when the button is clicked.
- * @cfg {string} [target] The frame or window in which to open the hyperlink.
- * @cfg {boolean} [noFollow] Search engine traversal hint (default: true)
- */
-OO.ui.ButtonWidget = function OoUiButtonWidget( config ) {
- // Configuration initialization
- config = config || {};
-
- // Parent constructor
- OO.ui.ButtonWidget.super.call( this, config );
-
- // Mixin constructors
- OO.ui.ButtonElement.call( this, config );
- OO.ui.IconElement.call( this, config );
- OO.ui.IndicatorElement.call( this, config );
- OO.ui.LabelElement.call( this, config );
- OO.ui.TitledElement.call( this, $.extend( {}, config, { $titled: this.$button } ) );
- OO.ui.FlaggedElement.call( this, config );
- OO.ui.TabIndexedElement.call( this, $.extend( {}, config, { $tabIndexed: this.$button } ) );
-
- // Properties
- this.href = null;
- this.target = null;
- this.noFollow = false;
-
- // Events
- this.connect( this, { disable: 'onDisable' } );
-
- // Initialization
- this.$button.append( this.$icon, this.$label, this.$indicator );
- this.$element
- .addClass( 'oo-ui-buttonWidget' )
- .append( this.$button );
- this.setHref( config.href );
- this.setTarget( config.target );
- this.setNoFollow( config.noFollow );
-};
-
-/* Setup */
-
-OO.inheritClass( OO.ui.ButtonWidget, OO.ui.Widget );
-OO.mixinClass( OO.ui.ButtonWidget, OO.ui.ButtonElement );
-OO.mixinClass( OO.ui.ButtonWidget, OO.ui.IconElement );
-OO.mixinClass( OO.ui.ButtonWidget, OO.ui.IndicatorElement );
-OO.mixinClass( OO.ui.ButtonWidget, OO.ui.LabelElement );
-OO.mixinClass( OO.ui.ButtonWidget, OO.ui.TitledElement );
-OO.mixinClass( OO.ui.ButtonWidget, OO.ui.FlaggedElement );
-OO.mixinClass( OO.ui.ButtonWidget, OO.ui.TabIndexedElement );
-
-/* Methods */
-
-/**
- * @inheritdoc
- */
-OO.ui.ButtonWidget.prototype.onMouseDown = function ( e ) {
- if ( !this.isDisabled() ) {
- // Remove the tab-index while the button is down to prevent the button from stealing focus
- this.$button.removeAttr( 'tabindex' );
- }
-
- return OO.ui.ButtonElement.prototype.onMouseDown.call( this, e );
-};
-
-/**
- * @inheritdoc
- */
-OO.ui.ButtonWidget.prototype.onMouseUp = function ( e ) {
- if ( !this.isDisabled() ) {
- // Restore the tab-index after the button is up to restore the button's accessibility
- this.$button.attr( 'tabindex', this.tabIndex );
- }
-
- return OO.ui.ButtonElement.prototype.onMouseUp.call( this, e );
-};
-
-/**
- * Get hyperlink location.
- *
- * @return {string} Hyperlink location
- */
-OO.ui.ButtonWidget.prototype.getHref = function () {
- return this.href;
-};
-
-/**
- * Get hyperlink target.
- *
- * @return {string} Hyperlink target
- */
-OO.ui.ButtonWidget.prototype.getTarget = function () {
- return this.target;
-};
-
-/**
- * Get search engine traversal hint.
- *
- * @return {boolean} Whether search engines should avoid traversing this hyperlink
- */
-OO.ui.ButtonWidget.prototype.getNoFollow = function () {
- return this.noFollow;
-};
-
-/**
- * Set hyperlink location.
- *
- * @param {string|null} href Hyperlink location, null to remove
- */
-OO.ui.ButtonWidget.prototype.setHref = function ( href ) {
- href = typeof href === 'string' ? href : null;
-
- if ( href !== this.href ) {
- this.href = href;
- this.updateHref();
- }
-
- return this;
-};
-
-/**
- * Update the `href` attribute, in case of changes to href or
- * disabled state.
- *
- * @private
- * @chainable
- */
-OO.ui.ButtonWidget.prototype.updateHref = function () {
- if ( this.href !== null && !this.isDisabled() ) {
- this.$button.attr( 'href', this.href );
- } else {
- this.$button.removeAttr( 'href' );
- }
-
- return this;
-};
-
-/**
- * Handle disable events.
- *
- * @private
- * @param {boolean} disabled Element is disabled
- */
-OO.ui.ButtonWidget.prototype.onDisable = function () {
- this.updateHref();
-};
-
-/**
- * Set hyperlink target.
- *
- * @param {string|null} target Hyperlink target, null to remove
- */
-OO.ui.ButtonWidget.prototype.setTarget = function ( target ) {
- target = typeof target === 'string' ? target : null;
-
- if ( target !== this.target ) {
- this.target = target;
- if ( target !== null ) {
- this.$button.attr( 'target', target );
- } else {
- this.$button.removeAttr( 'target' );
- }
- }
-
- return this;
-};
-
-/**
- * Set search engine traversal hint.
- *
- * @param {boolean} noFollow True if search engines should avoid traversing this hyperlink
- */
-OO.ui.ButtonWidget.prototype.setNoFollow = function ( noFollow ) {
- noFollow = typeof noFollow === 'boolean' ? noFollow : true;
-
- if ( noFollow !== this.noFollow ) {
- this.noFollow = noFollow;
- if ( noFollow ) {
- this.$button.attr( 'rel', 'nofollow' );
- } else {
- this.$button.removeAttr( 'rel' );
- }
- }
-
- return this;
-};
diff --git a/vendor/oojs/oojs-ui/src/widgets/CheckboxInputWidget.js b/vendor/oojs/oojs-ui/src/widgets/CheckboxInputWidget.js
deleted file mode 100644
index 1ac93bc5..00000000
--- a/vendor/oojs/oojs-ui/src/widgets/CheckboxInputWidget.js
+++ /dev/null
@@ -1,110 +0,0 @@
-/**
- * CheckboxInputWidgets, like HTML checkboxes, can be selected and/or configured with a value.
- * Note that these {@link OO.ui.InputWidget input widgets} are best laid out
- * in {@link OO.ui.FieldLayout field layouts} that use the {@link OO.ui.FieldLayout#align inline}
- * alignment. For more information, please see the [OOjs UI documentation on MediaWiki][1].
- *
- * This widget can be used inside a HTML form, such as a OO.ui.FormLayout.
- *
- * @example
- * // An example of selected, unselected, and disabled checkbox inputs
- * var checkbox1=new OO.ui.CheckboxInputWidget( {
- * value: 'a',
- * selected: true
- * } );
- * var checkbox2=new OO.ui.CheckboxInputWidget( {
- * value: 'b'
- * } );
- * var checkbox3=new OO.ui.CheckboxInputWidget( {
- * value:'c',
- * disabled: true
- * } );
- * // Create a fieldset layout with fields for each checkbox.
- * var fieldset = new OO.ui.FieldsetLayout( {
- * label: 'Checkboxes'
- * } );
- * fieldset.addItems( [
- * new OO.ui.FieldLayout( checkbox1, { label: 'Selected checkbox', align: 'inline' } ),
- * new OO.ui.FieldLayout( checkbox2, { label: 'Unselected checkbox', align: 'inline' } ),
- * new OO.ui.FieldLayout( checkbox3, { label: 'Disabled checkbox', align: 'inline' } ),
- * ] );
- * $( 'body' ).append( fieldset.$element );
- *
- * [1]: https://www.mediawiki.org/wiki/OOjs_UI/Widgets/Inputs
- *
- * @class
- * @extends OO.ui.InputWidget
- *
- * @constructor
- * @param {Object} [config] Configuration options
- * @cfg {boolean} [selected=false] Select the checkbox initially. By default, the checkbox is not selected.
- */
-OO.ui.CheckboxInputWidget = function OoUiCheckboxInputWidget( config ) {
- // Configuration initialization
- config = config || {};
-
- // Parent constructor
- OO.ui.CheckboxInputWidget.super.call( this, config );
-
- // Initialization
- this.$element.addClass( 'oo-ui-checkboxInputWidget' );
- this.setSelected( config.selected !== undefined ? config.selected : false );
-};
-
-/* Setup */
-
-OO.inheritClass( OO.ui.CheckboxInputWidget, OO.ui.InputWidget );
-
-/* Methods */
-
-/**
- * @inheritdoc
- * @private
- */
-OO.ui.CheckboxInputWidget.prototype.getInputElement = function () {
- return $( '<input type="checkbox" />' );
-};
-
-/**
- * @inheritdoc
- */
-OO.ui.CheckboxInputWidget.prototype.onEdit = function () {
- var widget = this;
- if ( !this.isDisabled() ) {
- // Allow the stack to clear so the value will be updated
- setTimeout( function () {
- widget.setSelected( widget.$input.prop( 'checked' ) );
- } );
- }
-};
-
-/**
- * Set selection state of this checkbox.
- *
- * @param {boolean} state `true` for selected
- * @chainable
- */
-OO.ui.CheckboxInputWidget.prototype.setSelected = function ( state ) {
- state = !!state;
- if ( this.selected !== state ) {
- this.selected = state;
- this.$input.prop( 'checked', this.selected );
- this.emit( 'change', this.selected );
- }
- return this;
-};
-
-/**
- * Check if this checkbox is selected.
- *
- * @return {boolean} Checkbox is selected
- */
-OO.ui.CheckboxInputWidget.prototype.isSelected = function () {
- // Resynchronize our internal data with DOM data. Other scripts executing on the page can modify
- // it, and we won't know unless they're kind enough to trigger a 'change' event.
- var selected = this.$input.prop( 'checked' );
- if ( this.selected !== selected ) {
- this.setSelected( selected );
- }
- return this.selected;
-};
diff --git a/vendor/oojs/oojs-ui/src/widgets/ComboBoxWidget.js b/vendor/oojs/oojs-ui/src/widgets/ComboBoxWidget.js
deleted file mode 100644
index 346d17ee..00000000
--- a/vendor/oojs/oojs-ui/src/widgets/ComboBoxWidget.js
+++ /dev/null
@@ -1,230 +0,0 @@
-/**
- * ComboBoxWidgets combine a {@link OO.ui.TextInputWidget text input} (where a value
- * can be entered manually) and a {@link OO.ui.MenuSelectWidget menu of options} (from which
- * a value can be chosen instead). Users can choose options from the combo box in one of two ways:
- *
- * - by typing a value in the text input field. If the value exactly matches the value of a menu
- * option, that option will appear to be selected.
- * - by choosing a value from the menu. The value of the chosen option will then appear in the text
- * input field.
- *
- * For more information about menus and options, please see the [OOjs UI documentation on MediaWiki][1].
- *
- * @example
- * // Example: A ComboBoxWidget.
- * var comboBox = new OO.ui.ComboBoxWidget( {
- * label: 'ComboBoxWidget',
- * input: { value: 'Option One' },
- * menu: {
- * items: [
- * new OO.ui.MenuOptionWidget( {
- * data: 'Option 1',
- * label: 'Option One'
- * } ),
- * new OO.ui.MenuOptionWidget( {
- * data: 'Option 2',
- * label: 'Option Two'
- * } ),
- * new OO.ui.MenuOptionWidget( {
- * data: 'Option 3',
- * label: 'Option Three'
- * } ),
- * new OO.ui.MenuOptionWidget( {
- * data: 'Option 4',
- * label: 'Option Four'
- * } ),
- * new OO.ui.MenuOptionWidget( {
- * data: 'Option 5',
- * label: 'Option Five'
- * } )
- * ]
- * }
- * } );
- * $( 'body' ).append( comboBox.$element );
- *
- * [1]: https://www.mediawiki.org/wiki/OOjs_UI/Widgets/Selects_and_Options#Menu_selects_and_options
- *
- * @class
- * @extends OO.ui.Widget
- * @mixins OO.ui.TabIndexedElement
- *
- * @constructor
- * @param {Object} [config] Configuration options
- * @cfg {Object} [menu] Configuration options to pass to the {@link OO.ui.MenuSelectWidget menu select widget}.
- * @cfg {Object} [input] Configuration options to pass to the {@link OO.ui.TextInputWidget text input widget}.
- * @cfg {jQuery} [$overlay] Render the menu into a separate layer. This configuration is useful in cases where
- * the expanded menu is larger than its containing `<div>`. The specified overlay layer is usually on top of the
- * containing `<div>` and has a larger area. By default, the menu uses relative positioning.
- */
-OO.ui.ComboBoxWidget = function OoUiComboBoxWidget( config ) {
- // Configuration initialization
- config = config || {};
-
- // Parent constructor
- OO.ui.ComboBoxWidget.super.call( this, config );
-
- // Properties (must be set before TabIndexedElement constructor call)
- this.$indicator = this.$( '<span>' );
-
- // Mixin constructors
- OO.ui.TabIndexedElement.call( this, $.extend( {}, config, { $tabIndexed: this.$indicator } ) );
-
- // Properties
- this.$overlay = config.$overlay || this.$element;
- this.input = new OO.ui.TextInputWidget( $.extend(
- {
- indicator: 'down',
- $indicator: this.$indicator,
- disabled: this.isDisabled()
- },
- config.input
- ) );
- this.input.$input.eq( 0 ).attr( {
- role: 'combobox',
- 'aria-autocomplete': 'list'
- } );
- this.menu = new OO.ui.TextInputMenuSelectWidget( this.input, $.extend(
- {
- widget: this,
- input: this.input,
- disabled: this.isDisabled()
- },
- config.menu
- ) );
-
- // Events
- this.$indicator.on( {
- click: this.onClick.bind( this ),
- keypress: this.onKeyPress.bind( this )
- } );
- this.input.connect( this, {
- change: 'onInputChange',
- enter: 'onInputEnter'
- } );
- this.menu.connect( this, {
- choose: 'onMenuChoose',
- add: 'onMenuItemsChange',
- remove: 'onMenuItemsChange'
- } );
-
- // Initialization
- this.$element.addClass( 'oo-ui-comboBoxWidget' ).append( this.input.$element );
- this.$overlay.append( this.menu.$element );
- this.onMenuItemsChange();
-};
-
-/* Setup */
-
-OO.inheritClass( OO.ui.ComboBoxWidget, OO.ui.Widget );
-OO.mixinClass( OO.ui.ComboBoxWidget, OO.ui.TabIndexedElement );
-
-/* Methods */
-
-/**
- * Get the combobox's menu.
- * @return {OO.ui.TextInputMenuSelectWidget} Menu widget
- */
-OO.ui.ComboBoxWidget.prototype.getMenu = function () {
- return this.menu;
-};
-
-/**
- * Handle input change events.
- *
- * @private
- * @param {string} value New value
- */
-OO.ui.ComboBoxWidget.prototype.onInputChange = function ( value ) {
- var match = this.menu.getItemFromData( value );
-
- this.menu.selectItem( match );
- if ( this.menu.getHighlightedItem() ) {
- this.menu.highlightItem( match );
- }
-
- if ( !this.isDisabled() ) {
- this.menu.toggle( true );
- }
-};
-
-/**
- * Handle mouse click events.
- *
- *
- * @private
- * @param {jQuery.Event} e Mouse click event
- */
-OO.ui.ComboBoxWidget.prototype.onClick = function ( e ) {
- if ( !this.isDisabled() && e.which === 1 ) {
- this.menu.toggle();
- this.input.$input[ 0 ].focus();
- }
- return false;
-};
-
-/**
- * Handle key press events.
- *
- *
- * @private
- * @param {jQuery.Event} e Key press event
- */
-OO.ui.ComboBoxWidget.prototype.onKeyPress = function ( e ) {
- if ( !this.isDisabled() && ( e.which === OO.ui.Keys.SPACE || e.which === OO.ui.Keys.ENTER ) ) {
- this.menu.toggle();
- this.input.$input[ 0 ].focus();
- return false;
- }
-};
-
-/**
- * Handle input enter events.
- *
- * @private
- */
-OO.ui.ComboBoxWidget.prototype.onInputEnter = function () {
- if ( !this.isDisabled() ) {
- this.menu.toggle( false );
- }
-};
-
-/**
- * Handle menu choose events.
- *
- * @private
- * @param {OO.ui.OptionWidget} item Chosen item
- */
-OO.ui.ComboBoxWidget.prototype.onMenuChoose = function ( item ) {
- this.input.setValue( item.getData() );
-};
-
-/**
- * Handle menu item change events.
- *
- * @private
- */
-OO.ui.ComboBoxWidget.prototype.onMenuItemsChange = function () {
- var match = this.menu.getItemFromData( this.input.getValue() );
- this.menu.selectItem( match );
- if ( this.menu.getHighlightedItem() ) {
- this.menu.highlightItem( match );
- }
- this.$element.toggleClass( 'oo-ui-comboBoxWidget-empty', this.menu.isEmpty() );
-};
-
-/**
- * @inheritdoc
- */
-OO.ui.ComboBoxWidget.prototype.setDisabled = function ( disabled ) {
- // Parent method
- OO.ui.ComboBoxWidget.super.prototype.setDisabled.call( this, disabled );
-
- if ( this.input ) {
- this.input.setDisabled( this.isDisabled() );
- }
- if ( this.menu ) {
- this.menu.setDisabled( this.isDisabled() );
- }
-
- return this;
-};
diff --git a/vendor/oojs/oojs-ui/src/widgets/DecoratedOptionWidget.js b/vendor/oojs/oojs-ui/src/widgets/DecoratedOptionWidget.js
deleted file mode 100644
index e39ebcad..00000000
--- a/vendor/oojs/oojs-ui/src/widgets/DecoratedOptionWidget.js
+++ /dev/null
@@ -1,55 +0,0 @@
-/**
- * DecoratedOptionWidgets are {@link OO.ui.OptionWidget options} that can be configured
- * with an {@link OO.ui.IconElement icon} and/or {@link OO.ui.IndicatorElement indicator}.
- * This class is used with OO.ui.SelectWidget to create a selection of mutually exclusive
- * options. For more information about options and selects, please see the
- * [OOjs UI documentation on MediaWiki][1].
- *
- * @example
- * // Decorated options in a select widget
- * var select = new OO.ui.SelectWidget( {
- * items: [
- * new OO.ui.DecoratedOptionWidget( {
- * data: 'a',
- * label: 'Option with icon',
- * icon: 'help'
- * } ),
- * new OO.ui.DecoratedOptionWidget( {
- * data: 'b',
- * label: 'Option with indicator',
- * indicator: 'next'
- * } )
- * ]
- * } );
- * $( 'body' ).append( select.$element );
- *
- * [1]: https://www.mediawiki.org/wiki/OOjs_UI/Widgets/Selects_and_Options
- *
- * @class
- * @extends OO.ui.OptionWidget
- * @mixins OO.ui.IconElement
- * @mixins OO.ui.IndicatorElement
- *
- * @constructor
- * @param {Object} [config] Configuration options
- */
-OO.ui.DecoratedOptionWidget = function OoUiDecoratedOptionWidget( config ) {
- // Parent constructor
- OO.ui.DecoratedOptionWidget.super.call( this, config );
-
- // Mixin constructors
- OO.ui.IconElement.call( this, config );
- OO.ui.IndicatorElement.call( this, config );
-
- // Initialization
- this.$element
- .addClass( 'oo-ui-decoratedOptionWidget' )
- .prepend( this.$icon )
- .append( this.$indicator );
-};
-
-/* Setup */
-
-OO.inheritClass( OO.ui.DecoratedOptionWidget, OO.ui.OptionWidget );
-OO.mixinClass( OO.ui.OptionWidget, OO.ui.IconElement );
-OO.mixinClass( OO.ui.OptionWidget, OO.ui.IndicatorElement );
diff --git a/vendor/oojs/oojs-ui/src/widgets/DropdownInputWidget.js b/vendor/oojs/oojs-ui/src/widgets/DropdownInputWidget.js
deleted file mode 100644
index d4a5ce2a..00000000
--- a/vendor/oojs/oojs-ui/src/widgets/DropdownInputWidget.js
+++ /dev/null
@@ -1,137 +0,0 @@
-/**
- * DropdownInputWidget is a {@link OO.ui.DropdownWidget DropdownWidget} intended to be used
- * within a HTML form, such as a OO.ui.FormLayout. The selected value is synchronized with the value
- * of a hidden HTML `input` tag. Please see the [OOjs UI documentation on MediaWiki][1] for
- * more information about input widgets.
- *
- * @example
- * // Example: A DropdownInputWidget with three options
- * var dropDown = new OO.ui.DropdownInputWidget( {
- * label: 'Dropdown menu: Select a menu option',
- * options: [
- * { data: 'a', label: 'First' } ,
- * { data: 'b', label: 'Second'} ,
- * { data: 'c', label: 'Third' }
- * ]
- * } );
- * $( 'body' ).append( dropDown.$element );
- *
- * [1]: https://www.mediawiki.org/wiki/OOjs_UI/Widgets/Inputs
- *
- * @class
- * @extends OO.ui.InputWidget
- *
- * @constructor
- * @param {Object} [config] Configuration options
- * @cfg {Object[]} [options=[]] Array of menu options in the format `{ data: …, label: … }`
- */
-OO.ui.DropdownInputWidget = function OoUiDropdownInputWidget( config ) {
- // Configuration initialization
- config = config || {};
-
- // Properties (must be done before parent constructor which calls #setDisabled)
- this.dropdownWidget = new OO.ui.DropdownWidget();
-
- // Parent constructor
- OO.ui.DropdownInputWidget.super.call( this, config );
-
- // Events
- this.dropdownWidget.getMenu().connect( this, { select: 'onMenuSelect' } );
-
- // Initialization
- this.setOptions( config.options || [] );
- this.$element
- .addClass( 'oo-ui-dropdownInputWidget' )
- .append( this.dropdownWidget.$element );
-};
-
-/* Setup */
-
-OO.inheritClass( OO.ui.DropdownInputWidget, OO.ui.InputWidget );
-
-/* Methods */
-
-/**
- * @inheritdoc
- * @private
- */
-OO.ui.DropdownInputWidget.prototype.getInputElement = function () {
- return $( '<input type="hidden">' );
-};
-
-/**
- * Handles menu select events.
- *
- * @private
- * @param {OO.ui.MenuOptionWidget} item Selected menu item
- */
-OO.ui.DropdownInputWidget.prototype.onMenuSelect = function ( item ) {
- this.setValue( item.getData() );
-};
-
-/**
- * @inheritdoc
- */
-OO.ui.DropdownInputWidget.prototype.setValue = function ( value ) {
- this.dropdownWidget.getMenu().selectItemByData( value );
- OO.ui.DropdownInputWidget.super.prototype.setValue.call( this, value );
- return this;
-};
-
-/**
- * @inheritdoc
- */
-OO.ui.DropdownInputWidget.prototype.setDisabled = function ( state ) {
- this.dropdownWidget.setDisabled( state );
- OO.ui.DropdownInputWidget.super.prototype.setDisabled.call( this, state );
- return this;
-};
-
-/**
- * Set the options available for this input.
- *
- * @param {Object[]} options Array of menu options in the format `{ data: …, label: … }`
- * @chainable
- */
-OO.ui.DropdownInputWidget.prototype.setOptions = function ( options ) {
- var value = this.getValue();
-
- // Rebuild the dropdown menu
- this.dropdownWidget.getMenu()
- .clearItems()
- .addItems( options.map( function ( opt ) {
- return new OO.ui.MenuOptionWidget( {
- data: opt.data,
- label: opt.label !== undefined ? opt.label : opt.data
- } );
- } ) );
-
- // Restore the previous value, or reset to something sensible
- if ( this.dropdownWidget.getMenu().getItemFromData( value ) ) {
- // Previous value is still available, ensure consistency with the dropdown
- this.setValue( value );
- } else {
- // No longer valid, reset
- if ( options.length ) {
- this.setValue( options[ 0 ].data );
- }
- }
-
- return this;
-};
-
-/**
- * @inheritdoc
- */
-OO.ui.DropdownInputWidget.prototype.focus = function () {
- this.dropdownWidget.getMenu().toggle( true );
- return this;
-};
-
-/**
- * @inheritdoc
- */
-OO.ui.DropdownInputWidget.prototype.blur = function () {
- this.dropdownWidget.getMenu().toggle( false );
- return this;
-};
diff --git a/vendor/oojs/oojs-ui/src/widgets/DropdownWidget.js b/vendor/oojs/oojs-ui/src/widgets/DropdownWidget.js
deleted file mode 100644
index f6c592e8..00000000
--- a/vendor/oojs/oojs-ui/src/widgets/DropdownWidget.js
+++ /dev/null
@@ -1,149 +0,0 @@
-/**
- * DropdownWidgets are not menus themselves, rather they contain a menu of options created with
- * OO.ui.MenuOptionWidget. The DropdownWidget takes care of opening and displaying the menu so that
- * users can interact with it.
- *
- * @example
- * // Example: A DropdownWidget with a menu that contains three options
- * var dropDown = new OO.ui.DropdownWidget( {
- * label: 'Dropdown menu: Select a menu option',
- * menu: {
- * items: [
- * new OO.ui.MenuOptionWidget( {
- * data: 'a',
- * label: 'First'
- * } ),
- * new OO.ui.MenuOptionWidget( {
- * data: 'b',
- * label: 'Second'
- * } ),
- * new OO.ui.MenuOptionWidget( {
- * data: 'c',
- * label: 'Third'
- * } )
- * ]
- * }
- * } );
- *
- * $( 'body' ).append( dropDown.$element );
- *
- * For more information, please see the [OOjs UI documentation on MediaWiki] [1].
- *
- * [1]: https://www.mediawiki.org/wiki/OOjs_UI/Widgets/Selects_and_Options#Menu_selects_and_options
- *
- * @class
- * @extends OO.ui.Widget
- * @mixins OO.ui.IconElement
- * @mixins OO.ui.IndicatorElement
- * @mixins OO.ui.LabelElement
- * @mixins OO.ui.TitledElement
- * @mixins OO.ui.TabIndexedElement
- *
- * @constructor
- * @param {Object} [config] Configuration options
- * @cfg {Object} [menu] Configuration options to pass to menu widget
- */
-OO.ui.DropdownWidget = function OoUiDropdownWidget( config ) {
- // Configuration initialization
- config = $.extend( { indicator: 'down' }, config );
-
- // Parent constructor
- OO.ui.DropdownWidget.super.call( this, config );
-
- // Properties (must be set before TabIndexedElement constructor call)
- this.$handle = this.$( '<span>' );
-
- // Mixin constructors
- OO.ui.IconElement.call( this, config );
- OO.ui.IndicatorElement.call( this, config );
- OO.ui.LabelElement.call( this, config );
- OO.ui.TitledElement.call( this, $.extend( {}, config, { $titled: this.$label } ) );
- OO.ui.TabIndexedElement.call( this, $.extend( {}, config, { $tabIndexed: this.$handle } ) );
-
- // Properties
- this.menu = new OO.ui.MenuSelectWidget( $.extend( { widget: this }, config.menu ) );
-
- // Events
- this.$handle.on( {
- click: this.onClick.bind( this ),
- keypress: this.onKeyPress.bind( this )
- } );
- this.menu.connect( this, { select: 'onMenuSelect' } );
-
- // Initialization
- this.$handle
- .addClass( 'oo-ui-dropdownWidget-handle' )
- .append( this.$icon, this.$label, this.$indicator );
- this.$element
- .addClass( 'oo-ui-dropdownWidget' )
- .append( this.$handle, this.menu.$element );
-};
-
-/* Setup */
-
-OO.inheritClass( OO.ui.DropdownWidget, OO.ui.Widget );
-OO.mixinClass( OO.ui.DropdownWidget, OO.ui.IconElement );
-OO.mixinClass( OO.ui.DropdownWidget, OO.ui.IndicatorElement );
-OO.mixinClass( OO.ui.DropdownWidget, OO.ui.LabelElement );
-OO.mixinClass( OO.ui.DropdownWidget, OO.ui.TitledElement );
-OO.mixinClass( OO.ui.DropdownWidget, OO.ui.TabIndexedElement );
-
-/* Methods */
-
-/**
- * Get the menu.
- *
- * @return {OO.ui.MenuSelectWidget} Menu of widget
- */
-OO.ui.DropdownWidget.prototype.getMenu = function () {
- return this.menu;
-};
-
-/**
- * Handles menu select events.
- *
- * @private
- * @param {OO.ui.MenuOptionWidget} item Selected menu item
- */
-OO.ui.DropdownWidget.prototype.onMenuSelect = function ( item ) {
- var selectedLabel;
-
- if ( !item ) {
- return;
- }
-
- selectedLabel = item.getLabel();
-
- // If the label is a DOM element, clone it, because setLabel will append() it
- if ( selectedLabel instanceof jQuery ) {
- selectedLabel = selectedLabel.clone();
- }
-
- this.setLabel( selectedLabel );
-};
-
-/**
- * Handle mouse click events.
- *
- * @private
- * @param {jQuery.Event} e Mouse click event
- */
-OO.ui.DropdownWidget.prototype.onClick = function ( e ) {
- if ( !this.isDisabled() && e.which === 1 ) {
- this.menu.toggle();
- }
- return false;
-};
-
-/**
- * Handle key press events.
- *
- * @private
- * @param {jQuery.Event} e Key press event
- */
-OO.ui.DropdownWidget.prototype.onKeyPress = function ( e ) {
- if ( !this.isDisabled() && ( e.which === OO.ui.Keys.SPACE || e.which === OO.ui.Keys.ENTER ) ) {
- this.menu.toggle();
- return false;
- }
-};
diff --git a/vendor/oojs/oojs-ui/src/widgets/GroupWidget.js b/vendor/oojs/oojs-ui/src/widgets/GroupWidget.js
deleted file mode 100644
index 7d9be905..00000000
--- a/vendor/oojs/oojs-ui/src/widgets/GroupWidget.js
+++ /dev/null
@@ -1,48 +0,0 @@
-/**
- * Mixin for OO.ui.Widget subclasses to provide OO.ui.GroupElement.
- *
- * Use together with OO.ui.ItemWidget to make disabled state inheritable.
- *
- * @private
- * @abstract
- * @class
- * @extends OO.ui.GroupElement
- *
- * @constructor
- * @param {Object} [config] Configuration options
- */
-OO.ui.GroupWidget = function OoUiGroupWidget( config ) {
- // Parent constructor
- OO.ui.GroupWidget.super.call( this, config );
-};
-
-/* Setup */
-
-OO.inheritClass( OO.ui.GroupWidget, OO.ui.GroupElement );
-
-/* Methods */
-
-/**
- * Set the disabled state of the widget.
- *
- * This will also update the disabled state of child widgets.
- *
- * @param {boolean} disabled Disable widget
- * @chainable
- */
-OO.ui.GroupWidget.prototype.setDisabled = function ( disabled ) {
- var i, len;
-
- // Parent method
- // Note: Calling #setDisabled this way assumes this is mixed into an OO.ui.Widget
- OO.ui.Widget.prototype.setDisabled.call( this, disabled );
-
- // During construction, #setDisabled is called before the OO.ui.GroupElement constructor
- if ( this.items ) {
- for ( i = 0, len = this.items.length; i < len; i++ ) {
- this.items[ i ].updateDisabled();
- }
- }
-
- return this;
-};
diff --git a/vendor/oojs/oojs-ui/src/widgets/IconWidget.js b/vendor/oojs/oojs-ui/src/widgets/IconWidget.js
deleted file mode 100644
index 66ea3871..00000000
--- a/vendor/oojs/oojs-ui/src/widgets/IconWidget.js
+++ /dev/null
@@ -1,54 +0,0 @@
-/**
- * IconWidget is a generic widget for {@link OO.ui.IconElement icons}. In general, IconWidgets should be used with OO.ui.LabelWidget,
- * which creates a label that identifies the icon’s function. See the [OOjs UI documentation on MediaWiki] [1]
- * for a list of icons included in the library.
- *
- * @example
- * // An icon widget with a label
- * var myIcon = new OO.ui.IconWidget( {
- * icon: 'help',
- * iconTitle: 'Help'
- * } );
- * // Create a label.
- * var iconLabel = new OO.ui.LabelWidget( {
- * label: 'Help'
- * } );
- * $( 'body' ).append( myIcon.$element, iconLabel.$element );
- *
- * [1]: https://www.mediawiki.org/wiki/OOjs_UI/Widgets/Icons,_Indicators,_and_Labels#Icons
- *
- * @class
- * @extends OO.ui.Widget
- * @mixins OO.ui.IconElement
- * @mixins OO.ui.TitledElement
- * @mixins OO.ui.FlaggedElement
- *
- * @constructor
- * @param {Object} [config] Configuration options
- */
-OO.ui.IconWidget = function OoUiIconWidget( config ) {
- // Configuration initialization
- config = config || {};
-
- // Parent constructor
- OO.ui.IconWidget.super.call( this, config );
-
- // Mixin constructors
- OO.ui.IconElement.call( this, $.extend( {}, config, { $icon: this.$element } ) );
- OO.ui.TitledElement.call( this, $.extend( {}, config, { $titled: this.$element } ) );
- OO.ui.FlaggedElement.call( this, $.extend( {}, config, { $flagged: this.$element } ) );
-
- // Initialization
- this.$element.addClass( 'oo-ui-iconWidget' );
-};
-
-/* Setup */
-
-OO.inheritClass( OO.ui.IconWidget, OO.ui.Widget );
-OO.mixinClass( OO.ui.IconWidget, OO.ui.IconElement );
-OO.mixinClass( OO.ui.IconWidget, OO.ui.TitledElement );
-OO.mixinClass( OO.ui.IconWidget, OO.ui.FlaggedElement );
-
-/* Static Properties */
-
-OO.ui.IconWidget.static.tagName = 'span';
diff --git a/vendor/oojs/oojs-ui/src/widgets/IndicatorWidget.js b/vendor/oojs/oojs-ui/src/widgets/IndicatorWidget.js
deleted file mode 100644
index e6ecddf0..00000000
--- a/vendor/oojs/oojs-ui/src/widgets/IndicatorWidget.js
+++ /dev/null
@@ -1,52 +0,0 @@
-/**
- * IndicatorWidgets create indicators, which are small graphics that are generally used to draw
- * attention to the status of an item or to clarify the function of a control. For a list of
- * indicators included in the library, please see the [OOjs UI documentation on MediaWiki][1].
- *
- * @example
- * // Example of an indicator widget
- * var indicator1 = new OO.ui.IndicatorWidget( {
- * indicator: 'alert'
- * } );
- *
- * // Create a fieldset layout to add a label
- * var fieldset = new OO.ui.FieldsetLayout();
- * fieldset.addItems( [
- * new OO.ui.FieldLayout( indicator1, { label: 'An alert indicator:' } )
- * ] );
- * $( 'body' ).append( fieldset.$element );
- *
- * [1]: https://www.mediawiki.org/wiki/OOjs_UI/Widgets/Icons,_Indicators,_and_Labels#Indicators
- *
- * @class
- * @extends OO.ui.Widget
- * @mixins OO.ui.IndicatorElement
- * @mixins OO.ui.TitledElement
- *
- * @constructor
- * @param {Object} [config] Configuration options
- */
-OO.ui.IndicatorWidget = function OoUiIndicatorWidget( config ) {
- // Configuration initialization
- config = config || {};
-
- // Parent constructor
- OO.ui.IndicatorWidget.super.call( this, config );
-
- // Mixin constructors
- OO.ui.IndicatorElement.call( this, $.extend( {}, config, { $indicator: this.$element } ) );
- OO.ui.TitledElement.call( this, $.extend( {}, config, { $titled: this.$element } ) );
-
- // Initialization
- this.$element.addClass( 'oo-ui-indicatorWidget' );
-};
-
-/* Setup */
-
-OO.inheritClass( OO.ui.IndicatorWidget, OO.ui.Widget );
-OO.mixinClass( OO.ui.IndicatorWidget, OO.ui.IndicatorElement );
-OO.mixinClass( OO.ui.IndicatorWidget, OO.ui.TitledElement );
-
-/* Static Properties */
-
-OO.ui.IndicatorWidget.static.tagName = 'span';
diff --git a/vendor/oojs/oojs-ui/src/widgets/InputWidget.js b/vendor/oojs/oojs-ui/src/widgets/InputWidget.js
deleted file mode 100644
index de790bac..00000000
--- a/vendor/oojs/oojs-ui/src/widgets/InputWidget.js
+++ /dev/null
@@ -1,207 +0,0 @@
-/**
- * InputWidget is the base class for all input widgets, which
- * include {@link OO.ui.TextInputWidget text inputs}, {@link OO.ui.CheckboxInputWidget checkbox inputs},
- * {@link OO.ui.RadioInputWidget radio inputs}, and {@link OO.ui.ButtonInputWidget button inputs}.
- * See the [OOjs UI documentation on MediaWiki] [1] for more information and examples.
- *
- * [1]: https://www.mediawiki.org/wiki/OOjs_UI/Widgets/Inputs
- *
- * @abstract
- * @class
- * @extends OO.ui.Widget
- * @mixins OO.ui.FlaggedElement
- * @mixins OO.ui.TabIndexedElement
- *
- * @constructor
- * @param {Object} [config] Configuration options
- * @cfg {string} [name=''] The value of the input’s HTML `name` attribute.
- * @cfg {string} [value=''] The value of the input.
- * @cfg {Function} [inputFilter] The name of an input filter function. Input filters modify the value of an input
- * before it is accepted.
- */
-OO.ui.InputWidget = function OoUiInputWidget( config ) {
- // Configuration initialization
- config = config || {};
-
- // Parent constructor
- OO.ui.InputWidget.super.call( this, config );
-
- // Properties
- this.$input = this.getInputElement( config );
- this.value = '';
- this.inputFilter = config.inputFilter;
-
- // Mixin constructors
- OO.ui.FlaggedElement.call( this, config );
- OO.ui.TabIndexedElement.call( this, $.extend( {}, config, { $tabIndexed: this.$input } ) );
-
- // Events
- this.$input.on( 'keydown mouseup cut paste change input select', this.onEdit.bind( this ) );
-
- // Initialization
- this.$input
- .attr( 'name', config.name )
- .prop( 'disabled', this.isDisabled() );
- this.$element.addClass( 'oo-ui-inputWidget' ).append( this.$input, $( '<span>' ) );
- this.setValue( config.value );
-};
-
-/* Setup */
-
-OO.inheritClass( OO.ui.InputWidget, OO.ui.Widget );
-OO.mixinClass( OO.ui.InputWidget, OO.ui.FlaggedElement );
-OO.mixinClass( OO.ui.InputWidget, OO.ui.TabIndexedElement );
-
-/* Events */
-
-/**
- * @event change
- *
- * A change event is emitted when the value of the input changes.
- *
- * @param {string} value
- */
-
-/* Methods */
-
-/**
- * Get input element.
- *
- * Subclasses of OO.ui.InputWidget use the `config` parameter to produce different elements in
- * different circumstances. The element must have a `value` property (like form elements).
- *
- * @private
- * @param {Object} config Configuration options
- * @return {jQuery} Input element
- */
-OO.ui.InputWidget.prototype.getInputElement = function () {
- return $( '<input>' );
-};
-
-/**
- * Handle potentially value-changing events.
- *
- * @private
- * @param {jQuery.Event} e Key down, mouse up, cut, paste, change, input, or select event
- */
-OO.ui.InputWidget.prototype.onEdit = function () {
- var widget = this;
- if ( !this.isDisabled() ) {
- // Allow the stack to clear so the value will be updated
- setTimeout( function () {
- widget.setValue( widget.$input.val() );
- } );
- }
-};
-
-/**
- * Get the value of the input.
- *
- * @return {string} Input value
- */
-OO.ui.InputWidget.prototype.getValue = function () {
- // Resynchronize our internal data with DOM data. Other scripts executing on the page can modify
- // it, and we won't know unless they're kind enough to trigger a 'change' event.
- var value = this.$input.val();
- if ( this.value !== value ) {
- this.setValue( value );
- }
- return this.value;
-};
-
-/**
- * Set the direction of the input, either RTL (right-to-left) or LTR (left-to-right).
- *
- * @param {boolean} isRTL
- * Direction is right-to-left
- */
-OO.ui.InputWidget.prototype.setRTL = function ( isRTL ) {
- this.$input.prop( 'dir', isRTL ? 'rtl' : 'ltr' );
-};
-
-/**
- * Set the value of the input.
- *
- * @param {string} value New value
- * @fires change
- * @chainable
- */
-OO.ui.InputWidget.prototype.setValue = function ( value ) {
- value = this.cleanUpValue( value );
- // Update the DOM if it has changed. Note that with cleanUpValue, it
- // is possible for the DOM value to change without this.value changing.
- if ( this.$input.val() !== value ) {
- this.$input.val( value );
- }
- if ( this.value !== value ) {
- this.value = value;
- this.emit( 'change', this.value );
- }
- return this;
-};
-
-/**
- * Clean up incoming value.
- *
- * Ensures value is a string, and converts undefined and null to empty string.
- *
- * @private
- * @param {string} value Original value
- * @return {string} Cleaned up value
- */
-OO.ui.InputWidget.prototype.cleanUpValue = function ( value ) {
- if ( value === undefined || value === null ) {
- return '';
- } else if ( this.inputFilter ) {
- return this.inputFilter( String( value ) );
- } else {
- return String( value );
- }
-};
-
-/**
- * Simulate the behavior of clicking on a label bound to this input. This method is only called by
- * {@link OO.ui.LabelWidget LabelWidget} and {@link OO.ui.FieldLayout FieldLayout}. It should not be
- * called directly.
- */
-OO.ui.InputWidget.prototype.simulateLabelClick = function () {
- if ( !this.isDisabled() ) {
- if ( this.$input.is( ':checkbox, :radio' ) ) {
- this.$input.click();
- }
- if ( this.$input.is( ':input' ) ) {
- this.$input[ 0 ].focus();
- }
- }
-};
-
-/**
- * @inheritdoc
- */
-OO.ui.InputWidget.prototype.setDisabled = function ( state ) {
- OO.ui.InputWidget.super.prototype.setDisabled.call( this, state );
- if ( this.$input ) {
- this.$input.prop( 'disabled', this.isDisabled() );
- }
- return this;
-};
-
-/**
- * Focus the input.
- *
- * @chainable
- */
-OO.ui.InputWidget.prototype.focus = function () {
- this.$input[ 0 ].focus();
- return this;
-};
-
-/**
- * Blur the input.
- *
- * @chainable
- */
-OO.ui.InputWidget.prototype.blur = function () {
- this.$input[ 0 ].blur();
- return this;
-};
diff --git a/vendor/oojs/oojs-ui/src/widgets/ItemWidget.js b/vendor/oojs/oojs-ui/src/widgets/ItemWidget.js
deleted file mode 100644
index 292514f4..00000000
--- a/vendor/oojs/oojs-ui/src/widgets/ItemWidget.js
+++ /dev/null
@@ -1,48 +0,0 @@
-/**
- * Mixin for widgets used as items in widgets that inherit OO.ui.GroupWidget.
- *
- * Item widgets have a reference to a OO.ui.GroupWidget while they are attached to the group. This
- * allows bidirectional communication.
- *
- * Use together with OO.ui.GroupWidget to make disabled state inheritable.
- *
- * @private
- * @abstract
- * @class
- *
- * @constructor
- */
-OO.ui.ItemWidget = function OoUiItemWidget() {
- //
-};
-
-/* Methods */
-
-/**
- * Check if widget is disabled.
- *
- * Checks parent if present, making disabled state inheritable.
- *
- * @return {boolean} Widget is disabled
- */
-OO.ui.ItemWidget.prototype.isDisabled = function () {
- return this.disabled ||
- ( this.elementGroup instanceof OO.ui.Widget && this.elementGroup.isDisabled() );
-};
-
-/**
- * Set group element is in.
- *
- * @param {OO.ui.GroupElement|null} group Group element, null if none
- * @chainable
- */
-OO.ui.ItemWidget.prototype.setElementGroup = function ( group ) {
- // Parent method
- // Note: Calling #setElementGroup this way assumes this is mixed into an OO.ui.Element
- OO.ui.Element.prototype.setElementGroup.call( this, group );
-
- // Initialize item disabled states
- this.updateDisabled();
-
- return this;
-};
diff --git a/vendor/oojs/oojs-ui/src/widgets/LabelWidget.js b/vendor/oojs/oojs-ui/src/widgets/LabelWidget.js
deleted file mode 100644
index e00990bb..00000000
--- a/vendor/oojs/oojs-ui/src/widgets/LabelWidget.js
+++ /dev/null
@@ -1,84 +0,0 @@
-/**
- * LabelWidgets help identify the function of interface elements. Each LabelWidget can
- * be configured with a `label` option that is set to a string, a label node, or a function:
- *
- * - String: a plaintext string
- * - jQuery selection: a jQuery selection, used for anything other than a plaintext label, e.g., a
- * label that includes a link or special styling, such as a gray color or additional graphical elements.
- * - Function: a function that will produce a string in the future. Functions are used
- * in cases where the value of the label is not currently defined.
- *
- * In addition, the LabelWidget can be associated with an {@link OO.ui.InputWidget input widget}, which
- * will come into focus when the label is clicked.
- *
- * @example
- * // Examples of LabelWidgets
- * var label1 = new OO.ui.LabelWidget( {
- * label: 'plaintext label'
- * } );
- * var label2 = new OO.ui.LabelWidget( {
- * label: $( '<a href="default.html">jQuery label</a>' )
- * } );
- * // Create a fieldset layout with fields for each example
- * var fieldset = new OO.ui.FieldsetLayout();
- * fieldset.addItems( [
- * new OO.ui.FieldLayout( label1 ),
- * new OO.ui.FieldLayout( label2 )
- * ] );
- * $( 'body' ).append( fieldset.$element );
- *
- *
- * @class
- * @extends OO.ui.Widget
- * @mixins OO.ui.LabelElement
- *
- * @constructor
- * @param {Object} [config] Configuration options
- * @cfg {OO.ui.InputWidget} [input] {@link OO.ui.InputWidget Input widget} that uses the label.
- * Clicking the label will focus the specified input field.
- */
-OO.ui.LabelWidget = function OoUiLabelWidget( config ) {
- // Configuration initialization
- config = config || {};
-
- // Parent constructor
- OO.ui.LabelWidget.super.call( this, config );
-
- // Mixin constructors
- OO.ui.LabelElement.call( this, $.extend( {}, config, { $label: this.$element } ) );
- OO.ui.TitledElement.call( this, config );
-
- // Properties
- this.input = config.input;
-
- // Events
- if ( this.input instanceof OO.ui.InputWidget ) {
- this.$element.on( 'click', this.onClick.bind( this ) );
- }
-
- // Initialization
- this.$element.addClass( 'oo-ui-labelWidget' );
-};
-
-/* Setup */
-
-OO.inheritClass( OO.ui.LabelWidget, OO.ui.Widget );
-OO.mixinClass( OO.ui.LabelWidget, OO.ui.LabelElement );
-OO.mixinClass( OO.ui.LabelWidget, OO.ui.TitledElement );
-
-/* Static Properties */
-
-OO.ui.LabelWidget.static.tagName = 'span';
-
-/* Methods */
-
-/**
- * Handles label mouse click events.
- *
- * @private
- * @param {jQuery.Event} e Mouse click event
- */
-OO.ui.LabelWidget.prototype.onClick = function () {
- this.input.simulateLabelClick();
- return false;
-};
diff --git a/vendor/oojs/oojs-ui/src/widgets/MenuOptionWidget.js b/vendor/oojs/oojs-ui/src/widgets/MenuOptionWidget.js
deleted file mode 100644
index cc620d97..00000000
--- a/vendor/oojs/oojs-ui/src/widgets/MenuOptionWidget.js
+++ /dev/null
@@ -1,33 +0,0 @@
-/**
- * MenuOptionWidget is an option widget that looks like a menu item. The class is used with
- * OO.ui.MenuSelectWidget to create a menu of mutually exclusive options. Please see
- * the [OOjs UI documentation on MediaWiki] [1] for more information.
- *
- * [1]: https://www.mediawiki.org/wiki/OOjs_UI/Widgets/Selects_and_Options#Menu_selects_and_options
- *
- * @class
- * @extends OO.ui.DecoratedOptionWidget
- *
- * @constructor
- * @param {Object} [config] Configuration options
- */
-OO.ui.MenuOptionWidget = function OoUiMenuOptionWidget( config ) {
- // Configuration initialization
- config = $.extend( { icon: 'check' }, config );
-
- // Parent constructor
- OO.ui.MenuOptionWidget.super.call( this, config );
-
- // Initialization
- this.$element
- .attr( 'role', 'menuitem' )
- .addClass( 'oo-ui-menuOptionWidget' );
-};
-
-/* Setup */
-
-OO.inheritClass( OO.ui.MenuOptionWidget, OO.ui.DecoratedOptionWidget );
-
-/* Static Properties */
-
-OO.ui.MenuOptionWidget.static.scrollIntoViewOnSelect = true;
diff --git a/vendor/oojs/oojs-ui/src/widgets/MenuSectionOptionWidget.js b/vendor/oojs/oojs-ui/src/widgets/MenuSectionOptionWidget.js
deleted file mode 100644
index 054df7fc..00000000
--- a/vendor/oojs/oojs-ui/src/widgets/MenuSectionOptionWidget.js
+++ /dev/null
@@ -1,55 +0,0 @@
-/**
- * MenuSectionOptionWidgets are used inside {@link OO.ui.MenuSelectWidget menu select widgets} to group one or more related
- * {@link OO.ui.MenuOptionWidget menu options}. MenuSectionOptionWidgets cannot be highlighted or selected.
- *
- * @example
- * var myDropdown = new OO.ui.DropdownWidget( {
- * menu: {
- * items: [
- * new OO.ui.MenuSectionOptionWidget( {
- * label: 'Dogs'
- * } ),
- * new OO.ui.MenuOptionWidget( {
- * data: 'corgi',
- * label: 'Welsh Corgi'
- * } ),
- * new OO.ui.MenuOptionWidget( {
- * data: 'poodle',
- * label: 'Standard Poodle'
- * } ),
- * new OO.ui.MenuSectionOptionWidget( {
- * label: 'Cats'
- * } ),
- * new OO.ui.MenuOptionWidget( {
- * data: 'lion',
- * label: 'Lion'
- * } )
- * ]
- * }
- * } );
- * $( 'body' ).append( myDropdown.$element );
- *
- *
- * @class
- * @extends OO.ui.DecoratedOptionWidget
- *
- * @constructor
- * @param {Object} [config] Configuration options
- */
-OO.ui.MenuSectionOptionWidget = function OoUiMenuSectionOptionWidget( config ) {
- // Parent constructor
- OO.ui.MenuSectionOptionWidget.super.call( this, config );
-
- // Initialization
- this.$element.addClass( 'oo-ui-menuSectionOptionWidget' );
-};
-
-/* Setup */
-
-OO.inheritClass( OO.ui.MenuSectionOptionWidget, OO.ui.DecoratedOptionWidget );
-
-/* Static Properties */
-
-OO.ui.MenuSectionOptionWidget.static.selectable = false;
-
-OO.ui.MenuSectionOptionWidget.static.highlightable = false;
diff --git a/vendor/oojs/oojs-ui/src/widgets/MenuSelectWidget.js b/vendor/oojs/oojs-ui/src/widgets/MenuSelectWidget.js
deleted file mode 100644
index a1755edd..00000000
--- a/vendor/oojs/oojs-ui/src/widgets/MenuSelectWidget.js
+++ /dev/null
@@ -1,254 +0,0 @@
-/**
- * MenuSelectWidget is a {@link OO.ui.SelectWidget select widget} that contains options and
- * is used together with OO.ui.MenuOptionWidget. It is designed be used as part of another widget.
- * See {@link OO.ui.DropdownWidget DropdownWidget}, {@link OO.ui.ComboBoxWidget ComboBoxWidget},
- * and {@link OO.ui.LookupElement LookupElement} for examples of widgets that contain menus.
- * MenuSelectWidgets themselves are not instantiated directly, rather subclassed
- * and customized to be opened, closed, and displayed as needed.
- *
- * By default, menus are clipped to the visible viewport and are not visible when a user presses the
- * mouse outside the menu.
- *
- * Menus also have support for keyboard interaction:
- *
- * - Enter/Return key: choose and select a menu option
- * - Up-arrow key: highlight the previous menu option
- * - Down-arrow key: highlight the next menu option
- * - Esc key: hide the menu
- *
- * Please see the [OOjs UI documentation on MediaWiki][1] for more information.
- * [1]: https://www.mediawiki.org/wiki/OOjs_UI/Widgets/Selects_and_Options
- *
- * @class
- * @extends OO.ui.SelectWidget
- * @mixins OO.ui.ClippableElement
- *
- * @constructor
- * @param {Object} [config] Configuration options
- * @cfg {OO.ui.TextInputWidget} [input] Text input used to implement option highlighting for menu items that match
- * the text the user types. This config is used by {@link OO.ui.ComboBoxWidget ComboBoxWidget}
- * and {@link OO.ui.LookupElement LookupElement}
- * @cfg {OO.ui.Widget} [widget] Widget associated with the menu’s active state. If the user clicks the mouse
- * anywhere on the page outside of this widget, the menu is hidden.
- * @cfg {boolean} [autoHide=true] Hide the menu when the mouse is pressed outside the menu.
- */
-OO.ui.MenuSelectWidget = function OoUiMenuSelectWidget( config ) {
- // Configuration initialization
- config = config || {};
-
- // Parent constructor
- OO.ui.MenuSelectWidget.super.call( this, config );
-
- // Mixin constructors
- OO.ui.ClippableElement.call( this, $.extend( {}, config, { $clippable: this.$group } ) );
-
- // Properties
- this.newItems = null;
- this.autoHide = config.autoHide === undefined || !!config.autoHide;
- this.$input = config.input ? config.input.$input : null;
- this.$widget = config.widget ? config.widget.$element : null;
- this.onDocumentMouseDownHandler = this.onDocumentMouseDown.bind( this );
-
- // Initialization
- this.$element
- .addClass( 'oo-ui-menuSelectWidget' )
- .attr( 'role', 'menu' );
-
- // Initially hidden - using #toggle may cause errors if subclasses override toggle with methods
- // that reference properties not initialized at that time of parent class construction
- // TODO: Find a better way to handle post-constructor setup
- this.visible = false;
- this.$element.addClass( 'oo-ui-element-hidden' );
-};
-
-/* Setup */
-
-OO.inheritClass( OO.ui.MenuSelectWidget, OO.ui.SelectWidget );
-OO.mixinClass( OO.ui.MenuSelectWidget, OO.ui.ClippableElement );
-
-/* Methods */
-
-/**
- * Handles document mouse down events.
- *
- * @protected
- * @param {jQuery.Event} e Key down event
- */
-OO.ui.MenuSelectWidget.prototype.onDocumentMouseDown = function ( e ) {
- if (
- !OO.ui.contains( this.$element[ 0 ], e.target, true ) &&
- ( !this.$widget || !OO.ui.contains( this.$widget[ 0 ], e.target, true ) )
- ) {
- this.toggle( false );
- }
-};
-
-/**
- * @inheritdoc
- */
-OO.ui.MenuSelectWidget.prototype.onKeyDown = function ( e ) {
- var currentItem = this.getHighlightedItem() || this.getSelectedItem();
-
- if ( !this.isDisabled() && this.isVisible() ) {
- switch ( e.keyCode ) {
- case OO.ui.Keys.LEFT:
- case OO.ui.Keys.RIGHT:
- // Do nothing if a text field is associated, arrow keys will be handled natively
- if ( !this.$input ) {
- OO.ui.MenuSelectWidget.super.prototype.onKeyDown.call( this, e );
- }
- break;
- case OO.ui.Keys.ESCAPE:
- case OO.ui.Keys.TAB:
- if ( currentItem ) {
- currentItem.setHighlighted( false );
- }
- this.toggle( false );
- // Don't prevent tabbing away, prevent defocusing
- if ( e.keyCode === OO.ui.Keys.ESCAPE ) {
- e.preventDefault();
- e.stopPropagation();
- }
- break;
- default:
- OO.ui.MenuSelectWidget.super.prototype.onKeyDown.call( this, e );
- return;
- }
- }
-};
-
-/**
- * @inheritdoc
- */
-OO.ui.MenuSelectWidget.prototype.bindKeyDownListener = function () {
- if ( this.$input ) {
- this.$input.on( 'keydown', this.onKeyDownHandler );
- } else {
- OO.ui.MenuSelectWidget.super.prototype.bindKeyDownListener.call( this );
- }
-};
-
-/**
- * @inheritdoc
- */
-OO.ui.MenuSelectWidget.prototype.unbindKeyDownListener = function () {
- if ( this.$input ) {
- this.$input.off( 'keydown', this.onKeyDownHandler );
- } else {
- OO.ui.MenuSelectWidget.super.prototype.unbindKeyDownListener.call( this );
- }
-};
-
-/**
- * Choose an item.
- *
- * When a user chooses an item, the menu is closed.
- *
- * Note that ‘choose’ should never be modified programmatically. A user can choose an option with the keyboard
- * or mouse and it becomes selected. To select an item programmatically, use the #selectItem method.
- * @param {OO.ui.OptionWidget} item Item to choose
- * @chainable
- */
-OO.ui.MenuSelectWidget.prototype.chooseItem = function ( item ) {
- OO.ui.MenuSelectWidget.super.prototype.chooseItem.call( this, item );
- this.toggle( false );
- return this;
-};
-
-/**
- * @inheritdoc
- */
-OO.ui.MenuSelectWidget.prototype.addItems = function ( items, index ) {
- var i, len, item;
-
- // Parent method
- OO.ui.MenuSelectWidget.super.prototype.addItems.call( this, items, index );
-
- // Auto-initialize
- if ( !this.newItems ) {
- this.newItems = [];
- }
-
- for ( i = 0, len = items.length; i < len; i++ ) {
- item = items[ i ];
- if ( this.isVisible() ) {
- // Defer fitting label until item has been attached
- item.fitLabel();
- } else {
- this.newItems.push( item );
- }
- }
-
- // Reevaluate clipping
- this.clip();
-
- return this;
-};
-
-/**
- * @inheritdoc
- */
-OO.ui.MenuSelectWidget.prototype.removeItems = function ( items ) {
- // Parent method
- OO.ui.MenuSelectWidget.super.prototype.removeItems.call( this, items );
-
- // Reevaluate clipping
- this.clip();
-
- return this;
-};
-
-/**
- * @inheritdoc
- */
-OO.ui.MenuSelectWidget.prototype.clearItems = function () {
- // Parent method
- OO.ui.MenuSelectWidget.super.prototype.clearItems.call( this );
-
- // Reevaluate clipping
- this.clip();
-
- return this;
-};
-
-/**
- * @inheritdoc
- */
-OO.ui.MenuSelectWidget.prototype.toggle = function ( visible ) {
- visible = ( visible === undefined ? !this.visible : !!visible ) && !!this.items.length;
-
- var i, len,
- change = visible !== this.isVisible();
-
- // Parent method
- OO.ui.MenuSelectWidget.super.prototype.toggle.call( this, visible );
-
- if ( change ) {
- if ( visible ) {
- this.bindKeyDownListener();
-
- if ( this.newItems && this.newItems.length ) {
- for ( i = 0, len = this.newItems.length; i < len; i++ ) {
- this.newItems[ i ].fitLabel();
- }
- this.newItems = null;
- }
- this.toggleClipping( true );
-
- // Auto-hide
- if ( this.autoHide ) {
- this.getElementDocument().addEventListener(
- 'mousedown', this.onDocumentMouseDownHandler, true
- );
- }
- } else {
- this.unbindKeyDownListener();
- this.getElementDocument().removeEventListener(
- 'mousedown', this.onDocumentMouseDownHandler, true
- );
- this.toggleClipping( false );
- }
- }
-
- return this;
-};
diff --git a/vendor/oojs/oojs-ui/src/widgets/OptionWidget.js b/vendor/oojs/oojs-ui/src/widgets/OptionWidget.js
deleted file mode 100644
index 0bc2486e..00000000
--- a/vendor/oojs/oojs-ui/src/widgets/OptionWidget.js
+++ /dev/null
@@ -1,177 +0,0 @@
-/**
- * OptionWidgets are special elements that can be selected and configured with data. The
- * data is often unique for each option, but it does not have to be. OptionWidgets are used
- * with OO.ui.SelectWidget to create a selection of mutually exclusive options. For more information
- * and examples, please see the [OOjs UI documentation on MediaWiki][1].
- *
- * [1]: https://www.mediawiki.org/wiki/OOjs_UI/Widgets/Selects_and_Options
- *
- * @class
- * @extends OO.ui.Widget
- * @mixins OO.ui.LabelElement
- * @mixins OO.ui.FlaggedElement
- *
- * @constructor
- * @param {Object} [config] Configuration options
- */
-OO.ui.OptionWidget = function OoUiOptionWidget( config ) {
- // Configuration initialization
- config = config || {};
-
- // Parent constructor
- OO.ui.OptionWidget.super.call( this, config );
-
- // Mixin constructors
- OO.ui.ItemWidget.call( this );
- OO.ui.LabelElement.call( this, config );
- OO.ui.FlaggedElement.call( this, config );
-
- // Properties
- this.selected = false;
- this.highlighted = false;
- this.pressed = false;
-
- // Initialization
- this.$element
- .data( 'oo-ui-optionWidget', this )
- .attr( 'role', 'option' )
- .addClass( 'oo-ui-optionWidget' )
- .append( this.$label );
-};
-
-/* Setup */
-
-OO.inheritClass( OO.ui.OptionWidget, OO.ui.Widget );
-OO.mixinClass( OO.ui.OptionWidget, OO.ui.ItemWidget );
-OO.mixinClass( OO.ui.OptionWidget, OO.ui.LabelElement );
-OO.mixinClass( OO.ui.OptionWidget, OO.ui.FlaggedElement );
-
-/* Static Properties */
-
-OO.ui.OptionWidget.static.selectable = true;
-
-OO.ui.OptionWidget.static.highlightable = true;
-
-OO.ui.OptionWidget.static.pressable = true;
-
-OO.ui.OptionWidget.static.scrollIntoViewOnSelect = false;
-
-/* Methods */
-
-/**
- * Check if the option can be selected.
- *
- * @return {boolean} Item is selectable
- */
-OO.ui.OptionWidget.prototype.isSelectable = function () {
- return this.constructor.static.selectable && !this.isDisabled();
-};
-
-/**
- * Check if the option can be highlighted. A highlight indicates that the option
- * may be selected when a user presses enter or clicks. Disabled items cannot
- * be highlighted.
- *
- * @return {boolean} Item is highlightable
- */
-OO.ui.OptionWidget.prototype.isHighlightable = function () {
- return this.constructor.static.highlightable && !this.isDisabled();
-};
-
-/**
- * Check if the option can be pressed. The pressed state occurs when a user mouses
- * down on an item, but has not yet let go of the mouse.
- *
- * @return {boolean} Item is pressable
- */
-OO.ui.OptionWidget.prototype.isPressable = function () {
- return this.constructor.static.pressable && !this.isDisabled();
-};
-
-/**
- * Check if the option is selected.
- *
- * @return {boolean} Item is selected
- */
-OO.ui.OptionWidget.prototype.isSelected = function () {
- return this.selected;
-};
-
-/**
- * Check if the option is highlighted. A highlight indicates that the
- * item may be selected when a user presses enter or clicks.
- *
- * @return {boolean} Item is highlighted
- */
-OO.ui.OptionWidget.prototype.isHighlighted = function () {
- return this.highlighted;
-};
-
-/**
- * Check if the option is pressed. The pressed state occurs when a user mouses
- * down on an item, but has not yet let go of the mouse. The item may appear
- * selected, but it will not be selected until the user releases the mouse.
- *
- * @return {boolean} Item is pressed
- */
-OO.ui.OptionWidget.prototype.isPressed = function () {
- return this.pressed;
-};
-
-/**
- * Set the option’s selected state. In general, all modifications to the selection
- * should be handled by the SelectWidget’s {@link OO.ui.SelectWidget#selectItem selectItem( [item] )}
- * method instead of this method.
- *
- * @param {boolean} [state=false] Select option
- * @chainable
- */
-OO.ui.OptionWidget.prototype.setSelected = function ( state ) {
- if ( this.constructor.static.selectable ) {
- this.selected = !!state;
- this.$element
- .toggleClass( 'oo-ui-optionWidget-selected', state )
- .attr( 'aria-selected', state.toString() );
- if ( state && this.constructor.static.scrollIntoViewOnSelect ) {
- this.scrollElementIntoView();
- }
- this.updateThemeClasses();
- }
- return this;
-};
-
-/**
- * Set the option’s highlighted state. In general, all programmatic
- * modifications to the highlight should be handled by the
- * SelectWidget’s {@link OO.ui.SelectWidget#highlightItem highlightItem( [item] )}
- * method instead of this method.
- *
- * @param {boolean} [state=false] Highlight option
- * @chainable
- */
-OO.ui.OptionWidget.prototype.setHighlighted = function ( state ) {
- if ( this.constructor.static.highlightable ) {
- this.highlighted = !!state;
- this.$element.toggleClass( 'oo-ui-optionWidget-highlighted', state );
- this.updateThemeClasses();
- }
- return this;
-};
-
-/**
- * Set the option’s pressed state. In general, all
- * programmatic modifications to the pressed state should be handled by the
- * SelectWidget’s {@link OO.ui.SelectWidget#pressItem pressItem( [item] )}
- * method instead of this method.
- *
- * @param {boolean} [state=false] Press option
- * @chainable
- */
-OO.ui.OptionWidget.prototype.setPressed = function ( state ) {
- if ( this.constructor.static.pressable ) {
- this.pressed = !!state;
- this.$element.toggleClass( 'oo-ui-optionWidget-pressed', state );
- this.updateThemeClasses();
- }
- return this;
-};
diff --git a/vendor/oojs/oojs-ui/src/widgets/OutlineControlsWidget.js b/vendor/oojs/oojs-ui/src/widgets/OutlineControlsWidget.js
deleted file mode 100644
index 0219a44d..00000000
--- a/vendor/oojs/oojs-ui/src/widgets/OutlineControlsWidget.js
+++ /dev/null
@@ -1,145 +0,0 @@
-/**
- * OutlineControlsWidget is a set of controls for an {@link OO.ui.OutlineSelectWidget outline select widget}.
- * Controls include moving items up and down, removing items, and adding different kinds of items.
- * ####Currently, this class is only used by {@link OO.ui.BookletLayout booklet layouts}.####
- *
- * @class
- * @extends OO.ui.Widget
- * @mixins OO.ui.GroupElement
- * @mixins OO.ui.IconElement
- *
- * @constructor
- * @param {OO.ui.OutlineSelectWidget} outline Outline to control
- * @param {Object} [config] Configuration options
- * @cfg {Object} [abilities] List of abilties
- * @cfg {boolean} [abilities.move=true] Allow moving movable items
- * @cfg {boolean} [abilities.remove=true] Allow removing removable items
- */
-OO.ui.OutlineControlsWidget = function OoUiOutlineControlsWidget( outline, config ) {
- // Allow passing positional parameters inside the config object
- if ( OO.isPlainObject( outline ) && config === undefined ) {
- config = outline;
- outline = config.outline;
- }
-
- // Configuration initialization
- config = $.extend( { icon: 'add' }, config );
-
- // Parent constructor
- OO.ui.OutlineControlsWidget.super.call( this, config );
-
- // Mixin constructors
- OO.ui.GroupElement.call( this, config );
- OO.ui.IconElement.call( this, config );
-
- // Properties
- this.outline = outline;
- this.$movers = $( '<div>' );
- this.upButton = new OO.ui.ButtonWidget( {
- framed: false,
- icon: 'collapse',
- title: OO.ui.msg( 'ooui-outline-control-move-up' )
- } );
- this.downButton = new OO.ui.ButtonWidget( {
- framed: false,
- icon: 'expand',
- title: OO.ui.msg( 'ooui-outline-control-move-down' )
- } );
- this.removeButton = new OO.ui.ButtonWidget( {
- framed: false,
- icon: 'remove',
- title: OO.ui.msg( 'ooui-outline-control-remove' )
- } );
- this.abilities = { move: true, remove: true };
-
- // Events
- outline.connect( this, {
- select: 'onOutlineChange',
- add: 'onOutlineChange',
- remove: 'onOutlineChange'
- } );
- this.upButton.connect( this, { click: [ 'emit', 'move', -1 ] } );
- this.downButton.connect( this, { click: [ 'emit', 'move', 1 ] } );
- this.removeButton.connect( this, { click: [ 'emit', 'remove' ] } );
-
- // Initialization
- this.$element.addClass( 'oo-ui-outlineControlsWidget' );
- this.$group.addClass( 'oo-ui-outlineControlsWidget-items' );
- this.$movers
- .addClass( 'oo-ui-outlineControlsWidget-movers' )
- .append( this.removeButton.$element, this.upButton.$element, this.downButton.$element );
- this.$element.append( this.$icon, this.$group, this.$movers );
- this.setAbilities( config.abilities || {} );
-};
-
-/* Setup */
-
-OO.inheritClass( OO.ui.OutlineControlsWidget, OO.ui.Widget );
-OO.mixinClass( OO.ui.OutlineControlsWidget, OO.ui.GroupElement );
-OO.mixinClass( OO.ui.OutlineControlsWidget, OO.ui.IconElement );
-
-/* Events */
-
-/**
- * @event move
- * @param {number} places Number of places to move
- */
-
-/**
- * @event remove
- */
-
-/* Methods */
-
-/**
- * Set abilities.
- *
- * @param {Object} abilities List of abilties
- * @param {boolean} [abilities.move] Allow moving movable items
- * @param {boolean} [abilities.remove] Allow removing removable items
- */
-OO.ui.OutlineControlsWidget.prototype.setAbilities = function ( abilities ) {
- var ability;
-
- for ( ability in this.abilities ) {
- if ( abilities[ability] !== undefined ) {
- this.abilities[ability] = !!abilities[ability];
- }
- }
-
- this.onOutlineChange();
-};
-
-/**
- *
- * @private
- * Handle outline change events.
- */
-OO.ui.OutlineControlsWidget.prototype.onOutlineChange = function () {
- var i, len, firstMovable, lastMovable,
- items = this.outline.getItems(),
- selectedItem = this.outline.getSelectedItem(),
- movable = this.abilities.move && selectedItem && selectedItem.isMovable(),
- removable = this.abilities.remove && selectedItem && selectedItem.isRemovable();
-
- if ( movable ) {
- i = -1;
- len = items.length;
- while ( ++i < len ) {
- if ( items[ i ].isMovable() ) {
- firstMovable = items[ i ];
- break;
- }
- }
- i = len;
- while ( i-- ) {
- if ( items[ i ].isMovable() ) {
- lastMovable = items[ i ];
- break;
- }
- }
- }
- this.upButton.setDisabled( !movable || selectedItem === firstMovable );
- this.downButton.setDisabled( !movable || selectedItem === lastMovable );
- this.removeButton.setDisabled( !removable );
-};
diff --git a/vendor/oojs/oojs-ui/src/widgets/OutlineOptionWidget.js b/vendor/oojs/oojs-ui/src/widgets/OutlineOptionWidget.js
deleted file mode 100644
index d792fee6..00000000
--- a/vendor/oojs/oojs-ui/src/widgets/OutlineOptionWidget.js
+++ /dev/null
@@ -1,130 +0,0 @@
-/**
- * OutlineOptionWidget is an item in an {@link OO.ui.OutlineSelectWidget OutlineSelectWidget}.
- *
- * Currently, this class is only used by {@link OO.ui.BookletLayout booklet layouts}, which contain
- * {@link OO.ui.PageLayout page layouts}. See {@link OO.ui.BookletLayout BookletLayout}
- * for an example.
- *
- * @class
- * @extends OO.ui.DecoratedOptionWidget
- *
- * @constructor
- * @param {Object} [config] Configuration options
- * @cfg {number} [level] Indentation level
- * @cfg {boolean} [movable] Allow modification from {@link OO.ui.OutlineControlsWidget outline controls}.
- */
-OO.ui.OutlineOptionWidget = function OoUiOutlineOptionWidget( config ) {
- // Configuration initialization
- config = config || {};
-
- // Parent constructor
- OO.ui.OutlineOptionWidget.super.call( this, config );
-
- // Properties
- this.level = 0;
- this.movable = !!config.movable;
- this.removable = !!config.removable;
-
- // Initialization
- this.$element.addClass( 'oo-ui-outlineOptionWidget' );
- this.setLevel( config.level );
-};
-
-/* Setup */
-
-OO.inheritClass( OO.ui.OutlineOptionWidget, OO.ui.DecoratedOptionWidget );
-
-/* Static Properties */
-
-OO.ui.OutlineOptionWidget.static.highlightable = false;
-
-OO.ui.OutlineOptionWidget.static.scrollIntoViewOnSelect = true;
-
-OO.ui.OutlineOptionWidget.static.levelClass = 'oo-ui-outlineOptionWidget-level-';
-
-OO.ui.OutlineOptionWidget.static.levels = 3;
-
-/* Methods */
-
-/**
- * Check if item is movable.
- *
- * Movability is used by {@link OO.ui.OutlineControlsWidget outline controls}.
- *
- * @return {boolean} Item is movable
- */
-OO.ui.OutlineOptionWidget.prototype.isMovable = function () {
- return this.movable;
-};
-
-/**
- * Check if item is removable.
- *
- * Removability is used by {@link OO.ui.OutlineControlsWidget outline controls}.
- *
- * @return {boolean} Item is removable
- */
-OO.ui.OutlineOptionWidget.prototype.isRemovable = function () {
- return this.removable;
-};
-
-/**
- * Get indentation level.
- *
- * @return {number} Indentation level
- */
-OO.ui.OutlineOptionWidget.prototype.getLevel = function () {
- return this.level;
-};
-
-/**
- * Set movability.
- *
- * Movability is used by {@link OO.ui.OutlineControlsWidget outline controls}.
- *
- * @param {boolean} movable Item is movable
- * @chainable
- */
-OO.ui.OutlineOptionWidget.prototype.setMovable = function ( movable ) {
- this.movable = !!movable;
- this.updateThemeClasses();
- return this;
-};
-
-/**
- * Set removability.
- *
- * Removability is used by {@link OO.ui.OutlineControlsWidget outline controls}.
- *
- * @param {boolean} movable Item is removable
- * @chainable
- */
-OO.ui.OutlineOptionWidget.prototype.setRemovable = function ( removable ) {
- this.removable = !!removable;
- this.updateThemeClasses();
- return this;
-};
-
-/**
- * Set indentation level.
- *
- * @param {number} [level=0] Indentation level, in the range of [0,#maxLevel]
- * @chainable
- */
-OO.ui.OutlineOptionWidget.prototype.setLevel = function ( level ) {
- var levels = this.constructor.static.levels,
- levelClass = this.constructor.static.levelClass,
- i = levels;
-
- this.level = level ? Math.max( 0, Math.min( levels - 1, level ) ) : 0;
- while ( i-- ) {
- if ( this.level === i ) {
- this.$element.addClass( levelClass + i );
- } else {
- this.$element.removeClass( levelClass + i );
- }
- }
- this.updateThemeClasses();
-
- return this;
-};
diff --git a/vendor/oojs/oojs-ui/src/widgets/OutlineSelectWidget.js b/vendor/oojs/oojs-ui/src/widgets/OutlineSelectWidget.js
deleted file mode 100644
index cd7db546..00000000
--- a/vendor/oojs/oojs-ui/src/widgets/OutlineSelectWidget.js
+++ /dev/null
@@ -1,34 +0,0 @@
-/**
- * OutlineSelectWidget is a structured list that contains {@link OO.ui.OutlineOptionWidget outline options}
- * A set of controls can be provided with an {@link OO.ui.OutlineControlsWidget outline controls} widget.
- *
- * ####Currently, this class is only used by {@link OO.ui.BookletLayout booklet layouts}.####
- *
- * @class
- * @extends OO.ui.SelectWidget
- * @mixins OO.ui.TabIndexedElement
- *
- * @constructor
- * @param {Object} [config] Configuration options
- */
-OO.ui.OutlineSelectWidget = function OoUiOutlineSelectWidget( config ) {
- // Parent constructor
- OO.ui.OutlineSelectWidget.super.call( this, config );
-
- // Mixin constructors
- OO.ui.TabIndexedElement.call( this, config );
-
- // Events
- this.$element.on( {
- focus: this.bindKeyDownListener.bind( this ),
- blur: this.unbindKeyDownListener.bind( this )
- } );
-
- // Initialization
- this.$element.addClass( 'oo-ui-outlineSelectWidget' );
-};
-
-/* Setup */
-
-OO.inheritClass( OO.ui.OutlineSelectWidget, OO.ui.SelectWidget );
-OO.mixinClass( OO.ui.OutlineSelectWidget, OO.ui.TabIndexedElement );
diff --git a/vendor/oojs/oojs-ui/src/widgets/PopupButtonWidget.js b/vendor/oojs/oojs-ui/src/widgets/PopupButtonWidget.js
deleted file mode 100644
index 5643b77c..00000000
--- a/vendor/oojs/oojs-ui/src/widgets/PopupButtonWidget.js
+++ /dev/null
@@ -1,57 +0,0 @@
-/**
- * PopupButtonWidgets toggle the visibility of a contained {@link OO.ui.PopupWidget PopupWidget},
- * which is used to display additional information or options.
- *
- * @example
- * // Example of a popup button.
- * var popupButton = new OO.ui.PopupButtonWidget( {
- * label: 'Popup button with options',
- * icon: 'menu',
- * popup: {
- * $content: $( '<p>Additional options here.</p>' ),
- * padded: true,
- * align: 'force-left'
- * }
- * } );
- * // Append the button to the DOM.
- * $( 'body' ).append( popupButton.$element );
- *
- * @class
- * @extends OO.ui.ButtonWidget
- * @mixins OO.ui.PopupElement
- *
- * @constructor
- * @param {Object} [config] Configuration options
- */
-OO.ui.PopupButtonWidget = function OoUiPopupButtonWidget( config ) {
- // Parent constructor
- OO.ui.PopupButtonWidget.super.call( this, config );
-
- // Mixin constructors
- OO.ui.PopupElement.call( this, config );
-
- // Events
- this.connect( this, { click: 'onAction' } );
-
- // Initialization
- this.$element
- .addClass( 'oo-ui-popupButtonWidget' )
- .attr( 'aria-haspopup', 'true' )
- .append( this.popup.$element );
-};
-
-/* Setup */
-
-OO.inheritClass( OO.ui.PopupButtonWidget, OO.ui.ButtonWidget );
-OO.mixinClass( OO.ui.PopupButtonWidget, OO.ui.PopupElement );
-
-/* Methods */
-
-/**
- * Handle the button action being triggered.
- *
- * @private
- */
-OO.ui.PopupButtonWidget.prototype.onAction = function () {
- this.popup.toggle();
-};
diff --git a/vendor/oojs/oojs-ui/src/widgets/PopupWidget.js b/vendor/oojs/oojs-ui/src/widgets/PopupWidget.js
deleted file mode 100644
index 0b1f4ca6..00000000
--- a/vendor/oojs/oojs-ui/src/widgets/PopupWidget.js
+++ /dev/null
@@ -1,395 +0,0 @@
-/**
- * PopupWidget is a container for content. The popup is overlaid and positioned absolutely.
- * By default, each popup has an anchor that points toward its origin.
- * Please see the [OOjs UI documentation on Mediawiki] [1] for more information and examples.
- *
- * @example
- * // A popup widget.
- * var popup = new OO.ui.PopupWidget( {
- * $content: $( '<p>Hi there!</p>' ),
- * padded: true,
- * width: 300
- * } );
- *
- * $( 'body' ).append( popup.$element );
- * // To display the popup, toggle the visibility to 'true'.
- * popup.toggle( true );
- *
- * [1]: https://www.mediawiki.org/wiki/OOjs_UI/Widgets/Popups
- *
- * @class
- * @extends OO.ui.Widget
- * @mixins OO.ui.LabelElement
- *
- * @constructor
- * @param {Object} [config] Configuration options
- * @cfg {number} [width=320] Width of popup in pixels
- * @cfg {number} [height] Height of popup in pixels. Omit to use the automatic height.
- * @cfg {boolean} [anchor=true] Show anchor pointing to origin of popup
- * @cfg {string} [align='center'] Alignment of the popup: `center`, `force-left`, `force-right`, `backwards` or `forwards`.
- * If the popup is forced-left the popup body is leaning towards the left. For force-right alignment, the body of the
- * popup is leaning towards the right of the screen.
- * Using 'backwards' is a logical direction which will result in the popup leaning towards the beginning of the sentence
- * in the given language, which means it will flip to the correct positioning in right-to-left languages.
- * Using 'forward' will also result in a logical alignment where the body of the popup leans towards the end of the
- * sentence in the given language.
- * @cfg {jQuery} [$container] Constrain the popup to the boundaries of the specified container.
- * See the [OOjs UI docs on MediaWiki][3] for an example.
- * [3]: https://www.mediawiki.org/wiki/OOjs_UI/Widgets/Popups#containerExample
- * @cfg {number} [containerPadding=10] Padding between the popup and its container, specified as a number of pixels.
- * @cfg {jQuery} [$content] Content to append to the popup's body
- * @cfg {boolean} [autoClose=false] Automatically close the popup when it loses focus.
- * @cfg {jQuery} [$autoCloseIgnore] Elements that will not close the popup when clicked.
- * This config option is only relevant if #autoClose is set to `true`. See the [OOjs UI docs on MediaWiki][2]
- * for an example.
- * [2]: https://www.mediawiki.org/wiki/OOjs_UI/Widgets/Popups#autocloseExample
- * @cfg {boolean} [head] Show a popup header that contains a #label (if specified) and close
- * button.
- * @cfg {boolean} [padded] Add padding to the popup's body
- */
-OO.ui.PopupWidget = function OoUiPopupWidget( config ) {
- // Configuration initialization
- config = config || {};
-
- // Parent constructor
- OO.ui.PopupWidget.super.call( this, config );
-
- // Properties (must be set before ClippableElement constructor call)
- this.$body = $( '<div>' );
-
- // Mixin constructors
- OO.ui.LabelElement.call( this, config );
- OO.ui.ClippableElement.call( this, $.extend( {}, config, { $clippable: this.$body } ) );
-
- // Properties
- this.$popup = $( '<div>' );
- this.$head = $( '<div>' );
- this.$anchor = $( '<div>' );
- // If undefined, will be computed lazily in updateDimensions()
- this.$container = config.$container;
- this.containerPadding = config.containerPadding !== undefined ? config.containerPadding : 10;
- this.autoClose = !!config.autoClose;
- this.$autoCloseIgnore = config.$autoCloseIgnore;
- this.transitionTimeout = null;
- this.anchor = null;
- this.width = config.width !== undefined ? config.width : 320;
- this.height = config.height !== undefined ? config.height : null;
- this.setAlignment( config.align );
- this.closeButton = new OO.ui.ButtonWidget( { framed: false, icon: 'close' } );
- this.onMouseDownHandler = this.onMouseDown.bind( this );
- this.onDocumentKeyDownHandler = this.onDocumentKeyDown.bind( this );
-
- // Events
- this.closeButton.connect( this, { click: 'onCloseButtonClick' } );
-
- // Initialization
- this.toggleAnchor( config.anchor === undefined || config.anchor );
- this.$body.addClass( 'oo-ui-popupWidget-body' );
- this.$anchor.addClass( 'oo-ui-popupWidget-anchor' );
- this.$head
- .addClass( 'oo-ui-popupWidget-head' )
- .append( this.$label, this.closeButton.$element );
- if ( !config.head ) {
- this.$head.addClass( 'oo-ui-element-hidden' );
- }
- this.$popup
- .addClass( 'oo-ui-popupWidget-popup' )
- .append( this.$head, this.$body );
- this.$element
- .addClass( 'oo-ui-popupWidget' )
- .append( this.$popup, this.$anchor );
- // Move content, which was added to #$element by OO.ui.Widget, to the body
- if ( config.$content instanceof jQuery ) {
- this.$body.append( config.$content );
- }
- if ( config.padded ) {
- this.$body.addClass( 'oo-ui-popupWidget-body-padded' );
- }
-
- // Initially hidden - using #toggle may cause errors if subclasses override toggle with methods
- // that reference properties not initialized at that time of parent class construction
- // TODO: Find a better way to handle post-constructor setup
- this.visible = false;
- this.$element.addClass( 'oo-ui-element-hidden' );
-};
-
-/* Setup */
-
-OO.inheritClass( OO.ui.PopupWidget, OO.ui.Widget );
-OO.mixinClass( OO.ui.PopupWidget, OO.ui.LabelElement );
-OO.mixinClass( OO.ui.PopupWidget, OO.ui.ClippableElement );
-
-/* Methods */
-
-/**
- * Handles mouse down events.
- *
- * @private
- * @param {MouseEvent} e Mouse down event
- */
-OO.ui.PopupWidget.prototype.onMouseDown = function ( e ) {
- if (
- this.isVisible() &&
- !$.contains( this.$element[ 0 ], e.target ) &&
- ( !this.$autoCloseIgnore || !this.$autoCloseIgnore.has( e.target ).length )
- ) {
- this.toggle( false );
- }
-};
-
-/**
- * Bind mouse down listener.
- *
- * @private
- */
-OO.ui.PopupWidget.prototype.bindMouseDownListener = function () {
- // Capture clicks outside popup
- this.getElementWindow().addEventListener( 'mousedown', this.onMouseDownHandler, true );
-};
-
-/**
- * Handles close button click events.
- *
- * @private
- */
-OO.ui.PopupWidget.prototype.onCloseButtonClick = function () {
- if ( this.isVisible() ) {
- this.toggle( false );
- }
-};
-
-/**
- * Unbind mouse down listener.
- *
- * @private
- */
-OO.ui.PopupWidget.prototype.unbindMouseDownListener = function () {
- this.getElementWindow().removeEventListener( 'mousedown', this.onMouseDownHandler, true );
-};
-
-/**
- * Handles key down events.
- *
- * @private
- * @param {KeyboardEvent} e Key down event
- */
-OO.ui.PopupWidget.prototype.onDocumentKeyDown = function ( e ) {
- if (
- e.which === OO.ui.Keys.ESCAPE &&
- this.isVisible()
- ) {
- this.toggle( false );
- e.preventDefault();
- e.stopPropagation();
- }
-};
-
-/**
- * Bind key down listener.
- *
- * @private
- */
-OO.ui.PopupWidget.prototype.bindKeyDownListener = function () {
- this.getElementWindow().addEventListener( 'keydown', this.onDocumentKeyDownHandler, true );
-};
-
-/**
- * Unbind key down listener.
- *
- * @private
- */
-OO.ui.PopupWidget.prototype.unbindKeyDownListener = function () {
- this.getElementWindow().removeEventListener( 'keydown', this.onDocumentKeyDownHandler, true );
-};
-
-/**
- * Show, hide, or toggle the visibility of the anchor.
- *
- * @param {boolean} [show] Show anchor, omit to toggle
- */
-OO.ui.PopupWidget.prototype.toggleAnchor = function ( show ) {
- show = show === undefined ? !this.anchored : !!show;
-
- if ( this.anchored !== show ) {
- if ( show ) {
- this.$element.addClass( 'oo-ui-popupWidget-anchored' );
- } else {
- this.$element.removeClass( 'oo-ui-popupWidget-anchored' );
- }
- this.anchored = show;
- }
-};
-
-/**
- * Check if the anchor is visible.
- *
- * @return {boolean} Anchor is visible
- */
-OO.ui.PopupWidget.prototype.hasAnchor = function () {
- return this.anchor;
-};
-
-/**
- * @inheritdoc
- */
-OO.ui.PopupWidget.prototype.toggle = function ( show ) {
- show = show === undefined ? !this.isVisible() : !!show;
-
- var change = show !== this.isVisible();
-
- // Parent method
- OO.ui.PopupWidget.super.prototype.toggle.call( this, show );
-
- if ( change ) {
- if ( show ) {
- if ( this.autoClose ) {
- this.bindMouseDownListener();
- this.bindKeyDownListener();
- }
- this.updateDimensions();
- this.toggleClipping( true );
- } else {
- this.toggleClipping( false );
- if ( this.autoClose ) {
- this.unbindMouseDownListener();
- this.unbindKeyDownListener();
- }
- }
- }
-
- return this;
-};
-
-/**
- * Set the size of the popup.
- *
- * Changing the size may also change the popup's position depending on the alignment.
- *
- * @param {number} width Width in pixels
- * @param {number} height Height in pixels
- * @param {boolean} [transition=false] Use a smooth transition
- * @chainable
- */
-OO.ui.PopupWidget.prototype.setSize = function ( width, height, transition ) {
- this.width = width;
- this.height = height !== undefined ? height : null;
- if ( this.isVisible() ) {
- this.updateDimensions( transition );
- }
-};
-
-/**
- * Update the size and position.
- *
- * Only use this to keep the popup properly anchored. Use #setSize to change the size, and this will
- * be called automatically.
- *
- * @param {boolean} [transition=false] Use a smooth transition
- * @chainable
- */
-OO.ui.PopupWidget.prototype.updateDimensions = function ( transition ) {
- var popupOffset, originOffset, containerLeft, containerWidth, containerRight,
- popupLeft, popupRight, overlapLeft, overlapRight, anchorWidth,
- align = this.align,
- widget = this;
-
- if ( !this.$container ) {
- // Lazy-initialize $container if not specified in constructor
- this.$container = $( this.getClosestScrollableElementContainer() );
- }
-
- // Set height and width before measuring things, since it might cause our measurements
- // to change (e.g. due to scrollbars appearing or disappearing)
- this.$popup.css( {
- width: this.width,
- height: this.height !== null ? this.height : 'auto'
- } );
-
- // If we are in RTL, we need to flip the alignment, unless it is center
- if ( align === 'forwards' || align === 'backwards' ) {
- if ( this.$container.css( 'direction' ) === 'rtl' ) {
- align = ( { forwards: 'force-left', backwards: 'force-right' } )[ this.align ];
- } else {
- align = ( { forwards: 'force-right', backwards: 'force-left' } )[ this.align ];
- }
-
- }
-
- // Compute initial popupOffset based on alignment
- popupOffset = this.width * ( { 'force-left': -1, center: -0.5, 'force-right': 0 } )[ align ];
-
- // Figure out if this will cause the popup to go beyond the edge of the container
- originOffset = this.$element.offset().left;
- containerLeft = this.$container.offset().left;
- containerWidth = this.$container.innerWidth();
- containerRight = containerLeft + containerWidth;
- popupLeft = popupOffset - this.containerPadding;
- popupRight = popupOffset + this.containerPadding + this.width + this.containerPadding;
- overlapLeft = ( originOffset + popupLeft ) - containerLeft;
- overlapRight = containerRight - ( originOffset + popupRight );
-
- // Adjust offset to make the popup not go beyond the edge, if needed
- if ( overlapRight < 0 ) {
- popupOffset += overlapRight;
- } else if ( overlapLeft < 0 ) {
- popupOffset -= overlapLeft;
- }
-
- // Adjust offset to avoid anchor being rendered too close to the edge
- // $anchor.width() doesn't work with the pure CSS anchor (returns 0)
- // TODO: Find a measurement that works for CSS anchors and image anchors
- anchorWidth = this.$anchor[ 0 ].scrollWidth * 2;
- if ( popupOffset + this.width < anchorWidth ) {
- popupOffset = anchorWidth - this.width;
- } else if ( -popupOffset < anchorWidth ) {
- popupOffset = -anchorWidth;
- }
-
- // Prevent transition from being interrupted
- clearTimeout( this.transitionTimeout );
- if ( transition ) {
- // Enable transition
- this.$element.addClass( 'oo-ui-popupWidget-transitioning' );
- }
-
- // Position body relative to anchor
- this.$popup.css( 'margin-left', popupOffset );
-
- if ( transition ) {
- // Prevent transitioning after transition is complete
- this.transitionTimeout = setTimeout( function () {
- widget.$element.removeClass( 'oo-ui-popupWidget-transitioning' );
- }, 200 );
- } else {
- // Prevent transitioning immediately
- this.$element.removeClass( 'oo-ui-popupWidget-transitioning' );
- }
-
- // Reevaluate clipping state since we've relocated and resized the popup
- this.clip();
-
- return this;
-};
-
-/**
- * Set popup alignment
- * @param {string} align Alignment of the popup, `center`, `force-left`, `force-right`,
- * `backwards` or `forwards`.
- */
-OO.ui.PopupWidget.prototype.setAlignment = function ( align ) {
- // Validate alignment and transform deprecated values
- if ( [ 'left', 'right', 'force-left', 'force-right', 'backwards', 'forwards', 'center' ].indexOf( align ) > -1 ) {
- this.align = { left: 'force-right', right: 'force-left' }[ align ] || align;
- } else {
- this.align = 'center';
- }
-};
-
-/**
- * Get popup alignment
- * @return {string} align Alignment of the popup, `center`, `force-left`, `force-right`,
- * `backwards` or `forwards`.
- */
-OO.ui.PopupWidget.prototype.getAlignment = function () {
- return this.align;
-};
diff --git a/vendor/oojs/oojs-ui/src/widgets/ProgressBarWidget.js b/vendor/oojs/oojs-ui/src/widgets/ProgressBarWidget.js
deleted file mode 100644
index a4676282..00000000
--- a/vendor/oojs/oojs-ui/src/widgets/ProgressBarWidget.js
+++ /dev/null
@@ -1,96 +0,0 @@
-/**
- * Progress bars visually display the status of an operation, such as a download,
- * and can be either determinate or indeterminate:
- *
- * - **determinate** process bars show the percent of an operation that is complete.
- *
- * - **indeterminate** process bars use a visual display of motion to indicate that an operation
- * is taking place. Because the extent of an indeterminate operation is unknown, the bar does
- * not use percentages.
- *
- * The value of the `progress` configuration determines whether the bar is determinate or indeterminate.
- *
- * @example
- * // Examples of determinate and indeterminate progress bars.
- * var progressBar1 = new OO.ui.ProgressBarWidget( {
- * progress: 33
- * } );
- * var progressBar2 = new OO.ui.ProgressBarWidget();
- *
- * // Create a FieldsetLayout to layout progress bars
- * var fieldset = new OO.ui.FieldsetLayout;
- * fieldset.addItems( [
- * new OO.ui.FieldLayout( progressBar1, {label: 'Determinate', align: 'top'}),
- * new OO.ui.FieldLayout( progressBar2, {label: 'Indeterminate', align: 'top'})
- * ] );
- * $( 'body' ).append( fieldset.$element );
- *
- * @class
- * @extends OO.ui.Widget
- *
- * @constructor
- * @param {Object} [config] Configuration options
- * @cfg {number|boolean} [progress=false] The type of progress bar (determinate or indeterminate).
- * To create a determinate progress bar, specify a number that reflects the initial percent complete.
- * By default, the progress bar is indeterminate.
- */
-OO.ui.ProgressBarWidget = function OoUiProgressBarWidget( config ) {
- // Configuration initialization
- config = config || {};
-
- // Parent constructor
- OO.ui.ProgressBarWidget.super.call( this, config );
-
- // Properties
- this.$bar = $( '<div>' );
- this.progress = null;
-
- // Initialization
- this.setProgress( config.progress !== undefined ? config.progress : false );
- this.$bar.addClass( 'oo-ui-progressBarWidget-bar' );
- this.$element
- .attr( {
- role: 'progressbar',
- 'aria-valuemin': 0,
- 'aria-valuemax': 100
- } )
- .addClass( 'oo-ui-progressBarWidget' )
- .append( this.$bar );
-};
-
-/* Setup */
-
-OO.inheritClass( OO.ui.ProgressBarWidget, OO.ui.Widget );
-
-/* Static Properties */
-
-OO.ui.ProgressBarWidget.static.tagName = 'div';
-
-/* Methods */
-
-/**
- * Get the percent of the progress that has been completed. Indeterminate progresses will return `false`.
- *
- * @return {number|boolean} Progress percent
- */
-OO.ui.ProgressBarWidget.prototype.getProgress = function () {
- return this.progress;
-};
-
-/**
- * Set the percent of the process completed or `false` for an indeterminate process.
- *
- * @param {number|boolean} progress Progress percent or `false` for indeterminate
- */
-OO.ui.ProgressBarWidget.prototype.setProgress = function ( progress ) {
- this.progress = progress;
-
- if ( progress !== false ) {
- this.$bar.css( 'width', this.progress + '%' );
- this.$element.attr( 'aria-valuenow', this.progress );
- } else {
- this.$bar.css( 'width', '' );
- this.$element.removeAttr( 'aria-valuenow' );
- }
- this.$element.toggleClass( 'oo-ui-progressBarWidget-indeterminate', !progress );
-};
diff --git a/vendor/oojs/oojs-ui/src/widgets/RadioInputWidget.js b/vendor/oojs/oojs-ui/src/widgets/RadioInputWidget.js
deleted file mode 100644
index 47ac20bf..00000000
--- a/vendor/oojs/oojs-ui/src/widgets/RadioInputWidget.js
+++ /dev/null
@@ -1,94 +0,0 @@
-/**
- * RadioInputWidget creates a single radio button. Because radio buttons are usually used as a set,
- * in most cases you will want to use a {@link OO.ui.RadioSelectWidget radio select}
- * with {@link OO.ui.RadioOptionWidget radio options} instead of this class. For more information,
- * please see the [OOjs UI documentation on MediaWiki][1].
- *
- * This widget can be used inside a HTML form, such as a OO.ui.FormLayout.
- *
- * @example
- * // An example of selected, unselected, and disabled radio inputs
- * var radio1 = new OO.ui.RadioInputWidget( {
- * value: 'a',
- * selected: true
- * } );
- * var radio2 = new OO.ui.RadioInputWidget( {
- * value: 'b'
- * } );
- * var radio3 = new OO.ui.RadioInputWidget( {
- * value: 'c',
- * disabled: true
- * } );
- * // Create a fieldset layout with fields for each radio button.
- * var fieldset = new OO.ui.FieldsetLayout( {
- * label: 'Radio inputs'
- * } );
- * fieldset.addItems( [
- * new OO.ui.FieldLayout( radio1, { label: 'Selected', align: 'inline' } ),
- * new OO.ui.FieldLayout( radio2, { label: 'Unselected', align: 'inline' } ),
- * new OO.ui.FieldLayout( radio3, { label: 'Disabled', align: 'inline' } ),
- * ] );
- * $( 'body' ).append( fieldset.$element );
- *
- * [1]: https://www.mediawiki.org/wiki/OOjs_UI/Widgets/Inputs
- *
- * @class
- * @extends OO.ui.InputWidget
- *
- * @constructor
- * @param {Object} [config] Configuration options
- * @cfg {boolean} [selected=false] Select the radio button initially. By default, the radio button is not selected.
- */
-OO.ui.RadioInputWidget = function OoUiRadioInputWidget( config ) {
- // Configuration initialization
- config = config || {};
-
- // Parent constructor
- OO.ui.RadioInputWidget.super.call( this, config );
-
- // Initialization
- this.$element.addClass( 'oo-ui-radioInputWidget' );
- this.setSelected( config.selected !== undefined ? config.selected : false );
-};
-
-/* Setup */
-
-OO.inheritClass( OO.ui.RadioInputWidget, OO.ui.InputWidget );
-
-/* Methods */
-
-/**
- * @inheritdoc
- * @private
- */
-OO.ui.RadioInputWidget.prototype.getInputElement = function () {
- return $( '<input type="radio" />' );
-};
-
-/**
- * @inheritdoc
- */
-OO.ui.RadioInputWidget.prototype.onEdit = function () {
- // RadioInputWidget doesn't track its state.
-};
-
-/**
- * Set selection state of this radio button.
- *
- * @param {boolean} state `true` for selected
- * @chainable
- */
-OO.ui.RadioInputWidget.prototype.setSelected = function ( state ) {
- // RadioInputWidget doesn't track its state.
- this.$input.prop( 'checked', state );
- return this;
-};
-
-/**
- * Check if this radio button is selected.
- *
- * @return {boolean} Radio is selected
- */
-OO.ui.RadioInputWidget.prototype.isSelected = function () {
- return this.$input.prop( 'checked' );
-};
diff --git a/vendor/oojs/oojs-ui/src/widgets/RadioOptionWidget.js b/vendor/oojs/oojs-ui/src/widgets/RadioOptionWidget.js
deleted file mode 100644
index 97187c0a..00000000
--- a/vendor/oojs/oojs-ui/src/widgets/RadioOptionWidget.js
+++ /dev/null
@@ -1,66 +0,0 @@
-/**
- * RadioOptionWidget is an option widget that looks like a radio button.
- * The class is used with OO.ui.RadioSelectWidget to create a selection of radio options.
- * Please see the [OOjs UI documentation on MediaWiki] [1] for more information.
- *
- * [1]: https://www.mediawiki.org/wiki/OOjs_UI/Widgets/Selects_and_Options#Button_selects_and_option
- *
- * @class
- * @extends OO.ui.OptionWidget
- *
- * @constructor
- * @param {Object} [config] Configuration options
- */
-OO.ui.RadioOptionWidget = function OoUiRadioOptionWidget( config ) {
- // Configuration initialization
- config = config || {};
-
- // Properties (must be done before parent constructor which calls #setDisabled)
- this.radio = new OO.ui.RadioInputWidget( { value: config.data, tabIndex: -1 } );
-
- // Parent constructor
- OO.ui.RadioOptionWidget.super.call( this, config );
-
- // Initialization
- this.$element
- .addClass( 'oo-ui-radioOptionWidget' )
- .prepend( this.radio.$element );
-};
-
-/* Setup */
-
-OO.inheritClass( OO.ui.RadioOptionWidget, OO.ui.OptionWidget );
-
-/* Static Properties */
-
-OO.ui.RadioOptionWidget.static.highlightable = false;
-
-OO.ui.RadioOptionWidget.static.scrollIntoViewOnSelect = true;
-
-OO.ui.RadioOptionWidget.static.pressable = false;
-
-OO.ui.RadioOptionWidget.static.tagName = 'label';
-
-/* Methods */
-
-/**
- * @inheritdoc
- */
-OO.ui.RadioOptionWidget.prototype.setSelected = function ( state ) {
- OO.ui.RadioOptionWidget.super.prototype.setSelected.call( this, state );
-
- this.radio.setSelected( state );
-
- return this;
-};
-
-/**
- * @inheritdoc
- */
-OO.ui.RadioOptionWidget.prototype.setDisabled = function ( disabled ) {
- OO.ui.RadioOptionWidget.super.prototype.setDisabled.call( this, disabled );
-
- this.radio.setDisabled( this.isDisabled() );
-
- return this;
-};
diff --git a/vendor/oojs/oojs-ui/src/widgets/RadioSelectWidget.js b/vendor/oojs/oojs-ui/src/widgets/RadioSelectWidget.js
deleted file mode 100644
index 3859205f..00000000
--- a/vendor/oojs/oojs-ui/src/widgets/RadioSelectWidget.js
+++ /dev/null
@@ -1,58 +0,0 @@
-/**
- * RadioSelectWidget is a {@link OO.ui.SelectWidget select widget} that contains radio
- * options and is used together with OO.ui.RadioOptionWidget. The RadioSelectWidget provides
- * an interface for adding, removing and selecting options.
- * Please see the [OOjs UI documentation on MediaWiki][1] for more information.
- *
- * @example
- * // A RadioSelectWidget with RadioOptions.
- * var option1 = new OO.ui.RadioOptionWidget( {
- * data: 'a',
- * label: 'Selected radio option'
- * } );
- *
- * var option2 = new OO.ui.RadioOptionWidget( {
- * data: 'b',
- * label: 'Unselected radio option'
- * } );
- *
- * var radioSelect=new OO.ui.RadioSelectWidget( {
- * items: [ option1, option2 ]
- * } );
- *
- * // Select 'option 1' using the RadioSelectWidget's selectItem() method.
- * radioSelect.selectItem( option1 );
- *
- * $( 'body' ).append( radioSelect.$element );
- *
- * [1]: https://www.mediawiki.org/wiki/OOjs_UI/Widgets/Selects_and_Options
-
- *
- * @class
- * @extends OO.ui.SelectWidget
- * @mixins OO.ui.TabIndexedElement
- *
- * @constructor
- * @param {Object} [config] Configuration options
- */
-OO.ui.RadioSelectWidget = function OoUiRadioSelectWidget( config ) {
- // Parent constructor
- OO.ui.RadioSelectWidget.super.call( this, config );
-
- // Mixin constructors
- OO.ui.TabIndexedElement.call( this, config );
-
- // Events
- this.$element.on( {
- focus: this.bindKeyDownListener.bind( this ),
- blur: this.unbindKeyDownListener.bind( this )
- } );
-
- // Initialization
- this.$element.addClass( 'oo-ui-radioSelectWidget' );
-};
-
-/* Setup */
-
-OO.inheritClass( OO.ui.RadioSelectWidget, OO.ui.SelectWidget );
-OO.mixinClass( OO.ui.RadioSelectWidget, OO.ui.TabIndexedElement );
diff --git a/vendor/oojs/oojs-ui/src/widgets/SearchWidget.js b/vendor/oojs/oojs-ui/src/widgets/SearchWidget.js
deleted file mode 100644
index 4909d9e1..00000000
--- a/vendor/oojs/oojs-ui/src/widgets/SearchWidget.js
+++ /dev/null
@@ -1,176 +0,0 @@
-/**
- * SearchWidgets combine a {@link OO.ui.TextInputWidget text input field}, where users can type a search query,
- * and a {@link OO.ui.TextInputMenuSelectWidget menu} of search results, which is displayed beneath the query
- * field. Unlike {@link OO.ui.LookupElement lookup menus}, search result menus are always visible to the user.
- * Users can choose an item from the menu or type a query into the text field to search for a matching result item.
- * In general, search widgets are used inside a separate {@link OO.ui.Dialog dialog} window.
- *
- * Each time the query is changed, the search result menu is cleared and repopulated. Please see
- * the [OOjs UI demos][1] for an example.
- *
- * [1]: https://tools.wmflabs.org/oojs-ui/oojs-ui/demos/#dialogs-mediawiki-vector-ltr
- *
- * @class
- * @extends OO.ui.Widget
- *
- * @constructor
- * @param {Object} [config] Configuration options
- * @cfg {string|jQuery} [placeholder] Placeholder text for query input
- * @cfg {string} [value] Initial query value
- */
-OO.ui.SearchWidget = function OoUiSearchWidget( config ) {
- // Configuration initialization
- config = config || {};
-
- // Parent constructor
- OO.ui.SearchWidget.super.call( this, config );
-
- // Properties
- this.query = new OO.ui.TextInputWidget( {
- icon: 'search',
- placeholder: config.placeholder,
- value: config.value
- } );
- this.results = new OO.ui.SelectWidget();
- this.$query = $( '<div>' );
- this.$results = $( '<div>' );
-
- // Events
- this.query.connect( this, {
- change: 'onQueryChange',
- enter: 'onQueryEnter'
- } );
- this.results.connect( this, {
- highlight: 'onResultsHighlight',
- select: 'onResultsSelect'
- } );
- this.query.$input.on( 'keydown', this.onQueryKeydown.bind( this ) );
-
- // Initialization
- this.$query
- .addClass( 'oo-ui-searchWidget-query' )
- .append( this.query.$element );
- this.$results
- .addClass( 'oo-ui-searchWidget-results' )
- .append( this.results.$element );
- this.$element
- .addClass( 'oo-ui-searchWidget' )
- .append( this.$results, this.$query );
-};
-
-/* Setup */
-
-OO.inheritClass( OO.ui.SearchWidget, OO.ui.Widget );
-
-/* Events */
-
-/**
- * A 'highlight' event is emitted when an item is highlighted. The highlight indicates which
- * item will be selected. When a user mouses over a menu item, it is highlighted. If a search
- * string is typed into the query field instead, the first menu item that matches the query
- * will be highlighted.
-
- * @event highlight
- * @deprecated Connect straight to getResults() events instead
- * @param {Object|null} item Item data or null if no item is highlighted
- */
-
-/**
- * A 'select' event is emitted when an item is selected. A menu item is selected when it is clicked,
- * or when a user types a search query, a menu result is highlighted, and the user presses enter.
- *
- * @event select
- * @deprecated Connect straight to getResults() events instead
- * @param {Object|null} item Item data or null if no item is selected
- */
-
-/* Methods */
-
-/**
- * Handle query key down events.
- *
- * @private
- * @param {jQuery.Event} e Key down event
- */
-OO.ui.SearchWidget.prototype.onQueryKeydown = function ( e ) {
- var highlightedItem, nextItem,
- dir = e.which === OO.ui.Keys.DOWN ? 1 : ( e.which === OO.ui.Keys.UP ? -1 : 0 );
-
- if ( dir ) {
- highlightedItem = this.results.getHighlightedItem();
- if ( !highlightedItem ) {
- highlightedItem = this.results.getSelectedItem();
- }
- nextItem = this.results.getRelativeSelectableItem( highlightedItem, dir );
- this.results.highlightItem( nextItem );
- nextItem.scrollElementIntoView();
- }
-};
-
-/**
- * Handle select widget select events.
- *
- * Clears existing results. Subclasses should repopulate items according to new query.
- *
- * @private
- * @param {string} value New value
- */
-OO.ui.SearchWidget.prototype.onQueryChange = function () {
- // Reset
- this.results.clearItems();
-};
-
-/**
- * Handle select widget enter key events.
- *
- * Selects highlighted item.
- *
- * @private
- * @param {string} value New value
- */
-OO.ui.SearchWidget.prototype.onQueryEnter = function () {
- // Reset
- this.results.selectItem( this.results.getHighlightedItem() );
-};
-
-/**
- * Handle select widget highlight events.
- *
- * @private
- * @deprecated Connect straight to getResults() events instead
- * @param {OO.ui.OptionWidget} item Highlighted item
- * @fires highlight
- */
-OO.ui.SearchWidget.prototype.onResultsHighlight = function ( item ) {
- this.emit( 'highlight', item ? item.getData() : null );
-};
-
-/**
- * Handle select widget select events.
- *
- * @private
- * @deprecated Connect straight to getResults() events instead
- * @param {OO.ui.OptionWidget} item Selected item
- * @fires select
- */
-OO.ui.SearchWidget.prototype.onResultsSelect = function ( item ) {
- this.emit( 'select', item ? item.getData() : null );
-};
-
-/**
- * Get the query input.
- *
- * @return {OO.ui.TextInputWidget} Query input
- */
-OO.ui.SearchWidget.prototype.getQuery = function () {
- return this.query;
-};
-
-/**
- * Get the search results menu.
- *
- * @return {OO.ui.SelectWidget} Menu of search results
- */
-OO.ui.SearchWidget.prototype.getResults = function () {
- return this.results;
-};
diff --git a/vendor/oojs/oojs-ui/src/widgets/SelectWidget.js b/vendor/oojs/oojs-ui/src/widgets/SelectWidget.js
deleted file mode 100644
index 91172af0..00000000
--- a/vendor/oojs/oojs-ui/src/widgets/SelectWidget.js
+++ /dev/null
@@ -1,630 +0,0 @@
-/**
- * A SelectWidget is of a generic selection of options. The OOjs UI library contains several types of
- * select widgets, including {@link OO.ui.ButtonSelectWidget button selects},
- * {@link OO.ui.RadioSelectWidget radio selects}, and {@link OO.ui.MenuSelectWidget
- * menu selects}.
- *
- * This class should be used together with OO.ui.OptionWidget or OO.ui.DecoratedOptionWidget. For more
- * information, please see the [OOjs UI documentation on MediaWiki][1].
- *
- * @example
- * // Example of a select widget with three options
- * var select = new OO.ui.SelectWidget( {
- * items: [
- * new OO.ui.OptionWidget( {
- * data: 'a',
- * label: 'Option One',
- * } ),
- * new OO.ui.OptionWidget( {
- * data: 'b',
- * label: 'Option Two',
- * } ),
- * new OO.ui.OptionWidget( {
- * data: 'c',
- * label: 'Option Three',
- * } )
- * ]
- * } );
- * $( 'body' ).append( select.$element );
- *
- * [1]: https://www.mediawiki.org/wiki/OOjs_UI/Widgets/Selects_and_Options
- *
- * @abstract
- * @class
- * @extends OO.ui.Widget
- * @mixins OO.ui.GroupElement
- *
- * @constructor
- * @param {Object} [config] Configuration options
- * @cfg {OO.ui.OptionWidget[]} [items] An array of options to add to the select.
- * Options are created with {@link OO.ui.OptionWidget OptionWidget} classes. See
- * the [OOjs UI documentation on MediaWiki] [2] for examples.
- * [2]: https://www.mediawiki.org/wiki/OOjs_UI/Widgets/Selects_and_Options
- */
-OO.ui.SelectWidget = function OoUiSelectWidget( config ) {
- // Configuration initialization
- config = config || {};
-
- // Parent constructor
- OO.ui.SelectWidget.super.call( this, config );
-
- // Mixin constructors
- OO.ui.GroupWidget.call( this, $.extend( {}, config, { $group: this.$element } ) );
-
- // Properties
- this.pressed = false;
- this.selecting = null;
- this.onMouseUpHandler = this.onMouseUp.bind( this );
- this.onMouseMoveHandler = this.onMouseMove.bind( this );
- this.onKeyDownHandler = this.onKeyDown.bind( this );
-
- // Events
- this.$element.on( {
- mousedown: this.onMouseDown.bind( this ),
- mouseover: this.onMouseOver.bind( this ),
- mouseleave: this.onMouseLeave.bind( this )
- } );
-
- // Initialization
- this.$element
- .addClass( 'oo-ui-selectWidget oo-ui-selectWidget-depressed' )
- .attr( 'role', 'listbox' );
- if ( Array.isArray( config.items ) ) {
- this.addItems( config.items );
- }
-};
-
-/* Setup */
-
-OO.inheritClass( OO.ui.SelectWidget, OO.ui.Widget );
-
-// Need to mixin base class as well
-OO.mixinClass( OO.ui.SelectWidget, OO.ui.GroupElement );
-OO.mixinClass( OO.ui.SelectWidget, OO.ui.GroupWidget );
-
-/* Events */
-
-/**
- * @event highlight
- *
- * A `highlight` event is emitted when the highlight is changed with the #highlightItem method.
- *
- * @param {OO.ui.OptionWidget|null} item Highlighted item
- */
-
-/**
- * @event press
- *
- * A `press` event is emitted when the #pressItem method is used to programmatically modify the
- * pressed state of an option.
- *
- * @param {OO.ui.OptionWidget|null} item Pressed item
- */
-
-/**
- * @event select
- *
- * A `select` event is emitted when the selection is modified programmatically with the #selectItem method.
- *
- * @param {OO.ui.OptionWidget|null} item Selected item
- */
-
-/**
- * @event choose
- * A `choose` event is emitted when an item is chosen with the #chooseItem method.
- * @param {OO.ui.OptionWidget} item Chosen item
- */
-
-/**
- * @event add
- *
- * An `add` event is emitted when options are added to the select with the #addItems method.
- *
- * @param {OO.ui.OptionWidget[]} items Added items
- * @param {number} index Index of insertion point
- */
-
-/**
- * @event remove
- *
- * A `remove` event is emitted when options are removed from the select with the #clearItems
- * or #removeItems methods.
- *
- * @param {OO.ui.OptionWidget[]} items Removed items
- */
-
-/* Methods */
-
-/**
- * Handle mouse down events.
- *
- * @private
- * @param {jQuery.Event} e Mouse down event
- */
-OO.ui.SelectWidget.prototype.onMouseDown = function ( e ) {
- var item;
-
- if ( !this.isDisabled() && e.which === 1 ) {
- this.togglePressed( true );
- item = this.getTargetItem( e );
- if ( item && item.isSelectable() ) {
- this.pressItem( item );
- this.selecting = item;
- this.getElementDocument().addEventListener(
- 'mouseup',
- this.onMouseUpHandler,
- true
- );
- this.getElementDocument().addEventListener(
- 'mousemove',
- this.onMouseMoveHandler,
- true
- );
- }
- }
- return false;
-};
-
-/**
- * Handle mouse up events.
- *
- * @private
- * @param {jQuery.Event} e Mouse up event
- */
-OO.ui.SelectWidget.prototype.onMouseUp = function ( e ) {
- var item;
-
- this.togglePressed( false );
- if ( !this.selecting ) {
- item = this.getTargetItem( e );
- if ( item && item.isSelectable() ) {
- this.selecting = item;
- }
- }
- if ( !this.isDisabled() && e.which === 1 && this.selecting ) {
- this.pressItem( null );
- this.chooseItem( this.selecting );
- this.selecting = null;
- }
-
- this.getElementDocument().removeEventListener(
- 'mouseup',
- this.onMouseUpHandler,
- true
- );
- this.getElementDocument().removeEventListener(
- 'mousemove',
- this.onMouseMoveHandler,
- true
- );
-
- return false;
-};
-
-/**
- * Handle mouse move events.
- *
- * @private
- * @param {jQuery.Event} e Mouse move event
- */
-OO.ui.SelectWidget.prototype.onMouseMove = function ( e ) {
- var item;
-
- if ( !this.isDisabled() && this.pressed ) {
- item = this.getTargetItem( e );
- if ( item && item !== this.selecting && item.isSelectable() ) {
- this.pressItem( item );
- this.selecting = item;
- }
- }
- return false;
-};
-
-/**
- * Handle mouse over events.
- *
- * @private
- * @param {jQuery.Event} e Mouse over event
- */
-OO.ui.SelectWidget.prototype.onMouseOver = function ( e ) {
- var item;
-
- if ( !this.isDisabled() ) {
- item = this.getTargetItem( e );
- this.highlightItem( item && item.isHighlightable() ? item : null );
- }
- return false;
-};
-
-/**
- * Handle mouse leave events.
- *
- * @private
- * @param {jQuery.Event} e Mouse over event
- */
-OO.ui.SelectWidget.prototype.onMouseLeave = function () {
- if ( !this.isDisabled() ) {
- this.highlightItem( null );
- }
- return false;
-};
-
-/**
- * Handle key down events.
- *
- * @protected
- * @param {jQuery.Event} e Key down event
- */
-OO.ui.SelectWidget.prototype.onKeyDown = function ( e ) {
- var nextItem,
- handled = false,
- currentItem = this.getHighlightedItem() || this.getSelectedItem();
-
- if ( !this.isDisabled() && this.isVisible() ) {
- switch ( e.keyCode ) {
- case OO.ui.Keys.ENTER:
- if ( currentItem && currentItem.constructor.static.highlightable ) {
- // Was only highlighted, now let's select it. No-op if already selected.
- this.chooseItem( currentItem );
- handled = true;
- }
- break;
- case OO.ui.Keys.UP:
- case OO.ui.Keys.LEFT:
- nextItem = this.getRelativeSelectableItem( currentItem, -1 );
- handled = true;
- break;
- case OO.ui.Keys.DOWN:
- case OO.ui.Keys.RIGHT:
- nextItem = this.getRelativeSelectableItem( currentItem, 1 );
- handled = true;
- break;
- case OO.ui.Keys.ESCAPE:
- case OO.ui.Keys.TAB:
- if ( currentItem && currentItem.constructor.static.highlightable ) {
- currentItem.setHighlighted( false );
- }
- this.unbindKeyDownListener();
- // Don't prevent tabbing away / defocusing
- handled = false;
- break;
- }
-
- if ( nextItem ) {
- if ( nextItem.constructor.static.highlightable ) {
- this.highlightItem( nextItem );
- } else {
- this.chooseItem( nextItem );
- }
- nextItem.scrollElementIntoView();
- }
-
- if ( handled ) {
- // Can't just return false, because e is not always a jQuery event
- e.preventDefault();
- e.stopPropagation();
- }
- }
-};
-
-/**
- * Bind key down listener.
- *
- * @protected
- */
-OO.ui.SelectWidget.prototype.bindKeyDownListener = function () {
- this.getElementWindow().addEventListener( 'keydown', this.onKeyDownHandler, true );
-};
-
-/**
- * Unbind key down listener.
- *
- * @protected
- */
-OO.ui.SelectWidget.prototype.unbindKeyDownListener = function () {
- this.getElementWindow().removeEventListener( 'keydown', this.onKeyDownHandler, true );
-};
-
-/**
- * Get the closest item to a jQuery.Event.
- *
- * @private
- * @param {jQuery.Event} e
- * @return {OO.ui.OptionWidget|null} Outline item widget, `null` if none was found
- */
-OO.ui.SelectWidget.prototype.getTargetItem = function ( e ) {
- return $( e.target ).closest( '.oo-ui-optionWidget' ).data( 'oo-ui-optionWidget' ) || null;
-};
-
-/**
- * Get selected item.
- *
- * @return {OO.ui.OptionWidget|null} Selected item, `null` if no item is selected
- */
-OO.ui.SelectWidget.prototype.getSelectedItem = function () {
- var i, len;
-
- for ( i = 0, len = this.items.length; i < len; i++ ) {
- if ( this.items[ i ].isSelected() ) {
- return this.items[ i ];
- }
- }
- return null;
-};
-
-/**
- * Get highlighted item.
- *
- * @return {OO.ui.OptionWidget|null} Highlighted item, `null` if no item is highlighted
- */
-OO.ui.SelectWidget.prototype.getHighlightedItem = function () {
- var i, len;
-
- for ( i = 0, len = this.items.length; i < len; i++ ) {
- if ( this.items[ i ].isHighlighted() ) {
- return this.items[ i ];
- }
- }
- return null;
-};
-
-/**
- * Toggle pressed state.
- *
- * Press is a state that occurs when a user mouses down on an item, but
- * has not yet let go of the mouse. The item may appear selected, but it will not be selected
- * until the user releases the mouse.
- *
- * @param {boolean} pressed An option is being pressed
- */
-OO.ui.SelectWidget.prototype.togglePressed = function ( pressed ) {
- if ( pressed === undefined ) {
- pressed = !this.pressed;
- }
- if ( pressed !== this.pressed ) {
- this.$element
- .toggleClass( 'oo-ui-selectWidget-pressed', pressed )
- .toggleClass( 'oo-ui-selectWidget-depressed', !pressed );
- this.pressed = pressed;
- }
-};
-
-/**
- * Highlight an option. If the `item` param is omitted, no options will be highlighted
- * and any existing highlight will be removed. The highlight is mutually exclusive.
- *
- * @param {OO.ui.OptionWidget} [item] Item to highlight, omit for no highlight
- * @fires highlight
- * @chainable
- */
-OO.ui.SelectWidget.prototype.highlightItem = function ( item ) {
- var i, len, highlighted,
- changed = false;
-
- for ( i = 0, len = this.items.length; i < len; i++ ) {
- highlighted = this.items[ i ] === item;
- if ( this.items[ i ].isHighlighted() !== highlighted ) {
- this.items[ i ].setHighlighted( highlighted );
- changed = true;
- }
- }
- if ( changed ) {
- this.emit( 'highlight', item );
- }
-
- return this;
-};
-
-/**
- * Programmatically select an option by its data. If the `data` parameter is omitted,
- * or if the item does not exist, all options will be deselected.
- *
- * @param {Object|string} [data] Value of the item to select, omit to deselect all
- * @fires select
- * @chainable
- */
-OO.ui.SelectWidget.prototype.selectItemByData = function ( data ) {
- var itemFromData = this.getItemFromData( data );
- if ( data === undefined || !itemFromData ) {
- return this.selectItem();
- }
- return this.selectItem( itemFromData );
-};
-
-/**
- * Programmatically select an option by its reference. If the `item` parameter is omitted,
- * all options will be deselected.
- *
- * @param {OO.ui.OptionWidget} [item] Item to select, omit to deselect all
- * @fires select
- * @chainable
- */
-OO.ui.SelectWidget.prototype.selectItem = function ( item ) {
- var i, len, selected,
- changed = false;
-
- for ( i = 0, len = this.items.length; i < len; i++ ) {
- selected = this.items[ i ] === item;
- if ( this.items[ i ].isSelected() !== selected ) {
- this.items[ i ].setSelected( selected );
- changed = true;
- }
- }
- if ( changed ) {
- this.emit( 'select', item );
- }
-
- return this;
-};
-
-/**
- * Press an item.
- *
- * Press is a state that occurs when a user mouses down on an item, but has not
- * yet let go of the mouse. The item may appear selected, but it will not be selected until the user
- * releases the mouse.
- *
- * @param {OO.ui.OptionWidget} [item] Item to press, omit to depress all
- * @fires press
- * @chainable
- */
-OO.ui.SelectWidget.prototype.pressItem = function ( item ) {
- var i, len, pressed,
- changed = false;
-
- for ( i = 0, len = this.items.length; i < len; i++ ) {
- pressed = this.items[ i ] === item;
- if ( this.items[ i ].isPressed() !== pressed ) {
- this.items[ i ].setPressed( pressed );
- changed = true;
- }
- }
- if ( changed ) {
- this.emit( 'press', item );
- }
-
- return this;
-};
-
-/**
- * Choose an item.
- *
- * Note that ‘choose’ should never be modified programmatically. A user can choose
- * an option with the keyboard or mouse and it becomes selected. To select an item programmatically,
- * use the #selectItem method.
- *
- * This method is identical to #selectItem, but may vary in subclasses that take additional action
- * when users choose an item with the keyboard or mouse.
- *
- * @param {OO.ui.OptionWidget} item Item to choose
- * @fires choose
- * @chainable
- */
-OO.ui.SelectWidget.prototype.chooseItem = function ( item ) {
- this.selectItem( item );
- this.emit( 'choose', item );
-
- return this;
-};
-
-/**
- * Get an option by its position relative to the specified item (or to the start of the option array,
- * if item is `null`). The direction in which to search through the option array is specified with a
- * number: -1 for reverse (the default) or 1 for forward. The method will return an option, or
- * `null` if there are no options in the array.
- *
- * @param {OO.ui.OptionWidget|null} item Item to describe the start position, or `null` to start at the beginning of the array.
- * @param {number} direction Direction to move in: -1 to move backward, 1 to move forward
- * @return {OO.ui.OptionWidget|null} Item at position, `null` if there are no items in the select
- */
-OO.ui.SelectWidget.prototype.getRelativeSelectableItem = function ( item, direction ) {
- var currentIndex, nextIndex, i,
- increase = direction > 0 ? 1 : -1,
- len = this.items.length;
-
- if ( item instanceof OO.ui.OptionWidget ) {
- currentIndex = $.inArray( item, this.items );
- nextIndex = ( currentIndex + increase + len ) % len;
- } else {
- // If no item is selected and moving forward, start at the beginning.
- // If moving backward, start at the end.
- nextIndex = direction > 0 ? 0 : len - 1;
- }
-
- for ( i = 0; i < len; i++ ) {
- item = this.items[ nextIndex ];
- if ( item instanceof OO.ui.OptionWidget && item.isSelectable() ) {
- return item;
- }
- nextIndex = ( nextIndex + increase + len ) % len;
- }
- return null;
-};
-
-/**
- * Get the next selectable item or `null` if there are no selectable items.
- * Disabled options and menu-section markers and breaks are not selectable.
- *
- * @return {OO.ui.OptionWidget|null} Item, `null` if there aren't any selectable items
- */
-OO.ui.SelectWidget.prototype.getFirstSelectableItem = function () {
- var i, len, item;
-
- for ( i = 0, len = this.items.length; i < len; i++ ) {
- item = this.items[ i ];
- if ( item instanceof OO.ui.OptionWidget && item.isSelectable() ) {
- return item;
- }
- }
-
- return null;
-};
-
-/**
- * Add an array of options to the select. Optionally, an index number can be used to
- * specify an insertion point.
- *
- * @param {OO.ui.OptionWidget[]} items Items to add
- * @param {number} [index] Index to insert items after
- * @fires add
- * @chainable
- */
-OO.ui.SelectWidget.prototype.addItems = function ( items, index ) {
- // Mixin method
- OO.ui.GroupWidget.prototype.addItems.call( this, items, index );
-
- // Always provide an index, even if it was omitted
- this.emit( 'add', items, index === undefined ? this.items.length - items.length - 1 : index );
-
- return this;
-};
-
-/**
- * Remove the specified array of options from the select. Options will be detached
- * from the DOM, not removed, so they can be reused later. To remove all options from
- * the select, you may wish to use the #clearItems method instead.
- *
- * @param {OO.ui.OptionWidget[]} items Items to remove
- * @fires remove
- * @chainable
- */
-OO.ui.SelectWidget.prototype.removeItems = function ( items ) {
- var i, len, item;
-
- // Deselect items being removed
- for ( i = 0, len = items.length; i < len; i++ ) {
- item = items[ i ];
- if ( item.isSelected() ) {
- this.selectItem( null );
- }
- }
-
- // Mixin method
- OO.ui.GroupWidget.prototype.removeItems.call( this, items );
-
- this.emit( 'remove', items );
-
- return this;
-};
-
-/**
- * Clear all options from the select. Options will be detached from the DOM, not removed,
- * so that they can be reused later. To remove a subset of options from the select, use
- * the #removeItems method.
- *
- * @fires remove
- * @chainable
- */
-OO.ui.SelectWidget.prototype.clearItems = function () {
- var items = this.items.slice();
-
- // Mixin method
- OO.ui.GroupWidget.prototype.clearItems.call( this );
-
- // Clear selection
- this.selectItem( null );
-
- this.emit( 'remove', items );
-
- return this;
-};
diff --git a/vendor/oojs/oojs-ui/src/widgets/TabOptionWidget.js b/vendor/oojs/oojs-ui/src/widgets/TabOptionWidget.js
deleted file mode 100644
index 08f5b30d..00000000
--- a/vendor/oojs/oojs-ui/src/widgets/TabOptionWidget.js
+++ /dev/null
@@ -1,31 +0,0 @@
-/**
- * TabOptionWidget is an item in a {@link OO.ui.TabSelectWidget TabSelectWidget}.
- *
- * Currently, this class is only used by {@link OO.ui.IndexLayout index layouts}, which contain
- * {@link OO.ui.CardLayout card layouts}. See {@link OO.ui.IndexLayout IndexLayout}
- * for an example.
- *
- * @class
- * @extends OO.ui.OptionWidget
- *
- * @constructor
- * @param {Object} [config] Configuration options
- */
-OO.ui.TabOptionWidget = function OoUiTabOptionWidget( config ) {
- // Configuration initialization
- config = config || {};
-
- // Parent constructor
- OO.ui.TabOptionWidget.super.call( this, config );
-
- // Initialization
- this.$element.addClass( 'oo-ui-tabOptionWidget' );
-};
-
-/* Setup */
-
-OO.inheritClass( OO.ui.TabOptionWidget, OO.ui.OptionWidget );
-
-/* Static Properties */
-
-OO.ui.TabOptionWidget.static.highlightable = false;
diff --git a/vendor/oojs/oojs-ui/src/widgets/TabSelectWidget.js b/vendor/oojs/oojs-ui/src/widgets/TabSelectWidget.js
deleted file mode 100644
index ced3218b..00000000
--- a/vendor/oojs/oojs-ui/src/widgets/TabSelectWidget.js
+++ /dev/null
@@ -1,33 +0,0 @@
-/**
- * TabSelectWidget is a list that contains {@link OO.ui.TabOptionWidget tab options}
- *
- * ####Currently, this class is only used by {@link OO.ui.IndexLayout index layouts}.####
- *
- * @class
- * @extends OO.ui.SelectWidget
- * @mixins OO.ui.TabIndexedElement
- *
- * @constructor
- * @param {Object} [config] Configuration options
- */
-OO.ui.TabSelectWidget = function OoUiTabSelectWidget( config ) {
- // Parent constructor
- OO.ui.TabSelectWidget.super.call( this, config );
-
- // Mixin constructors
- OO.ui.TabIndexedElement.call( this, config );
-
- // Events
- this.$element.on( {
- focus: this.bindKeyDownListener.bind( this ),
- blur: this.unbindKeyDownListener.bind( this )
- } );
-
- // Initialization
- this.$element.addClass( 'oo-ui-tabSelectWidget' );
-};
-
-/* Setup */
-
-OO.inheritClass( OO.ui.TabSelectWidget, OO.ui.SelectWidget );
-OO.mixinClass( OO.ui.TabSelectWidget, OO.ui.TabIndexedElement );
diff --git a/vendor/oojs/oojs-ui/src/widgets/TextInputMenuSelectWidget.js b/vendor/oojs/oojs-ui/src/widgets/TextInputMenuSelectWidget.js
deleted file mode 100644
index 6b971e81..00000000
--- a/vendor/oojs/oojs-ui/src/widgets/TextInputMenuSelectWidget.js
+++ /dev/null
@@ -1,103 +0,0 @@
-/**
- * TextInputMenuSelectWidget is a menu that is specially designed to be positioned beneath
- * a {@link OO.ui.TextInputWidget text input} field. The menu's position is automatically
- * calculated and maintained when the menu is toggled or the window is resized.
- * See OO.ui.ComboBoxWidget for an example of a widget that uses this class.
- *
- * @class
- * @extends OO.ui.MenuSelectWidget
- *
- * @constructor
- * @param {OO.ui.TextInputWidget} inputWidget Text input widget to provide menu for
- * @param {Object} [config] Configuration options
- * @cfg {jQuery} [$container=input.$element] Element to render menu under
- */
-OO.ui.TextInputMenuSelectWidget = function OoUiTextInputMenuSelectWidget( inputWidget, config ) {
- // Allow passing positional parameters inside the config object
- if ( OO.isPlainObject( inputWidget ) && config === undefined ) {
- config = inputWidget;
- inputWidget = config.inputWidget;
- }
-
- // Configuration initialization
- config = config || {};
-
- // Parent constructor
- OO.ui.TextInputMenuSelectWidget.super.call( this, config );
-
- // Properties
- this.inputWidget = inputWidget;
- this.$container = config.$container || this.inputWidget.$element;
- this.onWindowResizeHandler = this.onWindowResize.bind( this );
-
- // Initialization
- this.$element.addClass( 'oo-ui-textInputMenuSelectWidget' );
-};
-
-/* Setup */
-
-OO.inheritClass( OO.ui.TextInputMenuSelectWidget, OO.ui.MenuSelectWidget );
-
-/* Methods */
-
-/**
- * Handle window resize event.
- *
- * @private
- * @param {jQuery.Event} e Window resize event
- */
-OO.ui.TextInputMenuSelectWidget.prototype.onWindowResize = function () {
- this.position();
-};
-
-/**
- * @inheritdoc
- */
-OO.ui.TextInputMenuSelectWidget.prototype.toggle = function ( visible ) {
- visible = visible === undefined ? !this.isVisible() : !!visible;
-
- var change = visible !== this.isVisible();
-
- if ( change && visible ) {
- // Make sure the width is set before the parent method runs.
- // After this we have to call this.position(); again to actually
- // position ourselves correctly.
- this.position();
- }
-
- // Parent method
- OO.ui.TextInputMenuSelectWidget.super.prototype.toggle.call( this, visible );
-
- if ( change ) {
- if ( this.isVisible() ) {
- this.position();
- $( this.getElementWindow() ).on( 'resize', this.onWindowResizeHandler );
- } else {
- $( this.getElementWindow() ).off( 'resize', this.onWindowResizeHandler );
- }
- }
-
- return this;
-};
-
-/**
- * Position the menu.
- *
- * @private
- * @chainable
- */
-OO.ui.TextInputMenuSelectWidget.prototype.position = function () {
- var $container = this.$container,
- pos = OO.ui.Element.static.getRelativePosition( $container, this.$element.offsetParent() );
-
- // Position under input
- pos.top += $container.height();
- this.$element.css( pos );
-
- // Set width
- this.setIdealSize( $container.width() );
- // We updated the position, so re-evaluate the clipping state
- this.clip();
-
- return this;
-};
diff --git a/vendor/oojs/oojs-ui/src/widgets/TextInputWidget.js b/vendor/oojs/oojs-ui/src/widgets/TextInputWidget.js
deleted file mode 100644
index 1ba26641..00000000
--- a/vendor/oojs/oojs-ui/src/widgets/TextInputWidget.js
+++ /dev/null
@@ -1,535 +0,0 @@
-/**
- * TextInputWidgets, like HTML text inputs, can be configured with options that customize the
- * size of the field as well as its presentation. In addition, these widgets can be configured
- * with {@link OO.ui.IconElement icons}, {@link OO.ui.IndicatorElement indicators}, an optional
- * validation-pattern (used to determine if an input value is valid or not) and an input filter,
- * which modifies incoming values rather than validating them.
- * Please see the [OOjs UI documentation on MediaWiki] [1] for more information and examples.
- *
- * This widget can be used inside a HTML form, such as a OO.ui.FormLayout.
- *
- * @example
- * // Example of a text input widget
- * var textInput = new OO.ui.TextInputWidget( {
- * value: 'Text input'
- * } )
- * $( 'body' ).append( textInput.$element );
- *
- * [1]: https://www.mediawiki.org/wiki/OOjs_UI/Widgets/Inputs
- *
- * @class
- * @extends OO.ui.InputWidget
- * @mixins OO.ui.IconElement
- * @mixins OO.ui.IndicatorElement
- * @mixins OO.ui.PendingElement
- * @mixins OO.ui.LabelElement
- *
- * @constructor
- * @param {Object} [config] Configuration options
- * @cfg {string} [type='text'] The value of the HTML `type` attribute
- * @cfg {string} [placeholder] Placeholder text
- * @cfg {boolean} [autofocus=false] Use an HTML `autofocus` attribute to
- * instruct the browser to focus this widget.
- * @cfg {boolean} [readOnly=false] Prevent changes to the value of the text input.
- * @cfg {number} [maxLength] Maximum number of characters allowed in the input.
- * @cfg {boolean} [multiline=false] Allow multiple lines of text
- * @cfg {boolean} [autosize=false] Automatically resize the text input to fit its content.
- * Use the #maxRows config to specify a maximum number of displayed rows.
- * @cfg {boolean} [maxRows=10] Maximum number of rows to display when #autosize is set to true.
- * @cfg {string} [labelPosition='after'] The position of the inline label relative to that of
- * the value or placeholder text: `'before'` or `'after'`
- * @cfg {boolean} [required=false] Mark the field as required
- * @cfg {RegExp|Function|string} [validate] Validation pattern: when string, a symbolic name of a
- * pattern defined by the class: 'non-empty' (the value cannot be an empty string) or 'integer'
- * (the value must contain only numbers); when RegExp, a regular expression that must match the
- * value for it to be considered valid; when Function, a function receiving the value as parameter
- * that must return true, or promise resolving to true, for it to be considered valid.
- */
-OO.ui.TextInputWidget = function OoUiTextInputWidget( config ) {
- // Configuration initialization
- config = $.extend( {
- type: 'text',
- labelPosition: 'after',
- maxRows: 10
- }, config );
-
- // Parent constructor
- OO.ui.TextInputWidget.super.call( this, config );
-
- // Mixin constructors
- OO.ui.IconElement.call( this, config );
- OO.ui.IndicatorElement.call( this, config );
- OO.ui.PendingElement.call( this, config );
- OO.ui.LabelElement.call( this, config );
-
- // Properties
- this.readOnly = false;
- this.multiline = !!config.multiline;
- this.autosize = !!config.autosize;
- this.maxRows = config.maxRows;
- this.validate = null;
-
- // Clone for resizing
- if ( this.autosize ) {
- this.$clone = this.$input
- .clone()
- .insertAfter( this.$input )
- .attr( 'aria-hidden', 'true' )
- .addClass( 'oo-ui-element-hidden' );
- }
-
- this.setValidation( config.validate );
- this.setLabelPosition( config.labelPosition );
-
- // Events
- this.$input.on( {
- keypress: this.onKeyPress.bind( this ),
- blur: this.onBlur.bind( this )
- } );
- this.$input.one( {
- focus: this.onElementAttach.bind( this )
- } );
- this.$icon.on( 'mousedown', this.onIconMouseDown.bind( this ) );
- this.$indicator.on( 'mousedown', this.onIndicatorMouseDown.bind( this ) );
- this.on( 'labelChange', this.updatePosition.bind( this ) );
- this.connect( this, { change: 'onChange' } );
-
- // Initialization
- this.$element
- .addClass( 'oo-ui-textInputWidget' )
- .append( this.$icon, this.$indicator );
- this.setReadOnly( !!config.readOnly );
- if ( config.placeholder ) {
- this.$input.attr( 'placeholder', config.placeholder );
- }
- if ( config.maxLength !== undefined ) {
- this.$input.attr( 'maxlength', config.maxLength );
- }
- if ( config.autofocus ) {
- this.$input.attr( 'autofocus', 'autofocus' );
- }
- if ( config.required ) {
- this.$input.attr( 'required', 'required' );
- this.$input.attr( 'aria-required', 'true' );
- }
- if ( this.label || config.autosize ) {
- this.installParentChangeDetector();
- }
-};
-
-/* Setup */
-
-OO.inheritClass( OO.ui.TextInputWidget, OO.ui.InputWidget );
-OO.mixinClass( OO.ui.TextInputWidget, OO.ui.IconElement );
-OO.mixinClass( OO.ui.TextInputWidget, OO.ui.IndicatorElement );
-OO.mixinClass( OO.ui.TextInputWidget, OO.ui.PendingElement );
-OO.mixinClass( OO.ui.TextInputWidget, OO.ui.LabelElement );
-
-/* Static properties */
-
-OO.ui.TextInputWidget.static.validationPatterns = {
- 'non-empty': /.+/,
- integer: /^\d+$/
-};
-
-/* Events */
-
-/**
- * An `enter` event is emitted when the user presses 'enter' inside the text box.
- *
- * Not emitted if the input is multiline.
- *
- * @event enter
- */
-
-/* Methods */
-
-/**
- * Handle icon mouse down events.
- *
- * @private
- * @param {jQuery.Event} e Mouse down event
- * @fires icon
- */
-OO.ui.TextInputWidget.prototype.onIconMouseDown = function ( e ) {
- if ( e.which === 1 ) {
- this.$input[ 0 ].focus();
- return false;
- }
-};
-
-/**
- * Handle indicator mouse down events.
- *
- * @private
- * @param {jQuery.Event} e Mouse down event
- * @fires indicator
- */
-OO.ui.TextInputWidget.prototype.onIndicatorMouseDown = function ( e ) {
- if ( e.which === 1 ) {
- this.$input[ 0 ].focus();
- return false;
- }
-};
-
-/**
- * Handle key press events.
- *
- * @private
- * @param {jQuery.Event} e Key press event
- * @fires enter If enter key is pressed and input is not multiline
- */
-OO.ui.TextInputWidget.prototype.onKeyPress = function ( e ) {
- if ( e.which === OO.ui.Keys.ENTER && !this.multiline ) {
- this.emit( 'enter', e );
- }
-};
-
-/**
- * Handle blur events.
- *
- * @private
- * @param {jQuery.Event} e Blur event
- */
-OO.ui.TextInputWidget.prototype.onBlur = function () {
- this.setValidityFlag();
-};
-
-/**
- * Handle element attach events.
- *
- * @private
- * @param {jQuery.Event} e Element attach event
- */
-OO.ui.TextInputWidget.prototype.onElementAttach = function () {
- // Any previously calculated size is now probably invalid if we reattached elsewhere
- this.valCache = null;
- this.adjustSize();
- this.positionLabel();
-};
-
-/**
- * Handle change events.
- *
- * @param {string} value
- * @private
- */
-OO.ui.TextInputWidget.prototype.onChange = function () {
- this.setValidityFlag();
- this.adjustSize();
-};
-
-/**
- * Check if the input is {@link #readOnly read-only}.
- *
- * @return {boolean}
- */
-OO.ui.TextInputWidget.prototype.isReadOnly = function () {
- return this.readOnly;
-};
-
-/**
- * Set the {@link #readOnly read-only} state of the input.
- *
- * @param {boolean} state Make input read-only
- * @chainable
- */
-OO.ui.TextInputWidget.prototype.setReadOnly = function ( state ) {
- this.readOnly = !!state;
- this.$input.prop( 'readOnly', this.readOnly );
- return this;
-};
-
-/**
- * Support function for making #onElementAttach work across browsers.
- *
- * This whole function could be replaced with one line of code using the DOMNodeInsertedIntoDocument
- * event, but it's not supported by Firefox and allegedly deprecated, so we only use it as fallback.
- *
- * Due to MutationObserver performance woes, #onElementAttach is only somewhat reliably called the
- * first time that the element gets attached to the documented.
- */
-OO.ui.TextInputWidget.prototype.installParentChangeDetector = function () {
- var mutationObserver, onRemove, topmostNode, fakeParentNode,
- MutationObserver = window.MutationObserver || window.WebKitMutationObserver || window.MozMutationObserver,
- widget = this;
-
- if ( MutationObserver ) {
- // The new way. If only it wasn't so ugly.
-
- if ( this.$element.closest( 'html' ).length ) {
- // Widget is attached already, do nothing. This breaks the functionality of this function when
- // the widget is detached and reattached. Alas, doing this correctly with MutationObserver
- // would require observation of the whole document, which would hurt performance of other,
- // more important code.
- return;
- }
-
- // Find topmost node in the tree
- topmostNode = this.$element[0];
- while ( topmostNode.parentNode ) {
- topmostNode = topmostNode.parentNode;
- }
-
- // We have no way to detect the $element being attached somewhere without observing the entire
- // DOM with subtree modifications, which would hurt performance. So we cheat: we hook to the
- // parent node of $element, and instead detect when $element is removed from it (and thus
- // probably attached somewhere else). If there is no parent, we create a "fake" one. If it
- // doesn't get attached, we end up back here and create the parent.
-
- mutationObserver = new MutationObserver( function ( mutations ) {
- var i, j, removedNodes;
- for ( i = 0; i < mutations.length; i++ ) {
- removedNodes = mutations[ i ].removedNodes;
- for ( j = 0; j < removedNodes.length; j++ ) {
- if ( removedNodes[ j ] === topmostNode ) {
- setTimeout( onRemove, 0 );
- return;
- }
- }
- }
- } );
-
- onRemove = function () {
- // If the node was attached somewhere else, report it
- if ( widget.$element.closest( 'html' ).length ) {
- widget.onElementAttach();
- }
- mutationObserver.disconnect();
- widget.installParentChangeDetector();
- };
-
- // Create a fake parent and observe it
- fakeParentNode = $( '<div>' ).append( this.$element )[0];
- mutationObserver.observe( fakeParentNode, { childList: true } );
- } else {
- // Using the DOMNodeInsertedIntoDocument event is much nicer and less magical, and works for
- // detachment and reattachment, but it's not supported by Firefox and allegedly deprecated.
- this.$element.on( 'DOMNodeInsertedIntoDocument', this.onElementAttach.bind( this ) );
- }
-};
-
-/**
- * Automatically adjust the size of the text input.
- *
- * This only affects #multiline inputs that are {@link #autosize autosized}.
- *
- * @chainable
- */
-OO.ui.TextInputWidget.prototype.adjustSize = function () {
- var scrollHeight, innerHeight, outerHeight, maxInnerHeight, measurementError, idealHeight;
-
- if ( this.multiline && this.autosize && this.$input.val() !== this.valCache ) {
- this.$clone
- .val( this.$input.val() )
- .attr( 'rows', '' )
- // Set inline height property to 0 to measure scroll height
- .css( 'height', 0 );
-
- this.$clone.removeClass( 'oo-ui-element-hidden' );
-
- this.valCache = this.$input.val();
-
- scrollHeight = this.$clone[ 0 ].scrollHeight;
-
- // Remove inline height property to measure natural heights
- this.$clone.css( 'height', '' );
- innerHeight = this.$clone.innerHeight();
- outerHeight = this.$clone.outerHeight();
-
- // Measure max rows height
- this.$clone
- .attr( 'rows', this.maxRows )
- .css( 'height', 'auto' )
- .val( '' );
- maxInnerHeight = this.$clone.innerHeight();
-
- // Difference between reported innerHeight and scrollHeight with no scrollbars present
- // Equals 1 on Blink-based browsers and 0 everywhere else
- measurementError = maxInnerHeight - this.$clone[ 0 ].scrollHeight;
- idealHeight = Math.min( maxInnerHeight, scrollHeight + measurementError );
-
- this.$clone.addClass( 'oo-ui-element-hidden' );
-
- // Only apply inline height when expansion beyond natural height is needed
- if ( idealHeight > innerHeight ) {
- // Use the difference between the inner and outer height as a buffer
- this.$input.css( 'height', idealHeight + ( outerHeight - innerHeight ) );
- } else {
- this.$input.css( 'height', '' );
- }
- }
- return this;
-};
-
-/**
- * @inheritdoc
- * @private
- */
-OO.ui.TextInputWidget.prototype.getInputElement = function ( config ) {
- return config.multiline ? $( '<textarea>' ) : $( '<input type="' + config.type + '" />' );
-};
-
-/**
- * Check if the input supports multiple lines.
- *
- * @return {boolean}
- */
-OO.ui.TextInputWidget.prototype.isMultiline = function () {
- return !!this.multiline;
-};
-
-/**
- * Check if the input automatically adjusts its size.
- *
- * @return {boolean}
- */
-OO.ui.TextInputWidget.prototype.isAutosizing = function () {
- return !!this.autosize;
-};
-
-/**
- * Select the entire text of the input.
- *
- * @chainable
- */
-OO.ui.TextInputWidget.prototype.select = function () {
- this.$input.select();
- return this;
-};
-
-/**
- * Set the validation pattern.
- *
- * The validation pattern is either a regular expression, a function, or the symbolic name of a
- * pattern defined by the class: 'non-empty' (the value cannot be an empty string) or 'integer' (the
- * value must contain only numbers).
- *
- * @param {RegExp|Function|string|null} validate Regular expression, function, or the symbolic name
- * of a pattern (either ‘integer’ or ‘non-empty’) defined by the class.
- */
-OO.ui.TextInputWidget.prototype.setValidation = function ( validate ) {
- if ( validate instanceof RegExp || validate instanceof Function ) {
- this.validate = validate;
- } else {
- this.validate = this.constructor.static.validationPatterns[ validate ] || /.*/;
- }
-};
-
-/**
- * Sets the 'invalid' flag appropriately.
- *
- * @param {boolean} [isValid] Optionally override validation result
- */
-OO.ui.TextInputWidget.prototype.setValidityFlag = function ( isValid ) {
- var widget = this,
- setFlag = function ( valid ) {
- if ( !valid ) {
- widget.$input.attr( 'aria-invalid', 'true' );
- } else {
- widget.$input.removeAttr( 'aria-invalid' );
- }
- widget.setFlags( { invalid: !valid } );
- };
-
- if ( isValid !== undefined ) {
- setFlag( isValid );
- } else {
- this.isValid().done( setFlag );
- }
-};
-
-/**
- * Check if a value is valid.
- *
- * This method returns a promise that resolves with a boolean `true` if the current value is
- * considered valid according to the supplied {@link #validate validation pattern}.
- *
- * @return {jQuery.Promise} A promise that resolves to a boolean `true` if the value is valid.
- */
-OO.ui.TextInputWidget.prototype.isValid = function () {
- if ( this.validate instanceof Function ) {
- var result = this.validate( this.getValue() );
- if ( $.isFunction( result.promise ) ) {
- return result.promise();
- } else {
- return $.Deferred().resolve( !!result ).promise();
- }
- } else {
- return $.Deferred().resolve( !!this.getValue().match( this.validate ) ).promise();
- }
-};
-
-/**
- * Set the position of the inline label relative to that of the value: `‘before’` or `‘after’`.
- *
- * @param {string} labelPosition Label position, 'before' or 'after'
- * @chainable
- */
-OO.ui.TextInputWidget.prototype.setLabelPosition = function ( labelPosition ) {
- this.labelPosition = labelPosition;
- this.updatePosition();
- return this;
-};
-
-/**
- * Deprecated alias of #setLabelPosition
- *
- * @deprecated Use setLabelPosition instead.
- */
-OO.ui.TextInputWidget.prototype.setPosition =
- OO.ui.TextInputWidget.prototype.setLabelPosition;
-
-/**
- * Update the position of the inline label.
- *
- * This method is called by #setLabelPosition, and can also be called on its own if
- * something causes the label to be mispositioned.
- *
- *
- * @chainable
- */
-OO.ui.TextInputWidget.prototype.updatePosition = function () {
- var after = this.labelPosition === 'after';
-
- this.$element
- .toggleClass( 'oo-ui-textInputWidget-labelPosition-after', !!this.label && after )
- .toggleClass( 'oo-ui-textInputWidget-labelPosition-before', !!this.label && !after );
-
- if ( this.label ) {
- this.positionLabel();
- }
-
- return this;
-};
-
-/**
- * Position the label by setting the correct padding on the input.
- *
- * @private
- * @chainable
- */
-OO.ui.TextInputWidget.prototype.positionLabel = function () {
- // Clear old values
- this.$input
- // Clear old values if present
- .css( {
- 'padding-right': '',
- 'padding-left': ''
- } );
-
- if ( this.label ) {
- this.$element.append( this.$label );
- } else {
- this.$label.detach();
- return;
- }
-
- var after = this.labelPosition === 'after',
- rtl = this.$element.css( 'direction' ) === 'rtl',
- property = after === rtl ? 'padding-left' : 'padding-right';
-
- this.$input.css( property, this.$label.outerWidth( true ) );
-
- return this;
-};
diff --git a/vendor/oojs/oojs-ui/src/widgets/ToggleButtonWidget.js b/vendor/oojs/oojs-ui/src/widgets/ToggleButtonWidget.js
deleted file mode 100644
index bb36f083..00000000
--- a/vendor/oojs/oojs-ui/src/widgets/ToggleButtonWidget.js
+++ /dev/null
@@ -1,114 +0,0 @@
-/**
- * ToggleButtons are buttons that have a state (‘on’ or ‘off’) that is represented by a
- * Boolean value. Like other {@link OO.ui.ButtonWidget buttons}, toggle buttons can be
- * configured with {@link OO.ui.IconElement icons}, {@link OO.ui.IndicatorElement indicators},
- * {@link OO.ui.TitledElement titles}, {@link OO.ui.FlaggedElement styling flags},
- * and {@link OO.ui.LabelElement labels}. Please see
- * the [OOjs UI documentation][1] on MediaWiki for more information.
- *
- * @example
- * // Toggle buttons in the 'off' and 'on' state.
- * var toggleButton1 = new OO.ui.ToggleButtonWidget( {
- * label: 'Toggle Button off'
- * } );
- * var toggleButton2 = new OO.ui.ToggleButtonWidget( {
- * label: 'Toggle Button on',
- * value: true
- * } );
- * // Append the buttons to the DOM.
- * $( 'body' ).append( toggleButton1.$element, toggleButton2.$element );
- *
- * [1]: https://www.mediawiki.org/wiki/OOjs_UI/Widgets/Buttons_and_Switches#Toggle_buttons
- *
- * @class
- * @extends OO.ui.ToggleWidget
- * @mixins OO.ui.ButtonElement
- * @mixins OO.ui.IconElement
- * @mixins OO.ui.IndicatorElement
- * @mixins OO.ui.LabelElement
- * @mixins OO.ui.TitledElement
- * @mixins OO.ui.FlaggedElement
- * @mixins OO.ui.TabIndexedElement
- *
- * @constructor
- * @param {Object} [config] Configuration options
- * @cfg {boolean} [value=false] The toggle button’s initial on/off
- * state. By default, the button is in the 'off' state.
- */
-OO.ui.ToggleButtonWidget = function OoUiToggleButtonWidget( config ) {
- // Configuration initialization
- config = config || {};
-
- // Parent constructor
- OO.ui.ToggleButtonWidget.super.call( this, config );
-
- // Mixin constructors
- OO.ui.ButtonElement.call( this, config );
- OO.ui.IconElement.call( this, config );
- OO.ui.IndicatorElement.call( this, config );
- OO.ui.LabelElement.call( this, config );
- OO.ui.TitledElement.call( this, $.extend( {}, config, { $titled: this.$button } ) );
- OO.ui.FlaggedElement.call( this, config );
- OO.ui.TabIndexedElement.call( this, $.extend( {}, config, { $tabIndexed: this.$button } ) );
-
- // Events
- this.connect( this, { click: 'onAction' } );
-
- // Initialization
- this.$button.append( this.$icon, this.$label, this.$indicator );
- this.$element
- .addClass( 'oo-ui-toggleButtonWidget' )
- .append( this.$button );
-};
-
-/* Setup */
-
-OO.inheritClass( OO.ui.ToggleButtonWidget, OO.ui.ToggleWidget );
-OO.mixinClass( OO.ui.ToggleButtonWidget, OO.ui.ButtonElement );
-OO.mixinClass( OO.ui.ToggleButtonWidget, OO.ui.IconElement );
-OO.mixinClass( OO.ui.ToggleButtonWidget, OO.ui.IndicatorElement );
-OO.mixinClass( OO.ui.ToggleButtonWidget, OO.ui.LabelElement );
-OO.mixinClass( OO.ui.ToggleButtonWidget, OO.ui.TitledElement );
-OO.mixinClass( OO.ui.ToggleButtonWidget, OO.ui.FlaggedElement );
-OO.mixinClass( OO.ui.ToggleButtonWidget, OO.ui.TabIndexedElement );
-
-/* Methods */
-
-/**
- * Handle the button action being triggered.
- *
- * @private
- */
-OO.ui.ToggleButtonWidget.prototype.onAction = function () {
- this.setValue( !this.value );
-};
-
-/**
- * @inheritdoc
- */
-OO.ui.ToggleButtonWidget.prototype.setValue = function ( value ) {
- value = !!value;
- if ( value !== this.value ) {
- // Might be called from parent constructor before ButtonElement constructor
- if ( this.$button ) {
- this.$button.attr( 'aria-pressed', value.toString() );
- }
- this.setActive( value );
- }
-
- // Parent method
- OO.ui.ToggleButtonWidget.super.prototype.setValue.call( this, value );
-
- return this;
-};
-
-/**
- * @inheritdoc
- */
-OO.ui.ToggleButtonWidget.prototype.setButtonElement = function ( $button ) {
- if ( this.$button ) {
- this.$button.removeAttr( 'aria-pressed' );
- }
- OO.ui.ButtonElement.prototype.setButtonElement.call( this, $button );
- this.$button.attr( 'aria-pressed', this.value.toString() );
-};
diff --git a/vendor/oojs/oojs-ui/src/widgets/ToggleSwitchWidget.js b/vendor/oojs/oojs-ui/src/widgets/ToggleSwitchWidget.js
deleted file mode 100644
index 94f0f996..00000000
--- a/vendor/oojs/oojs-ui/src/widgets/ToggleSwitchWidget.js
+++ /dev/null
@@ -1,92 +0,0 @@
-/**
- * ToggleSwitches are switches that slide on and off. Their state is represented by a Boolean
- * value (`true` for ‘on’, and `false` otherwise, the default). The ‘off’ state is represented
- * visually by a slider in the leftmost position.
- *
- * @example
- * // Toggle switches in the 'off' and 'on' position.
- * var toggleSwitch1 = new OO.ui.ToggleSwitchWidget();
- * var toggleSwitch2 = new OO.ui.ToggleSwitchWidget( {
- * value: true
- * } );
- *
- * // Create a FieldsetLayout to layout and label switches
- * var fieldset = new OO.ui.FieldsetLayout( {
- * label: 'Toggle switches'
- * } );
- * fieldset.addItems( [
- * new OO.ui.FieldLayout( toggleSwitch1, { label: 'Off', align: 'top' } ),
- * new OO.ui.FieldLayout( toggleSwitch2, { label: 'On', align: 'top' } )
- * ] );
- * $( 'body' ).append( fieldset.$element );
- *
- * @class
- * @extends OO.ui.ToggleWidget
- * @mixins OO.ui.TabIndexedElement
- *
- * @constructor
- * @param {Object} [config] Configuration options
- * @cfg {boolean} [value=false] The toggle switch’s initial on/off state.
- * By default, the toggle switch is in the 'off' position.
- */
-OO.ui.ToggleSwitchWidget = function OoUiToggleSwitchWidget( config ) {
- // Parent constructor
- OO.ui.ToggleSwitchWidget.super.call( this, config );
-
- // Mixin constructors
- OO.ui.TabIndexedElement.call( this, config );
-
- // Properties
- this.dragging = false;
- this.dragStart = null;
- this.sliding = false;
- this.$glow = $( '<span>' );
- this.$grip = $( '<span>' );
-
- // Events
- this.$element.on( {
- click: this.onClick.bind( this ),
- keypress: this.onKeyPress.bind( this )
- } );
-
- // Initialization
- this.$glow.addClass( 'oo-ui-toggleSwitchWidget-glow' );
- this.$grip.addClass( 'oo-ui-toggleSwitchWidget-grip' );
- this.$element
- .addClass( 'oo-ui-toggleSwitchWidget' )
- .attr( 'role', 'checkbox' )
- .append( this.$glow, this.$grip );
-};
-
-/* Setup */
-
-OO.inheritClass( OO.ui.ToggleSwitchWidget, OO.ui.ToggleWidget );
-OO.mixinClass( OO.ui.ToggleSwitchWidget, OO.ui.TabIndexedElement );
-
-/* Methods */
-
-/**
- * Handle mouse click events.
- *
- * @private
- * @param {jQuery.Event} e Mouse click event
- */
-OO.ui.ToggleSwitchWidget.prototype.onClick = function ( e ) {
- if ( !this.isDisabled() && e.which === 1 ) {
- this.setValue( !this.value );
- }
- return false;
-};
-
-/**
- * Handle key press events.
- *
- * @private
- * @param {jQuery.Event} e Key press event
- */
-OO.ui.ToggleSwitchWidget.prototype.onKeyPress = function ( e ) {
- if ( !this.isDisabled() && ( e.which === OO.ui.Keys.SPACE || e.which === OO.ui.Keys.ENTER ) ) {
- this.setValue( !this.value );
- return false;
- }
-};
diff --git a/vendor/oojs/oojs-ui/src/widgets/ToggleWidget.js b/vendor/oojs/oojs-ui/src/widgets/ToggleWidget.js
deleted file mode 100644
index 16d6ba50..00000000
--- a/vendor/oojs/oojs-ui/src/widgets/ToggleWidget.js
+++ /dev/null
@@ -1,71 +0,0 @@
-/**
- * ToggleWidget implements basic behavior of widgets with an on/off state.
- * Please see OO.ui.ToggleButtonWidget and OO.ui.ToggleSwitchWidget for examples.
- *
- * @abstract
- * @class
- * @extends OO.ui.Widget
- *
- * @constructor
- * @param {Object} [config] Configuration options
- * @cfg {boolean} [value=false] The toggle’s initial on/off state.
- * By default, the toggle is in the 'off' state.
- */
-OO.ui.ToggleWidget = function OoUiToggleWidget( config ) {
- // Configuration initialization
- config = config || {};
-
- // Parent constructor
- OO.ui.ToggleWidget.super.call( this, config );
-
- // Properties
- this.value = null;
-
- // Initialization
- this.$element.addClass( 'oo-ui-toggleWidget' );
- this.setValue( !!config.value );
-};
-
-/* Setup */
-
-OO.inheritClass( OO.ui.ToggleWidget, OO.ui.Widget );
-
-/* Events */
-
-/**
- * @event change
- *
- * A change event is emitted when the on/off state of the toggle changes.
- *
- * @param {boolean} value Value representing the new state of the toggle
- */
-
-/* Methods */
-
-/**
- * Get the value representing the toggle’s state.
- *
- * @return {boolean} The on/off state of the toggle
- */
-OO.ui.ToggleWidget.prototype.getValue = function () {
- return this.value;
-};
-
-/**
- * Set the state of the toggle: `true` for 'on', `false' for 'off'.
- *
- * @param {boolean} value The state of the toggle
- * @fires change
- * @chainable
- */
-OO.ui.ToggleWidget.prototype.setValue = function ( value ) {
- value = !!value;
- if ( this.value !== value ) {
- this.value = value;
- this.emit( 'change', value );
- this.$element.toggleClass( 'oo-ui-toggleWidget-on', value );
- this.$element.toggleClass( 'oo-ui-toggleWidget-off', !value );
- this.$element.attr( 'aria-checked', value.toString() );
- }
- return this;
-};
diff --git a/vendor/oojs/oojs-ui/tests/Element.test.js b/vendor/oojs/oojs-ui/tests/Element.test.js
deleted file mode 100644
index b37d8e35..00000000
--- a/vendor/oojs/oojs-ui/tests/Element.test.js
+++ /dev/null
@@ -1,52 +0,0 @@
-QUnit.module( 'Element', {
- setup: function () {
- this.fixture = document.createElement( 'div' );
- document.body.appendChild( this.fixture );
-
- this.makeFrame = function () {
- var frame = document.createElement( 'iframe' );
- this.fixture.appendChild( frame );
- return ( frame.contentWindow && frame.contentWindow.document ) || frame.contentDocument;
- };
- },
- teardown: function () {
- this.fixture.parentNode.removeChild( this.fixture );
- this.fixture = null;
- }
-} );
-
-QUnit.test( 'static.getDocument', 10, function ( assert ) {
- var frameDoc, frameEl, frameDiv,
- el = this.fixture,
- div = document.createElement( 'div' ),
- $el = $( this.fixture ),
- $div = $( '<div>' ),
- win = window,
- doc = document;
-
- frameDoc = this.makeFrame();
- frameEl = frameDoc.createElement( 'span' );
- frameDoc.documentElement.appendChild( frameEl );
- frameDiv = frameDoc.createElement( 'div' );
-
- assert.strictEqual( OO.ui.Element.static.getDocument( $el ), doc, 'jQuery' );
- assert.strictEqual( OO.ui.Element.static.getDocument( $div ), doc, 'jQuery (detached)' );
- assert.strictEqual( OO.ui.Element.static.getDocument( el ), doc, 'HTMLElement' );
- assert.strictEqual( OO.ui.Element.static.getDocument( div ), doc, 'HTMLElement (detached)' );
- assert.strictEqual( OO.ui.Element.static.getDocument( win ), doc, 'Window' );
- assert.strictEqual( OO.ui.Element.static.getDocument( doc ), doc, 'HTMLDocument' );
-
- assert.strictEqual( OO.ui.Element.static.getDocument( frameEl ), frameDoc, 'HTMLElement (framed)' );
- assert.strictEqual( OO.ui.Element.static.getDocument( frameDiv ), frameDoc, 'HTMLElement (framed, detached)' );
- assert.strictEqual( OO.ui.Element.static.getDocument( frameDoc ), frameDoc, 'HTMLDocument (framed)' );
-
- assert.strictEqual( OO.ui.Element.static.getDocument( {} ), null, 'Invalid' );
-} );
-
-QUnit.test( 'getElementDocument', 1, function ( assert ) {
- var el, doc;
-
- doc = document;
- el = new OO.ui.Element();
- assert.strictEqual( el.getElementDocument(), doc );
-} );
diff --git a/vendor/oojs/oojs-ui/tests/JSPHP.test.karma.js b/vendor/oojs/oojs-ui/tests/JSPHP.test.karma.js
deleted file mode 100644
index 1a1473c1..00000000
--- a/vendor/oojs/oojs-ui/tests/JSPHP.test.karma.js
+++ /dev/null
@@ -1,61 +0,0 @@
-QUnit.module( 'JSPHP' );
-
-( function () {
- // Generate some tests based on the test suite data and HTML from PHP version.
- var theme, klassName,
- themes = {
- ApexTheme: new OO.ui.ApexTheme(),
- MediaWikiTheme: new OO.ui.MediaWikiTheme()
- };
-
- function unstub( value ) {
- var config;
- if ( typeof value === 'string' && value.substr( 0, 13 ) === '_placeholder_' ) {
- value = JSON.parse( value.substr( 13 ) );
- config = OO.copy( value.config, null, unstub );
- return new OO.ui[ value.class ]( config );
- }
- }
-
- function makeTest( theme, klassName, tests, output ) {
- QUnit.test( theme + ': ' + klassName, tests.length * 2, function ( assert ) {
- var test, config, instance, infused, $fromPhp, i, testName;
- OO.ui.theme = themes[ theme ];
- for ( i = 0; i < tests.length; i++ ) {
- test = tests[ i ];
- // Unstub placeholders
- config = OO.copy( test.config, null, unstub );
-
- instance = new OO.ui[ test.class ]( config );
- $fromPhp = $( $.parseHTML( output[ i ] ) );
-
- $( 'body' ).append( instance.$element, $fromPhp );
-
- // Updating theme classes is normally debounced, we need to do it immediately
- instance.debouncedUpdateThemeClasses();
-
- testName = JSON.stringify( test.config );
- assert.equalDomElement( instance.$element[ 0 ], $fromPhp[ 0 ], testName, true );
-
- infused = OO.ui.infuse( $fromPhp[ 0 ] );
- infused.debouncedUpdateThemeClasses();
-
- assert.equalDomElement( instance.$element[ 0 ], infused.$element[ 0 ], testName + ' (infuse)' );
- instance.$element.add( infused.$element ).detach();
- }
- } );
- }
-
- /*global testSuiteConfigs, testSuitePHPOutput */
- for ( klassName in testSuiteConfigs ) {
- for ( theme in themes ) {
- makeTest(
- theme,
- klassName,
- testSuiteConfigs[ klassName ],
- testSuitePHPOutput[ theme ][ klassName ]
- );
- }
- }
-
-} )();
diff --git a/vendor/oojs/oojs-ui/tests/JSPHP.test.standalone.js b/vendor/oojs/oojs-ui/tests/JSPHP.test.standalone.js
deleted file mode 100644
index 1cbebc3a..00000000
--- a/vendor/oojs/oojs-ui/tests/JSPHP.test.standalone.js
+++ /dev/null
@@ -1,55 +0,0 @@
-QUnit.module( 'JSPHP' );
-
-( function () {
- // Generate some tests based on the test suite data and HTML from PHP version.
- var theme, klassName,
- themes = {
- ApexTheme: new OO.ui.ApexTheme(),
- MediaWikiTheme: new OO.ui.MediaWikiTheme()
- };
-
- function unstub( value ) {
- var config;
- if ( typeof value === 'string' && value.substr( 0, 13 ) === '_placeholder_' ) {
- value = JSON.parse( value.substr( 13 ) );
- config = OO.copy( value.config, null, unstub );
- return new OO.ui[ value.class ]( config );
- }
- }
-
- function makeTest( theme, klassName, tests ) {
- QUnit.test( theme + ': ' + klassName, tests.length * 2, function ( assert ) {
- var test, config, instance, infused, id, fromPhp, i, testName;
- OO.ui.theme = themes[ theme ];
- for ( i = 0; i < tests.length; i++ ) {
- test = tests[ i ];
- // Unstub placeholders
- config = OO.copy( test.config, null, unstub );
-
- instance = new OO.ui[ test.class ]( config );
-
- id = 'JSPHPTestSuite_' + theme + klassName + i;
- fromPhp = document.getElementById( id ).firstChild;
- instance.$element.insertBefore( fromPhp );
-
- // Updating theme classes is normally debounced, we need to do it immediately
- instance.debouncedUpdateThemeClasses();
-
- testName = JSON.stringify( test.config );
- assert.equalDomElement( instance.$element[ 0 ], fromPhp, testName );
-
- infused = OO.ui.infuse( fromPhp );
- infused.debouncedUpdateThemeClasses();
-
- assert.equalDomElement( instance.$element[ 0 ], infused.$element[ 0 ], testName + ' (infuse)' );
- }
- } );
- }
-
- for ( klassName in OO.ui.JSPHPTestSuite ) {
- for ( theme in themes ) {
- makeTest( theme, klassName, OO.ui.JSPHPTestSuite[ klassName ] );
- }
- }
-
-} )();
diff --git a/vendor/oojs/oojs-ui/tests/Process.test.js b/vendor/oojs/oojs-ui/tests/Process.test.js
deleted file mode 100644
index 3f036407..00000000
--- a/vendor/oojs/oojs-ui/tests/Process.test.js
+++ /dev/null
@@ -1,179 +0,0 @@
-QUnit.module( 'OO.ui.Process' );
-
-/* Tests */
-
-QUnit.test( 'next', 1, function ( assert ) {
- var process = new OO.ui.Process(),
- result = [];
-
- process
- .next( function () {
- result.push( 0 );
- } )
- .next( function () {
- result.push( 1 );
- } )
- .next( function () {
- result.push( 2 );
- } )
- .execute();
-
- assert.deepEqual( result, [ 0, 1, 2 ], 'Steps can be added at the end' );
-} );
-
-QUnit.test( 'first', 1, function ( assert ) {
- var process = new OO.ui.Process(),
- result = [];
-
- process
- .first( function () {
- result.push( 0 );
- } )
- .first( function () {
- result.push( 1 );
- } )
- .first( function () {
- result.push( 2 );
- } )
- .execute();
-
- assert.deepEqual( result, [ 2, 1, 0 ], 'Steps can be added at the beginning' );
-} );
-
-QUnit.asyncTest( 'execute (async)', 1, function ( assert ) {
- // Async
- var process = new OO.ui.Process(),
- result = [];
-
- process
- .next( function () {
- var deferred = $.Deferred();
-
- setTimeout( function () {
- result.push( 1 );
- deferred.resolve();
- }, 10 );
-
- return deferred.promise();
- } )
- .first( function () {
- var deferred = $.Deferred();
-
- setTimeout( function () {
- result.push( 0 );
- deferred.resolve();
- }, 10 );
-
- return deferred.promise();
- } )
- .next( function () {
- result.push( 2 );
- } );
-
- process.execute().done( function () {
- assert.deepEqual(
- result,
- [ 0, 1, 2 ],
- 'Synchronous and asynchronous steps are executed in the correct order'
- );
- QUnit.start();
- } );
-} );
-
-QUnit.asyncTest( 'execute (return false)', 1, function ( assert ) {
- var process = new OO.ui.Process(),
- result = [];
-
- process
- .next( function () {
- var deferred = $.Deferred();
-
- setTimeout( function () {
- result.push( 0 );
- deferred.resolve();
- }, 10 );
-
- return deferred.promise();
- } )
- .next( function () {
- result.push( 1 );
- return false;
- } )
- .next( function () {
- // Should never be run because previous step is rejected
- result.push( 2 );
- } );
-
- process.execute().fail( function () {
- assert.deepEqual(
- result,
- [ 0, 1 ],
- 'Process is stopped when a step returns false'
- );
- QUnit.start();
- } );
-} );
-
-QUnit.asyncTest( 'execute (async reject)', 1, function ( assert ) {
- var process = new OO.ui.Process(),
- result = [];
-
- process
- .next( function () {
- result.push( 0 );
- } )
- .next( function () {
- var deferred = $.Deferred();
-
- setTimeout( function () {
- result.push( 1 );
- deferred.reject();
- }, 10 );
-
- return deferred.promise();
- } )
- .next( function () {
- // Should never be run because previous step is rejected
- result.push( 2 );
- } );
-
- process.execute().fail( function () {
- assert.deepEqual(
- result,
- [ 0, 1 ],
- 'Process is stopped when a step returns a promise that is then rejected'
- );
- QUnit.start();
- } );
-} );
-
-QUnit.asyncTest( 'execute (wait)', 1, function ( assert ) {
- var process = new OO.ui.Process(),
- result = [];
-
- process
- .next( function () {
- result.push( 'A' );
- return 10;
- } )
- .next( function () {
- result.push( 'B' );
- } );
-
- // Steps defined above don't run until execute()
- result.push( 'before' );
-
- // Process yields between step A and B
- setTimeout( function () {
- result.push( 'yield' );
- } );
-
- process.execute().done( function () {
- assert.deepEqual(
- result,
- [ 'before', 'A', 'yield', 'B' ],
- 'Process is stopped when a step returns a promise that is then rejected'
- );
- QUnit.start();
- } );
-} );
diff --git a/vendor/oojs/oojs-ui/tests/QUnit.assert.equalDomElement.js b/vendor/oojs/oojs-ui/tests/QUnit.assert.equalDomElement.js
deleted file mode 100644
index f041c258..00000000
--- a/vendor/oojs/oojs-ui/tests/QUnit.assert.equalDomElement.js
+++ /dev/null
@@ -1,113 +0,0 @@
-/*!
- * A QUnit assertion to compare DOM node trees.
- *
- * Adapted from VisualEditor plugin for QUnit. Additionally supports comparing properties to
- * attributes (for dynamically generated nodes) and order-insensitive comparison of classes on DOM
- * nodes.
- *
- * @copyright 2011-2015 VisualEditor Team and others; see http://ve.mit-license.org
- * @copyright 2011-2015 OOjs Team and other contributors
- */
-
-( function ( QUnit ) {
-
- /**
- * Build a summary of an HTML element.
- *
- * Summaries include node name, text, attributes and recursive summaries of children.
- * Used for serializing or comparing HTML elements.
- *
- * @private
- * @param {HTMLElement} element Element to summarize
- * @param {boolean} [includeHtml=false] Include an HTML summary for element nodes
- * @return {Object} Summary of element.
- */
- function getDomElementSummary( element, includeHtml ) {
- var i, name,
- summary = {
- type: element.nodeName.toLowerCase(),
- // $( '<div><textarea>Foo</textarea></div>' )[0].textContent === 'Foo', which breaks
- // comparisons :( childNodes are summarized anyway, this would just be a nicety
- // text: element.textContent,
- attributes: {},
- children: []
- };
-
- if ( includeHtml && element.nodeType === Node.ELEMENT_NODE ) {
- summary.html = element.outerHTML;
- }
-
- // Gather attributes
- if ( element.attributes ) {
- for ( i = 0; i < element.attributes.length; i++ ) {
- name = element.attributes[ i ].name;
- if ( name.substr( 0, 5 ) !== 'data-' && name !== 'id' ) {
- summary.attributes[ name ] = element.attributes[ i ].value;
- }
- }
- }
-
- // Sort classes
- if ( summary.attributes.class ) {
- summary.attributes.class = summary.attributes.class.split( ' ' ).sort().join( ' ' );
- }
-
- // Gather certain properties and pretend they are attributes.
- // Take note of casing differences.
- if ( element.value !== undefined ) {
- summary.attributes.value = element.value;
- }
- if ( element.readOnly !== undefined ) {
- summary.attributes.readonly = element.readOnly;
- }
- if ( element.checked !== undefined ) {
- summary.attributes.checked = element.checked;
- }
- if ( element.disabled !== undefined ) {
- summary.attributes.disabled = element.disabled;
- }
- if ( element.tabIndex !== undefined ) {
- summary.attributes.tabindex = element.tabIndex;
- }
-
- // Summarize children
- if ( element.childNodes ) {
- for ( i = 0; i < element.childNodes.length; i++ ) {
- summary.children.push( getDomElementSummary( element.childNodes[ i ], includeHtml ) );
- }
- }
-
- // Special handling for textareas, where we only want to account for the content as the 'value'
- // property, never as childNodes or textContent
- if ( summary.type === 'textarea' ) {
- // summary.text = '';
- summary.children = [];
- }
-
- return summary;
- }
-
- /**
- * @method
- * @static
- */
- QUnit.assert.equalDomElement = function ( actual, expected, message, stringify ) {
- var actualSummary = getDomElementSummary( actual ),
- expectedSummary = getDomElementSummary( expected ),
- actualSummaryHtml = getDomElementSummary( actual, true ),
- expectedSummaryHtml = getDomElementSummary( expected, true );
-
- // When running with Karma, the objects are not nicely stringified in the output when the test
- // fails, only showing "Expected: [object Object], Actual: [object Object]" instead. Running
- // QUnit in browser does this, and stringifying causes double escaping in output.
- if ( stringify ) {
- actualSummaryHtml = JSON.stringify( actualSummaryHtml, null, 2 );
- expectedSummaryHtml = JSON.stringify( expectedSummaryHtml, null, 2 );
- }
-
- QUnit.push(
- QUnit.equiv( actualSummary, expectedSummary ), actualSummaryHtml, expectedSummaryHtml, message
- );
- };
-
-}( QUnit ) );
diff --git a/vendor/oojs/oojs-ui/tests/elements/FlaggedElement.test.js b/vendor/oojs/oojs-ui/tests/elements/FlaggedElement.test.js
deleted file mode 100644
index f5c483ad..00000000
--- a/vendor/oojs/oojs-ui/tests/elements/FlaggedElement.test.js
+++ /dev/null
@@ -1,64 +0,0 @@
-( function () {
- QUnit.module( 'FlaggedElement' );
-
- function TestElement( config ) {
- TestElement.super.call( this, config );
- OO.ui.FlaggedElement.call( this, config );
- }
- OO.inheritClass( TestElement, OO.ui.Widget );
- OO.mixinClass( TestElement, OO.ui.FlaggedElement );
-
- QUnit.test( 'constructor', 2, function ( assert ) {
- var element;
-
- element = new TestElement();
- assert.deepEqual( element.getFlags(), [], 'No flags by default' );
-
- element = new TestElement( {
- flags: [ 'foo' ]
- } );
- assert.deepEqual( element.getFlags(), [ 'foo' ], 'Config option "flags"' );
- } );
-
- QUnit.test( 'getFlags', 2, function ( assert ) {
- var element = new TestElement();
-
- element.setFlags( 'foo' );
- assert.deepEqual( element.getFlags(), [ 'foo' ], 'Flag was set' );
-
- element.clearFlags();
- assert.deepEqual( element.getFlags(), [], 'Flag was removed' );
- } );
-
- QUnit.test( 'hasFlag', 3, function ( assert ) {
- var element = new TestElement();
- assert.deepEqual( element.hasFlag( 'foo' ), false, 'Flag absent by default' );
-
- element.setFlags( 'foo' );
- assert.deepEqual( element.hasFlag( 'foo' ), true, 'Flag was set' );
-
- element.clearFlags();
- assert.deepEqual( element.hasFlag( 'foo' ), false, 'Flag was removed' );
- } );
-
- QUnit.test( 'clearFlags', 1, function ( assert ) {
- var element = new TestElement();
- element.setFlags( 'foo' );
- element.clearFlags();
- assert.deepEqual( element.hasFlag( 'foo' ), false, 'Flag was removed' );
- } );
-
- QUnit.test( 'setFlags', 5, function ( assert ) {
- var element = new TestElement();
- element.setFlags( 'foo' );
- assert.deepEqual( element.hasFlag( 'foo' ), true, 'string' );
-
- element.setFlags( [ 'bar', 'qux' ] );
- assert.deepEqual( element.hasFlag( 'bar' ), true, 'array[ 0 ]' );
- assert.deepEqual( element.hasFlag( 'qux' ), true, 'array[ 1 ]' );
-
- element.setFlags( { bar: false, quux: true } );
- assert.deepEqual( element.hasFlag( 'bar' ), false, 'object set' );
- assert.deepEqual( element.hasFlag( 'quux' ), true, 'object remove' );
- } );
-}() );
diff --git a/vendor/oojs/oojs-ui/tests/index.php b/vendor/oojs/oojs-ui/tests/index.php
deleted file mode 100644
index d8e06835..00000000
--- a/vendor/oojs/oojs-ui/tests/index.php
+++ /dev/null
@@ -1,77 +0,0 @@
-<?php
- $autoload = '../vendor/autoload.php';
- if ( !file_exists( $autoload ) ) {
- echo '<h1>Did you forget to run <code>composer install</code>?</h1>';
- exit;
- }
- require_once $autoload;
-
- $testSuiteFile = 'JSPHP-suite.json';
- if ( !file_exists( $testSuiteFile ) ) {
- echo '<h1>Did you forget to run <code>grunt build</code>?</h1>';
- exit;
- }
- $testSuiteJSON = file_get_contents( $testSuiteFile );
- $testSuite = json_decode( $testSuiteJSON, true );
-?>
-<!DOCTYPE html>
-<html lang="en" dir="ltr">
-<head>
- <meta charset="UTF-8">
- <title>OOjs UI Test Suite</title>
- <link rel="stylesheet" href="../node_modules/qunitjs/qunit/qunit.css">
- <script src="../node_modules/qunitjs/qunit/qunit.js"></script>
- <script src="./QUnit.assert.equalDomElement.js"></script>
- <script>
- QUnit.config.requireExpects = true;
- </script>
- <!-- Dependencies -->
- <script src="../node_modules/jquery/dist/jquery.js"></script>
- <script src="../node_modules/oojs/dist/oojs.jquery.js"></script>
- <!-- Source code -->
- <script src="../dist/oojs-ui.js"></script>
- <script src="../dist/oojs-ui-apex.js"></script>
- <script src="../dist/oojs-ui-mediawiki.js"></script>
- <!-- Test suites -->
- <script src="./Element.test.js"></script>
- <script src="./Process.test.js"></script>
- <script src="./elements/FlaggedElement.test.js"></script>
- <!-- JS/PHP comparison tests -->
- <script>OO.ui.JSPHPTestSuite = <?php echo $testSuiteJSON; ?></script>
- <script src="./JSPHP.test.standalone.js"></script>
-</head>
-<body>
- <div id="JSPHPTestSuite" style="display: none;">
- <?php
- function new_OOUI( $class, $config = array() ) {
- $class = "OOUI\\" . $class;
- return new $class( $config );
- }
- function unstub( &$value ) {
- if ( is_string( $value ) && substr( $value, 0, 13 ) === '_placeholder_' ) {
- $value = json_decode( substr( $value, 13 ), true );
- array_walk_recursive( $value['config'], 'unstub' );
- $value = new_OOUI( $value['class'], $value['config'] );
- }
- }
- // Keep synchronized with bin/generate-JSPHP-for-karma.php
- $themes = array( 'ApexTheme', 'MediaWikiTheme' );
- foreach ( $themes as $theme ) {
- OOUI\Theme::setSingleton( new_OOUI( $theme ) );
- foreach ( $testSuite as $className => $tests ) {
- foreach ( $tests as $index => $test ) {
- // Unstub placeholders
- $config = $test['config'];
- array_walk_recursive( $config, 'unstub' );
- $config['infusable'] = true;
- $instance = new_OOUI( $test['class'], $config );
- echo "<div id='JSPHPTestSuite_$theme$className$index'>$instance</div>\n";
- }
- }
- }
- ?>
- </div>
- <div id="qunit"></div>
- <div id="qunit-fixture"></div>
-</body>
-</html>
diff --git a/vendor/oyejorge/less.php/CHANGES.md b/vendor/oyejorge/less.php/CHANGES.md
new file mode 100644
index 00000000..906a9af1
--- /dev/null
+++ b/vendor/oyejorge/less.php/CHANGES.md
@@ -0,0 +1,6 @@
+This is where the changelog will go for 1.7.0.9 or higher now.
+
+# 1.7.0.9
+
+ - Remove space at beginning of Version.php
+ - Revert require() paths in test interface \ No newline at end of file
diff --git a/vendor/oyejorge/less.php/LICENSE b/vendor/oyejorge/less.php/LICENSE
new file mode 100644
index 00000000..82216a5d
--- /dev/null
+++ b/vendor/oyejorge/less.php/LICENSE
@@ -0,0 +1,178 @@
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+END OF TERMS AND CONDITIONS
+
diff --git a/vendor/oyejorge/less.php/README.md b/vendor/oyejorge/less.php/README.md
new file mode 100644
index 00000000..1c53364d
--- /dev/null
+++ b/vendor/oyejorge/less.php/README.md
@@ -0,0 +1,322 @@
+[Less.php](http://lessphp.gpeasy.com)
+========
+
+This is a PHP port of the official LESS processor <http://lesscss.org>. [![Build Status](https://travis-ci.org/oyejorge/less.php.png?branch=master)](https://travis-ci.org/oyejorge/less.php)
+
+* [About](#about)
+* [Installation](#installation)
+* [Basic Use](#basic-use)
+* [Caching](#caching)
+* [Source Maps](#source-maps)
+* [Command Line](#command-line)
+* [Integration with other projects](#integration-with-other-projects)
+* [Transitioning from Leafo/lessphp](#transitioning-from-leafolessphp)
+* [Credits](#credits)
+
+
+
+About
+---
+The code structure of less.php mirrors that of the official processor which helps us ensure compatibility and allows for easy maintenance.
+
+Please note, there are a few unsupported LESS features:
+
+- Evaluation of JavaScript expressions within back-ticks (for obvious reasons).
+- Definition of custom functions.
+
+
+Installation
+---
+
+You can install the library with composer or manually.
+
+#### Composer
+
+Step 1. Edit your `composer.json`:
+
+```json
+{
+ "require": {
+ "oyejorge/less.php": "~1.5"
+ }
+}
+```
+
+Step 2. Install it:
+
+```bash
+$ curl -sS https://getcomposer.org/installer | php
+$ php composer.phar install
+```
+
+#### Manually From Release
+
+Step 1. [Download the latest release](https://github.com/oyejorge/less.php/releases) and upload the php files to your server.
+
+Step 2. Include the library:
+
+```php
+require_once '[path to less.php]/Less.php';
+```
+
+#### Manually From Source
+
+Step 1. [Download the source](https://github.com/oyejorge/less.php/archive/master.zip) and upload the files in /lib/Less to a folder on your server.
+
+Step 2. Include the library and register the Autoloader
+
+```php
+require_once '[path to less.php]/Autoloader.php';
+Less_Autoloader::register();
+```
+
+Basic Use
+---
+
+#### Parsing Strings
+
+```php
+$parser = new Less_Parser();
+$parser->parse( '@color: #4D926F; #header { color: @color; } h2 { color: @color; }' );
+$css = $parser->getCss();
+```
+
+
+#### Parsing Less Files
+The parseFile() function takes two arguments:
+
+1. The absolute path of the .less file to be parsed
+2. The url root to prepend to any relative image or @import urls in the .less file.
+
+```php
+$parser = new Less_Parser();
+$parser->parseFile( '/var/www/mysite/bootstrap.less', 'http://example.com/mysite/' );
+$css = $parser->getCss();
+```
+
+
+#### Handling Invalid Less
+An exception will be thrown if the compiler encounters invalid less
+
+```php
+try{
+ $parser = new Less_Parser();
+ $parser->parseFile( '/var/www/mysite/bootstrap.less', 'http://example.com/mysite/' );
+ $css = $parser->getCss();
+}catch(Exception $e){
+ $error_message = $e->getMessage();
+}
+```
+
+
+#### Parsing Multiple Sources
+less.php can parse multiple sources to generate a single css file
+
+```php
+$parser = new Less_Parser();
+$parser->parseFile( '/var/www/mysite/bootstrap.less', '/mysite/' );
+$parser->parse( '@color: #4D926F; #header { color: @color; } h2 { color: @color; }' );
+$css = $parser->getCss();
+```
+
+#### Getting Info About The Parsed Files
+less.php can tell you which .less files were imported and parsed.
+
+```php
+$parser = new Less_Parser();
+$parser->parseFile( '/var/www/mysite/bootstrap.less', '/mysite/' );
+$css = $parser->getCss();
+$imported_files = $parser->allParsedFiles();
+```
+
+
+#### Compressing Output
+You can tell less.php to remove comments and whitespace to generate minimized css files.
+
+```php
+$options = array( 'compress'=>true );
+$parser = new Less_Parser( $options );
+$parser->parseFile( '/var/www/mysite/bootstrap.less', '/mysite/' );
+$css = $parser->getCss();
+```
+
+#### Setting Variables
+You can use the ModifyVars() method to customize your css if you have variables stored in php associative arrays
+
+```php
+$parser = new Less_Parser();
+$parser->parseFile( '/var/www/mysite/bootstrap.less', '/mysite/' );
+$parser->ModifyVars( array('font-size-base'=>'16px') );
+$css = $parser->getCss();
+```
+
+
+#### Import Directories
+By default, less.php will look for @imports in the directory of the file passed to parsefile().
+If you're using parse() or if @imports reside in different directories, you can tell less.php where to look.
+
+```php
+$directories = array( '/var/www/mysite/bootstrap/' => '/mysite/bootstrap/' );
+$parser = new Less_Parser();
+$parser->SetImportDirs( $directories );
+$parser->parseFile( '/var/www/mysite/theme.less', '/mysite/' );
+$css = $parser->getCss();
+```
+
+
+Caching
+---
+Compiling less code into css is a time consuming process, caching your results is highly recommended.
+
+
+#### Caching CSS
+Use the Less_Cache class to save and reuse the results of compiled less files.
+This method will check the modified time and size of each less file (including imported files) and regenerate a new css file when changes are found.
+Note: When changes are found, this method will return a different file name for the new cached content.
+
+```php
+$less_files = array( '/var/www/mysite/bootstrap.less' => '/mysite/' );
+$options = array( 'cache_dir' => '/var/www/writable_folder' );
+$css_file_name = Less_Cache::Get( $less_files, $options );
+$compiled = file_get_contents( '/var/www/writable_folder/'.$css_file_name );
+```
+
+#### Caching CSS With Variables
+Passing options to Less_Cache::Get()
+
+```php
+$less_files = array( '/var/www/mysite/bootstrap.less' => '/mysite/' );
+$options = array( 'cache_dir' => '/var/www/writable_folder' );
+$variables = array( 'width' => '100px' );
+$css_file_name = Less_Cache::Get( $less_files, $options, $variables );
+$compiled = file_get_contents( '/var/www/writable_folder/'.$css_file_name );
+```
+
+
+#### Parser Caching
+less.php will save serialized parser data for each .less file if a writable folder is passed to the SetCacheDir() method.
+Note: This feature only caches intermediate parsing results to improve the performance of repeated css generation.
+Your application should cache any css generated by less.php.
+
+```php
+$options = array('cache_dir'=>'/var/www/writable_folder');
+$parser = new Less_Parser( $options );
+$parser->parseFile( '/var/www/mysite/bootstrap.less', '/mysite/' );
+$css = $parser->getCss();
+```
+
+You can specify the caching technique used by changing the ```cache_method``` option. Supported methods are:
+* ```php```: Creates valid PHP files which can be included without any changes (default method).
+* ```var_export```: Like "php", but using PHPs ```var_export()``` function without any optimizations.
+ It's recommended to use "php" instead.
+* ```serialize```: Faster, but pretty memory-intense.
+* ```callback```: Use custom callback functions to implement your own caching method. Give the "cache_callback_get" and
+ "cache_callback_set" options with callables (see PHPs ```call_user_func()``` and ```is_callable()``` functions). less.php
+ will pass the parser object (class ```Less_Parser```), the path to the parsed .less file ("/some/path/to/file.less") and
+ an identifier that will change every time the .less file is modified. The ```get``` callback must return the ruleset
+ (an array with ```Less_Tree``` objects) provided as fourth parameter of the ```set``` callback. If something goes wrong,
+ return ```NULL``` (cache doesn't exist) or ```FALSE```.
+
+
+
+Source Maps
+---
+Less.php supports v3 sourcemaps
+
+#### Inline
+The sourcemap will be appended to the generated css file.
+
+```php
+$options = array( 'sourceMap' => true );
+$parser = new Less_Parser($options);
+$parser->parseFile( '/var/www/mysite/bootstrap.less', '/mysite/' );
+$css = $parser->getCss();
+```
+
+#### Saving to Map File
+
+```php
+$options = array(
+ 'sourceMap' => true,
+ 'sourceMapWriteTo' => '/var/www/mysite/writable_folder/filename.map',
+ 'sourceMapURL' => '/mysite/writable_folder/filename.map',
+ );
+$parser = new Less_Parser($options);
+$parser->parseFile( '/var/www/mysite/bootstrap.less', '/mysite/' );
+$css = $parser->getCss();
+```
+
+
+Command line
+---
+An additional script has been included to use the compiler from the command line.
+In the simplest invocation, you specify an input file and the compiled css is written to standard out:
+
+```
+$ lessc input.less > output.css
+```
+
+By using the -w flag you can watch a specified input file and have it compile as needed to the output file:
+
+```
+$ lessc -w input.less output.css
+```
+
+Errors from watch mode are written to standard out.
+
+For more help, run `lessc --help`
+
+
+Integration with other projects
+---
+
+#### Drupal 7
+
+This library can be used as drop-in replacement of lessphp to work with [Drupal 7 less module](https://drupal.org/project/less).
+
+How to install:
+
+1. [Download the less.php source code](https://github.com/oyejorge/less.php/archive/master.zip) and unzip it so that 'lessc.inc.php' is located at 'sites/all/libraries/lessphp/lessc.inc.php'.
+2. Download and install [Drupal 7 less module](https://drupal.org/project/less) as usual.
+3. That's it :)
+
+#### JBST WordPress theme
+
+JBST has a built-in LESS compiler based on lessphp. Customize your WordPress theme with LESS.
+
+How to use / install:
+
+1. [Download the latest release](https://github.com/bassjobsen/jamedo-bootstrap-start-theme) copy the files to your {wordpress/}wp-content/themes folder and activate it.
+2. Find the compiler under Appearance > LESS Compiler in your WordPress dashboard
+3. Enter your LESS code in the text area and press (re)compile
+
+Use the built-in compiler to:
+- set any [Bootstrap](http://getbootstrap.com/customize/) variable or use Bootstrap's mixins:
+ -`@navbar-default-color: blue;`
+ - create a custom button: `.btn-custom {
+ .button-variant(white; red; blue);
+}`
+- set any built-in LESS variable: for example `@footer_bg_color: black;` sets the background color of the footer to black
+- use built-in mixins: - add a custom font: `.include-custom-font(@family: arial,@font-path, @path: @custom-font-dir, @weight: normal, @style: normal);`
+
+The compiler can also be download as [plugin](http://wordpress.org/plugins/wp-less-to-css/)
+
+#### WordPress
+
+This simple plugin will simply make the library available to other plugins and themes and can be used as a dependency using the [TGM Library](http://tgmpluginactivation.com/)
+
+How to install:
+
+1. Install the plugin from your WordPress Dashboard: http://wordpress.org/plugins/lessphp/
+2. That's it :)
+
+
+Transitioning from Leafo/lessphp
+---
+Projects looking for an easy transition from leafo/lessphp can use the lessc.inc.php adapter. To use, [Download the less.php source code](https://github.com/oyejorge/less.php/archive/master.zip) and unzip the files into your project so that the new 'lessc.inc.php' replaces the existing 'lessc.inc.php'.
+
+Note, the 'setPreserveComments' will no longer have any effect on the compiled less.
+
+Credits
+---
+less.php was originally ported to php by [Matt Agar](https://github.com/agar) and then updated by [Martin Jantošovič](https://github.com/Mordred).
diff --git a/vendor/oyejorge/less.php/bin/lessc b/vendor/oyejorge/less.php/bin/lessc
new file mode 100644
index 00000000..fa1fb958
--- /dev/null
+++ b/vendor/oyejorge/less.php/bin/lessc
@@ -0,0 +1,191 @@
+#!/usr/bin/env php
+<?php
+
+require_once dirname(__FILE__) . '/../lib/Less/Autoloader.php';
+Less_Autoloader::register();
+
+// Create our environment
+$env = array('compress' => false, 'relativeUrls' => false);
+$silent = false;
+$watch = false;
+$rootpath = '';
+
+// Check for arguments
+array_shift($argv);
+if (!count($argv)) {
+ $argv[] = '-h';
+}
+
+// parse arguments
+foreach ($argv as $key => $arg) {
+ if (preg_match('/^--?([a-z][0-9a-z-]*)(?:=([^\s]+))?$/i', $arg, $matches)) {
+ $option = $matches[1];
+ $value = isset($matches[2]) ? $matches[2] : false;
+ unset($argv[$key]);
+
+ switch ($option) {
+ case 'h':
+ case 'help':
+ echo <<<EOD
+Usage: lessc [options] sources [destination]
+
+ -h, --help Print help (this message) and exit.
+ -s, --silent Suppress output of error messages.
+ -v, --version Print version number and exit.
+ -x, --compress Compress output by removing some whitespaces.
+ --include-path=PATHS Set include paths. Separated by `:'. Use `;' on Windows.
+ --strict-imports Force evaluation of imports.
+ -sm=on|off Turn on or off strict math, where in strict mode, math
+ --strict-math=on|off requires brackets. This option may default to on and then
+ be removed in the future.
+ -su=on|off Allow mixed units, e.g. 1px+1em or 1px*1px which have units
+ --strict-units=on|off that cannot be represented.
+ -ru, --relative-urls re-write relative urls to the base less file.
+ -rp, --rootpath=URL Set rootpath for url rewriting in relative imports and urls.
+ Works with or without the relative-urls option.
+ -w, --watch Watch input files for changes.
+
+
+EOD;
+ exit;
+ case 's':
+ case 'silent':
+ $silent = true;
+ break;
+
+ case 'w':
+ case 'watch':
+ $watch = true;
+ break;
+
+ case 'v':
+ case 'version':
+ echo "lessc " . Less_Version::version . " (less.php)\n\n";
+ exit;
+
+ case 'rp':
+ case 'rootpath':
+ $rootpath = $value;
+ break;
+
+
+ //parser options
+ case 'compress':
+ $env['compress'] = true;
+ break;
+
+ case 'ru':
+ case 'relative-urls':
+ $env['relativeUrls'] = true;
+ break;
+
+ case 'su':
+ case 'strict-units':
+ $env['strictUnits'] = ($value === 'on');
+ break;
+
+ case 'sm':
+ case 'strict-math':
+ $env['strictMath'] = ($value === 'on');
+ break;
+
+ case 'x':
+ case 'include-path':
+ $env['import_dirs'] = preg_split('#;|\:#', $value);
+ break;
+
+ }
+ }
+}
+
+if (count($argv) > 1) {
+ $output = array_pop($argv);
+ $inputs = $argv;
+}
+else {
+ $inputs = $argv;
+ $output = false;
+}
+
+if (!count($inputs)) {
+ echo("lessc: no input files\n");
+ exit;
+}
+
+if ($watch) {
+ if (!$output) {
+ echo("lessc: you must specify the output file if --watch is given\n");
+ exit;
+ }
+
+ $lastAction = 0;
+
+ echo("lessc: watching input files\n");
+
+ while (1) {
+ clearstatcache();
+
+ $updated = false;
+ foreach ($inputs as $input) {
+ if ($input == '-') {
+ if (count($inputs) == 1) {
+ echo("lessc: during watching files is not possible to watch stdin\n");
+ exit;
+ }
+ else {
+ continue;
+ }
+ }
+
+ if (filemtime($input) > $lastAction) {
+ $updated = true;
+ break;
+ }
+ }
+
+ if ($updated) {
+ $lastAction = time();
+ $parser = new Less_Parser($env);
+ foreach ($inputs as $input) {
+ try {
+ $parser->parseFile($input, $rootpath);
+ }
+ catch (Exception $e) {
+ echo("lessc: " . $e->getMessage() . " \n");
+ continue; // Invalid processing
+ }
+ }
+
+ file_put_contents($output, $parser->getCss());
+ echo("lessc: output file recompiled\n");
+ }
+
+ sleep(1);
+ }
+}
+else {
+ $parser = new Less_Parser($env);
+ foreach ($inputs as $input) {
+ if ($input == '-') {
+ $content = file_get_contents('php://stdin');
+ $parser->parse($content);
+ }
+ else {
+ try {
+ $parser->parseFile($input);
+ }
+ catch (Exception $e) {
+ if (!$silent) {
+ echo("lessc: " . ((string)$e) . " \n");
+ }
+ }
+ }
+ }
+
+ if ($output) {
+ file_put_contents($output, $parser->getCss());
+ }
+ else {
+ echo $parser->getCss();
+ }
+}
diff --git a/vendor/oyejorge/less.php/composer.json b/vendor/oyejorge/less.php/composer.json
new file mode 100644
index 00000000..7724e3f2
--- /dev/null
+++ b/vendor/oyejorge/less.php/composer.json
@@ -0,0 +1,31 @@
+{
+ "name": "oyejorge/less.php",
+ "description": "PHP port of the Javascript version of LESS http://lesscss.org",
+ "keywords": [ "less", "css", "php", "stylesheet", "less.js", "lesscss" ],
+ "homepage": "http://lessphp.gpeasy.com",
+ "license": "Apache-2.0",
+ "authors": [
+ {
+ "name": "Josh Schmidt",
+ "homepage": "https://github.com/oyejorge"
+ },
+ {
+ "name": "Matt Agar",
+ "homepage": "https://github.com/agar"
+ },
+ {
+ "name": "Martin Jantošovič",
+ "homepage": "https://github.com/Mordred"
+ }
+ ],
+ "require": {
+ "PHP" : ">=5.3"
+ },
+ "autoload": {
+ "psr-0": { "Less": "lib/" },
+ "classmap": ["lessc.inc.php"]
+ },
+ "bin": [
+ "bin/lessc"
+ ]
+}
diff --git a/vendor/oyejorge/less.php/lessc.inc.php b/vendor/oyejorge/less.php/lessc.inc.php
new file mode 100644
index 00000000..c77a1c05
--- /dev/null
+++ b/vendor/oyejorge/less.php/lessc.inc.php
@@ -0,0 +1,268 @@
+<?php
+/**
+ *
+ * This file provides the part of lessphp API (https://github.com/leafo/lessphp)
+ * to be a drop-in replacement for following products:
+ * - Drupal 7, by the less module v3.0+ (https://drupal.org/project/less)
+ * - Symfony 2
+ *
+ */
+
+// Register autoloader for non-composer installations
+if (!class_exists('Less_Parser')) {
+ require_once dirname(__FILE__).'/lib/Less/Autoloader.php';
+ Less_Autoloader::register();
+}
+
+class lessc{
+
+ static public $VERSION = Less_Version::less_version;
+
+ public $importDir = '';
+ protected $allParsedFiles = array();
+ protected $libFunctions = array();
+ protected $registeredVars = array();
+ private $formatterName;
+
+ public function __construct($lessc=null, $sourceName=null) {}
+
+ public function setImportDir($dirs) {
+ $this->importDir = (array)$dirs;
+ }
+
+ public function addImportDir($dir){
+ $this->importDir = (array)$this->importDir;
+ $this->importDir[] = $dir;
+ }
+
+ public function setFormatter($name)
+ {
+ $this->formatterName = $name;
+ }
+
+ public function setPreserveComments($preserve) {}
+ public function registerFunction($name, $func) {
+ $this->libFunctions[$name] = $func;
+ }
+ public function unregisterFunction($name) {
+ unset($this->libFunctions[$name]);
+ }
+
+ public function setVariables($variables){
+ foreach( $variables as $name => $value ){
+ $this->setVariable( $name, $value );
+ }
+ }
+
+ public function setVariable($name, $value){
+ $this->registeredVars[$name] = $value;
+ }
+
+ public function unsetVariable($name){
+ unset( $this->registeredVars[$name] );
+ }
+
+ public function setOptions($options){
+ foreach( $options as $name => $value ){
+ $this->setOption( $name, $value);
+ }
+ }
+
+ public function setOption($name, $value){
+ $this->options[$name] = $value;
+ }
+
+ public function parse($buffer, $presets = array()){
+
+ $this->setVariables($presets);
+
+ $parser = new Less_Parser($this->getOptions());
+ $parser->setImportDirs($this->getImportDirs());
+ foreach ($this->libFunctions as $name => $func) {
+ $parser->registerFunction($name, $func);
+ }
+ $parser->parse($buffer);
+ if( count( $this->registeredVars ) ) $parser->ModifyVars( $this->registeredVars );
+
+ return $parser->getCss();
+ }
+
+ protected function getOptions(){
+ $options = array('relativeUrls'=>false);
+ switch($this->formatterName){
+ case 'compressed':
+ $options['compress'] = true;
+ break;
+ }
+ return $options;
+ }
+
+ protected function getImportDirs(){
+ $dirs_ = (array)$this->importDir;
+ $dirs = array();
+ foreach($dirs_ as $dir) {
+ $dirs[$dir] = '';
+ }
+ return $dirs;
+ }
+
+ public function compile($string, $name = null){
+
+ $oldImport = $this->importDir;
+ $this->importDir = (array)$this->importDir;
+
+ $this->allParsedFiles = array();
+
+ $parser = new Less_Parser($this->getOptions());
+ $parser->SetImportDirs($this->getImportDirs());
+ if( count( $this->registeredVars ) ){
+ $parser->ModifyVars( $this->registeredVars );
+ }
+ foreach ($this->libFunctions as $name => $func) {
+ $parser->registerFunction($name, $func);
+ }
+ $parser->parse($string);
+ $out = $parser->getCss();
+
+ $parsed = Less_Parser::AllParsedFiles();
+ foreach( $parsed as $file ){
+ $this->addParsedFile($file);
+ }
+
+ $this->importDir = $oldImport;
+
+ return $out;
+ }
+
+ public function compileFile($fname, $outFname = null) {
+ if (!is_readable($fname)) {
+ throw new Exception('load error: failed to find '.$fname);
+ }
+
+ $pi = pathinfo($fname);
+
+ $oldImport = $this->importDir;
+
+ $this->importDir = (array)$this->importDir;
+ $this->importDir[] = realpath($pi['dirname']).'/';
+
+ $this->allParsedFiles = array();
+ $this->addParsedFile($fname);
+
+ $parser = new Less_Parser($this->getOptions());
+ $parser->SetImportDirs($this->getImportDirs());
+ if( count( $this->registeredVars ) ) $parser->ModifyVars( $this->registeredVars );
+ foreach ($this->libFunctions as $name => $func) {
+ $parser->registerFunction($name, $func);
+ }
+ $parser->parseFile($fname);
+ $out = $parser->getCss();
+
+ $parsed = Less_Parser::AllParsedFiles();
+ foreach ($parsed as $file) {
+ $this->addParsedFile($file);
+ }
+
+ $this->importDir = $oldImport;
+
+ if ($outFname !== null) {
+ return file_put_contents($outFname, $out);
+ }
+
+ return $out;
+ }
+
+ public function checkedCompile($in, $out) {
+ if (!is_file($out) || filemtime($in) > filemtime($out)) {
+ $this->compileFile($in, $out);
+ return true;
+ }
+ return false;
+ }
+
+
+ /**
+ * Execute lessphp on a .less file or a lessphp cache structure
+ *
+ * The lessphp cache structure contains information about a specific
+ * less file having been parsed. It can be used as a hint for future
+ * calls to determine whether or not a rebuild is required.
+ *
+ * The cache structure contains two important keys that may be used
+ * externally:
+ *
+ * compiled: The final compiled CSS
+ * updated: The time (in seconds) the CSS was last compiled
+ *
+ * The cache structure is a plain-ol' PHP associative array and can
+ * be serialized and unserialized without a hitch.
+ *
+ * @param mixed $in Input
+ * @param bool $force Force rebuild?
+ * @return array lessphp cache structure
+ */
+ public function cachedCompile($in, $force = false) {
+ // assume no root
+ $root = null;
+
+ if (is_string($in)) {
+ $root = $in;
+ } elseif (is_array($in) and isset($in['root'])) {
+ if ($force or ! isset($in['files'])) {
+ // If we are forcing a recompile or if for some reason the
+ // structure does not contain any file information we should
+ // specify the root to trigger a rebuild.
+ $root = $in['root'];
+ } elseif (isset($in['files']) and is_array($in['files'])) {
+ foreach ($in['files'] as $fname => $ftime ) {
+ if (!file_exists($fname) or filemtime($fname) > $ftime) {
+ // One of the files we knew about previously has changed
+ // so we should look at our incoming root again.
+ $root = $in['root'];
+ break;
+ }
+ }
+ }
+ } else {
+ // TODO: Throw an exception? We got neither a string nor something
+ // that looks like a compatible lessphp cache structure.
+ return null;
+ }
+
+ if ($root !== null) {
+ // If we have a root value which means we should rebuild.
+ $out = array();
+ $out['root'] = $root;
+ $out['compiled'] = $this->compileFile($root);
+ $out['files'] = $this->allParsedFiles();
+ $out['updated'] = time();
+ return $out;
+ } else {
+ // No changes, pass back the structure
+ // we were given initially.
+ return $in;
+ }
+ }
+
+ public function ccompile( $in, $out, $less = null) {
+ if ($less === null) {
+ $less = new self;
+ }
+ return $less->checkedCompile($in, $out);
+ }
+
+ public static function cexecute($in, $force = false, $less = null) {
+ if ($less === null) {
+ $less = new self;
+ }
+ return $less->cachedCompile($in, $force);
+ }
+
+ public function allParsedFiles() {
+ return $this->allParsedFiles;
+ }
+
+ protected function addParsedFile($file) {
+ $this->allParsedFiles[realpath($file)] = filemtime($file);
+ }
+}
diff --git a/vendor/oyejorge/less.php/lib/Less/.easymin/ignore_prefixes b/vendor/oyejorge/less.php/lib/Less/.easymin/ignore_prefixes
new file mode 100644
index 00000000..ca953b29
--- /dev/null
+++ b/vendor/oyejorge/less.php/lib/Less/.easymin/ignore_prefixes
@@ -0,0 +1,2 @@
+.easymin
+Autoloader.php
diff --git a/vendor/oyejorge/less.php/lib/Less/Autoloader.php b/vendor/oyejorge/less.php/lib/Less/Autoloader.php
new file mode 100644
index 00000000..b6300c02
--- /dev/null
+++ b/vendor/oyejorge/less.php/lib/Less/Autoloader.php
@@ -0,0 +1,79 @@
+<?php
+
+/**
+ * Autoloader
+ *
+ * @package Less
+ * @subpackage autoload
+ */
+class Less_Autoloader {
+
+ /**
+ * Registered flag
+ *
+ * @var boolean
+ */
+ protected static $registered = false;
+
+ /**
+ * Library directory
+ *
+ * @var string
+ */
+ protected static $libDir;
+
+ /**
+ * Register the autoloader in the spl autoloader
+ *
+ * @return void
+ * @throws Exception If there was an error in registration
+ */
+ public static function register(){
+ if( self::$registered ){
+ return;
+ }
+
+ self::$libDir = dirname(__FILE__);
+
+ if(false === spl_autoload_register(array('Less_Autoloader', 'loadClass'))){
+ throw new Exception('Unable to register Less_Autoloader::loadClass as an autoloading method.');
+ }
+
+ self::$registered = true;
+ }
+
+ /**
+ * Unregisters the autoloader
+ *
+ * @return void
+ */
+ public static function unregister(){
+ spl_autoload_unregister(array('Less_Autoloader', 'loadClass'));
+ self::$registered = false;
+ }
+
+ /**
+ * Loads the class
+ *
+ * @param string $className The class to load
+ */
+ public static function loadClass($className){
+
+
+ // handle only package classes
+ if(strpos($className, 'Less_') !== 0){
+ return;
+ }
+
+ $className = substr($className,5);
+ $fileName = self::$libDir . DIRECTORY_SEPARATOR . str_replace('_', DIRECTORY_SEPARATOR, $className) . '.php';
+
+ if(file_exists($fileName)){
+ require $fileName;
+ return true;
+ }else{
+ throw new Exception('file not loadable '.$fileName);
+ }
+ }
+
+} \ No newline at end of file
diff --git a/vendor/oyejorge/less.php/lib/Less/Cache.php b/vendor/oyejorge/less.php/lib/Less/Cache.php
new file mode 100644
index 00000000..8c8be395
--- /dev/null
+++ b/vendor/oyejorge/less.php/lib/Less/Cache.php
@@ -0,0 +1,316 @@
+<?php
+
+require_once( dirname(__FILE__).'/Version.php');
+
+/**
+ * Utility for handling the generation and caching of css files
+ *
+ * @package Less
+ * @subpackage cache
+ *
+ */
+class Less_Cache{
+
+ // directory less.php can use for storing data
+ public static $cache_dir = false;
+
+ // prefix for the storing data
+ public static $prefix = 'lessphp_';
+
+ // prefix for the storing vars
+ public static $prefix_vars = 'lessphpvars_';
+
+ // specifies the number of seconds after which data created by less.php will be seen as 'garbage' and potentially cleaned up
+ public static $gc_lifetime = 604800;
+
+
+ /**
+ * Save and reuse the results of compiled less files.
+ * The first call to Get() will generate css and save it.
+ * Subsequent calls to Get() with the same arguments will return the same css filename
+ *
+ * @param array $less_files Array of .less files to compile
+ * @param array $parser_options Array of compiler options
+ * @param array $modify_vars Array of variables
+ * @return string Name of the css file
+ */
+ public static function Get( $less_files, $parser_options = array(), $modify_vars = array() ){
+
+
+ //check $cache_dir
+ if( isset($parser_options['cache_dir']) ){
+ Less_Cache::$cache_dir = $parser_options['cache_dir'];
+ }
+
+ if( empty(Less_Cache::$cache_dir) ){
+ throw new Exception('cache_dir not set');
+ }
+
+ if( isset($parser_options['prefix']) ){
+ Less_Cache::$prefix = $parser_options['prefix'];
+ }
+
+ if( empty(Less_Cache::$prefix) ){
+ throw new Exception('prefix not set');
+ }
+
+ if( isset($parser_options['prefix_vars']) ){
+ Less_Cache::$prefix_vars = $parser_options['prefix_vars'];
+ }
+
+ if( empty(Less_Cache::$prefix_vars) ){
+ throw new Exception('prefix_vars not set');
+ }
+
+ self::CheckCacheDir();
+ $less_files = (array)$less_files;
+
+
+ //create a file for variables
+ if( !empty($modify_vars) ){
+ $lessvars = Less_Parser::serializeVars($modify_vars);
+ $vars_file = Less_Cache::$cache_dir . Less_Cache::$prefix_vars . sha1($lessvars) . '.less';
+
+ if( !file_exists($vars_file) ){
+ file_put_contents($vars_file, $lessvars);
+ }
+
+ $less_files += array($vars_file => '/');
+ }
+
+
+ // generate name for compiled css file
+ $hash = md5(json_encode($less_files));
+ $list_file = Less_Cache::$cache_dir . Less_Cache::$prefix . $hash . '.list';
+
+
+ // check cached content
+ if( !isset($parser_options['use_cache']) || $parser_options['use_cache'] === true ){
+ if( file_exists($list_file) ){
+
+ self::ListFiles($list_file, $list, $cached_name);
+ $compiled_name = self::CompiledName($list);
+
+ // if $cached_name is the same as the $compiled name, don't regenerate
+ if( !$cached_name || $cached_name === $compiled_name ){
+
+ $output_file = self::OutputFile($compiled_name, $parser_options );
+
+ if( $output_file && file_exists($output_file) ){
+ @touch($list_file);
+ return basename($output_file); // for backwards compatibility, we just return the name of the file
+ }
+ }
+ }
+ }
+
+ $compiled = self::Cache( $less_files, $parser_options );
+ if( !$compiled ){
+ return false;
+ }
+
+ $compiled_name = self::CompiledName( $less_files );
+ $output_file = self::OutputFile($compiled_name, $parser_options );
+
+
+ //save the file list
+ $list = $less_files;
+ $list[] = $compiled_name;
+ $cache = implode("\n",$list);
+ file_put_contents( $list_file, $cache );
+
+
+ //save the css
+ file_put_contents( $output_file, $compiled );
+
+
+ //clean up
+ self::CleanCache();
+
+ return basename($output_file);
+ }
+
+ /**
+ * Force the compiler to regenerate the cached css file
+ *
+ * @param array $less_files Array of .less files to compile
+ * @param array $parser_options Array of compiler options
+ * @param array $modify_vars Array of variables
+ * @return string Name of the css file
+ */
+ public static function Regen( $less_files, $parser_options = array(), $modify_vars = array() ){
+ $parser_options['use_cache'] = false;
+ return self::Get( $less_files, $parser_options, $modify_vars );
+ }
+
+ public static function Cache( &$less_files, $parser_options = array() ){
+
+
+ // get less.php if it exists
+ $file = dirname(__FILE__) . '/Less.php';
+ if( file_exists($file) && !class_exists('Less_Parser') ){
+ require_once($file);
+ }
+
+ $parser_options['cache_dir'] = Less_Cache::$cache_dir;
+ $parser = new Less_Parser($parser_options);
+
+
+ // combine files
+ foreach($less_files as $file_path => $uri_or_less ){
+
+ //treat as less markup if there are newline characters
+ if( strpos($uri_or_less,"\n") !== false ){
+ $parser->Parse( $uri_or_less );
+ continue;
+ }
+
+ $parser->ParseFile( $file_path, $uri_or_less );
+ }
+
+ $compiled = $parser->getCss();
+
+
+ $less_files = $parser->allParsedFiles();
+
+ return $compiled;
+ }
+
+
+ private static function OutputFile( $compiled_name, $parser_options ){
+
+ //custom output file
+ if( !empty($parser_options['output']) ){
+
+ //relative to cache directory?
+ if( preg_match('#[\\\\/]#',$parser_options['output']) ){
+ return $parser_options['output'];
+ }
+
+ return Less_Cache::$cache_dir.$parser_options['output'];
+ }
+
+ return Less_Cache::$cache_dir.$compiled_name;
+ }
+
+
+ private static function CompiledName( $files ){
+
+ //save the file list
+ $temp = array(Less_Version::cache_version);
+ foreach($files as $file){
+ $temp[] = filemtime($file)."\t".filesize($file)."\t".$file;
+ }
+
+ return Less_Cache::$prefix.sha1(json_encode($temp)).'.css';
+ }
+
+
+ public static function SetCacheDir( $dir ){
+ Less_Cache::$cache_dir = $dir;
+ }
+
+ public static function CheckCacheDir(){
+
+ Less_Cache::$cache_dir = str_replace('\\','/',Less_Cache::$cache_dir);
+ Less_Cache::$cache_dir = rtrim(Less_Cache::$cache_dir,'/').'/';
+
+ if( !file_exists(Less_Cache::$cache_dir) ){
+ if( !mkdir(Less_Cache::$cache_dir) ){
+ throw new Less_Exception_Parser('Less.php cache directory couldn\'t be created: '.Less_Cache::$cache_dir);
+ }
+
+ }elseif( !is_dir(Less_Cache::$cache_dir) ){
+ throw new Less_Exception_Parser('Less.php cache directory doesn\'t exist: '.Less_Cache::$cache_dir);
+
+ }elseif( !is_writable(Less_Cache::$cache_dir) ){
+ throw new Less_Exception_Parser('Less.php cache directory isn\'t writable: '.Less_Cache::$cache_dir);
+
+ }
+
+ }
+
+
+ /**
+ * Delete unused less.php files
+ *
+ */
+ public static function CleanCache(){
+ static $clean = false;
+
+ if( $clean ){
+ return;
+ }
+
+ $files = scandir(Less_Cache::$cache_dir);
+ if( $files ){
+ $check_time = time() - self::$gc_lifetime;
+ foreach($files as $file){
+
+ // don't delete if the file wasn't created with less.php
+ if( strpos($file,Less_Cache::$prefix) !== 0 ){
+ continue;
+ }
+
+ $full_path = Less_Cache::$cache_dir . $file;
+
+ // make sure the file still exists
+ // css files may have already been deleted
+ if( !file_exists($full_path) ){
+ continue;
+ }
+ $mtime = filemtime($full_path);
+
+ // don't delete if it's a relatively new file
+ if( $mtime > $check_time ){
+ continue;
+ }
+
+ $parts = explode('.',$file);
+ $type = array_pop($parts);
+
+
+ // delete css files based on the list files
+ if( $type === 'css' ){
+ continue;
+ }
+
+
+ // delete the list file and associated css file
+ if( $type === 'list' ){
+ self::ListFiles($full_path, $list, $css_file_name);
+ if( $css_file_name ){
+ $css_file = Less_Cache::$cache_dir . $css_file_name;
+ if( file_exists($css_file) ){
+ unlink($css_file);
+ }
+ }
+ }
+
+ unlink($full_path);
+ }
+ }
+
+ $clean = true;
+ }
+
+
+ /**
+ * Get the list of less files and generated css file from a list file
+ *
+ */
+ static function ListFiles($list_file, &$list, &$css_file_name ){
+
+ $list = explode("\n",file_get_contents($list_file));
+
+ //pop the cached name that should match $compiled_name
+ $css_file_name = array_pop($list);
+
+ if( !preg_match('/^' . Less_Cache::$prefix . '[a-f0-9]+\.css$/',$css_file_name) ){
+ $list[] = $css_file_name;
+ $css_file_name = false;
+ }
+
+ }
+
+}
diff --git a/vendor/oyejorge/less.php/lib/Less/Colors.php b/vendor/oyejorge/less.php/lib/Less/Colors.php
new file mode 100644
index 00000000..ad3f31dc
--- /dev/null
+++ b/vendor/oyejorge/less.php/lib/Less/Colors.php
@@ -0,0 +1,170 @@
+<?php
+
+/**
+ * Utility for css colors
+ *
+ * @package Less
+ * @subpackage color
+ */
+class Less_Colors {
+
+ public static $colors = array(
+ 'aliceblue'=>'#f0f8ff',
+ 'antiquewhite'=>'#faebd7',
+ 'aqua'=>'#00ffff',
+ 'aquamarine'=>'#7fffd4',
+ 'azure'=>'#f0ffff',
+ 'beige'=>'#f5f5dc',
+ 'bisque'=>'#ffe4c4',
+ 'black'=>'#000000',
+ 'blanchedalmond'=>'#ffebcd',
+ 'blue'=>'#0000ff',
+ 'blueviolet'=>'#8a2be2',
+ 'brown'=>'#a52a2a',
+ 'burlywood'=>'#deb887',
+ 'cadetblue'=>'#5f9ea0',
+ 'chartreuse'=>'#7fff00',
+ 'chocolate'=>'#d2691e',
+ 'coral'=>'#ff7f50',
+ 'cornflowerblue'=>'#6495ed',
+ 'cornsilk'=>'#fff8dc',
+ 'crimson'=>'#dc143c',
+ 'cyan'=>'#00ffff',
+ 'darkblue'=>'#00008b',
+ 'darkcyan'=>'#008b8b',
+ 'darkgoldenrod'=>'#b8860b',
+ 'darkgray'=>'#a9a9a9',
+ 'darkgrey'=>'#a9a9a9',
+ 'darkgreen'=>'#006400',
+ 'darkkhaki'=>'#bdb76b',
+ 'darkmagenta'=>'#8b008b',
+ 'darkolivegreen'=>'#556b2f',
+ 'darkorange'=>'#ff8c00',
+ 'darkorchid'=>'#9932cc',
+ 'darkred'=>'#8b0000',
+ 'darksalmon'=>'#e9967a',
+ 'darkseagreen'=>'#8fbc8f',
+ 'darkslateblue'=>'#483d8b',
+ 'darkslategray'=>'#2f4f4f',
+ 'darkslategrey'=>'#2f4f4f',
+ 'darkturquoise'=>'#00ced1',
+ 'darkviolet'=>'#9400d3',
+ 'deeppink'=>'#ff1493',
+ 'deepskyblue'=>'#00bfff',
+ 'dimgray'=>'#696969',
+ 'dimgrey'=>'#696969',
+ 'dodgerblue'=>'#1e90ff',
+ 'firebrick'=>'#b22222',
+ 'floralwhite'=>'#fffaf0',
+ 'forestgreen'=>'#228b22',
+ 'fuchsia'=>'#ff00ff',
+ 'gainsboro'=>'#dcdcdc',
+ 'ghostwhite'=>'#f8f8ff',
+ 'gold'=>'#ffd700',
+ 'goldenrod'=>'#daa520',
+ 'gray'=>'#808080',
+ 'grey'=>'#808080',
+ 'green'=>'#008000',
+ 'greenyellow'=>'#adff2f',
+ 'honeydew'=>'#f0fff0',
+ 'hotpink'=>'#ff69b4',
+ 'indianred'=>'#cd5c5c',
+ 'indigo'=>'#4b0082',
+ 'ivory'=>'#fffff0',
+ 'khaki'=>'#f0e68c',
+ 'lavender'=>'#e6e6fa',
+ 'lavenderblush'=>'#fff0f5',
+ 'lawngreen'=>'#7cfc00',
+ 'lemonchiffon'=>'#fffacd',
+ 'lightblue'=>'#add8e6',
+ 'lightcoral'=>'#f08080',
+ 'lightcyan'=>'#e0ffff',
+ 'lightgoldenrodyellow'=>'#fafad2',
+ 'lightgray'=>'#d3d3d3',
+ 'lightgrey'=>'#d3d3d3',
+ 'lightgreen'=>'#90ee90',
+ 'lightpink'=>'#ffb6c1',
+ 'lightsalmon'=>'#ffa07a',
+ 'lightseagreen'=>'#20b2aa',
+ 'lightskyblue'=>'#87cefa',
+ 'lightslategray'=>'#778899',
+ 'lightslategrey'=>'#778899',
+ 'lightsteelblue'=>'#b0c4de',
+ 'lightyellow'=>'#ffffe0',
+ 'lime'=>'#00ff00',
+ 'limegreen'=>'#32cd32',
+ 'linen'=>'#faf0e6',
+ 'magenta'=>'#ff00ff',
+ 'maroon'=>'#800000',
+ 'mediumaquamarine'=>'#66cdaa',
+ 'mediumblue'=>'#0000cd',
+ 'mediumorchid'=>'#ba55d3',
+ 'mediumpurple'=>'#9370d8',
+ 'mediumseagreen'=>'#3cb371',
+ 'mediumslateblue'=>'#7b68ee',
+ 'mediumspringgreen'=>'#00fa9a',
+ 'mediumturquoise'=>'#48d1cc',
+ 'mediumvioletred'=>'#c71585',
+ 'midnightblue'=>'#191970',
+ 'mintcream'=>'#f5fffa',
+ 'mistyrose'=>'#ffe4e1',
+ 'moccasin'=>'#ffe4b5',
+ 'navajowhite'=>'#ffdead',
+ 'navy'=>'#000080',
+ 'oldlace'=>'#fdf5e6',
+ 'olive'=>'#808000',
+ 'olivedrab'=>'#6b8e23',
+ 'orange'=>'#ffa500',
+ 'orangered'=>'#ff4500',
+ 'orchid'=>'#da70d6',
+ 'palegoldenrod'=>'#eee8aa',
+ 'palegreen'=>'#98fb98',
+ 'paleturquoise'=>'#afeeee',
+ 'palevioletred'=>'#d87093',
+ 'papayawhip'=>'#ffefd5',
+ 'peachpuff'=>'#ffdab9',
+ 'peru'=>'#cd853f',
+ 'pink'=>'#ffc0cb',
+ 'plum'=>'#dda0dd',
+ 'powderblue'=>'#b0e0e6',
+ 'purple'=>'#800080',
+ 'red'=>'#ff0000',
+ 'rosybrown'=>'#bc8f8f',
+ 'royalblue'=>'#4169e1',
+ 'saddlebrown'=>'#8b4513',
+ 'salmon'=>'#fa8072',
+ 'sandybrown'=>'#f4a460',
+ 'seagreen'=>'#2e8b57',
+ 'seashell'=>'#fff5ee',
+ 'sienna'=>'#a0522d',
+ 'silver'=>'#c0c0c0',
+ 'skyblue'=>'#87ceeb',
+ 'slateblue'=>'#6a5acd',
+ 'slategray'=>'#708090',
+ 'slategrey'=>'#708090',
+ 'snow'=>'#fffafa',
+ 'springgreen'=>'#00ff7f',
+ 'steelblue'=>'#4682b4',
+ 'tan'=>'#d2b48c',
+ 'teal'=>'#008080',
+ 'thistle'=>'#d8bfd8',
+ 'tomato'=>'#ff6347',
+ 'turquoise'=>'#40e0d0',
+ 'violet'=>'#ee82ee',
+ 'wheat'=>'#f5deb3',
+ 'white'=>'#ffffff',
+ 'whitesmoke'=>'#f5f5f5',
+ 'yellow'=>'#ffff00',
+ 'yellowgreen'=>'#9acd32'
+ );
+
+ public static function hasOwnProperty($color) {
+ return isset(self::$colors[$color]);
+ }
+
+
+ public static function color($color) {
+ return self::$colors[$color];
+ }
+
+}
diff --git a/vendor/oyejorge/less.php/lib/Less/Configurable.php b/vendor/oyejorge/less.php/lib/Less/Configurable.php
new file mode 100644
index 00000000..aa7fd3eb
--- /dev/null
+++ b/vendor/oyejorge/less.php/lib/Less/Configurable.php
@@ -0,0 +1,69 @@
+<?php
+
+/**
+ * Configurable
+ *
+ * @package Less
+ * @subpackage Core
+ */
+abstract class Less_Configurable {
+
+ /**
+ * Array of options
+ *
+ * @var array
+ */
+ protected $options = array();
+
+ /**
+ * Array of default options
+ *
+ * @var array
+ */
+ protected $defaultOptions = array();
+
+
+ /**
+ * Set options
+ *
+ * If $options is an object it will be converted into an array by called
+ * it's toArray method.
+ *
+ * @throws Exception
+ * @param array|object $options
+ *
+ */
+ public function setOptions($options){
+ $options = array_intersect_key($options,$this->defaultOptions);
+ $this->options = array_merge($this->defaultOptions, $this->options, $options);
+ }
+
+
+ /**
+ * Get an option value by name
+ *
+ * If the option is empty or not set a NULL value will be returned.
+ *
+ * @param string $name
+ * @param mixed $default Default value if confiuration of $name is not present
+ * @return mixed
+ */
+ public function getOption($name, $default = null){
+ if(isset($this->options[$name])){
+ return $this->options[$name];
+ }
+ return $default;
+ }
+
+
+ /**
+ * Set an option
+ *
+ * @param string $name
+ * @param mixed $value
+ */
+ public function setOption($name, $value){
+ $this->options[$name] = $value;
+ }
+
+} \ No newline at end of file
diff --git a/vendor/oyejorge/less.php/lib/Less/Environment.php b/vendor/oyejorge/less.php/lib/Less/Environment.php
new file mode 100644
index 00000000..b2203014
--- /dev/null
+++ b/vendor/oyejorge/less.php/lib/Less/Environment.php
@@ -0,0 +1,166 @@
+<?php
+
+
+/**
+ * Environment
+ *
+ * @package Less
+ * @subpackage environment
+ */
+class Less_Environment{
+
+ //public $paths = array(); // option - unmodified - paths to search for imports on
+ //public static $files = array(); // list of files that have been imported, used for import-once
+ //public $rootpath; // option - rootpath to append to URL's
+ //public static $strictImports = null; // option -
+ //public $insecure; // option - whether to allow imports from insecure ssl hosts
+ //public $processImports; // option - whether to process imports. if false then imports will not be imported
+ //public $javascriptEnabled; // option - whether JavaScript is enabled. if undefined, defaults to true
+ //public $useFileCache; // browser only - whether to use the per file session cache
+ public $currentFileInfo; // information about the current file - for error reporting and importing and making urls relative etc.
+
+ public $importMultiple = false; // whether we are currently importing multiple copies
+
+
+ /**
+ * @var array
+ */
+ public $frames = array();
+
+ /**
+ * @var array
+ */
+ public $mediaBlocks = array();
+
+ /**
+ * @var array
+ */
+ public $mediaPath = array();
+
+ public static $parensStack = 0;
+
+ public static $tabLevel = 0;
+
+ public static $lastRule = false;
+
+ public static $_outputMap;
+
+ public static $mixin_stack = 0;
+
+ /**
+ * @var array
+ */
+ public $functions = array();
+
+
+ public function Init(){
+
+ self::$parensStack = 0;
+ self::$tabLevel = 0;
+ self::$lastRule = false;
+ self::$mixin_stack = 0;
+
+ if( Less_Parser::$options['compress'] ){
+
+ Less_Environment::$_outputMap = array(
+ ',' => ',',
+ ': ' => ':',
+ '' => '',
+ ' ' => ' ',
+ ':' => ' :',
+ '+' => '+',
+ '~' => '~',
+ '>' => '>',
+ '|' => '|',
+ '^' => '^',
+ '^^' => '^^'
+ );
+
+ }else{
+
+ Less_Environment::$_outputMap = array(
+ ',' => ', ',
+ ': ' => ': ',
+ '' => '',
+ ' ' => ' ',
+ ':' => ' :',
+ '+' => ' + ',
+ '~' => ' ~ ',
+ '>' => ' > ',
+ '|' => '|',
+ '^' => ' ^ ',
+ '^^' => ' ^^ '
+ );
+
+ }
+ }
+
+
+ public function copyEvalEnv($frames = array() ){
+ $new_env = new Less_Environment();
+ $new_env->frames = $frames;
+ return $new_env;
+ }
+
+
+ public static function isMathOn(){
+ return !Less_Parser::$options['strictMath'] || Less_Environment::$parensStack;
+ }
+
+ public static function isPathRelative($path){
+ return !preg_match('/^(?:[a-z-]+:|\/)/',$path);
+ }
+
+
+ /**
+ * Canonicalize a path by resolving references to '/./', '/../'
+ * Does not remove leading "../"
+ * @param string path or url
+ * @return string Canonicalized path
+ *
+ */
+ public static function normalizePath($path){
+
+ $segments = explode('/',$path);
+ $segments = array_reverse($segments);
+
+ $path = array();
+ $path_len = 0;
+
+ while( $segments ){
+ $segment = array_pop($segments);
+ switch( $segment ) {
+
+ case '.':
+ break;
+
+ case '..':
+ if( !$path_len || ( $path[$path_len-1] === '..') ){
+ $path[] = $segment;
+ $path_len++;
+ }else{
+ array_pop($path);
+ $path_len--;
+ }
+ break;
+
+ default:
+ $path[] = $segment;
+ $path_len++;
+ break;
+ }
+ }
+
+ return implode('/',$path);
+ }
+
+
+ public function unshiftFrame($frame){
+ array_unshift($this->frames, $frame);
+ }
+
+ public function shiftFrame(){
+ return array_shift($this->frames);
+ }
+
+}
diff --git a/vendor/oyejorge/less.php/lib/Less/Exception/Chunk.php b/vendor/oyejorge/less.php/lib/Less/Exception/Chunk.php
new file mode 100644
index 00000000..9a8b829e
--- /dev/null
+++ b/vendor/oyejorge/less.php/lib/Less/Exception/Chunk.php
@@ -0,0 +1,203 @@
+<?php
+
+/**
+ * Chunk Exception
+ *
+ * @package Less
+ * @subpackage exception
+ */
+class Less_Exception_Chunk extends Less_Exception_Parser{
+
+
+ protected $parserCurrentIndex = 0;
+
+ protected $emitFrom = 0;
+
+ protected $input_len;
+
+
+ /**
+ * Constructor
+ *
+ * @param string $input
+ * @param Exception $previous Previous exception
+ * @param integer $index The current parser index
+ * @param Less_FileInfo|string $currentFile The file
+ * @param integer $code The exception code
+ */
+ public function __construct($input, Exception $previous = null, $index = null, $currentFile = null, $code = 0){
+
+ $this->message = 'ParseError: Unexpected input'; //default message
+
+ $this->index = $index;
+
+ $this->currentFile = $currentFile;
+
+ $this->input = $input;
+ $this->input_len = strlen($input);
+
+ $this->Chunks();
+ $this->genMessage();
+ }
+
+
+ /**
+ * See less.js chunks()
+ * We don't actually need the chunks
+ *
+ */
+ protected function Chunks(){
+ $level = 0;
+ $parenLevel = 0;
+ $lastMultiCommentEndBrace = null;
+ $lastOpening = null;
+ $lastMultiComment = null;
+ $lastParen = null;
+
+ for( $this->parserCurrentIndex = 0; $this->parserCurrentIndex < $this->input_len; $this->parserCurrentIndex++ ){
+ $cc = $this->CharCode($this->parserCurrentIndex);
+ if ((($cc >= 97) && ($cc <= 122)) || ($cc < 34)) {
+ // a-z or whitespace
+ continue;
+ }
+
+ switch ($cc) {
+
+ // (
+ case 40:
+ $parenLevel++;
+ $lastParen = $this->parserCurrentIndex;
+ continue;
+
+ // )
+ case 41:
+ $parenLevel--;
+ if( $parenLevel < 0 ){
+ return $this->fail("missing opening `(`");
+ }
+ continue;
+
+ // ;
+ case 59:
+ //if (!$parenLevel) { $this->emitChunk(); }
+ continue;
+
+ // {
+ case 123:
+ $level++;
+ $lastOpening = $this->parserCurrentIndex;
+ continue;
+
+ // }
+ case 125:
+ $level--;
+ if( $level < 0 ){
+ return $this->fail("missing opening `{`");
+
+ }
+ //if (!$level && !$parenLevel) { $this->emitChunk(); }
+ continue;
+ // \
+ case 92:
+ if ($this->parserCurrentIndex < $this->input_len - 1) { $this->parserCurrentIndex++; continue; }
+ return $this->fail("unescaped `\\`");
+
+ // ", ' and `
+ case 34:
+ case 39:
+ case 96:
+ $matched = 0;
+ $currentChunkStartIndex = $this->parserCurrentIndex;
+ for ($this->parserCurrentIndex = $this->parserCurrentIndex + 1; $this->parserCurrentIndex < $this->input_len; $this->parserCurrentIndex++) {
+ $cc2 = $this->CharCode($this->parserCurrentIndex);
+ if ($cc2 > 96) { continue; }
+ if ($cc2 == $cc) { $matched = 1; break; }
+ if ($cc2 == 92) { // \
+ if ($this->parserCurrentIndex == $this->input_len - 1) {
+ return $this->fail("unescaped `\\`");
+ }
+ $this->parserCurrentIndex++;
+ }
+ }
+ if ($matched) { continue; }
+ return $this->fail("unmatched `" + chr($cc) + "`", $currentChunkStartIndex);
+
+ // /, check for comment
+ case 47:
+ if ($parenLevel || ($this->parserCurrentIndex == $this->input_len - 1)) { continue; }
+ $cc2 = $this->CharCode($this->parserCurrentIndex+1);
+ if ($cc2 == 47) {
+ // //, find lnfeed
+ for ($this->parserCurrentIndex = $this->parserCurrentIndex + 2; $this->parserCurrentIndex < $this->input_len; $this->parserCurrentIndex++) {
+ $cc2 = $this->CharCode($this->parserCurrentIndex);
+ if (($cc2 <= 13) && (($cc2 == 10) || ($cc2 == 13))) { break; }
+ }
+ } else if ($cc2 == 42) {
+ // /*, find */
+ $lastMultiComment = $currentChunkStartIndex = $this->parserCurrentIndex;
+ for ($this->parserCurrentIndex = $this->parserCurrentIndex + 2; $this->parserCurrentIndex < $this->input_len - 1; $this->parserCurrentIndex++) {
+ $cc2 = $this->CharCode($this->parserCurrentIndex);
+ if ($cc2 == 125) { $lastMultiCommentEndBrace = $this->parserCurrentIndex; }
+ if ($cc2 != 42) { continue; }
+ if ($this->CharCode($this->parserCurrentIndex+1) == 47) { break; }
+ }
+ if ($this->parserCurrentIndex == $this->input_len - 1) {
+ return $this->fail("missing closing `*/`", $currentChunkStartIndex);
+ }
+ }
+ continue;
+
+ // *, check for unmatched */
+ case 42:
+ if (($this->parserCurrentIndex < $this->input_len - 1) && ($this->CharCode($this->parserCurrentIndex+1) == 47)) {
+ return $this->fail("unmatched `/*`");
+ }
+ continue;
+ }
+ }
+
+ if( $level !== 0 ){
+ if( ($lastMultiComment > $lastOpening) && ($lastMultiCommentEndBrace > $lastMultiComment) ){
+ return $this->fail("missing closing `}` or `*/`", $lastOpening);
+ } else {
+ return $this->fail("missing closing `}`", $lastOpening);
+ }
+ } else if ( $parenLevel !== 0 ){
+ return $this->fail("missing closing `)`", $lastParen);
+ }
+
+
+ //chunk didn't fail
+
+
+ //$this->emitChunk(true);
+ }
+
+ public function CharCode($pos){
+ return ord($this->input[$pos]);
+ }
+
+
+ public function fail( $msg, $index = null ){
+
+ if( !$index ){
+ $this->index = $this->parserCurrentIndex;
+ }else{
+ $this->index = $index;
+ }
+ $this->message = 'ParseError: '.$msg;
+ }
+
+
+ /*
+ function emitChunk( $force = false ){
+ $len = $this->parserCurrentIndex - $this->emitFrom;
+ if ((($len < 512) && !$force) || !$len) {
+ return;
+ }
+ $chunks[] = substr($this->input, $this->emitFrom, $this->parserCurrentIndex + 1 - $this->emitFrom );
+ $this->emitFrom = $this->parserCurrentIndex + 1;
+ }
+ */
+
+}
diff --git a/vendor/oyejorge/less.php/lib/Less/Exception/Compiler.php b/vendor/oyejorge/less.php/lib/Less/Exception/Compiler.php
new file mode 100644
index 00000000..713e030d
--- /dev/null
+++ b/vendor/oyejorge/less.php/lib/Less/Exception/Compiler.php
@@ -0,0 +1,11 @@
+<?php
+
+/**
+ * Compiler Exception
+ *
+ * @package Less
+ * @subpackage exception
+ */
+class Less_Exception_Compiler extends Less_Exception_Parser{
+
+} \ No newline at end of file
diff --git a/vendor/oyejorge/less.php/lib/Less/Exception/Parser.php b/vendor/oyejorge/less.php/lib/Less/Exception/Parser.php
new file mode 100644
index 00000000..f96b23c8
--- /dev/null
+++ b/vendor/oyejorge/less.php/lib/Less/Exception/Parser.php
@@ -0,0 +1,125 @@
+<?php
+
+/**
+ * Parser Exception
+ *
+ * @package Less
+ * @subpackage exception
+ */
+class Less_Exception_Parser extends Exception{
+
+ /**
+ * The current file
+ *
+ * @var Less_ImportedFile
+ */
+ public $currentFile;
+
+ /**
+ * The current parser index
+ *
+ * @var integer
+ */
+ public $index;
+
+ protected $input;
+
+ protected $details = array();
+
+
+ /**
+ * Constructor
+ *
+ * @param string $message
+ * @param Exception $previous Previous exception
+ * @param integer $index The current parser index
+ * @param Less_FileInfo|string $currentFile The file
+ * @param integer $code The exception code
+ */
+ public function __construct($message = null, Exception $previous = null, $index = null, $currentFile = null, $code = 0){
+
+ if (PHP_VERSION_ID < 50300) {
+ $this->previous = $previous;
+ parent::__construct($message, $code);
+ } else {
+ parent::__construct($message, $code, $previous);
+ }
+
+ $this->currentFile = $currentFile;
+ $this->index = $index;
+
+ $this->genMessage();
+ }
+
+
+ protected function getInput(){
+
+ if( !$this->input && $this->currentFile && $this->currentFile['filename'] && file_exists($this->currentFile['filename']) ){
+ $this->input = file_get_contents( $this->currentFile['filename'] );
+ }
+ }
+
+
+
+ /**
+ * Converts the exception to string
+ *
+ * @return string
+ */
+ public function genMessage(){
+
+ if( $this->currentFile && $this->currentFile['filename'] ){
+ $this->message .= ' in '.basename($this->currentFile['filename']);
+ }
+
+ if( $this->index !== null ){
+ $this->getInput();
+ if( $this->input ){
+ $line = self::getLineNumber();
+ $this->message .= ' on line '.$line.', column '.self::getColumn();
+
+ $lines = explode("\n",$this->input);
+
+ $count = count($lines);
+ $start_line = max(0, $line-3);
+ $last_line = min($count, $start_line+6);
+ $num_len = strlen($last_line);
+ for( $i = $start_line; $i < $last_line; $i++ ){
+ $this->message .= "\n".str_pad($i+1,$num_len,'0',STR_PAD_LEFT).'| '.$lines[$i];
+ }
+ }
+ }
+
+ }
+
+ /**
+ * Returns the line number the error was encountered
+ *
+ * @return integer
+ */
+ public function getLineNumber(){
+ if( $this->index ){
+ // https://bugs.php.net/bug.php?id=49790
+ if (ini_get("mbstring.func_overload")) {
+ return substr_count(substr($this->input, 0, $this->index), "\n") + 1;
+ } else {
+ return substr_count($this->input, "\n", 0, $this->index) + 1;
+ }
+ }
+ return 1;
+ }
+
+
+ /**
+ * Returns the column the error was encountered
+ *
+ * @return integer
+ */
+ public function getColumn(){
+
+ $part = substr($this->input, 0, $this->index);
+ $pos = strrpos($part,"\n");
+ return $this->index - $pos;
+ }
+
+}
diff --git a/vendor/oyejorge/less.php/lib/Less/Functions.php b/vendor/oyejorge/less.php/lib/Less/Functions.php
new file mode 100644
index 00000000..419bee32
--- /dev/null
+++ b/vendor/oyejorge/less.php/lib/Less/Functions.php
@@ -0,0 +1,1183 @@
+<?php
+
+/**
+ * Builtin functions
+ *
+ * @package Less
+ * @subpackage function
+ * @see http://lesscss.org/functions/
+ */
+class Less_Functions{
+
+ public $env;
+ public $currentFileInfo;
+
+ function __construct($env, $currentFileInfo = null ){
+ $this->env = $env;
+ $this->currentFileInfo = $currentFileInfo;
+ }
+
+ /**
+ * @param string $op
+ */
+ public static function operate( $op, $a, $b ){
+ switch ($op) {
+ case '+': return $a + $b;
+ case '-': return $a - $b;
+ case '*': return $a * $b;
+ case '/': return $a / $b;
+ }
+ }
+
+ public static function clamp($val, $max = 1){
+ return min( max($val, 0), $max);
+ }
+
+ public static function fround( $value ){
+
+ if( $value === 0 ){
+ return $value;
+ }
+
+ if( Less_Parser::$options['numPrecision'] ){
+ $p = pow(10, Less_Parser::$options['numPrecision']);
+ return round( $value * $p) / $p;
+ }
+ return $value;
+ }
+
+ public static function number($n){
+
+ if ($n instanceof Less_Tree_Dimension) {
+ return floatval( $n->unit->is('%') ? $n->value / 100 : $n->value);
+ } else if (is_numeric($n)) {
+ return $n;
+ } else {
+ throw new Less_Exception_Compiler("color functions take numbers as parameters");
+ }
+ }
+
+ public static function scaled($n, $size = 255 ){
+ if( $n instanceof Less_Tree_Dimension && $n->unit->is('%') ){
+ return (float)$n->value * $size / 100;
+ } else {
+ return Less_Functions::number($n);
+ }
+ }
+
+ public function rgb ($r = null, $g = null, $b = null){
+ if (is_null($r) || is_null($g) || is_null($b)) {
+ throw new Less_Exception_Compiler("rgb expects three parameters");
+ }
+ return $this->rgba($r, $g, $b, 1.0);
+ }
+
+ public function rgba($r = null, $g = null, $b = null, $a = null){
+ $rgb = array($r, $g, $b);
+ $rgb = array_map(array('Less_Functions','scaled'),$rgb);
+
+ $a = self::number($a);
+ return new Less_Tree_Color($rgb, $a);
+ }
+
+ public function hsl($h, $s, $l){
+ return $this->hsla($h, $s, $l, 1.0);
+ }
+
+ public function hsla($h, $s, $l, $a){
+
+ $h = fmod(self::number($h), 360) / 360; // Classic % operator will change float to int
+ $s = self::clamp(self::number($s));
+ $l = self::clamp(self::number($l));
+ $a = self::clamp(self::number($a));
+
+ $m2 = $l <= 0.5 ? $l * ($s + 1) : $l + $s - $l * $s;
+
+ $m1 = $l * 2 - $m2;
+
+ return $this->rgba( self::hsla_hue($h + 1/3, $m1, $m2) * 255,
+ self::hsla_hue($h, $m1, $m2) * 255,
+ self::hsla_hue($h - 1/3, $m1, $m2) * 255,
+ $a);
+ }
+
+ /**
+ * @param double $h
+ */
+ public function hsla_hue($h, $m1, $m2){
+ $h = $h < 0 ? $h + 1 : ($h > 1 ? $h - 1 : $h);
+ if ($h * 6 < 1) return $m1 + ($m2 - $m1) * $h * 6;
+ else if ($h * 2 < 1) return $m2;
+ else if ($h * 3 < 2) return $m1 + ($m2 - $m1) * (2/3 - $h) * 6;
+ else return $m1;
+ }
+
+ public function hsv($h, $s, $v) {
+ return $this->hsva($h, $s, $v, 1.0);
+ }
+
+ /**
+ * @param double $a
+ */
+ public function hsva($h, $s, $v, $a) {
+ $h = ((Less_Functions::number($h) % 360) / 360 ) * 360;
+ $s = Less_Functions::number($s);
+ $v = Less_Functions::number($v);
+ $a = Less_Functions::number($a);
+
+ $i = floor(($h / 60) % 6);
+ $f = ($h / 60) - $i;
+
+ $vs = array( $v,
+ $v * (1 - $s),
+ $v * (1 - $f * $s),
+ $v * (1 - (1 - $f) * $s));
+
+ $perm = array(array(0, 3, 1),
+ array(2, 0, 1),
+ array(1, 0, 3),
+ array(1, 2, 0),
+ array(3, 1, 0),
+ array(0, 1, 2));
+
+ return $this->rgba($vs[$perm[$i][0]] * 255,
+ $vs[$perm[$i][1]] * 255,
+ $vs[$perm[$i][2]] * 255,
+ $a);
+ }
+
+ public function hue($color = null){
+ if (!$color instanceof Less_Tree_Color) {
+ throw new Less_Exception_Compiler('The first argument to hue must be a color' . ($color instanceof Less_Tree_Expression ? ' (did you forgot commas?)' : '') );
+ }
+
+ $c = $color->toHSL();
+ return new Less_Tree_Dimension(Less_Parser::round($c['h']));
+ }
+
+ public function saturation($color = null){
+ if (!$color instanceof Less_Tree_Color) {
+ throw new Less_Exception_Compiler('The first argument to saturation must be a color' . ($color instanceof Less_Tree_Expression ? ' (did you forgot commas?)' : '') );
+ }
+
+ $c = $color->toHSL();
+ return new Less_Tree_Dimension(Less_Parser::round($c['s'] * 100), '%');
+ }
+
+ public function lightness($color = null){
+ if (!$color instanceof Less_Tree_Color) {
+ throw new Less_Exception_Compiler('The first argument to lightness must be a color' . ($color instanceof Less_Tree_Expression ? ' (did you forgot commas?)' : '') );
+ }
+
+ $c = $color->toHSL();
+ return new Less_Tree_Dimension(Less_Parser::round($c['l'] * 100), '%');
+ }
+
+ public function hsvhue( $color = null ){
+ if (!$color instanceof Less_Tree_Color) {
+ throw new Less_Exception_Compiler('The first argument to hsvhue must be a color' . ($color instanceof Less_Tree_Expression ? ' (did you forgot commas?)' : '') );
+ }
+
+ $hsv = $color->toHSV();
+ return new Less_Tree_Dimension( Less_Parser::round($hsv['h']) );
+ }
+
+
+ public function hsvsaturation( $color = null ){
+ if (!$color instanceof Less_Tree_Color) {
+ throw new Less_Exception_Compiler('The first argument to hsvsaturation must be a color' . ($color instanceof Less_Tree_Expression ? ' (did you forgot commas?)' : '') );
+ }
+
+ $hsv = $color->toHSV();
+ return new Less_Tree_Dimension( Less_Parser::round($hsv['s'] * 100), '%' );
+ }
+
+ public function hsvvalue( $color = null ){
+ if (!$color instanceof Less_Tree_Color) {
+ throw new Less_Exception_Compiler('The first argument to hsvvalue must be a color' . ($color instanceof Less_Tree_Expression ? ' (did you forgot commas?)' : '') );
+ }
+
+ $hsv = $color->toHSV();
+ return new Less_Tree_Dimension( Less_Parser::round($hsv['v'] * 100), '%' );
+ }
+
+ public function red($color = null) {
+ if (!$color instanceof Less_Tree_Color) {
+ throw new Less_Exception_Compiler('The first argument to red must be a color' . ($color instanceof Less_Tree_Expression ? ' (did you forgot commas?)' : '') );
+ }
+
+ return new Less_Tree_Dimension( $color->rgb[0] );
+ }
+
+ public function green($color = null) {
+ if (!$color instanceof Less_Tree_Color) {
+ throw new Less_Exception_Compiler('The first argument to green must be a color' . ($color instanceof Less_Tree_Expression ? ' (did you forgot commas?)' : '') );
+ }
+
+ return new Less_Tree_Dimension( $color->rgb[1] );
+ }
+
+ public function blue($color = null) {
+ if (!$color instanceof Less_Tree_Color) {
+ throw new Less_Exception_Compiler('The first argument to blue must be a color' . ($color instanceof Less_Tree_Expression ? ' (did you forgot commas?)' : '') );
+ }
+
+ return new Less_Tree_Dimension( $color->rgb[2] );
+ }
+
+ public function alpha($color = null){
+ if (!$color instanceof Less_Tree_Color) {
+ throw new Less_Exception_Compiler('The first argument to alpha must be a color' . ($color instanceof Less_Tree_Expression ? ' (did you forgot commas?)' : '') );
+ }
+
+ $c = $color->toHSL();
+ return new Less_Tree_Dimension($c['a']);
+ }
+
+ public function luma ($color = null) {
+ if (!$color instanceof Less_Tree_Color) {
+ throw new Less_Exception_Compiler('The first argument to luma must be a color' . ($color instanceof Less_Tree_Expression ? ' (did you forgot commas?)' : '') );
+ }
+
+ return new Less_Tree_Dimension(Less_Parser::round( $color->luma() * $color->alpha * 100), '%');
+ }
+
+ public function luminance( $color = null ){
+ if (!$color instanceof Less_Tree_Color) {
+ throw new Less_Exception_Compiler('The first argument to luminance must be a color' . ($color instanceof Less_Tree_Expression ? ' (did you forgot commas?)' : '') );
+ }
+
+ $luminance =
+ (0.2126 * $color->rgb[0] / 255)
+ + (0.7152 * $color->rgb[1] / 255)
+ + (0.0722 * $color->rgb[2] / 255);
+
+ return new Less_Tree_Dimension(Less_Parser::round( $luminance * $color->alpha * 100), '%');
+ }
+
+ public function saturate($color = null, $amount = null){
+ // filter: saturate(3.2);
+ // should be kept as is, so check for color
+ if ($color instanceof Less_Tree_Dimension) {
+ return null;
+ }
+
+ if (!$color instanceof Less_Tree_Color) {
+ throw new Less_Exception_Compiler('The first argument to saturate must be a color' . ($color instanceof Less_Tree_Expression ? ' (did you forgot commas?)' : '') );
+ }
+ if (!$amount instanceof Less_Tree_Dimension) {
+ throw new Less_Exception_Compiler('The second argument to saturate must be a percentage' . ($amount instanceof Less_Tree_Expression ? ' (did you forgot commas?)' : '') );
+ }
+
+ $hsl = $color->toHSL();
+
+ $hsl['s'] += $amount->value / 100;
+ $hsl['s'] = self::clamp($hsl['s']);
+
+ return $this->hsla($hsl['h'], $hsl['s'], $hsl['l'], $hsl['a']);
+ }
+
+ /**
+ * @param Less_Tree_Dimension $amount
+ */
+ public function desaturate($color = null, $amount = null){
+ if (!$color instanceof Less_Tree_Color) {
+ throw new Less_Exception_Compiler('The first argument to desaturate must be a color' . ($color instanceof Less_Tree_Expression ? ' (did you forgot commas?)' : '') );
+ }
+ if (!$amount instanceof Less_Tree_Dimension) {
+ throw new Less_Exception_Compiler('The second argument to desaturate must be a percentage' . ($amount instanceof Less_Tree_Expression ? ' (did you forgot commas?)' : '') );
+ }
+
+ $hsl = $color->toHSL();
+
+ $hsl['s'] -= $amount->value / 100;
+ $hsl['s'] = self::clamp($hsl['s']);
+
+ return $this->hsla($hsl['h'], $hsl['s'], $hsl['l'], $hsl['a']);
+ }
+
+
+
+ public function lighten($color = null, $amount=null){
+ if (!$color instanceof Less_Tree_Color) {
+ throw new Less_Exception_Compiler('The first argument to lighten must be a color' . ($color instanceof Less_Tree_Expression ? ' (did you forgot commas?)' : '') );
+ }
+ if (!$amount instanceof Less_Tree_Dimension) {
+ throw new Less_Exception_Compiler('The second argument to lighten must be a percentage' . ($amount instanceof Less_Tree_Expression ? ' (did you forgot commas?)' : '') );
+ }
+
+ $hsl = $color->toHSL();
+
+ $hsl['l'] += $amount->value / 100;
+ $hsl['l'] = self::clamp($hsl['l']);
+
+ return $this->hsla($hsl['h'], $hsl['s'], $hsl['l'], $hsl['a']);
+ }
+
+ public function darken($color = null, $amount = null){
+ if (!$color instanceof Less_Tree_Color) {
+ throw new Less_Exception_Compiler('The first argument to darken must be a color' . ($color instanceof Less_Tree_Expression ? ' (did you forgot commas?)' : '') );
+ }
+ if (!$amount instanceof Less_Tree_Dimension) {
+ throw new Less_Exception_Compiler('The second argument to darken must be a percentage' . ($amount instanceof Less_Tree_Expression ? ' (did you forgot commas?)' : '') );
+ }
+
+ $hsl = $color->toHSL();
+ $hsl['l'] -= $amount->value / 100;
+ $hsl['l'] = self::clamp($hsl['l']);
+
+ return $this->hsla($hsl['h'], $hsl['s'], $hsl['l'], $hsl['a']);
+ }
+
+ public function fadein($color = null, $amount = null){
+ if (!$color instanceof Less_Tree_Color) {
+ throw new Less_Exception_Compiler('The first argument to fadein must be a color' . ($color instanceof Less_Tree_Expression ? ' (did you forgot commas?)' : '') );
+ }
+ if (!$amount instanceof Less_Tree_Dimension) {
+ throw new Less_Exception_Compiler('The second argument to fadein must be a percentage' . ($amount instanceof Less_Tree_Expression ? ' (did you forgot commas?)' : '') );
+ }
+
+ $hsl = $color->toHSL();
+ $hsl['a'] += $amount->value / 100;
+ $hsl['a'] = self::clamp($hsl['a']);
+ return $this->hsla($hsl['h'], $hsl['s'], $hsl['l'], $hsl['a']);
+ }
+
+ public function fadeout($color = null, $amount = null){
+ if (!$color instanceof Less_Tree_Color) {
+ throw new Less_Exception_Compiler('The first argument to fadeout must be a color' . ($color instanceof Less_Tree_Expression ? ' (did you forgot commas?)' : '') );
+ }
+ if (!$amount instanceof Less_Tree_Dimension) {
+ throw new Less_Exception_Compiler('The second argument to fadeout must be a percentage' . ($amount instanceof Less_Tree_Expression ? ' (did you forgot commas?)' : '') );
+ }
+
+ $hsl = $color->toHSL();
+ $hsl['a'] -= $amount->value / 100;
+ $hsl['a'] = self::clamp($hsl['a']);
+ return $this->hsla($hsl['h'], $hsl['s'], $hsl['l'], $hsl['a']);
+ }
+
+ public function fade($color = null, $amount = null){
+ if (!$color instanceof Less_Tree_Color) {
+ throw new Less_Exception_Compiler('The first argument to fade must be a color' . ($color instanceof Less_Tree_Expression ? ' (did you forgot commas?)' : '') );
+ }
+ if (!$amount instanceof Less_Tree_Dimension) {
+ throw new Less_Exception_Compiler('The second argument to fade must be a percentage' . ($amount instanceof Less_Tree_Expression ? ' (did you forgot commas?)' : '') );
+ }
+
+ $hsl = $color->toHSL();
+
+ $hsl['a'] = $amount->value / 100;
+ $hsl['a'] = self::clamp($hsl['a']);
+ return $this->hsla($hsl['h'], $hsl['s'], $hsl['l'], $hsl['a']);
+ }
+
+
+
+ public function spin($color = null, $amount = null){
+ if (!$color instanceof Less_Tree_Color) {
+ throw new Less_Exception_Compiler('The first argument to spin must be a color' . ($color instanceof Less_Tree_Expression ? ' (did you forgot commas?)' : '') );
+ }
+ if (!$amount instanceof Less_Tree_Dimension) {
+ throw new Less_Exception_Compiler('The second argument to spin must be a number' . ($amount instanceof Less_Tree_Expression ? ' (did you forgot commas?)' : '') );
+ }
+
+ $hsl = $color->toHSL();
+ $hue = fmod($hsl['h'] + $amount->value, 360);
+
+ $hsl['h'] = $hue < 0 ? 360 + $hue : $hue;
+
+ return $this->hsla($hsl['h'], $hsl['s'], $hsl['l'], $hsl['a']);
+ }
+
+ //
+ // Copyright (c) 2006-2009 Hampton Catlin, Nathan Weizenbaum, and Chris Eppstein
+ // http://sass-lang.com
+ //
+
+ /**
+ * @param Less_Tree_Color $color1
+ */
+ public function mix($color1 = null, $color2 = null, $weight = null){
+ if (!$color1 instanceof Less_Tree_Color) {
+ throw new Less_Exception_Compiler('The first argument to mix must be a color' . ($color1 instanceof Less_Tree_Expression ? ' (did you forgot commas?)' : '') );
+ }
+ if (!$color2 instanceof Less_Tree_Color) {
+ throw new Less_Exception_Compiler('The second argument to mix must be a color' . ($color2 instanceof Less_Tree_Expression ? ' (did you forgot commas?)' : '') );
+ }
+ if (!$weight) {
+ $weight = new Less_Tree_Dimension('50', '%');
+ }
+ if (!$weight instanceof Less_Tree_Dimension) {
+ throw new Less_Exception_Compiler('The third argument to contrast must be a percentage' . ($weight instanceof Less_Tree_Expression ? ' (did you forgot commas?)' : '') );
+ }
+
+ $p = $weight->value / 100.0;
+ $w = $p * 2 - 1;
+ $hsl1 = $color1->toHSL();
+ $hsl2 = $color2->toHSL();
+ $a = $hsl1['a'] - $hsl2['a'];
+
+ $w1 = (((($w * $a) == -1) ? $w : ($w + $a) / (1 + $w * $a)) + 1) / 2;
+ $w2 = 1 - $w1;
+
+ $rgb = array($color1->rgb[0] * $w1 + $color2->rgb[0] * $w2,
+ $color1->rgb[1] * $w1 + $color2->rgb[1] * $w2,
+ $color1->rgb[2] * $w1 + $color2->rgb[2] * $w2);
+
+ $alpha = $color1->alpha * $p + $color2->alpha * (1 - $p);
+
+ return new Less_Tree_Color($rgb, $alpha);
+ }
+
+ public function greyscale($color){
+ return $this->desaturate($color, new Less_Tree_Dimension(100,'%'));
+ }
+
+
+ public function contrast( $color, $dark = null, $light = null, $threshold = null){
+ // filter: contrast(3.2);
+ // should be kept as is, so check for color
+ if (!$color instanceof Less_Tree_Color) {
+ return null;
+ }
+ if( !$light ){
+ $light = $this->rgba(255, 255, 255, 1.0);
+ }
+ if( !$dark ){
+ $dark = $this->rgba(0, 0, 0, 1.0);
+ }
+
+ if (!$dark instanceof Less_Tree_Color) {
+ throw new Less_Exception_Compiler('The second argument to contrast must be a color' . ($dark instanceof Less_Tree_Expression ? ' (did you forgot commas?)' : '') );
+ }
+ if (!$light instanceof Less_Tree_Color) {
+ throw new Less_Exception_Compiler('The third argument to contrast must be a color' . ($light instanceof Less_Tree_Expression ? ' (did you forgot commas?)' : '') );
+ }
+
+ //Figure out which is actually light and dark!
+ if( $dark->luma() > $light->luma() ){
+ $t = $light;
+ $light = $dark;
+ $dark = $t;
+ }
+ if( !$threshold ){
+ $threshold = 0.43;
+ } else {
+ $threshold = Less_Functions::number($threshold);
+ }
+
+ if( $color->luma() < $threshold ){
+ return $light;
+ } else {
+ return $dark;
+ }
+ }
+
+ public function e ($str){
+ if( is_string($str) ){
+ return new Less_Tree_Anonymous($str);
+ }
+ return new Less_Tree_Anonymous($str instanceof Less_Tree_JavaScript ? $str->expression : $str->value);
+ }
+
+ public function escape ($str){
+
+ $revert = array('%21'=>'!', '%2A'=>'*', '%27'=>"'",'%3F'=>'?','%26'=>'&','%2C'=>',','%2F'=>'/','%40'=>'@','%2B'=>'+','%24'=>'$');
+
+ return new Less_Tree_Anonymous(strtr(rawurlencode($str->value), $revert));
+ }
+
+
+ /**
+ * todo: This function will need some additional work to make it work the same as less.js
+ *
+ */
+ public function replace( $string, $pattern, $replacement, $flags = null ){
+ $result = $string->value;
+
+ $expr = '/'.str_replace('/','\\/',$pattern->value).'/';
+ if( $flags && $flags->value){
+ $expr .= self::replace_flags($flags->value);
+ }
+
+ $result = preg_replace($expr,$replacement->value,$result);
+
+
+ if( property_exists($string,'quote') ){
+ return new Less_Tree_Quoted( $string->quote, $result, $string->escaped);
+ }
+ return new Less_Tree_Quoted( '', $result );
+ }
+
+ public static function replace_flags($flags){
+ $flags = str_split($flags,1);
+ $new_flags = '';
+
+ foreach($flags as $flag){
+ switch($flag){
+ case 'e':
+ case 'g':
+ break;
+
+ default:
+ $new_flags .= $flag;
+ break;
+ }
+ }
+
+ return $new_flags;
+ }
+
+ public function _percent(){
+ $string = func_get_arg(0);
+
+ $args = func_get_args();
+ array_shift($args);
+ $result = $string->value;
+
+ foreach($args as $arg){
+ if( preg_match('/%[sda]/i',$result, $token) ){
+ $token = $token[0];
+ $value = stristr($token, 's') ? $arg->value : $arg->toCSS();
+ $value = preg_match('/[A-Z]$/', $token) ? urlencode($value) : $value;
+ $result = preg_replace('/%[sda]/i',$value, $result, 1);
+ }
+ }
+ $result = str_replace('%%', '%', $result);
+
+ return new Less_Tree_Quoted( $string->quote , $result, $string->escaped);
+ }
+
+ public function unit( $val, $unit = null) {
+ if( !($val instanceof Less_Tree_Dimension) ){
+ throw new Less_Exception_Compiler('The first argument to unit must be a number' . ($val instanceof Less_Tree_Operation ? '. Have you forgotten parenthesis?' : '.') );
+ }
+
+ if( $unit ){
+ if( $unit instanceof Less_Tree_Keyword ){
+ $unit = $unit->value;
+ } else {
+ $unit = $unit->toCSS();
+ }
+ } else {
+ $unit = "";
+ }
+ return new Less_Tree_Dimension($val->value, $unit );
+ }
+
+ public function convert($val, $unit){
+ return $val->convertTo($unit->value);
+ }
+
+ public function round($n, $f = false) {
+
+ $fraction = 0;
+ if( $f !== false ){
+ $fraction = $f->value;
+ }
+
+ return $this->_math('Less_Parser::round',null, $n, $fraction);
+ }
+
+ public function pi(){
+ return new Less_Tree_Dimension(M_PI);
+ }
+
+ public function mod($a, $b) {
+ return new Less_Tree_Dimension( $a->value % $b->value, $a->unit);
+ }
+
+
+
+ public function pow($x, $y) {
+ if( is_numeric($x) && is_numeric($y) ){
+ $x = new Less_Tree_Dimension($x);
+ $y = new Less_Tree_Dimension($y);
+ }elseif( !($x instanceof Less_Tree_Dimension) || !($y instanceof Less_Tree_Dimension) ){
+ throw new Less_Exception_Compiler('Arguments must be numbers');
+ }
+
+ return new Less_Tree_Dimension( pow($x->value, $y->value), $x->unit );
+ }
+
+ // var mathFunctions = [{name:"ce ...
+ public function ceil( $n ){ return $this->_math('ceil', null, $n); }
+ public function floor( $n ){ return $this->_math('floor', null, $n); }
+ public function sqrt( $n ){ return $this->_math('sqrt', null, $n); }
+ public function abs( $n ){ return $this->_math('abs', null, $n); }
+
+ public function tan( $n ){ return $this->_math('tan', '', $n); }
+ public function sin( $n ){ return $this->_math('sin', '', $n); }
+ public function cos( $n ){ return $this->_math('cos', '', $n); }
+
+ public function atan( $n ){ return $this->_math('atan', 'rad', $n); }
+ public function asin( $n ){ return $this->_math('asin', 'rad', $n); }
+ public function acos( $n ){ return $this->_math('acos', 'rad', $n); }
+
+ private function _math() {
+ $args = func_get_args();
+ $fn = array_shift($args);
+ $unit = array_shift($args);
+
+ if ($args[0] instanceof Less_Tree_Dimension) {
+
+ if( $unit === null ){
+ $unit = $args[0]->unit;
+ }else{
+ $args[0] = $args[0]->unify();
+ }
+ $args[0] = (float)$args[0]->value;
+ return new Less_Tree_Dimension( call_user_func_array($fn, $args), $unit);
+ } else if (is_numeric($args[0])) {
+ return call_user_func_array($fn,$args);
+ } else {
+ throw new Less_Exception_Compiler("math functions take numbers as parameters");
+ }
+ }
+
+ /**
+ * @param boolean $isMin
+ */
+ private function _minmax( $isMin, $args ){
+
+ $arg_count = count($args);
+
+ if( $arg_count < 1 ){
+ throw new Less_Exception_Compiler( 'one or more arguments required');
+ }
+
+ $j = null;
+ $unitClone = null;
+ $unitStatic = null;
+
+
+ $order = array(); // elems only contains original argument values.
+ $values = array(); // key is the unit.toString() for unified tree.Dimension values,
+ // value is the index into the order array.
+
+
+ for( $i = 0; $i < $arg_count; $i++ ){
+ $current = $args[$i];
+ if( !($current instanceof Less_Tree_Dimension) ){
+ if( is_array($args[$i]->value) ){
+ $args[] = $args[$i]->value;
+ }
+ continue;
+ }
+
+ if( $current->unit->toString() === '' && !$unitClone ){
+ $temp = new Less_Tree_Dimension($current->value, $unitClone);
+ $currentUnified = $temp->unify();
+ }else{
+ $currentUnified = $current->unify();
+ }
+
+ if( $currentUnified->unit->toString() === "" && !$unitStatic ){
+ $unit = $unitStatic;
+ }else{
+ $unit = $currentUnified->unit->toString();
+ }
+
+ if( $unit !== '' && !$unitStatic || $unit !== '' && $order[0]->unify()->unit->toString() === "" ){
+ $unitStatic = $unit;
+ }
+
+ if( $unit != '' && !$unitClone ){
+ $unitClone = $current->unit->toString();
+ }
+
+ if( isset($values['']) && $unit !== '' && $unit === $unitStatic ){
+ $j = $values[''];
+ }elseif( isset($values[$unit]) ){
+ $j = $values[$unit];
+ }else{
+
+ if( $unitStatic && $unit !== $unitStatic ){
+ throw new Less_Exception_Compiler( 'incompatible types');
+ }
+ $values[$unit] = count($order);
+ $order[] = $current;
+ continue;
+ }
+
+
+ if( $order[$j]->unit->toString() === "" && $unitClone ){
+ $temp = new Less_Tree_Dimension( $order[$j]->value, $unitClone);
+ $referenceUnified = $temp->unify();
+ }else{
+ $referenceUnified = $order[$j]->unify();
+ }
+ if( ($isMin && $currentUnified->value < $referenceUnified->value) || (!$isMin && $currentUnified->value > $referenceUnified->value) ){
+ $order[$j] = $current;
+ }
+ }
+
+ if( count($order) == 1 ){
+ return $order[0];
+ }
+ $args = array();
+ foreach($order as $a){
+ $args[] = $a->toCSS($this->env);
+ }
+ return new Less_Tree_Anonymous( ($isMin?'min(':'max(') . implode(Less_Environment::$_outputMap[','],$args).')');
+ }
+
+ public function min(){
+ $args = func_get_args();
+ return $this->_minmax( true, $args );
+ }
+
+ public function max(){
+ $args = func_get_args();
+ return $this->_minmax( false, $args );
+ }
+
+ public function getunit($n){
+ return new Less_Tree_Anonymous($n->unit);
+ }
+
+ public function argb($color) {
+ if (!$color instanceof Less_Tree_Color) {
+ throw new Less_Exception_Compiler('The first argument to argb must be a color' . ($dark instanceof Less_Tree_Expression ? ' (did you forgot commas?)' : '') );
+ }
+
+ return new Less_Tree_Anonymous($color->toARGB());
+ }
+
+ public function percentage($n) {
+ return new Less_Tree_Dimension($n->value * 100, '%');
+ }
+
+ public function color($n) {
+
+ if( $n instanceof Less_Tree_Quoted ){
+ $colorCandidate = $n->value;
+ $returnColor = Less_Tree_Color::fromKeyword($colorCandidate);
+ if( $returnColor ){
+ return $returnColor;
+ }
+ if( preg_match('/^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})/',$colorCandidate) ){
+ return new Less_Tree_Color(substr($colorCandidate, 1));
+ }
+ throw new Less_Exception_Compiler("argument must be a color keyword or 3/6 digit hex e.g. #FFF");
+ } else {
+ throw new Less_Exception_Compiler("argument must be a string");
+ }
+ }
+
+
+ public function iscolor($n) {
+ return $this->_isa($n, 'Less_Tree_Color');
+ }
+
+ public function isnumber($n) {
+ return $this->_isa($n, 'Less_Tree_Dimension');
+ }
+
+ public function isstring($n) {
+ return $this->_isa($n, 'Less_Tree_Quoted');
+ }
+
+ public function iskeyword($n) {
+ return $this->_isa($n, 'Less_Tree_Keyword');
+ }
+
+ public function isurl($n) {
+ return $this->_isa($n, 'Less_Tree_Url');
+ }
+
+ public function ispixel($n) {
+ return $this->isunit($n, 'px');
+ }
+
+ public function ispercentage($n) {
+ return $this->isunit($n, '%');
+ }
+
+ public function isem($n) {
+ return $this->isunit($n, 'em');
+ }
+
+ /**
+ * @param string $unit
+ */
+ public function isunit( $n, $unit ){
+ return ($n instanceof Less_Tree_Dimension) && $n->unit->is( ( property_exists($unit,'value') ? $unit->value : $unit) ) ? new Less_Tree_Keyword('true') : new Less_Tree_Keyword('false');
+ }
+
+ /**
+ * @param string $type
+ */
+ private function _isa($n, $type) {
+ return is_a($n, $type) ? new Less_Tree_Keyword('true') : new Less_Tree_Keyword('false');
+ }
+
+ public function tint($color, $amount) {
+ return $this->mix( $this->rgb(255,255,255), $color, $amount);
+ }
+
+ public function shade($color, $amount) {
+ return $this->mix($this->rgb(0, 0, 0), $color, $amount);
+ }
+
+ public function extract($values, $index ){
+ $index = (int)$index->value - 1; // (1-based index)
+ // handle non-array values as an array of length 1
+ // return 'undefined' if index is invalid
+ if( property_exists($values,'value') && is_array($values->value) ){
+ if( isset($values->value[$index]) ){
+ return $values->value[$index];
+ }
+ return null;
+
+ }elseif( (int)$index === 0 ){
+ return $values;
+ }
+
+ return null;
+ }
+
+ public function length($values){
+ $n = (property_exists($values,'value') && is_array($values->value)) ? count($values->value) : 1;
+ return new Less_Tree_Dimension($n);
+ }
+
+ public function datauri($mimetypeNode, $filePathNode = null ) {
+
+ $filePath = ( $filePathNode ? $filePathNode->value : null );
+ $mimetype = $mimetypeNode->value;
+
+ $args = 2;
+ if( !$filePath ){
+ $filePath = $mimetype;
+ $args = 1;
+ }
+
+ $filePath = str_replace('\\','/',$filePath);
+ if( Less_Environment::isPathRelative($filePath) ){
+
+ if( Less_Parser::$options['relativeUrls'] ){
+ $temp = $this->currentFileInfo['currentDirectory'];
+ } else {
+ $temp = $this->currentFileInfo['entryPath'];
+ }
+
+ if( !empty($temp) ){
+ $filePath = Less_Environment::normalizePath(rtrim($temp,'/').'/'.$filePath);
+ }
+
+ }
+
+
+ // detect the mimetype if not given
+ if( $args < 2 ){
+
+ /* incomplete
+ $mime = require('mime');
+ mimetype = mime.lookup(path);
+
+ // use base 64 unless it's an ASCII or UTF-8 format
+ var charset = mime.charsets.lookup(mimetype);
+ useBase64 = ['US-ASCII', 'UTF-8'].indexOf(charset) < 0;
+ if (useBase64) mimetype += ';base64';
+ */
+
+ $mimetype = Less_Mime::lookup($filePath);
+
+ $charset = Less_Mime::charsets_lookup($mimetype);
+ $useBase64 = !in_array($charset,array('US-ASCII', 'UTF-8'));
+ if( $useBase64 ){ $mimetype .= ';base64'; }
+
+ }else{
+ $useBase64 = preg_match('/;base64$/',$mimetype);
+ }
+
+
+ if( file_exists($filePath) ){
+ $buf = @file_get_contents($filePath);
+ }else{
+ $buf = false;
+ }
+
+
+ // IE8 cannot handle a data-uri larger than 32KB. If this is exceeded
+ // and the --ieCompat flag is enabled, return a normal url() instead.
+ $DATA_URI_MAX_KB = 32;
+ $fileSizeInKB = round( strlen($buf) / 1024 );
+ if( $fileSizeInKB >= $DATA_URI_MAX_KB ){
+ $url = new Less_Tree_Url( ($filePathNode ? $filePathNode : $mimetypeNode), $this->currentFileInfo);
+ return $url->compile($this);
+ }
+
+ if( $buf ){
+ $buf = $useBase64 ? base64_encode($buf) : rawurlencode($buf);
+ $filePath = '"data:' . $mimetype . ',' . $buf . '"';
+ }
+
+ return new Less_Tree_Url( new Less_Tree_Anonymous($filePath) );
+ }
+
+ //svg-gradient
+ public function svggradient( $direction ){
+
+ $throw_message = 'svg-gradient expects direction, start_color [start_position], [color position,]..., end_color [end_position]';
+ $arguments = func_get_args();
+
+ if( count($arguments) < 3 ){
+ throw new Less_Exception_Compiler( $throw_message );
+ }
+
+ $stops = array_slice($arguments,1);
+ $gradientType = 'linear';
+ $rectangleDimension = 'x="0" y="0" width="1" height="1"';
+ $useBase64 = true;
+ $directionValue = $direction->toCSS();
+
+
+ switch( $directionValue ){
+ case "to bottom":
+ $gradientDirectionSvg = 'x1="0%" y1="0%" x2="0%" y2="100%"';
+ break;
+ case "to right":
+ $gradientDirectionSvg = 'x1="0%" y1="0%" x2="100%" y2="0%"';
+ break;
+ case "to bottom right":
+ $gradientDirectionSvg = 'x1="0%" y1="0%" x2="100%" y2="100%"';
+ break;
+ case "to top right":
+ $gradientDirectionSvg = 'x1="0%" y1="100%" x2="100%" y2="0%"';
+ break;
+ case "ellipse":
+ case "ellipse at center":
+ $gradientType = "radial";
+ $gradientDirectionSvg = 'cx="50%" cy="50%" r="75%"';
+ $rectangleDimension = 'x="-50" y="-50" width="101" height="101"';
+ break;
+ default:
+ throw new Less_Exception_Compiler( "svg-gradient direction must be 'to bottom', 'to right', 'to bottom right', 'to top right' or 'ellipse at center'" );
+ }
+
+ $returner = '<?xml version="1.0" ?>' .
+ '<svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="100%" height="100%" viewBox="0 0 1 1" preserveAspectRatio="none">' .
+ '<' . $gradientType . 'Gradient id="gradient" gradientUnits="userSpaceOnUse" ' . $gradientDirectionSvg . '>';
+
+ for( $i = 0; $i < count($stops); $i++ ){
+ if( is_object($stops[$i]) && property_exists($stops[$i],'value') ){
+ $color = $stops[$i]->value[0];
+ $position = $stops[$i]->value[1];
+ }else{
+ $color = $stops[$i];
+ $position = null;
+ }
+
+ if( !($color instanceof Less_Tree_Color) || (!(($i === 0 || $i+1 === count($stops)) && $position === null) && !($position instanceof Less_Tree_Dimension)) ){
+ throw new Less_Exception_Compiler( $throw_message );
+ }
+ if( $position ){
+ $positionValue = $position->toCSS();
+ }elseif( $i === 0 ){
+ $positionValue = '0%';
+ }else{
+ $positionValue = '100%';
+ }
+ $alpha = $color->alpha;
+ $returner .= '<stop offset="' . $positionValue . '" stop-color="' . $color->toRGB() . '"' . ($alpha < 1 ? ' stop-opacity="' . $alpha . '"' : '') . '/>';
+ }
+
+ $returner .= '</' . $gradientType . 'Gradient><rect ' . $rectangleDimension . ' fill="url(#gradient)" /></svg>';
+
+
+ if( $useBase64 ){
+ $returner = "'data:image/svg+xml;base64,".base64_encode($returner)."'";
+ }else{
+ $returner = "'data:image/svg+xml,".$returner."'";
+ }
+
+ return new Less_Tree_URL( new Less_Tree_Anonymous( $returner ) );
+ }
+
+
+ /**
+ * Php version of javascript's `encodeURIComponent` function
+ *
+ * @param string $string The string to encode
+ * @return string The encoded string
+ */
+ public static function encodeURIComponent($string){
+ $revert = array('%21' => '!', '%2A' => '*', '%27' => "'", '%28' => '(', '%29' => ')');
+ return strtr(rawurlencode($string), $revert);
+ }
+
+
+ // Color Blending
+ // ref: http://www.w3.org/TR/compositing-1
+
+ public function colorBlend( $mode, $color1, $color2 ){
+ $ab = $color1->alpha; // backdrop
+ $as = $color2->alpha; // source
+ $r = array(); // result
+
+ $ar = $as + $ab * (1 - $as);
+ for( $i = 0; $i < 3; $i++ ){
+ $cb = $color1->rgb[$i] / 255;
+ $cs = $color2->rgb[$i] / 255;
+ $cr = call_user_func( $mode, $cb, $cs );
+ if( $ar ){
+ $cr = ($as * $cs + $ab * ($cb - $as * ($cb + $cs - $cr))) / $ar;
+ }
+ $r[$i] = $cr * 255;
+ }
+
+ return new Less_Tree_Color($r, $ar);
+ }
+
+ public function multiply($color1 = null, $color2 = null ){
+ if (!$color1 instanceof Less_Tree_Color) {
+ throw new Less_Exception_Compiler('The first argument to multiply must be a color' . ($color instanceof Less_Tree_Expression ? ' (did you forgot commas?)' : '') );
+ }
+ if (!$color2 instanceof Less_Tree_Color) {
+ throw new Less_Exception_Compiler('The second argument to multiply must be a color' . ($color instanceof Less_Tree_Expression ? ' (did you forgot commas?)' : '') );
+ }
+
+ return $this->colorBlend( array($this,'colorBlendMultiply'), $color1, $color2 );
+ }
+
+ private function colorBlendMultiply($cb, $cs){
+ return $cb * $cs;
+ }
+
+ public function screen($color1 = null, $color2 = null ){
+ if (!$color1 instanceof Less_Tree_Color) {
+ throw new Less_Exception_Compiler('The first argument to screen must be a color' . ($color instanceof Less_Tree_Expression ? ' (did you forgot commas?)' : '') );
+ }
+ if (!$color2 instanceof Less_Tree_Color) {
+ throw new Less_Exception_Compiler('The second argument to screen must be a color' . ($color instanceof Less_Tree_Expression ? ' (did you forgot commas?)' : '') );
+ }
+
+ return $this->colorBlend( array($this,'colorBlendScreen'), $color1, $color2 );
+ }
+
+ private function colorBlendScreen( $cb, $cs){
+ return $cb + $cs - $cb * $cs;
+ }
+
+ public function overlay($color1 = null, $color2 = null){
+ if (!$color1 instanceof Less_Tree_Color) {
+ throw new Less_Exception_Compiler('The first argument to overlay must be a color' . ($color instanceof Less_Tree_Expression ? ' (did you forgot commas?)' : '') );
+ }
+ if (!$color2 instanceof Less_Tree_Color) {
+ throw new Less_Exception_Compiler('The second argument to overlay must be a color' . ($color instanceof Less_Tree_Expression ? ' (did you forgot commas?)' : '') );
+ }
+
+ return $this->colorBlend( array($this,'colorBlendOverlay'), $color1, $color2 );
+ }
+
+ private function colorBlendOverlay($cb, $cs ){
+ $cb *= 2;
+ return ($cb <= 1)
+ ? $this->colorBlendMultiply($cb, $cs)
+ : $this->colorBlendScreen($cb - 1, $cs);
+ }
+
+ public function softlight($color1 = null, $color2 = null){
+ if (!$color1 instanceof Less_Tree_Color) {
+ throw new Less_Exception_Compiler('The first argument to softlight must be a color' . ($color instanceof Less_Tree_Expression ? ' (did you forgot commas?)' : '') );
+ }
+ if (!$color2 instanceof Less_Tree_Color) {
+ throw new Less_Exception_Compiler('The second argument to softlight must be a color' . ($color instanceof Less_Tree_Expression ? ' (did you forgot commas?)' : '') );
+ }
+
+ return $this->colorBlend( array($this,'colorBlendSoftlight'), $color1, $color2 );
+ }
+
+ private function colorBlendSoftlight($cb, $cs ){
+ $d = 1;
+ $e = $cb;
+ if( $cs > 0.5 ){
+ $e = 1;
+ $d = ($cb > 0.25) ? sqrt($cb)
+ : ((16 * $cb - 12) * $cb + 4) * $cb;
+ }
+ return $cb - (1 - 2 * $cs) * $e * ($d - $cb);
+ }
+
+ public function hardlight($color1 = null, $color2 = null){
+ if (!$color1 instanceof Less_Tree_Color) {
+ throw new Less_Exception_Compiler('The first argument to hardlight must be a color' . ($color instanceof Less_Tree_Expression ? ' (did you forgot commas?)' : '') );
+ }
+ if (!$color2 instanceof Less_Tree_Color) {
+ throw new Less_Exception_Compiler('The second argument to hardlight must be a color' . ($color instanceof Less_Tree_Expression ? ' (did you forgot commas?)' : '') );
+ }
+
+ return $this->colorBlend( array($this,'colorBlendHardlight'), $color1, $color2 );
+ }
+
+ private function colorBlendHardlight( $cb, $cs ){
+ return $this->colorBlendOverlay($cs, $cb);
+ }
+
+ public function difference($color1 = null, $color2 = null) {
+ if (!$color1 instanceof Less_Tree_Color) {
+ throw new Less_Exception_Compiler('The first argument to difference must be a color' . ($color instanceof Less_Tree_Expression ? ' (did you forgot commas?)' : '') );
+ }
+ if (!$color2 instanceof Less_Tree_Color) {
+ throw new Less_Exception_Compiler('The second argument to difference must be a color' . ($color instanceof Less_Tree_Expression ? ' (did you forgot commas?)' : '') );
+ }
+
+ return $this->colorBlend( array($this,'colorBlendDifference'), $color1, $color2 );
+ }
+
+ private function colorBlendDifference( $cb, $cs ){
+ return abs($cb - $cs);
+ }
+
+ public function exclusion( $color1 = null, $color2 = null ){
+ if (!$color1 instanceof Less_Tree_Color) {
+ throw new Less_Exception_Compiler('The first argument to exclusion must be a color' . ($color instanceof Less_Tree_Expression ? ' (did you forgot commas?)' : '') );
+ }
+ if (!$color2 instanceof Less_Tree_Color) {
+ throw new Less_Exception_Compiler('The second argument to exclusion must be a color' . ($color instanceof Less_Tree_Expression ? ' (did you forgot commas?)' : '') );
+ }
+
+ return $this->colorBlend( array($this,'colorBlendExclusion'), $color1, $color2 );
+ }
+
+ private function colorBlendExclusion( $cb, $cs ){
+ return $cb + $cs - 2 * $cb * $cs;
+ }
+
+ public function average($color1 = null, $color2 = null){
+ if (!$color1 instanceof Less_Tree_Color) {
+ throw new Less_Exception_Compiler('The first argument to average must be a color' . ($color instanceof Less_Tree_Expression ? ' (did you forgot commas?)' : '') );
+ }
+ if (!$color2 instanceof Less_Tree_Color) {
+ throw new Less_Exception_Compiler('The second argument to average must be a color' . ($color instanceof Less_Tree_Expression ? ' (did you forgot commas?)' : '') );
+ }
+
+ return $this->colorBlend( array($this,'colorBlendAverage'), $color1, $color2 );
+ }
+
+ // non-w3c functions:
+ public function colorBlendAverage($cb, $cs ){
+ return ($cb + $cs) / 2;
+ }
+
+ public function negation($color1 = null, $color2 = null ){
+ if (!$color1 instanceof Less_Tree_Color) {
+ throw new Less_Exception_Compiler('The first argument to negation must be a color' . ($color instanceof Less_Tree_Expression ? ' (did you forgot commas?)' : '') );
+ }
+ if (!$color2 instanceof Less_Tree_Color) {
+ throw new Less_Exception_Compiler('The second argument to negation must be a color' . ($color instanceof Less_Tree_Expression ? ' (did you forgot commas?)' : '') );
+ }
+
+ return $this->colorBlend( array($this,'colorBlendNegation'), $color1, $color2 );
+ }
+
+ public function colorBlendNegation($cb, $cs){
+ return 1 - abs($cb + $cs - 1);
+ }
+
+ // ~ End of Color Blending
+
+}
diff --git a/vendor/oyejorge/less.php/lib/Less/Less.php.combine b/vendor/oyejorge/less.php/lib/Less/Less.php.combine
new file mode 100644
index 00000000..d63cc789
--- /dev/null
+++ b/vendor/oyejorge/less.php/lib/Less/Less.php.combine
@@ -0,0 +1,17 @@
+
+./Parser.php
+./Colors.php
+./Environment.php
+./Functions.php
+./Mime.php
+./Tree.php
+./Output.php
+./Visitor.php
+./VisitorReplacing.php
+./Configurable.php
+./Tree
+./Visitor
+./Exception/Parser.php
+./Exception/
+./Output
+./SourceMap
diff --git a/vendor/oyejorge/less.php/lib/Less/Mime.php b/vendor/oyejorge/less.php/lib/Less/Mime.php
new file mode 100644
index 00000000..109ecd3f
--- /dev/null
+++ b/vendor/oyejorge/less.php/lib/Less/Mime.php
@@ -0,0 +1,41 @@
+<?php
+
+/**
+ * Mime lookup
+ *
+ * @package Less
+ * @subpackage node
+ */
+class Less_Mime{
+
+ // this map is intentionally incomplete
+ // if you want more, install 'mime' dep
+ static $_types = array(
+ '.htm' => 'text/html',
+ '.html'=> 'text/html',
+ '.gif' => 'image/gif',
+ '.jpg' => 'image/jpeg',
+ '.jpeg'=> 'image/jpeg',
+ '.png' => 'image/png',
+ '.ttf' => 'application/x-font-ttf',
+ '.otf' => 'application/x-font-otf',
+ '.eot' => 'application/vnd.ms-fontobject',
+ '.woff' => 'application/x-font-woff',
+ '.svg' => 'image/svg+xml',
+ );
+
+ public static function lookup( $filepath ){
+ $parts = explode('.',$filepath);
+ $ext = '.'.strtolower(array_pop($parts));
+
+ if( !isset(self::$_types[$ext]) ){
+ return null;
+ }
+ return self::$_types[$ext];
+ }
+
+ public static function charsets_lookup( $type = null ){
+ // assumes all text types are UTF-8
+ return $type && preg_match('/^text\//',$type) ? 'UTF-8' : '';
+ }
+}
diff --git a/vendor/oyejorge/less.php/lib/Less/Output.php b/vendor/oyejorge/less.php/lib/Less/Output.php
new file mode 100644
index 00000000..f1b2b2a9
--- /dev/null
+++ b/vendor/oyejorge/less.php/lib/Less/Output.php
@@ -0,0 +1,49 @@
+<?php
+
+/**
+ * Parser output
+ *
+ * @package Less
+ * @subpackage output
+ */
+class Less_Output{
+
+ /**
+ * Output holder
+ *
+ * @var string
+ */
+ protected $strs = array();
+
+ /**
+ * Adds a chunk to the stack
+ *
+ * @param string $chunk The chunk to output
+ * @param Less_FileInfo $fileInfo The file information
+ * @param integer $index The index
+ * @param mixed $mapLines
+ */
+ public function add($chunk, $fileInfo = null, $index = 0, $mapLines = null){
+ $this->strs[] = $chunk;
+ }
+
+ /**
+ * Is the output empty?
+ *
+ * @return boolean
+ */
+ public function isEmpty(){
+ return count($this->strs) === 0;
+ }
+
+
+ /**
+ * Converts the output to string
+ *
+ * @return string
+ */
+ public function toString(){
+ return implode('',$this->strs);
+ }
+
+} \ No newline at end of file
diff --git a/vendor/oyejorge/less.php/lib/Less/Output/Mapped.php b/vendor/oyejorge/less.php/lib/Less/Output/Mapped.php
new file mode 100644
index 00000000..884490a2
--- /dev/null
+++ b/vendor/oyejorge/less.php/lib/Less/Output/Mapped.php
@@ -0,0 +1,122 @@
+<?php
+
+/**
+ * Parser output with source map
+ *
+ * @package Less
+ * @subpackage Output
+ */
+class Less_Output_Mapped extends Less_Output {
+
+ /**
+ * The source map generator
+ *
+ * @var Less_SourceMap_Generator
+ */
+ protected $generator;
+
+ /**
+ * Current line
+ *
+ * @var integer
+ */
+ protected $lineNumber = 0;
+
+ /**
+ * Current column
+ *
+ * @var integer
+ */
+ protected $column = 0;
+
+ /**
+ * Array of contents map (file and its content)
+ *
+ * @var array
+ */
+ protected $contentsMap = array();
+
+ /**
+ * Constructor
+ *
+ * @param array $contentsMap Array of filename to contents map
+ * @param Less_SourceMap_Generator $generator
+ */
+ public function __construct(array $contentsMap, $generator){
+ $this->contentsMap = $contentsMap;
+ $this->generator = $generator;
+ }
+
+ /**
+ * Adds a chunk to the stack
+ * The $index for less.php may be different from less.js since less.php does not chunkify inputs
+ *
+ * @param string $chunk
+ * @param string $fileInfo
+ * @param integer $index
+ * @param mixed $mapLines
+ */
+ public function add($chunk, $fileInfo = null, $index = 0, $mapLines = null){
+
+ //ignore adding empty strings
+ if( $chunk === '' ){
+ return;
+ }
+
+
+ $sourceLines = array();
+ $sourceColumns = ' ';
+
+
+ if( $fileInfo ){
+
+ $url = $fileInfo['currentUri'];
+
+ if( isset($this->contentsMap[$url]) ){
+ $inputSource = substr($this->contentsMap[$url], 0, $index);
+ $sourceLines = explode("\n", $inputSource);
+ $sourceColumns = end($sourceLines);
+ }else{
+ throw new Exception('Filename '.$url.' not in contentsMap');
+ }
+
+ }
+
+ $lines = explode("\n", $chunk);
+ $columns = end($lines);
+
+ if($fileInfo){
+
+ if(!$mapLines){
+ $this->generator->addMapping(
+ $this->lineNumber + 1, // generated_line
+ $this->column, // generated_column
+ count($sourceLines), // original_line
+ strlen($sourceColumns), // original_column
+ $fileInfo
+ );
+ }else{
+ for($i = 0, $count = count($lines); $i < $count; $i++){
+ $this->generator->addMapping(
+ $this->lineNumber + $i + 1, // generated_line
+ $i === 0 ? $this->column : 0, // generated_column
+ count($sourceLines) + $i, // original_line
+ $i === 0 ? strlen($sourceColumns) : 0, // original_column
+ $fileInfo
+ );
+ }
+ }
+ }
+
+ if(count($lines) === 1){
+ $this->column += strlen($columns);
+ }else{
+ $this->lineNumber += count($lines) - 1;
+ $this->column = strlen($columns);
+ }
+
+ // add only chunk
+ parent::add($chunk);
+ }
+
+} \ No newline at end of file
diff --git a/vendor/oyejorge/less.php/lib/Less/Parser.php b/vendor/oyejorge/less.php/lib/Less/Parser.php
new file mode 100644
index 00000000..86d455f1
--- /dev/null
+++ b/vendor/oyejorge/less.php/lib/Less/Parser.php
@@ -0,0 +1,2627 @@
+<?php
+
+require_once( dirname(__FILE__).'/Cache.php');
+
+/**
+ * Class for parsing and compiling less files into css
+ *
+ * @package Less
+ * @subpackage parser
+ *
+ */
+class Less_Parser{
+
+
+ /**
+ * Default parser options
+ */
+ public static $default_options = array(
+ 'compress' => false, // option - whether to compress
+ 'strictUnits' => false, // whether units need to evaluate correctly
+ 'strictMath' => false, // whether math has to be within parenthesis
+ 'relativeUrls' => true, // option - whether to adjust URL's to be relative
+ 'urlArgs' => array(), // whether to add args into url tokens
+ 'numPrecision' => 8,
+
+ 'import_dirs' => array(),
+ 'import_callback' => null,
+ 'cache_dir' => null,
+ 'cache_method' => 'php', // false, 'serialize', 'php', 'var_export', 'callback';
+ 'cache_callback_get' => null,
+ 'cache_callback_set' => null,
+
+ 'sourceMap' => false, // whether to output a source map
+ 'sourceMapBasepath' => null,
+ 'sourceMapWriteTo' => null,
+ 'sourceMapURL' => null,
+
+ 'plugins' => array(),
+
+ );
+
+ public static $options = array();
+
+
+ private $input; // Less input string
+ private $input_len; // input string length
+ private $pos; // current index in `input`
+ private $saveStack = array(); // holds state for backtracking
+ private $furthest;
+ private $mb_internal_encoding = ''; // for remember exists value of mbstring.internal_encoding
+
+ /**
+ * @var Less_Environment
+ */
+ private $env;
+
+ protected $rules = array();
+
+ private static $imports = array();
+
+ public static $has_extends = false;
+
+ public static $next_id = 0;
+
+ /**
+ * Filename to contents of all parsed the files
+ *
+ * @var array
+ */
+ public static $contentsMap = array();
+
+
+ /**
+ * @param Less_Environment|array|null $env
+ */
+ public function __construct( $env = null ){
+
+ // Top parser on an import tree must be sure there is one "env"
+ // which will then be passed around by reference.
+ if( $env instanceof Less_Environment ){
+ $this->env = $env;
+ }else{
+ $this->SetOptions(Less_Parser::$default_options);
+ $this->Reset( $env );
+ }
+
+ // mbstring.func_overload > 1 bugfix
+ // The encoding value must be set for each source file,
+ // therefore, to conserve resources and improve the speed of this design is taken here
+ if (ini_get('mbstring.func_overload')) {
+ $this->mb_internal_encoding = ini_get('mbstring.internal_encoding');
+ @ini_set('mbstring.internal_encoding', 'ascii');
+ }
+
+ }
+
+
+ /**
+ * Reset the parser state completely
+ *
+ */
+ public function Reset( $options = null ){
+ $this->rules = array();
+ self::$imports = array();
+ self::$has_extends = false;
+ self::$imports = array();
+ self::$contentsMap = array();
+
+ $this->env = new Less_Environment($options);
+ $this->env->Init();
+
+ //set new options
+ if( is_array($options) ){
+ $this->SetOptions(Less_Parser::$default_options);
+ $this->SetOptions($options);
+ }
+ }
+
+ /**
+ * Set one or more compiler options
+ * options: import_dirs, cache_dir, cache_method
+ *
+ */
+ public function SetOptions( $options ){
+ foreach($options as $option => $value){
+ $this->SetOption($option,$value);
+ }
+ }
+
+ /**
+ * Set one compiler option
+ *
+ */
+ public function SetOption($option,$value){
+
+ switch($option){
+
+ case 'import_dirs':
+ $this->SetImportDirs($value);
+ return;
+
+ case 'cache_dir':
+ if( is_string($value) ){
+ Less_Cache::SetCacheDir($value);
+ Less_Cache::CheckCacheDir();
+ }
+ return;
+ }
+
+ Less_Parser::$options[$option] = $value;
+ }
+
+ /**
+ * Registers a new custom function
+ *
+ * @param string $name function name
+ * @param callable $callback callback
+ */
+ public function registerFunction($name, $callback) {
+ $this->env->functions[$name] = $callback;
+ }
+
+ /**
+ * Removed an already registered function
+ *
+ * @param string $name function name
+ */
+ public function unregisterFunction($name) {
+ if( isset($this->env->functions[$name]) )
+ unset($this->env->functions[$name]);
+ }
+
+
+ /**
+ * Get the current css buffer
+ *
+ * @return string
+ */
+ public function getCss(){
+
+ $precision = ini_get('precision');
+ @ini_set('precision',16);
+ $locale = setlocale(LC_NUMERIC, 0);
+ setlocale(LC_NUMERIC, "C");
+
+ try {
+
+ $root = new Less_Tree_Ruleset(array(), $this->rules );
+ $root->root = true;
+ $root->firstRoot = true;
+
+
+ $this->PreVisitors($root);
+
+ self::$has_extends = false;
+ $evaldRoot = $root->compile($this->env);
+
+
+
+ $this->PostVisitors($evaldRoot);
+
+ if( Less_Parser::$options['sourceMap'] ){
+ $generator = new Less_SourceMap_Generator($evaldRoot, Less_Parser::$contentsMap, Less_Parser::$options );
+ // will also save file
+ // FIXME: should happen somewhere else?
+ $css = $generator->generateCSS();
+ }else{
+ $css = $evaldRoot->toCSS();
+ }
+
+ if( Less_Parser::$options['compress'] ){
+ $css = preg_replace('/(^(\s)+)|((\s)+$)/', '', $css);
+ }
+
+ } catch (Exception $exc) {
+ // Intentional fall-through so we can reset environment
+ }
+
+ //reset php settings
+ @ini_set('precision',$precision);
+ setlocale(LC_NUMERIC, $locale);
+
+ // If you previously defined $this->mb_internal_encoding
+ // is required to return the encoding as it was before
+ if ($this->mb_internal_encoding != '') {
+ @ini_set("mbstring.internal_encoding", $this->mb_internal_encoding);
+ $this->mb_internal_encoding = '';
+ }
+
+ // Rethrow exception after we handled resetting the environment
+ if (!empty($exc)) {
+ throw $exc;
+ }
+
+
+
+ return $css;
+ }
+
+ /**
+ * Run pre-compile visitors
+ *
+ */
+ private function PreVisitors($root){
+
+ if( Less_Parser::$options['plugins'] ){
+ foreach(Less_Parser::$options['plugins'] as $plugin){
+ if( !empty($plugin->isPreEvalVisitor) ){
+ $plugin->run($root);
+ }
+ }
+ }
+ }
+
+
+ /**
+ * Run post-compile visitors
+ *
+ */
+ private function PostVisitors($evaldRoot){
+
+ $visitors = array();
+ $visitors[] = new Less_Visitor_joinSelector();
+ if( self::$has_extends ){
+ $visitors[] = new Less_Visitor_processExtends();
+ }
+ $visitors[] = new Less_Visitor_toCSS();
+
+
+ if( Less_Parser::$options['plugins'] ){
+ foreach(Less_Parser::$options['plugins'] as $plugin){
+ if( property_exists($plugin,'isPreEvalVisitor') && $plugin->isPreEvalVisitor ){
+ continue;
+ }
+
+ if( property_exists($plugin,'isPreVisitor') && $plugin->isPreVisitor ){
+ array_unshift( $visitors, $plugin);
+ }else{
+ $visitors[] = $plugin;
+ }
+ }
+ }
+
+
+ for($i = 0; $i < count($visitors); $i++ ){
+ $visitors[$i]->run($evaldRoot);
+ }
+
+ }
+
+
+ /**
+ * Parse a Less string into css
+ *
+ * @param string $str The string to convert
+ * @param string $uri_root The url of the file
+ * @return Less_Tree_Ruleset|Less_Parser
+ */
+ public function parse( $str, $file_uri = null ){
+
+ if( !$file_uri ){
+ $uri_root = '';
+ $filename = 'anonymous-file-'.Less_Parser::$next_id++.'.less';
+ }else{
+ $file_uri = self::WinPath($file_uri);
+ $filename = $file_uri;
+ $uri_root = dirname($file_uri);
+ }
+
+ $previousFileInfo = $this->env->currentFileInfo;
+ $uri_root = self::WinPath($uri_root);
+ $this->SetFileInfo($filename, $uri_root);
+
+ $this->input = $str;
+ $this->_parse();
+
+ if( $previousFileInfo ){
+ $this->env->currentFileInfo = $previousFileInfo;
+ }
+
+ return $this;
+ }
+
+
+ /**
+ * Parse a Less string from a given file
+ *
+ * @throws Less_Exception_Parser
+ * @param string $filename The file to parse
+ * @param string $uri_root The url of the file
+ * @param bool $returnRoot Indicates whether the return value should be a css string a root node
+ * @return Less_Tree_Ruleset|Less_Parser
+ */
+ public function parseFile( $filename, $uri_root = '', $returnRoot = false){
+
+ if( !file_exists($filename) ){
+ $this->Error(sprintf('File `%s` not found.', $filename));
+ }
+
+
+ // fix uri_root?
+ // Instead of The mixture of file path for the first argument and directory path for the second argument has bee
+ if( !$returnRoot && !empty($uri_root) && basename($uri_root) == basename($filename) ){
+ $uri_root = dirname($uri_root);
+ }
+
+
+ $previousFileInfo = $this->env->currentFileInfo;
+
+
+ if( $filename ){
+ $filename = self::WinPath(realpath($filename));
+ }
+ $uri_root = self::WinPath($uri_root);
+
+ $this->SetFileInfo($filename, $uri_root);
+
+ self::AddParsedFile($filename);
+
+ if( $returnRoot ){
+ $rules = $this->GetRules( $filename );
+ $return = new Less_Tree_Ruleset(array(), $rules );
+ }else{
+ $this->_parse( $filename );
+ $return = $this;
+ }
+
+ if( $previousFileInfo ){
+ $this->env->currentFileInfo = $previousFileInfo;
+ }
+
+ return $return;
+ }
+
+
+ /**
+ * Allows a user to set variables values
+ * @param array $vars
+ * @return Less_Parser
+ */
+ public function ModifyVars( $vars ){
+
+ $this->input = Less_Parser::serializeVars( $vars );
+ $this->_parse();
+
+ return $this;
+ }
+
+
+ /**
+ * @param string $filename
+ */
+ public function SetFileInfo( $filename, $uri_root = ''){
+
+ $filename = Less_Environment::normalizePath($filename);
+ $dirname = preg_replace('/[^\/\\\\]*$/','',$filename);
+
+ if( !empty($uri_root) ){
+ $uri_root = rtrim($uri_root,'/').'/';
+ }
+
+ $currentFileInfo = array();
+
+ //entry info
+ if( isset($this->env->currentFileInfo) ){
+ $currentFileInfo['entryPath'] = $this->env->currentFileInfo['entryPath'];
+ $currentFileInfo['entryUri'] = $this->env->currentFileInfo['entryUri'];
+ $currentFileInfo['rootpath'] = $this->env->currentFileInfo['rootpath'];
+
+ }else{
+ $currentFileInfo['entryPath'] = $dirname;
+ $currentFileInfo['entryUri'] = $uri_root;
+ $currentFileInfo['rootpath'] = $dirname;
+ }
+
+ $currentFileInfo['currentDirectory'] = $dirname;
+ $currentFileInfo['currentUri'] = $uri_root.basename($filename);
+ $currentFileInfo['filename'] = $filename;
+ $currentFileInfo['uri_root'] = $uri_root;
+
+
+ //inherit reference
+ if( isset($this->env->currentFileInfo['reference']) && $this->env->currentFileInfo['reference'] ){
+ $currentFileInfo['reference'] = true;
+ }
+
+ $this->env->currentFileInfo = $currentFileInfo;
+ }
+
+
+ /**
+ * @deprecated 1.5.1.2
+ *
+ */
+ public function SetCacheDir( $dir ){
+
+ if( !file_exists($dir) ){
+ if( mkdir($dir) ){
+ return true;
+ }
+ throw new Less_Exception_Parser('Less.php cache directory couldn\'t be created: '.$dir);
+
+ }elseif( !is_dir($dir) ){
+ throw new Less_Exception_Parser('Less.php cache directory doesn\'t exist: '.$dir);
+
+ }elseif( !is_writable($dir) ){
+ throw new Less_Exception_Parser('Less.php cache directory isn\'t writable: '.$dir);
+
+ }else{
+ $dir = self::WinPath($dir);
+ Less_Cache::$cache_dir = rtrim($dir,'/').'/';
+ return true;
+ }
+ }
+
+
+ /**
+ * Set a list of directories or callbacks the parser should use for determining import paths
+ *
+ * @param array $dirs
+ */
+ public function SetImportDirs( $dirs ){
+ Less_Parser::$options['import_dirs'] = array();
+
+ foreach($dirs as $path => $uri_root){
+
+ $path = self::WinPath($path);
+ if( !empty($path) ){
+ $path = rtrim($path,'/').'/';
+ }
+
+ if ( !is_callable($uri_root) ){
+ $uri_root = self::WinPath($uri_root);
+ if( !empty($uri_root) ){
+ $uri_root = rtrim($uri_root,'/').'/';
+ }
+ }
+
+ Less_Parser::$options['import_dirs'][$path] = $uri_root;
+ }
+ }
+
+ /**
+ * @param string $file_path
+ */
+ private function _parse( $file_path = null ){
+ $this->rules = array_merge($this->rules, $this->GetRules( $file_path ));
+ }
+
+
+ /**
+ * Return the results of parsePrimary for $file_path
+ * Use cache and save cached results if possible
+ *
+ * @param string|null $file_path
+ */
+ private function GetRules( $file_path ){
+
+ $this->SetInput($file_path);
+
+ $cache_file = $this->CacheFile( $file_path );
+ if( $cache_file ){
+ if( Less_Parser::$options['cache_method'] == 'callback' ){
+ if( is_callable(Less_Parser::$options['cache_callback_get']) ){
+ $cache = call_user_func_array(
+ Less_Parser::$options['cache_callback_get'],
+ array($this, $file_path, $cache_file)
+ );
+
+ if( $cache ){
+ $this->UnsetInput();
+ return $cache;
+ }
+ }
+
+ }elseif( file_exists($cache_file) ){
+ switch(Less_Parser::$options['cache_method']){
+
+ // Using serialize
+ // Faster but uses more memory
+ case 'serialize':
+ $cache = unserialize(file_get_contents($cache_file));
+ if( $cache ){
+ touch($cache_file);
+ $this->UnsetInput();
+ return $cache;
+ }
+ break;
+
+
+ // Using generated php code
+ case 'var_export':
+ case 'php':
+ $this->UnsetInput();
+ return include($cache_file);
+ }
+ }
+ }
+
+ $rules = $this->parsePrimary();
+
+ if( $this->pos < $this->input_len ){
+ throw new Less_Exception_Chunk($this->input, null, $this->furthest, $this->env->currentFileInfo);
+ }
+
+ $this->UnsetInput();
+
+
+ //save the cache
+ if( $cache_file ){
+ if( Less_Parser::$options['cache_method'] == 'callback' ){
+ if( is_callable(Less_Parser::$options['cache_callback_set']) ){
+ call_user_func_array(
+ Less_Parser::$options['cache_callback_set'],
+ array($this, $file_path, $cache_file, $rules)
+ );
+ }
+
+ }else{
+ //msg('write cache file');
+ switch(Less_Parser::$options['cache_method']){
+ case 'serialize':
+ file_put_contents( $cache_file, serialize($rules) );
+ break;
+ case 'php':
+ file_put_contents( $cache_file, '<?php return '.self::ArgString($rules).'; ?>' );
+ break;
+ case 'var_export':
+ //Requires __set_state()
+ file_put_contents( $cache_file, '<?php return '.var_export($rules,true).'; ?>' );
+ break;
+ }
+
+ Less_Cache::CleanCache();
+ }
+ }
+
+ return $rules;
+ }
+
+
+ /**
+ * Set up the input buffer
+ *
+ */
+ public function SetInput( $file_path ){
+
+ if( $file_path ){
+ $this->input = file_get_contents( $file_path );
+ }
+
+ $this->pos = $this->furthest = 0;
+
+ // Remove potential UTF Byte Order Mark
+ $this->input = preg_replace('/\\G\xEF\xBB\xBF/', '', $this->input);
+ $this->input_len = strlen($this->input);
+
+
+ if( Less_Parser::$options['sourceMap'] && $this->env->currentFileInfo ){
+ $uri = $this->env->currentFileInfo['currentUri'];
+ Less_Parser::$contentsMap[$uri] = $this->input;
+ }
+
+ }
+
+
+ /**
+ * Free up some memory
+ *
+ */
+ public function UnsetInput(){
+ unset($this->input, $this->pos, $this->input_len, $this->furthest);
+ $this->saveStack = array();
+ }
+
+
+ public function CacheFile( $file_path ){
+
+ if( $file_path && $this->CacheEnabled() ){
+
+ $env = get_object_vars($this->env);
+ unset($env['frames']);
+
+ $parts = array();
+ $parts[] = $file_path;
+ $parts[] = filesize( $file_path );
+ $parts[] = filemtime( $file_path );
+ $parts[] = $env;
+ $parts[] = Less_Version::cache_version;
+ $parts[] = Less_Parser::$options['cache_method'];
+ return Less_Cache::$cache_dir . Less_Cache::$prefix . base_convert( sha1(json_encode($parts) ), 16, 36) . '.lesscache';
+ }
+ }
+
+
+ static function AddParsedFile($file){
+ self::$imports[] = $file;
+ }
+
+ static function AllParsedFiles(){
+ return self::$imports;
+ }
+
+ /**
+ * @param string $file
+ */
+ static function FileParsed($file){
+ return in_array($file,self::$imports);
+ }
+
+
+ function save() {
+ $this->saveStack[] = $this->pos;
+ }
+
+ private function restore() {
+ $this->pos = array_pop($this->saveStack);
+ }
+
+ private function forget(){
+ array_pop($this->saveStack);
+ }
+
+
+ private function isWhitespace($offset = 0) {
+ return preg_match('/\s/',$this->input[ $this->pos + $offset]);
+ }
+
+ /**
+ * Parse from a token, regexp or string, and move forward if match
+ *
+ * @param array $toks
+ * @return array
+ */
+ private function match($toks){
+
+ // The match is confirmed, add the match length to `this::pos`,
+ // and consume any extra white-space characters (' ' || '\n')
+ // which come after that. The reason for this is that LeSS's
+ // grammar is mostly white-space insensitive.
+ //
+
+ foreach($toks as $tok){
+
+ $char = $tok[0];
+
+ if( $char === '/' ){
+ $match = $this->MatchReg($tok);
+
+ if( $match ){
+ return count($match) === 1 ? $match[0] : $match;
+ }
+
+ }elseif( $char === '#' ){
+ $match = $this->MatchChar($tok[1]);
+
+ }else{
+ // Non-terminal, match using a function call
+ $match = $this->$tok();
+
+ }
+
+ if( $match ){
+ return $match;
+ }
+ }
+ }
+
+ /**
+ * @param string[] $toks
+ *
+ * @return string
+ */
+ private function MatchFuncs($toks){
+
+ if( $this->pos < $this->input_len ){
+ foreach($toks as $tok){
+ $match = $this->$tok();
+ if( $match ){
+ return $match;
+ }
+ }
+ }
+
+ }
+
+ // Match a single character in the input,
+ private function MatchChar($tok){
+ if( ($this->pos < $this->input_len) && ($this->input[$this->pos] === $tok) ){
+ $this->skipWhitespace(1);
+ return $tok;
+ }
+ }
+
+ // Match a regexp from the current start point
+ private function MatchReg($tok){
+
+ if( preg_match($tok, $this->input, $match, 0, $this->pos) ){
+ $this->skipWhitespace(strlen($match[0]));
+ return $match;
+ }
+ }
+
+
+ /**
+ * Same as match(), but don't change the state of the parser,
+ * just return the match.
+ *
+ * @param string $tok
+ * @return integer
+ */
+ public function PeekReg($tok){
+ return preg_match($tok, $this->input, $match, 0, $this->pos);
+ }
+
+ /**
+ * @param string $tok
+ */
+ public function PeekChar($tok){
+ //return ($this->input[$this->pos] === $tok );
+ return ($this->pos < $this->input_len) && ($this->input[$this->pos] === $tok );
+ }
+
+
+ /**
+ * @param integer $length
+ */
+ public function skipWhitespace($length){
+
+ $this->pos += $length;
+
+ for(; $this->pos < $this->input_len; $this->pos++ ){
+ $c = $this->input[$this->pos];
+
+ if( ($c !== "\n") && ($c !== "\r") && ($c !== "\t") && ($c !== ' ') ){
+ break;
+ }
+ }
+ }
+
+
+ /**
+ * @param string $tok
+ * @param string|null $msg
+ */
+ public function expect($tok, $msg = NULL) {
+ $result = $this->match( array($tok) );
+ if (!$result) {
+ $this->Error( $msg ? "Expected '" . $tok . "' got '" . $this->input[$this->pos] . "'" : $msg );
+ } else {
+ return $result;
+ }
+ }
+
+ /**
+ * @param string $tok
+ */
+ public function expectChar($tok, $msg = null ){
+ $result = $this->MatchChar($tok);
+ if( !$result ){
+ $this->Error( $msg ? "Expected '" . $tok . "' got '" . $this->input[$this->pos] . "'" : $msg );
+ }else{
+ return $result;
+ }
+ }
+
+ //
+ // Here in, the parsing rules/functions
+ //
+ // The basic structure of the syntax tree generated is as follows:
+ //
+ // Ruleset -> Rule -> Value -> Expression -> Entity
+ //
+ // Here's some LESS code:
+ //
+ // .class {
+ // color: #fff;
+ // border: 1px solid #000;
+ // width: @w + 4px;
+ // > .child {...}
+ // }
+ //
+ // And here's what the parse tree might look like:
+ //
+ // Ruleset (Selector '.class', [
+ // Rule ("color", Value ([Expression [Color #fff]]))
+ // Rule ("border", Value ([Expression [Dimension 1px][Keyword "solid"][Color #000]]))
+ // Rule ("width", Value ([Expression [Operation "+" [Variable "@w"][Dimension 4px]]]))
+ // Ruleset (Selector [Element '>', '.child'], [...])
+ // ])
+ //
+ // In general, most rules will try to parse a token with the `$()` function, and if the return
+ // value is truly, will return a new node, of the relevant type. Sometimes, we need to check
+ // first, before parsing, that's when we use `peek()`.
+ //
+
+ //
+ // The `primary` rule is the *entry* and *exit* point of the parser.
+ // The rules here can appear at any level of the parse tree.
+ //
+ // The recursive nature of the grammar is an interplay between the `block`
+ // rule, which represents `{ ... }`, the `ruleset` rule, and this `primary` rule,
+ // as represented by this simplified grammar:
+ //
+ // primary → (ruleset | rule)+
+ // ruleset → selector+ block
+ // block → '{' primary '}'
+ //
+ // Only at one point is the primary rule not called from the
+ // block rule: at the root level.
+ //
+ private function parsePrimary(){
+ $root = array();
+
+ while( true ){
+
+ if( $this->pos >= $this->input_len ){
+ break;
+ }
+
+ $node = $this->parseExtend(true);
+ if( $node ){
+ $root = array_merge($root,$node);
+ continue;
+ }
+
+ //$node = $this->MatchFuncs( array( 'parseMixinDefinition', 'parseRule', 'parseRuleset', 'parseMixinCall', 'parseComment', 'parseDirective'));
+ $node = $this->MatchFuncs( array( 'parseMixinDefinition', 'parseNameValue', 'parseRule', 'parseRuleset', 'parseMixinCall', 'parseComment', 'parseRulesetCall', 'parseDirective'));
+
+ if( $node ){
+ $root[] = $node;
+ }elseif( !$this->MatchReg('/\\G[\s\n;]+/') ){
+ break;
+ }
+
+ if( $this->PeekChar('}') ){
+ break;
+ }
+ }
+
+ return $root;
+ }
+
+
+
+ // We create a Comment node for CSS comments `/* */`,
+ // but keep the LeSS comments `//` silent, by just skipping
+ // over them.
+ private function parseComment(){
+
+ if( $this->input[$this->pos] !== '/' ){
+ return;
+ }
+
+ if( $this->input[$this->pos+1] === '/' ){
+ $match = $this->MatchReg('/\\G\/\/.*/');
+ return $this->NewObj4('Less_Tree_Comment',array($match[0], true, $this->pos, $this->env->currentFileInfo));
+ }
+
+ //$comment = $this->MatchReg('/\\G\/\*(?:[^*]|\*+[^\/*])*\*+\/\n?/');
+ $comment = $this->MatchReg('/\\G\/\*(?s).*?\*+\/\n?/');//not the same as less.js to prevent fatal errors
+ if( $comment ){
+ return $this->NewObj4('Less_Tree_Comment',array($comment[0], false, $this->pos, $this->env->currentFileInfo));
+ }
+ }
+
+ private function parseComments(){
+ $comments = array();
+
+ while( $this->pos < $this->input_len ){
+ $comment = $this->parseComment();
+ if( !$comment ){
+ break;
+ }
+
+ $comments[] = $comment;
+ }
+
+ return $comments;
+ }
+
+
+
+ //
+ // A string, which supports escaping " and '
+ //
+ // "milky way" 'he\'s the one!'
+ //
+ private function parseEntitiesQuoted() {
+ $j = $this->pos;
+ $e = false;
+ $index = $this->pos;
+
+ if( $this->input[$this->pos] === '~' ){
+ $j++;
+ $e = true; // Escaped strings
+ }
+
+ if( $this->input[$j] != '"' && $this->input[$j] !== "'" ){
+ return;
+ }
+
+ if ($e) {
+ $this->MatchChar('~');
+ }
+
+ // Fix for #124: match escaped newlines
+ //$str = $this->MatchReg('/\\G"((?:[^"\\\\\r\n]|\\\\.)*)"|\'((?:[^\'\\\\\r\n]|\\\\.)*)\'/');
+ $str = $this->MatchReg('/\\G"((?:[^"\\\\\r\n]|\\\\.|\\\\\r\n|\\\\[\n\r\f])*)"|\'((?:[^\'\\\\\r\n]|\\\\.|\\\\\r\n|\\\\[\n\r\f])*)\'/');
+
+ if( $str ){
+ $result = $str[0][0] == '"' ? $str[1] : $str[2];
+ return $this->NewObj5('Less_Tree_Quoted',array($str[0], $result, $e, $index, $this->env->currentFileInfo) );
+ }
+ return;
+ }
+
+
+ //
+ // A catch-all word, such as:
+ //
+ // black border-collapse
+ //
+ private function parseEntitiesKeyword(){
+
+ //$k = $this->MatchReg('/\\G[_A-Za-z-][_A-Za-z0-9-]*/');
+ $k = $this->MatchReg('/\\G%|\\G[_A-Za-z-][_A-Za-z0-9-]*/');
+ if( $k ){
+ $k = $k[0];
+ $color = $this->fromKeyword($k);
+ if( $color ){
+ return $color;
+ }
+ return $this->NewObj1('Less_Tree_Keyword',$k);
+ }
+ }
+
+ // duplicate of Less_Tree_Color::FromKeyword
+ private function FromKeyword( $keyword ){
+ $keyword = strtolower($keyword);
+
+ if( Less_Colors::hasOwnProperty($keyword) ){
+ // detect named color
+ return $this->NewObj1('Less_Tree_Color',substr(Less_Colors::color($keyword), 1));
+ }
+
+ if( $keyword === 'transparent' ){
+ return $this->NewObj3('Less_Tree_Color', array( array(0, 0, 0), 0, true));
+ }
+ }
+
+ //
+ // A function call
+ //
+ // rgb(255, 0, 255)
+ //
+ // We also try to catch IE's `alpha()`, but let the `alpha` parser
+ // deal with the details.
+ //
+ // The arguments are parsed with the `entities.arguments` parser.
+ //
+ private function parseEntitiesCall(){
+ $index = $this->pos;
+
+ if( !preg_match('/\\G([\w-]+|%|progid:[\w\.]+)\(/', $this->input, $name,0,$this->pos) ){
+ return;
+ }
+ $name = $name[1];
+ $nameLC = strtolower($name);
+
+ if ($nameLC === 'url') {
+ return null;
+ }
+
+ $this->pos += strlen($name);
+
+ if( $nameLC === 'alpha' ){
+ $alpha_ret = $this->parseAlpha();
+ if( $alpha_ret ){
+ return $alpha_ret;
+ }
+ }
+
+ $this->MatchChar('('); // Parse the '(' and consume whitespace.
+
+ $args = $this->parseEntitiesArguments();
+
+ if( !$this->MatchChar(')') ){
+ return;
+ }
+
+ if ($name) {
+ return $this->NewObj4('Less_Tree_Call',array($name, $args, $index, $this->env->currentFileInfo) );
+ }
+ }
+
+ /**
+ * Parse a list of arguments
+ *
+ * @return array
+ */
+ private function parseEntitiesArguments(){
+
+ $args = array();
+ while( true ){
+ $arg = $this->MatchFuncs( array('parseEntitiesAssignment','parseExpression') );
+ if( !$arg ){
+ break;
+ }
+
+ $args[] = $arg;
+ if( !$this->MatchChar(',') ){
+ break;
+ }
+ }
+ return $args;
+ }
+
+ private function parseEntitiesLiteral(){
+ return $this->MatchFuncs( array('parseEntitiesDimension','parseEntitiesColor','parseEntitiesQuoted','parseUnicodeDescriptor') );
+ }
+
+ // Assignments are argument entities for calls.
+ // They are present in ie filter properties as shown below.
+ //
+ // filter: progid:DXImageTransform.Microsoft.Alpha( *opacity=50* )
+ //
+ private function parseEntitiesAssignment() {
+
+ $key = $this->MatchReg('/\\G\w+(?=\s?=)/');
+ if( !$key ){
+ return;
+ }
+
+ if( !$this->MatchChar('=') ){
+ return;
+ }
+
+ $value = $this->parseEntity();
+ if( $value ){
+ return $this->NewObj2('Less_Tree_Assignment',array($key[0], $value));
+ }
+ }
+
+ //
+ // Parse url() tokens
+ //
+ // We use a specific rule for urls, because they don't really behave like
+ // standard function calls. The difference is that the argument doesn't have
+ // to be enclosed within a string, so it can't be parsed as an Expression.
+ //
+ private function parseEntitiesUrl(){
+
+
+ if( $this->input[$this->pos] !== 'u' || !$this->matchReg('/\\Gurl\(/') ){
+ return;
+ }
+
+ $value = $this->match( array('parseEntitiesQuoted','parseEntitiesVariable','/\\Gdata\:.*?[^\)]+/','/\\G(?:(?:\\\\[\(\)\'"])|[^\(\)\'"])+/') );
+ if( !$value ){
+ $value = '';
+ }
+
+
+ $this->expectChar(')');
+
+
+ if( isset($value->value) || $value instanceof Less_Tree_Variable ){
+ return $this->NewObj2('Less_Tree_Url',array($value, $this->env->currentFileInfo));
+ }
+
+ return $this->NewObj2('Less_Tree_Url', array( $this->NewObj1('Less_Tree_Anonymous',$value), $this->env->currentFileInfo) );
+ }
+
+
+ //
+ // A Variable entity, such as `@fink`, in
+ //
+ // width: @fink + 2px
+ //
+ // We use a different parser for variable definitions,
+ // see `parsers.variable`.
+ //
+ private function parseEntitiesVariable(){
+ $index = $this->pos;
+ if ($this->PeekChar('@') && ($name = $this->MatchReg('/\\G@@?[\w-]+/'))) {
+ return $this->NewObj3('Less_Tree_Variable', array( $name[0], $index, $this->env->currentFileInfo));
+ }
+ }
+
+
+ // A variable entity useing the protective {} e.g. @{var}
+ private function parseEntitiesVariableCurly() {
+ $index = $this->pos;
+
+ if( $this->input_len > ($this->pos+1) && $this->input[$this->pos] === '@' && ($curly = $this->MatchReg('/\\G@\{([\w-]+)\}/')) ){
+ return $this->NewObj3('Less_Tree_Variable',array('@'.$curly[1], $index, $this->env->currentFileInfo));
+ }
+ }
+
+ //
+ // A Hexadecimal color
+ //
+ // #4F3C2F
+ //
+ // `rgb` and `hsl` colors are parsed through the `entities.call` parser.
+ //
+ private function parseEntitiesColor(){
+ if ($this->PeekChar('#') && ($rgb = $this->MatchReg('/\\G#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})/'))) {
+ return $this->NewObj1('Less_Tree_Color',$rgb[1]);
+ }
+ }
+
+ //
+ // A Dimension, that is, a number and a unit
+ //
+ // 0.5em 95%
+ //
+ private function parseEntitiesDimension(){
+
+ $c = @ord($this->input[$this->pos]);
+
+ //Is the first char of the dimension 0-9, '.', '+' or '-'
+ if (($c > 57 || $c < 43) || $c === 47 || $c == 44){
+ return;
+ }
+
+ $value = $this->MatchReg('/\\G([+-]?\d*\.?\d+)(%|[a-z]+)?/');
+ if( $value ){
+
+ if( isset($value[2]) ){
+ return $this->NewObj2('Less_Tree_Dimension', array($value[1],$value[2]));
+ }
+ return $this->NewObj1('Less_Tree_Dimension',$value[1]);
+ }
+ }
+
+
+ //
+ // A unicode descriptor, as is used in unicode-range
+ //
+ // U+0?? or U+00A1-00A9
+ //
+ function parseUnicodeDescriptor() {
+ $ud = $this->MatchReg('/\\G(U\+[0-9a-fA-F?]+)(\-[0-9a-fA-F?]+)?/');
+ if( $ud ){
+ return $this->NewObj1('Less_Tree_UnicodeDescriptor', $ud[0]);
+ }
+ }
+
+
+ //
+ // JavaScript code to be evaluated
+ //
+ // `window.location.href`
+ //
+ private function parseEntitiesJavascript(){
+ $e = false;
+ $j = $this->pos;
+ if( $this->input[$j] === '~' ){
+ $j++;
+ $e = true;
+ }
+ if( $this->input[$j] !== '`' ){
+ return;
+ }
+ if( $e ){
+ $this->MatchChar('~');
+ }
+ $str = $this->MatchReg('/\\G`([^`]*)`/');
+ if( $str ){
+ return $this->NewObj3('Less_Tree_Javascript', array($str[1], $this->pos, $e));
+ }
+ }
+
+
+ //
+ // The variable part of a variable definition. Used in the `rule` parser
+ //
+ // @fink:
+ //
+ private function parseVariable(){
+ if ($this->PeekChar('@') && ($name = $this->MatchReg('/\\G(@[\w-]+)\s*:/'))) {
+ return $name[1];
+ }
+ }
+
+
+ //
+ // The variable part of a variable definition. Used in the `rule` parser
+ //
+ // @fink();
+ //
+ private function parseRulesetCall(){
+
+ if( $this->input[$this->pos] === '@' && ($name = $this->MatchReg('/\\G(@[\w-]+)\s*\(\s*\)\s*;/')) ){
+ return $this->NewObj1('Less_Tree_RulesetCall', $name[1] );
+ }
+ }
+
+
+ //
+ // extend syntax - used to extend selectors
+ //
+ function parseExtend($isRule = false){
+
+ $index = $this->pos;
+ $extendList = array();
+
+
+ if( !$this->MatchReg( $isRule ? '/\\G&:extend\(/' : '/\\G:extend\(/' ) ){ return; }
+
+ do{
+ $option = null;
+ $elements = array();
+ while( true ){
+ $option = $this->MatchReg('/\\G(all)(?=\s*(\)|,))/');
+ if( $option ){ break; }
+ $e = $this->parseElement();
+ if( !$e ){ break; }
+ $elements[] = $e;
+ }
+
+ if( $option ){
+ $option = $option[1];
+ }
+
+ $extendList[] = $this->NewObj3('Less_Tree_Extend', array( $this->NewObj1('Less_Tree_Selector',$elements), $option, $index ));
+
+ }while( $this->MatchChar(",") );
+
+ $this->expect('/\\G\)/');
+
+ if( $isRule ){
+ $this->expect('/\\G;/');
+ }
+
+ return $extendList;
+ }
+
+
+ //
+ // A Mixin call, with an optional argument list
+ //
+ // #mixins > .square(#fff);
+ // .rounded(4px, black);
+ // .button;
+ //
+ // The `while` loop is there because mixins can be
+ // namespaced, but we only support the child and descendant
+ // selector for now.
+ //
+ private function parseMixinCall(){
+
+ $char = $this->input[$this->pos];
+ if( $char !== '.' && $char !== '#' ){
+ return;
+ }
+
+ $index = $this->pos;
+ $this->save(); // stop us absorbing part of an invalid selector
+
+ $elements = $this->parseMixinCallElements();
+
+ if( $elements ){
+
+ if( $this->MatchChar('(') ){
+ $returned = $this->parseMixinArgs(true);
+ $args = $returned['args'];
+ $this->expectChar(')');
+ }else{
+ $args = array();
+ }
+
+ $important = $this->parseImportant();
+
+ if( $this->parseEnd() ){
+ $this->forget();
+ return $this->NewObj5('Less_Tree_Mixin_Call', array( $elements, $args, $index, $this->env->currentFileInfo, $important));
+ }
+ }
+
+ $this->restore();
+ }
+
+
+ private function parseMixinCallElements(){
+ $elements = array();
+ $c = null;
+
+ while( true ){
+ $elemIndex = $this->pos;
+ $e = $this->MatchReg('/\\G[#.](?:[\w-]|\\\\(?:[A-Fa-f0-9]{1,6} ?|[^A-Fa-f0-9]))+/');
+ if( !$e ){
+ break;
+ }
+ $elements[] = $this->NewObj4('Less_Tree_Element', array($c, $e[0], $elemIndex, $this->env->currentFileInfo));
+ $c = $this->MatchChar('>');
+ }
+
+ return $elements;
+ }
+
+
+
+ /**
+ * @param boolean $isCall
+ */
+ private function parseMixinArgs( $isCall ){
+ $expressions = array();
+ $argsSemiColon = array();
+ $isSemiColonSeperated = null;
+ $argsComma = array();
+ $expressionContainsNamed = null;
+ $name = null;
+ $returner = array('args'=>array(), 'variadic'=> false);
+
+ $this->save();
+
+ while( true ){
+ if( $isCall ){
+ $arg = $this->MatchFuncs( array( 'parseDetachedRuleset','parseExpression' ) );
+ } else {
+ $this->parseComments();
+ if( $this->input[ $this->pos ] === '.' && $this->MatchReg('/\\G\.{3}/') ){
+ $returner['variadic'] = true;
+ if( $this->MatchChar(";") && !$isSemiColonSeperated ){
+ $isSemiColonSeperated = true;
+ }
+
+ if( $isSemiColonSeperated ){
+ $argsSemiColon[] = array('variadic'=>true);
+ }else{
+ $argsComma[] = array('variadic'=>true);
+ }
+ break;
+ }
+ $arg = $this->MatchFuncs( array('parseEntitiesVariable','parseEntitiesLiteral','parseEntitiesKeyword') );
+ }
+
+ if( !$arg ){
+ break;
+ }
+
+
+ $nameLoop = null;
+ if( $arg instanceof Less_Tree_Expression ){
+ $arg->throwAwayComments();
+ }
+ $value = $arg;
+ $val = null;
+
+ if( $isCall ){
+ // Variable
+ if( property_exists($arg,'value') && count($arg->value) == 1 ){
+ $val = $arg->value[0];
+ }
+ } else {
+ $val = $arg;
+ }
+
+
+ if( $val instanceof Less_Tree_Variable ){
+
+ if( $this->MatchChar(':') ){
+ if( $expressions ){
+ if( $isSemiColonSeperated ){
+ $this->Error('Cannot mix ; and , as delimiter types');
+ }
+ $expressionContainsNamed = true;
+ }
+
+ // we do not support setting a ruleset as a default variable - it doesn't make sense
+ // However if we do want to add it, there is nothing blocking it, just don't error
+ // and remove isCall dependency below
+ $value = null;
+ if( $isCall ){
+ $value = $this->parseDetachedRuleset();
+ }
+ if( !$value ){
+ $value = $this->parseExpression();
+ }
+
+ if( !$value ){
+ if( $isCall ){
+ $this->Error('could not understand value for named argument');
+ } else {
+ $this->restore();
+ $returner['args'] = array();
+ return $returner;
+ }
+ }
+
+ $nameLoop = ($name = $val->name);
+ }elseif( !$isCall && $this->MatchReg('/\\G\.{3}/') ){
+ $returner['variadic'] = true;
+ if( $this->MatchChar(";") && !$isSemiColonSeperated ){
+ $isSemiColonSeperated = true;
+ }
+ if( $isSemiColonSeperated ){
+ $argsSemiColon[] = array('name'=> $arg->name, 'variadic' => true);
+ }else{
+ $argsComma[] = array('name'=> $arg->name, 'variadic' => true);
+ }
+ break;
+ }elseif( !$isCall ){
+ $name = $nameLoop = $val->name;
+ $value = null;
+ }
+ }
+
+ if( $value ){
+ $expressions[] = $value;
+ }
+
+ $argsComma[] = array('name'=>$nameLoop, 'value'=>$value );
+
+ if( $this->MatchChar(',') ){
+ continue;
+ }
+
+ if( $this->MatchChar(';') || $isSemiColonSeperated ){
+
+ if( $expressionContainsNamed ){
+ $this->Error('Cannot mix ; and , as delimiter types');
+ }
+
+ $isSemiColonSeperated = true;
+
+ if( count($expressions) > 1 ){
+ $value = $this->NewObj1('Less_Tree_Value', $expressions);
+ }
+ $argsSemiColon[] = array('name'=>$name, 'value'=>$value );
+
+ $name = null;
+ $expressions = array();
+ $expressionContainsNamed = false;
+ }
+ }
+
+ $this->forget();
+ $returner['args'] = ($isSemiColonSeperated ? $argsSemiColon : $argsComma);
+ return $returner;
+ }
+
+
+
+ //
+ // A Mixin definition, with a list of parameters
+ //
+ // .rounded (@radius: 2px, @color) {
+ // ...
+ // }
+ //
+ // Until we have a finer grained state-machine, we have to
+ // do a look-ahead, to make sure we don't have a mixin call.
+ // See the `rule` function for more information.
+ //
+ // We start by matching `.rounded (`, and then proceed on to
+ // the argument list, which has optional default values.
+ // We store the parameters in `params`, with a `value` key,
+ // if there is a value, such as in the case of `@radius`.
+ //
+ // Once we've got our params list, and a closing `)`, we parse
+ // the `{...}` block.
+ //
+ private function parseMixinDefinition(){
+ $cond = null;
+
+ $char = $this->input[$this->pos];
+ if( ($char !== '.' && $char !== '#') || ($char === '{' && $this->PeekReg('/\\G[^{]*\}/')) ){
+ return;
+ }
+
+ $this->save();
+
+ $match = $this->MatchReg('/\\G([#.](?:[\w-]|\\\(?:[A-Fa-f0-9]{1,6} ?|[^A-Fa-f0-9]))+)\s*\(/');
+ if( $match ){
+ $name = $match[1];
+
+ $argInfo = $this->parseMixinArgs( false );
+ $params = $argInfo['args'];
+ $variadic = $argInfo['variadic'];
+
+
+ // .mixincall("@{a}");
+ // looks a bit like a mixin definition..
+ // also
+ // .mixincall(@a: {rule: set;});
+ // so we have to be nice and restore
+ if( !$this->MatchChar(')') ){
+ $this->furthest = $this->pos;
+ $this->restore();
+ return;
+ }
+
+
+ $this->parseComments();
+
+ if ($this->MatchReg('/\\Gwhen/')) { // Guard
+ $cond = $this->expect('parseConditions', 'Expected conditions');
+ }
+
+ $ruleset = $this->parseBlock();
+
+ if( is_array($ruleset) ){
+ $this->forget();
+ return $this->NewObj5('Less_Tree_Mixin_Definition', array( $name, $params, $ruleset, $cond, $variadic));
+ }
+
+ $this->restore();
+ }else{
+ $this->forget();
+ }
+ }
+
+ //
+ // Entities are the smallest recognized token,
+ // and can be found inside a rule's value.
+ //
+ private function parseEntity(){
+
+ return $this->MatchFuncs( array('parseEntitiesLiteral','parseEntitiesVariable','parseEntitiesUrl','parseEntitiesCall','parseEntitiesKeyword','parseEntitiesJavascript','parseComment') );
+ }
+
+ //
+ // A Rule terminator. Note that we use `peek()` to check for '}',
+ // because the `block` rule will be expecting it, but we still need to make sure
+ // it's there, if ';' was ommitted.
+ //
+ private function parseEnd(){
+ return $this->MatchChar(';') || $this->PeekChar('}');
+ }
+
+ //
+ // IE's alpha function
+ //
+ // alpha(opacity=88)
+ //
+ private function parseAlpha(){
+
+ if ( ! $this->MatchReg('/\\G\(opacity=/i')) {
+ return;
+ }
+
+ $value = $this->MatchReg('/\\G[0-9]+/');
+ if( $value ){
+ $value = $value[0];
+ }else{
+ $value = $this->parseEntitiesVariable();
+ if( !$value ){
+ return;
+ }
+ }
+
+ $this->expectChar(')');
+ return $this->NewObj1('Less_Tree_Alpha',$value);
+ }
+
+
+ //
+ // A Selector Element
+ //
+ // div
+ // + h1
+ // #socks
+ // input[type="text"]
+ //
+ // Elements are the building blocks for Selectors,
+ // they are made out of a `Combinator` (see combinator rule),
+ // and an element name, such as a tag a class, or `*`.
+ //
+ private function parseElement(){
+ $c = $this->parseCombinator();
+ $index = $this->pos;
+
+ $e = $this->match( array('/\\G(?:\d+\.\d+|\d+)%/', '/\\G(?:[.#]?|:*)(?:[\w-]|[^\x00-\x9f]|\\\\(?:[A-Fa-f0-9]{1,6} ?|[^A-Fa-f0-9]))+/',
+ '#*', '#&', 'parseAttribute', '/\\G\([^()@]+\)/', '/\\G[\.#](?=@)/', 'parseEntitiesVariableCurly') );
+
+ if( is_null($e) ){
+ $this->save();
+ if( $this->MatchChar('(') ){
+ if( ($v = $this->parseSelector()) && $this->MatchChar(')') ){
+ $e = $this->NewObj1('Less_Tree_Paren',$v);
+ $this->forget();
+ }else{
+ $this->restore();
+ }
+ }else{
+ $this->forget();
+ }
+ }
+
+ if( !is_null($e) ){
+ return $this->NewObj4('Less_Tree_Element',array( $c, $e, $index, $this->env->currentFileInfo));
+ }
+ }
+
+ //
+ // Combinators combine elements together, in a Selector.
+ //
+ // Because our parser isn't white-space sensitive, special care
+ // has to be taken, when parsing the descendant combinator, ` `,
+ // as it's an empty space. We have to check the previous character
+ // in the input, to see if it's a ` ` character.
+ //
+ private function parseCombinator(){
+ if( $this->pos < $this->input_len ){
+ $c = $this->input[$this->pos];
+ if ($c === '>' || $c === '+' || $c === '~' || $c === '|' || $c === '^' ){
+
+ $this->pos++;
+ if( $this->input[$this->pos] === '^' ){
+ $c = '^^';
+ $this->pos++;
+ }
+
+ $this->skipWhitespace(0);
+
+ return $c;
+ }
+
+ if( $this->pos > 0 && $this->isWhitespace(-1) ){
+ return ' ';
+ }
+ }
+ }
+
+ //
+ // A CSS selector (see selector below)
+ // with less extensions e.g. the ability to extend and guard
+ //
+ private function parseLessSelector(){
+ return $this->parseSelector(true);
+ }
+
+ //
+ // A CSS Selector
+ //
+ // .class > div + h1
+ // li a:hover
+ //
+ // Selectors are made out of one or more Elements, see above.
+ //
+ private function parseSelector( $isLess = false ){
+ $elements = array();
+ $extendList = array();
+ $condition = null;
+ $when = false;
+ $extend = false;
+ $e = null;
+ $c = null;
+ $index = $this->pos;
+
+ while( ($isLess && ($extend = $this->parseExtend())) || ($isLess && ($when = $this->MatchReg('/\\Gwhen/') )) || ($e = $this->parseElement()) ){
+ if( $when ){
+ $condition = $this->expect('parseConditions', 'expected condition');
+ }elseif( $condition ){
+ //error("CSS guard can only be used at the end of selector");
+ }elseif( $extend ){
+ $extendList = array_merge($extendList,$extend);
+ }else{
+ //if( count($extendList) ){
+ //error("Extend can only be used at the end of selector");
+ //}
+ if( $this->pos < $this->input_len ){
+ $c = $this->input[ $this->pos ];
+ }
+ $elements[] = $e;
+ $e = null;
+ }
+
+ if( $c === '{' || $c === '}' || $c === ';' || $c === ',' || $c === ')') { break; }
+ }
+
+ if( $elements ){
+ return $this->NewObj5('Less_Tree_Selector',array($elements, $extendList, $condition, $index, $this->env->currentFileInfo));
+ }
+ if( $extendList ) {
+ $this->Error('Extend must be used to extend a selector, it cannot be used on its own');
+ }
+ }
+
+ private function parseTag(){
+ return ( $tag = $this->MatchReg('/\\G[A-Za-z][A-Za-z-]*[0-9]?/') ) ? $tag : $this->MatchChar('*');
+ }
+
+ private function parseAttribute(){
+
+ $val = null;
+
+ if( !$this->MatchChar('[') ){
+ return;
+ }
+
+ $key = $this->parseEntitiesVariableCurly();
+ if( !$key ){
+ $key = $this->expect('/\\G(?:[_A-Za-z0-9-\*]*\|)?(?:[_A-Za-z0-9-]|\\\\.)+/');
+ }
+
+ $op = $this->MatchReg('/\\G[|~*$^]?=/');
+ if( $op ){
+ $val = $this->match( array('parseEntitiesQuoted','/\\G[0-9]+%/','/\\G[\w-]+/','parseEntitiesVariableCurly') );
+ }
+
+ $this->expectChar(']');
+
+ return $this->NewObj3('Less_Tree_Attribute',array( $key, $op[0], $val));
+ }
+
+ //
+ // The `block` rule is used by `ruleset` and `mixin.definition`.
+ // It's a wrapper around the `primary` rule, with added `{}`.
+ //
+ private function parseBlock(){
+ if( $this->MatchChar('{') ){
+ $content = $this->parsePrimary();
+ if( $this->MatchChar('}') ){
+ return $content;
+ }
+ }
+ }
+
+ private function parseBlockRuleset(){
+ $block = $this->parseBlock();
+
+ if( $block ){
+ $block = $this->NewObj2('Less_Tree_Ruleset',array( null, $block));
+ }
+
+ return $block;
+ }
+
+ private function parseDetachedRuleset(){
+ $blockRuleset = $this->parseBlockRuleset();
+ if( $blockRuleset ){
+ return $this->NewObj1('Less_Tree_DetachedRuleset',$blockRuleset);
+ }
+ }
+
+ //
+ // div, .class, body > p {...}
+ //
+ private function parseRuleset(){
+ $selectors = array();
+
+ $this->save();
+
+ while( true ){
+ $s = $this->parseLessSelector();
+ if( !$s ){
+ break;
+ }
+ $selectors[] = $s;
+ $this->parseComments();
+
+ if( $s->condition && count($selectors) > 1 ){
+ $this->Error('Guards are only currently allowed on a single selector.');
+ }
+
+ if( !$this->MatchChar(',') ){
+ break;
+ }
+ if( $s->condition ){
+ $this->Error('Guards are only currently allowed on a single selector.');
+ }
+ $this->parseComments();
+ }
+
+
+ if( $selectors ){
+ $rules = $this->parseBlock();
+ if( is_array($rules) ){
+ $this->forget();
+ return $this->NewObj2('Less_Tree_Ruleset',array( $selectors, $rules)); //Less_Environment::$strictImports
+ }
+ }
+
+ // Backtrack
+ $this->furthest = $this->pos;
+ $this->restore();
+ }
+
+ /**
+ * Custom less.php parse function for finding simple name-value css pairs
+ * ex: width:100px;
+ *
+ */
+ private function parseNameValue(){
+
+ $index = $this->pos;
+ $this->save();
+
+
+ //$match = $this->MatchReg('/\\G([a-zA-Z\-]+)\s*:\s*((?:\'")?[a-zA-Z0-9\-% \.,!]+?(?:\'")?)\s*([;}])/');
+ $match = $this->MatchReg('/\\G([a-zA-Z\-]+)\s*:\s*([\'"]?[#a-zA-Z0-9\-%\.,]+?[\'"]?) *(! *important)?\s*([;}])/');
+ if( $match ){
+
+ if( $match[4] == '}' ){
+ $this->pos = $index + strlen($match[0])-1;
+ }
+
+ if( $match[3] ){
+ $match[2] .= ' !important';
+ }
+
+ return $this->NewObj4('Less_Tree_NameValue',array( $match[1], $match[2], $index, $this->env->currentFileInfo));
+ }
+
+ $this->restore();
+ }
+
+
+ private function parseRule( $tryAnonymous = null ){
+
+ $merge = false;
+ $startOfRule = $this->pos;
+
+ $c = $this->input[$this->pos];
+ if( $c === '.' || $c === '#' || $c === '&' ){
+ return;
+ }
+
+ $this->save();
+ $name = $this->MatchFuncs( array('parseVariable','parseRuleProperty'));
+
+ if( $name ){
+
+ $isVariable = is_string($name);
+
+ $value = null;
+ if( $isVariable ){
+ $value = $this->parseDetachedRuleset();
+ }
+
+ $important = null;
+ if( !$value ){
+
+ // prefer to try to parse first if its a variable or we are compressing
+ // but always fallback on the other one
+ //if( !$tryAnonymous && is_string($name) && $name[0] === '@' ){
+ if( !$tryAnonymous && (Less_Parser::$options['compress'] || $isVariable) ){
+ $value = $this->MatchFuncs( array('parseValue','parseAnonymousValue'));
+ }else{
+ $value = $this->MatchFuncs( array('parseAnonymousValue','parseValue'));
+ }
+
+ $important = $this->parseImportant();
+
+ // a name returned by this.ruleProperty() is always an array of the form:
+ // [string-1, ..., string-n, ""] or [string-1, ..., string-n, "+"]
+ // where each item is a tree.Keyword or tree.Variable
+ if( !$isVariable && is_array($name) ){
+ $nm = array_pop($name);
+ if( $nm->value ){
+ $merge = $nm->value;
+ }
+ }
+ }
+
+
+ if( $value && $this->parseEnd() ){
+ $this->forget();
+ return $this->NewObj6('Less_Tree_Rule',array( $name, $value, $important, $merge, $startOfRule, $this->env->currentFileInfo));
+ }else{
+ $this->furthest = $this->pos;
+ $this->restore();
+ if( $value && !$tryAnonymous ){
+ return $this->parseRule(true);
+ }
+ }
+ }else{
+ $this->forget();
+ }
+ }
+
+ function parseAnonymousValue(){
+
+ if( preg_match('/\\G([^@+\/\'"*`(;{}-]*);/',$this->input, $match, 0, $this->pos) ){
+ $this->pos += strlen($match[1]);
+ return $this->NewObj1('Less_Tree_Anonymous',$match[1]);
+ }
+ }
+
+ //
+ // An @import directive
+ //
+ // @import "lib";
+ //
+ // Depending on our environment, importing is done differently:
+ // In the browser, it's an XHR request, in Node, it would be a
+ // file-system operation. The function used for importing is
+ // stored in `import`, which we pass to the Import constructor.
+ //
+ private function parseImport(){
+
+ $this->save();
+
+ $dir = $this->MatchReg('/\\G@import?\s+/');
+
+ if( $dir ){
+ $options = $this->parseImportOptions();
+ $path = $this->MatchFuncs( array('parseEntitiesQuoted','parseEntitiesUrl'));
+
+ if( $path ){
+ $features = $this->parseMediaFeatures();
+ if( $this->MatchChar(';') ){
+ if( $features ){
+ $features = $this->NewObj1('Less_Tree_Value',$features);
+ }
+
+ $this->forget();
+ return $this->NewObj5('Less_Tree_Import',array( $path, $features, $options, $this->pos, $this->env->currentFileInfo));
+ }
+ }
+ }
+
+ $this->restore();
+ }
+
+ private function parseImportOptions(){
+
+ $options = array();
+
+ // list of options, surrounded by parens
+ if( !$this->MatchChar('(') ){
+ return $options;
+ }
+ do{
+ $optionName = $this->parseImportOption();
+ if( $optionName ){
+ $value = true;
+ switch( $optionName ){
+ case "css":
+ $optionName = "less";
+ $value = false;
+ break;
+ case "once":
+ $optionName = "multiple";
+ $value = false;
+ break;
+ }
+ $options[$optionName] = $value;
+ if( !$this->MatchChar(',') ){ break; }
+ }
+ }while( $optionName );
+ $this->expectChar(')');
+ return $options;
+ }
+
+ private function parseImportOption(){
+ $opt = $this->MatchReg('/\\G(less|css|multiple|once|inline|reference)/');
+ if( $opt ){
+ return $opt[1];
+ }
+ }
+
+ private function parseMediaFeature() {
+ $nodes = array();
+
+ do{
+ $e = $this->MatchFuncs(array('parseEntitiesKeyword','parseEntitiesVariable'));
+ if( $e ){
+ $nodes[] = $e;
+ } elseif ($this->MatchChar('(')) {
+ $p = $this->parseProperty();
+ $e = $this->parseValue();
+ if ($this->MatchChar(')')) {
+ if ($p && $e) {
+ $r = $this->NewObj7('Less_Tree_Rule', array( $p, $e, null, null, $this->pos, $this->env->currentFileInfo, true));
+ $nodes[] = $this->NewObj1('Less_Tree_Paren',$r);
+ } elseif ($e) {
+ $nodes[] = $this->NewObj1('Less_Tree_Paren',$e);
+ } else {
+ return null;
+ }
+ } else
+ return null;
+ }
+ } while ($e);
+
+ if ($nodes) {
+ return $this->NewObj1('Less_Tree_Expression',$nodes);
+ }
+ }
+
+ private function parseMediaFeatures() {
+ $features = array();
+
+ do{
+ $e = $this->parseMediaFeature();
+ if( $e ){
+ $features[] = $e;
+ if (!$this->MatchChar(',')) break;
+ }else{
+ $e = $this->parseEntitiesVariable();
+ if( $e ){
+ $features[] = $e;
+ if (!$this->MatchChar(',')) break;
+ }
+ }
+ } while ($e);
+
+ return $features ? $features : null;
+ }
+
+ private function parseMedia() {
+ if( $this->MatchReg('/\\G@media/') ){
+ $features = $this->parseMediaFeatures();
+ $rules = $this->parseBlock();
+
+ if( is_array($rules) ){
+ return $this->NewObj4('Less_Tree_Media',array( $rules, $features, $this->pos, $this->env->currentFileInfo));
+ }
+ }
+ }
+
+
+ //
+ // A CSS Directive
+ //
+ // @charset "utf-8";
+ //
+ private function parseDirective(){
+
+ if( !$this->PeekChar('@') ){
+ return;
+ }
+
+ $rules = null;
+ $index = $this->pos;
+ $hasBlock = true;
+ $hasIdentifier = false;
+ $hasExpression = false;
+ $hasUnknown = false;
+
+
+ $value = $this->MatchFuncs(array('parseImport','parseMedia'));
+ if( $value ){
+ return $value;
+ }
+
+ $this->save();
+
+ $name = $this->MatchReg('/\\G@[a-z-]+/');
+
+ if( !$name ) return;
+ $name = $name[0];
+
+
+ $nonVendorSpecificName = $name;
+ $pos = strpos($name,'-', 2);
+ if( $name[1] == '-' && $pos > 0 ){
+ $nonVendorSpecificName = "@" . substr($name, $pos + 1);
+ }
+
+
+ switch( $nonVendorSpecificName ){
+ /*
+ case "@font-face":
+ case "@viewport":
+ case "@top-left":
+ case "@top-left-corner":
+ case "@top-center":
+ case "@top-right":
+ case "@top-right-corner":
+ case "@bottom-left":
+ case "@bottom-left-corner":
+ case "@bottom-center":
+ case "@bottom-right":
+ case "@bottom-right-corner":
+ case "@left-top":
+ case "@left-middle":
+ case "@left-bottom":
+ case "@right-top":
+ case "@right-middle":
+ case "@right-bottom":
+ hasBlock = true;
+ break;
+ */
+ case "@charset":
+ $hasIdentifier = true;
+ $hasBlock = false;
+ break;
+ case "@namespace":
+ $hasExpression = true;
+ $hasBlock = false;
+ break;
+ case "@keyframes":
+ $hasIdentifier = true;
+ break;
+ case "@host":
+ case "@page":
+ case "@document":
+ case "@supports":
+ $hasUnknown = true;
+ break;
+ }
+
+ if( $hasIdentifier ){
+ $value = $this->parseEntity();
+ if( !$value ){
+ $this->error("expected " . $name . " identifier");
+ }
+ } else if( $hasExpression ){
+ $value = $this->parseExpression();
+ if( !$value ){
+ $this->error("expected " . $name. " expression");
+ }
+ } else if ($hasUnknown) {
+
+ $value = $this->MatchReg('/\\G[^{;]+/');
+ if( $value ){
+ $value = $this->NewObj1('Less_Tree_Anonymous',trim($value[0]));
+ }
+ }
+
+ if( $hasBlock ){
+ $rules = $this->parseBlockRuleset();
+ }
+
+ if( $rules || (!$hasBlock && $value && $this->MatchChar(';'))) {
+ $this->forget();
+ return $this->NewObj5('Less_Tree_Directive',array($name, $value, $rules, $index, $this->env->currentFileInfo));
+ }
+
+ $this->restore();
+ }
+
+
+ //
+ // A Value is a comma-delimited list of Expressions
+ //
+ // font-family: Baskerville, Georgia, serif;
+ //
+ // In a Rule, a Value represents everything after the `:`,
+ // and before the `;`.
+ //
+ private function parseValue(){
+ $expressions = array();
+
+ do{
+ $e = $this->parseExpression();
+ if( $e ){
+ $expressions[] = $e;
+ if (! $this->MatchChar(',')) {
+ break;
+ }
+ }
+ }while($e);
+
+ if( $expressions ){
+ return $this->NewObj1('Less_Tree_Value',$expressions);
+ }
+ }
+
+ private function parseImportant (){
+ if( $this->PeekChar('!') && $this->MatchReg('/\\G! *important/') ){
+ return ' !important';
+ }
+ }
+
+ private function parseSub (){
+
+ if( $this->MatchChar('(') ){
+ $a = $this->parseAddition();
+ if( $a ){
+ $this->expectChar(')');
+ return $this->NewObj2('Less_Tree_Expression',array( array($a), true) ); //instead of $e->parens = true so the value is cached
+ }
+ }
+ }
+
+
+ /**
+ * Parses multiplication operation
+ *
+ * @return Less_Tree_Operation|null
+ */
+ function parseMultiplication(){
+
+ $return = $m = $this->parseOperand();
+ if( $return ){
+ while( true ){
+
+ $isSpaced = $this->isWhitespace( -1 );
+
+ if( $this->PeekReg('/\\G\/[*\/]/') ){
+ break;
+ }
+
+ $op = $this->MatchChar('/');
+ if( !$op ){
+ $op = $this->MatchChar('*');
+ if( !$op ){
+ break;
+ }
+ }
+
+ $a = $this->parseOperand();
+
+ if(!$a) { break; }
+
+ $m->parensInOp = true;
+ $a->parensInOp = true;
+ $return = $this->NewObj3('Less_Tree_Operation',array( $op, array( $return, $a ), $isSpaced) );
+ }
+ }
+ return $return;
+
+ }
+
+
+ /**
+ * Parses an addition operation
+ *
+ * @return Less_Tree_Operation|null
+ */
+ private function parseAddition (){
+
+ $return = $m = $this->parseMultiplication();
+ if( $return ){
+ while( true ){
+
+ $isSpaced = $this->isWhitespace( -1 );
+
+ $op = $this->MatchReg('/\\G[-+]\s+/');
+ if( $op ){
+ $op = $op[0];
+ }else{
+ if( !$isSpaced ){
+ $op = $this->match(array('#+','#-'));
+ }
+ if( !$op ){
+ break;
+ }
+ }
+
+ $a = $this->parseMultiplication();
+ if( !$a ){
+ break;
+ }
+
+ $m->parensInOp = true;
+ $a->parensInOp = true;
+ $return = $this->NewObj3('Less_Tree_Operation',array($op, array($return, $a), $isSpaced));
+ }
+ }
+
+ return $return;
+ }
+
+
+ /**
+ * Parses the conditions
+ *
+ * @return Less_Tree_Condition|null
+ */
+ private function parseConditions() {
+ $index = $this->pos;
+ $return = $a = $this->parseCondition();
+ if( $a ){
+ while( true ){
+ if( !$this->PeekReg('/\\G,\s*(not\s*)?\(/') || !$this->MatchChar(',') ){
+ break;
+ }
+ $b = $this->parseCondition();
+ if( !$b ){
+ break;
+ }
+
+ $return = $this->NewObj4('Less_Tree_Condition',array('or', $return, $b, $index));
+ }
+ return $return;
+ }
+ }
+
+ private function parseCondition() {
+ $index = $this->pos;
+ $negate = false;
+ $c = null;
+
+ if ($this->MatchReg('/\\Gnot/')) $negate = true;
+ $this->expectChar('(');
+ $a = $this->MatchFuncs(array('parseAddition','parseEntitiesKeyword','parseEntitiesQuoted'));
+
+ if( $a ){
+ $op = $this->MatchReg('/\\G(?:>=|<=|=<|[<=>])/');
+ if( $op ){
+ $b = $this->MatchFuncs(array('parseAddition','parseEntitiesKeyword','parseEntitiesQuoted'));
+ if( $b ){
+ $c = $this->NewObj5('Less_Tree_Condition',array($op[0], $a, $b, $index, $negate));
+ } else {
+ $this->Error('Unexpected expression');
+ }
+ } else {
+ $k = $this->NewObj1('Less_Tree_Keyword','true');
+ $c = $this->NewObj5('Less_Tree_Condition',array('=', $a, $k, $index, $negate));
+ }
+ $this->expectChar(')');
+ return $this->MatchReg('/\\Gand/') ? $this->NewObj3('Less_Tree_Condition',array('and', $c, $this->parseCondition())) : $c;
+ }
+ }
+
+ /**
+ * An operand is anything that can be part of an operation,
+ * such as a Color, or a Variable
+ *
+ */
+ private function parseOperand (){
+
+ $negate = false;
+ $offset = $this->pos+1;
+ if( $offset >= $this->input_len ){
+ return;
+ }
+ $char = $this->input[$offset];
+ if( $char === '@' || $char === '(' ){
+ $negate = $this->MatchChar('-');
+ }
+
+ $o = $this->MatchFuncs(array('parseSub','parseEntitiesDimension','parseEntitiesColor','parseEntitiesVariable','parseEntitiesCall'));
+
+ if( $negate ){
+ $o->parensInOp = true;
+ $o = $this->NewObj1('Less_Tree_Negative',$o);
+ }
+
+ return $o;
+ }
+
+
+ /**
+ * Expressions either represent mathematical operations,
+ * or white-space delimited Entities.
+ *
+ * 1px solid black
+ * @var * 2
+ *
+ * @return Less_Tree_Expression|null
+ */
+ private function parseExpression (){
+ $entities = array();
+
+ do{
+ $e = $this->MatchFuncs(array('parseAddition','parseEntity'));
+ if( $e ){
+ $entities[] = $e;
+ // operations do not allow keyword "/" dimension (e.g. small/20px) so we support that here
+ if( !$this->PeekReg('/\\G\/[\/*]/') ){
+ $delim = $this->MatchChar('/');
+ if( $delim ){
+ $entities[] = $this->NewObj1('Less_Tree_Anonymous',$delim);
+ }
+ }
+ }
+ }while($e);
+
+ if( $entities ){
+ return $this->NewObj1('Less_Tree_Expression',$entities);
+ }
+ }
+
+
+ /**
+ * Parse a property
+ * eg: 'min-width', 'orientation', etc
+ *
+ * @return string
+ */
+ private function parseProperty (){
+ $name = $this->MatchReg('/\\G(\*?-?[_a-zA-Z0-9-]+)\s*:/');
+ if( $name ){
+ return $name[1];
+ }
+ }
+
+
+ /**
+ * Parse a rule property
+ * eg: 'color', 'width', 'height', etc
+ *
+ * @return string
+ */
+ private function parseRuleProperty(){
+ $offset = $this->pos;
+ $name = array();
+ $index = array();
+ $length = 0;
+
+
+ $this->rulePropertyMatch('/\\G(\*?)/', $offset, $length, $index, $name );
+ while( $this->rulePropertyMatch('/\\G((?:[\w-]+)|(?:@\{[\w-]+\}))/', $offset, $length, $index, $name )); // !
+
+ if( (count($name) > 1) && $this->rulePropertyMatch('/\\G\s*((?:\+_|\+)?)\s*:/', $offset, $length, $index, $name) ){
+ // at last, we have the complete match now. move forward,
+ // convert name particles to tree objects and return:
+ $this->skipWhitespace($length);
+
+ if( $name[0] === '' ){
+ array_shift($name);
+ array_shift($index);
+ }
+ foreach($name as $k => $s ){
+ if( !$s || $s[0] !== '@' ){
+ $name[$k] = $this->NewObj1('Less_Tree_Keyword',$s);
+ }else{
+ $name[$k] = $this->NewObj3('Less_Tree_Variable',array('@' . substr($s,2,-1), $index[$k], $this->env->currentFileInfo));
+ }
+ }
+ return $name;
+ }
+
+
+ }
+
+ private function rulePropertyMatch( $re, &$offset, &$length, &$index, &$name ){
+ preg_match($re, $this->input, $a, 0, $offset);
+ if( $a ){
+ $index[] = $this->pos + $length;
+ $length += strlen($a[0]);
+ $offset += strlen($a[0]);
+ $name[] = $a[1];
+ return true;
+ }
+ }
+
+ public static function serializeVars( $vars ){
+ $s = '';
+
+ foreach($vars as $name => $value){
+ $s .= (($name[0] === '@') ? '' : '@') . $name .': '. $value . ((substr($value,-1) === ';') ? '' : ';');
+ }
+
+ return $s;
+ }
+
+
+ /**
+ * Some versions of php have trouble with method_exists($a,$b) if $a is not an object
+ *
+ * @param string $b
+ */
+ public static function is_method($a,$b){
+ return is_object($a) && method_exists($a,$b);
+ }
+
+
+ /**
+ * Round numbers similarly to javascript
+ * eg: 1.499999 to 1 instead of 2
+ *
+ */
+ public static function round($i, $precision = 0){
+
+ $precision = pow(10,$precision);
+ $i = $i*$precision;
+
+ $ceil = ceil($i);
+ $floor = floor($i);
+ if( ($ceil - $i) <= ($i - $floor) ){
+ return $ceil/$precision;
+ }else{
+ return $floor/$precision;
+ }
+ }
+
+
+ /**
+ * Create Less_Tree_* objects and optionally generate a cache string
+ *
+ * @return mixed
+ */
+ public function NewObj0($class){
+ $obj = new $class();
+ if( $this->CacheEnabled() ){
+ $obj->cache_string = ' new '.$class.'()';
+ }
+ return $obj;
+ }
+
+ public function NewObj1($class, $arg){
+ $obj = new $class( $arg );
+ if( $this->CacheEnabled() ){
+ $obj->cache_string = ' new '.$class.'('.Less_Parser::ArgString($arg).')';
+ }
+ return $obj;
+ }
+
+ public function NewObj2($class, $args){
+ $obj = new $class( $args[0], $args[1] );
+ if( $this->CacheEnabled() ){
+ $this->ObjCache( $obj, $class, $args);
+ }
+ return $obj;
+ }
+
+ public function NewObj3($class, $args){
+ $obj = new $class( $args[0], $args[1], $args[2] );
+ if( $this->CacheEnabled() ){
+ $this->ObjCache( $obj, $class, $args);
+ }
+ return $obj;
+ }
+
+ public function NewObj4($class, $args){
+ $obj = new $class( $args[0], $args[1], $args[2], $args[3] );
+ if( $this->CacheEnabled() ){
+ $this->ObjCache( $obj, $class, $args);
+ }
+ return $obj;
+ }
+
+ public function NewObj5($class, $args){
+ $obj = new $class( $args[0], $args[1], $args[2], $args[3], $args[4] );
+ if( $this->CacheEnabled() ){
+ $this->ObjCache( $obj, $class, $args);
+ }
+ return $obj;
+ }
+
+ public function NewObj6($class, $args){
+ $obj = new $class( $args[0], $args[1], $args[2], $args[3], $args[4], $args[5] );
+ if( $this->CacheEnabled() ){
+ $this->ObjCache( $obj, $class, $args);
+ }
+ return $obj;
+ }
+
+ public function NewObj7($class, $args){
+ $obj = new $class( $args[0], $args[1], $args[2], $args[3], $args[4], $args[5], $args[6] );
+ if( $this->CacheEnabled() ){
+ $this->ObjCache( $obj, $class, $args);
+ }
+ return $obj;
+ }
+
+ //caching
+ public function ObjCache($obj, $class, $args=array()){
+ $obj->cache_string = ' new '.$class.'('. self::ArgCache($args).')';
+ }
+
+ public function ArgCache($args){
+ return implode(',',array_map( array('Less_Parser','ArgString'),$args));
+ }
+
+
+ /**
+ * Convert an argument to a string for use in the parser cache
+ *
+ * @return string
+ */
+ public static function ArgString($arg){
+
+ $type = gettype($arg);
+
+ if( $type === 'object'){
+ $string = $arg->cache_string;
+ unset($arg->cache_string);
+ return $string;
+
+ }elseif( $type === 'array' ){
+ $string = ' Array(';
+ foreach($arg as $k => $a){
+ $string .= var_export($k,true).' => '.self::ArgString($a).',';
+ }
+ return $string . ')';
+ }
+
+ return var_export($arg,true);
+ }
+
+ public function Error($msg){
+ throw new Less_Exception_Parser($msg, null, $this->furthest, $this->env->currentFileInfo);
+ }
+
+ public static function WinPath($path){
+ return str_replace('\\', '/', $path);
+ }
+
+ public function CacheEnabled(){
+ return (Less_Parser::$options['cache_method'] && (Less_Cache::$cache_dir || (Less_Parser::$options['cache_method'] == 'callback')));
+ }
+
+}
+
+
diff --git a/vendor/oyejorge/less.php/lib/Less/SourceMap/Base64VLQ.php b/vendor/oyejorge/less.php/lib/Less/SourceMap/Base64VLQ.php
new file mode 100644
index 00000000..f5b200c3
--- /dev/null
+++ b/vendor/oyejorge/less.php/lib/Less/SourceMap/Base64VLQ.php
@@ -0,0 +1,187 @@
+<?php
+
+/**
+ * Encode / Decode Base64 VLQ.
+ *
+ * @package Less
+ * @subpackage SourceMap
+ */
+class Less_SourceMap_Base64VLQ {
+
+ /**
+ * Shift
+ *
+ * @var integer
+ */
+ private $shift = 5;
+
+ /**
+ * Mask
+ *
+ * @var integer
+ */
+ private $mask = 0x1F; // == (1 << shift) == 0b00011111
+
+ /**
+ * Continuation bit
+ *
+ * @var integer
+ */
+ private $continuationBit = 0x20; // == (mask - 1 ) == 0b00100000
+
+ /**
+ * Char to integer map
+ *
+ * @var array
+ */
+ private $charToIntMap = array(
+ 'A' => 0, 'B' => 1, 'C' => 2, 'D' => 3, 'E' => 4, 'F' => 5, 'G' => 6,
+ 'H' => 7,'I' => 8, 'J' => 9, 'K' => 10, 'L' => 11, 'M' => 12, 'N' => 13,
+ 'O' => 14, 'P' => 15, 'Q' => 16, 'R' => 17, 'S' => 18, 'T' => 19, 'U' => 20,
+ 'V' => 21, 'W' => 22, 'X' => 23, 'Y' => 24, 'Z' => 25, 'a' => 26, 'b' => 27,
+ 'c' => 28, 'd' => 29, 'e' => 30, 'f' => 31, 'g' => 32, 'h' => 33, 'i' => 34,
+ 'j' => 35, 'k' => 36, 'l' => 37, 'm' => 38, 'n' => 39, 'o' => 40, 'p' => 41,
+ 'q' => 42, 'r' => 43, 's' => 44, 't' => 45, 'u' => 46, 'v' => 47, 'w' => 48,
+ 'x' => 49, 'y' => 50, 'z' => 51, 0 => 52, 1 => 53, 2 => 54, 3 => 55, 4 => 56,
+ 5 => 57, 6 => 58, 7 => 59, 8 => 60, 9 => 61, '+' => 62, '/' => 63,
+ );
+
+ /**
+ * Integer to char map
+ *
+ * @var array
+ */
+ private $intToCharMap = array(
+ 0 => 'A', 1 => 'B', 2 => 'C', 3 => 'D', 4 => 'E', 5 => 'F', 6 => 'G',
+ 7 => 'H', 8 => 'I', 9 => 'J', 10 => 'K', 11 => 'L', 12 => 'M', 13 => 'N',
+ 14 => 'O', 15 => 'P', 16 => 'Q', 17 => 'R', 18 => 'S', 19 => 'T', 20 => 'U',
+ 21 => 'V', 22 => 'W', 23 => 'X', 24 => 'Y', 25 => 'Z', 26 => 'a', 27 => 'b',
+ 28 => 'c', 29 => 'd', 30 => 'e', 31 => 'f', 32 => 'g', 33 => 'h', 34 => 'i',
+ 35 => 'j', 36 => 'k', 37 => 'l', 38 => 'm', 39 => 'n', 40 => 'o', 41 => 'p',
+ 42 => 'q', 43 => 'r', 44 => 's', 45 => 't', 46 => 'u', 47 => 'v', 48 => 'w',
+ 49 => 'x', 50 => 'y', 51 => 'z', 52 => '0', 53 => '1', 54 => '2', 55 => '3',
+ 56 => '4', 57 => '5', 58 => '6', 59 => '7', 60 => '8', 61 => '9', 62 => '+',
+ 63 => '/',
+ );
+
+ /**
+ * Constructor
+ */
+ public function __construct(){
+ // I leave it here for future reference
+ // foreach(str_split('ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/') as $i => $char)
+ // {
+ // $this->charToIntMap[$char] = $i;
+ // $this->intToCharMap[$i] = $char;
+ // }
+ }
+
+ /**
+ * Convert from a two-complement value to a value where the sign bit is
+ * is placed in the least significant bit. For example, as decimals:
+ * 1 becomes 2 (10 binary), -1 becomes 3 (11 binary)
+ * 2 becomes 4 (100 binary), -2 becomes 5 (101 binary)
+ * We generate the value for 32 bit machines, hence -2147483648 becomes 1, not 4294967297,
+ * even on a 64 bit machine.
+ * @param string $aValue
+ */
+ public function toVLQSigned($aValue){
+ return 0xffffffff & ($aValue < 0 ? ((-$aValue) << 1) + 1 : ($aValue << 1) + 0);
+ }
+
+ /**
+ * Convert to a two-complement value from a value where the sign bit is
+ * is placed in the least significant bit. For example, as decimals:
+ * 2 (10 binary) becomes 1, 3 (11 binary) becomes -1
+ * 4 (100 binary) becomes 2, 5 (101 binary) becomes -2
+ * We assume that the value was generated with a 32 bit machine in mind.
+ * Hence
+ * 1 becomes -2147483648
+ * even on a 64 bit machine.
+ * @param integer $aValue
+ */
+ public function fromVLQSigned($aValue){
+ return $aValue & 1 ? $this->zeroFill(~$aValue + 2, 1) | (-1 - 0x7fffffff) : $this->zeroFill($aValue, 1);
+ }
+
+ /**
+ * Return the base 64 VLQ encoded value.
+ *
+ * @param string $aValue The value to encode
+ * @return string The encoded value
+ */
+ public function encode($aValue){
+ $encoded = '';
+ $vlq = $this->toVLQSigned($aValue);
+ do
+ {
+ $digit = $vlq & $this->mask;
+ $vlq = $this->zeroFill($vlq, $this->shift);
+ if($vlq > 0){
+ $digit |= $this->continuationBit;
+ }
+ $encoded .= $this->base64Encode($digit);
+ } while($vlq > 0);
+
+ return $encoded;
+ }
+
+ /**
+ * Return the value decoded from base 64 VLQ.
+ *
+ * @param string $encoded The encoded value to decode
+ * @return integer The decoded value
+ */
+ public function decode($encoded){
+ $vlq = 0;
+ $i = 0;
+ do
+ {
+ $digit = $this->base64Decode($encoded[$i]);
+ $vlq |= ($digit & $this->mask) << ($i * $this->shift);
+ $i++;
+ } while($digit & $this->continuationBit);
+
+ return $this->fromVLQSigned($vlq);
+ }
+
+ /**
+ * Right shift with zero fill.
+ *
+ * @param integer $a number to shift
+ * @param integer $b number of bits to shift
+ * @return integer
+ */
+ public function zeroFill($a, $b){
+ return ($a >= 0) ? ($a >> $b) : ($a >> $b) & (PHP_INT_MAX >> ($b - 1));
+ }
+
+ /**
+ * Encode single 6-bit digit as base64.
+ *
+ * @param integer $number
+ * @return string
+ * @throws Exception If the number is invalid
+ */
+ public function base64Encode($number){
+ if($number < 0 || $number > 63){
+ throw new Exception(sprintf('Invalid number "%s" given. Must be between 0 and 63.', $number));
+ }
+ return $this->intToCharMap[$number];
+ }
+
+ /**
+ * Decode single 6-bit digit from base64
+ *
+ * @param string $char
+ * @return number
+ * @throws Exception If the number is invalid
+ */
+ public function base64Decode($char){
+ if(!array_key_exists($char, $this->charToIntMap)){
+ throw new Exception(sprintf('Invalid base 64 digit "%s" given.', $char));
+ }
+ return $this->charToIntMap[$char];
+ }
+
+}
diff --git a/vendor/oyejorge/less.php/lib/Less/SourceMap/Generator.php b/vendor/oyejorge/less.php/lib/Less/SourceMap/Generator.php
new file mode 100644
index 00000000..ff73af06
--- /dev/null
+++ b/vendor/oyejorge/less.php/lib/Less/SourceMap/Generator.php
@@ -0,0 +1,365 @@
+<?php
+
+/**
+ * Source map generator
+ *
+ * @package Less
+ * @subpackage Output
+ */
+class Less_SourceMap_Generator extends Less_Configurable {
+
+ /**
+ * What version of source map does the generator generate?
+ */
+ const VERSION = 3;
+
+ /**
+ * Array of default options
+ *
+ * @var array
+ */
+ protected $defaultOptions = array(
+ // an optional source root, useful for relocating source files
+ // on a server or removing repeated values in the 'sources' entry.
+ // This value is prepended to the individual entries in the 'source' field.
+ 'sourceRoot' => '',
+
+ // an optional name of the generated code that this source map is associated with.
+ 'sourceMapFilename' => null,
+
+ // url of the map
+ 'sourceMapURL' => null,
+
+ // absolute path to a file to write the map to
+ 'sourceMapWriteTo' => null,
+
+ // output source contents?
+ 'outputSourceFiles' => false,
+
+ // base path for filename normalization
+ 'sourceMapRootpath' => '',
+
+ // base path for filename normalization
+ 'sourceMapBasepath' => ''
+ );
+
+ /**
+ * The base64 VLQ encoder
+ *
+ * @var Less_SourceMap_Base64VLQ
+ */
+ protected $encoder;
+
+ /**
+ * Array of mappings
+ *
+ * @var array
+ */
+ protected $mappings = array();
+
+ /**
+ * The root node
+ *
+ * @var Less_Tree_Ruleset
+ */
+ protected $root;
+
+ /**
+ * Array of contents map
+ *
+ * @var array
+ */
+ protected $contentsMap = array();
+
+ /**
+ * File to content map
+ *
+ * @var array
+ */
+ protected $sources = array();
+ protected $source_keys = array();
+
+ /**
+ * Constructor
+ *
+ * @param Less_Tree_Ruleset $root The root node
+ * @param array $options Array of options
+ */
+ public function __construct(Less_Tree_Ruleset $root, $contentsMap, $options = array()){
+ $this->root = $root;
+ $this->contentsMap = $contentsMap;
+ $this->encoder = new Less_SourceMap_Base64VLQ();
+
+ $this->SetOptions($options);
+
+ $this->options['sourceMapRootpath'] = $this->fixWindowsPath($this->options['sourceMapRootpath'], true);
+ $this->options['sourceMapBasepath'] = $this->fixWindowsPath($this->options['sourceMapBasepath'], true);
+ }
+
+ /**
+ * Generates the CSS
+ *
+ * @return string
+ */
+ public function generateCSS(){
+ $output = new Less_Output_Mapped($this->contentsMap, $this);
+
+ // catch the output
+ $this->root->genCSS($output);
+
+
+ $sourceMapUrl = $this->getOption('sourceMapURL');
+ $sourceMapFilename = $this->getOption('sourceMapFilename');
+ $sourceMapContent = $this->generateJson();
+ $sourceMapWriteTo = $this->getOption('sourceMapWriteTo');
+
+ if( !$sourceMapUrl && $sourceMapFilename ){
+ $sourceMapUrl = $this->normalizeFilename($sourceMapFilename);
+ }
+
+ // write map to a file
+ if( $sourceMapWriteTo ){
+ $this->saveMap($sourceMapWriteTo, $sourceMapContent);
+ }
+
+ // inline the map
+ if( !$sourceMapUrl ){
+ $sourceMapUrl = sprintf('data:application/json,%s', Less_Functions::encodeURIComponent($sourceMapContent));
+ }
+
+ if( $sourceMapUrl ){
+ $output->add( sprintf('/*# sourceMappingURL=%s */', $sourceMapUrl) );
+ }
+
+ return $output->toString();
+ }
+
+ /**
+ * Saves the source map to a file
+ *
+ * @param string $file The absolute path to a file
+ * @param string $content The content to write
+ * @throws Exception If the file could not be saved
+ */
+ protected function saveMap($file, $content){
+ $dir = dirname($file);
+ // directory does not exist
+ if( !is_dir($dir) ){
+ // FIXME: create the dir automatically?
+ throw new Exception(sprintf('The directory "%s" does not exist. Cannot save the source map.', $dir));
+ }
+ // FIXME: proper saving, with dir write check!
+ if(file_put_contents($file, $content) === false){
+ throw new Exception(sprintf('Cannot save the source map to "%s"', $file));
+ }
+ return true;
+ }
+
+ /**
+ * Normalizes the filename
+ *
+ * @param string $filename
+ * @return string
+ */
+ protected function normalizeFilename($filename){
+
+ $filename = $this->fixWindowsPath($filename);
+
+ $rootpath = $this->getOption('sourceMapRootpath');
+ $basePath = $this->getOption('sourceMapBasepath');
+
+ // "Trim" the 'sourceMapBasepath' from the output filename.
+ if (strpos($filename, $basePath) === 0) {
+ $filename = substr($filename, strlen($basePath));
+ }
+
+ // Remove extra leading path separators.
+ if(strpos($filename, '\\') === 0 || strpos($filename, '/') === 0){
+ $filename = substr($filename, 1);
+ }
+
+ return $rootpath . $filename;
+ }
+
+ /**
+ * Adds a mapping
+ *
+ * @param integer $generatedLine The line number in generated file
+ * @param integer $generatedColumn The column number in generated file
+ * @param integer $originalLine The line number in original file
+ * @param integer $originalColumn The column number in original file
+ * @param string $sourceFile The original source file
+ */
+ public function addMapping($generatedLine, $generatedColumn, $originalLine, $originalColumn, $fileInfo ){
+
+ $this->mappings[] = array(
+ 'generated_line' => $generatedLine,
+ 'generated_column' => $generatedColumn,
+ 'original_line' => $originalLine,
+ 'original_column' => $originalColumn,
+ 'source_file' => $fileInfo['currentUri']
+ );
+
+ $this->sources[$fileInfo['currentUri']] = $fileInfo['filename'];
+ }
+
+
+ /**
+ * Generates the JSON source map
+ *
+ * @return string
+ * @see https://docs.google.com/document/d/1U1RGAehQwRypUTovF1KRlpiOFze0b-_2gc6fAH0KY0k/edit#
+ */
+ protected function generateJson(){
+
+ $sourceMap = array();
+ $mappings = $this->generateMappings();
+
+ // File version (always the first entry in the object) and must be a positive integer.
+ $sourceMap['version'] = self::VERSION;
+
+
+ // An optional name of the generated code that this source map is associated with.
+ $file = $this->getOption('sourceMapFilename');
+ if( $file ){
+ $sourceMap['file'] = $file;
+ }
+
+
+ // An optional source root, useful for relocating source files on a server or removing repeated values in the 'sources' entry. This value is prepended to the individual entries in the 'source' field.
+ $root = $this->getOption('sourceRoot');
+ if( $root ){
+ $sourceMap['sourceRoot'] = $root;
+ }
+
+
+ // A list of original sources used by the 'mappings' entry.
+ $sourceMap['sources'] = array();
+ foreach($this->sources as $source_uri => $source_filename){
+ $sourceMap['sources'][] = $this->normalizeFilename($source_filename);
+ }
+
+
+ // A list of symbol names used by the 'mappings' entry.
+ $sourceMap['names'] = array();
+
+ // A string with the encoded mapping data.
+ $sourceMap['mappings'] = $mappings;
+
+ if( $this->getOption('outputSourceFiles') ){
+ // An optional list of source content, useful when the 'source' can't be hosted.
+ // The contents are listed in the same order as the sources above.
+ // 'null' may be used if some original sources should be retrieved by name.
+ $sourceMap['sourcesContent'] = $this->getSourcesContent();
+ }
+
+ // less.js compat fixes
+ if( count($sourceMap['sources']) && empty($sourceMap['sourceRoot']) ){
+ unset($sourceMap['sourceRoot']);
+ }
+
+ return json_encode($sourceMap);
+ }
+
+ /**
+ * Returns the sources contents
+ *
+ * @return array|null
+ */
+ protected function getSourcesContent(){
+ if(empty($this->sources)){
+ return;
+ }
+ $content = array();
+ foreach($this->sources as $sourceFile){
+ $content[] = file_get_contents($sourceFile);
+ }
+ return $content;
+ }
+
+ /**
+ * Generates the mappings string
+ *
+ * @return string
+ */
+ public function generateMappings(){
+
+ if( !count($this->mappings) ){
+ return '';
+ }
+
+ $this->source_keys = array_flip(array_keys($this->sources));
+
+
+ // group mappings by generated line number.
+ $groupedMap = $groupedMapEncoded = array();
+ foreach($this->mappings as $m){
+ $groupedMap[$m['generated_line']][] = $m;
+ }
+ ksort($groupedMap);
+
+ $lastGeneratedLine = $lastOriginalIndex = $lastOriginalLine = $lastOriginalColumn = 0;
+
+ foreach($groupedMap as $lineNumber => $line_map){
+ while(++$lastGeneratedLine < $lineNumber){
+ $groupedMapEncoded[] = ';';
+ }
+
+ $lineMapEncoded = array();
+ $lastGeneratedColumn = 0;
+
+ foreach($line_map as $m){
+ $mapEncoded = $this->encoder->encode($m['generated_column'] - $lastGeneratedColumn);
+ $lastGeneratedColumn = $m['generated_column'];
+
+ // find the index
+ if( $m['source_file'] ){
+ $index = $this->findFileIndex($m['source_file']);
+ if( $index !== false ){
+ $mapEncoded .= $this->encoder->encode($index - $lastOriginalIndex);
+ $lastOriginalIndex = $index;
+
+ // lines are stored 0-based in SourceMap spec version 3
+ $mapEncoded .= $this->encoder->encode($m['original_line'] - 1 - $lastOriginalLine);
+ $lastOriginalLine = $m['original_line'] - 1;
+
+ $mapEncoded .= $this->encoder->encode($m['original_column'] - $lastOriginalColumn);
+ $lastOriginalColumn = $m['original_column'];
+ }
+ }
+
+ $lineMapEncoded[] = $mapEncoded;
+ }
+
+ $groupedMapEncoded[] = implode(',', $lineMapEncoded) . ';';
+ }
+
+ return rtrim(implode($groupedMapEncoded), ';');
+ }
+
+ /**
+ * Finds the index for the filename
+ *
+ * @param string $filename
+ * @return integer|false
+ */
+ protected function findFileIndex($filename){
+ return $this->source_keys[$filename];
+ }
+
+ /**
+ * fix windows paths
+ * @param string $path
+ * @return string
+ */
+ public function fixWindowsPath($path, $addEndSlash = false){
+ $slash = ($addEndSlash) ? '/' : '';
+ if( !empty($path) ){
+ $path = str_replace('\\', '/', $path);
+ $path = rtrim($path,'/') . $slash;
+ }
+
+ return $path;
+ }
+
+} \ No newline at end of file
diff --git a/vendor/oyejorge/less.php/lib/Less/Tree.php b/vendor/oyejorge/less.php/lib/Less/Tree.php
new file mode 100644
index 00000000..0de1b407
--- /dev/null
+++ b/vendor/oyejorge/less.php/lib/Less/Tree.php
@@ -0,0 +1,90 @@
+<?php
+
+/**
+ * Tree
+ *
+ * @package Less
+ * @subpackage tree
+ */
+class Less_Tree{
+
+ public $cache_string;
+
+ public function toCSS(){
+ $output = new Less_Output();
+ $this->genCSS($output);
+ return $output->toString();
+ }
+
+
+ /**
+ * Generate CSS by adding it to the output object
+ *
+ * @param Less_Output $output The output
+ * @return void
+ */
+ public function genCSS($output){}
+
+
+ /**
+ * @param Less_Tree_Ruleset[] $rules
+ */
+ public static function outputRuleset( $output, $rules ){
+
+ $ruleCnt = count($rules);
+ Less_Environment::$tabLevel++;
+
+
+ // Compressed
+ if( Less_Parser::$options['compress'] ){
+ $output->add('{');
+ for( $i = 0; $i < $ruleCnt; $i++ ){
+ $rules[$i]->genCSS( $output );
+ }
+
+ $output->add( '}' );
+ Less_Environment::$tabLevel--;
+ return;
+ }
+
+
+ // Non-compressed
+ $tabSetStr = "\n".str_repeat( ' ' , Less_Environment::$tabLevel-1 );
+ $tabRuleStr = $tabSetStr.' ';
+
+ $output->add( " {" );
+ for($i = 0; $i < $ruleCnt; $i++ ){
+ $output->add( $tabRuleStr );
+ $rules[$i]->genCSS( $output );
+ }
+ Less_Environment::$tabLevel--;
+ $output->add( $tabSetStr.'}' );
+
+ }
+
+ public function accept($visitor){}
+
+
+ public static function ReferencedArray($rules){
+ foreach($rules as $rule){
+ if( method_exists($rule, 'markReferenced') ){
+ $rule->markReferenced();
+ }
+ }
+ }
+
+
+ /**
+ * Requires php 5.3+
+ */
+ public static function __set_state($args){
+
+ $class = get_called_class();
+ $obj = new $class(null,null,null,null);
+ foreach($args as $key => $val){
+ $obj->$key = $val;
+ }
+ return $obj;
+ }
+
+} \ No newline at end of file
diff --git a/vendor/oyejorge/less.php/lib/Less/Tree/Alpha.php b/vendor/oyejorge/less.php/lib/Less/Tree/Alpha.php
new file mode 100644
index 00000000..935377da
--- /dev/null
+++ b/vendor/oyejorge/less.php/lib/Less/Tree/Alpha.php
@@ -0,0 +1,51 @@
+<?php
+
+/**
+ * Alpha
+ *
+ * @package Less
+ * @subpackage tree
+ */
+class Less_Tree_Alpha extends Less_Tree{
+ public $value;
+ public $type = 'Alpha';
+
+ public function __construct($val){
+ $this->value = $val;
+ }
+
+ //function accept( $visitor ){
+ // $this->value = $visitor->visit( $this->value );
+ //}
+
+ public function compile($env){
+
+ if( is_object($this->value) ){
+ $this->value = $this->value->compile($env);
+ }
+
+ return $this;
+ }
+
+ /**
+ * @see Less_Tree::genCSS
+ */
+ public function genCSS( $output ){
+
+ $output->add( "alpha(opacity=" );
+
+ if( is_string($this->value) ){
+ $output->add( $this->value );
+ }else{
+ $this->value->genCSS( $output);
+ }
+
+ $output->add( ')' );
+ }
+
+ public function toCSS(){
+ return "alpha(opacity=" . (is_string($this->value) ? $this->value : $this->value->toCSS()) . ")";
+ }
+
+
+} \ No newline at end of file
diff --git a/vendor/oyejorge/less.php/lib/Less/Tree/Anonymous.php b/vendor/oyejorge/less.php/lib/Less/Tree/Anonymous.php
new file mode 100644
index 00000000..8889dc0f
--- /dev/null
+++ b/vendor/oyejorge/less.php/lib/Less/Tree/Anonymous.php
@@ -0,0 +1,58 @@
+<?php
+
+/**
+ * Anonymous
+ *
+ * @package Less
+ * @subpackage tree
+ */
+class Less_Tree_Anonymous extends Less_Tree{
+ public $value;
+ public $quote;
+ public $index;
+ public $mapLines;
+ public $currentFileInfo;
+ public $type = 'Anonymous';
+
+ /**
+ * @param integer $index
+ * @param boolean $mapLines
+ */
+ public function __construct($value, $index = null, $currentFileInfo = null, $mapLines = null ){
+ $this->value = $value;
+ $this->index = $index;
+ $this->mapLines = $mapLines;
+ $this->currentFileInfo = $currentFileInfo;
+ }
+
+ public function compile(){
+ return new Less_Tree_Anonymous($this->value, $this->index, $this->currentFileInfo, $this->mapLines);
+ }
+
+ public function compare($x){
+ if( !is_object($x) ){
+ return -1;
+ }
+
+ $left = $this->toCSS();
+ $right = $x->toCSS();
+
+ if( $left === $right ){
+ return 0;
+ }
+
+ return $left < $right ? -1 : 1;
+ }
+
+ /**
+ * @see Less_Tree::genCSS
+ */
+ public function genCSS( $output ){
+ $output->add( $this->value, $this->currentFileInfo, $this->index, $this->mapLines );
+ }
+
+ public function toCSS(){
+ return $this->value;
+ }
+
+}
diff --git a/vendor/oyejorge/less.php/lib/Less/Tree/Assignment.php b/vendor/oyejorge/less.php/lib/Less/Tree/Assignment.php
new file mode 100644
index 00000000..23800064
--- /dev/null
+++ b/vendor/oyejorge/less.php/lib/Less/Tree/Assignment.php
@@ -0,0 +1,39 @@
+<?php
+
+/**
+ * Assignment
+ *
+ * @package Less
+ * @subpackage tree
+ */
+class Less_Tree_Assignment extends Less_Tree{
+
+ public $key;
+ public $value;
+ public $type = 'Assignment';
+
+ public function __construct($key, $val) {
+ $this->key = $key;
+ $this->value = $val;
+ }
+
+ public function accept( $visitor ){
+ $this->value = $visitor->visitObj( $this->value );
+ }
+
+ public function compile($env) {
+ return new Less_Tree_Assignment( $this->key, $this->value->compile($env));
+ }
+
+ /**
+ * @see Less_Tree::genCSS
+ */
+ public function genCSS( $output ){
+ $output->add( $this->key . '=' );
+ $this->value->genCSS( $output );
+ }
+
+ public function toCss(){
+ return $this->key . '=' . $this->value->toCSS();
+ }
+}
diff --git a/vendor/oyejorge/less.php/lib/Less/Tree/Attribute.php b/vendor/oyejorge/less.php/lib/Less/Tree/Attribute.php
new file mode 100644
index 00000000..32b8900d
--- /dev/null
+++ b/vendor/oyejorge/less.php/lib/Less/Tree/Attribute.php
@@ -0,0 +1,54 @@
+<?php
+
+/**
+ * Attribute
+ *
+ * @package Less
+ * @subpackage tree
+ */
+class Less_Tree_Attribute extends Less_Tree{
+
+ public $key;
+ public $op;
+ public $value;
+ public $type = 'Attribute';
+
+ public function __construct($key, $op, $value){
+ $this->key = $key;
+ $this->op = $op;
+ $this->value = $value;
+ }
+
+ public function compile($env){
+
+ $key_obj = is_object($this->key);
+ $val_obj = is_object($this->value);
+
+ if( !$key_obj && !$val_obj ){
+ return $this;
+ }
+
+ return new Less_Tree_Attribute(
+ $key_obj ? $this->key->compile($env) : $this->key ,
+ $this->op,
+ $val_obj ? $this->value->compile($env) : $this->value);
+ }
+
+ /**
+ * @see Less_Tree::genCSS
+ */
+ public function genCSS( $output ){
+ $output->add( $this->toCSS() );
+ }
+
+ public function toCSS(){
+ $value = $this->key;
+
+ if( $this->op ){
+ $value .= $this->op;
+ $value .= (is_object($this->value) ? $this->value->toCSS() : $this->value);
+ }
+
+ return '[' . $value . ']';
+ }
+} \ No newline at end of file
diff --git a/vendor/oyejorge/less.php/lib/Less/Tree/Call.php b/vendor/oyejorge/less.php/lib/Less/Tree/Call.php
new file mode 100644
index 00000000..1560351e
--- /dev/null
+++ b/vendor/oyejorge/less.php/lib/Less/Tree/Call.php
@@ -0,0 +1,121 @@
+<?php
+
+
+/**
+ * Call
+ *
+ * @package Less
+ * @subpackage tree
+ */
+class Less_Tree_Call extends Less_Tree{
+ public $value;
+
+ protected $name;
+ protected $args;
+ protected $index;
+ protected $currentFileInfo;
+ public $type = 'Call';
+
+ public function __construct($name, $args, $index, $currentFileInfo = null ){
+ $this->name = $name;
+ $this->args = $args;
+ $this->index = $index;
+ $this->currentFileInfo = $currentFileInfo;
+ }
+
+ public function accept( $visitor ){
+ $this->args = $visitor->visitArray( $this->args );
+ }
+
+ //
+ // When evaluating a function call,
+ // we either find the function in `tree.functions` [1],
+ // in which case we call it, passing the evaluated arguments,
+ // or we simply print it out as it appeared originally [2].
+ //
+ // The *functions.js* file contains the built-in functions.
+ //
+ // The reason why we evaluate the arguments, is in the case where
+ // we try to pass a variable to a function, like: `saturate(@color)`.
+ // The function should receive the value, not the variable.
+ //
+ public function compile($env=null){
+ $args = array();
+ foreach($this->args as $a){
+ $args[] = $a->compile($env);
+ }
+
+ $nameLC = strtolower($this->name);
+ switch($nameLC){
+ case '%':
+ $nameLC = '_percent';
+ break;
+
+ case 'get-unit':
+ $nameLC = 'getunit';
+ break;
+
+ case 'data-uri':
+ $nameLC = 'datauri';
+ break;
+
+ case 'svg-gradient':
+ $nameLC = 'svggradient';
+ break;
+ }
+
+ $result = null;
+ if( $nameLC === 'default' ){
+ $result = Less_Tree_DefaultFunc::compile();
+
+ }else{
+
+ if( method_exists('Less_Functions',$nameLC) ){ // 1.
+ try {
+
+ $func = new Less_Functions($env, $this->currentFileInfo);
+ $result = call_user_func_array( array($func,$nameLC),$args);
+
+ } catch (Exception $e) {
+ throw new Less_Exception_Compiler('error evaluating function `' . $this->name . '` '.$e->getMessage().' index: '. $this->index);
+ }
+ } elseif( isset( $env->functions[$nameLC] ) && is_callable( $env->functions[$nameLC] ) ) {
+ try {
+ $result = call_user_func_array( $env->functions[$nameLC], $args );
+ } catch (Exception $e) {
+ throw new Less_Exception_Compiler('error evaluating function `' . $this->name . '` '.$e->getMessage().' index: '. $this->index);
+ }
+ }
+ }
+
+ if( $result !== null ){
+ return $result;
+ }
+
+
+ return new Less_Tree_Call( $this->name, $args, $this->index, $this->currentFileInfo );
+ }
+
+ /**
+ * @see Less_Tree::genCSS
+ */
+ public function genCSS( $output ){
+
+ $output->add( $this->name . '(', $this->currentFileInfo, $this->index );
+ $args_len = count($this->args);
+ for($i = 0; $i < $args_len; $i++ ){
+ $this->args[$i]->genCSS( $output );
+ if( $i + 1 < $args_len ){
+ $output->add( ', ' );
+ }
+ }
+
+ $output->add( ')' );
+ }
+
+
+ //public function toCSS(){
+ // return $this->compile()->toCSS();
+ //}
+
+}
diff --git a/vendor/oyejorge/less.php/lib/Less/Tree/Color.php b/vendor/oyejorge/less.php/lib/Less/Tree/Color.php
new file mode 100644
index 00000000..77af07a6
--- /dev/null
+++ b/vendor/oyejorge/less.php/lib/Less/Tree/Color.php
@@ -0,0 +1,230 @@
+<?php
+
+/**
+ * Color
+ *
+ * @package Less
+ * @subpackage tree
+ */
+class Less_Tree_Color extends Less_Tree{
+ public $rgb;
+ public $alpha;
+ public $isTransparentKeyword;
+ public $type = 'Color';
+
+ public function __construct($rgb, $a = 1, $isTransparentKeyword = null ){
+
+ if( $isTransparentKeyword ){
+ $this->rgb = $rgb;
+ $this->alpha = $a;
+ $this->isTransparentKeyword = true;
+ return;
+ }
+
+ $this->rgb = array();
+ if( is_array($rgb) ){
+ $this->rgb = $rgb;
+ }else if( strlen($rgb) == 6 ){
+ foreach(str_split($rgb, 2) as $c){
+ $this->rgb[] = hexdec($c);
+ }
+ }else{
+ foreach(str_split($rgb, 1) as $c){
+ $this->rgb[] = hexdec($c.$c);
+ }
+ }
+ $this->alpha = is_numeric($a) ? $a : 1;
+ }
+
+ public function compile(){
+ return $this;
+ }
+
+ public function luma(){
+ $r = $this->rgb[0] / 255;
+ $g = $this->rgb[1] / 255;
+ $b = $this->rgb[2] / 255;
+
+ $r = ($r <= 0.03928) ? $r / 12.92 : pow((($r + 0.055) / 1.055), 2.4);
+ $g = ($g <= 0.03928) ? $g / 12.92 : pow((($g + 0.055) / 1.055), 2.4);
+ $b = ($b <= 0.03928) ? $b / 12.92 : pow((($b + 0.055) / 1.055), 2.4);
+
+ return 0.2126 * $r + 0.7152 * $g + 0.0722 * $b;
+ }
+
+ /**
+ * @see Less_Tree::genCSS
+ */
+ public function genCSS( $output ){
+ $output->add( $this->toCSS() );
+ }
+
+ public function toCSS( $doNotCompress = false ){
+ $compress = Less_Parser::$options['compress'] && !$doNotCompress;
+ $alpha = Less_Functions::fround( $this->alpha );
+
+
+ //
+ // If we have some transparency, the only way to represent it
+ // is via `rgba`. Otherwise, we use the hex representation,
+ // which has better compatibility with older browsers.
+ // Values are capped between `0` and `255`, rounded and zero-padded.
+ //
+ if( $alpha < 1 ){
+ if( ( $alpha === 0 || $alpha === 0.0 ) && isset($this->isTransparentKeyword) && $this->isTransparentKeyword ){
+ return 'transparent';
+ }
+
+ $values = array();
+ foreach($this->rgb as $c){
+ $values[] = Less_Functions::clamp( round($c), 255);
+ }
+ $values[] = $alpha;
+
+ $glue = ($compress ? ',' : ', ');
+ return "rgba(" . implode($glue, $values) . ")";
+ }else{
+
+ $color = $this->toRGB();
+
+ if( $compress ){
+
+ // Convert color to short format
+ if( $color[1] === $color[2] && $color[3] === $color[4] && $color[5] === $color[6]) {
+ $color = '#'.$color[1] . $color[3] . $color[5];
+ }
+ }
+
+ return $color;
+ }
+ }
+
+ //
+ // Operations have to be done per-channel, if not,
+ // channels will spill onto each other. Once we have
+ // our result, in the form of an integer triplet,
+ // we create a new Color node to hold the result.
+ //
+
+ /**
+ * @param string $op
+ */
+ public function operate( $op, $other) {
+ $rgb = array();
+ $alpha = $this->alpha * (1 - $other->alpha) + $other->alpha;
+ for ($c = 0; $c < 3; $c++) {
+ $rgb[$c] = Less_Functions::operate( $op, $this->rgb[$c], $other->rgb[$c]);
+ }
+ return new Less_Tree_Color($rgb, $alpha);
+ }
+
+ public function toRGB(){
+ return $this->toHex($this->rgb);
+ }
+
+ public function toHSL(){
+ $r = $this->rgb[0] / 255;
+ $g = $this->rgb[1] / 255;
+ $b = $this->rgb[2] / 255;
+ $a = $this->alpha;
+
+ $max = max($r, $g, $b);
+ $min = min($r, $g, $b);
+ $l = ($max + $min) / 2;
+ $d = $max - $min;
+
+ $h = $s = 0;
+ if( $max !== $min ){
+ $s = $l > 0.5 ? $d / (2 - $max - $min) : $d / ($max + $min);
+
+ switch ($max) {
+ case $r: $h = ($g - $b) / $d + ($g < $b ? 6 : 0); break;
+ case $g: $h = ($b - $r) / $d + 2; break;
+ case $b: $h = ($r - $g) / $d + 4; break;
+ }
+ $h /= 6;
+ }
+ return array('h' => $h * 360, 's' => $s, 'l' => $l, 'a' => $a );
+ }
+
+ //Adapted from http://mjijackson.com/2008/02/rgb-to-hsl-and-rgb-to-hsv-color-model-conversion-algorithms-in-javascript
+ public function toHSV() {
+ $r = $this->rgb[0] / 255;
+ $g = $this->rgb[1] / 255;
+ $b = $this->rgb[2] / 255;
+ $a = $this->alpha;
+
+ $max = max($r, $g, $b);
+ $min = min($r, $g, $b);
+
+ $v = $max;
+
+ $d = $max - $min;
+ if ($max === 0) {
+ $s = 0;
+ } else {
+ $s = $d / $max;
+ }
+
+ $h = 0;
+ if( $max !== $min ){
+ switch($max){
+ case $r: $h = ($g - $b) / $d + ($g < $b ? 6 : 0); break;
+ case $g: $h = ($b - $r) / $d + 2; break;
+ case $b: $h = ($r - $g) / $d + 4; break;
+ }
+ $h /= 6;
+ }
+ return array('h'=> $h * 360, 's'=> $s, 'v'=> $v, 'a' => $a );
+ }
+
+ public function toARGB(){
+ $argb = array_merge( (array) Less_Parser::round($this->alpha * 255), $this->rgb);
+ return $this->toHex( $argb );
+ }
+
+ public function compare($x){
+
+ if( !property_exists( $x, 'rgb' ) ){
+ return -1;
+ }
+
+
+ return ($x->rgb[0] === $this->rgb[0] &&
+ $x->rgb[1] === $this->rgb[1] &&
+ $x->rgb[2] === $this->rgb[2] &&
+ $x->alpha === $this->alpha) ? 0 : -1;
+ }
+
+ public function toHex( $v ){
+
+ $ret = '#';
+ foreach($v as $c){
+ $c = Less_Functions::clamp( Less_Parser::round($c), 255);
+ if( $c < 16 ){
+ $ret .= '0';
+ }
+ $ret .= dechex($c);
+ }
+
+ return $ret;
+ }
+
+
+ /**
+ * @param string $keyword
+ */
+ public static function fromKeyword( $keyword ){
+ $keyword = strtolower($keyword);
+
+ if( Less_Colors::hasOwnProperty($keyword) ){
+ // detect named color
+ return new Less_Tree_Color(substr(Less_Colors::color($keyword), 1));
+ }
+
+ if( $keyword === 'transparent' ){
+ return new Less_Tree_Color( array(0, 0, 0), 0, true);
+ }
+ }
+
+}
diff --git a/vendor/oyejorge/less.php/lib/Less/Tree/Comment.php b/vendor/oyejorge/less.php/lib/Less/Tree/Comment.php
new file mode 100644
index 00000000..7261284a
--- /dev/null
+++ b/vendor/oyejorge/less.php/lib/Less/Tree/Comment.php
@@ -0,0 +1,51 @@
+<?php
+
+/**
+ * Comment
+ *
+ * @package Less
+ * @subpackage tree
+ */
+class Less_Tree_Comment extends Less_Tree{
+
+ public $value;
+ public $silent;
+ public $isReferenced;
+ public $currentFileInfo;
+ public $type = 'Comment';
+
+ public function __construct($value, $silent, $index = null, $currentFileInfo = null ){
+ $this->value = $value;
+ $this->silent = !! $silent;
+ $this->currentFileInfo = $currentFileInfo;
+ }
+
+ /**
+ * @see Less_Tree::genCSS
+ */
+ public function genCSS( $output ){
+ //if( $this->debugInfo ){
+ //$output->add( tree.debugInfo($env, $this), $this->currentFileInfo, $this->index);
+ //}
+ $output->add( trim($this->value) );//TODO shouldn't need to trim, we shouldn't grab the \n
+ }
+
+ public function toCSS(){
+ return Less_Parser::$options['compress'] ? '' : $this->value;
+ }
+
+ public function isSilent(){
+ $isReference = ($this->currentFileInfo && isset($this->currentFileInfo['reference']) && (!isset($this->isReferenced) || !$this->isReferenced) );
+ $isCompressed = Less_Parser::$options['compress'] && !preg_match('/^\/\*!/', $this->value);
+ return $this->silent || $isReference || $isCompressed;
+ }
+
+ public function compile(){
+ return $this;
+ }
+
+ public function markReferenced(){
+ $this->isReferenced = true;
+ }
+
+}
diff --git a/vendor/oyejorge/less.php/lib/Less/Tree/Condition.php b/vendor/oyejorge/less.php/lib/Less/Tree/Condition.php
new file mode 100644
index 00000000..929d33be
--- /dev/null
+++ b/vendor/oyejorge/less.php/lib/Less/Tree/Condition.php
@@ -0,0 +1,72 @@
+<?php
+
+/**
+ * Condition
+ *
+ * @package Less
+ * @subpackage tree
+ */
+class Less_Tree_Condition extends Less_Tree{
+
+ public $op;
+ public $lvalue;
+ public $rvalue;
+ public $index;
+ public $negate;
+ public $type = 'Condition';
+
+ public function __construct($op, $l, $r, $i = 0, $negate = false) {
+ $this->op = trim($op);
+ $this->lvalue = $l;
+ $this->rvalue = $r;
+ $this->index = $i;
+ $this->negate = $negate;
+ }
+
+ public function accept($visitor){
+ $this->lvalue = $visitor->visitObj( $this->lvalue );
+ $this->rvalue = $visitor->visitObj( $this->rvalue );
+ }
+
+ public function compile($env) {
+ $a = $this->lvalue->compile($env);
+ $b = $this->rvalue->compile($env);
+
+ switch( $this->op ){
+ case 'and':
+ $result = $a && $b;
+ break;
+
+ case 'or':
+ $result = $a || $b;
+ break;
+
+ default:
+ if( Less_Parser::is_method($a, 'compare') ){
+ $result = $a->compare($b);
+ }elseif( Less_Parser::is_method($b, 'compare') ){
+ $result = $b->compare($a);
+ }else{
+ throw new Less_Exception_Compiler('Unable to perform comparison', null, $this->index);
+ }
+
+ switch ($result) {
+ case -1:
+ $result = $this->op === '<' || $this->op === '=<' || $this->op === '<=';
+ break;
+
+ case 0:
+ $result = $this->op === '=' || $this->op === '>=' || $this->op === '=<' || $this->op === '<=';
+ break;
+
+ case 1:
+ $result = $this->op === '>' || $this->op === '>=';
+ break;
+ }
+ break;
+ }
+
+ return $this->negate ? !$result : $result;
+ }
+
+}
diff --git a/vendor/oyejorge/less.php/lib/Less/Tree/DefaultFunc.php b/vendor/oyejorge/less.php/lib/Less/Tree/DefaultFunc.php
new file mode 100644
index 00000000..c2dbf749
--- /dev/null
+++ b/vendor/oyejorge/less.php/lib/Less/Tree/DefaultFunc.php
@@ -0,0 +1,34 @@
+<?php
+
+/**
+ * DefaultFunc
+ *
+ * @package Less
+ * @subpackage tree
+ */
+class Less_Tree_DefaultFunc{
+
+ static $error_;
+ static $value_;
+
+ public static function compile(){
+ if( self::$error_ ){
+ throw new Exception(self::$error_);
+ }
+ if( self::$value_ !== null ){
+ return self::$value_ ? new Less_Tree_Keyword('true') : new Less_Tree_Keyword('false');
+ }
+ }
+
+ public static function value( $v ){
+ self::$value_ = $v;
+ }
+
+ public static function error( $e ){
+ self::$error_ = $e;
+ }
+
+ public static function reset(){
+ self::$value_ = self::$error_ = null;
+ }
+} \ No newline at end of file
diff --git a/vendor/oyejorge/less.php/lib/Less/Tree/DetachedRuleset.php b/vendor/oyejorge/less.php/lib/Less/Tree/DetachedRuleset.php
new file mode 100644
index 00000000..c887e400
--- /dev/null
+++ b/vendor/oyejorge/less.php/lib/Less/Tree/DetachedRuleset.php
@@ -0,0 +1,40 @@
+<?php
+
+/**
+ * DetachedRuleset
+ *
+ * @package Less
+ * @subpackage tree
+ */
+class Less_Tree_DetachedRuleset extends Less_Tree{
+
+ public $ruleset;
+ public $frames;
+ public $type = 'DetachedRuleset';
+
+ public function __construct( $ruleset, $frames = null ){
+ $this->ruleset = $ruleset;
+ $this->frames = $frames;
+ }
+
+ public function accept($visitor) {
+ $this->ruleset = $visitor->visitObj($this->ruleset);
+ }
+
+ public function compile($env){
+ if( $this->frames ){
+ $frames = $this->frames;
+ }else{
+ $frames = $env->frames;
+ }
+ return new Less_Tree_DetachedRuleset($this->ruleset, $frames);
+ }
+
+ public function callEval($env) {
+ if( $this->frames ){
+ return $this->ruleset->compile( $env->copyEvalEnv( array_merge($this->frames,$env->frames) ) );
+ }
+ return $this->ruleset->compile( $env );
+ }
+}
+
diff --git a/vendor/oyejorge/less.php/lib/Less/Tree/Dimension.php b/vendor/oyejorge/less.php/lib/Less/Tree/Dimension.php
new file mode 100644
index 00000000..b693f57d
--- /dev/null
+++ b/vendor/oyejorge/less.php/lib/Less/Tree/Dimension.php
@@ -0,0 +1,201 @@
+<?php
+
+/**
+ * Dimension
+ *
+ * @package Less
+ * @subpackage tree
+ */
+class Less_Tree_Dimension extends Less_Tree{
+
+ public $value;
+ public $unit;
+ public $type = 'Dimension';
+
+ public function __construct($value, $unit = null){
+ $this->value = floatval($value);
+
+ if( $unit && ($unit instanceof Less_Tree_Unit) ){
+ $this->unit = $unit;
+ }elseif( $unit ){
+ $this->unit = new Less_Tree_Unit( array($unit) );
+ }else{
+ $this->unit = new Less_Tree_Unit( );
+ }
+ }
+
+ public function accept( $visitor ){
+ $this->unit = $visitor->visitObj( $this->unit );
+ }
+
+ public function compile(){
+ return $this;
+ }
+
+ public function toColor() {
+ return new Less_Tree_Color(array($this->value, $this->value, $this->value));
+ }
+
+ /**
+ * @see Less_Tree::genCSS
+ */
+ public function genCSS( $output ){
+
+ if( Less_Parser::$options['strictUnits'] && !$this->unit->isSingular() ){
+ throw new Less_Exception_Compiler("Multiple units in dimension. Correct the units or use the unit function. Bad unit: ".$this->unit->toString());
+ }
+
+ $value = Less_Functions::fround( $this->value );
+ $strValue = (string)$value;
+
+ if( $value !== 0 && $value < 0.000001 && $value > -0.000001 ){
+ // would be output 1e-6 etc.
+ $strValue = number_format($strValue,10);
+ $strValue = preg_replace('/\.?0+$/','', $strValue);
+ }
+
+ if( Less_Parser::$options['compress'] ){
+ // Zero values doesn't need a unit
+ if( $value === 0 && $this->unit->isLength() ){
+ $output->add( $strValue );
+ return $strValue;
+ }
+
+ // Float values doesn't need a leading zero
+ if( $value > 0 && $value < 1 && $strValue[0] === '0' ){
+ $strValue = substr($strValue,1);
+ }
+ }
+
+ $output->add( $strValue );
+ $this->unit->genCSS( $output );
+ }
+
+ public function __toString(){
+ return $this->toCSS();
+ }
+
+ // In an operation between two Dimensions,
+ // we default to the first Dimension's unit,
+ // so `1px + 2em` will yield `3px`.
+
+ /**
+ * @param string $op
+ */
+ public function operate( $op, $other){
+
+ $value = Less_Functions::operate( $op, $this->value, $other->value);
+ $unit = clone $this->unit;
+
+ if( $op === '+' || $op === '-' ){
+
+ if( !$unit->numerator && !$unit->denominator ){
+ $unit->numerator = $other->unit->numerator;
+ $unit->denominator = $other->unit->denominator;
+ }elseif( !$other->unit->numerator && !$other->unit->denominator ){
+ // do nothing
+ }else{
+ $other = $other->convertTo( $this->unit->usedUnits());
+
+ if( Less_Parser::$options['strictUnits'] && $other->unit->toString() !== $unit->toCSS() ){
+ throw new Less_Exception_Compiler("Incompatible units. Change the units or use the unit function. Bad units: '".$unit->toString() . "' and ".$other->unit->toString()+"'.");
+ }
+
+ $value = Less_Functions::operate( $op, $this->value, $other->value);
+ }
+ }elseif( $op === '*' ){
+ $unit->numerator = array_merge($unit->numerator, $other->unit->numerator);
+ $unit->denominator = array_merge($unit->denominator, $other->unit->denominator);
+ sort($unit->numerator);
+ sort($unit->denominator);
+ $unit->cancel();
+ }elseif( $op === '/' ){
+ $unit->numerator = array_merge($unit->numerator, $other->unit->denominator);
+ $unit->denominator = array_merge($unit->denominator, $other->unit->numerator);
+ sort($unit->numerator);
+ sort($unit->denominator);
+ $unit->cancel();
+ }
+ return new Less_Tree_Dimension( $value, $unit);
+ }
+
+ public function compare($other) {
+ if ($other instanceof Less_Tree_Dimension) {
+
+ if( $this->unit->isEmpty() || $other->unit->isEmpty() ){
+ $a = $this;
+ $b = $other;
+ } else {
+ $a = $this->unify();
+ $b = $other->unify();
+ if( $a->unit->compare($b->unit) !== 0 ){
+ return -1;
+ }
+ }
+ $aValue = $a->value;
+ $bValue = $b->value;
+
+ if ($bValue > $aValue) {
+ return -1;
+ } elseif ($bValue < $aValue) {
+ return 1;
+ } else {
+ return 0;
+ }
+ } else {
+ return -1;
+ }
+ }
+
+ public function unify() {
+ return $this->convertTo(array('length'=> 'px', 'duration'=> 's', 'angle' => 'rad' ));
+ }
+
+ public function convertTo($conversions) {
+ $value = $this->value;
+ $unit = clone $this->unit;
+
+ if( is_string($conversions) ){
+ $derivedConversions = array();
+ foreach( Less_Tree_UnitConversions::$groups as $i ){
+ if( isset(Less_Tree_UnitConversions::${$i}[$conversions]) ){
+ $derivedConversions = array( $i => $conversions);
+ }
+ }
+ $conversions = $derivedConversions;
+ }
+
+
+ foreach($conversions as $groupName => $targetUnit){
+ $group = Less_Tree_UnitConversions::${$groupName};
+
+ //numerator
+ foreach($unit->numerator as $i => $atomicUnit){
+ $atomicUnit = $unit->numerator[$i];
+ if( !isset($group[$atomicUnit]) ){
+ continue;
+ }
+
+ $value = $value * ($group[$atomicUnit] / $group[$targetUnit]);
+
+ $unit->numerator[$i] = $targetUnit;
+ }
+
+ //denominator
+ foreach($unit->denominator as $i => $atomicUnit){
+ $atomicUnit = $unit->denominator[$i];
+ if( !isset($group[$atomicUnit]) ){
+ continue;
+ }
+
+ $value = $value / ($group[$atomicUnit] / $group[$targetUnit]);
+
+ $unit->denominator[$i] = $targetUnit;
+ }
+ }
+
+ $unit->cancel();
+
+ return new Less_Tree_Dimension( $value, $unit);
+ }
+}
diff --git a/vendor/oyejorge/less.php/lib/Less/Tree/Directive.php b/vendor/oyejorge/less.php/lib/Less/Tree/Directive.php
new file mode 100644
index 00000000..04a1e467
--- /dev/null
+++ b/vendor/oyejorge/less.php/lib/Less/Tree/Directive.php
@@ -0,0 +1,100 @@
+<?php
+
+/**
+ * Directive
+ *
+ * @package Less
+ * @subpackage tree
+ */
+class Less_Tree_Directive extends Less_Tree{
+
+ public $name;
+ public $value;
+ public $rules;
+ public $index;
+ public $isReferenced;
+ public $currentFileInfo;
+ public $debugInfo;
+ public $type = 'Directive';
+
+ public function __construct($name, $value = null, $rules, $index = null, $currentFileInfo = null, $debugInfo = null ){
+ $this->name = $name;
+ $this->value = $value;
+ if( $rules ){
+ $this->rules = $rules;
+ $this->rules->allowImports = true;
+ }
+
+ $this->index = $index;
+ $this->currentFileInfo = $currentFileInfo;
+ $this->debugInfo = $debugInfo;
+ }
+
+
+ public function accept( $visitor ){
+ if( $this->rules ){
+ $this->rules = $visitor->visitObj( $this->rules );
+ }
+ if( $this->value ){
+ $this->value = $visitor->visitObj( $this->value );
+ }
+ }
+
+
+ /**
+ * @see Less_Tree::genCSS
+ */
+ public function genCSS( $output ){
+ $value = $this->value;
+ $rules = $this->rules;
+ $output->add( $this->name, $this->currentFileInfo, $this->index );
+ if( $this->value ){
+ $output->add(' ');
+ $this->value->genCSS($output);
+ }
+ if( $this->rules ){
+ Less_Tree::outputRuleset( $output, array($this->rules));
+ } else {
+ $output->add(';');
+ }
+ }
+
+ public function compile($env){
+
+ $value = $this->value;
+ $rules = $this->rules;
+ if( $value ){
+ $value = $value->compile($env);
+ }
+
+ if( $rules ){
+ $rules = $rules->compile($env);
+ $rules->root = true;
+ }
+
+ return new Less_Tree_Directive( $this->name, $value, $rules, $this->index, $this->currentFileInfo, $this->debugInfo );
+ }
+
+
+ public function variable($name){
+ if( $this->rules ){
+ return $this->rules->variable($name);
+ }
+ }
+
+ public function find($selector){
+ if( $this->rules ){
+ return $this->rules->find($selector, $this);
+ }
+ }
+
+ //rulesets: function () { if (this.rules) return tree.Ruleset.prototype.rulesets.apply(this.rules); },
+
+ public function markReferenced(){
+ $this->isReferenced = true;
+ if( $this->rules ){
+ Less_Tree::ReferencedArray($this->rules->rules);
+ }
+ }
+
+}
diff --git a/vendor/oyejorge/less.php/lib/Less/Tree/Element.php b/vendor/oyejorge/less.php/lib/Less/Tree/Element.php
new file mode 100644
index 00000000..9cea5e43
--- /dev/null
+++ b/vendor/oyejorge/less.php/lib/Less/Tree/Element.php
@@ -0,0 +1,75 @@
+<?php
+
+/**
+ * Element
+ *
+ * @package Less
+ * @subpackage tree
+ */
+class Less_Tree_Element extends Less_Tree{
+
+ public $combinator = '';
+ public $value = '';
+ public $index;
+ public $currentFileInfo;
+ public $type = 'Element';
+
+ public $value_is_object = false;
+
+ public function __construct($combinator, $value, $index = null, $currentFileInfo = null ){
+
+ $this->value = $value;
+ $this->value_is_object = is_object($value);
+
+ if( $combinator ){
+ $this->combinator = $combinator;
+ }
+
+ $this->index = $index;
+ $this->currentFileInfo = $currentFileInfo;
+ }
+
+ public function accept( $visitor ){
+ if( $this->value_is_object ){ //object or string
+ $this->value = $visitor->visitObj( $this->value );
+ }
+ }
+
+ public function compile($env){
+
+ if( Less_Environment::$mixin_stack ){
+ return new Less_Tree_Element($this->combinator, ($this->value_is_object ? $this->value->compile($env) : $this->value), $this->index, $this->currentFileInfo );
+ }
+
+ if( $this->value_is_object ){
+ $this->value = $this->value->compile($env);
+ }
+
+ return $this;
+ }
+
+ /**
+ * @see Less_Tree::genCSS
+ */
+ public function genCSS( $output ){
+ $output->add( $this->toCSS(), $this->currentFileInfo, $this->index );
+ }
+
+ public function toCSS(){
+
+ if( $this->value_is_object ){
+ $value = $this->value->toCSS();
+ }else{
+ $value = $this->value;
+ }
+
+
+ if( $value === '' && $this->combinator && $this->combinator === '&' ){
+ return '';
+ }
+
+
+ return Less_Environment::$_outputMap[$this->combinator] . $value;
+ }
+
+}
diff --git a/vendor/oyejorge/less.php/lib/Less/Tree/Expression.php b/vendor/oyejorge/less.php/lib/Less/Tree/Expression.php
new file mode 100644
index 00000000..d834354a
--- /dev/null
+++ b/vendor/oyejorge/less.php/lib/Less/Tree/Expression.php
@@ -0,0 +1,97 @@
+<?php
+
+/**
+ * Expression
+ *
+ * @package Less
+ * @subpackage tree
+ */
+class Less_Tree_Expression extends Less_Tree{
+
+ public $value = array();
+ public $parens = false;
+ public $parensInOp = false;
+ public $type = 'Expression';
+
+ public function __construct( $value, $parens = null ){
+ $this->value = $value;
+ $this->parens = $parens;
+ }
+
+ public function accept( $visitor ){
+ $this->value = $visitor->visitArray( $this->value );
+ }
+
+ public function compile($env) {
+
+ $doubleParen = false;
+
+ if( $this->parens && !$this->parensInOp ){
+ Less_Environment::$parensStack++;
+ }
+
+ $returnValue = null;
+ if( $this->value ){
+
+ $count = count($this->value);
+
+ if( $count > 1 ){
+
+ $ret = array();
+ foreach($this->value as $e){
+ $ret[] = $e->compile($env);
+ }
+ $returnValue = new Less_Tree_Expression($ret);
+
+ }else{
+
+ if( ($this->value[0] instanceof Less_Tree_Expression) && $this->value[0]->parens && !$this->value[0]->parensInOp ){
+ $doubleParen = true;
+ }
+
+ $returnValue = $this->value[0]->compile($env);
+ }
+
+ } else {
+ $returnValue = $this;
+ }
+
+ if( $this->parens ){
+ if( !$this->parensInOp ){
+ Less_Environment::$parensStack--;
+
+ }elseif( !Less_Environment::isMathOn() && !$doubleParen ){
+ $returnValue = new Less_Tree_Paren($returnValue);
+
+ }
+ }
+ return $returnValue;
+ }
+
+ /**
+ * @see Less_Tree::genCSS
+ */
+ public function genCSS( $output ){
+ $val_len = count($this->value);
+ for( $i = 0; $i < $val_len; $i++ ){
+ $this->value[$i]->genCSS( $output );
+ if( $i + 1 < $val_len ){
+ $output->add( ' ' );
+ }
+ }
+ }
+
+ public function throwAwayComments() {
+
+ if( is_array($this->value) ){
+ $new_value = array();
+ foreach($this->value as $v){
+ if( $v instanceof Less_Tree_Comment ){
+ continue;
+ }
+ $new_value[] = $v;
+ }
+ $this->value = $new_value;
+ }
+ }
+}
diff --git a/vendor/oyejorge/less.php/lib/Less/Tree/Extend.php b/vendor/oyejorge/less.php/lib/Less/Tree/Extend.php
new file mode 100644
index 00000000..8f21e939
--- /dev/null
+++ b/vendor/oyejorge/less.php/lib/Less/Tree/Extend.php
@@ -0,0 +1,77 @@
+<?php
+
+/**
+ * Extend
+ *
+ * @package Less
+ * @subpackage tree
+ */
+class Less_Tree_Extend extends Less_Tree{
+
+ public $selector;
+ public $option;
+ public $index;
+ public $selfSelectors = array();
+ public $allowBefore;
+ public $allowAfter;
+ public $firstExtendOnThisSelectorPath;
+ public $type = 'Extend';
+ public $ruleset;
+
+
+ public $object_id;
+ public $parent_ids = array();
+
+ /**
+ * @param integer $index
+ */
+ public function __construct($selector, $option, $index){
+ static $i = 0;
+ $this->selector = $selector;
+ $this->option = $option;
+ $this->index = $index;
+
+ switch($option){
+ case "all":
+ $this->allowBefore = true;
+ $this->allowAfter = true;
+ break;
+ default:
+ $this->allowBefore = false;
+ $this->allowAfter = false;
+ break;
+ }
+
+ $this->object_id = $i++;
+ $this->parent_ids = array($this->object_id);
+ }
+
+ public function accept( $visitor ){
+ $this->selector = $visitor->visitObj( $this->selector );
+ }
+
+ public function compile( $env ){
+ Less_Parser::$has_extends = true;
+ $this->selector = $this->selector->compile($env);
+ return $this;
+ //return new Less_Tree_Extend( $this->selector->compile($env), $this->option, $this->index);
+ }
+
+ public function findSelfSelectors( $selectors ){
+ $selfElements = array();
+
+
+ for( $i = 0, $selectors_len = count($selectors); $i < $selectors_len; $i++ ){
+ $selectorElements = $selectors[$i]->elements;
+ // duplicate the logic in genCSS function inside the selector node.
+ // future TODO - move both logics into the selector joiner visitor
+ if( $i && $selectorElements && $selectorElements[0]->combinator === "") {
+ $selectorElements[0]->combinator = ' ';
+ }
+ $selfElements = array_merge( $selfElements, $selectors[$i]->elements );
+ }
+
+ $this->selfSelectors = array(new Less_Tree_Selector($selfElements));
+ }
+
+} \ No newline at end of file
diff --git a/vendor/oyejorge/less.php/lib/Less/Tree/Import.php b/vendor/oyejorge/less.php/lib/Less/Tree/Import.php
new file mode 100644
index 00000000..e327b756
--- /dev/null
+++ b/vendor/oyejorge/less.php/lib/Less/Tree/Import.php
@@ -0,0 +1,307 @@
+<?php
+
+/**
+ * CSS @import node
+ *
+ * The general strategy here is that we don't want to wait
+ * for the parsing to be completed, before we start importing
+ * the file. That's because in the context of a browser,
+ * most of the time will be spent waiting for the server to respond.
+ *
+ * On creation, we push the import path to our import queue, though
+ * `import,push`, we also pass it a callback, which it'll call once
+ * the file has been fetched, and parsed.
+ *
+ * @package Less
+ * @subpackage tree
+ */
+class Less_Tree_Import extends Less_Tree{
+
+ public $options;
+ public $index;
+ public $path;
+ public $features;
+ public $currentFileInfo;
+ public $css;
+ public $skip;
+ public $root;
+ public $type = 'Import';
+
+ public function __construct($path, $features, $options, $index, $currentFileInfo = null ){
+ $this->options = $options;
+ $this->index = $index;
+ $this->path = $path;
+ $this->features = $features;
+ $this->currentFileInfo = $currentFileInfo;
+
+ if( is_array($options) ){
+ $this->options += array('inline'=>false);
+
+ if( isset($this->options['less']) || $this->options['inline'] ){
+ $this->css = !isset($this->options['less']) || !$this->options['less'] || $this->options['inline'];
+ } else {
+ $pathValue = $this->getPath();
+ if( $pathValue && preg_match('/css([\?;].*)?$/',$pathValue) ){
+ $this->css = true;
+ }
+ }
+ }
+ }
+
+//
+// The actual import node doesn't return anything, when converted to CSS.
+// The reason is that it's used at the evaluation stage, so that the rules
+// it imports can be treated like any other rules.
+//
+// In `eval`, we make sure all Import nodes get evaluated, recursively, so
+// we end up with a flat structure, which can easily be imported in the parent
+// ruleset.
+//
+
+ public function accept($visitor){
+
+ if( $this->features ){
+ $this->features = $visitor->visitObj($this->features);
+ }
+ $this->path = $visitor->visitObj($this->path);
+
+ if( !$this->options['inline'] && $this->root ){
+ $this->root = $visitor->visit($this->root);
+ }
+ }
+
+ /**
+ * @see Less_Tree::genCSS
+ */
+ public function genCSS( $output ){
+ if( $this->css ){
+
+ $output->add( '@import ', $this->currentFileInfo, $this->index );
+
+ $this->path->genCSS( $output );
+ if( $this->features ){
+ $output->add( ' ' );
+ $this->features->genCSS( $output );
+ }
+ $output->add( ';' );
+ }
+ }
+
+ public function toCSS(){
+ $features = $this->features ? ' ' . $this->features->toCSS() : '';
+
+ if ($this->css) {
+ return "@import " . $this->path->toCSS() . $features . ";\n";
+ } else {
+ return "";
+ }
+ }
+
+ /**
+ * @return string
+ */
+ public function getPath(){
+ if ($this->path instanceof Less_Tree_Quoted) {
+ $path = $this->path->value;
+ $path = ( isset($this->css) || preg_match('/(\.[a-z]*$)|([\?;].*)$/',$path)) ? $path : $path . '.less';
+ } else if ($this->path instanceof Less_Tree_URL) {
+ $path = $this->path->value->value;
+ }else{
+ return null;
+ }
+
+ //remove query string and fragment
+ return preg_replace('/[\?#][^\?]*$/','',$path);
+ }
+
+ public function compileForImport( $env ){
+ return new Less_Tree_Import( $this->path->compile($env), $this->features, $this->options, $this->index, $this->currentFileInfo);
+ }
+
+ public function compilePath($env) {
+ $path = $this->path->compile($env);
+ $rootpath = '';
+ if( $this->currentFileInfo && $this->currentFileInfo['rootpath'] ){
+ $rootpath = $this->currentFileInfo['rootpath'];
+ }
+
+
+ if( !($path instanceof Less_Tree_URL) ){
+ if( $rootpath ){
+ $pathValue = $path->value;
+ // Add the base path if the import is relative
+ if( $pathValue && Less_Environment::isPathRelative($pathValue) ){
+ $path->value = $this->currentFileInfo['uri_root'].$pathValue;
+ }
+ }
+ $path->value = Less_Environment::normalizePath($path->value);
+ }
+
+
+
+ return $path;
+ }
+
+ public function compile( $env ){
+
+ $evald = $this->compileForImport($env);
+
+ //get path & uri
+ $path_and_uri = null;
+ if( is_callable(Less_Parser::$options['import_callback']) ){
+ $path_and_uri = call_user_func(Less_Parser::$options['import_callback'],$evald);
+ }
+
+ if( !$path_and_uri ){
+ $path_and_uri = $evald->PathAndUri();
+ }
+
+ if( $path_and_uri ){
+ list($full_path, $uri) = $path_and_uri;
+ }else{
+ $full_path = $uri = $evald->getPath();
+ }
+
+
+ //import once
+ if( $evald->skip( $full_path, $env) ){
+ return array();
+ }
+
+ if( $this->options['inline'] ){
+ //todo needs to reference css file not import
+ //$contents = new Less_Tree_Anonymous($this->root, 0, array('filename'=>$this->importedFilename), true );
+
+ Less_Parser::AddParsedFile($full_path);
+ $contents = new Less_Tree_Anonymous( file_get_contents($full_path), 0, array(), true );
+
+ if( $this->features ){
+ return new Less_Tree_Media( array($contents), $this->features->value );
+ }
+
+ return array( $contents );
+ }
+
+
+ // css ?
+ if( $evald->css ){
+ $features = ( $evald->features ? $evald->features->compile($env) : null );
+ return new Less_Tree_Import( $this->compilePath( $env), $features, $this->options, $this->index);
+ }
+
+
+ return $this->ParseImport( $full_path, $uri, $env );
+ }
+
+
+ /**
+ * Using the import directories, get the full absolute path and uri of the import
+ *
+ * @param Less_Tree_Import $evald
+ */
+ public function PathAndUri(){
+
+ $evald_path = $this->getPath();
+
+ if( $evald_path ){
+
+ $import_dirs = array();
+
+ if( Less_Environment::isPathRelative($evald_path) ){
+ //if the path is relative, the file should be in the current directory
+ $import_dirs[ $this->currentFileInfo['currentDirectory'] ] = $this->currentFileInfo['uri_root'];
+
+ }else{
+ //otherwise, the file should be relative to the server root
+ $import_dirs[ $this->currentFileInfo['entryPath'] ] = $this->currentFileInfo['entryUri'];
+
+ //if the user supplied entryPath isn't the actual root
+ $import_dirs[ $_SERVER['DOCUMENT_ROOT'] ] = '';
+
+ }
+
+ // always look in user supplied import directories
+ $import_dirs = array_merge( $import_dirs, Less_Parser::$options['import_dirs'] );
+
+
+ foreach( $import_dirs as $rootpath => $rooturi){
+ if( is_callable($rooturi) ){
+ list($path, $uri) = call_user_func($rooturi, $evald_path);
+ if( is_string($path) ){
+ $full_path = $path;
+ return array( $full_path, $uri );
+ }
+ }elseif( !empty($rootpath) ){
+
+
+ if( $rooturi ){
+ if( strpos($evald_path,$rooturi) === 0 ){
+ $evald_path = substr( $evald_path, strlen($rooturi) );
+ }
+ }
+
+ $path = rtrim($rootpath,'/\\').'/'.ltrim($evald_path,'/\\');
+
+ if( file_exists($path) ){
+ $full_path = Less_Environment::normalizePath($path);
+ $uri = Less_Environment::normalizePath(dirname($rooturi.$evald_path));
+ return array( $full_path, $uri );
+ } elseif( file_exists($path.'.less') ){
+ $full_path = Less_Environment::normalizePath($path.'.less');
+ $uri = Less_Environment::normalizePath(dirname($rooturi.$evald_path.'.less'));
+ return array( $full_path, $uri );
+ }
+ }
+ }
+ }
+ }
+
+
+ /**
+ * Parse the import url and return the rules
+ *
+ * @return Less_Tree_Media|array
+ */
+ public function ParseImport( $full_path, $uri, $env ){
+
+ $import_env = clone $env;
+ if( (isset($this->options['reference']) && $this->options['reference']) || isset($this->currentFileInfo['reference']) ){
+ $import_env->currentFileInfo['reference'] = true;
+ }
+
+ if( (isset($this->options['multiple']) && $this->options['multiple']) ){
+ $import_env->importMultiple = true;
+ }
+
+ $parser = new Less_Parser($import_env);
+ $root = $parser->parseFile($full_path, $uri, true);
+
+
+ $ruleset = new Less_Tree_Ruleset(array(), $root->rules );
+ $ruleset->evalImports($import_env);
+
+ return $this->features ? new Less_Tree_Media($ruleset->rules, $this->features->value) : $ruleset->rules;
+ }
+
+
+ /**
+ * Should the import be skipped?
+ *
+ * @return boolean|null
+ */
+ private function Skip($path, $env){
+
+ $path = Less_Parser::winPath(realpath($path));
+
+ if( $path && Less_Parser::FileParsed($path) ){
+
+ if( isset($this->currentFileInfo['reference']) ){
+ return true;
+ }
+
+ return !isset($this->options['multiple']) && !$env->importMultiple;
+ }
+
+ }
+}
+
diff --git a/vendor/oyejorge/less.php/lib/Less/Tree/Javascript.php b/vendor/oyejorge/less.php/lib/Less/Tree/Javascript.php
new file mode 100644
index 00000000..1b03183d
--- /dev/null
+++ b/vendor/oyejorge/less.php/lib/Less/Tree/Javascript.php
@@ -0,0 +1,30 @@
+<?php
+
+/**
+ * Javascript
+ *
+ * @package Less
+ * @subpackage tree
+ */
+class Less_Tree_Javascript extends Less_Tree{
+
+ public $type = 'Javascript';
+ public $escaped;
+ public $expression;
+ public $index;
+
+ /**
+ * @param boolean $index
+ * @param boolean $escaped
+ */
+ public function __construct($string, $index, $escaped){
+ $this->escaped = $escaped;
+ $this->expression = $string;
+ $this->index = $index;
+ }
+
+ public function compile(){
+ return new Less_Tree_Anonymous('/* Sorry, can not do JavaScript evaluation in PHP... :( */');
+ }
+
+}
diff --git a/vendor/oyejorge/less.php/lib/Less/Tree/Keyword.php b/vendor/oyejorge/less.php/lib/Less/Tree/Keyword.php
new file mode 100644
index 00000000..e1d98c45
--- /dev/null
+++ b/vendor/oyejorge/less.php/lib/Less/Tree/Keyword.php
@@ -0,0 +1,44 @@
+<?php
+
+/**
+ * Keyword
+ *
+ * @package Less
+ * @subpackage tree
+ */
+class Less_Tree_Keyword extends Less_Tree{
+
+ public $value;
+ public $type = 'Keyword';
+
+ /**
+ * @param string $value
+ */
+ public function __construct($value){
+ $this->value = $value;
+ }
+
+ public function compile(){
+ return $this;
+ }
+
+ /**
+ * @see Less_Tree::genCSS
+ */
+ public function genCSS( $output ){
+
+ if( $this->value === '%') {
+ throw new Less_Exception_Compiler("Invalid % without number");
+ }
+
+ $output->add( $this->value );
+ }
+
+ public function compare($other) {
+ if ($other instanceof Less_Tree_Keyword) {
+ return $other->value === $this->value ? 0 : 1;
+ } else {
+ return -1;
+ }
+ }
+}
diff --git a/vendor/oyejorge/less.php/lib/Less/Tree/Media.php b/vendor/oyejorge/less.php/lib/Less/Tree/Media.php
new file mode 100644
index 00000000..f9ee9d42
--- /dev/null
+++ b/vendor/oyejorge/less.php/lib/Less/Tree/Media.php
@@ -0,0 +1,179 @@
+<?php
+
+/**
+ * Media
+ *
+ * @package Less
+ * @subpackage tree
+ */
+class Less_Tree_Media extends Less_Tree{
+
+ public $features;
+ public $rules;
+ public $index;
+ public $currentFileInfo;
+ public $isReferenced;
+ public $type = 'Media';
+
+ public function __construct($value = array(), $features = array(), $index = null, $currentFileInfo = null ){
+
+ $this->index = $index;
+ $this->currentFileInfo = $currentFileInfo;
+
+ $selectors = $this->emptySelectors();
+
+ $this->features = new Less_Tree_Value($features);
+
+ $this->rules = array(new Less_Tree_Ruleset($selectors, $value));
+ $this->rules[0]->allowImports = true;
+ }
+
+ public function accept( $visitor ){
+ $this->features = $visitor->visitObj($this->features);
+ $this->rules = $visitor->visitArray($this->rules);
+ }
+
+ /**
+ * @see Less_Tree::genCSS
+ */
+ public function genCSS( $output ){
+
+ $output->add( '@media ', $this->currentFileInfo, $this->index );
+ $this->features->genCSS( $output );
+ Less_Tree::outputRuleset( $output, $this->rules);
+
+ }
+
+ public function compile($env) {
+
+ $media = new Less_Tree_Media(array(), array(), $this->index, $this->currentFileInfo );
+
+ $strictMathBypass = false;
+ if( Less_Parser::$options['strictMath'] === false) {
+ $strictMathBypass = true;
+ Less_Parser::$options['strictMath'] = true;
+ }
+
+ $media->features = $this->features->compile($env);
+
+ if( $strictMathBypass ){
+ Less_Parser::$options['strictMath'] = false;
+ }
+
+ $env->mediaPath[] = $media;
+ $env->mediaBlocks[] = $media;
+
+ array_unshift($env->frames, $this->rules[0]);
+ $media->rules = array($this->rules[0]->compile($env));
+ array_shift($env->frames);
+
+ array_pop($env->mediaPath);
+
+ return !$env->mediaPath ? $media->compileTop($env) : $media->compileNested($env);
+ }
+
+ public function variable($name) {
+ return $this->rules[0]->variable($name);
+ }
+
+ public function find($selector) {
+ return $this->rules[0]->find($selector, $this);
+ }
+
+ public function emptySelectors(){
+ $el = new Less_Tree_Element('','&', $this->index, $this->currentFileInfo );
+ $sels = array( new Less_Tree_Selector(array($el), array(), null, $this->index, $this->currentFileInfo) );
+ $sels[0]->mediaEmpty = true;
+ return $sels;
+ }
+
+ public function markReferenced(){
+ $this->rules[0]->markReferenced();
+ $this->isReferenced = true;
+ Less_Tree::ReferencedArray($this->rules[0]->rules);
+ }
+
+ // evaltop
+ public function compileTop($env) {
+ $result = $this;
+
+ if (count($env->mediaBlocks) > 1) {
+ $selectors = $this->emptySelectors();
+ $result = new Less_Tree_Ruleset($selectors, $env->mediaBlocks);
+ $result->multiMedia = true;
+ }
+
+ $env->mediaBlocks = array();
+ $env->mediaPath = array();
+
+ return $result;
+ }
+
+ public function compileNested($env) {
+ $path = array_merge($env->mediaPath, array($this));
+
+ // Extract the media-query conditions separated with `,` (OR).
+ foreach ($path as $key => $p) {
+ $value = $p->features instanceof Less_Tree_Value ? $p->features->value : $p->features;
+ $path[$key] = is_array($value) ? $value : array($value);
+ }
+
+ // Trace all permutations to generate the resulting media-query.
+ //
+ // (a, b and c) with nested (d, e) ->
+ // a and d
+ // a and e
+ // b and c and d
+ // b and c and e
+
+ $permuted = $this->permute($path);
+ $expressions = array();
+ foreach($permuted as $path){
+
+ for( $i=0, $len=count($path); $i < $len; $i++){
+ $path[$i] = Less_Parser::is_method($path[$i], 'toCSS') ? $path[$i] : new Less_Tree_Anonymous($path[$i]);
+ }
+
+ for( $i = count($path) - 1; $i > 0; $i-- ){
+ array_splice($path, $i, 0, array(new Less_Tree_Anonymous('and')));
+ }
+
+ $expressions[] = new Less_Tree_Expression($path);
+ }
+ $this->features = new Less_Tree_Value($expressions);
+
+
+
+ // Fake a tree-node that doesn't output anything.
+ return new Less_Tree_Ruleset(array(), array());
+ }
+
+ public function permute($arr) {
+ if (!$arr)
+ return array();
+
+ if (count($arr) == 1)
+ return $arr[0];
+
+ $result = array();
+ $rest = $this->permute(array_slice($arr, 1));
+ foreach ($rest as $r) {
+ foreach ($arr[0] as $a) {
+ $result[] = array_merge(
+ is_array($a) ? $a : array($a),
+ is_array($r) ? $r : array($r)
+ );
+ }
+ }
+
+ return $result;
+ }
+
+ public function bubbleSelectors($selectors) {
+
+ if( !$selectors) return;
+
+ $this->rules = array(new Less_Tree_Ruleset( $selectors, array($this->rules[0])));
+ }
+
+}
diff --git a/vendor/oyejorge/less.php/lib/Less/Tree/Mixin/Call.php b/vendor/oyejorge/less.php/lib/Less/Tree/Mixin/Call.php
new file mode 100644
index 00000000..d7e2a137
--- /dev/null
+++ b/vendor/oyejorge/less.php/lib/Less/Tree/Mixin/Call.php
@@ -0,0 +1,202 @@
+<?php
+
+
+class Less_Tree_Mixin_Call extends Less_Tree{
+
+ public $selector;
+ public $arguments;
+ public $index;
+ public $currentFileInfo;
+
+ public $important;
+ public $type = 'MixinCall';
+
+ /**
+ * less.js: tree.mixin.Call
+ *
+ */
+ public function __construct($elements, $args, $index, $currentFileInfo, $important = false){
+ $this->selector = new Less_Tree_Selector($elements);
+ $this->arguments = $args;
+ $this->index = $index;
+ $this->currentFileInfo = $currentFileInfo;
+ $this->important = $important;
+ }
+
+ //function accept($visitor){
+ // $this->selector = $visitor->visit($this->selector);
+ // $this->arguments = $visitor->visit($this->arguments);
+ //}
+
+
+ public function compile($env){
+
+ $rules = array();
+ $match = false;
+ $isOneFound = false;
+ $candidates = array();
+ $defaultUsed = false;
+ $conditionResult = array();
+
+ $args = array();
+ foreach($this->arguments as $a){
+ $args[] = array('name'=> $a['name'], 'value' => $a['value']->compile($env) );
+ }
+
+ foreach($env->frames as $frame){
+
+ $mixins = $frame->find($this->selector);
+
+ if( !$mixins ){
+ continue;
+ }
+
+ $isOneFound = true;
+ $defNone = 0;
+ $defTrue = 1;
+ $defFalse = 2;
+
+ // To make `default()` function independent of definition order we have two "subpasses" here.
+ // At first we evaluate each guard *twice* (with `default() == true` and `default() == false`),
+ // and build candidate list with corresponding flags. Then, when we know all possible matches,
+ // we make a final decision.
+
+ $mixins_len = count($mixins);
+ for( $m = 0; $m < $mixins_len; $m++ ){
+ $mixin = $mixins[$m];
+
+ if( $this->IsRecursive( $env, $mixin ) ){
+ continue;
+ }
+
+ if( $mixin->matchArgs($args, $env) ){
+
+ $candidate = array('mixin' => $mixin, 'group' => $defNone);
+
+ if( $mixin instanceof Less_Tree_Ruleset ){
+
+ for( $f = 0; $f < 2; $f++ ){
+ Less_Tree_DefaultFunc::value($f);
+ $conditionResult[$f] = $mixin->matchCondition( $args, $env);
+ }
+ if( $conditionResult[0] || $conditionResult[1] ){
+ if( $conditionResult[0] != $conditionResult[1] ){
+ $candidate['group'] = $conditionResult[1] ? $defTrue : $defFalse;
+ }
+
+ $candidates[] = $candidate;
+ }
+ }else{
+ $candidates[] = $candidate;
+ }
+
+ $match = true;
+ }
+ }
+
+ Less_Tree_DefaultFunc::reset();
+
+
+ $count = array(0, 0, 0);
+ for( $m = 0; $m < count($candidates); $m++ ){
+ $count[ $candidates[$m]['group'] ]++;
+ }
+
+ if( $count[$defNone] > 0 ){
+ $defaultResult = $defFalse;
+ } else {
+ $defaultResult = $defTrue;
+ if( ($count[$defTrue] + $count[$defFalse]) > 1 ){
+ throw new Exception( 'Ambiguous use of `default()` found when matching for `'. $this->format($args) + '`' );
+ }
+ }
+
+
+ $candidates_length = count($candidates);
+ $length_1 = ($candidates_length == 1);
+
+ for( $m = 0; $m < $candidates_length; $m++){
+ $candidate = $candidates[$m]['group'];
+ if( ($candidate === $defNone) || ($candidate === $defaultResult) ){
+ try{
+ $mixin = $candidates[$m]['mixin'];
+ if( !($mixin instanceof Less_Tree_Mixin_Definition) ){
+ $mixin = new Less_Tree_Mixin_Definition('', array(), $mixin->rules, null, false);
+ $mixin->originalRuleset = $mixins[$m]->originalRuleset;
+ }
+ $rules = array_merge($rules, $mixin->evalCall($env, $args, $this->important)->rules);
+ } catch (Exception $e) {
+ //throw new Less_Exception_Compiler($e->getMessage(), $e->index, null, $this->currentFileInfo['filename']);
+ throw new Less_Exception_Compiler($e->getMessage(), null, null, $this->currentFileInfo);
+ }
+ }
+ }
+
+ if( $match ){
+ if( !$this->currentFileInfo || !isset($this->currentFileInfo['reference']) || !$this->currentFileInfo['reference'] ){
+ Less_Tree::ReferencedArray($rules);
+ }
+
+ return $rules;
+ }
+ }
+
+ if( $isOneFound ){
+ throw new Less_Exception_Compiler('No matching definition was found for `'.$this->Format( $args ).'`', null, $this->index, $this->currentFileInfo);
+
+ }else{
+ throw new Less_Exception_Compiler(trim($this->selector->toCSS()) . " is undefined in ".$this->currentFileInfo['filename'], null, $this->index);
+ }
+
+ }
+
+ /**
+ * Format the args for use in exception messages
+ *
+ */
+ private function Format($args){
+ $message = array();
+ if( $args ){
+ foreach($args as $a){
+ $argValue = '';
+ if( $a['name'] ){
+ $argValue += $a['name']+':';
+ }
+ if( is_object($a['value']) ){
+ $argValue += $a['value']->toCSS();
+ }else{
+ $argValue += '???';
+ }
+ $message[] = $argValue;
+ }
+ }
+ return implode(', ',$message);
+ }
+
+
+ /**
+ * Are we in a recursive mixin call?
+ *
+ * @return bool
+ */
+ private function IsRecursive( $env, $mixin ){
+
+ foreach($env->frames as $recur_frame){
+ if( !($mixin instanceof Less_Tree_Mixin_Definition) ){
+
+ if( $mixin === $recur_frame ){
+ return true;
+ }
+
+ if( isset($recur_frame->originalRuleset) && $mixin->ruleset_id === $recur_frame->originalRuleset ){
+ return true;
+ }
+ }
+ }
+
+ return false;
+ }
+
+}
+
+
diff --git a/vendor/oyejorge/less.php/lib/Less/Tree/Mixin/Definition.php b/vendor/oyejorge/less.php/lib/Less/Tree/Mixin/Definition.php
new file mode 100644
index 00000000..b16d6887
--- /dev/null
+++ b/vendor/oyejorge/less.php/lib/Less/Tree/Mixin/Definition.php
@@ -0,0 +1,241 @@
+<?php
+
+class Less_Tree_Mixin_Definition extends Less_Tree_Ruleset{
+ public $name;
+ public $selectors;
+ public $params;
+ public $arity = 0;
+ public $rules;
+ public $lookups = array();
+ public $required = 0;
+ public $frames = array();
+ public $condition;
+ public $variadic;
+ public $type = 'MixinDefinition';
+
+
+ // less.js : /lib/less/tree/mixin.js : tree.mixin.Definition
+ public function __construct($name, $params, $rules, $condition, $variadic = false, $frames = array() ){
+ $this->name = $name;
+ $this->selectors = array(new Less_Tree_Selector(array( new Less_Tree_Element(null, $name))));
+
+ $this->params = $params;
+ $this->condition = $condition;
+ $this->variadic = $variadic;
+ $this->rules = $rules;
+
+ if( $params ){
+ $this->arity = count($params);
+ foreach( $params as $p ){
+ if (! isset($p['name']) || ($p['name'] && !isset($p['value']))) {
+ $this->required++;
+ }
+ }
+ }
+
+ $this->frames = $frames;
+ $this->SetRulesetIndex();
+ }
+
+
+
+ //function accept( $visitor ){
+ // $this->params = $visitor->visit($this->params);
+ // $this->rules = $visitor->visit($this->rules);
+ // $this->condition = $visitor->visit($this->condition);
+ //}
+
+
+ public function toCSS(){
+ return '';
+ }
+
+ // less.js : /lib/less/tree/mixin.js : tree.mixin.Definition.evalParams
+ public function compileParams($env, $mixinFrames, $args = array() , &$evaldArguments = array() ){
+ $frame = new Less_Tree_Ruleset(null, array());
+ $params = $this->params;
+ $mixinEnv = null;
+ $argsLength = 0;
+
+ if( $args ){
+ $argsLength = count($args);
+ for($i = 0; $i < $argsLength; $i++ ){
+ $arg = $args[$i];
+
+ if( $arg && $arg['name'] ){
+ $isNamedFound = false;
+
+ foreach($params as $j => $param){
+ if( !isset($evaldArguments[$j]) && $arg['name'] === $params[$j]['name']) {
+ $evaldArguments[$j] = $arg['value']->compile($env);
+ array_unshift($frame->rules, new Less_Tree_Rule( $arg['name'], $arg['value']->compile($env) ) );
+ $isNamedFound = true;
+ break;
+ }
+ }
+ if ($isNamedFound) {
+ array_splice($args, $i, 1);
+ $i--;
+ $argsLength--;
+ continue;
+ } else {
+ throw new Less_Exception_Compiler("Named argument for " . $this->name .' '.$args[$i]['name'] . ' not found');
+ }
+ }
+ }
+ }
+
+ $argIndex = 0;
+ foreach($params as $i => $param){
+
+ if ( isset($evaldArguments[$i]) ){ continue; }
+
+ $arg = null;
+ if( isset($args[$argIndex]) ){
+ $arg = $args[$argIndex];
+ }
+
+ if (isset($param['name']) && $param['name']) {
+
+ if( isset($param['variadic']) ){
+ $varargs = array();
+ for ($j = $argIndex; $j < $argsLength; $j++) {
+ $varargs[] = $args[$j]['value']->compile($env);
+ }
+ $expression = new Less_Tree_Expression($varargs);
+ array_unshift($frame->rules, new Less_Tree_Rule($param['name'], $expression->compile($env)));
+ }else{
+ $val = ($arg && $arg['value']) ? $arg['value'] : false;
+
+ if ($val) {
+ $val = $val->compile($env);
+ } else if ( isset($param['value']) ) {
+
+ if( !$mixinEnv ){
+ $mixinEnv = new Less_Environment();
+ $mixinEnv->frames = array_merge( array($frame), $mixinFrames);
+ }
+
+ $val = $param['value']->compile($mixinEnv);
+ $frame->resetCache();
+ } else {
+ throw new Less_Exception_Compiler("Wrong number of arguments for " . $this->name . " (" . $argsLength . ' for ' . $this->arity . ")");
+ }
+
+ array_unshift($frame->rules, new Less_Tree_Rule($param['name'], $val));
+ $evaldArguments[$i] = $val;
+ }
+ }
+
+ if ( isset($param['variadic']) && $args) {
+ for ($j = $argIndex; $j < $argsLength; $j++) {
+ $evaldArguments[$j] = $args[$j]['value']->compile($env);
+ }
+ }
+ $argIndex++;
+ }
+
+ ksort($evaldArguments);
+ $evaldArguments = array_values($evaldArguments);
+
+ return $frame;
+ }
+
+ public function compile($env) {
+ if( $this->frames ){
+ return new Less_Tree_Mixin_Definition($this->name, $this->params, $this->rules, $this->condition, $this->variadic, $this->frames );
+ }
+ return new Less_Tree_Mixin_Definition($this->name, $this->params, $this->rules, $this->condition, $this->variadic, $env->frames );
+ }
+
+ public function evalCall($env, $args = NULL, $important = NULL) {
+
+ Less_Environment::$mixin_stack++;
+
+ $_arguments = array();
+
+ if( $this->frames ){
+ $mixinFrames = array_merge($this->frames, $env->frames);
+ }else{
+ $mixinFrames = $env->frames;
+ }
+
+ $frame = $this->compileParams($env, $mixinFrames, $args, $_arguments);
+
+ $ex = new Less_Tree_Expression($_arguments);
+ array_unshift($frame->rules, new Less_Tree_Rule('@arguments', $ex->compile($env)));
+
+
+ $ruleset = new Less_Tree_Ruleset(null, $this->rules);
+ $ruleset->originalRuleset = $this->ruleset_id;
+
+
+ $ruleSetEnv = new Less_Environment();
+ $ruleSetEnv->frames = array_merge( array($this, $frame), $mixinFrames );
+ $ruleset = $ruleset->compile( $ruleSetEnv );
+
+ if( $important ){
+ $ruleset = $ruleset->makeImportant();
+ }
+
+ Less_Environment::$mixin_stack--;
+
+ return $ruleset;
+ }
+
+
+ public function matchCondition($args, $env) {
+
+ if( !$this->condition ){
+ return true;
+ }
+
+ // set array to prevent error on array_merge
+ if(!is_array($this->frames)) {
+ $this->frames = array();
+ }
+
+ $frame = $this->compileParams($env, array_merge($this->frames,$env->frames), $args );
+
+ $compile_env = new Less_Environment();
+ $compile_env->frames = array_merge(
+ array($frame) // the parameter variables
+ , $this->frames // the parent namespace/mixin frames
+ , $env->frames // the current environment frames
+ );
+
+ $compile_env->functions = $env->functions;
+
+ return (bool)$this->condition->compile($compile_env);
+ }
+
+ public function matchArgs($args, $env = NULL){
+ $argsLength = count($args);
+
+ if( !$this->variadic ){
+ if( $argsLength < $this->required ){
+ return false;
+ }
+ if( $argsLength > count($this->params) ){
+ return false;
+ }
+ }else{
+ if( $argsLength < ($this->required - 1)){
+ return false;
+ }
+ }
+
+ $len = min($argsLength, $this->arity);
+
+ for( $i = 0; $i < $len; $i++ ){
+ if( !isset($this->params[$i]['name']) && !isset($this->params[$i]['variadic']) ){
+ if( $args[$i]['value']->compile($env)->toCSS() != $this->params[$i]['value']->compile($env)->toCSS() ){
+ return false;
+ }
+ }
+ }
+
+ return true;
+ }
+
+}
diff --git a/vendor/oyejorge/less.php/lib/Less/Tree/NameValue.php b/vendor/oyejorge/less.php/lib/Less/Tree/NameValue.php
new file mode 100644
index 00000000..e65737c2
--- /dev/null
+++ b/vendor/oyejorge/less.php/lib/Less/Tree/NameValue.php
@@ -0,0 +1,41 @@
+<?php
+
+/**
+ * A simple css name-value pair
+ * ex: width:100px;
+ *
+ * In bootstrap, there are about 600-1,000 simple name-value pairs (depending on how forgiving the match is) -vs- 6,020 dynamic rules (Less_Tree_Rule)
+ * Using the name-value object can speed up bootstrap compilation slightly, but it breaks color keyword interpretation: color:red -> color:#FF0000;
+ *
+ * @package Less
+ * @subpackage tree
+ */
+class Less_Tree_NameValue extends Less_Tree{
+
+ public $name;
+ public $value;
+ public $index;
+ public $currentFileInfo;
+ public $type = 'NameValue';
+
+ public function __construct($name, $value = null, $index = null, $currentFileInfo = null ){
+ $this->name = $name;
+ $this->value = $value;
+ $this->index = $index;
+ $this->currentFileInfo = $currentFileInfo;
+ }
+
+ public function genCSS( $output ){
+
+ $output->add(
+ $this->name
+ . Less_Environment::$_outputMap[': ']
+ . $this->value
+ . (((Less_Environment::$lastRule && Less_Parser::$options['compress'])) ? "" : ";")
+ , $this->currentFileInfo, $this->index);
+ }
+
+ public function compile ($env){
+ return $this;
+ }
+}
diff --git a/vendor/oyejorge/less.php/lib/Less/Tree/Negative.php b/vendor/oyejorge/less.php/lib/Less/Tree/Negative.php
new file mode 100644
index 00000000..507443ec
--- /dev/null
+++ b/vendor/oyejorge/less.php/lib/Less/Tree/Negative.php
@@ -0,0 +1,37 @@
+<?php
+
+/**
+ * Negative
+ *
+ * @package Less
+ * @subpackage tree
+ */
+class Less_Tree_Negative extends Less_Tree{
+
+ public $value;
+ public $type = 'Negative';
+
+ public function __construct($node){
+ $this->value = $node;
+ }
+
+ //function accept($visitor) {
+ // $this->value = $visitor->visit($this->value);
+ //}
+
+ /**
+ * @see Less_Tree::genCSS
+ */
+ public function genCSS( $output ){
+ $output->add( '-' );
+ $this->value->genCSS( $output );
+ }
+
+ public function compile($env) {
+ if( Less_Environment::isMathOn() ){
+ $ret = new Less_Tree_Operation('*', array( new Less_Tree_Dimension(-1), $this->value ) );
+ return $ret->compile($env);
+ }
+ return new Less_Tree_Negative( $this->value->compile($env) );
+ }
+} \ No newline at end of file
diff --git a/vendor/oyejorge/less.php/lib/Less/Tree/Operation.php b/vendor/oyejorge/less.php/lib/Less/Tree/Operation.php
new file mode 100644
index 00000000..e69e0da6
--- /dev/null
+++ b/vendor/oyejorge/less.php/lib/Less/Tree/Operation.php
@@ -0,0 +1,70 @@
+<?php
+
+/**
+ * Operation
+ *
+ * @package Less
+ * @subpackage tree
+ */
+class Less_Tree_Operation extends Less_Tree{
+
+ public $op;
+ public $operands;
+ public $isSpaced;
+ public $type = 'Operation';
+
+ /**
+ * @param string $op
+ */
+ public function __construct($op, $operands, $isSpaced = false){
+ $this->op = trim($op);
+ $this->operands = $operands;
+ $this->isSpaced = $isSpaced;
+ }
+
+ public function accept($visitor) {
+ $this->operands = $visitor->visitArray($this->operands);
+ }
+
+ public function compile($env){
+ $a = $this->operands[0]->compile($env);
+ $b = $this->operands[1]->compile($env);
+
+
+ if( Less_Environment::isMathOn() ){
+
+ if( $a instanceof Less_Tree_Dimension && $b instanceof Less_Tree_Color ){
+ $a = $a->toColor();
+
+ }elseif( $b instanceof Less_Tree_Dimension && $a instanceof Less_Tree_Color ){
+ $b = $b->toColor();
+
+ }
+
+ if( !method_exists($a,'operate') ){
+ throw new Less_Exception_Compiler("Operation on an invalid type");
+ }
+
+ return $a->operate( $this->op, $b);
+ }
+
+ return new Less_Tree_Operation($this->op, array($a, $b), $this->isSpaced );
+ }
+
+
+ /**
+ * @see Less_Tree::genCSS
+ */
+ public function genCSS( $output ){
+ $this->operands[0]->genCSS( $output );
+ if( $this->isSpaced ){
+ $output->add( " " );
+ }
+ $output->add( $this->op );
+ if( $this->isSpaced ){
+ $output->add( ' ' );
+ }
+ $this->operands[1]->genCSS( $output );
+ }
+
+}
diff --git a/vendor/oyejorge/less.php/lib/Less/Tree/Paren.php b/vendor/oyejorge/less.php/lib/Less/Tree/Paren.php
new file mode 100644
index 00000000..01864550
--- /dev/null
+++ b/vendor/oyejorge/less.php/lib/Less/Tree/Paren.php
@@ -0,0 +1,35 @@
+<?php
+
+/**
+ * Paren
+ *
+ * @package Less
+ * @subpackage tree
+ */
+class Less_Tree_Paren extends Less_Tree{
+
+ public $value;
+ public $type = 'Paren';
+
+ public function __construct($value) {
+ $this->value = $value;
+ }
+
+ public function accept($visitor){
+ $this->value = $visitor->visitObj($this->value);
+ }
+
+ /**
+ * @see Less_Tree::genCSS
+ */
+ public function genCSS( $output ){
+ $output->add( '(' );
+ $this->value->genCSS( $output );
+ $output->add( ')' );
+ }
+
+ public function compile($env) {
+ return new Less_Tree_Paren($this->value->compile($env));
+ }
+
+}
diff --git a/vendor/oyejorge/less.php/lib/Less/Tree/Quoted.php b/vendor/oyejorge/less.php/lib/Less/Tree/Quoted.php
new file mode 100644
index 00000000..80063b5e
--- /dev/null
+++ b/vendor/oyejorge/less.php/lib/Less/Tree/Quoted.php
@@ -0,0 +1,81 @@
+<?php
+
+/**
+ * Quoted
+ *
+ * @package Less
+ * @subpackage tree
+ */
+class Less_Tree_Quoted extends Less_Tree{
+ public $escaped;
+ public $value;
+ public $quote;
+ public $index;
+ public $currentFileInfo;
+ public $type = 'Quoted';
+
+ /**
+ * @param string $str
+ */
+ public function __construct($str, $content = '', $escaped = false, $index = false, $currentFileInfo = null ){
+ $this->escaped = $escaped;
+ $this->value = $content;
+ if( $str ){
+ $this->quote = $str[0];
+ }
+ $this->index = $index;
+ $this->currentFileInfo = $currentFileInfo;
+ }
+
+ /**
+ * @see Less_Tree::genCSS
+ */
+ public function genCSS( $output ){
+ if( !$this->escaped ){
+ $output->add( $this->quote, $this->currentFileInfo, $this->index );
+ }
+ $output->add( $this->value );
+ if( !$this->escaped ){
+ $output->add( $this->quote );
+ }
+ }
+
+ public function compile($env){
+
+ $value = $this->value;
+ if( preg_match_all('/`([^`]+)`/', $this->value, $matches) ){
+ foreach($matches as $i => $match){
+ $js = new Less_Tree_JavaScript($matches[1], $this->index, true);
+ $js = $js->compile()->value;
+ $value = str_replace($matches[0][$i], $js, $value);
+ }
+ }
+
+ if( preg_match_all('/@\{([\w-]+)\}/',$value,$matches) ){
+ foreach($matches[1] as $i => $match){
+ $v = new Less_Tree_Variable('@' . $match, $this->index, $this->currentFileInfo );
+ $v = $v->compile($env);
+ $v = ($v instanceof Less_Tree_Quoted) ? $v->value : $v->toCSS();
+ $value = str_replace($matches[0][$i], $v, $value);
+ }
+ }
+
+ return new Less_Tree_Quoted($this->quote . $value . $this->quote, $value, $this->escaped, $this->index, $this->currentFileInfo);
+ }
+
+ public function compare($x) {
+
+ if( !Less_Parser::is_method($x, 'toCSS') ){
+ return -1;
+ }
+
+ $left = $this->toCSS();
+ $right = $x->toCSS();
+
+ if ($left === $right) {
+ return 0;
+ }
+
+ return $left < $right ? -1 : 1;
+ }
+}
diff --git a/vendor/oyejorge/less.php/lib/Less/Tree/Rule.php b/vendor/oyejorge/less.php/lib/Less/Tree/Rule.php
new file mode 100644
index 00000000..ee4a9e25
--- /dev/null
+++ b/vendor/oyejorge/less.php/lib/Less/Tree/Rule.php
@@ -0,0 +1,115 @@
+<?php
+
+/**
+ * Rule
+ *
+ * @package Less
+ * @subpackage tree
+ */
+class Less_Tree_Rule extends Less_Tree{
+
+ public $name;
+ public $value;
+ public $important;
+ public $merge;
+ public $index;
+ public $inline;
+ public $variable;
+ public $currentFileInfo;
+ public $type = 'Rule';
+
+ /**
+ * @param string $important
+ */
+ public function __construct($name, $value = null, $important = null, $merge = null, $index = null, $currentFileInfo = null, $inline = false){
+ $this->name = $name;
+ $this->value = ($value instanceof Less_Tree_Value || $value instanceof Less_Tree_Ruleset) ? $value : new Less_Tree_Value(array($value));
+ $this->important = $important ? ' ' . trim($important) : '';
+ $this->merge = $merge;
+ $this->index = $index;
+ $this->currentFileInfo = $currentFileInfo;
+ $this->inline = $inline;
+ $this->variable = ( is_string($name) && $name[0] === '@');
+ }
+
+ public function accept($visitor) {
+ $this->value = $visitor->visitObj( $this->value );
+ }
+
+ /**
+ * @see Less_Tree::genCSS
+ */
+ public function genCSS( $output ){
+
+ $output->add( $this->name . Less_Environment::$_outputMap[': '], $this->currentFileInfo, $this->index);
+ try{
+ $this->value->genCSS( $output);
+
+ }catch( Less_Exception_Parser $e ){
+ $e->index = $this->index;
+ $e->currentFile = $this->currentFileInfo;
+ throw $e;
+ }
+ $output->add( $this->important . (($this->inline || (Less_Environment::$lastRule && Less_Parser::$options['compress'])) ? "" : ";"), $this->currentFileInfo, $this->index);
+ }
+
+ public function compile ($env){
+
+ $name = $this->name;
+ if( is_array($name) ){
+ // expand 'primitive' name directly to get
+ // things faster (~10% for benchmark.less):
+ if( count($name) === 1 && $name[0] instanceof Less_Tree_Keyword ){
+ $name = $name[0]->value;
+ }else{
+ $name = $this->CompileName($env,$name);
+ }
+ }
+
+ $strictMathBypass = Less_Parser::$options['strictMath'];
+ if( $name === "font" && !Less_Parser::$options['strictMath'] ){
+ Less_Parser::$options['strictMath'] = true;
+ }
+
+ try {
+ $evaldValue = $this->value->compile($env);
+
+ if( !$this->variable && $evaldValue->type === "DetachedRuleset") {
+ throw new Less_Exception_Compiler("Rulesets cannot be evaluated on a property.", null, $this->index, $this->currentFileInfo);
+ }
+
+ if( Less_Environment::$mixin_stack ){
+ $return = new Less_Tree_Rule($name, $evaldValue, $this->important, $this->merge, $this->index, $this->currentFileInfo, $this->inline);
+ }else{
+ $this->name = $name;
+ $this->value = $evaldValue;
+ $return = $this;
+ }
+
+ }catch( Less_Exception_Parser $e ){
+ if( !is_numeric($e->index) ){
+ $e->index = $this->index;
+ $e->currentFile = $this->currentFileInfo;
+ }
+ throw $e;
+ }
+
+ Less_Parser::$options['strictMath'] = $strictMathBypass;
+
+ return $return;
+ }
+
+
+ public function CompileName( $env, $name ){
+ $output = new Less_Output();
+ foreach($name as $n){
+ $n->compile($env)->genCSS($output);
+ }
+ return $output->toString();
+ }
+
+ public function makeImportant(){
+ return new Less_Tree_Rule($this->name, $this->value, '!important', $this->merge, $this->index, $this->currentFileInfo, $this->inline);
+ }
+
+}
diff --git a/vendor/oyejorge/less.php/lib/Less/Tree/Ruleset.php b/vendor/oyejorge/less.php/lib/Less/Tree/Ruleset.php
new file mode 100644
index 00000000..93d3d6b7
--- /dev/null
+++ b/vendor/oyejorge/less.php/lib/Less/Tree/Ruleset.php
@@ -0,0 +1,643 @@
+<?php
+
+/**
+ * Ruleset
+ *
+ * @package Less
+ * @subpackage tree
+ */
+class Less_Tree_Ruleset extends Less_Tree{
+
+ protected $lookups;
+ public $_variables;
+ public $_rulesets;
+
+ public $strictImports;
+
+ public $selectors;
+ public $rules;
+ public $root;
+ public $allowImports;
+ public $paths;
+ public $firstRoot;
+ public $type = 'Ruleset';
+ public $multiMedia;
+ public $allExtends;
+
+ public $ruleset_id;
+ public $originalRuleset;
+
+ public $first_oelements;
+
+ public function SetRulesetIndex(){
+ $this->ruleset_id = Less_Parser::$next_id++;
+ $this->originalRuleset = $this->ruleset_id;
+
+ if( $this->selectors ){
+ foreach($this->selectors as $sel){
+ if( $sel->_oelements ){
+ $this->first_oelements[$sel->_oelements[0]] = true;
+ }
+ }
+ }
+ }
+
+ public function __construct($selectors, $rules, $strictImports = null){
+ $this->selectors = $selectors;
+ $this->rules = $rules;
+ $this->lookups = array();
+ $this->strictImports = $strictImports;
+ $this->SetRulesetIndex();
+ }
+
+ public function accept( $visitor ){
+ if( $this->paths ){
+ $paths_len = count($this->paths);
+ for($i = 0,$paths_len; $i < $paths_len; $i++ ){
+ $this->paths[$i] = $visitor->visitArray($this->paths[$i]);
+ }
+ }elseif( $this->selectors ){
+ $this->selectors = $visitor->visitArray($this->selectors);
+ }
+
+ if( $this->rules ){
+ $this->rules = $visitor->visitArray($this->rules);
+ }
+ }
+
+ public function compile($env){
+
+ $ruleset = $this->PrepareRuleset($env);
+
+
+ // Store the frames around mixin definitions,
+ // so they can be evaluated like closures when the time comes.
+ $rsRuleCnt = count($ruleset->rules);
+ for( $i = 0; $i < $rsRuleCnt; $i++ ){
+ if( $ruleset->rules[$i] instanceof Less_Tree_Mixin_Definition || $ruleset->rules[$i] instanceof Less_Tree_DetachedRuleset ){
+ $ruleset->rules[$i] = $ruleset->rules[$i]->compile($env);
+ }
+ }
+
+ $mediaBlockCount = 0;
+ if( $env instanceof Less_Environment ){
+ $mediaBlockCount = count($env->mediaBlocks);
+ }
+
+ // Evaluate mixin calls.
+ $this->EvalMixinCalls( $ruleset, $env, $rsRuleCnt );
+
+
+ // Evaluate everything else
+ for( $i=0; $i<$rsRuleCnt; $i++ ){
+ if(! ($ruleset->rules[$i] instanceof Less_Tree_Mixin_Definition || $ruleset->rules[$i] instanceof Less_Tree_DetachedRuleset) ){
+ $ruleset->rules[$i] = $ruleset->rules[$i]->compile($env);
+ }
+ }
+
+ // Evaluate everything else
+ for( $i=0; $i<$rsRuleCnt; $i++ ){
+ $rule = $ruleset->rules[$i];
+
+ // for rulesets, check if it is a css guard and can be removed
+ if( $rule instanceof Less_Tree_Ruleset && $rule->selectors && count($rule->selectors) === 1 ){
+
+ // check if it can be folded in (e.g. & where)
+ if( $rule->selectors[0]->isJustParentSelector() ){
+ array_splice($ruleset->rules,$i--,1);
+ $rsRuleCnt--;
+
+ for($j = 0; $j < count($rule->rules); $j++ ){
+ $subRule = $rule->rules[$j];
+ if( !($subRule instanceof Less_Tree_Rule) || !$subRule->variable ){
+ array_splice($ruleset->rules, ++$i, 0, array($subRule));
+ $rsRuleCnt++;
+ }
+ }
+
+ }
+ }
+ }
+
+
+ // Pop the stack
+ $env->shiftFrame();
+
+ if ($mediaBlockCount) {
+ $len = count($env->mediaBlocks);
+ for($i = $mediaBlockCount; $i < $len; $i++ ){
+ $env->mediaBlocks[$i]->bubbleSelectors($ruleset->selectors);
+ }
+ }
+
+ return $ruleset;
+ }
+
+ /**
+ * Compile Less_Tree_Mixin_Call objects
+ *
+ * @param Less_Tree_Ruleset $ruleset
+ * @param integer $rsRuleCnt
+ */
+ private function EvalMixinCalls( $ruleset, $env, &$rsRuleCnt ){
+ for($i=0; $i < $rsRuleCnt; $i++){
+ $rule = $ruleset->rules[$i];
+
+ if( $rule instanceof Less_Tree_Mixin_Call ){
+ $rule = $rule->compile($env);
+
+ $temp = array();
+ foreach($rule as $r){
+ if( ($r instanceof Less_Tree_Rule) && $r->variable ){
+ // do not pollute the scope if the variable is
+ // already there. consider returning false here
+ // but we need a way to "return" variable from mixins
+ if( !$ruleset->variable($r->name) ){
+ $temp[] = $r;
+ }
+ }else{
+ $temp[] = $r;
+ }
+ }
+ $temp_count = count($temp)-1;
+ array_splice($ruleset->rules, $i, 1, $temp);
+ $rsRuleCnt += $temp_count;
+ $i += $temp_count;
+ $ruleset->resetCache();
+
+ }elseif( $rule instanceof Less_Tree_RulesetCall ){
+
+ $rule = $rule->compile($env);
+ $rules = array();
+ foreach($rule->rules as $r){
+ if( ($r instanceof Less_Tree_Rule) && $r->variable ){
+ continue;
+ }
+ $rules[] = $r;
+ }
+
+ array_splice($ruleset->rules, $i, 1, $rules);
+ $temp_count = count($rules);
+ $rsRuleCnt += $temp_count - 1;
+ $i += $temp_count-1;
+ $ruleset->resetCache();
+ }
+
+ }
+ }
+
+
+ /**
+ * Compile the selectors and create a new ruleset object for the compile() method
+ *
+ */
+ private function PrepareRuleset($env){
+
+ $hasOnePassingSelector = false;
+ $selectors = array();
+ if( $this->selectors ){
+ Less_Tree_DefaultFunc::error("it is currently only allowed in parametric mixin guards,");
+
+ foreach($this->selectors as $s){
+ $selector = $s->compile($env);
+ $selectors[] = $selector;
+ if( $selector->evaldCondition ){
+ $hasOnePassingSelector = true;
+ }
+ }
+
+ Less_Tree_DefaultFunc::reset();
+ } else {
+ $hasOnePassingSelector = true;
+ }
+
+ if( $this->rules && $hasOnePassingSelector ){
+ $rules = $this->rules;
+ }else{
+ $rules = array();
+ }
+
+ $ruleset = new Less_Tree_Ruleset($selectors, $rules, $this->strictImports);
+
+ $ruleset->originalRuleset = $this->ruleset_id;
+
+ $ruleset->root = $this->root;
+ $ruleset->firstRoot = $this->firstRoot;
+ $ruleset->allowImports = $this->allowImports;
+
+
+ // push the current ruleset to the frames stack
+ $env->unshiftFrame($ruleset);
+
+
+ // Evaluate imports
+ if( $ruleset->root || $ruleset->allowImports || !$ruleset->strictImports ){
+ $ruleset->evalImports($env);
+ }
+
+ return $ruleset;
+ }
+
+ function evalImports($env) {
+
+ $rules_len = count($this->rules);
+ for($i=0; $i < $rules_len; $i++){
+ $rule = $this->rules[$i];
+
+ if( $rule instanceof Less_Tree_Import ){
+ $rules = $rule->compile($env);
+ if( is_array($rules) ){
+ array_splice($this->rules, $i, 1, $rules);
+ $temp_count = count($rules)-1;
+ $i += $temp_count;
+ $rules_len += $temp_count;
+ }else{
+ array_splice($this->rules, $i, 1, array($rules));
+ }
+
+ $this->resetCache();
+ }
+ }
+ }
+
+ function makeImportant(){
+
+ $important_rules = array();
+ foreach($this->rules as $rule){
+ if( $rule instanceof Less_Tree_Rule || $rule instanceof Less_Tree_Ruleset ){
+ $important_rules[] = $rule->makeImportant();
+ }else{
+ $important_rules[] = $rule;
+ }
+ }
+
+ return new Less_Tree_Ruleset($this->selectors, $important_rules, $this->strictImports );
+ }
+
+ public function matchArgs($args){
+ return !$args;
+ }
+
+ // lets you call a css selector with a guard
+ public function matchCondition( $args, $env ){
+ $lastSelector = end($this->selectors);
+
+ if( !$lastSelector->evaldCondition ){
+ return false;
+ }
+ if( $lastSelector->condition && !$lastSelector->condition->compile( $env->copyEvalEnv( $env->frames ) ) ){
+ return false;
+ }
+ return true;
+ }
+
+ function resetCache(){
+ $this->_rulesets = null;
+ $this->_variables = null;
+ $this->lookups = array();
+ }
+
+ public function variables(){
+ $this->_variables = array();
+ foreach( $this->rules as $r){
+ if ($r instanceof Less_Tree_Rule && $r->variable === true) {
+ $this->_variables[$r->name] = $r;
+ }
+ }
+ }
+
+ public function variable($name){
+
+ if( is_null($this->_variables) ){
+ $this->variables();
+ }
+ return isset($this->_variables[$name]) ? $this->_variables[$name] : null;
+ }
+
+ public function find( $selector, $self = null ){
+
+ $key = implode(' ',$selector->_oelements);
+
+ if( !isset($this->lookups[$key]) ){
+
+ if( !$self ){
+ $self = $this->ruleset_id;
+ }
+
+ $this->lookups[$key] = array();
+
+ $first_oelement = $selector->_oelements[0];
+
+ foreach($this->rules as $rule){
+ if( $rule instanceof Less_Tree_Ruleset && $rule->ruleset_id != $self ){
+
+ if( isset($rule->first_oelements[$first_oelement]) ){
+
+ foreach( $rule->selectors as $ruleSelector ){
+ $match = $selector->match($ruleSelector);
+ if( $match ){
+ if( $selector->elements_len > $match ){
+ $this->lookups[$key] = array_merge($this->lookups[$key], $rule->find( new Less_Tree_Selector(array_slice($selector->elements, $match)), $self));
+ } else {
+ $this->lookups[$key][] = $rule;
+ }
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ return $this->lookups[$key];
+ }
+
+
+ /**
+ * @see Less_Tree::genCSS
+ */
+ public function genCSS( $output ){
+
+ if( !$this->root ){
+ Less_Environment::$tabLevel++;
+ }
+
+ $tabRuleStr = $tabSetStr = '';
+ if( !Less_Parser::$options['compress'] ){
+ if( Less_Environment::$tabLevel ){
+ $tabRuleStr = "\n".str_repeat( ' ' , Less_Environment::$tabLevel );
+ $tabSetStr = "\n".str_repeat( ' ' , Less_Environment::$tabLevel-1 );
+ }else{
+ $tabSetStr = $tabRuleStr = "\n";
+ }
+ }
+
+
+ $ruleNodes = array();
+ $rulesetNodes = array();
+ foreach($this->rules as $rule){
+
+ $class = get_class($rule);
+ if( ($class === 'Less_Tree_Media') || ($class === 'Less_Tree_Directive') || ($this->root && $class === 'Less_Tree_Comment') || ($class === 'Less_Tree_Ruleset' && $rule->rules) ){
+ $rulesetNodes[] = $rule;
+ }else{
+ $ruleNodes[] = $rule;
+ }
+ }
+
+ // If this is the root node, we don't render
+ // a selector, or {}.
+ if( !$this->root ){
+
+ /*
+ debugInfo = tree.debugInfo(env, this, tabSetStr);
+
+ if (debugInfo) {
+ output.add(debugInfo);
+ output.add(tabSetStr);
+ }
+ */
+
+ $paths_len = count($this->paths);
+ for( $i = 0; $i < $paths_len; $i++ ){
+ $path = $this->paths[$i];
+ $firstSelector = true;
+
+ foreach($path as $p){
+ $p->genCSS( $output, $firstSelector );
+ $firstSelector = false;
+ }
+
+ if( $i + 1 < $paths_len ){
+ $output->add( ',' . $tabSetStr );
+ }
+ }
+
+ $output->add( (Less_Parser::$options['compress'] ? '{' : " {") . $tabRuleStr );
+ }
+
+ // Compile rules and rulesets
+ $ruleNodes_len = count($ruleNodes);
+ $rulesetNodes_len = count($rulesetNodes);
+ for( $i = 0; $i < $ruleNodes_len; $i++ ){
+ $rule = $ruleNodes[$i];
+
+ // @page{ directive ends up with root elements inside it, a mix of rules and rulesets
+ // In this instance we do not know whether it is the last property
+ if( $i + 1 === $ruleNodes_len && (!$this->root || $rulesetNodes_len === 0 || $this->firstRoot ) ){
+ Less_Environment::$lastRule = true;
+ }
+
+ $rule->genCSS( $output );
+
+ if( !Less_Environment::$lastRule ){
+ $output->add( $tabRuleStr );
+ }else{
+ Less_Environment::$lastRule = false;
+ }
+ }
+
+ if( !$this->root ){
+ $output->add( $tabSetStr . '}' );
+ Less_Environment::$tabLevel--;
+ }
+
+ $firstRuleset = true;
+ $space = ($this->root ? $tabRuleStr : $tabSetStr);
+ for( $i = 0; $i < $rulesetNodes_len; $i++ ){
+
+ if( $ruleNodes_len && $firstRuleset ){
+ $output->add( $space );
+ }elseif( !$firstRuleset ){
+ $output->add( $space );
+ }
+ $firstRuleset = false;
+ $rulesetNodes[$i]->genCSS( $output);
+ }
+
+ if( !Less_Parser::$options['compress'] && $this->firstRoot ){
+ $output->add( "\n" );
+ }
+
+ }
+
+
+ function markReferenced(){
+ if( !$this->selectors ){
+ return;
+ }
+ foreach($this->selectors as $selector){
+ $selector->markReferenced();
+ }
+ }
+
+ public function joinSelectors( $context, $selectors ){
+ $paths = array();
+ if( is_array($selectors) ){
+ foreach($selectors as $selector) {
+ $this->joinSelector( $paths, $context, $selector);
+ }
+ }
+ return $paths;
+ }
+
+ public function joinSelector( &$paths, $context, $selector){
+
+ $hasParentSelector = false;
+
+ foreach($selector->elements as $el) {
+ if( $el->value === '&') {
+ $hasParentSelector = true;
+ }
+ }
+
+ if( !$hasParentSelector ){
+ if( $context ){
+ foreach($context as $context_el){
+ $paths[] = array_merge($context_el, array($selector) );
+ }
+ }else {
+ $paths[] = array($selector);
+ }
+ return;
+ }
+
+
+ // The paths are [[Selector]]
+ // The first list is a list of comma seperated selectors
+ // The inner list is a list of inheritance seperated selectors
+ // e.g.
+ // .a, .b {
+ // .c {
+ // }
+ // }
+ // == [[.a] [.c]] [[.b] [.c]]
+ //
+
+ // the elements from the current selector so far
+ $currentElements = array();
+ // the current list of new selectors to add to the path.
+ // We will build it up. We initiate it with one empty selector as we "multiply" the new selectors
+ // by the parents
+ $newSelectors = array(array());
+
+
+ foreach( $selector->elements as $el){
+
+ // non parent reference elements just get added
+ if( $el->value !== '&' ){
+ $currentElements[] = $el;
+ } else {
+ // the new list of selectors to add
+ $selectorsMultiplied = array();
+
+ // merge the current list of non parent selector elements
+ // on to the current list of selectors to add
+ if( $currentElements ){
+ $this->mergeElementsOnToSelectors( $currentElements, $newSelectors);
+ }
+
+ // loop through our current selectors
+ foreach($newSelectors as $sel){
+
+ // if we don't have any parent paths, the & might be in a mixin so that it can be used
+ // whether there are parents or not
+ if( !$context ){
+ // the combinator used on el should now be applied to the next element instead so that
+ // it is not lost
+ if( $sel ){
+ $sel[0]->elements = array_slice($sel[0]->elements,0);
+ $sel[0]->elements[] = new Less_Tree_Element($el->combinator, '', $el->index, $el->currentFileInfo );
+ }
+ $selectorsMultiplied[] = $sel;
+ }else {
+
+ // and the parent selectors
+ foreach($context as $parentSel){
+ // We need to put the current selectors
+ // then join the last selector's elements on to the parents selectors
+
+ // our new selector path
+ $newSelectorPath = array();
+ // selectors from the parent after the join
+ $afterParentJoin = array();
+ $newJoinedSelectorEmpty = true;
+
+ //construct the joined selector - if & is the first thing this will be empty,
+ // if not newJoinedSelector will be the last set of elements in the selector
+ if( $sel ){
+ $newSelectorPath = $sel;
+ $lastSelector = array_pop($newSelectorPath);
+ $newJoinedSelector = $selector->createDerived( array_slice($lastSelector->elements,0) );
+ $newJoinedSelectorEmpty = false;
+ }
+ else {
+ $newJoinedSelector = $selector->createDerived(array());
+ }
+
+ //put together the parent selectors after the join
+ if ( count($parentSel) > 1) {
+ $afterParentJoin = array_merge($afterParentJoin, array_slice($parentSel,1) );
+ }
+
+ if ( $parentSel ){
+ $newJoinedSelectorEmpty = false;
+
+ // join the elements so far with the first part of the parent
+ $newJoinedSelector->elements[] = new Less_Tree_Element( $el->combinator, $parentSel[0]->elements[0]->value, $el->index, $el->currentFileInfo);
+
+ $newJoinedSelector->elements = array_merge( $newJoinedSelector->elements, array_slice($parentSel[0]->elements, 1) );
+ }
+
+ if (!$newJoinedSelectorEmpty) {
+ // now add the joined selector
+ $newSelectorPath[] = $newJoinedSelector;
+ }
+
+ // and the rest of the parent
+ $newSelectorPath = array_merge($newSelectorPath, $afterParentJoin);
+
+ // add that to our new set of selectors
+ $selectorsMultiplied[] = $newSelectorPath;
+ }
+ }
+ }
+
+ // our new selectors has been multiplied, so reset the state
+ $newSelectors = $selectorsMultiplied;
+ $currentElements = array();
+ }
+ }
+
+ // if we have any elements left over (e.g. .a& .b == .b)
+ // add them on to all the current selectors
+ if( $currentElements ){
+ $this->mergeElementsOnToSelectors($currentElements, $newSelectors);
+ }
+ foreach( $newSelectors as $new_sel){
+ if( $new_sel ){
+ $paths[] = $new_sel;
+ }
+ }
+ }
+
+ function mergeElementsOnToSelectors( $elements, &$selectors){
+
+ if( !$selectors ){
+ $selectors[] = array( new Less_Tree_Selector($elements) );
+ return;
+ }
+
+
+ foreach( $selectors as &$sel){
+
+ // if the previous thing in sel is a parent this needs to join on to it
+ if( $sel ){
+ $last = count($sel)-1;
+ $sel[$last] = $sel[$last]->createDerived( array_merge($sel[$last]->elements, $elements) );
+ }else{
+ $sel[] = new Less_Tree_Selector( $elements );
+ }
+ }
+ }
+}
diff --git a/vendor/oyejorge/less.php/lib/Less/Tree/RulesetCall.php b/vendor/oyejorge/less.php/lib/Less/Tree/RulesetCall.php
new file mode 100644
index 00000000..ed4c7237
--- /dev/null
+++ b/vendor/oyejorge/less.php/lib/Less/Tree/RulesetCall.php
@@ -0,0 +1,26 @@
+<?php
+
+/**
+ * RulesetCall
+ *
+ * @package Less
+ * @subpackage tree
+ */
+class Less_Tree_RulesetCall extends Less_Tree{
+
+ public $variable;
+ public $type = "RulesetCall";
+
+ public function __construct($variable){
+ $this->variable = $variable;
+ }
+
+ public function accept($visitor) {}
+
+ public function compile( $env ){
+ $variable = new Less_Tree_Variable($this->variable);
+ $detachedRuleset = $variable->compile($env);
+ return $detachedRuleset->callEval($env);
+ }
+}
+
diff --git a/vendor/oyejorge/less.php/lib/Less/Tree/Selector.php b/vendor/oyejorge/less.php/lib/Less/Tree/Selector.php
new file mode 100644
index 00000000..6b9dae61
--- /dev/null
+++ b/vendor/oyejorge/less.php/lib/Less/Tree/Selector.php
@@ -0,0 +1,168 @@
+<?php
+
+/**
+ * Selector
+ *
+ * @package Less
+ * @subpackage tree
+ */
+class Less_Tree_Selector extends Less_Tree{
+
+ public $elements;
+ public $condition;
+ public $extendList = array();
+ public $_css;
+ public $index;
+ public $evaldCondition = false;
+ public $type = 'Selector';
+ public $currentFileInfo = array();
+ public $isReferenced;
+ public $mediaEmpty;
+
+ public $elements_len = 0;
+
+ public $_oelements;
+ public $_oelements_len;
+ public $cacheable = true;
+
+ /**
+ * @param boolean $isReferenced
+ */
+ public function __construct( $elements, $extendList = array() , $condition = null, $index=null, $currentFileInfo=null, $isReferenced=null ){
+
+ $this->elements = $elements;
+ $this->elements_len = count($elements);
+ $this->extendList = $extendList;
+ $this->condition = $condition;
+ if( $currentFileInfo ){
+ $this->currentFileInfo = $currentFileInfo;
+ }
+ $this->isReferenced = $isReferenced;
+ if( !$condition ){
+ $this->evaldCondition = true;
+ }
+
+ $this->CacheElements();
+ }
+
+ public function accept($visitor) {
+ $this->elements = $visitor->visitArray($this->elements);
+ $this->extendList = $visitor->visitArray($this->extendList);
+ if( $this->condition ){
+ $this->condition = $visitor->visitObj($this->condition);
+ }
+
+ if( $visitor instanceof Less_Visitor_extendFinder ){
+ $this->CacheElements();
+ }
+ }
+
+ public function createDerived( $elements, $extendList = null, $evaldCondition = null ){
+ $newSelector = new Less_Tree_Selector( $elements, ($extendList ? $extendList : $this->extendList), null, $this->index, $this->currentFileInfo, $this->isReferenced);
+ $newSelector->evaldCondition = $evaldCondition ? $evaldCondition : $this->evaldCondition;
+ return $newSelector;
+ }
+
+
+ public function match( $other ){
+
+ if( !$other->_oelements || ($this->elements_len < $other->_oelements_len) ){
+ return 0;
+ }
+
+ for( $i = 0; $i < $other->_oelements_len; $i++ ){
+ if( $this->elements[$i]->value !== $other->_oelements[$i]) {
+ return 0;
+ }
+ }
+
+ return $other->_oelements_len; // return number of matched elements
+ }
+
+
+ public function CacheElements(){
+
+ $this->_oelements = array();
+ $css = '';
+
+ foreach($this->elements as $v){
+
+ $css .= $v->combinator;
+ if( !$v->value_is_object ){
+ $css .= $v->value;
+ continue;
+ }
+
+ if( !property_exists($v->value,'value') || !is_string($v->value->value) ){
+ $this->cacheable = false;
+ return;
+ }
+ $css .= $v->value->value;
+ }
+
+ $this->_oelements_len = preg_match_all('/[,&#\.\w-](?:[\w-]|(?:\\\\.))*/', $css, $matches);
+ if( $this->_oelements_len ){
+ $this->_oelements = $matches[0];
+
+ if( $this->_oelements[0] === '&' ){
+ array_shift($this->_oelements);
+ $this->_oelements_len--;
+ }
+ }
+ }
+
+ public function isJustParentSelector(){
+ return !$this->mediaEmpty &&
+ count($this->elements) === 1 &&
+ $this->elements[0]->value === '&' &&
+ ($this->elements[0]->combinator === ' ' || $this->elements[0]->combinator === '');
+ }
+
+ public function compile($env) {
+
+ $elements = array();
+ foreach($this->elements as $el){
+ $elements[] = $el->compile($env);
+ }
+
+ $extendList = array();
+ foreach($this->extendList as $el){
+ $extendList[] = $el->compile($el);
+ }
+
+ $evaldCondition = false;
+ if( $this->condition ){
+ $evaldCondition = $this->condition->compile($env);
+ }
+
+ return $this->createDerived( $elements, $extendList, $evaldCondition );
+ }
+
+
+ /**
+ * @see Less_Tree::genCSS
+ */
+ public function genCSS( $output, $firstSelector = true ){
+
+ if( !$firstSelector && $this->elements[0]->combinator === "" ){
+ $output->add(' ', $this->currentFileInfo, $this->index);
+ }
+
+ foreach($this->elements as $element){
+ $element->genCSS( $output );
+ }
+ }
+
+ public function markReferenced(){
+ $this->isReferenced = true;
+ }
+
+ public function getIsReferenced(){
+ return !isset($this->currentFileInfo['reference']) || !$this->currentFileInfo['reference'] || $this->isReferenced;
+ }
+
+ public function getIsOutput(){
+ return $this->evaldCondition;
+ }
+
+}
diff --git a/vendor/oyejorge/less.php/lib/Less/Tree/UnicodeDescriptor.php b/vendor/oyejorge/less.php/lib/Less/Tree/UnicodeDescriptor.php
new file mode 100644
index 00000000..8c4707ef
--- /dev/null
+++ b/vendor/oyejorge/less.php/lib/Less/Tree/UnicodeDescriptor.php
@@ -0,0 +1,29 @@
+<?php
+
+/**
+ * UnicodeDescriptor
+ *
+ * @package Less
+ * @subpackage tree
+ */
+class Less_Tree_UnicodeDescriptor extends Less_Tree{
+
+ public $value;
+ public $type = 'UnicodeDescriptor';
+
+ public function __construct($value){
+ $this->value = $value;
+ }
+
+ /**
+ * @see Less_Tree::genCSS
+ */
+ public function genCSS( $output ){
+ $output->add( $this->value );
+ }
+
+ public function compile(){
+ return $this;
+ }
+}
+
diff --git a/vendor/oyejorge/less.php/lib/Less/Tree/Unit.php b/vendor/oyejorge/less.php/lib/Less/Tree/Unit.php
new file mode 100644
index 00000000..e13b100e
--- /dev/null
+++ b/vendor/oyejorge/less.php/lib/Less/Tree/Unit.php
@@ -0,0 +1,147 @@
+<?php
+
+/**
+ * Unit
+ *
+ * @package Less
+ * @subpackage tree
+ */
+class Less_Tree_Unit extends Less_Tree{
+
+ var $numerator = array();
+ var $denominator = array();
+ public $backupUnit;
+ public $type = 'Unit';
+
+ public function __construct($numerator = array(), $denominator = array(), $backupUnit = null ){
+ $this->numerator = $numerator;
+ $this->denominator = $denominator;
+ $this->backupUnit = $backupUnit;
+ }
+
+ public function __clone(){
+ }
+
+ /**
+ * @see Less_Tree::genCSS
+ */
+ public function genCSS( $output ){
+
+ if( $this->numerator ){
+ $output->add( $this->numerator[0] );
+ }elseif( $this->denominator ){
+ $output->add( $this->denominator[0] );
+ }elseif( !Less_Parser::$options['strictUnits'] && $this->backupUnit ){
+ $output->add( $this->backupUnit );
+ return ;
+ }
+ }
+
+ public function toString(){
+ $returnStr = implode('*',$this->numerator);
+ foreach($this->denominator as $d){
+ $returnStr .= '/'.$d;
+ }
+ return $returnStr;
+ }
+
+ public function __toString(){
+ return $this->toString();
+ }
+
+
+ /**
+ * @param Less_Tree_Unit $other
+ */
+ public function compare($other) {
+ return $this->is( $other->toString() ) ? 0 : -1;
+ }
+
+ public function is($unitString){
+ return $this->toString() === $unitString;
+ }
+
+ public function isLength(){
+ $css = $this->toCSS();
+ return !!preg_match('/px|em|%|in|cm|mm|pc|pt|ex/',$css);
+ }
+
+ public function isAngle() {
+ return isset( Less_Tree_UnitConversions::$angle[$this->toCSS()] );
+ }
+
+ public function isEmpty(){
+ return !$this->numerator && !$this->denominator;
+ }
+
+ public function isSingular() {
+ return count($this->numerator) <= 1 && !$this->denominator;
+ }
+
+
+ public function usedUnits(){
+ $result = array();
+
+ foreach(Less_Tree_UnitConversions::$groups as $groupName){
+ $group = Less_Tree_UnitConversions::${$groupName};
+
+ foreach($this->numerator as $atomicUnit){
+ if( isset($group[$atomicUnit]) && !isset($result[$groupName]) ){
+ $result[$groupName] = $atomicUnit;
+ }
+ }
+
+ foreach($this->denominator as $atomicUnit){
+ if( isset($group[$atomicUnit]) && !isset($result[$groupName]) ){
+ $result[$groupName] = $atomicUnit;
+ }
+ }
+ }
+
+ return $result;
+ }
+
+ public function cancel(){
+ $counter = array();
+ $backup = null;
+
+ foreach($this->numerator as $atomicUnit){
+ if( !$backup ){
+ $backup = $atomicUnit;
+ }
+ $counter[$atomicUnit] = ( isset($counter[$atomicUnit]) ? $counter[$atomicUnit] : 0) + 1;
+ }
+
+ foreach($this->denominator as $atomicUnit){
+ if( !$backup ){
+ $backup = $atomicUnit;
+ }
+ $counter[$atomicUnit] = ( isset($counter[$atomicUnit]) ? $counter[$atomicUnit] : 0) - 1;
+ }
+
+ $this->numerator = array();
+ $this->denominator = array();
+
+ foreach($counter as $atomicUnit => $count){
+ if( $count > 0 ){
+ for( $i = 0; $i < $count; $i++ ){
+ $this->numerator[] = $atomicUnit;
+ }
+ }elseif( $count < 0 ){
+ for( $i = 0; $i < -$count; $i++ ){
+ $this->denominator[] = $atomicUnit;
+ }
+ }
+ }
+
+ if( !$this->numerator && !$this->denominator && $backup ){
+ $this->backupUnit = $backup;
+ }
+
+ sort($this->numerator);
+ sort($this->denominator);
+ }
+
+
+}
+
diff --git a/vendor/oyejorge/less.php/lib/Less/Tree/UnitConversions.php b/vendor/oyejorge/less.php/lib/Less/Tree/UnitConversions.php
new file mode 100644
index 00000000..c86b2907
--- /dev/null
+++ b/vendor/oyejorge/less.php/lib/Less/Tree/UnitConversions.php
@@ -0,0 +1,35 @@
+<?php
+
+/**
+ * UnitConversions
+ *
+ * @package Less
+ * @subpackage tree
+ */
+class Less_Tree_UnitConversions{
+
+ public static $groups = array('length','duration','angle');
+
+ public static $length = array(
+ 'm'=> 1,
+ 'cm'=> 0.01,
+ 'mm'=> 0.001,
+ 'in'=> 0.0254,
+ 'px'=> 0.000264583, // 0.0254 / 96,
+ 'pt'=> 0.000352778, // 0.0254 / 72,
+ 'pc'=> 0.004233333, // 0.0254 / 72 * 12
+ );
+
+ public static $duration = array(
+ 's'=> 1,
+ 'ms'=> 0.001
+ );
+
+ public static $angle = array(
+ 'rad' => 0.1591549430919, // 1/(2*M_PI),
+ 'deg' => 0.002777778, // 1/360,
+ 'grad'=> 0.0025, // 1/400,
+ 'turn'=> 1
+ );
+
+} \ No newline at end of file
diff --git a/vendor/oyejorge/less.php/lib/Less/Tree/Url.php b/vendor/oyejorge/less.php/lib/Less/Tree/Url.php
new file mode 100644
index 00000000..ef9c3c68
--- /dev/null
+++ b/vendor/oyejorge/less.php/lib/Less/Tree/Url.php
@@ -0,0 +1,76 @@
+<?php
+
+/**
+ * Url
+ *
+ * @package Less
+ * @subpackage tree
+ */
+class Less_Tree_Url extends Less_Tree{
+
+ public $attrs;
+ public $value;
+ public $currentFileInfo;
+ public $isEvald;
+ public $type = 'Url';
+
+ public function __construct($value, $currentFileInfo = null, $isEvald = null){
+ $this->value = $value;
+ $this->currentFileInfo = $currentFileInfo;
+ $this->isEvald = $isEvald;
+ }
+
+ public function accept( $visitor ){
+ $this->value = $visitor->visitObj($this->value);
+ }
+
+ /**
+ * @see Less_Tree::genCSS
+ */
+ public function genCSS( $output ){
+ $output->add( 'url(' );
+ $this->value->genCSS( $output );
+ $output->add( ')' );
+ }
+
+ /**
+ * @param Less_Functions $ctx
+ */
+ public function compile($ctx){
+ $val = $this->value->compile($ctx);
+
+ if( !$this->isEvald ){
+ // Add the base path if the URL is relative
+ if( Less_Parser::$options['relativeUrls']
+ && $this->currentFileInfo
+ && is_string($val->value)
+ && Less_Environment::isPathRelative($val->value)
+ ){
+ $rootpath = $this->currentFileInfo['uri_root'];
+ if ( !$val->quote ){
+ $rootpath = preg_replace('/[\(\)\'"\s]/', '\\$1', $rootpath );
+ }
+ $val->value = $rootpath . $val->value;
+ }
+
+ $val->value = Less_Environment::normalizePath( $val->value);
+ }
+
+ // Add cache buster if enabled
+ if( Less_Parser::$options['urlArgs'] ){
+ if( !preg_match('/^\s*data:/',$val->value) ){
+ $delimiter = strpos($val->value,'?') === false ? '?' : '&';
+ $urlArgs = $delimiter . Less_Parser::$options['urlArgs'];
+ $hash_pos = strpos($val->value,'#');
+ if( $hash_pos !== false ){
+ $val->value = substr_replace($val->value,$urlArgs, $hash_pos, 0);
+ } else {
+ $val->value .= $urlArgs;
+ }
+ }
+ }
+
+ return new Less_Tree_URL($val, $this->currentFileInfo, true);
+ }
+
+}
diff --git a/vendor/oyejorge/less.php/lib/Less/Tree/Value.php b/vendor/oyejorge/less.php/lib/Less/Tree/Value.php
new file mode 100644
index 00000000..9f077bc5
--- /dev/null
+++ b/vendor/oyejorge/less.php/lib/Less/Tree/Value.php
@@ -0,0 +1,48 @@
+<?php
+
+/**
+ * Value
+ *
+ * @package Less
+ * @subpackage tree
+ */
+class Less_Tree_Value extends Less_Tree{
+
+ public $type = 'Value';
+ public $value;
+
+ public function __construct($value){
+ $this->value = $value;
+ }
+
+ public function accept($visitor) {
+ $this->value = $visitor->visitArray($this->value);
+ }
+
+ public function compile($env){
+
+ $ret = array();
+ $i = 0;
+ foreach($this->value as $i => $v){
+ $ret[] = $v->compile($env);
+ }
+ if( $i > 0 ){
+ return new Less_Tree_Value($ret);
+ }
+ return $ret[0];
+ }
+
+ /**
+ * @see Less_Tree::genCSS
+ */
+ function genCSS( $output ){
+ $len = count($this->value);
+ for($i = 0; $i < $len; $i++ ){
+ $this->value[$i]->genCSS( $output );
+ if( $i+1 < $len ){
+ $output->add( Less_Environment::$_outputMap[','] );
+ }
+ }
+ }
+
+}
diff --git a/vendor/oyejorge/less.php/lib/Less/Tree/Variable.php b/vendor/oyejorge/less.php/lib/Less/Tree/Variable.php
new file mode 100644
index 00000000..cc0182cd
--- /dev/null
+++ b/vendor/oyejorge/less.php/lib/Less/Tree/Variable.php
@@ -0,0 +1,52 @@
+<?php
+
+/**
+ * Variable
+ *
+ * @package Less
+ * @subpackage tree
+ */
+class Less_Tree_Variable extends Less_Tree{
+
+ public $name;
+ public $index;
+ public $currentFileInfo;
+ public $evaluating = false;
+ public $type = 'Variable';
+
+ /**
+ * @param string $name
+ */
+ public function __construct($name, $index = null, $currentFileInfo = null) {
+ $this->name = $name;
+ $this->index = $index;
+ $this->currentFileInfo = $currentFileInfo;
+ }
+
+ public function compile($env) {
+
+ if( $this->name[1] === '@' ){
+ $v = new Less_Tree_Variable(substr($this->name, 1), $this->index + 1, $this->currentFileInfo);
+ $name = '@' . $v->compile($env)->value;
+ }else{
+ $name = $this->name;
+ }
+
+ if ($this->evaluating) {
+ throw new Less_Exception_Compiler("Recursive variable definition for " . $name, null, $this->index, $this->currentFileInfo);
+ }
+
+ $this->evaluating = true;
+
+ foreach($env->frames as $frame){
+ if( $v = $frame->variable($name) ){
+ $r = $v->value->compile($env);
+ $this->evaluating = false;
+ return $r;
+ }
+ }
+
+ throw new Less_Exception_Compiler("variable " . $name . " is undefined in file ".$this->currentFileInfo["filename"], null, $this->index, $this->currentFileInfo);
+ }
+
+}
diff --git a/vendor/oyejorge/less.php/lib/Less/Version.php b/vendor/oyejorge/less.php/lib/Less/Version.php
new file mode 100644
index 00000000..704ec6e0
--- /dev/null
+++ b/vendor/oyejorge/less.php/lib/Less/Version.php
@@ -0,0 +1,15 @@
+<?php
+
+/**
+ * Release numbers
+ *
+ * @package Less
+ * @subpackage version
+ */
+class Less_Version{
+
+ const version = '1.7.0.9'; // The current build number of less.php
+ const less_version = '1.7'; // The less.js version that this build should be compatible with
+ const cache_version = '170'; // The parser cache version
+
+}
diff --git a/vendor/oyejorge/less.php/lib/Less/Visitor.php b/vendor/oyejorge/less.php/lib/Less/Visitor.php
new file mode 100644
index 00000000..d85f1d91
--- /dev/null
+++ b/vendor/oyejorge/less.php/lib/Less/Visitor.php
@@ -0,0 +1,49 @@
+<?php
+
+/**
+ * Visitor
+ *
+ * @package Less
+ * @subpackage visitor
+ */
+class Less_Visitor{
+
+ protected $methods = array();
+ protected $_visitFnCache = array();
+
+ public function __construct(){
+ $this->_visitFnCache = get_class_methods(get_class($this));
+ $this->_visitFnCache = array_flip($this->_visitFnCache);
+ }
+
+ public function visitObj( $node ){
+
+ $funcName = 'visit'.$node->type;
+ if( isset($this->_visitFnCache[$funcName]) ){
+
+ $visitDeeper = true;
+ $this->$funcName( $node, $visitDeeper );
+
+ if( $visitDeeper ){
+ $node->accept($this);
+ }
+
+ $funcName = $funcName . "Out";
+ if( isset($this->_visitFnCache[$funcName]) ){
+ $this->$funcName( $node );
+ }
+
+ }else{
+ $node->accept($this);
+ }
+
+ return $node;
+ }
+
+ public function visitArray( $nodes ){
+
+ array_map( array($this,'visitObj'), $nodes);
+ return $nodes;
+ }
+}
+
diff --git a/vendor/oyejorge/less.php/lib/Less/Visitor/extendFinder.php b/vendor/oyejorge/less.php/lib/Less/Visitor/extendFinder.php
new file mode 100644
index 00000000..22b3aac9
--- /dev/null
+++ b/vendor/oyejorge/less.php/lib/Less/Visitor/extendFinder.php
@@ -0,0 +1,114 @@
+<?php
+
+/**
+ * Extend Finder Visitor
+ *
+ * @package Less
+ * @subpackage visitor
+ */
+class Less_Visitor_extendFinder extends Less_Visitor{
+
+ public $contexts = array();
+ public $allExtendsStack;
+ public $foundExtends;
+
+ public function __construct(){
+ $this->contexts = array();
+ $this->allExtendsStack = array(array());
+ parent::__construct();
+ }
+
+ /**
+ * @param Less_Tree_Ruleset $root
+ */
+ public function run($root){
+ $root = $this->visitObj($root);
+ $root->allExtends =& $this->allExtendsStack[0];
+ return $root;
+ }
+
+ public function visitRule($ruleNode, &$visitDeeper ){
+ $visitDeeper = false;
+ }
+
+ public function visitMixinDefinition( $mixinDefinitionNode, &$visitDeeper ){
+ $visitDeeper = false;
+ }
+
+ public function visitRuleset($rulesetNode){
+
+ if( $rulesetNode->root ){
+ return;
+ }
+
+ $allSelectorsExtendList = array();
+
+ // get &:extend(.a); rules which apply to all selectors in this ruleset
+ if( $rulesetNode->rules ){
+ foreach($rulesetNode->rules as $rule){
+ if( $rule instanceof Less_Tree_Extend ){
+ $allSelectorsExtendList[] = $rule;
+ $rulesetNode->extendOnEveryPath = true;
+ }
+ }
+ }
+
+
+ // now find every selector and apply the extends that apply to all extends
+ // and the ones which apply to an individual extend
+ foreach($rulesetNode->paths as $selectorPath){
+ $selector = end($selectorPath); //$selectorPath[ count($selectorPath)-1];
+
+ $j = 0;
+ foreach($selector->extendList as $extend){
+ $this->allExtendsStackPush($rulesetNode, $selectorPath, $extend, $j);
+ }
+ foreach($allSelectorsExtendList as $extend){
+ $this->allExtendsStackPush($rulesetNode, $selectorPath, $extend, $j);
+ }
+ }
+
+ $this->contexts[] = $rulesetNode->selectors;
+ }
+
+ public function allExtendsStackPush($rulesetNode, $selectorPath, $extend, &$j){
+ $this->foundExtends = true;
+ $extend = clone $extend;
+ $extend->findSelfSelectors( $selectorPath );
+ $extend->ruleset = $rulesetNode;
+ if( $j === 0 ){
+ $extend->firstExtendOnThisSelectorPath = true;
+ }
+
+ $end_key = count($this->allExtendsStack)-1;
+ $this->allExtendsStack[$end_key][] = $extend;
+ $j++;
+ }
+
+
+ public function visitRulesetOut( $rulesetNode ){
+ if( !is_object($rulesetNode) || !$rulesetNode->root ){
+ array_pop($this->contexts);
+ }
+ }
+
+ public function visitMedia( $mediaNode ){
+ $mediaNode->allExtends = array();
+ $this->allExtendsStack[] =& $mediaNode->allExtends;
+ }
+
+ public function visitMediaOut(){
+ array_pop($this->allExtendsStack);
+ }
+
+ public function visitDirective( $directiveNode ){
+ $directiveNode->allExtends = array();
+ $this->allExtendsStack[] =& $directiveNode->allExtends;
+ }
+
+ public function visitDirectiveOut(){
+ array_pop($this->allExtendsStack);
+ }
+}
+
+
diff --git a/vendor/oyejorge/less.php/lib/Less/Visitor/import.php b/vendor/oyejorge/less.php/lib/Less/Visitor/import.php
new file mode 100644
index 00000000..f79a36da
--- /dev/null
+++ b/vendor/oyejorge/less.php/lib/Less/Visitor/import.php
@@ -0,0 +1,139 @@
+<?php
+
+/*
+class Less_Visitor_import extends Less_VisitorReplacing{
+
+ public $_visitor;
+ public $_importer;
+ public $importCount;
+
+ function __construct( $evalEnv ){
+ $this->env = $evalEnv;
+ $this->importCount = 0;
+ parent::__construct();
+ }
+
+
+ function run( $root ){
+ $root = $this->visitObj($root);
+ $this->isFinished = true;
+
+ //if( $this->importCount === 0) {
+ // $this->_finish();
+ //}
+ }
+
+ function visitImport($importNode, &$visitDeeper ){
+ $importVisitor = $this;
+ $inlineCSS = $importNode->options['inline'];
+
+ if( !$importNode->css || $inlineCSS ){
+ $evaldImportNode = $importNode->compileForImport($this->env);
+
+ if( $evaldImportNode && (!$evaldImportNode->css || $inlineCSS) ){
+ $importNode = $evaldImportNode;
+ $this->importCount++;
+ $env = clone $this->env;
+
+ if( (isset($importNode->options['multiple']) && $importNode->options['multiple']) ){
+ $env->importMultiple = true;
+ }
+
+ //get path & uri
+ $path_and_uri = null;
+ if( is_callable(Less_Parser::$options['import_callback']) ){
+ $path_and_uri = call_user_func(Less_Parser::$options['import_callback'],$importNode);
+ }
+
+ if( !$path_and_uri ){
+ $path_and_uri = $importNode->PathAndUri();
+ }
+
+ if( $path_and_uri ){
+ list($full_path, $uri) = $path_and_uri;
+ }else{
+ $full_path = $uri = $importNode->getPath();
+ }
+
+
+ //import once
+ if( $importNode->skip( $full_path, $env) ){
+ return array();
+ }
+
+ if( $importNode->options['inline'] ){
+ //todo needs to reference css file not import
+ //$contents = new Less_Tree_Anonymous($importNode->root, 0, array('filename'=>$importNode->importedFilename), true );
+
+ Less_Parser::AddParsedFile($full_path);
+ $contents = new Less_Tree_Anonymous( file_get_contents($full_path), 0, array(), true );
+
+ if( $importNode->features ){
+ return new Less_Tree_Media( array($contents), $importNode->features->value );
+ }
+
+ return array( $contents );
+ }
+
+
+ // css ?
+ if( $importNode->css ){
+ $features = ( $importNode->features ? $importNode->features->compile($env) : null );
+ return new Less_Tree_Import( $importNode->compilePath( $env), $features, $importNode->options, $this->index);
+ }
+
+ return $importNode->ParseImport( $full_path, $uri, $env );
+ }
+
+ }
+
+ $visitDeeper = false;
+ return $importNode;
+ }
+
+
+ function visitRule( $ruleNode, &$visitDeeper ){
+ $visitDeeper = false;
+ return $ruleNode;
+ }
+
+ function visitDirective($directiveNode, $visitArgs){
+ array_unshift($this->env->frames,$directiveNode);
+ return $directiveNode;
+ }
+
+ function visitDirectiveOut($directiveNode) {
+ array_shift($this->env->frames);
+ }
+
+ function visitMixinDefinition($mixinDefinitionNode, $visitArgs) {
+ array_unshift($this->env->frames,$mixinDefinitionNode);
+ return $mixinDefinitionNode;
+ }
+
+ function visitMixinDefinitionOut($mixinDefinitionNode) {
+ array_shift($this->env->frames);
+ }
+
+ function visitRuleset($rulesetNode, $visitArgs) {
+ array_unshift($this->env->frames,$rulesetNode);
+ return $rulesetNode;
+ }
+
+ function visitRulesetOut($rulesetNode) {
+ array_shift($this->env->frames);
+ }
+
+ function visitMedia($mediaNode, $visitArgs) {
+ array_unshift($this->env->frames, $mediaNode->ruleset);
+ return $mediaNode;
+ }
+
+ function visitMediaOut($mediaNode) {
+ array_shift($this->env->frames);
+ }
+
+}
+*/
+
+
diff --git a/vendor/oyejorge/less.php/lib/Less/Visitor/joinSelector.php b/vendor/oyejorge/less.php/lib/Less/Visitor/joinSelector.php
new file mode 100644
index 00000000..f62af1a9
--- /dev/null
+++ b/vendor/oyejorge/less.php/lib/Less/Visitor/joinSelector.php
@@ -0,0 +1,70 @@
+<?php
+
+/**
+ * Join Selector Visitor
+ *
+ * @package Less
+ * @subpackage visitor
+ */
+class Less_Visitor_joinSelector extends Less_Visitor{
+
+ public $contexts = array( array() );
+
+ /**
+ * @param Less_Tree_Ruleset $root
+ */
+ public function run( $root ){
+ return $this->visitObj($root);
+ }
+
+ public function visitRule( $ruleNode, &$visitDeeper ){
+ $visitDeeper = false;
+ }
+
+ public function visitMixinDefinition( $mixinDefinitionNode, &$visitDeeper ){
+ $visitDeeper = false;
+ }
+
+ public function visitRuleset( $rulesetNode ){
+
+ $paths = array();
+
+ if( !$rulesetNode->root ){
+ $selectors = array();
+
+ if( $rulesetNode->selectors && $rulesetNode->selectors ){
+ foreach($rulesetNode->selectors as $selector){
+ if( $selector->getIsOutput() ){
+ $selectors[] = $selector;
+ }
+ }
+ }
+
+ if( !$selectors ){
+ $rulesetNode->selectors = null;
+ $rulesetNode->rules = null;
+ }else{
+ $context = end($this->contexts); //$context = $this->contexts[ count($this->contexts) - 1];
+ $paths = $rulesetNode->joinSelectors( $context, $selectors);
+ }
+
+ $rulesetNode->paths = $paths;
+ }
+
+ $this->contexts[] = $paths; //different from less.js. Placed after joinSelectors() so that $this->contexts will get correct $paths
+ }
+
+ public function visitRulesetOut(){
+ array_pop($this->contexts);
+ }
+
+ public function visitMedia($mediaNode) {
+ $context = end($this->contexts); //$context = $this->contexts[ count($this->contexts) - 1];
+
+ if( !count($context) || (is_object($context[0]) && $context[0]->multiMedia) ){
+ $mediaNode->rules[0]->root = true;
+ }
+ }
+
+}
+
diff --git a/vendor/oyejorge/less.php/lib/Less/Visitor/processExtends.php b/vendor/oyejorge/less.php/lib/Less/Visitor/processExtends.php
new file mode 100644
index 00000000..c01f9c5d
--- /dev/null
+++ b/vendor/oyejorge/less.php/lib/Less/Visitor/processExtends.php
@@ -0,0 +1,469 @@
+<?php
+
+/**
+ * Process Extends Visitor
+ *
+ * @package Less
+ * @subpackage visitor
+ */
+class Less_Visitor_processExtends extends Less_Visitor{
+
+ public $allExtendsStack;
+
+ /**
+ * @param Less_Tree_Ruleset $root
+ */
+ public function run( $root ){
+ $extendFinder = new Less_Visitor_extendFinder();
+ $extendFinder->run( $root );
+ if( !$extendFinder->foundExtends){
+ return $root;
+ }
+
+ $root->allExtends = $this->doExtendChaining( $root->allExtends, $root->allExtends);
+
+ $this->allExtendsStack = array();
+ $this->allExtendsStack[] = &$root->allExtends;
+
+ return $this->visitObj( $root );
+ }
+
+ private function doExtendChaining( $extendsList, $extendsListTarget, $iterationCount = 0){
+ //
+ // chaining is different from normal extension.. if we extend an extend then we are not just copying, altering and pasting
+ // the selector we would do normally, but we are also adding an extend with the same target selector
+ // this means this new extend can then go and alter other extends
+ //
+ // this method deals with all the chaining work - without it, extend is flat and doesn't work on other extend selectors
+ // this is also the most expensive.. and a match on one selector can cause an extension of a selector we had already processed if
+ // we look at each selector at a time, as is done in visitRuleset
+
+ $extendsToAdd = array();
+
+
+ //loop through comparing every extend with every target extend.
+ // a target extend is the one on the ruleset we are looking at copy/edit/pasting in place
+ // e.g. .a:extend(.b) {} and .b:extend(.c) {} then the first extend extends the second one
+ // and the second is the target.
+ // the seperation into two lists allows us to process a subset of chains with a bigger set, as is the
+ // case when processing media queries
+ for( $extendIndex = 0, $extendsList_len = count($extendsList); $extendIndex < $extendsList_len; $extendIndex++ ){
+ for( $targetExtendIndex = 0; $targetExtendIndex < count($extendsListTarget); $targetExtendIndex++ ){
+
+ $extend = $extendsList[$extendIndex];
+ $targetExtend = $extendsListTarget[$targetExtendIndex];
+
+ // look for circular references
+ if( in_array($targetExtend->object_id, $extend->parent_ids,true) ){
+ continue;
+ }
+
+ // find a match in the target extends self selector (the bit before :extend)
+ $selectorPath = array( $targetExtend->selfSelectors[0] );
+ $matches = $this->findMatch( $extend, $selectorPath);
+
+
+ if( $matches ){
+
+ // we found a match, so for each self selector..
+ foreach($extend->selfSelectors as $selfSelector ){
+
+
+ // process the extend as usual
+ $newSelector = $this->extendSelector( $matches, $selectorPath, $selfSelector);
+
+ // but now we create a new extend from it
+ $newExtend = new Less_Tree_Extend( $targetExtend->selector, $targetExtend->option, 0);
+ $newExtend->selfSelectors = $newSelector;
+
+ // add the extend onto the list of extends for that selector
+ end($newSelector)->extendList = array($newExtend);
+ //$newSelector[ count($newSelector)-1]->extendList = array($newExtend);
+
+ // record that we need to add it.
+ $extendsToAdd[] = $newExtend;
+ $newExtend->ruleset = $targetExtend->ruleset;
+
+ //remember its parents for circular references
+ $newExtend->parent_ids = array_merge($newExtend->parent_ids,$targetExtend->parent_ids,$extend->parent_ids);
+
+ // only process the selector once.. if we have :extend(.a,.b) then multiple
+ // extends will look at the same selector path, so when extending
+ // we know that any others will be duplicates in terms of what is added to the css
+ if( $targetExtend->firstExtendOnThisSelectorPath ){
+ $newExtend->firstExtendOnThisSelectorPath = true;
+ $targetExtend->ruleset->paths[] = $newSelector;
+ }
+ }
+ }
+ }
+ }
+
+ if( $extendsToAdd ){
+ // try to detect circular references to stop a stack overflow.
+ // may no longer be needed. $this->extendChainCount++;
+ if( $iterationCount > 100) {
+
+ try{
+ $selectorOne = $extendsToAdd[0]->selfSelectors[0]->toCSS();
+ $selectorTwo = $extendsToAdd[0]->selector->toCSS();
+ }catch(Exception $e){
+ $selectorOne = "{unable to calculate}";
+ $selectorTwo = "{unable to calculate}";
+ }
+
+ throw new Less_Exception_Parser("extend circular reference detected. One of the circular extends is currently:"+$selectorOne+":extend(" + $selectorTwo+")");
+ }
+
+ // now process the new extends on the existing rules so that we can handle a extending b extending c ectending d extending e...
+ $extendsToAdd = $this->doExtendChaining( $extendsToAdd, $extendsListTarget, $iterationCount+1);
+ }
+
+ return array_merge($extendsList, $extendsToAdd);
+ }
+
+
+ protected function visitRule( $ruleNode, &$visitDeeper ){
+ $visitDeeper = false;
+ }
+
+ protected function visitMixinDefinition( $mixinDefinitionNode, &$visitDeeper ){
+ $visitDeeper = false;
+ }
+
+ protected function visitSelector( $selectorNode, &$visitDeeper ){
+ $visitDeeper = false;
+ }
+
+ protected function visitRuleset($rulesetNode){
+
+
+ if( $rulesetNode->root ){
+ return;
+ }
+
+ $allExtends = end($this->allExtendsStack);
+ $paths_len = count($rulesetNode->paths);
+
+ // look at each selector path in the ruleset, find any extend matches and then copy, find and replace
+ foreach($allExtends as $allExtend){
+ for($pathIndex = 0; $pathIndex < $paths_len; $pathIndex++ ){
+
+ // extending extends happens initially, before the main pass
+ if( isset($rulesetNode->extendOnEveryPath) && $rulesetNode->extendOnEveryPath ){
+ continue;
+ }
+
+ $selectorPath = $rulesetNode->paths[$pathIndex];
+
+ if( end($selectorPath)->extendList ){
+ continue;
+ }
+
+ $this->ExtendMatch( $rulesetNode, $allExtend, $selectorPath);
+
+ }
+ }
+ }
+
+
+ private function ExtendMatch( $rulesetNode, $extend, $selectorPath ){
+ $matches = $this->findMatch($extend, $selectorPath);
+
+ if( $matches ){
+ foreach($extend->selfSelectors as $selfSelector ){
+ $rulesetNode->paths[] = $this->extendSelector($matches, $selectorPath, $selfSelector);
+ }
+ }
+ }
+
+
+
+ private function findMatch($extend, $haystackSelectorPath ){
+
+
+ if( !$this->HasMatches($extend, $haystackSelectorPath) ){
+ return false;
+ }
+
+
+ //
+ // look through the haystack selector path to try and find the needle - extend.selector
+ // returns an array of selector matches that can then be replaced
+ //
+ $needleElements = $extend->selector->elements;
+ $potentialMatches = array();
+ $potentialMatches_len = 0;
+ $potentialMatch = null;
+ $matches = array();
+
+
+
+ // loop through the haystack elements
+ $haystack_path_len = count($haystackSelectorPath);
+ for($haystackSelectorIndex = 0; $haystackSelectorIndex < $haystack_path_len; $haystackSelectorIndex++ ){
+ $hackstackSelector = $haystackSelectorPath[$haystackSelectorIndex];
+
+ $haystack_elements_len = count($hackstackSelector->elements);
+ for($hackstackElementIndex = 0; $hackstackElementIndex < $haystack_elements_len; $hackstackElementIndex++ ){
+
+ $haystackElement = $hackstackSelector->elements[$hackstackElementIndex];
+
+ // if we allow elements before our match we can add a potential match every time. otherwise only at the first element.
+ if( $extend->allowBefore || ($haystackSelectorIndex === 0 && $hackstackElementIndex === 0) ){
+ $potentialMatches[] = array('pathIndex'=> $haystackSelectorIndex, 'index'=> $hackstackElementIndex, 'matched'=> 0, 'initialCombinator'=> $haystackElement->combinator);
+ $potentialMatches_len++;
+ }
+
+ for($i = 0; $i < $potentialMatches_len; $i++ ){
+
+ $potentialMatch = &$potentialMatches[$i];
+ $potentialMatch = $this->PotentialMatch( $potentialMatch, $needleElements, $haystackElement, $hackstackElementIndex );
+
+
+ // if we are still valid and have finished, test whether we have elements after and whether these are allowed
+ if( $potentialMatch && $potentialMatch['matched'] === $extend->selector->elements_len ){
+ $potentialMatch['finished'] = true;
+
+ if( !$extend->allowAfter && ($hackstackElementIndex+1 < $haystack_elements_len || $haystackSelectorIndex+1 < $haystack_path_len) ){
+ $potentialMatch = null;
+ }
+ }
+
+ // if null we remove, if not, we are still valid, so either push as a valid match or continue
+ if( $potentialMatch ){
+ if( $potentialMatch['finished'] ){
+ $potentialMatch['length'] = $extend->selector->elements_len;
+ $potentialMatch['endPathIndex'] = $haystackSelectorIndex;
+ $potentialMatch['endPathElementIndex'] = $hackstackElementIndex + 1; // index after end of match
+ $potentialMatches = array(); // we don't allow matches to overlap, so start matching again
+ $potentialMatches_len = 0;
+ $matches[] = $potentialMatch;
+ }
+ continue;
+ }
+
+ array_splice($potentialMatches, $i, 1);
+ $potentialMatches_len--;
+ $i--;
+ }
+ }
+ }
+
+ return $matches;
+ }
+
+
+ // Before going through all the nested loops, lets check to see if a match is possible
+ // Reduces Bootstrap 3.1 compile time from ~6.5s to ~5.6s
+ private function HasMatches($extend, $haystackSelectorPath){
+
+ if( !$extend->selector->cacheable ){
+ return true;
+ }
+
+ $first_el = $extend->selector->_oelements[0];
+
+ foreach($haystackSelectorPath as $hackstackSelector){
+ if( !$hackstackSelector->cacheable ){
+ return true;
+ }
+
+ if( in_array($first_el, $hackstackSelector->_oelements) ){
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+
+ /**
+ * @param integer $hackstackElementIndex
+ */
+ private function PotentialMatch( $potentialMatch, $needleElements, $haystackElement, $hackstackElementIndex ){
+
+
+ if( $potentialMatch['matched'] > 0 ){
+
+ // selectors add " " onto the first element. When we use & it joins the selectors together, but if we don't
+ // then each selector in haystackSelectorPath has a space before it added in the toCSS phase. so we need to work out
+ // what the resulting combinator will be
+ $targetCombinator = $haystackElement->combinator;
+ if( $targetCombinator === '' && $hackstackElementIndex === 0 ){
+ $targetCombinator = ' ';
+ }
+
+ if( $needleElements[ $potentialMatch['matched'] ]->combinator !== $targetCombinator ){
+ return null;
+ }
+ }
+
+ // if we don't match, null our match to indicate failure
+ if( !$this->isElementValuesEqual( $needleElements[$potentialMatch['matched'] ]->value, $haystackElement->value) ){
+ return null;
+ }
+
+ $potentialMatch['finished'] = false;
+ $potentialMatch['matched']++;
+
+ return $potentialMatch;
+ }
+
+
+ private function isElementValuesEqual( $elementValue1, $elementValue2 ){
+
+ if( $elementValue1 === $elementValue2 ){
+ return true;
+ }
+
+ if( is_string($elementValue1) || is_string($elementValue2) ) {
+ return false;
+ }
+
+ if( $elementValue1 instanceof Less_Tree_Attribute ){
+ return $this->isAttributeValuesEqual( $elementValue1, $elementValue2 );
+ }
+
+ $elementValue1 = $elementValue1->value;
+ if( $elementValue1 instanceof Less_Tree_Selector ){
+ return $this->isSelectorValuesEqual( $elementValue1, $elementValue2 );
+ }
+
+ return false;
+ }
+
+
+ /**
+ * @param Less_Tree_Selector $elementValue1
+ */
+ private function isSelectorValuesEqual( $elementValue1, $elementValue2 ){
+
+ $elementValue2 = $elementValue2->value;
+ if( !($elementValue2 instanceof Less_Tree_Selector) || $elementValue1->elements_len !== $elementValue2->elements_len ){
+ return false;
+ }
+
+ for( $i = 0; $i < $elementValue1->elements_len; $i++ ){
+
+ if( $elementValue1->elements[$i]->combinator !== $elementValue2->elements[$i]->combinator ){
+ if( $i !== 0 || ($elementValue1->elements[$i]->combinator || ' ') !== ($elementValue2->elements[$i]->combinator || ' ') ){
+ return false;
+ }
+ }
+
+ if( !$this->isElementValuesEqual($elementValue1->elements[$i]->value, $elementValue2->elements[$i]->value) ){
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+
+ /**
+ * @param Less_Tree_Attribute $elementValue1
+ */
+ private function isAttributeValuesEqual( $elementValue1, $elementValue2 ){
+
+ if( $elementValue1->op !== $elementValue2->op || $elementValue1->key !== $elementValue2->key ){
+ return false;
+ }
+
+ if( !$elementValue1->value || !$elementValue2->value ){
+ if( $elementValue1->value || $elementValue2->value ) {
+ return false;
+ }
+ return true;
+ }
+
+ $elementValue1 = ($elementValue1->value->value ? $elementValue1->value->value : $elementValue1->value );
+ $elementValue2 = ($elementValue2->value->value ? $elementValue2->value->value : $elementValue2->value );
+
+ return $elementValue1 === $elementValue2;
+ }
+
+
+ private function extendSelector($matches, $selectorPath, $replacementSelector){
+
+ //for a set of matches, replace each match with the replacement selector
+
+ $currentSelectorPathIndex = 0;
+ $currentSelectorPathElementIndex = 0;
+ $path = array();
+ $selectorPath_len = count($selectorPath);
+
+ for($matchIndex = 0, $matches_len = count($matches); $matchIndex < $matches_len; $matchIndex++ ){
+
+
+ $match = $matches[$matchIndex];
+ $selector = $selectorPath[ $match['pathIndex'] ];
+
+ $firstElement = new Less_Tree_Element(
+ $match['initialCombinator'],
+ $replacementSelector->elements[0]->value,
+ $replacementSelector->elements[0]->index,
+ $replacementSelector->elements[0]->currentFileInfo
+ );
+
+ if( $match['pathIndex'] > $currentSelectorPathIndex && $currentSelectorPathElementIndex > 0 ){
+ $last_path = end($path);
+ $last_path->elements = array_merge( $last_path->elements, array_slice( $selectorPath[$currentSelectorPathIndex]->elements, $currentSelectorPathElementIndex));
+ $currentSelectorPathElementIndex = 0;
+ $currentSelectorPathIndex++;
+ }
+
+ $newElements = array_merge(
+ array_slice($selector->elements, $currentSelectorPathElementIndex, ($match['index'] - $currentSelectorPathElementIndex) ) // last parameter of array_slice is different than the last parameter of javascript's slice
+ , array($firstElement)
+ , array_slice($replacementSelector->elements,1)
+ );
+
+ if( $currentSelectorPathIndex === $match['pathIndex'] && $matchIndex > 0 ){
+ $last_key = count($path)-1;
+ $path[$last_key]->elements = array_merge($path[$last_key]->elements,$newElements);
+ }else{
+ $path = array_merge( $path, array_slice( $selectorPath, $currentSelectorPathIndex, $match['pathIndex'] ));
+ $path[] = new Less_Tree_Selector( $newElements );
+ }
+
+ $currentSelectorPathIndex = $match['endPathIndex'];
+ $currentSelectorPathElementIndex = $match['endPathElementIndex'];
+ if( $currentSelectorPathElementIndex >= count($selectorPath[$currentSelectorPathIndex]->elements) ){
+ $currentSelectorPathElementIndex = 0;
+ $currentSelectorPathIndex++;
+ }
+ }
+
+ if( $currentSelectorPathIndex < $selectorPath_len && $currentSelectorPathElementIndex > 0 ){
+ $last_path = end($path);
+ $last_path->elements = array_merge( $last_path->elements, array_slice($selectorPath[$currentSelectorPathIndex]->elements, $currentSelectorPathElementIndex));
+ $currentSelectorPathIndex++;
+ }
+
+ $slice_len = $selectorPath_len - $currentSelectorPathIndex;
+ $path = array_merge($path, array_slice($selectorPath, $currentSelectorPathIndex, $slice_len));
+
+ return $path;
+ }
+
+
+ protected function visitMedia( $mediaNode ){
+ $newAllExtends = array_merge( $mediaNode->allExtends, end($this->allExtendsStack) );
+ $this->allExtendsStack[] = $this->doExtendChaining($newAllExtends, $mediaNode->allExtends);
+ }
+
+ protected function visitMediaOut(){
+ array_pop( $this->allExtendsStack );
+ }
+
+ protected function visitDirective( $directiveNode ){
+ $newAllExtends = array_merge( $directiveNode->allExtends, end($this->allExtendsStack) );
+ $this->allExtendsStack[] = $this->doExtendChaining($newAllExtends, $directiveNode->allExtends);
+ }
+
+ protected function visitDirectiveOut(){
+ array_pop($this->allExtendsStack);
+ }
+
+} \ No newline at end of file
diff --git a/vendor/oyejorge/less.php/lib/Less/Visitor/toCSS.php b/vendor/oyejorge/less.php/lib/Less/Visitor/toCSS.php
new file mode 100644
index 00000000..18d328ff
--- /dev/null
+++ b/vendor/oyejorge/less.php/lib/Less/Visitor/toCSS.php
@@ -0,0 +1,292 @@
+<?php
+
+/**
+ * toCSS Visitor
+ *
+ * @package Less
+ * @subpackage visitor
+ */
+class Less_Visitor_toCSS extends Less_VisitorReplacing{
+
+ private $charset;
+
+ public function __construct(){
+ parent::__construct();
+ }
+
+ /**
+ * @param Less_Tree_Ruleset $root
+ */
+ public function run( $root ){
+ return $this->visitObj($root);
+ }
+
+ public function visitRule( $ruleNode ){
+ if( $ruleNode->variable ){
+ return array();
+ }
+ return $ruleNode;
+ }
+
+ public function visitMixinDefinition($mixinNode){
+ // mixin definitions do not get eval'd - this means they keep state
+ // so we have to clear that state here so it isn't used if toCSS is called twice
+ $mixinNode->frames = array();
+ return array();
+ }
+
+ public function visitExtend(){
+ return array();
+ }
+
+ public function visitComment( $commentNode ){
+ if( $commentNode->isSilent() ){
+ return array();
+ }
+ return $commentNode;
+ }
+
+ public function visitMedia( $mediaNode, &$visitDeeper ){
+ $mediaNode->accept($this);
+ $visitDeeper = false;
+
+ if( !$mediaNode->rules ){
+ return array();
+ }
+ return $mediaNode;
+ }
+
+ public function visitDirective( $directiveNode ){
+ if( isset($directiveNode->currentFileInfo['reference']) && (!property_exists($directiveNode,'isReferenced') || !$directiveNode->isReferenced) ){
+ return array();
+ }
+ if( $directiveNode->name === '@charset' ){
+ // Only output the debug info together with subsequent @charset definitions
+ // a comment (or @media statement) before the actual @charset directive would
+ // be considered illegal css as it has to be on the first line
+ if( isset($this->charset) && $this->charset ){
+
+ //if( $directiveNode->debugInfo ){
+ // $comment = new Less_Tree_Comment('/* ' . str_replace("\n",'',$directiveNode->toCSS())." */\n");
+ // $comment->debugInfo = $directiveNode->debugInfo;
+ // return $this->visit($comment);
+ //}
+
+
+ return array();
+ }
+ $this->charset = true;
+ }
+ return $directiveNode;
+ }
+
+ public function checkPropertiesInRoot( $rulesetNode ){
+
+ if( !$rulesetNode->firstRoot ){
+ return;
+ }
+
+ foreach($rulesetNode->rules as $ruleNode){
+ if( $ruleNode instanceof Less_Tree_Rule && !$ruleNode->variable ){
+ $msg = "properties must be inside selector blocks, they cannot be in the root. Index ".$ruleNode->index.($ruleNode->currentFileInfo ? (' Filename: '.$ruleNode->currentFileInfo['filename']) : null);
+ throw new Less_Exception_Compiler($msg);
+ }
+ }
+ }
+
+
+ public function visitRuleset( $rulesetNode, &$visitDeeper ){
+
+ $visitDeeper = false;
+
+ $this->checkPropertiesInRoot( $rulesetNode );
+
+ if( $rulesetNode->root ){
+ return $this->visitRulesetRoot( $rulesetNode );
+ }
+
+ $rulesets = array();
+ $rulesetNode->paths = $this->visitRulesetPaths($rulesetNode);
+
+
+ // Compile rules and rulesets
+ $nodeRuleCnt = count($rulesetNode->rules);
+ for( $i = 0; $i < $nodeRuleCnt; ){
+ $rule = $rulesetNode->rules[$i];
+
+ if( property_exists($rule,'rules') ){
+ // visit because we are moving them out from being a child
+ $rulesets[] = $this->visitObj($rule);
+ array_splice($rulesetNode->rules,$i,1);
+ $nodeRuleCnt--;
+ continue;
+ }
+ $i++;
+ }
+
+
+ // accept the visitor to remove rules and refactor itself
+ // then we can decide now whether we want it or not
+ if( $nodeRuleCnt > 0 ){
+ $rulesetNode->accept($this);
+
+ if( $rulesetNode->rules ){
+
+ if( count($rulesetNode->rules) > 1 ){
+ $this->_mergeRules( $rulesetNode->rules );
+ $this->_removeDuplicateRules( $rulesetNode->rules );
+ }
+
+ // now decide whether we keep the ruleset
+ if( $rulesetNode->paths ){
+ //array_unshift($rulesets, $rulesetNode);
+ array_splice($rulesets,0,0,array($rulesetNode));
+ }
+ }
+
+ }
+
+
+ if( count($rulesets) === 1 ){
+ return $rulesets[0];
+ }
+ return $rulesets;
+ }
+
+
+ /**
+ * Helper function for visitiRuleset
+ *
+ * return array|Less_Tree_Ruleset
+ */
+ private function visitRulesetRoot( $rulesetNode ){
+ $rulesetNode->accept( $this );
+ if( $rulesetNode->firstRoot || $rulesetNode->rules ){
+ return $rulesetNode;
+ }
+ return array();
+ }
+
+
+ /**
+ * Helper function for visitRuleset()
+ *
+ * @return array
+ */
+ private function visitRulesetPaths($rulesetNode){
+
+ $paths = array();
+ foreach($rulesetNode->paths as $p){
+ if( $p[0]->elements[0]->combinator === ' ' ){
+ $p[0]->elements[0]->combinator = '';
+ }
+
+ foreach($p as $pi){
+ if( $pi->getIsReferenced() && $pi->getIsOutput() ){
+ $paths[] = $p;
+ break;
+ }
+ }
+ }
+
+ return $paths;
+ }
+
+ protected function _removeDuplicateRules( &$rules ){
+ // remove duplicates
+ $ruleCache = array();
+ for( $i = count($rules)-1; $i >= 0 ; $i-- ){
+ $rule = $rules[$i];
+ if( $rule instanceof Less_Tree_Rule || $rule instanceof Less_Tree_NameValue ){
+
+ if( !isset($ruleCache[$rule->name]) ){
+ $ruleCache[$rule->name] = $rule;
+ }else{
+ $ruleList =& $ruleCache[$rule->name];
+
+ if( $ruleList instanceof Less_Tree_Rule || $ruleList instanceof Less_Tree_NameValue ){
+ $ruleList = $ruleCache[$rule->name] = array( $ruleCache[$rule->name]->toCSS() );
+ }
+
+ $ruleCSS = $rule->toCSS();
+ if( array_search($ruleCSS,$ruleList) !== false ){
+ array_splice($rules,$i,1);
+ }else{
+ $ruleList[] = $ruleCSS;
+ }
+ }
+ }
+ }
+ }
+
+ protected function _mergeRules( &$rules ){
+ $groups = array();
+
+ //obj($rules);
+
+ $rules_len = count($rules);
+ for( $i = 0; $i < $rules_len; $i++ ){
+ $rule = $rules[$i];
+
+ if( ($rule instanceof Less_Tree_Rule) && $rule->merge ){
+
+ $key = $rule->name;
+ if( $rule->important ){
+ $key .= ',!';
+ }
+
+ if( !isset($groups[$key]) ){
+ $groups[$key] = array();
+ }else{
+ array_splice($rules, $i--, 1);
+ $rules_len--;
+ }
+
+ $groups[$key][] = $rule;
+ }
+ }
+
+
+ foreach($groups as $parts){
+
+ if( count($parts) > 1 ){
+ $rule = $parts[0];
+ $spacedGroups = array();
+ $lastSpacedGroup = array();
+ $parts_mapped = array();
+ foreach($parts as $p){
+ if( $p->merge === '+' ){
+ if( $lastSpacedGroup ){
+ $spacedGroups[] = self::toExpression($lastSpacedGroup);
+ }
+ $lastSpacedGroup = array();
+ }
+ $lastSpacedGroup[] = $p;
+ }
+
+ $spacedGroups[] = self::toExpression($lastSpacedGroup);
+ $rule->value = self::toValue($spacedGroups);
+ }
+ }
+
+ }
+
+ public static function toExpression($values){
+ $mapped = array();
+ foreach($values as $p){
+ $mapped[] = $p->value;
+ }
+ return new Less_Tree_Expression( $mapped );
+ }
+
+ public static function toValue($values){
+ //return new Less_Tree_Value($values); ??
+
+ $mapped = array();
+ foreach($values as $p){
+ $mapped[] = $p;
+ }
+ return new Less_Tree_Value($mapped);
+ }
+}
+
diff --git a/vendor/oyejorge/less.php/lib/Less/VisitorReplacing.php b/vendor/oyejorge/less.php/lib/Less/VisitorReplacing.php
new file mode 100644
index 00000000..5923170e
--- /dev/null
+++ b/vendor/oyejorge/less.php/lib/Less/VisitorReplacing.php
@@ -0,0 +1,75 @@
+<?php
+
+/**
+ * Replacing Visitor
+ *
+ * @package Less
+ * @subpackage visitor
+ */
+class Less_VisitorReplacing extends Less_Visitor{
+
+ public function visitObj( $node ){
+
+ $funcName = 'visit'.$node->type;
+ if( isset($this->_visitFnCache[$funcName]) ){
+
+ $visitDeeper = true;
+ $node = $this->$funcName( $node, $visitDeeper );
+
+ if( $node ){
+ if( $visitDeeper && is_object($node) ){
+ $node->accept($this);
+ }
+
+ $funcName = $funcName . "Out";
+ if( isset($this->_visitFnCache[$funcName]) ){
+ $this->$funcName( $node );
+ }
+ }
+
+ }else{
+ $node->accept($this);
+ }
+
+ return $node;
+ }
+
+ public function visitArray( $nodes ){
+
+ $newNodes = array();
+ foreach($nodes as $node){
+ $evald = $this->visitObj($node);
+ if( $evald ){
+ if( is_array($evald) ){
+ self::flatten($evald,$newNodes);
+ }else{
+ $newNodes[] = $evald;
+ }
+ }
+ }
+ return $newNodes;
+ }
+
+ public function flatten( $arr, &$out ){
+
+ foreach($arr as $item){
+ if( !is_array($item) ){
+ $out[] = $item;
+ continue;
+ }
+
+ foreach($item as $nestedItem){
+ if( is_array($nestedItem) ){
+ self::flatten( $nestedItem, $out);
+ }else{
+ $out[] = $nestedItem;
+ }
+ }
+ }
+
+ return $out;
+ }
+
+}
+
+
diff --git a/vendor/psr/log/Psr/Log/LoggerAwareTrait.php b/vendor/psr/log/Psr/Log/LoggerAwareTrait.php
deleted file mode 100644
index f087a3da..00000000
--- a/vendor/psr/log/Psr/Log/LoggerAwareTrait.php
+++ /dev/null
@@ -1,22 +0,0 @@
-<?php
-
-namespace Psr\Log;
-
-/**
- * Basic Implementation of LoggerAwareInterface.
- */
-trait LoggerAwareTrait
-{
- /** @var LoggerInterface */
- protected $logger;
-
- /**
- * Sets a logger.
- *
- * @param LoggerInterface $logger
- */
- public function setLogger(LoggerInterface $logger)
- {
- $this->logger = $logger;
- }
-}
diff --git a/vendor/psr/log/Psr/Log/LoggerTrait.php b/vendor/psr/log/Psr/Log/LoggerTrait.php
deleted file mode 100644
index 59124960..00000000
--- a/vendor/psr/log/Psr/Log/LoggerTrait.php
+++ /dev/null
@@ -1,131 +0,0 @@
-<?php
-
-namespace Psr\Log;
-
-/**
- * This is a simple Logger trait that classes unable to extend AbstractLogger
- * (because they extend another class, etc) can include.
- *
- * It simply delegates all log-level-specific methods to the `log` method to
- * reduce boilerplate code that a simple Logger that does the same thing with
- * messages regardless of the error level has to implement.
- */
-trait LoggerTrait
-{
- /**
- * System is unusable.
- *
- * @param string $message
- * @param array $context
- * @return null
- */
- public function emergency($message, array $context = array())
- {
- $this->log(LogLevel::EMERGENCY, $message, $context);
- }
-
- /**
- * Action must be taken immediately.
- *
- * Example: Entire website down, database unavailable, etc. This should
- * trigger the SMS alerts and wake you up.
- *
- * @param string $message
- * @param array $context
- * @return null
- */
- public function alert($message, array $context = array())
- {
- $this->log(LogLevel::ALERT, $message, $context);
- }
-
- /**
- * Critical conditions.
- *
- * Example: Application component unavailable, unexpected exception.
- *
- * @param string $message
- * @param array $context
- * @return null
- */
- public function critical($message, array $context = array())
- {
- $this->log(LogLevel::CRITICAL, $message, $context);
- }
-
- /**
- * Runtime errors that do not require immediate action but should typically
- * be logged and monitored.
- *
- * @param string $message
- * @param array $context
- * @return null
- */
- public function error($message, array $context = array())
- {
- $this->log(LogLevel::ERROR, $message, $context);
- }
-
- /**
- * Exceptional occurrences that are not errors.
- *
- * Example: Use of deprecated APIs, poor use of an API, undesirable things
- * that are not necessarily wrong.
- *
- * @param string $message
- * @param array $context
- * @return null
- */
- public function warning($message, array $context = array())
- {
- $this->log(LogLevel::WARNING, $message, $context);
- }
-
- /**
- * Normal but significant events.
- *
- * @param string $message
- * @param array $context
- * @return null
- */
- public function notice($message, array $context = array())
- {
- $this->log(LogLevel::NOTICE, $message, $context);
- }
-
- /**
- * Interesting events.
- *
- * Example: User logs in, SQL logs.
- *
- * @param string $message
- * @param array $context
- * @return null
- */
- public function info($message, array $context = array())
- {
- $this->log(LogLevel::INFO, $message, $context);
- }
-
- /**
- * Detailed debug information.
- *
- * @param string $message
- * @param array $context
- * @return null
- */
- public function debug($message, array $context = array())
- {
- $this->log(LogLevel::DEBUG, $message, $context);
- }
-
- /**
- * Logs with an arbitrary level.
- *
- * @param mixed $level
- * @param string $message
- * @param array $context
- * @return null
- */
- abstract public function log($level, $message, array $context = array());
-}
diff --git a/vendor/ruflin/elastica/CHANGELOG.md b/vendor/ruflin/elastica/CHANGELOG.md
new file mode 100644
index 00000000..1ea98234
--- /dev/null
+++ b/vendor/ruflin/elastica/CHANGELOG.md
@@ -0,0 +1,1038 @@
+# Change Log
+All notable changes to this project will be documented in this file based on the [Keep a Changelog](http://keepachangelog.com/) Standard. This project adheres to [Semantic Versioning](http://semver.org/).
+
+## [Unreleased](https://github.com/ruflin/Elastica/compare/2.2.0...HEAD)
+
+### Backward Compatibility Breaks
+
+### Bugfixes
+
+### Added
+
+### Improvements
+
+### Deprecated
+
+
+## [2.2.0](https://github.com/ruflin/Elastica/releases/tag/2.2.0) - 2015-07-08
+
+
+### Backward Compatibility Breaks
+- Usage of constant DEBUG and method Elastica\Util::debugEnabled is removed. [#868](https://github.com/ruflin/Elastica/pull/868)
+- Elastica\Response::getTransferInfo will not return "request_header" by default. [#868](https://github.com/ruflin/Elastica/pull/868)
+- The Image Plugin is currently not compatible with Elasticearch 1.6.0
+
+### Bugfixes
+- Fixed segmentation fault in PHP7 [#868](https://github.com/ruflin/Elastica/pull/868)
+- Removed deprecation for Elastica\Type::deleteByQuery [#875](https://github.com/ruflin/Elastica/pull/875)
+
+### Improvements
+- `CallbackStrategy` now will accept any `callable` as callback, not only instance of `Closure`. [#871](https://github.com/ruflin/Elastica/pull/871)
+- `StrategyFactory` now will try to find predefined strategy before looking to global namespace. [#877](https://github.com/ruflin/Elastica/pull/877)
+- Update elasticsearch dependency to elasticsearch 1.6.0 https://www.elastic.co/downloads/past-releases/elasticsearch-1-6-0
+- All elasticsearch plugin dependencies were updated to the newest version.
+- Methods of classes in `QueryBuilder\DSL` namespace now have exact same signatures as corresponding constructors. [#878](https://github.com/ruflin/Elastica/pull/878)
+- Constructor of `Aggregation\Filter` now accepts filter as second parameter [#878](https://github.com/ruflin/Elastica/pull/878)
+- Constructor of `Filter\AbstractMulti` (`BoolAnd`, `BooldOr`) now accepts array of filters as parameter [#878](https://github.com/ruflin/Elastica/pull/878)
+- Constructor of `Query\Match` now accepts arguments [#878](https://github.com/ruflin/Elastica/pull/878)
+- Coverage Reporting improved with Codecov [#888](https://github.com/ruflin/Elastica/pull/888)
+- Added 'query_cache' option for search [#886](https://github.com/ruflin/Elastica/pull/886)
+
+## [2.1.0](https://github.com/ruflin/Elastica/releases/tag/2.1.0) - 2015-06-01
+
+### Added
+- Multiple rescore query [#820](https://github.com/ruflin/Elastica/issues/820/)
+- Support for a custom connection timeout through a connectTimeout parameter. [#841](https://github.com/ruflin/Elastica/issues/841/)
+- SignificantTerms Aggregation [#847](https://github.com/ruflin/Elastica/issues/847/)
+- Support for 'precision_threshold' and 'rehash' options for the Cardinality Aggregation [#851]
+- Support for retrieving id node #852
+- Scroll Iterator [#842](https://github.com/ruflin/Elastica/issues/842/)
+- Gitter Elastica Chat Room add for Elastica discussions: https://gitter.im/ruflin/Elastica
+- Introduce PHP7 compatibility and tests. #837
+- `Tool\CrossIndex` for reindexing and copying data and mapping between indices [#853](https://github.com/ruflin/Elastica/pull/853)
+- CONTIRUBTING.md file added for contributor guidelines. #854
+
+### Improvements
+- Introduction of Changelog standard based on http://keepachangelog.com/. changes.txt moved to CHANGELOG.md [#844](https://github.com/ruflin/Elastica/issues/844/)
+- Make host for all tests dynamic to prepare it for a more dynamic test environment #846
+- Node information is retrieved based on id instead of name as multiple nodes can have the same name. #852
+- Guzzle Http dependency updated to 5.3.*
+- Remove NO_DEV builds from travis build matrix to speed up building. All builds include no dev packages.
+- Introduction of benchmark test group to make it easy to run benchmark tests.
+- Make the docker images directly [available](https://hub.docker.com/u/ruflin/) on the docker registry. This speeds up fetching of the images and automates the build of the images.
+
+### Backward Compatibility Breaks
+- `Elastica\ScanAndScroll::$_lastScrollId` removed: `key()` now always returns the next scroll id [#842](https://github.com/ruflin/Elastica/issues/842/)
+
+
+### Deprecated
+- Facets are deprecated. You are encouraged to migrate to aggregations instead. [#855](https://github.com/ruflin/Elastica/pull/855/)
+- Elastica\Query\Builder is deprecated. Use new Elastica\QueryBuilder instead. [#855](https://github.com/ruflin/Elastica/pull/855/)
+- For PHP 7 compatibility Elastica\Query\Bool was renamed to *\BoolQuery, Elastica\Filter\Bool was renamed to BoolFilter, Elastica\Transport\Null was renamed to NullTransport as Null and Bool are reserved phrases in PHP 7. Proxy objects for all three exist to keep backward compatibility. It is recommended to start using the new objects as the proxy classes will be deprecated as soon as PHP 7 is stable. #837
+
+
+
+## [2.0.0](https://github.com/ruflin/Elastica/releases/tag/2.0.0) - 2015-05-11
+
+
+### Backward Compatibility Breaks
+- Elastica\Query\QueryString::setLowercaseExpandedTerms removed [#813](https://github.com/ruflin/Elastica/issues/813/)
+- Update elasticsearch dependency to elasticsearch 1.5.2 https://www.elastic.co/downloads/past-releases/elasticsearch-1-5-2 [#834](https://github.com/ruflin/Elastica/issues/834/)
+- Added deprecation notice to Elastica\Transport\Thrift, Elastica\Transport\Memcached and Elastica\Type::deleteByQuery [#817](https://github.com/ruflin/Elastica/issues/817/)
+- Escape new symbols in Util::escapeTerm [#795](https://github.com/ruflin/Elastica/issues/795/)
+
+### Bugfixes
+- Fix empty bool query to act as match all query [#817](https://github.com/ruflin/Elastica/issues/817/)
+- Fixed short match construction in query DSL [#796](https://github.com/ruflin/Elastica/issues/796/)
+- Index optimize method to return Response object. [#797](https://github.com/ruflin/Elastica/issues/797/)
+- Fix fluent interface inconsistency [#788](https://github.com/ruflin/Elastica/issues/788/)
+
+
+### Improvements
+- Add testing on PHP 7 on Travis [#826](https://github.com/ruflin/Elastica/issues/826/)
+- Allow bool in Query::setSource function [#818](https://github.com/ruflin/Elastica/issues/818/) http://www.elastic.co/guide/en/elasticsearch/reference/current/search-request-source-filtering.html
+- deleteByQuery() implemented in Elastica\Index [#816](https://github.com/ruflin/Elastica/issues/816/)
+- Add MLT query against documents [#814](https://github.com/ruflin/Elastica/issues/814/)
+- Added Elastica\Query\SimpleQueryString::setMinimumShouldMatch [#813](https://github.com/ruflin/Elastica/issues/813/)
+- Added Elastica\Query\FunctionScore::setMinScore [#813](https://github.com/ruflin/Elastica/issues/813/)
+- Added Elastica\Query\MoreLikeThis::setMinimumShouldMatch [#813](https://github.com/ruflin/Elastica/issues/813/)
+- Added new methods to Elastica\Aggregation\DateHistogram: setOffset, setTimezone [#813](https://github.com/ruflin/Elastica/issues/813/)
+- Following methods in Elastica\Aggregation\DateHistogram marked as deprecated: setPreOffset, setPostOffset, setPreZone, setPostZone, setPreZoneAdjustLargeInterval [#813](https://github.com/ruflin/Elastica/issues/813/)
+- Add Elastica\Facet\DateHistogram::setFactor() [#806](https://github.com/ruflin/Elastica/issues/806/)
+- Added Elastica\Query\QueryString::setTimezone [#813](https://github.com/ruflin/Elastica/issues/813/)
+- Add .editorconfig [#807](https://github.com/ruflin/Elastica/issues/807/)
+- Added Elastica\Suggest\Completion [#808](https://github.com/ruflin/Elastica/issues/808/)
+- Fix elasticsearch links to elastic domain [#809](https://github.com/ruflin/Elastica/issues/809/)
+- Added Elastica\Query\Image [#787](https://github.com/ruflin/Elastica/issues/787/)
+- Add Scrutinizer Code Quality status badge
+- Added support for percentiles aggregation [#786](https://github.com/ruflin/Elastica/issues/786/)
+
+
+
+## Changelog before 2.0.0
+The changelog before version 2.0.0 was organised by date. All changes can be found below.
+
+2015-02-17
+- Release v1.4.3.0
+- Added Elastica\Query\MatchPhrase [#599](https://github.com/ruflin/Elastica/issues/599/)
+- Added Elastica\Query\MatchPhrasePrefix [#599](https://github.com/ruflin/Elastica/issues/599/)
+
+2015-02-04
+- Reset PHP 5.3 tests and enable compatibility for PHP 5.3 again
+
+2015-02-16
+- Update elasticsearch compatibility to 1.4.3 [#782](https://github.com/ruflin/Elastica/issues/782/)
+- Add support for scripted metric aggrations [#780](https://github.com/ruflin/Elastica/issues/780/)
+
+2015-02-14
+- Added availability to specify regexp options in \Elastica\Filters\Regexp [#583](https://github.com/ruflin/Elastica/issues/583/) [#777](https://github.com/ruflin/Elastica/issues/777/)
+- Add HHVM as build in travis [#649](https://github.com/ruflin/Elastica/issues/649/)
+
+2015-02-11
+- Fixed issue with OutOfMemory exception in travis builds [#775](https://github.com/ruflin/Elastica/issues/775/)
+- Add support for filters aggregation [#773](https://github.com/ruflin/Elastica/issues/773/)
+
+2015-01-27
+- Housekeeping, coding standard [#764](https://github.com/ruflin/Elastica/issues/764/)
+- Exception\ElasticsearchException now can be catched like all other exceptions as Exception\ExceptionInterface [#762](https://github.com/ruflin/Elastica/issues/762/)
+
+2015-01-25
+- Release v1.4.2.0
+
+2015-01-23
+- Added Elastica\Query\Regexp [#757](https://github.com/ruflin/Elastica/issues/757/)
+
+2015-01-19
+- Update to elasticsearch 1.4.2 [#378](https://github.com/ruflin/Elastica/issues/378/)
+- Remove support for PHP 5.3
+
+2015-01-14
+- added @return annotation to top_hits aggregation DSL method [#752](https://github.com/ruflin/Elastica/issues/752/)
+
+2015-01-07
+- Added Elastica\Aggregation\TopHits [#718](https://github.com/ruflin/Elastica/issues/718/)
+
+2015-01-05
+- Vagrantfile updated [#742](https://github.com/ruflin/Elastica/issues/742/)
+- Plugins updated to ES 1.3.4
+- Since new version of thrift plugin is compatible with ES 1.3.4, plugin added back to test environment
+
+2014-12-30
+- Added: Filter\Range::setExecution, Filter\Terms::setExecution, Filter\Missing::setExistence, Filter\Missing::setNullValue, Filter\HasChild::setMinumumChildrenCount, Filter\HasChild::Filter\HasChild::setMaximumChildrenCount, Filter\Indices::addIndex
+- Filter\HasChild::setType, Filter\HasParent::setType now support Type instance as argument
+- Filter\Indices::setIndices, Filter\Indices::addIndex now support Index instance as argument
+- (BC break) Removed as added by mistake: Filter\HasChild::setScope, Filter\HasParent::setScope, Filter\Nested::setScoreMode, Filter\Bool::setBoost
+
+2014-12-23
+- Additional Request Body Options for Percolator [#737](https://github.com/ruflin/Elastica/issues/737/)
+
+2014-12-19
+- making sure id is urlencoded when using updateDocument [#734](https://github.com/ruflin/Elastica/issues/734/)
+- Implement the `weight` in the function score query [#735](https://github.com/ruflin/Elastica/issues/735/)
+
+2014-12-09
+- Changed setRealWorldErrorLikelihood to setRealWordErrorLikelihood [#729](https://github.com/ruflin/Elastica/issues/729/)
+
+2014-11-23
+- allow to customize the key on a range aggregation [#728](https://github.com/ruflin/Elastica/issues/728/)
+
+2014-12-14
+- Added fluent interface to Elastica\Query::setRescore [#733](https://github.com/ruflin/Elastica/issues/733/)
+
+2014-11-30
+- Added transport to support egeloen/http-adapter [#727](https://github.com/ruflin/Elastica/issues/727/)
+
+2014-11-20
+- add cache control parameters support to Elastica\Filter\Bool [#725](https://github.com/ruflin/Elastica/issues/725/)
+
+2014-11-19
+- Avoid remove previously added params when adding a suggest to the query [#726](https://github.com/ruflin/Elastica/issues/726/)
+
+2014-11-16
+- Added Elastica\QueryBuilder [#724](https://github.com/ruflin/Elastica/issues/724/)
+- Update to elasticsearch 1.4.0
+- Disable official support for PHP 5.3
+
+2014-11-13
+- fixed reserved words in queries which composed of upper case letters (Util::replaceBooleanWords) [#722](https://github.com/ruflin/Elastica/issues/722/)
+
+2014-10-31
+- Adding PSR-4 autoloading support [#714](https://github.com/ruflin/Elastica/issues/714/)
+
+2014-10-29
+- Updated Type::getDocument() exception handling. \Elastica\Exception\ResponseException will be thrown instead of \Elastica\Exception\NotFoundException if the ES response contains any error (i.e: Missing index) (BC break) [#687](https://github.com/ruflin/Elastica/issues/687/)
+
+2014-10-22
+- Added Util::convertDateTimeObject to Util class to easily convert \DateTime objects to required format [#709](https://github.com/ruflin/Elastica/issues/709/)
+
+2014-10-15
+- Remove ResponseException catch in Type::getDocument() [#704](https://github.com/ruflin/Elastica/issues/704/)
+
+2014-10-10
+- Fixed Response::isOk() to work better with bulk update api [#702](https://github.com/ruflin/Elastica/issues/702/)
+- Adding magic __call() [#700](https://github.com/ruflin/Elastica/issues/700/)
+
+2014-10-05
+- ResultSet creation moved to static ResultSet::create() method [#690](https://github.com/ruflin/Elastica/issues/690/)
+- Accept an options array at Type::updateDocument() [#686](https://github.com/ruflin/Elastica/issues/686/)
+- Improve exception handling in Type::getDocument() [#693](https://github.com/ruflin/Elastica/issues/693/)
+
+2014-10-04
+- Release v1.3.4.0
+- Update to elasticsearch 1.3.4 [#691](https://github.com/ruflin/Elastica/issues/691/)
+
+2014-09-22
+- Update the branch alias in composer.json to match the library version [#683](https://github.com/ruflin/Elastica/issues/683/)
+
+2014-09-16
+- Update license in composer.json to match project [#681](https://github.com/ruflin/Elastica/issues/681/)
+
+2014-09-08
+- Delete execution permission from non-executable files [#677](https://github.com/ruflin/Elastica/issues/677/)
+
+2014-08-25
+- Top-level filter parameter in search has been renamed to post_filter [#669](https://github.com/ruflin/Elastica/issues/669/) [#670](https://github.com/ruflin/Elastica/issues/670/)
+- Deprecated: Elastica\Query::setFilter() is deprecated. Use Elastica\Query::setPostFilter() instead. [#669](https://github.com/ruflin/Elastica/issues/669/)
+- Deprecated: Elastica\Query::setPostFilter() passing filter as array is deprecated. Pass instance of AbstractFilter instead. [#669](https://github.com/ruflin/Elastica/issues/669/)
+
+2014-08-22
+- Fixed escaping of / character in Elastica\Util::escapeTerm(), removed usage of JSON_UNESCAPED_SLASHES in Elastica\JSON [#660](https://github.com/ruflin/Elastica/issues/660/)
+
+2014-08-06
+- Add connection pool and connection strategy
+
+2014-07-26
+- Release v1.3.0.0
+- Prepare Elastica Release v1.3.0.0
+
+2014-07-25
+- Update to elasticsearch version 1.3.0 https://www.elastic.co/downloads/past-releases/1-3-0
+
+2014-07-14
+ - Add setQuery() method to Elastica\Query\ConstantScore [#653](https://github.com/ruflin/Elastica/issues/653/)
+
+2014-07-12
+ - Be able to configure ES host/port via ENV var in test env [#652](https://github.com/ruflin/Elastica/issues/652/)
+
+2014-07-07
+ - Fix FunstionScore Query random_score without seed bug. [#647](https://github.com/ruflin/Elastica/issues/647/)
+
+2014-07-02
+- Add setPostFilter method to Elastica\Query (http://www.elastic.co/guide/en/elasticsearch/guide/current/_post_filter.html) [#645](https://github.com/ruflin/Elastica/issues/645/)
+
+2014-06-30
+- Add Reverse Nested aggregation (http://www.elastic.co/guide/en/elasticsearch/reference/current/search-aggregations-bucket-reverse-nested-aggregation.html). [#642](https://github.com/ruflin/Elastica/issues/642/)
+
+2014-06-14
+- Release v1.2.1.0
+- Removed the requirement to set arguments filter and/or query in Filtered, according to the documentation: http://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-filtered-query.html [#616](https://github.com/ruflin/Elastica/issues/616/)
+
+2014-06-13
+- Stop ClientTest->testDeleteIdsIdxStringTypeString from failing 1/3 of the time [#634](https://github.com/ruflin/Elastica/issues/634/)
+- Stop ScanAndScrollTest->testQuerySizeOverride from failing frequently for no reason [#635](https://github.com/ruflin/Elastica/issues/635/)
+- rework Document and Script so they can share some infrastructure allowing scripts to specify things like _retry_on_conflict and _routing [#629](https://github.com/ruflin/Elastica/issues/629/)
+
+2014-06-11
+- Allow bulk API deletes to be routed [#631](https://github.com/ruflin/Elastica/issues/631/)
+
+2014-06-10
+- Update travis to elasticsearch 1.2.1, disable Thrift plugin as not compatible and fix incompatible tests
+
+2014-06-04
+- Implement Boosting Query (http://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-boosting-query.html) [#625](https://github.com/ruflin/Elastica/issues/625/)
+
+2014-06-02
+- add retry_on_conflict support to bulk [#623](https://github.com/ruflin/Elastica/issues/623/)
+
+2014-06-01
+- toString updated to consider doc_as_upsert if sent an array source [#622](https://github.com/ruflin/Elastica/issues/622/)
+
+2014-05-27
+- Fix Aggragations/Filter to work with es v1.2.0 [#619](https://github.com/ruflin/Elastica/issues/619/)
+
+2014-05-25
+- Added Guzzle transport as an alternative to the default Http transport [#618](https://github.com/ruflin/Elastica/issues/618/)
+- Added Elastica\ScanAndScroll Iterator (http://www.elastic.co/guide/en/elasticsearch/guide/current/scan-scroll.html) [#617](https://github.com/ruflin/Elastica/issues/617/)
+
+2014-05-13
+- Add JSON compat library; Elasticsearch JSON flags and nicer error handling [#614](https://github.com/ruflin/Elastica/issues/614/)
+
+2014-05-12
+- Update dev builds to phpunit 4.1.*
+
+2014-05-11
+- Set processIsolation and backupGlobals to false to speed up tests. processIsolation was very slow with phpunit 4.0.19.
+
+2014-05-05
+- Fix get settings on alaised index [#608](https://github.com/ruflin/Elastica/issues/608/)
+- Added named function for source filtering [#605](https://github.com/ruflin/Elastica/issues/605/)
+- Scroll type constant to Elastica\Search added [#607](https://github.com/ruflin/Elastica/issues/607/)
+
+2014-04-28
+- Added setAnalyzer method to Query\FuzzyLikeThis Class and fixed issue with params not being merged [#611](https://github.com/ruflin/Elastica/issues/611/)
+- Typo fixes [#600](https://github.com/ruflin/Elastica/issues/600/), [#602](https://github.com/ruflin/Elastica/issues/602/)
+- Remove unreachable return statement [#598](https://github.com/ruflin/Elastica/issues/598/)
+
+2014-04-27
+- Release v1.1.1.1
+- Fix missing use in TermsStats->setOrder() [#597](https://github.com/ruflin/Elastica/issues/597/)
+- Replace all instances of ElasticSearch with Elasticsearch [#597](https://github.com/ruflin/Elastica/issues/597/)
+
+2014-04-24
+- Fixing the Bool filter with Bool filter children bug [#594](https://github.com/ruflin/Elastica/issues/594/)
+
+2014-04-22
+- Remove useless echo in the Memcache Transport object [#595](https://github.com/ruflin/Elastica/issues/595/)
+
+2014-04-21
+- escape \ by \\ [#592](https://github.com/ruflin/Elastica/issues/592/)
+
+2014-04-20
+- Handling of HasChild type parsing bug [#585](https://github.com/ruflin/Elastica/issues/585/)
+- Consolidate Index getMapping tests [#591](https://github.com/ruflin/Elastica/issues/591/)
+- Fix Type::getMapping when using an aliased index [#588](https://github.com/ruflin/Elastica/issues/588/)
+
+2014-04-19
+- Release v1.1.1.0
+- Update to elasticsearch 1.1.1 https://www.elastic.co/downloads/past-releases/1-1-1
+- Remove CustomFiltersScore and CustomScore query as removed in elasticsearch 1.1.0 https://github.com/elasticsearch/elasticsearch/pull/5076/files
+- Update Node Info to use plugins instead of plugin (https://github.com/elasticsearch/elasticsearch/pull/5072)
+- Fix mapping issue for aliases [#588](https://github.com/ruflin/Elastica/issues/588/)
+
+2014-04-17
+- Only trap real JSON parse errors in Response class [#586](https://github.com/ruflin/Elastica/issues/586/)
+
+2014-04-09
+- Added Cardinality aggregation [#581](https://github.com/ruflin/Elastica/issues/581/)
+
+2014-04-07
+- Support for Terms filter lookup options [#579](https://github.com/ruflin/Elastica/issues/579/)
+
+2014-03-29
+- Update to elasticsearch 1.1.0 https://www.elastic.co/downloads/past-releases/1-1-0
+
+2014-03-26
+- Fixed Query\Match Fuzziness parameter type [#576](https://github.com/ruflin/Elastica/issues/576/)
+
+2014-03-24
+- Release v1.0.1.2
+- Added Filter\Indices [#574](https://github.com/ruflin/Elastica/issues/574/)
+
+2014-03-25
+- Allow json string as data srouce for Bulk\Action on update [#575](https://github.com/ruflin/Elastica/issues/575/)
+
+2014-03-20
+- Allow for request params in delete by query calls [#573](https://github.com/ruflin/Elastica/issues/573/)
+
+2014-03-17
+- Added filters: AbstractGeoShape, GeoShapePreIndexed, GeoShapeProvided [#568](https://github.com/ruflin/Elastica/issues/568/)
+
+2014-03-15
+- Percolate existing documents and add percolate options ([#570](https://github.com/ruflin/Elastica/issues/570/))
+
+2014-03-14
+- Added Query\Rescore [#441](https://github.com/ruflin/Elastica/issues/441/)
+
+2014-03-13
+- Added missing query options for MultiMatch (operator, minimum_should_match, zero_terms_query, cutoff_frequency, type, fuzziness, prefix_length, max_expansions, analyzer) [#569](https://github.com/ruflin/Elastica/issues/569/)
+- Added missing query options for Match (zero_terms_query, cutoff_frequency) [#569](https://github.com/ruflin/Elastica/issues/569/)
+
+2014-03-11
+- Fixed request body reuse in http transport [#567](https://github.com/ruflin/Elastica/issues/567/)
+
+2014-03-08
+- Release v1.0.1.1
+- Enable goecluster-facet again as now compatible with elasticsearch 1.0 on travis
+- Run elasticsearch in the background to not have log output in travis build
+- Set memache php version as environment variable
+- Update to memcache 3.0.8 for travis
+
+2014-03-07
+- Add snapshot / restore functionality (Elastica\Snapshot) [#566](https://github.com/ruflin/Elastica/issues/566/)
+
+2014-03-04
+- Add PHP 5.6 to travis test environment
+- Improve performance of Elastica/Status->getIndicesWithAlias and aliasExists on clusters with many indices [#563](https://github.com/ruflin/Elastica/issues/563/)
+
+2014-03-02
+- Release v1.0.1.0
+- Fixed Type->deleteByQuery() not working with Query objects [#554](https://github.com/ruflin/Elastica/issues/554/)
+
+2014-02-27
+- Update to elasticsearch 1.0.1. Update Thrift and Geocluster plugin.
+
+2014-02-25
+- Add JSON_UNESCAPED_UNICODE and JSON_UNESCAPED_SLASHES options in Elastica/Transport/Http, Elastica/Bulk/Action [#559](https://github.com/ruflin/Elastica/issues/559/)
+
+2014-02-20
+- Fixed unregister percolator (still used _percolator instead of .percolator). removed duplicate slash from register percolator route. [#558](https://github.com/ruflin/Elastica/issues/558/)
+
+2014-02-17
+- Throw PartialShardFailureException if response has failed shards
+- Elastica/Aggregations/GlobalAggragation not allowed as sub aggragation [#555](https://github.com/ruflin/Elastica/issues/555/)
+
+2014-02-14
+- Add methods setSize, setShardSize to Elastica/Aggregation/Terms
+- Elastica/Aggregation/GlobalAggregationTest fixed bug where JSON returned [] instead of {}
+- Elastica/ResultSet added method hasAggregations
+
+2014-02-13
+- Moved from Apache License to MIT license
+
+2014-02-12
+- Release v1.0.0.0
+- Updated to elasticsearch 1.0: https://www.elastic.co/blog/1-0-0-released/
+
+2014-02-11
+- Add aggregations
+
+2014-02-08
+- Setting shard timeout doesn't work [#547](https://github.com/ruflin/Elastica/issues/547/)
+
+2014-02-04
+- Remove Elastica\Query\Field and Elastica\Query\Text, which are not supported in ES 1.0.0.RC1
+- Minor tweaking of request and result handling classes to adjust for changes in ES 1.0.0.RC1
+- Update mapper-attachments plugin to version 2.0.0.RC1 in .travis.yml
+- Adjust tests to account for changes in ES 1.0.0.RC1
+- Prevent the geocluster-facet plugin from being installed in test/bin/run_elasticsearch.sh as the plugin has not yet been updated for ES 1.0.0.RC1
+
+2014-01-06
+- Update to elasticsearch v1.0.0.RC2
+
+2014-01-02
+- Added Elastica\Query\DisMax
+- Update to elasticsearch v1.0.0.RC1
+
+2014-01-02
+- Release v0.90.10
+
+2014-01-31
+- Fix _bulk delete proxy methods if type or index not explicitly defined.
+
+2014-01-28
+- Add _bulk delete proxy methods to Index and Type for consistency.
+- Use the HTTP response code of GET requests (getDocument), instead of extists/found json property.
+
+2014-01-22
+- Add getParam & getProperties methods to Elastica\Type\Mapping
+
+2014-01-21
+- Code coverage generation for coveralls.io added: https://coveralls.io/r/ruflin/Elastica
+- Add support for shard timeout to the Bulk api.
+
+2014-01-17
+- Fix typo in constant name: Elastica\Query\FunctionScore::DECAY_GUASS becomes DECAY_GAUSS
+
+2014-01-13
+- Add support for _bulk update
+
+2014-01-14
+- added \Elastica\Exception\ResponseException::getElasticsearchException()
+- Changed logger default log level to debug from info
+
+2014-01-13
+- Update to elasticsearch 0.90.10
+- Add Elastica\Facet\TermsStats::setOrder()
+
+2014-01-08
+- Adding analyze function to Index to expose the _analyze API
+
+2014-01-07
+- Document::setDocAsUpsert() now returns the Document
+
+2013-12-18
+- Update to Elasticsearch 0.90.8
+- Add support for simple_query_string query
+
+2013-12-15
+- Add support for filter inside HasChild filter
+- Add support for filter inside HasParent filter
+
+2013-12-12
+- Always send scroll_id via HTTP body instead of as a query param
+- Fix the manner in which suggestion results are returned in \Elastica\ResultSet and adjust associated tests to account for the fix.
+- Add \Elastica\Resultset::hasSuggests()
+
+2013-12-11
+- Pass arguments to optimize as query
+- Add refreshAll on Client
+
+2013-12-07
+- Added Result::hasFields() and Result::hasParam() methods for consistency with Document
+
+2013-12-07
+- Escape slash in Util::escapeTerm, as it is used for regexp from Elastic 0.90
+
+2013-12-05
+- Add *.iml to .gitignore
+- Refactor suggest implementation (\Elastica\Suggest, \Elastica\Suggest\AbstractSuggest, and \Elastica\Suggest\Term) to more closely resemble query implementation. (BC break)
+- \Elastica\Search::addSuggest() has been renamed to \Elastica\Search::setSuggest()
+- \Elastica\Query::addSuggest() has been renamed to \Elastica\Query::setSuggest()
+- Add \Elastica\Suggest\Phrase, \Elastica\Suggest\CandidateGenerator\AbstractCandidateGenerator, and \Elastica\Suggest\CandidateGenerator\DirectGenerator
+ (see http://www.elastic.co/guide/en/elasticsearch/reference/current/search-suggesters-phrase.html)
+
+2013-12-04
+- Remove boost from FunctionScore::addFunction because this is not supported by elasticsearch
+
+2013-12-02
+- Issue [#491](https://github.com/ruflin/Elastica/issues/491/) resolved
+
+2013-12-01
+- Issue [#501](https://github.com/ruflin/Elastica/issues/501/) resolved
+- satooshi/php-coveralls package added for coverall.io
+- Multiple badges for downloads and latest stable release added
+
+2013-11-30
+- Remove facets param from query if is empty array
+- Add size param to API for TermsStats
+
+2013-11-23
+- Release v0.90.7.0
+
+2013-11-19
+- Updated geocluster-facet to 0.0.9
+
+2013-11-18
+- Added \Elastica\Filter\Regexp
+
+2013-11-16
+- Remove wrong documentation for "no limit" [#496](https://github.com/ruflin/Elastica/issues/496/)
+- Update to elasticsearch 0.90.7
+
+2013-11-03
+- Issue [#490](https://github.com/ruflin/Elastica/issues/490/): Set Elastica\Query\FunctionScore::DECAY_EXPONENTIAL to "exp" instead of "exponential"
+
+2013-10-29
+- Elastica_Type::exists() added
+ See http://www.elastic.co/guide/en/elasticsearch/reference/current/indices-types-exists.html#indices-types-exists
+
+2013-10-27
+- Adapted possible values (not only in) for minimum_should_match param based on elasticsearch documetnation http://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-minimum-should-match.html
+
+2013-10-27
+- Release v0.90.5.0
+
+2013-10-26
+- Update to elasticsearch 0.90.5
+
+2013-10-21
+- Fix \Elastica\Filter\HasParent usage of \Elastica\Query as to not collide with \Elastica\Filter\Query, bring \Elasitca\Filter\HasChild into line
+
+2013-10-01
+- Also pass the current client object to the failure callback in \Elastica\Client.
+
+2013-09-20
+- Update to geocluster-facet 0.0.8
+- Add support for term suggest API
+ See http://www.elastic.co/guide/en/elasticsearch/reference/current/search-suggesters-term.html
+
+2013-09-18
+- Fix \Elastica\Filter\HasChild usage of \Elastica\Query as to not collide with \Elastica\Filter\Query namespace
+
+2013-09-17
+- Update to elasticsearch 0.90.4
+- Add support for function_score query
+- Skip geocluster-facet test if the plugin is not installed
+- Correct \Elastica\Test\ClientTest to catch the proper exception type on connection failure
+- Fix unit test errors
+
+2013-09-14
+- Nested filter supports now the setFilter method
+
+2013-09-03
+- Support isset() calls on Result objects
+
+2013-08-27
+- Add \ArrayAccess on the ResultSet object
+
+2013-08-25
+- Update to elasticsearch 0.90.3
+
+2013-08-25
+- Release v0.90.2.0
+
+2013-08-20
+- Support for "proxy" param for http connections
+
+2013-08-17
+- Add support for fields parameter in Elastica_Type::getDocument()
+
+2013-08-13
+- Add a getQuery method on the FilteredQuery object
+
+2013-08-01
+- Second param to \Elastica\Search.php:count($query = '', $fullResult = false) added. If second param is set to true, full ResultSet is returned including facets.
+
+2013-07-16
+- Plugin geocluster-facet support added
+
+2013-07-02
+- Add Query\Common
+- Can now create a query by passing an array to Type::search()
+
+2013-07-01
+- Add Filter\GeohashCell
+
+2013-06-30
+- Revamped upsert so that Scripts are now first class citizens. (BC break)
+ See http://elastica.io/migration/0.90.2/upsert.html
+- Implemented doc_as_upsert.
+
+2013-06-29
+- Update to elasticsearch 0.90.2
+- Enabled ES_WAIT_ON_MAPPING_CHANGE for travis builds
+
+2013-06-25
+- Added upsert support when updating a document with a partial document or a script.
+
+2013-06-23
+- Add filtered queries to the percolator API.
+
+2013-06-21
+- Correct class name for TermTest unit test
+- Implement terms lookup feature for terms filter
+
+2013-06-14
+- Fix support for making scroll queries once the scroll has been started.
+
+2013-06-07
+- Release 0.90.1.0
+
+2013-06-05
+- Changed package name to lowercase to prevent potential issues with case sensitive file systems and to refelect the package name from packagist.org.
+ If you are requiring elastica in your project you might want to change the name in the require to lowercase, although it will still work if written in uppercase.
+ The composer autoloader will handle the package correctly and you will not notice any difference.
+ If you are requiring or including a file by hand with require() or include() from the composer vendor folder, pay attention that the package name in
+ the path will change to lowercase.
+- Add Bulk\Action\UpdateDocument.
+- Update Bulk\Action\AbstractDocument and Bulk\Action to enable use of OP_TYPE_UPDATE.
+- Update .travis.yml to use Elasticsearch version 0.9.1, as bulk update is a new feature in 0.9.1.
+
+2013-06-04
+- Elastica\Client::_configureParams() changed to _prepareConnectionParams(), which now takes the config array as an argument
+
+2013-06-03
+- Add getPlugins and hasPlugin methods to Node\Info
+
+2013-05-30
+- Update Index\Status::getAliases() to use new API
+- Update Index\Status::getSettings() to use new API
+
+2013-05-29
+- Add _meta to mapping. [#330](https://github.com/ruflin/Elastica/issues/330/)
+
+2013-05-27
+- Added parameters to implement scroll
+
+2013-05-23
+- add support PSR-3(https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-3-logger-interface.md)
+- Elastica\Log implement LoggerInterface(extends Psr\Log\AbstractLogger)
+ if you want use logging need install https://github.com/php-fig/log for example (composer require psr/log:dev-master)
+ if use Elastica\Log inside Elastica\Client nothing more is needed
+ if use Elastica\Log outside we need use as(https://github.com/php-fig/log) for example Elastica\Log::info($message) or Elastica\Log::log(LogLevel::INFO,$message)
+- Elastica\Client add setLogger for setting custom Logger for example Monolog(https://github.com/Seldaek/monolog)
+
+2013-05-18
+- Elastica\Index::exists fixed for 0.90.0. HEAD request method introduced
+- Elastica\Filter\AbstractMulti::getFilters() added
+- Implement Elastica\Type\Mapping::enableAllField
+- Refresh for Elastica\Index::flush implemented [#316](https://github.com/ruflin/Elastica/issues/316/)
+- Added optional parameter to filter result while percolate [#384](https://github.com/ruflin/Elastica/issues/384/)
+
+2013-05-07
+- Added EXPERIMENTAL DocumentObjectInterface to be used with Type::addObject()/addObjects()
+
+2013-04-23
+- Removed Elastica\Exception\AbstractException
+- All Exceptions now implement Elastica\Exception\ExceptionInterface
+
+2013-04-17
+- Query\Fuzzy to comply with DSL spec. Multi-field queries now throw an exception. Implemented: Query\Fuzzy::setField, Query\Fuzzy::setFieldOption.
+- Query\Fuzzy::addField has been deprecated.
+
+2013-04-12
+- Adding max score information in ResultSet
+- Adding test for the ResultSet class
+
+2013-03-20
+- Removal of unsupported minimum_number_should_match for Boolean Filter
+
+2013-02-25
+- Added Elastica\Bulk class responsible for performing bulk requests. New bulk requests implemented: Client::deleteDocuments(), Bulk::sendUdp()
+
+2013-02-20
+- Release candidate 0.20.5.0.RC1
+
+2013-02-14
+- Added factory for transports that is used by the Connection class
+- The transport instances now has support for parameters that can be injected by specifying an array as a transport when creating the Elastica client
+
+2013-02-08
+- Terms->setScript() Added, namespace Elastica\Facet
+
+2013-01-31
+- Removed deprecated method Type::getType()
+- Removed deprecated old constructor call in Filter\GeoDistance::__construct()
+- Removed deprecated method Filter\Script::setQuery()
+- Removed deprecated methods Query\QueryString::setTieBraker() and Query\QueryString::setQueryString()
+- Removed deprecated methods Query\Builder::minimumShouldMatch() and Query\Builder::tieBreaker()
+
+2013-01-25
+- Add get/set/has/remove methods to Document
+- Add magic methods __get/__set/__isset/__unset to Document
+- Document::add method became deprecated, use set instead
+- Populate document id created by elasticsearch on addDocument()/addDocuments() call if no document id was set
+- Populate updated fields in document on Client::updateDocument() call if fields options is set
+
+2013-01-24
+- Added serialization support. Objects can be added to elastica directly when a serializer callable is configured on \Elastica\Type
+
+2013-01-21
+- Added Thrift transport. Ir requires installing munkie/elasticsearch-thrift-php package and elasticsearch-tranport-thrift plugin should be installed in elastcisearch
+
+2013-01-13
+- Add version option to Elastica_Search::search
+- Remove compatibility for PHP 5.2
+- Changed all syntax using namespaces, in compliance with PSR-2.
+- Usage of composer for lib and test autoloading
+- Added PHPUnit as a dev dependency in composer.json
+- All tests were rewritten for new syntax.
+- All tests where moved in Elastica\Test namespace
+- All tests now inherit from Elastica\Test\Base
+- Removed all executable flags on files where not needed.
+- Update to elasticsearch 0.20.2
+- Refactored Elastica_Script and added it support in Elastica_Query_CustomFiltersScore, Elastica_Query_CustomScore and Elastica_Filter_Script
+- Refactored Elastica_Client::updateDocument() method to support partial document update. $data can be Elastic_Script, Elastic_Document or array.
+- Elastica_Type::updateDocument() now takes Elastica_Document instead of Elastica_Script (BC break). Script can be set to document to perform script update.
+
+2012-12-23
+- Elastica_Client config param "servers" to "connections" renamed. "headers" and "curl" are now a config param inside "connections"
+- Elastica_Connection added to allow connection management (enabled / disable)
+- Refactoring of Elastica_Request. Takes Elastica_Connection in constructor instead of Elastica_Client
+- Elastica_Transport refactored
+- Elastica_Log refactored
+- Renamed Elastica_Exception_Client to Elastica_Exception_Connection
+- Use Elastica_Connection for the following constants: DEFAULT_PORT, DEFAULT_HOST, DEFAULT_TRANSPORT, TIMEOUT
+
+2012-11-28
+- Added Elastica_Filter_GeoDistanceRange filter
+
+2012-11-23
+- Simplified Elastica_Document data handling by extending Elastica_Param
+
+2012-11-10
+- Added Elastica_Cluster_Health, Elastica_Cluster_Health_Index and Elastica_Cluster_Health_Shard which wrap the _cluster/health endpoint.
+- Added Elastica_Document::setId()
+- Added options parameter to Elastica_Type::getDocument()
+- Added Elastica_Query_Filtered::getFilter()
+
+2012-10-30
+- Elastica_Search implement Elastica_Searchable interface
+
+2012-10-28
+- Add Elastica_Filter_HasParent and Elastic_Query_HasParent
+
+2012-08-11
+- Release v0.19.8.0
+- Elastica_Query_Prefix added
+
+2012-07-26
+- Change Elastica_Filter_GeoDistance::__construct(), accepts geohash parameter (BC break, before: ($key, $latitude, $longitude, $distance), after: ($key, $location, $distance) where $location is array('lat' => $latitude, 'lon' => $longitude) or a geohash)
+
+2012-07-17
+- Changed naming for several methods to camelCase
+- Enforced PSR1 code style, as per https://github.com/pmjones/fig-standards/blob/psr-1-style-guide/proposed/PSR-1-basic.md
+- Added Elastica_Script::toArray
+- Added Elastica_ScriptFields
+- Elastica_Query::setScriptFields now takes Elastica_ScriptFields or associative array as argument, the old implementation was bogus.
+
+2012-06-24
+- Simplify Elastica_Type::search and Elastica_Index::search by using Elastica_Search
+- Implement Elastica_Filter_Abstract::setCache and Elastica_Filter_Abstract::setCacheKey
+- Add Elastica_Param::hasParam
+- Remove unsupported use of minimum number should match for Boolean Filter
+- Remove old style path creation through params in Elastica_Index::create and Elastica_Search::search
+
+2012-06-22
+- Add Elastica_Filter_Limit
+- Add getters+setters for Index Setting blocks 'read', 'write' and 'metadata'
+- Add Elastica_Filter_MatchAll
+
+2012-06-20
+- Facet scope added
+
+2012-06-09
+- Change $_parent to null to also support 0 for an id
+- Fix Elasitca_Document->toArray()
+
+2012-05-01
+- Release v0.19.3.0
+- MoreLikeThis Query in Elastica_Document
+- Add query param for request (allows GET params)
+
+2012-03-04
+- Node info call update. The receive os info and more, param is needed. By default, only basics are returned
+- Release v0.19.0.0 which is compatible with ES 0.19.0 https://www.elastic.co/downloads/past-releases/0-19-0
+
+2012-02-21
+- Allow percolate queries in bulk requests
+- Fix memory leak in curl requests
+
+2012-01-23
+- Packagist added http://packagist.org/
+
+2012-01-15
+- Vagrantfile for vagrant environment with elasticsearch added. Run: vagrant up
+
+2012-01-08
+- Allow to set curl params over client config [#106](https://github.com/ruflin/Elastica/issues/106/) [#107](https://github.com/ruflin/Elastica/issues/107/)
+- Add the possiblity to add path or url in config for a request [#120](https://github.com/ruflin/Elastica/issues/120/)
+
+2012-01-04
+- Elastica_Index::exists() and Elastica_Cluster::getIndexNames() added
+
+2012-01-01
+- Elastica_Cluster_Settings added
+- Read only feature for cluster and index added. This feature is elasticsearch >0.19.0 only. ES 0.19.0 release is not out yet
+
+2011-12-29
+- Elastica_Type::deleteByQuery implemented
+
+2011-12-20
+- Release v0.18.6.0
+
+2011-12-19
+- Percolator for Type and Documents added
+
+2011-12-06
+- Elastica_Percolator added. See tests for more details
+
+2011-12-02
+- Rename Elastica_Type::getType() to Elastica_Type::getName(), getType() is now deprecated
+
+2011-12-01
+- Elastica_Filter_Term::addTerm renamed to setTerm, Elastica_Filter_Term::setTerm renamed to setRawTerm
+- Elastica_Query_Term::addTerm renamed to setTerm, Elastica_Query_Term::setTerm renamed to setRawTerm
+
+2011-11-30
+- Release v0.18.5.0
+
+2011-11-28
+- Elastica_Filter_Nested added
+
+2011-11-26
+- Elastica_Search::addIndices(), Elastica_Search::addTypes() added
+
+2011-11-20
+- Release v0.18.4.1
+- Elastica_Log added for logging. Has to be passed as client config to enable
+- Elastica blogging introduced: http://ruflin.com/en/elastica
+
+2011-11-17
+- Release v0.18.4.0
+- Support for Travis CI added: http://travis-ci.org/ruflin/Elastica
+
+2011-11-07
+- Elastica_Index_Stats added
+
+2011-11-05
+- Elastica_Query_Nested added
+
+2011-10-29
+- TTL for document and mapping added
+
+2011-10-28
+- Refactored Elastica_Query_CustomScore::addCSParam to ::addParams
+- Rename Elastica_Query_CustomScore::addParam to ::addCSParam
+- Release v0.18.1.0
+
+2011-10-20
+- Release v0.17.9.0
+- Elastica_Filter_Type added
+
+2011-10-19
+- Elastica_Query_CustomFilterScore added
+
+2011-10-15
+- API Documentation changed to DocBlox
+
+2011-10-10
+- Bug fixing
+- Release v0.17.8.0 added
+
+2011-09-19
+- Release v0.17.7.0 added
+- Release v0.17.6.1 added
+
+2011-09-18
+- Elastica_Exception_ExpectedFieldNotFound renamed to Elastica_Exception_NotFound
+
+2011-08-25
+- Https transport layer added
+
+2011-08-22
+- Typo in Terms query fixed (issue [#74](https://github.com/ruflin/Elastica/issues/74/))
+
+2011-08-15
+- Refactoring HTTP connection to keep alive connection -> speed improvement during using the same client
+- Release v0.17.6.0 added
+
+2011-08-09
+- Automatic creation of id for documents added. This was more a bug
+- Release v0.17.4.0 added
+
+2011-08-08
+- Elastica_Query_Text added
+- Params (constructor) of Elastica_Filter_GeoBoundingBox changed (array instead of single params)
+
+2011-08-07
+- Elastica_Query_MoreLikeThis added by @juneym. Still work under progress
+- Refactoring Queries and Filters to use Elastica_Param. Adding tests
+
+2011-08-05
+- Elastica_Filter_Abstract enhanced for more general usage (set/get/addParam(s)) added
+
+2011-08-04
+- Release v0.17.3.0 added
+- Elastica_Index_Settings::set/get response updated. get('...') does not require 'index.' in front anymore
+- Nodes and Cluster shutdown added
+- Elastica_Node::getIp() and getPort() added
+
+2011-07-30
+- Readd merge_factor to settings. Now working as expected. Index has to be closed first.
+
+2011-07-29
+- Release tag v0.17.2.0 added. Elastica is compatible with elasticsearch 0.17.2
+
+2011-07-22
+- Elastica_Index_Settings::getMergePolicyMergeFactor and set removed because of enhanced merge policy implementation in ES 0.17.0 https://github.com/elasticsearch/elasticsearch/issues/998
+- Release tav v0.17.1.0 added
+
+2011-07-21
+- Elastica_Query_HasChild and _parent feature added by fabian
+- Elastica_Filter_GeoBoundingBox added by fabian
+
+2011-07-20
+- Elastica_Query_Builder added by chrisdegrim
+
+2011-07-19
+- Release tag v0.17.0.0 added. Elastica is compatible with elasticsearch 0.17.0
+
+2011-07-18
+- ResultSet::hasFacets added
+- QueryString useDisMax added
+
+2011-07-15
+- Facet/DateHistogram and Facet/Historgram added
+- Documentation pages added unter http://ruflin.github.com/Elastica
+- Release tag v0.16.4.0 added
+
+2011-06-19
+- Add support for multiple servers to Elastica_Client (issue [#39](https://github.com/ruflin/Elastica/issues/39/))
+
+2011-06-16
+- Support for multiple index, type queries and _all queries added through Elastica_Search object
+- Elastica_Index::clearCache added to clean cache
+- Elastica_Index::flush added
+
+2011-06-07
+- Elastica_Index::setNumberOfShards removed as not supported after creating index
+
+2011-05-11
+- Refactor client constructor. Elastica_Client::__construct(array $config) now takes a config array instead of host and port
+
+2011-05-08
+- Elastica_Query_QueryString::escapeTerm move to Elastica_Util::escapeTerm
+
+2011-04-29
+- Added getParam to Elastica_Result that more values can be retrieved from the hit array
+- Elastica_Filter_Ids added http://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-ids-filter.html
+- getMergePolicyMergeFactor and getRefreshInterval to Elastica_Type_Settings added. If no value is set, default values are returned
+
+2011-04-28
+- Release of version 0.16.0.0 (see new version naming structure in README)
+
+2011-04-27
+- Refactoring of Elastica_Type::setMapping. No source parameter anymore.
+- Elastica_Type_Mapping object introduced to set more fine grained mapping
+
+2011-04-17
+- Elastica_Filter_Exists added
+
+2011-04-14
+- Elastica_Type getCount replace by count()
+- Count has now optional query parametere
+
+2011-04-01
+- Renaming of functions in Elastica_Query_Terms and Ela-stica_Query_Filter to fit new naming convention. setTerms, addTerm have different API now!
+
+2011-03-31
+- Deprecated code removed
+- Break backward compatibility to 0.15.1 (versions introduced by wlp1979)
+
+2011-03-30
+- Filtered query introduced
+- setRawArguments in Elastica_Query is now setParam
+- open / close for index added
+- Remove Elastica_Filter and Elastica_Facets because not needed anymore
+
+2011-03-29
+- Renaming Elastica_Filter->addQuery, addFilter to setQuery, setFilter
+- Add parts of Facets API
+- Add facet Terms
+- Renaming Elastica_Query->addFilter to setFilter
+
+2011-03-24
+- Renaming of Elastica_Status_Index to Elastica_Index_Status => API Change!
+- IndexSettings added for improved bulk updating http://www.elastic.co/guide/en/elasticsearch/reference/current/indices-update-settings.html
+
+2011-03-21
+- Node object added
+- Node_Info and Node_Stats added
+- Refactoring of Cluster object
+
+2011-03-13
+- changes.txt introduced
+- getResponse in Elastica_Response renamed to getData. getResponse now deprecated
+- Index status objects added
+- getIndexName in Elastica_Index renamed to getName. getIndexName is deprecated
diff --git a/vendor/ruflin/elastica/CONTRIBUTING.md b/vendor/ruflin/elastica/CONTRIBUTING.md
new file mode 100644
index 00000000..aff25716
--- /dev/null
+++ b/vendor/ruflin/elastica/CONTRIBUTING.md
@@ -0,0 +1,75 @@
+Contributing
+============
+Help is very welcomed. Code contributions must be done in respect of [PSR-2](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-2-coding-style-guide.md).
+More details on how to contribute and guidelines for [pull requests](http://elastica.io/contribute/pull-request.html) can be found [here](http://elastica.io/contribute/).
+
+See [Coding guidelines](http://elastica.io/contribute/coding-guidelines.html) for tips on how to do so.
+All changes must be documented in the [CHANGELOG.md](https://github.com/ruflin/Elastica/blob/master/CHANGELOG.md).
+
+
+Issues
+------
+* Bugs & Feature requests: If you found a bug, open an issue on [Github](https://github.com/ruflin/Elastica/issues). Please search for already reported similary issues before opening a new one. You should include code examples (with dependencies if needed) and your Elastica version to the issue description.
+* Questions & Problems: If you have questions or a specific problem, use the [Elastica Gitter](https://gitter.im/ruflin/Elastica) Chat or open an issue on [Stackoverflow](http://stackoverflow.com/questions/tagged/elastica). Make sure to assign the tag Elastica.
+
+
+Setup
+-----
+Elastica currently allows two setups for development. Either through vagrant or docker-compose. To use the vagrant environment, run `vagrant up`. To use the docker environment, check out the Makefile for the necessary commands.
+* Run your changes / tests in the virtual environment to make sure it is reproducible.
+* Run the tests before creating the pull request using vagrant or docker-compose locally.
+
+Commands
+--------
+To run the commands below, you must have docker-compose [installed](https://docs.docker.com/compose/install/). The first time the commands are run it takes some time to download all the partial images. Form then on the commands should run very fast. The advantage in using the commands below is that no local tools and libraries have to be installed and it is guaranteed that everytone is using the same tools.
+
+## Run Tests
+
+To run all tests inside the docker environment, run the following command:
+
+```
+make run RUN="make phpunit"
+```
+
+If you want to run just a specific test or a one specific file, run the following command by replacing your file with the existingpath:
+
+```
+ make run RUN="phpunit -c ./test lib/Elastica/Test/SearchTest.php"
+```
+
+## Check style of your code
+This command will call php-cs-fixer with the predefined settings for the elastica project. No local setup of the tools is needed as everything will happen directly in the container.
+```
+make run RUN="make lint"
+```
+
+
+
+
+Coding
+------
+
+### Rules
+* Pull requests are made to master. Changes are never pushed directly (without pull request) into master.
+* We use the Forking Workflow. https://www.atlassian.com/git/tutorials/comparing-workflows/forking-workflow
+* Follow the coding guidelines.
+* Use a feature branch for every pull request. Don't open a pull request from your master branch.
+
+### Pull Requests
+* One change per pull requests: Keep your pull requests as small as possible. Only one change should happen per pull request. This makes it easier to review and provided feedback. If you have a large pull request, try to split it up in multiple smaller requests.
+* Commit messages: Make sure that your commit messages have meaning and provide an understanding on what was changed without looking at the code.
+* Pull requests should be opened as early as possible as pull requests are also here for communication / discussing changes. Add a comment when your pull request is ready to be merged.
+* Tests: Your addition / change must be tested and the builds must be green. Test your changes locally. Add unit tests and if possible functional tests. Don't forget to add the group to your tests. The 4 available groups are @functional, @unit, @shutdown, @benchmark
+* Update the CHANGELOG.md file with your changes
+* Backward Compatibility breaks: In case you break backward compatibility, provide details on why this is needed.
+* Merge: No one should ever merge his own pull request
+
+
+### Name Spaces & Classes
+Most name spaces and classes are self explanotary and use cases can be taken from classes which already exist.
+
+#### Tool Namespace
+The namespace Tool is used for making more complex functionality of Elastica available to the users. In general it maps existing functionality of Elastica and offers simplified functions.
+
+#### Util Class
+The util class is used for all static functions which are used in the Elastica library but don't access the library itself.
diff --git a/vendor/ruflin/elastica/Dockerfile b/vendor/ruflin/elastica/Dockerfile
new file mode 100644
index 00000000..c5055c5e
--- /dev/null
+++ b/vendor/ruflin/elastica/Dockerfile
@@ -0,0 +1,58 @@
+# PHP 6 Docker file with Composer installed
+FROM composer/composer
+
+RUN apt-get update
+RUN apt-get upgrade -y
+RUN apt-get install -y nano
+RUN apt-get install -y cloc
+
+# XSL and Graphviz for PhpDocumentor
+RUN apt-get install -y php5-xsl
+# TODO: Debian is putting the xsl extension in a different directory, should be in: /usr/local/lib/php/extensions/no-debug-non-zts-20131226
+RUN echo "extension=/usr/lib/php5/20131226/xsl.so" >> /usr/local/etc/php/conf.d/xsl.ini
+RUN apt-get install -y graphviz
+
+
+RUN echo "date.timezone=UTC" >> /usr/local/etc/php/conf.d/timezone.ini
+
+# Xdebug for coverage report
+RUN apt-get install -y php5-xdebug
+RUN echo "zend_extension=/usr/lib/php5/20131226/xdebug.so" >> /usr/local/etc/php/conf.d/xdebug.ini
+
+# Memcache
+RUN apt-get install -y php5-memcache
+RUN echo "extension=/usr/lib/php5/20131226/memcache.so" >> /usr/local/etc/php/conf.d/memcache.ini
+
+# Add composer bin to the environment
+ENV PATH=/root/composer/vendor/bin:$PATH
+
+# Overcome github access limits. GITHUB_OAUTH_TOKEN environment variable must be set with private token
+RUN composer self-update
+
+# Install development tools
+RUN composer global require "phpunit/phpunit=~4.7"
+RUN composer global require "pdepend/pdepend=~2.0"
+RUN composer global require "phpmd/phpmd=~2.2"
+RUN composer global require "mayflower/php-codebrowser=~1.1"
+RUN composer global require "sebastian/phpcpd=~2.0"
+RUN composer global require "squizlabs/php_codesniffer=~2.3"
+RUN composer global require "phploc/phploc=~2.1"
+RUN composer global require "fabpot/php-cs-fixer=1.8.1"
+
+
+# Documentor dependencies
+RUN composer global require "phpdocumentor/template-zend=~1.3"
+RUN composer global require "phpdocumentor/phpdocumentor=~2.8"
+
+# Install depdencies
+WORKDIR /app
+COPY composer.json /app/
+RUN composer install
+
+# Guzzle is not included composer.json because of PHP 5.3
+RUN composer require "guzzlehttp/guzzle=~6.0"
+
+ENTRYPOINT []
+
+ENV ES_HOST elasticsearch
+ENV PROXY_HOST nginx
diff --git a/vendor/ruflin/elastica/LICENSE.txt b/vendor/ruflin/elastica/LICENSE.txt
new file mode 100644
index 00000000..21580de7
--- /dev/null
+++ b/vendor/ruflin/elastica/LICENSE.txt
@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) 2014 Nicolas Ruflin
+
+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. \ No newline at end of file
diff --git a/vendor/ruflin/elastica/Makefile b/vendor/ruflin/elastica/Makefile
new file mode 100644
index 00000000..c033784b
--- /dev/null
+++ b/vendor/ruflin/elastica/Makefile
@@ -0,0 +1,108 @@
+#/bin/bash
+
+BASEDIR = $(shell pwd)
+SOURCE = "${BASEDIR}/lib"
+IMAGE = "elastica"
+
+
+### Setups around project sources. These commands should run ###
+init: prepare
+ composer install
+
+prepare:
+ mkdir -p ${BASEDIR}/build/api
+ mkdir -p ${BASEDIR}/build/code-browser
+ mkdir -p ${BASEDIR}/build/coverage
+ mkdir -p ${BASEDIR}/build/logs
+ mkdir -p ${BASEDIR}/build/docs
+ mkdir -p ${BASEDIR}/build/pdepend
+
+update: init
+
+clean:
+ rm -r -f ${BASEDIR}/build
+ #rm ${BASEDIR}/cache.properties
+
+
+# Handling virtual environment
+
+build:
+ docker-compose build
+
+setup: build
+ docker-compose scale elasticsearch=3
+
+start:
+ docker-compose up
+
+stop:
+ docker-compose stop
+
+destroy: clean
+ docker-compose kill
+ docker-compose rm
+
+# Runs commands inside virtual environemnt. Example usage inside docker: make run RUN="make phpunit"
+run:
+ docker-compose run elastica $(RUN)
+
+
+### Quality checks / development tools ###
+
+checkstyle:
+ phpcs --standard=PSR2 ${SOURCE}
+
+checkstyle-ci: prepare
+ phpcs --report=checkstyle --report-file=${BASEDIR}/build/logs/checkstyle.xml --standard=PSR2 ${SOURCE} > /dev/null
+
+code-browser: prepare
+ phpcb --log ${BASEDIR}/build/logs --source ${SOURCE} --output ${BASEDIR}/build/code-browser
+
+# Copy paste detector
+cpd: prepare
+ phpcpd --log-pmd ${BASEDIR}/build/logs/pmd-cpd.xml ${SOURCE}
+
+messdetector: prepare
+ phpmd ${SOURCE} text codesize,unusedcode,naming,design ${BASEDIR}/build/phpmd.xml
+
+messdetector-ci: prepare
+ phpmd ${SOURCE} xml codesize,unusedcode,naming,design --reportfile ${BASEDIR}/build/logs/pmd.xml
+
+dependencies: prepare
+ pdepend --jdepend-xml=${BASEDIR}/build/logs/jdepend.xml \
+ --jdepend-chart=${BASEDIR}/build/pdepend/dependencies.svg \
+ --overview-pyramid=${BASEDIR}/build/pdepend/overview-pyramid.svg \
+ ${SOURCE}
+
+phpunit: prepare
+ phpunit -c test/ --coverage-clover build/coverage/unit-coverage.xml --group unit
+ phpunit -c test/ --coverage-clover build/coverage/functional-coverage.xml --group functional
+ phpunit -c test/ --coverage-clover build/coverage/shutdown-coverage.xml --group shutdown
+
+doc: prepare
+ phpdoc run -d lib/ -t build/docs
+
+# Uses the preconfigured standards in .php_cs
+lint:
+ php-cs-fixer fix
+
+syntax-check:
+ php -lf ${SOURCE} **/*.php
+ php -lf ${BASEDIR}/test **/*.php
+
+
+loc:
+ cloc --by-file --xml --exclude-dir=build -out=build/cloc.xml .
+
+phploc:
+ phploc --log-csv $(BASEDIR)/build/logs/phploc.csv $(SOURCE)
+
+
+
+# Visualise repo
+gource:
+ gource --log-format git \
+ --seconds-per-day 0.1 \
+ --title 'Elastica (https://github.com/ruflin/Elastica)' \
+ --user-scale 1 \
+ --max-user-speed 50
diff --git a/vendor/ruflin/elastica/README.md b/vendor/ruflin/elastica/README.md
new file mode 100644
index 00000000..b6cf5376
--- /dev/null
+++ b/vendor/ruflin/elastica/README.md
@@ -0,0 +1,31 @@
+Elastica: elasticsearch PHP Client
+==================================
+
+[![Latest Stable Version](https://poser.pugx.org/ruflin/Elastica/v/stable.png)](https://packagist.org/packages/ruflin/elastica)
+[![Build Status](https://secure.travis-ci.org/ruflin/Elastica.png?branch=master)](http://travis-ci.org/ruflin/Elastica)
+[![codecov.io](http://codecov.io/github/ruflin/Elastica/coverage.svg?branch=master)](http://codecov.io/github/ruflin/Elastica?branch=master)
+[![Dependency Status](https://www.versioneye.com/php/ruflin:elastica/dev-master/badge.svg)](https://www.versioneye.com/php/ruflin:elastica/dev-master)
+[![Scrutinizer Code Quality](https://scrutinizer-ci.com/g/ruflin/Elastica/badges/quality-score.png?b=master)](https://scrutinizer-ci.com/g/ruflin/Elastica/?branch=master)
+[![Total Downloads](https://poser.pugx.org/ruflin/Elastica/downloads.png)](https://packagist.org/packages/ruflin/elastica)
+[![Flattr this git repo](http://api.flattr.com/button/flattr-badge-large.png)](https://flattr.com/submit/auto?user_id=ruflin&url=https://github.com/ruflin/Elastica&title=Elastica&language=PHP&tags=github&category=software)
+[![Join the chat at https://gitter.im/ruflin/Elastica](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/ruflin/Elastica?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
+
+All documentation for Elastica can be found under [Elastica.io](http://Elastica.io/).
+If you have questions, don't hesitate to ask them on [Stackoverflow](http://stackoverflow.com/questions/tagged/elastica) and add the Tag "Elastica" or
+in our [Gitter](https://gitter.im/ruflin/Elastica) channel.
+All library issues should go to the [issue tracker from github](https://github.com/ruflin/Elastica/issues).
+
+Contributing
+------------
+Contributions are always welcome. For details on how to contribute, check the [CONTRIBUTING](https://github.com/ruflin/Elastica/blob/master/CONTRIBUTING.md) file.
+
+Dependencies
+------------
+| Project | Version | Required |
+|---------|---------|----------|
+|[Elasticsearch](https://github.com/elasticsearch/elasticsearch/tree/v1.6.0)|1.6.0|yes|
+|[Elasticsearch mapper attachments plugin](https://github.com/elasticsearch/elasticsearch-mapper-attachments/tree/v2.6.0)|2.6.0|no|
+|[Elasticsearch thrift transport plugin](https://github.com/elasticsearch/elasticsearch-transport-thrift/tree/v2.6.0)|2.6.0|no|
+|[Elasticsearch memcached transport plugin](https://github.com/elastic/elasticsearch-transport-memcached/tree/v2.6.0)|2.6.0|no|
+|[Elasticsearch geocluster facet plugin](https://github.com/zenobase/geocluster-facet/tree/0.0.12)|0.0.12|no|
+|[Elasticsearch image plugin](https://github.com/SibaTokyo/elasticsearch-image/tree/1.4.0)|1.4.0|no|
diff --git a/vendor/ruflin/elastica/Vagrantfile b/vendor/ruflin/elastica/Vagrantfile
new file mode 100644
index 00000000..2deebbd4
--- /dev/null
+++ b/vendor/ruflin/elastica/Vagrantfile
@@ -0,0 +1,18 @@
+
+Vagrant.require_version ">= 1.4.0"
+
+Vagrant.configure("2") do |config|
+
+ config.vm.box = "ubuntu/precise32"
+
+ config.vm.network :private_network, ip: "10.10.10.10"
+
+ config.vm.provision "shell" do |sh|
+ sh.inline = "/bin/bash /vagrant/ansible/provision.sh"
+ end
+
+ config.vm.provider :virtualbox do |vb|
+ vb.customize ["modifyvm", :id, "--memory", "1024"]
+ end
+
+end
diff --git a/vendor/ruflin/elastica/ansible/es-playbook.yml b/vendor/ruflin/elastica/ansible/es-playbook.yml
new file mode 100644
index 00000000..3a471b64
--- /dev/null
+++ b/vendor/ruflin/elastica/ansible/es-playbook.yml
@@ -0,0 +1,20 @@
+---
+
+- name: Create a virtual machine
+ connection: local
+ hosts: localhost
+ sudo: true
+ vars:
+ - ES_VER: "1.6.0"
+ - ES_SHORT_VER: "1.6"
+ - ES_MAPPER_ATTACHMENTS_VER: "2.6.0"
+ - ES_TRANSPORT_MEMCACHED_VER: "2.6.0"
+ - ES_TRANSPORT_THRIFT_VER: "2.6.0"
+ - ES_GEOCLUSTER_FACET_VER: "0.0.12"
+ - ES_IMAGE_PLUGIN_VER: "1.4.0"
+ - ES_PROJECT_ROOT: "{{ lookup('env', 'ES_PROJECT_ROOT') }}"
+ roles:
+ - base
+ - elasticsearch
+ - nginx
+ - php
diff --git a/vendor/ruflin/elastica/ansible/provision.sh b/vendor/ruflin/elastica/ansible/provision.sh
new file mode 100644
index 00000000..6ea8e575
--- /dev/null
+++ b/vendor/ruflin/elastica/ansible/provision.sh
@@ -0,0 +1,63 @@
+#!/bin/bash
+
+set -o xtrace
+
+install_ansible() {
+ sudo apt-get update
+ sudo apt-get install python python-pip python-dev -y
+ sudo pip install ansible==1.8.2
+ sudo mkdir -p /etc/ansible/
+ echo "localhost" | sudo tee /etc/ansible/hosts
+}
+
+run_playbook() {
+ # Write to stdout directly
+ export PYTHONUNBUFFERED=1
+
+ # No cows >_<
+ export ANSIBLE_NOCOWS=1
+
+ # Root of git repo
+ if [ -z "$ES_PROJECT_ROOT" ]; then
+ export ES_PROJECT_ROOT="$(dirname $(dirname $(readlink -f $0)))"
+ fi
+
+ if [ ! -x $(which ansible-playbook) ]; then
+ echo "Ansible is not installed"
+ return 1
+ fi
+
+ ansible-playbook $ES_PROJECT_ROOT/ansible/es-playbook.yml -v | tee /tmp/ansible-playbook-progress
+
+ if grep -q "FATAL\|ERROR" /tmp/ansible-playbook-progress; then
+ return 1
+ fi
+}
+
+check_cluster() {
+ curl -m 5 -s -o /dev/null "http://localhost:9200" &&
+ curl -m 5 -s -o /dev/null "http://localhost:9201"
+ return $?
+}
+
+travis_retry() {
+ # We don't use builtin Travis CI function, because this script is also used for vagrant provision.
+ # But main idea of restarts is so simple, so lets override it without name change.
+
+ $@ && return 0
+
+ echo "The command $@ failed. Retrying, 2 of 3"
+ sleep 60s && $@ && return 0
+
+ echo "The command $@ failed. Retrying, 3 of 3"
+ sleep 60s && $@ && return 0
+
+ echo "The command $@ failed."
+ return 1
+}
+
+travis_retry install_ansible || exit 1
+
+travis_retry run_playbook || exit 1
+
+travis_retry check_cluster || exit 1
diff --git a/vendor/ruflin/elastica/ansible/roles/base/tasks/main.yml b/vendor/ruflin/elastica/ansible/roles/base/tasks/main.yml
new file mode 100644
index 00000000..061b8155
--- /dev/null
+++ b/vendor/ruflin/elastica/ansible/roles/base/tasks/main.yml
@@ -0,0 +1,13 @@
+---
+
+- name: install base packages
+ apt: >
+ force=yes
+ name={{ item }}
+ state=present
+ update_cache=no
+ with_items:
+ - curl
+ - git
+ - htop
+ - vim
diff --git a/vendor/ruflin/elastica/ansible/roles/elasticsearch/handlers/main.yml b/vendor/ruflin/elastica/ansible/roles/elasticsearch/handlers/main.yml
new file mode 100644
index 00000000..97cccdd2
--- /dev/null
+++ b/vendor/ruflin/elastica/ansible/roles/elasticsearch/handlers/main.yml
@@ -0,0 +1,6 @@
+---
+
+- name: restart elasticsearch
+ service: >
+ name=elasticsearch
+ state=restarted
diff --git a/vendor/ruflin/elastica/ansible/roles/elasticsearch/tasks/main.yml b/vendor/ruflin/elastica/ansible/roles/elasticsearch/tasks/main.yml
new file mode 100644
index 00000000..c2041343
--- /dev/null
+++ b/vendor/ruflin/elastica/ansible/roles/elasticsearch/tasks/main.yml
@@ -0,0 +1,101 @@
+---
+
+- name: import ppa:webupd8team/java gpg key
+ apt_key: >
+ id=EEA14886
+ keyserver=keyserver.ubuntu.com
+ state=present
+
+- name: add ppa:webupd8team/java repository
+ apt_repository: >
+ repo="deb http://ppa.launchpad.net/webupd8team/java/ubuntu precise main"
+ state=present
+ update_cache=yes
+
+- name: accept oracle license
+ shell: >
+ echo "oracle-java7-installer shared/accepted-oracle-license-v1-1 select true" | debconf-set-selections
+
+- name: install java
+ apt: >
+ force=yes
+ name={{ item }}
+ state=present
+ update_cache=no
+ with_items:
+ - oracle-java7-installer
+ - oracle-java7-set-default
+
+- name: import elasticsearch gpg key
+ apt_key: >
+ id=D88E42B4
+ url=https://packages.elasticsearch.org/GPG-KEY-elasticsearch
+ state=present
+
+- name: add elasticsearch repository
+ apt_repository: >
+ repo="deb http://packages.elasticsearch.org/elasticsearch/{{ ES_SHORT_VER }}/debian stable main"
+ state=present
+ update_cache=yes
+
+- name: install elasticsearch
+ apt: >
+ force=yes
+ name=elasticsearch={{ ES_VER }}
+ state=present
+ update_cache=no
+
+- name: install image plugin
+ command: >
+ creates=/usr/share/elasticsearch/plugins/image
+ /usr/share/elasticsearch/bin/plugin --url https://github.com/SibaTokyo/elasticsearch-image/releases/download/{{ ES_IMAGE_PLUGIN_VER }}/elasticsearch-image-{{ ES_IMAGE_PLUGIN_VER }}.zip -install image
+
+- name: install mapper-attachments plugin
+ command: >
+ creates=/usr/share/elasticsearch/plugins/mapper-attachments
+ /usr/share/elasticsearch/bin/plugin -install elasticsearch/elasticsearch-mapper-attachments/{{ ES_MAPPER_ATTACHMENTS_VER }}
+
+- name: install geocluster-facet plugin
+ command: >
+ creates=/usr/share/elasticsearch/plugins/geocluster-facet
+ /usr/share/elasticsearch/bin/plugin -install geocluster-facet --url https://github.com/zenobase/geocluster-facet/releases/download/{{ ES_GEOCLUSTER_FACET_VER }}/geocluster-facet-{{ ES_GEOCLUSTER_FACET_VER }}.jar
+
+- name: install transport-thrift plugin
+ command: >
+ creates=/usr/share/elasticsearch/plugins/transport-thrift
+ /usr/share/elasticsearch/bin/plugin -install elasticsearch/elasticsearch-transport-thrift/{{ ES_TRANSPORT_THRIFT_VER }}
+
+- name: install transport-memcached plugin
+ command: >
+ creates=/usr/share/elasticsearch/plugins/transport-memcached
+ /usr/share/elasticsearch/bin/plugin -install elasticsearch/elasticsearch-transport-memcached/{{ ES_TRANSPORT_MEMCACHED_VER }}
+
+- name: remove default config
+ file: >
+ path={{ item }}
+ state=absent
+ with_items:
+ - /etc/default/elasticsearch
+ - /etc/elasticsearch/elasticsearch.yml
+
+- name: create custom config
+ template: >
+ dest=/etc/elasticsearch/{{ item }}
+ src={{ item }}
+ with_items:
+ - config-0.yml
+ - config-1.yml
+ - logging.yml
+ notify: restart elasticsearch
+
+- name: create elasticsearch service script
+ template: >
+ dest=/etc/init.d/elasticsearch
+ src=elasticsearch.service
+ notify: restart elasticsearch
+
+- name: start elasticsearch
+ service: >
+ enabled=yes
+ name=elasticsearch
+ state=started
diff --git a/vendor/ruflin/elastica/ansible/roles/elasticsearch/templates/config-0.yml b/vendor/ruflin/elastica/ansible/roles/elasticsearch/templates/config-0.yml
new file mode 100644
index 00000000..aa956910
--- /dev/null
+++ b/vendor/ruflin/elastica/ansible/roles/elasticsearch/templates/config-0.yml
@@ -0,0 +1,10 @@
+{% extends "config-default.yml" %}
+
+{% block config %}
+
+http.port: 9200
+transport.tcp.port: 9300
+thrift.port: 9500
+memcached.port: 11211
+
+{% endblock %}
diff --git a/vendor/ruflin/elastica/ansible/roles/elasticsearch/templates/config-1.yml b/vendor/ruflin/elastica/ansible/roles/elasticsearch/templates/config-1.yml
new file mode 100644
index 00000000..a54d719e
--- /dev/null
+++ b/vendor/ruflin/elastica/ansible/roles/elasticsearch/templates/config-1.yml
@@ -0,0 +1,10 @@
+{% extends "config-default.yml" %}
+
+{% block config %}
+
+http.port: 9201
+transport.tcp.port: 9301
+thrift.port: 9501
+memcached.port: 11212
+
+{% endblock %}
diff --git a/vendor/ruflin/elastica/ansible/roles/elasticsearch/templates/config-default.yml b/vendor/ruflin/elastica/ansible/roles/elasticsearch/templates/config-default.yml
new file mode 100644
index 00000000..0917f244
--- /dev/null
+++ b/vendor/ruflin/elastica/ansible/roles/elasticsearch/templates/config-default.yml
@@ -0,0 +1,40 @@
+{% block default_config %}
+
+index.number_of_shards: 2
+index.number_of_replicas: 0
+
+# Dont write data to hdd in tests
+index.store.type: memory
+
+# Required plugins
+plugin.mandatory: mapper-attachments, geocluster-facet, transport-thrift, transport-memcached, image
+
+# For bulk tests
+bulk.udp.enabled: true
+bulk.udp.bulk_actions: 5
+
+# For script tests
+script.inline: on
+script.indexed: on
+
+# Disable dynamic memory allocation
+bootstrap.mlockall: true
+
+# Dont accept connections not from localhost
+network.host: "127.0.0.1"
+
+# Limit threadpool by set number of available processors to 1
+# Without this, travis builds will be failed with OutOfMemory error
+processors: 1
+
+# All nodes will be called Elastica
+node.name: Elastica
+
+# Added for snapshot tests
+path.repo: ["/tmp/test_register", "/tmp/test_repository"]
+
+{% endblock %}
+
+{% block config %}
+# Node specific config should be overwritten in child template
+{% endblock %}
diff --git a/vendor/ruflin/elastica/ansible/roles/elasticsearch/templates/elasticsearch.service b/vendor/ruflin/elastica/ansible/roles/elasticsearch/templates/elasticsearch.service
new file mode 100644
index 00000000..0268e230
--- /dev/null
+++ b/vendor/ruflin/elastica/ansible/roles/elasticsearch/templates/elasticsearch.service
@@ -0,0 +1,229 @@
+#!/bin/sh
+#
+# /etc/init.d/elasticsearch -- startup script for Elasticsearch
+#
+# Written by Miquel van Smoorenburg <miquels@cistron.nl>.
+# Modified for Debian GNU/Linux by Ian Murdock <imurdock@gnu.ai.mit.edu>.
+# Modified for Tomcat by Stefan Gybas <sgybas@debian.org>.
+# Modified for Tomcat6 by Thierry Carrez <thierry.carrez@ubuntu.com>.
+# Additional improvements by Jason Brittain <jason.brittain@mulesoft.com>.
+# Modified by Nicolas Huray for Elasticsearch <nicolas.huray@gmail.com>.
+# Modified by Igor Denisenko for Elastica <im.denisenko@yahoo.com>
+#
+### BEGIN INIT INFO
+# Provides: elasticsearch
+# Required-Start: $network $remote_fs $named
+# Required-Stop: $network $remote_fs $named
+# Default-Start: 2 3 4 5
+# Default-Stop: 0 1 6
+# Short-Description: Starts elasticsearch
+# Description: Starts elasticsearch using start-stop-daemon
+### END INIT INFO
+
+PATH="/bin:/usr/bin:/sbin:/usr/sbin"
+NAME="elasticsearch"
+DESC="Elasticsearch Server"
+
+if [ `id -u` -ne 0 ]; then
+ echo "You need root privileges to run this script"
+ exit 1
+fi
+
+
+. /lib/lsb/init-functions
+
+if [ -r /etc/default/rcS ]; then
+ . /etc/default/rcS
+fi
+
+
+# Run Elasticsearch as this user ID and group ID
+ES_USER="elasticsearch"
+ES_GROUP="elasticsearch"
+
+# The first existing directory is used for JAVA_HOME (if JAVA_HOME is not defined)
+JDK_DIRS="/usr/lib/jvm/java-8-oracle/ /usr/lib/jvm/j2sdk1.8-oracle/ /usr/lib/jvm/jdk-7-oracle-x64 /usr/lib/jvm/java-7-oracle /usr/lib/jvm/j2sdk1.7-oracle/ /usr/lib/jvm/java-7-openjdk /usr/lib/jvm/java-7-openjdk-amd64/ /usr/lib/jvm/java-7-openjdk-armhf /usr/lib/jvm/java-7-openjdk-i386/ /usr/lib/jvm/default-java"
+
+# Look for the right JVM to use
+for jdir in $JDK_DIRS; do
+ if [ -r "$jdir/bin/java" -a -z "${JAVA_HOME}" ]; then
+ JAVA_HOME="$jdir"
+ fi
+done
+export JAVA_HOME
+
+# Directory where the Elasticsearch binary distribution resides
+ES_HOME="/usr/share/$NAME"
+
+# Heap size defaults to 256m min, 1g max
+# Be modest. Entire cluster will allocate (3*ES_HEAP_SIZE) memory
+ES_HEAP_SIZE="256m"
+export ES_HEAP_SIZE
+
+# Heap new generation
+# ES_HEAP_NEWSIZE=
+# export ES_HEAP_NEWSIZE
+
+# max direct memory
+# ES_DIRECT_SIZE=
+# export ES_DIRECT_SIZE
+
+# Additional Java OPTS
+ES_JAVA_OPTS="-server"
+export ES_JAVA_OPTS
+
+# Maximum number of open files
+MAX_OPEN_FILES="65535"
+
+# Maximum amount of locked memory
+MAX_LOCKED_MEMORY="unlimited"
+
+# Elasticsearch log directory
+LOG_DIR="/var/log/$NAME"
+
+# Elasticsearch data directory
+DATA_DIR="/var/lib/$NAME"
+
+# Elasticsearch work directory
+WORK_DIR="/tmp/$NAME"
+
+# Elasticsearch configuration directory
+CONF_DIR="/etc/$NAME"
+
+# Define other required variables
+DAEMON="$ES_HOME/bin/elasticsearch"
+
+# Check DAEMON exists
+if [ ! -x $DAEMON ]; then
+ exit 0
+fi
+
+checkJava() {
+ if [ -x "$JAVA_HOME/bin/java" ]; then
+ JAVA="$JAVA_HOME/bin/java"
+ else
+ JAVA=`which java`
+ fi
+
+ if [ ! -x "$JAVA" ]; then
+ echo "Could not find any executable java binary. Please install java in your PATH or set JAVA_HOME"
+ exit 1
+ fi
+}
+
+case "$1" in
+ start)
+ checkJava
+
+ if [ -n "$MAX_LOCKED_MEMORY" -a -z "$ES_HEAP_SIZE" ]; then
+ log_failure_msg "MAX_LOCKED_MEMORY is set - ES_HEAP_SIZE must also be set"
+ exit 1
+ fi
+
+
+ mkdir -p "$LOG_DIR" "$DATA_DIR" "$WORK_DIR"
+ chown "$ES_USER":"$ES_GROUP" "$LOG_DIR" "$DATA_DIR" "$WORK_DIR"
+
+ if [ -n "$MAX_OPEN_FILES" ];then
+ ulimit -n $MAX_OPEN_FILES
+ fi
+
+ if [ -n "$MAX_LOCKED_MEMORY" ];then
+ ulimit -l $MAX_LOCKED_MEMORY
+ fi
+
+ ulimit -s 1024
+
+ for node in 0 1; do
+ log_daemon_msg "Starting elasticsearch node #$node"
+
+ PID_FILE="/var/run/$NAME-$node.pid"
+ CONF_FILE="$CONF_DIR/config-$node.yml"
+
+ DAEMON="$ES_HOME/bin/elasticsearch"
+ DAEMON_OPTS="
+ -Des.config=$CONF_FILE \
+ -Des.path.home=$ES_HOME \
+ -Des.path.logs=$LOG_DIR \
+ -Des.path.data=$DATA_DIR \
+ -Des.path.work=$WORK_DIR \
+ -Des.path.conf=$CONF_DIR \
+ -p $PID_FILE
+ "
+
+ pid=`pidofproc -p $PID_FILE elasticsearch`
+ if [ -n "$pid" ] ; then
+ log_begin_msg "Elasticsearch node #$node already running"
+ continue
+ fi
+
+ touch "$PID_FILE"
+ chown "$ES_USER":"$ES_GROUP" "$PID_FILE"
+
+ # Start Daemon
+ start-stop-daemon --start -b --user "$ES_USER" -c "$ES_USER" --pidfile "$PID_FILE" --exec "$DAEMON" -- "$DAEMON_OPTS"
+ return=$?
+ if [ $return -eq 0 ]; then
+ i=0
+ timeout=10
+ # Wait for the process to be properly started before exiting
+ until { cat "$PID_FILE" | xargs kill -0; } >/dev/null 2>&1
+ do
+ sleep 1
+ i=$(($i + 1))
+ [ $i -gt $timeout ] && log_end_msg 1
+ done
+ else
+ log_end_msg $return
+ fi
+ done
+ ;;
+ stop)
+ for node in 0 1; do
+ log_daemon_msg "Stopping elasticsearch node #$node"
+
+ PID_FILE="/var/run/$NAME-$node.pid"
+
+ if [ -f "$PID_FILE" ]; then
+ start-stop-daemon --stop --pidfile "$PID_FILE" \
+ --user "$ES_USER" \
+ --retry=TERM/20/KILL/5 >/dev/null
+ if [ $? -eq 1 ]; then
+ log_progress_msg "$DESC is not running but pid file exists, cleaning up"
+ elif [ $? -eq 3 ]; then
+ PID="`cat $PID_FILE`"
+ log_failure_msg "Failed to stop $DESC (pid $PID)"
+ exit 1
+ fi
+ rm -f "$PID_FILE"
+ else
+ log_progress_msg "(not running)"
+ fi
+ done
+
+ log_end_msg 0
+ ;;
+ status)
+ for node in 0 1; do
+ PID_FILE="/var/run/$NAME-$node.pid"
+ status_of_proc -p $PID_FILE "Elasticsearch node #$node" "Elasticsearch node #$node"
+ done
+ exit 0
+ ;;
+ restart|force-reload)
+ for node in 0 1; do
+ PID_FILE="/var/run/$NAME-$node.pid"
+ if [ -f "$PID_FILE" ]; then
+ $0 stop
+ sleep 1
+ fi
+ done
+ $0 start
+ ;;
+ *)
+ log_success_msg "Usage: $0 {start|stop|restart|force-reload|status}"
+ exit 1
+ ;;
+esac
+
+exit 0
diff --git a/vendor/ruflin/elastica/ansible/roles/elasticsearch/templates/logging.yml b/vendor/ruflin/elastica/ansible/roles/elasticsearch/templates/logging.yml
new file mode 100644
index 00000000..9e00d01c
--- /dev/null
+++ b/vendor/ruflin/elastica/ansible/roles/elasticsearch/templates/logging.yml
@@ -0,0 +1,56 @@
+# you can override this using by setting a system property, for example -Des.logger.level=DEBUG
+es.logger.level: INFO
+rootLogger: ${es.logger.level}, console, file
+logger:
+ # log action execution errors for easier debugging
+ action: DEBUG
+ # reduce the logging for aws, too much is logged under the default INFO
+ com.amazonaws: WARN
+
+ # gateway
+ #gateway: DEBUG
+ #index.gateway: DEBUG
+
+ # peer shard recovery
+ #indices.recovery: DEBUG
+
+ # discovery
+ #discovery: TRACE
+
+ index.search.slowlog: TRACE, index_search_slow_log_file
+ index.indexing.slowlog: TRACE, index_indexing_slow_log_file
+
+additivity:
+ index.search.slowlog: false
+ index.indexing.slowlog: false
+
+appender:
+ console:
+ type: console
+ layout:
+ type: consolePattern
+ conversionPattern: "[%d{ISO8601}][%-5p][%-25c] %m%n"
+
+ file:
+ type: dailyRollingFile
+ file: ${path.logs}/${cluster.name}.log
+ datePattern: "'.'yyyy-MM-dd"
+ layout:
+ type: pattern
+ conversionPattern: "[%d{ISO8601}][%-5p][%-25c] %m%n"
+
+ index_search_slow_log_file:
+ type: dailyRollingFile
+ file: ${path.logs}/${cluster.name}_index_search_slowlog.log
+ datePattern: "'.'yyyy-MM-dd"
+ layout:
+ type: pattern
+ conversionPattern: "[%d{ISO8601}][%-5p][%-25c] %m%n"
+
+ index_indexing_slow_log_file:
+ type: dailyRollingFile
+ file: ${path.logs}/${cluster.name}_index_indexing_slowlog.log
+ datePattern: "'.'yyyy-MM-dd"
+ layout:
+ type: pattern
+ conversionPattern: "[%d{ISO8601}][%-5p][%-25c] %m%n"
diff --git a/vendor/ruflin/elastica/ansible/roles/nginx/handlers/main.yml b/vendor/ruflin/elastica/ansible/roles/nginx/handlers/main.yml
new file mode 100644
index 00000000..fc583f27
--- /dev/null
+++ b/vendor/ruflin/elastica/ansible/roles/nginx/handlers/main.yml
@@ -0,0 +1,6 @@
+---
+
+- name: restart nginx
+ service: >
+ name=nginx
+ state=restarted
diff --git a/vendor/ruflin/elastica/ansible/roles/nginx/tasks/main.yml b/vendor/ruflin/elastica/ansible/roles/nginx/tasks/main.yml
new file mode 100644
index 00000000..6b260531
--- /dev/null
+++ b/vendor/ruflin/elastica/ansible/roles/nginx/tasks/main.yml
@@ -0,0 +1,26 @@
+---
+
+- name: install nginx
+ apt: >
+ force=yes
+ name=nginx
+ state=present
+ update_cache=no
+
+- name: create mime.types
+ template: >
+ dest=/etc/nginx/mime.types
+ src=mime.types.j2
+ notify: restart nginx
+
+- name: create nginx.conf
+ template: >
+ dest=/etc/nginx/nginx.conf
+ src=nginx.conf.j2
+ notify: restart nginx
+
+- name: start nginx
+ service: >
+ enabled=yes
+ name=nginx
+ state=started
diff --git a/vendor/ruflin/elastica/ansible/roles/nginx/templates/mime.types.j2 b/vendor/ruflin/elastica/ansible/roles/nginx/templates/mime.types.j2
new file mode 100644
index 00000000..6c64bf73
--- /dev/null
+++ b/vendor/ruflin/elastica/ansible/roles/nginx/templates/mime.types.j2
@@ -0,0 +1,109 @@
+types {
+
+# Audio
+ audio/midi mid midi kar;
+ audio/mp4 aac f4a f4b m4a;
+ audio/mpeg mp3;
+ audio/ogg oga ogg opus;
+ audio/x-realaudio ra;
+ audio/x-wav wav;
+
+# Images
+ image/bmp bmp;
+ image/gif gif;
+ image/jpeg jpeg jpg;
+ image/png png;
+ image/svg+xml svg svgz;
+ image/tiff tif tiff;
+ image/vnd.wap.wbmp wbmp;
+ image/webp webp;
+ image/x-icon ico cur;
+ image/x-jng jng;
+
+# JavaScript
+ application/javascript js;
+ application/json json;
+
+# Manifest files
+ application/x-web-app-manifest+json webapp;
+ text/cache-manifest manifest appcache;
+
+# Microsoft Office
+ application/msword doc;
+ application/vnd.ms-excel xls;
+ application/vnd.ms-powerpoint ppt;
+ application/vnd.openxmlformats-officedocument.wordprocessingml.document docx;
+ application/vnd.openxmlformats-officedocument.spreadsheetml.sheet xlsx;
+ application/vnd.openxmlformats-officedocument.presentationml.presentation pptx;
+
+# Video
+ video/3gpp 3gpp 3gp;
+ video/mp4 mp4 m4v f4v f4p;
+ video/mpeg mpeg mpg;
+ video/ogg ogv;
+ video/quicktime mov;
+ video/webm webm;
+ video/x-flv flv;
+ video/x-mng mng;
+ video/x-ms-asf asx asf;
+ video/x-ms-wmv wmv;
+ video/x-msvideo avi;
+
+# Web feeds
+ application/xml atom rdf rss xml;
+
+# Web fonts
+ application/font-woff woff;
+ application/font-woff2 woff2;
+ application/vnd.ms-fontobject eot;
+ application/x-font-ttf ttc ttf;
+ font/opentype otf;
+
+# Other
+ application/java-archive jar war ear;
+ application/mac-binhex40 hqx;
+ application/pdf pdf;
+ application/postscript ps eps ai;
+ application/rtf rtf;
+ application/vnd.wap.wmlc wmlc;
+ application/xhtml+xml xhtml;
+ application/vnd.google-earth.kml+xml kml;
+ application/vnd.google-earth.kmz kmz;
+ application/x-7z-compressed 7z;
+ application/x-chrome-extension crx;
+ application/x-opera-extension oex;
+ application/x-xpinstall xpi;
+ application/x-cocoa cco;
+ application/x-java-archive-diff jardiff;
+ application/x-java-jnlp-file jnlp;
+ application/x-makeself run;
+ application/x-perl pl pm;
+ application/x-pilot prc pdb;
+ application/x-rar-compressed rar;
+ application/x-redhat-package-manager rpm;
+ application/x-sea sea;
+ application/x-shockwave-flash swf;
+ application/x-stuffit sit;
+ application/x-tcl tcl tk;
+ application/x-x509-ca-cert der pem crt;
+ application/x-bittorrent torrent;
+ application/zip zip;
+
+ application/octet-stream bin exe dll;
+ application/octet-stream deb;
+ application/octet-stream dmg;
+ application/octet-stream iso img;
+ application/octet-stream msi msp msm;
+ application/octet-stream safariextz;
+
+ text/css css;
+ text/html html htm shtml;
+ text/mathml mml;
+ text/plain txt;
+ text/vnd.sun.j2me.app-descriptor jad;
+ text/vnd.wap.wml wml;
+ text/vtt vtt;
+ text/x-component htc;
+ text/x-vcard vcf;
+
+}
diff --git a/vendor/ruflin/elastica/ansible/roles/nginx/templates/nginx.conf.j2 b/vendor/ruflin/elastica/ansible/roles/nginx/templates/nginx.conf.j2
new file mode 100644
index 00000000..17966f7a
--- /dev/null
+++ b/vendor/ruflin/elastica/ansible/roles/nginx/templates/nginx.conf.j2
@@ -0,0 +1,35 @@
+events {
+ worker_connections 1024;
+}
+
+http {
+ include /etc/nginx/mime.types;
+ default_type application/octet-stream;
+ charset_types text/xml text/plain text/vnd.wap.wml application/x-javascript application/rss+xml text/css application/javascript application/json;
+
+ server {
+ listen 80;
+
+ root {{ ES_PROJECT_ROOT }};
+
+ location / {
+ autoindex on;
+ }
+ }
+
+ server {
+ listen 127.0.0.1:12345;
+
+ location / {
+ proxy_pass http://127.0.0.1:9200;
+ }
+ }
+
+ server {
+ listen 127.0.0.1:12346;
+
+ location / {
+ return 403;
+ }
+ }
+}
diff --git a/vendor/ruflin/elastica/ansible/roles/php/tasks/main.yml b/vendor/ruflin/elastica/ansible/roles/php/tasks/main.yml
new file mode 100644
index 00000000..fff65d52
--- /dev/null
+++ b/vendor/ruflin/elastica/ansible/roles/php/tasks/main.yml
@@ -0,0 +1,43 @@
+---
+- name: import ppa:ondrej/php5 gpg key
+ apt_key: >
+ id=E5267A6C
+ keyserver=keyserver.ubuntu.com
+ state=present
+
+- name: add ppa:ondrej/php5 repository
+ apt_repository: >
+ repo="deb http://ppa.launchpad.net/ondrej/php5/ubuntu precise main"
+ state=present
+ update_cache=yes
+
+- name: install php
+ apt: >
+ force=yes
+ name={{ item }}
+ state=present
+ update_cache=no
+ with_items:
+ - php5-cli
+ - php5-curl
+ - php5-xdebug
+ - php5-memcache
+
+- name: install phar packages
+ get_url: >
+ dest={{ item.dest }}
+ url={{ item.url }}
+ mode=0755
+ with_items:
+ - { dest: "/usr/local/bin/php-cs-fixer", url: "http://get.sensiolabs.org/php-cs-fixer.phar" }
+ - { dest: "/usr/local/bin/phpdoc", url: "http://phpdoc.org/phpDocumentor.phar" }
+ - { dest: "/usr/local/bin/phpunit", url: "https://phar.phpunit.de/phpunit.phar" }
+ - { dest: "/usr/local/bin/composer", url: "https://getcomposer.org/composer.phar" }
+
+- name: install dependencies from composer.json
+ composer: >
+ command=install
+ optimize_autoloader=yes
+ prefer_source=yes
+ no_dev=no
+ working_dir={{ ES_PROJECT_ROOT }}
diff --git a/vendor/ruflin/elastica/composer.json b/vendor/ruflin/elastica/composer.json
new file mode 100644
index 00000000..8bffc334
--- /dev/null
+++ b/vendor/ruflin/elastica/composer.json
@@ -0,0 +1,43 @@
+{
+ "name": "ruflin/elastica",
+ "description": "Elasticsearch Client",
+ "keywords": ["search","client"],
+ "homepage": "http://elastica.io/",
+ "type": "library",
+ "license": "MIT",
+ "authors": [
+ {
+ "name": "Nicolas Ruflin",
+ "homepage": "http://ruflin.com/"
+ }
+ ],
+ "require": {
+ "php": ">=5.3.3",
+ "psr/log": "~1.0"
+ },
+ "require-dev": {
+ "munkie/elasticsearch-thrift-php": "1.4.*",
+ "guzzlehttp/guzzle": "5.3.*"
+ },
+ "suggest": {
+ "munkie/elasticsearch-thrift-php": "Allow using thrift transport",
+ "guzzlehttp/guzzle": "Allow using guzzle 5.3.x as the http transport (Requires php 5.4)",
+ "egeloen/http-adapter": "Allow using httpadapter transport",
+ "monolog/monolog": "Logging request"
+ },
+ "autoload": {
+ "psr-4": {
+ "Elastica\\": "lib/Elastica/"
+ }
+ },
+ "autoload-dev": {
+ "psr-4": {
+ "Elastica\\Test\\": "test/lib/Elastica/Test/"
+ }
+ },
+ "extra": {
+ "branch-alias": {
+ "dev-master": "2.0.x-dev"
+ }
+ }
+}
diff --git a/vendor/ruflin/elastica/docker-compose.yml b/vendor/ruflin/elastica/docker-compose.yml
new file mode 100644
index 00000000..674d6e9e
--- /dev/null
+++ b/vendor/ruflin/elastica/docker-compose.yml
@@ -0,0 +1,27 @@
+elastica:
+ #build: . # In case the image must be built locally
+ image: ruflin/elastica
+ ports:
+ - "9200:9200"
+ volumes:
+ - .:/app
+ links:
+ - nginx
+ - elasticsearch
+ environment:
+ - ES_HOST=elasticsearch
+ - PROXY_HOST=nginx
+elasticsearch:
+ #build: ./env/elasticsearch/ # In case image must be built locally
+ image: ruflin/elasticsearch-elastica
+nginx:
+ image: nginx
+ volumes:
+ - ./env/nginx/nginx.conf:/etc/nginx/nginx.conf
+ - ./env/nginx/mime.types:/etc/nginx/mime.types
+ ports:
+ - "12345"
+ - "12346"
+ - "80"
+ links:
+ - elasticsearch
diff --git a/vendor/ruflin/elastica/env/elasticsearch/Dockerfile b/vendor/ruflin/elastica/env/elasticsearch/Dockerfile
new file mode 100644
index 00000000..ae2665a0
--- /dev/null
+++ b/vendor/ruflin/elastica/env/elasticsearch/Dockerfile
@@ -0,0 +1,26 @@
+FROM elasticsearch:1.6.0
+MAINTAINER Nicolas Ruflin <spam@ruflin.com>
+
+# Dependencies
+ENV ES_MAPPER_ATTACHMENTS_VER 2.6.0
+ENV ES_TRANSPORT_MEMCACHED_VER 2.6.0
+ENV ES_TRANSPORT_THRIFT_VER 2.6.0
+ENV ES_GEOCLUSTER_FACET_VER 0.0.12
+ENV ES_IMAGE_PLUGIN_VER 1.4.0
+ENV ES_PLUGIN_BIN /usr/share/elasticsearch/bin/plugin
+
+# Install Plugins
+RUN ${ES_PLUGIN_BIN} -install elasticsearch/elasticsearch-mapper-attachments/${ES_MAPPER_ATTACHMENTS_VER}
+RUN ${ES_PLUGIN_BIN} -install image --url https://github.com/SibaTokyo/elasticsearch-image/releases/download/${ES_IMAGE_PLUGIN_VER}/elasticsearch-image-${ES_IMAGE_PLUGIN_VER}.zip
+RUN ${ES_PLUGIN_BIN} -install geocluster-facet --url https://github.com/zenobase/geocluster-facet/releases/download/${ES_GEOCLUSTER_FACET_VER}/geocluster-facet-${ES_GEOCLUSTER_FACET_VER}.jar
+RUN ${ES_PLUGIN_BIN} -install elasticsearch/elasticsearch-transport-thrift/${ES_TRANSPORT_THRIFT_VER}
+RUN ${ES_PLUGIN_BIN} -install elasticsearch/elasticsearch-transport-memcached/${ES_TRANSPORT_MEMCACHED_VER}
+
+# Debug interface
+RUN ${ES_PLUGIN_BIN} -install mobz/elasticsearch-head
+
+# Copy config files
+COPY *.yml /usr/share/elasticsearch/config/
+
+# Expose standard ports, thrift, udp, memcache
+EXPOSE 9200 9300 9500 9700 9800 11211
diff --git a/vendor/ruflin/elastica/env/elasticsearch/elasticsearch.yml b/vendor/ruflin/elastica/env/elasticsearch/elasticsearch.yml
new file mode 100644
index 00000000..bd0368da
--- /dev/null
+++ b/vendor/ruflin/elastica/env/elasticsearch/elasticsearch.yml
@@ -0,0 +1,39 @@
+
+index.number_of_shards: 2
+index.number_of_replicas: 0
+
+# Dont write data to hdd in tests
+index.store.type: memory
+
+# Required plugins
+plugin.mandatory: mapper-attachments, geocluster-facet, transport-thrift, transport-memcached, image
+
+# For bulk tests
+bulk.udp.enabled: true
+bulk.udp.bulk_actions: 5
+
+# For script tests
+script.inline: on
+script.indexed: on
+
+# Disable dynamic memory allocation
+bootstrap.mlockall: true
+
+# Dont accept connections not from localhost
+#network.host: "127.0.0.1"
+
+# Limit threadpool by set number of available processors to 1
+# Without this, travis builds will be failed with OutOfMemory error
+processors: 1
+
+# All nodes will be called Elastica
+node.name: Elastica
+
+# Ports config
+http.port: 9200
+transport.tcp.port: 9300
+thrift.port: 9500
+memcached.port: 11211
+
+# Added for snapshot tests
+path.repo: ["/tmp/test_register", "/tmp/test_repository"] \ No newline at end of file
diff --git a/vendor/ruflin/elastica/env/elasticsearch/logging.yml b/vendor/ruflin/elastica/env/elasticsearch/logging.yml
new file mode 100644
index 00000000..9e00d01c
--- /dev/null
+++ b/vendor/ruflin/elastica/env/elasticsearch/logging.yml
@@ -0,0 +1,56 @@
+# you can override this using by setting a system property, for example -Des.logger.level=DEBUG
+es.logger.level: INFO
+rootLogger: ${es.logger.level}, console, file
+logger:
+ # log action execution errors for easier debugging
+ action: DEBUG
+ # reduce the logging for aws, too much is logged under the default INFO
+ com.amazonaws: WARN
+
+ # gateway
+ #gateway: DEBUG
+ #index.gateway: DEBUG
+
+ # peer shard recovery
+ #indices.recovery: DEBUG
+
+ # discovery
+ #discovery: TRACE
+
+ index.search.slowlog: TRACE, index_search_slow_log_file
+ index.indexing.slowlog: TRACE, index_indexing_slow_log_file
+
+additivity:
+ index.search.slowlog: false
+ index.indexing.slowlog: false
+
+appender:
+ console:
+ type: console
+ layout:
+ type: consolePattern
+ conversionPattern: "[%d{ISO8601}][%-5p][%-25c] %m%n"
+
+ file:
+ type: dailyRollingFile
+ file: ${path.logs}/${cluster.name}.log
+ datePattern: "'.'yyyy-MM-dd"
+ layout:
+ type: pattern
+ conversionPattern: "[%d{ISO8601}][%-5p][%-25c] %m%n"
+
+ index_search_slow_log_file:
+ type: dailyRollingFile
+ file: ${path.logs}/${cluster.name}_index_search_slowlog.log
+ datePattern: "'.'yyyy-MM-dd"
+ layout:
+ type: pattern
+ conversionPattern: "[%d{ISO8601}][%-5p][%-25c] %m%n"
+
+ index_indexing_slow_log_file:
+ type: dailyRollingFile
+ file: ${path.logs}/${cluster.name}_index_indexing_slowlog.log
+ datePattern: "'.'yyyy-MM-dd"
+ layout:
+ type: pattern
+ conversionPattern: "[%d{ISO8601}][%-5p][%-25c] %m%n"
diff --git a/vendor/ruflin/elastica/env/nginx/mime.types b/vendor/ruflin/elastica/env/nginx/mime.types
new file mode 100644
index 00000000..6c64bf73
--- /dev/null
+++ b/vendor/ruflin/elastica/env/nginx/mime.types
@@ -0,0 +1,109 @@
+types {
+
+# Audio
+ audio/midi mid midi kar;
+ audio/mp4 aac f4a f4b m4a;
+ audio/mpeg mp3;
+ audio/ogg oga ogg opus;
+ audio/x-realaudio ra;
+ audio/x-wav wav;
+
+# Images
+ image/bmp bmp;
+ image/gif gif;
+ image/jpeg jpeg jpg;
+ image/png png;
+ image/svg+xml svg svgz;
+ image/tiff tif tiff;
+ image/vnd.wap.wbmp wbmp;
+ image/webp webp;
+ image/x-icon ico cur;
+ image/x-jng jng;
+
+# JavaScript
+ application/javascript js;
+ application/json json;
+
+# Manifest files
+ application/x-web-app-manifest+json webapp;
+ text/cache-manifest manifest appcache;
+
+# Microsoft Office
+ application/msword doc;
+ application/vnd.ms-excel xls;
+ application/vnd.ms-powerpoint ppt;
+ application/vnd.openxmlformats-officedocument.wordprocessingml.document docx;
+ application/vnd.openxmlformats-officedocument.spreadsheetml.sheet xlsx;
+ application/vnd.openxmlformats-officedocument.presentationml.presentation pptx;
+
+# Video
+ video/3gpp 3gpp 3gp;
+ video/mp4 mp4 m4v f4v f4p;
+ video/mpeg mpeg mpg;
+ video/ogg ogv;
+ video/quicktime mov;
+ video/webm webm;
+ video/x-flv flv;
+ video/x-mng mng;
+ video/x-ms-asf asx asf;
+ video/x-ms-wmv wmv;
+ video/x-msvideo avi;
+
+# Web feeds
+ application/xml atom rdf rss xml;
+
+# Web fonts
+ application/font-woff woff;
+ application/font-woff2 woff2;
+ application/vnd.ms-fontobject eot;
+ application/x-font-ttf ttc ttf;
+ font/opentype otf;
+
+# Other
+ application/java-archive jar war ear;
+ application/mac-binhex40 hqx;
+ application/pdf pdf;
+ application/postscript ps eps ai;
+ application/rtf rtf;
+ application/vnd.wap.wmlc wmlc;
+ application/xhtml+xml xhtml;
+ application/vnd.google-earth.kml+xml kml;
+ application/vnd.google-earth.kmz kmz;
+ application/x-7z-compressed 7z;
+ application/x-chrome-extension crx;
+ application/x-opera-extension oex;
+ application/x-xpinstall xpi;
+ application/x-cocoa cco;
+ application/x-java-archive-diff jardiff;
+ application/x-java-jnlp-file jnlp;
+ application/x-makeself run;
+ application/x-perl pl pm;
+ application/x-pilot prc pdb;
+ application/x-rar-compressed rar;
+ application/x-redhat-package-manager rpm;
+ application/x-sea sea;
+ application/x-shockwave-flash swf;
+ application/x-stuffit sit;
+ application/x-tcl tcl tk;
+ application/x-x509-ca-cert der pem crt;
+ application/x-bittorrent torrent;
+ application/zip zip;
+
+ application/octet-stream bin exe dll;
+ application/octet-stream deb;
+ application/octet-stream dmg;
+ application/octet-stream iso img;
+ application/octet-stream msi msp msm;
+ application/octet-stream safariextz;
+
+ text/css css;
+ text/html html htm shtml;
+ text/mathml mml;
+ text/plain txt;
+ text/vnd.sun.j2me.app-descriptor jad;
+ text/vnd.wap.wml wml;
+ text/vtt vtt;
+ text/x-component htc;
+ text/x-vcard vcf;
+
+}
diff --git a/vendor/ruflin/elastica/env/nginx/nginx.conf b/vendor/ruflin/elastica/env/nginx/nginx.conf
new file mode 100644
index 00000000..edf177d3
--- /dev/null
+++ b/vendor/ruflin/elastica/env/nginx/nginx.conf
@@ -0,0 +1,38 @@
+
+worker_processes 1;
+
+events {
+ worker_connections 1024;
+}
+
+http {
+ include /etc/nginx/mime.types;
+ default_type application/octet-stream;
+ charset_types text/xml text/plain text/vnd.wap.wml application/x-javascript application/rss+xml text/css application/javascript application/json;
+
+ server {
+ listen 80;
+
+ #root {{ ES_PROJECT_ROOT }};
+
+ location / {
+ autoindex on;
+ }
+ }
+
+ server {
+ listen 12345;
+
+ location / {
+ proxy_pass http://elasticsearch:9200;
+ }
+ }
+
+ server {
+ listen 12346;
+
+ location / {
+ return 403;
+ }
+ }
+}
diff --git a/vendor/ruflin/elastica/lib/Elastica/AbstractUpdateAction.php b/vendor/ruflin/elastica/lib/Elastica/AbstractUpdateAction.php
new file mode 100644
index 00000000..468087af
--- /dev/null
+++ b/vendor/ruflin/elastica/lib/Elastica/AbstractUpdateAction.php
@@ -0,0 +1,568 @@
+<?php
+namespace Elastica;
+
+/**
+ * Base class for things that can be sent to the update api (Document and
+ * Script).
+ *
+ * @author Nik Everett <nik9000@gmail.com>
+ */
+class AbstractUpdateAction extends Param
+{
+ /**
+ * @var \Elastica\Document
+ */
+ protected $_upsert;
+
+ /**
+ * Sets the id of the document.
+ *
+ * @param string $id
+ *
+ * @return $this
+ */
+ public function setId($id)
+ {
+ return $this->setParam('_id', $id);
+ }
+
+ /**
+ * Returns document id.
+ *
+ * @return string|int Document id
+ */
+ public function getId()
+ {
+ return ($this->hasParam('_id')) ? $this->getParam('_id') : null;
+ }
+
+ /**
+ * @return bool
+ */
+ public function hasId()
+ {
+ return '' !== (string) $this->getId();
+ }
+
+ /**
+ * Sets lifetime of document.
+ *
+ * @param string $ttl
+ *
+ * @return $this
+ */
+ public function setTtl($ttl)
+ {
+ return $this->setParam('_ttl', $ttl);
+ }
+
+ /**
+ * @return string
+ */
+ public function getTtl()
+ {
+ return $this->getParam('_ttl');
+ }
+
+ /**
+ * @return bool
+ */
+ public function hasTtl()
+ {
+ return $this->hasParam('_ttl');
+ }
+
+ /**
+ * Sets the document type name.
+ *
+ * @param string $type Type name
+ *
+ * @return $this
+ */
+ public function setType($type)
+ {
+ if ($type instanceof Type) {
+ $this->setIndex($type->getIndex());
+ $type = $type->getName();
+ }
+
+ return $this->setParam('_type', $type);
+ }
+
+ /**
+ * Return document type name.
+ *
+ * @throws \Elastica\Exception\InvalidException
+ *
+ * @return string Document type name
+ */
+ public function getType()
+ {
+ return $this->getParam('_type');
+ }
+
+ /**
+ * Sets the document index name.
+ *
+ * @param string $index Index name
+ *
+ * @return $this
+ */
+ public function setIndex($index)
+ {
+ if ($index instanceof Index) {
+ $index = $index->getName();
+ }
+
+ return $this->setParam('_index', $index);
+ }
+
+ /**
+ * Get the document index name.
+ *
+ * @throws \Elastica\Exception\InvalidException
+ *
+ * @return string Index name
+ */
+ public function getIndex()
+ {
+ return $this->getParam('_index');
+ }
+
+ /**
+ * Sets the version of a document for use with optimistic concurrency control.
+ *
+ * @param int $version Document version
+ *
+ * @return $this
+ *
+ * @link https://www.elastic.co/blog/versioning
+ */
+ public function setVersion($version)
+ {
+ return $this->setParam('_version', (int) $version);
+ }
+
+ /**
+ * Returns document version.
+ *
+ * @return string|int Document version
+ */
+ public function getVersion()
+ {
+ return $this->getParam('_version');
+ }
+
+ /**
+ * @return bool
+ */
+ public function hasVersion()
+ {
+ return $this->hasParam('_version');
+ }
+
+ /**
+ * Sets the version_type of a document
+ * Default in ES is internal, but you can set to external to use custom versioning.
+ *
+ * @param int $versionType Document version type
+ *
+ * @return $this
+ */
+ public function setVersionType($versionType)
+ {
+ return $this->setParam('_version_type', $versionType);
+ }
+
+ /**
+ * Returns document version type.
+ *
+ * @return string|int Document version type
+ */
+ public function getVersionType()
+ {
+ return $this->getParam('_version_type');
+ }
+
+ /**
+ * @return bool
+ */
+ public function hasVersionType()
+ {
+ return $this->hasParam('_version_type');
+ }
+
+ /**
+ * Sets parent document id.
+ *
+ * @param string|int $parent Parent document id
+ *
+ * @return $this
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/mapping-parent-field.html
+ */
+ public function setParent($parent)
+ {
+ return $this->setParam('_parent', $parent);
+ }
+
+ /**
+ * Returns the parent document id.
+ *
+ * @return string|int Parent document id
+ */
+ public function getParent()
+ {
+ return $this->getParam('_parent');
+ }
+
+ /**
+ * @return bool
+ */
+ public function hasParent()
+ {
+ return $this->hasParam('_parent');
+ }
+
+ /**
+ * Set operation type.
+ *
+ * @param string $opType Only accept create
+ *
+ * @return $this
+ */
+ public function setOpType($opType)
+ {
+ return $this->setParam('_op_type', $opType);
+ }
+
+ /**
+ * Get operation type.
+ *
+ * @return string
+ */
+ public function getOpType()
+ {
+ return $this->getParam('_op_type');
+ }
+
+ /**
+ * @return bool
+ */
+ public function hasOpType()
+ {
+ return $this->hasParam('_op_type');
+ }
+
+ /**
+ * Set percolate query param.
+ *
+ * @param string $value percolator filter
+ *
+ * @return $this
+ */
+ public function setPercolate($value = '*')
+ {
+ return $this->setParam('_percolate', $value);
+ }
+
+ /**
+ * Get percolate parameter.
+ *
+ * @return string
+ */
+ public function getPercolate()
+ {
+ return $this->getParam('_percolate');
+ }
+
+ /**
+ * @return bool
+ */
+ public function hasPercolate()
+ {
+ return $this->hasParam('_percolate');
+ }
+
+ /**
+ * Set routing query param.
+ *
+ * @param string $value routing
+ *
+ * @return $this
+ */
+ public function setRouting($value)
+ {
+ return $this->setParam('_routing', $value);
+ }
+
+ /**
+ * Get routing parameter.
+ *
+ * @return string
+ */
+ public function getRouting()
+ {
+ return $this->getParam('_routing');
+ }
+
+ /**
+ * @return bool
+ */
+ public function hasRouting()
+ {
+ return $this->hasParam('_routing');
+ }
+
+ /**
+ * @param array|string $fields
+ *
+ * @return $this
+ */
+ public function setFields($fields)
+ {
+ if (is_array($fields)) {
+ $fields = implode(',', $fields);
+ }
+
+ return $this->setParam('_fields', (string) $fields);
+ }
+
+ /**
+ * @return $this
+ */
+ public function setFieldsSource()
+ {
+ return $this->setFields('_source');
+ }
+
+ /**
+ * @return string
+ */
+ public function getFields()
+ {
+ return $this->getParam('_fields');
+ }
+
+ /**
+ * @return bool
+ */
+ public function hasFields()
+ {
+ return $this->hasParam('_fields');
+ }
+
+ /**
+ * @param int $num
+ *
+ * @return $this
+ */
+ public function setRetryOnConflict($num)
+ {
+ return $this->setParam('_retry_on_conflict', (int) $num);
+ }
+
+ /**
+ * @return int
+ */
+ public function getRetryOnConflict()
+ {
+ return $this->getParam('_retry_on_conflict');
+ }
+
+ /**
+ * @return bool
+ */
+ public function hasRetryOnConflict()
+ {
+ return $this->hasParam('_retry_on_conflict');
+ }
+
+ /**
+ * @param string $timestamp
+ *
+ * @return $this
+ */
+ public function setTimestamp($timestamp)
+ {
+ return $this->setParam('_timestamp', $timestamp);
+ }
+
+ /**
+ * @return int
+ */
+ public function getTimestamp()
+ {
+ return $this->getParam('_timestamp');
+ }
+
+ /**
+ * @return bool
+ */
+ public function hasTimestamp()
+ {
+ return $this->hasParam('_timestamp');
+ }
+
+ /**
+ * @param bool $refresh
+ *
+ * @return $this
+ */
+ public function setRefresh($refresh = true)
+ {
+ return $this->setParam('_refresh', (bool) $refresh);
+ }
+
+ /**
+ * @return bool
+ */
+ public function getRefresh()
+ {
+ return $this->getParam('_refresh');
+ }
+
+ /**
+ * @return bool
+ */
+ public function hasRefresh()
+ {
+ return $this->hasParam('_refresh');
+ }
+
+ /**
+ * @param string $timeout
+ *
+ * @return $this
+ */
+ public function setTimeout($timeout)
+ {
+ return $this->setParam('_timeout', $timeout);
+ }
+
+ /**
+ * @return bool
+ */
+ public function getTimeout()
+ {
+ return $this->getParam('_timeout');
+ }
+
+ /**
+ * @return string
+ */
+ public function hasTimeout()
+ {
+ return $this->hasParam('_timeout');
+ }
+
+ /**
+ * @param string $timeout
+ *
+ * @return $this
+ */
+ public function setConsistency($timeout)
+ {
+ return $this->setParam('_consistency', $timeout);
+ }
+
+ /**
+ * @return string
+ */
+ public function getConsistency()
+ {
+ return $this->getParam('_consistency');
+ }
+
+ /**
+ * @return string
+ */
+ public function hasConsistency()
+ {
+ return $this->hasParam('_consistency');
+ }
+
+ /**
+ * @param string $timeout
+ *
+ * @return $this
+ */
+ public function setReplication($timeout)
+ {
+ return $this->setParam('_replication', $timeout);
+ }
+
+ /**
+ * @return string
+ */
+ public function getReplication()
+ {
+ return $this->getParam('_replication');
+ }
+
+ /**
+ * @return bool
+ */
+ public function hasReplication()
+ {
+ return $this->hasParam('_replication');
+ }
+
+ /**
+ * @param \Elastica\Document|array $data
+ *
+ * @return $this
+ */
+ public function setUpsert($data)
+ {
+ $document = Document::create($data);
+ $this->_upsert = $document;
+
+ return $this;
+ }
+
+ /**
+ * @return \Elastica\Document
+ */
+ public function getUpsert()
+ {
+ return $this->_upsert;
+ }
+
+ /**
+ * @return bool
+ */
+ public function hasUpsert()
+ {
+ return null !== $this->_upsert;
+ }
+
+ /**
+ * @param array $fields if empty array all options will be returned, field names can be either with underscored either without, i.e. _percolate, routing
+ * @param bool $withUnderscore should option keys contain underscore prefix
+ *
+ * @return array
+ */
+ public function getOptions(array $fields = array(), $withUnderscore = false)
+ {
+ if (!empty($fields)) {
+ $data = array();
+ foreach ($fields as $field) {
+ $key = '_'.ltrim($field, '_');
+ if ($this->hasParam($key) && '' !== (string) $this->getParam($key)) {
+ $data[$key] = $this->getParam($key);
+ }
+ }
+ } else {
+ $data = $this->getParams();
+ }
+ if (!$withUnderscore) {
+ foreach ($data as $key => $value) {
+ $data[ltrim($key, '_')] = $value;
+ unset($data[$key]);
+ }
+ }
+
+ return $data;
+ }
+}
diff --git a/vendor/ruflin/elastica/lib/Elastica/Aggregation/AbstractAggregation.php b/vendor/ruflin/elastica/lib/Elastica/Aggregation/AbstractAggregation.php
new file mode 100644
index 00000000..4cbb6b74
--- /dev/null
+++ b/vendor/ruflin/elastica/lib/Elastica/Aggregation/AbstractAggregation.php
@@ -0,0 +1,97 @@
+<?php
+namespace Elastica\Aggregation;
+
+use Elastica\Exception\InvalidException;
+use Elastica\Param;
+
+abstract class AbstractAggregation extends Param
+{
+ /**
+ * @var string The name of this aggregation
+ */
+ protected $_name;
+
+ /**
+ * @var array Subaggregations belonging to this aggregation
+ */
+ protected $_aggs = array();
+
+ /**
+ * @param string $name the name of this aggregation
+ */
+ public function __construct($name)
+ {
+ $this->setName($name);
+ }
+
+ /**
+ * Set the name of this aggregation.
+ *
+ * @param string $name
+ *
+ * @return $this
+ */
+ public function setName($name)
+ {
+ $this->_name = $name;
+
+ return $this;
+ }
+
+ /**
+ * Retrieve the name of this aggregation.
+ *
+ * @return string
+ */
+ public function getName()
+ {
+ return $this->_name;
+ }
+
+ /**
+ * Retrieve all subaggregations belonging to this aggregation.
+ *
+ * @return array
+ */
+ public function getAggs()
+ {
+ return $this->_aggs;
+ }
+
+ /**
+ * Add a sub-aggregation.
+ *
+ * @param AbstractAggregation $aggregation
+ *
+ * @throws \Elastica\Exception\InvalidException
+ *
+ * @return $this
+ */
+ public function addAggregation(AbstractAggregation $aggregation)
+ {
+ if ($aggregation instanceof GlobalAggregation) {
+ throw new InvalidException('Global aggregators can only be placed as top level aggregators');
+ }
+
+ $this->_aggs[$aggregation->getName()] = $aggregation->toArray();
+
+ return $this;
+ }
+
+ /**
+ * @return array
+ */
+ public function toArray()
+ {
+ $array = parent::toArray();
+ if (array_key_exists('global_aggregation', $array)) {
+ // compensate for class name GlobalAggregation
+ $array = array('global' => new \stdClass());
+ }
+ if (sizeof($this->_aggs)) {
+ $array['aggs'] = $this->_aggs;
+ }
+
+ return $array;
+ }
+}
diff --git a/vendor/ruflin/elastica/lib/Elastica/Aggregation/AbstractSimpleAggregation.php b/vendor/ruflin/elastica/lib/Elastica/Aggregation/AbstractSimpleAggregation.php
new file mode 100644
index 00000000..02a0fddb
--- /dev/null
+++ b/vendor/ruflin/elastica/lib/Elastica/Aggregation/AbstractSimpleAggregation.php
@@ -0,0 +1,37 @@
+<?php
+namespace Elastica\Aggregation;
+
+use Elastica\Script;
+
+abstract class AbstractSimpleAggregation extends AbstractAggregation
+{
+ /**
+ * Set the field for this aggregation.
+ *
+ * @param string $field the name of the document field on which to perform this aggregation
+ *
+ * @return $this
+ */
+ public function setField($field)
+ {
+ return $this->setParam('field', $field);
+ }
+
+ /**
+ * Set a script for this aggregation.
+ *
+ * @param string|Script $script
+ *
+ * @return $this
+ */
+ public function setScript($script)
+ {
+ if ($script instanceof Script) {
+ $params = array_merge($this->getParams(), $script->toArray());
+
+ return $this->setParams($params);
+ }
+
+ return $this->setParam('script', $script);
+ }
+}
diff --git a/vendor/ruflin/elastica/lib/Elastica/Aggregation/AbstractTermsAggregation.php b/vendor/ruflin/elastica/lib/Elastica/Aggregation/AbstractTermsAggregation.php
new file mode 100644
index 00000000..57b56964
--- /dev/null
+++ b/vendor/ruflin/elastica/lib/Elastica/Aggregation/AbstractTermsAggregation.php
@@ -0,0 +1,97 @@
+<?php
+namespace Elastica\Aggregation;
+
+/**
+ * Class AbstractTermsAggergation.
+ */
+abstract class AbstractTermsAggregation extends AbstractSimpleAggregation
+{
+ /**
+ * Set the minimum number of documents in which a term must appear in order to be returned in a bucket.
+ *
+ * @param int $count
+ *
+ * @return $this
+ */
+ public function setMinimumDocumentCount($count)
+ {
+ return $this->setParam('min_doc_count', $count);
+ }
+
+ /**
+ * Filter documents to include based on a regular expression.
+ *
+ * @param string $pattern a regular expression
+ * @param string $flags Java Pattern flags
+ *
+ * @return $this
+ */
+ public function setInclude($pattern, $flags = null)
+ {
+ if (is_null($flags)) {
+ return $this->setParam('include', $pattern);
+ }
+
+ return $this->setParam('include', array(
+ 'pattern' => $pattern,
+ 'flags' => $flags,
+ ));
+ }
+
+ /**
+ * Filter documents to exclude based on a regular expression.
+ *
+ * @param string $pattern a regular expression
+ * @param string $flags Java Pattern flags
+ *
+ * @return $this
+ */
+ public function setExclude($pattern, $flags = null)
+ {
+ if (is_null($flags)) {
+ return $this->setParam('exclude', $pattern);
+ }
+
+ return $this->setParam('exclude', array(
+ 'pattern' => $pattern,
+ 'flags' => $flags,
+ ));
+ }
+
+ /**
+ * Sets the amount of terms to be returned.
+ *
+ * @param int $size The amount of terms to be returned.
+ *
+ * @return $this
+ */
+ public function setSize($size)
+ {
+ return $this->setParam('size', $size);
+ }
+
+ /**
+ * Sets how many terms the coordinating node will request from each shard.
+ *
+ * @param int $shard_size The amount of terms to be returned.
+ *
+ * @return $this
+ */
+ public function setShardSize($shard_size)
+ {
+ return $this->setParam('shard_size', $shard_size);
+ }
+
+ /**
+ * Instruct Elasticsearch to use direct field data or ordinals of the field values to execute this aggregation.
+ * The execution hint will be ignored if it is not applicable.
+ *
+ * @param string $hint map or ordinals
+ *
+ * @return $this
+ */
+ public function setExecutionHint($hint)
+ {
+ return $this->setParam('execution_hint', $hint);
+ }
+}
diff --git a/vendor/ruflin/elastica/lib/Elastica/Aggregation/Avg.php b/vendor/ruflin/elastica/lib/Elastica/Aggregation/Avg.php
new file mode 100644
index 00000000..abc2f7a1
--- /dev/null
+++ b/vendor/ruflin/elastica/lib/Elastica/Aggregation/Avg.php
@@ -0,0 +1,11 @@
+<?php
+namespace Elastica\Aggregation;
+
+/**
+ * Class Avg.
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/search-aggregations-metrics-avg-aggregation.html
+ */
+class Avg extends AbstractSimpleAggregation
+{
+}
diff --git a/vendor/ruflin/elastica/lib/Elastica/Aggregation/Cardinality.php b/vendor/ruflin/elastica/lib/Elastica/Aggregation/Cardinality.php
new file mode 100644
index 00000000..72b2e3aa
--- /dev/null
+++ b/vendor/ruflin/elastica/lib/Elastica/Aggregation/Cardinality.php
@@ -0,0 +1,38 @@
+<?php
+namespace Elastica\Aggregation;
+
+/**
+ * Class Cardinality.
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/search-aggregations-metrics-cardinality-aggregation.html
+ */
+class Cardinality extends AbstractSimpleAggregation
+{
+ /**
+ * @param int $precisionThreshold
+ *
+ * @return $this
+ */
+ public function setPrecisionThreshold($precisionThreshold)
+ {
+ if (!is_int($precisionThreshold)) {
+ throw new \InvalidArgumentException('precision_threshold only supports integer values');
+ }
+
+ return $this->setParam('precision_threshold', $precisionThreshold);
+ }
+
+ /**
+ * @param bool $rehash
+ *
+ * @return $this
+ */
+ public function setRehash($rehash)
+ {
+ if (!is_bool($rehash)) {
+ throw new \InvalidArgumentException('rehash only supports boolean values');
+ }
+
+ return $this->setParam('rehash', $rehash);
+ }
+}
diff --git a/vendor/ruflin/elastica/lib/Elastica/Aggregation/DateHistogram.php b/vendor/ruflin/elastica/lib/Elastica/Aggregation/DateHistogram.php
new file mode 100644
index 00000000..8636f34c
--- /dev/null
+++ b/vendor/ruflin/elastica/lib/Elastica/Aggregation/DateHistogram.php
@@ -0,0 +1,130 @@
+<?php
+namespace Elastica\Aggregation;
+
+/**
+ * Class DateHistogram.
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/search-aggregations-bucket-datehistogram-aggregation.html
+ */
+class DateHistogram extends Histogram
+{
+ /**
+ * Set pre-rounding based on interval.
+ *
+ * @deprecated Option "pre_zone" is deprecated as of ES 1.5. Use "time_zone" instead
+ *
+ * @param string $preZone
+ *
+ * @return $this
+ */
+ public function setPreZone($preZone)
+ {
+ return $this->setParam('pre_zone', $preZone);
+ }
+
+ /**
+ * Set post-rounding based on interval.
+ *
+ * @deprecated Option "post_zone" is deprecated as of ES 1.5. Use "time_zone" instead
+ *
+ * @param string $postZone
+ *
+ * @return $this
+ */
+ public function setPostZone($postZone)
+ {
+ return $this->setParam('post_zone', $postZone);
+ }
+
+ /**
+ * Set time_zone option.
+ *
+ * @param string
+ *
+ * @return $this
+ */
+ public function setTimezone($timezone)
+ {
+ return $this->setParam('time_zone', $timezone);
+ }
+
+ /**
+ * Set pre-zone adjustment for larger time intervals (day and above).
+ *
+ * @deprecated Option "pre_zone_adjust_large_interval" is deprecated as of ES 1.5
+ *
+ * @param string $adjust
+ *
+ * @return $this
+ */
+ public function setPreZoneAdjustLargeInterval($adjust)
+ {
+ return $this->setParam('pre_zone_adjust_large_interval', $adjust);
+ }
+
+ /**
+ * Adjust for granularity of date data.
+ *
+ * @param int $factor set to 1000 if date is stored in seconds rather than milliseconds
+ *
+ * @return $this
+ */
+ public function setFactor($factor)
+ {
+ return $this->setParam('factor', $factor);
+ }
+
+ /**
+ * Set the offset for pre-rounding.
+ *
+ * @deprecated Option "pre_offset" is deprecated as of ES 1.5. Use "offset" instead
+ *
+ * @param string $offset "1d", for example
+ *
+ * @return $this
+ */
+ public function setPreOffset($offset)
+ {
+ return $this->setParam('pre_offset', $offset);
+ }
+
+ /**
+ * Set the offset for post-rounding.
+ *
+ * @deprecated Option "post_offset" is deprecated as of ES 1.5. Use "offset" instead
+ *
+ * @param string $offset "1d", for example
+ *
+ * @return $this
+ */
+ public function setPostOffset($offset)
+ {
+ return $this->setParam('post_offset', $offset);
+ }
+
+ /**
+ * Set offset option.
+ *
+ * @param string
+ *
+ * @return $this
+ */
+ public function setOffset($offset)
+ {
+ return $this->setParam('offset', $offset);
+ }
+
+ /**
+ * Set the format for returned bucket key_as_string values.
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/master/search-aggregations-bucket-daterange-aggregation.html#date-format-pattern
+ *
+ * @param string $format see link for formatting options
+ *
+ * @return $this
+ */
+ public function setFormat($format)
+ {
+ return $this->setParam('format', $format);
+ }
+}
diff --git a/vendor/ruflin/elastica/lib/Elastica/Aggregation/DateRange.php b/vendor/ruflin/elastica/lib/Elastica/Aggregation/DateRange.php
new file mode 100644
index 00000000..deb5881d
--- /dev/null
+++ b/vendor/ruflin/elastica/lib/Elastica/Aggregation/DateRange.php
@@ -0,0 +1,22 @@
+<?php
+namespace Elastica\Aggregation;
+
+/**
+ * Class DateRange.
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/search-aggregations-bucket-daterange-aggregation.html
+ */
+class DateRange extends Range
+{
+ /**
+ * Set the formatting for the returned date values.
+ *
+ * @param string $format see documentation for formatting options
+ *
+ * @return $this
+ */
+ public function setFormat($format)
+ {
+ return $this->setParam('format', $format);
+ }
+}
diff --git a/vendor/ruflin/elastica/lib/Elastica/Aggregation/ExtendedStats.php b/vendor/ruflin/elastica/lib/Elastica/Aggregation/ExtendedStats.php
new file mode 100644
index 00000000..2b108bd1
--- /dev/null
+++ b/vendor/ruflin/elastica/lib/Elastica/Aggregation/ExtendedStats.php
@@ -0,0 +1,11 @@
+<?php
+namespace Elastica\Aggregation;
+
+/**
+ * Class ExtendedStats.
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/search-aggregations-metrics-extendedstats-aggregation.html
+ */
+class ExtendedStats extends AbstractSimpleAggregation
+{
+}
diff --git a/vendor/ruflin/elastica/lib/Elastica/Aggregation/Filter.php b/vendor/ruflin/elastica/lib/Elastica/Aggregation/Filter.php
new file mode 100644
index 00000000..fc83419e
--- /dev/null
+++ b/vendor/ruflin/elastica/lib/Elastica/Aggregation/Filter.php
@@ -0,0 +1,53 @@
+<?php
+namespace Elastica\Aggregation;
+
+use Elastica\Filter\AbstractFilter;
+
+/**
+ * Class Filter.
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/search-aggregations-bucket-filter-aggregation.html
+ */
+class Filter extends AbstractAggregation
+{
+ /**
+ * @param string $name
+ * @param AbstractFilter $filter
+ */
+ public function __construct($name, AbstractFilter $filter = null)
+ {
+ parent::__construct($name);
+
+ if ($filter !== null) {
+ $this->setFilter($filter);
+ }
+ }
+
+ /**
+ * Set the filter for this aggregation.
+ *
+ * @param AbstractFilter $filter
+ *
+ * @return $this
+ */
+ public function setFilter(AbstractFilter $filter)
+ {
+ return $this->setParam('filter', $filter->toArray());
+ }
+
+ /**
+ * @return array
+ */
+ public function toArray()
+ {
+ $array = array(
+ 'filter' => $this->getParam('filter'),
+ );
+
+ if ($this->_aggs) {
+ $array['aggs'] = $this->_aggs;
+ }
+
+ return $array;
+ }
+}
diff --git a/vendor/ruflin/elastica/lib/Elastica/Aggregation/Filters.php b/vendor/ruflin/elastica/lib/Elastica/Aggregation/Filters.php
new file mode 100644
index 00000000..e0fbf060
--- /dev/null
+++ b/vendor/ruflin/elastica/lib/Elastica/Aggregation/Filters.php
@@ -0,0 +1,59 @@
+<?php
+namespace Elastica\Aggregation;
+
+use Elastica\Filter\AbstractFilter;
+
+/**
+ * Class Filters.
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/search-aggregations-bucket-filters-aggregation.html
+ */
+class Filters extends AbstractAggregation
+{
+ /**
+ * Add a filter.
+ *
+ * If a name is given, it will be added as a key, otherwise considered as an anonymous filter
+ *
+ * @param AbstractFilter $filter
+ * @param string $name
+ *
+ * @return $this
+ */
+ public function addFilter(AbstractFilter $filter, $name = '')
+ {
+ if (empty($name)) {
+ $filterArray[] = $filter->toArray();
+ } else {
+ $filterArray[$name] = $filter->toArray();
+ }
+
+ return $this->addParam('filters', $filterArray);
+ }
+
+ /**
+ * @return array
+ */
+ public function toArray()
+ {
+ $array = array();
+ $filters = $this->getParam('filters');
+
+ foreach ($filters as $filter) {
+ // Detect between anonymous filters and named ones
+ $key = key($filter);
+
+ if (is_string($key)) {
+ $array['filters']['filters'][$key] = current($filter);
+ } else {
+ $array['filters']['filters'][] = current($filter);
+ }
+ }
+
+ if ($this->_aggs) {
+ $array['aggs'] = $this->_aggs;
+ }
+
+ return $array;
+ }
+}
diff --git a/vendor/ruflin/elastica/lib/Elastica/Aggregation/GeoDistance.php b/vendor/ruflin/elastica/lib/Elastica/Aggregation/GeoDistance.php
new file mode 100644
index 00000000..c50018a0
--- /dev/null
+++ b/vendor/ruflin/elastica/lib/Elastica/Aggregation/GeoDistance.php
@@ -0,0 +1,104 @@
+<?php
+namespace Elastica\Aggregation;
+
+use Elastica\Exception\InvalidException;
+
+/**
+ * Class GeoDistance.
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/search-aggregations-bucket-geodistance-aggregation.html
+ */
+class GeoDistance extends AbstractAggregation
+{
+ const DISTANCE_TYPE_SLOPPY_ARC = 'sloppy_arc';
+ const DISTANCE_TYPE_ARC = 'arc';
+ const DISTANCE_TYPE_PLANE = 'plane';
+
+ /**
+ * @param string $name the name if this aggregation
+ * @param string $field the field on which to perform this aggregation
+ * @param string|array $origin the point from which distances will be calculated
+ */
+ public function __construct($name, $field, $origin)
+ {
+ parent::__construct($name);
+ $this->setField($field)->setOrigin($origin);
+ }
+
+ /**
+ * Set the field for this aggregation.
+ *
+ * @param string $field the name of the document field on which to perform this aggregation
+ *
+ * @return $this
+ */
+ public function setField($field)
+ {
+ return $this->setParam('field', $field);
+ }
+
+ /**
+ * Set the origin point from which distances will be calculated.
+ *
+ * @param string|array $origin valid formats are array("lat" => 52.3760, "lon" => 4.894), "52.3760, 4.894", and array(4.894, 52.3760)
+ *
+ * @return $this
+ */
+ public function setOrigin($origin)
+ {
+ return $this->setParam('origin', $origin);
+ }
+
+ /**
+ * Add a distance range to this aggregation.
+ *
+ * @param int $fromValue a distance
+ * @param int $toValue a distance
+ *
+ * @throws \Elastica\Exception\InvalidException
+ *
+ * @return $this
+ */
+ public function addRange($fromValue = null, $toValue = null)
+ {
+ if (is_null($fromValue) && is_null($toValue)) {
+ throw new InvalidException('Either fromValue or toValue must be set. Both cannot be null.');
+ }
+
+ $range = array();
+
+ if (!is_null($fromValue)) {
+ $range['from'] = $fromValue;
+ }
+
+ if (!is_null($toValue)) {
+ $range['to'] = $toValue;
+ }
+
+ return $this->addParam('ranges', $range);
+ }
+
+ /**
+ * Set the unit of distance measure for this aggregation.
+ *
+ * @param string $unit defaults to km
+ *
+ * @return $this
+ */
+ public function setUnit($unit)
+ {
+ return $this->setParam('unit', $unit);
+ }
+
+ /**
+ * Set the method by which distances will be calculated.
+ *
+ * @param string $distanceType see DISTANCE_TYPE_* constants for options. Defaults to sloppy_arc.
+ *
+ * @return $this
+ */
+ public function setDistanceType($distanceType)
+ {
+ return $this->setParam('distance_type', $distanceType);
+ }
+}
diff --git a/vendor/ruflin/elastica/lib/Elastica/Aggregation/GeohashGrid.php b/vendor/ruflin/elastica/lib/Elastica/Aggregation/GeohashGrid.php
new file mode 100644
index 00000000..e7a40471
--- /dev/null
+++ b/vendor/ruflin/elastica/lib/Elastica/Aggregation/GeohashGrid.php
@@ -0,0 +1,68 @@
+<?php
+namespace Elastica\Aggregation;
+
+/**
+ * Class GeohashGrid.
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/search-aggregations-bucket-geohashgrid-aggregation.html
+ */
+class GeohashGrid extends AbstractAggregation
+{
+ /**
+ * @param string $name the name of this aggregation
+ * @param string $field the field on which to perform this aggregation
+ */
+ public function __construct($name, $field)
+ {
+ parent::__construct($name);
+ $this->setField($field);
+ }
+
+ /**
+ * Set the field for this aggregation.
+ *
+ * @param string $field the name of the document field on which to perform this aggregation
+ *
+ * @return $this
+ */
+ public function setField($field)
+ {
+ return $this->setParam('field', $field);
+ }
+
+ /**
+ * Set the precision for this aggregation.
+ *
+ * @param int $precision an integer between 1 and 12, inclusive. Defaults to 5.
+ *
+ * @return $this
+ */
+ public function setPrecision($precision)
+ {
+ return $this->setParam('precision', $precision);
+ }
+
+ /**
+ * Set the maximum number of buckets to return.
+ *
+ * @param int $size defaults to 10,000
+ *
+ * @return $this
+ */
+ public function setSize($size)
+ {
+ return $this->setParam('size', $size);
+ }
+
+ /**
+ * Set the number of results returned from each shard.
+ *
+ * @param int $shardSize
+ *
+ * @return $this
+ */
+ public function setShardSize($shardSize)
+ {
+ return $this->setParam('shard_size', $shardSize);
+ }
+}
diff --git a/vendor/ruflin/elastica/lib/Elastica/Aggregation/GlobalAggregation.php b/vendor/ruflin/elastica/lib/Elastica/Aggregation/GlobalAggregation.php
new file mode 100644
index 00000000..523844d2
--- /dev/null
+++ b/vendor/ruflin/elastica/lib/Elastica/Aggregation/GlobalAggregation.php
@@ -0,0 +1,11 @@
+<?php
+namespace Elastica\Aggregation;
+
+/**
+ * Class GlobalAggregation.
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/search-aggregations-bucket-global-aggregation.html
+ */
+class GlobalAggregation extends AbstractAggregation
+{
+}
diff --git a/vendor/ruflin/elastica/lib/Elastica/Aggregation/Histogram.php b/vendor/ruflin/elastica/lib/Elastica/Aggregation/Histogram.php
new file mode 100644
index 00000000..79a8e517
--- /dev/null
+++ b/vendor/ruflin/elastica/lib/Elastica/Aggregation/Histogram.php
@@ -0,0 +1,59 @@
+<?php
+namespace Elastica\Aggregation;
+
+/**
+ * Class Histogram.
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/search-aggregations-bucket-histogram-aggregation.html
+ */
+class Histogram extends AbstractSimpleAggregation
+{
+ /**
+ * @param string $name the name of this aggregation
+ * @param string $field the name of the field on which to perform the aggregation
+ * @param int $interval the interval by which documents will be bucketed
+ */
+ public function __construct($name, $field, $interval)
+ {
+ parent::__construct($name);
+ $this->setField($field);
+ $this->setInterval($interval);
+ }
+
+ /**
+ * Set the interval by which documents will be bucketed.
+ *
+ * @param int $interval
+ *
+ * @return $this
+ */
+ public function setInterval($interval)
+ {
+ return $this->setParam('interval', $interval);
+ }
+
+ /**
+ * Set the bucket sort order.
+ *
+ * @param string $order "_count", "_term", or the name of a sub-aggregation or sub-aggregation response field
+ * @param string $direction "asc" or "desc"
+ *
+ * @return $this
+ */
+ public function setOrder($order, $direction)
+ {
+ return $this->setParam('order', array($order => $direction));
+ }
+
+ /**
+ * Set the minimum number of documents which must fall into a bucket in order for the bucket to be returned.
+ *
+ * @param int $count set to 0 to include empty buckets
+ *
+ * @return $this
+ */
+ public function setMinimumDocumentCount($count)
+ {
+ return $this->setParam('min_doc_count', $count);
+ }
+}
diff --git a/vendor/ruflin/elastica/lib/Elastica/Aggregation/IpRange.php b/vendor/ruflin/elastica/lib/Elastica/Aggregation/IpRange.php
new file mode 100644
index 00000000..7a4ef7c8
--- /dev/null
+++ b/vendor/ruflin/elastica/lib/Elastica/Aggregation/IpRange.php
@@ -0,0 +1,72 @@
+<?php
+namespace Elastica\Aggregation;
+
+use Elastica\Exception\InvalidException;
+
+/**
+ * Class IpRange.
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/search-aggregations-bucket-iprange-aggregation.html
+ */
+class IpRange extends AbstractAggregation
+{
+ /**
+ * @param string $name the name of this aggregation
+ * @param string $field the field on which to perform this aggregation
+ */
+ public function __construct($name, $field)
+ {
+ parent::__construct($name);
+ $this->setField($field);
+ }
+
+ /**
+ * Set the field for this aggregation.
+ *
+ * @param string $field the name of the document field on which to perform this aggregation
+ *
+ * @return $this
+ */
+ public function setField($field)
+ {
+ return $this->setParam('field', $field);
+ }
+
+ /**
+ * Add an ip range to this aggregation.
+ *
+ * @param string $fromValue a valid ipv4 address. Low end of this range, exclusive (greater than)
+ * @param string $toValue a valid ipv4 address. High end of this range, exclusive (less than)
+ *
+ * @throws \Elastica\Exception\InvalidException
+ *
+ * @return $this
+ */
+ public function addRange($fromValue = null, $toValue = null)
+ {
+ if (is_null($fromValue) && is_null($toValue)) {
+ throw new InvalidException('Either fromValue or toValue must be set. Both cannot be null.');
+ }
+ $range = array();
+ if (!is_null($fromValue)) {
+ $range['from'] = $fromValue;
+ }
+ if (!is_null($toValue)) {
+ $range['to'] = $toValue;
+ }
+
+ return $this->addParam('ranges', $range);
+ }
+
+ /**
+ * Add an ip range in the form of a CIDR mask.
+ *
+ * @param string $mask a valid CIDR mask
+ *
+ * @return $this
+ */
+ public function addMaskRange($mask)
+ {
+ return $this->addParam('ranges', array('mask' => $mask));
+ }
+}
diff --git a/vendor/ruflin/elastica/lib/Elastica/Aggregation/Max.php b/vendor/ruflin/elastica/lib/Elastica/Aggregation/Max.php
new file mode 100644
index 00000000..fc0294ca
--- /dev/null
+++ b/vendor/ruflin/elastica/lib/Elastica/Aggregation/Max.php
@@ -0,0 +1,11 @@
+<?php
+namespace Elastica\Aggregation;
+
+/**
+ * Class Max.
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/search-aggregations-metrics-max-aggregation.html
+ */
+class Max extends AbstractSimpleAggregation
+{
+}
diff --git a/vendor/ruflin/elastica/lib/Elastica/Aggregation/Min.php b/vendor/ruflin/elastica/lib/Elastica/Aggregation/Min.php
new file mode 100644
index 00000000..d5c5c31b
--- /dev/null
+++ b/vendor/ruflin/elastica/lib/Elastica/Aggregation/Min.php
@@ -0,0 +1,11 @@
+<?php
+namespace Elastica\Aggregation;
+
+/**
+ * Class Min.
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/search-aggregations-metrics-min-aggregation.html
+ */
+class Min extends AbstractSimpleAggregation
+{
+}
diff --git a/vendor/ruflin/elastica/lib/Elastica/Aggregation/Missing.php b/vendor/ruflin/elastica/lib/Elastica/Aggregation/Missing.php
new file mode 100644
index 00000000..11a6bdf9
--- /dev/null
+++ b/vendor/ruflin/elastica/lib/Elastica/Aggregation/Missing.php
@@ -0,0 +1,32 @@
+<?php
+namespace Elastica\Aggregation;
+
+/**
+ * Class Missing.
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/search-aggregations-bucket-missing-aggregation.html
+ */
+class Missing extends AbstractAggregation
+{
+ /**
+ * @param string $name the name of this aggregation
+ * @param string $field the field on which to perform this aggregation
+ */
+ public function __construct($name, $field)
+ {
+ parent::__construct($name);
+ $this->setField($field);
+ }
+
+ /**
+ * Set the field for this aggregation.
+ *
+ * @param string $field the name of the document field on which to perform this aggregation
+ *
+ * @return $this
+ */
+ public function setField($field)
+ {
+ return $this->setParam('field', $field);
+ }
+}
diff --git a/vendor/ruflin/elastica/lib/Elastica/Aggregation/Nested.php b/vendor/ruflin/elastica/lib/Elastica/Aggregation/Nested.php
new file mode 100644
index 00000000..76407bc8
--- /dev/null
+++ b/vendor/ruflin/elastica/lib/Elastica/Aggregation/Nested.php
@@ -0,0 +1,32 @@
+<?php
+namespace Elastica\Aggregation;
+
+/**
+ * Class Nested.
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/search-aggregations-bucket-nested-aggregation.html
+ */
+class Nested extends AbstractAggregation
+{
+ /**
+ * @param string $name the name of this aggregation
+ * @param string $path the nested path for this aggregation
+ */
+ public function __construct($name, $path)
+ {
+ parent::__construct($name);
+ $this->setPath($path);
+ }
+
+ /**
+ * Set the nested path for this aggregation.
+ *
+ * @param string $path
+ *
+ * @return $this
+ */
+ public function setPath($path)
+ {
+ return $this->setParam('path', $path);
+ }
+}
diff --git a/vendor/ruflin/elastica/lib/Elastica/Aggregation/Percentiles.php b/vendor/ruflin/elastica/lib/Elastica/Aggregation/Percentiles.php
new file mode 100644
index 00000000..22079634
--- /dev/null
+++ b/vendor/ruflin/elastica/lib/Elastica/Aggregation/Percentiles.php
@@ -0,0 +1,59 @@
+<?php
+namespace Elastica\Aggregation;
+
+/**
+ * Class Percentiles.
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/search-aggregations-metrics-percentile-aggregation.html
+ */
+class Percentiles extends AbstractSimpleAggregation
+{
+ /**
+ * @param string $name the name of this aggregation
+ * @param string $field the field on which to perform this aggregation
+ */
+ public function __construct($name, $field = null)
+ {
+ parent::__construct($name);
+
+ if (!is_null($field)) {
+ $this->setField($field);
+ }
+ }
+
+ /**
+ * Set compression parameter.
+ *
+ * @param float $value
+ *
+ * @return $this
+ */
+ public function setCompression($value)
+ {
+ return $this->setParam('compression', (float) $value);
+ }
+
+ /**
+ * Set which percents must be returned.
+ *
+ * @param float[] $percents
+ *
+ * @return $this
+ */
+ public function setPercents(array $percents)
+ {
+ return $this->setParam('percents', $percents);
+ }
+
+ /**
+ * Add yet another percent to result.
+ *
+ * @param float $percent
+ *
+ * @return $this
+ */
+ public function addPercent($percent)
+ {
+ return $this->addParam('percents', (float) $percent);
+ }
+}
diff --git a/vendor/ruflin/elastica/lib/Elastica/Aggregation/Range.php b/vendor/ruflin/elastica/lib/Elastica/Aggregation/Range.php
new file mode 100644
index 00000000..becafb28
--- /dev/null
+++ b/vendor/ruflin/elastica/lib/Elastica/Aggregation/Range.php
@@ -0,0 +1,58 @@
+<?php
+namespace Elastica\Aggregation;
+
+use Elastica\Exception\InvalidException;
+
+/**
+ * Class Range.
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/search-aggregations-bucket-range-aggregation.html
+ */
+class Range extends AbstractSimpleAggregation
+{
+ /**
+ * Add a range to this aggregation.
+ *
+ * @param int|float $fromValue low end of this range, exclusive (greater than or equal to)
+ * @param int|float $toValue high end of this range, exclusive (less than)
+ * @param string $key customized key value
+ *
+ * @throws \Elastica\Exception\InvalidException
+ *
+ * @return $this
+ */
+ public function addRange($fromValue = null, $toValue = null, $key = null)
+ {
+ if (is_null($fromValue) && is_null($toValue)) {
+ throw new InvalidException('Either fromValue or toValue must be set. Both cannot be null.');
+ }
+
+ $range = array();
+
+ if (!is_null($fromValue)) {
+ $range['from'] = $fromValue;
+ }
+
+ if (!is_null($toValue)) {
+ $range['to'] = $toValue;
+ }
+
+ if (!is_null($key)) {
+ $range['key'] = $key;
+ }
+
+ return $this->addParam('ranges', $range);
+ }
+
+ /**
+ * If set to true, a unique string key will be associated with each bucket, and ranges will be returned as an associative array.
+ *
+ * @param bool $keyed
+ *
+ * @return $this
+ */
+ public function setKeyedResponse($keyed = true)
+ {
+ return $this->setParam('keyed', (bool) $keyed);
+ }
+}
diff --git a/vendor/ruflin/elastica/lib/Elastica/Aggregation/ReverseNested.php b/vendor/ruflin/elastica/lib/Elastica/Aggregation/ReverseNested.php
new file mode 100644
index 00000000..5216ae85
--- /dev/null
+++ b/vendor/ruflin/elastica/lib/Elastica/Aggregation/ReverseNested.php
@@ -0,0 +1,49 @@
+<?php
+namespace Elastica\Aggregation;
+
+/**
+ * Reversed Nested Aggregation.
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/search-aggregations-bucket-reverse-nested-aggregation.html
+ */
+class ReverseNested extends AbstractAggregation
+{
+ /**
+ * @param string $name The name of this aggregation
+ * @param string $path Optional path to the nested object for this aggregation. Defaults to the root of the main document.
+ */
+ public function __construct($name, $path = null)
+ {
+ parent::__construct($name);
+
+ if ($path !== null) {
+ $this->setPath($path);
+ }
+ }
+
+ /**
+ * Set the nested path for this aggregation.
+ *
+ * @param string $path
+ *
+ * @return $this
+ */
+ public function setPath($path)
+ {
+ return $this->setParam('path', $path);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function toArray()
+ {
+ $array = parent::toArray();
+
+ // ensure we have an object for the reverse_nested key.
+ // if we don't have a path, then this would otherwise get encoded as an empty array, which is invalid.
+ $array['reverse_nested'] = (object) $array['reverse_nested'];
+
+ return $array;
+ }
+}
diff --git a/vendor/ruflin/elastica/lib/Elastica/Aggregation/ScriptedMetric.php b/vendor/ruflin/elastica/lib/Elastica/Aggregation/ScriptedMetric.php
new file mode 100644
index 00000000..3e51f056
--- /dev/null
+++ b/vendor/ruflin/elastica/lib/Elastica/Aggregation/ScriptedMetric.php
@@ -0,0 +1,82 @@
+<?php
+namespace Elastica\Aggregation;
+
+/**
+ * Class ScriptedMetric.
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/search-aggregations-metrics-scripted-metric-aggregation.html
+ */
+class ScriptedMetric extends AbstractAggregation
+{
+ /**
+ * @param string $name the name if this aggregation
+ * @param string|null $initScript Executed prior to any collection of documents
+ * @param string|null $mapScript Executed once per document collected
+ * @param string|null $combineScript Executed once on each shard after document collection is complete
+ * @param string|null $reduceScript Executed once on the coordinating node after all shards have returned their results
+ */
+ public function __construct($name, $initScript = null, $mapScript = null, $combineScript = null, $reduceScript = null)
+ {
+ parent::__construct($name);
+ if ($initScript) {
+ $this->setInitScript($initScript);
+ }
+ if ($mapScript) {
+ $this->setMapScript($mapScript);
+ }
+ if ($combineScript) {
+ $this->setCombineScript($combineScript);
+ }
+ if ($reduceScript) {
+ $this->setReduceScript($reduceScript);
+ }
+ }
+
+ /**
+ * Set the field for this aggregation.
+ *
+ * @param string $script the name of the document field on which to perform this aggregation
+ *
+ * @return $this
+ */
+ public function setCombineScript($script)
+ {
+ return $this->setParam('combine_script', $script);
+ }
+
+ /**
+ * Set the field for this aggregation.
+ *
+ * @param string $script the name of the document field on which to perform this aggregation
+ *
+ * @return $this
+ */
+ public function setInitScript($script)
+ {
+ return $this->setParam('init_script', $script);
+ }
+
+ /**
+ * Set the field for this aggregation.
+ *
+ * @param string $script the name of the document field on which to perform this aggregation
+ *
+ * @return $this
+ */
+ public function setMapScript($script)
+ {
+ return $this->setParam('map_script', $script);
+ }
+
+ /**
+ * Set the field for this aggregation.
+ *
+ * @param string $script the name of the document field on which to perform this aggregation
+ *
+ * @return $this
+ */
+ public function setReduceScript($script)
+ {
+ return $this->setParam('reduce_script', $script);
+ }
+}
diff --git a/vendor/ruflin/elastica/lib/Elastica/Aggregation/SignificantTerms.php b/vendor/ruflin/elastica/lib/Elastica/Aggregation/SignificantTerms.php
new file mode 100644
index 00000000..fa394791
--- /dev/null
+++ b/vendor/ruflin/elastica/lib/Elastica/Aggregation/SignificantTerms.php
@@ -0,0 +1,27 @@
+<?php
+namespace Elastica\Aggregation;
+
+use Elastica\Filter\AbstractFilter;
+
+/**
+ * Class SignificantTerms.
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/search-aggregations-bucket-significantterms-aggregation.html
+ */
+class SignificantTerms extends AbstractTermsAggregation
+{
+ /**
+ * The default source of statistical information for background term frequencies is the entire index and this scope can
+ * be narrowed through the use of a background_filter to focus in on significant terms within a narrower context.
+ *
+ * @param AbstractFilter $filter
+ *
+ * @return $this
+ *
+ * @see https://www.elastic.co/guide/en/elasticsearch/reference/current/search-aggregations-bucket-significantterms-aggregation.html#_custom_background_context
+ */
+ public function setBackgroundFilter(AbstractFilter $filter)
+ {
+ return $this->setParam('background_filter', $filter->toArray());
+ }
+}
diff --git a/vendor/ruflin/elastica/lib/Elastica/Aggregation/Stats.php b/vendor/ruflin/elastica/lib/Elastica/Aggregation/Stats.php
new file mode 100644
index 00000000..f512628c
--- /dev/null
+++ b/vendor/ruflin/elastica/lib/Elastica/Aggregation/Stats.php
@@ -0,0 +1,11 @@
+<?php
+namespace Elastica\Aggregation;
+
+/**
+ * Class Stats.
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/search-aggregations-metrics-stats-aggregation.html
+ */
+class Stats extends AbstractSimpleAggregation
+{
+}
diff --git a/vendor/ruflin/elastica/lib/Elastica/Aggregation/Sum.php b/vendor/ruflin/elastica/lib/Elastica/Aggregation/Sum.php
new file mode 100644
index 00000000..5172a684
--- /dev/null
+++ b/vendor/ruflin/elastica/lib/Elastica/Aggregation/Sum.php
@@ -0,0 +1,11 @@
+<?php
+namespace Elastica\Aggregation;
+
+/**
+ * Class Sum.
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/search-aggregations-metrics-sum-aggregation.html
+ */
+class Sum extends AbstractSimpleAggregation
+{
+}
diff --git a/vendor/ruflin/elastica/lib/Elastica/Aggregation/Terms.php b/vendor/ruflin/elastica/lib/Elastica/Aggregation/Terms.php
new file mode 100644
index 00000000..8d0d6bef
--- /dev/null
+++ b/vendor/ruflin/elastica/lib/Elastica/Aggregation/Terms.php
@@ -0,0 +1,23 @@
+<?php
+namespace Elastica\Aggregation;
+
+/**
+ * Class Terms.
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/search-aggregations-bucket-terms-aggregation.html
+ */
+class Terms extends AbstractTermsAggregation
+{
+ /**
+ * Set the bucket sort order.
+ *
+ * @param string $order "_count", "_term", or the name of a sub-aggregation or sub-aggregation response field
+ * @param string $direction "asc" or "desc"
+ *
+ * @return $this
+ */
+ public function setOrder($order, $direction)
+ {
+ return $this->setParam('order', array($order => $direction));
+ }
+}
diff --git a/vendor/ruflin/elastica/lib/Elastica/Aggregation/TopHits.php b/vendor/ruflin/elastica/lib/Elastica/Aggregation/TopHits.php
new file mode 100644
index 00000000..91a48a48
--- /dev/null
+++ b/vendor/ruflin/elastica/lib/Elastica/Aggregation/TopHits.php
@@ -0,0 +1,156 @@
+<?php
+namespace Elastica\Aggregation;
+
+use Elastica\Script;
+use Elastica\ScriptFields;
+
+/**
+ * Class TopHits.
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/search-aggregations-metrics-top-hits-aggregation.html
+ */
+class TopHits extends AbstractAggregation
+{
+ /**
+ * @return array
+ */
+ public function toArray()
+ {
+ $array = parent::toArray();
+
+ // if there are no params, it's ok, but ES will throw exception if json
+ // will be like {"top_hits":[]} instead of {"top_hits":{}}
+ if (empty($array['top_hits'])) {
+ $array['top_hits'] = new \stdClass();
+ }
+
+ return $array;
+ }
+
+ /**
+ * The maximum number of top matching hits to return per bucket. By default the top three matching hits are returned.
+ *
+ * @param int $size
+ *
+ * @return $this
+ */
+ public function setSize($size)
+ {
+ return $this->setParam('size', (int) $size);
+ }
+
+ /**
+ * The offset from the first result you want to fetch.
+ *
+ * @param int $from
+ *
+ * @return $this
+ */
+ public function setFrom($from)
+ {
+ return $this->setParam('from', (int) $from);
+ }
+
+ /**
+ * How the top matching hits should be sorted. By default the hits are sorted by the score of the main query.
+ *
+ * @param array $sortArgs
+ *
+ * @return $this
+ */
+ public function setSort(array $sortArgs)
+ {
+ return $this->setParam('sort', $sortArgs);
+ }
+
+ /**
+ * Allows to control how the _source field is returned with every hit.
+ *
+ * @param array $fields
+ *
+ * @return $this
+ */
+ public function setSource(array $fields)
+ {
+ return $this->setParam('_source', $fields);
+ }
+
+ /**
+ * Returns a version for each search hit.
+ *
+ * @param bool $version
+ *
+ * @return $this
+ */
+ public function setVersion($version)
+ {
+ return $this->setParam('version', (bool) $version);
+ }
+
+ /**
+ * Enables explanation for each hit on how its score was computed.
+ *
+ * @param bool $explain
+ *
+ * @return $this
+ */
+ public function setExplain($explain)
+ {
+ return $this->setParam('explain', (bool) $explain);
+ }
+
+ /**
+ * Set script fields.
+ *
+ * @param array|\Elastica\ScriptFields $scriptFields
+ *
+ * @return $this
+ */
+ public function setScriptFields($scriptFields)
+ {
+ if (is_array($scriptFields)) {
+ $scriptFields = new ScriptFields($scriptFields);
+ }
+
+ return $this->setParam('script_fields', $scriptFields->toArray());
+ }
+
+ /**
+ * Adds a Script to the aggregation.
+ *
+ * @param string $name
+ * @param \Elastica\Script $script
+ *
+ * @return $this
+ */
+ public function addScriptField($name, Script $script)
+ {
+ $this->_params['script_fields'][$name] = $script->toArray();
+
+ return $this;
+ }
+
+ /**
+ * Sets highlight arguments for the results.
+ *
+ * @param array $highlightArgs
+ *
+ * @return $this
+ */
+ public function setHighlight(array $highlightArgs)
+ {
+ return $this->setParam('highlight', $highlightArgs);
+ }
+
+ /**
+ * Allows to return the field data representation of a field for each hit.
+ *
+ * @param array $fields
+ *
+ * @return $this
+ */
+ public function setFieldDataFields(array $fields)
+ {
+ return $this->setParam('fielddata_fields', $fields);
+ }
+}
diff --git a/vendor/ruflin/elastica/lib/Elastica/Aggregation/ValueCount.php b/vendor/ruflin/elastica/lib/Elastica/Aggregation/ValueCount.php
new file mode 100644
index 00000000..8706a1be
--- /dev/null
+++ b/vendor/ruflin/elastica/lib/Elastica/Aggregation/ValueCount.php
@@ -0,0 +1,32 @@
+<?php
+namespace Elastica\Aggregation;
+
+/**
+ * Class ValueCount.
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/search-aggregations-metrics-valuecount-aggregation.html
+ */
+class ValueCount extends AbstractAggregation
+{
+ /**
+ * @param string $name the name of this aggregation
+ * @param string $field the field on which to perform this aggregation
+ */
+ public function __construct($name, $field)
+ {
+ parent::__construct($name);
+ $this->setField($field);
+ }
+
+ /**
+ * Set the field for this aggregation.
+ *
+ * @param string $field the name of the document field on which to perform this aggregation
+ *
+ * @return $this
+ */
+ public function setField($field)
+ {
+ return $this->setParam('field', $field);
+ }
+}
diff --git a/vendor/ruflin/elastica/lib/Elastica/Bulk.php b/vendor/ruflin/elastica/lib/Elastica/Bulk.php
new file mode 100644
index 00000000..e7693dce
--- /dev/null
+++ b/vendor/ruflin/elastica/lib/Elastica/Bulk.php
@@ -0,0 +1,442 @@
+<?php
+namespace Elastica;
+
+use Elastica\Bulk\Action;
+use Elastica\Bulk\Action\AbstractDocument as AbstractDocumentAction;
+use Elastica\Bulk\Response as BulkResponse;
+use Elastica\Bulk\ResponseSet;
+use Elastica\Exception\Bulk\ResponseException as BulkResponseException;
+use Elastica\Exception\Bulk\UdpException;
+use Elastica\Exception\InvalidException;
+
+class Bulk
+{
+ const DELIMITER = "\n";
+
+ const UDP_DEFAULT_HOST = 'localhost';
+ const UDP_DEFAULT_PORT = 9700;
+
+ /**
+ * @var \Elastica\Client
+ */
+ protected $_client;
+
+ /**
+ * @var \Elastica\Bulk\Action[]
+ */
+ protected $_actions = array();
+
+ /**
+ * @var string
+ */
+ protected $_index = '';
+
+ /**
+ * @var string
+ */
+ protected $_type = '';
+
+ /**
+ * @var array request parameters to the bulk api
+ */
+ protected $_requestParams = array();
+
+ /**
+ * @param \Elastica\Client $client
+ */
+ public function __construct(Client $client)
+ {
+ $this->_client = $client;
+ }
+
+ /**
+ * @param string|\Elastica\Index $index
+ *
+ * @return $this
+ */
+ public function setIndex($index)
+ {
+ if ($index instanceof Index) {
+ $index = $index->getName();
+ }
+
+ $this->_index = (string) $index;
+
+ return $this;
+ }
+
+ /**
+ * @return string
+ */
+ public function getIndex()
+ {
+ return $this->_index;
+ }
+
+ /**
+ * @return bool
+ */
+ public function hasIndex()
+ {
+ return '' !== $this->getIndex();
+ }
+
+ /**
+ * @param string|\Elastica\Type $type
+ *
+ * @return $this
+ */
+ public function setType($type)
+ {
+ if ($type instanceof Type) {
+ $this->setIndex($type->getIndex()->getName());
+ $type = $type->getName();
+ }
+
+ $this->_type = (string) $type;
+
+ return $this;
+ }
+
+ /**
+ * @return string
+ */
+ public function getType()
+ {
+ return $this->_type;
+ }
+
+ /**
+ * @return bool
+ */
+ public function hasType()
+ {
+ return '' !== $this->_type;
+ }
+
+ /**
+ * @return string
+ */
+ public function getPath()
+ {
+ $path = '';
+ if ($this->hasIndex()) {
+ $path .= $this->getIndex().'/';
+ if ($this->hasType()) {
+ $path .= $this->getType().'/';
+ }
+ }
+ $path .= '_bulk';
+
+ return $path;
+ }
+
+ /**
+ * @param \Elastica\Bulk\Action $action
+ *
+ * @return $this
+ */
+ public function addAction(Action $action)
+ {
+ $this->_actions[] = $action;
+
+ return $this;
+ }
+
+ /**
+ * @param \Elastica\Bulk\Action[] $actions
+ *
+ * @return $this
+ */
+ public function addActions(array $actions)
+ {
+ foreach ($actions as $action) {
+ $this->addAction($action);
+ }
+
+ return $this;
+ }
+
+ /**
+ * @return \Elastica\Bulk\Action[]
+ */
+ public function getActions()
+ {
+ return $this->_actions;
+ }
+
+ /**
+ * @param \Elastica\Document $document
+ * @param string $opType
+ *
+ * @return $this
+ */
+ public function addDocument(Document $document, $opType = null)
+ {
+ $action = AbstractDocumentAction::create($document, $opType);
+
+ return $this->addAction($action);
+ }
+
+ /**
+ * @param \Elastica\Document[] $documents
+ * @param string $opType
+ *
+ * @return $this
+ */
+ public function addDocuments(array $documents, $opType = null)
+ {
+ foreach ($documents as $document) {
+ $this->addDocument($document, $opType);
+ }
+
+ return $this;
+ }
+
+ /**
+ * @param \Elastica\Script $data
+ * @param string $opType
+ *
+ * @return $this
+ */
+ public function addScript(Script $script, $opType = null)
+ {
+ $action = AbstractDocumentAction::create($script, $opType);
+
+ return $this->addAction($action);
+ }
+
+ /**
+ * @param \Elastica\Document[] $scripts
+ * @param string $opType
+ *
+ * @return $this
+ */
+ public function addScripts(array $scripts, $opType = null)
+ {
+ foreach ($scripts as $document) {
+ $this->addScript($document, $opType);
+ }
+
+ return $this;
+ }
+
+ /**
+ * @param \Elastica\Script|\Elastica\Document\array $data
+ * @param string $opType
+ *
+ * @return $this
+ */
+ public function addData($data, $opType = null)
+ {
+ if (!is_array($data)) {
+ $data = array($data);
+ }
+
+ foreach ($data as $actionData) {
+ if ($actionData instanceof Script) {
+ $this->addScript($actionData, $opType);
+ } elseif ($actionData instanceof Document) {
+ $this->addDocument($actionData, $opType);
+ } else {
+ throw new \InvalidArgumentException('Data should be a Document, a Script or an array containing Documents and/or Scripts');
+ }
+ }
+
+ return $this;
+ }
+
+ /**
+ * @param array $data
+ *
+ * @throws \Elastica\Exception\InvalidException
+ *
+ * @return $this
+ */
+ public function addRawData(array $data)
+ {
+ foreach ($data as $row) {
+ if (is_array($row)) {
+ $opType = key($row);
+ $metadata = reset($row);
+ if (Action::isValidOpType($opType)) {
+ // add previous action
+ if (isset($action)) {
+ $this->addAction($action);
+ }
+ $action = new Action($opType, $metadata);
+ } elseif (isset($action)) {
+ $action->setSource($row);
+ $this->addAction($action);
+ $action = null;
+ } else {
+ throw new InvalidException('Invalid bulk data, source must follow action metadata');
+ }
+ } else {
+ throw new InvalidException('Invalid bulk data, should be array of array, Document or Bulk/Action');
+ }
+ }
+
+ // add last action if available
+ if (isset($action)) {
+ $this->addAction($action);
+ }
+
+ return $this;
+ }
+
+ /**
+ * Set a url parameter on the request bulk request.
+ *
+ * @param string $name name of the parameter
+ * @param string $value value of the parameter
+ *
+ * @return $this
+ */
+ public function setRequestParam($name, $value)
+ {
+ $this->_requestParams[$name] = $value;
+
+ return $this;
+ }
+
+ /**
+ * Set the amount of time that the request will wait the shards to come on line.
+ * Requires Elasticsearch version >= 0.90.8.
+ *
+ * @param string $time timeout in Elasticsearch time format
+ *
+ * @return $this
+ */
+ public function setShardTimeout($time)
+ {
+ return $this->setRequestParam('timeout', $time);
+ }
+
+ /**
+ * @return string
+ */
+ public function __toString()
+ {
+ return $this->toString();
+ }
+
+ /**
+ * @return string
+ */
+ public function toString()
+ {
+ $data = '';
+ foreach ($this->getActions() as $action) {
+ $data .= $action->toString();
+ }
+
+ return $data;
+ }
+
+ /**
+ * @return array
+ */
+ public function toArray()
+ {
+ $data = array();
+ foreach ($this->getActions() as $action) {
+ foreach ($action->toArray() as $row) {
+ $data[] = $row;
+ }
+ }
+
+ return $data;
+ }
+
+ /**
+ * @return \Elastica\Bulk\ResponseSet
+ */
+ public function send()
+ {
+ $path = $this->getPath();
+ $data = $this->toString();
+
+ $response = $this->_client->request($path, Request::PUT, $data, $this->_requestParams);
+
+ return $this->_processResponse($response);
+ }
+
+ /**
+ * @param \Elastica\Response $response
+ *
+ * @throws \Elastica\Exception\Bulk\ResponseException
+ * @throws \Elastica\Exception\InvalidException
+ *
+ * @return \Elastica\Bulk\ResponseSet
+ */
+ protected function _processResponse(Response $response)
+ {
+ $responseData = $response->getData();
+
+ $actions = $this->getActions();
+
+ $bulkResponses = array();
+
+ if (isset($responseData['items']) && is_array($responseData['items'])) {
+ foreach ($responseData['items'] as $key => $item) {
+ if (!isset($actions[$key])) {
+ throw new InvalidException('No response found for action #'.$key);
+ }
+
+ $action = $actions[$key];
+
+ $opType = key($item);
+ $bulkResponseData = reset($item);
+
+ if ($action instanceof AbstractDocumentAction) {
+ $data = $action->getData();
+ if ($data instanceof Document && $data->isAutoPopulate()
+ || $this->_client->getConfigValue(array('document', 'autoPopulate'), false)
+ ) {
+ if (!$data->hasId() && isset($bulkResponseData['_id'])) {
+ $data->setId($bulkResponseData['_id']);
+ }
+ if (isset($bulkResponseData['_version'])) {
+ $data->setVersion($bulkResponseData['_version']);
+ }
+ }
+ }
+
+ $bulkResponses[] = new BulkResponse($bulkResponseData, $action, $opType);
+ }
+ }
+
+ $bulkResponseSet = new ResponseSet($response, $bulkResponses);
+
+ if ($bulkResponseSet->hasError()) {
+ throw new BulkResponseException($bulkResponseSet);
+ }
+
+ return $bulkResponseSet;
+ }
+
+ /**
+ * @param string $host
+ * @param int $port
+ *
+ * @throws \Elastica\Exception\Bulk\UdpException
+ */
+ public function sendUdp($host = null, $port = null)
+ {
+ if (null === $host) {
+ $host = $this->_client->getConfigValue(array('udp', 'host'), self::UDP_DEFAULT_HOST);
+ }
+ if (null === $port) {
+ $port = $this->_client->getConfigValue(array('udp', 'port'), self::UDP_DEFAULT_PORT);
+ }
+
+ $message = $this->toString();
+ $socket = socket_create(AF_INET, SOCK_DGRAM, SOL_UDP);
+ $result = socket_sendto($socket, $message, strlen($message), 0, $host, $port);
+ socket_close($socket);
+ if (false === $result) {
+ throw new UdpException('UDP request failed');
+ }
+ }
+}
diff --git a/vendor/ruflin/elastica/lib/Elastica/Bulk/Action.php b/vendor/ruflin/elastica/lib/Elastica/Bulk/Action.php
new file mode 100644
index 00000000..25d02adc
--- /dev/null
+++ b/vendor/ruflin/elastica/lib/Elastica/Bulk/Action.php
@@ -0,0 +1,228 @@
+<?php
+namespace Elastica\Bulk;
+
+use Elastica\Bulk;
+use Elastica\Index;
+use Elastica\JSON;
+use Elastica\Type;
+
+class Action
+{
+ const OP_TYPE_CREATE = 'create';
+ const OP_TYPE_INDEX = 'index';
+ const OP_TYPE_DELETE = 'delete';
+ const OP_TYPE_UPDATE = 'update';
+
+ /**
+ * @var array
+ */
+ public static $opTypes = array(
+ self::OP_TYPE_CREATE,
+ self::OP_TYPE_INDEX,
+ self::OP_TYPE_DELETE,
+ self::OP_TYPE_UPDATE,
+ );
+
+ /**
+ * @var string
+ */
+ protected $_opType;
+
+ /**
+ * @var array
+ */
+ protected $_metadata = array();
+
+ /**
+ * @var array
+ */
+ protected $_source = array();
+
+ /**
+ * @param string $opType
+ * @param array $metadata
+ * @param array $source
+ */
+ public function __construct($opType = self::OP_TYPE_INDEX, array $metadata = array(), array $source = array())
+ {
+ $this->setOpType($opType);
+ $this->setMetadata($metadata);
+ $this->setSource($source);
+ }
+
+ /**
+ * @param string $type
+ *
+ * @return $this
+ */
+ public function setOpType($type)
+ {
+ $this->_opType = $type;
+
+ return $this;
+ }
+
+ /**
+ * @return string
+ */
+ public function getOpType()
+ {
+ return $this->_opType;
+ }
+
+ /**
+ * @param array $metadata
+ *
+ * @return $this
+ */
+ public function setMetadata(array $metadata)
+ {
+ $this->_metadata = $metadata;
+
+ return $this;
+ }
+
+ /**
+ * @return array
+ */
+ public function getMetadata()
+ {
+ return $this->_metadata;
+ }
+
+ /**
+ * @return array
+ */
+ public function getActionMetadata()
+ {
+ return array($this->_opType => $this->getMetadata());
+ }
+
+ /**
+ * @param array $source
+ *
+ * @return $this
+ */
+ public function setSource($source)
+ {
+ $this->_source = $source;
+
+ return $this;
+ }
+
+ /**
+ * @return array
+ */
+ public function getSource()
+ {
+ return $this->_source;
+ }
+
+ /**
+ * @return bool
+ */
+ public function hasSource()
+ {
+ return !empty($this->_source);
+ }
+
+ /**
+ * @param string|\Elastica\Index $index
+ *
+ * @return $this
+ */
+ public function setIndex($index)
+ {
+ if ($index instanceof Index) {
+ $index = $index->getName();
+ }
+ $this->_metadata['_index'] = $index;
+
+ return $this;
+ }
+
+ /**
+ * @param string|\Elastica\Type $type
+ *
+ * @return $this
+ */
+ public function setType($type)
+ {
+ if ($type instanceof Type) {
+ $this->setIndex($type->getIndex()->getName());
+ $type = $type->getName();
+ }
+ $this->_metadata['_type'] = $type;
+
+ return $this;
+ }
+
+ /**
+ * @param string $id
+ *
+ * @return $this
+ */
+ public function setId($id)
+ {
+ $this->_metadata['_id'] = $id;
+
+ return $this;
+ }
+
+ /**
+ * @param string $routing
+ *
+ * @return $this
+ */
+ public function setRouting($routing)
+ {
+ $this->_metadata['_routing'] = $routing;
+
+ return $this;
+ }
+
+ /**
+ * @return array
+ */
+ public function toArray()
+ {
+ $data[] = $this->getActionMetadata();
+ if ($this->hasSource()) {
+ $data[] = $this->getSource();
+ }
+
+ return $data;
+ }
+
+ /**
+ * @return string
+ */
+ public function toString()
+ {
+ $string = JSON::stringify($this->getActionMetadata(), JSON_FORCE_OBJECT).Bulk::DELIMITER;
+ if ($this->hasSource()) {
+ $source = $this->getSource();
+ if (is_string($source)) {
+ $string .= $source;
+ } elseif (is_array($source) && array_key_exists('doc', $source) && is_string($source['doc'])) {
+ $docAsUpsert = (isset($source['doc_as_upsert'])) ? ', "doc_as_upsert": '.$source['doc_as_upsert'] : '';
+ $string .= '{"doc": '.$source['doc'].$docAsUpsert.'}';
+ } else {
+ $string .= JSON::stringify($source, 'JSON_ELASTICSEARCH');
+ }
+ $string .= Bulk::DELIMITER;
+ }
+
+ return $string;
+ }
+
+ /**
+ * @param string $opType
+ *
+ * @return bool
+ */
+ public static function isValidOpType($opType)
+ {
+ return in_array($opType, self::$opTypes);
+ }
+}
diff --git a/vendor/ruflin/elastica/lib/Elastica/Bulk/Action/AbstractDocument.php b/vendor/ruflin/elastica/lib/Elastica/Bulk/Action/AbstractDocument.php
new file mode 100644
index 00000000..3127ff9c
--- /dev/null
+++ b/vendor/ruflin/elastica/lib/Elastica/Bulk/Action/AbstractDocument.php
@@ -0,0 +1,166 @@
+<?php
+namespace Elastica\Bulk\Action;
+
+use Elastica\AbstractUpdateAction;
+use Elastica\Bulk\Action;
+use Elastica\Document;
+use Elastica\Script;
+
+abstract class AbstractDocument extends Action
+{
+ /**
+ * @var \Elastica\Document|\Elastica\Script
+ */
+ protected $_data;
+
+ /**
+ * @param \Elastica\Document|\Elastica\Script $document
+ */
+ public function __construct($document)
+ {
+ $this->setData($document);
+ }
+
+ /**
+ * @param \Elastica\Document $document
+ *
+ * @return $this
+ */
+ public function setDocument(Document $document)
+ {
+ $this->_data = $document;
+
+ $metadata = $this->_getMetadata($document);
+
+ $this->setMetadata($metadata);
+
+ return $this;
+ }
+
+ /**
+ * @param \Elastica\Script $script
+ *
+ * @return $this
+ */
+ public function setScript(Script $script)
+ {
+ if (!($this instanceof UpdateDocument)) {
+ throw new \BadMethodCallException('setScript() can only be used for UpdateDocument');
+ }
+
+ $this->_data = $script;
+
+ $metadata = $this->_getMetadata($script);
+ $this->setMetadata($metadata);
+
+ return $this;
+ }
+
+ /**
+ * @param \Elastica\Script|\Elastica\Document $data
+ *
+ * @throws \InvalidArgumentException
+ *
+ * @return $this
+ */
+ public function setData($data)
+ {
+ if ($data instanceof Script) {
+ $this->setScript($data);
+ } elseif ($data instanceof Document) {
+ $this->setDocument($data);
+ } else {
+ throw new \InvalidArgumentException('Data should be a Document or a Script.');
+ }
+
+ return $this;
+ }
+
+ /**
+ * Note: This is for backwards compatibility.
+ *
+ * @return \Elastica\Document|null
+ */
+ public function getDocument()
+ {
+ if ($this->_data instanceof Document) {
+ return $this->_data;
+ }
+
+ return;
+ }
+
+ /**
+ * Note: This is for backwards compatibility.
+ *
+ * @return \Elastica\Script|null
+ */
+ public function getScript()
+ {
+ if ($this->_data instanceof Script) {
+ return $this->_data;
+ }
+
+ return;
+ }
+
+ /**
+ * @return \Elastica\Document|\Elastica\Script
+ */
+ public function getData()
+ {
+ return $this->_data;
+ }
+
+ /**
+ * @param \Elastica\AbstractUpdateAction $source
+ *
+ * @return array
+ */
+ abstract protected function _getMetadata(AbstractUpdateAction $source);
+
+ /**
+ * @param \Elastica\Document|\Elastica\Script $data
+ * @param string $opType
+ *
+ * @return static
+ */
+ public static function create($data, $opType = null)
+ {
+ //Check type
+ if (!($data instanceof Document) && !($data instanceof Script)) {
+ throw new \InvalidArgumentException('The data needs to be a Document or a Script.');
+ }
+
+ if (null === $opType && $data->hasOpType()) {
+ $opType = $data->getOpType();
+ }
+
+ //Check that scripts can only be used for updates
+ if ($data instanceof Script) {
+ if ($opType === null) {
+ $opType = self::OP_TYPE_UPDATE;
+ } elseif ($opType != self::OP_TYPE_UPDATE) {
+ throw new \InvalidArgumentException('Scripts can only be used with the update operation type.');
+ }
+ }
+
+ switch ($opType) {
+ case self::OP_TYPE_DELETE:
+ $action = new DeleteDocument($data);
+ break;
+ case self::OP_TYPE_CREATE:
+ $action = new CreateDocument($data);
+ break;
+ case self::OP_TYPE_UPDATE:
+ $action = new UpdateDocument($data);
+ break;
+ case self::OP_TYPE_INDEX:
+ default:
+ $action = new IndexDocument($data);
+ break;
+ }
+
+ return $action;
+ }
+}
diff --git a/vendor/ruflin/elastica/lib/Elastica/Bulk/Action/CreateDocument.php b/vendor/ruflin/elastica/lib/Elastica/Bulk/Action/CreateDocument.php
new file mode 100644
index 00000000..82581856
--- /dev/null
+++ b/vendor/ruflin/elastica/lib/Elastica/Bulk/Action/CreateDocument.php
@@ -0,0 +1,10 @@
+<?php
+namespace Elastica\Bulk\Action;
+
+class CreateDocument extends IndexDocument
+{
+ /**
+ * @var string
+ */
+ protected $_opType = self::OP_TYPE_CREATE;
+}
diff --git a/vendor/ruflin/elastica/lib/Elastica/Bulk/Action/DeleteDocument.php b/vendor/ruflin/elastica/lib/Elastica/Bulk/Action/DeleteDocument.php
new file mode 100644
index 00000000..5a243870
--- /dev/null
+++ b/vendor/ruflin/elastica/lib/Elastica/Bulk/Action/DeleteDocument.php
@@ -0,0 +1,33 @@
+<?php
+namespace Elastica\Bulk\Action;
+
+use Elastica\AbstractUpdateAction;
+
+class DeleteDocument extends AbstractDocument
+{
+ /**
+ * @var string
+ */
+ protected $_opType = self::OP_TYPE_DELETE;
+
+ /**
+ * @param \Elastica\AbstractUpdateAction $action
+ *
+ * @return array
+ */
+ protected function _getMetadata(AbstractUpdateAction $action)
+ {
+ $params = array(
+ 'index',
+ 'type',
+ 'id',
+ 'version',
+ 'version_type',
+ 'routing',
+ 'parent',
+ );
+ $metadata = $action->getOptions($params, true);
+
+ return $metadata;
+ }
+}
diff --git a/vendor/ruflin/elastica/lib/Elastica/Bulk/Action/IndexDocument.php b/vendor/ruflin/elastica/lib/Elastica/Bulk/Action/IndexDocument.php
new file mode 100644
index 00000000..0cf30e61
--- /dev/null
+++ b/vendor/ruflin/elastica/lib/Elastica/Bulk/Action/IndexDocument.php
@@ -0,0 +1,53 @@
+<?php
+namespace Elastica\Bulk\Action;
+
+use Elastica\AbstractUpdateAction;
+use Elastica\Document;
+
+class IndexDocument extends AbstractDocument
+{
+ /**
+ * @var string
+ */
+ protected $_opType = self::OP_TYPE_INDEX;
+
+ /**
+ * @param \Elastica\Document $document
+ *
+ * @return $this
+ */
+ public function setDocument(Document $document)
+ {
+ parent::setDocument($document);
+
+ $this->setSource($document->getData());
+
+ return $this;
+ }
+
+ /**
+ * @param \Elastica\AbstractUpdateAction $source
+ *
+ * @return array
+ */
+ protected function _getMetadata(AbstractUpdateAction $action)
+ {
+ $params = array(
+ 'index',
+ 'type',
+ 'id',
+ 'version',
+ 'version_type',
+ 'routing',
+ 'percolate',
+ 'parent',
+ 'ttl',
+ 'timestamp',
+ 'retry_on_conflict',
+ );
+
+ $metadata = $action->getOptions($params, true);
+
+ return $metadata;
+ }
+}
diff --git a/vendor/ruflin/elastica/lib/Elastica/Bulk/Action/UpdateDocument.php b/vendor/ruflin/elastica/lib/Elastica/Bulk/Action/UpdateDocument.php
new file mode 100644
index 00000000..2b133acb
--- /dev/null
+++ b/vendor/ruflin/elastica/lib/Elastica/Bulk/Action/UpdateDocument.php
@@ -0,0 +1,65 @@
+<?php
+namespace Elastica\Bulk\Action;
+
+use Elastica\Document;
+use Elastica\Script;
+
+class UpdateDocument extends IndexDocument
+{
+ /**
+ * @var string
+ */
+ protected $_opType = self::OP_TYPE_UPDATE;
+
+ /**
+ * Set the document for this bulk update action.
+ *
+ * @param \Elastica\Document $document
+ *
+ * @return $this
+ */
+ public function setDocument(Document $document)
+ {
+ parent::setDocument($document);
+
+ $source = array('doc' => $document->getData());
+
+ if ($document->getDocAsUpsert()) {
+ $source['doc_as_upsert'] = true;
+ } elseif ($document->hasUpsert()) {
+ $upsert = $document->getUpsert()->getData();
+
+ if (!empty($upsert)) {
+ $source['upsert'] = $upsert;
+ }
+ }
+
+ $this->setSource($source);
+
+ return $this;
+ }
+
+ /**
+ * @param \Elastica\Script $script
+ *
+ * @return $this
+ */
+ public function setScript(Script $script)
+ {
+ parent::setScript($script);
+
+ $source = $script->toArray();
+
+ if ($script->hasUpsert()) {
+ $upsert = $script->getUpsert()->getData();
+
+ if (!empty($upsert)) {
+ $source['upsert'] = $upsert;
+ }
+ }
+
+ $this->setSource($source);
+
+ return $this;
+ }
+}
diff --git a/vendor/ruflin/elastica/lib/Elastica/Bulk/Response.php b/vendor/ruflin/elastica/lib/Elastica/Bulk/Response.php
new file mode 100644
index 00000000..855a72c5
--- /dev/null
+++ b/vendor/ruflin/elastica/lib/Elastica/Bulk/Response.php
@@ -0,0 +1,46 @@
+<?php
+namespace Elastica\Bulk;
+
+use Elastica\Response as BaseResponse;
+
+class Response extends BaseResponse
+{
+ /**
+ * @var \Elastica\Bulk\Action
+ */
+ protected $_action;
+
+ /**
+ * @var string
+ */
+ protected $_opType;
+
+ /**
+ * @param array|string $responseData
+ * @param \Elastica\Bulk\Action $action
+ * @param string $opType
+ */
+ public function __construct($responseData, Action $action, $opType)
+ {
+ parent::__construct($responseData);
+
+ $this->_action = $action;
+ $this->_opType = $opType;
+ }
+
+ /**
+ * @return \Elastica\Bulk\Action
+ */
+ public function getAction()
+ {
+ return $this->_action;
+ }
+
+ /**
+ * @return string
+ */
+ public function getOpType()
+ {
+ return $this->_opType;
+ }
+}
diff --git a/vendor/ruflin/elastica/lib/Elastica/Bulk/ResponseSet.php b/vendor/ruflin/elastica/lib/Elastica/Bulk/ResponseSet.php
new file mode 100644
index 00000000..1837203f
--- /dev/null
+++ b/vendor/ruflin/elastica/lib/Elastica/Bulk/ResponseSet.php
@@ -0,0 +1,141 @@
+<?php
+namespace Elastica\Bulk;
+
+use Elastica\Response as BaseResponse;
+
+class ResponseSet extends BaseResponse implements \Iterator, \Countable
+{
+ /**
+ * @var \Elastica\Bulk\Response[]
+ */
+ protected $_bulkResponses = array();
+
+ /**
+ * @var int
+ */
+ protected $_position = 0;
+
+ /**
+ * @param \Elastica\Response $response
+ * @param \Elastica\Bulk\Response[] $bulkResponses
+ */
+ public function __construct(BaseResponse $response, array $bulkResponses)
+ {
+ parent::__construct($response->getData());
+
+ $this->_bulkResponses = $bulkResponses;
+ }
+
+ /**
+ * @return \Elastica\Bulk\Response[]
+ */
+ public function getBulkResponses()
+ {
+ return $this->_bulkResponses;
+ }
+
+ /**
+ * Returns first found error.
+ *
+ * @return string
+ */
+ public function getError()
+ {
+ $error = '';
+
+ foreach ($this->getBulkResponses() as $bulkResponse) {
+ if ($bulkResponse->hasError()) {
+ $error = $bulkResponse->getError();
+ break;
+ }
+ }
+
+ return $error;
+ }
+
+ /**
+ * @return bool
+ */
+ public function isOk()
+ {
+ $return = true;
+
+ foreach ($this->getBulkResponses() as $bulkResponse) {
+ if (!$bulkResponse->isOk()) {
+ $return = false;
+ break;
+ }
+ }
+
+ return $return;
+ }
+
+ /**
+ * @return bool
+ */
+ public function hasError()
+ {
+ $return = false;
+
+ foreach ($this->getBulkResponses() as $bulkResponse) {
+ if ($bulkResponse->hasError()) {
+ $return = true;
+ break;
+ }
+ }
+
+ return $return;
+ }
+
+ /**
+ * @return bool|\Elastica\Bulk\Response
+ */
+ public function current()
+ {
+ if ($this->valid()) {
+ return $this->_bulkResponses[$this->key()];
+ } else {
+ return false;
+ }
+ }
+
+ /**
+ *
+ */
+ public function next()
+ {
+ $this->_position++;
+ }
+
+ /**
+ * @return int
+ */
+ public function key()
+ {
+ return $this->_position;
+ }
+
+ /**
+ * @return bool
+ */
+ public function valid()
+ {
+ return isset($this->_bulkResponses[$this->key()]);
+ }
+
+ /**
+ *
+ */
+ public function rewind()
+ {
+ $this->_position = 0;
+ }
+
+ /**
+ * @return int
+ */
+ public function count()
+ {
+ return count($this->_bulkResponses);
+ }
+}
diff --git a/vendor/ruflin/elastica/lib/Elastica/Client.php b/vendor/ruflin/elastica/lib/Elastica/Client.php
new file mode 100644
index 00000000..b30bdb43
--- /dev/null
+++ b/vendor/ruflin/elastica/lib/Elastica/Client.php
@@ -0,0 +1,719 @@
+<?php
+namespace Elastica;
+
+use Elastica\Bulk\Action;
+use Elastica\Exception\ConnectionException;
+use Elastica\Exception\InvalidException;
+use Elastica\Exception\RuntimeException;
+use Psr\Log\LoggerInterface;
+
+/**
+ * Client to connect the the elasticsearch server.
+ *
+ * @author Nicolas Ruflin <spam@ruflin.com>
+ */
+class Client
+{
+ /**
+ * Config with defaults.
+ *
+ * log: Set to true, to enable logging, set a string to log to a specific file
+ * retryOnConflict: Use in \Elastica\Client::updateDocument
+ *
+ * @var array
+ */
+ protected $_config = array(
+ 'host' => null,
+ 'port' => null,
+ 'path' => null,
+ 'url' => null,
+ 'proxy' => null,
+ 'transport' => null,
+ 'persistent' => true,
+ 'timeout' => null,
+ 'connections' => array(), // host, port, path, timeout, transport, persistent, timeout, config -> (curl, headers, url)
+ 'roundRobin' => false,
+ 'log' => false,
+ 'retryOnConflict' => 0,
+ );
+
+ /**
+ * @var callback
+ */
+ protected $_callback = null;
+
+ /**
+ * @var \Elastica\Request
+ */
+ protected $_lastRequest;
+
+ /**
+ * @var \Elastica\Response
+ */
+ protected $_lastResponse;
+
+ /**
+ * @var LoggerInterface
+ */
+ protected $_logger = null;
+ /**
+ * @var Connection\ConnectionPool
+ */
+ protected $_connectionPool = null;
+
+ /**
+ * Creates a new Elastica client.
+ *
+ * @param array $config OPTIONAL Additional config options
+ * @param callback $callback OPTIONAL Callback function which can be used to be notified about errors (for example connection down)
+ */
+ public function __construct(array $config = array(), $callback = null)
+ {
+ $this->setConfig($config);
+ $this->_callback = $callback;
+ $this->_initConnections();
+ }
+
+ /**
+ * Inits the client connections.
+ */
+ protected function _initConnections()
+ {
+ $connections = array();
+
+ foreach ($this->getConfig('connections') as $connection) {
+ $connections[] = Connection::create($this->_prepareConnectionParams($connection));
+ }
+
+ if (isset($this->_config['servers'])) {
+ foreach ($this->getConfig('servers') as $server) {
+ $connections[] = Connection::create($this->_prepareConnectionParams($server));
+ }
+ }
+
+ // If no connections set, create default connection
+ if (empty($connections)) {
+ $connections[] = Connection::create($this->_prepareConnectionParams($this->getConfig()));
+ }
+
+ if (!isset($this->_config['connectionStrategy'])) {
+ if ($this->getConfig('roundRobin') === true) {
+ $this->setConfigValue('connectionStrategy', 'RoundRobin');
+ } else {
+ $this->setConfigValue('connectionStrategy', 'Simple');
+ }
+ }
+
+ $strategy = Connection\Strategy\StrategyFactory::create($this->getConfig('connectionStrategy'));
+
+ $this->_connectionPool = new Connection\ConnectionPool($connections, $strategy, $this->_callback);
+ }
+
+ /**
+ * Creates a Connection params array from a Client or server config array.
+ *
+ * @param array $config
+ *
+ * @return array
+ */
+ protected function _prepareConnectionParams(array $config)
+ {
+ $params = array();
+ $params['config'] = array();
+ foreach ($config as $key => $value) {
+ if (in_array($key, array('curl', 'headers', 'url'))) {
+ $params['config'][$key] = $value;
+ } else {
+ $params[$key] = $value;
+ }
+ }
+
+ return $params;
+ }
+
+ /**
+ * Sets specific config values (updates and keeps default values).
+ *
+ * @param array $config Params
+ *
+ * @return $this
+ */
+ public function setConfig(array $config)
+ {
+ foreach ($config as $key => $value) {
+ $this->_config[$key] = $value;
+ }
+
+ return $this;
+ }
+
+ /**
+ * Returns a specific config key or the whole
+ * config array if not set.
+ *
+ * @param string $key Config key
+ *
+ * @throws \Elastica\Exception\InvalidException
+ *
+ * @return array|string Config value
+ */
+ public function getConfig($key = '')
+ {
+ if (empty($key)) {
+ return $this->_config;
+ }
+
+ if (!array_key_exists($key, $this->_config)) {
+ throw new InvalidException('Config key is not set: '.$key);
+ }
+
+ return $this->_config[$key];
+ }
+
+ /**
+ * Sets / overwrites a specific config value.
+ *
+ * @param string $key Key to set
+ * @param mixed $value Value
+ *
+ * @return $this
+ */
+ public function setConfigValue($key, $value)
+ {
+ return $this->setConfig(array($key => $value));
+ }
+
+ /**
+ * @param array|string $keys config key or path of config keys
+ * @param mixed $default default value will be returned if key was not found
+ *
+ * @return mixed
+ */
+ public function getConfigValue($keys, $default = null)
+ {
+ $value = $this->_config;
+ foreach ((array) $keys as $key) {
+ if (isset($value[$key])) {
+ $value = $value[$key];
+ } else {
+ return $default;
+ }
+ }
+
+ return $value;
+ }
+
+ /**
+ * Returns the index for the given connection.
+ *
+ * @param string $name Index name to create connection to
+ *
+ * @return \Elastica\Index Index for the given name
+ */
+ public function getIndex($name)
+ {
+ return new Index($this, $name);
+ }
+
+ /**
+ * Adds a HTTP Header.
+ *
+ * @param string $header The HTTP Header
+ * @param string $headerValue The HTTP Header Value
+ *
+ * @throws \Elastica\Exception\InvalidException If $header or $headerValue is not a string
+ *
+ * @return $this
+ */
+ public function addHeader($header, $headerValue)
+ {
+ if (is_string($header) && is_string($headerValue)) {
+ $this->_config['headers'][$header] = $headerValue;
+ } else {
+ throw new InvalidException('Header must be a string');
+ }
+
+ return $this;
+ }
+
+ /**
+ * Remove a HTTP Header.
+ *
+ * @param string $header The HTTP Header to remove
+ *
+ * @throws \Elastica\Exception\InvalidException If $header is not a string
+ *
+ * @return $this
+ */
+ public function removeHeader($header)
+ {
+ if (is_string($header)) {
+ if (array_key_exists($header, $this->_config['headers'])) {
+ unset($this->_config['headers'][$header]);
+ }
+ } else {
+ throw new InvalidException('Header must be a string');
+ }
+
+ return $this;
+ }
+
+ /**
+ * Uses _bulk to send documents to the server.
+ *
+ * Array of \Elastica\Document as input. Index and type has to be
+ * set inside the document, because for bulk settings documents,
+ * documents can belong to any type and index
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/docs-bulk.html
+ *
+ * @param array|\Elastica\Document[] $docs Array of Elastica\Document
+ *
+ * @throws \Elastica\Exception\InvalidException If docs is empty
+ *
+ * @return \Elastica\Bulk\ResponseSet Response object
+ */
+ public function updateDocuments(array $docs)
+ {
+ if (empty($docs)) {
+ throw new InvalidException('Array has to consist of at least one element');
+ }
+
+ $bulk = new Bulk($this);
+
+ $bulk->addDocuments($docs, \Elastica\Bulk\Action::OP_TYPE_UPDATE);
+
+ return $bulk->send();
+ }
+
+ /**
+ * Uses _bulk to send documents to the server.
+ *
+ * Array of \Elastica\Document as input. Index and type has to be
+ * set inside the document, because for bulk settings documents,
+ * documents can belong to any type and index
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/docs-bulk.html
+ *
+ * @param array|\Elastica\Document[] $docs Array of Elastica\Document
+ *
+ * @throws \Elastica\Exception\InvalidException If docs is empty
+ *
+ * @return \Elastica\Bulk\ResponseSet Response object
+ */
+ public function addDocuments(array $docs)
+ {
+ if (empty($docs)) {
+ throw new InvalidException('Array has to consist of at least one element');
+ }
+
+ $bulk = new Bulk($this);
+
+ $bulk->addDocuments($docs);
+
+ return $bulk->send();
+ }
+
+ /**
+ * Update document, using update script. Requires elasticsearch >= 0.19.0.
+ *
+ * @param int $id document id
+ * @param array|\Elastica\Script|\Elastica\Document $data raw data for request body
+ * @param string $index index to update
+ * @param string $type type of index to update
+ * @param array $options array of query params to use for query. For possible options check es api
+ *
+ * @return \Elastica\Response
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/docs-update.html
+ */
+ public function updateDocument($id, $data, $index, $type, array $options = array())
+ {
+ $path = $index.'/'.$type.'/'.$id.'/_update';
+
+ if ($data instanceof Script) {
+ $requestData = $data->toArray();
+ } elseif ($data instanceof Document) {
+ $requestData = array('doc' => $data->getData());
+
+ if ($data->getDocAsUpsert()) {
+ $requestData['doc_as_upsert'] = true;
+ }
+
+ $docOptions = $data->getOptions(
+ array(
+ 'version',
+ 'version_type',
+ 'routing',
+ 'percolate',
+ 'parent',
+ 'fields',
+ 'retry_on_conflict',
+ 'consistency',
+ 'replication',
+ 'refresh',
+ 'timeout',
+ )
+ );
+ $options += $docOptions;
+ // set fields param to source only if options was not set before
+ if ($data instanceof Document && ($data->isAutoPopulate()
+ || $this->getConfigValue(array('document', 'autoPopulate'), false))
+ && !isset($options['fields'])
+ ) {
+ $options['fields'] = '_source';
+ }
+ } else {
+ $requestData = $data;
+ }
+
+ //If an upsert document exists
+ if ($data instanceof Script || $data instanceof Document) {
+ if ($data->hasUpsert()) {
+ $requestData['upsert'] = $data->getUpsert()->getData();
+ }
+ }
+
+ if (!isset($options['retry_on_conflict'])) {
+ $retryOnConflict = $this->getConfig('retryOnConflict');
+ $options['retry_on_conflict'] = $retryOnConflict;
+ }
+
+ $response = $this->request($path, Request::POST, $requestData, $options);
+
+ if ($response->isOk()
+ && $data instanceof Document
+ && ($data->isAutoPopulate() || $this->getConfigValue(array('document', 'autoPopulate'), false))
+ ) {
+ $responseData = $response->getData();
+ if (isset($responseData['_version'])) {
+ $data->setVersion($responseData['_version']);
+ }
+ if (isset($options['fields'])) {
+ $this->_populateDocumentFieldsFromResponse($response, $data, $options['fields']);
+ }
+ }
+
+ return $response;
+ }
+
+ /**
+ * @param \Elastica\Response $response
+ * @param \Elastica\Document $document
+ * @param string $fields Array of field names to be populated or '_source' if whole document data should be updated
+ */
+ protected function _populateDocumentFieldsFromResponse(Response $response, Document $document, $fields)
+ {
+ $responseData = $response->getData();
+ if ('_source' == $fields) {
+ if (isset($responseData['get']['_source']) && is_array($responseData['get']['_source'])) {
+ $document->setData($responseData['get']['_source']);
+ }
+ } else {
+ $keys = explode(',', $fields);
+ $data = $document->getData();
+ foreach ($keys as $key) {
+ if (isset($responseData['get']['fields'][$key])) {
+ $data[$key] = $responseData['get']['fields'][$key];
+ } elseif (isset($data[$key])) {
+ unset($data[$key]);
+ }
+ }
+ $document->setData($data);
+ }
+ }
+
+ /**
+ * Bulk deletes documents.
+ *
+ * @param array|\Elastica\Document[] $docs
+ *
+ * @throws \Elastica\Exception\InvalidException
+ *
+ * @return \Elastica\Bulk\ResponseSet
+ */
+ public function deleteDocuments(array $docs)
+ {
+ if (empty($docs)) {
+ throw new InvalidException('Array has to consist of at least one element');
+ }
+
+ $bulk = new Bulk($this);
+ $bulk->addDocuments($docs, Action::OP_TYPE_DELETE);
+
+ return $bulk->send();
+ }
+
+ /**
+ * Returns the status object for all indices.
+ *
+ * @return \Elastica\Status Status object
+ */
+ public function getStatus()
+ {
+ return new Status($this);
+ }
+
+ /**
+ * Returns the current cluster.
+ *
+ * @return \Elastica\Cluster Cluster object
+ */
+ public function getCluster()
+ {
+ return new Cluster($this);
+ }
+
+ /**
+ * @param \Elastica\Connection $connection
+ *
+ * @return $this
+ */
+ public function addConnection(Connection $connection)
+ {
+ $this->_connectionPool->addConnection($connection);
+
+ return $this;
+ }
+
+ /**
+ * Determines whether a valid connection is available for use.
+ *
+ * @return bool
+ */
+ public function hasConnection()
+ {
+ return $this->_connectionPool->hasConnection();
+ }
+
+ /**
+ * @throws \Elastica\Exception\ClientException
+ *
+ * @return \Elastica\Connection
+ */
+ public function getConnection()
+ {
+ return $this->_connectionPool->getConnection();
+ }
+
+ /**
+ * @return \Elastica\Connection[]
+ */
+ public function getConnections()
+ {
+ return $this->_connectionPool->getConnections();
+ }
+
+ /**
+ * @return \Elastica\Connection\Strategy\StrategyInterface
+ */
+ public function getConnectionStrategy()
+ {
+ return $this->_connectionPool->getStrategy();
+ }
+
+ /**
+ * @param array|\Elastica\Connection[] $connections
+ *
+ * @return $this
+ */
+ public function setConnections(array $connections)
+ {
+ $this->_connectionPool->setConnections($connections);
+
+ return $this;
+ }
+
+ /**
+ * Deletes documents with the given ids, index, type from the index.
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/docs-bulk.html
+ *
+ * @param array $ids Document ids
+ * @param string|\Elastica\Index $index Index name
+ * @param string|\Elastica\Type $type Type of documents
+ * @param string|false $routing Optional routing key for all ids
+ *
+ * @throws \Elastica\Exception\InvalidException
+ *
+ * @return \Elastica\Bulk\ResponseSet Response object
+ */
+ public function deleteIds(array $ids, $index, $type, $routing = false)
+ {
+ if (empty($ids)) {
+ throw new InvalidException('Array has to consist of at least one id');
+ }
+
+ $bulk = new Bulk($this);
+ $bulk->setIndex($index);
+ $bulk->setType($type);
+
+ foreach ($ids as $id) {
+ $action = new Action(Action::OP_TYPE_DELETE);
+ $action->setId($id);
+
+ if (!empty($routing)) {
+ $action->setRouting($routing);
+ }
+
+ $bulk->addAction($action);
+ }
+
+ return $bulk->send();
+ }
+
+ /**
+ * Bulk operation.
+ *
+ * Every entry in the params array has to exactly on array
+ * of the bulk operation. An example param array would be:
+ *
+ * array(
+ * array('index' => array('_index' => 'test', '_type' => 'user', '_id' => '1')),
+ * array('user' => array('name' => 'hans')),
+ * array('delete' => array('_index' => 'test', '_type' => 'user', '_id' => '2'))
+ * );
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/docs-bulk.html
+ *
+ * @param array $params Parameter array
+ *
+ * @throws \Elastica\Exception\ResponseException
+ * @throws \Elastica\Exception\InvalidException
+ *
+ * @return \Elastica\Bulk\ResponseSet Response object
+ */
+ public function bulk(array $params)
+ {
+ if (empty($params)) {
+ throw new InvalidException('Array has to consist of at least one param');
+ }
+
+ $bulk = new Bulk($this);
+
+ $bulk->addRawData($params);
+
+ return $bulk->send();
+ }
+
+ /**
+ * Makes calls to the elasticsearch server based on this index.
+ *
+ * It's possible to make any REST query directly over this method
+ *
+ * @param string $path Path to call
+ * @param string $method Rest method to use (GET, POST, DELETE, PUT)
+ * @param array $data OPTIONAL Arguments as array
+ * @param array $query OPTIONAL Query params
+ *
+ * @throws Exception\ConnectionException|\Exception
+ *
+ * @return \Elastica\Response Response object
+ */
+ public function request($path, $method = Request::GET, $data = array(), array $query = array())
+ {
+ $connection = $this->getConnection();
+ try {
+ $request = new Request($path, $method, $data, $query, $connection);
+
+ $this->_log($request);
+
+ $response = $request->send();
+
+ $this->_lastRequest = $request;
+ $this->_lastResponse = $response;
+
+ return $response;
+ } catch (ConnectionException $e) {
+ $this->_connectionPool->onFail($connection, $e, $this);
+
+ // In case there is no valid connection left, throw exception which caused the disabling of the connection.
+ if (!$this->hasConnection()) {
+ throw $e;
+ }
+
+ return $this->request($path, $method, $data, $query);
+ }
+ }
+
+ /**
+ * Optimizes all search indices.
+ *
+ * @param array $args OPTIONAL Optional arguments
+ *
+ * @return \Elastica\Response Response object
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/indices-optimize.html
+ */
+ public function optimizeAll($args = array())
+ {
+ return $this->request('_optimize', Request::POST, array(), $args);
+ }
+
+ /**
+ * Refreshes all search indices.
+ *
+ * @return \Elastica\Response Response object
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/indices-refresh.html
+ */
+ public function refreshAll()
+ {
+ return $this->request('_refresh', Request::POST);
+ }
+
+ /**
+ * logging.
+ *
+ * @param string|\Elastica\Request $context
+ *
+ * @throws Exception\RuntimeException
+ */
+ protected function _log($context)
+ {
+ $log = $this->getConfig('log');
+ if ($log && !class_exists('Psr\Log\AbstractLogger')) {
+ throw new RuntimeException('Class Psr\Log\AbstractLogger not found');
+ } elseif (!$this->_logger && $log) {
+ $this->setLogger(new Log($this->getConfig('log')));
+ }
+ if ($this->_logger) {
+ if ($context instanceof Request) {
+ $data = $context->toArray();
+ } else {
+ $data = array('message' => $context);
+ }
+ $this->_logger->debug('logging Request', $data);
+ }
+ }
+
+ /**
+ * @return \Elastica\Request
+ */
+ public function getLastRequest()
+ {
+ return $this->_lastRequest;
+ }
+
+ /**
+ * @return \Elastica\Response
+ */
+ public function getLastResponse()
+ {
+ return $this->_lastResponse;
+ }
+
+ /**
+ * set Logger.
+ *
+ * @param LoggerInterface $logger
+ *
+ * @return $this
+ */
+ public function setLogger(LoggerInterface $logger)
+ {
+ $this->_logger = $logger;
+
+ return $this;
+ }
+}
diff --git a/vendor/ruflin/elastica/lib/Elastica/Cluster.php b/vendor/ruflin/elastica/lib/Elastica/Cluster.php
new file mode 100644
index 00000000..990aeeb2
--- /dev/null
+++ b/vendor/ruflin/elastica/lib/Elastica/Cluster.php
@@ -0,0 +1,192 @@
+<?php
+namespace Elastica;
+
+use Elastica\Cluster\Health;
+use Elastica\Cluster\Settings;
+use Elastica\Exception\NotImplementedException;
+
+/**
+ * Cluster informations for elasticsearch.
+ *
+ * @author Nicolas Ruflin <spam@ruflin.com>
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/cluster.html
+ */
+class Cluster
+{
+ /**
+ * Client.
+ *
+ * @var \Elastica\Client Client object
+ */
+ protected $_client = null;
+
+ /**
+ * Cluster state response.
+ *
+ * @var \Elastica\Response
+ */
+ protected $_response;
+
+ /**
+ * Cluster state data.
+ *
+ * @var array
+ */
+ protected $_data;
+
+ /**
+ * Creates a cluster object.
+ *
+ * @param \Elastica\Client $client Connection client object
+ */
+ public function __construct(Client $client)
+ {
+ $this->_client = $client;
+ $this->refresh();
+ }
+
+ /**
+ * Refreshes all cluster information (state).
+ */
+ public function refresh()
+ {
+ $path = '_cluster/state';
+ $this->_response = $this->_client->request($path, Request::GET);
+ $this->_data = $this->getResponse()->getData();
+ }
+
+ /**
+ * Returns the response object.
+ *
+ * @return \Elastica\Response Response object
+ */
+ public function getResponse()
+ {
+ return $this->_response;
+ }
+
+ /**
+ * Return list of index names.
+ *
+ * @return array List of index names
+ */
+ public function getIndexNames()
+ {
+ $metaData = $this->_data['metadata']['indices'];
+
+ $indices = array();
+ foreach ($metaData as $key => $value) {
+ $indices[] = $key;
+ }
+
+ return $indices;
+ }
+
+ /**
+ * Returns the full state of the cluster.
+ *
+ * @return array State array
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/cluster-state.html
+ */
+ public function getState()
+ {
+ return $this->_data;
+ }
+
+ /**
+ * Returns a list of existing node names.
+ *
+ * @return array List of node names
+ */
+ public function getNodeNames()
+ {
+ $data = $this->getState();
+ $nodeNames = array();
+ foreach ($data['nodes'] as $node) {
+ $nodeNames[] = $node['name'];
+ }
+
+ return $nodeNames;
+ }
+
+ /**
+ * Returns all nodes of the cluster.
+ *
+ * @return \Elastica\Node[]
+ */
+ public function getNodes()
+ {
+ $nodes = array();
+ $data = $this->getState();
+
+ foreach ($data['nodes'] as $id => $name) {
+ $nodes[] = new Node($id, $this->getClient());
+ }
+
+ return $nodes;
+ }
+
+ /**
+ * Returns the client object.
+ *
+ * @return \Elastica\Client Client object
+ */
+ public function getClient()
+ {
+ return $this->_client;
+ }
+
+ /**
+ * Returns the cluster information (not implemented yet).
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/cluster-nodes-info.html
+ *
+ * @param array $args Additional arguments
+ *
+ * @throws \Elastica\Exception\NotImplementedException
+ */
+ public function getInfo(array $args)
+ {
+ throw new NotImplementedException('not implemented yet');
+ }
+
+ /**
+ * Return Cluster health.
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/cluster-health.html
+ *
+ * @return \Elastica\Cluster\Health
+ */
+ public function getHealth()
+ {
+ return new Health($this->getClient());
+ }
+
+ /**
+ * Return Cluster settings.
+ *
+ * @return \Elastica\Cluster\Settings
+ */
+ public function getSettings()
+ {
+ return new Settings($this->getClient());
+ }
+
+ /**
+ * Shuts down the complete cluster.
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/cluster-nodes-shutdown.html
+ *
+ * @param string $delay OPTIONAL Seconds to shutdown cluster after (default = 1s)
+ *
+ * @return \Elastica\Response
+ */
+ public function shutdown($delay = '1s')
+ {
+ $path = '_shutdown?delay='.$delay;
+
+ return $this->_client->request($path, Request::POST);
+ }
+}
diff --git a/vendor/ruflin/elastica/lib/Elastica/Cluster/Health.php b/vendor/ruflin/elastica/lib/Elastica/Cluster/Health.php
new file mode 100644
index 00000000..d5d25ff1
--- /dev/null
+++ b/vendor/ruflin/elastica/lib/Elastica/Cluster/Health.php
@@ -0,0 +1,185 @@
+<?php
+namespace Elastica\Cluster;
+
+use Elastica\Client;
+use Elastica\Cluster\Health\Index;
+use Elastica\Request;
+
+/**
+ * Elastic cluster health.
+ *
+ * @author Ray Ward <ray.ward@bigcommerce.com>
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/cluster-health.html
+ */
+class Health
+{
+ /**
+ * @var \Elastica\Client Client object.
+ */
+ protected $_client = null;
+
+ /**
+ * @var array The cluster health data.
+ */
+ protected $_data = null;
+
+ /**
+ * @param \Elastica\Client $client The Elastica client.
+ */
+ public function __construct(Client $client)
+ {
+ $this->_client = $client;
+ $this->refresh();
+ }
+
+ /**
+ * Retrieves the health data from the cluster.
+ *
+ * @return array
+ */
+ protected function _retrieveHealthData()
+ {
+ $path = '_cluster/health?level=shards';
+ $response = $this->_client->request($path, Request::GET);
+
+ return $response->getData();
+ }
+
+ /**
+ * Gets the health data.
+ *
+ * @return array
+ */
+ public function getData()
+ {
+ return $this->_data;
+ }
+
+ /**
+ * Refreshes the health data for the cluster.
+ *
+ * @return $this
+ */
+ public function refresh()
+ {
+ $this->_data = $this->_retrieveHealthData();
+
+ return $this;
+ }
+
+ /**
+ * Gets the name of the cluster.
+ *
+ * @return string
+ */
+ public function getClusterName()
+ {
+ return $this->_data['cluster_name'];
+ }
+
+ /**
+ * Gets the status of the cluster.
+ *
+ * @return string green, yellow or red.
+ */
+ public function getStatus()
+ {
+ return $this->_data['status'];
+ }
+
+ /**
+ * TODO determine the purpose of this.
+ *
+ * @return bool
+ */
+ public function getTimedOut()
+ {
+ return $this->_data['timed_out'];
+ }
+
+ /**
+ * Gets the number of nodes in the cluster.
+ *
+ * @return int
+ */
+ public function getNumberOfNodes()
+ {
+ return $this->_data['number_of_nodes'];
+ }
+
+ /**
+ * Gets the number of data nodes in the cluster.
+ *
+ * @return int
+ */
+ public function getNumberOfDataNodes()
+ {
+ return $this->_data['number_of_data_nodes'];
+ }
+
+ /**
+ * Gets the number of active primary shards.
+ *
+ * @return int
+ */
+ public function getActivePrimaryShards()
+ {
+ return $this->_data['active_primary_shards'];
+ }
+
+ /**
+ * Gets the number of active shards.
+ *
+ * @return int
+ */
+ public function getActiveShards()
+ {
+ return $this->_data['active_shards'];
+ }
+
+ /**
+ * Gets the number of relocating shards.
+ *
+ * @return int
+ */
+ public function getRelocatingShards()
+ {
+ return $this->_data['relocating_shards'];
+ }
+
+ /**
+ * Gets the number of initializing shards.
+ *
+ * @return int
+ */
+ public function getInitializingShards()
+ {
+ return $this->_data['initializing_shards'];
+ }
+
+ /**
+ * Gets the number of unassigned shards.
+ *
+ * @return int
+ */
+ public function getUnassignedShards()
+ {
+ return $this->_data['unassigned_shards'];
+ }
+
+ /**
+ * Gets the status of the indices.
+ *
+ * @return \Elastica\Cluster\Health\Index[]
+ */
+ public function getIndices()
+ {
+ $indices = array();
+ foreach ($this->_data['indices'] as $indexName => $index) {
+ $indices[] = new Index($indexName, $index);
+ }
+
+ return $indices;
+ }
+}
diff --git a/vendor/ruflin/elastica/lib/Elastica/Cluster/Health/Index.php b/vendor/ruflin/elastica/lib/Elastica/Cluster/Health/Index.php
new file mode 100644
index 00000000..ef55bd00
--- /dev/null
+++ b/vendor/ruflin/elastica/lib/Elastica/Cluster/Health/Index.php
@@ -0,0 +1,137 @@
+<?php
+namespace Elastica\Cluster\Health;
+
+/**
+ * Wraps status information for an index.
+ *
+ * @author Ray Ward <ray.ward@bigcommerce.com>
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/cluster-health.html
+ */
+class Index
+{
+ /**
+ * @var string The name of the index.
+ */
+ protected $_name;
+
+ /**
+ * @var array The index health data.
+ */
+ protected $_data;
+
+ /**
+ * @param string $name The name of the index.
+ * @param array $data The index health data.
+ */
+ public function __construct($name, $data)
+ {
+ $this->_name = $name;
+ $this->_data = $data;
+ }
+
+ /**
+ * Gets the name of the index.
+ *
+ * @return string
+ */
+ public function getName()
+ {
+ return $this->_name;
+ }
+
+ /**
+ * Gets the status of the index.
+ *
+ * @return string green, yellow or red.
+ */
+ public function getStatus()
+ {
+ return $this->_data['status'];
+ }
+
+ /**
+ * Gets the number of nodes in the index.
+ *
+ * @return int
+ */
+ public function getNumberOfShards()
+ {
+ return $this->_data['number_of_shards'];
+ }
+
+ /**
+ * Gets the number of data nodes in the index.
+ *
+ * @return int
+ */
+ public function getNumberOfReplicas()
+ {
+ return $this->_data['number_of_replicas'];
+ }
+
+ /**
+ * Gets the number of active primary shards.
+ *
+ * @return int
+ */
+ public function getActivePrimaryShards()
+ {
+ return $this->_data['active_primary_shards'];
+ }
+
+ /**
+ * Gets the number of active shards.
+ *
+ * @return int
+ */
+ public function getActiveShards()
+ {
+ return $this->_data['active_shards'];
+ }
+
+ /**
+ * Gets the number of relocating shards.
+ *
+ * @return int
+ */
+ public function getRelocatingShards()
+ {
+ return $this->_data['relocating_shards'];
+ }
+
+ /**
+ * Gets the number of initializing shards.
+ *
+ * @return int
+ */
+ public function getInitializingShards()
+ {
+ return $this->_data['initializing_shards'];
+ }
+
+ /**
+ * Gets the number of unassigned shards.
+ *
+ * @return int
+ */
+ public function getUnassignedShards()
+ {
+ return $this->_data['unassigned_shards'];
+ }
+
+ /**
+ * Gets the health of the shards in this index.
+ *
+ * @return \Elastica\Cluster\Health\Shard[]
+ */
+ public function getShards()
+ {
+ $shards = array();
+ foreach ($this->_data['shards'] as $shardNumber => $shard) {
+ $shards[] = new Shard($shardNumber, $shard);
+ }
+
+ return $shards;
+ }
+}
diff --git a/vendor/ruflin/elastica/lib/Elastica/Cluster/Health/Shard.php b/vendor/ruflin/elastica/lib/Elastica/Cluster/Health/Shard.php
new file mode 100644
index 00000000..e1d2c8dc
--- /dev/null
+++ b/vendor/ruflin/elastica/lib/Elastica/Cluster/Health/Shard.php
@@ -0,0 +1,102 @@
+<?php
+namespace Elastica\Cluster\Health;
+
+/**
+ * Wraps status information for a shard.
+ *
+ * @author Ray Ward <ray.ward@bigcommerce.com>
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/cluster-health.html
+ */
+class Shard
+{
+ /**
+ * @var int The shard index/number.
+ */
+ protected $_shardNumber;
+
+ /**
+ * @var array The shard health data.
+ */
+ protected $_data;
+
+ /**
+ * @param int $shardNumber The shard index/number.
+ * @param array $data The shard health data.
+ */
+ public function __construct($shardNumber, $data)
+ {
+ $this->_shardNumber = $shardNumber;
+ $this->_data = $data;
+ }
+
+ /**
+ * Gets the index/number of this shard.
+ *
+ * @return int
+ */
+ public function getShardNumber()
+ {
+ return $this->_shardNumber;
+ }
+
+ /**
+ * Gets the status of this shard.
+ *
+ * @return string green, yellow or red.
+ */
+ public function getStatus()
+ {
+ return $this->_data['status'];
+ }
+
+ /**
+ * Is the primary active?
+ *
+ * @return bool
+ */
+ public function isPrimaryActive()
+ {
+ return $this->_data['primary_active'];
+ }
+
+ /**
+ * Is this shard active?
+ *
+ * @return bool
+ */
+ public function isActive()
+ {
+ return $this->_data['active_shards'] == 1;
+ }
+
+ /**
+ * Is this shard relocating?
+ *
+ * @return bool
+ */
+ public function isRelocating()
+ {
+ return $this->_data['relocating_shards'] == 1;
+ }
+
+ /**
+ * Is this shard initialized?
+ *
+ * @return bool
+ */
+ public function isInitialized()
+ {
+ return $this->_data['initializing_shards'] == 1;
+ }
+
+ /**
+ * Is this shard unassigned?
+ *
+ * @return bool
+ */
+ public function isUnassigned()
+ {
+ return $this->_data['unassigned_shards'] == 1;
+ }
+}
diff --git a/vendor/ruflin/elastica/lib/Elastica/Cluster/Settings.php b/vendor/ruflin/elastica/lib/Elastica/Cluster/Settings.php
new file mode 100644
index 00000000..c597417f
--- /dev/null
+++ b/vendor/ruflin/elastica/lib/Elastica/Cluster/Settings.php
@@ -0,0 +1,202 @@
+<?php
+namespace Elastica\Cluster;
+
+use Elastica\Client;
+use Elastica\Request;
+
+/**
+ * Cluster settings.
+ *
+ * @author Nicolas Ruflin <spam@ruflin.com>
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/cluster-update-settings.html
+ */
+class Settings
+{
+ /**
+ * @var \Elastica\Client Client object
+ */
+ protected $_client = null;
+
+ /**
+ * Creates a cluster object.
+ *
+ * @param \Elastica\Client $client Connection client object
+ */
+ public function __construct(Client $client)
+ {
+ $this->_client = $client;
+ }
+
+ /**
+ * Returns settings data.
+ *
+ * @return array Settings data (persistent and transient)
+ */
+ public function get()
+ {
+ return $this->request()->getData();
+ }
+
+ /**
+ * Returns the current persistent settings of the cluster.
+ *
+ * If param is set, only specified setting is return.
+ *
+ * @param string $setting OPTIONAL Setting name to return
+ *
+ * @return array|string|null Settings data
+ */
+ public function getPersistent($setting = '')
+ {
+ $data = $this->get();
+ $settings = $data['persistent'];
+
+ if (!empty($setting)) {
+ if (isset($settings[$setting])) {
+ return $settings[$setting];
+ } else {
+ return;
+ }
+ }
+
+ return $settings;
+ }
+
+ /**
+ * Returns the current transient settings of the cluster.
+ *
+ * If param is set, only specified setting is return.
+ *
+ * @param string $setting OPTIONAL Setting name to return
+ *
+ * @return array|string|null Settings data
+ */
+ public function getTransient($setting = '')
+ {
+ $data = $this->get();
+ $settings = $data['transient'];
+
+ if (!empty($setting)) {
+ if (isset($settings[$setting])) {
+ return $settings[$setting];
+ } else {
+ if (strpos($setting, '.') !== false) {
+ // convert dot notation to nested arrays
+ $keys = explode('.', $setting);
+ foreach ($keys as $key) {
+ if (isset($settings[$key])) {
+ $settings = $settings[$key];
+ } else {
+ return;
+ }
+ }
+
+ return $settings;
+ }
+
+ return;
+ }
+ }
+
+ return $settings;
+ }
+
+ /**
+ * Sets persistent setting.
+ *
+ * @param string $key
+ * @param string $value
+ *
+ * @return \Elastica\Response
+ */
+ public function setPersistent($key, $value)
+ {
+ return $this->set(
+ array(
+ 'persistent' => array(
+ $key => $value,
+ ),
+ )
+ );
+ }
+
+ /**
+ * Sets transient settings.
+ *
+ * @param string $key
+ * @param string $value
+ *
+ * @return \Elastica\Response
+ */
+ public function setTransient($key, $value)
+ {
+ return $this->set(
+ array(
+ 'transient' => array(
+ $key => $value,
+ ),
+ )
+ );
+ }
+
+ /**
+ * Sets the cluster to read only.
+ *
+ * Second param can be used to set it persistent
+ *
+ * @param bool $readOnly
+ * @param bool $persistent
+ *
+ * @return \Elastica\Response $response
+ */
+ public function setReadOnly($readOnly = true, $persistent = false)
+ {
+ $key = 'cluster.blocks.read_only';
+
+ if ($persistent) {
+ $response = $this->setPersistent($key, $readOnly);
+ } else {
+ $response = $this->setTransient($key, $readOnly);
+ }
+
+ return $response;
+ }
+
+ /**
+ * Set settings for cluster.
+ *
+ * @param array $settings Raw settings (including persistent or transient)
+ *
+ * @return \Elastica\Response
+ */
+ public function set(array $settings)
+ {
+ return $this->request($settings, Request::PUT);
+ }
+
+ /**
+ * Get the client.
+ *
+ * @return \Elastica\Client
+ */
+ public function getClient()
+ {
+ return $this->_client;
+ }
+
+ /**
+ * Sends settings request.
+ *
+ * @param array $data OPTIONAL Data array
+ * @param string $method OPTIONAL Transfer method (default = \Elastica\Request::GET)
+ *
+ * @return \Elastica\Response Response object
+ */
+ public function request(array $data = array(), $method = Request::GET)
+ {
+ $path = '_cluster/settings';
+
+ return $this->getClient()->request($path, $method, $data);
+ }
+}
diff --git a/vendor/ruflin/elastica/lib/Elastica/Connection.php b/vendor/ruflin/elastica/lib/Elastica/Connection.php
new file mode 100644
index 00000000..0084b6ee
--- /dev/null
+++ b/vendor/ruflin/elastica/lib/Elastica/Connection.php
@@ -0,0 +1,320 @@
+<?php
+namespace Elastica;
+
+use Elastica\Exception\InvalidException;
+use Elastica\Transport\AbstractTransport;
+
+/**
+ * Elastica connection instance to an elasticasearch node.
+ *
+ * @author Nicolas Ruflin <spam@ruflin.com>
+ */
+class Connection extends Param
+{
+ /**
+ * Default elastic search port.
+ */
+ const DEFAULT_PORT = 9200;
+
+ /**
+ * Default host.
+ */
+ const DEFAULT_HOST = 'localhost';
+
+ /**
+ * Default transport.
+ *
+ * @var string
+ */
+ const DEFAULT_TRANSPORT = 'Http';
+
+ /**
+ * Number of seconds after a timeout occurs for every request
+ * If using indexing of file large value necessary.
+ */
+ const TIMEOUT = 300;
+
+ /**
+ * Number of seconds after a connection timeout occurs for every request during the connection phase.
+ *
+ * @see Connection::setConnectTimeout();
+ */
+ const CONNECT_TIMEOUT = 0;
+
+ /**
+ * Creates a new connection object. A connection is enabled by default.
+ *
+ * @param array $params OPTIONAL Connection params: host, port, transport, timeout. All are optional
+ */
+ public function __construct(array $params = array())
+ {
+ $this->setParams($params);
+ $this->setEnabled(true);
+
+ // Set empty config param if not exists
+ if (!$this->hasParam('config')) {
+ $this->setParam('config', array());
+ }
+ }
+
+ /**
+ * @return int Server port
+ */
+ public function getPort()
+ {
+ return $this->hasParam('port') ? $this->getParam('port') : self::DEFAULT_PORT;
+ }
+
+ /**
+ * @param int $port
+ *
+ * @return $this
+ */
+ public function setPort($port)
+ {
+ return $this->setParam('port', (int) $port);
+ }
+
+ /**
+ * @return string Host
+ */
+ public function getHost()
+ {
+ return $this->hasParam('host') ? $this->getParam('host') : self::DEFAULT_HOST;
+ }
+
+ /**
+ * @param string $host
+ *
+ * @return $this
+ */
+ public function setHost($host)
+ {
+ return $this->setParam('host', $host);
+ }
+
+ /**
+ * @return string|null Host
+ */
+ public function getProxy()
+ {
+ return $this->hasParam('proxy') ? $this->getParam('proxy') : null;
+ }
+
+ /**
+ * Set proxy for http connections. Null is for environmental proxy,
+ * empty string to disable proxy and proxy string to set actual http proxy.
+ *
+ * @see http://curl.haxx.se/libcurl/c/curl_easy_setopt.html#CURLOPTPROXY
+ *
+ * @param string|null $proxy
+ *
+ * @return $this
+ */
+ public function setProxy($proxy)
+ {
+ return $this->setParam('proxy', $proxy);
+ }
+
+ /**
+ * @return string|array
+ */
+ public function getTransport()
+ {
+ return $this->hasParam('transport') ? $this->getParam('transport') : self::DEFAULT_TRANSPORT;
+ }
+
+ /**
+ * @param string|array $transport
+ *
+ * @return $this
+ */
+ public function setTransport($transport)
+ {
+ return $this->setParam('transport', $transport);
+ }
+
+ /**
+ * @return string
+ */
+ public function getPath()
+ {
+ return $this->hasParam('path') ? $this->getParam('path') : '';
+ }
+
+ /**
+ * @param string $path
+ *
+ * @return $this
+ */
+ public function setPath($path)
+ {
+ return $this->setParam('path', $path);
+ }
+
+ /**
+ * @param int $timeout Timeout in seconds
+ *
+ * @return $this
+ */
+ public function setTimeout($timeout)
+ {
+ return $this->setParam('timeout', $timeout);
+ }
+
+ /**
+ * @return int Connection timeout in seconds
+ */
+ public function getTimeout()
+ {
+ return (int) $this->hasParam('timeout') ? $this->getParam('timeout') : self::TIMEOUT;
+ }
+
+ /**
+ * Number of seconds after a connection timeout occurs for every request during the connection phase.
+ * Use a small value if you need a fast fail in case of dead, unresponsive or unreachable servers (~5 sec).
+ *
+ * Set to zero to switch to the default built-in connection timeout (300 seconds in curl).
+ *
+ * @see http://curl.haxx.se/libcurl/c/CURLOPT_CONNECTTIMEOUT.html
+ *
+ * @param int $timeout Connect timeout in seconds
+ *
+ * @return $this
+ */
+ public function setConnectTimeout($timeout)
+ {
+ return $this->setParam('connectTimeout', $timeout);
+ }
+
+ /**
+ * @return int Connection timeout in seconds
+ */
+ public function getConnectTimeout()
+ {
+ return (int) $this->hasParam('connectTimeout') ? $this->getParam('connectTimeout') : self::CONNECT_TIMEOUT;
+ }
+
+ /**
+ * Enables a connection.
+ *
+ * @param bool $enabled OPTIONAL (default = true)
+ *
+ * @return $this
+ */
+ public function setEnabled($enabled = true)
+ {
+ return $this->setParam('enabled', $enabled);
+ }
+
+ /**
+ * @return bool True if enabled
+ */
+ public function isEnabled()
+ {
+ return (bool) $this->getParam('enabled');
+ }
+
+ /**
+ * Returns an instance of the transport type.
+ *
+ * @throws \Elastica\Exception\InvalidException If invalid transport type
+ *
+ * @return \Elastica\Transport\AbstractTransport Transport object
+ */
+ public function getTransportObject()
+ {
+ $transport = $this->getTransport();
+
+ return AbstractTransport::create($transport, $this);
+ }
+
+ /**
+ * @return bool Returns true if connection is persistent. True by default
+ */
+ public function isPersistent()
+ {
+ return (bool) $this->hasParam('persistent') ? $this->getParam('persistent') : true;
+ }
+
+ /**
+ * @param array $config
+ *
+ * @return $this
+ */
+ public function setConfig(array $config)
+ {
+ return $this->setParam('config', $config);
+ }
+
+ /**
+ * @param string $key
+ * @param mixed $value
+ *
+ * @return $this
+ */
+ public function addConfig($key, $value)
+ {
+ $this->_params['config'][$key] = $value;
+
+ return $this;
+ }
+
+ /**
+ * @param string $key
+ *
+ * @return bool
+ */
+ public function hasConfig($key)
+ {
+ $config = $this->getConfig();
+
+ return isset($config[$key]);
+ }
+
+ /**
+ * Returns a specific config key or the whole
+ * config array if not set.
+ *
+ * @param string $key Config key
+ *
+ * @throws \Elastica\Exception\InvalidException
+ *
+ * @return array|string Config value
+ */
+ public function getConfig($key = '')
+ {
+ $config = $this->getParam('config');
+ if (empty($key)) {
+ return $config;
+ }
+
+ if (!array_key_exists($key, $config)) {
+ throw new InvalidException('Config key is not set: '.$key);
+ }
+
+ return $config[$key];
+ }
+
+ /**
+ * @param \Elastica\Connection|array $params Params to create a connection
+ *
+ * @throws Exception\InvalidException
+ *
+ * @return self
+ */
+ public static function create($params = array())
+ {
+ $connection = null;
+
+ if ($params instanceof self) {
+ $connection = $params;
+ } elseif (is_array($params)) {
+ $connection = new self($params);
+ } else {
+ throw new InvalidException('Invalid data type');
+ }
+
+ return $connection;
+ }
+}
diff --git a/vendor/ruflin/elastica/lib/Elastica/Connection/ConnectionPool.php b/vendor/ruflin/elastica/lib/Elastica/Connection/ConnectionPool.php
new file mode 100644
index 00000000..b5fa681d
--- /dev/null
+++ b/vendor/ruflin/elastica/lib/Elastica/Connection/ConnectionPool.php
@@ -0,0 +1,122 @@
+<?php
+namespace Elastica\Connection;
+
+use Elastica\Client;
+use Elastica\Connection;
+use Elastica\Connection\Strategy\StrategyInterface;
+use Exception;
+
+/**
+ * Description of ConnectionPool.
+ *
+ * @author chabior
+ */
+class ConnectionPool
+{
+ /**
+ * @var array|\Elastica\Connection[] Connections array
+ */
+ protected $_connections;
+
+ /**
+ * @var \Elastica\Connection\Strategy\StrategyInterface Strategy for connection
+ */
+ protected $_strategy;
+
+ /**
+ * @var callback Function called on connection fail
+ */
+ protected $_callback;
+
+ /**
+ * @param array $connections
+ * @param \Elastica\Connection\Strategy\StrategyInterface $strategy
+ * @param callback $callback
+ */
+ public function __construct(array $connections, StrategyInterface $strategy, $callback = null)
+ {
+ $this->_connections = $connections;
+
+ $this->_strategy = $strategy;
+
+ $this->_callback = $callback;
+ }
+
+ /**
+ * @param \Elastica\Connection $connection
+ *
+ * @return $this
+ */
+ public function addConnection(Connection $connection)
+ {
+ $this->_connections[] = $connection;
+
+ return $this;
+ }
+
+ /**
+ * @param array|\Elastica\Connection[] $connections
+ *
+ * @return $this
+ */
+ public function setConnections(array $connections)
+ {
+ $this->_connections = $connections;
+
+ return $this;
+ }
+
+ /**
+ * @return bool
+ */
+ public function hasConnection()
+ {
+ foreach ($this->_connections as $connection) {
+ if ($connection->isEnabled()) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * @return array
+ */
+ public function getConnections()
+ {
+ return $this->_connections;
+ }
+
+ /**
+ * @throws \Elastica\Exception\ClientException
+ *
+ * @return \Elastica\Connection
+ */
+ public function getConnection()
+ {
+ return $this->_strategy->getConnection($this->getConnections());
+ }
+
+ /**
+ * @param \Elastica\Connection $connection
+ * @param \Exception $e
+ * @param Client $client
+ */
+ public function onFail(Connection $connection, Exception $e, Client $client)
+ {
+ $connection->setEnabled(false);
+
+ if ($this->_callback) {
+ call_user_func($this->_callback, $connection, $e, $client);
+ }
+ }
+
+ /**
+ * @return \Elastica\Connection\Strategy\StrategyInterface
+ */
+ public function getStrategy()
+ {
+ return $this->_strategy;
+ }
+}
diff --git a/vendor/ruflin/elastica/lib/Elastica/Connection/Strategy/CallbackStrategy.php b/vendor/ruflin/elastica/lib/Elastica/Connection/Strategy/CallbackStrategy.php
new file mode 100644
index 00000000..ccaeb6dd
--- /dev/null
+++ b/vendor/ruflin/elastica/lib/Elastica/Connection/Strategy/CallbackStrategy.php
@@ -0,0 +1,51 @@
+<?php
+namespace Elastica\Connection\Strategy;
+
+use Elastica\Exception\InvalidException;
+
+/**
+ * Description of CallbackStrategy.
+ *
+ * @author chabior
+ */
+class CallbackStrategy implements StrategyInterface
+{
+ /**
+ * @var callable
+ */
+ protected $_callback;
+
+ /**
+ * @param callable $callback
+ *
+ * @throws \Elastica\Exception\InvalidException
+ */
+ public function __construct($callback)
+ {
+ if (!self::isValid($callback)) {
+ throw new InvalidException(sprintf('Callback should be a callable, %s given!', gettype($callback)));
+ }
+
+ $this->_callback = $callback;
+ }
+
+ /**
+ * @param array|\Elastica\Connection[] $connections
+ *
+ * @return \Elastica\Connection
+ */
+ public function getConnection($connections)
+ {
+ return call_user_func_array($this->_callback, array($connections));
+ }
+
+ /**
+ * @param callable $callback
+ *
+ * @return bool
+ */
+ public static function isValid($callback)
+ {
+ return is_callable($callback);
+ }
+}
diff --git a/vendor/ruflin/elastica/lib/Elastica/Connection/Strategy/RoundRobin.php b/vendor/ruflin/elastica/lib/Elastica/Connection/Strategy/RoundRobin.php
new file mode 100644
index 00000000..92cd570e
--- /dev/null
+++ b/vendor/ruflin/elastica/lib/Elastica/Connection/Strategy/RoundRobin.php
@@ -0,0 +1,24 @@
+<?php
+namespace Elastica\Connection\Strategy;
+
+/**
+ * Description of RoundRobin.
+ *
+ * @author chabior
+ */
+class RoundRobin extends Simple
+{
+ /**
+ * @param array|\Elastica\Connection[] $connections
+ *
+ * @throws \Elastica\Exception\ClientException
+ *
+ * @return \Elastica\Connection
+ */
+ public function getConnection($connections)
+ {
+ shuffle($connections);
+
+ return parent::getConnection($connections);
+ }
+}
diff --git a/vendor/ruflin/elastica/lib/Elastica/Connection/Strategy/Simple.php b/vendor/ruflin/elastica/lib/Elastica/Connection/Strategy/Simple.php
new file mode 100644
index 00000000..7c42dd3b
--- /dev/null
+++ b/vendor/ruflin/elastica/lib/Elastica/Connection/Strategy/Simple.php
@@ -0,0 +1,30 @@
+<?php
+namespace Elastica\Connection\Strategy;
+
+use Elastica\Exception\ClientException;
+
+/**
+ * Description of SimpleStrategy.
+ *
+ * @author chabior
+ */
+class Simple implements StrategyInterface
+{
+ /**
+ * @param array|\Elastica\Connection[] $connections
+ *
+ * @throws \Elastica\Exception\ClientException
+ *
+ * @return \Elastica\Connection
+ */
+ public function getConnection($connections)
+ {
+ foreach ($connections as $connection) {
+ if ($connection->isEnabled()) {
+ return $connection;
+ }
+ }
+
+ throw new ClientException('No enabled connection');
+ }
+}
diff --git a/vendor/ruflin/elastica/lib/Elastica/Connection/Strategy/StrategyFactory.php b/vendor/ruflin/elastica/lib/Elastica/Connection/Strategy/StrategyFactory.php
new file mode 100644
index 00000000..7590ab11
--- /dev/null
+++ b/vendor/ruflin/elastica/lib/Elastica/Connection/Strategy/StrategyFactory.php
@@ -0,0 +1,45 @@
+<?php
+namespace Elastica\Connection\Strategy;
+
+use Elastica\Exception\InvalidException;
+
+/**
+ * Description of StrategyFactory.
+ *
+ * @author chabior
+ */
+class StrategyFactory
+{
+ /**
+ * @param mixed|callable|string|StrategyInterface $strategyName
+ *
+ * @throws \Elastica\Exception\InvalidException
+ *
+ * @return \Elastica\Connection\Strategy\StrategyInterface
+ */
+ public static function create($strategyName)
+ {
+ if ($strategyName instanceof StrategyInterface) {
+ return $strategyName;
+ }
+
+ if (CallbackStrategy::isValid($strategyName)) {
+ return new CallbackStrategy($strategyName);
+ }
+
+ if (is_string($strategyName)) {
+ $requiredInterface = '\\Elastica\\Connection\\Strategy\\StrategyInterface';
+ $predefinedStrategy = '\\Elastica\\Connection\\Strategy\\'.$strategyName;
+
+ if (class_exists($predefinedStrategy) && class_implements($predefinedStrategy, $requiredInterface)) {
+ return new $predefinedStrategy();
+ }
+
+ if (class_exists($strategyName) && class_implements($strategyName, $requiredInterface)) {
+ return new $strategyName();
+ }
+ }
+
+ throw new InvalidException('Can\'t create strategy instance by given argument');
+ }
+}
diff --git a/vendor/ruflin/elastica/lib/Elastica/Connection/Strategy/StrategyInterface.php b/vendor/ruflin/elastica/lib/Elastica/Connection/Strategy/StrategyInterface.php
new file mode 100644
index 00000000..29bf7701
--- /dev/null
+++ b/vendor/ruflin/elastica/lib/Elastica/Connection/Strategy/StrategyInterface.php
@@ -0,0 +1,17 @@
+<?php
+namespace Elastica\Connection\Strategy;
+
+/**
+ * Description of AbstractStrategy.
+ *
+ * @author chabior
+ */
+interface StrategyInterface
+{
+ /**
+ * @param array|\Elastica\Connection[] $connections
+ *
+ * @return \Elastica\Connection
+ */
+ public function getConnection($connections);
+}
diff --git a/vendor/ruflin/elastica/lib/Elastica/Document.php b/vendor/ruflin/elastica/lib/Elastica/Document.php
new file mode 100644
index 00000000..e82afae9
--- /dev/null
+++ b/vendor/ruflin/elastica/lib/Elastica/Document.php
@@ -0,0 +1,356 @@
+<?php
+namespace Elastica;
+
+use Elastica\Bulk\Action;
+use Elastica\Exception\InvalidException;
+use Elastica\Exception\NotImplementedException;
+
+/**
+ * Single document stored in elastic search.
+ *
+ * @author Nicolas Ruflin <spam@ruflin.com>
+ */
+class Document extends AbstractUpdateAction
+{
+ const OP_TYPE_CREATE = Action::OP_TYPE_CREATE;
+
+ /**
+ * Document data.
+ *
+ * @var array Document data
+ */
+ protected $_data = array();
+
+ /**
+ * Whether to use this document to upsert if the document does not exist.
+ *
+ * @var bool
+ */
+ protected $_docAsUpsert = false;
+
+ /**
+ * @var bool
+ */
+ protected $_autoPopulate = false;
+
+ /**
+ * Creates a new document.
+ *
+ * @param int|string $id OPTIONAL $id Id is create if empty
+ * @param array|string $data OPTIONAL Data array
+ * @param string $type OPTIONAL Type name
+ * @param string $index OPTIONAL Index name
+ */
+ public function __construct($id = '', $data = array(), $type = '', $index = '')
+ {
+ $this->setId($id);
+ $this->setData($data);
+ $this->setType($type);
+ $this->setIndex($index);
+ }
+
+ /**
+ * @param string $key
+ *
+ * @return mixed
+ */
+ public function __get($key)
+ {
+ return $this->get($key);
+ }
+
+ /**
+ * @param string $key
+ * @param mixed $value
+ */
+ public function __set($key, $value)
+ {
+ $this->set($key, $value);
+ }
+
+ /**
+ * @param string $key
+ *
+ * @return bool
+ */
+ public function __isset($key)
+ {
+ return $this->has($key) && null !== $this->get($key);
+ }
+
+ /**
+ * @param string $key
+ */
+ public function __unset($key)
+ {
+ $this->remove($key);
+ }
+
+ /**
+ * @param string $key
+ *
+ * @throws \Elastica\Exception\InvalidException
+ *
+ * @return mixed
+ */
+ public function get($key)
+ {
+ if (!$this->has($key)) {
+ throw new InvalidException("Field {$key} does not exist");
+ }
+
+ return $this->_data[$key];
+ }
+
+ /**
+ * @param string $key
+ * @param mixed $value
+ *
+ * @throws \Elastica\Exception\InvalidException
+ *
+ * @return $this
+ */
+ public function set($key, $value)
+ {
+ if (!is_array($this->_data)) {
+ throw new InvalidException('Document data is serialized data. Data creation is forbidden.');
+ }
+ $this->_data[$key] = $value;
+
+ return $this;
+ }
+
+ /**
+ * @param string $key
+ *
+ * @return bool
+ */
+ public function has($key)
+ {
+ return is_array($this->_data) && array_key_exists($key, $this->_data);
+ }
+
+ /**
+ * @param string $key
+ *
+ * @throws \Elastica\Exception\InvalidException
+ *
+ * @return $this
+ */
+ public function remove($key)
+ {
+ if (!$this->has($key)) {
+ throw new InvalidException("Field {$key} does not exist");
+ }
+ unset($this->_data[$key]);
+
+ return $this;
+ }
+
+ /**
+ * Adds the given key/value pair to the document.
+ *
+ * @deprecated
+ *
+ * @param string $key Document entry key
+ * @param mixed $value Document entry value
+ *
+ * @return $this
+ */
+ public function add($key, $value)
+ {
+ return $this->set($key, $value);
+ }
+
+ /**
+ * Adds a file to the index.
+ *
+ * To use this feature you have to call the following command in the
+ * elasticsearch directory:
+ * <code>
+ * ./bin/plugin -install elasticsearch/elasticsearch-mapper-attachments/1.6.0
+ * </code>
+ * This installs the tika file analysis plugin. More infos about supported formats
+ * can be found here: {@link http://tika.apache.org/0.7/formats.html}
+ *
+ * @param string $key Key to add the file to
+ * @param string $filepath Path to add the file
+ * @param string $mimeType OPTIONAL Header mime type
+ *
+ * @return $this
+ */
+ public function addFile($key, $filepath, $mimeType = '')
+ {
+ $value = base64_encode(file_get_contents($filepath));
+
+ if (!empty($mimeType)) {
+ $value = array('_content_type' => $mimeType, '_name' => $filepath, '_content' => $value);
+ }
+
+ $this->set($key, $value);
+
+ return $this;
+ }
+
+ /**
+ * Add file content.
+ *
+ * @param string $key Document key
+ * @param string $content Raw file content
+ *
+ * @return $this
+ */
+ public function addFileContent($key, $content)
+ {
+ return $this->set($key, base64_encode($content));
+ }
+
+ /**
+ * Adds a geopoint to the document.
+ *
+ * Geohashes are not yet supported
+ *
+ * @param string $key Field key
+ * @param float $latitude Latitude value
+ * @param float $longitude Longitude value
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/mapping-geo-point-type.html
+ *
+ * @return $this
+ */
+ public function addGeoPoint($key, $latitude, $longitude)
+ {
+ $value = array('lat' => $latitude, 'lon' => $longitude);
+
+ $this->set($key, $value);
+
+ return $this;
+ }
+
+ /**
+ * Overwrites the current document data with the given data.
+ *
+ * @param array|string $data Data array
+ *
+ * @return $this
+ */
+ public function setData($data)
+ {
+ $this->_data = $data;
+
+ return $this;
+ }
+
+ /**
+ * Returns the document data.
+ *
+ * @return array|string Document data
+ */
+ public function getData()
+ {
+ return $this->_data;
+ }
+
+ /**
+ * @deprecated
+ *
+ * @param \Elastica\Script $data
+ *
+ * @throws NotImplementedException
+ */
+ public function setScript($data)
+ {
+ throw new NotImplementedException('setScript() is no longer available as of 0.90.2. See http://elastica.io/migration/0.90.2/upsert.html to migrate');
+ }
+
+ /**
+ * @throws NotImplementedException
+ *
+ * @deprecated
+ */
+ public function getScript()
+ {
+ throw new NotImplementedException('getScript() is no longer available as of 0.90.2. See http://elastica.io/migration/0.90.2/upsert.html to migrate');
+ }
+
+ /**
+ * @throws NotImplementedException
+ *
+ * @deprecated
+ */
+ public function hasScript()
+ {
+ throw new NotImplementedException('hasScript() is no longer available as of 0.90.2. See http://elastica.io/migration/0.90.2/upsert.html to migrate');
+ }
+
+ /**
+ * @param bool $value
+ *
+ * @return $this
+ */
+ public function setDocAsUpsert($value)
+ {
+ $this->_docAsUpsert = (bool) $value;
+
+ return $this;
+ }
+
+ /**
+ * @return bool
+ */
+ public function getDocAsUpsert()
+ {
+ return $this->_docAsUpsert;
+ }
+
+ /**
+ * @param bool $autoPopulate
+ *
+ * @return $this
+ */
+ public function setAutoPopulate($autoPopulate = true)
+ {
+ $this->_autoPopulate = (bool) $autoPopulate;
+
+ return $this;
+ }
+
+ /**
+ * @return bool
+ */
+ public function isAutoPopulate()
+ {
+ return $this->_autoPopulate;
+ }
+
+ /**
+ * Returns the document as an array.
+ *
+ * @return array
+ */
+ public function toArray()
+ {
+ $doc = $this->getParams();
+ $doc['_source'] = $this->getData();
+
+ return $doc;
+ }
+
+ /**
+ * @param array|\Elastica\Document $data
+ *
+ * @throws \Elastica\Exception\InvalidException
+ *
+ * @return self
+ */
+ public static function create($data)
+ {
+ if ($data instanceof self) {
+ return $data;
+ } elseif (is_array($data)) {
+ return new self('', $data);
+ } else {
+ throw new InvalidException('Failed to create document. Invalid data passed.');
+ }
+ }
+}
diff --git a/vendor/ruflin/elastica/lib/Elastica/Exception/Bulk/Response/ActionException.php b/vendor/ruflin/elastica/lib/Elastica/Exception/Bulk/Response/ActionException.php
new file mode 100644
index 00000000..5db0e49f
--- /dev/null
+++ b/vendor/ruflin/elastica/lib/Elastica/Exception/Bulk/Response/ActionException.php
@@ -0,0 +1,65 @@
+<?php
+namespace Elastica\Exception\Bulk\Response;
+
+use Elastica\Bulk\Response;
+use Elastica\Exception\BulkException;
+
+class ActionException extends BulkException
+{
+ /**
+ * @var \Elastica\Response
+ */
+ protected $_response;
+
+ /**
+ * @param \Elastica\Bulk\Response $response
+ */
+ public function __construct(Response $response)
+ {
+ $this->_response = $response;
+
+ parent::__construct($this->getErrorMessage($response));
+ }
+
+ /**
+ * @return \Elastica\Bulk\Action
+ */
+ public function getAction()
+ {
+ return $this->getResponse()->getAction();
+ }
+
+ /**
+ * @return \Elastica\Bulk\Response
+ */
+ public function getResponse()
+ {
+ return $this->_response;
+ }
+
+ /**
+ * @param \Elastica\Bulk\Response $response
+ *
+ * @return string
+ */
+ public function getErrorMessage(Response $response)
+ {
+ $error = $response->getError();
+ $opType = $response->getOpType();
+ $data = $response->getData();
+
+ $path = '';
+ if (isset($data['_index'])) {
+ $path .= '/'.$data['_index'];
+ }
+ if (isset($data['_type'])) {
+ $path .= '/'.$data['_type'];
+ }
+ if (isset($data['_id'])) {
+ $path .= '/'.$data['_id'];
+ }
+ $message = "$opType: $path caused $error";
+
+ return $message;
+ }
+}
diff --git a/vendor/ruflin/elastica/lib/Elastica/Exception/Bulk/ResponseException.php b/vendor/ruflin/elastica/lib/Elastica/Exception/Bulk/ResponseException.php
new file mode 100644
index 00000000..54b5702b
--- /dev/null
+++ b/vendor/ruflin/elastica/lib/Elastica/Exception/Bulk/ResponseException.php
@@ -0,0 +1,98 @@
+<?php
+namespace Elastica\Exception\Bulk;
+
+use Elastica\Bulk\ResponseSet;
+use Elastica\Exception\Bulk\Response\ActionException;
+use Elastica\Exception\BulkException;
+
+/**
+ * Bulk Response exception.
+ */
+class ResponseException extends BulkException
+{
+ /**
+ * @var \Elastica\Bulk\ResponseSet ResponseSet object
+ */
+ protected $_responseSet;
+
+ /**
+ * @var \Elastica\Exception\Bulk\Response\ActionException[]
+ */
+ protected $_actionExceptions = array();
+
+ /**
+ * Construct Exception.
+ *
+ * @param \Elastica\Bulk\ResponseSet $responseSet
+ */
+ public function __construct(ResponseSet $responseSet)
+ {
+ $this->_init($responseSet);
+
+ $message = 'Error in one or more bulk request actions:'.PHP_EOL.PHP_EOL;
+ $message .= $this->getActionExceptionsAsString();
+
+ parent::__construct($message);
+ }
+
+ /**
+ * @param \Elastica\Bulk\ResponseSet $responseSet
+ */
+ protected function _init(ResponseSet $responseSet)
+ {
+ $this->_responseSet = $responseSet;
+
+ foreach ($responseSet->getBulkResponses() as $bulkResponse) {
+ if ($bulkResponse->hasError()) {
+ $this->_actionExceptions[] = new ActionException($bulkResponse);
+ }
+ }
+ }
+
+ /**
+ * Returns bulk response set object.
+ *
+ * @return \Elastica\Bulk\ResponseSet
+ */
+ public function getResponseSet()
+ {
+ return $this->_responseSet;
+ }
+
+ /**
+ * Returns array of failed actions.
+ *
+ * @return array Array of failed actions
+ */
+ public function getFailures()
+ {
+ $errors = array();
+
+ foreach ($this->getActionExceptions() as $actionException) {
+ $errors[] = $actionException->getMessage();
+ }
+
+ return $errors;
+ }
+
+ /**
+ * @return \Elastica\Exception\Bulk\Response\ActionException[]
+ */
+ public function getActionExceptions()
+ {
+ return $this->_actionExceptions;
+ }
+
+ /**
+ * @return string
+ */
+ public function getActionExceptionsAsString()
+ {
+ $message = '';
+ foreach ($this->getActionExceptions() as $actionException) {
+ $message .= $actionException->getMessage().PHP_EOL;
+ }
+
+ return $message;
+ }
+}
diff --git a/vendor/ruflin/elastica/lib/Elastica/Exception/Bulk/UdpException.php b/vendor/ruflin/elastica/lib/Elastica/Exception/Bulk/UdpException.php
new file mode 100644
index 00000000..e332b92f
--- /dev/null
+++ b/vendor/ruflin/elastica/lib/Elastica/Exception/Bulk/UdpException.php
@@ -0,0 +1,8 @@
+<?php
+namespace Elastica\Exception\Bulk;
+
+use Elastica\Exception\BulkException;
+
+class UdpException extends BulkException
+{
+}
diff --git a/vendor/ruflin/elastica/lib/Elastica/Exception/BulkException.php b/vendor/ruflin/elastica/lib/Elastica/Exception/BulkException.php
new file mode 100644
index 00000000..121cf557
--- /dev/null
+++ b/vendor/ruflin/elastica/lib/Elastica/Exception/BulkException.php
@@ -0,0 +1,6 @@
+<?php
+namespace Elastica\Exception;
+
+class BulkException extends \RuntimeException implements ExceptionInterface
+{
+}
diff --git a/vendor/ruflin/elastica/lib/Elastica/Exception/ClientException.php b/vendor/ruflin/elastica/lib/Elastica/Exception/ClientException.php
new file mode 100644
index 00000000..66af363d
--- /dev/null
+++ b/vendor/ruflin/elastica/lib/Elastica/Exception/ClientException.php
@@ -0,0 +1,11 @@
+<?php
+namespace Elastica\Exception;
+
+/**
+ * Client exception.
+ *
+ * @author Nicolas Ruflin <spam@ruflin.com>
+ */
+class ClientException extends \RuntimeException implements ExceptionInterface
+{
+}
diff --git a/vendor/ruflin/elastica/lib/Elastica/Exception/Connection/GuzzleException.php b/vendor/ruflin/elastica/lib/Elastica/Exception/Connection/GuzzleException.php
new file mode 100644
index 00000000..614ad139
--- /dev/null
+++ b/vendor/ruflin/elastica/lib/Elastica/Exception/Connection/GuzzleException.php
@@ -0,0 +1,50 @@
+<?php
+namespace Elastica\Exception\Connection;
+
+use Elastica\Exception\ConnectionException;
+use Elastica\Request;
+use Elastica\Response;
+use GuzzleHttp\Exception\TransferException;
+
+/**
+ * Transport exception.
+ *
+ * @author Milan Magudia <milan@magudia.com>
+ */
+class GuzzleException extends ConnectionException
+{
+ /**
+ * @var TransferException
+ */
+ protected $_guzzleException;
+
+ /**
+ * @param \GuzzleHttp\Exception\TransferException $guzzleException
+ * @param \Elastica\Request $request
+ * @param \Elastica\Response $response
+ */
+ public function __construct(TransferException $guzzleException, Request $request = null, Response $response = null)
+ {
+ $this->_guzzleException = $guzzleException;
+ $message = $this->getErrorMessage($this->getGuzzleException());
+ parent::__construct($message, $request, $response);
+ }
+
+ /**
+ * @param \GuzzleHttp\Exception\TransferException $guzzleException
+ *
+ * @return string
+ */
+ public function getErrorMessage(TransferException $guzzleException)
+ {
+ return $guzzleException->getMessage();
+ }
+
+ /**
+ * @return TransferException
+ */
+ public function getGuzzleException()
+ {
+ return $this->_guzzleException;
+ }
+}
diff --git a/vendor/ruflin/elastica/lib/Elastica/Exception/Connection/HttpException.php b/vendor/ruflin/elastica/lib/Elastica/Exception/Connection/HttpException.php
new file mode 100644
index 00000000..28e78e77
--- /dev/null
+++ b/vendor/ruflin/elastica/lib/Elastica/Exception/Connection/HttpException.php
@@ -0,0 +1,86 @@
+<?php
+namespace Elastica\Exception\Connection;
+
+use Elastica\Exception\ConnectionException;
+use Elastica\Request;
+use Elastica\Response;
+
+/**
+ * Connection exception.
+ *
+ * @author Nicolas Ruflin <spam@ruflin.com>
+ */
+class HttpException extends ConnectionException
+{
+ /**
+ * Error code / message.
+ *
+ * @var string Error code / message
+ */
+ protected $_error = 0;
+
+ /**
+ * Construct Exception.
+ *
+ * @param string $error Error
+ * @param \Elastica\Request $request
+ * @param \Elastica\Response $response
+ */
+ public function __construct($error, Request $request = null, Response $response = null)
+ {
+ $this->_error = $error;
+
+ $message = $this->getErrorMessage($this->getError());
+ parent::__construct($message, $request, $response);
+ }
+
+ /**
+ * Returns the error message corresponding to the error code
+ * cUrl error code reference can be found here {@link http://curl.haxx.se/libcurl/c/libcurl-errors.html}.
+ *
+ * @param string $error Error code
+ *
+ * @return string Error message
+ */
+ public function getErrorMessage($error)
+ {
+ switch ($error) {
+ case CURLE_UNSUPPORTED_PROTOCOL:
+ $error = 'Unsupported protocol';
+ break;
+ case CURLE_FAILED_INIT:
+ $error = 'Internal cUrl error?';
+ break;
+ case CURLE_URL_MALFORMAT:
+ $error = 'Malformed URL';
+ break;
+ case CURLE_COULDNT_RESOLVE_PROXY:
+ $error = "Couldn't resolve proxy";
+ break;
+ case CURLE_COULDNT_RESOLVE_HOST:
+ $error = "Couldn't resolve host";
+ break;
+ case CURLE_COULDNT_CONNECT:
+ $error = "Couldn't connect to host, Elasticsearch down?";
+ break;
+ case 28:
+ $error = 'Operation timed out';
+ break;
+ default:
+ $error = 'Unknown error:'.$error;
+ break;
+ }
+
+ return $error;
+ }
+
+ /**
+ * Return Error code / message.
+ *
+ * @return string Error code / message
+ */
+ public function getError()
+ {
+ return $this->_error;
+ }
+}
diff --git a/vendor/ruflin/elastica/lib/Elastica/Exception/Connection/MemcacheException.php b/vendor/ruflin/elastica/lib/Elastica/Exception/Connection/MemcacheException.php
new file mode 100644
index 00000000..24181379
--- /dev/null
+++ b/vendor/ruflin/elastica/lib/Elastica/Exception/Connection/MemcacheException.php
@@ -0,0 +1,13 @@
+<?php
+namespace Elastica\Exception\Connection;
+
+use Elastica\Exception\ConnectionException;
+
+/**
+ * Transport exception.
+ *
+ * @author Igor Denisenko <im.denisenko@yahoo.com>
+ */
+class MemcacheException extends ConnectionException
+{
+}
diff --git a/vendor/ruflin/elastica/lib/Elastica/Exception/Connection/ThriftException.php b/vendor/ruflin/elastica/lib/Elastica/Exception/Connection/ThriftException.php
new file mode 100644
index 00000000..499cbd7d
--- /dev/null
+++ b/vendor/ruflin/elastica/lib/Elastica/Exception/Connection/ThriftException.php
@@ -0,0 +1,49 @@
+<?php
+namespace Elastica\Exception\Connection;
+
+use Elastica\Exception\ConnectionException;
+use Elastica\Request;
+use Elastica\Response;
+use Thrift\Exception\TException;
+
+/**
+ * Transport exception.
+ *
+ * @author Mikhail Shamin <munk13@gmail.com>
+ */
+class ThriftException extends ConnectionException
+{
+ /**
+ * @var TException
+ */
+ protected $_thriftException;
+
+ /**
+ * @param \Thrift\Exception\TException $thriftException
+ * @param \Elastica\Request $request
+ * @param \Elastica\Response $response
+ */
+ public function __construct(TException $thriftException, Request $request = null, Response $response = null)
+ {
+ $this->_thriftException = $thriftException;
+ $message = $this->getErrorMessage($this->getThriftException());
+ parent::__construct($message, $request, $response);
+ }
+
+ /**
+ * @param \Thrift\Exception\TException $thriftException
+ *
+ * @return string
+ */
+ public function getErrorMessage(TException $thriftException)
+ {
+ return $thriftException->getMessage();
+ }
+ /**
+ * @return TException
+ */
+ public function getThriftException()
+ {
+ return $this->_thriftException;
+ }
+}
diff --git a/vendor/ruflin/elastica/lib/Elastica/Exception/ConnectionException.php b/vendor/ruflin/elastica/lib/Elastica/Exception/ConnectionException.php
new file mode 100644
index 00000000..b2376d2f
--- /dev/null
+++ b/vendor/ruflin/elastica/lib/Elastica/Exception/ConnectionException.php
@@ -0,0 +1,58 @@
+<?php
+namespace Elastica\Exception;
+
+use Elastica\Request;
+use Elastica\Response;
+
+/**
+ * Connection exception.
+ *
+ * @author Nicolas Ruflin <spam@ruflin.com>
+ */
+class ConnectionException extends \RuntimeException implements ExceptionInterface
+{
+ /**
+ * @var \Elastica\Request Request object
+ */
+ protected $_request;
+
+ /**
+ * @var \Elastica\Response Response object
+ */
+ protected $_response;
+
+ /**
+ * Construct Exception.
+ *
+ * @param string $message Message
+ * @param \Elastica\Request $request
+ * @param \Elastica\Response $response
+ */
+ public function __construct($message, Request $request = null, Response $response = null)
+ {
+ $this->_request = $request;
+ $this->_response = $response;
+
+ parent::__construct($message);
+ }
+
+ /**
+ * Returns request object.
+ *
+ * @return \Elastica\Request Request object
+ */
+ public function getRequest()
+ {
+ return $this->_request;
+ }
+
+ /**
+ * Returns response object.
+ *
+ * @return \Elastica\Response Response object
+ */
+ public function getResponse()
+ {
+ return $this->_response;
+ }
+}
diff --git a/vendor/ruflin/elastica/lib/Elastica/Exception/ElasticsearchException.php b/vendor/ruflin/elastica/lib/Elastica/Exception/ElasticsearchException.php
new file mode 100644
index 00000000..59cca0c6
--- /dev/null
+++ b/vendor/ruflin/elastica/lib/Elastica/Exception/ElasticsearchException.php
@@ -0,0 +1,91 @@
+<?php
+namespace Elastica\Exception;
+
+/**
+ * Elasticsearch exception.
+ *
+ * @author Ian Babrou <ibobrik@gmail.com>
+ */
+class ElasticsearchException extends \Exception implements ExceptionInterface
+{
+ const REMOTE_TRANSPORT_EXCEPTION = 'RemoteTransportException';
+
+ /**
+ * @var string|null Elasticsearch exception name
+ */
+ private $_exception;
+
+ /**
+ * @var bool Whether exception was local to server node or remote
+ */
+ private $_isRemote = false;
+
+ /**
+ * Constructs elasticsearch exception.
+ *
+ * @param int $code Error code
+ * @param string $error Error message from elasticsearch
+ */
+ public function __construct($code, $error)
+ {
+ $this->_parseError($error);
+ parent::__construct($error, $code);
+ }
+
+ /**
+ * Parse error message from elasticsearch.
+ *
+ * @param string $error Error message
+ */
+ protected function _parseError($error)
+ {
+ $errors = explode(']; nested: ', $error);
+
+ if (count($errors) == 1) {
+ $this->_exception = $this->_extractException($errors[0]);
+ } else {
+ if ($this->_extractException($errors[0]) == self::REMOTE_TRANSPORT_EXCEPTION) {
+ $this->_isRemote = true;
+ $this->_exception = $this->_extractException($errors[1]);
+ } else {
+ $this->_exception = $this->_extractException($errors[0]);
+ }
+ }
+ }
+
+ /**
+ * Extract exception name from error response.
+ *
+ * @param string $error
+ *
+ * @return null|string
+ */
+ protected function _extractException($error)
+ {
+ if (preg_match('/^(\w+)\[.*\]/', $error, $matches)) {
+ return $matches[1];
+ } else {
+ return;
+ }
+ }
+
+ /**
+ * Returns elasticsearch exception name.
+ *
+ * @return string|null
+ */
+ public function getExceptionName()
+ {
+ return $this->_exception;
+ }
+
+ /**
+ * Returns whether exception was local to server node or remote.
+ *
+ * @return bool
+ */
+ public function isRemoteTransportException()
+ {
+ return $this->_isRemote;
+ }
+}
diff --git a/vendor/ruflin/elastica/lib/Elastica/Exception/ExceptionInterface.php b/vendor/ruflin/elastica/lib/Elastica/Exception/ExceptionInterface.php
new file mode 100644
index 00000000..02f43092
--- /dev/null
+++ b/vendor/ruflin/elastica/lib/Elastica/Exception/ExceptionInterface.php
@@ -0,0 +1,11 @@
+<?php
+namespace Elastica\Exception;
+
+/**
+ * General Elastica exception interface.
+ *
+ * @author Nicolas Ruflin <spam@ruflin.com>
+ */
+interface ExceptionInterface
+{
+}
diff --git a/vendor/ruflin/elastica/lib/Elastica/Exception/InvalidException.php b/vendor/ruflin/elastica/lib/Elastica/Exception/InvalidException.php
new file mode 100644
index 00000000..996a9389
--- /dev/null
+++ b/vendor/ruflin/elastica/lib/Elastica/Exception/InvalidException.php
@@ -0,0 +1,11 @@
+<?php
+namespace Elastica\Exception;
+
+/**
+ * Invalid exception.
+ *
+ * @author Nicolas Ruflin <spam@ruflin.com>
+ */
+class InvalidException extends \InvalidArgumentException implements ExceptionInterface
+{
+}
diff --git a/vendor/ruflin/elastica/lib/Elastica/Exception/JSONParseException.php b/vendor/ruflin/elastica/lib/Elastica/Exception/JSONParseException.php
new file mode 100644
index 00000000..010adf45
--- /dev/null
+++ b/vendor/ruflin/elastica/lib/Elastica/Exception/JSONParseException.php
@@ -0,0 +1,9 @@
+<?php
+namespace Elastica\Exception;
+
+/**
+ * JSON Parse exception.
+ */
+class JSONParseException extends \RuntimeException implements ExceptionInterface
+{
+}
diff --git a/vendor/ruflin/elastica/lib/Elastica/Exception/NotFoundException.php b/vendor/ruflin/elastica/lib/Elastica/Exception/NotFoundException.php
new file mode 100644
index 00000000..a2897fd7
--- /dev/null
+++ b/vendor/ruflin/elastica/lib/Elastica/Exception/NotFoundException.php
@@ -0,0 +1,11 @@
+<?php
+namespace Elastica\Exception;
+
+/**
+ * Not found exception.
+ *
+ * @author Nicolas Ruflin <spam@ruflin.com>
+ */
+class NotFoundException extends \RuntimeException implements ExceptionInterface
+{
+}
diff --git a/vendor/ruflin/elastica/lib/Elastica/Exception/NotImplementedException.php b/vendor/ruflin/elastica/lib/Elastica/Exception/NotImplementedException.php
new file mode 100644
index 00000000..591417b6
--- /dev/null
+++ b/vendor/ruflin/elastica/lib/Elastica/Exception/NotImplementedException.php
@@ -0,0 +1,13 @@
+<?php
+namespace Elastica\Exception;
+
+/**
+ * Not implemented exception.
+ *
+ * Is thrown if a function or feature is not implemented yet
+ *
+ * @author Nicolas Ruflin <spam@ruflin.com>
+ */
+class NotImplementedException extends \BadMethodCallException implements ExceptionInterface
+{
+}
diff --git a/vendor/ruflin/elastica/lib/Elastica/Exception/PartialShardFailureException.php b/vendor/ruflin/elastica/lib/Elastica/Exception/PartialShardFailureException.php
new file mode 100644
index 00000000..bb3fa44a
--- /dev/null
+++ b/vendor/ruflin/elastica/lib/Elastica/Exception/PartialShardFailureException.php
@@ -0,0 +1,28 @@
+<?php
+namespace Elastica\Exception;
+
+use Elastica\JSON;
+use Elastica\Request;
+use Elastica\Response;
+
+/**
+ * Partial shard failure exception.
+ *
+ * @author Ian Babrou <ibobrik@gmail.com>
+ */
+class PartialShardFailureException extends ResponseException
+{
+ /**
+ * Construct Exception.
+ *
+ * @param \Elastica\Request $request
+ * @param \Elastica\Response $response
+ */
+ public function __construct(Request $request, Response $response)
+ {
+ parent::__construct($request, $response);
+
+ $shardsStatistics = $response->getShardsStatistics();
+ $this->message = JSON::stringify($shardsStatistics['failed']);
+ }
+}
diff --git a/vendor/ruflin/elastica/lib/Elastica/Exception/QueryBuilderException.php b/vendor/ruflin/elastica/lib/Elastica/Exception/QueryBuilderException.php
new file mode 100644
index 00000000..ae03c831
--- /dev/null
+++ b/vendor/ruflin/elastica/lib/Elastica/Exception/QueryBuilderException.php
@@ -0,0 +1,11 @@
+<?php
+namespace Elastica\Exception;
+
+/**
+ * QueryBuilder exception.
+ *
+ * @author Manuel Andreo Garcia <andreo.garcia@googlemail.com>
+ */
+class QueryBuilderException extends \RuntimeException implements ExceptionInterface
+{
+}
diff --git a/vendor/ruflin/elastica/lib/Elastica/Exception/ResponseException.php b/vendor/ruflin/elastica/lib/Elastica/Exception/ResponseException.php
new file mode 100644
index 00000000..57502307
--- /dev/null
+++ b/vendor/ruflin/elastica/lib/Elastica/Exception/ResponseException.php
@@ -0,0 +1,70 @@
+<?php
+namespace Elastica\Exception;
+
+use Elastica\Request;
+use Elastica\Response;
+
+/**
+ * Response exception.
+ *
+ * @author Nicolas Ruflin <spam@ruflin.com>
+ */
+class ResponseException extends \RuntimeException implements ExceptionInterface
+{
+ /**
+ * @var \Elastica\Request Request object
+ */
+ protected $_request = null;
+
+ /**
+ * @var \Elastica\Response Response object
+ */
+ protected $_response = null;
+
+ /**
+ * Construct Exception.
+ *
+ * @param \Elastica\Request $request
+ * @param \Elastica\Response $response
+ */
+ public function __construct(Request $request, Response $response)
+ {
+ $this->_request = $request;
+ $this->_response = $response;
+ parent::__construct($response->getError());
+ }
+
+ /**
+ * Returns request object.
+ *
+ * @return \Elastica\Request Request object
+ */
+ public function getRequest()
+ {
+ return $this->_request;
+ }
+
+ /**
+ * Returns response object.
+ *
+ * @return \Elastica\Response Response object
+ */
+ public function getResponse()
+ {
+ return $this->_response;
+ }
+
+ /**
+ * Returns elasticsearch exception.
+ *
+ * @return ElasticsearchException
+ */
+ public function getElasticsearchException()
+ {
+ $response = $this->getResponse();
+ $transfer = $response->getTransferInfo();
+ $code = array_key_exists('http_code', $transfer) ? $transfer['http_code'] : 0;
+
+ return new ElasticsearchException($code, $response->getError());
+ }
+}
diff --git a/vendor/ruflin/elastica/lib/Elastica/Exception/RuntimeException.php b/vendor/ruflin/elastica/lib/Elastica/Exception/RuntimeException.php
new file mode 100644
index 00000000..af18faff
--- /dev/null
+++ b/vendor/ruflin/elastica/lib/Elastica/Exception/RuntimeException.php
@@ -0,0 +1,11 @@
+<?php
+namespace Elastica\Exception;
+
+/**
+ * Client exception.
+ *
+ * @author Mikhail Shamin <munk13@gmail.com>
+ */
+class RuntimeException extends \RuntimeException implements ExceptionInterface
+{
+}
diff --git a/vendor/ruflin/elastica/lib/Elastica/Facet/AbstractFacet.php b/vendor/ruflin/elastica/lib/Elastica/Facet/AbstractFacet.php
new file mode 100644
index 00000000..743cefe1
--- /dev/null
+++ b/vendor/ruflin/elastica/lib/Elastica/Facet/AbstractFacet.php
@@ -0,0 +1,145 @@
+<?php
+namespace Elastica\Facet;
+
+use Elastica\Exception\InvalidException;
+use Elastica\Filter\AbstractFilter;
+use Elastica\Param;
+
+/**
+ * Abstract facet object. Should be extended by all facet types.
+ *
+ * @author Nicolas Ruflin <spam@ruflin.com>
+ * @author Jasper van Wanrooy <jasper@vanwanrooy.net>
+ *
+ * @deprecated Facets are deprecated and will be removed in a future release. You are encouraged to migrate to aggregations instead.
+ */
+abstract class AbstractFacet extends Param
+{
+ /**
+ * @var string Holds the name of the facet.
+ */
+ protected $_name = '';
+
+ /**
+ * @var array Holds all facet parameters.
+ */
+ protected $_facet = array();
+
+ /**
+ * Constructs a Facet object.
+ *
+ * @param string $name The name of the facet.
+ */
+ public function __construct($name)
+ {
+ $this->setName($name);
+ }
+
+ /**
+ * Sets the name of the facet. It is automatically set by
+ * the constructor.
+ *
+ * @param string $name The name of the facet.
+ *
+ * @throws \Elastica\Exception\InvalidException If name is empty
+ *
+ * @return $this
+ */
+ public function setName($name)
+ {
+ if (empty($name)) {
+ throw new InvalidException('Facet name has to be set');
+ }
+ $this->_name = $name;
+
+ return $this;
+ }
+
+ /**
+ * Gets the name of the facet.
+ *
+ * @return string
+ */
+ public function getName()
+ {
+ return $this->_name;
+ }
+
+ /**
+ * Sets a filter for this facet.
+ *
+ * @param \Elastica\Filter\AbstractFilter $filter A filter to apply on the facet.
+ *
+ * @return $this
+ */
+ public function setFilter(AbstractFilter $filter)
+ {
+ return $this->_setFacetParam('facet_filter', $filter->toArray());
+ }
+
+ /**
+ * Sets the flag to either run the facet globally or bound to the
+ * current search query. When not set, it defaults to the
+ * Elasticsearch default value.
+ *
+ * @param bool $global Flag to either run the facet globally.
+ *
+ * @return $this
+ */
+ public function setGlobal($global = true)
+ {
+ return $this->_setFacetParam('global', (bool) $global);
+ }
+
+ /**
+ * Sets the path to the nested document.
+ *
+ * @param string $nestedPath Nested path
+ *
+ * @return $this
+ */
+ public function setNested($nestedPath)
+ {
+ return $this->_setFacetParam('nested', $nestedPath);
+ }
+
+ /**
+ * Sets the scope.
+ *
+ * @param string $scope Scope
+ *
+ * @return $this
+ */
+ public function setScope($scope)
+ {
+ return $this->_setFacetParam('scope', $scope);
+ }
+
+ /**
+ * Basic definition of all specs of the facet. Each implementation
+ * should override this function in order to set it's specific
+ * settings.
+ *
+ * @return array
+ */
+ public function toArray()
+ {
+ return $this->_facet;
+ }
+
+ /**
+ * Sets a param for the facet. Each facet implementation needs to take
+ * care of handling their own params.
+ *
+ * @param string $key The key of the param to set.
+ * @param mixed $value The value of the param.
+ *
+ * @return $this
+ */
+ protected function _setFacetParam($key, $value)
+ {
+ $this->_facet[$key] = $value;
+
+ return $this;
+ }
+}
diff --git a/vendor/ruflin/elastica/lib/Elastica/Facet/DateHistogram.php b/vendor/ruflin/elastica/lib/Elastica/Facet/DateHistogram.php
new file mode 100644
index 00000000..c47eddab
--- /dev/null
+++ b/vendor/ruflin/elastica/lib/Elastica/Facet/DateHistogram.php
@@ -0,0 +1,58 @@
+<?php
+namespace Elastica\Facet;
+
+/**
+ * Implements the Date Histogram facet.
+ *
+ * @author Raul Martinez Jr <juneym@gmail.com>
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/search-facets-date-histogram-facet.html
+ * @link https://github.com/elasticsearch/elasticsearch/issues/591
+ * @deprecated Facets are deprecated and will be removed in a future release. You are encouraged to migrate to aggregations instead.
+ */
+class DateHistogram extends Histogram
+{
+ /**
+ * Set the time_zone parameter.
+ *
+ * @param string $tzOffset
+ *
+ * @return $this
+ */
+ public function setTimezone($tzOffset)
+ {
+ return $this->setParam('time_zone', $tzOffset);
+ }
+
+ /**
+ * Set the factor parameter.
+ *
+ * @param int $factor
+ *
+ * @return $this
+ */
+ public function setFactor($factor)
+ {
+ return $this->setParam('factor', $factor);
+ }
+
+ /**
+ * Creates the full facet definition, which includes the basic
+ * facet definition of the parent.
+ *
+ * @see \Elastica\Facet\AbstractFacet::toArray()
+ *
+ * @throws \Elastica\Exception\InvalidException When the right fields haven't been set.
+ *
+ * @return array
+ */
+ public function toArray()
+ {
+ /*
+ * Set the range in the abstract as param.
+ */
+ $this->_setFacetParam('date_histogram', $this->_params);
+
+ return $this->_facet;
+ }
+}
diff --git a/vendor/ruflin/elastica/lib/Elastica/Facet/Filter.php b/vendor/ruflin/elastica/lib/Elastica/Facet/Filter.php
new file mode 100644
index 00000000..26f032b4
--- /dev/null
+++ b/vendor/ruflin/elastica/lib/Elastica/Facet/Filter.php
@@ -0,0 +1,27 @@
+<?php
+namespace Elastica\Facet;
+
+use Elastica\Filter\AbstractFilter;
+
+/**
+ * Filter facet.
+ *
+ * @author Nicolas Ruflin <spam@ruflin.com>
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/search-facets-filter-facet.html
+ * @deprecated Facets are deprecated and will be removed in a future release. You are encouraged to migrate to aggregations instead.
+ */
+class Filter extends AbstractFacet
+{
+ /**
+ * Set the filter for the facet.
+ *
+ * @param \Elastica\Filter\AbstractFilter $filter
+ *
+ * @return $this
+ */
+ public function setFilter(AbstractFilter $filter)
+ {
+ return $this->_setFacetParam('filter', $filter->toArray());
+ }
+}
diff --git a/vendor/ruflin/elastica/lib/Elastica/Facet/GeoCluster.php b/vendor/ruflin/elastica/lib/Elastica/Facet/GeoCluster.php
new file mode 100644
index 00000000..71fa5094
--- /dev/null
+++ b/vendor/ruflin/elastica/lib/Elastica/Facet/GeoCluster.php
@@ -0,0 +1,66 @@
+<?php
+namespace Elastica\Facet;
+
+/**
+ * Implements the Geo Cluster facet.
+ *
+ * @author Konstantin Nikiforov <konstantin.nikiforov@gmail.com>
+ *
+ * @link https://github.com/zenobase/geocluster-facet
+ * @deprecated Facets are deprecated and will be removed in a future release. You are encouraged to migrate to aggregations instead.
+ */
+class GeoCluster extends AbstractFacet
+{
+ /**
+ * @param string $fieldName
+ *
+ * @return $this
+ */
+ public function setField($fieldName)
+ {
+ $this->setParam('field', $fieldName);
+
+ return $this;
+ }
+
+ /**
+ * @param float $factor
+ *
+ * @return $this
+ */
+ public function setFactor($factor)
+ {
+ $this->setParam('factor', $factor);
+
+ return $this;
+ }
+
+ /**
+ * @param bool $showIds
+ *
+ * @return $this
+ */
+ public function setShowIds($showIds)
+ {
+ $this->setParam('showIds', $showIds);
+
+ return $this;
+ }
+
+ /**
+ * Creates the full facet definition, which includes the basic
+ * facet definition of the parent.
+ *
+ * @see \Elastica\Facet\AbstractFacet::toArray()
+ *
+ * @throws \Elastica\Exception\InvalidException When the right fields haven't been set.
+ *
+ * @return array
+ */
+ public function toArray()
+ {
+ $this->_setFacetParam('geo_cluster', $this->_params);
+
+ return parent::toArray();
+ }
+}
diff --git a/vendor/ruflin/elastica/lib/Elastica/Facet/GeoDistance.php b/vendor/ruflin/elastica/lib/Elastica/Facet/GeoDistance.php
new file mode 100644
index 00000000..664d33a6
--- /dev/null
+++ b/vendor/ruflin/elastica/lib/Elastica/Facet/GeoDistance.php
@@ -0,0 +1,69 @@
+<?php
+namespace Elastica\Facet;
+
+/**
+ * Implements the Geo Distance facet.
+ *
+ * @author Gerard A. Matthew <gerard.matthew@gmail.com>
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/search-facets-geo-distance-facet.html
+ * @deprecated Facets are deprecated and will be removed in a future release. You are encouraged to migrate to aggregations instead.
+ */
+class GeoDistance extends AbstractFacet
+{
+ /**
+ * Sets the ranges for the facet all at once.
+ * Sample ranges:
+ * array (
+ * array('to' => 50),
+ * array('from' => 20, 'to' => 70),
+ * array('from' => 70, 'to' => 120),
+ * array('from' => 150)
+ * ).
+ *
+ * @param array $ranges Numerical array with range definitions.
+ *
+ * @return $this
+ */
+ public function setRanges(array $ranges)
+ {
+ return $this->setParam('ranges', $ranges);
+ }
+
+ /**
+ * Set the relative GeoPoint for the facet.
+ *
+ * @param string $typeField index type and field e.g foo.bar
+ * @param float $latitude
+ * @param float $longitude
+ *
+ * @return $this
+ */
+ public function setGeoPoint($typeField, $latitude, $longitude)
+ {
+ return $this->setParam($typeField, array(
+ 'lat' => $latitude,
+ 'lon' => $longitude,
+ ));
+ }
+
+ /**
+ * Creates the full facet definition, which includes the basic
+ * facet definition of the parent.
+ *
+ * @see \Elastica\Facet\AbstractFacet::toArray()
+ *
+ * @throws \Elastica\Exception\InvalidException When the right fields haven't been set.
+ *
+ * @return array
+ */
+ public function toArray()
+ {
+ /*
+ * Set the geo_distance in the abstract as param.
+ */
+ $this->_setFacetParam('geo_distance', $this->_params);
+
+ return parent::toArray();
+ }
+}
diff --git a/vendor/ruflin/elastica/lib/Elastica/Facet/Histogram.php b/vendor/ruflin/elastica/lib/Elastica/Facet/Histogram.php
new file mode 100644
index 00000000..1b76ea89
--- /dev/null
+++ b/vendor/ruflin/elastica/lib/Elastica/Facet/Histogram.php
@@ -0,0 +1,96 @@
+<?php
+namespace Elastica\Facet;
+
+/**
+ * Implements the Histogram facet.
+ *
+ * @author Raul Martinez Jr <juneym@gmail.com>
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/search-facets-histogram-facet.html
+ * @deprecated Facets are deprecated and will be removed in a future release. You are encouraged to migrate to aggregations instead.
+ */
+class Histogram extends AbstractFacet
+{
+ /**
+ * Sets the field for histogram.
+ *
+ * @param string $field The name of the field for the histogram
+ *
+ * @return $this
+ */
+ public function setField($field)
+ {
+ return $this->setParam('field', $field);
+ }
+
+ /**
+ * Set the value for interval.
+ *
+ * @param string $interval
+ *
+ * @return $this
+ */
+ public function setInterval($interval)
+ {
+ return $this->setParam('interval', $interval);
+ }
+
+ /**
+ * Set the fields for key_field and value_field.
+ *
+ * @param string $keyField Key field
+ * @param string $valueField Value field
+ *
+ * @return $this
+ */
+ public function setKeyValueFields($keyField, $valueField)
+ {
+ return $this->setParam('key_field', $keyField)->setParam('value_field', $valueField);
+ }
+
+ /**
+ * Sets the key and value for this facet by script.
+ *
+ * @param string $keyScript Script to check whether it falls into the range.
+ * @param string $valueScript Script to use for statistical calculations.
+ *
+ * @return $this
+ */
+ public function setKeyValueScripts($keyScript, $valueScript)
+ {
+ return $this->setParam('key_script', $keyScript)
+ ->setParam('value_script', $valueScript);
+ }
+
+ /**
+ * Set the "params" essential to the a script.
+ *
+ * @param array $params Associative array (key/value pair)
+ *
+ * @return $this
+ */
+ public function setScriptParams(array $params)
+ {
+ return $this->setParam('params', $params);
+ }
+
+ /**
+ * Creates the full facet definition, which includes the basic
+ * facet definition of the parent.
+ *
+ * @see \Elastica\Facet\AbstractFacet::toArray()
+ *
+ * @throws \Elastica\Exception\InvalidException When the right fields haven't been set.
+ *
+ * @return array
+ */
+ public function toArray()
+ {
+ /*
+ * Set the range in the abstract as param.
+ */
+ $this->_setFacetParam('histogram', $this->_params);
+
+ return parent::toArray();
+ }
+}
diff --git a/vendor/ruflin/elastica/lib/Elastica/Facet/Query.php b/vendor/ruflin/elastica/lib/Elastica/Facet/Query.php
new file mode 100644
index 00000000..522090d5
--- /dev/null
+++ b/vendor/ruflin/elastica/lib/Elastica/Facet/Query.php
@@ -0,0 +1,27 @@
+<?php
+namespace Elastica\Facet;
+
+use Elastica\Query\AbstractQuery;
+
+/**
+ * Query facet.
+ *
+ * @author Nicolas Ruflin <spam@ruflin.com>
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/search-facets-query-facet.html
+ * @deprecated Facets are deprecated and will be removed in a future release. You are encouraged to migrate to aggregations instead.
+ */
+class Query extends AbstractFacet
+{
+ /**
+ * Set the query for the facet.
+ *
+ * @param \Elastica\Query\AbstractQuery $query
+ *
+ * @return $this
+ */
+ public function setQuery(AbstractQuery $query)
+ {
+ return $this->_setFacetParam('query', $query->toArray());
+ }
+}
diff --git a/vendor/ruflin/elastica/lib/Elastica/Facet/Range.php b/vendor/ruflin/elastica/lib/Elastica/Facet/Range.php
new file mode 100644
index 00000000..f81caf3d
--- /dev/null
+++ b/vendor/ruflin/elastica/lib/Elastica/Facet/Range.php
@@ -0,0 +1,143 @@
+<?php
+namespace Elastica\Facet;
+
+use Elastica\Exception\InvalidException;
+
+/**
+ * Implements the range facet.
+ *
+ * @author Jasper van Wanrooy <jasper@vanwanrooy.net>
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/search-facets-range-facet.html
+ * @deprecated Facets are deprecated and will be removed in a future release. You are encouraged to migrate to aggregations instead.
+ */
+class Range extends AbstractFacet
+{
+ /**
+ * Sets the field for the range.
+ *
+ * @param string $field The name of the field for range.
+ *
+ * @return $this
+ */
+ public function setField($field)
+ {
+ return $this->setParam('field', $field);
+ }
+
+ /**
+ * Sets the fields by their separate key and value fields.
+ *
+ * @param string $keyField The key_field param for the range.
+ * @param string $valueField The key_value param for the range.
+ *
+ * @return $this
+ */
+ public function setKeyValueFields($keyField, $valueField)
+ {
+ return $this->setParam('key_field', $keyField)
+ ->setParam('value_field', $valueField);
+ }
+
+ /**
+ * Sets the key and value for this facet by script.
+ *
+ * @param string $keyScript Script to check whether it falls into the range.
+ * @param string $valueScript Script to use for statistical calculations.
+ *
+ * @return $this
+ */
+ public function setKeyValueScripts($keyScript, $valueScript)
+ {
+ return $this->setParam('key_script', $keyScript)
+ ->setParam('value_script', $valueScript);
+ }
+
+ /**
+ * Sets the ranges for the facet all at once. Sample ranges:
+ * array (
+ * array('to' => 50),
+ * array('from' => 20, 'to' 70),
+ * array('from' => 70, 'to' => 120),
+ * array('from' => 150)
+ * ).
+ *
+ * @param array $ranges Numerical array with range definitions.
+ *
+ * @return $this
+ */
+ public function setRanges(array $ranges)
+ {
+ return $this->setParam('ranges', $ranges);
+ }
+
+ /**
+ * Adds a range to the range facet.
+ *
+ * @param mixed $from The from for the range.
+ * @param mixed $to The to for the range.
+ *
+ * @return $this
+ */
+ public function addRange($from = null, $to = null)
+ {
+ if (!isset($this->_params['ranges']) || !is_array($this->_params['ranges'])) {
+ $this->_params['ranges'] = array();
+ }
+
+ $range = array();
+ if (isset($from)) {
+ $range['from'] = $from;
+ }
+ if (isset($to)) {
+ $range['to'] = $to;
+ }
+ $this->_params['ranges'][] = $range;
+
+ return $this;
+ }
+
+ /**
+ * Creates the full facet definition, which includes the basic
+ * facet definition of the parent.
+ *
+ * @see \Elastica\Facet\AbstractFacet::toArray()
+ *
+ * @throws \Elastica\Exception\InvalidException When the right fields haven't been set.
+ *
+ * @return array
+ */
+ public function toArray()
+ {
+ /*
+ * Check the facet for validity.
+ * There are three ways to set the key and value field for the range:
+ * - a single field for both key and value; or
+ * - separate fields for key and value; or
+ * - separate scripts for key and value.
+ */
+ $fieldTypesSet = 0;
+ if (isset($this->_params['field'])) {
+ $fieldTypesSet++;
+ }
+ if (isset($this->_params['key_field'])) {
+ $fieldTypesSet++;
+ }
+ if (isset($this->_params['key_script'])) {
+ $fieldTypesSet++;
+ }
+
+ if ($fieldTypesSet === 0) {
+ throw new InvalidException('Neither field, key_field nor key_script is set.');
+ } elseif ($fieldTypesSet > 1) {
+ throw new InvalidException('Either field, key_field and key_value or key_script and value_script should be set.');
+ }
+
+ /*
+ * Set the range in the abstract as param.
+ */
+ $this->_setFacetParam('range', $this->_params);
+
+ return parent::toArray();
+ }
+}
diff --git a/vendor/ruflin/elastica/lib/Elastica/Facet/Statistical.php b/vendor/ruflin/elastica/lib/Elastica/Facet/Statistical.php
new file mode 100644
index 00000000..bb4eef8b
--- /dev/null
+++ b/vendor/ruflin/elastica/lib/Elastica/Facet/Statistical.php
@@ -0,0 +1,64 @@
+<?php
+namespace Elastica\Facet;
+
+/**
+ * Implements the statistical facet.
+ *
+ * @author Robert Katzki <robert@katzki.de>
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/search-facets-statistical-facet.html
+ * @deprecated Facets are deprecated and will be removed in a future release. You are encouraged to migrate to aggregations instead.
+ */
+class Statistical extends AbstractFacet
+{
+ /**
+ * Sets the field for the statistical query.
+ *
+ * @param string $field The field name for the statistical query.
+ *
+ * @return $this
+ */
+ public function setField($field)
+ {
+ return $this->setParam('field', $field);
+ }
+
+ /**
+ * Sets multiple fields for the statistical query.
+ *
+ * @param array $fields Numerical array with the fields for the statistical query.
+ *
+ * @return $this
+ */
+ public function setFields(array $fields)
+ {
+ return $this->setParam('fields', $fields);
+ }
+
+ /**
+ * Sets a script to calculate statistical information.
+ *
+ * @param string $script The script to do calculations on the statistical values
+ *
+ * @return $this
+ */
+ public function setScript($script)
+ {
+ return $this->setParam('script', $script);
+ }
+
+ /**
+ * Creates the full facet definition, which includes the basic
+ * facet definition of the parent.
+ *
+ * @see \Elastica\Facet\AbstractFacet::toArray()
+ *
+ * @return array
+ */
+ public function toArray()
+ {
+ $this->_setFacetParam('statistical', $this->_params);
+
+ return parent::toArray();
+ }
+}
diff --git a/vendor/ruflin/elastica/lib/Elastica/Facet/Terms.php b/vendor/ruflin/elastica/lib/Elastica/Facet/Terms.php
new file mode 100644
index 00000000..6af8867b
--- /dev/null
+++ b/vendor/ruflin/elastica/lib/Elastica/Facet/Terms.php
@@ -0,0 +1,137 @@
+<?php
+namespace Elastica\Facet;
+
+use Elastica\Exception\InvalidException;
+use Elastica\Script;
+
+/**
+ * Implements the terms facet.
+ *
+ * @author Nicolas Ruflin <spam@ruflin.com>
+ * @author Jasper van Wanrooy <jasper@vanwanrooy.net>
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/search-facets-terms-facet.html
+ * @deprecated Facets are deprecated and will be removed in a future release. You are encouraged to migrate to aggregations instead.
+ */
+class Terms extends AbstractFacet
+{
+ /**
+ * Holds the types of ordering which are allowed
+ * by Elasticsearch.
+ *
+ * @var array
+ */
+ protected $_orderTypes = array('count', 'term', 'reverse_count', 'reverse_term');
+
+ /**
+ * Sets the field for the terms.
+ *
+ * @param string $field The field name for the terms.
+ *
+ * @return $this
+ */
+ public function setField($field)
+ {
+ return $this->setParam('field', $field);
+ }
+
+ /**
+ * Sets the script for the term.
+ *
+ * @param string $script The script for the term.
+ *
+ * @return $this
+ */
+ public function setScript($script)
+ {
+ $script = Script::create($script);
+ foreach ($script->toArray() as $param => $value) {
+ $this->setParam($param, $value);
+ }
+
+ return $this;
+ }
+
+ /**
+ * Sets multiple fields for the terms.
+ *
+ * @param array $fields Numerical array with the fields for the terms.
+ *
+ * @return $this
+ */
+ public function setFields(array $fields)
+ {
+ return $this->setParam('fields', $fields);
+ }
+
+ /**
+ * Sets the flag to return all available terms. When they
+ * don't have a hit, they have a count of zero.
+ *
+ * @param bool $allTerms Flag to fetch all terms.
+ *
+ * @return $this
+ */
+ public function setAllTerms($allTerms)
+ {
+ return $this->setParam('all_terms', (bool) $allTerms);
+ }
+
+ /**
+ * Sets the ordering type for this facet. Elasticsearch
+ * internal default is count.
+ *
+ * @param string $type The order type to set use for sorting of the terms.
+ *
+ * @throws \Elastica\Exception\InvalidException When an invalid order type was set.
+ *
+ * @return $this
+ */
+ public function setOrder($type)
+ {
+ if (!in_array($type, $this->_orderTypes)) {
+ throw new InvalidException('Invalid order type: '.$type);
+ }
+
+ return $this->setParam('order', $type);
+ }
+
+ /**
+ * Set an array with terms which are omitted in the search.
+ *
+ * @param array $exclude Numerical array which includes all terms which needs to be ignored.
+ *
+ * @return $this
+ */
+ public function setExclude(array $exclude)
+ {
+ return $this->setParam('exclude', $exclude);
+ }
+
+ /**
+ * Sets the amount of terms to be returned.
+ *
+ * @param int $size The amount of terms to be returned.
+ *
+ * @return $this
+ */
+ public function setSize($size)
+ {
+ return $this->setParam('size', (int) $size);
+ }
+
+ /**
+ * Creates the full facet definition, which includes the basic
+ * facet definition of the parent.
+ *
+ * @see \Elastica\Facet\AbstractFacet::toArray()
+ *
+ * @return array
+ */
+ public function toArray()
+ {
+ $this->_setFacetParam('terms', $this->_params);
+
+ return parent::toArray();
+ }
+}
diff --git a/vendor/ruflin/elastica/lib/Elastica/Facet/TermsStats.php b/vendor/ruflin/elastica/lib/Elastica/Facet/TermsStats.php
new file mode 100644
index 00000000..22d284c5
--- /dev/null
+++ b/vendor/ruflin/elastica/lib/Elastica/Facet/TermsStats.php
@@ -0,0 +1,107 @@
+<?php
+namespace Elastica\Facet;
+
+use Elastica\Exception\InvalidException;
+
+/**
+ * Implements the statistical facet on a per term basis.
+ *
+ * @author Tom Michaelis <tom.michaelis@gmail.com>
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/search-facets-terms-stats-facet.html
+ * @deprecated Facets are deprecated and will be removed in a future release. You are encouraged to migrate to aggregations instead.
+ */
+class TermsStats extends AbstractFacet
+{
+ /**
+ * Holds the types of ordering which are allowed
+ * by Elasticsearch.
+ *
+ * @var array
+ */
+ protected $_orderTypes = array('term', 'reverse_term', 'count', 'reverse_count',
+ 'total', 'reverse_total', 'min', 'reverse_min', 'max', 'reverse_max', 'mean',
+ 'reverse_mean', );
+
+ /**
+ * Sets the key field for the query.
+ *
+ * @param string $keyField The key field name for the query.
+ *
+ * @return $this
+ */
+ public function setKeyField($keyField)
+ {
+ return $this->setParam('key_field', $keyField);
+ }
+
+ /**
+ * Sets a script to calculate statistical information on a per term basis.
+ *
+ * @param string $valueScript The script to do calculations on the statistical values
+ *
+ * @return $this
+ */
+ public function setValueScript($valueScript)
+ {
+ return $this->setParam('value_script', $valueScript);
+ }
+
+ /**
+ * Sets the ordering type for this facet. Elasticsearch
+ * internal default is count.
+ *
+ * @param string $type The order type to set use for sorting of the terms.
+ *
+ * @throws \Elastica\Exception\InvalidException When an invalid order type was set.
+ *
+ * @return $this
+ */
+ public function setOrder($type)
+ {
+ if (!in_array($type, $this->_orderTypes)) {
+ throw new InvalidException('Invalid order type: '.$type);
+ }
+
+ return $this->setParam('order', $type);
+ }
+
+ /**
+ * Sets a field to compute basic statistical results on.
+ *
+ * @param string $valueField The field to compute statistical values for
+ *
+ * @return $this
+ */
+ public function setValueField($valueField)
+ {
+ return $this->setParam('value_field', $valueField);
+ }
+
+ /**
+ * Sets the amount of terms to be returned.
+ *
+ * @param int $size The amount of terms to be returned.
+ *
+ * @return $this
+ */
+ public function setSize($size)
+ {
+ return $this->setParam('size', (int) $size);
+ }
+
+ /**
+ * Creates the full facet definition, which includes the basic
+ * facet definition of the parent.
+ *
+ * @see \Elastica\Facet\AbstractFacet::toArray()
+ *
+ * @return array
+ */
+ public function toArray()
+ {
+ $this->_setFacetParam('terms_stats', $this->_params);
+
+ return parent::toArray();
+ }
+}
diff --git a/vendor/ruflin/elastica/lib/Elastica/Filter/AbstractFilter.php b/vendor/ruflin/elastica/lib/Elastica/Filter/AbstractFilter.php
new file mode 100644
index 00000000..7c7dc4f7
--- /dev/null
+++ b/vendor/ruflin/elastica/lib/Elastica/Filter/AbstractFilter.php
@@ -0,0 +1,59 @@
+<?php
+namespace Elastica\Filter;
+
+use Elastica\Exception\InvalidException;
+use Elastica\Param;
+
+/**
+ * Abstract filter object. Should be extended by all filter types.
+ *
+ * @author Nicolas Ruflin <spam@ruflin.com>
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-filters.html
+ */
+abstract class AbstractFilter extends Param
+{
+ /**
+ * Sets the filter cache.
+ *
+ * @param bool $cached Cached
+ *
+ * @return $this
+ */
+ public function setCached($cached = true)
+ {
+ return $this->setParam('_cache', (bool) $cached);
+ }
+
+ /**
+ * Sets the filter cache key.
+ *
+ * @param string $cacheKey Cache key
+ *
+ * @throws \Elastica\Exception\InvalidException If given key is empty
+ *
+ * @return $this
+ */
+ public function setCacheKey($cacheKey)
+ {
+ $cacheKey = (string) $cacheKey;
+
+ if (empty($cacheKey)) {
+ throw new InvalidException('Invalid parameter. Has to be a non empty string');
+ }
+
+ return $this->setParam('_cache_key', (string) $cacheKey);
+ }
+
+ /**
+ * Sets the filter name.
+ *
+ * @param string $name Name
+ *
+ * @return $this
+ */
+ public function setName($name)
+ {
+ return $this->setParam('_name', $name);
+ }
+}
diff --git a/vendor/ruflin/elastica/lib/Elastica/Filter/AbstractGeoDistance.php b/vendor/ruflin/elastica/lib/Elastica/Filter/AbstractGeoDistance.php
new file mode 100644
index 00000000..b208afb4
--- /dev/null
+++ b/vendor/ruflin/elastica/lib/Elastica/Filter/AbstractGeoDistance.php
@@ -0,0 +1,198 @@
+<?php
+namespace Elastica\Filter;
+
+use Elastica\Exception\InvalidException;
+
+/**
+ * Geo distance filter.
+ *
+ * @author Nicolas Ruflin <spam@ruflin.com>
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-geo-distance-filter.html
+ */
+abstract class AbstractGeoDistance extends AbstractFilter
+{
+ const LOCATION_TYPE_GEOHASH = 'geohash';
+ const LOCATION_TYPE_LATLON = 'latlon';
+
+ /**
+ * Location type.
+ *
+ * Decides if this filter uses latitude/longitude or geohash for the location.
+ * Values are "latlon" or "geohash".
+ *
+ * @var string
+ */
+ protected $_locationType = null;
+
+ /**
+ * Key.
+ *
+ * @var string
+ */
+ protected $_key = null;
+
+ /**
+ * Latitude.
+ *
+ * @var float
+ */
+ protected $_latitude = null;
+
+ /**
+ * Longitude.
+ *
+ * @var float
+ */
+ protected $_longitude = null;
+
+ /**
+ * Geohash.
+ *
+ * @var string
+ */
+ protected $_geohash = null;
+
+ /**
+ * Create GeoDistance object.
+ *
+ * @param string $key Key
+ * @param array|string $location Location as array or geohash: array('lat' => 48.86, 'lon' => 2.35) OR 'drm3btev3e86'
+ *
+ * @internal param string $distance Distance
+ */
+ public function __construct($key, $location)
+ {
+ // Key
+ $this->setKey($key);
+ $this->setLocation($location);
+ }
+
+ /**
+ * @param string $key
+ *
+ * @return $this
+ */
+ public function setKey($key)
+ {
+ $this->_key = $key;
+
+ return $this;
+ }
+
+ /**
+ * @param array|string $location
+ *
+ * @throws \Elastica\Exception\InvalidException
+ *
+ * @return $this
+ */
+ public function setLocation($location)
+ {
+ // Location
+ if (is_array($location)) { // Latitude/Longitude
+ // Latitude
+ if (isset($location['lat'])) {
+ $this->setLatitude($location['lat']);
+ } else {
+ throw new InvalidException('$location[\'lat\'] has to be set');
+ }
+
+ // Longitude
+ if (isset($location['lon'])) {
+ $this->setLongitude($location['lon']);
+ } else {
+ throw new InvalidException('$location[\'lon\'] has to be set');
+ }
+ } elseif (is_string($location)) { // Geohash
+ $this->setGeohash($location);
+ } else { // Invalid location
+ throw new InvalidException('$location has to be an array (latitude/longitude) or a string (geohash)');
+ }
+
+ return $this;
+ }
+
+ /**
+ * @param float $latitude
+ *
+ * @return $this
+ */
+ public function setLatitude($latitude)
+ {
+ $this->_latitude = (float) $latitude;
+ $this->_locationType = self::LOCATION_TYPE_LATLON;
+
+ return $this;
+ }
+
+ /**
+ * @param float $longitude
+ *
+ * @return $this
+ */
+ public function setLongitude($longitude)
+ {
+ $this->_longitude = (float) $longitude;
+ $this->_locationType = self::LOCATION_TYPE_LATLON;
+
+ return $this;
+ }
+
+ /**
+ * @param string $geohash
+ *
+ * @return $this
+ */
+ public function setGeohash($geohash)
+ {
+ $this->_geohash = $geohash;
+ $this->_locationType = self::LOCATION_TYPE_GEOHASH;
+
+ return $this;
+ }
+
+ /**
+ * @throws \Elastica\Exception\InvalidException
+ *
+ * @return array|string
+ */
+ protected function _getLocationData()
+ {
+ if ($this->_locationType === self::LOCATION_TYPE_LATLON) { // Latitude/longitude
+ $location = array();
+
+ if (isset($this->_latitude)) { // Latitude
+ $location['lat'] = $this->_latitude;
+ } else {
+ throw new InvalidException('Latitude has to be set');
+ }
+
+ if (isset($this->_longitude)) { // Geohash
+ $location['lon'] = $this->_longitude;
+ } else {
+ throw new InvalidException('Longitude has to be set');
+ }
+ } elseif ($this->_locationType === self::LOCATION_TYPE_GEOHASH) { // Geohash
+ $location = $this->_geohash;
+ } else { // Invalid location type
+ throw new InvalidException('Invalid location type');
+ }
+
+ return $location;
+ }
+
+ /**
+ * @see \Elastica\Param::toArray()
+ *
+ * @throws \Elastica\Exception\InvalidException
+ *
+ * @return array
+ */
+ public function toArray()
+ {
+ $this->setParam($this->_key, $this->_getLocationData());
+
+ return parent::toArray();
+ }
+}
diff --git a/vendor/ruflin/elastica/lib/Elastica/Filter/AbstractGeoShape.php b/vendor/ruflin/elastica/lib/Elastica/Filter/AbstractGeoShape.php
new file mode 100644
index 00000000..4f5c0f93
--- /dev/null
+++ b/vendor/ruflin/elastica/lib/Elastica/Filter/AbstractGeoShape.php
@@ -0,0 +1,52 @@
+<?php
+namespace Elastica\Filter;
+
+/**
+ * geo_shape filter.
+ *
+ * Filter pre-indexed shape definitions
+ *
+ * @author Bennie Krijger <benniekrijger@gmail.com>
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-geo-shape-filter.html
+ */
+abstract class AbstractGeoShape extends AbstractFilter
+{
+ const RELATION_INTERSECT = 'intersects';
+ const RELATION_DISJOINT = 'disjoint';
+ const RELATION_CONTAINS = 'within';
+
+ /**
+ * @var string
+ *
+ * elasticsearch path of the pre-indexed shape
+ */
+ protected $_path;
+
+ /**
+ * @var string
+ *
+ * the relation of the 2 shaped: intersects, disjoint, within
+ */
+ protected $_relation = self::RELATION_INTERSECT;
+
+ /**
+ * @param string $relation
+ *
+ * @return $this
+ */
+ public function setRelation($relation)
+ {
+ $this->_relation = $relation;
+
+ return $this;
+ }
+
+ /**
+ * @return string
+ */
+ public function getRelation()
+ {
+ return $this->_relation;
+ }
+}
diff --git a/vendor/ruflin/elastica/lib/Elastica/Filter/AbstractMulti.php b/vendor/ruflin/elastica/lib/Elastica/Filter/AbstractMulti.php
new file mode 100644
index 00000000..06f6daea
--- /dev/null
+++ b/vendor/ruflin/elastica/lib/Elastica/Filter/AbstractMulti.php
@@ -0,0 +1,89 @@
+<?php
+namespace Elastica\Filter;
+
+/**
+ * Multi Abstract filter object. Should be extended by filter types composed of an array of sub filters.
+ *
+ * @author Nicolas Ruflin <spam@ruflin.com>
+ */
+abstract class AbstractMulti extends AbstractFilter
+{
+ /**
+ * Filters.
+ *
+ * @var array
+ */
+ protected $_filters = array();
+
+ /**
+ * @param \Elastica\Filter\AbstractFilter $filters
+ */
+ public function __construct(array $filters = array())
+ {
+ if (!empty($filters)) {
+ $this->setFilters($filters);
+ }
+ }
+
+ /**
+ * Add filter.
+ *
+ * @param \Elastica\Filter\AbstractFilter $filter
+ *
+ * @return $this
+ */
+ public function addFilter(AbstractFilter $filter)
+ {
+ $this->_filters[] = $filter->toArray();
+
+ return $this;
+ }
+
+ /**
+ * Set filters.
+ *
+ * @param array $filters
+ *
+ * @return $this
+ */
+ public function setFilters(array $filters)
+ {
+ $this->_filters = array();
+
+ foreach ($filters as $filter) {
+ $this->addFilter($filter);
+ }
+
+ return $this;
+ }
+
+ /**
+ * @return array Filters
+ */
+ public function getFilters()
+ {
+ return $this->_filters;
+ }
+
+ /**
+ * @see \Elastica\Param::toArray()
+ *
+ * @return array
+ */
+ public function toArray()
+ {
+ $data = parent::toArray();
+ $name = $this->_getBaseName();
+ $filterData = $data[$name];
+
+ if (empty($filterData)) {
+ $filterData = $this->_filters;
+ } else {
+ $filterData['filters'] = $this->_filters;
+ }
+
+ $data[$name] = $filterData;
+
+ return $data;
+ }
+}
diff --git a/vendor/ruflin/elastica/lib/Elastica/Filter/Bool.php b/vendor/ruflin/elastica/lib/Elastica/Filter/Bool.php
new file mode 100644
index 00000000..0d30f83f
--- /dev/null
+++ b/vendor/ruflin/elastica/lib/Elastica/Filter/Bool.php
@@ -0,0 +1,15 @@
+<?php
+namespace Elastica\Filter;
+
+/**
+ * Bool Filter.
+ *
+ * This class is for backward compatibility reason for all php < 7 versions. For PHP 7 and above use BoolFilter as Bool is reserved.
+ *
+ * @author Nicolas Ruflin <spam@ruflin.com>
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-bool-filter.html
+ */
+class Bool extends BoolFilter
+{
+}
diff --git a/vendor/ruflin/elastica/lib/Elastica/Filter/BoolAnd.php b/vendor/ruflin/elastica/lib/Elastica/Filter/BoolAnd.php
new file mode 100644
index 00000000..8a08ea9c
--- /dev/null
+++ b/vendor/ruflin/elastica/lib/Elastica/Filter/BoolAnd.php
@@ -0,0 +1,20 @@
+<?php
+namespace Elastica\Filter;
+
+/**
+ * And Filter.
+ *
+ * @author Lee Parker, Nicolas Ruflin <spam@ruflin.com>
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-and-filter.html
+ */
+class BoolAnd extends AbstractMulti
+{
+ /**
+ * @return string
+ */
+ protected function _getBaseName()
+ {
+ return 'and';
+ }
+}
diff --git a/vendor/ruflin/elastica/lib/Elastica/Filter/BoolFilter.php b/vendor/ruflin/elastica/lib/Elastica/Filter/BoolFilter.php
new file mode 100644
index 00000000..5a488b77
--- /dev/null
+++ b/vendor/ruflin/elastica/lib/Elastica/Filter/BoolFilter.php
@@ -0,0 +1,133 @@
+<?php
+namespace Elastica\Filter;
+
+use Elastica\Exception\InvalidException;
+
+/**
+ * Bool Filter.
+ *
+ * @author Nicolas Ruflin <spam@ruflin.com>
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-bool-filter.html
+ */
+class BoolFilter extends AbstractFilter
+{
+ /**
+ * Must.
+ *
+ * @var array
+ */
+ protected $_must = array();
+
+ /**
+ * Should.
+ *
+ * @var array
+ */
+ protected $_should = array();
+
+ /**
+ * Must not.
+ *
+ * @var array
+ */
+ protected $_mustNot = array();
+
+ /**
+ * Adds should filter.
+ *
+ * @param array|\Elastica\Filter\AbstractFilter $args Filter data
+ *
+ * @return $this
+ */
+ public function addShould($args)
+ {
+ return $this->_addFilter('should', $args);
+ }
+
+ /**
+ * Adds must filter.
+ *
+ * @param array|\Elastica\Filter\AbstractFilter $args Filter data
+ *
+ * @return $this
+ */
+ public function addMust($args)
+ {
+ return $this->_addFilter('must', $args);
+ }
+
+ /**
+ * Adds mustNot filter.
+ *
+ * @param array|\Elastica\Filter\AbstractFilter $args Filter data
+ *
+ * @return $this
+ */
+ public function addMustNot($args)
+ {
+ return $this->_addFilter('mustNot', $args);
+ }
+
+ /**
+ * Adds general filter based on type.
+ *
+ * @param string $type Filter type
+ * @param array|\Elastica\Filter\AbstractFilter $args Filter data
+ *
+ * @throws \Elastica\Exception\InvalidException
+ *
+ * @return $this
+ */
+ protected function _addFilter($type, $args)
+ {
+ if ($args instanceof AbstractFilter) {
+ $args = $args->toArray();
+ } elseif (!is_array($args)) {
+ throw new InvalidException('Invalid parameter. Has to be array or instance of Elastica\Filter');
+ } else {
+ $parsedArgs = array();
+ foreach ($args as $filter) {
+ if ($filter instanceof AbstractFilter) {
+ $parsedArgs[] = $filter->toArray();
+ }
+ }
+ $args = $parsedArgs;
+ }
+
+ $varName = '_'.$type;
+ $this->{$varName}[] = $args;
+
+ return $this;
+ }
+
+ /**
+ * Converts bool filter to array.
+ *
+ * @see \Elastica\Filter\AbstractFilter::toArray()
+ *
+ * @return array Filter array
+ */
+ public function toArray()
+ {
+ $args = array();
+
+ if (!empty($this->_must)) {
+ $args['bool']['must'] = $this->_must;
+ }
+
+ if (!empty($this->_should)) {
+ $args['bool']['should'] = $this->_should;
+ }
+
+ if (!empty($this->_mustNot)) {
+ $args['bool']['must_not'] = $this->_mustNot;
+ }
+
+ if (isset($args['bool'])) {
+ $args['bool'] = array_merge($args['bool'], $this->getParams());
+ }
+
+ return $args;
+ }
+}
diff --git a/vendor/ruflin/elastica/lib/Elastica/Filter/BoolNot.php b/vendor/ruflin/elastica/lib/Elastica/Filter/BoolNot.php
new file mode 100644
index 00000000..81db7f65
--- /dev/null
+++ b/vendor/ruflin/elastica/lib/Elastica/Filter/BoolNot.php
@@ -0,0 +1,42 @@
+<?php
+namespace Elastica\Filter;
+
+/**
+ * Not Filter.
+ *
+ * @author Lee Parker, Nicolas Ruflin <spam@ruflin.com>
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-not-filter.html
+ */
+class BoolNot extends AbstractFilter
+{
+ /**
+ * Creates Not filter query.
+ *
+ * @param \Elastica\Filter\AbstractFilter $filter Filter object
+ */
+ public function __construct(AbstractFilter $filter)
+ {
+ $this->setFilter($filter);
+ }
+
+ /**
+ * Set filter.
+ *
+ * @param \Elastica\Filter\AbstractFilter $filter
+ *
+ * @return $this
+ */
+ public function setFilter(AbstractFilter $filter)
+ {
+ return $this->setParam('filter', $filter->toArray());
+ }
+
+ /**
+ * @return string
+ */
+ protected function _getBaseName()
+ {
+ return 'not';
+ }
+}
diff --git a/vendor/ruflin/elastica/lib/Elastica/Filter/BoolOr.php b/vendor/ruflin/elastica/lib/Elastica/Filter/BoolOr.php
new file mode 100644
index 00000000..9091e496
--- /dev/null
+++ b/vendor/ruflin/elastica/lib/Elastica/Filter/BoolOr.php
@@ -0,0 +1,20 @@
+<?php
+namespace Elastica\Filter;
+
+/**
+ * Or Filter.
+ *
+ * @author Nicolas Ruflin <spam@ruflin.com>
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-or-filter.html
+ */
+class BoolOr extends AbstractMulti
+{
+ /**
+ * @return string
+ */
+ protected function _getBaseName()
+ {
+ return 'or';
+ }
+}
diff --git a/vendor/ruflin/elastica/lib/Elastica/Filter/Exists.php b/vendor/ruflin/elastica/lib/Elastica/Filter/Exists.php
new file mode 100644
index 00000000..d6dc9962
--- /dev/null
+++ b/vendor/ruflin/elastica/lib/Elastica/Filter/Exists.php
@@ -0,0 +1,34 @@
+<?php
+namespace Elastica\Filter;
+
+/**
+ * Exists query.
+ *
+ * @author Oleg Cherniy <oleg.cherniy@gmail.com>
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-exists-filter.html
+ */
+class Exists extends AbstractFilter
+{
+ /**
+ * Construct exists filter.
+ *
+ * @param string $field
+ */
+ public function __construct($field)
+ {
+ $this->setField($field);
+ }
+
+ /**
+ * Set field.
+ *
+ * @param string $field
+ *
+ * @return $this
+ */
+ public function setField($field)
+ {
+ return $this->setParam('field', $field);
+ }
+}
diff --git a/vendor/ruflin/elastica/lib/Elastica/Filter/GeoBoundingBox.php b/vendor/ruflin/elastica/lib/Elastica/Filter/GeoBoundingBox.php
new file mode 100644
index 00000000..f67febe3
--- /dev/null
+++ b/vendor/ruflin/elastica/lib/Elastica/Filter/GeoBoundingBox.php
@@ -0,0 +1,49 @@
+<?php
+namespace Elastica\Filter;
+
+use Elastica\Exception\InvalidException;
+
+/**
+ * Geo bounding box filter.
+ *
+ * @author Fabian Vogler <fabian@equivalence.ch>
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-geo-bounding-box-filter.html
+ */
+class GeoBoundingBox extends AbstractFilter
+{
+ /**
+ * Construct BoundingBoxFilter.
+ *
+ * @param string $key Key
+ * @param array $coordinates Array with top left coordinate as first and bottom right coordinate as second element
+ */
+ public function __construct($key, array $coordinates)
+ {
+ $this->addCoordinates($key, $coordinates);
+ }
+
+ /**
+ * Add coordinates.
+ *
+ * @param string $key Key
+ * @param array $coordinates Array with top left coordinate as first and bottom right coordinate as second element
+ *
+ * @throws \Elastica\Exception\InvalidException If $coordinates doesn't have two elements
+ *
+ * @return $this
+ */
+ public function addCoordinates($key, array $coordinates)
+ {
+ if (!isset($coordinates[0]) || !isset($coordinates[1])) {
+ throw new InvalidException('expected $coordinates to be an array with two elements');
+ }
+
+ $this->setParam($key, array(
+ 'top_left' => $coordinates[0],
+ 'bottom_right' => $coordinates[1],
+ ));
+
+ return $this;
+ }
+}
diff --git a/vendor/ruflin/elastica/lib/Elastica/Filter/GeoDistance.php b/vendor/ruflin/elastica/lib/Elastica/Filter/GeoDistance.php
new file mode 100644
index 00000000..f4cb51d9
--- /dev/null
+++ b/vendor/ruflin/elastica/lib/Elastica/Filter/GeoDistance.php
@@ -0,0 +1,76 @@
+<?php
+namespace Elastica\Filter;
+
+/**
+ * Geo distance filter.
+ *
+ * @author Nicolas Ruflin <spam@ruflin.com>
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-geo-distance-filter.html
+ */
+class GeoDistance extends AbstractGeoDistance
+{
+ const DISTANCE_TYPE_ARC = 'arc';
+ const DISTANCE_TYPE_PLANE = 'plane';
+ const DISTANCE_TYPE_SLOPPY_ARC = 'sloppy_arc';
+
+ const OPTIMIZE_BBOX_MEMORY = 'memory';
+ const OPTIMIZE_BBOX_INDEXED = 'indexed';
+ const OPTIMIZE_BBOX_NONE = 'none';
+
+ /**
+ * Create GeoDistance object.
+ *
+ * @param string $key Key
+ * @param array|string $location Location as array or geohash: array('lat' => 48.86, 'lon' => 2.35) OR 'drm3btev3e86'
+ * @param string $distance Distance
+ *
+ * @throws \Elastica\Exception\InvalidException
+ */
+ public function __construct($key, $location, $distance)
+ {
+ parent::__construct($key, $location);
+
+ $this->setDistance($distance);
+ }
+
+ /**
+ * @param string $distance
+ *
+ * @return $this
+ */
+ public function setDistance($distance)
+ {
+ $this->setParam('distance', $distance);
+
+ return $this;
+ }
+
+ /**
+ * See DISTANCE_TYPE_* constants.
+ *
+ * @param string $distanceType
+ *
+ * @return $this
+ */
+ public function setDistanceType($distanceType)
+ {
+ $this->setParam('distance_type', $distanceType);
+
+ return $this;
+ }
+
+ /**
+ * See OPTIMIZE_BBOX_* constants.
+ *
+ * @param string $optimizeBbox
+ *
+ * @return $this
+ */
+ public function setOptimizeBbox($optimizeBbox)
+ {
+ $this->setParam('optimize_bbox', $optimizeBbox);
+
+ return $this;
+ }
+}
diff --git a/vendor/ruflin/elastica/lib/Elastica/Filter/GeoDistanceRange.php b/vendor/ruflin/elastica/lib/Elastica/Filter/GeoDistanceRange.php
new file mode 100644
index 00000000..f5cbbeb7
--- /dev/null
+++ b/vendor/ruflin/elastica/lib/Elastica/Filter/GeoDistanceRange.php
@@ -0,0 +1,103 @@
+<?php
+namespace Elastica\Filter;
+
+use Elastica\Exception\InvalidException;
+
+/**
+ * Geo distance filter.
+ *
+ * @author munkie
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-geo-distance-range-filter.html
+ */
+class GeoDistanceRange extends AbstractGeoDistance
+{
+ const RANGE_FROM = 'from';
+ const RANGE_TO = 'to';
+ const RANGE_LT = 'lt';
+ const RANGE_LTE = 'lte';
+ const RANGE_GT = 'gt';
+ const RANGE_GTE = 'gte';
+
+ const RANGE_INCLUDE_LOWER = 'include_lower';
+ const RANGE_INCLUDE_UPPER = 'include_upper';
+
+ /**
+ * @var array
+ */
+ protected $_ranges = array();
+
+ /**
+ * @param string $key
+ * @param array|string $location
+ * @param array $ranges
+ *
+ * @internal param string $distance
+ */
+ public function __construct($key, $location, array $ranges = array())
+ {
+ parent::__construct($key, $location);
+
+ if (!empty($ranges)) {
+ $this->setRanges($ranges);
+ }
+ }
+
+ /**
+ * @param array $ranges
+ *
+ * @return $this
+ */
+ public function setRanges(array $ranges)
+ {
+ $this->_ranges = array();
+
+ foreach ($ranges as $key => $value) {
+ $this->setRange($key, $value);
+ }
+
+ return $this;
+ }
+
+ /**
+ * @param string $key
+ * @param mixed $value
+ *
+ * @throws \Elastica\Exception\InvalidException
+ *
+ * @return $this
+ */
+ public function setRange($key, $value)
+ {
+ switch ($key) {
+ case self::RANGE_TO:
+ case self::RANGE_FROM:
+ case self::RANGE_GT:
+ case self::RANGE_GTE:
+ case self::RANGE_LT:
+ case self::RANGE_LTE:
+ break;
+ case self::RANGE_INCLUDE_LOWER:
+ case self::RANGE_INCLUDE_UPPER:
+ $value = (boolean) $value;
+ break;
+ default:
+ throw new InvalidException('Invalid range parameter given: '.$key);
+ }
+ $this->_ranges[$key] = $value;
+
+ return $this;
+ }
+
+ /**
+ * @return array
+ */
+ public function toArray()
+ {
+ foreach ($this->_ranges as $key => $value) {
+ $this->setParam($key, $value);
+ }
+
+ return parent::toArray();
+ }
+}
diff --git a/vendor/ruflin/elastica/lib/Elastica/Filter/GeoPolygon.php b/vendor/ruflin/elastica/lib/Elastica/Filter/GeoPolygon.php
new file mode 100644
index 00000000..86ca2b80
--- /dev/null
+++ b/vendor/ruflin/elastica/lib/Elastica/Filter/GeoPolygon.php
@@ -0,0 +1,56 @@
+<?php
+namespace Elastica\Filter;
+
+/**
+ * Geo polygon filter.
+ *
+ * @author Michael Maclean <mgdm@php.net>
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-geo-polygon-filter.html
+ */
+class GeoPolygon extends AbstractFilter
+{
+ /**
+ * Key.
+ *
+ * @var string Key
+ */
+ protected $_key = '';
+
+ /**
+ * Points making up polygon.
+ *
+ * @var array Points making up polygon
+ */
+ protected $_points = array();
+
+ /**
+ * Construct polygon filter.
+ *
+ * @param string $key Key
+ * @param array $points Points making up polygon
+ */
+ public function __construct($key, array $points)
+ {
+ $this->_key = $key;
+ $this->_points = $points;
+ }
+
+ /**
+ * Converts filter to array.
+ *
+ * @see \Elastica\Filter\AbstractFilter::toArray()
+ *
+ * @return array
+ */
+ public function toArray()
+ {
+ return array(
+ 'geo_polygon' => array(
+ $this->_key => array(
+ 'points' => $this->_points,
+ ),
+ ),
+ );
+ }
+}
diff --git a/vendor/ruflin/elastica/lib/Elastica/Filter/GeoShapePreIndexed.php b/vendor/ruflin/elastica/lib/Elastica/Filter/GeoShapePreIndexed.php
new file mode 100644
index 00000000..d07cffff
--- /dev/null
+++ b/vendor/ruflin/elastica/lib/Elastica/Filter/GeoShapePreIndexed.php
@@ -0,0 +1,84 @@
+<?php
+namespace Elastica\Filter;
+
+/**
+ * geo_shape filter for pre-indexed shapes.
+ *
+ * Filter pre-indexed shape definitions
+ *
+ * @author Bennie Krijger <benniekrijger@gmail.com>
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-geo-shape-filter.html
+ */
+class GeoShapePreIndexed extends AbstractGeoShape
+{
+ /**
+ * elasticsearch id of the pre-indexed shape.
+ *
+ * @var string
+ */
+ protected $_indexedId;
+
+ /**
+ * elasticsearch type of the pre-indexed shape.
+ *
+ * @var string
+ */
+ protected $_indexedType;
+
+ /**
+ * elasticsearch index of the pre-indexed shape.
+ *
+ * @var string
+ */
+ protected $_indexedIndex;
+
+ /**
+ * elasticsearch path/field name of the pre-indexed shape.
+ *
+ * @var string
+ */
+ protected $_indexedPath;
+
+ /**
+ * Construct geo_shape filter with a pre-indexed shape.
+ *
+ * @param string $path The path/field of the shape searched
+ * @param string $indexedId Id of the pre-indexed shape
+ * @param string $indexedType Type of the pre-indexed shape
+ * @param string $indexedIndex Index of the pre-indexed shape
+ * @param string $indexedPath Path of the pre-indexed shape
+ */
+ public function __construct($path, $indexedId, $indexedType, $indexedIndex, $indexedPath)
+ {
+ $this->_path = $path;
+ $this->_indexedId = $indexedId;
+ $this->_indexedType = $indexedType;
+ $this->_indexedIndex = $indexedIndex;
+ $this->_indexedPath = $indexedPath;
+ }
+
+ /**
+ * Converts filter to array.
+ *
+ * @see \Elastica\Filter\AbstractFilter::toArray()
+ *
+ * @return array
+ */
+ public function toArray()
+ {
+ return array(
+ 'geo_shape' => array(
+ $this->_path => array(
+ 'indexed_shape' => array(
+ 'id' => $this->_indexedId,
+ 'type' => $this->_indexedType,
+ 'index' => $this->_indexedIndex,
+ 'path' => $this->_indexedPath,
+ ),
+ 'relation' => $this->_relation,
+ ),
+ ),
+ );
+ }
+}
diff --git a/vendor/ruflin/elastica/lib/Elastica/Filter/GeoShapeProvided.php b/vendor/ruflin/elastica/lib/Elastica/Filter/GeoShapeProvided.php
new file mode 100644
index 00000000..0f25beeb
--- /dev/null
+++ b/vendor/ruflin/elastica/lib/Elastica/Filter/GeoShapeProvided.php
@@ -0,0 +1,73 @@
+<?php
+namespace Elastica\Filter;
+
+/**
+ * geo_shape filter or provided shapes.
+ *
+ * Filter provided shape definitions
+ *
+ * @author BennieKrijger <benniekrijger@gmail.com>
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-geo-shape-filter.html
+ */
+class GeoShapeProvided extends AbstractGeoShape
+{
+ const TYPE_ENVELOPE = 'envelope';
+ const TYPE_MULTIPOINT = 'multipoint';
+ const TYPE_POINT = 'point';
+ const TYPE_MULTIPOLYGON = 'multipolygon';
+ const TYPE_LINESTRING = 'linestring';
+ const TYPE_POLYGON = 'polygon';
+
+ /**
+ * Type of the geo_shape.
+ *
+ * @var string
+ */
+ protected $_shapeType;
+
+ /**
+ * Coordinates making up geo_shape.
+ *
+ * @var array Coordinates making up geo_shape
+ */
+ protected $_coordinates;
+
+ /**
+ * Construct geo_shape filter.
+ *
+ * @param string $path The path/field of the shape searched
+ * @param array $coordinates Points making up the shape
+ * @param string $shapeType Type of the geo_shape:
+ * point, envelope, linestring, polygon,
+ * multipoint or multipolygon
+ */
+ public function __construct($path, array $coordinates, $shapeType = self::TYPE_ENVELOPE)
+ {
+ $this->_path = $path;
+ $this->_shapeType = $shapeType;
+ $this->_coordinates = $coordinates;
+ }
+
+ /**
+ * Converts filter to array.
+ *
+ * @see \Elastica\Filter\AbstractFilter::toArray()
+ *
+ * @return array
+ */
+ public function toArray()
+ {
+ return array(
+ 'geo_shape' => array(
+ $this->_path => array(
+ 'shape' => array(
+ 'type' => $this->_shapeType,
+ 'coordinates' => $this->_coordinates,
+ ),
+ 'relation' => $this->_relation,
+ ),
+ ),
+ );
+ }
+}
diff --git a/vendor/ruflin/elastica/lib/Elastica/Filter/GeohashCell.php b/vendor/ruflin/elastica/lib/Elastica/Filter/GeohashCell.php
new file mode 100644
index 00000000..dd147152
--- /dev/null
+++ b/vendor/ruflin/elastica/lib/Elastica/Filter/GeohashCell.php
@@ -0,0 +1,47 @@
+<?php
+namespace Elastica\Filter;
+
+/**
+ * Class GeohashCell.
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-geohash-cell-filter.html
+ */
+class GeohashCell extends AbstractGeoDistance
+{
+ /**
+ * @param string $key The field on which to filter
+ * @param array|string $location Location as coordinates array or geohash string ['lat' => 40.3, 'lon' => 45.2]
+ * @param string|int $precision Integer length of geohash prefix or distance (3, or "50m")
+ * @param bool $neighbors If true, filters cells next to the given cell.
+ */
+ public function __construct($key, $location, $precision = -1, $neighbors = false)
+ {
+ parent::__construct($key, $location);
+ $this->setPrecision($precision);
+ $this->setNeighbors($neighbors);
+ }
+
+ /**
+ * Set the precision for this filter.
+ *
+ * @param string|int $precision Integer length of geohash prefix or distance (3, or "50m")
+ *
+ * @return $this
+ */
+ public function setPrecision($precision)
+ {
+ return $this->setParam('precision', $precision);
+ }
+
+ /**
+ * Set the neighbors option for this filter.
+ *
+ * @param bool $neighbors If true, filters cells next to the given cell.
+ *
+ * @return $this
+ */
+ public function setNeighbors($neighbors)
+ {
+ return $this->setParam('neighbors', (bool) $neighbors);
+ }
+}
diff --git a/vendor/ruflin/elastica/lib/Elastica/Filter/HasChild.php b/vendor/ruflin/elastica/lib/Elastica/Filter/HasChild.php
new file mode 100644
index 00000000..2c4cc0d6
--- /dev/null
+++ b/vendor/ruflin/elastica/lib/Elastica/Filter/HasChild.php
@@ -0,0 +1,95 @@
+<?php
+namespace Elastica\Filter;
+
+/**
+ * Returns parent documents having child docs matching the query.
+ *
+ * @author Fabian Vogler <fabian@equivalence.ch>
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-has-child-filter.html
+ */
+class HasChild extends AbstractFilter
+{
+ /**
+ * Construct HasChild filter.
+ *
+ * @param string|\Elastica\Query|\Elastica\Filter\AbstractFilter $query Query string or a Elastica\Query object or a filter
+ * @param string|\Elastica\Type $type Child document type
+ */
+ public function __construct($query, $type = null)
+ {
+ $this->setType($type);
+ if ($query instanceof AbstractFilter) {
+ $this->setFilter($query);
+ } else {
+ $this->setQuery($query);
+ }
+ }
+
+ /**
+ * Sets query object.
+ *
+ * @param string|\Elastica\Query|\Elastica\Query\AbstractQuery $query
+ *
+ * @return $this
+ */
+ public function setQuery($query)
+ {
+ $query = \Elastica\Query::create($query);
+ $data = $query->toArray();
+
+ return $this->setParam('query', $data['query']);
+ }
+
+ /**
+ * Sets the filter object.
+ *
+ * @param \Elastica\Filter\AbstractFilter $filter
+ *
+ * @return $this
+ */
+ public function setFilter($filter)
+ {
+ return $this->setParam('filter', $filter->toArray());
+ }
+
+ /**
+ * Set type of the child document.
+ *
+ * @param string|\Elastica\Type $type Child document type
+ *
+ * @return $this
+ */
+ public function setType($type)
+ {
+ if ($type instanceof \Elastica\Type) {
+ $type = $type->getName();
+ }
+
+ return $this->setParam('type', (string) $type);
+ }
+
+ /**
+ * Set minimum number of children are required to match for the parent doc to be considered a match.
+ *
+ * @param int $count
+ *
+ * @return $this
+ */
+ public function setMinimumChildrenCount($count)
+ {
+ return $this->setParam('min_children', (int) $count);
+ }
+
+ /**
+ * Set maximum number of children are required to match for the parent doc to be considered a match.
+ *
+ * @param int $count
+ *
+ * @return $this
+ */
+ public function setMaximumChildrenCount($count)
+ {
+ return $this->setParam('max_children', (int) $count);
+ }
+}
diff --git a/vendor/ruflin/elastica/lib/Elastica/Filter/HasParent.php b/vendor/ruflin/elastica/lib/Elastica/Filter/HasParent.php
new file mode 100644
index 00000000..73a2dc5a
--- /dev/null
+++ b/vendor/ruflin/elastica/lib/Elastica/Filter/HasParent.php
@@ -0,0 +1,69 @@
+<?php
+namespace Elastica\Filter;
+
+/**
+ * Returns child documents having parent docs matching the query.
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-has-parent-filter.html
+ */
+class HasParent extends AbstractFilter
+{
+ /**
+ * Construct HasParent filter.
+ *
+ * @param string|\Elastica\Query|\Elastica\Filter\AbstractFilter $query Query string or a Query object or a filter
+ * @param string|\Elastica\Type $type Parent document type
+ */
+ public function __construct($query, $type)
+ {
+ if ($query instanceof AbstractFilter) {
+ $this->setFilter($query);
+ } else {
+ $this->setQuery($query);
+ }
+ $this->setType($type);
+ }
+
+ /**
+ * Sets query object.
+ *
+ * @param string|\Elastica\Query|\Elastica\Query\AbstractQuery $query
+ *
+ * @return $this
+ */
+ public function setQuery($query)
+ {
+ $query = \Elastica\Query::create($query);
+ $data = $query->toArray();
+
+ return $this->setParam('query', $data['query']);
+ }
+
+ /**
+ * Sets filter object.
+ *
+ * @param \Elastica\Filter\AbstractFilter $filter
+ *
+ * @return $this
+ */
+ public function setFilter($filter)
+ {
+ return $this->setParam('filter', $filter->toArray());
+ }
+
+ /**
+ * Set type of the parent document.
+ *
+ * @param string|\Elastica\Type $type Parent document type
+ *
+ * @return $this
+ */
+ public function setType($type)
+ {
+ if ($type instanceof \Elastica\Type) {
+ $type = $type->getName();
+ }
+
+ return $this->setParam('type', (string) $type);
+ }
+}
diff --git a/vendor/ruflin/elastica/lib/Elastica/Filter/Ids.php b/vendor/ruflin/elastica/lib/Elastica/Filter/Ids.php
new file mode 100644
index 00000000..bfb8cc48
--- /dev/null
+++ b/vendor/ruflin/elastica/lib/Elastica/Filter/Ids.php
@@ -0,0 +1,94 @@
+<?php
+namespace Elastica\Filter;
+
+use Elastica\Type as ElasticaType;
+
+/**
+ * Ids Filter.
+ *
+ * @author Lee Parker, Nicolas Ruflin <spam@ruflin.com>
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-ids-filter.html
+ */
+class Ids extends AbstractFilter
+{
+ /**
+ * Creates filter object.
+ *
+ * @param string|\Elastica\Type $type Type to filter on
+ * @param array $ids List of ids
+ */
+ public function __construct($type = null, array $ids = array())
+ {
+ $this->setType($type);
+ $this->setIds($ids);
+ }
+
+ /**
+ * Adds one more filter to the and filter.
+ *
+ * @param string $id Adds id to filter
+ *
+ * @return $this
+ */
+ public function addId($id)
+ {
+ return $this->addParam('values', $id);
+ }
+
+ /**
+ * Adds one more type to query.
+ *
+ * @param string|\Elastica\Type $type Type name or object
+ *
+ * @return $this
+ */
+ public function addType($type)
+ {
+ if ($type instanceof ElasticaType) {
+ $type = $type->getName();
+ } elseif (empty($type) && !is_numeric($type)) {
+ // TODO: Shouldn't this throw an exception?
+ // A type can be 0, but cannot be empty
+ return $this;
+ }
+
+ return $this->addParam('type', $type);
+ }
+
+ /**
+ * Set type.
+ *
+ * @param string|\Elastica\Type $type Type name or object
+ *
+ * @return $this
+ */
+ public function setType($type)
+ {
+ if ($type instanceof ElasticaType) {
+ $type = $type->getName();
+ } elseif (empty($type) && !is_numeric($type)) {
+ // TODO: Shouldn't this throw an exception or let handling of invalid params to ES?
+ // A type can be 0, but cannot be empty
+ return $this;
+ }
+
+ return $this->setParam('type', $type);
+ }
+
+ /**
+ * Sets the ids to filter.
+ *
+ * @param array|string $ids List of ids
+ *
+ * @return $this
+ */
+ public function setIds($ids)
+ {
+ if (!is_array($ids)) {
+ $ids = array($ids);
+ }
+
+ return $this->setParam('values', $ids);
+ }
+}
diff --git a/vendor/ruflin/elastica/lib/Elastica/Filter/Indices.php b/vendor/ruflin/elastica/lib/Elastica/Filter/Indices.php
new file mode 100644
index 00000000..ffaf5975
--- /dev/null
+++ b/vendor/ruflin/elastica/lib/Elastica/Filter/Indices.php
@@ -0,0 +1,78 @@
+<?php
+namespace Elastica\Filter;
+
+use Elastica\Index as ElasticaIndex;
+
+/**
+ * Class Indices.
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-indices-filter.html
+ */
+class Indices extends AbstractFilter
+{
+ /**
+ * @param AbstractFilter $filter filter which will be applied to docs in the specified indices
+ * @param mixed[] $indices
+ */
+ public function __construct(AbstractFilter $filter, array $indices)
+ {
+ $this->setIndices($indices)->setFilter($filter);
+ }
+
+ /**
+ * Set the indices on which this filter should be applied.
+ *
+ * @param mixed[] $indices
+ *
+ * @return $this
+ */
+ public function setIndices(array $indices)
+ {
+ $this->setParam('indices', array());
+ foreach ($indices as $index) {
+ $this->addIndex($index);
+ }
+
+ return $this;
+ }
+
+ /**
+ * Adds one more index on which this filter should be applied.
+ *
+ * @param string|\Elastica\Index $index
+ *
+ * @return $this
+ */
+ public function addIndex($index)
+ {
+ if ($index instanceof ElasticaIndex) {
+ $index = $index->getName();
+ }
+
+ return $this->addParam('indices', (string) $index);
+ }
+
+ /**
+ * Set the filter to be applied to docs in the specified indices.
+ *
+ * @param AbstractFilter $filter
+ *
+ * @return $this
+ */
+ public function setFilter(AbstractFilter $filter)
+ {
+ return $this->setParam('filter', $filter->toArray());
+ }
+
+ /**
+ * Set the filter to be applied to docs in indices which do not match those specified in the "indices" parameter.
+ *
+ * @param AbstractFilter $filter
+ *
+ * @return $this
+ */
+ public function setNoMatchFilter(AbstractFilter $filter)
+ {
+ return $this->setParam('no_match_filter', $filter->toArray());
+ }
+}
diff --git a/vendor/ruflin/elastica/lib/Elastica/Filter/Limit.php b/vendor/ruflin/elastica/lib/Elastica/Filter/Limit.php
new file mode 100644
index 00000000..bf3f8e13
--- /dev/null
+++ b/vendor/ruflin/elastica/lib/Elastica/Filter/Limit.php
@@ -0,0 +1,34 @@
+<?php
+namespace Elastica\Filter;
+
+/**
+ * Limit Filter.
+ *
+ * @author Nicolas Ruflin <spam@ruflin.com>
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-limit-filter.html
+ */
+class Limit extends AbstractFilter
+{
+ /**
+ * Construct limit filter.
+ *
+ * @param int $limit Limit
+ */
+ public function __construct($limit)
+ {
+ $this->setLimit($limit);
+ }
+
+ /**
+ * Set the limit.
+ *
+ * @param int $limit Limit
+ *
+ * @return $this
+ */
+ public function setLimit($limit)
+ {
+ return $this->setParam('value', (int) $limit);
+ }
+}
diff --git a/vendor/ruflin/elastica/lib/Elastica/Filter/MatchAll.php b/vendor/ruflin/elastica/lib/Elastica/Filter/MatchAll.php
new file mode 100644
index 00000000..607c5fd1
--- /dev/null
+++ b/vendor/ruflin/elastica/lib/Elastica/Filter/MatchAll.php
@@ -0,0 +1,20 @@
+<?php
+namespace Elastica\Filter;
+
+/**
+ * Match all filter.
+ *
+ * @author Nicolas Ruflin <spam@ruflin.com>
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-match-all-filter.html
+ */
+class MatchAll extends AbstractFilter
+{
+ /**
+ * Creates match all filter.
+ */
+ public function __construct()
+ {
+ $this->_params = new \stdClass();
+ }
+}
diff --git a/vendor/ruflin/elastica/lib/Elastica/Filter/Missing.php b/vendor/ruflin/elastica/lib/Elastica/Filter/Missing.php
new file mode 100644
index 00000000..9b157b2c
--- /dev/null
+++ b/vendor/ruflin/elastica/lib/Elastica/Filter/Missing.php
@@ -0,0 +1,60 @@
+<?php
+namespace Elastica\Filter;
+
+/**
+ * Missing Filter.
+ *
+ * @author Maciej Wiercinski <maciej@wiercinski.net>
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-missing-filter.html
+ */
+class Missing extends AbstractFilter
+{
+ /**
+ * Construct missing filter.
+ *
+ * @param string $field OPTIONAL
+ */
+ public function __construct($field = '')
+ {
+ if (strlen($field)) {
+ $this->setField($field);
+ }
+ }
+
+ /**
+ * Set field.
+ *
+ * @param string $field
+ *
+ * @return $this
+ */
+ public function setField($field)
+ {
+ return $this->setParam('field', (string) $field);
+ }
+
+ /**
+ * Set "existence" parameter.
+ *
+ * @param bool $existence
+ *
+ * @return $this
+ */
+ public function setExistence($existence)
+ {
+ return $this->setParam('existence', (bool) $existence);
+ }
+
+ /**
+ * Set "null_value" parameter.
+ *
+ * @param bool $nullValue
+ *
+ * @return $this
+ */
+ public function setNullValue($nullValue)
+ {
+ return $this->setParam('null_value', (bool) $nullValue);
+ }
+}
diff --git a/vendor/ruflin/elastica/lib/Elastica/Filter/Nested.php b/vendor/ruflin/elastica/lib/Elastica/Filter/Nested.php
new file mode 100644
index 00000000..ad21bc7e
--- /dev/null
+++ b/vendor/ruflin/elastica/lib/Elastica/Filter/Nested.php
@@ -0,0 +1,62 @@
+<?php
+namespace Elastica\Filter;
+
+use Elastica\Query\AbstractQuery;
+
+/**
+ * Nested filter.
+ *
+ * @author Nicolas Ruflin <spam@ruflin.com>
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-nested-filter.html
+ */
+class Nested extends AbstractFilter
+{
+ /**
+ * Adds field to mlt filter.
+ *
+ * @param string $path Nested object path
+ *
+ * @return $this
+ */
+ public function setPath($path)
+ {
+ return $this->setParam('path', $path);
+ }
+
+ /**
+ * Sets nested query.
+ *
+ * @param \Elastica\Query\AbstractQuery $query
+ *
+ * @return $this
+ */
+ public function setQuery(AbstractQuery $query)
+ {
+ return $this->setParam('query', $query->toArray());
+ }
+
+ /**
+ * Sets nested filter.
+ *
+ * @param \Elastica\Filter\AbstractFilter $filter
+ *
+ * @return $this
+ */
+ public function setFilter(AbstractFilter $filter)
+ {
+ return $this->setParam('filter', $filter->toArray());
+ }
+
+ /**
+ * Set join option.
+ *
+ * @param bool $join
+ *
+ * @return $this
+ */
+ public function setJoin($join)
+ {
+ return $this->setParam('join', (bool) $join);
+ }
+}
diff --git a/vendor/ruflin/elastica/lib/Elastica/Filter/NumericRange.php b/vendor/ruflin/elastica/lib/Elastica/Filter/NumericRange.php
new file mode 100644
index 00000000..08342616
--- /dev/null
+++ b/vendor/ruflin/elastica/lib/Elastica/Filter/NumericRange.php
@@ -0,0 +1,13 @@
+<?php
+namespace Elastica\Filter;
+
+/**
+ * Numeric Range Filter.
+ *
+ * @author Nicolas Ruflin <spam@ruflin.com>
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-range-filter.html
+ */
+class NumericRange extends Range
+{
+}
diff --git a/vendor/ruflin/elastica/lib/Elastica/Filter/Prefix.php b/vendor/ruflin/elastica/lib/Elastica/Filter/Prefix.php
new file mode 100644
index 00000000..e845fd73
--- /dev/null
+++ b/vendor/ruflin/elastica/lib/Elastica/Filter/Prefix.php
@@ -0,0 +1,80 @@
+<?php
+namespace Elastica\Filter;
+
+/**
+ * Prefix filter.
+ *
+ * @author Jasper van Wanrooy <jasper@vanwanrooy.net>
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-prefix-filter.html
+ */
+class Prefix extends AbstractFilter
+{
+ /**
+ * Holds the name of the field for the prefix.
+ *
+ * @var string
+ */
+ protected $_field = '';
+
+ /**
+ * Holds the prefix string.
+ *
+ * @var string
+ */
+ protected $_prefix = '';
+
+ /**
+ * Creates prefix filter.
+ *
+ * @param string $field Field name
+ * @param string $prefix Prefix string
+ */
+ public function __construct($field = '', $prefix = '')
+ {
+ $this->setField($field);
+ $this->setPrefix($prefix);
+ }
+
+ /**
+ * Sets the name of the prefix field.
+ *
+ * @param string $field Field name
+ *
+ * @return $this
+ */
+ public function setField($field)
+ {
+ $this->_field = $field;
+
+ return $this;
+ }
+
+ /**
+ * Sets the prefix string.
+ *
+ * @param string $prefix Prefix string
+ *
+ * @return $this
+ */
+ public function setPrefix($prefix)
+ {
+ $this->_prefix = $prefix;
+
+ return $this;
+ }
+
+ /**
+ * Converts object to an array.
+ *
+ * @see \Elastica\Filter\AbstractFilter::toArray()
+ *
+ * @return array data array
+ */
+ public function toArray()
+ {
+ $this->setParam($this->_field, $this->_prefix);
+
+ return parent::toArray();
+ }
+}
diff --git a/vendor/ruflin/elastica/lib/Elastica/Filter/Query.php b/vendor/ruflin/elastica/lib/Elastica/Filter/Query.php
new file mode 100644
index 00000000..acb6a124
--- /dev/null
+++ b/vendor/ruflin/elastica/lib/Elastica/Filter/Query.php
@@ -0,0 +1,91 @@
+<?php
+namespace Elastica\Filter;
+
+use Elastica\Exception\InvalidException;
+use Elastica\Query\AbstractQuery;
+
+/**
+ * Query filter.
+ *
+ * @author Nicolas Ruflin <spam@ruflin.com>
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-query-filter.html
+ */
+class Query extends AbstractFilter
+{
+ /**
+ * Query.
+ *
+ * @var array
+ */
+ protected $_query;
+
+ /**
+ * Construct query filter.
+ *
+ * @param array|\Elastica\Query\AbstractQuery $query
+ */
+ public function __construct($query = null)
+ {
+ if (!is_null($query)) {
+ $this->setQuery($query);
+ }
+ }
+
+ /**
+ * Set query.
+ *
+ * @param array|\Elastica\Query\AbstractQuery $query
+ *
+ * @throws \Elastica\Exception\InvalidException If parameter is invalid
+ *
+ * @return $this
+ */
+ public function setQuery($query)
+ {
+ if (!$query instanceof AbstractQuery && !is_array($query)) {
+ throw new InvalidException('expected an array or instance of Elastica\Query\AbstractQuery');
+ }
+
+ if ($query instanceof AbstractQuery) {
+ $query = $query->toArray();
+ }
+
+ $this->_query = $query;
+
+ return $this;
+ }
+
+ /**
+ * @see \Elastica\Param::_getBaseName()
+ */
+ protected function _getBaseName()
+ {
+ if (empty($this->_params)) {
+ return 'query';
+ } else {
+ return 'fquery';
+ }
+ }
+
+ /**
+ * @see \Elastica\Param::toArray()
+ */
+ public function toArray()
+ {
+ $data = parent::toArray();
+
+ $name = $this->_getBaseName();
+ $filterData = $data[$name];
+
+ if (empty($filterData)) {
+ $filterData = $this->_query;
+ } else {
+ $filterData['query'] = $this->_query;
+ }
+
+ $data[$name] = $filterData;
+
+ return $data;
+ }
+}
diff --git a/vendor/ruflin/elastica/lib/Elastica/Filter/Range.php b/vendor/ruflin/elastica/lib/Elastica/Filter/Range.php
new file mode 100644
index 00000000..1e7bf132
--- /dev/null
+++ b/vendor/ruflin/elastica/lib/Elastica/Filter/Range.php
@@ -0,0 +1,73 @@
+<?php
+namespace Elastica\Filter;
+
+/**
+ * Range Filter.
+ *
+ * @author Nicolas Ruflin <spam@ruflin.com>
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-range-filter.html
+ */
+class Range extends AbstractFilter
+{
+ /**
+ * Fields.
+ *
+ * @var array Fields
+ */
+ protected $_fields = array();
+
+ /**
+ * Construct range filter.
+ *
+ * @param string $fieldName Field name
+ * @param array $args Field arguments
+ */
+ public function __construct($fieldName = '', array $args = array())
+ {
+ if ($fieldName) {
+ $this->addField($fieldName, $args);
+ }
+ }
+
+ /**
+ * Ads a field with arguments to the range query.
+ *
+ * @param string $fieldName Field name
+ * @param array $args Field arguments
+ *
+ * @return $this
+ */
+ public function addField($fieldName, array $args)
+ {
+ $this->_fields[$fieldName] = $args;
+
+ return $this;
+ }
+
+ /**
+ * Set execution mode.
+ *
+ * @param string $execution Options: "index" or "fielddata"
+ *
+ * @return $this
+ */
+ public function setExecution($execution)
+ {
+ return $this->setParam('execution', (string) $execution);
+ }
+
+ /**
+ * Converts object to array.
+ *
+ * @see \Elastica\Filter\AbstractFilter::toArray()
+ *
+ * @return array Filter array
+ */
+ public function toArray()
+ {
+ $this->setParams(array_merge($this->getParams(), $this->_fields));
+
+ return parent::toArray();
+ }
+}
diff --git a/vendor/ruflin/elastica/lib/Elastica/Filter/Regexp.php b/vendor/ruflin/elastica/lib/Elastica/Filter/Regexp.php
new file mode 100644
index 00000000..612dc434
--- /dev/null
+++ b/vendor/ruflin/elastica/lib/Elastica/Filter/Regexp.php
@@ -0,0 +1,112 @@
+<?php
+namespace Elastica\Filter;
+
+/**
+ * Regexp filter.
+ *
+ * @author Timothy Lamb <trash80@gmail.com>
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-regexp-filter.html
+ */
+class Regexp extends AbstractFilter
+{
+ /**
+ * Holds the name of the field for the regular expression.
+ *
+ * @var string
+ */
+ protected $_field = '';
+
+ /**
+ * Holds the regexp string.
+ *
+ * @var string
+ */
+ protected $_regexp = '';
+
+ /**
+ * Holds the regexp options.
+ *
+ * @var array
+ */
+ protected $_options = array();
+
+ /**
+ * Create Regexp object.
+ *
+ * @param string $field Field name
+ * @param string $regexp Regular expression
+ * @param array $options Regular expression options
+ *
+ * @throws \Elastica\Exception\InvalidException
+ */
+ public function __construct($field = '', $regexp = '', $options = array())
+ {
+ $this->setField($field);
+ $this->setRegexp($regexp);
+ $this->setOptions($options);
+ }
+
+ /**
+ * Sets the name of the regexp field.
+ *
+ * @param string $field Field name
+ *
+ * @return $this
+ */
+ public function setField($field)
+ {
+ $this->_field = $field;
+
+ return $this;
+ }
+
+ /**
+ * Sets the regular expression query string.
+ *
+ * @param string $regexp Regular expression
+ *
+ * @return $this
+ */
+ public function setRegexp($regexp)
+ {
+ $this->_regexp = $regexp;
+
+ return $this;
+ }
+
+ /**
+ * Sets the regular expression query options.
+ *
+ * @param array $options Regular expression options
+ *
+ * @return $this
+ */
+ public function setOptions($options)
+ {
+ $this->_options = $options;
+
+ return $this;
+ }
+
+ /**
+ * Converts object to an array.
+ *
+ * @see \Elastica\Filter\AbstractFilter::toArray()
+ *
+ * @return array data array
+ */
+ public function toArray()
+ {
+ if (count($this->_options) > 0) {
+ $options = array('value' => $this->_regexp);
+ $options = array_merge($options, $this->_options);
+
+ $this->setParam($this->_field, $options);
+ } else {
+ $this->setParam($this->_field, $this->_regexp);
+ }
+
+ return parent::toArray();
+ }
+}
diff --git a/vendor/ruflin/elastica/lib/Elastica/Filter/Script.php b/vendor/ruflin/elastica/lib/Elastica/Filter/Script.php
new file mode 100644
index 00000000..2c8d34bf
--- /dev/null
+++ b/vendor/ruflin/elastica/lib/Elastica/Filter/Script.php
@@ -0,0 +1,47 @@
+<?php
+namespace Elastica\Filter;
+
+use Elastica;
+
+/**
+ * Script filter.
+ *
+ * @author Nicolas Ruflin <spam@ruflin.com>
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-script-filter.html
+ */
+class Script extends AbstractFilter
+{
+ /**
+ * Query object.
+ *
+ * @var array|\Elastica\Query\AbstractQuery
+ */
+ protected $_query = null;
+
+ /**
+ * Construct script filter.
+ *
+ * @param array|string|\Elastica\Script $script OPTIONAL Script
+ */
+ public function __construct($script = null)
+ {
+ if ($script) {
+ $this->setScript($script);
+ }
+ }
+
+ /**
+ * Sets script object.
+ *
+ * @param \Elastica\Script|string|array $script
+ *
+ * @return $this
+ */
+ public function setScript($script)
+ {
+ $script = Elastica\Script::create($script);
+
+ return $this->setParams($script->toArray());
+ }
+}
diff --git a/vendor/ruflin/elastica/lib/Elastica/Filter/Term.php b/vendor/ruflin/elastica/lib/Elastica/Filter/Term.php
new file mode 100644
index 00000000..2a387318
--- /dev/null
+++ b/vendor/ruflin/elastica/lib/Elastica/Filter/Term.php
@@ -0,0 +1,47 @@
+<?php
+namespace Elastica\Filter;
+
+/**
+ * Term query.
+ *
+ * @author Nicolas Ruflin <spam@ruflin.com>
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-term-filter.html
+ */
+class Term extends AbstractFilter
+{
+ /**
+ * Construct term filter.
+ *
+ * @param array $term Term array
+ */
+ public function __construct(array $term = array())
+ {
+ $this->setRawTerm($term);
+ }
+
+ /**
+ * Sets/overwrites key and term directly.
+ *
+ * @param array $term Key value pair
+ *
+ * @return $this
+ */
+ public function setRawTerm(array $term)
+ {
+ return $this->setParams($term);
+ }
+
+ /**
+ * Adds a term to the term query.
+ *
+ * @param string $key Key to query
+ * @param string|array $value Values(s) for the query. Boost can be set with array
+ *
+ * @return $this
+ */
+ public function setTerm($key, $value)
+ {
+ return $this->setRawTerm(array($key => $value));
+ }
+}
diff --git a/vendor/ruflin/elastica/lib/Elastica/Filter/Terms.php b/vendor/ruflin/elastica/lib/Elastica/Filter/Terms.php
new file mode 100644
index 00000000..c099ab3d
--- /dev/null
+++ b/vendor/ruflin/elastica/lib/Elastica/Filter/Terms.php
@@ -0,0 +1,149 @@
+<?php
+namespace Elastica\Filter;
+
+use Elastica\Exception\InvalidException;
+
+/**
+ * Terms filter.
+ *
+ * @author Nicolas Ruflin <spam@ruflin.com>
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-terms-filter.html
+ */
+class Terms extends AbstractFilter
+{
+ /**
+ * Terms.
+ *
+ * @var array Terms
+ */
+ protected $_terms = array();
+
+ /**
+ * Params.
+ *
+ * @var array Params
+ */
+ protected $_params = array();
+
+ /**
+ * Terms key.
+ *
+ * @var string Terms key
+ */
+ protected $_key = '';
+
+ /**
+ * Creates terms filter.
+ *
+ * @param string $key Terms key
+ * @param array $terms Terms values
+ */
+ public function __construct($key = '', array $terms = array())
+ {
+ $this->setTerms($key, $terms);
+ }
+
+ /**
+ * Sets key and terms for the filter.
+ *
+ * @param string $key Terms key
+ * @param array $terms Terms for the query.
+ *
+ * @return $this
+ */
+ public function setTerms($key, array $terms)
+ {
+ $this->_key = $key;
+ $this->_terms = array_values($terms);
+
+ return $this;
+ }
+
+ /**
+ * Set the lookup parameters for this filter.
+ *
+ * @param string $key terms key
+ * @param string|\Elastica\Type $type document type from which to fetch the terms values
+ * @param string $id id of the document from which to fetch the terms values
+ * @param string $path the field from which to fetch the values for the filter
+ * @param string|array|\Elastica\Index $options An array of options or the index from which to fetch the terms values. Defaults to the current index.
+ *
+ * @return $this
+ */
+ public function setLookup($key, $type, $id, $path, $options = array())
+ {
+ $this->_key = $key;
+ if ($type instanceof \Elastica\Type) {
+ $type = $type->getName();
+ }
+ $this->_terms = array(
+ 'type' => $type,
+ 'id' => $id,
+ 'path' => $path,
+ );
+
+ $index = $options;
+ if (is_array($options)) {
+ if (isset($options['index'])) {
+ $index = $options['index'];
+ unset($options['index']);
+ }
+ $this->_terms = array_merge($options, $this->_terms);
+ }
+
+ if (!is_null($index)) {
+ if ($index instanceof \Elastica\Index) {
+ $index = $index->getName();
+ }
+ $this->_terms['index'] = $index;
+ }
+
+ return $this;
+ }
+
+ /**
+ * Adds an additional term to the query.
+ *
+ * @param string $term Filter term
+ *
+ * @return $this
+ */
+ public function addTerm($term)
+ {
+ $this->_terms[] = $term;
+
+ return $this;
+ }
+
+ /**
+ * Converts object to an array.
+ *
+ * @see \Elastica\Filter\AbstractFilter::toArray()
+ *
+ * @throws \Elastica\Exception\InvalidException
+ *
+ * @return array
+ */
+ public function toArray()
+ {
+ if (empty($this->_key)) {
+ throw new InvalidException('Terms key has to be set');
+ }
+ $this->_params[$this->_key] = $this->_terms;
+
+ return array('terms' => $this->_params);
+ }
+
+ /**
+ * Set execution mode.
+ *
+ * @param string $execution Options: "bool", "and", "or", "plain" or "fielddata"
+ *
+ * @return $this
+ */
+ public function setExecution($execution)
+ {
+ return $this->setParam('execution', (string) $execution);
+ }
+}
diff --git a/vendor/ruflin/elastica/lib/Elastica/Filter/Type.php b/vendor/ruflin/elastica/lib/Elastica/Filter/Type.php
new file mode 100644
index 00000000..f9c17813
--- /dev/null
+++ b/vendor/ruflin/elastica/lib/Elastica/Filter/Type.php
@@ -0,0 +1,59 @@
+<?php
+namespace Elastica\Filter;
+
+/**
+ * Type Filter.
+ *
+ * @author James Wilson <jwilson556@gmail.com>
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-type-filter.html
+ */
+class Type extends AbstractFilter
+{
+ /**
+ * Type name.
+ *
+ * @var string
+ */
+ protected $_type = null;
+
+ /**
+ * Construct Type Filter.
+ *
+ * @param string $type Type name
+ */
+ public function __construct($type = null)
+ {
+ if ($type) {
+ $this->setType($type);
+ }
+ }
+
+ /**
+ * Ads a field with arguments to the range query.
+ *
+ * @param string $typeName Type name
+ *
+ * @return $this
+ */
+ public function setType($typeName)
+ {
+ $this->_type = $typeName;
+
+ return $this;
+ }
+
+ /**
+ * Convert object to array.
+ *
+ * @see \Elastica\Filter\AbstractFilter::toArray()
+ *
+ * @return array Filter array
+ */
+ public function toArray()
+ {
+ return array(
+ 'type' => array('value' => $this->_type),
+ );
+ }
+}
diff --git a/vendor/ruflin/elastica/lib/Elastica/Index.php b/vendor/ruflin/elastica/lib/Elastica/Index.php
new file mode 100644
index 00000000..3b8d431b
--- /dev/null
+++ b/vendor/ruflin/elastica/lib/Elastica/Index.php
@@ -0,0 +1,515 @@
+<?php
+namespace Elastica;
+
+use Elastica\Exception\InvalidException;
+use Elastica\Exception\ResponseException;
+use Elastica\Index\Settings as IndexSettings;
+use Elastica\Index\Stats as IndexStats;
+use Elastica\Index\Status as IndexStatus;
+
+/**
+ * Elastica index object.
+ *
+ * Handles reads, deletes and configurations of an index
+ *
+ * @author Nicolas Ruflin <spam@ruflin.com>
+ */
+class Index implements SearchableInterface
+{
+ /**
+ * Index name.
+ *
+ * @var string Index name
+ */
+ protected $_name = '';
+
+ /**
+ * Client object.
+ *
+ * @var \Elastica\Client Client object
+ */
+ protected $_client = null;
+
+ /**
+ * Creates a new index object.
+ *
+ * All the communication to and from an index goes of this object
+ *
+ * @param \Elastica\Client $client Client object
+ * @param string $name Index name
+ *
+ * @throws \Elastica\Exception\InvalidException
+ */
+ public function __construct(Client $client, $name)
+ {
+ $this->_client = $client;
+
+ if (!is_scalar($name)) {
+ throw new InvalidException('Index name should be a scalar type');
+ }
+ $this->_name = (string) $name;
+ }
+
+ /**
+ * Returns a type object for the current index with the given name.
+ *
+ * @param string $type Type name
+ *
+ * @return \Elastica\Type Type object
+ */
+ public function getType($type)
+ {
+ return new Type($this, $type);
+ }
+
+ /**
+ * Returns the current status of the index.
+ *
+ * @return \Elastica\Index\Status Index status
+ */
+ public function getStatus()
+ {
+ return new IndexStatus($this);
+ }
+
+ /**
+ * Return Index Stats.
+ *
+ * @return \Elastica\Index\Stats
+ */
+ public function getStats()
+ {
+ return new IndexStats($this);
+ }
+
+ /**
+ * Gets all the type mappings for an index.
+ *
+ * @return array
+ */
+ public function getMapping()
+ {
+ $path = '_mapping';
+
+ $response = $this->request($path, Request::GET);
+ $data = $response->getData();
+
+ // Get first entry as if index is an Alias, the name of the mapping is the real name and not alias name
+ $mapping = array_shift($data);
+
+ if (isset($mapping['mappings'])) {
+ return $mapping['mappings'];
+ }
+
+ return array();
+ }
+
+ /**
+ * Returns the index settings object.
+ *
+ * @return \Elastica\Index\Settings Settings object
+ */
+ public function getSettings()
+ {
+ return new IndexSettings($this);
+ }
+
+ /**
+ * Uses _bulk to send documents to the server.
+ *
+ * @param array|\Elastica\Document[] $docs Array of Elastica\Document
+ *
+ * @return \Elastica\Bulk\ResponseSet
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/docs-bulk.html
+ */
+ public function updateDocuments(array $docs)
+ {
+ foreach ($docs as $doc) {
+ $doc->setIndex($this->getName());
+ }
+
+ return $this->getClient()->updateDocuments($docs);
+ }
+
+ /**
+ * Uses _bulk to send documents to the server.
+ *
+ * @param array|\Elastica\Document[] $docs Array of Elastica\Document
+ *
+ * @return \Elastica\Bulk\ResponseSet
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/docs-bulk.html
+ */
+ public function addDocuments(array $docs)
+ {
+ foreach ($docs as $doc) {
+ $doc->setIndex($this->getName());
+ }
+
+ return $this->getClient()->addDocuments($docs);
+ }
+
+ /**
+ * Deletes entries in the db based on a query.
+ *
+ * @param \Elastica\Query|string $query Query object
+ * @param array $options Optional params
+ *
+ * @return \Elastica\Response
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/docs-delete-by-query.html
+ */
+ public function deleteByQuery($query, array $options = array())
+ {
+ if (is_string($query)) {
+ // query_string queries are not supported for delete by query operations
+ $options['q'] = $query;
+
+ return $this->request('_query', Request::DELETE, array(), $options);
+ }
+ $query = Query::create($query);
+
+ return $this->request('_query', Request::DELETE, array('query' => $query->getQuery()), $options);
+ }
+
+ /**
+ * Deletes the index.
+ *
+ * @return \Elastica\Response Response object
+ */
+ public function delete()
+ {
+ $response = $this->request('', Request::DELETE);
+
+ return $response;
+ }
+
+ /**
+ * Uses _bulk to delete documents from the server.
+ *
+ * @param array|\Elastica\Document[] $docs Array of Elastica\Document
+ *
+ * @return \Elastica\Bulk\ResponseSet
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/docs-bulk.html
+ */
+ public function deleteDocuments(array $docs)
+ {
+ foreach ($docs as $doc) {
+ $doc->setIndex($this->getName());
+ }
+
+ return $this->getClient()->deleteDocuments($docs);
+ }
+
+ /**
+ * Optimizes search index.
+ *
+ * Detailed arguments can be found here in the link
+ *
+ * @param array $args OPTIONAL Additional arguments
+ *
+ * @return array Server response
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/indices-optimize.html
+ */
+ public function optimize($args = array())
+ {
+ return $this->request('_optimize', Request::POST, array(), $args);
+ }
+
+ /**
+ * Refreshes the index.
+ *
+ * @return \Elastica\Response Response object
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/indices-refresh.html
+ */
+ public function refresh()
+ {
+ return $this->request('_refresh', Request::POST, array());
+ }
+
+ /**
+ * Creates a new index with the given arguments.
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/indices-create-index.html
+ *
+ * @param array $args OPTIONAL Arguments to use
+ * @param bool|array $options OPTIONAL
+ * bool=> Deletes index first if already exists (default = false).
+ * array => Associative array of options (option=>value)
+ *
+ * @throws \Elastica\Exception\InvalidException
+ * @throws \Elastica\Exception\ResponseException
+ *
+ * @return array Server response
+ */
+ public function create(array $args = array(), $options = null)
+ {
+ $path = '';
+ $query = array();
+
+ if (is_bool($options)) {
+ if ($options) {
+ try {
+ $this->delete();
+ } catch (ResponseException $e) {
+ // Table can't be deleted, because doesn't exist
+ }
+ }
+ } else {
+ if (is_array($options)) {
+ foreach ($options as $key => $value) {
+ switch ($key) {
+ case 'recreate' :
+ try {
+ $this->delete();
+ } catch (ResponseException $e) {
+ // Table can't be deleted, because doesn't exist
+ }
+ break;
+ case 'routing' :
+ $query = array('routing' => $value);
+ break;
+ default:
+ throw new InvalidException('Invalid option '.$key);
+ break;
+ }
+ }
+ }
+ }
+
+ return $this->request($path, Request::PUT, $args, $query);
+ }
+
+ /**
+ * Checks if the given index is already created.
+ *
+ * @return bool True if index exists
+ */
+ public function exists()
+ {
+ $response = $this->getClient()->request($this->getName(), Request::HEAD);
+ $info = $response->getTransferInfo();
+
+ return (bool) ($info['http_code'] == 200);
+ }
+
+ /**
+ * @param string|array|\Elastica\Query $query
+ * @param int|array $options
+ *
+ * @return \Elastica\Search
+ */
+ public function createSearch($query = '', $options = null)
+ {
+ $search = new Search($this->getClient());
+ $search->addIndex($this);
+ $search->setOptionsAndQuery($options, $query);
+
+ return $search;
+ }
+
+ /**
+ * Searches in this index.
+ *
+ * @param string|array|\Elastica\Query $query Array with all query data inside or a Elastica\Query object
+ * @param int|array $options OPTIONAL Limit or associative array of options (option=>value)
+ *
+ * @return \Elastica\ResultSet ResultSet with all results inside
+ *
+ * @see \Elastica\SearchableInterface::search
+ */
+ public function search($query = '', $options = null)
+ {
+ $search = $this->createSearch($query, $options);
+
+ return $search->search();
+ }
+
+ /**
+ * Counts results of query.
+ *
+ * @param string|array|\Elastica\Query $query Array with all query data inside or a Elastica\Query object
+ *
+ * @return int number of documents matching the query
+ *
+ * @see \Elastica\SearchableInterface::count
+ */
+ public function count($query = '')
+ {
+ $search = $this->createSearch($query);
+
+ return $search->count();
+ }
+
+ /**
+ * Opens an index.
+ *
+ * @return \Elastica\Response Response object
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/indices-open-close.html
+ */
+ public function open()
+ {
+ return $this->request('_open', Request::POST);
+ }
+
+ /**
+ * Closes the index.
+ *
+ * @return \Elastica\Response Response object
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/indices-open-close.html
+ */
+ public function close()
+ {
+ return $this->request('_close', Request::POST);
+ }
+
+ /**
+ * Returns the index name.
+ *
+ * @return string Index name
+ */
+ public function getName()
+ {
+ return $this->_name;
+ }
+
+ /**
+ * Returns index client.
+ *
+ * @return \Elastica\Client Index client object
+ */
+ public function getClient()
+ {
+ return $this->_client;
+ }
+
+ /**
+ * Adds an alias to the current index.
+ *
+ * @param string $name Alias name
+ * @param bool $replace OPTIONAL If set, an existing alias will be replaced
+ *
+ * @return \Elastica\Response Response
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/indices-aliases.html
+ */
+ public function addAlias($name, $replace = false)
+ {
+ $path = '_aliases';
+
+ $data = array('actions' => array());
+
+ if ($replace) {
+ $status = new Status($this->getClient());
+ foreach ($status->getIndicesWithAlias($name) as $index) {
+ $data['actions'][] = array('remove' => array('index' => $index->getName(), 'alias' => $name));
+ }
+ }
+
+ $data['actions'][] = array('add' => array('index' => $this->getName(), 'alias' => $name));
+
+ return $this->getClient()->request($path, Request::POST, $data);
+ }
+
+ /**
+ * Removes an alias pointing to the current index.
+ *
+ * @param string $name Alias name
+ *
+ * @return \Elastica\Response Response
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/indices-aliases.html
+ */
+ public function removeAlias($name)
+ {
+ $path = '_aliases';
+
+ $data = array('actions' => array(array('remove' => array('index' => $this->getName(), 'alias' => $name))));
+
+ return $this->getClient()->request($path, Request::POST, $data);
+ }
+
+ /**
+ * Clears the cache of an index.
+ *
+ * @return \Elastica\Response Response object
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/indices-clearcache.html
+ */
+ public function clearCache()
+ {
+ $path = '_cache/clear';
+ // TODO: add additional cache clean arguments
+ return $this->request($path, Request::POST);
+ }
+
+ /**
+ * Flushes the index to storage.
+ *
+ * @return \Elastica\Response Response object
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/indices-flush.html
+ */
+ public function flush($refresh = false)
+ {
+ $path = '_flush';
+
+ return $this->request($path, Request::POST, array(), array('refresh' => $refresh));
+ }
+
+ /**
+ * Can be used to change settings during runtime. One example is to use it for bulk updating.
+ *
+ * @param array $data Data array
+ *
+ * @return \Elastica\Response Response object
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/indices-update-settings.html
+ */
+ public function setSettings(array $data)
+ {
+ return $this->request('_settings', Request::PUT, $data);
+ }
+
+ /**
+ * Makes calls to the elasticsearch server based on this index.
+ *
+ * @param string $path Path to call
+ * @param string $method Rest method to use (GET, POST, DELETE, PUT)
+ * @param array $data OPTIONAL Arguments as array
+ * @param array $query OPTIONAL Query params
+ *
+ * @return \Elastica\Response Response object
+ */
+ public function request($path, $method, $data = array(), array $query = array())
+ {
+ $path = $this->getName().'/'.$path;
+
+ return $this->getClient()->request($path, $method, $data, $query);
+ }
+
+ /**
+ * Analyzes a string.
+ *
+ * Detailed arguments can be found here in the link
+ *
+ * @param string $text String to be analyzed
+ * @param array $args OPTIONAL Additional arguments
+ *
+ * @return array Server response
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/indices-analyze.html
+ */
+ public function analyze($text, $args = array())
+ {
+ $data = $this->request('_analyze', Request::POST, $text, $args)->getData();
+
+ return $data['tokens'];
+ }
+}
diff --git a/vendor/ruflin/elastica/lib/Elastica/Index/Settings.php b/vendor/ruflin/elastica/lib/Elastica/Index/Settings.php
new file mode 100644
index 00000000..f97e360a
--- /dev/null
+++ b/vendor/ruflin/elastica/lib/Elastica/Index/Settings.php
@@ -0,0 +1,366 @@
+<?php
+namespace Elastica\Index;
+
+use Elastica\Exception\NotFoundException;
+use Elastica\Exception\ResponseException;
+use Elastica\Index as BaseIndex;
+use Elastica\Request;
+
+/**
+ * Elastica index settings object.
+ *
+ * All settings listed in the update settings API (http://www.elastic.co/guide/en/elasticsearch/reference/current/indices-update-settings.html)
+ * can be changed on a running indices. To make changes like the merge policy (http://www.elastic.co/guide/en/elasticsearch/reference/current/index-modules-merge.html)
+ * the index has to be closed first and reopened after the call
+ *
+ * @author Nicolas Ruflin <spam@ruflin.com>
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/indices-update-settings.html
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/index-modules-merge.html
+ */
+class Settings
+{
+ /**
+ * Response.
+ *
+ * @var \Elastica\Response Response object
+ */
+ protected $_response = null;
+
+ /**
+ * Stats info.
+ *
+ * @var array Stats info
+ */
+ protected $_data = array();
+
+ /**
+ * Index.
+ *
+ * @var \Elastica\Index Index object
+ */
+ protected $_index = null;
+
+ const DEFAULT_REFRESH_INTERVAL = '1s';
+
+ /**
+ * Construct.
+ *
+ * @param \Elastica\Index $index Index object
+ */
+ public function __construct(BaseIndex $index)
+ {
+ $this->_index = $index;
+ }
+
+ /**
+ * Returns the current settings of the index.
+ *
+ * If param is set, only specified setting is return.
+ * 'index.' is added in front of $setting.
+ *
+ * @param string $setting OPTIONAL Setting name to return
+ *
+ * @return array|string|null Settings data
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/indices-update-settings.html
+ */
+ public function get($setting = '')
+ {
+ $requestData = $this->request()->getData();
+ $data = reset($requestData);
+
+ if (empty($data['settings']) || empty($data['settings']['index'])) {
+ // should not append, the request should throw a ResponseException
+ throw new NotFoundException('Index '.$this->getIndex()->getName().' not found');
+ }
+ $settings = $data['settings']['index'];
+
+ if (!$setting) {
+ // return all array
+ return $settings;
+ }
+
+ if (isset($settings[$setting])) {
+ return $settings[$setting];
+ } else {
+ if (strpos($setting, '.') !== false) {
+ // translate old dot-notation settings to nested arrays
+ $keys = explode('.', $setting);
+ foreach ($keys as $key) {
+ if (isset($settings[$key])) {
+ $settings = $settings[$key];
+ } else {
+ return;
+ }
+ }
+
+ return $settings;
+ }
+
+ return;
+ }
+ }
+
+ /**
+ * Sets the number of replicas.
+ *
+ * @param int $replicas Number of replicas
+ *
+ * @return \Elastica\Response Response object
+ */
+ public function setNumberOfReplicas($replicas)
+ {
+ $replicas = (int) $replicas;
+
+ $data = array('number_of_replicas' => $replicas);
+
+ return $this->set($data);
+ }
+
+ /**
+ * Sets the index to read only.
+ *
+ * @param bool $readOnly (default = true)
+ *
+ * @return \Elastica\Response
+ */
+ public function setReadOnly($readOnly = true)
+ {
+ return $this->set(array('blocks.write' => $readOnly));
+ }
+
+ /**
+ * getReadOnly.
+ *
+ * @return bool
+ */
+ public function getReadOnly()
+ {
+ return $this->get('blocks.write') === 'true'; // ES returns a string for this setting
+ }
+
+ /**
+ * @return bool
+ */
+ public function getBlocksRead()
+ {
+ return (bool) $this->get('blocks.read');
+ }
+
+ /**
+ * @param bool $state OPTIONAL (default = true)
+ *
+ * @return \Elastica\Response
+ */
+ public function setBlocksRead($state = true)
+ {
+ $state = $state ? 1 : 0;
+
+ return $this->set(array('blocks.read' => $state));
+ }
+
+ /**
+ * @return bool
+ */
+ public function getBlocksWrite()
+ {
+ return (bool) $this->get('blocks.write');
+ }
+
+ /**
+ * @param bool $state OPTIONAL (default = true)
+ *
+ * @return \Elastica\Response
+ */
+ public function setBlocksWrite($state = true)
+ {
+ $state = $state ? 1 : 0;
+
+ return $this->set(array('blocks.write' => $state));
+ }
+
+ /**
+ * @return bool
+ */
+ public function getBlocksMetadata()
+ {
+ // TODO will have to be replace by block.metadata.write once https://github.com/elasticsearch/elasticsearch/pull/9203 has been fixed
+ // the try/catch will have to be remove too
+ try {
+ return (bool) $this->get('blocks.metadata');
+ } catch (ResponseException $e) {
+ if (strpos($e->getMessage(), 'ClusterBlockException') !== false) {
+ // hacky way to test if the metadata is blocked since bug 9203 is not fixed
+ return true;
+ } else {
+ throw $e;
+ }
+ }
+ }
+
+ /**
+ * @param bool $state OPTIONAL (default = true)
+ *
+ * @return \Elastica\Response
+ */
+ public function setBlocksMetadata($state = true)
+ {
+ // TODO will have to be replace by block.metadata.write once https://github.com/elasticsearch/elasticsearch/pull/9203 has been fixed
+ $state = $state ? 1 : 0;
+
+ return $this->set(array('blocks.metadata' => $state));
+ }
+
+ /**
+ * Sets the index refresh interval.
+ *
+ * Value can be for example 3s for 3 seconds or
+ * 5m for 5 minutes. -1 refreshing is disabled.
+ *
+ * @param int $interval Number of milliseconds
+ *
+ * @return \Elastica\Response Response object
+ */
+ public function setRefreshInterval($interval)
+ {
+ return $this->set(array('refresh_interval' => $interval));
+ }
+
+ /**
+ * Returns the refresh interval.
+ *
+ * If no interval is set, the default interval is returned
+ *
+ * @return string Refresh interval
+ */
+ public function getRefreshInterval()
+ {
+ $interval = $this->get('refresh_interval');
+
+ if (empty($interval)) {
+ $interval = self::DEFAULT_REFRESH_INTERVAL;
+ }
+
+ return $interval;
+ }
+
+ /**
+ * Return merge policy.
+ *
+ * @return string Merge policy type
+ */
+ public function getMergePolicyType()
+ {
+ return $this->get('merge.policy.type');
+ }
+
+ /**
+ * Sets merge policy.
+ *
+ * @param string $type Merge policy type
+ *
+ * @return \Elastica\Response Response object
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/index-modules-merge.html
+ */
+ public function setMergePolicyType($type)
+ {
+ $this->getIndex()->close();
+ $response = $this->set(array('merge.policy.type' => $type));
+ $this->getIndex()->open();
+
+ return $response;
+ }
+
+ /**
+ * Sets the specific merge policies.
+ *
+ * To have this changes made the index has to be closed and reopened
+ *
+ * @param string $key Merge policy key (for ex. expunge_deletes_allowed)
+ * @param string $value
+ *
+ * @return \Elastica\Response
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/index-modules-merge.html
+ */
+ public function setMergePolicy($key, $value)
+ {
+ $this->getIndex()->close();
+ $response = $this->set(array('merge.policy.'.$key => $value));
+ $this->getIndex()->open();
+
+ return $response;
+ }
+
+ /**
+ * Returns the specific merge policy value.
+ *
+ * @param string $key Merge policy key (for ex. expunge_deletes_allowed)
+ *
+ * @return string Refresh interval
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/index-modules-merge.html
+ */
+ public function getMergePolicy($key)
+ {
+ $settings = $this->get();
+ if (isset($settings['merge']['policy'][$key])) {
+ return $settings['merge']['policy'][$key];
+ }
+
+ return;
+ }
+
+ /**
+ * Can be used to set/update settings.
+ *
+ * @param array $data Arguments
+ *
+ * @return \Elastica\Response Response object
+ */
+ public function set(array $data)
+ {
+ return $this->request($data, Request::PUT);
+ }
+
+ /**
+ * Returns the index object.
+ *
+ * @return \Elastica\Index Index object
+ */
+ public function getIndex()
+ {
+ return $this->_index;
+ }
+
+ /**
+ * Updates the given settings for the index.
+ *
+ * With elasticsearch 0.16 the following settings are supported
+ * - index.term_index_interval
+ * - index.term_index_divisor
+ * - index.translog.flush_threshold_ops
+ * - index.translog.flush_threshold_size
+ * - index.translog.flush_threshold_period
+ * - index.refresh_interval
+ * - index.merge.policy
+ * - index.auto_expand_replicas
+ *
+ * @param array $data OPTIONAL Data array
+ * @param string $method OPTIONAL Transfer method (default = \Elastica\Request::GET)
+ *
+ * @return \Elastica\Response Response object
+ */
+ public function request(array $data = array(), $method = Request::GET)
+ {
+ $path = '_settings';
+
+ if (!empty($data)) {
+ $data = array('index' => $data);
+ }
+
+ return $this->getIndex()->request($path, $method, $data);
+ }
+}
diff --git a/vendor/ruflin/elastica/lib/Elastica/Index/Stats.php b/vendor/ruflin/elastica/lib/Elastica/Index/Stats.php
new file mode 100644
index 00000000..d86903dc
--- /dev/null
+++ b/vendor/ruflin/elastica/lib/Elastica/Index/Stats.php
@@ -0,0 +1,108 @@
+<?php
+namespace Elastica\Index;
+
+use Elastica\Index as BaseIndex;
+use Elastica\Request;
+
+/**
+ * Elastica index stats object.
+ *
+ * @author Nicolas Ruflin <spam@ruflin.com>
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/indices-stats.html
+ */
+class Stats
+{
+ /**
+ * Response.
+ *
+ * @var \Elastica\Response Response object
+ */
+ protected $_response = null;
+
+ /**
+ * Stats info.
+ *
+ * @var array Stats info
+ */
+ protected $_data = array();
+
+ /**
+ * Index.
+ *
+ * @var \Elastica\Index Index object
+ */
+ protected $_index = null;
+
+ /**
+ * Construct.
+ *
+ * @param \Elastica\Index $index Index object
+ */
+ public function __construct(BaseIndex $index)
+ {
+ $this->_index = $index;
+ $this->refresh();
+ }
+
+ /**
+ * Returns the raw stats info.
+ *
+ * @return array Stats info
+ */
+ public function getData()
+ {
+ return $this->_data;
+ }
+
+ /**
+ * Returns the entry in the data array based on the params.
+ * Various params possible.
+ *
+ * @return mixed Data array entry or null if not found
+ */
+ public function get()
+ {
+ $data = $this->getData();
+
+ foreach (func_get_args() as $arg) {
+ if (isset($data[$arg])) {
+ $data = $data[$arg];
+ } else {
+ return;
+ }
+ }
+
+ return $data;
+ }
+
+ /**
+ * Returns the index object.
+ *
+ * @return \Elastica\Index Index object
+ */
+ public function getIndex()
+ {
+ return $this->_index;
+ }
+
+ /**
+ * Returns response object.
+ *
+ * @return \Elastica\Response Response object
+ */
+ public function getResponse()
+ {
+ return $this->_response;
+ }
+
+ /**
+ * Reloads all status data of this object.
+ */
+ public function refresh()
+ {
+ $path = '_stats';
+ $this->_response = $this->getIndex()->request($path, Request::GET);
+ $this->_data = $this->getResponse()->getData();
+ }
+}
diff --git a/vendor/ruflin/elastica/lib/Elastica/Index/Status.php b/vendor/ruflin/elastica/lib/Elastica/Index/Status.php
new file mode 100644
index 00000000..0b9dff48
--- /dev/null
+++ b/vendor/ruflin/elastica/lib/Elastica/Index/Status.php
@@ -0,0 +1,150 @@
+<?php
+namespace Elastica\Index;
+
+use Elastica\Index as BaseIndex;
+use Elastica\Request;
+
+/**
+ * Elastica index status object.
+ *
+ * @author Nicolas Ruflin <spam@ruflin.com>
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/indices-status.html
+ */
+class Status
+{
+ /**
+ * Response.
+ *
+ * @var \Elastica\Response Response object
+ */
+ protected $_response = null;
+
+ /**
+ * Stats info.
+ *
+ * @var array Stats info
+ */
+ protected $_data = array();
+
+ /**
+ * Index.
+ *
+ * @var \Elastica\Index Index object
+ */
+ protected $_index = null;
+
+ /**
+ * Construct.
+ *
+ * @param \Elastica\Index $index Index object
+ */
+ public function __construct(BaseIndex $index)
+ {
+ $this->_index = $index;
+ $this->refresh();
+ }
+
+ /**
+ * Returns all status info.
+ *
+ * @return array Status info
+ */
+ public function getData()
+ {
+ return $this->_data;
+ }
+
+ /**
+ * Returns the entry in the data array based on the params.
+ * Various params possible.
+ *
+ * @return mixed Data array entry or null if not found
+ */
+ public function get()
+ {
+ $data = $this->getData();
+ $data = $data['indices'][$this->getIndex()->getName()];
+
+ foreach (func_get_args() as $arg) {
+ if (isset($data[$arg])) {
+ $data = $data[$arg];
+ } else {
+ return;
+ }
+ }
+
+ return $data;
+ }
+
+ /**
+ * Returns all index aliases.
+ *
+ * @return array Aliases
+ */
+ public function getAliases()
+ {
+ $responseData = $this->getIndex()->request('_aliases', \Elastica\Request::GET)->getData();
+
+ $data = $responseData[$this->getIndex()->getName()];
+ if (!empty($data['aliases'])) {
+ return array_keys($data['aliases']);
+ }
+
+ return array();
+ }
+
+ /**
+ * Returns all index settings.
+ *
+ * @return array Index settings
+ */
+ public function getSettings()
+ {
+ $responseData = $this->getIndex()->request('_settings', \Elastica\Request::GET)->getData();
+
+ return $responseData[$this->getIndex()->getName()]['settings'];
+ }
+
+ /**
+ * Checks if the index has the given alias.
+ *
+ * @param string $name Alias name
+ *
+ * @return bool
+ */
+ public function hasAlias($name)
+ {
+ return in_array($name, $this->getAliases());
+ }
+
+ /**
+ * Returns the index object.
+ *
+ * @return \Elastica\Index Index object
+ */
+ public function getIndex()
+ {
+ return $this->_index;
+ }
+
+ /**
+ * Returns response object.
+ *
+ * @return \Elastica\Response Response object
+ */
+ public function getResponse()
+ {
+ return $this->_response;
+ }
+
+ /**
+ * Reloads all status data of this object.
+ */
+ public function refresh()
+ {
+ $path = '_status';
+ $this->_response = $this->getIndex()->request($path, Request::GET);
+ $this->_data = $this->getResponse()->getData();
+ }
+}
diff --git a/vendor/ruflin/elastica/lib/Elastica/JSON.php b/vendor/ruflin/elastica/lib/Elastica/JSON.php
new file mode 100644
index 00000000..921bc484
--- /dev/null
+++ b/vendor/ruflin/elastica/lib/Elastica/JSON.php
@@ -0,0 +1,67 @@
+<?php
+namespace Elastica;
+
+use Elastica\Exception\JSONParseException;
+
+/**
+ * Elastica JSON tools.
+ */
+class JSON
+{
+ /**
+ * Parse JSON string to an array.
+ *
+ * @link http://php.net/manual/en/function.json-decode.php
+ * @link http://php.net/manual/en/function.json-last-error.php
+ *
+ * @param string $json JSON string to parse
+ *
+ * @return array PHP array representation of JSON string
+ */
+ public static function parse(/* inherit from json_decode */)
+ {
+ // extract arguments
+ $args = func_get_args();
+
+ // default to decoding into an assoc array
+ if (sizeof($args) === 1) {
+ $args[] = true;
+ }
+
+ // run decode
+ $array = call_user_func_array('json_decode', $args);
+
+ // turn errors into exceptions for easier catching
+ $error = json_last_error();
+ if ($error !== JSON_ERROR_NONE) {
+ throw new JSONParseException($error);
+ }
+
+ // output
+ return $array;
+ }
+
+ /**
+ * Convert input to JSON string with standard options.
+ *
+ * @link http://php.net/manual/en/function.json-encode.php
+ *
+ * @param mixed check args for PHP function json_encode
+ *
+ * @return string Valid JSON representation of $input
+ */
+ public static function stringify(/* inherit from json_encode */)
+ {
+ // extract arguments
+ $args = func_get_args();
+
+ // allow special options value for Elasticsearch compatibility
+ if (sizeof($args) > 1 && $args[1] === 'JSON_ELASTICSEARCH') {
+ // Use built in JSON constants if available (php >= 5.4)
+ $args[1] = defined('JSON_UNESCAPED_UNICODE') ? JSON_UNESCAPED_UNICODE : 256;
+ }
+
+ // run encode and output
+ return call_user_func_array('json_encode', $args);
+ }
+}
diff --git a/vendor/ruflin/elastica/lib/Elastica/Log.php b/vendor/ruflin/elastica/lib/Elastica/Log.php
new file mode 100644
index 00000000..c2f0c18a
--- /dev/null
+++ b/vendor/ruflin/elastica/lib/Elastica/Log.php
@@ -0,0 +1,81 @@
+<?php
+namespace Elastica;
+
+use Psr\Log\AbstractLogger;
+
+/**
+ * Elastica log object.
+ *
+ * @author Nicolas Ruflin <spam@ruflin.com>
+ */
+class Log extends AbstractLogger
+{
+ /**
+ * Log path or true if enabled.
+ *
+ * @var string|bool
+ */
+ protected $_log = true;
+
+ /**
+ * Last logged message.
+ *
+ * @var string Last logged message
+ */
+ protected $_lastMessage = '';
+
+ /**
+ * Inits log object.
+ *
+ * @param string|bool String to set a specific file for logging
+ */
+ public function __construct($log = '')
+ {
+ $this->setLog($log);
+ }
+
+ /**
+ * Log a message.
+ *
+ * @param mixed $level
+ * @param string $message
+ * @param array $context
+ *
+ * @return null|void
+ */
+ public function log($level, $message, array $context = array())
+ {
+ $context['error_message'] = $message;
+ $this->_lastMessage = JSON::stringify($context);
+
+ if (!empty($this->_log) && is_string($this->_log)) {
+ error_log($this->_lastMessage.PHP_EOL, 3, $this->_log);
+ } else {
+ error_log($this->_lastMessage);
+ }
+ }
+
+ /**
+ * Enable/disable log or set log path.
+ *
+ * @param bool|string $log Enables log or sets log path
+ *
+ * @return $this
+ */
+ public function setLog($log)
+ {
+ $this->_log = $log;
+
+ return $this;
+ }
+
+ /**
+ * Return last logged message.
+ *
+ * @return string Last logged message
+ */
+ public function getLastMessage()
+ {
+ return $this->_lastMessage;
+ }
+}
diff --git a/vendor/ruflin/elastica/lib/Elastica/Multi/ResultSet.php b/vendor/ruflin/elastica/lib/Elastica/Multi/ResultSet.php
new file mode 100644
index 00000000..4d4186af
--- /dev/null
+++ b/vendor/ruflin/elastica/lib/Elastica/Multi/ResultSet.php
@@ -0,0 +1,205 @@
+<?php
+namespace Elastica\Multi;
+
+use Elastica\Exception\InvalidException;
+use Elastica\Response;
+use Elastica\ResultSet as BaseResultSet;
+use Elastica\Search as BaseSearch;
+
+/**
+ * Elastica multi search result set
+ * List of result sets for each search request.
+ *
+ * @author munkie
+ */
+class ResultSet implements \Iterator, \ArrayAccess, \Countable
+{
+ /**
+ * Result Sets.
+ *
+ * @var array|\Elastica\ResultSet[] Result Sets
+ */
+ protected $_resultSets = array();
+
+ /**
+ * Current position.
+ *
+ * @var int Current position
+ */
+ protected $_position = 0;
+
+ /**
+ * Response.
+ *
+ * @var \Elastica\Response Response object
+ */
+ protected $_response;
+
+ /**
+ * Constructs ResultSet object.
+ *
+ * @param \Elastica\Response $response
+ * @param array|\Elastica\Search[] $searches
+ */
+ public function __construct(Response $response, array $searches)
+ {
+ $this->rewind();
+ $this->_init($response, $searches);
+ }
+
+ /**
+ * @param \Elastica\Response $response
+ * @param array|\Elastica\Search[] $searches
+ *
+ * @throws \Elastica\Exception\InvalidException
+ */
+ protected function _init(Response $response, array $searches)
+ {
+ $this->_response = $response;
+ $responseData = $response->getData();
+
+ if (isset($responseData['responses']) && is_array($responseData['responses'])) {
+ reset($searches);
+ foreach ($responseData['responses'] as $key => $responseData) {
+ $currentSearch = each($searches);
+
+ if ($currentSearch === false) {
+ throw new InvalidException('No result found for search #'.$key);
+ } elseif (!$currentSearch['value'] instanceof BaseSearch) {
+ throw new InvalidException('Invalid object for search #'.$key.' provided. Should be Elastica\Search');
+ }
+
+ $search = $currentSearch['value'];
+ $query = $search->getQuery();
+
+ $response = new Response($responseData);
+ $this->_resultSets[$currentSearch['key']] = new BaseResultSet($response, $query);
+ }
+ }
+ }
+
+ /**
+ * @return array|\Elastica\ResultSet[]
+ */
+ public function getResultSets()
+ {
+ return $this->_resultSets;
+ }
+
+ /**
+ * Returns response object.
+ *
+ * @return \Elastica\Response Response object
+ */
+ public function getResponse()
+ {
+ return $this->_response;
+ }
+
+ /**
+ * There is at least one result set with error.
+ *
+ * @return bool
+ */
+ public function hasError()
+ {
+ foreach ($this->getResultSets() as $resultSet) {
+ if ($resultSet->getResponse()->hasError()) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * @return bool|\Elastica\ResultSet
+ */
+ public function current()
+ {
+ if ($this->valid()) {
+ return $this->_resultSets[$this->key()];
+ } else {
+ return false;
+ }
+ }
+
+ /**
+ */
+ public function next()
+ {
+ $this->_position++;
+ }
+
+ /**
+ * @return int
+ */
+ public function key()
+ {
+ return $this->_position;
+ }
+
+ /**
+ * @return bool
+ */
+ public function valid()
+ {
+ return isset($this->_resultSets[$this->key()]);
+ }
+
+ /**
+ */
+ public function rewind()
+ {
+ $this->_position = 0;
+ }
+
+ /**
+ * @return int
+ */
+ public function count()
+ {
+ return count($this->_resultSets);
+ }
+
+ /**
+ * @param string|int $offset
+ *
+ * @return bool true on success or false on failure.
+ */
+ public function offsetExists($offset)
+ {
+ return isset($this->_resultSets[$offset]);
+ }
+
+ /**
+ * @param mixed $offset
+ *
+ * @return mixed Can return all value types.
+ */
+ public function offsetGet($offset)
+ {
+ return isset($this->_resultSets[$offset]) ? $this->_resultSets[$offset] : null;
+ }
+
+ /**
+ * @param mixed $offset
+ * @param mixed $value
+ */
+ public function offsetSet($offset, $value)
+ {
+ if (is_null($offset)) {
+ $this->_resultSets[] = $value;
+ } else {
+ $this->_resultSets[$offset] = $value;
+ }
+ }
+
+ /**
+ * @param mixed $offset
+ */
+ public function offsetUnset($offset)
+ {
+ unset($this->_resultSets[$offset]);
+ }
+}
diff --git a/vendor/ruflin/elastica/lib/Elastica/Multi/Search.php b/vendor/ruflin/elastica/lib/Elastica/Multi/Search.php
new file mode 100644
index 00000000..294fc0a7
--- /dev/null
+++ b/vendor/ruflin/elastica/lib/Elastica/Multi/Search.php
@@ -0,0 +1,203 @@
+<?php
+namespace Elastica\Multi;
+
+use Elastica\Client;
+use Elastica\JSON;
+use Elastica\Request;
+use Elastica\Search as BaseSearch;
+
+/**
+ * Elastica multi search.
+ *
+ * @author munkie
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/search-multi-search.html
+ */
+class Search
+{
+ /**
+ * @var array|\Elastica\Search[]
+ */
+ protected $_searches = array();
+
+ /**
+ * @var array
+ */
+ protected $_options = array();
+
+ /**
+ * @var \Elastica\Client
+ */
+ protected $_client;
+
+ /**
+ * Constructs search object.
+ *
+ * @param \Elastica\Client $client Client object
+ */
+ public function __construct(Client $client)
+ {
+ $this->setClient($client);
+ }
+
+ /**
+ * @return \Elastica\Client
+ */
+ public function getClient()
+ {
+ return $this->_client;
+ }
+
+ /**
+ * @param \Elastica\Client $client
+ *
+ * @return $this
+ */
+ public function setClient(Client $client)
+ {
+ $this->_client = $client;
+
+ return $this;
+ }
+
+ /**
+ * @return $this
+ */
+ public function clearSearches()
+ {
+ $this->_searches = array();
+
+ return $this;
+ }
+
+ /**
+ * @param \Elastica\Search $search
+ * @param string $key Optional key
+ *
+ * @return $this
+ */
+ public function addSearch(BaseSearch $search, $key = null)
+ {
+ if ($key) {
+ $this->_searches[$key] = $search;
+ } else {
+ $this->_searches[] = $search;
+ }
+
+ return $this;
+ }
+
+ /**
+ * @param array|\Elastica\Search[] $searches
+ *
+ * @return $this
+ */
+ public function addSearches(array $searches)
+ {
+ foreach ($searches as $key => $search) {
+ $this->addSearch($search, $key);
+ }
+
+ return $this;
+ }
+
+ /**
+ * @param array|\Elastica\Search[] $searches
+ *
+ * @return $this
+ */
+ public function setSearches(array $searches)
+ {
+ $this->clearSearches();
+ $this->addSearches($searches);
+
+ return $this;
+ }
+
+ /**
+ * @return array|\Elastica\Search[]
+ */
+ public function getSearches()
+ {
+ return $this->_searches;
+ }
+
+ /**
+ * @param string $searchType
+ *
+ * @return $this
+ */
+ public function setSearchType($searchType)
+ {
+ $this->_options[BaseSearch::OPTION_SEARCH_TYPE] = $searchType;
+
+ return $this;
+ }
+
+ /**
+ * @return \Elastica\Multi\ResultSet
+ */
+ public function search()
+ {
+ $data = $this->_getData();
+
+ $response = $this->getClient()->request(
+ '_msearch',
+ Request::POST,
+ $data,
+ $this->_options
+ );
+
+ return new ResultSet($response, $this->getSearches());
+ }
+
+ /**
+ * @return string
+ */
+ protected function _getData()
+ {
+ $data = '';
+ foreach ($this->getSearches() as $search) {
+ $data .= $this->_getSearchData($search);
+ }
+
+ return $data;
+ }
+
+ /**
+ * @param \Elastica\Search $search
+ *
+ * @return string
+ */
+ protected function _getSearchData(BaseSearch $search)
+ {
+ $header = $this->_getSearchDataHeader($search);
+ $header = (empty($header)) ? new \stdClass() : $header;
+ $query = $search->getQuery();
+
+ $data = JSON::stringify($header)."\n";
+ $data .= JSON::stringify($query->toArray())."\n";
+
+ return $data;
+ }
+
+ /**
+ * @param \Elastica\Search $search
+ *
+ * @return array
+ */
+ protected function _getSearchDataHeader(BaseSearch $search)
+ {
+ $header = $search->getOptions();
+
+ if ($search->hasIndices()) {
+ $header['index'] = $search->getIndices();
+ }
+
+ if ($search->hasTypes()) {
+ $header['types'] = $search->getTypes();
+ }
+
+ return $header;
+ }
+}
diff --git a/vendor/ruflin/elastica/lib/Elastica/Node.php b/vendor/ruflin/elastica/lib/Elastica/Node.php
new file mode 100644
index 00000000..1453418d
--- /dev/null
+++ b/vendor/ruflin/elastica/lib/Elastica/Node.php
@@ -0,0 +1,161 @@
+<?php
+namespace Elastica;
+
+use Elastica\Node\Info;
+use Elastica\Node\Stats;
+
+/**
+ * Elastica cluster node object.
+ *
+ * @author Nicolas Ruflin <spam@ruflin.com>
+ */
+class Node
+{
+ /**
+ * Client.
+ *
+ * @var \Elastica\Client
+ */
+ protected $_client = null;
+
+ /**
+ * @var string Unique node id
+ */
+ protected $_id = '';
+
+ /**
+ * Node name.
+ *
+ * @var string Node name
+ */
+ protected $_name = '';
+
+ /**
+ * Node stats.
+ *
+ * @var \Elastica\Node\Stats Node Stats
+ */
+ protected $_stats = null;
+
+ /**
+ * Node info.
+ *
+ * @var \Elastica\Node\Info Node info
+ */
+ protected $_info = null;
+
+ /**
+ * Create a new node object.
+ *
+ * @param string $id Node id or name
+ * @param \Elastica\Client $client Node object
+ */
+ public function __construct($id, Client $client)
+ {
+ $this->_client = $client;
+ $this->setId($id);
+ }
+
+ /**
+ * @return string Unique node id. Can also be name if id not exists.
+ */
+ public function getId()
+ {
+ return $this->_id;
+ }
+
+ /**
+ * @param string $id Node id
+ *
+ * @return $this Refreshed object
+ */
+ public function setId($id)
+ {
+ $this->_id = $id;
+
+ return $this->refresh();
+ }
+
+ /**
+ * Get the name of the node.
+ *
+ * @return string Node name
+ */
+ public function getName()
+ {
+ if (empty($this->_name)) {
+ $this->_name = $this->getInfo()->getName();
+ }
+
+ return $this->_name;
+ }
+
+ /**
+ * Returns the current client object.
+ *
+ * @return \Elastica\Client Client
+ */
+ public function getClient()
+ {
+ return $this->_client;
+ }
+
+ /**
+ * Return stats object of the current node.
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/cluster-nodes-stats.html
+ *
+ * @return \Elastica\Node\Stats Node stats
+ */
+ public function getStats()
+ {
+ if (!$this->_stats) {
+ $this->_stats = new Stats($this);
+ }
+
+ return $this->_stats;
+ }
+
+ /**
+ * Return info object of the current node.
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/cluster-nodes-info.html
+ *
+ * @return \Elastica\Node\Info Node info object
+ */
+ public function getInfo()
+ {
+ if (!$this->_info) {
+ $this->_info = new Info($this);
+ }
+
+ return $this->_info;
+ }
+
+ /**
+ * Refreshes all node information.
+ *
+ * This should be called after updating a node to refresh all information
+ */
+ public function refresh()
+ {
+ $this->_stats = null;
+ $this->_info = null;
+ }
+
+ /**
+ * Shuts this node down.
+ *
+ * @param string $delay OPTIONAL Delay after which node is shut down (default = 1s)
+ *
+ * @return \Elastica\Response
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/cluster-nodes-shutdown.html
+ */
+ public function shutdown($delay = '1s')
+ {
+ $path = '_cluster/nodes/'.$this->getId().'/_shutdown?delay='.$delay;
+
+ return $this->_client->request($path, Request::POST);
+ }
+}
diff --git a/vendor/ruflin/elastica/lib/Elastica/Node/Info.php b/vendor/ruflin/elastica/lib/Elastica/Node/Info.php
new file mode 100644
index 00000000..25734641
--- /dev/null
+++ b/vendor/ruflin/elastica/lib/Elastica/Node/Info.php
@@ -0,0 +1,220 @@
+<?php
+namespace Elastica\Node;
+
+use Elastica\Node as BaseNode;
+use Elastica\Request;
+
+/**
+ * Elastica cluster node object.
+ *
+ * @author Nicolas Ruflin <spam@ruflin.com>
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/indices-status.html
+ */
+class Info
+{
+ /**
+ * Response.
+ *
+ * @var \Elastica\Response Response object
+ */
+ protected $_response = null;
+
+ /**
+ * Stats data.
+ *
+ * @var array stats data
+ */
+ protected $_data = array();
+
+ /**
+ * Node.
+ *
+ * @var \Elastica\Node Node object
+ */
+ protected $_node = null;
+
+ /**
+ * Query parameters.
+ *
+ * @var array
+ */
+ protected $_params = array();
+
+ /**
+ * Create new info object for node.
+ *
+ * @param \Elastica\Node $node Node object
+ * @param array $params List of params to return. Can be: settings, os, process, jvm, thread_pool, network, transport, http
+ */
+ public function __construct(BaseNode $node, array $params = array())
+ {
+ $this->_node = $node;
+ $this->refresh($params);
+ }
+
+ /**
+ * Returns the entry in the data array based on the params.
+ * Several params possible.
+ *
+ * Example 1: get('os', 'mem', 'total') returns total memory of the system the
+ * node is running on
+ * Example 2: get('os', 'mem') returns an array with all mem infos
+ *
+ * @return mixed Data array entry or null if not found
+ */
+ public function get()
+ {
+ $data = $this->getData();
+
+ foreach (func_get_args() as $arg) {
+ if (isset($data[$arg])) {
+ $data = $data[$arg];
+ } else {
+ return;
+ }
+ }
+
+ return $data;
+ }
+
+ /**
+ * Return port of the node.
+ *
+ * @return string Returns Node port
+ */
+ public function getPort()
+ {
+ // Returns string in format: inet[/192.168.1.115:9201]
+ $data = $this->get('http_address');
+ $data = substr($data, 6, strlen($data) - 7);
+ $data = explode(':', $data);
+
+ return $data[1];
+ }
+
+ /**
+ * Return IP of the node.
+ *
+ * @return string Returns Node ip address
+ */
+ public function getIp()
+ {
+ // Returns string in format: inet[/192.168.1.115:9201]
+ $data = $this->get('http_address');
+ $data = substr($data, 6, strlen($data) - 7);
+ $data = explode(':', $data);
+
+ return $data[0];
+ }
+
+ /**
+ * Return data regarding plugins installed on this node.
+ *
+ * @return array plugin data
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/cluster-nodes-info.html
+ */
+ public function getPlugins()
+ {
+ if (!in_array('plugins', $this->_params)) {
+ //Plugin data was not retrieved when refresh() was called last. Get it now.
+ $this->_params[] = 'plugins';
+ $this->refresh($this->_params);
+ }
+
+ return $this->get('plugins');
+ }
+
+ /**
+ * Check if the given plugin is installed on this node.
+ *
+ * @param string $name plugin name
+ *
+ * @return bool true if the plugin is installed, false otherwise
+ */
+ public function hasPlugin($name)
+ {
+ foreach ($this->getPlugins() as $plugin) {
+ if ($plugin['name'] == $name) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Return all info data.
+ *
+ * @return array Data array
+ */
+ public function getData()
+ {
+ return $this->_data;
+ }
+
+ /**
+ * Return node object.
+ *
+ * @return \Elastica\Node Node object
+ */
+ public function getNode()
+ {
+ return $this->_node;
+ }
+
+ /**
+ * @return string Unique node id
+ */
+ public function getId()
+ {
+ return $this->_id;
+ }
+
+ /**
+ * @return string Node name
+ */
+ public function getName()
+ {
+ return $this->_data['name'];
+ }
+
+ /**
+ * Returns response object.
+ *
+ * @return \Elastica\Response Response object
+ */
+ public function getResponse()
+ {
+ return $this->_response;
+ }
+
+ /**
+ * Reloads all nodes information. Has to be called if informations changed.
+ *
+ * @param array $params Params to return (default none). Possible options: settings, os, process, jvm, thread_pool, network, transport, http, plugin
+ *
+ * @return \Elastica\Response Response object
+ */
+ public function refresh(array $params = array())
+ {
+ $this->_params = $params;
+
+ $path = '_nodes/'.$this->getNode()->getId();
+
+ if (!empty($params)) {
+ $path .= '?';
+ foreach ($params as $param) {
+ $path .= $param.'=true&';
+ }
+ }
+
+ $this->_response = $this->getNode()->getClient()->request($path, Request::GET);
+ $data = $this->getResponse()->getData();
+
+ $this->_data = reset($data['nodes']);
+ $this->_id = key($data['nodes']);
+ $this->getNode()->setId($this->getId());
+ }
+}
diff --git a/vendor/ruflin/elastica/lib/Elastica/Node/Stats.php b/vendor/ruflin/elastica/lib/Elastica/Node/Stats.php
new file mode 100644
index 00000000..1af94b07
--- /dev/null
+++ b/vendor/ruflin/elastica/lib/Elastica/Node/Stats.php
@@ -0,0 +1,113 @@
+<?php
+namespace Elastica\Node;
+
+use Elastica\Node as BaseNode;
+use Elastica\Request;
+
+/**
+ * Elastica cluster node object.
+ *
+ * @author Nicolas Ruflin <spam@ruflin.com>
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/indices-status.html
+ */
+class Stats
+{
+ /**
+ * Response.
+ *
+ * @var \Elastica\Response Response object
+ */
+ protected $_response = null;
+
+ /**
+ * Stats data.
+ *
+ * @var array stats data
+ */
+ protected $_data = array();
+
+ /**
+ * Node.
+ *
+ * @var \Elastica\Node Node object
+ */
+ protected $_node = null;
+
+ /**
+ * Create new stats for node.
+ *
+ * @param \Elastica\Node $node Elastica node object
+ */
+ public function __construct(BaseNode $node)
+ {
+ $this->_node = $node;
+ $this->refresh();
+ }
+
+ /**
+ * Returns all node stats as array based on the arguments.
+ *
+ * Several arguments can be use
+ * get('index', 'test', 'example')
+ *
+ * @return array Node stats for the given field or null if not found
+ */
+ public function get()
+ {
+ $data = $this->getData();
+
+ foreach (func_get_args() as $arg) {
+ if (isset($data[$arg])) {
+ $data = $data[$arg];
+ } else {
+ return;
+ }
+ }
+
+ return $data;
+ }
+
+ /**
+ * Returns all stats data.
+ *
+ * @return array Data array
+ */
+ public function getData()
+ {
+ return $this->_data;
+ }
+
+ /**
+ * Returns node object.
+ *
+ * @return \Elastica\Node Node object
+ */
+ public function getNode()
+ {
+ return $this->_node;
+ }
+
+ /**
+ * Returns response object.
+ *
+ * @return \Elastica\Response Response object
+ */
+ public function getResponse()
+ {
+ return $this->_response;
+ }
+
+ /**
+ * Reloads all nodes information. Has to be called if informations changed.
+ *
+ * @return \Elastica\Response Response object
+ */
+ public function refresh()
+ {
+ $path = '_nodes/'.$this->getNode()->getName().'/stats';
+ $this->_response = $this->getNode()->getClient()->request($path, Request::GET);
+ $data = $this->getResponse()->getData();
+ $this->_data = reset($data['nodes']);
+ }
+}
diff --git a/vendor/ruflin/elastica/lib/Elastica/Param.php b/vendor/ruflin/elastica/lib/Elastica/Param.php
new file mode 100644
index 00000000..484fbbc3
--- /dev/null
+++ b/vendor/ruflin/elastica/lib/Elastica/Param.php
@@ -0,0 +1,167 @@
+<?php
+namespace Elastica;
+
+use Elastica\Exception\InvalidException;
+
+/**
+ * Class to handle params.
+ *
+ * This function can be used to handle params for queries, filter, facets
+ *
+ * @author Nicolas Ruflin <spam@ruflin.com>
+ */
+class Param
+{
+ /**
+ * Params.
+ *
+ * @var array
+ */
+ protected $_params = array();
+
+ /**
+ * Raw Params.
+ *
+ * @var array
+ */
+ protected $_rawParams = array();
+
+ /**
+ * Converts the params to an array. A default implementation exist to create
+ * the an array out of the class name (last part of the class name)
+ * and the params.
+ *
+ * @return array Filter array
+ */
+ public function toArray()
+ {
+ $data = array($this->_getBaseName() => $this->getParams());
+
+ if (!empty($this->_rawParams)) {
+ $data = array_merge($data, $this->_rawParams);
+ }
+
+ return $data;
+ }
+
+ /**
+ * Param's name
+ * Picks the last part of the class name and makes it snake_case
+ * You can override this method if you want to change the name.
+ *
+ * @return string name
+ */
+ protected function _getBaseName()
+ {
+ return Util::getParamName($this);
+ }
+
+ /**
+ * Sets params not inside params array.
+ *
+ * @param string $key
+ * @param mixed $value
+ *
+ * @return $this
+ */
+ protected function _setRawParam($key, $value)
+ {
+ $this->_rawParams[$key] = $value;
+
+ return $this;
+ }
+
+ /**
+ * Sets (overwrites) the value at the given key.
+ *
+ * @param string $key Key to set
+ * @param mixed $value Key Value
+ *
+ * @return $this
+ */
+ public function setParam($key, $value)
+ {
+ $this->_params[$key] = $value;
+
+ return $this;
+ }
+
+ /**
+ * Sets (overwrites) all params of this object.
+ *
+ * @param array $params Parameter list
+ *
+ * @return $this
+ */
+ public function setParams(array $params)
+ {
+ $this->_params = $params;
+
+ return $this;
+ }
+
+ /**
+ * Adds a param to the list.
+ *
+ * This function can be used to add an array of params
+ *
+ * @param string $key Param key
+ * @param mixed $value Value to set
+ *
+ * @return $this
+ */
+ public function addParam($key, $value)
+ {
+ if ($key != null) {
+ if (!isset($this->_params[$key])) {
+ $this->_params[$key] = array();
+ }
+
+ $this->_params[$key][] = $value;
+ } else {
+ $this->_params = $value;
+ }
+
+ return $this;
+ }
+
+ /**
+ * Returns a specific param.
+ *
+ * @param string $key Key to return
+ *
+ * @throws \Elastica\Exception\InvalidException If requested key is not set
+ *
+ * @return mixed Key value
+ */
+ public function getParam($key)
+ {
+ if (!$this->hasParam($key)) {
+ throw new InvalidException('Param '.$key.' does not exist');
+ }
+
+ return $this->_params[$key];
+ }
+
+ /**
+ * Test if a param is set.
+ *
+ * @param string $key Key to test
+ *
+ * @return bool True if the param is set, false otherwise
+ */
+ public function hasParam($key)
+ {
+ return isset($this->_params[$key]);
+ }
+
+ /**
+ * Returns the params array.
+ *
+ * @return array Params
+ */
+ public function getParams()
+ {
+ return $this->_params;
+ }
+}
diff --git a/vendor/ruflin/elastica/lib/Elastica/Percolator.php b/vendor/ruflin/elastica/lib/Elastica/Percolator.php
new file mode 100644
index 00000000..98d0490a
--- /dev/null
+++ b/vendor/ruflin/elastica/lib/Elastica/Percolator.php
@@ -0,0 +1,194 @@
+<?php
+namespace Elastica;
+
+/**
+ * Percolator class.
+ *
+ * @author Nicolas Ruflin <spam@ruflin.com>
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/search-percolate.html
+ */
+class Percolator
+{
+ const EXTRA_FILTER = 'filter';
+ const EXTRA_QUERY = 'query';
+ const EXTRA_SIZE = 'size';
+ const EXTRA_TRACK_SCORES = 'track_scores';
+ const EXTRA_SORT = 'sort';
+ const EXTRA_FACETS = 'facets';
+ const EXTRA_AGGS = 'aggs';
+ const EXTRA_HIGHLIGHT = 'highlight';
+
+ private $_extraRequestBodyOptions = array(
+ self::EXTRA_FILTER,
+ self::EXTRA_QUERY,
+ self::EXTRA_SIZE,
+ self::EXTRA_TRACK_SCORES,
+ self::EXTRA_SORT,
+ self::EXTRA_FACETS,
+ self::EXTRA_AGGS,
+ self::EXTRA_HIGHLIGHT,
+ );
+
+ /**
+ * Index object.
+ *
+ * @var \Elastica\Index
+ */
+ protected $_index = null;
+
+ /**
+ * Construct new percolator.
+ *
+ * @param \Elastica\Index $index
+ */
+ public function __construct(Index $index)
+ {
+ $this->_index = $index;
+ }
+
+ /**
+ * Registers a percolator query, with optional extra fields to include in the registered query.
+ *
+ * @param string $name Query name
+ * @param string|\Elastica\Query|\Elastica\Query\AbstractQuery $query Query to add
+ * @param array $fields Extra fields to include in the registered query
+ * and can be used to filter executed queries.
+ *
+ * @return \Elastica\Response
+ */
+ public function registerQuery($name, $query, $fields = array())
+ {
+ $path = $this->_index->getName().'/.percolator/'.$name;
+ $query = Query::create($query);
+
+ $data = array_merge($query->toArray(), $fields);
+
+ return $this->_index->getClient()->request($path, Request::PUT, $data);
+ }
+
+ /**
+ * Removes a percolator query.
+ *
+ * @param string $name query name
+ *
+ * @return \Elastica\Response
+ */
+ public function unregisterQuery($name)
+ {
+ $path = $this->_index->getName().'/.percolator/'.$name;
+
+ return $this->_index->getClient()->request($path, Request::DELETE);
+ }
+
+ /**
+ * Match a document to percolator queries.
+ *
+ * @param \Elastica\Document $doc
+ * @param string|\Elastica\Query|\Elastica\Query\AbstractQuery $query Query to filter the percolator queries which
+ * are executed.
+ * @param string $type
+ * @param array $params Supports setting additional request body options to the percolate request.
+ * [ Percolator::EXTRA_FILTER,
+ * Percolator::EXTRA_QUERY,
+ * Percolator::EXTRA_SIZE,
+ * Percolator::EXTRA_TRACK_SCORES,
+ * Percolator::EXTRA_SORT,
+ * Percolator::EXTRA_FACETS,
+ * Percolator::EXTRA_AGGS,
+ * Percolator::EXTRA_HIGHLIGHT ]
+ *
+ * @return array With matching registered queries.
+ */
+ public function matchDoc(Document $doc, $query = null, $type = 'type', $params = array())
+ {
+ $path = $this->_index->getName().'/'.$type.'/_percolate';
+ $data = array('doc' => $doc->getData());
+
+ $this->_applyAdditionalRequestBodyOptions($params, $data);
+
+ return $this->_percolate($path, $query, $data, $params);
+ }
+
+ /**
+ * Percolating an existing document.
+ *
+ * @param string $id
+ * @param string $type
+ * @param string|\Elastica\Query|\Elastica\Query\AbstractQuery $query Query to filter the percolator queries which
+ * are executed.
+ * @param array $params Supports setting additional request body options to the percolate request.
+ * [ Percolator::EXTRA_FILTER,
+ * Percolator::EXTRA_QUERY,
+ * Percolator::EXTRA_SIZE,
+ * Percolator::EXTRA_TRACK_SCORES,
+ * Percolator::EXTRA_SORT,
+ * Percolator::EXTRA_FACETS,
+ * Percolator::EXTRA_AGGS,
+ * Percolator::EXTRA_HIGHLIGHT ]
+ *
+ * @return array With matching registered queries.
+ */
+ public function matchExistingDoc($id, $type, $query = null, $params = array())
+ {
+ $id = urlencode($id);
+ $path = $this->_index->getName().'/'.$type.'/'.$id.'/_percolate';
+
+ $data = array();
+ $this->_applyAdditionalRequestBodyOptions($params, $data);
+
+ return $this->_percolate($path, $query, $data, $params);
+ }
+
+ /**
+ * Process the provided parameters and apply them to the data array.
+ *
+ * @param &$params
+ * @param &$data
+ */
+ protected function _applyAdditionalRequestBodyOptions(&$params, &$data)
+ {
+ foreach ($params as $key => $value) {
+ if (in_array($key, $this->_extraRequestBodyOptions)) {
+ $data[$key] = $params[$key];
+ unset($params[$key]);
+ }
+ }
+ }
+
+ /**
+ * @param string $path
+ * @param string|\Elastica\Query|\Elastica\Query\AbstractQuery $query] $query [description]
+ * @param array $data
+ * @param array $params
+ *
+ * @return array
+ */
+ protected function _percolate($path, $query, $data = array(), $params = array())
+ {
+ // Add query to filter the percolator queries which are executed.
+ if ($query) {
+ $query = Query::create($query);
+ $data['query'] = $query->getQuery();
+ }
+
+ $response = $this->getIndex()->getClient()->request($path, Request::GET, $data, $params);
+ $data = $response->getData();
+
+ if (isset($data['matches'])) {
+ return $data['matches'];
+ }
+
+ return array();
+ }
+
+ /**
+ * Return index object.
+ *
+ * @return \Elastica\Index
+ */
+ public function getIndex()
+ {
+ return $this->_index;
+ }
+}
diff --git a/vendor/ruflin/elastica/lib/Elastica/Query.php b/vendor/ruflin/elastica/lib/Elastica/Query.php
new file mode 100644
index 00000000..175c8c95
--- /dev/null
+++ b/vendor/ruflin/elastica/lib/Elastica/Query.php
@@ -0,0 +1,488 @@
+<?php
+namespace Elastica;
+
+use Elastica\Aggregation\AbstractAggregation;
+use Elastica\Exception\InvalidException;
+use Elastica\Exception\NotImplementedException;
+use Elastica\Facet\AbstractFacet;
+use Elastica\Filter\AbstractFilter;
+use Elastica\Query\AbstractQuery;
+use Elastica\Query\MatchAll;
+use Elastica\Query\QueryString;
+use Elastica\Suggest\AbstractSuggest;
+
+/**
+ * Elastica query object.
+ *
+ * Creates different types of queries
+ *
+ * @author Nicolas Ruflin <spam@ruflin.com>
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/search-request-body.html
+ */
+class Query extends Param
+{
+ /**
+ * Params.
+ *
+ * @var array Params
+ */
+ protected $_params = array();
+
+ /**
+ * Suggest query or not.
+ *
+ * @var int Suggest
+ */
+ protected $_suggest = 0;
+
+ /**
+ * Creates a query object.
+ *
+ * @param array|\Elastica\Query\AbstractQuery $query OPTIONAL Query object (default = null)
+ */
+ public function __construct($query = null)
+ {
+ if (is_array($query)) {
+ $this->setRawQuery($query);
+ } elseif ($query instanceof AbstractQuery) {
+ $this->setQuery($query);
+ } elseif ($query instanceof Suggest) {
+ $this->setSuggest($query);
+ }
+ }
+
+ /**
+ * Transforms a string or an array to a query object.
+ *
+ * If query is empty,
+ *
+ * @param mixed $query
+ *
+ * @throws \Elastica\Exception\NotImplementedException
+ *
+ * @return self
+ */
+ public static function create($query)
+ {
+ switch (true) {
+ case $query instanceof self:
+ return $query;
+ case $query instanceof AbstractQuery:
+ return new self($query);
+ case $query instanceof AbstractFilter:
+ $newQuery = new self();
+ $newQuery->setPostFilter($query);
+
+ return $newQuery;
+ case empty($query):
+ return new self(new MatchAll());
+ case is_array($query):
+ return new self($query);
+ case is_string($query):
+ return new self(new QueryString($query));
+ case $query instanceof AbstractSuggest:
+ return new self(new Suggest($query));
+
+ case $query instanceof Suggest:
+ return new self($query);
+
+ }
+
+ // TODO: Implement queries without
+ throw new NotImplementedException();
+ }
+
+ /**
+ * Sets query as raw array. Will overwrite all already set arguments.
+ *
+ * @param array $query Query array
+ *
+ * @return $this
+ */
+ public function setRawQuery(array $query)
+ {
+ $this->_params = $query;
+
+ return $this;
+ }
+
+ /**
+ * Sets the query.
+ *
+ * @param \Elastica\Query\AbstractQuery $query Query object
+ *
+ * @return $this
+ */
+ public function setQuery(AbstractQuery $query)
+ {
+ return $this->setParam('query', $query->toArray());
+ }
+
+ /**
+ * Gets the query array.
+ *
+ * @return array
+ **/
+ public function getQuery()
+ {
+ return $this->getParam('query');
+ }
+
+ /**
+ * Set Filter.
+ *
+ * @param \Elastica\Filter\AbstractFilter $filter Filter object
+ *
+ * @return $this
+ *
+ * @link https://github.com/elasticsearch/elasticsearch/issues/7422
+ * @deprecated
+ */
+ public function setFilter(AbstractFilter $filter)
+ {
+ trigger_error('Deprecated: Elastica\Query::setFilter() is deprecated. Use Elastica\Query::setPostFilter() instead.', E_USER_DEPRECATED);
+
+ return $this->setPostFilter($filter);
+ }
+
+ /**
+ * Sets the start from which the search results should be returned.
+ *
+ * @param int $from
+ *
+ * @return $this
+ */
+ public function setFrom($from)
+ {
+ return $this->setParam('from', $from);
+ }
+
+ /**
+ * Sets sort arguments for the query
+ * Replaces existing values.
+ *
+ * @param array $sortArgs Sorting arguments
+ *
+ * @return $this
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/search-request-sort.html
+ */
+ public function setSort(array $sortArgs)
+ {
+ return $this->setParam('sort', $sortArgs);
+ }
+
+ /**
+ * Adds a sort param to the query.
+ *
+ * @param mixed $sort Sort parameter
+ *
+ * @return $this
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/search-request-sort.html
+ */
+ public function addSort($sort)
+ {
+ return $this->addParam('sort', $sort);
+ }
+
+ /**
+ * Sets highlight arguments for the query.
+ *
+ * @param array $highlightArgs Set all highlight arguments
+ *
+ * @return $this
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/search-request-highlighting.html
+ */
+ public function setHighlight(array $highlightArgs)
+ {
+ return $this->setParam('highlight', $highlightArgs);
+ }
+
+ /**
+ * Adds a highlight argument.
+ *
+ * @param mixed $highlight Add highlight argument
+ *
+ * @return $this
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/search-request-highlighting.html
+ */
+ public function addHighlight($highlight)
+ {
+ return $this->addParam('highlight', $highlight);
+ }
+
+ /**
+ * Sets maximum number of results for this query.
+ *
+ * @param int $size OPTIONAL Maximal number of results for query (default = 10)
+ *
+ * @return $this
+ */
+ public function setSize($size = 10)
+ {
+ return $this->setParam('size', $size);
+ }
+
+ /**
+ * Alias for setSize.
+ *
+ * @deprecated Use the setSize() method, this method will be removed in future releases
+ *
+ * @param int $limit OPTIONAL Maximal number of results for query (default = 10)
+ *
+ * @return $this
+ */
+ public function setLimit($limit = 10)
+ {
+ return $this->setSize($limit);
+ }
+
+ /**
+ * Enables explain on the query.
+ *
+ * @param bool $explain OPTIONAL Enabled or disable explain (default = true)
+ *
+ * @return $this
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/search-request-explain.html
+ */
+ public function setExplain($explain = true)
+ {
+ return $this->setParam('explain', $explain);
+ }
+
+ /**
+ * Enables version on the query.
+ *
+ * @param bool $version OPTIONAL Enabled or disable version (default = true)
+ *
+ * @return $this
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/search-request-version.html
+ */
+ public function setVersion($version = true)
+ {
+ return $this->setParam('version', $version);
+ }
+
+ /**
+ * Sets the fields to be returned by the search
+ * NOTICE php will encode modified(or named keys) array into object format in json format request
+ * so the fields array must a sequence(list) type of array.
+ *
+ * @param array $fields Fields to be returned
+ *
+ * @return $this
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/search-request-fields.html
+ */
+ public function setFields(array $fields)
+ {
+ return $this->setParam('fields', $fields);
+ }
+
+ /**
+ * Set script fields.
+ *
+ * @param array|\Elastica\ScriptFields $scriptFields Script fields
+ *
+ * @return $this
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/search-request-script-fields.html
+ */
+ public function setScriptFields($scriptFields)
+ {
+ if (is_array($scriptFields)) {
+ $scriptFields = new ScriptFields($scriptFields);
+ }
+
+ return $this->setParam('script_fields', $scriptFields->toArray());
+ }
+
+ /**
+ * Adds a Script to the query.
+ *
+ * @param string $name
+ * @param \Elastica\Script $script Script object
+ *
+ * @return $this
+ */
+ public function addScriptField($name, Script $script)
+ {
+ $this->_params['script_fields'][$name] = $script->toArray();
+
+ return $this;
+ }
+
+ /**
+ * Sets all facets for this query object. Replaces existing facets.
+ *
+ * @param array $facets List of facet objects
+ *
+ * @return $this
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/search-facets.html
+ * @deprecated Facets are deprecated and will be removed in a future release. You are encouraged to migrate to aggregations instead.
+ */
+ public function setFacets(array $facets)
+ {
+ $this->_params['facets'] = array();
+ foreach ($facets as $facet) {
+ $this->addFacet($facet);
+ }
+
+ return $this;
+ }
+
+ /**
+ * Adds a Facet to the query.
+ *
+ * @param \Elastica\Facet\AbstractFacet $facet Facet object
+ *
+ * @return $this
+ *
+ * @deprecated Facets are deprecated and will be removed in a future release. You are encouraged to migrate to aggregations instead.
+ */
+ public function addFacet(AbstractFacet $facet)
+ {
+ $this->_params['facets'][$facet->getName()] = $facet->toArray();
+
+ return $this;
+ }
+
+ /**
+ * Adds an Aggregation to the query.
+ *
+ * @param AbstractAggregation $agg
+ *
+ * @return $this
+ */
+ public function addAggregation(AbstractAggregation $agg)
+ {
+ if (!array_key_exists('aggs', $this->_params)) {
+ $this->_params['aggs'] = array();
+ }
+ $this->_params['aggs'][$agg->getName()] = $agg->toArray();
+
+ return $this;
+ }
+
+ /**
+ * Converts all query params to an array.
+ *
+ * @return array Query array
+ */
+ public function toArray()
+ {
+ if (!isset($this->_params['query']) && ($this->_suggest == 0)) {
+ $this->setQuery(new MatchAll());
+ }
+
+ if (isset($this->_params['facets']) && 0 === count($this->_params['facets'])) {
+ unset($this->_params['facets']);
+ }
+
+ if (isset($this->_params['post_filter']) && 0 === count($this->_params['post_filter'])) {
+ unset($this->_params['post_filter']);
+ }
+
+ return $this->_params;
+ }
+
+ /**
+ * Allows filtering of documents based on a minimum score.
+ *
+ * @param int $minScore Minimum score to filter documents by
+ *
+ * @throws \Elastica\Exception\InvalidException
+ *
+ * @return $this
+ */
+ public function setMinScore($minScore)
+ {
+ if (!is_numeric($minScore)) {
+ throw new InvalidException('has to be numeric param');
+ }
+
+ return $this->setParam('min_score', $minScore);
+ }
+
+ /**
+ * Add a suggest term.
+ *
+ * @param \Elastica\Suggest $suggest suggestion object
+ *
+ * @return $this
+ */
+ public function setSuggest(Suggest $suggest)
+ {
+ $this->setParams(array_merge(
+ $this->getParams(),
+ $suggest->toArray()
+ ));
+
+ $this->_suggest = 1;
+
+ return $this;
+ }
+
+ /**
+ * Add a Rescore.
+ *
+ * @param mixed $rescore suggestion object
+ *
+ * @return $this
+ */
+ public function setRescore($rescore)
+ {
+ if (is_array($rescore)) {
+ $buffer = array();
+
+ foreach ($rescore as $rescoreQuery) {
+ $buffer [] = $rescoreQuery->toArray();
+ }
+ } else {
+ $buffer = $rescore->toArray();
+ }
+
+ return $this->setParam('rescore', $buffer);
+ }
+
+ /**
+ * Sets the _source field to be returned with every hit.
+ *
+ * @param array|bool $params Fields to be returned or false to disable source
+ *
+ * @return $this
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/search-request-source-filtering.html
+ */
+ public function setSource($params)
+ {
+ return $this->setParam('_source', $params);
+ }
+
+ /**
+ * Sets post_filter argument for the query. The filter is applied after the query has executed.
+ *
+ * @param array|\Elastica\Filter\AbstractFilter $filter
+ *
+ * @return $this
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/search-request-post-filter.html
+ */
+ public function setPostFilter($filter)
+ {
+ if ($filter instanceof AbstractFilter) {
+ $filter = $filter->toArray();
+ } else {
+ trigger_error('Deprecated: Elastica\Query::setPostFilter() passing filter as array is deprecated. Pass instance of AbstractFilter instead.', E_USER_DEPRECATED);
+ }
+
+ return $this->setParam('post_filter', $filter);
+ }
+}
diff --git a/vendor/ruflin/elastica/lib/Elastica/Query/AbstractQuery.php b/vendor/ruflin/elastica/lib/Elastica/Query/AbstractQuery.php
new file mode 100644
index 00000000..fd1c29b0
--- /dev/null
+++ b/vendor/ruflin/elastica/lib/Elastica/Query/AbstractQuery.php
@@ -0,0 +1,13 @@
+<?php
+namespace Elastica\Query;
+
+use Elastica\Param;
+
+/**
+ * Abstract query object. Should be extended by all query types.
+ *
+ * @author Nicolas Ruflin <spam@ruflin.com>
+ */
+abstract class AbstractQuery extends Param
+{
+}
diff --git a/vendor/ruflin/elastica/lib/Elastica/Query/Bool.php b/vendor/ruflin/elastica/lib/Elastica/Query/Bool.php
new file mode 100644
index 00000000..c5bccc54
--- /dev/null
+++ b/vendor/ruflin/elastica/lib/Elastica/Query/Bool.php
@@ -0,0 +1,15 @@
+<?php
+namespace Elastica\Query;
+
+/**
+ * Bool query.
+ *
+ * This class is for backward compatibility reason for all php < 7 versions. For PHP 7 and above use BoolFilter as Bool is reserved.
+ *
+ * @author Nicolas Ruflin <spam@ruflin.com>
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-bool-query.html
+ */
+class Bool extends BoolQuery
+{
+}
diff --git a/vendor/ruflin/elastica/lib/Elastica/Query/BoolQuery.php b/vendor/ruflin/elastica/lib/Elastica/Query/BoolQuery.php
new file mode 100644
index 00000000..7b8bd4da
--- /dev/null
+++ b/vendor/ruflin/elastica/lib/Elastica/Query/BoolQuery.php
@@ -0,0 +1,111 @@
+<?php
+namespace Elastica\Query;
+
+use Elastica\Exception\InvalidException;
+
+/**
+ * Bool query.
+ *
+ * @author Nicolas Ruflin <spam@ruflin.com>
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-bool-query.html
+ */
+class BoolQuery extends AbstractQuery
+{
+ /**
+ * Add should part to query.
+ *
+ * @param \Elastica\Query\AbstractQuery|array $args Should query
+ *
+ * @return $this
+ */
+ public function addShould($args)
+ {
+ return $this->_addQuery('should', $args);
+ }
+
+ /**
+ * Add must part to query.
+ *
+ * @param \Elastica\Query\AbstractQuery|array $args Must query
+ *
+ * @return $this
+ */
+ public function addMust($args)
+ {
+ return $this->_addQuery('must', $args);
+ }
+
+ /**
+ * Add must not part to query.
+ *
+ * @param \Elastica\Query\AbstractQuery|array $args Must not query
+ *
+ * @return $this
+ */
+ public function addMustNot($args)
+ {
+ return $this->_addQuery('must_not', $args);
+ }
+
+ /**
+ * Adds a query to the current object.
+ *
+ * @param string $type Query type
+ * @param \Elastica\Query\AbstractQuery|array $args Query
+ *
+ * @throws \Elastica\Exception\InvalidException If not valid query
+ *
+ * @return $this
+ */
+ protected function _addQuery($type, $args)
+ {
+ if ($args instanceof AbstractQuery) {
+ $args = $args->toArray();
+ }
+
+ if (!is_array($args)) {
+ throw new InvalidException('Invalid parameter. Has to be array or instance of Elastica\Query\AbstractQuery');
+ }
+
+ return $this->addParam($type, $args);
+ }
+
+ /**
+ * Sets boost value of this query.
+ *
+ * @param float $boost Boost value
+ *
+ * @return $this
+ */
+ public function setBoost($boost)
+ {
+ return $this->setParam('boost', $boost);
+ }
+
+ /**
+ * Set the minimum number of of should match.
+ *
+ * @param int $minimumNumberShouldMatch Should match minimum
+ *
+ * @return $this
+ */
+ public function setMinimumNumberShouldMatch($minimumNumberShouldMatch)
+ {
+ return $this->setParam('minimum_number_should_match', $minimumNumberShouldMatch);
+ }
+
+ /**
+ * Converts array to an object in case no queries are added.
+ *
+ * @return array
+ */
+ public function toArray()
+ {
+ if (empty($this->_params)) {
+ $this->_params = new \stdClass();
+ }
+
+ return parent::toArray();
+ }
+}
diff --git a/vendor/ruflin/elastica/lib/Elastica/Query/Boosting.php b/vendor/ruflin/elastica/lib/Elastica/Query/Boosting.php
new file mode 100644
index 00000000..95dcde3d
--- /dev/null
+++ b/vendor/ruflin/elastica/lib/Elastica/Query/Boosting.php
@@ -0,0 +1,50 @@
+<?php
+namespace Elastica\Query;
+
+/**
+ * Class Boosting.
+ *
+ * @author Balazs Nadasdi <yitsushi@gmail.com>
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-boosting-query.html
+ */
+class Boosting extends AbstractQuery
+{
+ const NEGATIVE_BOOST = 0.2;
+
+ /**
+ * Set the positive query for this Boosting Query.
+ *
+ * @param AbstractQuery $query
+ *
+ * @return $this
+ */
+ public function setPositiveQuery(AbstractQuery $query)
+ {
+ return $this->setParam('positive', $query->toArray());
+ }
+
+ /**
+ * Set the negative query for this Boosting Query.
+ *
+ * @param AbstractQuery $query
+ *
+ * @return $this
+ */
+ public function setNegativeQuery(AbstractQuery $query)
+ {
+ return $this->setParam('negative', $query->toArray());
+ }
+
+ /**
+ * Set the negative_boost parameter for this Boosting Query.
+ *
+ * @param Float $negativeBoost
+ *
+ * @return $this
+ */
+ public function setNegativeBoost($negativeBoost)
+ {
+ return $this->setParam('negative_boost', (float) $negativeBoost);
+ }
+}
diff --git a/vendor/ruflin/elastica/lib/Elastica/Query/Builder.php b/vendor/ruflin/elastica/lib/Elastica/Query/Builder.php
new file mode 100644
index 00000000..55b6b903
--- /dev/null
+++ b/vendor/ruflin/elastica/lib/Elastica/Query/Builder.php
@@ -0,0 +1,935 @@
+<?php
+namespace Elastica\Query;
+
+use Elastica\Exception\InvalidException;
+use Elastica\Exception\JSONParseException;
+use Elastica\JSON;
+
+/**
+ * Query Builder.
+ *
+ * @author Chris Gedrim <chris@gedr.im>
+ *
+ * @link http://www.elastic.co/
+ * @deprecated This builder is deprecated and will be removed. Use new Elastica\QueryBuilder instead.
+ **/
+class Builder extends AbstractQuery
+{
+ /**
+ * Query string.
+ *
+ * @var string
+ */
+ private $_string = '{';
+
+ /**
+ * Factory method.
+ *
+ * @param string $string JSON encoded string to use as query.
+ *
+ * @return self
+ */
+ public static function factory($string = null)
+ {
+ return new self($string);
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param string $string JSON encoded string to use as query.
+ */
+ public function __construct($string = null)
+ {
+ if (!$string == null) {
+ $this->_string .= substr($string, 1, -1);
+ }
+ }
+
+ /**
+ * Output the query string.
+ *
+ * @return string
+ */
+ public function __toString()
+ {
+ return rtrim($this->_string, ',').'}';
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function toArray()
+ {
+ try {
+ return JSON::parse($input = $this->__toString());
+ } catch (JSONParseException $e) {
+ throw new InvalidException(sprintf(
+ 'The produced query is not a valid json string : "%s"',
+ $input
+ ));
+ }
+ }
+
+ /**
+ * Allow wildcards (*, ?) as the first character in a query.
+ *
+ * @param bool $bool Defaults to true.
+ *
+ * @return $this
+ */
+ public function allowLeadingWildcard($bool = true)
+ {
+ return $this->field('allow_leading_wildcard', (bool) $bool);
+ }
+
+ /**
+ * Enable best effort analysis of wildcard terms.
+ *
+ * @param bool $bool Defaults to true.
+ *
+ * @return $this
+ */
+ public function analyzeWildcard($bool = true)
+ {
+ return $this->field('analyze_wildcard', (bool) $bool);
+ }
+
+ /**
+ * Set the analyzer name used to analyze the query string.
+ *
+ * @param string $analyzer Analyzer to use.
+ *
+ * @return $this
+ */
+ public function analyzer($analyzer)
+ {
+ return $this->field('analyzer', $analyzer);
+ }
+
+ /**
+ * Autogenerate phrase queries.
+ *
+ * @param bool $bool Defaults to true.
+ *
+ * @return $this
+ */
+ public function autoGeneratePhraseQueries($bool = true)
+ {
+ return $this->field('auto_generate_phrase_queries', (bool) $bool);
+ }
+
+ /**
+ * Bool Query.
+ *
+ * A query that matches documents matching boolean combinations of other queries.
+ *
+ * The bool query maps to Lucene BooleanQuery.
+ *
+ * It is built using one or more boolean clauses, each clause with a typed
+ * occurrence.
+ *
+ * The occurrence types are: must, should, must_not.
+ *
+ * @return $this
+ */
+ public function bool()
+ {
+ return $this->fieldOpen('bool');
+ }
+
+ /**
+ * Close a 'bool' block.
+ *
+ * Alias of close() for ease of reading in source.
+ *
+ * @return $this
+ */
+ public function boolClose()
+ {
+ return $this->fieldClose();
+ }
+
+ /**
+ * Sets the boost value of the query.
+ *
+ * @param float $boost Defaults to 1.0.
+ *
+ * @return $this
+ */
+ public function boost($boost = 1.0)
+ {
+ return $this->field('boost', (float) $boost);
+ }
+
+ /**
+ * Close a previously opened brace.
+ *
+ * @return $this
+ */
+ public function close()
+ {
+ $this->_string = rtrim($this->_string, ' ,').'},';
+
+ return $this;
+ }
+
+ /**
+ * Constant Score Query.
+ *
+ * A query that wraps a filter or another query and simply returns a constant
+ * score equal to the query boost for every document in the filter.
+ *
+ * Maps to Lucene ConstantScoreQuery.
+ *
+ * @return $this
+ */
+ public function constantScore()
+ {
+ return $this->fieldOpen('constant_score');
+ }
+
+ /**
+ * Close a 'constant_score' block.
+ *
+ * Alias of close() for ease of reading in source.
+ *
+ * @return $this
+ */
+ public function constantScoreClose()
+ {
+ return $this->fieldClose();
+ }
+
+ /**
+ * The default field for query terms if no prefix field is specified.
+ *
+ * @param string $field Defaults to _all.
+ *
+ * @return $this
+ */
+ public function defaultField($field = '_all')
+ {
+ return $this->field('default_field', $field);
+ }
+
+ /**
+ * The default operator used if no explicit operator is specified.
+ *
+ * For example, with a default operator of OR, the query "capital of Hungary"
+ * is translated to "capital OR of OR Hungary", and with default operator of
+ * AND, the same query is translated to "capital AND of AND Hungary".
+ *
+ * @param string $operator Defaults to OR.
+ *
+ * @return $this
+ */
+ public function defaultOperator($operator = 'OR')
+ {
+ return $this->field('default_operator', $operator);
+ }
+
+ /**
+ * Dis Max Query.
+ *
+ * A query that generates the union of documents produced by its subqueries,
+ * and that scores each document with the maximum score for that document as
+ * produced by any subquery, plus a tie breaking increment for any additional
+ * matching subqueries.
+ *
+ * @return $this
+ */
+ public function disMax()
+ {
+ return $this->fieldOpen('dis_max');
+ }
+
+ /**
+ * Close a 'dis_max' block.
+ *
+ * Alias of close() for ease of reading in source.
+ *
+ * @return $this
+ */
+ public function disMaxClose()
+ {
+ return $this->fieldClose();
+ }
+
+ /**
+ * Enable position increments in result queries.
+ *
+ * @param bool $bool Defaults to true.
+ *
+ * @return $this
+ */
+ public function enablePositionIncrements($bool = true)
+ {
+ return $this->field('enable_position_increments', (bool) $bool);
+ }
+
+ /**
+ * Enables explanation for each hit on how its score was computed.
+ *
+ * @param bool $value Turn on / off explain.
+ *
+ * @return $this
+ */
+ public function explain($value = true)
+ {
+ return $this->field('explain', $value);
+ }
+
+ /**
+ * Open 'facets' block.
+ *
+ * Facets provide aggregated data based on a search query.
+ *
+ * In the simple case, a facet can return facet counts for various facet
+ * values for a specific field.
+ *
+ * Elasticsearch supports more advanced facet implementations, such as
+ * statistical or date histogram facets.
+ *
+ * @return $this
+ */
+ public function facets()
+ {
+ return $this->fieldOpen('facets');
+ }
+
+ /**
+ * Close a facets block.
+ *
+ * Alias of close() for ease of reading in source.
+ *
+ * @return $this
+ */
+ public function facetsClose()
+ {
+ return $this->close();
+ }
+
+ /**
+ * Add a specific field / value entry.
+ *
+ * @param string $name Field to add.
+ * @param mixed $value Value to set.
+ *
+ * @return $this
+ */
+ public function field($name, $value)
+ {
+ if (is_bool($value)) {
+ $value = '"'.var_export($value, true).'"';
+ } elseif (is_array($value)) {
+ $value = '["'.implode('","', $value).'"]';
+ } else {
+ $value = '"'.$value.'"';
+ }
+
+ $this->_string .= '"'.$name.'":'.$value.',';
+
+ return $this;
+ }
+
+ /**
+ * Close a field block.
+ *
+ * Alias of close() for ease of reading in source.
+ * Passed parameters will be ignored, however they can be useful in source for
+ * seeing which field is being closed.
+ *
+ * Builder::factory()
+ * ->query()
+ * ->range()
+ * ->fieldOpen('created')
+ * ->gte('2011-07-18 00:00:00')
+ * ->lt('2011-07-19 00:00:00')
+ * ->fieldClose('created')
+ * ->rangeClose()
+ * ->queryClose();
+ *
+ * @return $this
+ */
+ public function fieldClose()
+ {
+ return $this->close();
+ }
+
+ /**
+ * Open a node for the specified name.
+ *
+ * @param string $name Field name.
+ *
+ * @return $this
+ */
+ public function fieldOpen($name)
+ {
+ $this->_string .= '"'.$name.'":';
+ $this->open();
+
+ return $this;
+ }
+
+ /**
+ * Explicitly define fields to return.
+ *
+ * @param array $fields Array of fields to return.
+ *
+ * @return $this
+ */
+ public function fields(array $fields)
+ {
+ $this->_string .= '"fields":[';
+
+ foreach ($fields as $field) {
+ $this->_string .= '"'.$field.'",';
+ }
+
+ $this->_string = rtrim($this->_string, ',').'],';
+
+ return $this;
+ }
+
+ /**
+ * Open a 'filter' block.
+ *
+ * @return $this
+ */
+ public function filter()
+ {
+ return $this->fieldOpen('filter');
+ }
+
+ /**
+ * Close a filter block.
+ *
+ * @return $this
+ */
+ public function filterClose()
+ {
+ return $this->close();
+ }
+
+ /**
+ * Query.
+ *
+ * @return $this
+ */
+ public function filteredQuery()
+ {
+ return $this->fieldOpen('filtered');
+ }
+
+ /**
+ * Close a 'filtered_query' block.
+ *
+ * Alias of close() for ease of reading in source.
+ *
+ * @return $this
+ */
+ public function filteredQueryClose()
+ {
+ return $this->fieldClose();
+ }
+
+ /**
+ * Set the from parameter (offset).
+ *
+ * @param int $value Result number to start from.
+ *
+ * @return $this
+ */
+ public function from($value = 0)
+ {
+ return $this->field('from', $value);
+ }
+
+ /**
+ * Set the minimum similarity for fuzzy queries.
+ *
+ * @param float $value Defaults to 0.5.
+ *
+ * @return $this
+ */
+ public function fuzzyMinSim($value = 0.5)
+ {
+ return $this->field('fuzzy_min_sim', (float) $value);
+ }
+
+ /**
+ * Set the prefix length for fuzzy queries.
+ *
+ * @param int $value Defaults to 0.
+ *
+ * @return $this
+ */
+ public function fuzzyPrefixLength($value = 0)
+ {
+ return $this->field('fuzzy_prefix_length', (int) $value);
+ }
+
+ /**
+ * Add a greater than (gt) clause.
+ *
+ * Used in range blocks.
+ *
+ * @param mixed $value Value to be gt.
+ *
+ * @return $this
+ */
+ public function gt($value)
+ {
+ return $this->field('gt', $value);
+ }
+
+ /**
+ * Add a greater than or equal to (gte) clause.
+ *
+ * Used in range blocks.
+ *
+ * @param mixed $value Value to be gte to.
+ *
+ * @return $this
+ */
+ public function gte($value)
+ {
+ return $this->field('gte', $value);
+ }
+
+ /**
+ * Automatically lower-case terms of wildcard, prefix, fuzzy, and range queries.
+ *
+ * @param bool $bool Defaults to true.
+ *
+ * @return $this
+ */
+ public function lowercaseExpandedTerms($bool = true)
+ {
+ return $this->field('lowercase_expanded_terms', (bool) $bool);
+ }
+
+ /**
+ * Add a less than (lt) clause.
+ *
+ * Used in range blocks.
+ *
+ * @param mixed $value Value to be lt.
+ *
+ * @return $this
+ */
+ public function lt($value)
+ {
+ return $this->field('lt', $value);
+ }
+
+ /**
+ * Add a less than or equal to (lte) clause.
+ *
+ * Used in range blocks.
+ *
+ * @param mixed $value Value to be lte to.
+ *
+ * @return $this
+ */
+ public function lte($value)
+ {
+ return $this->field('lte', $value);
+ }
+
+ /**
+ * Match All Query.
+ *
+ * A query that matches all documents.
+ *
+ * Maps to Lucene MatchAllDocsQuery.
+ *
+ * @param float $boost Boost to use.
+ *
+ * @return $this
+ */
+ public function matchAll($boost = null)
+ {
+ $this->fieldOpen('match_all');
+
+ if (!$boost == null && is_numeric($boost)) {
+ $this->field('boost', (float) $boost);
+ }
+
+ return $this->close();
+ }
+
+ /**
+ * The minimum number of should clauses to match.
+ *
+ * @param int $minimum Minimum number that should match.
+ *
+ * @return $this
+ */
+ public function minimumNumberShouldMatch($minimum)
+ {
+ return $this->field('minimum_number_should_match', (int) $minimum);
+ }
+
+ /**
+ * The clause (query) must appear in matching documents.
+ *
+ * @return $this
+ */
+ public function must()
+ {
+ return $this->fieldOpen('must');
+ }
+
+ /**
+ * Close a 'must' block.
+ *
+ * Alias of close() for ease of reading in source.
+ *
+ * @return $this
+ */
+ public function mustClose()
+ {
+ return $this->fieldClose();
+ }
+
+ /**
+ * The clause (query) must not appear in the matching documents.
+ *
+ * Note that it is not possible to search on documents that only consists of
+ * a must_not clauses.
+ *
+ * @return $this
+ */
+ public function mustNot()
+ {
+ return $this->fieldOpen('must_not');
+ }
+
+ /**
+ * Close a 'must_not' block.
+ *
+ * Alias of close() for ease of reading in source.
+ *
+ * @return $this
+ */
+ public function mustNotClose()
+ {
+ return $this->fieldClose();
+ }
+
+ /**
+ * Add an opening brace.
+ *
+ * @return $this
+ */
+ public function open()
+ {
+ $this->_string .= '{';
+
+ return $this;
+ }
+
+ /**
+ * Sets the default slop for phrases.
+ *
+ * If zero, then exact phrase matches are required.
+ *
+ * @param int $value Defaults to 0.
+ *
+ * @return $this
+ */
+ public function phraseSlop($value = 0)
+ {
+ return $this->field('phrase_slop', (int) $value);
+ }
+
+ /**
+ * Query.
+ *
+ * @return $this
+ */
+ public function prefix()
+ {
+ return $this->fieldOpen('prefix');
+ }
+
+ /**
+ * Close a 'prefix' block.
+ *
+ * Alias of close() for ease of reading in source.
+ *
+ * @return $this
+ */
+ public function prefixClose()
+ {
+ return $this->fieldClose();
+ }
+
+ /**
+ * Queries to run within a dis_max query.
+ *
+ * @param array $queries Array of queries.
+ *
+ * @return $this
+ */
+ public function queries(array $queries)
+ {
+ $this->_string .= '"queries":[';
+
+ foreach ($queries as $query) {
+ $this->_string .= $query.',';
+ }
+
+ $this->_string = rtrim($this->_string, ' ,').'],';
+
+ return $this;
+ }
+
+ /**
+ * Open a query block.
+ *
+ * @return $this
+ */
+ public function query()
+ {
+ return $this->fieldOpen('query');
+ }
+
+ /**
+ * Close a query block.
+ *
+ * Alias of close() for ease of reading in source.
+ *
+ * @return $this
+ */
+ public function queryClose()
+ {
+ return $this->close();
+ }
+
+ /**
+ * Query String Query.
+ *
+ * A query that uses a query parser in order to parse its content
+ *
+ * @return $this
+ */
+ public function queryString()
+ {
+ return $this->fieldOpen('query_string');
+ }
+
+ /**
+ * Close a 'query_string' block.
+ *
+ * Alias of close() for ease of reading in source.
+ *
+ * @return $this
+ */
+ public function queryStringClose()
+ {
+ return $this->fieldClose();
+ }
+
+ /**
+ * Open a range block.
+ *
+ * @return $this
+ */
+ public function range()
+ {
+ return $this->fieldOpen('range');
+ }
+
+ /**
+ * Close a range block.
+ *
+ * Alias of close() for ease of reading in source.
+ *
+ * @return $this
+ */
+ public function rangeClose()
+ {
+ return $this->close();
+ }
+
+ /**
+ * The clause (query) should appear in the matching document.
+ *
+ * A boolean query with no must clauses, one or more should clauses must
+ * match a document.
+ *
+ * @return $this
+ */
+ public function should()
+ {
+ return $this->fieldOpen('should');
+ }
+
+ /**
+ * Close a 'should' block.
+ *
+ * Alias of close() for ease of reading in source.
+ *
+ * @return $this
+ */
+ public function shouldClose()
+ {
+ return $this->fieldClose();
+ }
+
+ /**
+ * Set the size parameter (number of records to return).
+ *
+ * @param int $value Number of records to return.
+ *
+ * @return $this
+ */
+ public function size($value = 10)
+ {
+ return $this->field('size', $value);
+ }
+
+ /**
+ * Allows to add one or more sort on specific fields.
+ *
+ * @return $this
+ */
+ public function sort()
+ {
+ return $this->fieldOpen('sort');
+ }
+
+ /**
+ * Close a sort block.
+ *
+ * Alias of close() for ease of reading in source.
+ *
+ * @return $this
+ */
+ public function sortClose()
+ {
+ return $this->close();
+ }
+
+ /**
+ * Add a field to sort on.
+ *
+ * @param string $name Field to sort.
+ * @param bool $reverse Reverse direction.
+ *
+ * @return $this
+ */
+ public function sortField($name, $reverse = false)
+ {
+ return $this
+ ->fieldOpen('sort')
+ ->fieldOpen($name)
+ ->field('reverse', $reverse)
+ ->close()
+ ->close();
+ }
+
+ /**
+ * Sort on multiple fields.
+ *
+ * @param array $fields Associative array where the keys are field names to sort on, and the
+ * values are the sort order: "asc" or "desc"
+ *
+ * @return $this
+ */
+ public function sortFields(array $fields)
+ {
+ $this->_string .= '"sort":[';
+
+ foreach ($fields as $fieldName => $order) {
+ $this->_string .= '{"'.$fieldName.'":"'.$order.'"},';
+ }
+
+ $this->_string = rtrim($this->_string, ',').'],';
+
+ return $this;
+ }
+
+ /**
+ * Term Query.
+ *
+ * Matches documents that have fields that contain a term (not analyzed).
+ *
+ * The term query maps to Lucene TermQuery.
+ *
+ * @return $this
+ */
+ public function term()
+ {
+ return $this->fieldOpen('term');
+ }
+
+ /**
+ * Close a 'term' block.
+ *
+ * Alias of close() for ease of reading in source.
+ *
+ * @return $this
+ */
+ public function termClose()
+ {
+ return $this->fieldClose();
+ }
+
+ /**
+ * Open a 'text_phrase' block.
+ *
+ * @return $this
+ */
+ public function textPhrase()
+ {
+ return $this->fieldOpen('text_phrase');
+ }
+
+ /**
+ * Close a 'text_phrase' block.
+ *
+ * @return $this
+ */
+ public function textPhraseClose()
+ {
+ return $this->close();
+ }
+
+ /**
+ * When using dis_max, the disjunction max tie breaker.
+ *
+ * @param float $multiplier Multiplier to use.
+ *
+ * @return $this
+ */
+ public function tieBreakerMultiplier($multiplier)
+ {
+ return $this->field('tie_breaker_multiplier', (float) $multiplier);
+ }
+
+ /**
+ * Query.
+ *
+ * @return $this
+ */
+ public function wildcard()
+ {
+ return $this->fieldOpen('wildcard');
+ }
+
+ /**
+ * Close a 'wildcard' block.
+ *
+ * Alias of close() for ease of reading in source.
+ *
+ * @return $this
+ */
+ public function wildcardClose()
+ {
+ return $this->fieldClose();
+ }
+}
diff --git a/vendor/ruflin/elastica/lib/Elastica/Query/Common.php b/vendor/ruflin/elastica/lib/Elastica/Query/Common.php
new file mode 100644
index 00000000..9ca58d2e
--- /dev/null
+++ b/vendor/ruflin/elastica/lib/Elastica/Query/Common.php
@@ -0,0 +1,172 @@
+<?php
+namespace Elastica\Query;
+
+/**
+ * Class Common.
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-common-terms-query.html
+ */
+class Common extends AbstractQuery
+{
+ const OPERATOR_AND = 'and';
+ const OPERATOR_OR = 'or';
+
+ /**
+ * @var string
+ */
+ protected $_field;
+
+ /**
+ * @var array
+ */
+ protected $_queryParams = array();
+
+ /**
+ * @param string $field the field on which to query
+ * @param string $query the query string
+ * @param float $cutoffFrequency percentage in decimal form (.001 == 0.1%)
+ */
+ public function __construct($field, $query, $cutoffFrequency)
+ {
+ $this->setField($field);
+ $this->setQuery($query);
+ $this->setCutoffFrequency($cutoffFrequency);
+ }
+
+ /**
+ * Set the field on which to query.
+ *
+ * @param string $field the field on which to query
+ *
+ * @return $this
+ */
+ public function setField($field)
+ {
+ $this->_field = $field;
+
+ return $this;
+ }
+
+ /**
+ * Set the query string for this query.
+ *
+ * @param string $query
+ *
+ * @return $this
+ */
+ public function setQuery($query)
+ {
+ return $this->setQueryParam('query', $query);
+ }
+
+ /**
+ * Set the frequency below which terms will be put in the low frequency group.
+ *
+ * @param float $frequency percentage in decimal form (.001 == 0.1%)
+ *
+ * @return $this
+ */
+ public function setCutoffFrequency($frequency)
+ {
+ return $this->setQueryParam('cutoff_frequency', (float) $frequency);
+ }
+
+ /**
+ * Set the logic operator for low frequency terms.
+ *
+ * @param string $operator see OPERATOR_* class constants for options
+ *
+ * @return $this
+ */
+ public function setLowFrequencyOperator($operator)
+ {
+ return $this->setQueryParam('low_freq_operator', $operator);
+ }
+
+ /**
+ * Set the logic operator for high frequency terms.
+ *
+ * @param string $operator see OPERATOR_* class constants for options
+ *
+ * @return $this
+ */
+ public function setHighFrequencyOperator($operator)
+ {
+ return $this->setQueryParam('high_frequency_operator', $operator);
+ }
+
+ /**
+ * Set the minimum_should_match parameter.
+ *
+ * @param int|string $minimum minimum number of low frequency terms which must be present
+ *
+ * @return $this
+ *
+ * @link Possible values for minimum_should_match http://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-minimum-should-match.html
+ */
+ public function setMinimumShouldMatch($minimum)
+ {
+ return $this->setQueryParam('minimum_should_match', $minimum);
+ }
+
+ /**
+ * Set the boost for this query.
+ *
+ * @param float $boost
+ *
+ * @return $this
+ */
+ public function setBoost($boost)
+ {
+ return $this->setQueryParam('boost', (float) $boost);
+ }
+
+ /**
+ * Set the analyzer for this query.
+ *
+ * @param string $analyzer
+ *
+ * @return $this
+ */
+ public function setAnalyzer($analyzer)
+ {
+ return $this->setQueryParam('analyzer', $analyzer);
+ }
+
+ /**
+ * Enable / disable computation of score factor based on the fraction of all query terms contained in the document.
+ *
+ * @param bool $disable disable_coord is false by default
+ *
+ * @return $this
+ */
+ public function setDisableCoord($disable = true)
+ {
+ return $this->setQueryParam('disable_coord', (bool) $disable);
+ }
+
+ /**
+ * Set a parameter in the body of this query.
+ *
+ * @param string $key parameter key
+ * @param mixed $value parameter value
+ *
+ * @return $this
+ */
+ public function setQueryParam($key, $value)
+ {
+ $this->_queryParams[$key] = $value;
+
+ return $this;
+ }
+
+ /**
+ * @return array
+ */
+ public function toArray()
+ {
+ $this->setParam($this->_field, $this->_queryParams);
+
+ return parent::toArray();
+ }
+}
diff --git a/vendor/ruflin/elastica/lib/Elastica/Query/ConstantScore.php b/vendor/ruflin/elastica/lib/Elastica/Query/ConstantScore.php
new file mode 100644
index 00000000..3578606d
--- /dev/null
+++ b/vendor/ruflin/elastica/lib/Elastica/Query/ConstantScore.php
@@ -0,0 +1,70 @@
+<?php
+namespace Elastica\Query;
+
+use Elastica\Filter\AbstractFilter;
+
+/**
+ * Constant score query.
+ *
+ * @author Nicolas Ruflin <spam@ruflin.com>
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-constant-score-query.html
+ */
+class ConstantScore extends AbstractQuery
+{
+ /**
+ * Construct constant score query.
+ *
+ * @param null|\Elastica\Filter\AbstractFilter|array $filter
+ */
+ public function __construct($filter = null)
+ {
+ if (!is_null($filter)) {
+ $this->setFilter($filter);
+ }
+ }
+
+ /**
+ * Set filter.
+ *
+ * @param array|\Elastica\Filter\AbstractFilter $filter
+ *
+ * @return $this
+ */
+ public function setFilter($filter)
+ {
+ if ($filter instanceof AbstractFilter) {
+ $filter = $filter->toArray();
+ }
+
+ return $this->setParam('filter', $filter);
+ }
+
+ /**
+ * Set query.
+ *
+ * @param array|\Elastica\Query\AbstractQuery $query
+ *
+ * @return $this
+ */
+ public function setQuery($query)
+ {
+ if ($query instanceof AbstractQuery) {
+ $query = $query->toArray();
+ }
+
+ return $this->setParam('query', $query);
+ }
+
+ /**
+ * Set boost.
+ *
+ * @param float $boost
+ *
+ * @return $this
+ */
+ public function setBoost($boost)
+ {
+ return $this->setParam('boost', $boost);
+ }
+}
diff --git a/vendor/ruflin/elastica/lib/Elastica/Query/DisMax.php b/vendor/ruflin/elastica/lib/Elastica/Query/DisMax.php
new file mode 100644
index 00000000..b3c5f252
--- /dev/null
+++ b/vendor/ruflin/elastica/lib/Elastica/Query/DisMax.php
@@ -0,0 +1,62 @@
+<?php
+namespace Elastica\Query;
+
+use Elastica\Exception\InvalidException;
+
+/**
+ * DisMax query.
+ *
+ * @author Hung Tran <oohnoitz@gmail.com>
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-dis-max-query.html
+ */
+class DisMax extends AbstractQuery
+{
+ /**
+ * Adds a query to the current object.
+ *
+ * @param \Elastica\Query\AbstractQuery|array $args Query
+ *
+ * @throws \Elastica\Exception\InvalidException If not valid query
+ *
+ * @return $this
+ */
+ public function addQuery($args)
+ {
+ if ($args instanceof AbstractQuery) {
+ $args = $args->toArray();
+ }
+
+ if (!is_array($args)) {
+ throw new InvalidException('Invalid parameter. Has to be array or instance of Elastica\Query\AbstractQuery');
+ }
+
+ return $this->addParam('queries', $args);
+ }
+
+ /**
+ * Set boost.
+ *
+ * @param float $boost
+ *
+ * @return $this
+ */
+ public function setBoost($boost)
+ {
+ return $this->setParam('boost', $boost);
+ }
+
+ /**
+ * Sets tie breaker to multiplier value to balance the scores between lower and higher scoring fields.
+ *
+ * If not set, defaults to 0.0
+ *
+ * @param float $tieBreaker
+ *
+ * @return $this
+ */
+ public function setTieBreaker($tieBreaker = 0.0)
+ {
+ return $this->setParam('tie_breaker', $tieBreaker);
+ }
+}
diff --git a/vendor/ruflin/elastica/lib/Elastica/Query/Filtered.php b/vendor/ruflin/elastica/lib/Elastica/Query/Filtered.php
new file mode 100644
index 00000000..ac085037
--- /dev/null
+++ b/vendor/ruflin/elastica/lib/Elastica/Query/Filtered.php
@@ -0,0 +1,97 @@
+<?php
+namespace Elastica\Query;
+
+use Elastica\Exception\InvalidException;
+use Elastica\Filter\AbstractFilter;
+
+/**
+ * Filtered query. Needs a query and a filter.
+ *
+ * @author Nicolas Ruflin <spam@ruflin.com>
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-filtered-query.html
+ */
+class Filtered extends AbstractQuery
+{
+ /**
+ * Constructs a filtered query.
+ *
+ * @param \Elastica\Query\AbstractQuery $query OPTIONAL Query object
+ * @param \Elastica\Filter\AbstractFilter $filter OPTIONAL Filter object
+ */
+ public function __construct(AbstractQuery $query = null, AbstractFilter $filter = null)
+ {
+ $this->setQuery($query);
+ $this->setFilter($filter);
+ }
+
+ /**
+ * Sets a query.
+ *
+ * @param \Elastica\Query\AbstractQuery $query Query object
+ *
+ * @return $this
+ */
+ public function setQuery(AbstractQuery $query = null)
+ {
+ return $this->setParam('query', $query);
+ }
+
+ /**
+ * Sets the filter.
+ *
+ * @param \Elastica\Filter\AbstractFilter $filter Filter object
+ *
+ * @return $this
+ */
+ public function setFilter(AbstractFilter $filter = null)
+ {
+ return $this->setParam('filter', $filter);
+ }
+
+ /**
+ * Gets the filter.
+ *
+ * @return \Elastica\Filter\AbstractFilter
+ */
+ public function getFilter()
+ {
+ return $this->getParam('filter');
+ }
+
+ /**
+ * Gets the query.
+ *
+ * @return \Elastica\Query\AbstractQuery
+ */
+ public function getQuery()
+ {
+ return $this->getParam('query');
+ }
+
+ /**
+ * Converts query to array.
+ *
+ * @return array Query array
+ *
+ * @see \Elastica\Query\AbstractQuery::toArray()
+ */
+ public function toArray()
+ {
+ $filtered = array();
+
+ if ($this->hasParam('query') && $this->getParam('query') instanceof AbstractQuery) {
+ $filtered['query'] = $this->getParam('query')->toArray();
+ }
+
+ if ($this->hasParam('filter') && $this->getParam('filter') instanceof AbstractFilter) {
+ $filtered['filter'] = $this->getParam('filter')->toArray();
+ }
+
+ if (empty($filtered)) {
+ throw new InvalidException('A query and/or filter is required');
+ }
+
+ return array('filtered' => $filtered);
+ }
+}
diff --git a/vendor/ruflin/elastica/lib/Elastica/Query/FunctionScore.php b/vendor/ruflin/elastica/lib/Elastica/Query/FunctionScore.php
new file mode 100644
index 00000000..b11454fb
--- /dev/null
+++ b/vendor/ruflin/elastica/lib/Elastica/Query/FunctionScore.php
@@ -0,0 +1,260 @@
+<?php
+namespace Elastica\Query;
+
+use Elastica\Filter\AbstractFilter;
+use Elastica\Script;
+
+/**
+ * Class FunctionScore.
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-function-score-query.html
+ */
+class FunctionScore extends AbstractQuery
+{
+ const BOOST_MODE_MULTIPLY = 'multiply';
+ const BOOST_MODE_REPLACE = 'replace';
+ const BOOST_MODE_SUM = 'sum';
+ const BOOST_MODE_AVERAGE = 'average';
+ const BOOST_MODE_MAX = 'max';
+ const BOOST_MODE_MIN = 'min';
+
+ const SCORE_MODE_MULTIPLY = 'multiply';
+ const SCORE_MODE_SUM = 'sum';
+ const SCORE_MODE_AVERAGE = 'avg';
+ const SCORE_MODE_FIRST = 'first';
+ const SCORE_MODE_MAX = 'max';
+ const SCORE_MODE_MIN = 'min';
+
+ const DECAY_GAUSS = 'gauss';
+ const DECAY_EXPONENTIAL = 'exp';
+ const DECAY_LINEAR = 'linear';
+
+ protected $_functions = array();
+
+ /**
+ * Set the child query for this function_score query.
+ *
+ * @param AbstractQuery $query
+ *
+ * @return $this
+ */
+ public function setQuery(AbstractQuery $query)
+ {
+ return $this->setParam('query', $query->toArray());
+ }
+
+ /**
+ * @param AbstractFilter $filter
+ *
+ * @return $this
+ */
+ public function setFilter(AbstractFilter $filter)
+ {
+ return $this->setParam('filter', $filter->toArray());
+ }
+
+ /**
+ * Add a function to the function_score query.
+ *
+ * @param string $functionType valid values are DECAY_* constants and script_score
+ * @param array|float $functionParams the body of the function. See documentation for proper syntax.
+ * @param AbstractFilter $filter optional filter to apply to the function
+ * @param float $weight function weight
+ *
+ * @return $this
+ */
+ public function addFunction($functionType, $functionParams, AbstractFilter $filter = null, $weight = null)
+ {
+ $function = array(
+ $functionType => $functionParams,
+ );
+ if (!is_null($filter)) {
+ $function['filter'] = $filter->toArray();
+ }
+ if ($weight !== null) {
+ $function['weight'] = $weight;
+ }
+
+ $this->_functions[] = $function;
+
+ return $this;
+ }
+
+ /**
+ * Add a script_score function to the query.
+ *
+ * @param Script $script a Script object
+ * @param AbstractFilter $filter an optional filter to apply to the function
+ * @param float $weight the weight of the function
+ *
+ * @return $this
+ */
+ public function addScriptScoreFunction(Script $script, AbstractFilter $filter = null, $weight = null)
+ {
+ return $this->addFunction('script_score', $script->toArray(), $filter, $weight);
+ }
+
+ /**
+ * Add a decay function to the query.
+ *
+ * @param string $function see DECAY_* constants for valid options
+ * @param string $field the document field on which to perform the decay function
+ * @param string $origin the origin value for this decay function
+ * @param string $scale a scale to define the rate of decay for this function
+ * @param string $offset If defined, this function will only be computed for documents with a distance from the origin greater than this value
+ * @param float $decay optionally defines how documents are scored at the distance given by the $scale parameter
+ * @param float $scaleWeight optional factor by which to multiply the score at the value provided by the $scale parameter
+ * @param float $weight optional factor by which to multiply the score at the value provided by the $scale parameter
+ * @param AbstractFilter $filter a filter associated with this function
+ *
+ * @return $this
+ */
+ public function addDecayFunction(
+ $function,
+ $field,
+ $origin,
+ $scale,
+ $offset = null,
+ $decay = null,
+ $weight = null,
+ AbstractFilter $filter = null
+ ) {
+ $functionParams = array(
+ $field => array(
+ 'origin' => $origin,
+ 'scale' => $scale,
+ ),
+ );
+ if (!is_null($offset)) {
+ $functionParams[$field]['offset'] = $offset;
+ }
+ if (!is_null($decay)) {
+ $functionParams[$field]['decay'] = (float) $decay;
+ }
+
+ return $this->addFunction($function, $functionParams, $filter, $weight);
+ }
+
+ /**
+ * Add a boost_factor function to the query.
+ *
+ * @param float $boostFactor the boost factor value
+ * @param AbstractFilter $filter a filter associated with this function
+ *
+ * @deprecated
+ */
+ public function addBoostFactorFunction($boostFactor, AbstractFilter $filter = null)
+ {
+ $this->addWeightFunction($boostFactor, $filter);
+ }
+
+ /**
+ * @param float $weight the weight of the function
+ * @param AbstractFilter $filter a filter associated with this function
+ */
+ public function addWeightFunction($weight, AbstractFilter $filter = null)
+ {
+ $this->addFunction('weight', $weight, $filter);
+ }
+
+ /**
+ * Add a random_score function to the query.
+ *
+ * @param number $seed the seed value
+ * @param AbstractFilter $filter a filter associated with this function
+ * @param float $weight an optional boost value associated with this function
+ */
+ public function addRandomScoreFunction($seed, AbstractFilter $filter = null, $weight = null)
+ {
+ $this->addFunction('random_score', array('seed' => $seed), $filter, $weight);
+ }
+
+ /**
+ * Set an overall boost value for this query.
+ *
+ * @param float $boost
+ *
+ * @return $this
+ */
+ public function setBoost($boost)
+ {
+ return $this->setParam('boost', (float) $boost);
+ }
+
+ /**
+ * Restrict the combined boost of the function_score query and its child query.
+ *
+ * @param float $maxBoost
+ *
+ * @return $this
+ */
+ public function setMaxBoost($maxBoost)
+ {
+ return $this->setParam('max_boost', (float) $maxBoost);
+ }
+
+ /**
+ * The boost mode determines how the score of this query is combined with that of the child query.
+ *
+ * @param string $mode see BOOST_MODE_* constants for valid options. Default is multiply.
+ *
+ * @return $this
+ */
+ public function setBoostMode($mode)
+ {
+ return $this->setParam('boost_mode', $mode);
+ }
+
+ /**
+ * If set, this query will return results in random order.
+ *
+ * @param int $seed Set a seed value to return results in the same random order for consistent pagination.
+ *
+ * @return $this
+ */
+ public function setRandomScore($seed = null)
+ {
+ $seedParam = new \stdClass();
+ if (!is_null($seed)) {
+ $seedParam->seed = $seed;
+ }
+
+ return $this->setParam('random_score', $seedParam);
+ }
+
+ /**
+ * Set the score method.
+ *
+ * @param string $mode see SCORE_MODE_* constants for valid options. Default is multiply.
+ *
+ * @return $this
+ */
+ public function setScoreMode($mode)
+ {
+ return $this->setParam('score_mode', $mode);
+ }
+
+ /**
+ * Set min_score option.
+ *
+ * @param float $minScore
+ *
+ * @return $this
+ */
+ public function setMinScore($minScore)
+ {
+ return $this->setParam('min_score', (float) $minScore);
+ }
+
+ /**
+ * @return array
+ */
+ public function toArray()
+ {
+ if (sizeof($this->_functions)) {
+ $this->setParam('functions', $this->_functions);
+ }
+
+ return parent::toArray();
+ }
+}
diff --git a/vendor/ruflin/elastica/lib/Elastica/Query/Fuzzy.php b/vendor/ruflin/elastica/lib/Elastica/Query/Fuzzy.php
new file mode 100644
index 00000000..a3a46693
--- /dev/null
+++ b/vendor/ruflin/elastica/lib/Elastica/Query/Fuzzy.php
@@ -0,0 +1,87 @@
+<?php
+namespace Elastica\Query;
+
+use Elastica\Exception\InvalidException;
+
+/**
+ * Fuzzy query.
+ *
+ * @author Nicolas Ruflin <spam@ruflin.com>
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-fuzzy-query.html
+ */
+class Fuzzy extends AbstractQuery
+{
+ /**
+ * Construct a fuzzy query.
+ *
+ * @param string $fieldName Field name
+ * @param string $value String to search for
+ */
+ public function __construct($fieldName = null, $value = null)
+ {
+ if ($fieldName and $value) {
+ $this->setField($fieldName, $value);
+ }
+ }
+
+ /**
+ * Set field for fuzzy query.
+ *
+ * @param string $fieldName Field name
+ * @param string $value String to search for
+ *
+ * @return $this
+ */
+ public function setField($fieldName, $value)
+ {
+ if (!is_string($value) or !is_string($fieldName)) {
+ throw new InvalidException('The field and value arguments must be of type string.');
+ }
+ if (count($this->getParams()) > 0 and array_shift(array_keys($this->getParams())) != $fieldName) {
+ throw new InvalidException('Fuzzy query can only support a single field.');
+ }
+
+ return $this->setParam($fieldName, array('value' => $value));
+ }
+
+ /**
+ * Set optional parameters on the existing query.
+ *
+ * @param string $param option name
+ * @param mixed $value Value of the parameter
+ *
+ * @return $this
+ */
+ public function setFieldOption($param, $value)
+ {
+ //Retrieve the single existing field for alteration.
+ $params = $this->getParams();
+ if (count($params) < 1) {
+ throw new InvalidException('No field has been set');
+ }
+ $keyArray = array_keys($params);
+ $params[$keyArray[0]][$param] = $value;
+
+ return $this->setParam($keyArray[0], $params[$keyArray[0]]);
+ }
+
+ /**
+ * Deprecated method of setting a field.
+ *
+ * @deprecated
+ */
+ public function addField($fieldName, $args)
+ {
+ if (!array_key_exists('value', $args)) {
+ throw new InvalidException('Fuzzy query can only support a single field.');
+ }
+ $this->setField($fieldName, $args['value']);
+ unset($args['value']);
+ foreach ($args as $param => $value) {
+ $this->setFieldOption($param, $value);
+ }
+
+ return $this;
+ }
+}
diff --git a/vendor/ruflin/elastica/lib/Elastica/Query/FuzzyLikeThis.php b/vendor/ruflin/elastica/lib/Elastica/Query/FuzzyLikeThis.php
new file mode 100644
index 00000000..2de480a8
--- /dev/null
+++ b/vendor/ruflin/elastica/lib/Elastica/Query/FuzzyLikeThis.php
@@ -0,0 +1,217 @@
+<?php
+namespace Elastica\Query;
+
+/**
+ * Fuzzy Like This query.
+ *
+ * @author Raul Martinez, Jr <juneym@gmail.com>
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-flt-query.html
+ */
+class FuzzyLikeThis extends AbstractQuery
+{
+ /**
+ * Field names.
+ *
+ * @var array Field names
+ */
+ protected $_fields = array();
+
+ /**
+ * Like text.
+ *
+ * @var string Like text
+ */
+ protected $_likeText = '';
+
+ /**
+ * Ignore term frequency.
+ *
+ * @var bool ignore term frequency
+ */
+ protected $_ignoreTF = false;
+
+ /**
+ * Max query terms value.
+ *
+ * @var int Max query terms value
+ */
+ protected $_maxQueryTerms = 25;
+
+ /**
+ * minimum similarity.
+ *
+ * @var int minimum similarity
+ */
+ protected $_minSimilarity = 0.5;
+
+ /**
+ * Prefix Length.
+ *
+ * @var int Prefix Length
+ */
+ protected $_prefixLength = 0;
+
+ /**
+ * Boost.
+ *
+ * @var float Boost
+ */
+ protected $_boost = 1.0;
+
+ /**
+ * Analyzer.
+ *
+ * @var sting Analyzer
+ */
+ protected $_analyzer;
+
+ /**
+ * Adds field to flt query.
+ *
+ * @param array $fields Field names
+ *
+ * @return $this
+ */
+ public function addFields(array $fields)
+ {
+ $this->_fields = $fields;
+
+ return $this;
+ }
+
+ /**
+ * Set the "like_text" value.
+ *
+ * @param string $text
+ *
+ * @return $this
+ */
+ public function setLikeText($text)
+ {
+ $text = trim($text);
+ $this->_likeText = $text;
+
+ return $this;
+ }
+
+ /**
+ * Set the "ignore_tf" value (ignore term frequency).
+ *
+ * @param bool $ignoreTF
+ *
+ * @return $this
+ */
+ public function setIgnoreTF($ignoreTF)
+ {
+ $this->_ignoreTF = (bool) $ignoreTF;
+
+ return $this;
+ }
+
+ /**
+ * Set the minimum similarity.
+ *
+ * @param int $value
+ *
+ * @return $this
+ */
+ public function setMinSimilarity($value)
+ {
+ $value = (float) $value;
+ $this->_minSimilarity = $value;
+
+ return $this;
+ }
+
+ /**
+ * Set boost.
+ *
+ * @param float $value Boost value
+ *
+ * @return $this
+ */
+ public function setBoost($value)
+ {
+ $this->_boost = (float) $value;
+
+ return $this;
+ }
+
+ /**
+ * Set Prefix Length.
+ *
+ * @param int $value Prefix length
+ *
+ * @return $this
+ */
+ public function setPrefixLength($value)
+ {
+ $this->_prefixLength = (int) $value;
+
+ return $this;
+ }
+
+ /**
+ * Set max_query_terms.
+ *
+ * @param int $value Max query terms value
+ *
+ * @return $this
+ */
+ public function setMaxQueryTerms($value)
+ {
+ $this->_maxQueryTerms = (int) $value;
+
+ return $this;
+ }
+
+ /**
+ * Set analyzer.
+ *
+ * @param string $text Analyzer text
+ *
+ * @return $this
+ */
+ public function setAnalyzer($text)
+ {
+ $text = trim($text);
+ $this->_analyzer = $text;
+
+ return $this;
+ }
+
+ /**
+ * Converts fuzzy like this query to array.
+ *
+ * @return array Query array
+ *
+ * @see \Elastica\Query\AbstractQuery::toArray()
+ */
+ public function toArray()
+ {
+ if (!empty($this->_fields)) {
+ $args['fields'] = $this->_fields;
+ }
+
+ if (!empty($this->_boost)) {
+ $args['boost'] = $this->_boost;
+ }
+
+ if (!empty($this->_analyzer)) {
+ $args['analyzer'] = $this->_analyzer;
+ }
+
+ $args['min_similarity'] = ($this->_minSimilarity > 0) ? $this->_minSimilarity : 0;
+
+ $args['like_text'] = $this->_likeText;
+ $args['prefix_length'] = $this->_prefixLength;
+ $args['ignore_tf'] = $this->_ignoreTF;
+ $args['max_query_terms'] = $this->_maxQueryTerms;
+
+ $data = parent::toArray();
+ $args = array_merge($args, $data['fuzzy_like_this']);
+
+ return array('fuzzy_like_this' => $args);
+ }
+}
diff --git a/vendor/ruflin/elastica/lib/Elastica/Query/HasChild.php b/vendor/ruflin/elastica/lib/Elastica/Query/HasChild.php
new file mode 100644
index 00000000..190fa592
--- /dev/null
+++ b/vendor/ruflin/elastica/lib/Elastica/Query/HasChild.php
@@ -0,0 +1,65 @@
+<?php
+namespace Elastica\Query;
+
+use Elastica\Query as BaseQuery;
+
+/**
+ * Returns parent documents having child docs matching the query.
+ *
+ * @author Fabian Vogler <fabian@equivalence.ch>
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-has-child-query.html
+ */
+class HasChild extends AbstractQuery
+{
+ /**
+ * Construct HasChild Query.
+ *
+ * @param string|\Elastica\Query|\Elastica\Query\AbstractQuery $query
+ * @param string $type Parent document type
+ */
+ public function __construct($query, $type = null)
+ {
+ $this->setType($type);
+ $this->setQuery($query);
+ }
+
+ /**
+ * Sets query object.
+ *
+ * @param string|\Elastica\Query|\Elastica\Query\AbstractQuery $query
+ *
+ * @return $this
+ */
+ public function setQuery($query)
+ {
+ $query = BaseQuery::create($query);
+ $data = $query->toArray();
+
+ return $this->setParam('query', $data['query']);
+ }
+
+ /**
+ * Set type of the parent document.
+ *
+ * @param string $type Parent document type
+ *
+ * @return $this
+ */
+ public function setType($type)
+ {
+ return $this->setParam('type', $type);
+ }
+
+ /**
+ * Sets the scope.
+ *
+ * @param string $scope Scope
+ *
+ * @return $this
+ */
+ public function setScope($scope)
+ {
+ return $this->setParam('_scope', $scope);
+ }
+}
diff --git a/vendor/ruflin/elastica/lib/Elastica/Query/HasParent.php b/vendor/ruflin/elastica/lib/Elastica/Query/HasParent.php
new file mode 100644
index 00000000..03aae13b
--- /dev/null
+++ b/vendor/ruflin/elastica/lib/Elastica/Query/HasParent.php
@@ -0,0 +1,63 @@
+<?php
+namespace Elastica\Query;
+
+use Elastica\Query as BaseQuery;
+
+/**
+ * Returns child documents having parent docs matching the query.
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-has-parent-query.html
+ */
+class HasParent extends AbstractQuery
+{
+ /**
+ * Construct HasChild Query.
+ *
+ * @param string|\Elastica\Query|\Elastica\Query\AbstractQuery $query
+ * @param string $type Parent document type
+ */
+ public function __construct($query, $type)
+ {
+ $this->setQuery($query);
+ $this->setType($type);
+ }
+
+ /**
+ * Sets query object.
+ *
+ * @param string|\Elastica\Query|\Elastica\Query\AbstractQuery $query
+ *
+ * @return $this
+ */
+ public function setQuery($query)
+ {
+ $query = BaseQuery::create($query);
+ $data = $query->toArray();
+
+ return $this->setParam('query', $data['query']);
+ }
+
+ /**
+ * Set type of the parent document.
+ *
+ * @param string $type Parent document type
+ *
+ * @return $this
+ */
+ public function setType($type)
+ {
+ return $this->setParam('type', $type);
+ }
+
+ /**
+ * Sets the scope.
+ *
+ * @param string $scope Scope
+ *
+ * @return $this
+ */
+ public function setScope($scope)
+ {
+ return $this->setParam('_scope', $scope);
+ }
+}
diff --git a/vendor/ruflin/elastica/lib/Elastica/Query/Ids.php b/vendor/ruflin/elastica/lib/Elastica/Query/Ids.php
new file mode 100644
index 00000000..5d76efcf
--- /dev/null
+++ b/vendor/ruflin/elastica/lib/Elastica/Query/Ids.php
@@ -0,0 +1,121 @@
+<?php
+namespace Elastica\Query;
+
+use Elastica\Type;
+
+/**
+ * Ids Query.
+ *
+ * @author Lee Parker
+ * @author Nicolas Ruflin <spam@ruflin.com>
+ * @author Tim Rupp
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-ids-query.html
+ */
+class Ids extends AbstractQuery
+{
+ /**
+ * Params.
+ *
+ * @var array Params
+ */
+ protected $_params = array();
+
+ /**
+ * Creates filter object.
+ *
+ * @param string|\Elastica\Type $type Type to filter on
+ * @param array $ids List of ids
+ */
+ public function __construct($type = null, array $ids = array())
+ {
+ $this->setType($type);
+ $this->setIds($ids);
+ }
+
+ /**
+ * Adds one more filter to the and filter.
+ *
+ * @param string $id Adds id to filter
+ *
+ * @return $this
+ */
+ public function addId($id)
+ {
+ $this->_params['values'][] = $id;
+
+ return $this;
+ }
+
+ /**
+ * Adds one more type to query.
+ *
+ * @param string|\Elastica\Type $type Type name or object
+ *
+ * @return $this
+ */
+ public function addType($type)
+ {
+ if ($type instanceof Type) {
+ $type = $type->getName();
+ } elseif (empty($type) && !is_numeric($type)) {
+ // A type can be 0, but cannot be empty
+ return $this;
+ }
+
+ $this->_params['type'][] = $type;
+
+ return $this;
+ }
+
+ /**
+ * Set type.
+ *
+ * @param string|\Elastica\Type $type Type name or object
+ *
+ * @return $this
+ */
+ public function setType($type)
+ {
+ if ($type instanceof Type) {
+ $type = $type->getName();
+ } elseif (empty($type) && !is_numeric($type)) {
+ // A type can be 0, but cannot be empty
+ return $this;
+ }
+
+ $this->_params['type'] = $type;
+
+ return $this;
+ }
+
+ /**
+ * Sets the ids to filter.
+ *
+ * @param array|string $ids List of ids
+ *
+ * @return $this
+ */
+ public function setIds($ids)
+ {
+ if (is_array($ids)) {
+ $this->_params['values'] = $ids;
+ } else {
+ $this->_params['values'] = array($ids);
+ }
+
+ return $this;
+ }
+
+ /**
+ * Converts filter to array.
+ *
+ * @see \Elastica\Query\AbstractQuery::toArray()
+ *
+ * @return array Query array
+ */
+ public function toArray()
+ {
+ return array('ids' => $this->_params);
+ }
+}
diff --git a/vendor/ruflin/elastica/lib/Elastica/Query/Image.php b/vendor/ruflin/elastica/lib/Elastica/Query/Image.php
new file mode 100644
index 00000000..bf7d028b
--- /dev/null
+++ b/vendor/ruflin/elastica/lib/Elastica/Query/Image.php
@@ -0,0 +1,187 @@
+<?php
+namespace Elastica\Query;
+
+/**
+ * Image query.
+ *
+ * @author Jacques Moati <jacques@moati.net>
+ *
+ * @link https://github.com/kzwang/elasticsearch-image
+ *
+ * To use this feature you have to call the following command in the
+ * elasticsearch directory:
+ * <code>
+ * ./bin/plugin --url https://github.com/SibaTokyo/elasticsearch-image/releases/download/1.4.0/elasticsearch-image-1.4.0.zip --install image
+ * </code>
+ * This installs the image plugin. More infos
+ * can be found here: {@link https://github.com/SibaTokyo/elasticsearch-image}
+ */
+class Image extends AbstractQuery
+{
+ public function __construct(array $image = array())
+ {
+ $this->setParams($image);
+ }
+
+ /**
+ * Sets a param for the given field.
+ *
+ * @param string $field
+ * @param string $key
+ * @param string $value
+ *
+ * @return $this
+ */
+ public function setFieldParam($field, $key, $value)
+ {
+ if (!isset($this->_params[$field])) {
+ $this->_params[$field] = array();
+ }
+
+ $this->_params[$field][$key] = $value;
+
+ return $this;
+ }
+
+ /**
+ * Set field boost value.
+ *
+ * If not set, defaults to 1.0.
+ *
+ * @param string $field
+ * @param float $boost
+ *
+ * @return $this
+ */
+ public function setFieldBoost($field, $boost = 1.0)
+ {
+ return $this->setFieldParam($field, 'boost', (float) $boost);
+ }
+
+ /**
+ * Set field feature value.
+ *
+ * If not set, defaults CEDD.
+ *
+ * @param string $field
+ * @param string $feature
+ *
+ * @return $this
+ */
+ public function setFieldFeature($field, $feature = 'CEDD')
+ {
+ return $this->setFieldParam($field, 'feature', $feature);
+ }
+
+ /**
+ * Set field hash value.
+ *
+ * If not set, defaults BIT_SAMPLING.
+ *
+ * @param string $field
+ * @param string $hash
+ *
+ * @return $this
+ */
+ public function setFieldHash($field, $hash = 'BIT_SAMPLING')
+ {
+ return $this->setFieldParam($field, 'hash', $hash);
+ }
+
+ /**
+ * Set field image value.
+ *
+ * @param string $field
+ * @param string $path File will be base64_encode
+ *
+ * @throws \Exception
+ *
+ * @return $this
+ */
+ public function setFieldImage($field, $path)
+ {
+ if (!file_exists($path) || !is_readable($path)) {
+ throw new \Exception(sprintf("File %s can't be open", $path));
+ }
+
+ return $this->setFieldParam($field, 'image', base64_encode(file_get_contents($path)));
+ }
+
+ /**
+ * Set field index value.
+ *
+ * @param string $field
+ * @param string $index
+ *
+ * @return $this
+ */
+ public function setFieldIndex($field, $index)
+ {
+ return $this->setFieldParam($field, 'index', $index);
+ }
+
+ /**
+ * Set field type value.
+ *
+ * @param string $field
+ * @param string $type
+ *
+ * @return $this
+ */
+ public function setFieldType($field, $type)
+ {
+ return $this->setFieldParam($field, 'type', $type);
+ }
+
+ /**
+ * Set field id value.
+ *
+ * @param string $field
+ * @param string $id
+ *
+ * @return $this
+ */
+ public function setFieldId($field, $id)
+ {
+ return $this->setFieldParam($field, 'id', $id);
+ }
+
+ /**
+ * Set field path value.
+ *
+ * @param string $field
+ * @param string $path
+ *
+ * @return $this
+ */
+ public function setFieldPath($field, $path)
+ {
+ return $this->setFieldParam($field, 'path', $path);
+ }
+
+ /**
+ * Define quickly a reference image already in your elasticsearch database.
+ *
+ * If not set, path will be the same as $field.
+ *
+ * @param string $field
+ * @param string $index
+ * @param string $type
+ * @param string $id
+ * @param string $path
+ *
+ * @return $this
+ */
+ public function setImageByReference($field, $index, $type, $id, $path = null)
+ {
+ if (null === $path) {
+ $path = $field;
+ }
+
+ $this->setFieldIndex($field, $index);
+ $this->setFieldType($field, $type);
+ $this->setFieldId($field, $id);
+
+ return $this->setFieldPath($field, $path);
+ }
+}
diff --git a/vendor/ruflin/elastica/lib/Elastica/Query/Match.php b/vendor/ruflin/elastica/lib/Elastica/Query/Match.php
new file mode 100644
index 00000000..abb40970
--- /dev/null
+++ b/vendor/ruflin/elastica/lib/Elastica/Query/Match.php
@@ -0,0 +1,222 @@
+<?php
+namespace Elastica\Query;
+
+/**
+ * Match query.
+ *
+ * @author F21
+ * @author WONG Wing Lun <luiges90@gmail.com>
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-match-query.html
+ */
+class Match extends AbstractQuery
+{
+ const ZERO_TERM_NONE = 'none';
+ const ZERO_TERM_ALL = 'all';
+
+ /**
+ * @param string $field
+ * @param mixed $values
+ */
+ public function __construct($field = null, $values = null)
+ {
+ if ($field !== null && $values !== null) {
+ $this->setParam($field, $values);
+ }
+ }
+
+ /**
+ * Sets a param for the message array.
+ *
+ * @param string $field
+ * @param mixed $values
+ *
+ * @return $this
+ */
+ public function setField($field, $values)
+ {
+ return $this->setParam($field, $values);
+ }
+
+ /**
+ * Sets a param for the given field.
+ *
+ * @param string $field
+ * @param string $key
+ * @param string $value
+ *
+ * @return $this
+ */
+ public function setFieldParam($field, $key, $value)
+ {
+ if (!isset($this->_params[$field])) {
+ $this->_params[$field] = array();
+ }
+
+ $this->_params[$field][$key] = $value;
+
+ return $this;
+ }
+
+ /**
+ * Sets the query string.
+ *
+ * @param string $field
+ * @param string $query
+ *
+ * @return $this
+ */
+ public function setFieldQuery($field, $query)
+ {
+ return $this->setFieldParam($field, 'query', $query);
+ }
+
+ /**
+ * Set field type.
+ *
+ * @param string $field
+ * @param string $type
+ *
+ * @return $this
+ */
+ public function setFieldType($field, $type)
+ {
+ return $this->setFieldParam($field, 'type', $type);
+ }
+
+ /**
+ * Set field operator.
+ *
+ * @param string $field
+ * @param string $operator
+ *
+ * @return $this
+ */
+ public function setFieldOperator($field, $operator)
+ {
+ return $this->setFieldParam($field, 'operator', $operator);
+ }
+
+ /**
+ * Set field analyzer.
+ *
+ * @param string $field
+ * @param string $analyzer
+ *
+ * @return $this
+ */
+ public function setFieldAnalyzer($field, $analyzer)
+ {
+ return $this->setFieldParam($field, 'analyzer', $analyzer);
+ }
+
+ /**
+ * Set field boost value.
+ *
+ * If not set, defaults to 1.0.
+ *
+ * @param string $field
+ * @param float $boost
+ *
+ * @return $this
+ */
+ public function setFieldBoost($field, $boost = 1.0)
+ {
+ return $this->setFieldParam($field, 'boost', (float) $boost);
+ }
+
+ /**
+ * Set field minimum should match.
+ *
+ * @param string $field
+ * @param int|string $minimumShouldMatch
+ *
+ * @return $this
+ *
+ * @link Possible values for minimum_should_match http://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-minimum-should-match.html
+ */
+ public function setFieldMinimumShouldMatch($field, $minimumShouldMatch)
+ {
+ return $this->setFieldParam($field, 'minimum_should_match', $minimumShouldMatch);
+ }
+
+ /**
+ * Set field fuzziness.
+ *
+ * @param string $field
+ * @param mixed $fuzziness
+ *
+ * @return $this
+ */
+ public function setFieldFuzziness($field, $fuzziness)
+ {
+ return $this->setFieldParam($field, 'fuzziness', $fuzziness);
+ }
+
+ /**
+ * Set field fuzzy rewrite.
+ *
+ * @param string $field
+ * @param string $fuzzyRewrite
+ *
+ * @return $this
+ */
+ public function setFieldFuzzyRewrite($field, $fuzzyRewrite)
+ {
+ return $this->setFieldParam($field, 'fuzzy_rewrite', $fuzzyRewrite);
+ }
+
+ /**
+ * Set field prefix length.
+ *
+ * @param string $field
+ * @param int $prefixLength
+ *
+ * @return $this
+ */
+ public function setFieldPrefixLength($field, $prefixLength)
+ {
+ return $this->setFieldParam($field, 'prefix_length', (int) $prefixLength);
+ }
+
+ /**
+ * Set field max expansions.
+ *
+ * @param string $field
+ * @param int $maxExpansions
+ *
+ * @return $this
+ */
+ public function setFieldMaxExpansions($field, $maxExpansions)
+ {
+ return $this->setFieldParam($field, 'max_expansions', (int) $maxExpansions);
+ }
+
+ /**
+ * Set zero terms query.
+ *
+ * If not set, default to 'none'
+ *
+ * @param string $field
+ * @param string $zeroTermQuery
+ *
+ * @return $this
+ */
+ public function setFieldZeroTermsQuery($field, $zeroTermQuery = 'none')
+ {
+ return $this->setFieldParam($field, 'zero_terms_query', $zeroTermQuery);
+ }
+
+ /**
+ * Set cutoff frequency.
+ *
+ * @param string $field
+ * @param float $cutoffFrequency
+ *
+ * @return $this
+ */
+ public function setFieldCutoffFrequency($field, $cutoffFrequency)
+ {
+ return $this->setFieldParam($field, 'cutoff_frequency', $cutoffFrequency);
+ }
+}
diff --git a/vendor/ruflin/elastica/lib/Elastica/Query/MatchAll.php b/vendor/ruflin/elastica/lib/Elastica/Query/MatchAll.php
new file mode 100644
index 00000000..d01aaee8
--- /dev/null
+++ b/vendor/ruflin/elastica/lib/Elastica/Query/MatchAll.php
@@ -0,0 +1,20 @@
+<?php
+namespace Elastica\Query;
+
+/**
+ * Match all query. Returns all results.
+ *
+ * @author Nicolas Ruflin <spam@ruflin.com>
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-match-all-query.html
+ */
+class MatchAll extends AbstractQuery
+{
+ /**
+ * Creates match all query.
+ */
+ public function __construct()
+ {
+ $this->_params = new \stdClass();
+ }
+}
diff --git a/vendor/ruflin/elastica/lib/Elastica/Query/MatchPhrase.php b/vendor/ruflin/elastica/lib/Elastica/Query/MatchPhrase.php
new file mode 100644
index 00000000..54302f90
--- /dev/null
+++ b/vendor/ruflin/elastica/lib/Elastica/Query/MatchPhrase.php
@@ -0,0 +1,13 @@
+<?php
+namespace Elastica\Query;
+
+/**
+ * Match Phrase query.
+ *
+ * @author Jacques Moati <jacques@moati.net>
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-match-query.html#_phrase
+ */
+class MatchPhrase extends Match
+{
+}
diff --git a/vendor/ruflin/elastica/lib/Elastica/Query/MatchPhrasePrefix.php b/vendor/ruflin/elastica/lib/Elastica/Query/MatchPhrasePrefix.php
new file mode 100644
index 00000000..61764bda
--- /dev/null
+++ b/vendor/ruflin/elastica/lib/Elastica/Query/MatchPhrasePrefix.php
@@ -0,0 +1,13 @@
+<?php
+namespace Elastica\Query;
+
+/**
+ * Match Phrase Prefix query.
+ *
+ * @author Jacques Moati <jacques@moati.net>
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-match-query.html#_match_phrase_prefix
+ */
+class MatchPhrasePrefix extends Match
+{
+}
diff --git a/vendor/ruflin/elastica/lib/Elastica/Query/MoreLikeThis.php b/vendor/ruflin/elastica/lib/Elastica/Query/MoreLikeThis.php
new file mode 100644
index 00000000..cd375db5
--- /dev/null
+++ b/vendor/ruflin/elastica/lib/Elastica/Query/MoreLikeThis.php
@@ -0,0 +1,198 @@
+<?php
+namespace Elastica\Query;
+
+/**
+ * More Like This query.
+ *
+ * @author Raul Martinez, Jr <juneym@gmail.com>
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-mlt-query.html
+ */
+class MoreLikeThis extends AbstractQuery
+{
+ /**
+ * Set fields to which to restrict the mlt query.
+ *
+ * @param array $fields Field names
+ *
+ * @return \Elastica\Query\MoreLikeThis Current object
+ */
+ public function setFields(array $fields)
+ {
+ return $this->setParam('fields', $fields);
+ }
+
+ /**
+ * Set document ids for the mlt query.
+ *
+ * @param array $ids Document ids
+ *
+ * @return \Elastica\Query\MoreLikeThis Current object
+ */
+ public function setIds(array $ids)
+ {
+ return $this->setParam('ids', $ids);
+ }
+
+ /**
+ * Set the "like_text" value.
+ *
+ * @param string $likeText
+ *
+ * @return $this
+ */
+ public function setLikeText($likeText)
+ {
+ $likeText = trim($likeText);
+
+ return $this->setParam('like_text', $likeText);
+ }
+
+ /**
+ * Set boost.
+ *
+ * @param float $boost Boost value
+ *
+ * @return $this
+ */
+ public function setBoost($boost)
+ {
+ return $this->setParam('boost', (float) $boost);
+ }
+
+ /**
+ * Set max_query_terms.
+ *
+ * @param int $maxQueryTerms Max query terms value
+ *
+ * @return $this
+ */
+ public function setMaxQueryTerms($maxQueryTerms)
+ {
+ return $this->setParam('max_query_terms', (int) $maxQueryTerms);
+ }
+
+ /**
+ * Set percent terms to match.
+ *
+ * @param float $percentTermsToMatch Percentage
+ *
+ * @return $this
+ *
+ * @deprecated Option "percent_terms_to_match" deprecated as of ES 1.5. Use "minimum_should_match" instead.
+ */
+ public function setPercentTermsToMatch($percentTermsToMatch)
+ {
+ return $this->setParam('percent_terms_to_match', (float) $percentTermsToMatch);
+ }
+
+ /**
+ * Set min term frequency.
+ *
+ * @param int $minTermFreq
+ *
+ * @return $this
+ */
+ public function setMinTermFrequency($minTermFreq)
+ {
+ return $this->setParam('min_term_freq', (int) $minTermFreq);
+ }
+
+ /**
+ * set min document frequency.
+ *
+ * @param int $minDocFreq
+ *
+ * @return $this
+ */
+ public function setMinDocFrequency($minDocFreq)
+ {
+ return $this->setParam('min_doc_freq', (int) $minDocFreq);
+ }
+
+ /**
+ * set max document frequency.
+ *
+ * @param int $maxDocFreq
+ *
+ * @return $this
+ */
+ public function setMaxDocFrequency($maxDocFreq)
+ {
+ return $this->setParam('max_doc_freq', (int) $maxDocFreq);
+ }
+
+ /**
+ * Set min word length.
+ *
+ * @param int $minWordLength
+ *
+ * @return $this
+ */
+ public function setMinWordLength($minWordLength)
+ {
+ return $this->setParam('min_word_length', (int) $minWordLength);
+ }
+
+ /**
+ * Set max word length.
+ *
+ * @param int $maxWordLength
+ *
+ * @return $this
+ */
+ public function setMaxWordLength($maxWordLength)
+ {
+ return $this->setParam('max_word_length', (int) $maxWordLength);
+ }
+
+ /**
+ * Set boost terms.
+ *
+ * @param bool $boostTerms
+ *
+ * @return $this
+ */
+ public function setBoostTerms($boostTerms)
+ {
+ return $this->setParam('boost_terms', (bool) $boostTerms);
+ }
+
+ /**
+ * Set analyzer.
+ *
+ * @param string $analyzer
+ *
+ * @return $this
+ */
+ public function setAnalyzer($analyzer)
+ {
+ $analyzer = trim($analyzer);
+
+ return $this->setParam('analyzer', $analyzer);
+ }
+
+ /**
+ * Set stop words.
+ *
+ * @param array $stopWords
+ *
+ * @return $this
+ */
+ public function setStopWords(array $stopWords)
+ {
+ return $this->setParam('stop_words', $stopWords);
+ }
+
+ /**
+ * Set minimum_should_match option.
+ *
+ * @param int|string $minimumShouldMatch
+ *
+ * @return $this
+ */
+ public function setMinimumShouldMatch($minimumShouldMatch)
+ {
+ return $this->setParam('minimum_should_match', $minimumShouldMatch);
+ }
+}
diff --git a/vendor/ruflin/elastica/lib/Elastica/Query/MultiMatch.php b/vendor/ruflin/elastica/lib/Elastica/Query/MultiMatch.php
new file mode 100644
index 00000000..0771f370
--- /dev/null
+++ b/vendor/ruflin/elastica/lib/Elastica/Query/MultiMatch.php
@@ -0,0 +1,191 @@
+<?php
+namespace Elastica\Query;
+
+/**
+ * Multi Match.
+ *
+ * @author Rodolfo Adhenawer Campagnoli Moraes <adhenawer@gmail.com>
+ * @author Wong Wing Lun <luiges90@gmail.com>
+ * @author Tristan Maindron <tmaindron@gmail.com>
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-multi-match-query.html
+ */
+class MultiMatch extends AbstractQuery
+{
+ const TYPE_BEST_FIELDS = 'best_fields';
+ const TYPE_MOST_FIELDS = 'most_fields';
+ const TYPE_CROSS_FIELDS = 'cross_fields';
+ const TYPE_PHRASE = 'phrase';
+ const TYPE_PHRASE_PREFIX = 'phrase_prefix';
+
+ const OPERATOR_OR = 'or';
+ const OPERATOR_AND = 'and';
+
+ const ZERO_TERM_NONE = 'none';
+ const ZERO_TERM_ALL = 'all';
+
+ /**
+ * Sets the query.
+ *
+ * @param string $query Query
+ *
+ * @return $this
+ */
+ public function setQuery($query = '')
+ {
+ return $this->setParam('query', $query);
+ }
+
+ /**
+ * Sets Fields to be used in the query.
+ *
+ * @param array $fields Fields
+ *
+ * @return $this
+ */
+ public function setFields($fields = array())
+ {
+ return $this->setParam('fields', $fields);
+ }
+
+ /**
+ * Sets use dis max indicating to either create a dis_max query or a bool query.
+ *
+ * If not set, defaults to true.
+ *
+ * @param bool $useDisMax
+ *
+ * @return $this
+ */
+ public function setUseDisMax($useDisMax = true)
+ {
+ return $this->setParam('use_dis_max', $useDisMax);
+ }
+
+ /**
+ * Sets tie breaker to multiplier value to balance the scores between lower and higher scoring fields.
+ *
+ * If not set, defaults to 0.0.
+ *
+ * @param float $tieBreaker
+ *
+ * @return $this
+ */
+ public function setTieBreaker($tieBreaker = 0.0)
+ {
+ return $this->setParam('tie_breaker', $tieBreaker);
+ }
+
+ /**
+ * Sets operator for Match Query.
+ *
+ * If not set, defaults to 'or'
+ *
+ * @param string $operator
+ *
+ * @return $this
+ */
+ public function setOperator($operator = 'or')
+ {
+ return $this->setParam('operator', $operator);
+ }
+
+ /**
+ * Set field minimum should match for Match Query.
+ *
+ * @param mixed $minimumShouldMatch
+ *
+ * @return $this
+ */
+ public function setMinimumShouldMatch($minimumShouldMatch)
+ {
+ return $this->setParam('minimum_should_match', $minimumShouldMatch);
+ }
+
+ /**
+ * Set zero terms query for Match Query.
+ *
+ * If not set, default to 'none'
+ *
+ * @param string $zeroTermQuery
+ *
+ * @return $this
+ */
+ public function setZeroTermsQuery($zeroTermQuery = 'none')
+ {
+ return $this->setParam('zero_terms_query', $zeroTermQuery);
+ }
+
+ /**
+ * Set cutoff frequency for Match Query.
+ *
+ * @param float $cutoffFrequency
+ *
+ * @return $this
+ */
+ public function setCutoffFrequency($cutoffFrequency)
+ {
+ return $this->setParam('cutoff_frequency', $cutoffFrequency);
+ }
+
+ /**
+ * Set type.
+ *
+ * @param string $field
+ * @param string $type
+ *
+ * @return $this
+ */
+ public function setType($type)
+ {
+ return $this->setParam('type', $type);
+ }
+
+ /**
+ * Set fuzziness.
+ *
+ * @param float $fuzziness
+ *
+ * @return $this
+ */
+ public function setFuzziness($fuzziness)
+ {
+ return $this->setParam('fuzziness', (float) $fuzziness);
+ }
+
+ /**
+ * Set prefix length.
+ *
+ * @param int $prefixLength
+ *
+ * @return $this
+ */
+ public function setPrefixLength($prefixLength)
+ {
+ return $this->setParam('prefix_length', (int) $prefixLength);
+ }
+
+ /**
+ * Set max expansions.
+ *
+ * @param int $maxExpansions
+ *
+ * @return $this
+ */
+ public function setMaxExpansions($maxExpansions)
+ {
+ return $this->setParam('max_expansions', (int) $maxExpansions);
+ }
+
+ /**
+ * Set analyzer.
+ *
+ * @param string $analyzer
+ *
+ * @return $this
+ */
+ public function setAnalyzer($analyzer)
+ {
+ return $this->setParam('analyzer', $analyzer);
+ }
+}
diff --git a/vendor/ruflin/elastica/lib/Elastica/Query/Nested.php b/vendor/ruflin/elastica/lib/Elastica/Query/Nested.php
new file mode 100644
index 00000000..b072cfc8
--- /dev/null
+++ b/vendor/ruflin/elastica/lib/Elastica/Query/Nested.php
@@ -0,0 +1,48 @@
+<?php
+namespace Elastica\Query;
+
+/**
+ * Nested query.
+ *
+ * @author Nicolas Ruflin <spam@ruflin.com>
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-nested-query.html
+ */
+class Nested extends AbstractQuery
+{
+ /**
+ * Adds field to mlt query.
+ *
+ * @param string $path Nested object path
+ *
+ * @return $this
+ */
+ public function setPath($path)
+ {
+ return $this->setParam('path', $path);
+ }
+
+ /**
+ * Sets nested query.
+ *
+ * @param \Elastica\Query\AbstractQuery $query
+ *
+ * @return $this
+ */
+ public function setQuery(AbstractQuery $query)
+ {
+ return $this->setParam('query', $query->toArray());
+ }
+
+ /**
+ * Set score method.
+ *
+ * @param string $scoreMode Options: avg, total, max and none.
+ *
+ * @return $this
+ */
+ public function setScoreMode($scoreMode)
+ {
+ return $this->setParam('score_mode', $scoreMode);
+ }
+}
diff --git a/vendor/ruflin/elastica/lib/Elastica/Query/Prefix.php b/vendor/ruflin/elastica/lib/Elastica/Query/Prefix.php
new file mode 100644
index 00000000..c2b903ea
--- /dev/null
+++ b/vendor/ruflin/elastica/lib/Elastica/Query/Prefix.php
@@ -0,0 +1,47 @@
+<?php
+namespace Elastica\Query;
+
+/**
+ * Prefix query.
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-prefix-query.html
+ */
+class Prefix extends AbstractQuery
+{
+ /**
+ * Constructs the Prefix query object.
+ *
+ * @param array $prefix OPTIONAL Calls setRawPrefix with the given $prefix array
+ */
+ public function __construct(array $prefix = array())
+ {
+ $this->setRawPrefix($prefix);
+ }
+
+ /**
+ * setRawPrefix can be used instead of setPrefix if some more special
+ * values for a prefix have to be set.
+ *
+ * @param array $prefix Prefix array
+ *
+ * @return $this
+ */
+ public function setRawPrefix(array $prefix)
+ {
+ return $this->setParams($prefix);
+ }
+
+ /**
+ * Adds a prefix to the prefix query.
+ *
+ * @param string $key Key to query
+ * @param string|array $value Values(s) for the query. Boost can be set with array
+ * @param float $boost OPTIONAL Boost value (default = 1.0)
+ *
+ * @return $this
+ */
+ public function setPrefix($key, $value, $boost = 1.0)
+ {
+ return $this->setRawPrefix(array($key => array('value' => $value, 'boost' => $boost)));
+ }
+}
diff --git a/vendor/ruflin/elastica/lib/Elastica/Query/QueryString.php b/vendor/ruflin/elastica/lib/Elastica/Query/QueryString.php
new file mode 100644
index 00000000..89ea77cd
--- /dev/null
+++ b/vendor/ruflin/elastica/lib/Elastica/Query/QueryString.php
@@ -0,0 +1,282 @@
+<?php
+namespace Elastica\Query;
+
+use Elastica\Exception\InvalidException;
+
+/**
+ * QueryString query.
+ *
+ * @author Nicolas Ruflin <spam@ruflin.com>, Jasper van Wanrooy <jasper@vanwanrooy.net>
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-query-string-query.html
+ */
+class QueryString extends AbstractQuery
+{
+ /**
+ * Query string.
+ *
+ * @var string Query string
+ */
+ protected $_queryString = '';
+
+ /**
+ * Creates query string object. Calls setQuery with argument.
+ *
+ * @param string $queryString OPTIONAL Query string for object
+ */
+ public function __construct($queryString = '')
+ {
+ $this->setQuery($queryString);
+ }
+
+ /**
+ * Sets a new query string for the object.
+ *
+ * @param string $query Query string
+ *
+ * @throws \Elastica\Exception\InvalidException If given parameter is not a string
+ *
+ * @return $this
+ */
+ public function setQuery($query = '')
+ {
+ if (!is_string($query)) {
+ throw new InvalidException('Parameter has to be a string');
+ }
+
+ return $this->setParam('query', $query);
+ }
+
+ /**
+ * Sets the default field.
+ *
+ * If no field is set, _all is chosen
+ *
+ * @param string $field Field
+ *
+ * @return $this
+ */
+ public function setDefaultField($field)
+ {
+ return $this->setParam('default_field', $field);
+ }
+
+ /**
+ * Sets the default operator AND or OR.
+ *
+ * If no operator is set, OR is chosen
+ *
+ * @param string $operator Operator
+ *
+ * @return $this
+ */
+ public function setDefaultOperator($operator)
+ {
+ return $this->setParam('default_operator', $operator);
+ }
+
+ /**
+ * Sets the analyzer to analyze the query with.
+ *
+ * @param string $analyzer Analyser to use
+ *
+ * @return $this
+ */
+ public function setAnalyzer($analyzer)
+ {
+ return $this->setParam('analyzer', $analyzer);
+ }
+
+ /**
+ * Sets the parameter to allow * and ? as first characters.
+ *
+ * If not set, defaults to true.
+ *
+ * @param bool $allow
+ *
+ * @return $this
+ */
+ public function setAllowLeadingWildcard($allow = true)
+ {
+ return $this->setParam('allow_leading_wildcard', (bool) $allow);
+ }
+
+ /**
+ * Sets the parameter to enable the position increments in result queries.
+ *
+ * If not set, defaults to true.
+ *
+ * @param bool $enabled
+ *
+ * @return $this
+ */
+ public function setEnablePositionIncrements($enabled = true)
+ {
+ return $this->setParam('enable_position_increments', (bool) $enabled);
+ }
+
+ /**
+ * Sets the fuzzy prefix length parameter.
+ *
+ * If not set, defaults to 0.
+ *
+ * @param int $length
+ *
+ * @return $this
+ */
+ public function setFuzzyPrefixLength($length = 0)
+ {
+ return $this->setParam('fuzzy_prefix_length', (int) $length);
+ }
+
+ /**
+ * Sets the fuzzy minimal similarity parameter.
+ *
+ * If not set, defaults to 0.5
+ *
+ * @param float $minSim
+ *
+ * @return $this
+ */
+ public function setFuzzyMinSim($minSim = 0.5)
+ {
+ return $this->setParam('fuzzy_min_sim', (float) $minSim);
+ }
+
+ /**
+ * Sets the phrase slop.
+ *
+ * If zero, exact phrases are required.
+ * If not set, defaults to zero.
+ *
+ * @param int $phraseSlop
+ *
+ * @return $this
+ */
+ public function setPhraseSlop($phraseSlop = 0)
+ {
+ return $this->setParam('phrase_slop', (int) $phraseSlop);
+ }
+
+ /**
+ * Sets the boost value of the query.
+ *
+ * If not set, defaults to 1.0.
+ *
+ * @param float $boost
+ *
+ * @return $this
+ */
+ public function setBoost($boost = 1.0)
+ {
+ return $this->setParam('boost', (float) $boost);
+ }
+
+ /**
+ * Allows analyzing of wildcard terms.
+ *
+ * If not set, defaults to true
+ *
+ * @param bool $analyze
+ *
+ * @return $this
+ */
+ public function setAnalyzeWildcard($analyze = true)
+ {
+ return $this->setParam('analyze_wildcard', (bool) $analyze);
+ }
+
+ /**
+ * Sets the param to automatically generate phrase queries.
+ *
+ * If not set, defaults to true.
+ *
+ * @param bool $autoGenerate
+ *
+ * @return $this
+ */
+ public function setAutoGeneratePhraseQueries($autoGenerate = true)
+ {
+ return $this->setParam('auto_generate_phrase_queries', (bool) $autoGenerate);
+ }
+
+ /**
+ * Sets the fields. If no fields are set, _all is chosen.
+ *
+ * @param array $fields Fields
+ *
+ * @throws \Elastica\Exception\InvalidException If given parameter is not an array
+ *
+ * @return $this
+ */
+ public function setFields(array $fields)
+ {
+ if (!is_array($fields)) {
+ throw new InvalidException('Parameter has to be an array');
+ }
+
+ return $this->setParam('fields', $fields);
+ }
+
+ /**
+ * Whether to use bool or dis_max queries to internally combine results for multi field search.
+ *
+ * @param bool $value Determines whether to use
+ *
+ * @return $this
+ */
+ public function setUseDisMax($value = true)
+ {
+ return $this->setParam('use_dis_max', (bool) $value);
+ }
+
+ /**
+ * When using dis_max, the disjunction max tie breaker.
+ *
+ * If not set, defaults to 0.
+ *
+ * @param int $tieBreaker
+ *
+ * @return $this
+ */
+ public function setTieBreaker($tieBreaker = 0)
+ {
+ return $this->setParam('tie_breaker', (float) $tieBreaker);
+ }
+
+ /**
+ * Set a re-write condition. See https://github.com/elasticsearch/elasticsearch/issues/1186 for additional information.
+ *
+ * @param string $rewrite
+ *
+ * @return $this
+ */
+ public function setRewrite($rewrite = '')
+ {
+ return $this->setParam('rewrite', $rewrite);
+ }
+
+ /**
+ * Set timezone option.
+ *
+ * @param string $timezone
+ *
+ * @return $this
+ */
+ public function setTimezone($timezone)
+ {
+ return $this->setParam('time_zone', $timezone);
+ }
+
+ /**
+ * Converts query to array.
+ *
+ * @see \Elastica\Query\AbstractQuery::toArray()
+ *
+ * @return array Query array
+ */
+ public function toArray()
+ {
+ return array('query_string' => array_merge(array('query' => $this->_queryString), $this->getParams()));
+ }
+}
diff --git a/vendor/ruflin/elastica/lib/Elastica/Query/Range.php b/vendor/ruflin/elastica/lib/Elastica/Query/Range.php
new file mode 100644
index 00000000..b2f9175a
--- /dev/null
+++ b/vendor/ruflin/elastica/lib/Elastica/Query/Range.php
@@ -0,0 +1,38 @@
+<?php
+namespace Elastica\Query;
+
+/**
+ * Range query.
+ *
+ * @author Nicolas Ruflin <spam@ruflin.com>
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-range-query.html
+ */
+class Range extends AbstractQuery
+{
+ /**
+ * Constructor.
+ *
+ * @param string $fieldName Field name
+ * @param array $args Field arguments
+ */
+ public function __construct($fieldName = null, array $args = array())
+ {
+ if ($fieldName) {
+ $this->addField($fieldName, $args);
+ }
+ }
+
+ /**
+ * Adds a range field to the query.
+ *
+ * @param string $fieldName Field name
+ * @param array $args Field arguments
+ *
+ * @return $this
+ */
+ public function addField($fieldName, array $args)
+ {
+ return $this->setParam($fieldName, $args);
+ }
+}
diff --git a/vendor/ruflin/elastica/lib/Elastica/Query/Regexp.php b/vendor/ruflin/elastica/lib/Elastica/Query/Regexp.php
new file mode 100644
index 00000000..22a48560
--- /dev/null
+++ b/vendor/ruflin/elastica/lib/Elastica/Query/Regexp.php
@@ -0,0 +1,40 @@
+<?php
+namespace Elastica\Query;
+
+/**
+ * Regexp query.
+ *
+ * @author Aurélien Le Grand <gnitg@yahoo.fr>
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-regexp-query.html
+ */
+class Regexp extends AbstractQuery
+{
+ /**
+ * Construct regexp query.
+ *
+ * @param string $key OPTIONAL Regexp key
+ * @param string $value OPTIONAL Regexp value
+ * @param float $boost OPTIONAL Boost value (default = 1)
+ */
+ public function __construct($key = '', $value = null, $boost = 1.0)
+ {
+ if (!empty($key)) {
+ $this->setValue($key, $value, $boost);
+ }
+ }
+
+ /**
+ * Sets the query expression for a key with its boost value.
+ *
+ * @param string $key
+ * @param string $value
+ * @param float $boost
+ *
+ * @return $this
+ */
+ public function setValue($key, $value, $boost = 1.0)
+ {
+ return $this->setParam($key, array('value' => $value, 'boost' => $boost));
+ }
+}
diff --git a/vendor/ruflin/elastica/lib/Elastica/Query/Simple.php b/vendor/ruflin/elastica/lib/Elastica/Query/Simple.php
new file mode 100644
index 00000000..6ba9310d
--- /dev/null
+++ b/vendor/ruflin/elastica/lib/Elastica/Query/Simple.php
@@ -0,0 +1,54 @@
+<?php
+namespace Elastica\Query;
+
+/**
+ * Simple query
+ * Pure php array query. Can be used to create any not existing type of query.
+ *
+ * @author Nicolas Ruflin <spam@ruflin.com>
+ */
+class Simple extends AbstractQuery
+{
+ /**
+ * Query.
+ *
+ * @var array Query
+ */
+ protected $_query = array();
+
+ /**
+ * Constructs a query based on an array.
+ *
+ * @param array $query Query array
+ */
+ public function __construct(array $query)
+ {
+ $this->setQuery($query);
+ }
+
+ /**
+ * Sets new query array.
+ *
+ * @param array $query Query array
+ *
+ * @return $this
+ */
+ public function setQuery(array $query)
+ {
+ $this->_query = $query;
+
+ return $this;
+ }
+
+ /**
+ * Converts query to array.
+ *
+ * @return array Query array
+ *
+ * @see \Elastica\Query\AbstractQuery::toArray()
+ */
+ public function toArray()
+ {
+ return $this->_query;
+ }
+}
diff --git a/vendor/ruflin/elastica/lib/Elastica/Query/SimpleQueryString.php b/vendor/ruflin/elastica/lib/Elastica/Query/SimpleQueryString.php
new file mode 100644
index 00000000..c2302d44
--- /dev/null
+++ b/vendor/ruflin/elastica/lib/Elastica/Query/SimpleQueryString.php
@@ -0,0 +1,83 @@
+<?php
+namespace Elastica\Query;
+
+/**
+ * Class SimpleQueryString.
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-simple-query-string-query.html
+ */
+class SimpleQueryString extends AbstractQuery
+{
+ const OPERATOR_AND = 'and';
+ const OPERATOR_OR = 'or';
+
+ /**
+ * @param string $query
+ * @param array $fields
+ */
+ public function __construct($query, array $fields = array())
+ {
+ $this->setQuery($query);
+ if (sizeof($fields)) {
+ $this->setFields($fields);
+ }
+ }
+
+ /**
+ * Set the querystring for this query.
+ *
+ * @param string $query see ES documentation for querystring syntax
+ *
+ * @return $this
+ */
+ public function setQuery($query)
+ {
+ return $this->setParam('query', $query);
+ }
+
+ /**
+ * @param string[] $fields the fields on which to perform this query. Defaults to index.query.default_field.
+ *
+ * @return $this
+ */
+ public function setFields(array $fields)
+ {
+ return $this->setParam('fields', $fields);
+ }
+
+ /**
+ * Set the default operator to use if no explicit operator is defined in the query string.
+ *
+ * @param string $operator see OPERATOR_* constants for options
+ *
+ * @return $this
+ */
+ public function setDefaultOperator($operator)
+ {
+ return $this->setParam('default_operator', $operator);
+ }
+
+ /**
+ * Set the analyzer used to analyze each term of the query.
+ *
+ * @param string $analyzer
+ *
+ * @return $this
+ */
+ public function setAnalyzer($analyzer)
+ {
+ return $this->setParam('analyzer', $analyzer);
+ }
+
+ /**
+ * Set minimum_should_match option.
+ *
+ * @param int|string $minimumShouldMatch
+ *
+ * @return $this
+ */
+ public function setMinimumShouldMatch($minimumShouldMatch)
+ {
+ return $this->setParam('minimum_should_match', $minimumShouldMatch);
+ }
+}
diff --git a/vendor/ruflin/elastica/lib/Elastica/Query/Term.php b/vendor/ruflin/elastica/lib/Elastica/Query/Term.php
new file mode 100644
index 00000000..8cfe0a88
--- /dev/null
+++ b/vendor/ruflin/elastica/lib/Elastica/Query/Term.php
@@ -0,0 +1,49 @@
+<?php
+namespace Elastica\Query;
+
+/**
+ * Term query.
+ *
+ * @author Nicolas Ruflin <spam@ruflin.com>
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-term-query.html
+ */
+class Term extends AbstractQuery
+{
+ /**
+ * Constructs the Term query object.
+ *
+ * @param array $term OPTIONAL Calls setTerm with the given $term array
+ */
+ public function __construct(array $term = array())
+ {
+ $this->setRawTerm($term);
+ }
+
+ /**
+ * Set term can be used instead of addTerm if some more special
+ * values for a term have to be set.
+ *
+ * @param array $term Term array
+ *
+ * @return $this
+ */
+ public function setRawTerm(array $term)
+ {
+ return $this->setParams($term);
+ }
+
+ /**
+ * Adds a term to the term query.
+ *
+ * @param string $key Key to query
+ * @param string|array $value Values(s) for the query. Boost can be set with array
+ * @param float $boost OPTIONAL Boost value (default = 1.0)
+ *
+ * @return $this
+ */
+ public function setTerm($key, $value, $boost = 1.0)
+ {
+ return $this->setRawTerm(array($key => array('value' => $value, 'boost' => $boost)));
+ }
+}
diff --git a/vendor/ruflin/elastica/lib/Elastica/Query/Terms.php b/vendor/ruflin/elastica/lib/Elastica/Query/Terms.php
new file mode 100644
index 00000000..54f26461
--- /dev/null
+++ b/vendor/ruflin/elastica/lib/Elastica/Query/Terms.php
@@ -0,0 +1,107 @@
+<?php
+namespace Elastica\Query;
+
+use Elastica\Exception\InvalidException;
+
+/**
+ * Terms query.
+ *
+ * @author Nicolas Ruflin <spam@ruflin.com>
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-terms-query.html
+ */
+class Terms extends AbstractQuery
+{
+ /**
+ * Terms.
+ *
+ * @var array Terms
+ */
+ protected $_terms = array();
+
+ /**
+ * Params.
+ *
+ * @var array Params
+ */
+ protected $_params = array();
+
+ /**
+ * Terms key.
+ *
+ * @var string Terms key
+ */
+ protected $_key = '';
+
+ /**
+ * Construct terms query.
+ *
+ * @param string $key OPTIONAL Terms key
+ * @param array $terms OPTIONAL Terms list
+ */
+ public function __construct($key = '', array $terms = array())
+ {
+ $this->setTerms($key, $terms);
+ }
+
+ /**
+ * Sets key and terms for the query.
+ *
+ * @param string $key Terms key
+ * @param array $terms Terms for the query.
+ *
+ * @return $this
+ */
+ public function setTerms($key, array $terms)
+ {
+ $this->_key = $key;
+ $this->_terms = array_values($terms);
+
+ return $this;
+ }
+
+ /**
+ * Adds a single term to the list.
+ *
+ * @param string $term Term
+ *
+ * @return $this
+ */
+ public function addTerm($term)
+ {
+ $this->_terms[] = $term;
+
+ return $this;
+ }
+
+ /**
+ * Sets the minimum matching values.
+ *
+ * @param int $minimum Minimum value
+ *
+ * @return $this
+ */
+ public function setMinimumMatch($minimum)
+ {
+ return $this->setParam('minimum_match', (int) $minimum);
+ }
+
+ /**
+ * Converts the terms object to an array.
+ *
+ * @see \Elastica\Query\AbstractQuery::toArray()
+ *
+ * @throws \Elastica\Exception\InvalidException If term key is empty
+ *
+ * @return array Query array
+ */
+ public function toArray()
+ {
+ if (empty($this->_key)) {
+ throw new InvalidException('Terms key has to be set');
+ }
+ $this->setParam($this->_key, $this->_terms);
+
+ return parent::toArray();
+ }
+}
diff --git a/vendor/ruflin/elastica/lib/Elastica/Query/TopChildren.php b/vendor/ruflin/elastica/lib/Elastica/Query/TopChildren.php
new file mode 100644
index 00000000..6f15c79d
--- /dev/null
+++ b/vendor/ruflin/elastica/lib/Elastica/Query/TopChildren.php
@@ -0,0 +1,53 @@
+<?php
+namespace Elastica\Query;
+
+use Elastica\Query as BaseQuery;
+
+/**
+ * Runs the child query with an estimated hits size, and out of the hit docs, aggregates it into parent docs.
+ *
+ * @author Wu Yang <darkyoung@gmail.com>
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-top-children-query.html
+ */
+class TopChildren extends AbstractQuery
+{
+ /**
+ * Construct topChildren query.
+ *
+ * @param string|\Elastica\Query|\Elastica\Query\AbstractQuery $query
+ * @param string $type Parent document type
+ */
+ public function __construct($query, $type = null)
+ {
+ $this->setQuery($query);
+ $this->setType($type);
+ }
+
+ /**
+ * Sets query object.
+ *
+ * @param string|\Elastica\Query|\Elastica\Query\AbstractQuery $query
+ *
+ * @return $this
+ */
+ public function setQuery($query)
+ {
+ $query = BaseQuery::create($query);
+ $data = $query->toArray();
+
+ return $this->setParam('query', $data['query']);
+ }
+
+ /**
+ * Set type of the parent document.
+ *
+ * @param string $type Parent document type
+ *
+ * @return $this
+ */
+ public function setType($type)
+ {
+ return $this->setParam('type', $type);
+ }
+}
diff --git a/vendor/ruflin/elastica/lib/Elastica/Query/Wildcard.php b/vendor/ruflin/elastica/lib/Elastica/Query/Wildcard.php
new file mode 100644
index 00000000..bfa5e751
--- /dev/null
+++ b/vendor/ruflin/elastica/lib/Elastica/Query/Wildcard.php
@@ -0,0 +1,40 @@
+<?php
+namespace Elastica\Query;
+
+/**
+ * Wildcard query.
+ *
+ * @author Nicolas Ruflin <spam@ruflin.com>
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-wildcard-query.html
+ */
+class Wildcard extends AbstractQuery
+{
+ /**
+ * Construct wildcard query.
+ *
+ * @param string $key OPTIONAL Wildcard key
+ * @param string $value OPTIONAL Wildcard value
+ * @param float $boost OPTIONAL Boost value (default = 1)
+ */
+ public function __construct($key = '', $value = null, $boost = 1.0)
+ {
+ if (!empty($key)) {
+ $this->setValue($key, $value, $boost);
+ }
+ }
+
+ /**
+ * Sets the query expression for a key with its boost value.
+ *
+ * @param string $key
+ * @param string $value
+ * @param float $boost
+ *
+ * @return $this
+ */
+ public function setValue($key, $value, $boost = 1.0)
+ {
+ return $this->setParam($key, array('value' => $value, 'boost' => $boost));
+ }
+}
diff --git a/vendor/ruflin/elastica/lib/Elastica/QueryBuilder.php b/vendor/ruflin/elastica/lib/Elastica/QueryBuilder.php
new file mode 100644
index 00000000..477c4525
--- /dev/null
+++ b/vendor/ruflin/elastica/lib/Elastica/QueryBuilder.php
@@ -0,0 +1,114 @@
+<?php
+namespace Elastica;
+
+use Elastica\Exception\QueryBuilderException;
+use Elastica\QueryBuilder\DSL;
+use Elastica\QueryBuilder\Facade;
+use Elastica\QueryBuilder\Version;
+use Elastica\QueryBuilder\Version\Version150;
+
+/**
+ * Query Builder.
+ *
+ * @author Manuel Andreo Garcia <andreo.garcia@googlemail.com>
+ */
+class QueryBuilder
+{
+ /**
+ * @var Version
+ */
+ private $_version;
+
+ /**
+ * @var Facade[]
+ */
+ private $_facades = array();
+
+ /**
+ * Constructor.
+ *
+ * @param Version $version
+ */
+ public function __construct(Version $version = null)
+ {
+ $this->_version = $version ?: new Version150();
+
+ $this->addDSL(new DSL\Query());
+ $this->addDSL(new DSL\Filter());
+ $this->addDSL(new DSL\Aggregation());
+ $this->addDSL(new DSL\Suggest());
+ }
+
+ /**
+ * Returns Facade for custom DSL object.
+ *
+ * @param $dsl
+ * @param array $arguments
+ *
+ * @throws QueryBuilderException
+ *
+ * @return Facade
+ */
+ public function __call($dsl, array $arguments)
+ {
+ if (false === isset($this->_facades[$dsl])) {
+ throw new QueryBuilderException('DSL "'.$dsl.'" not supported');
+ }
+
+ return $this->_facades[$dsl];
+ }
+
+ /**
+ * Adds a new DSL object.
+ *
+ * @param DSL $dsl
+ */
+ public function addDSL(DSL $dsl)
+ {
+ $this->_facades[$dsl->getType()] = new Facade($dsl, $this->_version);
+ }
+
+ /*
+ * convenience methods
+ */
+
+ /**
+ * Query DSL.
+ *
+ * @return DSL\Query
+ */
+ public function query()
+ {
+ return $this->_facades[DSL::TYPE_QUERY];
+ }
+
+ /**
+ * Filter DSL.
+ *
+ * @return DSL\Filter
+ */
+ public function filter()
+ {
+ return $this->_facades[DSL::TYPE_FILTER];
+ }
+
+ /**
+ * Aggregation DSL.
+ *
+ * @return DSL\Aggregation
+ */
+ public function aggregation()
+ {
+ return $this->_facades[DSL::TYPE_AGGREGATION];
+ }
+
+ /**
+ * Suggest DSL.
+ *
+ * @return DSL\Suggest
+ */
+ public function suggest()
+ {
+ return $this->_facades[DSL::TYPE_SUGGEST];
+ }
+}
diff --git a/vendor/ruflin/elastica/lib/Elastica/QueryBuilder/DSL.php b/vendor/ruflin/elastica/lib/Elastica/QueryBuilder/DSL.php
new file mode 100644
index 00000000..976de5f4
--- /dev/null
+++ b/vendor/ruflin/elastica/lib/Elastica/QueryBuilder/DSL.php
@@ -0,0 +1,22 @@
+<?php
+namespace Elastica\QueryBuilder;
+
+/**
+ * DSL Interface.
+ *
+ * @author Manuel Andreo Garcia <andreo.garcia@googlemail.com>
+ */
+interface DSL
+{
+ const TYPE_QUERY = 'query';
+ const TYPE_FILTER = 'filter';
+ const TYPE_AGGREGATION = 'aggregation';
+ const TYPE_SUGGEST = 'suggest';
+
+ /**
+ * must return type for QueryBuilder usage.
+ *
+ * @return string
+ */
+ public function getType();
+}
diff --git a/vendor/ruflin/elastica/lib/Elastica/QueryBuilder/DSL/Aggregation.php b/vendor/ruflin/elastica/lib/Elastica/QueryBuilder/DSL/Aggregation.php
new file mode 100644
index 00000000..8393b8aa
--- /dev/null
+++ b/vendor/ruflin/elastica/lib/Elastica/QueryBuilder/DSL/Aggregation.php
@@ -0,0 +1,470 @@
+<?php
+namespace Elastica\QueryBuilder\DSL;
+
+use Elastica\Aggregation\Avg;
+use Elastica\Aggregation\Cardinality;
+use Elastica\Aggregation\DateHistogram;
+use Elastica\Aggregation\DateRange;
+use Elastica\Aggregation\ExtendedStats;
+use Elastica\Aggregation\Filter as FilterAggregation;
+use Elastica\Aggregation\Filters;
+use Elastica\Aggregation\GeoDistance;
+use Elastica\Aggregation\GeohashGrid;
+use Elastica\Aggregation\GlobalAggregation;
+use Elastica\Aggregation\Histogram;
+use Elastica\Aggregation\IpRange;
+use Elastica\Aggregation\Max;
+use Elastica\Aggregation\Min;
+use Elastica\Aggregation\Missing;
+use Elastica\Aggregation\Nested;
+use Elastica\Aggregation\Percentiles;
+use Elastica\Aggregation\Range;
+use Elastica\Aggregation\ReverseNested;
+use Elastica\Aggregation\ScriptedMetric;
+use Elastica\Aggregation\SignificantTerms;
+use Elastica\Aggregation\Stats;
+use Elastica\Aggregation\Sum;
+use Elastica\Aggregation\Terms;
+use Elastica\Aggregation\TopHits;
+use Elastica\Aggregation\ValueCount;
+use Elastica\Exception\NotImplementedException;
+use Elastica\Filter\AbstractFilter;
+use Elastica\QueryBuilder\DSL;
+
+/**
+ * elasticsearch aggregation DSL.
+ *
+ * @author Manuel Andreo Garcia <andreo.garcia@googlemail.com>
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/search-aggregations.html
+ */
+class Aggregation implements DSL
+{
+ /**
+ * must return type for QueryBuilder usage.
+ *
+ * @return string
+ */
+ public function getType()
+ {
+ return DSL::TYPE_AGGREGATION;
+ }
+
+ /**
+ * min aggregation.
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/search-aggregations-metrics-min-aggregation.html
+ *
+ * @param string $name
+ *
+ * @return Min
+ */
+ public function min($name)
+ {
+ return new Min($name);
+ }
+
+ /**
+ * max aggregation.
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/search-aggregations-metrics-max-aggregation.html
+ *
+ * @param string $name
+ *
+ * @return Max
+ */
+ public function max($name)
+ {
+ return new Max($name);
+ }
+
+ /**
+ * sum aggregation.
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/search-aggregations-metrics-sum-aggregation.html
+ *
+ * @param string $name
+ *
+ * @return Sum
+ */
+ public function sum($name)
+ {
+ return new Sum($name);
+ }
+
+ /**
+ * avg aggregation.
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/search-aggregations-metrics-avg-aggregation.html
+ *
+ * @param string $name
+ *
+ * @return Avg
+ */
+ public function avg($name)
+ {
+ return new Avg($name);
+ }
+
+ /**
+ * stats aggregation.
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/search-aggregations-metrics-stats-aggregation.html
+ *
+ * @param string $name
+ *
+ * @return Stats
+ */
+ public function stats($name)
+ {
+ return new Stats($name);
+ }
+
+ /**
+ * extended stats aggregation.
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/search-aggregations-metrics-extendedstats-aggregation.html
+ *
+ * @param string $name
+ *
+ * @return ExtendedStats
+ */
+ public function extended_stats($name)
+ {
+ return new ExtendedStats($name);
+ }
+
+ /**
+ * value count aggregation.
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/search-aggregations-metrics-valuecount-aggregation.html
+ *
+ * @param string $name
+ * @param string $field
+ *
+ * @return ValueCount
+ */
+ public function value_count($name, $field)
+ {
+ return new ValueCount($name, $field);
+ }
+
+ /**
+ * percentiles aggregation.
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/search-aggregations-metrics-percentile-aggregation.html
+ *
+ * @param string $name the name of this aggregation
+ * @param string $field the field on which to perform this aggregation
+ *
+ * @return Percentiles
+ */
+ public function percentiles($name, $field = null)
+ {
+ return new Percentiles($name, $field);
+ }
+
+ /**
+ * percentile ranks aggregation.
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/search-aggregations-metrics-percentile-rank-aggregation.html
+ *
+ * @param string $name
+ */
+ public function percentile_ranks($name)
+ {
+ throw new NotImplementedException();
+ }
+
+ /**
+ * cardinality aggregation.
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/search-aggregations-metrics-cardinality-aggregation.html
+ *
+ * @param string $name
+ *
+ * @return Cardinality
+ */
+ public function cardinality($name)
+ {
+ return new Cardinality($name);
+ }
+
+ /**
+ * geo bounds aggregation.
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/search-aggregations-metrics-geobounds-aggregation.html
+ *
+ * @param string $name
+ */
+ public function geo_bounds($name)
+ {
+ throw new NotImplementedException();
+ }
+
+ /**
+ * top hits aggregation.
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/search-aggregations-metrics-top-hits-aggregation.html
+ *
+ * @param string $name
+ *
+ * @return TopHits
+ */
+ public function top_hits($name)
+ {
+ return new TopHits($name);
+ }
+
+ /**
+ * scripted metric aggregation.
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/search-aggregations-metrics-scripted-metric-aggregation.html
+ *
+ * @param string $name
+ * @param string|null $initScript
+ * @param string|null $mapScript
+ * @param string|null $combineScript
+ * @param string|null $reduceScript
+ *
+ * @return ScriptedMetric
+ */
+ public function scripted_metric($name, $initScript = null, $mapScript = null, $combineScript = null, $reduceScript = null)
+ {
+ return new ScriptedMetric($name, $initScript, $mapScript, $combineScript, $reduceScript);
+ }
+
+ /**
+ * global aggregation.
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/search-aggregations-bucket-global-aggregation.html
+ *
+ * @param string $name
+ *
+ * @return GlobalAggregation
+ */
+ public function global_agg($name)
+ {
+ return new GlobalAggregation($name);
+ }
+
+ /**
+ * filter aggregation.
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/search-aggregations-bucket-filter-aggregation.html
+ *
+ * @param string $name
+ * @param AbstractFilter $filter
+ *
+ * @return FilterAggregation
+ */
+ public function filter($name, AbstractFilter $filter = null)
+ {
+ return new FilterAggregation($name, $filter);
+ }
+
+ /**
+ * filters aggregation.
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/search-aggregations-bucket-filters-aggregation.html
+ *
+ * @param string $name
+ *
+ * @return Filters
+ */
+ public function filters($name)
+ {
+ return new Filters($name);
+ }
+
+ /**
+ * missing aggregation.
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/search-aggregations-bucket-missing-aggregation.html
+ *
+ * @param string $name
+ * @param string $field
+ *
+ * @return Missing
+ */
+ public function missing($name, $field)
+ {
+ return new Missing($name, $field);
+ }
+
+ /**
+ * nested aggregation.
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/search-aggregations-bucket-nested-aggregation.html
+ *
+ * @param string $name
+ * @param string $path the nested path for this aggregation
+ *
+ * @return Nested
+ */
+ public function nested($name, $path)
+ {
+ return new Nested($name, $path);
+ }
+
+ /**
+ * reverse nested aggregation.
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/search-aggregations-bucket-reverse-nested-aggregation.html
+ *
+ * @param string $name The name of this aggregation
+ * @param string $path Optional path to the nested object for this aggregation. Defaults to the root of the main document.
+ *
+ * @return ReverseNested
+ */
+ public function reverse_nested($name, $path = null)
+ {
+ return new ReverseNested($name);
+ }
+
+ /**
+ * children aggregation.
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/search-aggregations-bucket-children-aggregation.html
+ *
+ * @param string $name
+ */
+ public function children($name)
+ {
+ throw new NotImplementedException();
+ }
+
+ /**
+ * terms aggregation.
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/search-aggregations-bucket-terms-aggregation.html
+ *
+ * @param string $name
+ *
+ * @return Terms
+ */
+ public function terms($name)
+ {
+ return new Terms($name);
+ }
+
+ /**
+ * significant terms aggregation.
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/search-aggregations-bucket-significantterms-aggregation.html
+ *
+ * @param string $name
+ *
+ * @return SignificantTerms
+ */
+ public function significant_terms($name)
+ {
+ return new SignificantTerms($name);
+ }
+
+ /**
+ * range aggregation.
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/search-aggregations-bucket-range-aggregation.html
+ *
+ * @param string $name
+ *
+ * @return Range
+ */
+ public function range($name)
+ {
+ return new Range($name);
+ }
+
+ /**
+ * date range aggregation.
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/search-aggregations-bucket-daterange-aggregation.html
+ *
+ * @param string $name
+ *
+ * @return DateRange
+ */
+ public function date_range($name)
+ {
+ return new DateRange($name);
+ }
+
+ /**
+ * ipv4 range aggregation.
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/search-aggregations-bucket-iprange-aggregation.html
+ *
+ * @param string $name
+ * @param string $field
+ *
+ * @return IpRange
+ */
+ public function ipv4_range($name, $field)
+ {
+ return new IpRange($name, $field);
+ }
+
+ /**
+ * histogram aggregation.
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/search-aggregations-bucket-histogram-aggregation.html
+ *
+ * @param string $name the name of this aggregation
+ * @param string $field the name of the field on which to perform the aggregation
+ * @param int $interval the interval by which documents will be bucketed
+ *
+ * @return Histogram
+ */
+ public function histogram($name, $field, $interval)
+ {
+ return new Histogram($name, $field, $interval);
+ }
+
+ /**
+ * date histogram aggregation.
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/search-aggregations-bucket-datehistogram-aggregation.html
+ *
+ * @param string $name the name of this aggregation
+ * @param string $field the name of the field on which to perform the aggregation
+ * @param int $interval the interval by which documents will be bucketed
+ *
+ * @return DateHistogram
+ */
+ public function date_histogram($name, $field, $interval)
+ {
+ return new DateHistogram($name, $field, $interval);
+ }
+
+ /**
+ * geo distance aggregation.
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/search-aggregations-bucket-geodistance-aggregation.html
+ *
+ * @param string $name the name if this aggregation
+ * @param string $field the field on which to perform this aggregation
+ * @param string|array $origin the point from which distances will be calculated
+ *
+ * @return GeoDistance
+ */
+ public function geo_distance($name, $field, $origin)
+ {
+ return new GeoDistance($name, $field, $origin);
+ }
+
+ /**
+ * geohash grid aggregation.
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/search-aggregations-bucket-geohashgrid-aggregation.html
+ *
+ * @param string $name the name of this aggregation
+ * @param string $field the field on which to perform this aggregation
+ *
+ * @return GeohashGrid
+ */
+ public function geohash_grid($name, $field)
+ {
+ return new GeohashGrid($name, $field);
+ }
+}
diff --git a/vendor/ruflin/elastica/lib/Elastica/QueryBuilder/DSL/Filter.php b/vendor/ruflin/elastica/lib/Elastica/QueryBuilder/DSL/Filter.php
new file mode 100644
index 00000000..1c41239f
--- /dev/null
+++ b/vendor/ruflin/elastica/lib/Elastica/QueryBuilder/DSL/Filter.php
@@ -0,0 +1,480 @@
+<?php
+namespace Elastica\QueryBuilder\DSL;
+
+use Elastica\Filter\AbstractFilter;
+use Elastica\Filter\BoolAnd;
+use Elastica\Filter\BoolFilter;
+use Elastica\Filter\BoolNot;
+use Elastica\Filter\BoolOr;
+use Elastica\Filter\Exists;
+use Elastica\Filter\GeoBoundingBox;
+use Elastica\Filter\GeoDistance;
+use Elastica\Filter\GeoDistanceRange;
+use Elastica\Filter\GeohashCell;
+use Elastica\Filter\GeoPolygon;
+use Elastica\Filter\GeoShapePreIndexed;
+use Elastica\Filter\GeoShapeProvided;
+use Elastica\Filter\HasChild;
+use Elastica\Filter\HasParent;
+use Elastica\Filter\Ids;
+use Elastica\Filter\Indices;
+use Elastica\Filter\Limit;
+use Elastica\Filter\MatchAll;
+use Elastica\Filter\Missing;
+use Elastica\Filter\Nested;
+use Elastica\Filter\NumericRange;
+use Elastica\Filter\Prefix;
+use Elastica\Filter\Query as QueryFilter;
+use Elastica\Filter\Range;
+use Elastica\Filter\Regexp;
+use Elastica\Filter\Script;
+use Elastica\Filter\Term;
+use Elastica\Filter\Terms;
+use Elastica\Filter\Type;
+use Elastica\Query\AbstractQuery;
+use Elastica\QueryBuilder\DSL;
+
+/**
+ * elasticsearch filter DSL.
+ *
+ * @author Manuel Andreo Garcia <andreo.garcia@googlemail.com>
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-filters.html
+ */
+class Filter implements DSL
+{
+ /**
+ * must return type for QueryBuilder usage.
+ *
+ * @return string
+ */
+ public function getType()
+ {
+ return self::TYPE_FILTER;
+ }
+
+ /**
+ * and filter.
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-and-filter.html
+ *
+ * @param AbstractFilter[] $filters
+ *
+ * @return BoolAnd
+ */
+ public function bool_and(array $filters = array())
+ {
+ return new BoolAnd($filters);
+ }
+
+ /**
+ * bool filter.
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-bool-filter.html
+ *
+ * @return \Elastica\Filter\Bool
+ */
+ public function bool()
+ {
+ return new BoolFilter();
+ }
+
+ /**
+ * exists filter.
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-exists-filter.html
+ *
+ * @param string $field
+ *
+ * @return Exists
+ */
+ public function exists($field)
+ {
+ return new Exists($field);
+ }
+
+ /**
+ * geo bounding box filter.
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-geo-bounding-box-filter.html
+ *
+ * @param string $key
+ * @param array $coordinates
+ *
+ * @return GeoBoundingBox
+ */
+ public function geo_bounding_box($key, array $coordinates)
+ {
+ return new GeoBoundingBox($key, $coordinates);
+ }
+
+ /**
+ * geo distance filter.
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-geo-distance-filter.html
+ *
+ * @param string $key Key
+ * @param array|string $location Location as array or geohash: array('lat' => 48.86, 'lon' => 2.35) OR 'drm3btev3e86'
+ * @param string $distance Distance
+ *
+ * @return GeoDistance
+ */
+ public function geo_distance($key, $location, $distance)
+ {
+ return new GeoDistance($key, $location, $distance);
+ }
+
+ /**
+ * geo distance rangefilter.
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-geo-distance-range-filter.html
+ *
+ * @param string $key
+ * @param array|string $location
+ * @param array $ranges
+ *
+ * @return GeoDistanceRange
+ */
+ public function geo_distance_range($key, $location, array $ranges = array())
+ {
+ return new GeoDistanceRange($key, $location, $ranges);
+ }
+
+ /**
+ * geo polygon filter.
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-geo-polygon-filter.html
+ *
+ * @param string $key Key
+ * @param array $points Points making up polygon
+ *
+ * @return GeoPolygon
+ */
+ public function geo_polygon($key, array $points)
+ {
+ return new GeoPolygon($key, $points);
+ }
+
+ /**
+ * provided geo shape filter.
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-geo-shape-filter.html#_provided_shape_definition
+ *
+ * @param string $path
+ * @param array $coordinates
+ * @param string $shapeType
+ *
+ * @return GeoShapeProvided
+ */
+ public function geo_shape_provided($path, array $coordinates, $shapeType = GeoShapeProvided::TYPE_ENVELOPE)
+ {
+ return new GeoShapeProvided($path, $coordinates, $shapeType);
+ }
+
+ /**
+ * pre indexed geo shape filter.
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-geo-shape-filter.html#_pre_indexed_shape
+ *
+ * @param string $path The path/field of the shape searched
+ * @param string $indexedId Id of the pre-indexed shape
+ * @param string $indexedType Type of the pre-indexed shape
+ * @param string $indexedIndex Index of the pre-indexed shape
+ * @param string $indexedPath Path of the pre-indexed shape
+ *
+ * @return GeoShapePreIndexed
+ */
+ public function geo_shape_pre_indexed($path, $indexedId, $indexedType, $indexedIndex, $indexedPath)
+ {
+ return new GeoShapePreIndexed($path, $indexedId, $indexedType, $indexedIndex, $indexedPath);
+ }
+
+ /**
+ * geohash cell filter.
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-geohash-cell-filter.html
+ *
+ * @param string $key The field on which to filter
+ * @param array|string $location Location as coordinates array or geohash string ['lat' => 40.3, 'lon' => 45.2]
+ * @param int|string $precision length of geohash prefix or distance (3, or "50m")
+ * @param bool $neighbors If true, filters cells next to the given cell.
+ *
+ * @return GeohashCell
+ */
+ public function geohash_cell($key, $location, $precision = -1, $neighbors = false)
+ {
+ return new GeohashCell($key, $location, $precision, $neighbors);
+ }
+
+ /**
+ * has child filter.
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-has-child-filter.html
+ *
+ * @param AbstractQuery|AbstractFilter $query
+ * @param string $type
+ *
+ * @return HasChild
+ */
+ public function has_child($query, $type = null)
+ {
+ return new HasChild($query, $type);
+ }
+
+ /**
+ * has parent filter.
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-has-parent-filter.html
+ *
+ * @param AbstractQuery|AbstractFilter $query
+ * @param string $type
+ *
+ * @return HasParent
+ */
+ public function has_parent($query, $type)
+ {
+ return new HasParent($query, $type);
+ }
+
+ /**
+ * ids filter.
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-ids-filter.html
+ *
+ * @param string|\Elastica\Type $type
+ * @param array $ids
+ *
+ * @return Ids
+ */
+ public function ids($type = null, array $ids = array())
+ {
+ return new Ids($type, $ids);
+ }
+
+ /**
+ * indices filter.
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-indices-filter.html
+ *
+ * @param AbstractFilter $filter filter which will be applied to docs in the specified indices
+ * @param string[] $indices
+ *
+ * @return Indices
+ */
+ public function indices(AbstractFilter $filter, array $indices)
+ {
+ return new Indices($filter, $indices);
+ }
+
+ /**
+ * limit filter.
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-limit-filter.html
+ *
+ * @param int $limit Limit
+ *
+ * @return Limit
+ */
+ public function limit($limit)
+ {
+ return new Limit($limit);
+ }
+
+ /**
+ * match all filter.
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-match-all-filter.html
+ *
+ * @return MatchAll
+ */
+ public function match_all()
+ {
+ return new MatchAll();
+ }
+
+ /**
+ * missing filter.
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-missing-filter.html
+ *
+ * @param string $field
+ *
+ * @return Missing
+ */
+ public function missing($field = '')
+ {
+ return new Missing($field);
+ }
+
+ /**
+ * nested filter.
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-nested-filter.html
+ *
+ * @return Nested
+ */
+ public function nested()
+ {
+ return new Nested();
+ }
+
+ /**
+ * not filter.
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-not-filter.html
+ *
+ * @param AbstractFilter $filter
+ *
+ * @return BoolNot
+ */
+ public function bool_not(AbstractFilter $filter)
+ {
+ return new BoolNot($filter);
+ }
+
+ /**
+ * numeric range filter.
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/0.90/query-dsl-numeric-range-filter.html
+ *
+ * @param string $fieldName Field name
+ * @param array $args Field arguments
+ *
+ * @return NumericRange
+ */
+ public function numeric_range($fieldName = '', array $args = array())
+ {
+ return new NumericRange($fieldName, $args);
+ }
+
+ /**
+ * or filter.
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-or-filter.html
+ *
+ * @param AbstractFilter[] $filters
+ *
+ * @return BoolOr
+ */
+ public function bool_or(array $filters = array())
+ {
+ return new BoolOr($filters);
+ }
+
+ /**
+ * prefix filter.
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-prefix-filter.html
+ *
+ * @param string $field
+ * @param string $prefix
+ *
+ * @return Prefix
+ */
+ public function prefix($field = '', $prefix = '')
+ {
+ return new Prefix($field, $prefix);
+ }
+
+ /**
+ * query filter.
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-query-filter.html
+ *
+ * @param array|AbstractQuery $query
+ *
+ * @return QueryFilter
+ */
+ public function query($query = null)
+ {
+ return new QueryFilter($query);
+ }
+
+ /**
+ * range filter.
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-range-filter.html
+ *
+ * @param string $fieldName
+ * @param array $args
+ *
+ * @return Range
+ */
+ public function range($fieldName = '', array $args = array())
+ {
+ return new Range($fieldName, $args);
+ }
+
+ /**
+ * regexp filter.
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-regexp-filter.html
+ *
+ * @param string $field Field name
+ * @param string $regexp Regular expression
+ * @param array $options Regular expression options
+ *
+ * @return Regexp
+ */
+ public function regexp($field = '', $regexp = '', $options = array())
+ {
+ return new Regexp($field, $regexp, $options);
+ }
+
+ /**
+ * script filter.
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-script-filter.html
+ *
+ * @param array|string|\Elastica\Script $script
+ *
+ * @return Script
+ */
+ public function script($script = null)
+ {
+ return new Script($script);
+ }
+
+ /**
+ * term filter.
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-term-filter.html
+ *
+ * @param array $term
+ *
+ * @return Term
+ */
+ public function term(array $term = array())
+ {
+ return new Term($term);
+ }
+
+ /**
+ * terms filter.
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-terms-filter.html
+ *
+ * @param string $key
+ * @param array $terms
+ *
+ * @return Terms
+ */
+ public function terms($key = '', array $terms = array())
+ {
+ return new Terms($key, $terms);
+ }
+
+ /**
+ * type filter.
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-type-filter.html
+ *
+ * @param string $type
+ *
+ * @return Type
+ */
+ public function type($type = null)
+ {
+ return new Type($type);
+ }
+}
diff --git a/vendor/ruflin/elastica/lib/Elastica/QueryBuilder/DSL/Query.php b/vendor/ruflin/elastica/lib/Elastica/QueryBuilder/DSL/Query.php
new file mode 100644
index 00000000..7d1aca68
--- /dev/null
+++ b/vendor/ruflin/elastica/lib/Elastica/QueryBuilder/DSL/Query.php
@@ -0,0 +1,586 @@
+<?php
+namespace Elastica\QueryBuilder\DSL;
+
+use Elastica\Exception\NotImplementedException;
+use Elastica\Filter\AbstractFilter;
+use Elastica\Query\AbstractQuery;
+use Elastica\Query\BoolQuery;
+use Elastica\Query\Boosting;
+use Elastica\Query\Common;
+use Elastica\Query\ConstantScore;
+use Elastica\Query\DisMax;
+use Elastica\Query\Filtered;
+use Elastica\Query\FunctionScore;
+use Elastica\Query\Fuzzy;
+use Elastica\Query\FuzzyLikeThis;
+use Elastica\Query\HasChild;
+use Elastica\Query\HasParent;
+use Elastica\Query\Ids;
+use Elastica\Query\Match;
+use Elastica\Query\MatchAll;
+use Elastica\Query\MoreLikeThis;
+use Elastica\Query\MultiMatch;
+use Elastica\Query\Nested;
+use Elastica\Query\Prefix;
+use Elastica\Query\QueryString;
+use Elastica\Query\Range;
+use Elastica\Query\Regexp;
+use Elastica\Query\SimpleQueryString;
+use Elastica\Query\Term;
+use Elastica\Query\Terms;
+use Elastica\Query\TopChildren;
+use Elastica\Query\Wildcard;
+use Elastica\QueryBuilder\DSL;
+
+/**
+ * elasticsearch query DSL.
+ *
+ * @author Manuel Andreo Garcia <andreo.garcia@googlemail.com>
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-queries.html
+ */
+class Query implements DSL
+{
+ /**
+ * must return type for QueryBuilder usage.
+ *
+ * @return string
+ */
+ public function getType()
+ {
+ return self::TYPE_QUERY;
+ }
+
+ /**
+ * match query.
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-match-query.html
+ *
+ * @param string $field
+ * @param mixed $values
+ *
+ * @return Match
+ */
+ public function match($field = null, $values = null)
+ {
+ return new Match($field, $values);
+ }
+
+ /**
+ * multi match query.
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-multi-match-query.html
+ *
+ * @return \Elastica\Query\MultiMatch
+ */
+ public function multi_match()
+ {
+ return new MultiMatch();
+ }
+
+ /**
+ * bool query.
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-bool-query.html
+ *
+ * @return \Elastica\Query\BoolQuery
+ */
+ public function bool()
+ {
+ return new BoolQuery();
+ }
+
+ /**
+ * boosting query.
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-boosting-query.html
+ *
+ * @return Boosting
+ */
+ public function boosting()
+ {
+ return new Boosting();
+ }
+
+ /**
+ * common terms query.
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-common-terms-query.html
+ *
+ * @param string $field
+ * @param string $query
+ * @param float $cutoffFrequency percentage in decimal form (.001 == 0.1%)
+ *
+ * @return Common
+ */
+ public function common_terms($field, $query, $cutoffFrequency)
+ {
+ return new Common($field, $query, $cutoffFrequency);
+ }
+
+ /**
+ * custom filters score query.
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/0.90/query-dsl-custom-filters-score-query.html
+ */
+ public function custom_filters_score()
+ {
+ throw new NotImplementedException();
+ }
+
+ /**
+ * custom score query.
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/0.90/query-dsl-custom-score-query.html
+ */
+ public function custom_score()
+ {
+ throw new NotImplementedException();
+ }
+
+ /**
+ * custom boost factor query.
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/0.90/query-dsl-custom-boost-factor-query.html
+ */
+ public function custom_boost_factor()
+ {
+ throw new NotImplementedException();
+ }
+
+ /**
+ * constant score query.
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-constant-score-query.html
+ *
+ * @param null|\Elastica\Filter\AbstractFilter|array $filter
+ *
+ * @return ConstantScore
+ */
+ public function constant_score($filter = null)
+ {
+ return new ConstantScore($filter);
+ }
+
+ /**
+ * dis max query.
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-dis-max-query.html
+ *
+ * @return DisMax
+ */
+ public function dis_max()
+ {
+ return new DisMax();
+ }
+
+ /**
+ * field query.
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/0.90/query-dsl-field-query.html
+ */
+ public function field()
+ {
+ throw new NotImplementedException();
+ }
+
+ /**
+ * filtered query.
+ *
+ * @param AbstractFilter $filter
+ * @param AbstractQuery $query
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-filtered-query.html
+ *
+ * @return Filtered
+ */
+ public function filtered(AbstractQuery $query = null, AbstractFilter $filter = null)
+ {
+ return new Filtered($query, $filter);
+ }
+
+ /**
+ * fuzzy like this query.
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-flt-query.html
+ *
+ * @return FuzzyLikeThis
+ */
+ public function fuzzy_like_this()
+ {
+ return new FuzzyLikeThis();
+ }
+
+ /**
+ * fuzzy like this field query.
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-flt-field-query.html
+ */
+ public function fuzzy_like_this_field()
+ {
+ throw new NotImplementedException();
+ }
+
+ /**
+ * function score query.
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-function-score-query.html
+ *
+ * @return FunctionScore
+ */
+ public function function_score()
+ {
+ return new FunctionScore();
+ }
+
+ /**
+ * fuzzy query.
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-fuzzy-query.html
+ *
+ * @param string $fieldName Field name
+ * @param string $value String to search for
+ *
+ * @return Fuzzy
+ */
+ public function fuzzy($fieldName = null, $value = null)
+ {
+ return new Fuzzy($fieldName, $value);
+ }
+
+ /**
+ * geo shape query.
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-geo-shape-query.html
+ */
+ public function geo_shape()
+ {
+ throw new NotImplementedException();
+ }
+
+ /**
+ * has child query.
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-has-child-query.html
+ *
+ * @param string|\Elastica\Query|\Elastica\Query\AbstractQuery $query
+ * @param string $type Parent document type
+ *
+ * @return HasChild
+ */
+ public function has_child($query, $type = null)
+ {
+ return new HasChild($query, $type);
+ }
+
+ /**
+ * has parent query.
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-has-parent-query.html
+ *
+ * @param string|\Elastica\Query|\Elastica\Query\AbstractQuery $query
+ * @param string $type Parent document type
+ *
+ * @return HasParent
+ */
+ public function has_parent($query, $type)
+ {
+ return new HasParent($query, $type);
+ }
+
+ /**
+ * ids query.
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-ids-query.html
+ *
+ * @param array|string|\Elastica\Type $type
+ * @param array $ids
+ *
+ * @return Ids
+ */
+ public function ids($type = null, array $ids = array())
+ {
+ return new Ids($type, $ids);
+ }
+
+ /**
+ * indices query.
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-indices-query.html
+ */
+ public function indices()
+ {
+ throw new NotImplementedException();
+ }
+
+ /**
+ * match all query.
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-match-all-query.html
+ *
+ * @return MatchAll
+ */
+ public function match_all()
+ {
+ return new MatchAll();
+ }
+
+ /**
+ * more like this query.
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-mlt-query.html
+ *
+ * @return MoreLikeThis
+ */
+ public function more_like_this()
+ {
+ return new MoreLikeThis();
+ }
+
+ /**
+ * more_like_this_field query.
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/1.4/query-dsl-mlt-field-query.html
+ * @deprecated More Like This Field query is deprecated as of ES 1.4 and will be removed in ES 2.0
+ */
+ public function more_like_this_field()
+ {
+ throw new NotImplementedException();
+ }
+
+ /**
+ * nested query.
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-nested-query.html
+ *
+ * @return Nested
+ */
+ public function nested()
+ {
+ return new Nested();
+ }
+
+ /**
+ * prefix query.
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-prefix-query.html
+ *
+ * @param array $prefix Prefix array
+ *
+ * @return Prefix
+ */
+ public function prefix(array $prefix = array())
+ {
+ return new Prefix($prefix);
+ }
+
+ /**
+ * query string query.
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-query-string-query.html
+ *
+ * @param string $queryString OPTIONAL Query string for object
+ *
+ * @return QueryString
+ */
+ public function query_string($queryString = '')
+ {
+ return new QueryString($queryString);
+ }
+
+ /**
+ * simple_query_string query.
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-simple-query-string-query.html
+ *
+ * @param string $query
+ * @param array $fields
+ *
+ * @return SimpleQueryString
+ */
+ public function simple_query_string($query, array $fields = array())
+ {
+ return new SimpleQueryString($query, $fields);
+ }
+
+ /**
+ * range query.
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-range-query.html
+ *
+ * @param string $fieldName
+ * @param array $args
+ *
+ * @return Range
+ */
+ public function range($fieldName = null, array $args = array())
+ {
+ return new Range($fieldName, $args);
+ }
+
+ /**
+ * regexp query.
+ *
+ * @param string $key
+ * @param string $value
+ * @param float $boost
+ *
+ * @return Regexp
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-regexp-query.html
+ */
+ public function regexp($key = '', $value = null, $boost = 1.0)
+ {
+ return new Regexp($key, $value, $boost);
+ }
+
+ /**
+ * span first query.
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-span-first-query.html
+ */
+ public function span_first()
+ {
+ throw new NotImplementedException();
+ }
+
+ /**
+ * span multi term query.
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-span-multi-term-query.html
+ */
+ public function span_multi_term()
+ {
+ throw new NotImplementedException();
+ }
+
+ /**
+ * span near query.
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-span-near-query.html
+ */
+ public function span_near()
+ {
+ throw new NotImplementedException();
+ }
+
+ /**
+ * span not query.
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-span-not-query.html
+ */
+ public function span_not()
+ {
+ throw new NotImplementedException();
+ }
+
+ /**
+ * span or query.
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-span-or-query.html
+ */
+ public function span_or()
+ {
+ throw new NotImplementedException();
+ }
+
+ /**
+ * span term query.
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-span-term-query.html
+ */
+ public function span_term()
+ {
+ throw new NotImplementedException();
+ }
+
+ /**
+ * term query.
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-term-query.html
+ *
+ * @param array $term
+ *
+ * @return Term
+ */
+ public function term(array $term = array())
+ {
+ return new Term($term);
+ }
+
+ /**
+ * terms query.
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-terms-query.html
+ *
+ * @param string $key
+ * @param array $terms
+ *
+ * @return Terms
+ */
+ public function terms($key = '', array $terms = array())
+ {
+ return new Terms($key, $terms);
+ }
+
+ /**
+ * top children query.
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-top-children-query.html
+ *
+ * @param string|AbstractQuery|\Elastica\Query $query
+ * @param string $type
+ *
+ * @return TopChildren
+ */
+ public function top_children($query, $type = null)
+ {
+ return new TopChildren($query, $type);
+ }
+
+ /**
+ * wildcard query.
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-wildcard-query.html
+ *
+ * @param string $key OPTIONAL Wildcard key
+ * @param string $value OPTIONAL Wildcard value
+ * @param float $boost OPTIONAL Boost value (default = 1)
+ *
+ * @return Wildcard
+ */
+ public function wildcard($key = '', $value = null, $boost = 1.0)
+ {
+ return new Wildcard($key, $value, $boost);
+ }
+
+ /**
+ * text query.
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/0.90/query-dsl-text-query.html
+ */
+ public function text()
+ {
+ throw new NotImplementedException();
+ }
+
+ /**
+ * minimum should match query.
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-minimum-should-match.html
+ */
+ public function minimum_should_match()
+ {
+ throw new NotImplementedException();
+ }
+
+ /**
+ * template query.
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-template-query.html
+ */
+ public function template()
+ {
+ throw new NotImplementedException();
+ }
+}
diff --git a/vendor/ruflin/elastica/lib/Elastica/QueryBuilder/DSL/Suggest.php b/vendor/ruflin/elastica/lib/Elastica/QueryBuilder/DSL/Suggest.php
new file mode 100644
index 00000000..9a54ccde
--- /dev/null
+++ b/vendor/ruflin/elastica/lib/Elastica/QueryBuilder/DSL/Suggest.php
@@ -0,0 +1,83 @@
+<?php
+namespace Elastica\QueryBuilder\DSL;
+
+use Elastica\Exception\NotImplementedException;
+use Elastica\QueryBuilder\DSL;
+use Elastica\Suggest\Completion;
+use Elastica\Suggest\Phrase;
+use Elastica\Suggest\Term;
+
+/**
+ * elasticsearch suggesters DSL.
+ *
+ * @author Manuel Andreo Garcia <andreo.garcia@googlemail.com>
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/search-suggesters.html
+ */
+class Suggest implements DSL
+{
+ /**
+ * must return type for QueryBuilder usage.
+ *
+ * @return string
+ */
+ public function getType()
+ {
+ return self::TYPE_SUGGEST;
+ }
+
+ /**
+ * term suggester.
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/search-suggesters-term.html
+ *
+ * @param $name
+ * @param $field
+ *
+ * @return Term
+ */
+ public function term($name, $field)
+ {
+ return new Term($name, $field);
+ }
+
+ /**
+ * phrase suggester.
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/search-suggesters-phrase.html
+ *
+ * @param $name
+ * @param $field
+ *
+ * @return Phrase
+ */
+ public function phrase($name, $field)
+ {
+ return new Phrase($name, $field);
+ }
+
+ /**
+ * completion suggester.
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/search-suggesters-completion.html
+ *
+ * @param string $name
+ * @param string $field
+ *
+ * @return Completion
+ */
+ public function completion($name, $field)
+ {
+ return new Completion($name, $field);
+ }
+
+ /**
+ * context suggester.
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/suggester-context.html
+ */
+ public function context()
+ {
+ throw new NotImplementedException();
+ }
+}
diff --git a/vendor/ruflin/elastica/lib/Elastica/QueryBuilder/Facade.php b/vendor/ruflin/elastica/lib/Elastica/QueryBuilder/Facade.php
new file mode 100644
index 00000000..b0f6da82
--- /dev/null
+++ b/vendor/ruflin/elastica/lib/Elastica/QueryBuilder/Facade.php
@@ -0,0 +1,64 @@
+<?php
+namespace Elastica\QueryBuilder;
+
+use Elastica\Exception\QueryBuilderException;
+
+/**
+ * Facade for a specific DSL object.
+ *
+ * @author Manuel Andreo Garcia <andreo.garcia@googlemail.com>
+ **/
+class Facade
+{
+ /**
+ * @var DSL
+ */
+ private $_dsl;
+
+ /**
+ * @var Version
+ */
+ private $_version;
+
+ /**
+ * Constructor.
+ *
+ * @param DSL $dsl
+ * @param Version $version
+ */
+ public function __construct(DSL $dsl, Version $version)
+ {
+ $this->_dsl = $dsl;
+ $this->_version = $version;
+ }
+
+ /**
+ * Executes DSL methods.
+ *
+ * @param string $name
+ * @param array $arguments
+ *
+ * @throws QueryBuilderException
+ *
+ * @return mixed
+ */
+ public function __call($name, array $arguments)
+ {
+ // defined check
+ if (false === method_exists($this->_dsl, $name)) {
+ throw new QueryBuilderException(
+ 'undefined '.$this->_dsl->getType().' "'.$name.'"'
+ );
+ }
+
+ // version support check
+ if (false === $this->_version->supports($name, $this->_dsl->getType())) {
+ $reflection = new \ReflectionClass($this->_version);
+ throw new QueryBuilderException(
+ $this->_dsl->getType().' "'.$name.'" in '.$reflection->getShortName().' not supported'
+ );
+ }
+
+ return call_user_func_array(array($this->_dsl, $name), $arguments);
+ }
+}
diff --git a/vendor/ruflin/elastica/lib/Elastica/QueryBuilder/Version.php b/vendor/ruflin/elastica/lib/Elastica/QueryBuilder/Version.php
new file mode 100644
index 00000000..5230600d
--- /dev/null
+++ b/vendor/ruflin/elastica/lib/Elastica/QueryBuilder/Version.php
@@ -0,0 +1,101 @@
+<?php
+namespace Elastica\QueryBuilder;
+
+/**
+ * Abstract Version class.
+ *
+ * @author Manuel Andreo Garcia <andreo.garcia@googlemail.com>
+ */
+abstract class Version
+{
+ /**
+ * supported query methods.
+ *
+ * @var string[]
+ */
+ protected $queries = array();
+
+ /**
+ * supported filter methods.
+ *
+ * @var string[]
+ */
+ protected $filters = array();
+
+ /**
+ * supported aggregation methods.
+ *
+ * @var string[]
+ */
+ protected $aggregations = array();
+
+ /**
+ * supported $suggester methods.
+ *
+ * @var string[]
+ */
+ protected $suggesters = array();
+
+ /**
+ * returns true if $name is supported, false otherwise.
+ *
+ * @param string $name
+ * @param $type
+ *
+ * @return bool
+ */
+ public function supports($name, $type)
+ {
+ switch ($type) {
+ case DSL::TYPE_QUERY:
+ $supports = in_array($name, $this->queries);
+ break;
+ case DSL::TYPE_FILTER:
+ $supports = in_array($name, $this->filters);
+ break;
+ case DSL::TYPE_AGGREGATION:
+ $supports = in_array($name, $this->aggregations);
+ break;
+ case DSL::TYPE_SUGGEST:
+ $supports = in_array($name, $this->suggesters);
+ break;
+ default:
+ // disables version check in Facade for custom DSL objects
+ $supports = true;
+ }
+
+ return $supports;
+ }
+
+ /**
+ * @return string[]
+ */
+ public function getAggregations()
+ {
+ return $this->aggregations;
+ }
+
+ /**
+ * @return string[]
+ */
+ public function getFilters()
+ {
+ return $this->filters;
+ }
+
+ /**
+ * @return string[]
+ */
+ public function getQueries()
+ {
+ return $this->queries;
+ }
+
+ /**
+ * @return string[]
+ */
+ public function getSuggesters()
+ {
+ return $this->suggesters;
+ }
+}
diff --git a/vendor/ruflin/elastica/lib/Elastica/QueryBuilder/Version/Version090.php b/vendor/ruflin/elastica/lib/Elastica/QueryBuilder/Version/Version090.php
new file mode 100644
index 00000000..193ba852
--- /dev/null
+++ b/vendor/ruflin/elastica/lib/Elastica/QueryBuilder/Version/Version090.php
@@ -0,0 +1,97 @@
+<?php
+namespace Elastica\QueryBuilder\Version;
+
+use Elastica\QueryBuilder\Version;
+
+/**
+ * elasticsearch 0.9 DSL.
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/0.90/index.html
+ *
+ * @author Manuel Andreo Garcia <andreo.garcia@googlemail.com>
+ */
+class Version090 extends Version
+{
+ protected $queries = array(
+ 'match',
+ 'multi_match',
+ 'bool',
+ 'boosting',
+ 'common_terms',
+ 'custom_filters_score',
+ 'custom_score',
+ 'custom_boost_factor',
+ 'constant_score',
+ 'dis_max',
+ 'field',
+ 'filtered',
+ 'fuzzy_like_this',
+ 'fuzzy_like_this_field',
+ 'function_score',
+ 'fuzzy',
+ 'geo_shape',
+ 'has_child',
+ 'has_parent',
+ 'ids',
+ 'indices',
+ 'match_all',
+ 'more_like_this',
+ 'more_like_this_field',
+ 'nested',
+ 'prefix',
+ 'query_string',
+ 'simple_query_string',
+ 'range',
+ 'regexp',
+ 'span_first',
+ 'span_multi_term',
+ 'span_near',
+ 'span_not',
+ 'span_or',
+ 'span_term',
+ 'term',
+ 'terms',
+ 'top_children',
+ 'wildcard',
+ 'text',
+ 'minimum_should_match',
+ );
+
+ protected $filters = array(
+ 'bool_and', // original: bool
+ 'bool',
+ 'exists',
+ 'geo_bounding_box',
+ 'geo_distance',
+ 'geo_distance_range',
+ 'geo_polygon',
+ 'geo_shape_provided', // original: geo_shape
+ 'geo_shape_pre_indexed', // original: geo_shape
+ 'geohash_cell',
+ 'has_child',
+ 'has_parent',
+ 'ids',
+ 'indices',
+ 'limit',
+ 'match_all',
+ 'missing',
+ 'nested',
+ 'bool_not', // original: not
+ 'numeric_range',
+ 'bool_or', // original: or
+ 'prefix',
+ 'query',
+ 'range',
+ 'regexp',
+ 'script',
+ 'term',
+ 'terms',
+ 'type',
+ );
+
+ protected $suggesters = array(
+ 'term',
+ 'phrase',
+ 'completion',
+ );
+}
diff --git a/vendor/ruflin/elastica/lib/Elastica/QueryBuilder/Version/Version100.php b/vendor/ruflin/elastica/lib/Elastica/QueryBuilder/Version/Version100.php
new file mode 100644
index 00000000..66a5c9cd
--- /dev/null
+++ b/vendor/ruflin/elastica/lib/Elastica/QueryBuilder/Version/Version100.php
@@ -0,0 +1,123 @@
+<?php
+namespace Elastica\QueryBuilder\Version;
+
+use Elastica\QueryBuilder\Version;
+
+/**
+ * elasticsearch 1.0 DSL.
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/1.x/index.html
+ *
+ * @author Manuel Andreo Garcia <andreo.garcia@googlemail.com>
+ */
+class Version100 extends Version
+{
+ protected $queries = array(
+ 'match',
+ 'multi_match',
+ 'bool',
+ 'boosting',
+ 'common_terms',
+ 'constant_score',
+ 'dis_max',
+ 'filtered',
+ 'fuzzy_like_this',
+ 'fuzzy_like_this_field',
+ 'function_score',
+ 'fuzzy',
+ 'geo_shape',
+ 'has_child',
+ 'has_parent',
+ 'ids',
+ 'indices',
+ 'match_all',
+ 'more_like_this',
+ 'more_like_this_field',
+ 'nested',
+ 'prefix',
+ 'query_string',
+ 'simple_query_string',
+ 'range',
+ 'regexp',
+ 'span_first',
+ 'span_multi_term',
+ 'span_near',
+ 'span_not',
+ 'span_or',
+ 'span_term',
+ 'term',
+ 'terms',
+ 'top_children',
+ 'wildcard',
+ 'minimum_should_match',
+
+ // removed in 1.0.0
+ // 'text'
+ // 'field'
+ // 'custom_filters_score'
+ // 'custom_score'
+ // 'custom_boost_factor'
+ );
+
+ protected $filters = array(
+ 'bool_and', // original: bool
+ 'bool',
+ 'exists',
+ 'geo_bounding_box',
+ 'geo_distance',
+ 'geo_distance_range',
+ 'geo_polygon',
+ 'geo_shape_provided', // original: geo_shape
+ 'geo_shape_pre_indexed', // original: geo_shape
+ 'geohash_cell',
+ 'has_child',
+ 'has_parent',
+ 'ids',
+ 'indices',
+ 'limit',
+ 'match_all',
+ 'missing',
+ 'nested',
+ 'bool_not', // original: not
+ 'bool_or', // original: or
+ 'prefix',
+ 'query',
+ 'range',
+ 'regexp',
+ 'script',
+ 'term',
+ 'terms',
+ 'type',
+
+ // removed in 1.0.0
+ // 'numeric_range'
+ );
+
+ protected $aggregations = array(
+ 'min',
+ 'max',
+ 'sum',
+ 'avg',
+ 'stats',
+ 'extended_stats',
+ 'value_count',
+ 'global_agg', // original: global
+ 'filter',
+ 'missing',
+ 'nested',
+ 'terms',
+ 'range',
+ 'date_range',
+ 'ipv4_range',
+ 'histogram',
+ 'date_histogram',
+ 'geo_distance',
+ 'geohash_grid',
+ );
+
+ protected $suggesters = array(
+ 'term',
+ 'phrase',
+ 'completion',
+ );
+}
diff --git a/vendor/ruflin/elastica/lib/Elastica/QueryBuilder/Version/Version110.php b/vendor/ruflin/elastica/lib/Elastica/QueryBuilder/Version/Version110.php
new file mode 100644
index 00000000..b6465e76
--- /dev/null
+++ b/vendor/ruflin/elastica/lib/Elastica/QueryBuilder/Version/Version110.php
@@ -0,0 +1,131 @@
+<?php
+namespace Elastica\QueryBuilder\Version;
+
+use Elastica\QueryBuilder\Version;
+
+/**
+ * elasticsearch 1.1 DSL.
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/1.x/index.html
+ *
+ * @author Manuel Andreo Garcia <andreo.garcia@googlemail.com>
+ */
+class Version110 extends Version
+{
+ protected $queries = array(
+ 'match',
+ 'multi_match',
+ 'bool',
+ 'boosting',
+ 'common_terms',
+ 'constant_score',
+ 'dis_max',
+ 'filtered',
+ 'fuzzy_like_this',
+ 'fuzzy_like_this_field',
+ 'function_score',
+ 'fuzzy',
+ 'geo_shape',
+ 'has_child',
+ 'has_parent',
+ 'ids',
+ 'indices',
+ 'match_all',
+ 'more_like_this',
+ 'more_like_this_field',
+ 'nested',
+ 'prefix',
+ 'query_string',
+ 'simple_query_string',
+ 'range',
+ 'regexp',
+ 'span_first',
+ 'span_multi_term',
+ 'span_near',
+ 'span_not',
+ 'span_or',
+ 'span_term',
+ 'term',
+ 'terms',
+ 'top_children',
+ 'wildcard',
+ 'minimum_should_match',
+
+ // removed in 1.0.0
+ // 'text'
+ // 'field'
+ // 'custom_filters_score'
+ // 'custom_score'
+ // 'custom_boost_factor'
+
+ // new in 1.1.0
+ 'template',
+ );
+
+ protected $filters = array(
+ 'bool_and', // original: bool
+ 'bool',
+ 'exists',
+ 'geo_bounding_box',
+ 'geo_distance',
+ 'geo_distance_range',
+ 'geo_polygon',
+ 'geo_shape_provided', // original: geo_shape
+ 'geo_shape_pre_indexed', // original: geo_shape
+ 'geohash_cell',
+ 'has_child',
+ 'has_parent',
+ 'ids',
+ 'indices',
+ 'limit',
+ 'match_all',
+ 'missing',
+ 'nested',
+ 'bool_not', // original: not
+ 'bool_or', // original: or
+ 'prefix',
+ 'query',
+ 'range',
+ 'regexp',
+ 'script',
+ 'term',
+ 'terms',
+ 'type',
+
+ // removed in 1.0.0
+ // 'numeric_range'
+ );
+
+ protected $aggregations = array(
+ 'min',
+ 'max',
+ 'sum',
+ 'avg',
+ 'stats',
+ 'extended_stats',
+ 'value_count',
+ 'global_agg', // original: global
+ 'filter',
+ 'missing',
+ 'nested',
+ 'terms',
+ 'range',
+ 'date_range',
+ 'ipv4_range',
+ 'histogram',
+ 'date_histogram',
+ 'geo_distance',
+ 'geohash_grid',
+
+ // new in 1.1.0
+ 'percentiles',
+ 'cardinality',
+ 'significant_terms',
+ );
+
+ protected $suggesters = array(
+ 'term',
+ 'phrase',
+ 'completion',
+ );
+}
diff --git a/vendor/ruflin/elastica/lib/Elastica/QueryBuilder/Version/Version120.php b/vendor/ruflin/elastica/lib/Elastica/QueryBuilder/Version/Version120.php
new file mode 100644
index 00000000..f74e3bdc
--- /dev/null
+++ b/vendor/ruflin/elastica/lib/Elastica/QueryBuilder/Version/Version120.php
@@ -0,0 +1,137 @@
+<?php
+namespace Elastica\QueryBuilder\Version;
+
+use Elastica\QueryBuilder\Version;
+
+/**
+ * elasticsearch 1.2 DSL.
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/1.x/index.html
+ *
+ * @author Manuel Andreo Garcia <andreo.garcia@googlemail.com>
+ */
+class Version120 extends Version
+{
+ protected $queries = array(
+ 'match',
+ 'multi_match',
+ 'bool',
+ 'boosting',
+ 'common_terms',
+ 'constant_score',
+ 'dis_max',
+ 'filtered',
+ 'fuzzy_like_this',
+ 'fuzzy_like_this_field',
+ 'function_score',
+ 'fuzzy',
+ 'geo_shape',
+ 'has_child',
+ 'has_parent',
+ 'ids',
+ 'indices',
+ 'match_all',
+ 'more_like_this',
+ 'more_like_this_field',
+ 'nested',
+ 'prefix',
+ 'query_string',
+ 'simple_query_string',
+ 'range',
+ 'regexp',
+ 'span_first',
+ 'span_multi_term',
+ 'span_near',
+ 'span_not',
+ 'span_or',
+ 'span_term',
+ 'term',
+ 'terms',
+ 'top_children',
+ 'wildcard',
+ 'minimum_should_match',
+
+ // removed in 1.0.0
+ // 'text'
+ // 'field'
+ // 'custom_filters_score'
+ // 'custom_score'
+ // 'custom_boost_factor'
+
+ // new in 1.1.0
+ 'template',
+ );
+
+ protected $filters = array(
+ 'bool_and', // original: bool
+ 'bool',
+ 'exists',
+ 'geo_bounding_box',
+ 'geo_distance',
+ 'geo_distance_range',
+ 'geo_polygon',
+ 'geo_shape_provided', // original: geo_shape
+ 'geo_shape_pre_indexed', // original: geo_shape
+ 'geohash_cell',
+ 'has_child',
+ 'has_parent',
+ 'ids',
+ 'indices',
+ 'limit',
+ 'match_all',
+ 'missing',
+ 'nested',
+ 'bool_not', // original: not
+ 'bool_or', // original: or
+ 'prefix',
+ 'query',
+ 'range',
+ 'regexp',
+ 'script',
+ 'term',
+ 'terms',
+ 'type',
+
+ // removed in 1.0.0
+ // 'numeric_range'
+ );
+
+ protected $aggregations = array(
+ 'min',
+ 'max',
+ 'sum',
+ 'avg',
+ 'stats',
+ 'extended_stats',
+ 'value_count',
+ 'global_agg', // original: global
+ 'filter',
+ 'missing',
+ 'nested',
+ 'terms',
+ 'range',
+ 'date_range',
+ 'ipv4_range',
+ 'histogram',
+ 'date_histogram',
+ 'geo_distance',
+ 'geohash_grid',
+
+ // new in 1.1.0
+ 'percentiles',
+ 'cardinality',
+ 'significant_terms',
+
+ // new in 1.2.0
+ 'reverse_nested',
+ );
+
+ protected $suggesters = array(
+ 'term',
+ 'phrase',
+ 'completion',
+
+ // new in 1.2.0
+ 'context',
+ );
+}
diff --git a/vendor/ruflin/elastica/lib/Elastica/QueryBuilder/Version/Version130.php b/vendor/ruflin/elastica/lib/Elastica/QueryBuilder/Version/Version130.php
new file mode 100644
index 00000000..ad52e3e7
--- /dev/null
+++ b/vendor/ruflin/elastica/lib/Elastica/QueryBuilder/Version/Version130.php
@@ -0,0 +1,142 @@
+<?php
+namespace Elastica\QueryBuilder\Version;
+
+use Elastica\QueryBuilder\Version;
+
+/**
+ * elasticsearch 1.3 DSL.
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/1.3/index.html
+ *
+ * @author Manuel Andreo Garcia <andreo.garcia@googlemail.com>
+ */
+class Version130 extends Version
+{
+ protected $queries = array(
+ 'match',
+ 'multi_match',
+ 'bool',
+ 'boosting',
+ 'common_terms',
+ 'constant_score',
+ 'dis_max',
+ 'filtered',
+ 'fuzzy_like_this',
+ 'fuzzy_like_this_field',
+ 'function_score',
+ 'fuzzy',
+ 'geo_shape',
+ 'has_child',
+ 'has_parent',
+ 'ids',
+ 'indices',
+ 'match_all',
+ 'more_like_this',
+ 'more_like_this_field',
+ 'nested',
+ 'prefix',
+ 'query_string',
+ 'simple_query_string',
+ 'range',
+ 'regexp',
+ 'span_first',
+ 'span_multi_term',
+ 'span_near',
+ 'span_not',
+ 'span_or',
+ 'span_term',
+ 'term',
+ 'terms',
+ 'top_children',
+ 'wildcard',
+ 'minimum_should_match',
+
+ // removed in 1.0.0
+ // 'text'
+ // 'field'
+ // 'custom_filters_score'
+ // 'custom_score'
+ // 'custom_boost_factor'
+
+ // new in 1.1.0
+ 'template',
+ );
+
+ protected $filters = array(
+ 'bool_and', // original: bool
+ 'bool',
+ 'exists',
+ 'geo_bounding_box',
+ 'geo_distance',
+ 'geo_distance_range',
+ 'geo_polygon',
+ 'geo_shape_provided', // original: geo_shape
+ 'geo_shape_pre_indexed', // original: geo_shape
+ 'geohash_cell',
+ 'has_child',
+ 'has_parent',
+ 'ids',
+ 'indices',
+ 'limit',
+ 'match_all',
+ 'missing',
+ 'nested',
+ 'bool_not', // original: not
+ 'bool_or', // original: or
+ 'prefix',
+ 'query',
+ 'range',
+ 'regexp',
+ 'script',
+ 'term',
+ 'terms',
+ 'type',
+
+ // removed in 1.0.0
+ // 'numeric_range'
+ );
+
+ protected $aggregations = array(
+ 'min',
+ 'max',
+ 'sum',
+ 'avg',
+ 'stats',
+ 'extended_stats',
+ 'value_count',
+ 'global_agg', // original: global
+ 'filter',
+ 'missing',
+ 'nested',
+ 'terms',
+ 'range',
+ 'date_range',
+ 'ipv4_range',
+ 'histogram',
+ 'date_histogram',
+ 'geo_distance',
+ 'geohash_grid',
+
+ // new in 1.1.0
+ 'percentiles',
+ 'cardinality',
+ 'significant_terms',
+
+ // new in 1.2.0
+ 'reverse_nested',
+
+ // new in 1.3.0
+ 'percentile_ranks',
+ 'geo_bounds',
+ 'top_hits',
+ );
+
+ protected $suggesters = array(
+ 'term',
+ 'phrase',
+ 'completion',
+
+ // new in 1.2.0
+ 'context',
+ );
+}
diff --git a/vendor/ruflin/elastica/lib/Elastica/QueryBuilder/Version/Version140.php b/vendor/ruflin/elastica/lib/Elastica/QueryBuilder/Version/Version140.php
new file mode 100644
index 00000000..7b5d73e3
--- /dev/null
+++ b/vendor/ruflin/elastica/lib/Elastica/QueryBuilder/Version/Version140.php
@@ -0,0 +1,145 @@
+<?php
+namespace Elastica\QueryBuilder\Version;
+
+/**
+ * elasticsearch 1.4 DSL.
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/1.4/index.html
+ *
+ * @author Manuel Andreo Garcia <andreo.garcia@googlemail.com>
+ */
+class Version140 extends Version130
+{
+ protected $queries = array(
+ 'match',
+ 'multi_match',
+ 'bool',
+ 'boosting',
+ 'common_terms',
+ 'constant_score',
+ 'dis_max',
+ 'filtered',
+ 'fuzzy_like_this',
+ 'fuzzy_like_this_field',
+ 'function_score',
+ 'fuzzy',
+ 'geo_shape',
+ 'has_child',
+ 'has_parent',
+ 'ids',
+ 'indices',
+ 'match_all',
+ 'more_like_this',
+ 'more_like_this_field',
+ 'nested',
+ 'prefix',
+ 'query_string',
+ 'simple_query_string',
+ 'range',
+ 'regexp',
+ 'span_first',
+ 'span_multi_term',
+ 'span_near',
+ 'span_not',
+ 'span_or',
+ 'span_term',
+ 'term',
+ 'terms',
+ 'top_children',
+ 'wildcard',
+ 'minimum_should_match',
+
+ // removed in 1.0.0
+ // 'text'
+ // 'field'
+ // 'custom_filters_score'
+ // 'custom_score'
+ // 'custom_boost_factor'
+
+ // new in 1.1.0
+ 'template',
+ );
+
+ protected $filters = array(
+ 'bool_and', // original: bool
+ 'bool',
+ 'exists',
+ 'geo_bounding_box',
+ 'geo_distance',
+ 'geo_distance_range',
+ 'geo_polygon',
+ 'geo_shape_provided', // original: geo_shape
+ 'geo_shape_pre_indexed', // original: geo_shape
+ 'geohash_cell',
+ 'has_child',
+ 'has_parent',
+ 'ids',
+ 'indices',
+ 'limit',
+ 'match_all',
+ 'missing',
+ 'nested',
+ 'bool_not', // original: not
+ 'bool_or', // original: or
+ 'prefix',
+ 'query',
+ 'range',
+ 'regexp',
+ 'script',
+ 'term',
+ 'terms',
+ 'type',
+
+ // removed in 1.0.0
+ // 'numeric_range'
+ );
+
+ protected $aggregations = array(
+ 'min',
+ 'max',
+ 'sum',
+ 'avg',
+ 'stats',
+ 'extended_stats',
+ 'value_count',
+ 'global_agg', // original: global
+ 'filter',
+ 'missing',
+ 'nested',
+ 'terms',
+ 'range',
+ 'date_range',
+ 'ipv4_range',
+ 'histogram',
+ 'date_histogram',
+ 'geo_distance',
+ 'geohash_grid',
+
+ // new in 1.1.0
+ 'percentiles',
+ 'cardinality',
+ 'significant_terms',
+
+ // new in 1.2.0
+ 'reverse_nested',
+
+ // new in 1.3.0
+ 'percentile_ranks',
+ 'geo_bounds',
+ 'top_hits',
+
+ // new in 1.4.0
+ 'scripted_metric',
+ 'filters',
+ 'children',
+ );
+
+ protected $suggesters = array(
+ 'term',
+ 'phrase',
+ 'completion',
+
+ // new in 1.2.0
+ 'context',
+ );
+}
diff --git a/vendor/ruflin/elastica/lib/Elastica/QueryBuilder/Version/Version150.php b/vendor/ruflin/elastica/lib/Elastica/QueryBuilder/Version/Version150.php
new file mode 100644
index 00000000..fcb5e087
--- /dev/null
+++ b/vendor/ruflin/elastica/lib/Elastica/QueryBuilder/Version/Version150.php
@@ -0,0 +1,14 @@
+<?php
+namespace Elastica\QueryBuilder\Version;
+
+/**
+ * elasticsearch 1.5 DSL.
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/1.5/index.html
+ *
+ * @author Igor Denisenko <im.denisenko@yahoo.com>
+ */
+class Version150 extends Version140
+{
+ // nothing was added nor removed
+}
diff --git a/vendor/ruflin/elastica/lib/Elastica/Request.php b/vendor/ruflin/elastica/lib/Elastica/Request.php
new file mode 100644
index 00000000..ab26ff09
--- /dev/null
+++ b/vendor/ruflin/elastica/lib/Elastica/Request.php
@@ -0,0 +1,204 @@
+<?php
+namespace Elastica;
+
+use Elastica\Exception\InvalidException;
+
+/**
+ * Elastica Request object.
+ *
+ * @author Nicolas Ruflin <spam@ruflin.com>
+ */
+class Request extends Param
+{
+ const HEAD = 'HEAD';
+ const POST = 'POST';
+ const PUT = 'PUT';
+ const GET = 'GET';
+ const DELETE = 'DELETE';
+
+ /**
+ * @var \Elastica\Connection
+ */
+ protected $_connection;
+
+ /**
+ * Construct.
+ *
+ * @param string $path Request path
+ * @param string $method OPTIONAL Request method (use const's) (default = self::GET)
+ * @param array $data OPTIONAL Data array
+ * @param array $query OPTIONAL Query params
+ * @param Connection $connection
+ *
+ * @return \Elastica\Request OPTIONAL Connection object
+ */
+ public function __construct($path, $method = self::GET, $data = array(), array $query = array(), Connection $connection = null)
+ {
+ $this->setPath($path);
+ $this->setMethod($method);
+ $this->setData($data);
+ $this->setQuery($query);
+
+ if ($connection) {
+ $this->setConnection($connection);
+ }
+ }
+
+ /**
+ * Sets the request method. Use one of the for consts.
+ *
+ * @param string $method Request method
+ *
+ * @return $this
+ */
+ public function setMethod($method)
+ {
+ return $this->setParam('method', $method);
+ }
+
+ /**
+ * Get request method.
+ *
+ * @return string Request method
+ */
+ public function getMethod()
+ {
+ return $this->getParam('method');
+ }
+
+ /**
+ * Sets the request data.
+ *
+ * @param array $data Request data
+ *
+ * @return $this
+ */
+ public function setData($data)
+ {
+ return $this->setParam('data', $data);
+ }
+
+ /**
+ * Return request data.
+ *
+ * @return array Request data
+ */
+ public function getData()
+ {
+ return $this->getParam('data');
+ }
+
+ /**
+ * Sets the request path.
+ *
+ * @param string $path Request path
+ *
+ * @return $this
+ */
+ public function setPath($path)
+ {
+ return $this->setParam('path', $path);
+ }
+
+ /**
+ * Return request path.
+ *
+ * @return string Request path
+ */
+ public function getPath()
+ {
+ return $this->getParam('path');
+ }
+
+ /**
+ * Return query params.
+ *
+ * @return array Query params
+ */
+ public function getQuery()
+ {
+ return $this->getParam('query');
+ }
+
+ /**
+ * @param array $query
+ *
+ * @return $this
+ */
+ public function setQuery(array $query = array())
+ {
+ return $this->setParam('query', $query);
+ }
+
+ /**
+ * @param \Elastica\Connection $connection
+ *
+ * @return $this
+ */
+ public function setConnection(Connection $connection)
+ {
+ $this->_connection = $connection;
+
+ return $this;
+ }
+
+ /**
+ * Return Connection Object.
+ *
+ * @throws Exception\InvalidException If no valid connection was setted
+ *
+ * @return \Elastica\Connection
+ */
+ public function getConnection()
+ {
+ if (empty($this->_connection)) {
+ throw new InvalidException('No valid connection object set');
+ }
+
+ return $this->_connection;
+ }
+
+ /**
+ * Sends request to server.
+ *
+ * @return \Elastica\Response Response object
+ */
+ public function send()
+ {
+ $transport = $this->getConnection()->getTransportObject();
+
+ // Refactor: Not full toArray needed in exec?
+ return $transport->exec($this, $this->getConnection()->toArray());
+ }
+
+ /**
+ * @return array
+ */
+ public function toArray()
+ {
+ $data = $this->getParams();
+ if ($this->_connection) {
+ $data['connection'] = $this->_connection->getParams();
+ }
+
+ return $data;
+ }
+
+ /**
+ * Converts request to curl request format.
+ *
+ * @return string
+ */
+ public function toString()
+ {
+ return JSON::stringify($this->toArray());
+ }
+
+ /**
+ * @return string
+ */
+ public function __toString()
+ {
+ return $this->toString();
+ }
+}
diff --git a/vendor/ruflin/elastica/lib/Elastica/Rescore/AbstractRescore.php b/vendor/ruflin/elastica/lib/Elastica/Rescore/AbstractRescore.php
new file mode 100644
index 00000000..0839424d
--- /dev/null
+++ b/vendor/ruflin/elastica/lib/Elastica/Rescore/AbstractRescore.php
@@ -0,0 +1,36 @@
+<?php
+namespace Elastica\Rescore;
+
+use Elastica\Param;
+
+/**
+ * Abstract rescore object. Should be extended by all rescorers.
+ *
+ * @author Jason Hu <mjhu91@gmail.com>
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/search-request-rescore.html
+ */
+abstract class AbstractRescore extends Param
+{
+ /**
+ * Overridden to return rescore as name.
+ *
+ * @return string name
+ */
+ protected function _getBaseName()
+ {
+ return 'rescore';
+ }
+
+ /**
+ * Sets window_size.
+ *
+ * @param int $size
+ *
+ * @return $this
+ */
+ public function setWindowSize($size)
+ {
+ return $this->setParam('window_size', $size);
+ }
+}
diff --git a/vendor/ruflin/elastica/lib/Elastica/Rescore/Query.php b/vendor/ruflin/elastica/lib/Elastica/Rescore/Query.php
new file mode 100644
index 00000000..3b0a1071
--- /dev/null
+++ b/vendor/ruflin/elastica/lib/Elastica/Rescore/Query.php
@@ -0,0 +1,91 @@
+<?php
+namespace Elastica\Rescore;
+
+use Elastica\Query as BaseQuery;
+
+/**
+ * Query Rescore.
+ *
+ * @author Jason Hu <mjhu91@gmail.com>
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/search-request-rescore.html
+ */
+class Query extends AbstractRescore
+{
+ /**
+ * Constructor.
+ *
+ * @param string|\Elastica\Query\AbstractQuery $rescoreQuery
+ * @param string|\Elastica\Query\AbstractQuery $query
+ */
+ public function __construct($query = null)
+ {
+ $this->setParam('query', array());
+ $this->setRescoreQuery($query);
+ }
+
+ /**
+ * Override default implementation so params are in the format
+ * expected by elasticsearch.
+ *
+ * @return array Rescore array
+ */
+ public function toArray()
+ {
+ $data = $this->getParams();
+
+ if (!empty($this->_rawParams)) {
+ $data = array_merge($data, $this->_rawParams);
+ }
+
+ return $data;
+ }
+
+ /**
+ * Sets rescoreQuery object.
+ *
+ * @param string|\Elastica\Query|\Elastica\Query\AbstractQuery $query
+ *
+ * @return $this
+ */
+ public function setRescoreQuery($rescoreQuery)
+ {
+ $query = BaseQuery::create($rescoreQuery);
+ $data = $query->toArray();
+
+ $query = $this->getParam('query');
+ $query['rescore_query'] = $data['query'];
+
+ return $this->setParam('query', $query);
+ }
+
+ /**
+ * Sets query_weight.
+ *
+ * @param float $weight
+ *
+ * @return $this
+ */
+ public function setQueryWeight($weight)
+ {
+ $query = $this->getParam('query');
+ $query['query_weight'] = $weight;
+
+ return $this->setParam('query', $query);
+ }
+
+ /**
+ * Sets rescore_query_weight.
+ *
+ * @param float $size
+ *
+ * @return $this
+ */
+ public function setRescoreQueryWeight($weight)
+ {
+ $query = $this->getParam('query');
+ $query['rescore_query_weight'] = $weight;
+
+ return $this->setParam('query', $query);
+ }
+}
diff --git a/vendor/ruflin/elastica/lib/Elastica/Response.php b/vendor/ruflin/elastica/lib/Elastica/Response.php
new file mode 100644
index 00000000..b537fe80
--- /dev/null
+++ b/vendor/ruflin/elastica/lib/Elastica/Response.php
@@ -0,0 +1,308 @@
+<?php
+namespace Elastica;
+
+use Elastica\Exception\JSONParseException;
+use Elastica\Exception\NotFoundException;
+
+/**
+ * Elastica Response object.
+ *
+ * Stores query time, and result array -> is given to result set, returned by ...
+ *
+ * @author Nicolas Ruflin <spam@ruflin.com>
+ */
+class Response
+{
+ /**
+ * Query time.
+ *
+ * @var float Query time
+ */
+ protected $_queryTime = null;
+
+ /**
+ * Response string (json).
+ *
+ * @var string Response
+ */
+ protected $_responseString = '';
+
+ /**
+ * Error.
+ *
+ * @var bool Error
+ */
+ protected $_error = false;
+
+ /**
+ * Transfer info.
+ *
+ * @var array transfer info
+ */
+ protected $_transferInfo = array();
+
+ /**
+ * Response.
+ *
+ * @var \Elastica\Response Response object
+ */
+ protected $_response = null;
+
+ /**
+ * HTTP response status code.
+ *
+ * @var int
+ */
+ protected $_status = null;
+
+ /**
+ * Construct.
+ *
+ * @param string|array $responseString Response string (json)
+ * @param int $responseStatus http status code
+ */
+ public function __construct($responseString, $responseStatus = null)
+ {
+ if (is_array($responseString)) {
+ $this->_response = $responseString;
+ } else {
+ $this->_responseString = $responseString;
+ }
+ $this->_status = $responseStatus;
+ }
+
+ /**
+ * Error message.
+ *
+ * @return string Error message
+ */
+ public function getError()
+ {
+ $message = '';
+ $response = $this->getData();
+
+ if (isset($response['error'])) {
+ $message = $response['error'];
+ }
+
+ return $message;
+ }
+
+ /**
+ * True if response has error.
+ *
+ * @return bool True if response has error
+ */
+ public function hasError()
+ {
+ $response = $this->getData();
+
+ if (isset($response['error'])) {
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * True if response has failed shards.
+ *
+ * @return bool True if response has failed shards
+ */
+ public function hasFailedShards()
+ {
+ try {
+ $shardsStatistics = $this->getShardsStatistics();
+ } catch (NotFoundException $e) {
+ return false;
+ }
+
+ return array_key_exists('failures', $shardsStatistics);
+ }
+
+ /**
+ * Checks if the query returned ok.
+ *
+ * @return bool True if ok
+ */
+ public function isOk()
+ {
+ $data = $this->getData();
+
+ // Bulk insert checks. Check every item
+ if (isset($data['status'])) {
+ if ($data['status'] >= 200 && $data['status'] <= 300) {
+ return true;
+ }
+
+ return false;
+ }
+
+ if (isset($data['items'])) {
+ if (isset($data['errors']) && true === $data['errors']) {
+ return false;
+ }
+
+ foreach ($data['items'] as $item) {
+ if (isset($item['index']['ok']) && false == $item['index']['ok']) {
+ return false;
+ } elseif (isset($item['index']['status']) && ($item['index']['status'] < 200 || $item['index']['status'] >= 300)) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ if ($this->_status >= 200 && $this->_status <= 300) {
+ // http status is ok
+ return true;
+ }
+
+ return (isset($data['ok']) && $data['ok']);
+ }
+
+ /**
+ * @return int
+ */
+ public function getStatus()
+ {
+ return $this->_status;
+ }
+
+ /**
+ * Response data array.
+ *
+ * @return array Response data array
+ */
+ public function getData()
+ {
+ if ($this->_response == null) {
+ $response = $this->_responseString;
+ if ($response === false) {
+ $this->_error = true;
+ } else {
+ try {
+ $response = JSON::parse($response);
+ } catch (JSONParseException $e) {
+ // leave reponse as is if parse fails
+ }
+ }
+
+ if (empty($response)) {
+ $response = array();
+ }
+
+ if (is_string($response)) {
+ $response = array('message' => $response);
+ }
+
+ $this->_response = $response;
+ }
+
+ return $this->_response;
+ }
+
+ /**
+ * Gets the transfer information.
+ *
+ * @return array Information about the curl request.
+ */
+ public function getTransferInfo()
+ {
+ return $this->_transferInfo;
+ }
+
+ /**
+ * Sets the transfer info of the curl request. This function is called
+ * from the \Elastica\Client::_callService .
+ *
+ * @param array $transferInfo The curl transfer information.
+ *
+ * @return $this
+ */
+ public function setTransferInfo(array $transferInfo)
+ {
+ $this->_transferInfo = $transferInfo;
+
+ return $this;
+ }
+
+ /**
+ * Returns query execution time.
+ *
+ * @return float Query time
+ */
+ public function getQueryTime()
+ {
+ return $this->_queryTime;
+ }
+
+ /**
+ * Sets the query time.
+ *
+ * @param float $queryTime Query time
+ *
+ * @return $this
+ */
+ public function setQueryTime($queryTime)
+ {
+ $this->_queryTime = $queryTime;
+
+ return $this;
+ }
+
+ /**
+ * Time request took.
+ *
+ * @throws \Elastica\Exception\NotFoundException
+ *
+ * @return int Time request took
+ */
+ public function getEngineTime()
+ {
+ $data = $this->getData();
+
+ if (!isset($data['took'])) {
+ throw new NotFoundException('Unable to find the field [took]from the response');
+ }
+
+ return $data['took'];
+ }
+
+ /**
+ * Get the _shard statistics for the response.
+ *
+ * @throws \Elastica\Exception\NotFoundException
+ *
+ * @return array
+ */
+ public function getShardsStatistics()
+ {
+ $data = $this->getData();
+
+ if (!isset($data['_shards'])) {
+ throw new NotFoundException('Unable to find the field [_shards] from the response');
+ }
+
+ return $data['_shards'];
+ }
+
+ /**
+ * Get the _scroll value for the response.
+ *
+ * @throws \Elastica\Exception\NotFoundException
+ *
+ * @return string
+ */
+ public function getScrollId()
+ {
+ $data = $this->getData();
+
+ if (!isset($data['_scroll_id'])) {
+ throw new NotFoundException('Unable to find the field [_scroll_id] from the response');
+ }
+
+ return $data['_scroll_id'];
+ }
+}
diff --git a/vendor/ruflin/elastica/lib/Elastica/Result.php b/vendor/ruflin/elastica/lib/Elastica/Result.php
new file mode 100644
index 00000000..6b3c68f2
--- /dev/null
+++ b/vendor/ruflin/elastica/lib/Elastica/Result.php
@@ -0,0 +1,217 @@
+<?php
+namespace Elastica;
+
+/**
+ * Elastica result item.
+ *
+ * Stores all information from a result
+ *
+ * @author Nicolas Ruflin <spam@ruflin.com>
+ */
+class Result
+{
+ /**
+ * Hit array.
+ *
+ * @var array Hit array
+ */
+ protected $_hit = array();
+
+ /**
+ * Constructs a single results object.
+ *
+ * @param array $hit Hit data
+ */
+ public function __construct(array $hit)
+ {
+ $this->_hit = $hit;
+ }
+
+ /**
+ * Returns a param from the result hit array.
+ *
+ * This function can be used to retrieve all data for which a specific
+ * function doesn't exist.
+ * If the param does not exist, an empty array is returned
+ *
+ * @param string $name Param name
+ *
+ * @return array Result data
+ */
+ public function getParam($name)
+ {
+ if (isset($this->_hit[$name])) {
+ return $this->_hit[$name];
+ }
+
+ return array();
+ }
+
+ /**
+ * Test if a param from the result hit is set.
+ *
+ * @param string $name Param name to test
+ *
+ * @return bool True if the param is set, false otherwise
+ */
+ public function hasParam($name)
+ {
+ return isset($this->_hit[$name]);
+ }
+
+ /**
+ * Returns the hit id.
+ *
+ * @return string Hit id
+ */
+ public function getId()
+ {
+ return $this->getParam('_id');
+ }
+
+ /**
+ * Returns the type of the result.
+ *
+ * @return string Result type
+ */
+ public function getType()
+ {
+ return $this->getParam('_type');
+ }
+
+ /**
+ * Returns list of fields.
+ *
+ * @return array Fields list
+ */
+ public function getFields()
+ {
+ return $this->getParam('fields');
+ }
+
+ /**
+ * Returns whether result has fields.
+ *
+ * @return bool
+ */
+ public function hasFields()
+ {
+ return $this->hasParam('fields');
+ }
+
+ /**
+ * Returns the index name of the result.
+ *
+ * @return string Index name
+ */
+ public function getIndex()
+ {
+ return $this->getParam('_index');
+ }
+
+ /**
+ * Returns the score of the result.
+ *
+ * @return float Result score
+ */
+ public function getScore()
+ {
+ return $this->getParam('_score');
+ }
+
+ /**
+ * Returns the raw hit array.
+ *
+ * @return array Hit array
+ */
+ public function getHit()
+ {
+ return $this->_hit;
+ }
+
+ /**
+ * Returns the version information from the hit.
+ *
+ * @return string|int Document version
+ */
+ public function getVersion()
+ {
+ return $this->getParam('_version');
+ }
+
+ /**
+ * Returns result data.
+ *
+ * Checks for partial result data with getFields, falls back to getSource
+ *
+ * @return array Result data array
+ */
+ public function getData()
+ {
+ if (isset($this->_hit['fields']) && !isset($this->_hit['_source'])) {
+ return $this->getFields();
+ }
+
+ return $this->getSource();
+ }
+
+ /**
+ * Returns the result source.
+ *
+ * @return array Source data array
+ */
+ public function getSource()
+ {
+ return $this->getParam('_source');
+ }
+
+ /**
+ * Returns result data.
+ *
+ * @return array Result data array
+ */
+ public function getHighlights()
+ {
+ return $this->getParam('highlight');
+ }
+
+ /**
+ * Returns explanation on how its score was computed.
+ *
+ * @return array explanations
+ */
+ public function getExplanation()
+ {
+ return $this->getParam('_explanation');
+ }
+
+ /**
+ * Magic function to directly access keys inside the result.
+ *
+ * Returns null if key does not exist
+ *
+ * @param string $key Key name
+ *
+ * @return mixed Key value
+ */
+ public function __get($key)
+ {
+ $source = $this->getData();
+
+ return array_key_exists($key, $source) ? $source[$key] : null;
+ }
+
+ /**
+ * Magic function to support isset() calls.
+ *
+ * @param string $key Key name
+ *
+ * @return bool
+ */
+ public function __isset($key)
+ {
+ $source = $this->getData();
+
+ return array_key_exists($key, $source) && $source[$key] !== null;
+ }
+}
diff --git a/vendor/ruflin/elastica/lib/Elastica/ResultSet.php b/vendor/ruflin/elastica/lib/Elastica/ResultSet.php
new file mode 100644
index 00000000..ae4141b9
--- /dev/null
+++ b/vendor/ruflin/elastica/lib/Elastica/ResultSet.php
@@ -0,0 +1,433 @@
+<?php
+namespace Elastica;
+
+use Elastica\Exception\InvalidException;
+
+/**
+ * Elastica result set.
+ *
+ * List of all hits that are returned for a search on elasticsearch
+ * Result set implements iterator
+ *
+ * @author Nicolas Ruflin <spam@ruflin.com>
+ */
+class ResultSet implements \Iterator, \Countable, \ArrayAccess
+{
+ /**
+ * Class for the static create method to use.
+ *
+ * @var string
+ */
+ protected static $_class = 'Elastica\\ResultSet';
+
+ /**
+ * Results.
+ *
+ * @var array Results
+ */
+ protected $_results = array();
+
+ /**
+ * Current position.
+ *
+ * @var int Current position
+ */
+ protected $_position = 0;
+
+ /**
+ * Response.
+ *
+ * @var \Elastica\Response Response object
+ */
+ protected $_response = null;
+
+ /**
+ * Query.
+ *
+ * @var \Elastica\Query Query object
+ */
+ protected $_query;
+
+ /**
+ * @var int
+ */
+ protected $_took = 0;
+
+ /**
+ * @var bool
+ */
+ protected $_timedOut = false;
+
+ /**
+ * @var int
+ */
+ protected $_totalHits = 0;
+
+ /**
+ * @var float
+ */
+ protected $_maxScore = 0;
+
+ /**
+ * Constructs ResultSet object.
+ *
+ * @param \Elastica\Response $response Response object
+ * @param \Elastica\Query $query Query object
+ */
+ public function __construct(Response $response, Query $query)
+ {
+ $this->rewind();
+ $this->_init($response);
+ $this->_query = $query;
+ }
+
+ /**
+ * Creates a new ResultSet object. Can be configured to return a different
+ * implementation of the ResultSet class.
+ *
+ * @param Response $response
+ * @param Query $query
+ *
+ * @return ResultSet
+ */
+ public static function create(Response $response, Query $query)
+ {
+ $class = static::$_class;
+
+ return new $class($response, $query);
+ }
+
+ /**
+ * Sets the class to be used for the static create method.
+ *
+ * @param string $class
+ */
+ public static function setClass($class)
+ {
+ static::$_class = $class;
+ }
+
+ /**
+ * Loads all data into the results object (initialisation).
+ *
+ * @param \Elastica\Response $response Response object
+ */
+ protected function _init(Response $response)
+ {
+ $this->_response = $response;
+ $result = $response->getData();
+ $this->_totalHits = isset($result['hits']['total']) ? $result['hits']['total'] : 0;
+ $this->_maxScore = isset($result['hits']['max_score']) ? $result['hits']['max_score'] : 0;
+ $this->_took = isset($result['took']) ? $result['took'] : 0;
+ $this->_timedOut = !empty($result['timed_out']);
+ if (isset($result['hits']['hits'])) {
+ foreach ($result['hits']['hits'] as $hit) {
+ $this->_results[] = new Result($hit);
+ }
+ }
+ }
+
+ /**
+ * Returns all results.
+ *
+ * @return Result[] Results
+ */
+ public function getResults()
+ {
+ return $this->_results;
+ }
+
+ /**
+ * Returns true if the response contains suggestion results; false otherwise.
+ *
+ * @return bool
+ */
+ public function hasSuggests()
+ {
+ $data = $this->_response->getData();
+
+ return isset($data['suggest']);
+ }
+
+ /**
+ * Return all suggests.
+ *
+ * @return array suggest results
+ */
+ public function getSuggests()
+ {
+ $data = $this->_response->getData();
+
+ return isset($data['suggest']) ? $data['suggest'] : array();
+ }
+
+ /**
+ * Returns whether facets exist.
+ *
+ * @return bool Facet existence
+ *
+ * @deprecated Facets are deprecated and will be removed in a future release. You are encouraged to migrate to aggregations instead.
+ */
+ public function hasFacets()
+ {
+ $data = $this->_response->getData();
+
+ return isset($data['facets']);
+ }
+
+ /**
+ * Returns whether aggregations exist.
+ *
+ * @return bool Aggregation existence
+ */
+ public function hasAggregations()
+ {
+ $data = $this->_response->getData();
+
+ return isset($data['aggregations']);
+ }
+
+ /**
+ * Returns all aggregation results.
+ *
+ * @return array
+ */
+ public function getAggregations()
+ {
+ $data = $this->_response->getData();
+
+ return isset($data['aggregations']) ? $data['aggregations'] : array();
+ }
+
+ /**
+ * Retrieve a specific aggregation from this result set.
+ *
+ * @param string $name the name of the desired aggregation
+ *
+ * @throws Exception\InvalidException if an aggregation by the given name cannot be found
+ *
+ * @return array
+ */
+ public function getAggregation($name)
+ {
+ $data = $this->_response->getData();
+
+ if (isset($data['aggregations']) && isset($data['aggregations'][$name])) {
+ return $data['aggregations'][$name];
+ }
+ throw new InvalidException("This result set does not contain an aggregation named {$name}.");
+ }
+
+ /**
+ * Returns all facets results.
+ *
+ * @return array Facet results
+ *
+ * @deprecated Facets are deprecated and will be removed in a future release. You are encouraged to migrate to aggregations instead.
+ */
+ public function getFacets()
+ {
+ $data = $this->_response->getData();
+
+ return isset($data['facets']) ? $data['facets'] : array();
+ }
+
+ /**
+ * Returns the total number of found hits.
+ *
+ * @return int Total hits
+ */
+ public function getTotalHits()
+ {
+ return (int) $this->_totalHits;
+ }
+
+ /**
+ * Returns the max score of the results found.
+ *
+ * @return float Max Score
+ */
+ public function getMaxScore()
+ {
+ return (float) $this->_maxScore;
+ }
+
+ /**
+ * Returns the total number of ms for this search to complete.
+ *
+ * @return int Total time
+ */
+ public function getTotalTime()
+ {
+ return (int) $this->_took;
+ }
+
+ /**
+ * Returns true iff the query has timed out.
+ *
+ * @return bool Timed out
+ */
+ public function hasTimedOut()
+ {
+ return (bool) $this->_timedOut;
+ }
+
+ /**
+ * Returns response object.
+ *
+ * @return \Elastica\Response Response object
+ */
+ public function getResponse()
+ {
+ return $this->_response;
+ }
+
+ /**
+ * @return \Elastica\Query
+ */
+ public function getQuery()
+ {
+ return $this->_query;
+ }
+
+ /**
+ * Returns size of current set.
+ *
+ * @return int Size of set
+ */
+ public function count()
+ {
+ return sizeof($this->_results);
+ }
+
+ /**
+ * Returns size of current suggests.
+ *
+ * @return int Size of suggests
+ */
+ public function countSuggests()
+ {
+ return sizeof($this->getSuggests());
+ }
+
+ /**
+ * Returns the current object of the set.
+ *
+ * @return \Elastica\Result|bool Set object or false if not valid (no more entries)
+ */
+ public function current()
+ {
+ if ($this->valid()) {
+ return $this->_results[$this->key()];
+ } else {
+ return false;
+ }
+ }
+
+ /**
+ * Sets pointer (current) to the next item of the set.
+ */
+ public function next()
+ {
+ $this->_position++;
+
+ return $this->current();
+ }
+
+ /**
+ * Returns the position of the current entry.
+ *
+ * @return int Current position
+ */
+ public function key()
+ {
+ return $this->_position;
+ }
+
+ /**
+ * Check if an object exists at the current position.
+ *
+ * @return bool True if object exists
+ */
+ public function valid()
+ {
+ return isset($this->_results[$this->key()]);
+ }
+
+ /**
+ * Resets position to 0, restarts iterator.
+ */
+ public function rewind()
+ {
+ $this->_position = 0;
+ }
+
+ /**
+ * Whether a offset exists.
+ *
+ * @link http://php.net/manual/en/arrayaccess.offsetexists.php
+ *
+ * @param int $offset
+ *
+ * @return bool true on success or false on failure.
+ */
+ public function offsetExists($offset)
+ {
+ return isset($this->_results[$offset]);
+ }
+
+ /**
+ * Offset to retrieve.
+ *
+ * @link http://php.net/manual/en/arrayaccess.offsetget.php
+ *
+ * @param int $offset
+ *
+ * @throws Exception\InvalidException If offset doesn't exist
+ *
+ * @return Result|null
+ */
+ public function offsetGet($offset)
+ {
+ if ($this->offsetExists($offset)) {
+ return $this->_results[$offset];
+ } else {
+ throw new InvalidException('Offset does not exist.');
+ }
+ }
+
+ /**
+ * Offset to set.
+ *
+ * @link http://php.net/manual/en/arrayaccess.offsetset.php
+ *
+ * @param int $offset
+ * @param Result $value
+ *
+ * @throws Exception\InvalidException
+ */
+ public function offsetSet($offset, $value)
+ {
+ if (!($value instanceof Result)) {
+ throw new InvalidException('ResultSet is a collection of Result only.');
+ }
+
+ if (!isset($this->_results[$offset])) {
+ throw new InvalidException('Offset does not exist.');
+ }
+
+ $this->_results[$offset] = $value;
+ }
+
+ /**
+ * Offset to unset.
+ *
+ * @link http://php.net/manual/en/arrayaccess.offsetunset.php
+ *
+ * @param int $offset
+ */
+ public function offsetUnset($offset)
+ {
+ unset($this->_results[$offset]);
+ }
+}
diff --git a/vendor/ruflin/elastica/lib/Elastica/ScanAndScroll.php b/vendor/ruflin/elastica/lib/Elastica/ScanAndScroll.php
new file mode 100644
index 00000000..6713856e
--- /dev/null
+++ b/vendor/ruflin/elastica/lib/Elastica/ScanAndScroll.php
@@ -0,0 +1,80 @@
+<?php
+namespace Elastica;
+
+/**
+ * Scan and Scroll Iterator.
+ *
+ * @author Manuel Andreo Garcia <andreo.garcia@gmail.com>
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/guide/current/scan-scroll.html
+ */
+class ScanAndScroll extends Scroll
+{
+ /**
+ * @var int
+ */
+ public $sizePerShard;
+
+ /**
+ * Constructor.
+ *
+ * @param Search $search
+ * @param string $expiryTime
+ * @param int $sizePerShard
+ */
+ public function __construct(Search $search, $expiryTime = '1m', $sizePerShard = 1000)
+ {
+ $this->sizePerShard = $sizePerShard;
+
+ parent::__construct($search, $expiryTime);
+ }
+
+ /**
+ * Initial scan search.
+ *
+ * @link http://php.net/manual/en/iterator.rewind.php
+ */
+ public function rewind()
+ {
+ // reset state
+ $this->_nextScrollId = null;
+ $this->_options = array(null, null, null, null);
+
+ $this->_saveOptions();
+
+ // initial scan request
+ $this->_search->getQuery()->setSize($this->sizePerShard);
+ $this->_search->setOption(Search::OPTION_SCROLL, $this->expiryTime);
+ $this->_search->setOption(Search::OPTION_SCROLL_ID, null);
+ $this->_search->setOption(Search::OPTION_SEARCH_TYPE, Search::OPTION_SEARCH_TYPE_SCAN);
+ $this->_setScrollId($this->_search->search());
+
+ $this->_revertOptions();
+
+ // first scroll request
+ $this->next();
+ }
+
+ /**
+ * Save all search options manipulated by Scroll.
+ */
+ protected function _saveOptions()
+ {
+ $query = $this->_search->getQuery();
+ if ($query->hasParam('size')) {
+ $this->_options[3] = $query->getParam('size');
+ }
+
+ parent::_saveOptions();
+ }
+
+ /**
+ * Revert search options to previously saved state.
+ */
+ protected function _revertOptions()
+ {
+ $this->_search->getQuery()->setSize($this->_options[3]);
+
+ parent::_revertOptions();
+ }
+}
diff --git a/vendor/ruflin/elastica/lib/Elastica/Script.php b/vendor/ruflin/elastica/lib/Elastica/Script.php
new file mode 100644
index 00000000..6df3d583
--- /dev/null
+++ b/vendor/ruflin/elastica/lib/Elastica/Script.php
@@ -0,0 +1,163 @@
+<?php
+namespace Elastica;
+
+use Elastica\Exception\InvalidException;
+
+/**
+ * Script objects, containing script internals.
+ *
+ * @author avasilenko <aa.vasilenko@gmail.com>
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/modules-scripting.html
+ */
+class Script extends AbstractUpdateAction
+{
+ const LANG_MVEL = 'mvel';
+ const LANG_JS = 'js';
+ const LANG_GROOVY = 'groovy';
+ const LANG_PYTHON = 'python';
+ const LANG_NATIVE = 'native';
+
+ /**
+ * @var string
+ */
+ private $_script;
+
+ /**
+ * @var string
+ */
+ private $_lang;
+
+ /**
+ * @param string $script
+ * @param array|null $params
+ * @param string|null $lang
+ */
+ public function __construct($script, array $params = null, $lang = null, $id = null)
+ {
+ $this->setScript($script);
+
+ if ($params) {
+ $this->setParams($params);
+ }
+
+ if ($lang) {
+ $this->setLang($lang);
+ }
+
+ if ($id) {
+ $this->setId($id);
+ }
+ }
+
+ /**
+ * @param string $lang
+ *
+ * @return $this
+ */
+ public function setLang($lang)
+ {
+ $this->_lang = $lang;
+
+ return $this;
+ }
+
+ /**
+ * @return string
+ */
+ public function getLang()
+ {
+ return $this->_lang;
+ }
+
+ /**
+ * @param string $script
+ *
+ * @return $this
+ */
+ public function setScript($script)
+ {
+ $this->_script = $script;
+
+ return $this;
+ }
+
+ /**
+ * @return string
+ */
+ public function getScript()
+ {
+ return $this->_script;
+ }
+
+ /**
+ * @param string|array|\Elastica\Script $data
+ *
+ * @throws \Elastica\Exception\InvalidException
+ *
+ * @return self
+ */
+ public static function create($data)
+ {
+ if ($data instanceof self) {
+ $script = $data;
+ } elseif (is_array($data)) {
+ $script = self::_createFromArray($data);
+ } elseif (is_string($data)) {
+ $script = new self($data);
+ } else {
+ throw new InvalidException('Failed to create script. Invalid data passed.');
+ }
+
+ return $script;
+ }
+
+ /**
+ * @param array $data
+ *
+ * @throws \Elastica\Exception\InvalidException
+ *
+ * @return self
+ */
+ protected static function _createFromArray(array $data)
+ {
+ if (!isset($data['script'])) {
+ throw new InvalidException("\$data['script'] is required");
+ }
+
+ $script = new self($data['script']);
+
+ if (isset($data['lang'])) {
+ $script->setLang($data['lang']);
+ }
+
+ if (isset($data['params'])) {
+ if (!is_array($data['params'])) {
+ throw new InvalidException("\$data['params'] should be array");
+ }
+ $script->setParams($data['params']);
+ }
+
+ return $script;
+ }
+
+ /**
+ * @return array
+ */
+ public function toArray()
+ {
+ $array = array(
+ 'script' => $this->_script,
+ );
+
+ if (!empty($this->_params)) {
+ $array['params'] = $this->_params;
+ }
+
+ if ($this->_lang) {
+ $array['lang'] = $this->_lang;
+ }
+
+ return $array;
+ }
+}
diff --git a/vendor/ruflin/elastica/lib/Elastica/ScriptFields.php b/vendor/ruflin/elastica/lib/Elastica/ScriptFields.php
new file mode 100644
index 00000000..41b5b913
--- /dev/null
+++ b/vendor/ruflin/elastica/lib/Elastica/ScriptFields.php
@@ -0,0 +1,65 @@
+<?php
+namespace Elastica;
+
+use Elastica\Exception\InvalidException;
+
+/**
+ * Container for scripts as fields.
+ *
+ * @author Sebastien Lavoie <github@lavoie.sl>
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/search-request-script-fields.html
+ */
+class ScriptFields extends Param
+{
+ /**
+ * @param \Elastica\Script[]|array $scripts OPTIONAL
+ */
+ public function __construct(array $scripts = array())
+ {
+ if ($scripts) {
+ $this->setScripts($scripts);
+ }
+ }
+
+ /**
+ * @param string $name Name of the Script field
+ * @param \Elastica\Script $script
+ *
+ * @throws \Elastica\Exception\InvalidException
+ *
+ * @return $this
+ */
+ public function addScript($name, Script $script)
+ {
+ if (!is_string($name) || !strlen($name)) {
+ throw new InvalidException('The name of a Script is required and must be a string');
+ }
+ $this->setParam($name, $script->toArray());
+
+ return $this;
+ }
+
+ /**
+ * @param \Elastica\Script[]|array $scripts Associative array of string => Elastica\Script
+ *
+ * @return $this
+ */
+ public function setScripts(array $scripts)
+ {
+ $this->_params = array();
+ foreach ($scripts as $name => $script) {
+ $this->addScript($name, $script);
+ }
+
+ return $this;
+ }
+
+ /**
+ * @return array
+ */
+ public function toArray()
+ {
+ return $this->_params;
+ }
+}
diff --git a/vendor/ruflin/elastica/lib/Elastica/Scroll.php b/vendor/ruflin/elastica/lib/Elastica/Scroll.php
new file mode 100644
index 00000000..44fa73e9
--- /dev/null
+++ b/vendor/ruflin/elastica/lib/Elastica/Scroll.php
@@ -0,0 +1,174 @@
+<?php
+namespace Elastica;
+
+/**
+ * Scroll Iterator.
+ *
+ * @author Manuel Andreo Garcia <andreo.garcia@gmail.com>
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/search-request-scroll.html
+ */
+class Scroll implements \Iterator
+{
+ /**
+ * @var string
+ */
+ public $expiryTime;
+
+ /**
+ * @var Search
+ */
+ protected $_search;
+
+ /**
+ * @var null|string
+ */
+ protected $_nextScrollId = null;
+
+ /**
+ * @var null|ResultSet
+ */
+ protected $_currentResultSet = null;
+
+ /**
+ * 0: scroll<br>
+ * 1: scroll id<br>
+ * 2: search type.
+ *
+ * @var array
+ */
+ protected $_options = array(null, null, null);
+
+ /**
+ * Constructor.
+ *
+ * @param Search $search
+ * @param string $expiryTime
+ */
+ public function __construct(Search $search, $expiryTime = '1m')
+ {
+ $this->_search = $search;
+ $this->expiryTime = $expiryTime;
+ }
+
+ /**
+ * Returns current result set.
+ *
+ * @link http://php.net/manual/en/iterator.current.php
+ *
+ * @return ResultSet
+ */
+ public function current()
+ {
+ return $this->_currentResultSet;
+ }
+
+ /**
+ * Next scroll search.
+ *
+ * @link http://php.net/manual/en/iterator.next.php
+ */
+ public function next()
+ {
+ $this->_saveOptions();
+
+ $this->_search->setOption(Search::OPTION_SCROLL, $this->expiryTime);
+ $this->_search->setOption(Search::OPTION_SCROLL_ID, $this->_nextScrollId);
+ $this->_search->setOption(Search::OPTION_SEARCH_TYPE, Search::OPTION_SEARCH_TYPE_SCROLL);
+ $this->_setScrollId($this->_search->search());
+
+ $this->_revertOptions();
+ }
+
+ /**
+ * Returns scroll id.
+ *
+ * @link http://php.net/manual/en/iterator.key.php
+ *
+ * @return string
+ */
+ public function key()
+ {
+ return $this->_nextScrollId;
+ }
+
+ /**
+ * Returns true if current result set contains at least one hit.
+ *
+ * @link http://php.net/manual/en/iterator.valid.php
+ *
+ * @return bool
+ */
+ public function valid()
+ {
+ return
+ $this->_nextScrollId !== null
+ && $this->_currentResultSet !== null
+ && $this->_currentResultSet->count() > 0;
+ }
+
+ /**
+ * Initial scroll search.
+ *
+ * @link http://php.net/manual/en/iterator.rewind.php
+ */
+ public function rewind()
+ {
+ // reset state
+ $this->_nextScrollId = null;
+ $this->_options = array(null, null, null);
+
+ // initial search
+ $this->_saveOptions();
+
+ $this->_search->setOption(Search::OPTION_SCROLL, $this->expiryTime);
+ $this->_search->setOption(Search::OPTION_SCROLL_ID, null);
+ $this->_search->setOption(Search::OPTION_SEARCH_TYPE, null);
+ $this->_setScrollId($this->_search->search());
+
+ $this->_revertOptions();
+ }
+
+ /**
+ * Prepares Scroll for next request.
+ *
+ * @param ResultSet $resultSet
+ */
+ protected function _setScrollId(ResultSet $resultSet)
+ {
+ $this->_currentResultSet = $resultSet;
+
+ $this->_nextScrollId = null;
+ if ($resultSet->getResponse()->isOk()) {
+ $this->_nextScrollId = $resultSet->getResponse()->getScrollId();
+ }
+ }
+
+ /**
+ * Save all search options manipulated by Scroll.
+ */
+ protected function _saveOptions()
+ {
+ if ($this->_search->hasOption(Search::OPTION_SCROLL)) {
+ $this->_options[0] = $this->_search->getOption(Search::OPTION_SCROLL);
+ }
+
+ if ($this->_search->hasOption(Search::OPTION_SCROLL_ID)) {
+ $this->_options[1] = $this->_search->getOption(Search::OPTION_SCROLL_ID);
+ }
+
+ if ($this->_search->hasOption(Search::OPTION_SEARCH_TYPE)) {
+ $this->_options[2] = $this->_search->getOption(Search::OPTION_SEARCH_TYPE);
+ }
+ }
+
+ /**
+ * Revert search options to previously saved state.
+ */
+ protected function _revertOptions()
+ {
+ $this->_search->setOption(Search::OPTION_SCROLL, $this->_options[0]);
+ $this->_search->setOption(Search::OPTION_SCROLL_ID, $this->_options[1]);
+ $this->_search->setOption(Search::OPTION_SEARCH_TYPE, $this->_options[2]);
+ }
+}
diff --git a/vendor/ruflin/elastica/lib/Elastica/Search.php b/vendor/ruflin/elastica/lib/Elastica/Search.php
new file mode 100644
index 00000000..7306eb75
--- /dev/null
+++ b/vendor/ruflin/elastica/lib/Elastica/Search.php
@@ -0,0 +1,553 @@
+<?php
+namespace Elastica;
+
+use Elastica\Exception\InvalidException;
+
+/**
+ * Elastica search object.
+ *
+ * @author Nicolas Ruflin <spam@ruflin.com>
+ */
+class Search
+{
+ /*
+ * Options
+ */
+ const OPTION_SEARCH_TYPE = 'search_type';
+ const OPTION_ROUTING = 'routing';
+ const OPTION_PREFERENCE = 'preference';
+ const OPTION_VERSION = 'version';
+ const OPTION_TIMEOUT = 'timeout';
+ const OPTION_FROM = 'from';
+ const OPTION_SIZE = 'size';
+ const OPTION_SCROLL = 'scroll';
+ const OPTION_SCROLL_ID = 'scroll_id';
+ const OPTION_QUERY_CACHE = 'query_cache';
+
+ /*
+ * Search types
+ */
+ const OPTION_SEARCH_TYPE_COUNT = 'count';
+ const OPTION_SEARCH_TYPE_SCAN = 'scan';
+ const OPTION_SEARCH_TYPE_DFS_QUERY_THEN_FETCH = 'dfs_query_then_fetch';
+ const OPTION_SEARCH_TYPE_DFS_QUERY_AND_FETCH = 'dfs_query_and_fetch';
+ const OPTION_SEARCH_TYPE_QUERY_THEN_FETCH = 'query_then_fetch';
+ const OPTION_SEARCH_TYPE_QUERY_AND_FETCH = 'query_and_fetch';
+ const OPTION_SEARCH_TYPE_SUGGEST = 'suggest';
+ const OPTION_SEARCH_TYPE_SCROLL = 'scroll';
+ const OPTION_SEARCH_IGNORE_UNAVAILABLE = 'ignore_unavailable';
+
+ /**
+ * Array of indices.
+ *
+ * @var array
+ */
+ protected $_indices = array();
+
+ /**
+ * Array of types.
+ *
+ * @var array
+ */
+ protected $_types = array();
+
+ /**
+ * @var \Elastica\Query
+ */
+ protected $_query;
+
+ /**
+ * @var array
+ */
+ protected $_options = array();
+
+ /**
+ * Client object.
+ *
+ * @var \Elastica\Client
+ */
+ protected $_client;
+
+ /**
+ * Constructs search object.
+ *
+ * @param \Elastica\Client $client Client object
+ */
+ public function __construct(Client $client)
+ {
+ $this->_client = $client;
+ }
+
+ /**
+ * Adds a index to the list.
+ *
+ * @param \Elastica\Index|string $index Index object or string
+ *
+ * @throws \Elastica\Exception\InvalidException
+ *
+ * @return $this
+ */
+ public function addIndex($index)
+ {
+ if ($index instanceof Index) {
+ $index = $index->getName();
+ }
+
+ if (!is_scalar($index)) {
+ throw new InvalidException('Invalid param type');
+ }
+
+ $this->_indices[] = (string) $index;
+
+ return $this;
+ }
+
+ /**
+ * Add array of indices at once.
+ *
+ * @param array $indices
+ *
+ * @return $this
+ */
+ public function addIndices(array $indices = array())
+ {
+ foreach ($indices as $index) {
+ $this->addIndex($index);
+ }
+
+ return $this;
+ }
+
+ /**
+ * Adds a type to the current search.
+ *
+ * @param \Elastica\Type|string $type Type name or object
+ *
+ * @throws \Elastica\Exception\InvalidException
+ *
+ * @return $this
+ */
+ public function addType($type)
+ {
+ if ($type instanceof Type) {
+ $type = $type->getName();
+ }
+
+ if (!is_string($type)) {
+ throw new InvalidException('Invalid type type');
+ }
+
+ $this->_types[] = $type;
+
+ return $this;
+ }
+
+ /**
+ * Add array of types.
+ *
+ * @param array $types
+ *
+ * @return $this
+ */
+ public function addTypes(array $types = array())
+ {
+ foreach ($types as $type) {
+ $this->addType($type);
+ }
+
+ return $this;
+ }
+
+ /**
+ * @param string|array|\Elastica\Query|\Elastica\Suggest|\Elastica\Query\AbstractQuery|\Elastica\Filter\AbstractFilter $query|
+ *
+ * @return $this
+ */
+ public function setQuery($query)
+ {
+ $this->_query = Query::create($query);
+
+ return $this;
+ }
+
+ /**
+ * @param string $key
+ * @param mixed $value
+ *
+ * @return $this
+ */
+ public function setOption($key, $value)
+ {
+ $this->_validateOption($key);
+
+ $this->_options[$key] = $value;
+
+ return $this;
+ }
+
+ /**
+ * @param array $options
+ *
+ * @return $this
+ */
+ public function setOptions(array $options)
+ {
+ $this->clearOptions();
+
+ foreach ($options as $key => $value) {
+ $this->setOption($key, $value);
+ }
+
+ return $this;
+ }
+
+ /**
+ * @return $this
+ */
+ public function clearOptions()
+ {
+ $this->_options = array();
+
+ return $this;
+ }
+
+ /**
+ * @param string $key
+ * @param mixed $value
+ *
+ * @return $this
+ */
+ public function addOption($key, $value)
+ {
+ $this->_validateOption($key);
+
+ if (!isset($this->_options[$key])) {
+ $this->_options[$key] = array();
+ }
+
+ $this->_options[$key][] = $value;
+
+ return $this;
+ }
+
+ /**
+ * @param string $key
+ *
+ * @return bool
+ */
+ public function hasOption($key)
+ {
+ return isset($this->_options[$key]);
+ }
+
+ /**
+ * @param string $key
+ *
+ * @throws \Elastica\Exception\InvalidException
+ *
+ * @return mixed
+ */
+ public function getOption($key)
+ {
+ if (!$this->hasOption($key)) {
+ throw new InvalidException('Option '.$key.' does not exist');
+ }
+
+ return $this->_options[$key];
+ }
+
+ /**
+ * @return array
+ */
+ public function getOptions()
+ {
+ return $this->_options;
+ }
+
+ /**
+ * @param string $key
+ *
+ * @throws \Elastica\Exception\InvalidException
+ *
+ * @return bool
+ */
+ protected function _validateOption($key)
+ {
+ switch ($key) {
+ case self::OPTION_SEARCH_TYPE:
+ case self::OPTION_ROUTING:
+ case self::OPTION_PREFERENCE:
+ case self::OPTION_VERSION:
+ case self::OPTION_TIMEOUT:
+ case self::OPTION_FROM:
+ case self::OPTION_SIZE:
+ case self::OPTION_SCROLL:
+ case self::OPTION_SCROLL_ID:
+ case self::OPTION_SEARCH_TYPE_SUGGEST:
+ case self::OPTION_SEARCH_IGNORE_UNAVAILABLE:
+ case self::OPTION_QUERY_CACHE:
+ return true;
+ }
+
+ throw new InvalidException('Invalid option '.$key);
+ }
+
+ /**
+ * Return client object.
+ *
+ * @return \Elastica\Client Client object
+ */
+ public function getClient()
+ {
+ return $this->_client;
+ }
+
+ /**
+ * Return array of indices.
+ *
+ * @return array List of index names
+ */
+ public function getIndices()
+ {
+ return $this->_indices;
+ }
+
+ /**
+ * @return bool
+ */
+ public function hasIndices()
+ {
+ return count($this->_indices) > 0;
+ }
+
+ /**
+ * @param Index|string $index
+ *
+ * @return bool
+ */
+ public function hasIndex($index)
+ {
+ if ($index instanceof Index) {
+ $index = $index->getName();
+ }
+
+ return in_array($index, $this->_indices);
+ }
+
+ /**
+ * Return array of types.
+ *
+ * @return array List of types
+ */
+ public function getTypes()
+ {
+ return $this->_types;
+ }
+
+ /**
+ * @return bool
+ */
+ public function hasTypes()
+ {
+ return count($this->_types) > 0;
+ }
+
+ /**
+ * @param \Elastica\Type|string $type
+ *
+ * @return bool
+ */
+ public function hasType($type)
+ {
+ if ($type instanceof Type) {
+ $type = $type->getName();
+ }
+
+ return in_array($type, $this->_types);
+ }
+
+ /**
+ * @return \Elastica\Query
+ */
+ public function getQuery()
+ {
+ if (null === $this->_query) {
+ $this->_query = Query::create('');
+ }
+
+ return $this->_query;
+ }
+
+ /**
+ * Creates new search object.
+ *
+ * @param \Elastica\SearchableInterface $searchObject
+ *
+ * @return Search
+ */
+ public static function create(SearchableInterface $searchObject)
+ {
+ return $searchObject->createSearch();
+ }
+
+ /**
+ * Combines indices and types to the search request path.
+ *
+ * @return string Search path
+ */
+ public function getPath()
+ {
+ if (isset($this->_options[self::OPTION_SCROLL_ID])) {
+ return '_search/scroll';
+ }
+
+ $indices = $this->getIndices();
+
+ $path = '';
+ $types = $this->getTypes();
+
+ if (empty($indices)) {
+ if (!empty($types)) {
+ $path .= '_all';
+ }
+ } else {
+ $path .= implode(',', $indices);
+ }
+
+ if (!empty($types)) {
+ $path .= '/'.implode(',', $types);
+ }
+
+ // Add full path based on indices and types -> could be all
+ return $path.'/_search';
+ }
+
+ /**
+ * Search in the set indices, types.
+ *
+ * @param mixed $query
+ * @param int|array $options OPTIONAL Limit or associative array of options (option=>value)
+ *
+ * @throws \Elastica\Exception\InvalidException
+ *
+ * @return \Elastica\ResultSet
+ */
+ public function search($query = '', $options = null)
+ {
+ $this->setOptionsAndQuery($options, $query);
+
+ $query = $this->getQuery();
+ $path = $this->getPath();
+
+ $params = $this->getOptions();
+
+ // Send scroll_id via raw HTTP body to handle cases of very large (> 4kb) ids.
+ if ('_search/scroll' == $path) {
+ $data = $params[self::OPTION_SCROLL_ID];
+ unset($params[self::OPTION_SCROLL_ID]);
+ } else {
+ $data = $query->toArray();
+ }
+
+ $response = $this->getClient()->request(
+ $path,
+ Request::GET,
+ $data,
+ $params
+ );
+
+ return ResultSet::create($response, $query);
+ }
+
+ /**
+ * @param mixed $query
+ * @param $fullResult (default = false) By default only the total hit count is returned. If set to true, the full ResultSet including aggregations is returned.
+ *
+ * @return int|ResultSet
+ */
+ public function count($query = '', $fullResult = false)
+ {
+ $this->setOptionsAndQuery(null, $query);
+
+ $query = $this->getQuery();
+ $path = $this->getPath();
+
+ $response = $this->getClient()->request(
+ $path,
+ Request::GET,
+ $query->toArray(),
+ array(self::OPTION_SEARCH_TYPE => self::OPTION_SEARCH_TYPE_COUNT)
+ );
+ $resultSet = ResultSet::create($response, $query);
+
+ return $fullResult ? $resultSet : $resultSet->getTotalHits();
+ }
+
+ /**
+ * @param array|int $options
+ * @param string|array|\Elastica\Query $query
+ *
+ * @return $this
+ */
+ public function setOptionsAndQuery($options = null, $query = '')
+ {
+ if ('' != $query) {
+ $this->setQuery($query);
+ }
+
+ if (is_int($options)) {
+ $this->getQuery()->setSize($options);
+ } elseif (is_array($options)) {
+ if (isset($options['limit'])) {
+ $this->getQuery()->setSize($options['limit']);
+ unset($options['limit']);
+ }
+ if (isset($options['explain'])) {
+ $this->getQuery()->setExplain($options['explain']);
+ unset($options['explain']);
+ }
+ $this->setOptions($options);
+ }
+
+ return $this;
+ }
+
+ /**
+ * @param Suggest $suggest
+ *
+ * @return $this
+ */
+ public function setSuggest(Suggest $suggest)
+ {
+ return $this->setOptionsAndQuery(array(self::OPTION_SEARCH_TYPE_SUGGEST => 'suggest'), $suggest);
+ }
+
+ /**
+ * Returns the Scroll Iterator.
+ *
+ * @see Elastica\Scroll
+ *
+ * @param string $expiryTime
+ *
+ * @return Scroll
+ */
+ public function scroll($expiryTime = '1m')
+ {
+ return new Scroll($this, $expiryTime);
+ }
+
+ /**
+ * Returns the ScanAndScroll Iterator.
+ *
+ * @see Elastica\ScanAndScroll
+ *
+ * @param string $expiryTime
+ * @param int $sizePerShard
+ *
+ * @return ScanAndScroll
+ */
+ public function scanAndScroll($expiryTime = '1m', $sizePerShard = 1000)
+ {
+ return new ScanAndScroll($this, $expiryTime, $sizePerShard);
+ }
+}
diff --git a/vendor/ruflin/elastica/lib/Elastica/SearchableInterface.php b/vendor/ruflin/elastica/lib/Elastica/SearchableInterface.php
new file mode 100644
index 00000000..abfacb85
--- /dev/null
+++ b/vendor/ruflin/elastica/lib/Elastica/SearchableInterface.php
@@ -0,0 +1,52 @@
+<?php
+namespace Elastica;
+
+/**
+ * Elastica searchable interface.
+ *
+ * @author Thibault Duplessis <thibault.duplessis@gmail.com>
+ */
+interface SearchableInterface
+{
+ /**
+ * Searches results for a query.
+ *
+ * TODO: Improve sample code
+ * {
+ * "from" : 0,
+ * "size" : 10,
+ * "sort" : {
+ * "postDate" : {"reverse" : true},
+ * "user" : { },
+ * "_score" : { }
+ * },
+ * "query" : {
+ * "term" : { "user" : "kimchy" }
+ * }
+ * }
+ *
+ * @param string|array|\Elastica\Query $query Array with all query data inside or a Elastica\Query object
+ *
+ * @return \Elastica\ResultSet ResultSet with all results inside
+ */
+ public function search($query = '', $options = null);
+
+ /**
+ * Counts results for a query.
+ *
+ * If no query is set, matchall query is created
+ *
+ * @param string|array|\Elastica\Query $query Array with all query data inside or a Elastica\Query object
+ *
+ * @return int number of documents matching the query
+ */
+ public function count($query = '');
+
+ /**
+ * @param \Elastica\Query $query
+ * @param array $options
+ *
+ * @return \Elastica\Search
+ */
+ public function createSearch($query = '', $options = null);
+}
diff --git a/vendor/ruflin/elastica/lib/Elastica/Snapshot.php b/vendor/ruflin/elastica/lib/Elastica/Snapshot.php
new file mode 100644
index 00000000..80924b79
--- /dev/null
+++ b/vendor/ruflin/elastica/lib/Elastica/Snapshot.php
@@ -0,0 +1,176 @@
+<?php
+namespace Elastica;
+
+use Elastica\Exception\NotFoundException;
+use Elastica\Exception\ResponseException;
+
+/**
+ * Class Snapshot.
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/modules-snapshots.html
+ */
+class Snapshot
+{
+ /**
+ * @var Client
+ */
+ protected $_client;
+
+ /**
+ * @param Client $client
+ */
+ public function __construct(Client $client)
+ {
+ $this->_client = $client;
+ }
+
+ /**
+ * Register a snapshot repository.
+ *
+ * @param string $name the name of the repository
+ * @param string $type the repository type ("fs" for file system)
+ * @param array $settings Additional repository settings. If type "fs" is used, the "location" setting must be provided.
+ *
+ * @return Response
+ */
+ public function registerRepository($name, $type, $settings = array())
+ {
+ $data = array(
+ 'type' => $type,
+ 'settings' => $settings,
+ );
+
+ return $this->request($name, Request::PUT, $data);
+ }
+
+ /**
+ * Retrieve a repository record by name.
+ *
+ * @param string $name the name of the desired repository
+ *
+ * @throws Exception\ResponseException
+ * @throws Exception\NotFoundException
+ *
+ * @return array
+ */
+ public function getRepository($name)
+ {
+ try {
+ $response = $this->request($name);
+ } catch (ResponseException $e) {
+ if ($e->getResponse()->getStatus() == 404) {
+ throw new NotFoundException("Repository '".$name."' does not exist.");
+ }
+ throw $e;
+ }
+ $data = $response->getData();
+
+ return $data[$name];
+ }
+
+ /**
+ * Retrieve all repository records.
+ *
+ * @return array
+ */
+ public function getAllRepositories()
+ {
+ return $this->request('_all')->getData();
+ }
+
+ /**
+ * Create a new snapshot.
+ *
+ * @param string $repository the name of the repository in which this snapshot should be stored
+ * @param string $name the name of this snapshot
+ * @param array $options optional settings for this snapshot
+ * @param bool $waitForCompletion if true, the request will not return until the snapshot operation is complete
+ *
+ * @return Response
+ */
+ public function createSnapshot($repository, $name, $options = array(), $waitForCompletion = false)
+ {
+ return $this->request($repository.'/'.$name, Request::PUT, $options, array('wait_for_completion' => $waitForCompletion));
+ }
+
+ /**
+ * Retrieve data regarding a specific snapshot.
+ *
+ * @param string $repository the name of the repository from which to retrieve the snapshot
+ * @param string $name the name of the desired snapshot
+ *
+ * @throws Exception\ResponseException
+ * @throws Exception\NotFoundException
+ *
+ * @return array
+ */
+ public function getSnapshot($repository, $name)
+ {
+ try {
+ $response = $this->request($repository.'/'.$name);
+ } catch (ResponseException $e) {
+ if ($e->getResponse()->getStatus() == 404) {
+ throw new NotFoundException("Snapshot '".$name."' does not exist in repository '".$repository."'.");
+ }
+ throw $e;
+ }
+ $data = $response->getData();
+
+ return $data['snapshots'][0];
+ }
+
+ /**
+ * Retrieve data regarding all snapshots in the given repository.
+ *
+ * @param string $repository the repository name
+ *
+ * @return array
+ */
+ public function getAllSnapshots($repository)
+ {
+ return $this->request($repository.'/_all')->getData();
+ }
+
+ /**
+ * Delete a snapshot.
+ *
+ * @param string $repository the repository in which the snapshot resides
+ * @param string $name the name of the snapshot to be deleted
+ *
+ * @return Response
+ */
+ public function deleteSnapshot($repository, $name)
+ {
+ return $this->request($repository.'/'.$name, Request::DELETE);
+ }
+
+ /**
+ * Restore a snapshot.
+ *
+ * @param string $repository the name of the repository
+ * @param string $name the name of the snapshot
+ * @param array $options options for the restore operation
+ * @param bool $waitForCompletion if true, the request will not return until the restore operation is complete
+ *
+ * @return Response
+ */
+ public function restoreSnapshot($repository, $name, $options = array(), $waitForCompletion = false)
+ {
+ return $this->request($repository.'/'.$name.'/_restore', Request::POST, $options, array('wait_for_completion' => $waitForCompletion));
+ }
+
+ /**
+ * Perform a snapshot request.
+ *
+ * @param string $path the URL
+ * @param string $method the HTTP method
+ * @param array $data request body data
+ * @param array $query query string parameters
+ *
+ * @return Response
+ */
+ public function request($path, $method = Request::GET, $data = array(), array $query = array())
+ {
+ return $this->_client->request('/_snapshot/'.$path, $method, $data, $query);
+ }
+}
diff --git a/vendor/ruflin/elastica/lib/Elastica/Status.php b/vendor/ruflin/elastica/lib/Elastica/Status.php
new file mode 100644
index 00000000..c22a5f61
--- /dev/null
+++ b/vendor/ruflin/elastica/lib/Elastica/Status.php
@@ -0,0 +1,177 @@
+<?php
+namespace Elastica;
+
+use Elastica\Exception\ResponseException;
+use Elastica\Index\Status as IndexStatus;
+
+/**
+ * Elastica general status.
+ *
+ * @author Nicolas Ruflin <spam@ruflin.com>
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/indices-status.html
+ */
+class Status
+{
+ /**
+ * Contains all status infos.
+ *
+ * @var \Elastica\Response Response object
+ */
+ protected $_response = null;
+
+ /**
+ * Data.
+ *
+ * @var array Data
+ */
+ protected $_data = array();
+
+ /**
+ * Client object.
+ *
+ * @var \Elastica\Client Client object
+ */
+ protected $_client = null;
+
+ /**
+ * Constructs Status object.
+ *
+ * @param \Elastica\Client $client Client object
+ */
+ public function __construct(Client $client)
+ {
+ $this->_client = $client;
+ $this->refresh();
+ }
+
+ /**
+ * Returns status data.
+ *
+ * @return array Status data
+ */
+ public function getData()
+ {
+ return $this->_data;
+ }
+
+ /**
+ * Returns status objects of all indices.
+ *
+ * @return array|\Elastica\Index\Status[] List of Elastica\Client\Index objects
+ */
+ public function getIndexStatuses()
+ {
+ $statuses = array();
+ foreach ($this->getIndexNames() as $name) {
+ $index = new Index($this->_client, $name);
+ $statuses[] = new IndexStatus($index);
+ }
+
+ return $statuses;
+ }
+
+ /**
+ * Returns a list of the existing index names.
+ *
+ * @return array Index names list
+ */
+ public function getIndexNames()
+ {
+ return array_keys($this->_data['indices']);
+ }
+
+ /**
+ * Checks if the given index exists.
+ *
+ * @param string $name Index name to check
+ *
+ * @return bool True if index exists
+ */
+ public function indexExists($name)
+ {
+ return in_array($name, $this->getIndexNames());
+ }
+
+ /**
+ * Checks if the given alias exists.
+ *
+ * @param string $name Alias name
+ *
+ * @return bool True if alias exists
+ */
+ public function aliasExists($name)
+ {
+ return count($this->getIndicesWithAlias($name)) > 0;
+ }
+
+ /**
+ * Returns an array with all indices that the given alias name points to.
+ *
+ * @param string $alias Alias name
+ *
+ * @return array|\Elastica\Index[] List of Elastica\Index
+ */
+ public function getIndicesWithAlias($alias)
+ {
+ $response = null;
+ try {
+ $response = $this->_client->request('/_alias/'.$alias);
+ } catch (ResponseException $e) {
+ $transferInfo = $e->getResponse()->getTransferInfo();
+ // 404 means the index alias doesn't exist which means no indexes have it.
+ if ($transferInfo['http_code'] === 404) {
+ return array();
+ }
+ // If we don't have a 404 then this is still unexpected so rethrow the exception.
+ throw $e;
+ }
+ $indices = array();
+ foreach ($response->getData() as $name => $unused) {
+ $indices[] = new Index($this->_client, $name);
+ }
+
+ return $indices;
+ }
+
+ /**
+ * Returns response object.
+ *
+ * @return \Elastica\Response Response object
+ */
+ public function getResponse()
+ {
+ return $this->_response;
+ }
+
+ /**
+ * Return shards info.
+ *
+ * @return array Shards info
+ */
+ public function getShards()
+ {
+ return $this->_data['shards'];
+ }
+
+ /**
+ * Refresh status object.
+ */
+ public function refresh()
+ {
+ $path = '_status';
+ $this->_response = $this->_client->request($path, Request::GET);
+ $this->_data = $this->getResponse()->getData();
+ }
+
+ /**
+ * Refresh serverStatus object.
+ */
+ public function getServerStatus()
+ {
+ $path = '';
+ $response = $this->_client->request($path, Request::GET);
+
+ return $response->getData();
+ }
+}
diff --git a/vendor/ruflin/elastica/lib/Elastica/Suggest.php b/vendor/ruflin/elastica/lib/Elastica/Suggest.php
new file mode 100644
index 00000000..73b1ea36
--- /dev/null
+++ b/vendor/ruflin/elastica/lib/Elastica/Suggest.php
@@ -0,0 +1,65 @@
+<?php
+namespace Elastica;
+
+use Elastica\Exception\NotImplementedException;
+use Elastica\Suggest\AbstractSuggest;
+
+/**
+ * Class Suggest.
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/search-suggesters.html
+ */
+class Suggest extends Param
+{
+ /**
+ * @param AbstractSuggest $suggestion
+ */
+ public function __construct(AbstractSuggest $suggestion = null)
+ {
+ if (!is_null($suggestion)) {
+ $this->addSuggestion($suggestion);
+ }
+ }
+
+ /**
+ * Set the global text for this suggester.
+ *
+ * @param string $text
+ *
+ * @return $this
+ */
+ public function setGlobalText($text)
+ {
+ return $this->setParam('text', $text);
+ }
+
+ /**
+ * Add a suggestion to this suggest clause.
+ *
+ * @param AbstractSuggest $suggestion
+ *
+ * @return $this
+ */
+ public function addSuggestion(AbstractSuggest $suggestion)
+ {
+ return $this->setParam($suggestion->getName(), $suggestion->toArray());
+ }
+
+ /**
+ * @param Suggest|AbstractSuggest $suggestion
+ *
+ * @throws Exception\NotImplementedException
+ *
+ * @return self
+ */
+ public static function create($suggestion)
+ {
+ switch (true) {
+ case $suggestion instanceof self:
+ return $suggestion;
+ case $suggestion instanceof AbstractSuggest:
+ return new self($suggestion);
+ }
+ throw new NotImplementedException();
+ }
+}
diff --git a/vendor/ruflin/elastica/lib/Elastica/Suggest/AbstractSuggest.php b/vendor/ruflin/elastica/lib/Elastica/Suggest/AbstractSuggest.php
new file mode 100644
index 00000000..00f21e44
--- /dev/null
+++ b/vendor/ruflin/elastica/lib/Elastica/Suggest/AbstractSuggest.php
@@ -0,0 +1,97 @@
+<?php
+namespace Elastica\Suggest;
+
+use Elastica\Param;
+
+/**
+ * Class AbstractSuggestion.
+ */
+abstract class AbstractSuggest extends Param
+{
+ /**
+ * @var string the name of this suggestion
+ */
+ protected $_name;
+
+ /**
+ * @var string the text for this suggestion
+ */
+ protected $_text;
+
+ /**
+ * @param string $name
+ * @param string $field
+ */
+ public function __construct($name, $field)
+ {
+ $this->_name = $name;
+ $this->setField($field);
+ }
+
+ /**
+ * Suggest text must be set either globally or per suggestion.
+ *
+ * @param string $text
+ *
+ * @return $this
+ */
+ public function setText($text)
+ {
+ $this->_text = $text;
+
+ return $this;
+ }
+
+ /**
+ * @param string $field
+ *
+ * @return $this
+ */
+ public function setField($field)
+ {
+ return $this->setParam('field', $field);
+ }
+
+ /**
+ * @param int $size
+ *
+ * @return $this
+ */
+ public function setSize($size)
+ {
+ return $this->setParam('size', $size);
+ }
+
+ /**
+ * @param int $size maximum number of suggestions to be retrieved from each shard
+ *
+ * @return $this
+ */
+ public function setShardSize($size)
+ {
+ return $this->setParam('shard_size', $size);
+ }
+
+ /**
+ * Retrieve the name of this suggestion.
+ *
+ * @return string
+ */
+ public function getName()
+ {
+ return $this->_name;
+ }
+
+ /**
+ * @return array
+ */
+ public function toArray()
+ {
+ $array = parent::toArray();
+ if (isset($this->_text)) {
+ $array['text'] = $this->_text;
+ }
+
+ return $array;
+ }
+}
diff --git a/vendor/ruflin/elastica/lib/Elastica/Suggest/CandidateGenerator/AbstractCandidateGenerator.php b/vendor/ruflin/elastica/lib/Elastica/Suggest/CandidateGenerator/AbstractCandidateGenerator.php
new file mode 100644
index 00000000..6fba49db
--- /dev/null
+++ b/vendor/ruflin/elastica/lib/Elastica/Suggest/CandidateGenerator/AbstractCandidateGenerator.php
@@ -0,0 +1,8 @@
+<?php
+namespace Elastica\Suggest\CandidateGenerator;
+
+use Elastica\Param;
+
+class AbstractCandidateGenerator extends Param
+{
+}
diff --git a/vendor/ruflin/elastica/lib/Elastica/Suggest/CandidateGenerator/DirectGenerator.php b/vendor/ruflin/elastica/lib/Elastica/Suggest/CandidateGenerator/DirectGenerator.php
new file mode 100644
index 00000000..54ac7649
--- /dev/null
+++ b/vendor/ruflin/elastica/lib/Elastica/Suggest/CandidateGenerator/DirectGenerator.php
@@ -0,0 +1,140 @@
+<?php
+namespace Elastica\Suggest\CandidateGenerator;
+
+/**
+ * Class DirectGenerator.
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/search-suggesters-phrase.html#_direct_generators
+ */
+class DirectGenerator extends AbstractCandidateGenerator
+{
+ const SUGGEST_MODE_MISSING = 'missing';
+ const SUGGEST_MODE_POPULAR = 'popular';
+ const SUGGEST_MODE_ALWAYS = 'always';
+
+ /**
+ * @param string $field
+ */
+ public function __construct($field)
+ {
+ $this->setField($field);
+ }
+
+ /**
+ * Set the field name from which to fetch candidate suggestions.
+ *
+ * @param string $field
+ *
+ * @return $this
+ */
+ public function setField($field)
+ {
+ return $this->setParam('field', $field);
+ }
+
+ /**
+ * Set the maximum corrections to be returned per suggest text token.
+ *
+ * @param int $size
+ *
+ * @return $this
+ */
+ public function setSize($size)
+ {
+ return $this->setParam('size', $size);
+ }
+
+ /**
+ * @param string $mode see SUGGEST_MODE_* constants for options
+ *
+ * @return $this
+ */
+ public function setSuggestMode($mode)
+ {
+ return $this->setParam('suggest_mode', $mode);
+ }
+
+ /**
+ * @param int $max can only be a value between 1 and 2. Defaults to 2.
+ *
+ * @return $this
+ */
+ public function setMaxEdits($max)
+ {
+ return $this->setParam('max_edits', $max);
+ }
+
+ /**
+ * @param int $length defaults to 1
+ *
+ * @return $this
+ */
+ public function setPrefixLength($length)
+ {
+ return $this->setParam('prefix_len', $length);
+ }
+
+ /**
+ * @param int $min defaults to 4
+ *
+ * @return $this
+ */
+ public function setMinWordLength($min)
+ {
+ return $this->setParam('min_word_len', $min);
+ }
+
+ /**
+ * @param int $max
+ *
+ * @return $this
+ */
+ public function setMaxInspections($max)
+ {
+ return $this->setParam('max_inspections', $max);
+ }
+
+ /**
+ * @param float $min
+ *
+ * @return $this
+ */
+ public function setMinDocFrequency($min)
+ {
+ return $this->setParam('min_doc_freq', $min);
+ }
+
+ /**
+ * @param float $max
+ *
+ * @return $this
+ */
+ public function setMaxTermFrequency($max)
+ {
+ return $this->setParam('max_term_freq', $max);
+ }
+
+ /**
+ * Set an analyzer to be applied to the original token prior to candidate generation.
+ *
+ * @param string $pre an analyzer
+ *
+ * @return $this
+ */
+ public function setPreFilter($pre)
+ {
+ return $this->setParam('pre_filter', $pre);
+ }
+
+ /**
+ * Set an analyzer to be applied to generated tokens before they are passed to the phrase scorer.
+ *
+ * @param string $post
+ *
+ * @return $this
+ */
+ public function setPostFilter($post)
+ {
+ return $this->setParam('post_filter', $post);
+ }
+}
diff --git a/vendor/ruflin/elastica/lib/Elastica/Suggest/Completion.php b/vendor/ruflin/elastica/lib/Elastica/Suggest/Completion.php
new file mode 100644
index 00000000..0f0b3e61
--- /dev/null
+++ b/vendor/ruflin/elastica/lib/Elastica/Suggest/Completion.php
@@ -0,0 +1,26 @@
+<?php
+namespace Elastica\Suggest;
+
+/**
+ * Comletion suggester.
+ *
+ * @author Igor Denisenko <im.denisenko@yahoo.com>
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/search-suggesters-completion.html
+ */
+class Completion extends AbstractSuggest
+{
+ /**
+ * Set fuzzy parameter.
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/search-suggesters-completion.html#fuzzy
+ *
+ * @param array $fuzzy
+ *
+ * @return $this
+ */
+ public function setFuzzy(array $fuzzy)
+ {
+ return $this->setParam('fuzzy', $fuzzy);
+ }
+}
diff --git a/vendor/ruflin/elastica/lib/Elastica/Suggest/Phrase.php b/vendor/ruflin/elastica/lib/Elastica/Suggest/Phrase.php
new file mode 100644
index 00000000..544f3678
--- /dev/null
+++ b/vendor/ruflin/elastica/lib/Elastica/Suggest/Phrase.php
@@ -0,0 +1,164 @@
+<?php
+namespace Elastica\Suggest;
+
+use Elastica\Suggest\CandidateGenerator\AbstractCandidateGenerator;
+
+/**
+ * Class Phrase.
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/search-suggesters-phrase.html
+ */
+class Phrase extends AbstractSuggest
+{
+ /**
+ * @param string $analyzer
+ *
+ * @return $this
+ */
+ public function setAnalyzer($analyzer)
+ {
+ return $this->setParam('analyzer', $analyzer);
+ }
+
+ /**
+ * Set the max size of the n-grams (shingles) in the field.
+ *
+ * @param int $size
+ *
+ * @return $this
+ */
+ public function setGramSize($size)
+ {
+ return $this->setParam('gram_size', $size);
+ }
+
+ /**
+ * Set the likelihood of a term being misspelled even if the term exists in the dictionary.
+ *
+ * @param float $likelihood Defaults to 0.95, meaning 5% of the words are misspelled.
+ *
+ * @return $this
+ */
+ public function setRealWordErrorLikelihood($likelihood)
+ {
+ return $this->setParam('real_word_error_likelihood', $likelihood);
+ }
+
+ /**
+ * Set the factor applied to the input phrases score to be used as a threshold for other suggestion candidates.
+ * Only candidates which score higher than this threshold will be included in the result.
+ *
+ * @param float $confidence Defaults to 1.0.
+ *
+ * @return $this
+ */
+ public function setConfidence($confidence)
+ {
+ return $this->setParam('confidence', $confidence);
+ }
+
+ /**
+ * Set the maximum percentage of the terms considered to be misspellings in order to form a correction.
+ *
+ * @param float $max
+ *
+ * @return $this
+ */
+ public function setMaxErrors($max)
+ {
+ return $this->setParam('max_errors', $max);
+ }
+
+ /**
+ * @param string $separator
+ *
+ * @return $this
+ */
+ public function setSeparator($separator)
+ {
+ return $this->setParam('separator', $separator);
+ }
+
+ /**
+ * Set suggestion highlighting.
+ *
+ * @param string $preTag
+ * @param string $postTag
+ *
+ * @return $this
+ */
+ public function setHighlight($preTag, $postTag)
+ {
+ return $this->setParam('highlight', array(
+ 'pre_tag' => $preTag,
+ 'post_tag' => $postTag,
+ ));
+ }
+
+ /**
+ * @param float $discount
+ *
+ * @return $this
+ */
+ public function setStupidBackoffSmoothing($discount = 0.4)
+ {
+ return $this->setSmoothingModel('stupid_backoff', array(
+ 'discount' => $discount,
+ ));
+ }
+
+ /**
+ * @param float $alpha
+ *
+ * @return $this
+ */
+ public function setLaplaceSmoothing($alpha = 0.5)
+ {
+ return $this->setSmoothingModel('laplace', array(
+ 'alpha' => $alpha,
+ ));
+ }
+
+ /**
+ * @param float $trigramLambda
+ * @param float $bigramLambda
+ * @param float $unigramLambda
+ *
+ * @return $this
+ */
+ public function setLinearInterpolationSmoothing($trigramLambda, $bigramLambda, $unigramLambda)
+ {
+ return $this->setSmoothingModel('linear_interpolation', array(
+ 'trigram_lambda' => $trigramLambda,
+ 'bigram_lambda' => $bigramLambda,
+ 'unigram_lambda' => $unigramLambda,
+ ));
+ }
+
+ /**
+ * @param string $model the name of the smoothing model
+ * @param array $params
+ *
+ * @return $this
+ */
+ public function setSmoothingModel($model, array $params)
+ {
+ return $this->setParam('smoothing', array(
+ $model => $params,
+ ));
+ }
+
+ /**
+ * @param AbstractCandidateGenerator $generator
+ *
+ * @return $this
+ */
+ public function addCandidateGenerator(AbstractCandidateGenerator $generator)
+ {
+ $generator = $generator->toArray();
+ $keys = array_keys($generator);
+ $values = array_values($generator);
+
+ return $this->addParam($keys[0], $values[0]);
+ }
+}
diff --git a/vendor/ruflin/elastica/lib/Elastica/Suggest/Term.php b/vendor/ruflin/elastica/lib/Elastica/Suggest/Term.php
new file mode 100644
index 00000000..9f082873
--- /dev/null
+++ b/vendor/ruflin/elastica/lib/Elastica/Suggest/Term.php
@@ -0,0 +1,129 @@
+<?php
+namespace Elastica\Suggest;
+
+/**
+ * Class Term.
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/search-suggesters-term.html
+ */
+class Term extends AbstractSuggest
+{
+ const SORT_SCORE = 'score';
+ const SORT_FREQUENCY = 'frequency';
+
+ const SUGGEST_MODE_MISSING = 'missing';
+ const SUGGEST_MODE_POPULAR = 'popular';
+ const SUGGEST_MODE_ALWAYS = 'always';
+
+ /**
+ * @param string $analyzer
+ *
+ * @return $this
+ */
+ public function setAnalyzer($analyzer)
+ {
+ return $this->setParam('analyzer', $analyzer);
+ }
+
+ /**
+ * @param string $sort see SORT_* constants for options
+ *
+ * @return $this
+ */
+ public function setSort($sort)
+ {
+ return $this->setParam('sort', $sort);
+ }
+
+ /**
+ * @param string $mode see SUGGEST_MODE_* constants for options
+ *
+ * @return $this
+ */
+ public function setSuggestMode($mode)
+ {
+ return $this->setParam('suggest_mode', $mode);
+ }
+
+ /**
+ * If true, suggest terms will be lower cased after text analysis.
+ *
+ * @param bool $lowercase
+ *
+ * @return $this
+ */
+ public function setLowercaseTerms($lowercase = true)
+ {
+ return $this->setParam('lowercase_terms', (bool) $lowercase);
+ }
+
+ /**
+ * Set the maximum edit distance candidate suggestions can have in order to be considered as a suggestion.
+ *
+ * @param int $max Either 1 or 2. Any other value will result in an error.
+ *
+ * @return $this
+ */
+ public function setMaxEdits($max)
+ {
+ return $this->setParam('max_edits', (int) $max);
+ }
+
+ /**
+ * The number of minimum prefix characters that must match in order to be a suggestion candidate.
+ *
+ * @param int $length Defaults to 1.
+ *
+ * @return $this
+ */
+ public function setPrefixLength($length)
+ {
+ return $this->setParam('prefix_len', (int) $length);
+ }
+
+ /**
+ * The minimum length a suggest text term must have in order to be included.
+ *
+ * @param int $length Defaults to 4.
+ *
+ * @return $this
+ */
+ public function setMinWordLength($length)
+ {
+ return $this->setParam('min_word_len', (int) $length);
+ }
+
+ /**
+ * @param int $max Defaults to 5.
+ *
+ * @return $this
+ */
+ public function setMaxInspections($max)
+ {
+ return $this->setParam('max_inspections', $max);
+ }
+
+ /**
+ * Set the minimum number of documents in which a suggestion should appear.
+ *
+ * @param int|float $min Defaults to 0. If the value is greater than 1, it must be a whole number.
+ *
+ * @return $this
+ */
+ public function setMinDocFrequency($min)
+ {
+ return $this->setParam('min_doc_freq', $min);
+ }
+
+ /**
+ * Set the maximum number of documents in which a suggest text token can exist in order to be included.
+ *
+ * @param float $max
+ *
+ * @return $this
+ */
+ public function setMaxTermFrequency($max)
+ {
+ return $this->setParam('max_term_freq', $max);
+ }
+}
diff --git a/vendor/ruflin/elastica/lib/Elastica/Tool/CrossIndex.php b/vendor/ruflin/elastica/lib/Elastica/Tool/CrossIndex.php
new file mode 100644
index 00000000..89fc0532
--- /dev/null
+++ b/vendor/ruflin/elastica/lib/Elastica/Tool/CrossIndex.php
@@ -0,0 +1,160 @@
+<?php
+namespace Elastica\Tool;
+
+use Elastica\Bulk;
+use Elastica\Index;
+use Elastica\Query\MatchAll;
+use Elastica\ScanAndScroll;
+use Elastica\Search;
+use Elastica\Type;
+
+/**
+ * Functions to move documents and types between indices.
+ *
+ * @author Manuel Andreo Garcia <andreo.garcia@gmail.com>
+ */
+class CrossIndex
+{
+ /**
+ * Type option.
+ *
+ * type: string | string[] | \Elastica\Type | \Elastica\Type[] | null
+ * default: null (means all types)
+ */
+ const OPTION_TYPE = 'type';
+
+ /**
+ * Query option.
+ *
+ * type: see \Elastica\Query::create()
+ * default: Elastica\Query\MatchAll
+ */
+ const OPTION_QUERY = 'query';
+
+ /**
+ * Expiry time option.
+ *
+ * type: string (see Elastica\ScanAndScroll)
+ * default: '1m'
+ */
+ const OPTION_EXPIRY_TIME = 'expiryTime';
+
+ /**
+ * Size per shard option.
+ *
+ * type: int (see Elastica\ScanAndScroll)
+ * default: 1000
+ */
+ const OPTION_SIZE_PER_SHARD = 'sizePerShard';
+
+ /**
+ * Reindex documents from an old index to a new index.
+ *
+ * @link https://www.elastic.co/guide/en/elasticsearch/guide/master/reindex.html
+ *
+ * @param \Elastica\Index $oldIndex
+ * @param \Elastica\Index $newIndex
+ * @param array $options keys: CrossIndex::OPTION_* constants
+ *
+ * @return \Elastica\Index The new index object
+ */
+ public static function reindex(
+ Index $oldIndex,
+ Index $newIndex,
+ array $options = array()
+ ) {
+ // prepare search
+ $search = new Search($oldIndex->getClient());
+
+ $options = array_merge(
+ array(
+ self::OPTION_TYPE => null,
+ self::OPTION_QUERY => new MatchAll(),
+ self::OPTION_EXPIRY_TIME => '1m',
+ self::OPTION_SIZE_PER_SHARD => 1000,
+ ),
+ $options
+ );
+
+ $search->addIndex($oldIndex);
+ if (isset($options[self::OPTION_TYPE])) {
+ $type = $options[self::OPTION_TYPE];
+ $search->addTypes(is_array($type) ? $type : array($type));
+ }
+ $search->setQuery($options[self::OPTION_QUERY]);
+
+ // search on old index and bulk insert in new index
+ $scanAndScroll = new ScanAndScroll(
+ $search,
+ $options[self::OPTION_EXPIRY_TIME],
+ $options[self::OPTION_SIZE_PER_SHARD]
+ );
+ foreach ($scanAndScroll as $resultSet) {
+ $bulk = new Bulk($newIndex->getClient());
+ $bulk->setIndex($newIndex);
+
+ foreach ($resultSet as $result) {
+ $action = new Bulk\Action();
+ $action->setType($result->getType());
+ $action->setId($result->getId());
+ $action->setSource($result->getData());
+
+ $bulk->addAction($action);
+ }
+
+ $bulk->send();
+ }
+
+ $newIndex->refresh();
+
+ return $newIndex;
+ }
+
+ /**
+ * Copies type mappings and documents from an old index to a new index.
+ *
+ * @see \Elastica\Tool\CrossIndex::reindex()
+ *
+ * @param \Elastica\Index $oldIndex
+ * @param \Elastica\Index $newIndex
+ * @param array $options keys: CrossIndex::OPTION_* constants
+ *
+ * @return \Elastica\Index The new index object
+ */
+ public static function copy(
+ Index $oldIndex,
+ Index $newIndex,
+ array $options = array()
+ ) {
+ // normalize types to array of string
+ $types = array();
+ if (isset($options[self::OPTION_TYPE])) {
+ $types = $options[self::OPTION_TYPE];
+ $types = is_array($types) ? $types : array($types);
+
+ $types = array_map(
+ function ($type) {
+ if ($type instanceof Type) {
+ $type = $type->getName();
+ }
+
+ return (string) $type;
+ },
+ $types
+ );
+ }
+
+ // copy mapping
+ foreach ($oldIndex->getMapping() as $type => $mapping) {
+ if (!empty($types) && !in_array($type, $types, true)) {
+ continue;
+ }
+
+ $type = new Type($newIndex, $type);
+ $type->setMapping($mapping['properties']);
+ }
+
+ // copy documents
+ return self::reindex($oldIndex, $newIndex, $options);
+ }
+}
diff --git a/vendor/ruflin/elastica/lib/Elastica/Transport/AbstractTransport.php b/vendor/ruflin/elastica/lib/Elastica/Transport/AbstractTransport.php
new file mode 100644
index 00000000..c40b5107
--- /dev/null
+++ b/vendor/ruflin/elastica/lib/Elastica/Transport/AbstractTransport.php
@@ -0,0 +1,113 @@
+<?php
+namespace Elastica\Transport;
+
+use Elastica\Connection;
+use Elastica\Exception\InvalidException;
+use Elastica\Param;
+use Elastica\Request;
+
+/**
+ * Elastica Abstract Transport object.
+ *
+ * @author Nicolas Ruflin <spam@ruflin.com>
+ */
+abstract class AbstractTransport extends Param
+{
+ /**
+ * @var \Elastica\Connection
+ */
+ protected $_connection;
+
+ /**
+ * Construct transport.
+ *
+ * @param \Elastica\Connection $connection Connection object
+ */
+ public function __construct(Connection $connection = null)
+ {
+ if ($connection) {
+ $this->setConnection($connection);
+ }
+ }
+
+ /**
+ * @return \Elastica\Connection Connection object
+ */
+ public function getConnection()
+ {
+ return $this->_connection;
+ }
+
+ /**
+ * @param \Elastica\Connection $connection Connection object
+ *
+ * @return $this
+ */
+ public function setConnection(Connection $connection)
+ {
+ $this->_connection = $connection;
+
+ return $this;
+ }
+
+ /**
+ * Executes the transport request.
+ *
+ * @param \Elastica\Request $request Request object
+ * @param array $params Hostname, port, path, ...
+ *
+ * @return \Elastica\Response Response object
+ */
+ abstract public function exec(Request $request, array $params);
+
+ /**
+ * Create a transport.
+ *
+ * The $transport parameter can be one of the following values:
+ *
+ * * string: The short name of a transport. For instance "Http", "Memcache" or "Thrift"
+ * * object: An already instantiated instance of a transport
+ * * array: An array with a "type" key which must be set to one of the two options. All other
+ * keys in the array will be set as parameters in the transport instance
+ *
+ * @param mixed $transport A transport definition
+ * @param \Elastica\Connection $connection A connection instance
+ * @param array $params Parameters for the transport class
+ *
+ * @throws \Elastica\Exception\InvalidException
+ *
+ * @return AbstractTransport
+ */
+ public static function create($transport, Connection $connection, array $params = array())
+ {
+ if (is_array($transport) && isset($transport['type'])) {
+ $transportParams = $transport;
+ unset($transportParams['type']);
+
+ $params = array_replace($params, $transportParams);
+ $transport = $transport['type'];
+ }
+
+ if (is_string($transport)) {
+ $className = 'Elastica\\Transport\\'.$transport;
+
+ if (!class_exists($className)) {
+ throw new InvalidException('Invalid transport');
+ }
+
+ $transport = new $className();
+ }
+
+ if ($transport instanceof self) {
+ $transport->setConnection($connection);
+
+ foreach ($params as $key => $value) {
+ $transport->setParam($key, $value);
+ }
+ } else {
+ throw new InvalidException('Invalid transport');
+ }
+
+ return $transport;
+ }
+}
diff --git a/vendor/ruflin/elastica/lib/Elastica/Transport/Guzzle.php b/vendor/ruflin/elastica/lib/Elastica/Transport/Guzzle.php
new file mode 100644
index 00000000..5c98d83b
--- /dev/null
+++ b/vendor/ruflin/elastica/lib/Elastica/Transport/Guzzle.php
@@ -0,0 +1,179 @@
+<?php
+namespace Elastica\Transport;
+
+use Elastica\Connection;
+use Elastica\Exception\Connection\GuzzleException;
+use Elastica\Exception\PartialShardFailureException;
+use Elastica\Exception\ResponseException;
+use Elastica\JSON;
+use Elastica\Request;
+use Elastica\Response;
+use GuzzleHttp\Client;
+use GuzzleHttp\Exception\TransferException;
+use GuzzleHttp\Stream\Stream;
+
+/**
+ * Elastica Guzzle Transport object.
+ *
+ * @author Milan Magudia <milan@magudia.com>
+ */
+class Guzzle extends AbstractTransport
+{
+ /**
+ * Http scheme.
+ *
+ * @var string Http scheme
+ */
+ protected $_scheme = 'http';
+
+ /**
+ * Curl resource to reuse.
+ *
+ * @var resource Guzzle resource to reuse
+ */
+ protected static $_guzzleClientConnection = null;
+
+ /**
+ * Makes calls to the elasticsearch server.
+ *
+ * All calls that are made to the server are done through this function
+ *
+ * @param \Elastica\Request $request
+ * @param array $params Host, Port, ...
+ *
+ * @throws \Elastica\Exception\ConnectionException
+ * @throws \Elastica\Exception\ResponseException
+ * @throws \Elastica\Exception\Connection\HttpException
+ *
+ * @return \Elastica\Response Response object
+ */
+ public function exec(Request $request, array $params)
+ {
+ $connection = $this->getConnection();
+
+ $client = $this->_getGuzzleClient($this->_getBaseUrl($connection), $connection->isPersistent());
+
+ $options = array(
+ 'exceptions' => false, // 4xx and 5xx is expected and NOT an exceptions in this context
+ );
+ if ($connection->getTimeout()) {
+ $options['timeout'] = $connection->getTimeout();
+ }
+
+ $proxy = $connection->getProxy();
+
+ // See: https://github.com/facebook/hhvm/issues/4875
+ if (is_null($proxy) && defined('HHVM_VERSION')) {
+ $proxy = getenv('http_proxy') ?: null;
+ }
+
+ if (!is_null($proxy)) {
+ $options['proxy'] = $proxy;
+ }
+
+ $req = $client->createRequest($request->getMethod(), $this->_getActionPath($request), $options);
+ $req->setHeaders($connection->hasConfig('headers') ? $connection->getConfig('headers') : array());
+
+ $data = $request->getData();
+ if (!empty($data) || '0' === $data) {
+ if ($req->getMethod() == Request::GET) {
+ $req->setMethod(Request::POST);
+ }
+
+ if ($this->hasParam('postWithRequestBody') && $this->getParam('postWithRequestBody') == true) {
+ $request->setMethod(Request::POST);
+ $req->setMethod(Request::POST);
+ }
+
+ if (is_array($data)) {
+ $content = JSON::stringify($data, 'JSON_ELASTICSEARCH');
+ } else {
+ $content = $data;
+ }
+ $req->setBody(Stream::factory($content));
+ }
+
+ try {
+ $start = microtime(true);
+ $res = $client->send($req);
+ $end = microtime(true);
+ } catch (TransferException $ex) {
+ throw new GuzzleException($ex, $request, new Response($ex->getMessage()));
+ }
+
+ $response = new Response((string) $res->getBody(), $res->getStatusCode());
+ $response->setQueryTime($end - $start);
+
+ $response->setTransferInfo(
+ array(
+ 'request_header' => $request->getMethod(),
+ 'http_code' => $res->getStatusCode(),
+ )
+ );
+
+ if ($response->hasError()) {
+ throw new ResponseException($request, $response);
+ }
+
+ if ($response->hasFailedShards()) {
+ throw new PartialShardFailureException($request, $response);
+ }
+
+ return $response;
+ }
+
+ /**
+ * Return Guzzle resource.
+ *
+ * @param bool $persistent False if not persistent connection
+ *
+ * @return resource Connection resource
+ */
+ protected function _getGuzzleClient($baseUrl, $persistent = true)
+ {
+ if (!$persistent || !self::$_guzzleClientConnection) {
+ self::$_guzzleClientConnection = new Client(array('base_url' => $baseUrl));
+ }
+
+ return self::$_guzzleClientConnection;
+ }
+
+ /**
+ * Builds the base url for the guzzle connection.
+ *
+ * @param \Elastica\Connection $connection
+ */
+ protected function _getBaseUrl(Connection $connection)
+ {
+ // If url is set, url is taken. Otherwise port, host and path
+ $url = $connection->hasConfig('url') ? $connection->getConfig('url') : '';
+
+ if (!empty($url)) {
+ $baseUri = $url;
+ } else {
+ $baseUri = $this->_scheme.'://'.$connection->getHost().':'.$connection->getPort().'/'.$connection->getPath();
+ }
+
+ return rtrim($baseUri, '/');
+ }
+
+ /**
+ * Builds the action path url for each request.
+ *
+ * @param \Elastica\Request $request
+ */
+ protected function _getActionPath(Request $request)
+ {
+ $action = $request->getPath();
+ if ($action) {
+ $action = '/'.ltrim($action, '/');
+ }
+ $query = $request->getQuery();
+
+ if (!empty($query)) {
+ $action .= '?'.http_build_query($query);
+ }
+
+ return $action;
+ }
+}
diff --git a/vendor/ruflin/elastica/lib/Elastica/Transport/Http.php b/vendor/ruflin/elastica/lib/Elastica/Transport/Http.php
new file mode 100644
index 00000000..1a33c0a6
--- /dev/null
+++ b/vendor/ruflin/elastica/lib/Elastica/Transport/Http.php
@@ -0,0 +1,190 @@
+<?php
+namespace Elastica\Transport;
+
+use Elastica\Exception\Connection\HttpException;
+use Elastica\Exception\PartialShardFailureException;
+use Elastica\Exception\ResponseException;
+use Elastica\JSON;
+use Elastica\Request;
+use Elastica\Response;
+
+/**
+ * Elastica Http Transport object.
+ *
+ * @author Nicolas Ruflin <spam@ruflin.com>
+ */
+class Http extends AbstractTransport
+{
+ /**
+ * Http scheme.
+ *
+ * @var string Http scheme
+ */
+ protected $_scheme = 'http';
+
+ /**
+ * Curl resource to reuse.
+ *
+ * @var resource Curl resource to reuse
+ */
+ protected static $_curlConnection = null;
+
+ /**
+ * Makes calls to the elasticsearch server.
+ *
+ * All calls that are made to the server are done through this function
+ *
+ * @param \Elastica\Request $request
+ * @param array $params Host, Port, ...
+ *
+ * @throws \Elastica\Exception\ConnectionException
+ * @throws \Elastica\Exception\ResponseException
+ * @throws \Elastica\Exception\Connection\HttpException
+ *
+ * @return \Elastica\Response Response object
+ */
+ public function exec(Request $request, array $params)
+ {
+ $connection = $this->getConnection();
+
+ $conn = $this->_getConnection($connection->isPersistent());
+
+ // If url is set, url is taken. Otherwise port, host and path
+ $url = $connection->hasConfig('url') ? $connection->getConfig('url') : '';
+
+ if (!empty($url)) {
+ $baseUri = $url;
+ } else {
+ $baseUri = $this->_scheme.'://'.$connection->getHost().':'.$connection->getPort().'/'.$connection->getPath();
+ }
+
+ $baseUri .= $request->getPath();
+
+ $query = $request->getQuery();
+
+ if (!empty($query)) {
+ $baseUri .= '?'.http_build_query($query);
+ }
+
+ curl_setopt($conn, CURLOPT_URL, $baseUri);
+ curl_setopt($conn, CURLOPT_TIMEOUT, $connection->getTimeout());
+ curl_setopt($conn, CURLOPT_FORBID_REUSE, 0);
+
+ /* @see Connection::setConnectTimeout() */
+ $connectTimeout = $connection->getConnectTimeout();
+ if ($connectTimeout > 0) {
+ curl_setopt($conn, CURLOPT_CONNECTTIMEOUT, $connectTimeout);
+ }
+
+ $proxy = $connection->getProxy();
+
+ // See: https://github.com/facebook/hhvm/issues/4875
+ if (is_null($proxy) && defined('HHVM_VERSION')) {
+ $proxy = getenv('http_proxy') ?: null;
+ }
+
+ if (!is_null($proxy)) {
+ curl_setopt($conn, CURLOPT_PROXY, $proxy);
+ }
+
+ $this->_setupCurl($conn);
+
+ $headersConfig = $connection->hasConfig('headers') ? $connection->getConfig('headers') : array();
+
+ if (!empty($headersConfig)) {
+ $headers = array();
+ while (list($header, $headerValue) = each($headersConfig)) {
+ array_push($headers, $header.': '.$headerValue);
+ }
+
+ curl_setopt($conn, CURLOPT_HTTPHEADER, $headers);
+ }
+
+ // TODO: REFACTOR
+ $data = $request->getData();
+ $httpMethod = $request->getMethod();
+
+ if (!empty($data) || '0' === $data) {
+ if ($this->hasParam('postWithRequestBody') && $this->getParam('postWithRequestBody') == true) {
+ $httpMethod = Request::POST;
+ }
+
+ if (is_array($data)) {
+ $content = JSON::stringify($data, 'JSON_ELASTICSEARCH');
+ } else {
+ $content = $data;
+ }
+
+ // Escaping of / not necessary. Causes problems in base64 encoding of files
+ $content = str_replace('\/', '/', $content);
+
+ curl_setopt($conn, CURLOPT_POSTFIELDS, $content);
+ } else {
+ curl_setopt($conn, CURLOPT_POSTFIELDS, '');
+ }
+
+ curl_setopt($conn, CURLOPT_NOBODY, $httpMethod == 'HEAD');
+
+ curl_setopt($conn, CURLOPT_CUSTOMREQUEST, $httpMethod);
+
+ $start = microtime(true);
+
+ // cURL opt returntransfer leaks memory, therefore OB instead.
+ ob_start();
+ curl_exec($conn);
+ $responseString = ob_get_clean();
+
+ $end = microtime(true);
+
+ // Checks if error exists
+ $errorNumber = curl_errno($conn);
+
+ $response = new Response($responseString, curl_getinfo($conn, CURLINFO_HTTP_CODE));
+ $response->setQueryTime($end - $start);
+ $response->setTransferInfo(curl_getinfo($conn));
+
+ if ($response->hasError()) {
+ throw new ResponseException($request, $response);
+ }
+
+ if ($response->hasFailedShards()) {
+ throw new PartialShardFailureException($request, $response);
+ }
+
+ if ($errorNumber > 0) {
+ throw new HttpException($errorNumber, $request, $response);
+ }
+
+ return $response;
+ }
+
+ /**
+ * Called to add additional curl params.
+ *
+ * @param resource $curlConnection Curl connection
+ */
+ protected function _setupCurl($curlConnection)
+ {
+ if ($this->getConnection()->hasConfig('curl')) {
+ foreach ($this->getConnection()->getConfig('curl') as $key => $param) {
+ curl_setopt($curlConnection, $key, $param);
+ }
+ }
+ }
+
+ /**
+ * Return Curl resource.
+ *
+ * @param bool $persistent False if not persistent connection
+ *
+ * @return resource Connection resource
+ */
+ protected function _getConnection($persistent = true)
+ {
+ if (!$persistent || !self::$_curlConnection) {
+ self::$_curlConnection = curl_init();
+ }
+
+ return self::$_curlConnection;
+ }
+}
diff --git a/vendor/ruflin/elastica/lib/Elastica/Transport/HttpAdapter.php b/vendor/ruflin/elastica/lib/Elastica/Transport/HttpAdapter.php
new file mode 100644
index 00000000..efc27ab5
--- /dev/null
+++ b/vendor/ruflin/elastica/lib/Elastica/Transport/HttpAdapter.php
@@ -0,0 +1,156 @@
+<?php
+namespace Elastica\Transport;
+
+use Elastica\Connection;
+use Elastica\Exception\PartialShardFailureException;
+use Elastica\Exception\ResponseException;
+use Elastica\JSON;
+use Elastica\Request as ElasticaRequest;
+use Elastica\Response as ElasticaResponse;
+use Ivory\HttpAdapter\HttpAdapterInterface;
+use Ivory\HttpAdapter\Message\Request as HttpAdapterRequest;
+use Ivory\HttpAdapter\Message\Response as HttpAdapterResponse;
+use Ivory\HttpAdapter\Message\Stream\StringStream;
+
+class HttpAdapter extends AbstractTransport
+{
+ /**
+ * @var HttpAdapterInterface
+ */
+ private $httpAdapter;
+
+ /**
+ * @var string
+ */
+ private $_scheme = 'http';
+
+ /**
+ * Construct transport.
+ */
+ public function __construct(Connection $connection = null, HttpAdapterInterface $httpAdapter)
+ {
+ parent::__construct($connection);
+ $this->httpAdapter = $httpAdapter;
+ }
+
+ /**
+ * Makes calls to the elasticsearch server.
+ *
+ * All calls that are made to the server are done through this function
+ *
+ * @param \Elastica\Request $elasticaRequest
+ * @param array $params Host, Port, ...
+ *
+ * @throws \Elastica\Exception\ConnectionException
+ * @throws \Elastica\Exception\ResponseException
+ * @throws \Elastica\Exception\Connection\HttpException
+ *
+ * @return \Elastica\Response Response object
+ */
+ public function exec(ElasticaRequest $elasticaRequest, array $params)
+ {
+ $connection = $this->getConnection();
+
+ if ($timeout = $connection->getTimeout()) {
+ $this->httpAdapter->getConfiguration()->setTimeout($timeout);
+ }
+
+ $httpAdapterRequest = $this->_createHttpAdapterRequest($elasticaRequest, $connection);
+
+ $start = microtime(true);
+ $httpAdapterResponse = $this->httpAdapter->sendRequest($httpAdapterRequest);
+ $end = microtime(true);
+
+ $elasticaResponse = $this->_createElasticaResponse($httpAdapterResponse, $connection);
+ $elasticaResponse->setQueryTime($end - $start);
+
+ $elasticaResponse->setTransferInfo(
+ array(
+ 'request_header' => $httpAdapterRequest->getMethod(),
+ 'http_code' => $httpAdapterResponse->getStatusCode(),
+ )
+ );
+
+ if ($elasticaResponse->hasError()) {
+ throw new ResponseException($elasticaRequest, $elasticaResponse);
+ }
+
+ if ($elasticaResponse->hasFailedShards()) {
+ throw new PartialShardFailureException($elasticaRequest, $elasticaResponse);
+ }
+
+ return $elasticaResponse;
+ }
+
+ /**
+ * @param HttpAdapterResponse $httpAdapterResponse
+ *
+ * @return ElasticaResponse
+ */
+ protected function _createElasticaResponse(HttpAdapterResponse $httpAdapterResponse)
+ {
+ return new ElasticaResponse((string) $httpAdapterResponse->getBody(), $httpAdapterResponse->getStatusCode());
+ }
+
+ /**
+ * @param ElasticaRequest $elasticaRequest
+ * @param Connection $connection
+ *
+ * @return HttpAdapterRequest
+ */
+ protected function _createHttpAdapterRequest(ElasticaRequest $elasticaRequest, Connection $connection)
+ {
+ $data = $elasticaRequest->getData();
+ $body = null;
+ $method = $elasticaRequest->getMethod();
+ $headers = $connection->hasConfig('headers') ?: array();
+ if (!empty($data) || '0' === $data) {
+ if ($method == ElasticaRequest::GET) {
+ $method = ElasticaRequest::POST;
+ }
+
+ if ($this->hasParam('postWithRequestBody') && $this->getParam('postWithRequestBody') == true) {
+ $elasticaRequest->setMethod(ElasticaRequest::POST);
+ $method = ElasticaRequest::POST;
+ }
+
+ if (is_array($data)) {
+ $body = JSON::stringify($data, 'JSON_ELASTICSEARCH');
+ } else {
+ $body = $data;
+ }
+ }
+
+ $url = $this->_getUri($elasticaRequest, $connection);
+ $streamBody = new StringStream($body);
+
+ return new HttpAdapterRequest($url, $method, HttpAdapterRequest::PROTOCOL_VERSION_1_1, $headers, $streamBody);
+ }
+
+ /**
+ * @param ElasticaRequest $request
+ * @param \Elastica\Connection $connection
+ *
+ * @return string
+ */
+ protected function _getUri(ElasticaRequest $request, Connection $connection)
+ {
+ $url = $connection->hasConfig('url') ? $connection->getConfig('url') : '';
+
+ if (!empty($url)) {
+ $baseUri = $url;
+ } else {
+ $baseUri = $this->_scheme.'://'.$connection->getHost().':'.$connection->getPort().'/'.$connection->getPath();
+ }
+
+ $baseUri .= $request->getPath();
+
+ $query = $request->getQuery();
+
+ if (!empty($query)) {
+ $baseUri .= '?'.http_build_query($query);
+ }
+
+ return $baseUri;
+ }
+}
diff --git a/vendor/ruflin/elastica/lib/Elastica/Transport/Https.php b/vendor/ruflin/elastica/lib/Elastica/Transport/Https.php
new file mode 100644
index 00000000..b2b489dd
--- /dev/null
+++ b/vendor/ruflin/elastica/lib/Elastica/Transport/Https.php
@@ -0,0 +1,27 @@
+<?php
+namespace Elastica\Transport;
+
+/**
+ * Elastica Http Transport object.
+ *
+ * @author Nicolas Ruflin <spam@ruflin.com>
+ */
+class Https extends Http
+{
+ /**
+ * Https scheme.
+ *
+ * @var string https scheme
+ */
+ protected $_scheme = 'https';
+
+ /**
+ * Overloads setupCurl to set SSL params.
+ *
+ * @param resource $connection Curl connection resource
+ */
+ protected function _setupCurl($connection)
+ {
+ parent::_setupCurl($connection);
+ }
+}
diff --git a/vendor/ruflin/elastica/lib/Elastica/Transport/Memcache.php b/vendor/ruflin/elastica/lib/Elastica/Transport/Memcache.php
new file mode 100644
index 00000000..fb56cdf4
--- /dev/null
+++ b/vendor/ruflin/elastica/lib/Elastica/Transport/Memcache.php
@@ -0,0 +1,109 @@
+<?php
+namespace Elastica\Transport;
+
+use Elastica\Exception\Connection\MemcacheException;
+use Elastica\Exception\InvalidException;
+use Elastica\Exception\PartialShardFailureException;
+use Elastica\Exception\ResponseException;
+use Elastica\JSON;
+use Elastica\Request;
+use Elastica\Response;
+
+/**
+ * Elastica Memcache Transport object.
+ *
+ * @author Nicolas Ruflin <spam@ruflin.com>
+ *
+ * @deprecated The memcached transport is deprecated as of ES 1.5, and will be removed in ES 2.0
+ */
+class Memcache extends AbstractTransport
+{
+ const MAX_KEY_LENGTH = 250;
+
+ /**
+ * Makes calls to the elasticsearch server.
+ *
+ * @param \Elastica\Request $request
+ * @param array $params Host, Port, ...
+ *
+ * @throws \Elastica\Exception\ResponseException
+ * @throws \Elastica\Exception\InvalidException
+ *
+ * @return \Elastica\Response Response object
+ */
+ public function exec(Request $request, array $params)
+ {
+ $memcache = new \Memcache();
+ $memcache->connect($this->getConnection()->getHost(), $this->getConnection()->getPort());
+
+ $data = $request->getData();
+
+ $content = '';
+
+ if (!empty($data) || '0' === $data) {
+ if (is_array($data)) {
+ $content = JSON::stringify($data);
+ } else {
+ $content = $data;
+ }
+
+ // Escaping of / not necessary. Causes problems in base64 encoding of files
+ $content = str_replace('\/', '/', $content);
+ }
+
+ $responseString = '';
+
+ $start = microtime(true);
+
+ switch ($request->getMethod()) {
+ case Request::POST:
+ case Request::PUT:
+ $key = $request->getPath();
+ $this->_checkKeyLength($key);
+ $memcache->set($key, $content);
+ break;
+ case Request::GET:
+ $key = $request->getPath().'?source='.$content;
+ $this->_checkKeyLength($key);
+ $responseString = $memcache->get($key);
+ break;
+ case Request::DELETE:
+ $key = $request->getPath().'?source='.$content;
+ $this->_checkKeyLength($key);
+ $responseString = $memcache->delete($key);
+ break;
+ default:
+ case Request::HEAD:
+ throw new InvalidException('Method '.$request->getMethod().' is not supported in memcache transport');
+ }
+
+ $end = microtime(true);
+
+ $response = new Response($responseString);
+ $response->setQueryTime($end - $start);
+
+ if ($response->hasError()) {
+ throw new ResponseException($request, $response);
+ }
+
+ if ($response->hasFailedShards()) {
+ throw new PartialShardFailureException($request, $response);
+ }
+
+ return $response;
+ }
+
+ /**
+ * Check if key that will be used dont exceed 250 symbols.
+ *
+ * @param string $key
+ *
+ * @throws Elastica\Exception\Connection\MemcacheException If key is too long
+ */
+ private function _checkKeyLength($key)
+ {
+ if (strlen($key) >= self::MAX_KEY_LENGTH) {
+ throw new MemcacheException('Memcache key is too long');
+ }
+ }
+}
diff --git a/vendor/ruflin/elastica/lib/Elastica/Transport/Null.php b/vendor/ruflin/elastica/lib/Elastica/Transport/Null.php
new file mode 100644
index 00000000..70dd9af1
--- /dev/null
+++ b/vendor/ruflin/elastica/lib/Elastica/Transport/Null.php
@@ -0,0 +1,13 @@
+<?php
+namespace Elastica\Transport;
+
+/**
+ * Elastica Null Transport object.
+ *
+ * This class is for backward compatibility reason for all php < 7 versions. For PHP 7 and above use NullTransport as Null is reserved.
+ *
+ * @author James Boehmer <james.boehmer@jamesboehmer.com>
+ */
+class Null extends NullTransport
+{
+}
diff --git a/vendor/ruflin/elastica/lib/Elastica/Transport/NullTransport.php b/vendor/ruflin/elastica/lib/Elastica/Transport/NullTransport.php
new file mode 100644
index 00000000..d24f2110
--- /dev/null
+++ b/vendor/ruflin/elastica/lib/Elastica/Transport/NullTransport.php
@@ -0,0 +1,46 @@
+<?php
+namespace Elastica\Transport;
+
+use Elastica\JSON;
+use Elastica\Request;
+use Elastica\Response;
+
+/**
+ * Elastica Null Transport object.
+ *
+ * This is used in case you just need a test transport that doesn't do any connection to an elasticsearch
+ * host but still returns a valid response object
+ *
+ * @author James Boehmer <james.boehmer@jamesboehmer.com>
+ */
+class NullTransport extends AbstractTransport
+{
+ /**
+ * Null transport.
+ *
+ * @param \Elastica\Request $request
+ * @param array $params Hostname, port, path, ...
+ *
+ * @return \Elastica\Response Response empty object
+ */
+ public function exec(Request $request, array $params)
+ {
+ $response = array(
+ 'took' => 0,
+ 'timed_out' => false,
+ '_shards' => array(
+ 'total' => 0,
+ 'successful' => 0,
+ 'failed' => 0,
+ ),
+ 'hits' => array(
+ 'total' => 0,
+ 'max_score' => null,
+ 'hits' => array(),
+ ),
+ 'params' => $params,
+ );
+
+ return new Response(JSON::stringify($response));
+ }
+}
diff --git a/vendor/ruflin/elastica/lib/Elastica/Transport/Thrift.php b/vendor/ruflin/elastica/lib/Elastica/Transport/Thrift.php
new file mode 100644
index 00000000..5790f665
--- /dev/null
+++ b/vendor/ruflin/elastica/lib/Elastica/Transport/Thrift.php
@@ -0,0 +1,176 @@
+<?php
+namespace Elastica\Transport;
+
+use Elastica\Connection;
+use Elastica\Exception\Connection\ThriftException;
+use Elastica\Exception\PartialShardFailureException;
+use Elastica\Exception\ResponseException;
+use Elastica\Exception\RuntimeException;
+use Elastica\JSON;
+use Elastica\Request;
+use Elastica\Response;
+use Elasticsearch\Method;
+use Elasticsearch\RestClient;
+use Elasticsearch\RestRequest;
+use Elasticsearch\RestResponse;
+use Thrift\Exception\TException;
+use Thrift\Protocol\TBinaryProtocolAccelerated;
+use Thrift\Transport\TBufferedTransport;
+use Thrift\Transport\TFramedTransport;
+use Thrift\Transport\TSocket;
+
+/**
+ * Elastica Thrift Transport object.
+ *
+ * @author Mikhail Shamin <munk13@gmail.com>
+ *
+ * @deprecated The thrift transport is deprecated as of ES 1.5, and will be removed in ES 2.0
+ */
+class Thrift extends AbstractTransport
+{
+ /**
+ * @var RestClient[]
+ */
+ protected $_clients = array();
+
+ /**
+ * Construct transport.
+ *
+ * @param \Elastica\Connection $connection Connection object
+ *
+ * @throws \Elastica\Exception\RuntimeException
+ */
+ public function __construct(Connection $connection = null)
+ {
+ parent::__construct($connection);
+ if (!class_exists('Elasticsearch\\RestClient')) {
+ throw new RuntimeException('Elasticsearch\\RestClient class not found. Check that suggested package munkie/elasticsearch-thrift-php is required in composer.json');
+ }
+ }
+
+ /**
+ * @param string $host
+ * @param int $port
+ * @param int $sendTimeout msec
+ * @param int $recvTimeout msec
+ * @param bool $framedTransport
+ *
+ * @return \Elasticsearch\RestClient
+ */
+ protected function _createClient($host, $port, $sendTimeout = null, $recvTimeout = null, $framedTransport = false)
+ {
+ $socket = new TSocket($host, $port, true);
+
+ if (null !== $sendTimeout) {
+ $socket->setSendTimeout($sendTimeout);
+ }
+
+ if (null !== $recvTimeout) {
+ $socket->setRecvTimeout($recvTimeout);
+ }
+
+ if ($framedTransport) {
+ $transport = new TFramedTransport($socket);
+ } else {
+ $transport = new TBufferedTransport($socket);
+ }
+ $protocol = new TBinaryProtocolAccelerated($transport);
+
+ $client = new RestClient($protocol);
+
+ $transport->open();
+
+ return $client;
+ }
+
+ /**
+ * @param string $host
+ * @param int $port
+ * @param int $sendTimeout
+ * @param int $recvTimeout
+ * @param bool $framedTransport
+ *
+ * @return \Elasticsearch\RestClient
+ */
+ protected function _getClient($host, $port, $sendTimeout = null, $recvTimeout = null, $framedTransport = false)
+ {
+ $key = $host.':'.$port;
+ if (!isset($this->_clients[$key])) {
+ $this->_clients[$key] = $this->_createClient($host, $port, $sendTimeout, $recvTimeout, $framedTransport);
+ }
+
+ return $this->_clients[$key];
+ }
+
+ /**
+ * Makes calls to the elasticsearch server.
+ *
+ * @param \Elastica\Request $request
+ * @param array $params Host, Port, ...
+ *
+ * @throws \Elastica\Exception\Connection\ThriftException
+ * @throws \Elastica\Exception\ResponseException
+ *
+ * @return \Elastica\Response Response object
+ */
+ public function exec(Request $request, array $params)
+ {
+ $connection = $this->getConnection();
+
+ $sendTimeout = $connection->hasConfig('sendTimeout') ? $connection->getConfig('sendTimeout') : null;
+ $recvTimeout = $connection->hasConfig('recvTimeout') ? $connection->getConfig('recvTimeout') : null;
+ $framedTransport = $connection->hasConfig('framedTransport') ? (bool) $connection->getConfig('framedTransport') : false;
+
+ try {
+ $client = $this->_getClient(
+ $connection->getHost(),
+ $connection->getPort(),
+ $sendTimeout,
+ $recvTimeout,
+ $framedTransport
+ );
+
+ $restRequest = new RestRequest();
+ $restRequest->method = array_search($request->getMethod(), Method::$__names);
+ $restRequest->uri = $request->getPath();
+
+ $query = $request->getQuery();
+ if (!empty($query)) {
+ $restRequest->parameters = $query;
+ }
+
+ $data = $request->getData();
+ if (!empty($data) || '0' === $data) {
+ if (is_array($data)) {
+ $content = JSON::stringify($data);
+ } else {
+ $content = $data;
+ }
+ $restRequest->body = $content;
+ }
+
+ /* @var $result RestResponse */
+ $start = microtime(true);
+
+ $result = $client->execute($restRequest);
+ $response = new Response($result->body);
+
+ $end = microtime(true);
+ } catch (TException $e) {
+ $response = new Response('');
+ throw new ThriftException($e, $request, $response);
+ }
+
+ $response->setQueryTime($end - $start);
+
+ if ($response->hasError()) {
+ throw new ResponseException($request, $response);
+ }
+
+ if ($response->hasFailedShards()) {
+ throw new PartialShardFailureException($request, $response);
+ }
+
+ return $response;
+ }
+}
diff --git a/vendor/ruflin/elastica/lib/Elastica/Type.php b/vendor/ruflin/elastica/lib/Elastica/Type.php
new file mode 100644
index 00000000..8abec330
--- /dev/null
+++ b/vendor/ruflin/elastica/lib/Elastica/Type.php
@@ -0,0 +1,572 @@
+<?php
+namespace Elastica;
+
+use Elastica\Exception\InvalidException;
+use Elastica\Exception\NotFoundException;
+use Elastica\Exception\RuntimeException;
+use Elastica\Type\Mapping;
+
+/**
+ * Elastica type object.
+ *
+ * elasticsearch has for every types as a substructure. This object
+ * represents a type inside a context
+ * The hierarchy is as following: client -> index -> type -> document
+ *
+ * @author Nicolas Ruflin <spam@ruflin.com>
+ */
+class Type implements SearchableInterface
+{
+ /**
+ * Index.
+ *
+ * @var \Elastica\Index Index object
+ */
+ protected $_index = null;
+
+ /**
+ * Type name.
+ *
+ * @var string Type name
+ */
+ protected $_name = '';
+
+ /**
+ * @var array|string A callable that serializes an object passed to it
+ */
+ protected $_serializer;
+
+ /**
+ * Creates a new type object inside the given index.
+ *
+ * @param \Elastica\Index $index Index Object
+ * @param string $name Type name
+ */
+ public function __construct(Index $index, $name)
+ {
+ $this->_index = $index;
+ $this->_name = $name;
+ }
+
+ /**
+ * Adds the given document to the search index.
+ *
+ * @param \Elastica\Document $doc Document with data
+ *
+ * @return \Elastica\Response
+ */
+ public function addDocument(Document $doc)
+ {
+ $path = urlencode($doc->getId());
+
+ $type = Request::PUT;
+
+ // If id is empty, POST has to be used to automatically create id
+ if (empty($path)) {
+ $type = Request::POST;
+ }
+
+ $options = $doc->getOptions(
+ array(
+ 'version',
+ 'version_type',
+ 'routing',
+ 'percolate',
+ 'parent',
+ 'ttl',
+ 'timestamp',
+ 'op_type',
+ 'consistency',
+ 'replication',
+ 'refresh',
+ 'timeout',
+ )
+ );
+
+ $response = $this->request($path, $type, $doc->getData(), $options);
+
+ $data = $response->getData();
+ // set autogenerated id to document
+ if (($doc->isAutoPopulate()
+ || $this->getIndex()->getClient()->getConfigValue(array('document', 'autoPopulate'), false))
+ && $response->isOk()
+ ) {
+ if (!$doc->hasId()) {
+ if (isset($data['_id'])) {
+ $doc->setId($data['_id']);
+ }
+ }
+ if (isset($data['_version'])) {
+ $doc->setVersion($data['_version']);
+ }
+ }
+
+ return $response;
+ }
+
+ /**
+ * @param $object
+ * @param Document $doc
+ *
+ * @throws Exception\RuntimeException
+ *
+ * @return Response
+ */
+ public function addObject($object, Document $doc = null)
+ {
+ if (!isset($this->_serializer)) {
+ throw new RuntimeException('No serializer defined');
+ }
+
+ $data = call_user_func($this->_serializer, $object);
+ if (!$doc) {
+ $doc = new Document();
+ }
+ $doc->setData($data);
+
+ return $this->addDocument($doc);
+ }
+
+ /**
+ * Update document, using update script. Requires elasticsearch >= 0.19.0.
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/docs-update.html
+ *
+ * @param \Elastica\Document|\Elastica\Script $data Document with update data
+ * @param array $options array of query params to use for query. For possible options check es api
+ *
+ * @throws \Elastica\Exception\InvalidException
+ *
+ * @return \Elastica\Response
+ */
+ public function updateDocument($data, array $options = array())
+ {
+ if (!($data instanceof Document) && !($data instanceof Script)) {
+ throw new \InvalidArgumentException('Data should be a Document or Script');
+ }
+
+ if (!$data->hasId()) {
+ throw new InvalidException('Document or Script id is not set');
+ }
+
+ $id = urlencode($data->getId());
+
+ return $this->getIndex()->getClient()->updateDocument(
+ $id,
+ $data,
+ $this->getIndex()->getName(),
+ $this->getName(),
+ $options
+ );
+ }
+
+ /**
+ * Uses _bulk to send documents to the server.
+ *
+ * @param array|\Elastica\Document[] $docs Array of Elastica\Document
+ *
+ * @return \Elastica\Bulk\ResponseSet
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/docs-bulk.html
+ */
+ public function updateDocuments(array $docs)
+ {
+ foreach ($docs as $doc) {
+ $doc->setType($this->getName());
+ }
+
+ return $this->getIndex()->updateDocuments($docs);
+ }
+
+ /**
+ * Uses _bulk to send documents to the server.
+ *
+ * @param array|\Elastica\Document[] $docs Array of Elastica\Document
+ *
+ * @return \Elastica\Bulk\ResponseSet
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/docs-bulk.html
+ */
+ public function addDocuments(array $docs)
+ {
+ foreach ($docs as $doc) {
+ $doc->setType($this->getName());
+ }
+
+ return $this->getIndex()->addDocuments($docs);
+ }
+
+ /**
+ * Uses _bulk to send documents to the server.
+ *
+ * @param objects[] $objects
+ *
+ * @return \Elastica\Bulk\ResponseSet
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/docs-bulk.html
+ */
+ public function addObjects(array $objects)
+ {
+ if (!isset($this->_serializer)) {
+ throw new RuntimeException('No serializer defined');
+ }
+
+ $docs = array();
+ foreach ($objects as $object) {
+ $data = call_user_func($this->_serializer, $object);
+ $doc = new Document();
+ $doc->setData($data);
+ $doc->setType($this->getName());
+ $docs[] = $doc;
+ }
+
+ return $this->getIndex()->addDocuments($docs);
+ }
+
+ /**
+ * Get the document from search index.
+ *
+ * @param string $id Document id
+ * @param array $options Options for the get request.
+ *
+ * @throws \Elastica\Exception\NotFoundException
+ * @throws \Elastica\Exception\ResponseException
+ *
+ * @return \Elastica\Document
+ */
+ public function getDocument($id, $options = array())
+ {
+ $path = urlencode($id);
+
+ $response = $this->request($path, Request::GET, array(), $options);
+ $result = $response->getData();
+
+ if (!isset($result['found']) || $result['found'] === false) {
+ throw new NotFoundException('doc id '.$id.' not found');
+ }
+
+ if (isset($result['fields'])) {
+ $data = $result['fields'];
+ } elseif (isset($result['_source'])) {
+ $data = $result['_source'];
+ } else {
+ $data = array();
+ }
+
+ $document = new Document($id, $data, $this->getName(), $this->getIndex());
+ $document->setVersion($result['_version']);
+
+ return $document;
+ }
+
+ /**
+ * @param string $id
+ * @param array|string $data
+ *
+ * @return Document
+ */
+ public function createDocument($id = '', $data = array())
+ {
+ $document = new Document($id, $data);
+ $document->setType($this);
+
+ return $document;
+ }
+
+ /**
+ * Returns the type name.
+ *
+ * @return string Type name
+ */
+ public function getName()
+ {
+ return $this->_name;
+ }
+
+ /**
+ * Sets value type mapping for this type.
+ *
+ * @param \Elastica\Type\Mapping|array $mapping Elastica\Type\MappingType object or property array with all mappings
+ *
+ * @return \Elastica\Response
+ */
+ public function setMapping($mapping)
+ {
+ $mapping = Mapping::create($mapping);
+ $mapping->setType($this);
+
+ return $mapping->send();
+ }
+
+ /**
+ * Returns current mapping for the given type.
+ *
+ * @return array Current mapping
+ */
+ public function getMapping()
+ {
+ $path = '_mapping';
+
+ $response = $this->request($path, Request::GET);
+ $data = $response->getData();
+
+ $mapping = array_shift($data);
+ if (isset($mapping['mappings'])) {
+ return $mapping['mappings'];
+ }
+
+ return array();
+ }
+
+ /**
+ * Create search object.
+ *
+ * @param string|array|\Elastica\Query $query Array with all query data inside or a Elastica\Query object
+ * @param int|array $options OPTIONAL Limit or associative array of options (option=>value)
+ *
+ * @return \Elastica\Search
+ */
+ public function createSearch($query = '', $options = null)
+ {
+ $search = new Search($this->getIndex()->getClient());
+ $search->addIndex($this->getIndex());
+ $search->addType($this);
+ $search->setOptionsAndQuery($options, $query);
+
+ return $search;
+ }
+
+ /**
+ * Do a search on this type.
+ *
+ * @param string|array|\Elastica\Query $query Array with all query data inside or a Elastica\Query object
+ * @param int|array $options OPTIONAL Limit or associative array of options (option=>value)
+ *
+ * @return \Elastica\ResultSet ResultSet with all results inside
+ *
+ * @see \Elastica\SearchableInterface::search
+ */
+ public function search($query = '', $options = null)
+ {
+ $search = $this->createSearch($query, $options);
+
+ return $search->search();
+ }
+
+ /**
+ * Count docs by query.
+ *
+ * @param string|array|\Elastica\Query $query Array with all query data inside or a Elastica\Query object
+ *
+ * @return int number of documents matching the query
+ *
+ * @see \Elastica\SearchableInterface::count
+ */
+ public function count($query = '')
+ {
+ $search = $this->createSearch($query);
+
+ return $search->count();
+ }
+
+ /**
+ * Returns index client.
+ *
+ * @return \Elastica\Index Index object
+ */
+ public function getIndex()
+ {
+ return $this->_index;
+ }
+
+ /**
+ * @param \Elastica\Document $document
+ *
+ * @return \Elastica\Response
+ */
+ public function deleteDocument(Document $document)
+ {
+ $options = $document->getOptions(
+ array(
+ 'version',
+ 'version_type',
+ 'routing',
+ 'parent',
+ 'replication',
+ 'consistency',
+ 'refresh',
+ 'timeout',
+ )
+ );
+
+ return $this->deleteById($document->getId(), $options);
+ }
+
+ /**
+ * Uses _bulk to delete documents from the server.
+ *
+ * @param array|\Elastica\Document[] $docs Array of Elastica\Document
+ *
+ * @return \Elastica\Bulk\ResponseSet
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/docs-bulk.html
+ */
+ public function deleteDocuments(array $docs)
+ {
+ foreach ($docs as $doc) {
+ $doc->setType($this->getName());
+ }
+
+ return $this->getIndex()->deleteDocuments($docs);
+ }
+
+ /**
+ * Deletes an entry by its unique identifier.
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/docs-delete.html
+ *
+ * @param int|string $id Document id
+ * @param array $options
+ *
+ * @throws \InvalidArgumentException
+ * @throws \Elastica\Exception\NotFoundException
+ *
+ * @return \Elastica\Response Response object
+ */
+ public function deleteById($id, array $options = array())
+ {
+ if (empty($id) || !trim($id)) {
+ throw new \InvalidArgumentException();
+ }
+
+ $id = urlencode($id);
+
+ $response = $this->request($id, Request::DELETE, array(), $options);
+
+ $responseData = $response->getData();
+
+ if (isset($responseData['found']) && false == $responseData['found']) {
+ throw new NotFoundException('Doc id '.$id.' not found and can not be deleted');
+ }
+
+ return $response;
+ }
+
+ /**
+ * Deletes the given list of ids from this type.
+ *
+ * @param array $ids
+ * @param string|false $routing Optional routing key for all ids
+ *
+ * @return \Elastica\Response Response object
+ */
+ public function deleteIds(array $ids, $routing = false)
+ {
+ return $this->getIndex()->getClient()->deleteIds($ids, $this->getIndex(), $this, $routing);
+ }
+
+ /**
+ * Deletes entries in the db based on a query.
+ *
+ * @param \Elastica\Query|string $query Query object
+ * @param array $options Optional params
+ *
+ * @return \Elastica\Response
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/docs-delete-by-query.html
+ */
+ public function deleteByQuery($query, array $options = array())
+ {
+ if (is_string($query)) {
+ // query_string queries are not supported for delete by query operations
+ $options['q'] = $query;
+
+ return $this->request('_query', Request::DELETE, array(), $options);
+ }
+ $query = Query::create($query);
+
+ return $this->request('_query', Request::DELETE, array('query' => $query->getQuery()), $options);
+ }
+
+ /**
+ * Deletes the index type.
+ *
+ * @return \Elastica\Response
+ */
+ public function delete()
+ {
+ $response = $this->request('', Request::DELETE);
+
+ return $response;
+ }
+
+ /**
+ * More like this query based on the given object.
+ *
+ * The id in the given object has to be set
+ *
+ * @param \Elastica\Document $doc Document to query for similar objects
+ * @param array $params OPTIONAL Additional arguments for the query
+ * @param string|array|\Elastica\Query $query OPTIONAL Query to filter the moreLikeThis results
+ *
+ * @return \Elastica\ResultSet ResultSet with all results inside
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/search-more-like-this.html
+ */
+ public function moreLikeThis(Document $doc, $params = array(), $query = array())
+ {
+ $path = $doc->getId().'/_mlt';
+
+ $query = Query::create($query);
+
+ $response = $this->request($path, Request::GET, $query->toArray(), $params);
+
+ return ResultSet::create($response, $query);
+ }
+
+ /**
+ * Makes calls to the elasticsearch server based on this type.
+ *
+ * @param string $path Path to call
+ * @param string $method Rest method to use (GET, POST, DELETE, PUT)
+ * @param array $data OPTIONAL Arguments as array
+ * @param array $query OPTIONAL Query params
+ *
+ * @return \Elastica\Response Response object
+ */
+ public function request($path, $method, $data = array(), array $query = array())
+ {
+ $path = $this->getName().'/'.$path;
+
+ return $this->getIndex()->request($path, $method, $data, $query);
+ }
+
+ /**
+ * Sets the serializer callable used in addObject.
+ *
+ * @see \Elastica\Type::addObject
+ *
+ * @param array|string $serializer @see \Elastica\Type::_serializer
+ *
+ * @return $this
+ */
+ public function setSerializer($serializer)
+ {
+ $this->_serializer = $serializer;
+
+ return $this;
+ }
+
+ /**
+ * Checks if the given type exists in Index.
+ *
+ * @return bool True if type exists
+ */
+ public function exists()
+ {
+ $response = $this->getIndex()->request($this->getName(), Request::HEAD);
+ $info = $response->getTransferInfo();
+
+ return (bool) ($info['http_code'] == 200);
+ }
+}
diff --git a/vendor/ruflin/elastica/lib/Elastica/Type/AbstractType.php b/vendor/ruflin/elastica/lib/Elastica/Type/AbstractType.php
new file mode 100644
index 00000000..648102d2
--- /dev/null
+++ b/vendor/ruflin/elastica/lib/Elastica/Type/AbstractType.php
@@ -0,0 +1,205 @@
+<?php
+namespace Elastica\Type;
+
+use Elastica\Client;
+use Elastica\Exception\InvalidException;
+use Elastica\Index;
+use Elastica\SearchableInterface;
+use Elastica\Type as BaseType;
+use Elastica\Util;
+
+/**
+ * Abstract helper class to implement search indices based on models.
+ *
+ * This abstract model should help creating search index and a subtype
+ * with some easy config entries that are overloaded.
+ *
+ * The following variables have to be set:
+ * - $_indexName
+ * - $_typeName
+ *
+ * The following variables can be set for additional configuration
+ * - $_mapping: Value type mapping for the given type
+ * - $_indexParams: Parameters for the index
+ *
+ * @todo Add some settings examples to code
+ *
+ * @author Nicolas Ruflin <spam@ruflin.com>
+ */
+abstract class AbstractType implements SearchableInterface
+{
+ const MAX_DOCS_PER_REQUEST = 1000;
+
+ /**
+ * Index name.
+ *
+ * @var string Index name
+ */
+ protected $_indexName = '';
+
+ /**
+ * Index name.
+ *
+ * @var string Index name
+ */
+ protected $_typeName = '';
+
+ /**
+ * Client.
+ *
+ * @var \Elastica\Client Client object
+ */
+ protected $_client = null;
+
+ /**
+ * Index.
+ *
+ * @var \Elastica\Index Index object
+ */
+ protected $_index = null;
+
+ /**
+ * Type.
+ *
+ * @var \Elastica\Type Type object
+ */
+ protected $_type = null;
+
+ /**
+ * Mapping.
+ *
+ * @var array Mapping
+ */
+ protected $_mapping = array();
+
+ /**
+ * Index params.
+ *
+ * @var array Index params
+ */
+ protected $_indexParams = array();
+
+ /**
+ * Source.
+ *
+ * @var bool Source
+ */
+ protected $_source = true;
+
+ /**
+ * Creates index object with client connection.
+ *
+ * Reads index and type name from protected vars _indexName and _typeName.
+ * Has to be set in child class
+ *
+ * @param \Elastica\Client $client OPTIONAL Client object
+ *
+ * @throws \Elastica\Exception\InvalidException
+ */
+ public function __construct(Client $client = null)
+ {
+ if (!$client) {
+ $client = new Client();
+ }
+
+ if (empty($this->_indexName)) {
+ throw new InvalidException('Index name has to be set');
+ }
+
+ if (empty($this->_typeName)) {
+ throw new InvalidException('Type name has to be set');
+ }
+
+ $this->_client = $client;
+ $this->_index = new Index($this->_client, $this->_indexName);
+ $this->_type = new BaseType($this->_index, $this->_typeName);
+ }
+
+ /**
+ * Creates the index and sets the mapping for this type.
+ *
+ * @param bool $recreate OPTIONAL Recreates the index if true (default = false)
+ */
+ public function create($recreate = false)
+ {
+ $this->getIndex()->create($this->_indexParams, $recreate);
+
+ $mapping = new Mapping($this->getType());
+ $mapping->setProperties($this->_mapping);
+ $mapping->setSource(array('enabled' => $this->_source));
+ $mapping->send();
+ }
+
+ /**
+ * @param \Elastica\Query $query
+ * @param array|int $options
+ *
+ * @return \Elastica\Search
+ */
+ public function createSearch($query = '', $options = null)
+ {
+ return $this->getType()->createSearch($query, $options);
+ }
+
+ /**
+ * Search on the type.
+ *
+ * @param string|array|\Elastica\Query $query Array with all query data inside or a Elastica\Query object
+ *
+ * @return \Elastica\ResultSet ResultSet with all results inside
+ *
+ * @see \Elastica\SearchableInterface::search
+ */
+ public function search($query = '', $options = null)
+ {
+ return $this->getType()->search($query, $options = null);
+ }
+
+ /**
+ * Count docs in the type based on query.
+ *
+ * @param string|array|\Elastica\Query $query Array with all query data inside or a Elastica\Query object
+ *
+ * @return int number of documents matching the query
+ *
+ * @see \Elastica\SearchableInterface::count
+ */
+ public function count($query = '')
+ {
+ return $this->getType()->count($query);
+ }
+
+ /**
+ * Returns the search index.
+ *
+ * @return \Elastica\Index Index object
+ */
+ public function getIndex()
+ {
+ return $this->_index;
+ }
+
+ /**
+ * Returns type object.
+ *
+ * @return \Elastica\Type Type object
+ */
+ public function getType()
+ {
+ return $this->_type;
+ }
+
+ /**
+ * Converts given time to format: 1995-12-31T23:59:59Z.
+ *
+ * This is the lucene date format
+ *
+ * @param int $date Date input (could be string etc.) -> must be supported by strtotime
+ *
+ * @return string Converted date string
+ */
+ public function convertDate($date)
+ {
+ return Util::convertDate($date);
+ }
+}
diff --git a/vendor/ruflin/elastica/lib/Elastica/Type/Mapping.php b/vendor/ruflin/elastica/lib/Elastica/Type/Mapping.php
new file mode 100644
index 00000000..509f0ce2
--- /dev/null
+++ b/vendor/ruflin/elastica/lib/Elastica/Type/Mapping.php
@@ -0,0 +1,297 @@
+<?php
+namespace Elastica\Type;
+
+use Elastica\Exception\InvalidException;
+use Elastica\Request;
+use Elastica\Type;
+
+/**
+ * Elastica Mapping object.
+ *
+ * @author Nicolas Ruflin <spam@ruflin.com>
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/mapping.html
+ */
+class Mapping
+{
+ /**
+ * Mapping.
+ *
+ * @var array Mapping
+ */
+ protected $_mapping = array();
+
+ /**
+ * Type.
+ *
+ * @var \Elastica\Type Type object
+ */
+ protected $_type = null;
+
+ /**
+ * Construct Mapping.
+ *
+ * @param \Elastica\Type $type OPTIONAL Type object
+ * @param array $properties OPTIONAL Properties
+ */
+ public function __construct(Type $type = null, array $properties = array())
+ {
+ if ($type) {
+ $this->setType($type);
+ }
+
+ if (!empty($properties)) {
+ $this->setProperties($properties);
+ }
+ }
+
+ /**
+ * Sets the mapping type
+ * Enter description here ...
+ *
+ * @param \Elastica\Type $type Type object
+ *
+ * @return $this
+ */
+ public function setType(Type $type)
+ {
+ $this->_type = $type;
+
+ return $this;
+ }
+
+ /**
+ * Sets the mapping properties.
+ *
+ * @param array $properties Properties
+ *
+ * @return $this
+ */
+ public function setProperties(array $properties)
+ {
+ return $this->setParam('properties', $properties);
+ }
+
+ /**
+ * Gets the mapping properties.
+ *
+ * @return array $properties Properties
+ */
+ public function getProperties()
+ {
+ return $this->getParam('properties');
+ }
+
+ /**
+ * Sets the mapping _meta.
+ *
+ * @param array $meta metadata
+ *
+ * @return $this
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/mapping-meta.html
+ */
+ public function setMeta(array $meta)
+ {
+ return $this->setParam('_meta', $meta);
+ }
+
+ /**
+ * Returns mapping type.
+ *
+ * @return \Elastica\Type Type
+ */
+ public function getType()
+ {
+ return $this->_type;
+ }
+
+ /**
+ * Sets source values.
+ *
+ * To disable source, argument is
+ * array('enabled' => false)
+ *
+ * @param array $source Source array
+ *
+ * @return $this
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/mapping-source-field.html
+ */
+ public function setSource(array $source)
+ {
+ return $this->setParam('_source', $source);
+ }
+
+ /**
+ * Disables the source in the index.
+ *
+ * Param can be set to true to enable again
+ *
+ * @param bool $enabled OPTIONAL (default = false)
+ *
+ * @return $this
+ */
+ public function disableSource($enabled = false)
+ {
+ return $this->setSource(array('enabled' => $enabled));
+ }
+
+ /**
+ * Sets raw parameters.
+ *
+ * Possible options:
+ * _uid
+ * _id
+ * _type
+ * _source
+ * _all
+ * _analyzer
+ * _boost
+ * _parent
+ * _routing
+ * _index
+ * _size
+ * properties
+ *
+ * @param string $key Key name
+ * @param mixed $value Key value
+ *
+ * @return $this
+ */
+ public function setParam($key, $value)
+ {
+ $this->_mapping[$key] = $value;
+
+ return $this;
+ }
+
+ /**
+ * Get raw parameters.
+ *
+ * @see setParam
+ *
+ * @param string $key Key name
+ *
+ * @return mixed $value Key value
+ */
+ public function getParam($key)
+ {
+ return isset($this->_mapping[$key]) ? $this->_mapping[$key] : null;
+ }
+
+ /**
+ * Sets params for the "_all" field.
+ *
+ * @param array $params _all Params (enabled, store, term_vector, analyzer)
+ *
+ * @return $this
+ */
+ public function setAllField(array $params)
+ {
+ return $this->setParam('_all', $params);
+ }
+
+ /**
+ * Enables the "_all" field.
+ *
+ * @param bool $enabled OPTIONAL (default = true)
+ *
+ * @return $this
+ */
+ public function enableAllField($enabled = true)
+ {
+ return $this->setAllField(array('enabled' => $enabled));
+ }
+
+ /**
+ * Set TTL.
+ *
+ * @param array $params TTL Params (enabled, default, ...)
+ *
+ * @return $this
+ */
+ public function setTtl(array $params)
+ {
+ return $this->setParam('_ttl', $params);
+ }
+
+ /**
+ * Enables TTL for all documents in this type.
+ *
+ * @param bool $enabled OPTIONAL (default = true)
+ *
+ * @return $this
+ */
+ public function enableTtl($enabled = true)
+ {
+ return $this->setTTL(array('enabled' => $enabled));
+ }
+
+ /**
+ * Set parent type.
+ *
+ * @param string $type Parent type
+ *
+ * @return $this
+ */
+ public function setParent($type)
+ {
+ return $this->setParam('_parent', array('type' => $type));
+ }
+
+ /**
+ * Converts the mapping to an array.
+ *
+ * @throws \Elastica\Exception\InvalidException
+ *
+ * @return array Mapping as array
+ */
+ public function toArray()
+ {
+ $type = $this->getType();
+
+ if (empty($type)) {
+ throw new InvalidException('Type has to be set');
+ }
+
+ return array($type->getName() => $this->_mapping);
+ }
+
+ /**
+ * Submits the mapping and sends it to the server.
+ *
+ * @return \Elastica\Response Response object
+ */
+ public function send()
+ {
+ $path = '_mapping';
+
+ return $this->getType()->request($path, Request::PUT, $this->toArray());
+ }
+
+ /**
+ * Creates a mapping object.
+ *
+ * @param array|\Elastica\Type\Mapping $mapping Mapping object or properties array
+ *
+ * @throws \Elastica\Exception\InvalidException If invalid type
+ *
+ * @return self
+ */
+ public static function create($mapping)
+ {
+ if (is_array($mapping)) {
+ $mappingObject = new self();
+ $mappingObject->setProperties($mapping);
+ } else {
+ $mappingObject = $mapping;
+ }
+
+ if (!$mappingObject instanceof self) {
+ throw new InvalidException('Invalid object type');
+ }
+
+ return $mappingObject;
+ }
+}
diff --git a/vendor/ruflin/elastica/lib/Elastica/Util.php b/vendor/ruflin/elastica/lib/Elastica/Util.php
new file mode 100644
index 00000000..a49f2d78
--- /dev/null
+++ b/vendor/ruflin/elastica/lib/Elastica/Util.php
@@ -0,0 +1,194 @@
+<?php
+namespace Elastica;
+
+/**
+ * Elastica tools.
+ *
+ * @author Nicolas Ruflin <spam@ruflin.com>
+ * @author Thibault Duplessis <thibault.duplessis@gmail.com>
+ * @author Oleg Zinchenko <olegz@default-value.com>
+ * @author Roberto Nygaard <roberto@nygaard.es>
+ */
+class Util
+{
+ /**
+ * Replace the following reserved words: AND OR NOT
+ * and
+ * escapes the following terms: + - && || ! ( ) { } [ ] ^ " ~ * ? : \.
+ *
+ * @link http://lucene.apache.org/java/2_4_0/queryparsersyntax.html#Boolean%20operators
+ * @link http://lucene.apache.org/java/2_4_0/queryparsersyntax.html#Escaping%20Special%20Characters
+ *
+ * @param string $term Query term to replace and escape
+ *
+ * @return string Replaced and escaped query term
+ */
+ public static function replaceBooleanWordsAndEscapeTerm($term)
+ {
+ $result = $term;
+ $result = self::replaceBooleanWords($result);
+ $result = self::escapeTerm($result);
+
+ return $result;
+ }
+
+ /**
+ * Escapes the following terms (because part of the query language)
+ * + - && || ! ( ) { } [ ] ^ " ~ * ? : \ < >.
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-query-string-query.html#_reserved_characters
+ *
+ * @param string $term Query term to escape
+ *
+ * @return string Escaped query term
+ */
+ public static function escapeTerm($term)
+ {
+ $result = $term;
+ // \ escaping has to be first, otherwise escaped later once again
+ $chars = array('\\', '+', '-', '&&', '||', '!', '(', ')', '{', '}', '[', ']', '^', '"', '~', '*', '?', ':', '/', '<', '>');
+
+ foreach ($chars as $char) {
+ $result = str_replace($char, '\\'.$char, $result);
+ }
+
+ return $result;
+ }
+
+ /**
+ * Replace the following reserved words (because part of the query language)
+ * AND OR NOT.
+ *
+ * @link http://lucene.apache.org/java/2_4_0/queryparsersyntax.html#Boolean%20operators
+ *
+ * @param string $term Query term to replace
+ *
+ * @return string Replaced query term
+ */
+ public static function replaceBooleanWords($term)
+ {
+ $replacementMap = array(' AND ' => ' && ', ' OR ' => ' || ', ' NOT ' => ' !');
+ $result = strtr($term, $replacementMap);
+
+ return $result;
+ }
+
+ /**
+ * Converts a snake_case string to CamelCase.
+ *
+ * For example: hello_world to HelloWorld
+ *
+ * @param string $string snake_case string
+ *
+ * @return string CamelCase string
+ */
+ public static function toCamelCase($string)
+ {
+ return str_replace(' ', '', ucwords(str_replace('_', ' ', $string)));
+ }
+
+ /**
+ * Converts a CamelCase string to snake_case.
+ *
+ * For Example HelloWorld to hello_world
+ *
+ * @param string $string CamelCase String to Convert
+ *
+ * @return string SnakeCase string
+ */
+ public static function toSnakeCase($string)
+ {
+ $string = preg_replace('/([A-Z])/', '_$1', $string);
+
+ return strtolower(substr($string, 1));
+ }
+
+ /**
+ * Converts given time to format: 1995-12-31T23:59:59Z.
+ *
+ * This is the lucene date format
+ *
+ * @param int $date Date input (could be string etc.) -> must be supported by strtotime
+ *
+ * @return string Converted date string
+ */
+ public static function convertDate($date)
+ {
+ if (is_int($date)) {
+ $timestamp = $date;
+ } else {
+ $timestamp = strtotime($date);
+ }
+ $string = date('Y-m-d\TH:i:s\Z', $timestamp);
+
+ return $string;
+ }
+
+ /**
+ * Convert a \DateTime object to format: 1995-12-31T23:59:59Z+02:00.
+ *
+ * Converts it to the lucene format, including the appropriate TimeZone
+ *
+ * @param \DateTime $dateTime
+ * @param bool $includeTimezone
+ *
+ * @return string
+ */
+ public static function convertDateTimeObject(\DateTime $dateTime, $includeTimezone = true)
+ {
+ $formatString = 'Y-m-d\TH:i:s'.($includeTimezone === true ? 'P' : '\Z');
+ $string = $dateTime->format($formatString);
+
+ return $string;
+ }
+
+ /**
+ * Tries to guess the name of the param, based on its class
+ * Example: \Elastica\Filter\HasChildFilter => has_child.
+ *
+ * @param string|object Class or Class name
+ *
+ * @return string parameter name
+ */
+ public static function getParamName($class)
+ {
+ if (is_object($class)) {
+ $class = get_class($class);
+ }
+
+ $parts = explode('\\', $class);
+ $last = array_pop($parts);
+ $last = preg_replace('/(Facet|Query|Filter)$/', '', $last);
+ $name = self::toSnakeCase($last);
+
+ return $name;
+ }
+
+ /**
+ * Converts Request to Curl console command.
+ *
+ * @param Request $request
+ *
+ * @return string
+ */
+ public static function convertRequestToCurlCommand(Request $request)
+ {
+ $message = 'curl -X'.strtoupper($request->getMethod()).' ';
+ $message .= '\'http://'.$request->getConnection()->getHost().':'.$request->getConnection()->getPort().'/';
+ $message .= $request->getPath();
+
+ $query = $request->getQuery();
+ if (!empty($query)) {
+ $message .= '?'.http_build_query($query);
+ }
+
+ $message .= '\'';
+
+ $data = $request->getData();
+ if (!empty($data)) {
+ $message .= ' -d \''.JSON::stringify($data).'\'';
+ }
+
+ return $message;
+ }
+}
diff --git a/vendor/ruflin/elastica/phpdoc.dist.xml b/vendor/ruflin/elastica/phpdoc.dist.xml
new file mode 100644
index 00000000..585a4687
--- /dev/null
+++ b/vendor/ruflin/elastica/phpdoc.dist.xml
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<docblox>
+ <title>Elastica</title>
+ <parser>
+ <target>./build/api</target>
+ </parser>
+ <transformer>
+ <target>./build/api</target>
+ </transformer>
+ <files>
+ <directory>./lib</directory>
+ </files>
+</docblox>
diff --git a/vendor/ruflin/elastica/test/bootstrap.php b/vendor/ruflin/elastica/test/bootstrap.php
new file mode 100644
index 00000000..8a29cf0f
--- /dev/null
+++ b/vendor/ruflin/elastica/test/bootstrap.php
@@ -0,0 +1,5 @@
+<?php
+
+defined('BASE_PATH') || define('BASE_PATH', realpath(__DIR__));
+
+require dirname(__DIR__).'/vendor/autoload.php';
diff --git a/vendor/ruflin/elastica/test/data/test.doc b/vendor/ruflin/elastica/test/data/test.doc
new file mode 100644
index 00000000..d90d83c1
--- /dev/null
+++ b/vendor/ruflin/elastica/test/data/test.doc
Binary files differ
diff --git a/vendor/ruflin/elastica/test/data/test.docx b/vendor/ruflin/elastica/test/data/test.docx
new file mode 100644
index 00000000..924c1066
--- /dev/null
+++ b/vendor/ruflin/elastica/test/data/test.docx
Binary files differ
diff --git a/vendor/ruflin/elastica/test/data/test.jpg b/vendor/ruflin/elastica/test/data/test.jpg
new file mode 100644
index 00000000..d69e5672
--- /dev/null
+++ b/vendor/ruflin/elastica/test/data/test.jpg
Binary files differ
diff --git a/vendor/ruflin/elastica/test/data/test.pdf b/vendor/ruflin/elastica/test/data/test.pdf
new file mode 100644
index 00000000..e94c3f67
--- /dev/null
+++ b/vendor/ruflin/elastica/test/data/test.pdf
Binary files differ
diff --git a/vendor/ruflin/elastica/test/data/test.txt b/vendor/ruflin/elastica/test/data/test.txt
new file mode 100644
index 00000000..839b72a1
--- /dev/null
+++ b/vendor/ruflin/elastica/test/data/test.txt
@@ -0,0 +1 @@
+Wie geht es ihnen? \ No newline at end of file
diff --git a/vendor/ruflin/elastica/test/lib/Elastica/Test/Aggregation/AvgTest.php b/vendor/ruflin/elastica/test/lib/Elastica/Test/Aggregation/AvgTest.php
new file mode 100644
index 00000000..650a4655
--- /dev/null
+++ b/vendor/ruflin/elastica/test/lib/Elastica/Test/Aggregation/AvgTest.php
@@ -0,0 +1,39 @@
+<?php
+namespace Elastica\Test\Aggregation;
+
+use Elastica\Aggregation\Avg;
+use Elastica\Document;
+use Elastica\Query;
+
+class AvgTest extends BaseAggregationTest
+{
+ protected function _getIndexForTest()
+ {
+ $index = $this->_createIndex();
+
+ $index->getType('test')->addDocuments(array(
+ new Document(1, array('price' => 5)),
+ new Document(2, array('price' => 8)),
+ new Document(3, array('price' => 1)),
+ new Document(4, array('price' => 3)),
+ ));
+
+ $index->refresh();
+
+ return $index;
+ }
+
+ /**
+ * @group functional
+ */
+ public function testAvgAggregation()
+ {
+ $agg = new Avg('avg');
+ $agg->setField('price');
+
+ $query = new Query();
+ $query->addAggregation($agg);
+ $results = $this->_getIndexForTest()->search($query)->getAggregations();
+ $this->assertEquals((5 + 8 + 1 + 3) / 4.0, $results['avg']['value']);
+ }
+}
diff --git a/vendor/ruflin/elastica/test/lib/Elastica/Test/Aggregation/BaseAggregationTest.php b/vendor/ruflin/elastica/test/lib/Elastica/Test/Aggregation/BaseAggregationTest.php
new file mode 100644
index 00000000..48003d7e
--- /dev/null
+++ b/vendor/ruflin/elastica/test/lib/Elastica/Test/Aggregation/BaseAggregationTest.php
@@ -0,0 +1,8 @@
+<?php
+namespace Elastica\Test\Aggregation;
+
+use Elastica\Test\Base;
+
+abstract class BaseAggregationTest extends Base
+{
+}
diff --git a/vendor/ruflin/elastica/test/lib/Elastica/Test/Aggregation/CardinalityTest.php b/vendor/ruflin/elastica/test/lib/Elastica/Test/Aggregation/CardinalityTest.php
new file mode 100644
index 00000000..7bc383f0
--- /dev/null
+++ b/vendor/ruflin/elastica/test/lib/Elastica/Test/Aggregation/CardinalityTest.php
@@ -0,0 +1,132 @@
+<?php
+namespace Elastica\Test\Aggregation;
+
+use Elastica\Aggregation\Cardinality;
+use Elastica\Document;
+use Elastica\Query;
+
+class CardinalityTest extends BaseAggregationTest
+{
+ protected function _getIndexForTest()
+ {
+ $index = $this->_createIndex();
+
+ $index->getType('test')->addDocuments(array(
+ new Document(1, array('color' => 'blue')),
+ new Document(2, array('color' => 'blue')),
+ new Document(3, array('color' => 'red')),
+ new Document(4, array('color' => 'green')),
+ ));
+
+ $index->refresh();
+
+ return $index;
+ }
+
+ /**
+ * @group functional
+ */
+ public function testCardinalityAggregation()
+ {
+ $agg = new Cardinality('cardinality');
+ $agg->setField('color');
+
+ $query = new Query();
+ $query->addAggregation($agg);
+ $results = $this->_getIndexForTest()->search($query)->getAggregation('cardinality');
+
+ $this->assertEquals(3, $results['value']);
+ }
+
+ /**
+ * @dataProvider invalidPrecisionThresholdProvider
+ * @expectedException \InvalidArgumentException
+ *
+ * @param $threshold
+ */
+ public function testInvalidPrecisionThreshold($threshold)
+ {
+ $agg = new Cardinality('threshold');
+ $agg->setPrecisionThreshold($threshold);
+ }
+
+ /**
+ * @dataProvider validPrecisionThresholdProvider
+ *
+ * @param $threshold
+ */
+ public function testPrecisionThreshold($threshold)
+ {
+ $agg = new Cardinality('threshold');
+ $agg->setPrecisionThreshold($threshold);
+
+ $this->assertNotNull($agg->getParam('precision_threshold'));
+ $this->assertInternalType('int', $agg->getParam('precision_threshold'));
+ }
+
+ public function invalidPrecisionThresholdProvider()
+ {
+ return array(
+ 'string' => array('100'),
+ 'float' => array(7.8),
+ 'boolean' => array(true),
+ 'array' => array(array()),
+ 'object' => array(new \StdClass()),
+ );
+ }
+
+ public function validPrecisionThresholdProvider()
+ {
+ return array(
+ 'negative-int' => array(-140),
+ 'zero' => array(0),
+ 'positive-int' => array(150),
+ 'more-than-max' => array(40001),
+ );
+ }
+
+ /**
+ * @dataProvider validRehashProvider
+ *
+ * @param bool $rehash
+ */
+ public function testRehash($rehash)
+ {
+ $agg = new Cardinality('rehash');
+ $agg->setRehash($rehash);
+
+ $this->assertNotNull($agg->getParam('rehash'));
+ $this->assertInternalType('boolean', $agg->getParam('rehash'));
+ }
+
+ /**
+ * @dataProvider invalidRehashProvider
+ * @expectedException \InvalidArgumentException
+ *
+ * @param mixed $rehash
+ */
+ public function testInvalidRehash($rehash)
+ {
+ $agg = new Cardinality('rehash');
+ $agg->setRehash($rehash);
+ }
+
+ public function invalidRehashProvider()
+ {
+ return array(
+ 'string' => array('100'),
+ 'int' => array(100),
+ 'float' => array(7.8),
+ 'array' => array(array()),
+ 'object' => array(new \StdClass()),
+ );
+ }
+
+ public function validRehashProvider()
+ {
+ return array(
+ 'true' => array(true),
+ 'false' => array(false),
+ );
+ }
+}
diff --git a/vendor/ruflin/elastica/test/lib/Elastica/Test/Aggregation/DateHistogramTest.php b/vendor/ruflin/elastica/test/lib/Elastica/Test/Aggregation/DateHistogramTest.php
new file mode 100644
index 00000000..ca115ccc
--- /dev/null
+++ b/vendor/ruflin/elastica/test/lib/Elastica/Test/Aggregation/DateHistogramTest.php
@@ -0,0 +1,103 @@
+<?php
+namespace Elastica\Test\Aggregation;
+
+use Elastica\Aggregation\DateHistogram;
+use Elastica\Document;
+use Elastica\Query;
+use Elastica\Type\Mapping;
+
+class DateHistogramTest extends BaseAggregationTest
+{
+ protected function _getIndexForTest()
+ {
+ $index = $this->_createIndex();
+ $type = $index->getType('test');
+
+ $type->setMapping(new Mapping(null, array(
+ 'created' => array('type' => 'date'),
+ )));
+
+ $type->addDocuments(array(
+ new Document(1, array('created' => '2014-01-29T00:20:00')),
+ new Document(2, array('created' => '2014-01-29T02:20:00')),
+ new Document(3, array('created' => '2014-01-29T03:20:00')),
+ ));
+
+ $index->refresh();
+
+ return $index;
+ }
+
+ /**
+ * @group functional
+ */
+ public function testDateHistogramAggregation()
+ {
+ $agg = new DateHistogram('hist', 'created', '1h');
+
+ $query = new Query();
+ $query->addAggregation($agg);
+ $results = $this->_getIndexForTest()->search($query)->getAggregation('hist');
+
+ $this->assertEquals(3, sizeof($results['buckets']));
+ }
+
+ /**
+ * @group unit
+ */
+ public function testSetOffset()
+ {
+ $agg = new DateHistogram('hist', 'created', '1h');
+
+ $agg->setOffset('3m');
+
+ $expected = array(
+ 'date_histogram' => array(
+ 'field' => 'created',
+ 'interval' => '1h',
+ 'offset' => '3m',
+ ),
+ );
+
+ $this->assertEquals($expected, $agg->toArray());
+
+ $this->assertInstanceOf('Elastica\Aggregation\DateHistogram', $agg->setOffset('3m'));
+ }
+
+ /**
+ * @group functional
+ */
+ public function testSetOffsetWorks()
+ {
+ $agg = new DateHistogram('hist', 'created', '1m');
+ $agg->setOffset('+40s');
+
+ $query = new Query();
+ $query->addAggregation($agg);
+ $results = $this->_getIndexForTest()->search($query)->getAggregation('hist');
+
+ $this->assertEquals('2014-01-29T00:19:40.000Z', $results['buckets'][0]['key_as_string']);
+ }
+
+ /**
+ * @group unit
+ */
+ public function testSetTimezone()
+ {
+ $agg = new DateHistogram('hist', 'created', '1h');
+
+ $agg->setTimezone('-02:30');
+
+ $expected = array(
+ 'date_histogram' => array(
+ 'field' => 'created',
+ 'interval' => '1h',
+ 'time_zone' => '-02:30',
+ ),
+ );
+
+ $this->assertEquals($expected, $agg->toArray());
+
+ $this->assertInstanceOf('Elastica\Aggregation\DateHistogram', $agg->setTimezone('-02:30'));
+ }
+}
diff --git a/vendor/ruflin/elastica/test/lib/Elastica/Test/Aggregation/DateRangeTest.php b/vendor/ruflin/elastica/test/lib/Elastica/Test/Aggregation/DateRangeTest.php
new file mode 100644
index 00000000..b8078a4c
--- /dev/null
+++ b/vendor/ruflin/elastica/test/lib/Elastica/Test/Aggregation/DateRangeTest.php
@@ -0,0 +1,52 @@
+<?php
+namespace Elastica\Test\Aggregation;
+
+use Elastica\Aggregation\DateRange;
+use Elastica\Document;
+use Elastica\Query;
+use Elastica\Type\Mapping;
+
+class DateRangeTest extends BaseAggregationTest
+{
+ protected function _getIndexForTest()
+ {
+ $index = $this->_createIndex();
+ $type = $index->getType('test');
+
+ $type->setMapping(new Mapping(null, array(
+ 'created' => array('type' => 'date'),
+ )));
+
+ $type->addDocuments(array(
+ new Document(1, array('created' => 1390962135000)),
+ new Document(2, array('created' => 1390965735000)),
+ new Document(3, array('created' => 1390954935000)),
+ ));
+
+ $index->refresh();
+
+ return $index;
+ }
+
+ /**
+ * @group functional
+ */
+ public function testDateRangeAggregation()
+ {
+ $agg = new DateRange('date');
+ $agg->setField('created');
+ $agg->addRange(1390958535000)->addRange(null, 1390958535000);
+
+ $query = new Query();
+ $query->addAggregation($agg);
+ $results = $this->_getIndexForTest()->search($query)->getAggregation('date');
+
+ foreach ($results['buckets'] as $bucket) {
+ if (array_key_exists('to', $bucket)) {
+ $this->assertEquals(1, $bucket['doc_count']);
+ } elseif (array_key_exists('from', $bucket)) {
+ $this->assertEquals(2, $bucket['doc_count']);
+ }
+ }
+ }
+}
diff --git a/vendor/ruflin/elastica/test/lib/Elastica/Test/Aggregation/ExtendedStatsTest.php b/vendor/ruflin/elastica/test/lib/Elastica/Test/Aggregation/ExtendedStatsTest.php
new file mode 100644
index 00000000..8c336245
--- /dev/null
+++ b/vendor/ruflin/elastica/test/lib/Elastica/Test/Aggregation/ExtendedStatsTest.php
@@ -0,0 +1,45 @@
+<?php
+namespace Elastica\Test\Aggregation;
+
+use Elastica\Aggregation\ExtendedStats;
+use Elastica\Document;
+use Elastica\Query;
+
+class ExtendedStatsTest extends BaseAggregationTest
+{
+ protected function _getIndexForTest()
+ {
+ $index = $this->_createIndex();
+
+ $index->getType('test')->addDocuments(array(
+ new Document(1, array('price' => 5)),
+ new Document(2, array('price' => 8)),
+ new Document(3, array('price' => 1)),
+ new Document(4, array('price' => 3)),
+ ));
+
+ $index->refresh();
+
+ return $index;
+ }
+
+ /**
+ * @group functional
+ */
+ public function testExtendedStatsAggregation()
+ {
+ $agg = new ExtendedStats('stats');
+ $agg->setField('price');
+
+ $query = new Query();
+ $query->addAggregation($agg);
+ $results = $this->_getIndexForTest()->search($query)->getAggregation('stats');
+
+ $this->assertEquals(4, $results['count']);
+ $this->assertEquals(1, $results['min']);
+ $this->assertEquals(8, $results['max']);
+ $this->assertEquals((5 + 8 + 1 + 3) / 4.0, $results['avg']);
+ $this->assertEquals((5 + 8 + 1 + 3), $results['sum']);
+ $this->assertTrue(array_key_exists('sum_of_squares', $results));
+ }
+}
diff --git a/vendor/ruflin/elastica/test/lib/Elastica/Test/Aggregation/FilterTest.php b/vendor/ruflin/elastica/test/lib/Elastica/Test/Aggregation/FilterTest.php
new file mode 100644
index 00000000..9198bb95
--- /dev/null
+++ b/vendor/ruflin/elastica/test/lib/Elastica/Test/Aggregation/FilterTest.php
@@ -0,0 +1,113 @@
+<?php
+namespace Elastica\Test\Aggregation;
+
+use Elastica\Aggregation\Avg;
+use Elastica\Aggregation\Filter;
+use Elastica\Document;
+use Elastica\Filter\Range;
+use Elastica\Filter\Term;
+use Elastica\Query;
+
+class FilterTest extends BaseAggregationTest
+{
+ protected function _getIndexForTest()
+ {
+ $index = $this->_createIndex();
+
+ $index->getType('test')->addDocuments(array(
+ new Document(1, array('price' => 5, 'color' => 'blue')),
+ new Document(2, array('price' => 8, 'color' => 'blue')),
+ new Document(3, array('price' => 1, 'color' => 'red')),
+ new Document(4, array('price' => 3, 'color' => 'green')),
+ ));
+
+ $index->refresh();
+
+ return $index;
+ }
+
+ /**
+ * @group unit
+ */
+ public function testToArray()
+ {
+ $expected = array(
+ 'filter' => array('range' => array('stock' => array('gt' => 0))),
+ 'aggs' => array(
+ 'avg_price' => array('avg' => array('field' => 'price')),
+ ),
+ );
+
+ $agg = new Filter('in_stock_products');
+ $agg->setFilter(new Range('stock', array('gt' => 0)));
+ $avg = new Avg('avg_price');
+ $avg->setField('price');
+ $agg->addAggregation($avg);
+
+ $this->assertEquals($expected, $agg->toArray());
+ }
+
+ /**
+ * @group functional
+ */
+ public function testFilterAggregation()
+ {
+ $agg = new Filter('filter');
+ $agg->setFilter(new Term(array('color' => 'blue')));
+ $avg = new Avg('price');
+ $avg->setField('price');
+ $agg->addAggregation($avg);
+
+ $query = new Query();
+ $query->addAggregation($agg);
+
+ $results = $this->_getIndexForTest()->search($query)->getAggregation('filter');
+ $results = $results['price']['value'];
+
+ $this->assertEquals((5 + 8) / 2.0, $results);
+ }
+
+ /**
+ * @group functional
+ */
+ public function testFilterNoSubAggregation()
+ {
+ $agg = new Avg('price');
+ $agg->setField('price');
+
+ $query = new Query();
+ $query->addAggregation($agg);
+
+ $results = $this->_getIndexForTest()->search($query)->getAggregation('price');
+ $results = $results['value'];
+
+ $this->assertEquals((5 + 8 + 1 + 3) / 4.0, $results);
+ }
+
+ /**
+ * @group unit
+ */
+ public function testConstruct()
+ {
+ $agg = new Filter('foo', new Term(array('color' => 'blue')));
+
+ $expected = array(
+ 'filter' => array(
+ 'term' => array(
+ 'color' => 'blue',
+ ),
+ ),
+ );
+
+ $this->assertEquals($expected, $agg->toArray());
+ }
+
+ /**
+ * @group unit
+ */
+ public function testConstructWithoutFilter()
+ {
+ $agg = new Filter('foo');
+ $this->assertEquals('foo', $agg->getName());
+ }
+}
diff --git a/vendor/ruflin/elastica/test/lib/Elastica/Test/Aggregation/FiltersTest.php b/vendor/ruflin/elastica/test/lib/Elastica/Test/Aggregation/FiltersTest.php
new file mode 100644
index 00000000..36ebcd45
--- /dev/null
+++ b/vendor/ruflin/elastica/test/lib/Elastica/Test/Aggregation/FiltersTest.php
@@ -0,0 +1,120 @@
+<?php
+namespace Elastica\Test\Aggregation;
+
+use Elastica\Aggregation\Avg;
+use Elastica\Aggregation\Filter;
+use Elastica\Aggregation\Filters;
+use Elastica\Document;
+use Elastica\Filter\Term;
+use Elastica\Query;
+
+class FiltersTest extends BaseAggregationTest
+{
+ protected function _getIndexForTest()
+ {
+ $index = $this->_createIndex('filter');
+
+ $index->getType('test')->addDocuments(array(
+ new Document(1, array('price' => 5, 'color' => 'blue')),
+ new Document(2, array('price' => 8, 'color' => 'blue')),
+ new Document(3, array('price' => 1, 'color' => 'red')),
+ new Document(4, array('price' => 3, 'color' => 'green')),
+ ));
+
+ $index->refresh();
+
+ return $index;
+ }
+
+ /**
+ * @group unit
+ */
+ public function testToArrayUsingNamedFilters()
+ {
+ $expected = array(
+ 'filters' => array(
+ 'filters' => array(
+ 'blue' => array(
+ 'term' => array('color' => 'blue'),
+ ),
+ 'red' => array(
+ 'term' => array('color' => 'red'),
+ ),
+ ),
+ ),
+ 'aggs' => array(
+ 'avg_price' => array('avg' => array('field' => 'price')),
+ ),
+ );
+
+ $agg = new Filters('by_color');
+ $agg->addFilter(new Term(array('color' => 'blue')), 'blue');
+ $agg->addFilter(new Term(array('color' => 'red')), 'red');
+
+ $avg = new Avg('avg_price');
+ $avg->setField('price');
+ $agg->addAggregation($avg);
+
+ $this->assertEquals($expected, $agg->toArray());
+ }
+
+ /**
+ * @group unit
+ */
+ public function testToArrayUsingAnonymousFilters()
+ {
+ $expected = array(
+ 'filters' => array(
+ 'filters' => array(
+ array(
+ 'term' => array('color' => 'blue'),
+ ),
+ array(
+ 'term' => array('color' => 'red'),
+ ),
+ ),
+ ),
+ 'aggs' => array(
+ 'avg_price' => array('avg' => array('field' => 'price')),
+ ),
+ );
+
+ $agg = new Filters('by_color');
+ $agg->addFilter(new Term(array('color' => 'blue')));
+ $agg->addFilter(new Term(array('color' => 'red')));
+
+ $avg = new Avg('avg_price');
+ $avg->setField('price');
+ $agg->addAggregation($avg);
+
+ $this->assertEquals($expected, $agg->toArray());
+ }
+
+ /**
+ * @group functional
+ */
+ public function testFilterAggregation()
+ {
+ $agg = new Filters('by_color');
+ $agg->addFilter(new Term(array('color' => 'blue')), 'blue');
+ $agg->addFilter(new Term(array('color' => 'red')), 'red');
+
+ $avg = new Avg('avg_price');
+ $avg->setField('price');
+ $agg->addAggregation($avg);
+
+ $query = new Query();
+ $query->addAggregation($agg);
+
+ $results = $this->_getIndexForTest()->search($query)->getAggregation('by_color');
+
+ $resultsForBlue = $results['buckets']['blue'];
+ $resultsForRed = $results['buckets']['red'];
+
+ $this->assertEquals(2, $resultsForBlue['doc_count']);
+ $this->assertEquals(1, $resultsForRed['doc_count']);
+
+ $this->assertEquals((5 + 8) / 2, $resultsForBlue['avg_price']['value']);
+ $this->assertEquals(1, $resultsForRed['avg_price']['value']);
+ }
+}
diff --git a/vendor/ruflin/elastica/test/lib/Elastica/Test/Aggregation/GeoDistanceTest.php b/vendor/ruflin/elastica/test/lib/Elastica/Test/Aggregation/GeoDistanceTest.php
new file mode 100644
index 00000000..f8a02d1d
--- /dev/null
+++ b/vendor/ruflin/elastica/test/lib/Elastica/Test/Aggregation/GeoDistanceTest.php
@@ -0,0 +1,46 @@
+<?php
+namespace Elastica\Test\Aggregation;
+
+use Elastica\Aggregation\GeoDistance;
+use Elastica\Document;
+use Elastica\Query;
+use Elastica\Type\Mapping;
+
+class GeoDistanceTest extends BaseAggregationTest
+{
+ protected function _getIndexForTest()
+ {
+ $index = $this->_createIndex();
+ $type = $index->getType('test');
+
+ $type->setMapping(new Mapping(null, array(
+ 'location' => array('type' => 'geo_point'),
+ )));
+
+ $type->addDocuments(array(
+ new Document(1, array('location' => array('lat' => 32.849437, 'lon' => -117.271732))),
+ new Document(2, array('location' => array('lat' => 32.798320, 'lon' => -117.246648))),
+ new Document(3, array('location' => array('lat' => 37.782439, 'lon' => -122.392560))),
+ ));
+
+ $index->refresh();
+
+ return $index;
+ }
+
+ /**
+ * @group functional
+ */
+ public function testGeoDistanceAggregation()
+ {
+ $agg = new GeoDistance('geo', 'location', array('lat' => 32.804654, 'lon' => -117.242594));
+ $agg->addRange(null, 100);
+ $agg->setUnit('mi');
+
+ $query = new Query();
+ $query->addAggregation($agg);
+ $results = $this->_getIndexForTest()->search($query)->getAggregation('geo');
+
+ $this->assertEquals(2, $results['buckets'][0]['doc_count']);
+ }
+}
diff --git a/vendor/ruflin/elastica/test/lib/Elastica/Test/Aggregation/GeohashGridTest.php b/vendor/ruflin/elastica/test/lib/Elastica/Test/Aggregation/GeohashGridTest.php
new file mode 100644
index 00000000..6e0d43fd
--- /dev/null
+++ b/vendor/ruflin/elastica/test/lib/Elastica/Test/Aggregation/GeohashGridTest.php
@@ -0,0 +1,46 @@
+<?php
+namespace Elastica\Test\Aggregation;
+
+use Elastica\Aggregation\GeohashGrid;
+use Elastica\Document;
+use Elastica\Query;
+use Elastica\Type\Mapping;
+
+class GeohashGridTest extends BaseAggregationTest
+{
+ protected function _getIndexForTest()
+ {
+ $index = $this->_createIndex();
+ $type = $index->getType('test');
+
+ $type->setMapping(new Mapping(null, array(
+ 'location' => array('type' => 'geo_point'),
+ )));
+
+ $type->addDocuments(array(
+ new Document(1, array('location' => array('lat' => 32.849437, 'lon' => -117.271732))),
+ new Document(2, array('location' => array('lat' => 32.798320, 'lon' => -117.246648))),
+ new Document(3, array('location' => array('lat' => 37.782439, 'lon' => -122.392560))),
+ ));
+
+ $index->refresh();
+
+ return $index;
+ }
+
+ /**
+ * @group functional
+ */
+ public function testGeohashGridAggregation()
+ {
+ $agg = new GeohashGrid('hash', 'location');
+ $agg->setPrecision(3);
+
+ $query = new Query();
+ $query->addAggregation($agg);
+ $results = $this->_getIndexForTest()->search($query)->getAggregation('hash');
+
+ $this->assertEquals(2, $results['buckets'][0]['doc_count']);
+ $this->assertEquals(1, $results['buckets'][1]['doc_count']);
+ }
+}
diff --git a/vendor/ruflin/elastica/test/lib/Elastica/Test/Aggregation/GlobalAggregationTest.php b/vendor/ruflin/elastica/test/lib/Elastica/Test/Aggregation/GlobalAggregationTest.php
new file mode 100644
index 00000000..6ab086d0
--- /dev/null
+++ b/vendor/ruflin/elastica/test/lib/Elastica/Test/Aggregation/GlobalAggregationTest.php
@@ -0,0 +1,27 @@
+<?php
+namespace Elastica\Test\Aggregation;
+
+use Elastica\Aggregation\Avg;
+use Elastica\Aggregation\GlobalAggregation;
+
+class GlobalAggregationTest extends BaseAggregationTest
+{
+ /**
+ * @group unit
+ */
+ public function testToArray()
+ {
+ $expected = array(
+ 'global' => new \stdClass(),
+ 'aggs' => array(
+ 'avg_price' => array('avg' => array('field' => 'price')),
+ ),
+ );
+
+ $agg = new GlobalAggregation('all_products');
+ $avg = new Avg('avg_price');
+ $avg->setField('price');
+ $agg->addAggregation($avg);
+ $this->assertEquals($expected, $agg->toArray());
+ }
+}
diff --git a/vendor/ruflin/elastica/test/lib/Elastica/Test/Aggregation/HistogramTest.php b/vendor/ruflin/elastica/test/lib/Elastica/Test/Aggregation/HistogramTest.php
new file mode 100644
index 00000000..ffdf73a4
--- /dev/null
+++ b/vendor/ruflin/elastica/test/lib/Elastica/Test/Aggregation/HistogramTest.php
@@ -0,0 +1,47 @@
+<?php
+namespace Elastica\Test\Aggregation;
+
+use Elastica\Aggregation\Histogram;
+use Elastica\Document;
+use Elastica\Query;
+
+class HistogramTest extends BaseAggregationTest
+{
+ protected function _getIndexForTest()
+ {
+ $index = $this->_createIndex();
+
+ $index->getType('test')->addDocuments(array(
+ new Document(1, array('price' => 5, 'color' => 'blue')),
+ new Document(2, array('price' => 8, 'color' => 'blue')),
+ new Document(3, array('price' => 1, 'color' => 'red')),
+ new Document(4, array('price' => 30, 'color' => 'green')),
+ new Document(5, array('price' => 40, 'color' => 'red')),
+ new Document(6, array('price' => 35, 'color' => 'green')),
+ new Document(7, array('price' => 42, 'color' => 'red')),
+ new Document(8, array('price' => 41, 'color' => 'blue')),
+ ));
+
+ $index->refresh();
+
+ return $index;
+ }
+
+ /**
+ * @group functional
+ */
+ public function testHistogramAggregation()
+ {
+ $agg = new Histogram('hist', 'price', 10);
+ $agg->setMinimumDocumentCount(0); // should return empty buckets
+
+ $query = new Query();
+ $query->addAggregation($agg);
+ $results = $this->_getIndexForTest()->search($query)->getAggregation('hist');
+
+ $buckets = $results['buckets'];
+ $this->assertEquals(5, sizeof($buckets));
+ $this->assertEquals(30, $buckets[3]['key']);
+ $this->assertEquals(2, $buckets[3]['doc_count']);
+ }
+}
diff --git a/vendor/ruflin/elastica/test/lib/Elastica/Test/Aggregation/IpRangeTest.php b/vendor/ruflin/elastica/test/lib/Elastica/Test/Aggregation/IpRangeTest.php
new file mode 100644
index 00000000..2f3099f6
--- /dev/null
+++ b/vendor/ruflin/elastica/test/lib/Elastica/Test/Aggregation/IpRangeTest.php
@@ -0,0 +1,57 @@
+<?php
+namespace Elastica\Test\Aggregation;
+
+use Elastica\Aggregation\IpRange;
+use Elastica\Document;
+use Elastica\Query;
+use Elastica\Type\Mapping;
+
+class IpRangeTest extends BaseAggregationTest
+{
+ protected function _getIndexForTest()
+ {
+ $index = $this->_createIndex();
+ $type = $index->getType('test');
+
+ $type->setMapping(new Mapping(null, array(
+ 'address' => array('type' => 'ip'),
+ )));
+
+ $type->addDocuments(array(
+ new Document(1, array('address' => '192.168.1.100')),
+ new Document(2, array('address' => '192.168.1.150')),
+ new Document(3, array('address' => '192.168.1.200')),
+ ));
+
+ $index->refresh();
+
+ return $index;
+ }
+
+ /**
+ * @group functional
+ */
+ public function testIpRangeAggregation()
+ {
+ $agg = new IpRange('ip', 'address');
+ $agg->addRange('192.168.1.101');
+ $agg->addRange(null, '192.168.1.200');
+
+ $cidrRange = '192.168.1.0/24';
+ $agg->addMaskRange($cidrRange);
+
+ $query = new Query();
+ $query->addAggregation($agg);
+ $results = $this->_getIndexForTest()->search($query)->getAggregation('ip');
+
+ foreach ($results['buckets'] as $bucket) {
+ if (array_key_exists('key', $bucket) && $bucket['key'] == $cidrRange) {
+ // the CIDR mask
+ $this->assertEquals(3, $bucket['doc_count']);
+ } else {
+ // the normal ip ranges
+ $this->assertEquals(2, $bucket['doc_count']);
+ }
+ }
+ }
+}
diff --git a/vendor/ruflin/elastica/test/lib/Elastica/Test/Aggregation/MaxTest.php b/vendor/ruflin/elastica/test/lib/Elastica/Test/Aggregation/MaxTest.php
new file mode 100644
index 00000000..f057b81d
--- /dev/null
+++ b/vendor/ruflin/elastica/test/lib/Elastica/Test/Aggregation/MaxTest.php
@@ -0,0 +1,79 @@
+<?php
+namespace Elastica\Test\Aggregation;
+
+use Elastica\Aggregation\Max;
+use Elastica\Document;
+use Elastica\Query;
+use Elastica\Script;
+
+class MaxTest extends BaseAggregationTest
+{
+ protected function _getIndexForTest()
+ {
+ $index = $this->_createIndex();
+
+ $index->getType('test')->addDocuments(array(
+ new Document(1, array('price' => 5)),
+ new Document(2, array('price' => 8)),
+ new Document(3, array('price' => 1)),
+ new Document(4, array('price' => 3)),
+ ));
+
+ $index->refresh();
+
+ return $index;
+ }
+
+ /**
+ * @group unit
+ */
+ public function testToArray()
+ {
+ $expected = array(
+ 'max' => array(
+ 'field' => 'price',
+ 'script' => '_value * conversion_rate',
+ 'params' => array(
+ 'conversion_rate' => 1.2,
+ ),
+ ),
+ 'aggs' => array(
+ 'subagg' => array('max' => array('field' => 'foo')),
+ ),
+ );
+
+ $agg = new Max('min_price_in_euros');
+ $agg->setField('price');
+ $agg->setScript(new Script('_value * conversion_rate', array('conversion_rate' => 1.2)));
+ $max = new Max('subagg');
+ $max->setField('foo');
+ $agg->addAggregation($max);
+
+ $this->assertEquals($expected, $agg->toArray());
+ }
+
+ /**
+ * @group functional
+ */
+ public function testMaxAggregation()
+ {
+ $index = $this->_getIndexForTest();
+
+ $agg = new Max('min_price');
+ $agg->setField('price');
+
+ $query = new Query();
+ $query->addAggregation($agg);
+ $results = $index->search($query)->getAggregation('min_price');
+
+ $this->assertEquals(8, $results['value']);
+
+ // test using a script
+ $agg->setScript(new Script('_value * conversion_rate', array('conversion_rate' => 1.2)));
+ $query = new Query();
+ $query->addAggregation($agg);
+ $results = $index->search($query)->getAggregation('min_price');
+
+ $this->assertEquals(8 * 1.2, $results['value']);
+ }
+}
diff --git a/vendor/ruflin/elastica/test/lib/Elastica/Test/Aggregation/MinTest.php b/vendor/ruflin/elastica/test/lib/Elastica/Test/Aggregation/MinTest.php
new file mode 100644
index 00000000..ce0ad5e7
--- /dev/null
+++ b/vendor/ruflin/elastica/test/lib/Elastica/Test/Aggregation/MinTest.php
@@ -0,0 +1,40 @@
+<?php
+namespace Elastica\Test\Aggregation;
+
+use Elastica\Aggregation\Min;
+use Elastica\Document;
+use Elastica\Query;
+
+class MinTest extends BaseAggregationTest
+{
+ protected function _getIndexForTest()
+ {
+ $index = $this->_createIndex();
+
+ $index->getType('test')->addDocuments(array(
+ new Document(1, array('price' => 5)),
+ new Document(2, array('price' => 8)),
+ new Document(3, array('price' => 1)),
+ new Document(4, array('price' => 3)),
+ ));
+
+ $index->refresh();
+
+ return $index;
+ }
+
+ /**
+ * @group functional
+ */
+ public function testMinAggregation()
+ {
+ $agg = new Min('min_price');
+ $agg->setField('price');
+
+ $query = new Query();
+ $query->addAggregation($agg);
+ $results = $this->_getIndexForTest()->search($query)->getAggregation('min_price');
+
+ $this->assertEquals(1, $results['value']);
+ }
+}
diff --git a/vendor/ruflin/elastica/test/lib/Elastica/Test/Aggregation/MissingTest.php b/vendor/ruflin/elastica/test/lib/Elastica/Test/Aggregation/MissingTest.php
new file mode 100644
index 00000000..85461879
--- /dev/null
+++ b/vendor/ruflin/elastica/test/lib/Elastica/Test/Aggregation/MissingTest.php
@@ -0,0 +1,39 @@
+<?php
+namespace Elastica\Test\Aggregation;
+
+use Elastica\Aggregation\Missing;
+use Elastica\Document;
+use Elastica\Query;
+
+class MissingTest extends BaseAggregationTest
+{
+ protected function _getIndexForTest()
+ {
+ $index = $this->_createIndex();
+
+ $index->getType('test')->addDocuments(array(
+ new Document(1, array('price' => 5, 'color' => 'blue')),
+ new Document(2, array('price' => 8, 'color' => 'blue')),
+ new Document(3, array('price' => 1)),
+ new Document(4, array('price' => 3, 'color' => 'green')),
+ ));
+
+ $index->refresh();
+
+ return $index;
+ }
+
+ /**
+ * @group functional
+ */
+ public function testMissingAggregation()
+ {
+ $agg = new Missing('missing', 'color');
+
+ $query = new Query();
+ $query->addAggregation($agg);
+ $results = $this->_getIndexForTest()->search($query)->getAggregation('missing');
+
+ $this->assertEquals(1, $results['doc_count']);
+ }
+}
diff --git a/vendor/ruflin/elastica/test/lib/Elastica/Test/Aggregation/NestedTest.php b/vendor/ruflin/elastica/test/lib/Elastica/Test/Aggregation/NestedTest.php
new file mode 100644
index 00000000..58c5d13a
--- /dev/null
+++ b/vendor/ruflin/elastica/test/lib/Elastica/Test/Aggregation/NestedTest.php
@@ -0,0 +1,63 @@
+<?php
+namespace Elastica\Test\Aggregation;
+
+use Elastica\Aggregation\Min;
+use Elastica\Aggregation\Nested;
+use Elastica\Document;
+use Elastica\Query;
+use Elastica\Type\Mapping;
+
+class NestedTest extends BaseAggregationTest
+{
+ protected function _getIndexForTest()
+ {
+ $index = $this->_createIndex();
+ $type = $index->getType('test');
+
+ $type->setMapping(new Mapping(null, array(
+ 'resellers' => array(
+ 'type' => 'nested',
+ 'properties' => array(
+ 'name' => array('type' => 'string'),
+ 'price' => array('type' => 'double'),
+ ),
+ ),
+ )));
+
+ $type->addDocuments(array(
+ new Document(1, array(
+ 'resellers' => array(
+ 'name' => 'spacely sprockets',
+ 'price' => 5.55,
+ ),
+ )),
+ new Document(2, array(
+ 'resellers' => array(
+ 'name' => 'cogswell cogs',
+ 'price' => 4.98,
+ ),
+ )),
+ ));
+
+ $index->refresh();
+
+ return $index;
+ }
+
+ /**
+ * @group functional
+ */
+ public function testNestedAggregation()
+ {
+ $agg = new Nested('resellers', 'resellers');
+ $min = new Min('min_price');
+ $min->setField('price');
+ $agg->addAggregation($min);
+
+ $query = new Query();
+ $query->addAggregation($agg);
+ $results = $this->_getIndexForTest()->search($query)->getAggregation('resellers');
+
+ $this->assertEquals(4.98, $results['min_price']['value']);
+ }
+}
diff --git a/vendor/ruflin/elastica/test/lib/Elastica/Test/Aggregation/PercentilesTest.php b/vendor/ruflin/elastica/test/lib/Elastica/Test/Aggregation/PercentilesTest.php
new file mode 100644
index 00000000..ee4dd2c5
--- /dev/null
+++ b/vendor/ruflin/elastica/test/lib/Elastica/Test/Aggregation/PercentilesTest.php
@@ -0,0 +1,125 @@
+<?php
+namespace Elastica\Test\Aggregation;
+
+use Elastica\Aggregation\Percentiles;
+use Elastica\Document;
+use Elastica\Query;
+
+class PercentilesTest extends BaseAggregationTest
+{
+ /**
+ * @group functional
+ */
+ public function testConstruct()
+ {
+ $aggr = new Percentiles('price_percentile');
+ $this->assertEquals('price_percentile', $aggr->getName());
+
+ $aggr = new Percentiles('price_percentile', 'price');
+ $this->assertEquals('price', $aggr->getParam('field'));
+ }
+
+ /**
+ * @group functional
+ */
+ public function testSetField()
+ {
+ $aggr = new Percentiles('price_percentile');
+ $aggr->setField('price');
+
+ $this->assertEquals('price', $aggr->getParam('field'));
+ $this->assertInstanceOf('Elastica\Aggregation\Percentiles', $aggr->setField('price'));
+ }
+
+ /**
+ * @group functional
+ */
+ public function testSetCompression()
+ {
+ $aggr = new Percentiles('price_percentile');
+ $aggr->setCompression(200);
+ $this->assertEquals(200, $aggr->getParam('compression'));
+ $this->assertInstanceOf('Elastica\Aggregation\Percentiles', $aggr->setCompression(200));
+ }
+
+ /**
+ * @group functional
+ */
+ public function testSetPercents()
+ {
+ $percents = array(1, 2, 3);
+ $aggr = new Percentiles('price_percentile');
+ $aggr->setPercents($percents);
+ $this->assertEquals($percents, $aggr->getParam('percents'));
+ $this->assertInstanceOf('Elastica\Aggregation\Percentiles', $aggr->setPercents($percents));
+ }
+
+ /**
+ * @group functional
+ */
+ public function testAddPercent()
+ {
+ $percents = array(1, 2, 3);
+ $aggr = new Percentiles('price_percentile');
+ $aggr->setPercents($percents);
+ $this->assertEquals($percents, $aggr->getParam('percents'));
+ $aggr->addPercent(4);
+ $percents[] = 4;
+ $this->assertEquals($percents, $aggr->getParam('percents'));
+ $this->assertInstanceOf('Elastica\Aggregation\Percentiles', $aggr->addPercent(4));
+ }
+
+ /**
+ * @group functional
+ */
+ public function testSetScript()
+ {
+ $script = 'doc["load_time"].value / 20';
+ $aggr = new Percentiles('price_percentile');
+ $aggr->setScript($script);
+ $this->assertEquals($script, $aggr->getParam('script'));
+ $this->assertInstanceOf('Elastica\Aggregation\Percentiles', $aggr->setScript($script));
+ }
+
+ /**
+ * @group functional
+ */
+ public function testActualWork()
+ {
+ // prepare
+ $index = $this->_createIndex();
+ $type = $index->getType('offer');
+ $type->addDocuments(array(
+ new Document(1, array('price' => 100)),
+ new Document(2, array('price' => 200)),
+ new Document(3, array('price' => 300)),
+ new Document(4, array('price' => 400)),
+ new Document(5, array('price' => 500)),
+ new Document(6, array('price' => 600)),
+ new Document(7, array('price' => 700)),
+ new Document(8, array('price' => 800)),
+ new Document(9, array('price' => 900)),
+ new Document(10, array('price' => 1000)),
+ ));
+ $index->refresh();
+
+ // execute
+ $aggr = new Percentiles('price_percentile');
+ $aggr->setField('price');
+
+ $query = new Query();
+ $query->addAggregation($aggr);
+
+ $resultSet = $type->search($query);
+ $aggrResult = $resultSet->getAggregation('price_percentile');
+
+ // hope it's ok to hardcode results...
+ $this->assertEquals(109.0, $aggrResult['values']['1.0']);
+ $this->assertEquals(145.0, $aggrResult['values']['5.0']);
+ $this->assertEquals(325.0, $aggrResult['values']['25.0']);
+ $this->assertEquals(550.0, $aggrResult['values']['50.0']);
+ $this->assertEquals(775.0, $aggrResult['values']['75.0']);
+ $this->assertEquals(955.0, $aggrResult['values']['95.0']);
+ $this->assertEquals(991.0, $aggrResult['values']['99.0']);
+ }
+}
diff --git a/vendor/ruflin/elastica/test/lib/Elastica/Test/Aggregation/RangeTest.php b/vendor/ruflin/elastica/test/lib/Elastica/Test/Aggregation/RangeTest.php
new file mode 100644
index 00000000..f96e4096
--- /dev/null
+++ b/vendor/ruflin/elastica/test/lib/Elastica/Test/Aggregation/RangeTest.php
@@ -0,0 +1,78 @@
+<?php
+namespace Elastica\Test\Aggregation;
+
+use Elastica\Aggregation\Range;
+use Elastica\Document;
+use Elastica\Query;
+
+class RangeTest extends BaseAggregationTest
+{
+ protected function _getIndexForTest()
+ {
+ $index = $this->_createIndex();
+
+ $index->getType('test')->addDocuments(array(
+ new Document(1, array('price' => 5)),
+ new Document(2, array('price' => 8)),
+ new Document(3, array('price' => 1)),
+ new Document(4, array('price' => 3)),
+ new Document(5, array('price' => 1.5)),
+ new Document(6, array('price' => 2)),
+ ));
+
+ $index->refresh();
+
+ return $index;
+ }
+
+ /**
+ * @group functional
+ */
+ public function testRangeAggregation()
+ {
+ $agg = new Range('range');
+ $agg->setField('price');
+ $agg->addRange(1.5, 5);
+
+ $query = new Query();
+ $query->addAggregation($agg);
+ $results = $this->_getIndexForTest()->search($query)->getAggregation('range');
+
+ $this->assertEquals(2, $results['buckets'][0]['doc_count']);
+ }
+
+ /**
+ * @group unit
+ */
+ public function testRangeAggregationWithKey()
+ {
+ $agg = new Range('range');
+ $agg->setField('price');
+ $agg->addRange(null, 50, 'cheap');
+ $agg->addRange(50, 100, 'average');
+ $agg->addRange(100, null, 'expensive');
+
+ $expected = array(
+ 'range' => array(
+ 'field' => 'price',
+ 'ranges' => array(
+ array(
+ 'to' => 50,
+ 'key' => 'cheap',
+ ),
+ array(
+ 'from' => 50,
+ 'to' => 100,
+ 'key' => 'average',
+ ),
+ array(
+ 'from' => 100,
+ 'key' => 'expensive',
+ ),
+ ),
+ ),
+ );
+
+ $this->assertEquals($expected, $agg->toArray());
+ }
+}
diff --git a/vendor/ruflin/elastica/test/lib/Elastica/Test/Aggregation/ReverseNestedTest.php b/vendor/ruflin/elastica/test/lib/Elastica/Test/Aggregation/ReverseNestedTest.php
new file mode 100644
index 00000000..0e2ed2e6
--- /dev/null
+++ b/vendor/ruflin/elastica/test/lib/Elastica/Test/Aggregation/ReverseNestedTest.php
@@ -0,0 +1,134 @@
+<?php
+namespace Elastica\Test\Aggregation;
+
+use Elastica\Aggregation\Nested;
+use Elastica\Aggregation\ReverseNested;
+use Elastica\Aggregation\Terms;
+use Elastica\Document;
+use Elastica\Query;
+use Elastica\Type\Mapping;
+
+class ReverseNestedTest extends BaseAggregationTest
+{
+ protected function _getIndexForTest()
+ {
+ $index = $this->_createIndex();
+ $mapping = new Mapping();
+ $mapping->setProperties(array(
+ 'comments' => array(
+ 'type' => 'nested',
+ 'properties' => array(
+ 'name' => array('type' => 'string'),
+ 'body' => array('type' => 'string'),
+ ),
+ ),
+ ));
+ $type = $index->getType('test');
+ $type->setMapping($mapping);
+
+ $type->addDocuments(array(
+ new Document(1, array(
+ 'comments' => array(
+ array(
+ 'name' => 'bob',
+ 'body' => 'this is bobs comment',
+ ),
+ array(
+ 'name' => 'john',
+ 'body' => 'this is johns comment',
+ ),
+ ),
+ 'tags' => array('foo', 'bar'),
+ )),
+ new Document(2, array(
+ 'comments' => array(
+ array(
+ 'name' => 'bob',
+ 'body' => 'this is another comment from bob',
+ ),
+ array(
+ 'name' => 'susan',
+ 'body' => 'this is susans comment',
+ ),
+ ),
+ 'tags' => array('foo', 'baz'),
+ )),
+ ));
+
+ $index->refresh();
+
+ return $index;
+ }
+
+ /**
+ * @group unit
+ */
+ public function testPathNotSetIfNull()
+ {
+ $agg = new ReverseNested('nested');
+ $this->assertFalse($agg->hasParam('path'));
+ }
+
+ /**
+ * @group unit
+ */
+ public function testPathSetIfNotNull()
+ {
+ $agg = new ReverseNested('nested', 'some_field');
+ $this->assertEquals('some_field', $agg->getParam('path'));
+ }
+
+ /**
+ * @group functional
+ */
+ public function testReverseNestedAggregation()
+ {
+ $agg = new Nested('comments', 'comments');
+ $names = new Terms('name');
+ $names->setField('comments.name');
+
+ $tags = new Terms('tags');
+ $tags->setField('tags');
+
+ $reverseNested = new ReverseNested('main');
+ $reverseNested->addAggregation($tags);
+
+ $names->addAggregation($reverseNested);
+
+ $agg->addAggregation($names);
+
+ $query = new Query();
+ $query->addAggregation($agg);
+ $results = $this->_getIndexForTest()->search($query)->getAggregation('comments');
+
+ $this->assertArrayHasKey('name', $results);
+ $nameResults = $results['name'];
+
+ $this->assertCount(3, $nameResults['buckets']);
+
+ // bob
+ $this->assertEquals('bob', $nameResults['buckets'][0]['key']);
+ $tags = array(
+ array('key' => 'foo', 'doc_count' => 2),
+ array('key' => 'bar', 'doc_count' => 1),
+ array('key' => 'baz', 'doc_count' => 1),
+ );
+ $this->assertEquals($tags, $nameResults['buckets'][0]['main']['tags']['buckets']);
+
+ // john
+ $this->assertEquals('john', $nameResults['buckets'][1]['key']);
+ $tags = array(
+ array('key' => 'bar', 'doc_count' => 1),
+ array('key' => 'foo', 'doc_count' => 1),
+ );
+ $this->assertEquals($tags, $nameResults['buckets'][1]['main']['tags']['buckets']);
+
+ // susan
+ $this->assertEquals('susan', $nameResults['buckets'][2]['key']);
+ $tags = array(
+ array('key' => 'baz', 'doc_count' => 1),
+ array('key' => 'foo', 'doc_count' => 1),
+ );
+ $this->assertEquals($tags, $nameResults['buckets'][2]['main']['tags']['buckets']);
+ }
+}
diff --git a/vendor/ruflin/elastica/test/lib/Elastica/Test/Aggregation/ScriptTest.php b/vendor/ruflin/elastica/test/lib/Elastica/Test/Aggregation/ScriptTest.php
new file mode 100644
index 00000000..bf32b251
--- /dev/null
+++ b/vendor/ruflin/elastica/test/lib/Elastica/Test/Aggregation/ScriptTest.php
@@ -0,0 +1,87 @@
+<?php
+namespace Elastica\Test\Aggregation;
+
+use Elastica\Aggregation\Sum;
+use Elastica\Document;
+use Elastica\Query;
+use Elastica\Script;
+
+class ScriptTest extends BaseAggregationTest
+{
+ protected function _getIndexForTest()
+ {
+ $index = $this->_createIndex();
+
+ $index->getType('test')->addDocuments(array(
+ new Document('1', array('price' => 5)),
+ new Document('2', array('price' => 8)),
+ new Document('3', array('price' => 1)),
+ new Document('4', array('price' => 3)),
+ ));
+
+ $index->refresh();
+
+ return $index;
+ }
+
+ /**
+ * @group functional
+ */
+ public function testAggregationScript()
+ {
+ $agg = new Sum('sum');
+ // x = (0..1) is groovy-specific syntax, to see if lang is recognized
+ $script = new Script("x = (0..1); return doc['price'].value", null, 'groovy');
+ $agg->setScript($script);
+
+ $query = new Query();
+ $query->addAggregation($agg);
+ $results = $this->_getIndexForTest()->search($query)->getAggregation('sum');
+
+ $this->assertEquals(5 + 8 + 1 + 3, $results['value']);
+ }
+
+ /**
+ * @group functional
+ */
+ public function testAggregationScriptAsString()
+ {
+ $agg = new Sum('sum');
+ $agg->setScript("doc['price'].value");
+
+ $query = new Query();
+ $query->addAggregation($agg);
+ $results = $this->_getIndexForTest()->search($query)->getAggregation('sum');
+
+ $this->assertEquals(5 + 8 + 1 + 3, $results['value']);
+ }
+
+ /**
+ * @group unit
+ */
+ public function testSetScript()
+ {
+ $aggregation = 'sum';
+ $string = "doc['price'].value";
+ $params = array(
+ 'param1' => 'one',
+ 'param2' => 1,
+ );
+ $lang = 'groovy';
+
+ $agg = new Sum($aggregation);
+ $script = new Script($string, $params, $lang);
+ $agg->setScript($script);
+
+ $array = $agg->toArray();
+
+ $expected = array(
+ $aggregation => array(
+ 'script' => $string,
+ 'params' => $params,
+ 'lang' => $lang,
+ ),
+ );
+ $this->assertEquals($expected, $array);
+ }
+}
diff --git a/vendor/ruflin/elastica/test/lib/Elastica/Test/Aggregation/ScriptedMetricTest.php b/vendor/ruflin/elastica/test/lib/Elastica/Test/Aggregation/ScriptedMetricTest.php
new file mode 100644
index 00000000..31f5798b
--- /dev/null
+++ b/vendor/ruflin/elastica/test/lib/Elastica/Test/Aggregation/ScriptedMetricTest.php
@@ -0,0 +1,50 @@
+<?php
+namespace Elastica\Test\Aggregation;
+
+use Elastica\Aggregation\ScriptedMetric;
+use Elastica\Document;
+use Elastica\Query;
+use Elastica\Type\Mapping;
+
+class ScriptedMetricTest extends BaseAggregationTest
+{
+ protected function _getIndexForTest()
+ {
+ $index = $this->_createIndex();
+ $type = $index->getType('test');
+
+ $type->setMapping(new Mapping(null, array(
+ 'start' => array('type' => 'long'),
+ 'end' => array('type' => 'long'),
+ )));
+
+ $type->addDocuments(array(
+ new Document(1, array('start' => 100, 'end' => 200)),
+ new Document(2, array('start' => 200, 'end' => 250)),
+ new Document(3, array('start' => 300, 'end' => 450)),
+ ));
+
+ $index->refresh();
+
+ return $index;
+ }
+
+ /**
+ * @group functional
+ */
+ public function testScriptedMetricAggregation()
+ {
+ $agg = new ScriptedMetric(
+ 'scripted',
+ "_agg['durations'] = [:]",
+ "key = doc['start'].value+ \":\"+ doc['end'].value; _agg.durations[key] = doc['end'].value - doc['start'].value;",
+ 'values = []; for (item in _agg.durations) { values.add(item.value) }; return values'
+ );
+
+ $query = new Query();
+ $query->addAggregation($agg);
+ $results = $this->_getIndexForTest()->search($query)->getAggregation('scripted');
+
+ $this->assertEquals(array(100, 50, 150), $results['value'][0]);
+ }
+}
diff --git a/vendor/ruflin/elastica/test/lib/Elastica/Test/Aggregation/SignificantTermsTest.php b/vendor/ruflin/elastica/test/lib/Elastica/Test/Aggregation/SignificantTermsTest.php
new file mode 100644
index 00000000..8960768b
--- /dev/null
+++ b/vendor/ruflin/elastica/test/lib/Elastica/Test/Aggregation/SignificantTermsTest.php
@@ -0,0 +1,72 @@
+<?php
+namespace Elastica\Test\Aggregation;
+
+use Elastica\Aggregation\SignificantTerms;
+use Elastica\Document;
+use Elastica\Filter\Terms as TermsFilter;
+use Elastica\Query;
+use Elastica\Query\Terms;
+
+class SignificantTermsTest extends BaseAggregationTest
+{
+ protected function _getIndexForTest()
+ {
+ $index = $this->_createIndex();
+ $colors = array('blue', 'blue', 'red', 'red', 'green', 'yellow', 'white', 'cyan', 'magenta');
+ $temperatures = array(1500, 1500, 1500, 1500, 2500, 3500, 4500, 5500, 6500, 7500, 7500, 8500, 9500);
+ $docs = array();
+ for ($i = 0;$i < 250;$i++) {
+ $docs[] = new Document($i, array('color' => $colors[$i % count($colors)], 'temperature' => $temperatures[$i % count($temperatures)]));
+ }
+ $index->getType('test')->addDocuments($docs);
+ $index->refresh();
+
+ return $index;
+ }
+
+ /**
+ * @group functional
+ */
+ public function testSignificantTermsAggregation()
+ {
+ $agg = new SignificantTerms('significantTerms');
+ $agg->setField('temperature');
+ $agg->setSize(1);
+
+ $termsQuery = new Terms();
+ $termsQuery->setTerms('color', array('blue', 'red', 'green', 'yellow', 'white'));
+
+ $query = new Query($termsQuery);
+ $query->addAggregation($agg);
+ $results = $this->_getIndexForTest()->search($query)->getAggregation('significantTerms');
+
+ $this->assertEquals(1, count($results['buckets']));
+ $this->assertEquals(63, $results['buckets'][0]['doc_count']);
+ $this->assertEquals(79, $results['buckets'][0]['bg_count']);
+ $this->assertEquals('1500', $results['buckets'][0]['key_as_string']);
+ }
+
+ /**
+ * @group functional
+ */
+ public function testSignificantTermsAggregationWithBackgroundFilter()
+ {
+ $agg = new SignificantTerms('significantTerms');
+ $agg->setField('temperature');
+ $agg->setSize(1);
+ $termsFilter = new TermsFilter();
+ $termsFilter->setTerms('color', array('blue', 'red', 'green', 'yellow'));
+ $agg->setBackgroundFilter($termsFilter);
+
+ $termsQuery = new Terms();
+ $termsQuery->setTerms('color', array('blue', 'red', 'green', 'yellow', 'white'));
+
+ $query = new Query($termsQuery);
+ $query->addAggregation($agg);
+ $results = $this->_getIndexForTest()->search($query)->getAggregation('significantTerms');
+
+ $this->assertEquals(15, $results['buckets'][0]['doc_count']);
+ $this->assertEquals(12, $results['buckets'][0]['bg_count']);
+ $this->assertEquals('4500', $results['buckets'][0]['key_as_string']);
+ }
+}
diff --git a/vendor/ruflin/elastica/test/lib/Elastica/Test/Aggregation/StatsTest.php b/vendor/ruflin/elastica/test/lib/Elastica/Test/Aggregation/StatsTest.php
new file mode 100644
index 00000000..45c9d08c
--- /dev/null
+++ b/vendor/ruflin/elastica/test/lib/Elastica/Test/Aggregation/StatsTest.php
@@ -0,0 +1,44 @@
+<?php
+namespace Elastica\Test\Aggregation;
+
+use Elastica\Aggregation\Stats;
+use Elastica\Document;
+use Elastica\Query;
+
+class StatsTest extends BaseAggregationTest
+{
+ protected function _getIndexForTest()
+ {
+ $index = $this->_createIndex();
+
+ $index->getType('test')->addDocuments(array(
+ new Document(1, array('price' => 5)),
+ new Document(2, array('price' => 8)),
+ new Document(3, array('price' => 1)),
+ new Document(4, array('price' => 3)),
+ ));
+
+ $index->refresh();
+
+ return $index;
+ }
+
+ /**
+ * @group functional
+ */
+ public function testStatsAggregation()
+ {
+ $agg = new Stats('stats');
+ $agg->setField('price');
+
+ $query = new Query();
+ $query->addAggregation($agg);
+ $results = $this->_getIndexForTest()->search($query)->getAggregation('stats');
+
+ $this->assertEquals(4, $results['count']);
+ $this->assertEquals(1, $results['min']);
+ $this->assertEquals(8, $results['max']);
+ $this->assertEquals((5 + 8 + 1 + 3) / 4.0, $results['avg']);
+ $this->assertEquals((5 + 8 + 1 + 3), $results['sum']);
+ }
+}
diff --git a/vendor/ruflin/elastica/test/lib/Elastica/Test/Aggregation/SumTest.php b/vendor/ruflin/elastica/test/lib/Elastica/Test/Aggregation/SumTest.php
new file mode 100644
index 00000000..b60e6e14
--- /dev/null
+++ b/vendor/ruflin/elastica/test/lib/Elastica/Test/Aggregation/SumTest.php
@@ -0,0 +1,40 @@
+<?php
+namespace Elastica\Test\Aggregation;
+
+use Elastica\Aggregation\Sum;
+use Elastica\Document;
+use Elastica\Query;
+
+class SumTest extends BaseAggregationTest
+{
+ protected function _getIndexForTest()
+ {
+ $index = $this->_createIndex();
+
+ $index->getType('test')->addDocuments(array(
+ new Document(1, array('price' => 5)),
+ new Document(2, array('price' => 8)),
+ new Document(3, array('price' => 1)),
+ new Document(4, array('price' => 3)),
+ ));
+
+ $index->refresh();
+
+ return $index;
+ }
+
+ /**
+ * @group functional
+ */
+ public function testSumAggregation()
+ {
+ $agg = new Sum('sum');
+ $agg->setField('price');
+
+ $query = new Query();
+ $query->addAggregation($agg);
+ $results = $this->_getIndexForTest()->search($query)->getAggregation('sum');
+
+ $this->assertEquals(5 + 8 + 1 + 3, $results['value']);
+ }
+}
diff --git a/vendor/ruflin/elastica/test/lib/Elastica/Test/Aggregation/TermsTest.php b/vendor/ruflin/elastica/test/lib/Elastica/Test/Aggregation/TermsTest.php
new file mode 100644
index 00000000..58eb02c2
--- /dev/null
+++ b/vendor/ruflin/elastica/test/lib/Elastica/Test/Aggregation/TermsTest.php
@@ -0,0 +1,41 @@
+<?php
+namespace Elastica\Test\Aggregation;
+
+use Elastica\Aggregation\Terms;
+use Elastica\Document;
+use Elastica\Query;
+
+class TermsTest extends BaseAggregationTest
+{
+ protected function _getIndexForTest()
+ {
+ $index = $this->_createIndex();
+
+ $index->getType('test')->addDocuments(array(
+ new Document(1, array('color' => 'blue')),
+ new Document(2, array('color' => 'blue')),
+ new Document(3, array('color' => 'red')),
+ new Document(4, array('color' => 'green')),
+ ));
+
+ $index->refresh();
+
+ return $index;
+ }
+
+ /**
+ * @group functional
+ */
+ public function testTermsAggregation()
+ {
+ $agg = new Terms('terms');
+ $agg->setField('color');
+
+ $query = new Query();
+ $query->addAggregation($agg);
+ $results = $this->_getIndexForTest()->search($query)->getAggregation('terms');
+
+ $this->assertEquals(2, $results['buckets'][0]['doc_count']);
+ $this->assertEquals('blue', $results['buckets'][0]['key']);
+ }
+}
diff --git a/vendor/ruflin/elastica/test/lib/Elastica/Test/Aggregation/TopHitsTest.php b/vendor/ruflin/elastica/test/lib/Elastica/Test/Aggregation/TopHitsTest.php
new file mode 100644
index 00000000..afe23e27
--- /dev/null
+++ b/vendor/ruflin/elastica/test/lib/Elastica/Test/Aggregation/TopHitsTest.php
@@ -0,0 +1,385 @@
+<?php
+namespace Elastica\Test\Aggregation;
+
+use Elastica\Aggregation\Terms;
+use Elastica\Aggregation\TopHits;
+use Elastica\Document;
+use Elastica\Query;
+use Elastica\Query\MatchAll;
+use Elastica\Query\SimpleQueryString;
+use Elastica\Script;
+use Elastica\ScriptFields;
+
+class TopHitsTest extends BaseAggregationTest
+{
+ protected function _getIndexForTest()
+ {
+ $index = $this->_createIndex();
+
+ $index->getType('questions')->addDocuments(array(
+ new Document(1, array(
+ 'tags' => array('linux'),
+ 'last_activity_date' => '2015-01-05',
+ 'title' => 'Question about linux #1',
+ )),
+ new Document(2, array(
+ 'tags' => array('linux'),
+ 'last_activity_date' => '2014-12-23',
+ 'title' => 'Question about linux #2',
+ )),
+ new Document(3, array(
+ 'tags' => array('windows'),
+ 'last_activity_date' => '2015-01-05',
+ 'title' => 'Question about windows #1',
+ )),
+ new Document(4, array(
+ 'tags' => array('windows'),
+ 'last_activity_date' => '2014-12-23',
+ 'title' => 'Question about windows #2',
+ )),
+ new Document(5, array(
+ 'tags' => array('osx', 'apple'),
+ 'last_activity_date' => '2014-12-23',
+ 'title' => 'Question about osx',
+ )),
+ ));
+
+ $index->refresh();
+
+ return $index;
+ }
+
+ /**
+ * @group unit
+ */
+ public function testSetSize()
+ {
+ $agg = new TopHits('agg_name');
+ $returnValue = $agg->setSize(12);
+ $this->assertEquals(12, $agg->getParam('size'));
+ $this->assertInstanceOf('Elastica\Aggregation\TopHits', $returnValue);
+ }
+
+ /**
+ * @group unit
+ */
+ public function testSetFrom()
+ {
+ $agg = new TopHits('agg_name');
+ $returnValue = $agg->setFrom(12);
+ $this->assertEquals(12, $agg->getParam('from'));
+ $this->assertInstanceOf('Elastica\Aggregation\TopHits', $returnValue);
+ }
+
+ /**
+ * @group unit
+ */
+ public function testSetSort()
+ {
+ $sort = array('last_activity_date' => array('order' => 'desc'));
+ $agg = new TopHits('agg_name');
+ $returnValue = $agg->setSort($sort);
+ $this->assertEquals($sort, $agg->getParam('sort'));
+ $this->assertInstanceOf('Elastica\Aggregation\TopHits', $returnValue);
+ }
+
+ /**
+ * @group unit
+ */
+ public function testSetSource()
+ {
+ $fields = array('title', 'tags');
+ $agg = new TopHits('agg_name');
+ $returnValue = $agg->setSource($fields);
+ $this->assertEquals($fields, $agg->getParam('_source'));
+ $this->assertInstanceOf('Elastica\Aggregation\TopHits', $returnValue);
+ }
+
+ /**
+ * @group unit
+ */
+ public function testSetVersion()
+ {
+ $agg = new TopHits('agg_name');
+ $returnValue = $agg->setVersion(true);
+ $this->assertTrue($agg->getParam('version'));
+ $this->assertInstanceOf('Elastica\Aggregation\TopHits', $returnValue);
+
+ $agg->setVersion(false);
+ $this->assertFalse($agg->getParam('version'));
+ }
+
+ /**
+ * @group unit
+ */
+ public function testSetExplain()
+ {
+ $agg = new TopHits('agg_name');
+ $returnValue = $agg->setExplain(true);
+ $this->assertTrue($agg->getParam('explain'));
+ $this->assertInstanceOf('Elastica\Aggregation\TopHits', $returnValue);
+
+ $agg->setExplain(false);
+ $this->assertFalse($agg->getParam('explain'));
+ }
+
+ /**
+ * @group unit
+ */
+ public function testSetHighlight()
+ {
+ $highlight = array(
+ 'fields' => array(
+ 'title',
+ ),
+ );
+ $agg = new TopHits('agg_name');
+ $returnValue = $agg->setHighlight($highlight);
+ $this->assertEquals($highlight, $agg->getParam('highlight'));
+ $this->assertInstanceOf('Elastica\Aggregation\TopHits', $returnValue);
+ }
+
+ /**
+ * @group unit
+ */
+ public function testSetFieldDataFields()
+ {
+ $fields = array('title', 'tags');
+ $agg = new TopHits('agg_name');
+ $returnValue = $agg->setFieldDataFields($fields);
+ $this->assertEquals($fields, $agg->getParam('fielddata_fields'));
+ $this->assertInstanceOf('Elastica\Aggregation\TopHits', $returnValue);
+ }
+
+ /**
+ * @group unit
+ */
+ public function testSetScriptFields()
+ {
+ $script = new Script('1 + 2');
+ $scriptFields = new ScriptFields(array('three' => $script));
+
+ $agg = new TopHits('agg_name');
+ $returnValue = $agg->setScriptFields($scriptFields);
+ $this->assertEquals($scriptFields->toArray(), $agg->getParam('script_fields'));
+ $this->assertInstanceOf('Elastica\Aggregation\TopHits', $returnValue);
+ }
+
+ /**
+ * @group unit
+ */
+ public function testAddScriptField()
+ {
+ $script = new Script('2+3');
+ $agg = new TopHits('agg_name');
+ $returnValue = $agg->addScriptField('five', $script);
+ $this->assertEquals(array('five' => $script->toArray()), $agg->getParam('script_fields'));
+ $this->assertInstanceOf('Elastica\Aggregation\TopHits', $returnValue);
+ }
+
+ protected function getOuterAggregationResult($innerAggr)
+ {
+ $outerAggr = new Terms('top_tags');
+ $outerAggr->setField('tags');
+ $outerAggr->setMinimumDocumentCount(2);
+ $outerAggr->addAggregation($innerAggr);
+
+ $query = new Query(new MatchAll());
+ $query->addAggregation($outerAggr);
+
+ return $this->_getIndexForTest()->search($query)->getAggregation('top_tags');
+ }
+
+ /**
+ * @group functional
+ */
+ public function testAggregateUpdatedRecently()
+ {
+ $aggr = new TopHits('top_tag_hits');
+ $aggr->setSize(1);
+ $aggr->setSort(array('last_activity_date' => array('order' => 'desc')));
+
+ $resultDocs = array();
+ $outerAggrResult = $this->getOuterAggregationResult($aggr);
+ foreach ($outerAggrResult['buckets'] as $bucket) {
+ foreach ($bucket['top_tag_hits']['hits']['hits'] as $doc) {
+ $resultDocs[] = $doc['_id'];
+ }
+ }
+ $this->assertEquals(array(1, 3), $resultDocs);
+ }
+
+ /**
+ * @group functional
+ */
+ public function testAggregateUpdatedFarAgo()
+ {
+ $aggr = new TopHits('top_tag_hits');
+ $aggr->setSize(1);
+ $aggr->setSort(array('last_activity_date' => array('order' => 'asc')));
+
+ $resultDocs = array();
+ $outerAggrResult = $this->getOuterAggregationResult($aggr);
+ foreach ($outerAggrResult['buckets'] as $bucket) {
+ foreach ($bucket['top_tag_hits']['hits']['hits'] as $doc) {
+ $resultDocs[] = $doc['_id'];
+ }
+ }
+ $this->assertEquals(array(2, 4), $resultDocs);
+ }
+
+ /**
+ * @group functional
+ */
+ public function testAggregateTwoDocumentPerTag()
+ {
+ $aggr = new TopHits('top_tag_hits');
+ $aggr->setSize(2);
+
+ $resultDocs = array();
+ $outerAggrResult = $this->getOuterAggregationResult($aggr);
+ foreach ($outerAggrResult['buckets'] as $bucket) {
+ foreach ($bucket['top_tag_hits']['hits']['hits'] as $doc) {
+ $resultDocs[] = $doc['_id'];
+ }
+ }
+ $this->assertEquals(array(1, 2, 3, 4), $resultDocs);
+ }
+
+ /**
+ * @group functional
+ */
+ public function testAggregateTwoDocumentPerTagWithOffset()
+ {
+ $aggr = new TopHits('top_tag_hits');
+ $aggr->setSize(2);
+ $aggr->setFrom(1);
+ $aggr->setSort(array('last_activity_date' => array('order' => 'desc')));
+
+ $resultDocs = array();
+ $outerAggrResult = $this->getOuterAggregationResult($aggr);
+ foreach ($outerAggrResult['buckets'] as $bucket) {
+ foreach ($bucket['top_tag_hits']['hits']['hits'] as $doc) {
+ $resultDocs[] = $doc['_id'];
+ }
+ }
+ $this->assertEquals(array(2, 4), $resultDocs);
+ }
+
+ /**
+ * @group functional
+ */
+ public function testAggregateWithLimitedSource()
+ {
+ $aggr = new TopHits('top_tag_hits');
+ $aggr->setSource(array('title'));
+
+ $resultDocs = array();
+ $outerAggrResult = $this->getOuterAggregationResult($aggr);
+ foreach ($outerAggrResult['buckets'] as $bucket) {
+ foreach ($bucket['top_tag_hits']['hits']['hits'] as $doc) {
+ $this->assertArrayHasKey('title', $doc['_source']);
+ $this->assertArrayNotHasKey('tags', $doc['_source']);
+ $this->assertArrayNotHasKey('last_activity_date', $doc['_source']);
+ }
+ }
+ }
+
+ /**
+ * @group functional
+ */
+ public function testAggregateWithVersion()
+ {
+ $aggr = new TopHits('top_tag_hits');
+ $aggr->setVersion(true);
+
+ $resultDocs = array();
+ $outerAggrResult = $this->getOuterAggregationResult($aggr);
+ foreach ($outerAggrResult['buckets'] as $bucket) {
+ foreach ($bucket['top_tag_hits']['hits']['hits'] as $doc) {
+ $this->assertArrayHasKey('_version', $doc);
+ }
+ }
+ }
+
+ /**
+ * @group functional
+ */
+ public function testAggregateWithExplain()
+ {
+ $aggr = new TopHits('top_tag_hits');
+ $aggr->setExplain(true);
+
+ $resultDocs = array();
+ $outerAggrResult = $this->getOuterAggregationResult($aggr);
+ foreach ($outerAggrResult['buckets'] as $bucket) {
+ foreach ($bucket['top_tag_hits']['hits']['hits'] as $doc) {
+ $this->assertArrayHasKey('_explanation', $doc);
+ }
+ }
+ }
+
+ /**
+ * @group functional
+ */
+ public function testAggregateWithScriptFields()
+ {
+ $aggr = new TopHits('top_tag_hits');
+ $aggr->setSize(1);
+ $aggr->setScriptFields(array('three' => new Script('1 + 2')));
+ $aggr->addScriptField('five', new Script('3 + 2'));
+
+ $resultDocs = array();
+ $outerAggrResult = $this->getOuterAggregationResult($aggr);
+ foreach ($outerAggrResult['buckets'] as $bucket) {
+ foreach ($bucket['top_tag_hits']['hits']['hits'] as $doc) {
+ $this->assertEquals(3, $doc['fields']['three'][0]);
+ $this->assertEquals(5, $doc['fields']['five'][0]);
+ }
+ }
+ }
+
+ /**
+ * @group functional
+ */
+ public function testAggregateWithHighlight()
+ {
+ $queryString = new SimpleQueryString('linux', array('title'));
+
+ $aggr = new TopHits('top_tag_hits');
+ $aggr->setHighlight(array('fields' => array('title' => new \stdClass())));
+
+ $query = new Query($queryString);
+ $query->addAggregation($aggr);
+
+ $resultSet = $this->_getIndexForTest()->search($query);
+ $aggrResult = $resultSet->getAggregation('top_tag_hits');
+
+ foreach ($aggrResult['hits']['hits'] as $doc) {
+ $this->assertArrayHasKey('highlight', $doc);
+ $this->assertRegExp('#<em>linux</em>#', $doc['highlight']['title'][0]);
+ }
+ }
+
+ /**
+ * @group functional
+ */
+ public function testAggregateWithFieldData()
+ {
+ $aggr = new TopHits('top_tag_hits');
+ $aggr->setFieldDataFields(array('title'));
+
+ $query = new Query(new MatchAll());
+ $query->addAggregation($aggr);
+
+ $resultSet = $this->_getIndexForTest()->search($query);
+ $aggrResult = $resultSet->getAggregation('top_tag_hits');
+
+ foreach ($aggrResult['hits']['hits'] as $doc) {
+ $this->assertArrayHasKey('fields', $doc);
+ $this->assertArrayHasKey('title', $doc['fields']);
+ $this->assertArrayNotHasKey('tags', $doc['fields']);
+ $this->assertArrayNotHasKey('last_activity_date', $doc['fields']);
+ }
+ }
+}
diff --git a/vendor/ruflin/elastica/test/lib/Elastica/Test/Aggregation/ValueCountTest.php b/vendor/ruflin/elastica/test/lib/Elastica/Test/Aggregation/ValueCountTest.php
new file mode 100644
index 00000000..21b63cbe
--- /dev/null
+++ b/vendor/ruflin/elastica/test/lib/Elastica/Test/Aggregation/ValueCountTest.php
@@ -0,0 +1,40 @@
+<?php
+namespace Elastica\Test\Aggregation;
+
+use Elastica\Aggregation\ValueCount;
+use Elastica\Document;
+use Elastica\Query;
+
+class ValueCountTest extends BaseAggregationTest
+{
+ protected function _getIndexForTest()
+ {
+ $index = $this->_createIndex();
+
+ $index->getType('test')->addDocuments(array(
+ new Document(1, array('price' => 5)),
+ new Document(2, array('price' => 8)),
+ new Document(3, array('price' => 1)),
+ new Document(4, array('price' => 3)),
+ new Document(5, array('price' => 3)),
+ ));
+
+ $index->refresh();
+
+ return $index;
+ }
+
+ /**
+ * @group functional
+ */
+ public function testValueCountAggregation()
+ {
+ $agg = new ValueCount('count', 'price');
+
+ $query = new Query();
+ $query->addAggregation($agg);
+ $results = $this->_getIndexForTest()->search($query)->getAggregation('count');
+
+ $this->assertEquals(5, $results['value']);
+ }
+}
diff --git a/vendor/ruflin/elastica/test/lib/Elastica/Test/Base.php b/vendor/ruflin/elastica/test/lib/Elastica/Test/Base.php
new file mode 100644
index 00000000..c826c747
--- /dev/null
+++ b/vendor/ruflin/elastica/test/lib/Elastica/Test/Base.php
@@ -0,0 +1,142 @@
+<?php
+namespace Elastica\Test;
+
+use Elastica\Client;
+use Elastica\Connection;
+use Elastica\Index;
+
+class Base extends \PHPUnit_Framework_TestCase
+{
+ /**
+ * @param array $params Additional configuration params. Host and Port are already set
+ * @param callback $callback
+ *
+ * @return Client
+ */
+ protected function _getClient(array $params = array(), $callback = null)
+ {
+ $config = array(
+ 'host' => $this->_getHost(),
+ 'port' => $this->_getPort(),
+ );
+
+ $config = array_merge($config, $params);
+
+ return new Client($config, $callback);
+ }
+
+ /**
+ * @return string Host to es for elastica tests
+ */
+ protected function _getHost()
+ {
+ return getenv('ES_HOST') ?: Connection::DEFAULT_HOST;
+ }
+
+ /**
+ * @return int Port to es for elastica tests
+ */
+ protected function _getPort()
+ {
+ return getenv('ES_PORT') ?: Connection::DEFAULT_PORT;
+ }
+
+ /**
+ * @return string Proxy url string
+ */
+ protected function _getProxyUrl()
+ {
+ $proxyHost = getenv('PROXY_HOST') ?: Connection::DEFAULT_HOST;
+
+ return 'http://'.$proxyHost.':12345';
+ }
+
+ /**
+ * @return string Proxy url string to proxy which returns 403
+ */
+ protected function _getProxyUrl403()
+ {
+ $proxyHost = getenv('PROXY_HOST') ?: Connection::DEFAULT_HOST;
+
+ return 'http://'.$proxyHost.':12346';
+ }
+
+ /**
+ * @param string $name Index name
+ * @param bool $delete Delete index if it exists
+ * @param int $shards Number of shards to create
+ *
+ * @return \Elastica\Index
+ */
+ protected function _createIndex($name = null, $delete = true, $shards = 1)
+ {
+ if (is_null($name)) {
+ $name = preg_replace('/[^a-z]/i', '', strtolower(get_called_class())).uniqid();
+ }
+
+ $client = $this->_getClient();
+ $index = $client->getIndex('elastica_'.$name);
+ $index->create(array('index' => array('number_of_shards' => $shards, 'number_of_replicas' => 0)), $delete);
+
+ return $index;
+ }
+
+ protected function _waitForAllocation(Index $index)
+ {
+ do {
+ $settings = $index->getStatus()->get();
+ $allocated = true;
+ foreach ($settings['shards'] as $shard) {
+ if ($shard[0]['routing']['state'] != 'STARTED') {
+ $allocated = false;
+ }
+ }
+ } while (!$allocated);
+ }
+
+ protected function setUp()
+ {
+ parent::setUp();
+
+ $hasGroup = $this->_isUnitGroup() || $this->_isFunctionalGroup() || $this->_isShutdownGroup() || $this->_isBenchmarkGroup();
+ $this->assertTrue($hasGroup, 'Every test must have one of "unit", "functional", "shutdown" or "benchmark" group');
+ }
+
+ protected function tearDown()
+ {
+ if ($this->_isFunctionalGroup()) {
+ $this->_getClient()->getIndex('_all')->delete();
+ $this->_getClient()->getIndex('_all')->clearCache();
+ }
+
+ parent::tearDown();
+ }
+
+ protected function _isUnitGroup()
+ {
+ $groups = \PHPUnit_Util_Test::getGroups(get_class($this), $this->getName(false));
+
+ return in_array('unit', $groups);
+ }
+
+ protected function _isFunctionalGroup()
+ {
+ $groups = \PHPUnit_Util_Test::getGroups(get_class($this), $this->getName(false));
+
+ return in_array('functional', $groups);
+ }
+
+ protected function _isShutdownGroup()
+ {
+ $groups = \PHPUnit_Util_Test::getGroups(get_class($this), $this->getName(false));
+
+ return in_array('shutdown', $groups);
+ }
+
+ protected function _isBenchmarkGroup()
+ {
+ $groups = \PHPUnit_Util_Test::getGroups(get_class($this), $this->getName(false));
+
+ return in_array('benchmark', $groups);
+ }
+}
diff --git a/vendor/ruflin/elastica/test/lib/Elastica/Test/Bulk/ActionTest.php b/vendor/ruflin/elastica/test/lib/Elastica/Test/Bulk/ActionTest.php
new file mode 100644
index 00000000..e4588e70
--- /dev/null
+++ b/vendor/ruflin/elastica/test/lib/Elastica/Test/Bulk/ActionTest.php
@@ -0,0 +1,66 @@
+<?php
+namespace Elastica\Test\Bulk;
+
+use Elastica\Bulk\Action;
+use Elastica\Index;
+use Elastica\Test\Base as BaseTest;
+use Elastica\Type;
+
+class ActionTest extends BaseTest
+{
+ /**
+ * @group unit
+ */
+ public function testAction()
+ {
+ $action = new Action();
+ $this->assertEquals('index', $action->getOpType());
+ $this->assertFalse($action->hasSource());
+
+ $expected = '{"index":{}}'."\n";
+ $this->assertEquals($expected, $action->toString());
+
+ $action->setIndex('index');
+
+ $expected = '{"index":{"_index":"index"}}'."\n";
+ $this->assertEquals($expected, $action->toString());
+
+ $action->setType('type');
+
+ $expected = '{"index":{"_index":"index","_type":"type"}}'."\n";
+ $this->assertEquals($expected, $action->toString());
+
+ $action->setId(1);
+ $expected = '{"index":{"_index":"index","_type":"type","_id":1}}'."\n";
+ $this->assertEquals($expected, $action->toString());
+
+ $action->setRouting(1);
+ $expected = '{"index":{"_index":"index","_type":"type","_id":1,"_routing":1}}'."\n";
+ $this->assertEquals($expected, $action->toString());
+
+ $client = $this->_getClient();
+ $index = new Index($client, 'index2');
+ $type = new Type($index, 'type2');
+
+ $action->setIndex($index);
+
+ $expected = '{"index":{"_index":"index2","_type":"type","_id":1,"_routing":1}}'."\n";
+ $this->assertEquals($expected, $action->toString());
+
+ $action->setType($type);
+
+ $expected = '{"index":{"_index":"index2","_type":"type2","_id":1,"_routing":1}}'."\n";
+ $this->assertEquals($expected, $action->toString());
+
+ $action->setSource(array('user' => 'name'));
+
+ $expected = '{"index":{"_index":"index2","_type":"type2","_id":1,"_routing":1}}'."\n";
+ $expected .= '{"user":"name"}'."\n";
+
+ $this->assertEquals($expected, $action->toString());
+ $this->assertTrue($action->hasSource());
+
+ $this->assertFalse(Action::isValidOpType('foo'));
+ $this->assertTrue(Action::isValidOpType('delete'));
+ }
+}
diff --git a/vendor/ruflin/elastica/test/lib/Elastica/Test/Bulk/ResponseSetTest.php b/vendor/ruflin/elastica/test/lib/Elastica/Test/Bulk/ResponseSetTest.php
new file mode 100644
index 00000000..949dcf7a
--- /dev/null
+++ b/vendor/ruflin/elastica/test/lib/Elastica/Test/Bulk/ResponseSetTest.php
@@ -0,0 +1,200 @@
+<?php
+namespace Elastica\Test\Bulk;
+
+use Elastica\Bulk;
+use Elastica\Bulk\Action;
+use Elastica\Exception\Bulk\ResponseException;
+use Elastica\Response;
+use Elastica\Test\Base as BaseTest;
+
+class ResponseSetTest extends BaseTest
+{
+ /**
+ * @group unit
+ * @dataProvider isOkDataProvider
+ */
+ public function testIsOk($responseData, $actions, $expected)
+ {
+ $responseSet = $this->_createResponseSet($responseData, $actions);
+ $this->assertEquals($expected, $responseSet->isOk());
+ }
+
+ /**
+ * @group unit
+ */
+ public function testGetError()
+ {
+ list($responseData, $actions) = $this->_getFixture();
+ $responseData['items'][1]['index']['ok'] = false;
+ $responseData['items'][1]['index']['error'] = 'SomeExceptionMessage';
+ $responseData['items'][2]['index']['ok'] = false;
+ $responseData['items'][2]['index']['error'] = 'AnotherExceptionMessage';
+
+ try {
+ $this->_createResponseSet($responseData, $actions);
+ $this->fail('Bulk request should fail');
+ } catch (ResponseException $e) {
+ $responseSet = $e->getResponseSet();
+
+ $this->assertInstanceOf('Elastica\\Bulk\\ResponseSet', $responseSet);
+
+ $this->assertTrue($responseSet->hasError());
+ $this->assertNotEquals('AnotherExceptionMessage', $responseSet->getError());
+ $this->assertEquals('SomeExceptionMessage', $responseSet->getError());
+
+ $actionExceptions = $e->getActionExceptions();
+ $this->assertEquals(2, count($actionExceptions));
+
+ $this->assertInstanceOf('Elastica\Exception\Bulk\Response\ActionException', $actionExceptions[0]);
+ $this->assertSame($actions[1], $actionExceptions[0]->getAction());
+ $this->assertContains('SomeExceptionMessage', $actionExceptions[0]->getMessage());
+ $this->assertTrue($actionExceptions[0]->getResponse()->hasError());
+
+ $this->assertInstanceOf('Elastica\Exception\Bulk\Response\ActionException', $actionExceptions[1]);
+ $this->assertSame($actions[2], $actionExceptions[1]->getAction());
+ $this->assertContains('AnotherExceptionMessage', $actionExceptions[1]->getMessage());
+ $this->assertTrue($actionExceptions[1]->getResponse()->hasError());
+ }
+ }
+
+ /**
+ * @group unit
+ */
+ public function testGetBulkResponses()
+ {
+ list($responseData, $actions) = $this->_getFixture();
+
+ $responseSet = $this->_createResponseSet($responseData, $actions);
+
+ $bulkResponses = $responseSet->getBulkResponses();
+ $this->assertInternalType('array', $bulkResponses);
+ $this->assertEquals(3, count($bulkResponses));
+
+ foreach ($bulkResponses as $i => $bulkResponse) {
+ $this->assertInstanceOf('Elastica\\Bulk\\Response', $bulkResponse);
+ $bulkResponseData = $bulkResponse->getData();
+ $this->assertInternalType('array', $bulkResponseData);
+ $this->assertArrayHasKey('_id', $bulkResponseData);
+ $this->assertEquals($responseData['items'][$i]['index']['_id'], $bulkResponseData['_id']);
+ $this->assertSame($actions[$i], $bulkResponse->getAction());
+ $this->assertEquals('index', $bulkResponse->getOpType());
+ }
+ }
+
+ /**
+ * @group unit
+ */
+ public function testIterator()
+ {
+ list($responseData, $actions) = $this->_getFixture();
+
+ $responseSet = $this->_createResponseSet($responseData, $actions);
+
+ $this->assertEquals(3, count($responseSet));
+
+ foreach ($responseSet as $i => $bulkResponse) {
+ $this->assertInstanceOf('Elastica\Bulk\Response', $bulkResponse);
+ $bulkResponseData = $bulkResponse->getData();
+ $this->assertInternalType('array', $bulkResponseData);
+ $this->assertArrayHasKey('_id', $bulkResponseData);
+ $this->assertEquals($responseData['items'][$i]['index']['_id'], $bulkResponseData['_id']);
+ $this->assertSame($actions[$i], $bulkResponse->getAction());
+ $this->assertEquals('index', $bulkResponse->getOpType());
+ }
+
+ $this->assertFalse($responseSet->valid());
+ $this->assertNotInstanceOf('Elastica\Bulk\Response', $responseSet->current());
+ $this->assertFalse($responseSet->current());
+
+ $responseSet->next();
+
+ $this->assertFalse($responseSet->valid());
+ $this->assertNotInstanceOf('Elastica\Bulk\Response', $responseSet->current());
+ $this->assertFalse($responseSet->current());
+
+ $responseSet->rewind();
+
+ $this->assertEquals(0, $responseSet->key());
+ $this->assertTrue($responseSet->valid());
+ $this->assertInstanceOf('Elastica\Bulk\Response', $responseSet->current());
+ }
+
+ public function isOkDataProvider()
+ {
+ list($responseData, $actions) = $this->_getFixture();
+
+ $return = array();
+ $return[] = array($responseData, $actions, true);
+ $responseData['items'][2]['index']['ok'] = false;
+ $return[] = array($responseData, $actions, false);
+
+ return $return;
+ }
+
+ /**
+ * @param array $responseData
+ * @param array $actions
+ *
+ * @return \Elastica\Bulk\ResponseSet
+ */
+ protected function _createResponseSet(array $responseData, array $actions)
+ {
+ $client = $this->getMock('Elastica\\Client', array('request'));
+
+ $client->expects($this->once())
+ ->method('request')
+ ->withAnyParameters()
+ ->will($this->returnValue(new Response($responseData)));
+
+ $bulk = new Bulk($client);
+ $bulk->addActions($actions);
+
+ return $bulk->send();
+ }
+
+ /**
+ * @return array
+ */
+ protected function _getFixture()
+ {
+ $responseData = array(
+ 'took' => 5,
+ 'items' => array(
+ array(
+ 'index' => array(
+ '_index' => 'index',
+ '_type' => 'type',
+ '_id' => '1',
+ '_version' => 1,
+ 'ok' => true,
+ ),
+ ),
+ array(
+ 'index' => array(
+ '_index' => 'index',
+ '_type' => 'type',
+ '_id' => '2',
+ '_version' => 1,
+ 'ok' => true,
+ ),
+ ),
+ array(
+ 'index' => array(
+ '_index' => 'index',
+ '_type' => 'type',
+ '_id' => '3',
+ '_version' => 1,
+ 'ok' => true,
+ ),
+ ),
+ ),
+ );
+ $bulkResponses = array(
+ new Action(),
+ new Action(),
+ new Action(),
+ );
+
+ return array($responseData, $bulkResponses);
+ }
+}
diff --git a/vendor/ruflin/elastica/test/lib/Elastica/Test/BulkTest.php b/vendor/ruflin/elastica/test/lib/Elastica/Test/BulkTest.php
new file mode 100644
index 00000000..c3ff15bc
--- /dev/null
+++ b/vendor/ruflin/elastica/test/lib/Elastica/Test/BulkTest.php
@@ -0,0 +1,792 @@
+<?php
+namespace Elastica\Test;
+
+use Elastica\Bulk;
+use Elastica\Bulk\Action;
+use Elastica\Bulk\Action\AbstractDocument;
+use Elastica\Document;
+use Elastica\Exception\Bulk\ResponseException;
+use Elastica\Exception\NotFoundException;
+use Elastica\Filter\Script;
+use Elastica\Test\Base as BaseTest;
+
+class BulkTest extends BaseTest
+{
+ /**
+ * @group functional
+ */
+ public function testSend()
+ {
+ $index = $this->_createIndex();
+ $indexName = $index->getName();
+ $type = $index->getType('bulk_test');
+ $type2 = $index->getType('bulk_test2');
+ $client = $index->getClient();
+
+ $newDocument1 = $type->createDocument(1, array('name' => 'Mister Fantastic'));
+ $newDocument2 = new Document(2, array('name' => 'Invisible Woman'));
+ $newDocument3 = $type->createDocument(3, array('name' => 'The Human Torch'));
+ $newDocument4 = $type->createDocument(null, array('name' => 'The Thing'));
+
+ $newDocument3->setOpType(Document::OP_TYPE_CREATE);
+
+ $documents = array(
+ $newDocument1,
+ $newDocument2,
+ $newDocument3,
+ $newDocument4,
+ );
+
+ $bulk = new Bulk($client);
+ $bulk->setType($type2);
+ $bulk->addDocuments($documents);
+
+ $actions = $bulk->getActions();
+
+ $this->assertInstanceOf('Elastica\Bulk\Action\IndexDocument', $actions[0]);
+ $this->assertEquals('index', $actions[0]->getOpType());
+ $this->assertSame($newDocument1, $actions[0]->getDocument());
+
+ $this->assertInstanceOf('Elastica\Bulk\Action\IndexDocument', $actions[1]);
+ $this->assertEquals('index', $actions[1]->getOpType());
+ $this->assertSame($newDocument2, $actions[1]->getDocument());
+
+ $this->assertInstanceOf('Elastica\Bulk\Action\CreateDocument', $actions[2]);
+ $this->assertEquals('create', $actions[2]->getOpType());
+ $this->assertSame($newDocument3, $actions[2]->getDocument());
+
+ $this->assertInstanceOf('Elastica\Bulk\Action\IndexDocument', $actions[3]);
+ $this->assertEquals('index', $actions[3]->getOpType());
+ $this->assertSame($newDocument4, $actions[3]->getDocument());
+
+ $data = $bulk->toArray();
+
+ $expected = array(
+ array('index' => array('_index' => $indexName, '_type' => 'bulk_test', '_id' => 1)),
+ array('name' => 'Mister Fantastic'),
+ array('index' => array('_id' => 2)),
+ array('name' => 'Invisible Woman'),
+ array('create' => array('_index' => $indexName, '_type' => 'bulk_test', '_id' => 3)),
+ array('name' => 'The Human Torch'),
+ array('index' => array('_index' => $indexName, '_type' => 'bulk_test')),
+ array('name' => 'The Thing'),
+ );
+ $this->assertEquals($expected, $data);
+
+ $expected = '{"index":{"_index":"'.$indexName.'","_type":"bulk_test","_id":1}}
+{"name":"Mister Fantastic"}
+{"index":{"_id":2}}
+{"name":"Invisible Woman"}
+{"create":{"_index":"'.$indexName.'","_type":"bulk_test","_id":3}}
+{"name":"The Human Torch"}
+{"index":{"_index":"'.$indexName.'","_type":"bulk_test"}}
+{"name":"The Thing"}
+';
+
+ $expected = str_replace(PHP_EOL, "\n", $expected);
+ $this->assertEquals($expected, (string) str_replace(PHP_EOL, "\n", (string) $bulk));
+
+ $response = $bulk->send();
+
+ $this->assertInstanceOf('Elastica\Bulk\ResponseSet', $response);
+
+ $this->assertTrue($response->isOk());
+ $this->assertFalse($response->hasError());
+
+ foreach ($response as $i => $bulkResponse) {
+ $this->assertInstanceOf('Elastica\Bulk\Response', $bulkResponse);
+ $this->assertTrue($bulkResponse->isOk());
+ $this->assertFalse($bulkResponse->hasError());
+ $this->assertSame($actions[$i], $bulkResponse->getAction());
+ }
+
+ $type->getIndex()->refresh();
+ $type2->getIndex()->refresh();
+
+ $this->assertEquals(3, $type->count());
+ $this->assertEquals(1, $type2->count());
+
+ $bulk = new Bulk($client);
+ $bulk->addDocument($newDocument3, Action::OP_TYPE_DELETE);
+
+ $data = $bulk->toArray();
+
+ $expected = array(
+ array('delete' => array('_index' => $indexName, '_type' => 'bulk_test', '_id' => 3)),
+ );
+ $this->assertEquals($expected, $data);
+
+ $bulk->send();
+
+ $type->getIndex()->refresh();
+
+ $this->assertEquals(2, $type->count());
+
+ try {
+ $type->getDocument(3);
+ $this->fail('Document #3 should be deleted');
+ } catch (NotFoundException $e) {
+ $this->assertTrue(true);
+ }
+ }
+
+ /**
+ * @group functional
+ */
+ public function testUnicodeBulkSend()
+ {
+ $index = $this->_createIndex();
+ $type = $index->getType('bulk_test');
+ $type2 = $index->getType('bulk_test2');
+ $client = $index->getClient();
+
+ $newDocument1 = $type->createDocument(1, array('name' => 'Сегодня, я вижу, особенно грустен твой взгляд,'));
+ $newDocument2 = new Document(2, array('name' => 'И руки особенно тонки, колени обняв.'));
+ $newDocument3 = $type->createDocument(3, array('name' => 'Послушай: далеко, далеко, на озере Чад / Изысканный бродит жираф.'));
+
+ $documents = array(
+ $newDocument1,
+ $newDocument2,
+ $newDocument3,
+ );
+
+ $bulk = new Bulk($client);
+ $bulk->setType($type2);
+ $bulk->addDocuments($documents);
+
+ $actions = $bulk->getActions();
+
+ $this->assertSame($newDocument1, $actions[0]->getDocument());
+ $this->assertSame($newDocument2, $actions[1]->getDocument());
+ $this->assertSame($newDocument3, $actions[2]->getDocument());
+ }
+
+ /**
+ * @group functional
+ */
+ public function testSetIndexType()
+ {
+ $client = $this->_getClient();
+ $index = $client->getIndex('index');
+ $type = $index->getType('type');
+
+ $index2 = $client->getIndex('index2');
+ $type2 = $index2->getType('type2');
+
+ $bulk = new Bulk($client);
+
+ $this->assertFalse($bulk->hasIndex());
+ $this->assertFalse($bulk->hasType());
+
+ $bulk->setIndex($index);
+ $this->assertTrue($bulk->hasIndex());
+ $this->assertFalse($bulk->hasType());
+ $this->assertEquals('index', $bulk->getIndex());
+
+ $bulk->setType($type2);
+ $this->assertTrue($bulk->hasIndex());
+ $this->assertTrue($bulk->hasType());
+ $this->assertEquals('index2', $bulk->getIndex());
+ $this->assertEquals('type2', $bulk->getType());
+
+ $bulk->setType($type);
+ $this->assertTrue($bulk->hasIndex());
+ $this->assertTrue($bulk->hasType());
+ $this->assertEquals('index', $bulk->getIndex());
+ $this->assertEquals('type', $bulk->getType());
+
+ $bulk->setIndex($index2);
+ $this->assertTrue($bulk->hasIndex());
+ $this->assertTrue($bulk->hasType());
+ $this->assertEquals('index2', $bulk->getIndex());
+ $this->assertEquals('type', $bulk->getType());
+ }
+
+ /**
+ * @group unit
+ */
+ public function testAddActions()
+ {
+ $client = $this->_getClient();
+ $bulk = new Bulk($client);
+
+ $action1 = new Action(Action::OP_TYPE_DELETE);
+ $action1->setIndex('index');
+ $action1->setType('type');
+ $action1->setId(1);
+
+ $action2 = new Action(Action::OP_TYPE_INDEX);
+ $action2->setIndex('index');
+ $action2->setType('type');
+ $action2->setId(1);
+ $action2->setSource(array('name' => 'Batman'));
+
+ $actions = array(
+ $action1,
+ $action2,
+ );
+
+ $bulk->addActions($actions);
+
+ $getActions = $bulk->getActions();
+
+ $this->assertSame($action1, $getActions[0]);
+ $this->assertSame($action2, $getActions[1]);
+ }
+
+ /**
+ * @group unit
+ */
+ public function testAddRawData()
+ {
+ $bulk = new Bulk($this->_getClient());
+
+ $rawData = array(
+ array('index' => array('_index' => 'test', '_type' => 'user', '_id' => '1')),
+ array('user' => array('name' => 'hans')),
+ array('delete' => array('_index' => 'test', '_type' => 'user', '_id' => '2')),
+ array('delete' => array('_index' => 'test', '_type' => 'user', '_id' => '3')),
+ array('create' => array('_index' => 'test', '_type' => 'user', '_id' => '4')),
+ array('user' => array('name' => 'mans')),
+ array('delete' => array('_index' => 'test', '_type' => 'user', '_id' => '5')),
+ );
+
+ $bulk->addRawData($rawData);
+
+ $actions = $bulk->getActions();
+
+ $this->assertInternalType('array', $actions);
+ $this->assertEquals(5, count($actions));
+
+ $this->assertInstanceOf('Elastica\Bulk\Action', $actions[0]);
+ $this->assertEquals('index', $actions[0]->getOpType());
+ $this->assertEquals($rawData[0]['index'], $actions[0]->getMetadata());
+ $this->assertTrue($actions[0]->hasSource());
+ $this->assertEquals($rawData[1], $actions[0]->getSource());
+
+ $this->assertInstanceOf('Elastica\Bulk\Action', $actions[1]);
+ $this->assertEquals('delete', $actions[1]->getOpType());
+ $this->assertEquals($rawData[2]['delete'], $actions[1]->getMetadata());
+ $this->assertFalse($actions[1]->hasSource());
+
+ $this->assertInstanceOf('Elastica\Bulk\Action', $actions[2]);
+ $this->assertEquals('delete', $actions[2]->getOpType());
+ $this->assertEquals($rawData[3]['delete'], $actions[2]->getMetadata());
+ $this->assertFalse($actions[2]->hasSource());
+
+ $this->assertInstanceOf('Elastica\Bulk\Action', $actions[3]);
+ $this->assertEquals('create', $actions[3]->getOpType());
+ $this->assertEquals($rawData[4]['create'], $actions[3]->getMetadata());
+ $this->assertTrue($actions[3]->hasSource());
+ $this->assertEquals($rawData[5], $actions[3]->getSource());
+
+ $this->assertInstanceOf('Elastica\Bulk\Action', $actions[4]);
+ $this->assertEquals('delete', $actions[4]->getOpType());
+ $this->assertEquals($rawData[6]['delete'], $actions[4]->getMetadata());
+ $this->assertFalse($actions[4]->hasSource());
+ }
+
+ /**
+ * @group unit
+ * @dataProvider invalidRawDataProvider
+ * @expectedException \Elastica\Exception\InvalidException
+ */
+ public function testInvalidRawData($rawData, $failMessage)
+ {
+ $bulk = new Bulk($this->_getClient());
+
+ $bulk->addRawData($rawData);
+
+ $this->fail($failMessage);
+ }
+
+ public function invalidRawDataProvider()
+ {
+ return array(
+ array(
+ array(
+ array('index' => array('_index' => 'test', '_type' => 'user', '_id' => '1')),
+ array('user' => array('name' => 'hans')),
+ array('user' => array('name' => 'mans')),
+ ),
+ 'Two sources for one action',
+ ),
+ array(
+ array(
+ array('index' => array('_index' => 'test', '_type' => 'user', '_id' => '1')),
+ array('user' => array('name' => 'hans')),
+ array('upsert' => array('_index' => 'test', '_type' => 'user', '_id' => '2')),
+ ),
+ 'Invalid optype for action',
+ ),
+ array(
+ array(
+ array('user' => array('name' => 'mans')),
+ ),
+ 'Source without action',
+ ),
+ array(
+ array(
+ array(),
+ ),
+ 'Empty array',
+ ),
+ array(
+ array(
+ 'dummy',
+ ),
+ 'String as data',
+ ),
+ );
+ }
+
+ /**
+ * @group unit
+ */
+ public function testCreateAbstractDocumentWithInvalidData()
+ {
+ //Wrong class type
+ try {
+ $badDocument = new \stdClass();
+ AbstractDocument::create($badDocument);
+ $this->fail('Tried to create an abstract document with an object that is not a Document or Script, but no exception was thrown');
+ } catch (\Exception $e) {
+ //Excepted exception was thrown.
+ }
+
+ //Try to create document with a script
+ try {
+ $script = new Script();
+ AbstractDocument::create($script, AbstractDocument::OP_TYPE_CREATE);
+ $this->fail('Tried to create an abstract document with a Script, but no exception was thrown');
+ } catch (\Exception $e) {
+ //Excepted exception was thrown.
+ }
+ }
+
+ /**
+ * @group functional
+ */
+ public function testErrorRequest()
+ {
+ $index = $this->_createIndex();
+ $type = $index->getType('bulk_test');
+ $client = $index->getClient();
+
+ $documents = array(
+ $type->createDocument(1, array('name' => 'Mister Fantastic')),
+ $type->createDocument(2, array('name' => 'Invisible Woman')),
+ $type->createDocument(2, array('name' => 'The Human Torch')),
+ );
+
+ $documents[2]->setOpType(Document::OP_TYPE_CREATE);
+
+ $bulk = new Bulk($client);
+ $bulk->addDocuments($documents);
+
+ try {
+ $bulk->send();
+ $bulk->fail('3rd document create should produce error');
+ } catch (ResponseException $e) {
+ $this->assertContains('DocumentAlreadyExists', $e->getMessage());
+ $failures = $e->getFailures();
+ $this->assertInternalType('array', $failures);
+ $this->assertArrayHasKey(0, $failures);
+ $this->assertContains('DocumentAlreadyExists', $failures[0]);
+ }
+ }
+
+ /**
+ * @group functional
+ */
+ public function testRawDocumentDataRequest()
+ {
+ $index = $this->_createIndex();
+ $type = $index->getType('bulk_test');
+ $client = $index->getClient();
+
+ $documents = array(
+ new Document(null, '{"name":"Mister Fantastic"}'),
+ new Document(null, '{"name":"Invisible Woman"}'),
+ new Document(null, '{"name":"The Human Torch"}'),
+ );
+
+ $bulk = new Bulk($client);
+ $bulk->addDocuments($documents);
+ $bulk->setType($type);
+
+ $expectedJson = '{"index":{}}
+{"name":"Mister Fantastic"}
+{"index":{}}
+{"name":"Invisible Woman"}
+{"index":{}}
+{"name":"The Human Torch"}
+';
+ $expectedJson = str_replace(PHP_EOL, "\n", $expectedJson);
+ $this->assertEquals($expectedJson, $bulk->toString());
+
+ $response = $bulk->send();
+ $this->assertTrue($response->isOk());
+
+ $type->getIndex()->refresh();
+
+ $response = $type->search();
+ $this->assertEquals(3, $response->count());
+
+ foreach (array('Mister', 'Invisible', 'Torch') as $name) {
+ $result = $type->search($name);
+ $this->assertEquals(1, count($result->getResults()));
+ }
+ }
+
+ /**
+ * @group functional
+ * @dataProvider udpDataProvider
+ */
+ public function testUdp($clientConfig, $host, $port, $shouldFail = false)
+ {
+ if (!function_exists('socket_create')) {
+ $this->markTestSkipped('Function socket_create() does not exist.');
+ }
+ $client = $this->_getClient($clientConfig);
+ $index = $client->getIndex('elastica_test');
+ $index->create(array('index' => array('number_of_shards' => 1, 'number_of_replicas' => 0)), true);
+ $type = $index->getType('udp_test');
+ $client = $index->getClient();
+
+ $type->setMapping(array('name' => array('type' => 'string')));
+
+ $docs = array(
+ $type->createDocument(1, array('name' => 'Mister Fantastic')),
+ $type->createDocument(2, array('name' => 'Invisible Woman')),
+ $type->createDocument(3, array('name' => 'The Human Torch')),
+ $type->createDocument(4, array('name' => 'The Thing')),
+ $type->createDocument(5, array('name' => 'Mole Man')),
+ $type->createDocument(6, array('name' => 'The Skrulls')),
+ );
+
+ $bulk = new Bulk($client);
+ $bulk->addDocuments($docs);
+
+ $bulk->sendUdp($host, $port);
+
+ $i = 0;
+ $limit = 20;
+ do {
+ usleep(200000);
+ } while ($type->count() < 6 && ++$i < $limit);
+
+ if ($shouldFail) {
+ $this->assertEquals($limit, $i, 'Invalid udp connection data. Test should fail');
+ } else {
+ $this->assertLessThan($limit, $i, 'It took too much time waiting for UDP request result');
+
+ foreach ($docs as $doc) {
+ $getDoc = $type->getDocument($doc->getId());
+ $this->assertEquals($doc->getData(), $getDoc->getData());
+ }
+ }
+ }
+
+ /**
+ * @group functional
+ */
+ public function testUpdate()
+ {
+ $index = $this->_createIndex();
+ $type = $index->getType('bulk_test');
+ $client = $index->getClient();
+
+ $doc1 = $type->createDocument(1, array('name' => 'John'));
+ $doc2 = $type->createDocument(2, array('name' => 'Paul'));
+ $doc3 = $type->createDocument(3, array('name' => 'George'));
+ $doc4 = $type->createDocument(4, array('name' => 'Ringo'));
+ $documents = array($doc1, $doc2, $doc3, $doc4);
+
+ //index some documents
+ $bulk = new Bulk($client);
+ $bulk->setType($type);
+ $bulk->addDocuments($documents);
+ $response = $bulk->send();
+
+ $this->assertTrue($response->isOk());
+ $this->assertFalse($response->hasError());
+
+ $index->refresh();
+
+ //test updating via document
+ $doc2 = $type->createDocument(2, array('name' => 'The Walrus'));
+ $bulk = new Bulk($client);
+ $bulk->setType($type);
+ $updateAction = new \Elastica\Bulk\Action\UpdateDocument($doc2);
+ $bulk->addAction($updateAction);
+ $response = $bulk->send();
+
+ $this->assertTrue($response->isOk());
+ $this->assertFalse($response->hasError());
+
+ $index->refresh();
+
+ $doc = $type->getDocument(2);
+ $docData = $doc->getData();
+ $this->assertEquals('The Walrus', $docData['name']);
+
+ //test updating via script
+ $script = new \Elastica\Script('ctx._source.name += param1;', array('param1' => ' was Paul'), null, 2);
+ $doc2 = new Document();
+ $script->setUpsert($doc2);
+ $updateAction = Action\AbstractDocument::create($script, Action::OP_TYPE_UPDATE);
+ $bulk = new Bulk($client);
+ $bulk->setType($type);
+ $bulk->addAction($updateAction);
+ $response = $bulk->send();
+
+ $this->assertTrue($response->isOk());
+ $this->assertFalse($response->hasError());
+
+ $index->refresh();
+
+ $doc2 = $type->getDocument(2);
+ $this->assertEquals('The Walrus was Paul', $doc2->name);
+
+ //test upsert
+ $script = new \Elastica\Script('ctx._scource.counter += count', array('count' => 1), null, 5);
+ $doc = new Document('', array('counter' => 1));
+ $script->setUpsert($doc);
+ $updateAction = Action\AbstractDocument::create($script, Action::OP_TYPE_UPDATE);
+ $bulk = new Bulk($client);
+ $bulk->setType($type);
+ $bulk->addAction($updateAction);
+ $response = $bulk->send();
+
+ $this->assertTrue($response->isOk());
+ $this->assertFalse($response->hasError());
+
+ $index->refresh();
+ $doc = $type->getDocument(5);
+ $this->assertEquals(1, $doc->counter);
+
+ //test doc_as_upsert
+ $doc = new \Elastica\Document(6, array('test' => 'test'));
+ $doc->setDocAsUpsert(true);
+ $updateAction = Action\AbstractDocument::create($doc, Action::OP_TYPE_UPDATE);
+ $bulk = new Bulk($client);
+ $bulk->setType($type);
+ $bulk->addAction($updateAction);
+ $response = $bulk->send();
+
+ $this->assertTrue($response->isOk());
+ $this->assertFalse($response->hasError());
+
+ $index->refresh();
+ $doc = $type->getDocument(6);
+ $this->assertEquals('test', $doc->test);
+
+ //test doc_as_upsert with set of documents (use of addDocuments)
+ $doc1 = new \Elastica\Document(7, array('test' => 'test1'));
+ $doc1->setDocAsUpsert(true);
+ $doc2 = new \Elastica\Document(8, array('test' => 'test2'));
+ $doc2->setDocAsUpsert(true);
+ $docs = array($doc1, $doc2);
+ $bulk = new Bulk($client);
+ $bulk->setType($type);
+ $bulk->addDocuments($docs, \Elastica\Bulk\Action::OP_TYPE_UPDATE);
+ $response = $bulk->send();
+
+ $this->assertTrue($response->isOk());
+ $this->assertFalse($response->hasError());
+
+ $index->refresh();
+ $doc = $type->getDocument(7);
+ $this->assertEquals('test1', $doc->test);
+ $doc = $type->getDocument(8);
+ $this->assertEquals('test2', $doc->test);
+
+ //test updating via document with json string as data
+ $doc3 = $type->createDocument(2);
+ $bulk = new Bulk($client);
+ $bulk->setType($type);
+ $doc3->setData('{"name" : "Paul it is"}');
+ $updateAction = new \Elastica\Bulk\Action\UpdateDocument($doc3);
+ $bulk->addAction($updateAction);
+ $response = $bulk->send();
+
+ $this->assertTrue($response->isOk());
+ $this->assertFalse($response->hasError());
+
+ $index->refresh();
+
+ $doc = $type->getDocument(2);
+ $docData = $doc->getData();
+ $this->assertEquals('Paul it is', $docData['name']);
+
+ $index->delete();
+ }
+
+ /**
+ * @group unit
+ */
+ public function testGetPath()
+ {
+ $client = $this->_getClient();
+ $bulk = new Bulk($client);
+
+ $this->assertEquals('_bulk', $bulk->getPath());
+
+ $indexName = 'testIndex';
+
+ $bulk->setIndex($indexName);
+ $this->assertEquals($indexName.'/_bulk', $bulk->getPath());
+
+ $typeName = 'testType';
+ $bulk->setType($typeName);
+ $this->assertEquals($indexName.'/'.$typeName.'/_bulk', $bulk->getPath());
+ }
+
+ /**
+ * @group functional
+ */
+ public function testRetry()
+ {
+ $index = $this->_createIndex();
+ $type = $index->getType('bulk_test');
+ $client = $index->getClient();
+
+ $doc1 = $type->createDocument(1, array('name' => 'Mister Fantastic'));
+ $doc1->setOpType(Action::OP_TYPE_UPDATE);
+ $doc1->setRetryOnConflict(5);
+
+ $bulk = new Bulk($client);
+ $bulk->addDocument($doc1);
+
+ $actions = $bulk->getActions();
+
+ $metadata = $actions[0]->getMetadata();
+ $this->assertEquals(5, $metadata[ '_retry_on_conflict' ]);
+
+ $script = new \Elastica\Script('');
+ $script->setRetryOnConflict(5);
+
+ $bulk = new Bulk($client);
+ $bulk->addScript($script);
+
+ $actions = $bulk->getActions();
+
+ $metadata = $actions[0]->getMetadata();
+ $this->assertEquals(5, $metadata[ '_retry_on_conflict' ]);
+ }
+
+ /**
+ * @group unit
+ */
+ public function testSetShardTimeout()
+ {
+ $bulk = new Bulk($this->_getClient());
+ $this->assertInstanceOf('Elastica\Bulk', $bulk->setShardTimeout(10));
+ }
+
+ /**
+ * @group unit
+ */
+ public function testSetRequestParam()
+ {
+ $bulk = new Bulk($this->_getClient());
+ $this->assertInstanceOf('Elastica\Bulk', $bulk->setRequestParam('key', 'value'));
+ }
+
+ /**
+ * @group benchmark
+ */
+ public function testMemoryUsage()
+ {
+ $type = $this->_createIndex()->getType('test');
+
+ $data = array(
+ 'text1' => 'Very long text for a string',
+ 'text2' => 'But this is not very long',
+ 'text3' => 'random or not random?',
+ );
+
+ $startMemory = memory_get_usage();
+
+ for ($n = 1; $n < 10; $n++) {
+ $docs = array();
+
+ for ($i = 1; $i <= 3000; $i++) {
+ $docs[] = new Document(uniqid(), $data);
+ }
+
+ $type->addDocuments($docs);
+ $docs = array();
+ }
+
+ unset($docs);
+
+ $endMemory = memory_get_usage();
+
+ $this->assertLessThan(1.3, $endMemory / $startMemory);
+ }
+
+ public function udpDataProvider()
+ {
+ return array(
+ array(
+ array(),
+ null,
+ null,
+ ),
+ array(
+ array(),
+ $this->_getHost(),
+ null,
+ ),
+ array(
+ array(),
+ null,
+ 9700,
+ ),
+ array(
+ array(),
+ $this->_getHost(),
+ 9700,
+ ),
+ array(
+ array(
+ 'udp' => array(
+ 'host' => $this->_getHost(),
+ 'port' => 9700,
+ ),
+ ),
+ null,
+ null,
+ ),
+ array(
+ array(
+ 'udp' => array(
+ 'host' => $this->_getHost(),
+ 'port' => 9800,
+ ),
+ ),
+ $this->_getHost(),
+ 9700,
+ ),
+ array(
+ array(
+ 'udp' => array(
+ 'host' => $this->_getHost(),
+ 'port' => 9800,
+ ),
+ ),
+ null,
+ null,
+ true,
+ ),
+ array(
+ array(),
+ $this->_getHost(),
+ 9800,
+ true,
+ ),
+ );
+ }
+}
diff --git a/vendor/ruflin/elastica/test/lib/Elastica/Test/ClientTest.php b/vendor/ruflin/elastica/test/lib/Elastica/Test/ClientTest.php
new file mode 100644
index 00000000..a5f2b46f
--- /dev/null
+++ b/vendor/ruflin/elastica/test/lib/Elastica/Test/ClientTest.php
@@ -0,0 +1,1160 @@
+<?php
+namespace Elastica\Test;
+
+use Elastica\Connection;
+use Elastica\Document;
+use Elastica\Exception\Connection\HttpException;
+use Elastica\Exception\InvalidException;
+use Elastica\Index;
+use Elastica\Request;
+use Elastica\Script;
+use Elastica\Test\Base as BaseTest;
+use Elastica\Type;
+
+class ClientTest extends BaseTest
+{
+ /**
+ * @group unit
+ */
+ public function testConstruct()
+ {
+ $client = $this->_getClient();
+ $this->assertCount(1, $client->getConnections());
+ }
+
+ /**
+ * @group functional
+ */
+ public function testConnectionsArray()
+ {
+ // Creates a new index 'xodoa' and a type 'user' inside this index
+ $client = $this->_getClient(array('connections' => array(array('host' => $this->_getHost(), 'port' => 9200))));
+ $index = $client->getIndex('elastica_test1');
+ $index->create(array(), true);
+
+ $type = $index->getType('user');
+
+ // Adds 1 document to the index
+ $doc1 = new Document(1,
+ array('username' => 'hans', 'test' => array('2', '3', '5'))
+ );
+ $type->addDocument($doc1);
+
+ // Adds a list of documents with _bulk upload to the index
+ $docs = array();
+ $docs[] = new Document(2,
+ array('username' => 'john', 'test' => array('1', '3', '6'))
+ );
+ $docs[] = new Document(3,
+ array('username' => 'rolf', 'test' => array('2', '3', '7'))
+ );
+ $type->addDocuments($docs);
+
+ // Refresh index
+ $index->refresh();
+
+ $resultSet = $type->search('rolf');
+ }
+
+ /**
+ * @group functional
+ */
+ public function testTwoServersSame()
+ {
+ // Creates a new index 'xodoa' and a type 'user' inside this index
+ $client = $this->_getClient(array('connections' => array(
+ array('host' => $this->_getHost(), 'port' => 9200),
+ array('host' => $this->_getHost(), 'port' => 9200),
+ )));
+ $index = $client->getIndex('elastica_test1');
+ $index->create(array(), true);
+
+ $type = $index->getType('user');
+
+ // Adds 1 document to the index
+ $doc1 = new Document(1,
+ array('username' => 'hans', 'test' => array('2', '3', '5'))
+ );
+ $type->addDocument($doc1);
+
+ // Adds a list of documents with _bulk upload to the index
+ $docs = array();
+ $docs[] = new Document(2,
+ array('username' => 'john', 'test' => array('1', '3', '6'))
+ );
+ $docs[] = new Document(3,
+ array('username' => 'rolf', 'test' => array('2', '3', '7'))
+ );
+ $type->addDocuments($docs);
+
+ // Refresh index
+ $index->refresh();
+
+ $resultSet = $type->search('rolf');
+ }
+
+ /**
+ * @group unit
+ */
+ public function testConnectionParamsArePreparedForConnectionsOption()
+ {
+ $url = 'https://'.$this->_getHost().':9200';
+ $client = $this->_getClient(array('connections' => array(array('url' => $url))));
+ $connection = $client->getConnection();
+
+ $this->assertEquals($url, $connection->getConfig('url'));
+ }
+
+ /**
+ * @group unit
+ */
+ public function testConnectionParamsArePreparedForServersOption()
+ {
+ $url = 'https://'.$this->_getHost().':9200';
+ $client = $this->_getClient(array('servers' => array(array('url' => $url))));
+ $connection = $client->getConnection();
+
+ $this->assertEquals($url, $connection->getConfig('url'));
+ }
+
+ /**
+ * @group unit
+ */
+ public function testConnectionParamsArePreparedForDefaultOptions()
+ {
+ $url = 'https://'.$this->_getHost().':9200';
+ $client = $this->_getClient(array('url' => $url));
+ $connection = $client->getConnection();
+
+ $this->assertEquals($url, $connection->getConfig('url'));
+ }
+
+ /**
+ * @group functional
+ */
+ public function testBulk()
+ {
+ $client = $this->_getClient();
+
+ $params = array(
+ array('index' => array('_index' => 'test', '_type' => 'user', '_id' => '1')),
+ array('user' => array('name' => 'hans')),
+ array('index' => array('_index' => 'test', '_type' => 'user', '_id' => '2')),
+ array('user' => array('name' => 'peter')),
+ );
+
+ $client->bulk($params);
+ }
+
+ /**
+ * @group functional
+ */
+ public function testOptimizeAll()
+ {
+ $client = $this->_getClient();
+ $response = $client->optimizeAll();
+
+ $this->assertFalse($response->hasError());
+ }
+
+ /**
+ * @group unit
+ * @expectedException \Elastica\Exception\InvalidException
+ */
+ public function testAddDocumentsEmpty()
+ {
+ $client = $this->_getClient();
+ $client->addDocuments(array());
+ }
+
+ /**
+ * Test bulk operations on Index.
+ *
+ * @group functional
+ */
+ public function testBulkIndex()
+ {
+ $index = $this->_getClient()->getIndex('cryptocurrencies');
+
+ $anonCoin = new Document(1, array('name' => 'anoncoin'), 'altcoin');
+ $ixCoin = new Document(2, array('name' => 'ixcoin'), 'altcoin');
+
+ $index->addDocuments(array($anonCoin, $ixCoin));
+
+ $this->assertEquals('anoncoin', $index->getType('altcoin')->getDocument(1)->get('name'));
+ $this->assertEquals('ixcoin', $index->getType('altcoin')->getDocument(2)->get('name'));
+
+ $index->updateDocuments(array(
+ new Document(1, array('name' => 'AnonCoin'), 'altcoin'),
+ new Document(2, array('name' => 'iXcoin'), 'altcoin'),
+ ));
+
+ $this->assertEquals('AnonCoin', $index->getType('altcoin')->getDocument(1)->get('name'));
+ $this->assertEquals('iXcoin', $index->getType('altcoin')->getDocument(2)->get('name'));
+
+ $ixCoin->setIndex(null); // Make sure the index gets set properly if missing
+ $index->deleteDocuments(array($anonCoin, $ixCoin));
+
+ $this->setExpectedException('Elastica\Exception\NotFoundException');
+ $index->getType('altcoin')->getDocument(1);
+ $index->getType('altcoin')->getDocument(2);
+ }
+
+ /**
+ * Test bulk operations on Type.
+ *
+ * @group functional
+ */
+ public function testBulkType()
+ {
+ $type = $this->_getClient()->getIndex('cryptocurrencies')->getType('altcoin');
+
+ $liteCoin = new Document(1, array('name' => 'litecoin'));
+ $nameCoin = new Document(2, array('name' => 'namecoin'));
+
+ $type->addDocuments(array($liteCoin, $nameCoin));
+
+ $this->assertEquals('litecoin', $type->getDocument(1)->get('name'));
+ $this->assertEquals('namecoin', $type->getDocument(2)->get('name'));
+
+ $type->updateDocuments(array(
+ new Document(1, array('name' => 'LiteCoin')),
+ new Document(2, array('name' => 'NameCoin')),
+ ));
+
+ $this->assertEquals('LiteCoin', $type->getDocument(1)->get('name'));
+ $this->assertEquals('NameCoin', $type->getDocument(2)->get('name'));
+
+ $nameCoin->setType(null); // Make sure the type gets set properly if missing
+ $type->deleteDocuments(array($liteCoin, $nameCoin));
+
+ $this->setExpectedException('Elastica\Exception\NotFoundException');
+ $type->getDocument(1);
+ $type->getDocument(2);
+ }
+
+ /**
+ * @group functional
+ */
+ public function testUpdateDocuments()
+ {
+ $indexName = 'test';
+ $typeName = 'people';
+
+ $client = $this->_getClient();
+ $type = $client->getIndex($indexName)->getType($typeName);
+
+ $initialValue = 28;
+ $modifiedValue = 27;
+
+ $doc1 = new Document(
+ 1,
+ array('name' => 'hans', 'age' => $initialValue),
+ $typeName,
+ $indexName
+ );
+ $doc2 = new Document(
+ 2,
+ array('name' => 'anna', 'age' => $initialValue),
+ $typeName,
+ $indexName
+ );
+ $data = array($doc1, $doc2);
+ $client->addDocuments($data);
+
+ foreach ($data as $i => $doc) {
+ $data[$i]->age = $modifiedValue;
+ }
+ $client->updateDocuments($data);
+
+ $docData1 = $type->getDocument(1)->getData();
+ $docData2 = $type->getDocument(2)->getData();
+
+ $this->assertEquals($modifiedValue, $docData1['age']);
+ $this->assertEquals($modifiedValue, $docData2['age']);
+ }
+
+ /**
+ * Test deleteIds method using string parameters.
+ *
+ * This test ensures that the deleteIds method of
+ * the \Elastica\Client can properly accept and use
+ * an $index parameter and $type parameter that are
+ * strings
+ *
+ * This test is a bit more verbose than just sending the
+ * values to deleteIds and checking for exceptions or
+ * warnings.
+ *
+ * It will add a document, search for it, then delete it
+ * using the parameter types we are interested in, and then
+ * re-search to verify that they have been deleted
+ *
+ * @group functional
+ */
+ public function testDeleteIdsIdxStringTypeString()
+ {
+ $data = array('username' => 'hans');
+ $userSearch = 'username:hans';
+
+ $index = $this->_createIndex(null, true, 2);
+
+ // Create the index, deleting it first if it already exists
+ $index->create(array(), true);
+ $type = $index->getType('user');
+
+ // Adds 1 document to the index
+ $doc = new Document(null, $data);
+ $doc->setRouting(1);
+ $result = $type->addDocument($doc);
+
+ // Refresh index
+ $index->refresh();
+
+ $resultData = $result->getData();
+ $ids = array($resultData['_id']);
+
+ // Check to make sure the document is in the index
+ $resultSet = $type->search($userSearch);
+ $totalHits = $resultSet->getTotalHits();
+ $this->assertEquals(1, $totalHits);
+
+ // And verify that the variables we are doing to send to
+ // deleteIds are the type we are testing for
+ $idxString = $index->getName();
+ $typeString = $type->getName();
+ $this->assertTrue(is_string($idxString));
+ $this->assertTrue(is_string($typeString));
+
+ // Try to delete doc with a routing value which hashes to
+ // a different shard then the id.
+ $resp = $index->getClient()->deleteIds($ids, $index, $type, 2);
+
+ // Refresh the index
+ $index->refresh();
+
+ // Research the index to verify that the items are still there
+ $resultSet = $type->search($userSearch);
+ $totalHits = $resultSet->getTotalHits();
+ $this->assertEquals(1, $totalHits);
+
+ // Using the existing $index and $type variables which
+ // are \Elastica\Index and \Elastica\Type objects respectively
+ $resp = $index->getClient()->deleteIds($ids, $index, $type, 1);
+
+ // Refresh the index to clear out deleted ID information
+ $index->refresh();
+
+ // Research the index to verify that the items have been deleted
+ $resultSet = $type->search($userSearch);
+ $totalHits = $resultSet->getTotalHits();
+ $this->assertEquals(0, $totalHits);
+ }
+
+ /**
+ * Test deleteIds method using string parameter for $index
+ * and object parameter for $type.
+ *
+ * This test ensures that the deleteIds method of
+ * the \Elastica\Client can properly accept and use
+ * an $index parameter that is a string and a $type
+ * parameter that is of type \Elastica\Type
+ *
+ * This test is a bit more verbose than just sending the
+ * values to deleteIds and checking for exceptions or
+ * warnings.
+ *
+ * It will add a document, search for it, then delete it
+ * using the parameter types we are interested in, and then
+ * re-search to verify that they have been deleted
+ *
+ * @group functional
+ */
+ public function testDeleteIdsIdxStringTypeObject()
+ {
+ $data = array('username' => 'hans');
+ $userSearch = 'username:hans';
+
+ $index = $this->_createIndex();
+
+ // Create the index, deleting it first if it already exists
+ $index->create(array(), true);
+ $type = $index->getType('user');
+
+ // Adds 1 document to the index
+ $doc = new Document(null, $data);
+ $result = $type->addDocument($doc);
+
+ // Refresh index
+ $index->refresh();
+
+ $resultData = $result->getData();
+ $ids = array($resultData['_id']);
+
+ // Check to make sure the document is in the index
+ $resultSet = $type->search($userSearch);
+ $totalHits = $resultSet->getTotalHits();
+ $this->assertEquals(1, $totalHits);
+
+ // And verify that the variables we are doing to send to
+ // deleteIds are the type we are testing for
+ $idxString = $index->getName();
+ $this->assertTrue(is_string($idxString));
+ $this->assertInstanceOf('Elastica\Type', $type);
+
+ // Using the existing $index and $type variables which
+ // are \Elastica\Index and \Elastica\Type objects respectively
+ $resp = $index->getClient()->deleteIds($ids, $index, $type);
+
+ // Refresh the index to clear out deleted ID information
+ $index->refresh();
+
+ // Research the index to verify that the items have been deleted
+ $resultSet = $type->search($userSearch);
+ $totalHits = $resultSet->getTotalHits();
+ $this->assertEquals(0, $totalHits);
+ }
+
+ /**
+ * Test deleteIds method using object parameter for $index
+ * and string parameter for $type.
+ *
+ * This test ensures that the deleteIds method of
+ * the \Elastica\Client can properly accept and use
+ * an $index parameter that is of type Elasitca_Index
+ * and a $type parameter that is a string
+ *
+ * This test is a bit more verbose than just sending the
+ * values to deleteIds and checking for exceptions or
+ * warnings.
+ *
+ * It will add a document, search for it, then delete it
+ * using the parameter types we are interested in, and then
+ * re-search to verify that they have been deleted
+ *
+ * @group functional
+ */
+ public function testDeleteIdsIdxObjectTypeString()
+ {
+ $data = array('username' => 'hans');
+ $userSearch = 'username:hans';
+
+ $index = $this->_createIndex();
+
+ // Create the index, deleting it first if it already exists
+ $index->create(array(), true);
+ $type = $index->getType('user');
+
+ // Adds 1 document to the index
+ $doc = new Document(null, $data);
+ $result = $type->addDocument($doc);
+
+ // Refresh index
+ $index->refresh();
+
+ $resultData = $result->getData();
+ $ids = array($resultData['_id']);
+
+ // Check to make sure the document is in the index
+ $resultSet = $type->search($userSearch);
+ $totalHits = $resultSet->getTotalHits();
+ $this->assertEquals(1, $totalHits);
+
+ // And verify that the variables we are doing to send to
+ // deleteIds are the type we are testing for
+ $typeString = $type->getName();
+ $this->assertInstanceOf('Elastica\Index', $index);
+ $this->assertTrue(is_string($typeString));
+
+ // Using the existing $index and $type variables which
+ // are \Elastica\Index and \Elastica\Type objects respectively
+ $resp = $index->getClient()->deleteIds($ids, $index, $type);
+
+ // Refresh the index to clear out deleted ID information
+ $index->refresh();
+
+ // Research the index to verify that the items have been deleted
+ $resultSet = $type->search($userSearch);
+ $totalHits = $resultSet->getTotalHits();
+ $this->assertEquals(0, $totalHits);
+ }
+
+ /**
+ * Test deleteIds method using object parameter for $index
+ * and object parameter for $type.
+ *
+ * This test ensures that the deleteIds method of
+ * the \Elastica\Client can properly accept and use
+ * an $index parameter that is an object and a $type
+ * parameter that is of type \Elastica\Type
+ *
+ * This test is a bit more verbose than just sending the
+ * values to deleteIds and checking for exceptions or
+ * warnings.
+ *
+ * It will add a document, search for it, then delete it
+ * using the parameter types we are interested in, and then
+ * re-search to verify that they have been deleted
+ *
+ * @group functional
+ */
+ public function testDeleteIdsIdxObjectTypeObject()
+ {
+ $data = array('username' => 'hans');
+ $userSearch = 'username:hans';
+
+ $index = $this->_createIndex();
+
+ // Create the index, deleting it first if it already exists
+ $index->create(array(), true);
+ $type = $index->getType('user');
+
+ // Adds 1 document to the index
+ $doc = new Document(null, $data);
+ $result = $type->addDocument($doc);
+
+ // Refresh index
+ $index->refresh();
+
+ $resultData = $result->getData();
+ $ids = array($resultData['_id']);
+
+ // Check to make sure the document is in the index
+ $resultSet = $type->search($userSearch);
+ $totalHits = $resultSet->getTotalHits();
+ $this->assertEquals(1, $totalHits);
+
+ // And verify that the variables we are doing to send to
+ // deleteIds are the type we are testing for
+ $this->assertInstanceOf('Elastica\Index', $index);
+ $this->assertInstanceOf('Elastica\Type', $type);
+
+ // Using the existing $index and $type variables which
+ // are \Elastica\Index and \Elastica\Type objects respectively
+ $resp = $index->getClient()->deleteIds($ids, $index, $type);
+
+ // Refresh the index to clear out deleted ID information
+ $index->refresh();
+
+ // Research the index to verify that the items have been deleted
+ $resultSet = $type->search($userSearch);
+ $totalHits = $resultSet->getTotalHits();
+ $this->assertEquals(0, $totalHits);
+ }
+
+ /**
+ * @group functional
+ */
+ public function testOneInvalidConnection()
+ {
+ $client = $this->_getClient();
+
+ // First connection work, second should not work
+ $connection1 = new Connection(array('port' => '9100', 'timeout' => 2, 'host' => $this->_getHost()));
+ $connection2 = new Connection(array('port' => '9200', 'timeout' => 2, 'host' => $this->_getHost()));
+
+ $client->setConnections(array($connection1, $connection2));
+
+ $client->request('_status', Request::GET);
+
+ $connections = $client->getConnections();
+
+ // two connections are setup
+ $this->assertEquals(2, count($connections));
+
+ // One connection has to be disabled
+ $this->assertTrue($connections[0]->isEnabled() == false || $connections[1]->isEnabled() == false);
+ }
+
+ /**
+ * @group functional
+ */
+ public function testTwoInvalidConnection()
+ {
+ $client = $this->_getClient();
+
+ // First connection work, second should not work
+ $connection1 = new Connection(array('port' => '9101', 'timeout' => 2));
+ $connection2 = new Connection(array('port' => '9102', 'timeout' => 2));
+
+ $client->setConnections(array($connection1, $connection2));
+
+ try {
+ $client->request('_status', Request::GET);
+ $this->fail('Should throw exception as no connection valid');
+ } catch (HttpException $e) {
+ }
+
+ $connections = $client->getConnections();
+
+ // two connections are setup
+ $this->assertEquals(2, count($connections));
+
+ // One connection has to be disabled
+ $this->assertTrue($connections[0]->isEnabled() == false || $connections[1]->isEnabled() == false);
+ }
+
+ /**
+ * Tests if the callback works in case a connection is down.
+ *
+ * @group functional
+ */
+ public function testCallback()
+ {
+ $count = 0;
+ $object = $this;
+
+ // Callback function which verifies that disabled connection objects are returned
+ $callback = function ($connection, $exception, $client) use (&$object, &$count) {
+ $object->assertInstanceOf('Elastica\Connection', $connection);
+ $object->assertInstanceOf('Elastica\Exception\ConnectionException', $exception);
+ $object->assertInstanceOf('Elastica\Client', $client);
+ $object->assertFalse($connection->isEnabled());
+ $count++;
+ };
+
+ $client = $this->_getClient(array(), $callback);
+
+ // First connection work, second should not work
+ $connection1 = new Connection(array('port' => '9101', 'timeout' => 2));
+ $connection2 = new Connection(array('port' => '9102', 'timeout' => 2));
+
+ $client->setConnections(array($connection1, $connection2));
+
+ $this->assertEquals(0, $count);
+
+ try {
+ $client->request('_status', Request::GET);
+ $this->fail('Should throw exception as no connection valid');
+ } catch (HttpException $e) {
+ $this->assertTrue(true);
+ }
+
+ // Two disabled connections (from closure call)
+ $this->assertEquals(2, $count);
+ }
+
+ /**
+ * @group functional
+ */
+ public function testUrlConstructor()
+ {
+ $url = 'http://'.$this->_getHost().':9200/';
+
+ // Url should overwrite invalid host
+ $client = $this->_getClient(array('url' => $url, 'port' => '9101', 'timeout' => 2));
+
+ $response = $client->request('_status');
+ $this->assertInstanceOf('Elastica\Response', $response);
+ }
+
+ /**
+ * @group functional
+ */
+ public function testUpdateDocumentByDocument()
+ {
+ $index = $this->_createIndex();
+ $type = $index->getType('test');
+ $client = $index->getClient();
+
+ $newDocument = new Document(1, array('field1' => 'value1', 'field2' => 'value2'));
+ $type->addDocument($newDocument);
+
+ $updateDocument = new Document(1, array('field2' => 'value2changed', 'field3' => 'value3added'));
+ $client->updateDocument(1, $updateDocument, $index->getName(), $type->getName());
+
+ $document = $type->getDocument(1);
+
+ $this->assertInstanceOf('Elastica\Document', $document);
+ $data = $document->getData();
+ $this->assertArrayHasKey('field1', $data);
+ $this->assertEquals('value1', $data['field1']);
+ $this->assertArrayHasKey('field2', $data);
+ $this->assertEquals('value2changed', $data['field2']);
+ $this->assertArrayHasKey('field3', $data);
+ $this->assertEquals('value3added', $data['field3']);
+ }
+
+ /**
+ * @group functional
+ */
+ public function testUpdateDocumentByScript()
+ {
+ $index = $this->_createIndex();
+ $type = $index->getType('test');
+ $client = $index->getClient();
+
+ $newDocument = new Document(1, array('field1' => 'value1', 'field2' => 10, 'field3' => 'should be removed', 'field4' => 'should be changed'));
+ $type->addDocument($newDocument);
+
+ $script = new Script('ctx._source.field2 += 5; ctx._source.remove("field3"); ctx._source.field4 = "changed"');
+ $client->updateDocument(1, $script, $index->getName(), $type->getName());
+
+ $document = $type->getDocument(1);
+
+ $this->assertInstanceOf('Elastica\Document', $document);
+ $data = $document->getData();
+ $this->assertArrayHasKey('field1', $data);
+ $this->assertEquals('value1', $data['field1']);
+ $this->assertArrayHasKey('field2', $data);
+ $this->assertEquals(15, $data['field2']);
+ $this->assertArrayHasKey('field2', $data);
+ $this->assertEquals('changed', $data['field4']);
+ $this->assertArrayNotHasKey('field3', $data);
+ }
+
+ /**
+ * @group functional
+ */
+ public function testUpdateDocumentByScriptWithUpsert()
+ {
+ $index = $this->_createIndex();
+ $type = $index->getType('test');
+ $client = $index->getClient();
+
+ $script = new Script('ctx._source.field2 += count; ctx._source.remove("field3"); ctx._source.field4 = "changed"');
+ $script->setParam('count', 5);
+ $script->setUpsert(array('field1' => 'value1', 'field2' => 10, 'field3' => 'should be removed', 'field4' => 'value4'));
+
+ // should use document fields because document does not exist, script is avoided
+ $client->updateDocument(1, $script, $index->getName(), $type->getName(), array('fields' => '_source'));
+
+ $document = $type->getDocument(1);
+
+ $this->assertInstanceOf('Elastica\Document', $document);
+ $data = $document->getData();
+ $this->assertArrayHasKey('field1', $data);
+ $this->assertEquals('value1', $data['field1']);
+ $this->assertArrayHasKey('field2', $data);
+ $this->assertEquals(10, $data['field2']);
+ $this->assertArrayHasKey('field3', $data);
+ $this->assertEquals('should be removed', $data['field3']);
+ $this->assertArrayHasKey('field4', $data);
+ $this->assertEquals('value4', $data['field4']);
+
+ // should use script because document exists, document values are ignored
+ $client->updateDocument(1, $script, $index->getName(), $type->getName(), array('fields' => '_source'));
+
+ $document = $type->getDocument(1);
+
+ $this->assertInstanceOf('Elastica\Document', $document);
+ $data = $document->getData();
+ $this->assertArrayHasKey('field1', $data);
+ $this->assertEquals('value1', $data['field1']);
+ $this->assertArrayHasKey('field2', $data);
+ $this->assertEquals(15, $data['field2']);
+ $this->assertArrayHasKey('field4', $data);
+ $this->assertEquals('changed', $data['field4']);
+ $this->assertArrayNotHasKey('field3', $data);
+ }
+
+ /**
+ * @group functional
+ */
+ public function testUpdateDocumentByRawData()
+ {
+ $index = $this->_createIndex();
+ $type = $index->getType('test');
+ $client = $index->getClient();
+
+ $newDocument = new Document(1, array('field1' => 'value1'));
+ $type->addDocument($newDocument);
+
+ $rawData = array(
+ 'doc' => array(
+ 'field2' => 'value2',
+ ),
+ );
+
+ $response = $client->updateDocument(1, $rawData, $index->getName(), $type->getName(), array('retry_on_conflict' => 1));
+ $this->assertTrue($response->isOk());
+
+ $document = $type->getDocument(1);
+
+ $this->assertInstanceOf('Elastica\Document', $document);
+ $data = $document->getData();
+ $this->assertArrayHasKey('field1', $data);
+ $this->assertEquals('value1', $data['field1']);
+ $this->assertArrayHasKey('field2', $data);
+ $this->assertEquals('value2', $data['field2']);
+ }
+
+ /**
+ * @group functional
+ */
+ public function testUpdateDocumentByDocumentWithUpsert()
+ {
+ $index = $this->_createIndex();
+ $type = $index->getType('test');
+ $client = $index->getClient();
+
+ $newDocument = new Document(1, array('field1' => 'value1updated', 'field2' => 'value2updated'));
+ $upsert = new Document(1, array('field1' => 'value1', 'field2' => 'value2'));
+ $newDocument->setUpsert($upsert);
+ $client->updateDocument(1, $newDocument, $index->getName(), $type->getName(), array('fields' => '_source'));
+
+ $document = $type->getDocument(1);
+ $this->assertInstanceOf('Elastica\Document', $document);
+ $data = $document->getData();
+ $this->assertArrayHasKey('field1', $data);
+ $this->assertEquals('value1', $data['field1']);
+ $this->assertArrayHasKey('field2', $data);
+ $this->assertEquals('value2', $data['field2']);
+
+ // should use update document because document exists, upsert document values are ignored
+ $client->updateDocument(1, $newDocument, $index->getName(), $type->getName(), array('fields' => '_source'));
+
+ $document = $type->getDocument(1);
+ $this->assertInstanceOf('Elastica\Document', $document);
+ $data = $document->getData();
+ $this->assertArrayHasKey('field1', $data);
+ $this->assertEquals('value1updated', $data['field1']);
+ $this->assertArrayHasKey('field2', $data);
+ $this->assertEquals('value2updated', $data['field2']);
+ }
+
+ /**
+ * @group functional
+ */
+ public function testDocAsUpsert()
+ {
+ $index = $this->_createIndex();
+ $type = $index->getType('test');
+ $client = $index->getClient();
+
+ //Confirm document one does not exist
+ try {
+ $document = $type->getDocument(1);
+ $this->fail('Exception was not thrown. Maybe the document exists?');
+ } catch (\Exception $e) {
+ //Ignore the exception because we expect the document to not exist.
+ }
+
+ $newDocument = new Document(1, array('field1' => 'value1', 'field2' => 'value2'));
+ $newDocument->setDocAsUpsert(true);
+ $client->updateDocument(1, $newDocument, $index->getName(), $type->getName(), array('fields' => '_source'));
+
+ $document = $type->getDocument(1);
+ $this->assertInstanceOf('Elastica\Document', $document);
+ $data = $document->getData();
+ $this->assertArrayHasKey('field1', $data);
+ $this->assertEquals('value1', $data['field1']);
+ $this->assertArrayHasKey('field2', $data);
+ $this->assertEquals('value2', $data['field2']);
+ }
+
+ /**
+ * @group functional
+ */
+ public function testUpdateWithInvalidType()
+ {
+ $index = $this->_createIndex();
+ $type = $index->getType('test');
+ $client = $index->getClient();
+
+ //Try to update using a stdClass object
+ $badDocument = new \stdClass();
+
+ try {
+ $client->updateDocument(1, $badDocument, $index->getName(), $type->getName());
+ $this->fail('Tried to update using an object that is not a Document or a Script but no exception was thrown');
+ } catch (\Exception $e) {
+ //Good. An exception was thrown.
+ }
+ }
+
+ /**
+ * @group functional
+ */
+ public function testDeleteDocuments()
+ {
+ $index = $this->_createIndex();
+ $type = $index->getType('test');
+ $client = $index->getClient();
+
+ $docs = array(
+ new Document(1, array('field' => 'value1'), $type, $index),
+ new Document(2, array('field' => 'value2'), $type, $index),
+ new Document(3, array('field' => 'value3'), $type, $index),
+ );
+
+ $response = $client->addDocuments($docs);
+
+ $this->assertInstanceOf('Elastica\Bulk\ResponseSet', $response);
+ $this->assertEquals(3, count($response));
+ $this->assertTrue($response->isOk());
+ $this->assertFalse($response->hasError());
+ $this->assertEquals('', $response->getError());
+
+ $index->refresh();
+
+ $this->assertEquals(3, $type->count());
+
+ $deleteDocs = array(
+ $docs[0],
+ $docs[2],
+ );
+
+ $response = $client->deleteDocuments($deleteDocs);
+
+ $this->assertInstanceOf('Elastica\Bulk\ResponseSet', $response);
+ $this->assertEquals(2, count($response));
+ $this->assertTrue($response->isOk());
+ $this->assertFalse($response->hasError());
+ $this->assertEquals('', $response->getError());
+
+ $index->refresh();
+
+ $this->assertEquals(1, $type->count());
+ }
+
+ /**
+ * @group functional
+ */
+ public function testLastRequestResponse()
+ {
+ $client = $this->_getClient();
+ $response = $client->request('_status');
+
+ $this->assertInstanceOf('Elastica\Response', $response);
+
+ $lastRequest = $client->getLastRequest();
+
+ $this->assertInstanceOf('Elastica\Request', $lastRequest);
+ $this->assertEquals('_status', $lastRequest->getPath());
+
+ $lastResponse = $client->getLastResponse();
+ $this->assertInstanceOf('Elastica\Response', $lastResponse);
+ $this->assertSame($response, $lastResponse);
+ }
+
+ /**
+ * @group functional
+ */
+ public function testUpdateDocumentPopulateFields()
+ {
+ $index = $this->_createIndex();
+ $type = $index->getType('test');
+ $client = $index->getClient();
+
+ $newDocument = new Document(1, array('field1' => 'value1', 'field2' => 10, 'field3' => 'should be removed', 'field4' => 'value4'));
+ $newDocument->setAutoPopulate();
+ $type->addDocument($newDocument);
+
+ $script = new Script('ctx._source.field2 += count; ctx._source.remove("field3"); ctx._source.field4 = "changed"');
+ $script->setParam('count', 5);
+ $script->setUpsert($newDocument);
+
+ $client->updateDocument(
+ 1,
+ $script,
+ $index->getName(),
+ $type->getName(),
+ array('fields' => '_source')
+ );
+
+ $data = $type->getDocument(1)->getData();
+ $this->assertArrayHasKey('field1', $data);
+ $this->assertEquals('value1', $data['field1']);
+ $this->assertArrayHasKey('field2', $data);
+ $this->assertEquals(15, $data['field2']);
+ $this->assertArrayHasKey('field4', $data);
+ $this->assertEquals('changed', $data['field4']);
+ $this->assertArrayNotHasKey('field3', $data);
+
+ $script = new Script('ctx._source.field2 += count; ctx._source.remove("field4"); ctx._source.field1 = field1;');
+ $script->setParam('count', 5);
+ $script->setParam('field1', 'updated');
+ $script->setUpsert($newDocument);
+
+ $client->updateDocument(
+ 1,
+ $script,
+ $index->getName(),
+ $type->getName(),
+ array('fields' => 'field2,field4')
+ );
+
+ $document = $type->getDocument(1);
+
+ $data = $document->getData();
+
+ $this->assertArrayHasKey('field1', $data);
+ $this->assertEquals('updated', $data['field1']);
+ $this->assertArrayHasKey('field2', $data);
+ $this->assertEquals(20, $data['field2']);
+ $this->assertArrayNotHasKey('field3', $data);
+ $this->assertArrayNotHasKey('field4', $data);
+ }
+
+ /**
+ * @group functional
+ */
+ public function testAddDocumentsWithoutIds()
+ {
+ $docs = array();
+ for ($i = 0; $i < 10; $i++) {
+ $docs[] = new Document(null, array('pos' => $i));
+ }
+
+ foreach ($docs as $doc) {
+ $this->assertFalse($doc->hasId());
+ }
+
+ $index = $this->_createIndex();
+
+ $client = $index->getClient();
+ $client->setConfigValue('document', array('autoPopulate' => true));
+
+ $type = $index->getType('pos');
+ $type->addDocuments($docs);
+
+ foreach ($docs as $doc) {
+ $this->assertTrue($doc->hasId());
+ $this->assertTrue($doc->hasVersion());
+ $this->assertEquals(1, $doc->getVersion());
+ }
+ }
+
+ /**
+ * @group unit
+ */
+ public function testConfigValue()
+ {
+ $config = array(
+ 'level1' => array(
+ 'level2' => array(
+ 'level3' => 'value3',
+ ),
+ 'level21' => 'value21',
+ ),
+ 'level11' => 'value11',
+ );
+ $client = $this->_getClient($config);
+
+ $this->assertNull($client->getConfigValue('level12'));
+ $this->assertFalse($client->getConfigValue('level12', false));
+ $this->assertEquals(10, $client->getConfigValue('level12', 10));
+
+ $this->assertEquals('value11', $client->getConfigValue('level11'));
+ $this->assertNotNull($client->getConfigValue('level11'));
+ $this->assertNotEquals(false, $client->getConfigValue('level11', false));
+ $this->assertNotEquals(10, $client->getConfigValue('level11', 10));
+
+ $this->assertEquals('value3', $client->getConfigValue(array('level1', 'level2', 'level3')));
+ $this->assertInternalType('array', $client->getConfigValue(array('level1', 'level2')));
+ }
+
+ /**
+ * @group functional
+ */
+ public function testArrayQuery()
+ {
+ $client = $this->_getClient();
+
+ $index = $client->getIndex('test');
+ $index->create(array(), true);
+ $type = $index->getType('test');
+ $type->addDocument(new Document(1, array('username' => 'ruflin')));
+ $index->refresh();
+
+ $query = array(
+ 'query' => array(
+ 'query_string' => array(
+ 'query' => 'ruflin',
+ ),
+ ),
+ );
+
+ $path = $index->getName().'/'.$type->getName().'/_search';
+
+ $response = $client->request($path, Request::GET, $query);
+ $responseArray = $response->getData();
+
+ $this->assertEquals(1, $responseArray['hits']['total']);
+ }
+
+ /**
+ * @group functional
+ */
+ public function testJSONQuery()
+ {
+ $client = $this->_getClient();
+
+ $index = $client->getIndex('test');
+ $index->create(array(), true);
+ $type = $index->getType('test');
+ $type->addDocument(new Document(1, array('username' => 'ruflin')));
+ $index->refresh();
+
+ $query = '{"query":{"query_string":{"query":"ruflin"}}}';
+
+ $path = $index->getName().'/'.$type->getName().'/_search';
+
+ $response = $client->request($path, Request::GET, $query);
+ $responseArray = $response->getData();
+
+ $this->assertEquals(1, $responseArray['hits']['total']);
+ }
+
+ /**
+ * @group unit
+ */
+ public function testAddHeader()
+ {
+ $client = $this->_getClient();
+
+ // add one header
+ $client->addHeader('foo', 'bar');
+ $this->assertEquals(array('foo' => 'bar'), $client->getConfigValue('headers'));
+
+ // check class
+ $this->assertInstanceOf('Elastica\Client', $client->addHeader('foo', 'bar'));
+
+ // check invalid parameters
+ try {
+ $client->addHeader(new \stdClass(), 'foo');
+ $this->fail('Header name is not a string but exception not thrown');
+ } catch (InvalidException $ex) {
+ }
+
+ try {
+ $client->addHeader('foo', new \stdClass());
+ $this->fail('Header value is not a string but exception not thrown');
+ } catch (InvalidException $ex) {
+ }
+ }
+
+ /**
+ * @group unit
+ */
+ public function testRemoveHeader()
+ {
+ $client = $this->_getClient();
+
+ // set headers
+ $headers = array(
+ 'first' => 'first value',
+ 'second' => 'second value',
+ );
+ foreach ($headers as $key => $value) {
+ $client->addHeader($key, $value);
+ }
+ $this->assertEquals($headers, $client->getConfigValue('headers'));
+
+ // remove one
+ $client->removeHeader('first');
+ unset($headers['first']);
+ $this->assertEquals($headers, $client->getConfigValue('headers'));
+
+ // check class
+ $this->assertInstanceOf('Elastica\Client', $client->removeHeader('second'));
+
+ // check invalid parameter
+ try {
+ $client->removeHeader(new \stdClass());
+ $this->fail('Header name is not a string but exception not thrown');
+ } catch (InvalidException $ex) {
+ }
+ }
+}
diff --git a/vendor/ruflin/elastica/test/lib/Elastica/Test/Cluster/Health/IndexTest.php b/vendor/ruflin/elastica/test/lib/Elastica/Test/Cluster/Health/IndexTest.php
new file mode 100644
index 00000000..00a121fc
--- /dev/null
+++ b/vendor/ruflin/elastica/test/lib/Elastica/Test/Cluster/Health/IndexTest.php
@@ -0,0 +1,144 @@
+<?php
+namespace Elastica\Test\Cluster\Health;
+
+use Elastica\Cluster\Health\Index as HealthIndex;
+use Elastica\Test\Base as BaseTest;
+
+class IndexTest extends BaseTest
+{
+ /**
+ * @var \Elastica\Cluster\Health\Index
+ */
+ protected $_index;
+
+ public function setUp()
+ {
+ parent::setUp();
+
+ $data = array(
+ 'status' => 'yellow',
+ 'number_of_shards' => 1,
+ 'number_of_replicas' => 2,
+ 'active_primary_shards' => 3,
+ 'active_shards' => 4,
+ 'relocating_shards' => 5,
+ 'initializing_shards' => 6,
+ 'unassigned_shards' => 7,
+ 'shards' => array(
+ '0' => array(
+ 'status' => 'yellow',
+ 'primary_active' => false,
+ 'active_shards' => 0,
+ 'relocating_shards' => 1,
+ 'initializing_shards' => 0,
+ 'unassigned_shards' => 1,
+ ),
+ '1' => array(
+ 'status' => 'yellow',
+ 'primary_active' => true,
+ 'active_shards' => 1,
+ 'relocating_shards' => 0,
+ 'initializing_shards' => 0,
+ 'unassigned_shards' => 1,
+ ),
+ '2' => array(
+ 'status' => 'green',
+ 'primary_active' => true,
+ 'active_shards' => 1,
+ 'relocating_shards' => 0,
+ 'initializing_shards' => 0,
+ 'unassigned_shards' => 0,
+ ),
+ ),
+ );
+
+ $this->_index = new HealthIndex('test', $data);
+ }
+
+ /**
+ * @group unit
+ */
+ public function testGetName()
+ {
+ $this->assertEquals('test', $this->_index->getName());
+ }
+
+ /**
+ * @group unit
+ */
+ public function testGetStatus()
+ {
+ $this->assertEquals('yellow', $this->_index->getStatus());
+ }
+
+ /**
+ * @group unit
+ */
+ public function testGetNumberOfShards()
+ {
+ $this->assertEquals(1, $this->_index->getNumberOfShards());
+ }
+
+ /**
+ * @group unit
+ */
+ public function testGetNumberOfReplicas()
+ {
+ $this->assertEquals(2, $this->_index->getNumberOfReplicas());
+ }
+
+ /**
+ * @group unit
+ */
+ public function testGetActivePrimaryShards()
+ {
+ $this->assertEquals(3, $this->_index->getActivePrimaryShards());
+ }
+
+ /**
+ * @group unit
+ */
+ public function testGetActiveShards()
+ {
+ $this->assertEquals(4, $this->_index->getActiveShards());
+ }
+
+ /**
+ * @group unit
+ */
+ public function testGetRelocatingShards()
+ {
+ $this->assertEquals(5, $this->_index->getRelocatingShards());
+ }
+
+ /**
+ * @group unit
+ */
+ public function testGetInitializingShards()
+ {
+ $this->assertEquals(6, $this->_index->getInitializingShards());
+ }
+
+ /**
+ * @group unit
+ */
+ public function testGetUnassignedShards()
+ {
+ $this->assertEquals(7, $this->_index->getUnassignedShards());
+ }
+
+ /**
+ * @group unit
+ */
+ public function testGetShards()
+ {
+ $shards = $this->_index->getShards();
+
+ $this->assertInternalType('array', $shards);
+ $this->assertEquals(3, count($shards));
+
+ foreach ($shards as $shard) {
+ $this->assertInstanceOf('Elastica\Cluster\Health\Shard', $shard);
+ }
+ }
+}
diff --git a/vendor/ruflin/elastica/test/lib/Elastica/Test/Cluster/Health/ShardTest.php b/vendor/ruflin/elastica/test/lib/Elastica/Test/Cluster/Health/ShardTest.php
new file mode 100644
index 00000000..5a436623
--- /dev/null
+++ b/vendor/ruflin/elastica/test/lib/Elastica/Test/Cluster/Health/ShardTest.php
@@ -0,0 +1,85 @@
+<?php
+namespace Elastica\Test\Cluster\Health;
+
+use Elastica\Cluster\Health\Shard as HealthShard;
+use Elastica\Test\Base as BaseTest;
+
+class ShardTest extends BaseTest
+{
+ /**
+ * @var \Elastica\Cluster\Health\Shard
+ */
+ protected $_shard;
+
+ public function setUp()
+ {
+ parent::setUp();
+
+ $shardData = array(
+ 'status' => 'red',
+ 'primary_active' => true,
+ 'active_shards' => 1,
+ 'relocating_shards' => 0,
+ 'initializing_shards' => 0,
+ 'unassigned_shards' => 1,
+ );
+
+ $this->_shard = new HealthShard(2, $shardData);
+ }
+
+ /**
+ * @group unit
+ */
+ public function testGetShardNumber()
+ {
+ $this->assertEquals(2, $this->_shard->getShardNumber());
+ }
+
+ /**
+ * @group unit
+ */
+ public function testGetStatus()
+ {
+ $this->assertEquals('red', $this->_shard->getStatus());
+ }
+
+ /**
+ * @group unit
+ */
+ public function testisPrimaryActive()
+ {
+ $this->assertTrue($this->_shard->isPrimaryActive());
+ }
+
+ /**
+ * @group unit
+ */
+ public function testIsActive()
+ {
+ $this->assertTrue($this->_shard->isActive());
+ }
+
+ /**
+ * @group unit
+ */
+ public function testIsRelocating()
+ {
+ $this->assertFalse($this->_shard->isRelocating());
+ }
+
+ /**
+ * @group unit
+ */
+ public function testIsInitialized()
+ {
+ $this->assertFalse($this->_shard->isInitialized());
+ }
+
+ /**
+ * @group unit
+ */
+ public function testIsUnassigned()
+ {
+ $this->assertTrue($this->_shard->isUnassigned());
+ }
+}
diff --git a/vendor/ruflin/elastica/test/lib/Elastica/Test/Cluster/HealthTest.php b/vendor/ruflin/elastica/test/lib/Elastica/Test/Cluster/HealthTest.php
new file mode 100644
index 00000000..bb3e82ec
--- /dev/null
+++ b/vendor/ruflin/elastica/test/lib/Elastica/Test/Cluster/HealthTest.php
@@ -0,0 +1,147 @@
+<?php
+namespace Elastica\Test\Cluster;
+
+use Elastica\Test\Base as BaseTest;
+
+class HealthTest extends BaseTest
+{
+ /**
+ * @var \Elastica\Cluster\Health
+ */
+ protected $_health;
+
+ protected function setUp()
+ {
+ parent::setUp();
+
+ $data = array(
+ 'cluster_name' => 'test_cluster',
+ 'status' => 'green',
+ 'timed_out' => false,
+ 'number_of_nodes' => 10,
+ 'number_of_data_nodes' => 8,
+ 'active_primary_shards' => 3,
+ 'active_shards' => 4,
+ 'relocating_shards' => 2,
+ 'initializing_shards' => 7,
+ 'unassigned_shards' => 5,
+ 'indices' => array(
+ 'index_one' => array(
+ ),
+ 'index_two' => array(
+ ),
+ ),
+ );
+
+ $health = $this
+ ->getMockBuilder('Elastica\Cluster\Health')
+ ->setConstructorArgs(array($this->_getClient()))
+ ->setMethods(array('_retrieveHealthData'))
+ ->getMock();
+
+ $health
+ ->expects($this->any())
+ ->method('_retrieveHealthData')
+ ->will($this->returnValue($data));
+
+ // need to explicitly refresh because the mocking won't refresh the data in the constructor
+ $health->refresh();
+
+ $this->_health = $health;
+ }
+
+ /**
+ * @group unit
+ */
+ public function testGetClusterName()
+ {
+ $this->assertEquals('test_cluster', $this->_health->getClusterName());
+ }
+
+ /**
+ * @group unit
+ */
+ public function testGetStatus()
+ {
+ $this->assertEquals('green', $this->_health->getStatus());
+ }
+
+ /**
+ * @group unit
+ */
+ public function testGetTimedOut()
+ {
+ $this->assertFalse($this->_health->getTimedOut());
+ }
+
+ /**
+ * @group unit
+ */
+ public function testGetNumberOfNodes()
+ {
+ $this->assertEquals(10, $this->_health->getNumberOfNodes());
+ }
+
+ /**
+ * @group unit
+ */
+ public function testGetNumberOfDataNodes()
+ {
+ $this->assertEquals(8, $this->_health->getNumberOfDataNodes());
+ }
+
+ /**
+ * @group unit
+ */
+ public function testGetActivePrimaryShards()
+ {
+ $this->assertEquals(3, $this->_health->getActivePrimaryShards());
+ }
+
+ /**
+ * @group unit
+ */
+ public function testGetActiveShards()
+ {
+ $this->assertEquals(4, $this->_health->getActiveShards());
+ }
+
+ /**
+ * @group unit
+ */
+ public function testGetRelocatingShards()
+ {
+ $this->assertEquals(2, $this->_health->getRelocatingShards());
+ }
+
+ /**
+ * @group unit
+ */
+ public function testGetInitializingShards()
+ {
+ $this->assertEquals(7, $this->_health->getInitializingShards());
+ }
+
+ /**
+ * @group unit
+ */
+ public function testGetUnassignedShards()
+ {
+ $this->assertEquals(5, $this->_health->getUnassignedShards());
+ }
+
+ /**
+ * @group unit
+ */
+ public function testGetIndices()
+ {
+ $indices = $this->_health->getIndices();
+
+ $this->assertInternalType('array', $indices);
+ $this->assertEquals(2, count($indices));
+
+ foreach ($indices as $index) {
+ $this->assertInstanceOf('Elastica\Cluster\Health\Index', $index);
+ }
+ }
+}
diff --git a/vendor/ruflin/elastica/test/lib/Elastica/Test/Cluster/SettingsTest.php b/vendor/ruflin/elastica/test/lib/Elastica/Test/Cluster/SettingsTest.php
new file mode 100644
index 00000000..2a52fc8f
--- /dev/null
+++ b/vendor/ruflin/elastica/test/lib/Elastica/Test/Cluster/SettingsTest.php
@@ -0,0 +1,117 @@
+<?php
+namespace Elastica\Test\Cluster;
+
+use Elastica\Cluster\Settings;
+use Elastica\Document;
+use Elastica\Exception\ResponseException;
+use Elastica\Test\Base as BaseTest;
+
+class SettingsTest extends BaseTest
+{
+ /**
+ * @group functional
+ */
+ public function testSetTransient()
+ {
+ $index = $this->_createIndex();
+
+ if (count($index->getClient()->getCluster()->getNodes()) < 2) {
+ $this->markTestSkipped('At least two master nodes have to be running for this test');
+ }
+
+ $settings = new Settings($index->getClient());
+
+ $settings->setTransient('discovery.zen.minimum_master_nodes', 2);
+ $data = $settings->get();
+ $this->assertEquals(2, $data['transient']['discovery']['zen']['minimum_master_nodes']);
+
+ $settings->setTransient('discovery.zen.minimum_master_nodes', 1);
+ $data = $settings->get();
+ $this->assertEquals(1, $data['transient']['discovery']['zen']['minimum_master_nodes']);
+ }
+
+ /**
+ * @group functional
+ */
+ public function testSetPersistent()
+ {
+ $index = $this->_createIndex();
+
+ if (count($index->getClient()->getCluster()->getNodes()) < 2) {
+ $this->markTestSkipped('At least two master nodes have to be running for this test');
+ }
+
+ $settings = new Settings($index->getClient());
+
+ $settings->setPersistent('discovery.zen.minimum_master_nodes', 2);
+ $data = $settings->get();
+ $this->assertEquals(2, $data['persistent']['discovery']['zen']['minimum_master_nodes']);
+
+ $settings->setPersistent('discovery.zen.minimum_master_nodes', 1);
+ $data = $settings->get();
+ $this->assertEquals(1, $data['persistent']['discovery']['zen']['minimum_master_nodes']);
+ }
+
+ /**
+ * @group functional
+ */
+ public function testSetReadOnly()
+ {
+ // Create two indices to check that the complete cluster is read only
+ $settings = new Settings($this->_getClient());
+ $settings->setReadOnly(false);
+ $index1 = $this->_createIndex();
+ $index2 = $this->_createIndex();
+
+ $doc1 = new Document(null, array('hello' => 'world'));
+ $doc2 = new Document(null, array('hello' => 'world'));
+ $doc3 = new Document(null, array('hello' => 'world'));
+ $doc4 = new Document(null, array('hello' => 'world'));
+ $doc5 = new Document(null, array('hello' => 'world'));
+ $doc6 = new Document(null, array('hello' => 'world'));
+
+ // Check that adding documents work
+ $index1->getType('test')->addDocument($doc1);
+ $index2->getType('test')->addDocument($doc2);
+
+ $response = $settings->setReadOnly(true);
+ $this->assertFalse($response->hasError());
+ $setting = $settings->getTransient('cluster.blocks.read_only');
+ $this->assertEquals('true', $setting);
+
+ // Make sure both index are read only
+ try {
+ $index1->getType('test')->addDocument($doc3);
+ $this->fail('should throw read only exception');
+ } catch (ResponseException $e) {
+ $message = $e->getMessage();
+ $this->assertContains('ClusterBlockException', $message);
+ $this->assertContains('cluster read-only', $message);
+ }
+
+ try {
+ $index2->getType('test')->addDocument($doc4);
+ $this->fail('should throw read only exception');
+ } catch (ResponseException $e) {
+ $message = $e->getMessage();
+ $this->assertContains('ClusterBlockException', $message);
+ $this->assertContains('cluster read-only', $message);
+ }
+
+ $response = $settings->setReadOnly(false);
+ $this->assertFalse($response->hasError());
+ $setting = $settings->getTransient('cluster.blocks.read_only');
+ $this->assertEquals('false', $setting);
+
+ // Check that adding documents works again
+ $index1->getType('test')->addDocument($doc5);
+ $index2->getType('test')->addDocument($doc6);
+
+ $index1->refresh();
+ $index2->refresh();
+
+ // 2 docs should be in each index
+ $this->assertEquals(2, $index1->count());
+ $this->assertEquals(2, $index2->count());
+ }
+}
diff --git a/vendor/ruflin/elastica/test/lib/Elastica/Test/ClusterTest.php b/vendor/ruflin/elastica/test/lib/Elastica/Test/ClusterTest.php
new file mode 100644
index 00000000..ebd89f01
--- /dev/null
+++ b/vendor/ruflin/elastica/test/lib/Elastica/Test/ClusterTest.php
@@ -0,0 +1,83 @@
+<?php
+namespace Elastica\Test;
+
+use Elastica\Cluster;
+use Elastica\Test\Base as BaseTest;
+
+class ClusterTest extends BaseTest
+{
+ /**
+ * @group functional
+ */
+ public function testGetNodeNames()
+ {
+ $client = $this->_getClient();
+
+ $cluster = new Cluster($client);
+
+ foreach ($cluster->getNodeNames() as $name) {
+ $this->assertEquals('Elastica', $name);
+ }
+ }
+
+ /**
+ * @group functional
+ */
+ public function testGetNodes()
+ {
+ $client = $this->_getClient();
+ $cluster = $client->getCluster();
+
+ $nodes = $cluster->getNodes();
+
+ foreach ($nodes as $node) {
+ $this->assertInstanceOf('Elastica\Node', $node);
+ }
+
+ $this->assertGreaterThan(0, count($nodes));
+ }
+
+ /**
+ * @group functional
+ */
+ public function testGetState()
+ {
+ $client = $this->_getClient();
+ $cluster = $client->getCluster();
+ $state = $cluster->getState();
+ $this->assertInternalType('array', $state);
+ }
+
+ /**
+ * @group functional
+ */
+ public function testGetIndexNames()
+ {
+ $client = $this->_getClient();
+ $cluster = $client->getCluster();
+
+ $index = $this->_createIndex();
+ $index->delete();
+ $cluster->refresh();
+
+ // Checks that index does not exist
+ $indexNames = $cluster->getIndexNames();
+ $this->assertNotContains($index->getName(), $indexNames);
+
+ $index = $this->_createIndex();
+ $cluster->refresh();
+
+ // Now index should exist
+ $indexNames = $cluster->getIndexNames();
+ $this->assertContains($index->getname(), $indexNames);
+ }
+
+ /**
+ * @group functional
+ */
+ public function testGetHealth()
+ {
+ $client = $this->_getClient();
+ $this->assertInstanceOf('Elastica\Cluster\Health', $client->getCluster()->getHealth());
+ }
+}
diff --git a/vendor/ruflin/elastica/test/lib/Elastica/Test/Connection/ConnectionPoolTest.php b/vendor/ruflin/elastica/test/lib/Elastica/Test/Connection/ConnectionPoolTest.php
new file mode 100644
index 00000000..ee03587a
--- /dev/null
+++ b/vendor/ruflin/elastica/test/lib/Elastica/Test/Connection/ConnectionPoolTest.php
@@ -0,0 +1,112 @@
+<?php
+namespace Elastica\Test\Connection;
+
+use Elastica\Connection;
+use Elastica\Connection\ConnectionPool;
+use Elastica\Connection\Strategy\StrategyFactory;
+use Elastica\Test\Base as BaseTest;
+
+/**
+ * @author chabior
+ */
+class ConnectionPoolTest extends BaseTest
+{
+ /**
+ * @group unit
+ */
+ public function testConstruct()
+ {
+ $pool = $this->createPool();
+
+ $this->assertEquals($this->getConnections(), $pool->getConnections());
+ }
+
+ /**
+ * @group unit
+ */
+ public function testSetConnections()
+ {
+ $pool = $this->createPool();
+
+ $connections = $this->getConnections(5);
+
+ $pool->setConnections($connections);
+
+ $this->assertEquals($connections, $pool->getConnections());
+
+ $this->assertInstanceOf('Elastica\Connection\ConnectionPool', $pool->setConnections($connections));
+ }
+
+ /**
+ * @group unit
+ */
+ public function testAddConnection()
+ {
+ $pool = $this->createPool();
+ $pool->setConnections(array());
+
+ $connections = $this->getConnections(5);
+
+ foreach ($connections as $connection) {
+ $pool->addConnection($connection);
+ }
+
+ $this->assertEquals($connections, $pool->getConnections());
+
+ $this->assertInstanceOf('Elastica\Connection\ConnectionPool', $pool->addConnection($connections[0]));
+ }
+
+ /**
+ * @group unit
+ */
+ public function testHasConnection()
+ {
+ $pool = $this->createPool();
+
+ $this->assertTrue($pool->hasConnection());
+ }
+
+ /**
+ * @group unit
+ */
+ public function testFailHasConnections()
+ {
+ $pool = $this->createPool();
+
+ $pool->setConnections(array());
+
+ $this->assertFalse($pool->hasConnection());
+ }
+
+ /**
+ * @group unit
+ */
+ public function testGetConnection()
+ {
+ $pool = $this->createPool();
+
+ $this->assertInstanceOf('Elastica\Connection', $pool->getConnection());
+ }
+
+ protected function getConnections($quantity = 1)
+ {
+ $params = array();
+ $connections = array();
+
+ for ($i = 0; $i < $quantity; $i++) {
+ $connections[] = new Connection($params);
+ }
+
+ return $connections;
+ }
+
+ protected function createPool()
+ {
+ $connections = $this->getConnections();
+ $strategy = StrategyFactory::create('Simple');
+
+ $pool = new ConnectionPool($connections, $strategy);
+
+ return $pool;
+ }
+}
diff --git a/vendor/ruflin/elastica/test/lib/Elastica/Test/Connection/Strategy/CallbackStrategyTest.php b/vendor/ruflin/elastica/test/lib/Elastica/Test/Connection/Strategy/CallbackStrategyTest.php
new file mode 100644
index 00000000..de8290ae
--- /dev/null
+++ b/vendor/ruflin/elastica/test/lib/Elastica/Test/Connection/Strategy/CallbackStrategyTest.php
@@ -0,0 +1,97 @@
+<?php
+namespace Elastica\Test\Connection\Strategy;
+
+use Elastica\Connection\Strategy\CallbackStrategy;
+use Elastica\Test\Base;
+
+/**
+ * Description of CallbackStrategyTest.
+ *
+ * @author chabior
+ */
+class CallbackStrategyTest extends Base
+{
+ /**
+ * @group unit
+ */
+ public function testInvoke()
+ {
+ $count = 0;
+
+ $callback = function ($connections) use (&$count) {
+ $count++;
+ };
+
+ $strategy = new CallbackStrategy($callback);
+ $strategy->getConnection(array());
+
+ $this->assertEquals(1, $count);
+ }
+
+ /**
+ * @group unit
+ */
+ public function testIsValid()
+ {
+ // closure is valid
+ $isValid = CallbackStrategy::isValid(function () {});
+ $this->assertTrue($isValid);
+
+ // object implementing __invoke
+ $isValid = CallbackStrategy::isValid(new CallbackStrategyTestHelper());
+ $this->assertTrue($isValid);
+
+ // static method as string
+ $isValid = CallbackStrategy::isValid('Elastica\Test\Connection\Strategy\CallbackStrategyTestHelper::getFirstConnectionStatic');
+ $this->assertTrue($isValid);
+
+ // static method as array
+ $isValid = CallbackStrategy::isValid(array('Elastica\Test\Connection\Strategy\CallbackStrategyTestHelper', 'getFirstConnectionStatic'));
+ $this->assertTrue($isValid);
+
+ // object method
+ $isValid = CallbackStrategy::isValid(array(new CallbackStrategyTestHelper(), 'getFirstConnectionStatic'));
+ $this->assertTrue($isValid);
+
+ // function name
+ $isValid = CallbackStrategy::isValid('array_pop');
+ $this->assertTrue($isValid);
+ }
+
+ /**
+ * @group unit
+ */
+ public function testFailIsValid()
+ {
+ $isValid = CallbackStrategy::isValid(new \stdClass());
+ $this->assertFalse($isValid);
+
+ $isValid = CallbackStrategy::isValid('array_pop_pop_pop_pop_pop_pop');
+ $this->assertFalse($isValid);
+ }
+
+ /**
+ * @group functional
+ */
+ public function testConnection()
+ {
+ $count = 0;
+
+ $config = array('connectionStrategy' => function ($connections) use (&$count) {
+ ++$count;
+
+ return current($connections);
+ });
+
+ $client = $this->_getClient($config);
+ $response = $client->request('/_aliases');
+
+ $this->assertEquals(1, $count);
+
+ $this->assertTrue($response->isOk());
+
+ $strategy = $client->getConnectionStrategy();
+
+ $this->assertInstanceOf('Elastica\Connection\Strategy\CallbackStrategy', $strategy);
+ }
+}
diff --git a/vendor/ruflin/elastica/test/lib/Elastica/Test/Connection/Strategy/CallbackStrategyTestHelper.php b/vendor/ruflin/elastica/test/lib/Elastica/Test/Connection/Strategy/CallbackStrategyTestHelper.php
new file mode 100644
index 00000000..b15efe91
--- /dev/null
+++ b/vendor/ruflin/elastica/test/lib/Elastica/Test/Connection/Strategy/CallbackStrategyTestHelper.php
@@ -0,0 +1,20 @@
+<?php
+namespace Elastica\Test\Connection\Strategy;
+
+class CallbackStrategyTestHelper
+{
+ public function __invoke($connections)
+ {
+ return $connections[0];
+ }
+
+ public function getFirstConnection($connections)
+ {
+ return $connections[0];
+ }
+
+ public static function getFirstConnectionStatic($connections)
+ {
+ return $connections[0];
+ }
+}
diff --git a/vendor/ruflin/elastica/test/lib/Elastica/Test/Connection/Strategy/EmptyStrategy.php b/vendor/ruflin/elastica/test/lib/Elastica/Test/Connection/Strategy/EmptyStrategy.php
new file mode 100644
index 00000000..8d2aa5df
--- /dev/null
+++ b/vendor/ruflin/elastica/test/lib/Elastica/Test/Connection/Strategy/EmptyStrategy.php
@@ -0,0 +1,17 @@
+<?php
+namespace Elastica\Test\Connection\Strategy;
+
+use Elastica\Connection\Strategy\StrategyInterface;
+
+/**
+ * Description of EmptyStrategy.
+ *
+ * @author chabior
+ */
+class EmptyStrategy implements StrategyInterface
+{
+ public function getConnection($connections)
+ {
+ return;
+ }
+}
diff --git a/vendor/ruflin/elastica/test/lib/Elastica/Test/Connection/Strategy/RoundRobinTest.php b/vendor/ruflin/elastica/test/lib/Elastica/Test/Connection/Strategy/RoundRobinTest.php
new file mode 100644
index 00000000..0dedbc22
--- /dev/null
+++ b/vendor/ruflin/elastica/test/lib/Elastica/Test/Connection/Strategy/RoundRobinTest.php
@@ -0,0 +1,128 @@
+<?php
+namespace Elastica\Test\Connection\Strategy;
+
+use Elastica\Connection;
+use Elastica\Connection\Strategy\RoundRobin;
+use Elastica\Exception\ConnectionException;
+use Elastica\Response;
+use Elastica\Test\Base;
+
+/**
+ * Description of RoundRobinTest.
+ *
+ * @author chabior
+ */
+class RoundRobinTest extends Base
+{
+ /**
+ * @var int Number of seconds to wait before timeout is called. Is set low for tests to have fast tests.
+ */
+ protected $_timeout = 1;
+
+ /**
+ * @group functional
+ */
+ public function testConnection()
+ {
+ $config = array('connectionStrategy' => 'RoundRobin');
+ $client = $this->_getClient($config);
+ $response = $client->request('/_aliases');
+ /* @var $response Response */
+
+ $this->_checkResponse($response);
+
+ $this->_checkStrategy($client);
+ }
+
+ /**
+ * @group unit
+ */
+ public function testOldStrategySetted()
+ {
+ $config = array('roundRobin' => true);
+ $client = $this->_getClient($config);
+
+ $this->_checkStrategy($client);
+ }
+
+ /**
+ * @group functional
+ * @expectedException \Elastica\Exception\ConnectionException
+ */
+ public function testFailConnection()
+ {
+ $config = array('connectionStrategy' => 'RoundRobin', 'host' => '255.255.255.0', 'timeout' => $this->_timeout);
+ $client = $this->_getClient($config);
+
+ $this->_checkStrategy($client);
+
+ $client->request('/_aliases');
+ }
+
+ /**
+ * @group functional
+ */
+ public function testWithOneFailConnection()
+ {
+ $connections = array(
+ new Connection(array('host' => '255.255.255.0', 'timeout' => $this->_timeout)),
+ new Connection(array('host' => $this->_getHost(), 'timeout' => $this->_timeout)),
+ );
+
+ $count = 0;
+ $callback = function ($connection, $exception, $client) use (&$count) {
+ ++$count;
+ };
+
+ $client = $this->_getClient(array('connectionStrategy' => 'RoundRobin'), $callback);
+ $client->setConnections($connections);
+
+ $response = $client->request('/_aliases');
+ /* @var $response Response */
+
+ $this->_checkResponse($response);
+
+ $this->_checkStrategy($client);
+
+ $this->assertLessThan(count($connections), $count);
+ }
+
+ /**
+ * @group functional
+ */
+ public function testWithNoValidConnection()
+ {
+ $connections = array(
+ new Connection(array('host' => '255.255.255.0', 'timeout' => $this->_timeout)),
+ new Connection(array('host' => '45.45.45.45', 'port' => '80', 'timeout' => $this->_timeout)),
+ new Connection(array('host' => '10.123.213.123', 'timeout' => $this->_timeout)),
+ );
+
+ $count = 0;
+ $client = $this->_getClient(array('roundRobin' => true), function () use (&$count) {
+ ++$count;
+ });
+
+ $client->setConnections($connections);
+
+ try {
+ $client->request('/_aliases');
+ $this->fail('Should throw exception as no connection valid');
+ } catch (ConnectionException $e) {
+ $this->assertEquals(count($connections), $count);
+ $this->_checkStrategy($client);
+ }
+ }
+
+ protected function _checkStrategy($client)
+ {
+ $strategy = $client->getConnectionStrategy();
+
+ $this->assertInstanceOf('Elastica\Connection\Strategy\RoundRobin', $strategy);
+ }
+
+ protected function _checkResponse($response)
+ {
+ $this->assertTrue($response->isOk());
+ }
+}
diff --git a/vendor/ruflin/elastica/test/lib/Elastica/Test/Connection/Strategy/SimpleTest.php b/vendor/ruflin/elastica/test/lib/Elastica/Test/Connection/Strategy/SimpleTest.php
new file mode 100644
index 00000000..3b6ac89d
--- /dev/null
+++ b/vendor/ruflin/elastica/test/lib/Elastica/Test/Connection/Strategy/SimpleTest.php
@@ -0,0 +1,113 @@
+<?php
+namespace Elastica\Test\Connection\Strategy;
+
+use Elastica\Connection;
+use Elastica\Exception\ConnectionException;
+use Elastica\Test\Base;
+
+/**
+ * Description of SimplyTest.
+ *
+ * @author chabior
+ */
+class SimpleTest extends Base
+{
+ /**
+ * @var int Number of seconds to wait before timeout is called. Is set low for tests to have fast tests.
+ */
+ protected $_timeout = 1;
+
+ /**
+ * @group functional
+ */
+ public function testConnection()
+ {
+ $client = $this->_getClient();
+ $response = $client->request('/_aliases');
+ /* @var $response \Elastica\Response */
+
+ $this->_checkResponse($response);
+
+ $this->_checkStrategy($client);
+ }
+
+ /**
+ * @group functional
+ * @expectedException \Elastica\Exception\ConnectionException
+ */
+ public function testFailConnection()
+ {
+ $config = array('host' => '255.255.255.0', 'timeout' => $this->_timeout);
+ $client = $this->_getClient($config);
+
+ $this->_checkStrategy($client);
+
+ $client->request('/_aliases');
+ }
+
+ /**
+ * @group functional
+ */
+ public function testWithOneFailConnection()
+ {
+ $connections = array(
+ new Connection(array('host' => '255.255.255.0', 'timeout' => $this->_timeout)),
+ new Connection(array('host' => $this->_getHost(), 'timeout' => $this->_timeout)),
+ );
+
+ $count = 0;
+ $callback = function ($connection, $exception, $client) use (&$count) {
+ ++$count;
+ };
+
+ $client = $this->_getClient(array(), $callback);
+ $client->setConnections($connections);
+
+ $response = $client->request('/_aliases');
+ /* @var $response Response */
+
+ $this->_checkResponse($response);
+
+ $this->_checkStrategy($client);
+
+ $this->assertLessThan(count($connections), $count);
+ }
+
+ /**
+ * @group functional
+ */
+ public function testWithNoValidConnection()
+ {
+ $connections = array(
+ new Connection(array('host' => '255.255.255.0', 'timeout' => $this->_timeout)),
+ new Connection(array('host' => '45.45.45.45', 'port' => '80', 'timeout' => $this->_timeout)),
+ new Connection(array('host' => '10.123.213.123', 'timeout' => $this->_timeout)),
+ );
+
+ $count = 0;
+ $client = $this->_getClient(array(), function () use (&$count) {
+ ++$count;
+ });
+
+ $client->setConnections($connections);
+
+ try {
+ $client->request('/_aliases');
+ $this->fail('Should throw exception as no connection valid');
+ } catch (ConnectionException $e) {
+ $this->assertEquals(count($connections), $count);
+ }
+ }
+
+ protected function _checkStrategy($client)
+ {
+ $strategy = $client->getConnectionStrategy();
+
+ $this->assertInstanceOf('Elastica\Connection\Strategy\Simple', $strategy);
+ }
+
+ protected function _checkResponse($response)
+ {
+ $this->assertTrue($response->isOk());
+ }
+}
diff --git a/vendor/ruflin/elastica/test/lib/Elastica/Test/Connection/Strategy/StrategyFactoryTest.php b/vendor/ruflin/elastica/test/lib/Elastica/Test/Connection/Strategy/StrategyFactoryTest.php
new file mode 100644
index 00000000..978f8fd5
--- /dev/null
+++ b/vendor/ruflin/elastica/test/lib/Elastica/Test/Connection/Strategy/StrategyFactoryTest.php
@@ -0,0 +1,84 @@
+<?php
+namespace Elastica\Test\Connection\Strategy;
+
+use Elastica\Connection\Strategy\StrategyFactory;
+use Elastica\Test\Base;
+
+/**
+ * Description of StrategyFactoryTest.
+ *
+ * @author chabior
+ */
+class StrategyFactoryTest extends Base
+{
+ /**
+ * @group unit
+ */
+ public function testCreateCallbackStrategy()
+ {
+ $callback = function ($connections) {
+ };
+
+ $strategy = StrategyFactory::create($callback);
+
+ $this->assertInstanceOf('Elastica\Connection\Strategy\CallbackStrategy', $strategy);
+ }
+
+ /**
+ * @group unit
+ */
+ public function testCreateByName()
+ {
+ $strategyName = 'Simple';
+
+ $strategy = StrategyFactory::create($strategyName);
+
+ $this->assertInstanceOf('Elastica\Connection\Strategy\Simple', $strategy);
+ }
+
+ /**
+ * @group unit
+ */
+ public function testCreateByClass()
+ {
+ $strategy = new EmptyStrategy();
+
+ $this->assertEquals($strategy, StrategyFactory::create($strategy));
+ }
+
+ /**
+ * @group unit
+ */
+ public function testCreateByClassName()
+ {
+ $strategyName = '\\Elastica\Test\Connection\Strategy\\EmptyStrategy';
+
+ $strategy = StrategyFactory::create($strategyName);
+
+ $this->assertInstanceOf($strategyName, $strategy);
+ }
+
+ /**
+ * @group unit
+ * @expectedException \InvalidArgumentException
+ */
+ public function testFailCreate()
+ {
+ $strategy = new \stdClass();
+
+ StrategyFactory::create($strategy);
+ }
+
+ /**
+ * @group unit
+ */
+ public function testNoCollisionWithGlobalNamespace()
+ {
+ // create collision
+ if (!class_exists('Simple')) {
+ class_alias('Elastica\Util', 'Simple');
+ }
+ $strategy = StrategyFactory::create('Simple');
+ $this->assertInstanceOf('Elastica\Connection\Strategy\Simple', $strategy);
+ }
+}
diff --git a/vendor/ruflin/elastica/test/lib/Elastica/Test/ConnectionTest.php b/vendor/ruflin/elastica/test/lib/Elastica/Test/ConnectionTest.php
new file mode 100644
index 00000000..7600524b
--- /dev/null
+++ b/vendor/ruflin/elastica/test/lib/Elastica/Test/ConnectionTest.php
@@ -0,0 +1,121 @@
+<?php
+namespace Elastica\Test;
+
+use Elastica\Connection;
+use Elastica\Request;
+use Elastica\Test\Base as BaseTest;
+
+class ConnectionTest extends BaseTest
+{
+ /**
+ * @group unit
+ */
+ public function testEmptyConstructor()
+ {
+ $connection = new Connection();
+ $this->assertEquals(Connection::DEFAULT_HOST, $connection->getHost());
+ $this->assertEquals(Connection::DEFAULT_PORT, $connection->getPort());
+ $this->assertEquals(Connection::DEFAULT_TRANSPORT, $connection->getTransport());
+ $this->assertInstanceOf('Elastica\Transport\AbstractTransport', $connection->getTransportObject());
+ $this->assertEquals(Connection::TIMEOUT, $connection->getTimeout());
+ $this->assertEquals(Connection::CONNECT_TIMEOUT, $connection->getConnectTimeout());
+ $this->assertEquals(array(), $connection->getConfig());
+ $this->assertTrue($connection->isEnabled());
+ }
+
+ /**
+ * @group unit
+ */
+ public function testEnabledDisable()
+ {
+ $connection = new Connection();
+ $this->assertTrue($connection->isEnabled());
+ $connection->setEnabled(false);
+ $this->assertFalse($connection->isEnabled());
+ $connection->setEnabled(true);
+ $this->assertTrue($connection->isEnabled());
+ }
+
+ /**
+ * @group unit
+ * @expectedException \Elastica\Exception\ConnectionException
+ */
+ public function testInvalidConnection()
+ {
+ $connection = new Connection(array('port' => 9999));
+
+ $request = new Request('_status', Request::GET);
+ $request->setConnection($connection);
+
+ // Throws exception because no valid connection
+ $request->send();
+ }
+
+ /**
+ * @group unit
+ */
+ public function testCreate()
+ {
+ $connection = Connection::create();
+ $this->assertInstanceOf('Elastica\Connection', $connection);
+
+ $connection = Connection::create(array());
+ $this->assertInstanceOf('Elastica\Connection', $connection);
+
+ $port = 9999;
+ $connection = Connection::create(array('port' => $port));
+ $this->assertInstanceOf('Elastica\Connection', $connection);
+ $this->assertEquals($port, $connection->getPort());
+ }
+
+ /**
+ * @group unit
+ * @expectedException \Elastica\Exception\InvalidException
+ * @expectedException \Elastica\Exception\InvalidException
+ */
+ public function testCreateInvalid()
+ {
+ Connection::create('test');
+ }
+
+ /**
+ * @group unit
+ */
+ public function testGetConfig()
+ {
+ $url = 'test';
+ $connection = new Connection(array('config' => array('url' => $url)));
+ $this->assertTrue($connection->hasConfig('url'));
+ $this->assertEquals($url, $connection->getConfig('url'));
+ }
+
+ /**
+ * @group unit
+ */
+ public function testGetConfigWithArrayUsedForTransport()
+ {
+ $connection = new Connection(array('transport' => array('type' => 'Http')));
+ $this->assertInstanceOf('Elastica\Transport\Http', $connection->getTransportObject());
+ }
+
+ /**
+ * @group unit
+ * @expectedException Elastica\Exception\InvalidException
+ * @expectedExceptionMessage Invalid transport
+ */
+ public function testGetInvalidConfigWithArrayUsedForTransport()
+ {
+ $connection = new Connection(array('transport' => array('type' => 'invalidtransport')));
+ $connection->getTransportObject();
+ }
+
+ /**
+ * @group unit
+ * @expectedException \Elastica\Exception\InvalidException
+ */
+ public function testGetConfigInvalidValue()
+ {
+ $connection = new Connection();
+ $connection->getConfig('url');
+ }
+}
diff --git a/vendor/ruflin/elastica/test/lib/Elastica/Test/DocumentTest.php b/vendor/ruflin/elastica/test/lib/Elastica/Test/DocumentTest.php
new file mode 100644
index 00000000..969c5b22
--- /dev/null
+++ b/vendor/ruflin/elastica/test/lib/Elastica/Test/DocumentTest.php
@@ -0,0 +1,349 @@
+<?php
+namespace Elastica\Test;
+
+use Elastica\Document;
+use Elastica\Exception\InvalidException;
+use Elastica\Index;
+use Elastica\Test\Base as BaseTest;
+use Elastica\Type;
+
+class DocumentTest extends BaseTest
+{
+ /**
+ * @group unit
+ */
+ public function testAddFile()
+ {
+ $fileName = '/dev/null';
+ if (!file_exists($fileName)) {
+ $this->markTestSkipped("File {$fileName} does not exist.");
+ }
+ $doc = new Document();
+ $returnValue = $doc->addFile('key', $fileName);
+ $this->assertInstanceOf('Elastica\Document', $returnValue);
+ }
+
+ /**
+ * @group unit
+ */
+ public function testAddGeoPoint()
+ {
+ $doc = new Document();
+ $returnValue = $doc->addGeoPoint('point', 38.89859, -77.035971);
+ $this->assertInstanceOf('Elastica\Document', $returnValue);
+ }
+
+ /**
+ * @group unit
+ */
+ public function testSetData()
+ {
+ $doc = new Document();
+ $returnValue = $doc->setData(array('data'));
+ $this->assertInstanceOf('Elastica\Document', $returnValue);
+ }
+
+ /**
+ * @group unit
+ */
+ public function testToArray()
+ {
+ $id = 17;
+ $data = array('hello' => 'world');
+ $type = 'testtype';
+ $index = 'textindex';
+
+ $doc = new Document($id, $data, $type, $index);
+
+ $result = array('_index' => $index, '_type' => $type, '_id' => $id, '_source' => $data);
+ $this->assertEquals($result, $doc->toArray());
+ }
+
+ /**
+ * @group unit
+ */
+ public function testSetType()
+ {
+ $document = new Document();
+ $document->setType('type');
+
+ $this->assertEquals('type', $document->getType());
+
+ $index = new Index($this->_getClient(), 'index');
+ $type = $index->getType('type');
+
+ $document->setIndex('index2');
+ $this->assertEquals('index2', $document->getIndex());
+
+ $document->setType($type);
+
+ $this->assertEquals('index', $document->getIndex());
+ $this->assertEquals('type', $document->getType());
+ }
+
+ /**
+ * @group unit
+ */
+ public function testSetIndex()
+ {
+ $document = new Document();
+ $document->setIndex('index2');
+ $document->setType('type2');
+
+ $this->assertEquals('index2', $document->getIndex());
+ $this->assertEquals('type2', $document->getType());
+
+ $index = new Index($this->_getClient(), 'index');
+
+ $document->setIndex($index);
+
+ $this->assertEquals('index', $document->getIndex());
+ $this->assertEquals('type2', $document->getType());
+ }
+
+ /**
+ * @group unit
+ */
+ public function testHasId()
+ {
+ $document = new Document();
+ $this->assertFalse($document->hasId());
+ $document->setId('');
+ $this->assertFalse($document->hasId());
+ $document->setId(0);
+ $this->assertTrue($document->hasId());
+ $document->setId('hello');
+ $this->assertTrue($document->hasId());
+ }
+
+ /**
+ * @group unit
+ */
+ public function testGetOptions()
+ {
+ $document = new Document();
+ $document->setIndex('index');
+ $document->setOpType('create');
+ $document->setParent('2');
+ $document->setId(1);
+
+ $options = $document->getOptions(array('index', 'type', 'id', 'parent'));
+
+ $this->assertInternalType('array', $options);
+ $this->assertEquals(3, count($options));
+ $this->assertArrayHasKey('index', $options);
+ $this->assertArrayHasKey('id', $options);
+ $this->assertArrayHasKey('parent', $options);
+ $this->assertEquals('index', $options['index']);
+ $this->assertEquals(1, $options['id']);
+ $this->assertEquals('2', $options['parent']);
+ $this->assertArrayNotHasKey('type', $options);
+ $this->assertArrayNotHasKey('op_type', $options);
+ $this->assertArrayNotHasKey('_index', $options);
+ $this->assertArrayNotHasKey('_id', $options);
+ $this->assertArrayNotHasKey('_parent', $options);
+
+ $options = $document->getOptions(array('parent', 'op_type', 'percolate'), true);
+
+ $this->assertInternalType('array', $options);
+ $this->assertEquals(2, count($options));
+ $this->assertArrayHasKey('_parent', $options);
+ $this->assertArrayHasKey('_op_type', $options);
+ $this->assertEquals('2', $options['_parent']);
+ $this->assertEquals('create', $options['_op_type']);
+ $this->assertArrayNotHasKey('percolate', $options);
+ $this->assertArrayNotHasKey('op_type', $options);
+ $this->assertArrayNotHasKey('parent', $options);
+ }
+
+ /**
+ * @group unit
+ */
+ public function testGetSetHasRemove()
+ {
+ $document = new Document(1, array('field1' => 'value1', 'field2' => 'value2', 'field3' => 'value3', 'field4' => null));
+
+ $this->assertEquals('value1', $document->get('field1'));
+ $this->assertEquals('value2', $document->get('field2'));
+ $this->assertEquals('value3', $document->get('field3'));
+ $this->assertNull($document->get('field4'));
+ try {
+ $document->get('field5');
+ $this->fail('Undefined field get should throw exception');
+ } catch (InvalidException $e) {
+ $this->assertTrue(true);
+ }
+
+ $this->assertTrue($document->has('field1'));
+ $this->assertTrue($document->has('field2'));
+ $this->assertTrue($document->has('field3'));
+ $this->assertTrue($document->has('field4'));
+ $this->assertFalse($document->has('field5'), 'Field5 should not be isset, because it is not set');
+
+ $data = $document->getData();
+
+ $this->assertArrayHasKey('field1', $data);
+ $this->assertEquals('value1', $data['field1']);
+ $this->assertArrayHasKey('field2', $data);
+ $this->assertEquals('value2', $data['field2']);
+ $this->assertArrayHasKey('field3', $data);
+ $this->assertEquals('value3', $data['field3']);
+ $this->assertArrayHasKey('field4', $data);
+ $this->assertNull($data['field4']);
+
+ $returnValue = $document->set('field1', 'changed1');
+ $this->assertInstanceOf('Elastica\Document', $returnValue);
+ $returnValue = $document->remove('field3');
+ $this->assertInstanceOf('Elastica\Document', $returnValue);
+ try {
+ $document->remove('field5');
+ $this->fail('Undefined field unset should throw exception');
+ } catch (InvalidException $e) {
+ $this->assertTrue(true);
+ }
+
+ $this->assertEquals('changed1', $document->get('field1'));
+ $this->assertFalse($document->has('field3'));
+
+ $newData = $document->getData();
+
+ $this->assertNotEquals($data, $newData);
+ }
+
+ /**
+ * @group unit
+ */
+ public function testDataPropertiesOverloading()
+ {
+ $document = new Document(1, array('field1' => 'value1', 'field2' => 'value2', 'field3' => 'value3', 'field4' => null));
+
+ $this->assertEquals('value1', $document->field1);
+ $this->assertEquals('value2', $document->field2);
+ $this->assertEquals('value3', $document->field3);
+ $this->assertNull($document->field4);
+ try {
+ $document->field5;
+ $this->fail('Undefined field get should throw exception');
+ } catch (InvalidException $e) {
+ $this->assertTrue(true);
+ }
+
+ $this->assertTrue(isset($document->field1));
+ $this->assertTrue(isset($document->field2));
+ $this->assertTrue(isset($document->field3));
+ $this->assertFalse(isset($document->field4), 'Field4 should not be isset, because it is null');
+ $this->assertFalse(isset($document->field5), 'Field5 should not be isset, because it is not set');
+
+ $data = $document->getData();
+
+ $this->assertArrayHasKey('field1', $data);
+ $this->assertEquals('value1', $data['field1']);
+ $this->assertArrayHasKey('field2', $data);
+ $this->assertEquals('value2', $data['field2']);
+ $this->assertArrayHasKey('field3', $data);
+ $this->assertEquals('value3', $data['field3']);
+ $this->assertArrayHasKey('field4', $data);
+ $this->assertNull($data['field4']);
+
+ $document->field1 = 'changed1';
+ unset($document->field3);
+ try {
+ unset($document->field5);
+ $this->fail('Undefined field unset should throw exception');
+ } catch (InvalidException $e) {
+ $this->assertTrue(true);
+ }
+
+ $this->assertEquals('changed1', $document->field1);
+ $this->assertFalse(isset($document->field3));
+
+ $newData = $document->getData();
+
+ $this->assertNotEquals($data, $newData);
+ }
+
+ /**
+ * @group unit
+ */
+ public function testSetTtl()
+ {
+ $document = new Document();
+
+ $this->assertFalse($document->hasTtl());
+ $options = $document->getOptions();
+ $this->assertArrayNotHasKey('ttl', $options);
+
+ $document->setTtl('1d');
+
+ $newOptions = $document->getOptions();
+
+ $this->assertArrayHasKey('ttl', $newOptions);
+ $this->assertEquals('1d', $newOptions['ttl']);
+ $this->assertNotEquals($options, $newOptions);
+
+ $this->assertTrue($document->hasTtl());
+ $this->assertEquals('1d', $document->getTtl());
+ }
+
+ /**
+ * @group unit
+ */
+ public function testSerializedData()
+ {
+ $data = '{"user":"rolf"}';
+ $document = new Document(1, $data);
+
+ $this->assertFalse($document->has('user'));
+
+ try {
+ $document->get('user');
+ $this->fail('User field should not be available');
+ } catch (InvalidException $e) {
+ $this->assertTrue(true);
+ }
+
+ try {
+ $document->remove('user');
+ $this->fail('User field should not be available for removal');
+ } catch (InvalidException $e) {
+ $this->assertTrue(true);
+ }
+
+ try {
+ $document->set('name', 'shawn');
+ $this->fail('Document should not allow to set new data');
+ } catch (InvalidException $e) {
+ $this->assertTrue(true);
+ }
+ }
+
+ /**
+ * @group unit
+ */
+ public function testUpsert()
+ {
+ $document = new Document();
+
+ $upsert = new Document();
+ $upsert->setData(array('someproperty' => 'somevalue'));
+
+ $this->assertFalse($document->hasUpsert());
+
+ $document->setUpsert($upsert);
+
+ $this->assertTrue($document->hasUpsert());
+ $this->assertSame($upsert, $document->getUpsert());
+ }
+
+ /**
+ * @group unit
+ */
+ public function testDocAsUpsert()
+ {
+ $document = new Document();
+
+ $this->assertFalse($document->getDocAsUpsert());
+ $this->assertSame($document, $document->setDocAsUpsert(true));
+ $this->assertTrue($document->getDocAsUpsert());
+ }
+}
diff --git a/vendor/ruflin/elastica/test/lib/Elastica/Test/ExampleTest.php b/vendor/ruflin/elastica/test/lib/Elastica/Test/ExampleTest.php
new file mode 100644
index 00000000..efdc04eb
--- /dev/null
+++ b/vendor/ruflin/elastica/test/lib/Elastica/Test/ExampleTest.php
@@ -0,0 +1,61 @@
+<?php
+namespace Elastica\Test;
+
+use Elastica\Document;
+use Elastica\Test\Base as BaseTest;
+
+/**
+ * Tests the example code.
+ */
+class ExampleTest extends BaseTest
+{
+ /**
+ * @group functional
+ */
+ public function testBasicGettingStarted()
+ {
+ $client = $this->_getClient();
+ $index = $client->getIndex('ruflin');
+ $type = $index->getType('users');
+
+ $id = 2;
+ $data = array('firstname' => 'Nicolas', 'lastname' => 'Ruflin');
+ $doc = new Document($id, $data);
+
+ $type->addDocument($doc);
+ }
+
+ /**
+ * @group functional
+ */
+ public function testExample()
+ {
+ // Creates a new index 'xodoa' and a type 'user' inside this index
+ $client = $this->_getClient();
+ $index = $client->getIndex('elastica_test');
+ $index->create(array(), true);
+
+ $type = $index->getType('user');
+
+ // Adds 1 document to the index
+ $doc1 = new Document(1,
+ array('username' => 'hans', 'test' => array('2', '3', '5'))
+ );
+ $type->addDocument($doc1);
+
+ // Adds a list of documents with _bulk upload to the index
+ $docs = array();
+ $docs[] = new Document(2,
+ array('username' => 'john', 'test' => array('1', '3', '6'))
+ );
+ $docs[] = new Document(3,
+ array('username' => 'rolf', 'test' => array('2', '3', '7'))
+ );
+ $type->addDocuments($docs);
+
+ // Refresh index
+ $index->refresh();
+
+ $resultSet = $type->search('rolf');
+ }
+}
diff --git a/vendor/ruflin/elastica/test/lib/Elastica/Test/Exception/AbstractExceptionTest.php b/vendor/ruflin/elastica/test/lib/Elastica/Test/Exception/AbstractExceptionTest.php
new file mode 100644
index 00000000..ea84218a
--- /dev/null
+++ b/vendor/ruflin/elastica/test/lib/Elastica/Test/Exception/AbstractExceptionTest.php
@@ -0,0 +1,31 @@
+<?php
+namespace Elastica\Test\Exception;
+
+use Elastica\Test\Base as BaseTest;
+
+abstract class AbstractExceptionTest extends BaseTest
+{
+ protected function _getExceptionClass()
+ {
+ $reflection = new \ReflectionObject($this);
+
+ // Elastica\Test\Exception\RuntimeExceptionTest => Elastica\Exception\RuntimeExceptionTest
+ $name = preg_replace('/^Elastica\\\\Test/', 'Elastica', $reflection->getName());
+
+ // Elastica\Exception\RuntimeExceptionTest => Elastica\Exception\RuntimeException
+ $name = preg_replace('/Test$/', '', $name);
+
+ return $name;
+ }
+
+ /**
+ * @group unit
+ */
+ public function testInheritance()
+ {
+ $className = $this->_getExceptionClass();
+ $reflection = new \ReflectionClass($className);
+ $this->assertTrue($reflection->isSubclassOf('Exception'));
+ $this->assertTrue($reflection->implementsInterface('Elastica\Exception\ExceptionInterface'));
+ }
+}
diff --git a/vendor/ruflin/elastica/test/lib/Elastica/Test/Exception/Bulk/Response/ActionExceptionTest.php b/vendor/ruflin/elastica/test/lib/Elastica/Test/Exception/Bulk/Response/ActionExceptionTest.php
new file mode 100644
index 00000000..38a2f873
--- /dev/null
+++ b/vendor/ruflin/elastica/test/lib/Elastica/Test/Exception/Bulk/Response/ActionExceptionTest.php
@@ -0,0 +1,8 @@
+<?php
+namespace Elastica\Test\Exception\Bulk\Response;
+
+use Elastica\Test\Exception\AbstractExceptionTest;
+
+class ActionExceptionTest extends AbstractExceptionTest
+{
+}
diff --git a/vendor/ruflin/elastica/test/lib/Elastica/Test/Exception/Bulk/ResponseExceptionTest.php b/vendor/ruflin/elastica/test/lib/Elastica/Test/Exception/Bulk/ResponseExceptionTest.php
new file mode 100644
index 00000000..2164f0e3
--- /dev/null
+++ b/vendor/ruflin/elastica/test/lib/Elastica/Test/Exception/Bulk/ResponseExceptionTest.php
@@ -0,0 +1,8 @@
+<?php
+namespace Elastica\Test\Exception\Bulk;
+
+use Elastica\Test\Exception\AbstractExceptionTest;
+
+class ResponseExceptionTest extends AbstractExceptionTest
+{
+}
diff --git a/vendor/ruflin/elastica/test/lib/Elastica/Test/Exception/Bulk/UdpExceptionTest.php b/vendor/ruflin/elastica/test/lib/Elastica/Test/Exception/Bulk/UdpExceptionTest.php
new file mode 100644
index 00000000..2b7660bf
--- /dev/null
+++ b/vendor/ruflin/elastica/test/lib/Elastica/Test/Exception/Bulk/UdpExceptionTest.php
@@ -0,0 +1,8 @@
+<?php
+namespace Elastica\Test\Exception\Bulk;
+
+use Elastica\Test\Exception\AbstractExceptionTest;
+
+class UdpExceptionTest extends AbstractExceptionTest
+{
+}
diff --git a/vendor/ruflin/elastica/test/lib/Elastica/Test/Exception/BulkExceptionTest.php b/vendor/ruflin/elastica/test/lib/Elastica/Test/Exception/BulkExceptionTest.php
new file mode 100644
index 00000000..1bd07689
--- /dev/null
+++ b/vendor/ruflin/elastica/test/lib/Elastica/Test/Exception/BulkExceptionTest.php
@@ -0,0 +1,6 @@
+<?php
+namespace Elastica\Test\Exception;
+
+class BulkExceptionTest extends AbstractExceptionTest
+{
+}
diff --git a/vendor/ruflin/elastica/test/lib/Elastica/Test/Exception/ClientExceptionTest.php b/vendor/ruflin/elastica/test/lib/Elastica/Test/Exception/ClientExceptionTest.php
new file mode 100644
index 00000000..3f75e456
--- /dev/null
+++ b/vendor/ruflin/elastica/test/lib/Elastica/Test/Exception/ClientExceptionTest.php
@@ -0,0 +1,6 @@
+<?php
+namespace Elastica\Test\Exception;
+
+class ClientExceptionTest extends AbstractExceptionTest
+{
+}
diff --git a/vendor/ruflin/elastica/test/lib/Elastica/Test/Exception/Connection/GuzzleExceptionTest.php b/vendor/ruflin/elastica/test/lib/Elastica/Test/Exception/Connection/GuzzleExceptionTest.php
new file mode 100644
index 00000000..48a39de4
--- /dev/null
+++ b/vendor/ruflin/elastica/test/lib/Elastica/Test/Exception/Connection/GuzzleExceptionTest.php
@@ -0,0 +1,14 @@
+<?php
+namespace Elastica\Test\Exception\Connection;
+
+use Elastica\Test\Exception\AbstractExceptionTest;
+
+class GuzzleExceptionTest extends AbstractExceptionTest
+{
+ public static function setUpBeforeClass()
+ {
+ if (!class_exists('GuzzleHttp\\Client')) {
+ self::markTestSkipped('guzzlehttp/guzzle package should be installed to run guzzle transport tests');
+ }
+ }
+}
diff --git a/vendor/ruflin/elastica/test/lib/Elastica/Test/Exception/Connection/HttpExceptionTest.php b/vendor/ruflin/elastica/test/lib/Elastica/Test/Exception/Connection/HttpExceptionTest.php
new file mode 100644
index 00000000..39d58013
--- /dev/null
+++ b/vendor/ruflin/elastica/test/lib/Elastica/Test/Exception/Connection/HttpExceptionTest.php
@@ -0,0 +1,8 @@
+<?php
+namespace Elastica\Test\Exception\Connection;
+
+use Elastica\Test\Exception\AbstractExceptionTest;
+
+class HttpExceptionTest extends AbstractExceptionTest
+{
+}
diff --git a/vendor/ruflin/elastica/test/lib/Elastica/Test/Exception/Connection/MemcacheExceptionTest.php b/vendor/ruflin/elastica/test/lib/Elastica/Test/Exception/Connection/MemcacheExceptionTest.php
new file mode 100644
index 00000000..5bf8fd35
--- /dev/null
+++ b/vendor/ruflin/elastica/test/lib/Elastica/Test/Exception/Connection/MemcacheExceptionTest.php
@@ -0,0 +1,8 @@
+<?php
+namespace Elastica\Test\Exception\Connection;
+
+use Elastica\Test\Exception\AbstractExceptionTest;
+
+class MemcacheExceptionTest extends AbstractExceptionTest
+{
+}
diff --git a/vendor/ruflin/elastica/test/lib/Elastica/Test/Exception/Connection/ThriftExceptionTest.php b/vendor/ruflin/elastica/test/lib/Elastica/Test/Exception/Connection/ThriftExceptionTest.php
new file mode 100644
index 00000000..5cef43be
--- /dev/null
+++ b/vendor/ruflin/elastica/test/lib/Elastica/Test/Exception/Connection/ThriftExceptionTest.php
@@ -0,0 +1,14 @@
+<?php
+namespace Elastica\Test\Exception\Connection;
+
+use Elastica\Test\Exception\AbstractExceptionTest;
+
+class ThriftExceptionTest extends AbstractExceptionTest
+{
+ public static function setUpBeforeClass()
+ {
+ if (!class_exists('Elasticsearch\\RestClient')) {
+ self::markTestSkipped('munkie/elasticsearch-thrift-php package should be installed to run thrift exception tests');
+ }
+ }
+}
diff --git a/vendor/ruflin/elastica/test/lib/Elastica/Test/Exception/ConnectionExceptionTest.php b/vendor/ruflin/elastica/test/lib/Elastica/Test/Exception/ConnectionExceptionTest.php
new file mode 100644
index 00000000..5196b29e
--- /dev/null
+++ b/vendor/ruflin/elastica/test/lib/Elastica/Test/Exception/ConnectionExceptionTest.php
@@ -0,0 +1,6 @@
+<?php
+namespace Elastica\Test\Exception;
+
+class ConnectionExceptionTest extends AbstractExceptionTest
+{
+}
diff --git a/vendor/ruflin/elastica/test/lib/Elastica/Test/Exception/ElasticsearchExceptionTest.php b/vendor/ruflin/elastica/test/lib/Elastica/Test/Exception/ElasticsearchExceptionTest.php
new file mode 100644
index 00000000..d11894f7
--- /dev/null
+++ b/vendor/ruflin/elastica/test/lib/Elastica/Test/Exception/ElasticsearchExceptionTest.php
@@ -0,0 +1,6 @@
+<?php
+namespace Elastica\Test\Exception;
+
+class ElasticsearchExceptionTest extends AbstractExceptionTest
+{
+}
diff --git a/vendor/ruflin/elastica/test/lib/Elastica/Test/Exception/InvalidExceptionTest.php b/vendor/ruflin/elastica/test/lib/Elastica/Test/Exception/InvalidExceptionTest.php
new file mode 100644
index 00000000..e6e11899
--- /dev/null
+++ b/vendor/ruflin/elastica/test/lib/Elastica/Test/Exception/InvalidExceptionTest.php
@@ -0,0 +1,6 @@
+<?php
+namespace Elastica\Test\Exception;
+
+class InvalidExceptionTest extends AbstractExceptionTest
+{
+}
diff --git a/vendor/ruflin/elastica/test/lib/Elastica/Test/Exception/JSONParseExceptionTest.php b/vendor/ruflin/elastica/test/lib/Elastica/Test/Exception/JSONParseExceptionTest.php
new file mode 100644
index 00000000..4fd01c49
--- /dev/null
+++ b/vendor/ruflin/elastica/test/lib/Elastica/Test/Exception/JSONParseExceptionTest.php
@@ -0,0 +1,6 @@
+<?php
+namespace Elastica\Test\Exception;
+
+class JSONParseExceptionTest extends AbstractExceptionTest
+{
+}
diff --git a/vendor/ruflin/elastica/test/lib/Elastica/Test/Exception/NotFoundExceptionTest.php b/vendor/ruflin/elastica/test/lib/Elastica/Test/Exception/NotFoundExceptionTest.php
new file mode 100644
index 00000000..ff80a708
--- /dev/null
+++ b/vendor/ruflin/elastica/test/lib/Elastica/Test/Exception/NotFoundExceptionTest.php
@@ -0,0 +1,6 @@
+<?php
+namespace Elastica\Test\Exception;
+
+class NotFoundExceptionTest extends AbstractExceptionTest
+{
+}
diff --git a/vendor/ruflin/elastica/test/lib/Elastica/Test/Exception/NotImplementedExceptionTest.php b/vendor/ruflin/elastica/test/lib/Elastica/Test/Exception/NotImplementedExceptionTest.php
new file mode 100644
index 00000000..117aa012
--- /dev/null
+++ b/vendor/ruflin/elastica/test/lib/Elastica/Test/Exception/NotImplementedExceptionTest.php
@@ -0,0 +1,19 @@
+<?php
+namespace Elastica\Test\Exception;
+
+use Elastica\Exception\NotImplementedException;
+
+class NotImplementedExceptionTest extends AbstractExceptionTest
+{
+ /**
+ * @group unit
+ */
+ public function testInstance()
+ {
+ $code = 4;
+ $message = 'Hello world';
+ $exception = new NotImplementedException($message, $code);
+ $this->assertEquals($message, $exception->getMessage());
+ $this->assertEquals($code, $exception->getCode());
+ }
+}
diff --git a/vendor/ruflin/elastica/test/lib/Elastica/Test/Exception/PartialShardFailureExceptionTest.php b/vendor/ruflin/elastica/test/lib/Elastica/Test/Exception/PartialShardFailureExceptionTest.php
new file mode 100644
index 00000000..afcca1ec
--- /dev/null
+++ b/vendor/ruflin/elastica/test/lib/Elastica/Test/Exception/PartialShardFailureExceptionTest.php
@@ -0,0 +1,54 @@
+<?php
+namespace Elastica\Test\Exception;
+
+use Elastica\Document;
+use Elastica\Exception\PartialShardFailureException;
+use Elastica\Query;
+use Elastica\ResultSet;
+
+class PartialShardFailureExceptionTest extends AbstractExceptionTest
+{
+ /**
+ * @group functional
+ */
+ public function testPartialFailure()
+ {
+ $client = $this->_getClient();
+ $index = $client->getIndex('elastica_partial_failure');
+ $index->create(array(
+ 'index' => array(
+ 'number_of_shards' => 5,
+ 'number_of_replicas' => 0,
+ ),
+ ), true);
+
+ $type = $index->getType('folks');
+
+ $type->addDocument(new Document('', array('name' => 'ruflin')));
+ $type->addDocument(new Document('', array('name' => 'bobrik')));
+ $type->addDocument(new Document('', array('name' => 'kimchy')));
+
+ $index->refresh();
+
+ $query = Query::create(array(
+ 'query' => array(
+ 'filtered' => array(
+ 'filter' => array(
+ 'script' => array(
+ 'script' => 'doc["undefined"] > 8', // compiles, but doesn't work
+ ),
+ ),
+ ),
+ ),
+ ));
+
+ try {
+ $index->search($query);
+
+ $this->fail('PartialShardFailureException should have been thrown');
+ } catch (PartialShardFailureException $e) {
+ $resultSet = new ResultSet($e->getResponse(), $query);
+ $this->assertEquals(0, count($resultSet->getResults()));
+ }
+ }
+}
diff --git a/vendor/ruflin/elastica/test/lib/Elastica/Test/Exception/QueryBuilderExceptionTest.php b/vendor/ruflin/elastica/test/lib/Elastica/Test/Exception/QueryBuilderExceptionTest.php
new file mode 100644
index 00000000..375731ba
--- /dev/null
+++ b/vendor/ruflin/elastica/test/lib/Elastica/Test/Exception/QueryBuilderExceptionTest.php
@@ -0,0 +1,6 @@
+<?php
+namespace Elastica\Test\Exception;
+
+class QueryBuilderExceptionTest extends AbstractExceptionTest
+{
+}
diff --git a/vendor/ruflin/elastica/test/lib/Elastica/Test/Exception/ResponseExceptionTest.php b/vendor/ruflin/elastica/test/lib/Elastica/Test/Exception/ResponseExceptionTest.php
new file mode 100644
index 00000000..6fc975e7
--- /dev/null
+++ b/vendor/ruflin/elastica/test/lib/Elastica/Test/Exception/ResponseExceptionTest.php
@@ -0,0 +1,65 @@
+<?php
+namespace Elastica\Test\Exception;
+
+use Elastica\Document;
+use Elastica\Exception\ResponseException;
+
+class ResponseExceptionTest extends AbstractExceptionTest
+{
+ /**
+ * @group functional
+ */
+ public function testCreateExistingIndex()
+ {
+ $this->_createIndex('woo', true);
+
+ try {
+ $this->_createIndex('woo', false);
+ $this->fail('Index created when it should fail');
+ } catch (ResponseException $ex) {
+ $this->assertEquals('IndexAlreadyExistsException', $ex->getElasticsearchException()->getExceptionName());
+ $this->assertEquals(400, $ex->getElasticsearchException()->getCode());
+ }
+ }
+
+ /**
+ * @group functional
+ */
+ public function testBadType()
+ {
+ $index = $this->_createIndex();
+ $type = $index->getType('test');
+
+ $type->setMapping(array(
+ 'num' => array(
+ 'type' => 'long',
+ ),
+ ));
+
+ try {
+ $type->addDocument(new Document('', array(
+ 'num' => 'not number at all',
+ )));
+ $this->fail('Indexing with wrong type should fail');
+ } catch (ResponseException $ex) {
+ $this->assertEquals('MapperParsingException', $ex->getElasticsearchException()->getExceptionName());
+ $this->assertEquals(400, $ex->getElasticsearchException()->getCode());
+ }
+ }
+
+ /**
+ * @group functional
+ */
+ public function testWhatever()
+ {
+ $index = $this->_createIndex();
+ $index->delete();
+
+ try {
+ $index->search();
+ } catch (ResponseException $ex) {
+ $this->assertEquals('IndexMissingException', $ex->getElasticsearchException()->getExceptionName());
+ $this->assertEquals(404, $ex->getElasticsearchException()->getCode());
+ }
+ }
+}
diff --git a/vendor/ruflin/elastica/test/lib/Elastica/Test/Exception/RuntimeExceptionTest.php b/vendor/ruflin/elastica/test/lib/Elastica/Test/Exception/RuntimeExceptionTest.php
new file mode 100644
index 00000000..9dd18951
--- /dev/null
+++ b/vendor/ruflin/elastica/test/lib/Elastica/Test/Exception/RuntimeExceptionTest.php
@@ -0,0 +1,6 @@
+<?php
+namespace Elastica\Test\Exception;
+
+class RuntimeExceptionTest extends AbstractExceptionTest
+{
+}
diff --git a/vendor/ruflin/elastica/test/lib/Elastica/Test/Facet/DateHistogramTest.php b/vendor/ruflin/elastica/test/lib/Elastica/Test/Facet/DateHistogramTest.php
new file mode 100644
index 00000000..96d30aa2
--- /dev/null
+++ b/vendor/ruflin/elastica/test/lib/Elastica/Test/Facet/DateHistogramTest.php
@@ -0,0 +1,106 @@
+<?php
+namespace Elastica\Test\Facet;
+
+use Elastica\Document;
+use Elastica\Facet\DateHistogram;
+use Elastica\Query;
+use Elastica\Query\MatchAll;
+use Elastica\Test\Base as BaseTest;
+use Elastica\Type\Mapping;
+
+class DateHistogramTest extends BaseTest
+{
+ /**
+ * @group unit
+ */
+ public function testClassHierarchy()
+ {
+ $facet = new DateHistogram('dateHist1');
+ $this->assertInstanceOf('Elastica\Facet\Histogram', $facet);
+ $this->assertInstanceOf('Elastica\Facet\AbstractFacet', $facet);
+ unset($facet);
+ }
+
+ /**
+ * @group functional
+ */
+ public function testQuery()
+ {
+ $client = $this->_getClient();
+ $index = $client->getIndex('test');
+ $index->create(array(), true);
+ $type = $index->getType('helloworld');
+
+ $mapping = new Mapping($type, array(
+ 'name' => array('type' => 'string', 'store' => 'no'),
+ 'dtmPosted' => array('type' => 'date', 'store' => 'no', 'format' => 'yyyy-MM-dd HH:mm:ss'),
+ ));
+ $type->setMapping($mapping);
+
+ $doc = new Document(1, array('name' => 'nicolas ruflin', 'dtmPosted' => '2011-06-23 21:53:00'));
+ $type->addDocument($doc);
+ $doc = new Document(2, array('name' => 'raul martinez jr', 'dtmPosted' => '2011-06-23 09:53:00'));
+ $type->addDocument($doc);
+ $doc = new Document(3, array('name' => 'rachelle clemente', 'dtmPosted' => '2011-07-08 08:53:00'));
+ $type->addDocument($doc);
+ $doc = new Document(4, array('name' => 'elastica search', 'dtmPosted' => '2011-07-08 01:53:00'));
+ $type->addDocument($doc);
+
+ $facet = new DateHistogram('dateHist1');
+ $facet->setInterval('day');
+ $facet->setField('dtmPosted');
+
+ $query = new Query();
+ $query->addFacet($facet);
+ $query->setQuery(new MatchAll());
+ $index->refresh();
+
+ $response = $type->search($query);
+ $facets = $response->getFacets();
+
+ $this->assertEquals(4, $response->getTotalHits());
+ $this->assertEquals(2, count($facets['dateHist1']['entries']));
+ }
+
+ /**
+ * @group functional
+ */
+ public function testFactor()
+ {
+ $client = $this->_getClient();
+ $index = $client->getIndex('test');
+ $index->create(array(), true);
+ $type = $index->getType('helloworld');
+
+ $mapping = new Mapping($type, array(
+ 'name' => array('type' => 'string', 'store' => 'no'),
+ 'dtmPosted' => array('type' => 'long', 'store' => 'no'),
+ ));
+ $type->setMapping($mapping);
+
+ $doc = new Document(1, array('name' => 'nicolas ruflin', 'dtmPosted' => 1308865980));
+ $type->addDocument($doc);
+ $doc = new Document(2, array('name' => 'raul martinez jr', 'dtmPosted' => 1308822780));
+ $type->addDocument($doc);
+ $doc = new Document(3, array('name' => 'rachelle clemente', 'dtmPosted' => 1310115180));
+ $type->addDocument($doc);
+ $doc = new Document(4, array('name' => 'elastica search', 'dtmPosted' => 1310089980));
+ $type->addDocument($doc);
+
+ $facet = new DateHistogram('dateHist1');
+ $facet->setInterval('day');
+ $facet->setField('dtmPosted');
+ $facet->setFactor(1000);
+
+ $query = new Query();
+ $query->addFacet($facet);
+ $query->setQuery(new MatchAll());
+ $index->refresh();
+
+ $response = $type->search($query);
+ $facets = $response->getFacets();
+
+ $this->assertEquals(4, $response->getTotalHits());
+ $this->assertEquals(2, count($facets['dateHist1']['entries']));
+ }
+}
diff --git a/vendor/ruflin/elastica/test/lib/Elastica/Test/Facet/FilterTest.php b/vendor/ruflin/elastica/test/lib/Elastica/Test/Facet/FilterTest.php
new file mode 100644
index 00000000..622923fe
--- /dev/null
+++ b/vendor/ruflin/elastica/test/lib/Elastica/Test/Facet/FilterTest.php
@@ -0,0 +1,42 @@
+<?php
+namespace Elastica\Test\Facet;
+
+use Elastica\Document;
+use Elastica\Facet\Filter;
+use Elastica\Filter\Term;
+use Elastica\Query;
+use Elastica\Test\Base as BaseTest;
+
+class FilterTest extends BaseTest
+{
+ /**
+ * @group functional
+ */
+ public function testFilter()
+ {
+ $client = $this->_getClient();
+ $index = $client->getIndex('test');
+ $index->create(array(), true);
+ $type = $index->getType('helloworld');
+
+ $type->addDocument(new Document(1, array('color' => 'red')));
+ $type->addDocument(new Document(2, array('color' => 'green')));
+ $type->addDocument(new Document(3, array('color' => 'blue')));
+
+ $index->refresh();
+
+ $filter = new Term(array('color' => 'red'));
+
+ $facet = new Filter('test');
+ $facet->setFilter($filter);
+
+ $query = new Query();
+ $query->addFacet($facet);
+
+ $resultSet = $type->search($query);
+
+ $facets = $resultSet->getFacets();
+
+ $this->assertEquals(1, $facets['test']['count']);
+ }
+}
diff --git a/vendor/ruflin/elastica/test/lib/Elastica/Test/Facet/GeoClusterTest.php b/vendor/ruflin/elastica/test/lib/Elastica/Test/Facet/GeoClusterTest.php
new file mode 100644
index 00000000..f771ac32
--- /dev/null
+++ b/vendor/ruflin/elastica/test/lib/Elastica/Test/Facet/GeoClusterTest.php
@@ -0,0 +1,57 @@
+<?php
+namespace Elastica\Test\Facet;
+
+use Elastica\Document;
+use Elastica\Facet\GeoCluster;
+use Elastica\Query;
+use Elastica\Test\Base as BaseTest;
+use Elastica\Type\Mapping;
+
+class GeoClusterTest extends BaseTest
+{
+ /**
+ * @group functional
+ */
+ public function testQuery()
+ {
+ $client = $this->_getClient();
+ $nodes = $client->getCluster()->getNodes();
+ if (!$nodes[0]->getInfo()->hasPlugin('geocluster-facet')) {
+ $this->markTestSkipped('geocluster-facet plugin not installed');
+ }
+
+ $index = $this->_createIndex();
+ $type = $index->getType('testQuery');
+ $geoField = 'location';
+
+ $type->setMapping(new Mapping($type, array(
+ $geoField => array('type' => 'geo_point', 'lat_lon' => true),
+ )));
+
+ $doc = new Document(1, array('name' => 'item1', 'location' => array(20, 20)));
+ $type->addDocument($doc);
+
+ $doc = new Document(2, array('name' => 'item2', 'location' => array(20, 20)));
+ $type->addDocument($doc);
+
+ $doc = new Document(3, array('name' => 'item3', 'location' => array(20, 20)));
+ $type->addDocument($doc);
+
+ $index->refresh();
+
+ $facet = new GeoCluster('clusters');
+ $facet
+ ->setField($geoField)
+ ->setFactor(1)
+ ->setShowIds(false);
+ $query = new Query();
+ $query->setFacets(array($facet));
+
+ $response = $type->search($query);
+ $facets = $response->getFacets();
+
+ $this->assertEquals(1, count($facets['clusters']['clusters']));
+
+ $index->delete();
+ }
+}
diff --git a/vendor/ruflin/elastica/test/lib/Elastica/Test/Facet/QueryTest.php b/vendor/ruflin/elastica/test/lib/Elastica/Test/Facet/QueryTest.php
new file mode 100644
index 00000000..8e0231aa
--- /dev/null
+++ b/vendor/ruflin/elastica/test/lib/Elastica/Test/Facet/QueryTest.php
@@ -0,0 +1,42 @@
+<?php
+namespace Elastica\Test\Facet;
+
+use Elastica\Document;
+use Elastica\Facet\Query as FacetQuery;
+use Elastica\Query;
+use Elastica\Query\Term;
+use Elastica\Test\Base as BaseTest;
+
+class QueryTest extends BaseTest
+{
+ /**
+ * @group functional
+ */
+ public function testFilter()
+ {
+ $client = $this->_getClient();
+ $index = $client->getIndex('test');
+ $index->create(array(), true);
+ $type = $index->getType('helloworld');
+
+ $type->addDocument(new Document(1, array('color' => 'red')));
+ $type->addDocument(new Document(2, array('color' => 'green')));
+ $type->addDocument(new Document(3, array('color' => 'blue')));
+
+ $index->refresh();
+
+ $termQuery = new Term(array('color' => 'red'));
+
+ $facet = new FacetQuery('test');
+ $facet->setQuery($termQuery);
+
+ $query = new Query();
+ $query->addFacet($facet);
+
+ $resultSet = $type->search($query);
+
+ $facets = $resultSet->getFacets();
+
+ $this->assertEquals(1, $facets['test']['count']);
+ }
+}
diff --git a/vendor/ruflin/elastica/test/lib/Elastica/Test/Facet/StatisticalTest.php b/vendor/ruflin/elastica/test/lib/Elastica/Test/Facet/StatisticalTest.php
new file mode 100644
index 00000000..dc374289
--- /dev/null
+++ b/vendor/ruflin/elastica/test/lib/Elastica/Test/Facet/StatisticalTest.php
@@ -0,0 +1,82 @@
+<?php
+namespace Elastica\Test\Facet;
+
+use Elastica\Document;
+use Elastica\Facet\Statistical;
+use Elastica\Query;
+use Elastica\Query\MatchAll;
+use Elastica\Test\Base as BaseTest;
+
+/**
+ * @todo Add test for Statistical with setScript
+ */
+class StatisticalTest extends BaseTest
+{
+ /**
+ * @group functional
+ */
+ public function testStatisticalWithSetField()
+ {
+ $client = $this->_getClient();
+ $index = $client->getIndex('test');
+ $index->create(array(), true);
+ $type = $index->getType('helloworld');
+
+ $doc = new Document(1, array('price' => 10));
+ $type->addDocument($doc);
+ $doc = new Document(2, array('price' => 35));
+ $type->addDocument($doc);
+ $doc = new Document(2, array('price' => 45));
+ $type->addDocument($doc);
+
+ $facet = new Statistical('stats');
+ $facet->setField('price');
+
+ $query = new Query();
+ $query->addFacet($facet);
+ $query->setQuery(new MatchAll());
+
+ $index->refresh();
+
+ $response = $type->search($query);
+ $facets = $response->getFacets();
+
+ $this->assertEquals(55, $facets['stats']['total']);
+ $this->assertEquals(10, $facets['stats']['min']);
+ $this->assertEquals(45, $facets['stats']['max']);
+ }
+
+ /**
+ * @group functional
+ */
+ public function testStatisticalWithSetFields()
+ {
+ $client = $this->_getClient();
+ $index = $client->getIndex('test');
+ $index->create(array(), true);
+ $type = $index->getType('helloworld');
+
+ $doc = new Document(1, array('price' => 10, 'price2' => 20));
+ $type->addDocument($doc);
+ $doc = new Document(2, array('price' => 35, 'price2' => 70));
+ $type->addDocument($doc);
+ $doc = new Document(2, array('price' => 45, 'price2' => 90));
+ $type->addDocument($doc);
+
+ $facet = new Statistical('stats');
+ $facet->setFields(array('price', 'price2'));
+
+ $query = new Query();
+ $query->addFacet($facet);
+ $query->setQuery(new MatchAll());
+
+ $index->refresh();
+
+ $response = $type->search($query);
+ $facets = $response->getFacets();
+
+ $this->assertEquals(165, $facets['stats']['total']);
+ $this->assertEquals(10, $facets['stats']['min']);
+ $this->assertEquals(90, $facets['stats']['max']);
+ }
+}
diff --git a/vendor/ruflin/elastica/test/lib/Elastica/Test/Facet/TermsStatsTest.php b/vendor/ruflin/elastica/test/lib/Elastica/Test/Facet/TermsStatsTest.php
new file mode 100644
index 00000000..e3377930
--- /dev/null
+++ b/vendor/ruflin/elastica/test/lib/Elastica/Test/Facet/TermsStatsTest.php
@@ -0,0 +1,113 @@
+<?php
+namespace Elastica\Test\Facet;
+
+use Elastica\Document;
+use Elastica\Facet\TermsStats;
+use Elastica\Query;
+use Elastica\Query\MatchAll;
+use Elastica\Test\Base as BaseTest;
+
+class TermsStatsTest extends BaseTest
+{
+ /**
+ * @group functional
+ */
+ public function testOrder()
+ {
+ $client = $this->_getClient();
+ $index = $client->getIndex('test');
+ $index->create(array(), true);
+ $type = $index->getType('helloworld');
+
+ $doc = new Document(1, array('name' => 'tom', 'paid' => 7));
+ $type->addDocument($doc);
+ $doc = new Document(2, array('name' => 'tom', 'paid' => 2));
+ $type->addDocument($doc);
+ $doc = new Document(3, array('name' => 'tom', 'paid' => 5));
+ $type->addDocument($doc);
+ $doc = new Document(4, array('name' => 'mike', 'paid' => 13));
+ $type->addDocument($doc);
+ $doc = new Document(5, array('name' => 'mike', 'paid' => 1));
+ $type->addDocument($doc);
+ $doc = new Document(6, array('name' => 'mike', 'paid' => 15));
+ $type->addDocument($doc);
+
+ $facet = new TermsStats('test');
+ $facet->setKeyField('name');
+ $facet->setValueField('paid');
+ $facet->setOrder('reverse_total');
+
+ $query = new Query();
+ $query->addFacet($facet);
+ $query->setQuery(new MatchAll());
+
+ $index->refresh();
+
+ $response = $type->search($query);
+ $facets = $response->getFacets();
+
+ $this->assertEquals(14, $facets[ 'test' ][ 'terms' ][0]['total']);
+ $this->assertEquals(29, $facets[ 'test' ][ 'terms' ][1]['total']);
+ }
+
+ /**
+ * @group functional
+ */
+ public function testQuery()
+ {
+ $client = $this->_getClient();
+ $index = $client->getIndex('test');
+ $index->create(array(), true);
+ $type = $index->getType('helloworld');
+
+ $doc = new Document(1, array('name' => 'tom', 'paid' => 7));
+ $type->addDocument($doc);
+ $doc = new Document(2, array('name' => 'tom', 'paid' => 2));
+ $type->addDocument($doc);
+ $doc = new Document(3, array('name' => 'tom', 'paid' => 5));
+ $type->addDocument($doc);
+ $doc = new Document(4, array('name' => 'mike', 'paid' => 13));
+ $type->addDocument($doc);
+ $doc = new Document(5, array('name' => 'mike', 'paid' => 1));
+ $type->addDocument($doc);
+ $doc = new Document(6, array('name' => 'mike', 'paid' => 15));
+ $type->addDocument($doc);
+
+ $facet = new TermsStats('test');
+ $facet->setKeyField('name');
+ $facet->setValueField('paid');
+
+ $query = new Query();
+ $query->addFacet($facet);
+ $query->setQuery(new MatchAll());
+
+ $index->refresh();
+
+ $response = $type->search($query);
+ $facets = $response->getFacets();
+
+ $this->assertEquals(2, count($facets[ 'test' ][ 'terms' ]));
+ foreach ($facets[ 'test' ][ 'terms' ] as $facet) {
+ if ($facet[ 'term' ] === 'tom') {
+ $this->assertEquals(14, $facet[ 'total' ]);
+ }
+ if ($facet[ 'term' ] === 'mike') {
+ $this->assertEquals(29, $facet[ 'total' ]);
+ }
+ }
+ }
+
+ /**
+ * @group unit
+ */
+ public function testSetSize()
+ {
+ $facet = new TermsStats('test');
+ $facet->setSize(100);
+
+ $data = $facet->toArray();
+
+ $this->assertArrayHasKey('size', $data['terms_stats']);
+ $this->assertEquals(100, $data['terms_stats']['size']);
+ }
+}
diff --git a/vendor/ruflin/elastica/test/lib/Elastica/Test/Facet/TermsTest.php b/vendor/ruflin/elastica/test/lib/Elastica/Test/Facet/TermsTest.php
new file mode 100644
index 00000000..f4c95796
--- /dev/null
+++ b/vendor/ruflin/elastica/test/lib/Elastica/Test/Facet/TermsTest.php
@@ -0,0 +1,74 @@
+<?php
+namespace Elastica\Test\Facet;
+
+use Elastica\Document;
+use Elastica\Facet\Terms;
+use Elastica\Query;
+use Elastica\Query\MatchAll;
+use Elastica\Test\Base as BaseTest;
+
+class TermsTest extends BaseTest
+{
+ /**
+ * @group functional
+ */
+ public function testQuery()
+ {
+ $client = $this->_getClient();
+ $index = $client->getIndex('test');
+ $index->create(array(), true);
+ $type = $index->getType('helloworld');
+
+ $doc = new Document(1, array('name' => 'nicolas ruflin'));
+ $type->addDocument($doc);
+ $doc = new Document(2, array('name' => 'ruflin test'));
+ $type->addDocument($doc);
+ $doc = new Document(2, array('name' => 'nicolas helloworld'));
+ $type->addDocument($doc);
+
+ $facet = new Terms('test');
+ $facet->setField('name');
+
+ $query = new Query();
+ $query->addFacet($facet);
+ $query->setQuery(new MatchAll());
+
+ $index->refresh();
+
+ $response = $type->search($query);
+ $facets = $response->getFacets();
+
+ $this->assertEquals(3, count($facets['test']['terms']));
+ }
+
+ /**
+ * @group functional
+ */
+ public function testFacetScript()
+ {
+ $client = $this->_getClient();
+ $index = $client->getIndex('test');
+ $index->create(array(), true);
+ $type = $index->getType('helloworld');
+
+ $doc = new Document(1, array('name' => 'rodolfo', 'last_name' => 'moraes'));
+ $type->addDocument($doc);
+ $doc = new Document(2, array('name' => 'jose', 'last_name' => 'honjoya'));
+ $type->addDocument($doc);
+
+ $facet = new Terms('test');
+ $facet->setField('name');
+ $facet->setScript('term + " "+doc["last_name"].value');
+
+ $query = new Query();
+ $query->addFacet($facet);
+ $query->setQuery(new MatchAll());
+
+ $index->refresh();
+
+ $response = $type->search($query);
+ $facets = $response->getFacets();
+
+ $this->assertEquals(2, count($facets['test']['terms']));
+ }
+}
diff --git a/vendor/ruflin/elastica/test/lib/Elastica/Test/Filter/AbstractTest.php b/vendor/ruflin/elastica/test/lib/Elastica/Test/Filter/AbstractTest.php
new file mode 100644
index 00000000..3ba64dd1
--- /dev/null
+++ b/vendor/ruflin/elastica/test/lib/Elastica/Test/Filter/AbstractTest.php
@@ -0,0 +1,81 @@
+<?php
+namespace Elastica\Test\Filter;
+
+use Elastica\Test\Base as BaseTest;
+
+class AbstractTest extends BaseTest
+{
+ /**
+ * @group unit
+ */
+ public function testSetCached()
+ {
+ $stubFilter = $this->getStub();
+
+ $stubFilter->setCached(true);
+ $arrayFilter = current($stubFilter->toArray());
+ $this->assertTrue($arrayFilter['_cache']);
+
+ $stubFilter->setCached(false);
+ $arrayFilter = current($stubFilter->toArray());
+ $this->assertFalse($arrayFilter['_cache']);
+ }
+
+ /**
+ * @group unit
+ */
+ public function testSetCachedDefaultValue()
+ {
+ $stubFilter = $this->getStub();
+
+ $stubFilter->setCached();
+ $arrayFilter = current($stubFilter->toArray());
+ $this->assertTrue($arrayFilter['_cache']);
+ }
+
+ /**
+ * @group unit
+ */
+ public function testSetCacheKey()
+ {
+ $stubFilter = $this->getStub();
+
+ $cacheKey = 'myCacheKey';
+
+ $stubFilter->setCacheKey($cacheKey);
+ $arrayFilter = current($stubFilter->toArray());
+ $this->assertEquals($cacheKey, $arrayFilter['_cache_key']);
+ }
+
+ /**
+ * @group unit
+ * @expectedException \Elastica\Exception\InvalidException
+ */
+ public function testSetCacheKeyEmptyKey()
+ {
+ $stubFilter = $this->getStub();
+
+ $cacheKey = '';
+
+ $stubFilter->setCacheKey($cacheKey);
+ }
+
+ /**
+ * @group unit
+ */
+ public function testSetName()
+ {
+ $stubFilter = $this->getStub();
+
+ $name = 'myFilter';
+
+ $stubFilter->setName($name);
+ $arrayFilter = current($stubFilter->toArray());
+ $this->assertEquals($name, $arrayFilter['_name']);
+ }
+
+ private function getStub()
+ {
+ return $this->getMockForAbstractClass('Elastica\Filter\AbstractFilter');
+ }
+}
diff --git a/vendor/ruflin/elastica/test/lib/Elastica/Test/Filter/BoolAndTest.php b/vendor/ruflin/elastica/test/lib/Elastica/Test/Filter/BoolAndTest.php
new file mode 100644
index 00000000..a8f47633
--- /dev/null
+++ b/vendor/ruflin/elastica/test/lib/Elastica/Test/Filter/BoolAndTest.php
@@ -0,0 +1,86 @@
+<?php
+namespace Elastica\Test\Filter;
+
+use Elastica\Document;
+use Elastica\Filter\BoolAnd;
+use Elastica\Filter\Ids;
+use Elastica\Test\Base as BaseTest;
+
+class BoolAndTest extends BaseTest
+{
+ /**
+ * @group unit
+ */
+ public function testToArray()
+ {
+ $and = new BoolAnd();
+ $this->assertEquals(array('and' => array()), $and->toArray());
+
+ $idsFilter = new Ids();
+ $idsFilter->setIds(12);
+
+ $and->addFilter($idsFilter);
+ $and->addFilter($idsFilter);
+
+ $expectedArray = array(
+ 'and' => array(
+ $idsFilter->toArray(),
+ $idsFilter->toArray(),
+ ),
+ );
+
+ $this->assertEquals($expectedArray, $and->toArray());
+ }
+
+ /**
+ * @group functional
+ */
+ public function testSetCache()
+ {
+ $client = $this->_getClient();
+ $index = $client->getIndex('test');
+ $index->create(array(), true);
+ $type = $index->getType('test');
+
+ $type->addDocuments(array(
+ new Document(1, array('name' => 'hello world')),
+ new Document(2, array('name' => 'nicolas ruflin')),
+ new Document(3, array('name' => 'ruflin')),
+ ));
+
+ $and = new BoolAnd();
+
+ $idsFilter1 = new Ids();
+ $idsFilter1->setIds(1);
+
+ $idsFilter2 = new Ids();
+ $idsFilter2->setIds(1);
+
+ $and->addFilter($idsFilter1);
+ $and->addFilter($idsFilter2);
+
+ $index->refresh();
+ $and->setCached(true);
+
+ $resultSet = $type->search($and);
+
+ $this->assertEquals(1, $resultSet->count());
+ }
+
+ /**
+ * @group unit
+ */
+ public function testConstruct()
+ {
+ $ids1 = new Ids('foo', array(1, 2));
+ $ids2 = new Ids('bar', array(3, 4));
+
+ $and1 = new BoolAnd(array($ids1, $ids2));
+
+ $and2 = new BoolAnd();
+ $and2->addFilter($ids1);
+ $and2->addFilter($ids2);
+
+ $this->assertEquals($and1->toArray(), $and2->toArray());
+ }
+}
diff --git a/vendor/ruflin/elastica/test/lib/Elastica/Test/Filter/BoolFilterTest.php b/vendor/ruflin/elastica/test/lib/Elastica/Test/Filter/BoolFilterTest.php
new file mode 100644
index 00000000..ec7728af
--- /dev/null
+++ b/vendor/ruflin/elastica/test/lib/Elastica/Test/Filter/BoolFilterTest.php
@@ -0,0 +1,200 @@
+<?php
+namespace Elastica\Test\Filter;
+
+use Elastica\Document;
+use Elastica\Filter\BoolFilter;
+use Elastica\Filter\Ids;
+use Elastica\Filter\Term;
+use Elastica\Filter\Terms;
+use Elastica\Query;
+use Elastica\Test\Base as BaseTest;
+
+class BoolFilterTest extends BaseTest
+{
+ /**
+ * @return array
+ */
+ public function getTestToArrayData()
+ {
+ $out = array();
+
+ // case #0
+ $mainBool = new BoolFilter();
+
+ $idsFilter1 = new Ids();
+ $idsFilter1->setIds(1);
+ $idsFilter2 = new Ids();
+ $idsFilter2->setIds(2);
+ $idsFilter3 = new Ids();
+ $idsFilter3->setIds(3);
+
+ $childBool = new BoolFilter();
+ $childBool->addShould(array($idsFilter1, $idsFilter2));
+ $mainBool->addShould(array($childBool, $idsFilter3));
+
+ $expectedArray = array(
+ 'bool' => array(
+ 'should' => array(
+ array(
+ array(
+ 'bool' => array(
+ 'should' => array(
+ array(
+ $idsFilter1->toArray(),
+ $idsFilter2->toArray(),
+ ),
+ ),
+ ),
+ ),
+ $idsFilter3->toArray(),
+ ),
+ ),
+ ),
+ );
+ $out[] = array($mainBool, $expectedArray);
+
+ // case #1 _cache parameter should be supported
+ $bool = new BoolFilter();
+ $terms = new Terms('field1', array('value1', 'value2'));
+ $termsNot = new Terms('field2', array('value1', 'value2'));
+ $bool->addMust($terms);
+ $bool->addMustNot($termsNot);
+ $bool->setCached(true);
+ $bool->setCacheKey('my-cache-key');
+ $expected = array(
+ 'bool' => array(
+ 'must' => array(
+ $terms->toArray(),
+ ),
+ 'must_not' => array(
+ $termsNot->toArray(),
+ ),
+ '_cache' => true,
+ '_cache_key' => 'my-cache-key',
+ ),
+ );
+ $out[] = array($bool, $expected);
+
+ return $out;
+ }
+
+ /**
+ * @group unit
+ * @dataProvider getTestToArrayData()
+ *
+ * @param Bool $bool
+ * @param array $expectedArray
+ */
+ public function testToArray(BoolFilter $bool, $expectedArray)
+ {
+ $this->assertEquals($expectedArray, $bool->toArray());
+ }
+
+ /**
+ * @group functional
+ */
+ public function testBoolFilter()
+ {
+ $index = $this->_createIndex();
+ $type = $index->getType('book');
+
+ //index some test data
+ $type->addDocuments(array(
+ new Document(1, array('author' => 'Michael Shermer', 'title' => 'The Believing Brain', 'publisher' => 'Robinson')),
+ new Document(2, array('author' => 'Jared Diamond', 'title' => 'Guns, Germs and Steel', 'publisher' => 'Vintage')),
+ new Document(3, array('author' => 'Jared Diamond', 'title' => 'Collapse', 'publisher' => 'Penguin')),
+ new Document(4, array('author' => 'Richard Dawkins', 'title' => 'The Selfish Gene', 'publisher' => 'OUP Oxford')),
+ new Document(5, array('author' => 'Anthony Burges', 'title' => 'A Clockwork Orange', 'publisher' => 'Penguin')),
+ ));
+
+ $index->refresh();
+
+ //use the terms lookup feature to query for some data
+ //build query
+ //must
+ // should
+ // author = jared
+ // author = richard
+ // must_not
+ // publisher = penguin
+
+ //construct the query
+ $query = new Query();
+ $mainBoolFilter = new BoolFilter();
+ $shouldFilter = new BoolFilter();
+ $authorFilter1 = new Term();
+ $authorFilter1->setTerm('author', 'jared');
+ $authorFilter2 = new Term();
+ $authorFilter2->setTerm('author', 'richard');
+ $shouldFilter->addShould(array($authorFilter1, $authorFilter2));
+
+ $mustNotFilter = new BoolFilter();
+ $publisherFilter = new Term();
+ $publisherFilter->setTerm('publisher', 'penguin');
+ $mustNotFilter->addMustNot($publisherFilter);
+
+ $mainBoolFilter->addMust(array($shouldFilter, $mustNotFilter));
+ $query->setPostFilter($mainBoolFilter);
+ //execute the query
+ $results = $index->search($query);
+
+ //check the number of results
+ $this->assertEquals($results->count(), 2, 'Bool filter with child Bool filters: number of results check');
+
+ //count compare the id's
+ $ids = array();
+ /** @var \Elastica\Result $result **/
+ foreach ($results as $result) {
+ $ids[] = $result->getId();
+ }
+ $this->assertEquals($ids, array('2', '4'), 'Bool filter with child Bool filters: result ID check');
+
+ $index->delete();
+ }
+
+ /**
+ * @group unit
+ * @expectedException \Elastica\Exception\InvalidException
+ */
+ public function testAddMustInvalidException()
+ {
+ $filter = new BoolFilter();
+ $filter->addMust('fail!');
+ }
+
+ /**
+ * @group unit
+ * @expectedException \Elastica\Exception\InvalidException
+ */
+ public function testAddMustNotInvalidException()
+ {
+ $filter = new BoolFilter();
+ $filter->addMustNot('fail!');
+ }
+
+ /**
+ * @group unit
+ * @expectedException \Elastica\Exception\InvalidException
+ */
+ public function testAddShouldInvalidException()
+ {
+ $filter = new BoolFilter();
+ $filter->addShould('fail!');
+ }
+
+ /**
+ * Small unit test to check if also the old object name works.
+ *
+ * @group unit
+ * @expectedException \Elastica\Exception\InvalidException
+ */
+ public function testOldObject()
+ {
+ if (version_compare(phpversion(), 7, '>=')) {
+ self::markTestSkipped('These objects are not supported in PHP 7');
+ }
+
+ $filter = new \Elastica\Filter\Bool();
+ $filter->addShould('fail!');
+ }
+}
diff --git a/vendor/ruflin/elastica/test/lib/Elastica/Test/Filter/BoolNotTest.php b/vendor/ruflin/elastica/test/lib/Elastica/Test/Filter/BoolNotTest.php
new file mode 100644
index 00000000..75461496
--- /dev/null
+++ b/vendor/ruflin/elastica/test/lib/Elastica/Test/Filter/BoolNotTest.php
@@ -0,0 +1,27 @@
+<?php
+namespace Elastica\Test\Filter;
+
+use Elastica\Filter\BoolNot;
+use Elastica\Filter\Ids;
+use Elastica\Test\Base as BaseTest;
+
+class BoolNotTest extends BaseTest
+{
+ /**
+ * @group unit
+ */
+ public function testToArray()
+ {
+ $idsFilter = new Ids();
+ $idsFilter->setIds(12);
+ $filter = new BoolNot($idsFilter);
+
+ $expectedArray = array(
+ 'not' => array(
+ 'filter' => $idsFilter->toArray(),
+ ),
+ );
+
+ $this->assertEquals($expectedArray, $filter->toArray());
+ }
+}
diff --git a/vendor/ruflin/elastica/test/lib/Elastica/Test/Filter/BoolOrTest.php b/vendor/ruflin/elastica/test/lib/Elastica/Test/Filter/BoolOrTest.php
new file mode 100644
index 00000000..6462d1fa
--- /dev/null
+++ b/vendor/ruflin/elastica/test/lib/Elastica/Test/Filter/BoolOrTest.php
@@ -0,0 +1,90 @@
+<?php
+namespace Elastica\Test\Filter;
+
+use Elastica\Document;
+use Elastica\Filter\BoolOr;
+use Elastica\Filter\Ids;
+use Elastica\Test\Base as BaseTest;
+
+class BoolOrTest extends BaseTest
+{
+ /**
+ * @group unit
+ */
+ public function testAddFilter()
+ {
+ $filter = $this->getMockForAbstractClass('Elastica\Filter\AbstractFilter');
+ $orFilter = new BoolOr();
+ $returnValue = $orFilter->addFilter($filter);
+ $this->assertInstanceOf('Elastica\Filter\BoolOr', $returnValue);
+ }
+
+ /**
+ * @group unit
+ */
+ public function testToArray()
+ {
+ $orFilter = new BoolOr();
+
+ $filter1 = new Ids();
+ $filter1->setIds('1');
+
+ $filter2 = new Ids();
+ $filter2->setIds('2');
+
+ $orFilter->addFilter($filter1);
+ $orFilter->addFilter($filter2);
+
+ $expectedArray = array(
+ 'or' => array(
+ $filter1->toArray(),
+ $filter2->toArray(),
+ ),
+ );
+
+ $this->assertEquals($expectedArray, $orFilter->toArray());
+ }
+
+ /**
+ * @group unit
+ */
+ public function testConstruct()
+ {
+ $ids1 = new Ids('foo', array(1, 2));
+ $ids2 = new Ids('bar', array(3, 4));
+
+ $and1 = new BoolOr(array($ids1, $ids2));
+
+ $and2 = new BoolOr();
+ $and2->addFilter($ids1);
+ $and2->addFilter($ids2);
+
+ $this->assertEquals($and1->toArray(), $and2->toArray());
+ }
+
+ /**
+ * @group functional
+ */
+ public function testOrFilter()
+ {
+ $index = $this->_createIndex();
+ $type = $index->getType('test');
+
+ $doc1 = new Document('', array('categoryId' => 1));
+ $doc2 = new Document('', array('categoryId' => 2));
+ $doc3 = new Document('', array('categoryId' => 3));
+
+ $type->addDocument($doc1);
+ $type->addDocument($doc2);
+ $type->addDocument($doc3);
+
+ $index->refresh();
+
+ $boolOr = new \Elastica\Filter\BoolOr();
+ $boolOr->addFilter(new \Elastica\Filter\Term(array('categoryId' => '1')));
+ $boolOr->addFilter(new \Elastica\Filter\Term(array('categoryId' => '2')));
+
+ $resultSet = $type->search($boolOr);
+ $this->assertEquals(2, $resultSet->count());
+ }
+}
diff --git a/vendor/ruflin/elastica/test/lib/Elastica/Test/Filter/ExistsTest.php b/vendor/ruflin/elastica/test/lib/Elastica/Test/Filter/ExistsTest.php
new file mode 100644
index 00000000..25afa724
--- /dev/null
+++ b/vendor/ruflin/elastica/test/lib/Elastica/Test/Filter/ExistsTest.php
@@ -0,0 +1,36 @@
+<?php
+namespace Elastica\Test\Filter;
+
+use Elastica\Filter\Exists;
+use Elastica\Test\Base as BaseTest;
+
+class ExistsTest extends BaseTest
+{
+ /**
+ * @group unit
+ */
+ public function testToArray()
+ {
+ $field = 'test';
+ $filter = new Exists($field);
+
+ $expectedArray = array('exists' => array('field' => $field));
+ $this->assertEquals($expectedArray, $filter->toArray());
+ }
+
+ /**
+ * @group unit
+ */
+ public function testSetField()
+ {
+ $field = 'test';
+ $filter = new Exists($field);
+
+ $this->assertEquals($field, $filter->getParam('field'));
+
+ $newField = 'hello world';
+ $this->assertInstanceOf('Elastica\Filter\Exists', $filter->setField($newField));
+
+ $this->assertEquals($newField, $filter->getParam('field'));
+ }
+}
diff --git a/vendor/ruflin/elastica/test/lib/Elastica/Test/Filter/GeoBoundingBoxTest.php b/vendor/ruflin/elastica/test/lib/Elastica/Test/Filter/GeoBoundingBoxTest.php
new file mode 100644
index 00000000..8fdde965
--- /dev/null
+++ b/vendor/ruflin/elastica/test/lib/Elastica/Test/Filter/GeoBoundingBoxTest.php
@@ -0,0 +1,55 @@
+<?php
+namespace Elastica\Test\Filter;
+
+use Elastica\Filter\GeoBoundingBox;
+use Elastica\Test\Base as BaseTest;
+
+class GeoBoundingBoxTest extends BaseTest
+{
+ /**
+ * @group unit
+ */
+ public function testAddCoordinates()
+ {
+ $key = 'pin.location';
+ $coords = array('40.73, -74.1', '40.01, -71.12');
+ $filter = new GeoBoundingBox($key, array('1,2', '3,4'));
+
+ $filter->addCoordinates($key, $coords);
+ $expectedArray = array('top_left' => $coords[0], 'bottom_right' => $coords[1]);
+ $this->assertEquals($expectedArray, $filter->getParam($key));
+
+ $returnValue = $filter->addCoordinates($key, $coords);
+ $this->assertInstanceOf('Elastica\Filter\GeoBoundingBox', $returnValue);
+ }
+
+ /**
+ * @group unit
+ * @expectedException \Elastica\Exception\InvalidException
+ */
+ public function testAddCoordinatesInvalidException()
+ {
+ $filter = new GeoBoundingBox('foo', array());
+ }
+
+ /**
+ * @group unit
+ */
+ public function testToArray()
+ {
+ $key = 'pin.location';
+ $coords = array('40.73, -74.1', '40.01, -71.12');
+ $filter = new GeoBoundingBox($key, $coords);
+
+ $expectedArray = array(
+ 'geo_bounding_box' => array(
+ $key => array(
+ 'top_left' => $coords[0],
+ 'bottom_right' => $coords[1],
+ ),
+ ),
+ );
+
+ $this->assertEquals($expectedArray, $filter->toArray());
+ }
+}
diff --git a/vendor/ruflin/elastica/test/lib/Elastica/Test/Filter/GeoDistanceRangeTest.php b/vendor/ruflin/elastica/test/lib/Elastica/Test/Filter/GeoDistanceRangeTest.php
new file mode 100644
index 00000000..203a45de
--- /dev/null
+++ b/vendor/ruflin/elastica/test/lib/Elastica/Test/Filter/GeoDistanceRangeTest.php
@@ -0,0 +1,220 @@
+<?php
+namespace Elastica\Test\Filter;
+
+use Elastica\Document;
+use Elastica\Filter\GeoDistanceRange;
+use Elastica\Query;
+use Elastica\Query\MatchAll;
+use Elastica\Test\Base as BaseTest;
+
+class GeoDistanceRangeTest extends BaseTest
+{
+ /**
+ * @group functional
+ */
+ public function testGeoPoint()
+ {
+ $index = $this->_createIndex();
+ $type = $index->getType('test');
+
+ // Set mapping
+ $type->setMapping(array('point' => array('type' => 'geo_point')));
+
+ // Add doc 1
+ $doc1 = new Document(1,
+ array(
+ 'name' => 'ruflin',
+ )
+ );
+
+ $doc1->addGeoPoint('point', 17, 19);
+ $type->addDocument($doc1);
+
+ // Add doc 2
+ $doc2 = new Document(2,
+ array(
+ 'name' => 'ruflin',
+ )
+ );
+
+ $doc2->addGeoPoint('point', 30, 40);
+ $type->addDocument($doc2);
+
+ $index->optimize();
+ $index->refresh();
+
+ // Only one point should be in radius
+ $query = new Query();
+ $geoFilter = new GeoDistanceRange(
+ 'point',
+ array('lat' => 30, 'lon' => 40),
+ array('from' => '0km', 'to' => '2km')
+ );
+
+ $query = new Query(new MatchAll());
+ $query->setPostFilter($geoFilter);
+ $this->assertEquals(1, $type->search($query)->count());
+
+ // Both points should be inside
+ $query = new Query();
+ $geoFilter = new GeoDistanceRange(
+ 'point',
+ array('lat' => 30, 'lon' => 40),
+ array('gte' => '0km', 'lte' => '40000km')
+ );
+ $query = new Query(new MatchAll());
+ $query->setPostFilter($geoFilter);
+ $index->refresh();
+
+ $this->assertEquals(2, $type->search($query)->count());
+ }
+
+ /**
+ * @group unit
+ * @expectedException \Elastica\Exception\InvalidException
+ */
+ public function testInvalidRange()
+ {
+ $geoFilter = new GeoDistanceRange(
+ 'point',
+ array('lat' => 30, 'lon' => 40),
+ array('invalid' => '0km', 'lte' => '40000km')
+ );
+ }
+
+ /**
+ * @group unit
+ * @dataProvider invalidLocationDataProvider
+ * @expectedException \Elastica\Exception\InvalidException
+ */
+ public function testInvalidLocation($location)
+ {
+ $geoFilter = new GeoDistanceRange(
+ 'point',
+ $location,
+ array('gt' => '0km', 'lte' => '40000km')
+ );
+ }
+
+ /**
+ * @group unit
+ * @dataProvider constructDataProvider
+ */
+ public function testConstruct($key, $location, $ranges, $expected)
+ {
+ $filter = new GeoDistanceRange($key, $location, $ranges);
+
+ $data = $filter->toArray();
+
+ $this->assertEquals($expected, $data);
+ }
+
+ public function invalidLocationDataProvider()
+ {
+ return array(
+ array(
+ array('lat' => 1.0),
+ ),
+ array(
+ array('lon' => 1.0),
+ ),
+ array(
+ array(),
+ ),
+ array(
+ new \stdClass(),
+ ),
+ array(
+ null,
+ ),
+ array(
+ true,
+ ),
+ array(
+ false,
+ ),
+ );
+ }
+
+ public function constructDataProvider()
+ {
+ return array(
+ array(
+ 'location',
+ 'u09tvqx',
+ array(
+ 'from' => '10km',
+ 'to' => '20km',
+ ),
+ array(
+ 'geo_distance_range' => array(
+ 'from' => '10km',
+ 'to' => '20km',
+ 'location' => 'u09tvqx',
+ ),
+ ),
+ ),
+ array(
+ 'location',
+ 'u09tvqx',
+ array(
+ 'to' => '20km',
+ 'include_upper' => 0,
+ 'from' => '10km',
+ 'include_lower' => 1,
+ ),
+ array(
+ 'geo_distance_range' => array(
+ 'to' => '20km',
+ 'include_upper' => false,
+ 'from' => '10km',
+ 'include_lower' => true,
+ 'location' => 'u09tvqx',
+ ),
+ ),
+ ),
+ array(
+ 'location',
+ array(
+ 'lon' => 2.35,
+ 'lat' => 48.86,
+ ),
+ array(
+ 'lte' => '20km',
+ 'gt' => '10km',
+ ),
+ array(
+ 'geo_distance_range' => array(
+ 'lte' => '20km',
+ 'gt' => '10km',
+ 'location' => array(
+ 'lat' => 48.86,
+ 'lon' => 2.35,
+ ),
+ ),
+ ),
+ ),
+ array(
+ 'location',
+ array(
+ 'lat' => 48.86,
+ 'lon' => 2.35,
+ ),
+ array(
+ 'lt' => '20km',
+ 'gte' => '10km',
+ ),
+ array(
+ 'geo_distance_range' => array(
+ 'lt' => '20km',
+ 'gte' => '10km',
+ 'location' => array(
+ 'lat' => 48.86,
+ 'lon' => 2.35,
+ ),
+ ),
+ ),
+ ),
+ );
+ }
+}
diff --git a/vendor/ruflin/elastica/test/lib/Elastica/Test/Filter/GeoDistanceTest.php b/vendor/ruflin/elastica/test/lib/Elastica/Test/Filter/GeoDistanceTest.php
new file mode 100644
index 00000000..b61b4adc
--- /dev/null
+++ b/vendor/ruflin/elastica/test/lib/Elastica/Test/Filter/GeoDistanceTest.php
@@ -0,0 +1,141 @@
+<?php
+namespace Elastica\Test\Filter;
+
+use Elastica\Document;
+use Elastica\Filter\GeoDistance;
+use Elastica\Query;
+use Elastica\Query\MatchAll;
+use Elastica\Test\Base as BaseTest;
+
+class GeoDistanceTest extends BaseTest
+{
+ /**
+ * @group functional
+ */
+ public function testGeoPoint()
+ {
+ $index = $this->_createIndex();
+
+ $type = $index->getType('test');
+
+ // Set mapping
+ $type->setMapping(array('point' => array('type' => 'geo_point')));
+
+ // Add doc 1
+ $doc1 = new Document(1,
+ array(
+ 'name' => 'ruflin',
+ )
+ );
+
+ $doc1->addGeoPoint('point', 17, 19);
+ $type->addDocument($doc1);
+
+ // Add doc 2
+ $doc2 = new Document(2,
+ array(
+ 'name' => 'ruflin',
+ )
+ );
+
+ $doc2->addGeoPoint('point', 30, 40);
+ $type->addDocument($doc2);
+
+ $index->optimize();
+ $index->refresh();
+
+ // Only one point should be in radius
+ $query = new Query();
+ $geoFilter = new GeoDistance('point', array('lat' => 30, 'lon' => 40), '1km');
+
+ $query = new Query(new MatchAll());
+ $query->setPostFilter($geoFilter);
+ $this->assertEquals(1, $type->search($query)->count());
+
+ // Both points should be inside
+ $query = new Query();
+ $geoFilter = new GeoDistance('point', array('lat' => 30, 'lon' => 40), '40000km');
+ $query = new Query(new MatchAll());
+ $query->setPostFilter($geoFilter);
+ $index->refresh();
+
+ $this->assertEquals(2, $type->search($query)->count());
+ }
+
+ /**
+ * @group unit
+ */
+ public function testConstructLatlon()
+ {
+ $key = 'location';
+ $location = array(
+ 'lat' => 48.86,
+ 'lon' => 2.35,
+ );
+ $distance = '10km';
+
+ $filter = new GeoDistance($key, $location, $distance);
+
+ $expected = array(
+ 'geo_distance' => array(
+ $key => $location,
+ 'distance' => $distance,
+ ),
+ );
+
+ $data = $filter->toArray();
+
+ $this->assertEquals($expected, $data);
+ }
+
+ /**
+ * @group unit
+ */
+ public function testConstructGeohash()
+ {
+ $key = 'location';
+ $location = 'u09tvqx';
+ $distance = '10km';
+
+ $filter = new GeoDistance($key, $location, $distance);
+
+ $expected = array(
+ 'geo_distance' => array(
+ $key => $location,
+ 'distance' => $distance,
+ ),
+ );
+
+ $data = $filter->toArray();
+
+ $this->assertEquals($expected, $data);
+ }
+
+ /**
+ * @group unit
+ */
+ public function testSetDistanceType()
+ {
+ $filter = new GeoDistance('location', array('lat' => 48.86, 'lon' => 2.35), '10km');
+ $distanceType = GeoDistance::DISTANCE_TYPE_ARC;
+ $filter->setDistanceType($distanceType);
+
+ $data = $filter->toArray();
+
+ $this->assertEquals($distanceType, $data['geo_distance']['distance_type']);
+ }
+
+ /**
+ * @group unit
+ */
+ public function testSetOptimizeBbox()
+ {
+ $filter = new GeoDistance('location', array('lat' => 48.86, 'lon' => 2.35), '10km');
+ $optimizeBbox = GeoDistance::OPTIMIZE_BBOX_MEMORY;
+ $filter->setOptimizeBbox($optimizeBbox);
+
+ $data = $filter->toArray();
+
+ $this->assertEquals($optimizeBbox, $data['geo_distance']['optimize_bbox']);
+ }
+}
diff --git a/vendor/ruflin/elastica/test/lib/Elastica/Test/Filter/GeoPolygonTest.php b/vendor/ruflin/elastica/test/lib/Elastica/Test/Filter/GeoPolygonTest.php
new file mode 100644
index 00000000..b56f73b0
--- /dev/null
+++ b/vendor/ruflin/elastica/test/lib/Elastica/Test/Filter/GeoPolygonTest.php
@@ -0,0 +1,65 @@
+<?php
+namespace Elastica\Test\Filter;
+
+use Elastica\Document;
+use Elastica\Filter\GeoPolygon;
+use Elastica\Query;
+use Elastica\Query\MatchAll;
+use Elastica\Test\Base as BaseTest;
+
+class GeoPolygonTest extends BaseTest
+{
+ /**
+ * @group functional
+ */
+ public function testGeoPoint()
+ {
+ $index = $this->_createIndex();
+
+ $type = $index->getType('test');
+
+ // Set mapping
+ $type->setMapping(array('location' => array('type' => 'geo_point')));
+
+ // Add doc 1
+ $doc1 = new Document(1,
+ array(
+ 'name' => 'ruflin',
+ )
+ );
+
+ $doc1->addGeoPoint('location', 17, 19);
+ $type->addDocument($doc1);
+
+ // Add doc 2
+ $doc2 = new Document(2,
+ array(
+ 'name' => 'ruflin',
+ )
+ );
+
+ $doc2->addGeoPoint('location', 30, 40);
+ $type->addDocument($doc2);
+
+ $index->refresh();
+
+ // Only one point should be in polygon
+ $query = new Query();
+ $points = array(array(16, 16), array(16, 20), array(20, 20), array(20, 16), array(16, 16));
+ $geoFilter = new GeoPolygon('location', $points);
+
+ $query = new Query(new MatchAll());
+ $query->setPostFilter($geoFilter);
+ $this->assertEquals(1, $type->search($query)->count());
+
+ // Both points should be inside
+ $query = new Query();
+ $points = array(array(16, 16), array(16, 40), array(40, 40), array(40, 16), array(16, 16));
+ $geoFilter = new GeoPolygon('location', $points);
+
+ $query = new Query(new MatchAll());
+ $query->setPostFilter($geoFilter);
+
+ $this->assertEquals(2, $type->search($query)->count());
+ }
+}
diff --git a/vendor/ruflin/elastica/test/lib/Elastica/Test/Filter/GeoShapePreIndexedTest.php b/vendor/ruflin/elastica/test/lib/Elastica/Test/Filter/GeoShapePreIndexedTest.php
new file mode 100644
index 00000000..96453527
--- /dev/null
+++ b/vendor/ruflin/elastica/test/lib/Elastica/Test/Filter/GeoShapePreIndexedTest.php
@@ -0,0 +1,102 @@
+<?php
+namespace Elastica\Test\Filter;
+
+use Elastica\Filter\AbstractGeoShape;
+use Elastica\Filter\GeoShapePreIndexed;
+use Elastica\Query\Filtered;
+use Elastica\Query\MatchAll;
+use Elastica\Test\Base as BaseTest;
+
+class GeoShapePreIndexedTest extends BaseTest
+{
+ /**
+ * @group functional
+ */
+ public function testGeoProvided()
+ {
+ $index = $this->_createIndex();
+ $indexName = $index->getName();
+ $type = $index->getType('type');
+ $otherType = $index->getType('other_type');
+
+ // create mapping
+ $mapping = new \Elastica\Type\Mapping($type, array(
+ 'location' => array(
+ 'type' => 'geo_shape',
+ ),
+ ));
+ $type->setMapping($mapping);
+
+ // create other type mapping
+ $otherMapping = new \Elastica\Type\Mapping($type, array(
+ 'location' => array(
+ 'type' => 'geo_shape',
+ ),
+ ));
+ $otherType->setMapping($otherMapping);
+
+ // add type docs
+ $type->addDocument(new \Elastica\Document('1', array(
+ 'location' => array(
+ 'type' => 'envelope',
+ 'coordinates' => array(
+ array(0.0, 50.0),
+ array(50.0, 0.0),
+ ),
+ ),
+ )));
+
+ // add other type docs
+ $otherType->addDocument(new \Elastica\Document('2', array(
+ 'location' => array(
+ 'type' => 'envelope',
+ 'coordinates' => array(
+ array(25.0, 75.0),
+ array(75.0, 25.0),
+ ),
+ ),
+ )));
+
+ $index->optimize();
+ $index->refresh();
+
+ $gsp = new GeoShapePreIndexed(
+ 'location', '1', 'type', $indexName, 'location'
+ );
+ $gsp->setRelation(AbstractGeoShape::RELATION_INTERSECT);
+
+ $expected = array(
+ 'geo_shape' => array(
+ 'location' => array(
+ 'indexed_shape' => array(
+ 'id' => '1',
+ 'type' => 'type',
+ 'index' => $indexName,
+ 'path' => 'location',
+ ),
+ 'relation' => $gsp->getRelation(),
+ ),
+ ),
+ );
+
+ $this->assertEquals($expected, $gsp->toArray());
+
+ $query = new Filtered(new MatchAll(), $gsp);
+ $results = $index->getType('type')->search($query);
+
+ $this->assertEquals(1, $results->count());
+
+ $index->delete();
+ }
+
+ /**
+ * @group unit
+ */
+ public function testSetRelation()
+ {
+ $gsp = new GeoShapePreIndexed('location', '1', 'type', 'indexName', 'location');
+ $gsp->setRelation(AbstractGeoShape::RELATION_INTERSECT);
+ $this->assertEquals(AbstractGeoShape::RELATION_INTERSECT, $gsp->getRelation());
+ $this->assertInstanceOf('Elastica\Filter\GeoShapePreIndexed', $gsp->setRelation(AbstractGeoShape::RELATION_INTERSECT));
+ }
+}
diff --git a/vendor/ruflin/elastica/test/lib/Elastica/Test/Filter/GeoShapeProvidedTest.php b/vendor/ruflin/elastica/test/lib/Elastica/Test/Filter/GeoShapeProvidedTest.php
new file mode 100644
index 00000000..d631e44e
--- /dev/null
+++ b/vendor/ruflin/elastica/test/lib/Elastica/Test/Filter/GeoShapeProvidedTest.php
@@ -0,0 +1,103 @@
+<?php
+namespace Elastica\Test\Filter;
+
+use Elastica\Document;
+use Elastica\Filter\AbstractGeoShape;
+use Elastica\Filter\GeoShapeProvided;
+use Elastica\Query\Filtered;
+use Elastica\Query\MatchAll;
+use Elastica\Test\Base as BaseTest;
+use Elastica\Type\Mapping;
+
+class GeoShapeProvidedTest extends BaseTest
+{
+ /**
+ * @group functional
+ */
+ public function testConstructEnvelope()
+ {
+ $index = $this->_createIndex();
+ $type = $index->getType('test');
+
+ // create mapping
+ $mapping = new Mapping($type, array(
+ 'location' => array(
+ 'type' => 'geo_shape',
+ ),
+ ));
+ $type->setMapping($mapping);
+
+ // add docs
+ $type->addDocument(new Document(1, array(
+ 'location' => array(
+ 'type' => 'envelope',
+ 'coordinates' => array(
+ array(-50.0, 50.0),
+ array(50.0, -50.0),
+ ),
+ ),
+ )));
+
+ $index->optimize();
+ $index->refresh();
+
+ $envelope = array(
+ array(25.0, 75.0),
+ array(75.0, 25.0),
+ );
+ $gsp = new GeoShapeProvided('location', $envelope);
+
+ $expected = array(
+ 'geo_shape' => array(
+ 'location' => array(
+ 'shape' => array(
+ 'type' => GeoShapeProvided::TYPE_ENVELOPE,
+ 'coordinates' => $envelope,
+ ),
+ 'relation' => AbstractGeoShape::RELATION_INTERSECT,
+ ),
+ ),
+ );
+
+ $this->assertEquals($expected, $gsp->toArray());
+
+ $query = new Filtered(new MatchAll(), $gsp);
+ $results = $type->search($query);
+
+ $this->assertEquals(1, $results->count());
+ }
+
+ /**
+ * @group unit
+ */
+ public function testConstructPolygon()
+ {
+ $polygon = array(array(102.0, 2.0), array(103.0, 2.0), array(103.0, 3.0), array(103.0, 3.0), array(102.0, 2.0));
+ $gsp = new GeoShapeProvided('location', $polygon, GeoShapeProvided::TYPE_POLYGON);
+
+ $expected = array(
+ 'geo_shape' => array(
+ 'location' => array(
+ 'shape' => array(
+ 'type' => GeoShapeProvided::TYPE_POLYGON,
+ 'coordinates' => $polygon,
+ ),
+ 'relation' => $gsp->getRelation(),
+ ),
+ ),
+ );
+
+ $this->assertEquals($expected, $gsp->toArray());
+ }
+
+ /**
+ * @group unit
+ */
+ public function testSetRelation()
+ {
+ $gsp = new GeoShapeProvided('location', array(array(25.0, 75.0), array(75.0, 25.0)));
+ $gsp->setRelation(AbstractGeoShape::RELATION_INTERSECT);
+ $this->assertEquals(AbstractGeoShape::RELATION_INTERSECT, $gsp->getRelation());
+ $this->assertInstanceOf('Elastica\Filter\GeoShapeProvided', $gsp->setRelation(AbstractGeoShape::RELATION_INTERSECT));
+ }
+}
diff --git a/vendor/ruflin/elastica/test/lib/Elastica/Test/Filter/GeohashCellTest.php b/vendor/ruflin/elastica/test/lib/Elastica/Test/Filter/GeohashCellTest.php
new file mode 100644
index 00000000..7ef0d04f
--- /dev/null
+++ b/vendor/ruflin/elastica/test/lib/Elastica/Test/Filter/GeohashCellTest.php
@@ -0,0 +1,68 @@
+<?php
+namespace Elastica\Test\Filter;
+
+use Elastica\Document;
+use Elastica\Filter\GeohashCell;
+use Elastica\Query;
+use Elastica\Test\Base as BaseTest;
+use Elastica\Type\Mapping;
+
+class GeohashCellTest extends BaseTest
+{
+ /**
+ * @group unit
+ */
+ public function testToArray()
+ {
+ $filter = new GeohashCell('pin', array('lat' => 37.789018, 'lon' => -122.391506), '50m');
+ $expected = array(
+ 'geohash_cell' => array(
+ 'pin' => array(
+ 'lat' => 37.789018,
+ 'lon' => -122.391506,
+ ),
+ 'precision' => '50m',
+ 'neighbors' => false,
+ ),
+ );
+ $this->assertEquals($expected, $filter->toArray());
+ }
+
+ /**
+ * @group functional
+ */
+ public function testFilter()
+ {
+ $index = $this->_createIndex();
+ $type = $index->getType('test');
+ $mapping = new Mapping($type, array(
+ 'pin' => array(
+ 'type' => 'geo_point',
+ 'geohash' => true,
+ 'geohash_prefix' => true,
+ ),
+ ));
+ $type->setMapping($mapping);
+
+ $type->addDocument(new Document(1, array('pin' => '9q8yyzm0zpw8')));
+ $type->addDocument(new Document(2, array('pin' => '9mudgb0yued0')));
+ $index->refresh();
+
+ $filter = new GeohashCell('pin', array('lat' => 32.828326, 'lon' => -117.255854));
+ $query = new Query();
+ $query->setPostFilter($filter);
+ $results = $type->search($query);
+
+ $this->assertEquals(1, $results->count());
+
+ //test precision parameter
+ $filter = new GeohashCell('pin', '9', 1);
+ $query = new Query();
+ $query->setPostFilter($filter);
+ $results = $type->search($query);
+
+ $this->assertEquals(2, $results->count());
+
+ $index->delete();
+ }
+}
diff --git a/vendor/ruflin/elastica/test/lib/Elastica/Test/Filter/HasChildTest.php b/vendor/ruflin/elastica/test/lib/Elastica/Test/Filter/HasChildTest.php
new file mode 100644
index 00000000..00af1def
--- /dev/null
+++ b/vendor/ruflin/elastica/test/lib/Elastica/Test/Filter/HasChildTest.php
@@ -0,0 +1,213 @@
+<?php
+namespace Elastica\Test\Filter;
+
+use Elastica\Document;
+use Elastica\Filter\HasChild;
+use Elastica\Query\MatchAll;
+use Elastica\Test\Base as BaseTest;
+
+class HasChildTest extends BaseTest
+{
+ /**
+ * @group unit
+ */
+ public function testToArray()
+ {
+ $q = new MatchAll();
+
+ $type = 'test';
+
+ $filter = new HasChild($q, $type);
+
+ $expectedArray = array(
+ 'has_child' => array(
+ 'query' => $q->toArray(),
+ 'type' => $type,
+ ),
+ );
+
+ $this->assertEquals($expectedArray, $filter->toArray());
+ }
+
+ /**
+ * @group functional
+ */
+ public function testSetType()
+ {
+ $index = $this->prepareSearchData();
+
+ $filter = new HasChild(new MatchAll(), 'type_name');
+ $this->assertEquals('type_name', $filter->getParam('type'));
+
+ $filter->setType('new_type_name');
+ $this->assertEquals('new_type_name', $filter->getParam('type'));
+
+ $type = $index->getType('foo');
+ $filter = new HasChild(new MatchAll(), $type);
+ $this->assertEquals('foo', $filter->getParam('type'));
+
+ $type = $index->getType('bar');
+ $filter->setType($type);
+ $this->assertEquals('bar', $filter->getParam('type'));
+
+ $returnValue = $filter->setType('last');
+ $this->assertInstanceOf('Elastica\Filter\HasChild', $returnValue);
+ }
+
+ /**
+ * @group unit
+ */
+ public function testSetMinimumChildrenCount()
+ {
+ $query = new MatchAll();
+ $filter = new HasChild($query, 'test');
+
+ $filter->setMinimumChildrenCount(2);
+ $this->assertEquals(2, $filter->getParam('min_children'));
+
+ $returnValue = $filter->setMinimumChildrenCount(2);
+ $this->assertInstanceOf('Elastica\Filter\HasChild', $returnValue);
+ }
+
+ /**
+ * @group unit
+ */
+ public function testSetMaximumChildrenCount()
+ {
+ $query = new MatchAll();
+ $filter = new HasChild($query, 'test');
+
+ $filter->setMaximumChildrenCount(10);
+ $this->assertEquals(10, $filter->getParam('max_children'));
+
+ $returnValue = $filter->setMaximumChildrenCount(10);
+ $this->assertInstanceOf('Elastica\Filter\HasChild', $returnValue);
+ }
+
+ /**
+ * @group unit
+ */
+ public function testFilterInsideHasChild()
+ {
+ $f = new \Elastica\Filter\MatchAll();
+
+ $type = 'test';
+
+ $filter = new HasChild($f, $type);
+
+ $expectedArray = array(
+ 'has_child' => array(
+ 'filter' => $f->toArray(),
+ 'type' => $type,
+ ),
+ );
+
+ $this->assertEquals($expectedArray, $filter->toArray());
+ }
+
+ /**
+ * @group functional
+ */
+ public function testFilterInsideHasChildSearch()
+ {
+ $index = $this->prepareSearchData();
+
+ $f = new \Elastica\Filter\Term();
+ $f->setTerm('user', 'child1');
+ $filter = new HasChild($f, 'child');
+
+ $searchQuery = new \Elastica\Query();
+ $searchQuery->setPostFilter($filter);
+ $searchResults = $index->search($searchQuery);
+
+ $this->assertEquals(1, $searchResults->count());
+
+ $result = $searchResults->current()->getData();
+ $expected = array('id' => 'parent1', 'user' => 'parent1', 'email' => 'parent1@test.com');
+
+ $this->assertEquals($expected, $result);
+ }
+
+ /**
+ * @group functional
+ */
+ public function testQueryInsideHasChildSearch()
+ {
+ $index = $this->prepareSearchData();
+
+ $f = new \Elastica\Query\Term();
+ $f->setTerm('user', 'child1');
+ $filter = new HasChild($f, 'child');
+
+ $searchQuery = new \Elastica\Query();
+ $searchQuery->setPostFilter($filter);
+ $searchResults = $index->search($searchQuery);
+
+ $this->assertEquals(1, $searchResults->count());
+
+ $result = $searchResults->current()->getData();
+ $expected = array('id' => 'parent1', 'user' => 'parent1', 'email' => 'parent1@test.com');
+
+ $this->assertEquals($expected, $result);
+ }
+
+ /**
+ * @group functional
+ */
+ public function testTypeInsideHasChildSearch()
+ {
+ $index = $this->prepareSearchData();
+
+ $f = new \Elastica\Query\Match();
+ $f->setField('alt.name', 'testname');
+ $filter = new HasChild($f, 'child');
+
+ $searchQuery = new \Elastica\Query();
+ $searchQuery->setPostFilter($filter);
+ $searchResults = $index->search($searchQuery);
+
+ $this->assertEquals(1, $searchResults->count());
+
+ $result = $searchResults->current()->getData();
+ $expected = array('id' => 'parent2', 'user' => 'parent2', 'email' => 'parent2@test.com');
+
+ $this->assertEquals($expected, $result);
+ }
+
+ private function prepareSearchData()
+ {
+ $client = $this->_getClient();
+ $index = $client->getIndex('has_child_test');
+ $index->create(array(), true);
+
+ $parentType = $index->getType('parent');
+
+ $childType = $index->getType('child');
+ $childMapping = new \Elastica\Type\Mapping($childType);
+ $childMapping->setParent('parent');
+ $childMapping->send();
+
+ $altType = $index->getType('alt');
+ $altDoc = new Document('alt1', array('name' => 'altname'));
+ $altType->addDocument($altDoc);
+
+ $parent1 = new Document('parent1', array('id' => 'parent1', 'user' => 'parent1', 'email' => 'parent1@test.com'));
+ $parentType->addDocument($parent1);
+ $parent2 = new Document('parent2', array('id' => 'parent2', 'user' => 'parent2', 'email' => 'parent2@test.com'));
+ $parentType->addDocument($parent2);
+
+ $child1 = new Document('child1', array('id' => 'child1', 'user' => 'child1', 'email' => 'child1@test.com'));
+ $child1->setParent('parent1');
+ $childType->addDocument($child1);
+ $child2 = new Document('child2', array('id' => 'child2', 'user' => 'child2', 'email' => 'child2@test.com'));
+ $child2->setParent('parent2');
+ $childType->addDocument($child2);
+ $child3 = new Document('child3', array('id' => 'child3', 'user' => 'child3', 'email' => 'child3@test.com', 'alt' => array(array('name' => 'testname'))));
+ $child3->setParent('parent2');
+ $childType->addDocument($child3);
+
+ $index->refresh();
+
+ return $index;
+ }
+}
diff --git a/vendor/ruflin/elastica/test/lib/Elastica/Test/Filter/HasParentTest.php b/vendor/ruflin/elastica/test/lib/Elastica/Test/Filter/HasParentTest.php
new file mode 100644
index 00000000..50143dda
--- /dev/null
+++ b/vendor/ruflin/elastica/test/lib/Elastica/Test/Filter/HasParentTest.php
@@ -0,0 +1,153 @@
+<?php
+namespace Elastica\Test\Filter;
+
+use Elastica\Document;
+use Elastica\Filter\HasParent;
+use Elastica\Query\MatchAll;
+use Elastica\Test\Base as BaseTest;
+
+class HasParentTest extends BaseTest
+{
+ /**
+ * @group unit
+ */
+ public function testToArray()
+ {
+ $q = new MatchAll();
+
+ $type = 'test';
+
+ $filter = new HasParent($q, $type);
+
+ $expectedArray = array(
+ 'has_parent' => array(
+ 'query' => $q->toArray(),
+ 'type' => $type,
+ ),
+ );
+
+ $this->assertEquals($expectedArray, $filter->toArray());
+ }
+
+ /**
+ * @group functional
+ */
+ public function testSetType()
+ {
+ $index = $this->prepareSearchData();
+
+ $filter = new HasParent(new MatchAll(), 'type_name');
+ $this->assertEquals('type_name', $filter->getParam('type'));
+
+ $filter->setType('new_type_name');
+ $this->assertEquals('new_type_name', $filter->getParam('type'));
+
+ $type = $index->getType('foo');
+ $filter = new HasParent(new MatchAll(), $type);
+ $this->assertEquals('foo', $filter->getParam('type'));
+
+ $type = $index->getType('bar');
+ $filter->setType($type);
+ $this->assertEquals('bar', $filter->getParam('type'));
+
+ $returnValue = $filter->setType('last');
+ $this->assertInstanceOf('Elastica\Filter\HasParent', $returnValue);
+ }
+
+ /**
+ * @group unit
+ */
+ public function testFilterInsideHasParent()
+ {
+ $f = new \Elastica\Filter\MatchAll();
+
+ $type = 'test';
+
+ $filter = new HasParent($f, $type);
+
+ $expectedArray = array(
+ 'has_parent' => array(
+ 'filter' => $f->toArray(),
+ 'type' => $type,
+ ),
+ );
+
+ $this->assertEquals($expectedArray, $filter->toArray());
+ }
+
+ /**
+ * @group functional
+ */
+ public function testFilterInsideHasParentSearch()
+ {
+ $index = $this->prepareSearchData();
+
+ $f = new \Elastica\Filter\Term();
+ $f->setTerm('user', 'parent1');
+ $filter = new HasParent($f, 'parent');
+
+ $searchQuery = new \Elastica\Query();
+ $searchQuery->setPostFilter($filter);
+ $searchResults = $index->search($searchQuery);
+
+ $this->assertEquals(1, $searchResults->count());
+
+ $result = $searchResults->current()->getData();
+ $expected = array('id' => 'child1', 'user' => 'child1', 'email' => 'child1@test.com');
+
+ $this->assertEquals($expected, $result);
+ }
+
+ /**
+ * @group functional
+ */
+ public function testQueryInsideHasParentSearch()
+ {
+ $index = $this->prepareSearchData();
+
+ $f = new \Elastica\Query\Term();
+ $f->setTerm('user', 'parent1');
+ $filter = new HasParent($f, 'parent');
+
+ $searchQuery = new \Elastica\Query();
+ $searchQuery->setPostFilter($filter);
+ $searchResults = $index->search($searchQuery);
+
+ $this->assertEquals(1, $searchResults->count());
+
+ $result = $searchResults->current()->getData();
+ $expected = array('id' => 'child1', 'user' => 'child1', 'email' => 'child1@test.com');
+
+ $this->assertEquals($expected, $result);
+ }
+
+ private function prepareSearchData()
+ {
+ $client = $this->_getClient();
+ $index = $client->getIndex('has_parent_test');
+ $index->create(array(), true);
+
+ $parentType = $index->getType('parent');
+
+ $childType = $index->getType('child');
+ $childMapping = new \Elastica\Type\Mapping($childType);
+ $childMapping->setParent('parent');
+ $childMapping->send();
+
+ $parent1 = new Document('parent1', array('id' => 'parent1', 'user' => 'parent1', 'email' => 'parent1@test.com'));
+ $parentType->addDocument($parent1);
+ $parent2 = new Document('parent2', array('id' => 'parent2', 'user' => 'parent2', 'email' => 'parent2@test.com'));
+ $parentType->addDocument($parent2);
+
+ $child1 = new Document('child1', array('id' => 'child1', 'user' => 'child1', 'email' => 'child1@test.com'));
+ $child1->setParent('parent1');
+ $childType->addDocument($child1);
+ $child2 = new Document('child2', array('id' => 'child2', 'user' => 'child2', 'email' => 'child2@test.com'));
+ $child2->setParent('parent2');
+ $childType->addDocument($child2);
+
+ $index->refresh();
+
+ return $index;
+ }
+}
diff --git a/vendor/ruflin/elastica/test/lib/Elastica/Test/Filter/IdsTest.php b/vendor/ruflin/elastica/test/lib/Elastica/Test/Filter/IdsTest.php
new file mode 100644
index 00000000..8395f39a
--- /dev/null
+++ b/vendor/ruflin/elastica/test/lib/Elastica/Test/Filter/IdsTest.php
@@ -0,0 +1,244 @@
+<?php
+namespace Elastica\Test\Filter;
+
+use Elastica\Document;
+use Elastica\Filter\Ids;
+use Elastica\Filter\Type;
+use Elastica\Query;
+use Elastica\Test\Base as BaseTest;
+
+class IdsTest extends BaseTest
+{
+ protected function _getIndexForTest()
+ {
+ $index = $this->_createIndex();
+
+ // Add documents to first type
+ $docs = array();
+ for ($i = 1; $i < 100; $i++) {
+ $docs[] = new Document($i, array('name' => 'ruflin'));
+ }
+ $index->getType('helloworld1')->addDocuments($docs);
+
+ // Add documents to second type
+ $docs = array();
+ for ($i = 1; $i < 100; $i++) {
+ $docs[] = new Document($i, array('name' => 'ruflin'));
+ }
+ // This is a special id that will only be in the second type
+ $docs[] = new Document(101, array('name' => 'ruflin'));
+ $index->getType('helloworld2')->addDocuments($docs);
+
+ $index->optimize();
+ $index->refresh();
+
+ return $index;
+ }
+
+ protected function _getTypeForTest()
+ {
+ return $this->_getIndexForTest()->getType('helloworld1');
+ }
+
+ /**
+ * @group functional
+ */
+ public function testSetIdsSearchSingle()
+ {
+ $filter = new Ids();
+ $filter->setIds('1');
+
+ $query = Query::create($filter);
+ $resultSet = $this->_getTypeForTest()->search($query);
+
+ $this->assertEquals(1, $resultSet->count());
+ }
+
+ /**
+ * @group functional
+ */
+ public function testSetIdsSearchArray()
+ {
+ $filter = new Ids();
+ $filter->setIds(array(1, 7, 13));
+
+ $query = Query::create($filter);
+ $resultSet = $this->_getTypeForTest()->search($query);
+
+ $this->assertEquals(3, $resultSet->count());
+ }
+
+ /**
+ * @group functional
+ */
+ public function testAddIdsSearchSingle()
+ {
+ $filter = new Ids();
+ $filter->addId('39');
+
+ $query = Query::create($filter);
+ $resultSet = $this->_getTypeForTest()->search($query);
+
+ $this->assertEquals(1, $resultSet->count());
+ }
+
+ /**
+ * @group functional
+ */
+ public function testAddIdsSearchSingleNotInType()
+ {
+ $filter = new Ids();
+ $filter->addId('39');
+
+ // Add an ID that is not in the index
+ $filter->addId(104);
+
+ $query = Query::create($filter);
+ $resultSet = $this->_getTypeForTest()->search($query);
+
+ $this->assertEquals(1, $resultSet->count());
+ }
+
+ /**
+ * @group functional
+ */
+ public function testComboIdsSearchArray()
+ {
+ $filter = new Ids();
+ $filter->setIds(array(1, 7, 13));
+ $filter->addId('39');
+
+ $query = Query::create($filter);
+ $resultSet = $this->_getTypeForTest()->search($query);
+
+ $this->assertEquals(4, $resultSet->count());
+ }
+
+ /**
+ * @group functional
+ */
+ public function testSetTypeSingleSearchSingle()
+ {
+ $filter = new Ids();
+ $filter->setIds('1');
+ $filter->setType('helloworld1');
+
+ $query = Query::create($filter);
+ $resultSet = $this->_getIndexForTest()->search($query);
+
+ $this->assertEquals(1, $resultSet->count());
+ }
+
+ /**
+ * @group functional
+ */
+ public function testSetTypeSingleSearchArray()
+ {
+ $filter = new Ids();
+ $filter->setIds(array('1', '2'));
+ $filter->setType('helloworld1');
+
+ $query = Query::create($filter);
+ $resultSet = $this->_getIndexForTest()->search($query);
+
+ $this->assertEquals(2, $resultSet->count());
+ }
+
+ /**
+ * @group functional
+ */
+ public function testSetTypeSingleSearchSingleDocInOtherType()
+ {
+ $filter = new Ids();
+
+ // Doc 4 is in the second type...
+ $filter->setIds('101');
+ $filter->setType('helloworld1');
+
+ $query = Query::create($filter);
+ $resultSet = $this->_getTypeForTest()->search($query);
+
+ // ...therefore 0 results should be returned
+ $this->assertEquals(0, $resultSet->count());
+ }
+
+ /**
+ * @group functional
+ */
+ public function testSetTypeSingleSearchArrayDocInOtherType()
+ {
+ $filter = new Ids();
+
+ // Doc 4 is in the second type...
+ $filter->setIds(array('1', '101'));
+ $filter->setType('helloworld1');
+
+ $query = Query::create($filter);
+ $resultSet = $this->_getTypeForTest()->search($query);
+
+ // ...therefore only 1 result should be returned
+ $this->assertEquals(1, $resultSet->count());
+ }
+
+ /**
+ * @group functional
+ */
+ public function testSetTypeArraySearchArray()
+ {
+ $filter = new Ids();
+ $filter->setIds(array('1', '4'));
+ $filter->setType(array('helloworld1', 'helloworld2'));
+
+ $query = Query::create($filter);
+ $resultSet = $this->_getIndexForTest()->search($query);
+
+ $this->assertEquals(4, $resultSet->count());
+ }
+
+ /**
+ * @group functional
+ */
+ public function testSetTypeArraySearchSingle()
+ {
+ $filter = new Ids();
+ $filter->setIds('4');
+ $filter->setType(array('helloworld1', 'helloworld2'));
+
+ $query = Query::create($filter);
+ $resultSet = $this->_getIndexForTest()->search($query);
+
+ $this->assertEquals(2, $resultSet->count());
+ }
+
+ /**
+ * @group unit
+ */
+ public function testFilterTypeAndTypeCollision()
+ {
+ // This test ensures that Elastica\Type and Elastica\Filter\Type
+ // do not collide when used together, which at one point
+ // happened because of a use statement in Elastica\Filter\Ids
+ // Test goal is to make sure a Fatal Error is not triggered
+ $filterType = new Type();
+ $filter = new Ids();
+ }
+
+ /**
+ * @group unit
+ */
+ public function testAddType()
+ {
+ $type = $this->_getClient()->getIndex('indexname')->getType('typename');
+
+ $filter = new Ids();
+
+ $filter->addType('foo');
+ $this->assertEquals(array('foo'), $filter->getParam('type'));
+
+ $filter->addType($type);
+ $this->assertEquals(array('foo', $type->getName()), $filter->getParam('type'));
+
+ $returnValue = $filter->addType('bar');
+ $this->assertInstanceOf('Elastica\Filter\Ids', $returnValue);
+ }
+}
diff --git a/vendor/ruflin/elastica/test/lib/Elastica/Test/Filter/IndicesTest.php b/vendor/ruflin/elastica/test/lib/Elastica/Test/Filter/IndicesTest.php
new file mode 100644
index 00000000..bc78aa6b
--- /dev/null
+++ b/vendor/ruflin/elastica/test/lib/Elastica/Test/Filter/IndicesTest.php
@@ -0,0 +1,125 @@
+<?php
+namespace Elastica\Test\Filter;
+
+use Elastica\Document;
+use Elastica\Filter\BoolNot;
+use Elastica\Filter\Indices;
+use Elastica\Filter\Term;
+use Elastica\Index;
+use Elastica\Query;
+use Elastica\Test\Base as BaseTest;
+
+class IndicesTest extends BaseTest
+{
+ /**
+ * @group unit
+ */
+ public function testToArray()
+ {
+ $expected = array(
+ 'indices' => array(
+ 'indices' => array('index1', 'index2'),
+ 'filter' => array(
+ 'term' => array('tag' => 'wow'),
+ ),
+ 'no_match_filter' => array(
+ 'term' => array('tag' => 'such filter'),
+ ),
+ ),
+ );
+ $filter = new Indices(new Term(array('tag' => 'wow')), array('index1', 'index2'));
+ $filter->setNoMatchFilter(new Term(array('tag' => 'such filter')));
+ $this->assertEquals($expected, $filter->toArray());
+ }
+
+ /**
+ * @group functional
+ */
+ public function testIndicesFilter()
+ {
+ $docs = array(
+ new Document(1, array('color' => 'blue')),
+ new Document(2, array('color' => 'green')),
+ new Document(3, array('color' => 'blue')),
+ new Document(4, array('color' => 'yellow')),
+ );
+
+ $index1 = $this->_createIndex();
+ $index1->addAlias('indices_filter');
+ $index1->getType('test')->addDocuments($docs);
+ $index1->refresh();
+
+ $index2 = $this->_createIndex();
+ $index2->addAlias('indices_filter');
+ $index2->getType('test')->addDocuments($docs);
+ $index2->refresh();
+
+ $filter = new Indices(new BoolNot(new Term(array('color' => 'blue'))), array($index1->getName()));
+ $filter->setNoMatchFilter(new BoolNot(new Term(array('color' => 'yellow'))));
+ $query = new Query();
+ $query->setPostFilter($filter);
+
+ // search over the alias
+ $index = $this->_getClient()->getIndex('indices_filter');
+ $results = $index->search($query);
+
+ // ensure that the proper docs have been filtered out for each index
+ $this->assertEquals(5, $results->count());
+ foreach ($results->getResults() as $result) {
+ $data = $result->getData();
+ $color = $data['color'];
+ if ($result->getIndex() === $index1->getName()) {
+ $this->assertNotEquals('blue', $color);
+ } else {
+ $this->assertNotEquals('yellow', $color);
+ }
+ }
+ }
+
+ /**
+ * @group unit
+ */
+ public function testSetIndices()
+ {
+ $client = $this->_getClient();
+ $index1 = $client->getIndex('index1');
+ $index2 = $client->getIndex('index2');
+
+ $indices = array('one', 'two');
+ $filter = new Indices(new Term(array('color' => 'blue')), $indices);
+ $this->assertEquals($indices, $filter->getParam('indices'));
+
+ $indices[] = 'three';
+ $filter->setIndices($indices);
+ $this->assertEquals($indices, $filter->getParam('indices'));
+
+ $filter->setIndices(array($index1, $index2));
+ $expected = array($index1->getName(), $index2->getName());
+ $this->assertEquals($expected, $filter->getParam('indices'));
+
+ $returnValue = $filter->setIndices($indices);
+ $this->assertInstanceOf('Elastica\Filter\Indices', $returnValue);
+ }
+
+ /**
+ * @group unit
+ */
+ public function testAddIndex()
+ {
+ $client = $this->_getClient();
+ $index = $client->getIndex('someindex');
+
+ $filter = new Indices(new Term(array('color' => 'blue')), array());
+
+ $filter->addIndex($index);
+ $expected = array($index->getName());
+ $this->assertEquals($expected, $filter->getParam('indices'));
+
+ $filter->addIndex('foo');
+ $expected = array($index->getName(), 'foo');
+ $this->assertEquals($expected, $filter->getParam('indices'));
+
+ $returnValue = $filter->addIndex('bar');
+ $this->assertInstanceOf('Elastica\Filter\Indices', $returnValue);
+ }
+}
diff --git a/vendor/ruflin/elastica/test/lib/Elastica/Test/Filter/LimitTest.php b/vendor/ruflin/elastica/test/lib/Elastica/Test/Filter/LimitTest.php
new file mode 100644
index 00000000..0cdfee39
--- /dev/null
+++ b/vendor/ruflin/elastica/test/lib/Elastica/Test/Filter/LimitTest.php
@@ -0,0 +1,34 @@
+<?php
+namespace Elastica\Test\Filter;
+
+use Elastica\Filter\Limit;
+use Elastica\Test\Base as BaseTest;
+
+class LimitTest extends BaseTest
+{
+ /**
+ * @group unit
+ */
+ public function testSetType()
+ {
+ $filter = new Limit(10);
+ $this->assertEquals(10, $filter->getParam('value'));
+
+ $this->assertInstanceOf('Elastica\Filter\Limit', $filter->setLimit(20));
+ $this->assertEquals(20, $filter->getParam('value'));
+ }
+
+ /**
+ * @group unit
+ */
+ public function testToArray()
+ {
+ $filter = new Limit(15);
+
+ $expectedArray = array(
+ 'limit' => array('value' => 15),
+ );
+
+ $this->assertEquals($expectedArray, $filter->toArray());
+ }
+}
diff --git a/vendor/ruflin/elastica/test/lib/Elastica/Test/Filter/MatchAllTest.php b/vendor/ruflin/elastica/test/lib/Elastica/Test/Filter/MatchAllTest.php
new file mode 100644
index 00000000..9bfd511f
--- /dev/null
+++ b/vendor/ruflin/elastica/test/lib/Elastica/Test/Filter/MatchAllTest.php
@@ -0,0 +1,20 @@
+<?php
+namespace Elastica\Test\Filter;
+
+use Elastica\Filter\MatchAll;
+use Elastica\Test\Base as BaseTest;
+
+class MatchAllTest extends BaseTest
+{
+ /**
+ * @group unit
+ */
+ public function testToArray()
+ {
+ $filter = new MatchAll();
+
+ $expectedArray = array('match_all' => new \stdClass());
+
+ $this->assertEquals($expectedArray, $filter->toArray());
+ }
+}
diff --git a/vendor/ruflin/elastica/test/lib/Elastica/Test/Filter/MissingTest.php b/vendor/ruflin/elastica/test/lib/Elastica/Test/Filter/MissingTest.php
new file mode 100644
index 00000000..f87df790
--- /dev/null
+++ b/vendor/ruflin/elastica/test/lib/Elastica/Test/Filter/MissingTest.php
@@ -0,0 +1,78 @@
+<?php
+namespace Elastica\Test\Filter;
+
+use Elastica\Filter\Missing;
+use Elastica\Test\Base as BaseTest;
+
+class MissingTest extends BaseTest
+{
+ /**
+ * @group unit
+ */
+ public function testToArray()
+ {
+ $filter = new Missing('field_name');
+ $expectedArray = array('missing' => array('field' => 'field_name'));
+ $this->assertEquals($expectedArray, $filter->toArray());
+
+ $filter = new Missing('field_name');
+ $filter->setExistence(true);
+ $expectedArray = array('missing' => array('field' => 'field_name', 'existence' => true));
+ $this->assertEquals($expectedArray, $filter->toArray());
+
+ $filter = new Missing('field_name');
+ $filter->setNullValue(true);
+ $expectedArray = array('missing' => array('field' => 'field_name', 'null_value' => true));
+ $this->assertEquals($expectedArray, $filter->toArray());
+ }
+
+ /**
+ * @group unit
+ */
+ public function testSetField()
+ {
+ $filter = new Missing('field_name');
+
+ $this->assertEquals('field_name', $filter->getParam('field'));
+
+ $filter->setField('new_field_name');
+ $this->assertEquals('new_field_name', $filter->getParam('field'));
+
+ $returnValue = $filter->setField('very_new_field_name');
+ $this->assertInstanceOf('Elastica\Filter\Missing', $returnValue);
+ }
+
+ /**
+ * @group unit
+ */
+ public function testSetExistence()
+ {
+ $filter = new Missing('field_name');
+
+ $filter->setExistence(true);
+ $this->assertTrue($filter->getParam('existence'));
+
+ $filter->setExistence(false);
+ $this->assertFalse($filter->getParam('existence'));
+
+ $returnValue = $filter->setExistence(true);
+ $this->assertInstanceOf('Elastica\Filter\Missing', $returnValue);
+ }
+
+ /**
+ * @group unit
+ */
+ public function testSetNullValue()
+ {
+ $filter = new Missing('field_name');
+
+ $filter->setNullValue(true);
+ $this->assertTrue($filter->getParam('null_value'));
+
+ $filter->setNullValue(false);
+ $this->assertFalse($filter->getParam('null_value'));
+
+ $returnValue = $filter->setNullValue(true);
+ $this->assertInstanceOf('Elastica\Filter\Missing', $returnValue);
+ }
+}
diff --git a/vendor/ruflin/elastica/test/lib/Elastica/Test/Filter/MultiTest.php b/vendor/ruflin/elastica/test/lib/Elastica/Test/Filter/MultiTest.php
new file mode 100644
index 00000000..cc8a56e8
--- /dev/null
+++ b/vendor/ruflin/elastica/test/lib/Elastica/Test/Filter/MultiTest.php
@@ -0,0 +1,109 @@
+<?php
+namespace Elastica\Test\Filter;
+
+use Elastica\Filter\AbstractMulti;
+use Elastica\Filter\MatchAll;
+use Elastica\Test\Base as BaseTest;
+
+class AbstractMultiTest extends BaseTest
+{
+ /**
+ * @group unit
+ */
+ public function testConstruct()
+ {
+ $stub = $this->getStub();
+
+ $this->assertEmpty($stub->getFilters());
+ }
+
+ /**
+ * @group unit
+ */
+ public function testAddFilter()
+ {
+ $stub = $this->getStub();
+
+ $filter = new MatchAll();
+ $stub->addFilter($filter);
+
+ $expected = array(
+ $filter->toArray(),
+ );
+
+ $this->assertEquals($expected, $stub->getFilters());
+ }
+
+ /**
+ * @group unit
+ */
+ public function testSetFilters()
+ {
+ $stub = $this->getStub();
+
+ $filter = new MatchAll();
+ $stub->setFilters(array($filter));
+
+ $expected = array(
+ $filter->toArray(),
+ );
+
+ $this->assertEquals($expected, $stub->getFilters());
+ }
+
+ /**
+ * @group unit
+ */
+ public function testToArray()
+ {
+ $stub = $this->getStub();
+
+ $filter = new MatchAll();
+ $stub->addFilter($filter);
+
+ $expected = array(
+ $stub->getBaseName() => array(
+ $filter->toArray(),
+ ),
+ );
+
+ $this->assertEquals($expected, $stub->toArray());
+ }
+
+ /**
+ * @group unit
+ */
+ public function testToArrayWithParam()
+ {
+ $stub = $this->getStub();
+
+ $stub->setCached(true);
+
+ $filter = new MatchAll();
+ $stub->addFilter($filter);
+
+ $expected = array(
+ $stub->getBaseName() => array(
+ '_cache' => true,
+ 'filters' => array(
+ $filter->toArray(),
+ ),
+ ),
+ );
+
+ $this->assertEquals($expected, $stub->toArray());
+ }
+
+ private function getStub()
+ {
+ return $this->getMockForAbstractClass('Elastica\Test\Filter\AbstractMultiDebug');
+ }
+}
+
+class AbstractMultiDebug extends AbstractMulti
+{
+ public function getBaseName()
+ {
+ return parent::_getBaseName();
+ }
+}
diff --git a/vendor/ruflin/elastica/test/lib/Elastica/Test/Filter/NestedFilterWithSetFilterTest.php b/vendor/ruflin/elastica/test/lib/Elastica/Test/Filter/NestedFilterWithSetFilterTest.php
new file mode 100644
index 00000000..96a49a77
--- /dev/null
+++ b/vendor/ruflin/elastica/test/lib/Elastica/Test/Filter/NestedFilterWithSetFilterTest.php
@@ -0,0 +1,110 @@
+<?php
+namespace Elastica\Test\Filter;
+
+use Elastica\Document;
+use Elastica\Filter\Nested;
+use Elastica\Filter\Terms;
+use Elastica\Search;
+use Elastica\Test\Base as BaseTest;
+use Elastica\Type\Mapping;
+
+class NestedFilterWithSetFilterTest extends BaseTest
+{
+ protected function _getIndexForTest()
+ {
+ $index = $this->_createIndex();
+ $type = $index->getType('user');
+
+ $type->setMapping(new Mapping(null, array(
+ 'firstname' => array('type' => 'string', 'store' => 'yes'),
+ // default is store => no expected
+ 'lastname' => array('type' => 'string'),
+ 'hobbies' => array(
+ 'type' => 'nested',
+ 'include_in_parent' => true,
+ 'properties' => array('hobby' => array('type' => 'string')),
+ ),
+ )));
+
+ $type->addDocuments(array(
+ new Document(1, array(
+ 'firstname' => 'Nicolas',
+ 'lastname' => 'Ruflin',
+ 'hobbies' => array(
+ array('hobby' => 'opensource'),
+ ),
+ )),
+ new Document(2, array(
+ 'firstname' => 'Nicolas',
+ 'lastname' => 'Ippolito',
+ 'hobbies' => array(
+ array('hobby' => 'opensource'),
+ array('hobby' => 'guitar'),
+ ),
+ )),
+ ));
+
+ $index->refresh();
+
+ return $index;
+ }
+
+ /**
+ * @group unit
+ */
+ public function testToArray()
+ {
+ $filter = new Nested();
+ $this->assertEquals(array('nested' => array()), $filter->toArray());
+ $query = new Terms();
+ $query->setTerms('hobby', array('guitar'));
+ $filter->setPath('hobbies');
+ $filter->setFilter($query);
+
+ $expectedArray = array(
+ 'nested' => array(
+ 'path' => 'hobbies',
+ 'filter' => array('terms' => array(
+ 'hobby' => array('guitar'),
+ )),
+ ),
+ );
+
+ $this->assertEquals($expectedArray, $filter->toArray());
+ }
+
+ /**
+ * @group functional
+ */
+ public function testShouldReturnTheRightNumberOfResult()
+ {
+ $filter = new Nested();
+ $this->assertEquals(array('nested' => array()), $filter->toArray());
+ $query = new Terms();
+ $query->setTerms('hobby', array('guitar'));
+ $filter->setPath('hobbies');
+ $filter->setFilter($query);
+
+ $client = $this->_getClient();
+ $search = new Search($client);
+ $index = $this->_getIndexForTest();
+ $search->addIndex($index);
+ $resultSet = $search->search($filter);
+
+ $this->assertEquals(1, $resultSet->getTotalHits());
+
+ $filter = new Nested();
+ $this->assertEquals(array('nested' => array()), $filter->toArray());
+ $query = new Terms();
+ $query->setTerms('hobby', array('opensource'));
+ $filter->setPath('hobbies');
+ $filter->setFilter($query);
+
+ $client = $this->_getClient();
+ $search = new Search($client);
+ $index = $this->_getIndexForTest();
+ $search->addIndex($index);
+ $resultSet = $search->search($filter);
+ $this->assertEquals(2, $resultSet->getTotalHits());
+ }
+}
diff --git a/vendor/ruflin/elastica/test/lib/Elastica/Test/Filter/NestedTest.php b/vendor/ruflin/elastica/test/lib/Elastica/Test/Filter/NestedTest.php
new file mode 100644
index 00000000..8eb42d37
--- /dev/null
+++ b/vendor/ruflin/elastica/test/lib/Elastica/Test/Filter/NestedTest.php
@@ -0,0 +1,127 @@
+<?php
+namespace Elastica\Test\Filter;
+
+use Elastica\Document;
+use Elastica\Filter\Nested;
+use Elastica\Query\Terms;
+use Elastica\Search;
+use Elastica\Test\Base as BaseTest;
+use Elastica\Type\Mapping;
+
+class NestedTest extends BaseTest
+{
+ protected function _getIndexForTest()
+ {
+ $index = $this->_createIndex('elastica_test_filter_nested');
+ $type = $index->getType('user');
+ $mapping = new Mapping();
+ $mapping->setProperties(
+ array(
+ 'firstname' => array('type' => 'string', 'store' => 'yes'),
+ // default is store => no expected
+ 'lastname' => array('type' => 'string'),
+ 'hobbies' => array(
+ 'type' => 'nested',
+ 'include_in_parent' => true,
+ 'properties' => array('hobby' => array('type' => 'string')),
+ ),
+ )
+ );
+ $type->setMapping($mapping);
+
+ $response = $type->addDocuments(array(
+ new Document(1,
+ array(
+ 'firstname' => 'Nicolas',
+ 'lastname' => 'Ruflin',
+ 'hobbies' => array(
+ array('hobby' => 'opensource'),
+ ),
+ )
+ ),
+ new Document(2,
+ array(
+ 'firstname' => 'Nicolas',
+ 'lastname' => 'Ippolito',
+ 'hobbies' => array(
+ array('hobby' => 'opensource'),
+ array('hobby' => 'guitar'),
+ ),
+ )
+ ),
+ ));
+
+ $index->refresh();
+
+ return $index;
+ }
+
+ /**
+ * @group unit
+ */
+ public function testToArray()
+ {
+ $filter = new Nested();
+ $this->assertEquals(array('nested' => array()), $filter->toArray());
+ $query = new Terms();
+ $query->setTerms('hobby', array('guitar'));
+ $filter->setPath('hobbies');
+ $filter->setQuery($query);
+
+ $expectedArray = array(
+ 'nested' => array(
+ 'path' => 'hobbies',
+ 'query' => array('terms' => array(
+ 'hobby' => array('guitar'),
+ )),
+ ),
+ );
+
+ $this->assertEquals($expectedArray, $filter->toArray());
+ }
+
+ /**
+ * @group functional
+ */
+ public function testShouldReturnTheRightNumberOfResult()
+ {
+ $filter = new Nested();
+ $this->assertEquals(array('nested' => array()), $filter->toArray());
+ $query = new Terms();
+ $query->setTerms('hobby', array('guitar'));
+ $filter->setPath('hobbies');
+ $filter->setQuery($query);
+
+ $search = new Search($this->_getClient());
+ $search->addIndex($this->_getIndexForTest());
+ $resultSet = $search->search($filter);
+ $this->assertEquals(1, $resultSet->getTotalHits());
+
+ $filter = new Nested();
+ $this->assertEquals(array('nested' => array()), $filter->toArray());
+ $query = new Terms();
+ $query->setTerms('hobby', array('opensource'));
+ $filter->setPath('hobbies');
+ $filter->setQuery($query);
+
+ $search = new Search($this->_getClient());
+ $search->addIndex($this->_getIndexForTest());
+ $resultSet = $search->search($filter);
+ $this->assertEquals(2, $resultSet->getTotalHits());
+ }
+
+ /**
+ * @group unit
+ */
+ public function testSetJoin()
+ {
+ $filter = new Nested();
+
+ $this->assertTrue($filter->setJoin(true)->getParam('join'));
+
+ $this->assertFalse($filter->setJoin(false)->getParam('join'));
+
+ $returnValue = $filter->setJoin(true);
+ $this->assertInstanceOf('Elastica\Filter\Nested', $returnValue);
+ }
+}
diff --git a/vendor/ruflin/elastica/test/lib/Elastica/Test/Filter/NumericRangeTest.php b/vendor/ruflin/elastica/test/lib/Elastica/Test/Filter/NumericRangeTest.php
new file mode 100644
index 00000000..590b5137
--- /dev/null
+++ b/vendor/ruflin/elastica/test/lib/Elastica/Test/Filter/NumericRangeTest.php
@@ -0,0 +1,37 @@
+<?php
+namespace Elastica\Test\Filter;
+
+use Elastica\Filter\NumericRange;
+use Elastica\Test\Base as BaseTest;
+
+class NumericRangeTest extends BaseTest
+{
+ /**
+ * @group unit
+ */
+ public function testAddField()
+ {
+ $rangeFilter = new NumericRange();
+ $returnValue = $rangeFilter->addField('fieldName', array('to' => 'value'));
+ $this->assertInstanceOf('Elastica\Filter\NumericRange', $returnValue);
+ }
+
+ /**
+ * @group unit
+ */
+ public function testToArray()
+ {
+ $filter = new NumericRange();
+
+ $fromTo = array('from' => 'ra', 'to' => 'ru');
+ $filter->addField('name', $fromTo);
+
+ $expectedArray = array(
+ 'numeric_range' => array(
+ 'name' => $fromTo,
+ ),
+ );
+
+ $this->assertEquals($expectedArray, $filter->toArray());
+ }
+}
diff --git a/vendor/ruflin/elastica/test/lib/Elastica/Test/Filter/PrefixTest.php b/vendor/ruflin/elastica/test/lib/Elastica/Test/Filter/PrefixTest.php
new file mode 100644
index 00000000..aab37615
--- /dev/null
+++ b/vendor/ruflin/elastica/test/lib/Elastica/Test/Filter/PrefixTest.php
@@ -0,0 +1,138 @@
+<?php
+namespace Elastica\Test\Filter;
+
+use Elastica\Document;
+use Elastica\Filter\Prefix;
+use Elastica\Test\Base as BaseTest;
+use Elastica\Type\Mapping;
+
+class PrefixTest extends BaseTest
+{
+ /**
+ * @group unit
+ */
+ public function testToArray()
+ {
+ $field = 'name';
+ $prefix = 'ruf';
+
+ $filter = new Prefix($field, $prefix);
+
+ $expectedArray = array(
+ 'prefix' => array(
+ $field => $prefix,
+ ),
+ );
+
+ $this->assertequals($expectedArray, $filter->toArray());
+ }
+
+ /**
+ * @group functional
+ */
+ public function testDifferentPrefixes()
+ {
+ $client = $this->_getClient();
+ $index = $client->getIndex('test');
+
+ $index->create(array(), true);
+ $type = $index->getType('test');
+
+ $mapping = new Mapping($type, array(
+ 'name' => array('type' => 'string', 'store' => 'no', 'index' => 'not_analyzed'),
+ )
+ );
+ $type->setMapping($mapping);
+ $type->addDocuments(array(
+ new Document(1, array('name' => 'Basel-Stadt')),
+ new Document(2, array('name' => 'New York')),
+ new Document(3, array('name' => 'Baden')),
+ new Document(4, array('name' => 'Baden Baden')),
+ new Document(5, array('name' => 'New Orleans')),
+ ));
+
+ $index->refresh();
+
+ $query = new Prefix('name', 'Ba');
+ $resultSet = $index->search($query);
+ $this->assertEquals(3, $resultSet->count());
+
+ // Lower case should not return a result
+ $query = new Prefix('name', 'ba');
+ $resultSet = $index->search($query);
+ $this->assertEquals(0, $resultSet->count());
+
+ $query = new Prefix('name', 'Baden');
+ $resultSet = $index->search($query);
+ $this->assertEquals(2, $resultSet->count());
+
+ $query = new Prefix('name', 'Baden B');
+ $resultSet = $index->search($query);
+ $this->assertEquals(1, $resultSet->count());
+
+ $query = new Prefix('name', 'Baden Bas');
+ $resultSet = $index->search($query);
+ $this->assertEquals(0, $resultSet->count());
+ }
+
+ /**
+ * @group functional
+ */
+ public function testDifferentPrefixesLowercase()
+ {
+ $client = $this->_getClient();
+ $index = $client->getIndex('test');
+
+ $indexParams = array(
+ 'analysis' => array(
+ 'analyzer' => array(
+ 'lw' => array(
+ 'type' => 'custom',
+ 'tokenizer' => 'keyword',
+ 'filter' => array('lowercase'),
+ ),
+ ),
+ ),
+ );
+
+ $index->create($indexParams, true);
+ $type = $index->getType('test');
+
+ $mapping = new Mapping($type, array(
+ 'name' => array('type' => 'string', 'store' => 'no', 'analyzer' => 'lw'),
+ )
+ );
+ $type->setMapping($mapping);
+
+ $type->addDocuments(array(
+ new Document(1, array('name' => 'Basel-Stadt')),
+ new Document(2, array('name' => 'New York')),
+ new Document(3, array('name' => 'Baden')),
+ new Document(4, array('name' => 'Baden Baden')),
+ new Document(5, array('name' => 'New Orleans')),
+ ));
+
+ $index->refresh();
+
+ $query = new Prefix('name', 'ba');
+ $resultSet = $index->search($query);
+ $this->assertEquals(3, $resultSet->count());
+
+ // Upper case should not return a result
+ $query = new Prefix('name', 'Ba');
+ $resultSet = $index->search($query);
+ $this->assertEquals(0, $resultSet->count());
+
+ $query = new Prefix('name', 'baden');
+ $resultSet = $index->search($query);
+ $this->assertEquals(2, $resultSet->count());
+
+ $query = new Prefix('name', 'baden b');
+ $resultSet = $index->search($query);
+ $this->assertEquals(1, $resultSet->count());
+
+ $query = new Prefix('name', 'baden bas');
+ $resultSet = $index->search($query);
+ $this->assertEquals(0, $resultSet->count());
+ }
+}
diff --git a/vendor/ruflin/elastica/test/lib/Elastica/Test/Filter/QueryTest.php b/vendor/ruflin/elastica/test/lib/Elastica/Test/Filter/QueryTest.php
new file mode 100644
index 00000000..23754510
--- /dev/null
+++ b/vendor/ruflin/elastica/test/lib/Elastica/Test/Filter/QueryTest.php
@@ -0,0 +1,51 @@
+<?php
+namespace Elastica\Test\Filter;
+
+use Elastica\Filter\Query;
+use Elastica\Query\QueryString;
+use Elastica\Test\Base as BaseTest;
+
+class QueryTest extends BaseTest
+{
+ /**
+ * @group unit
+ */
+ public function testSimple()
+ {
+ $query = new QueryString('foo bar');
+ $filter = new Query($query);
+
+ $expected = array(
+ 'query' => array(
+ 'query_string' => array(
+ 'query' => 'foo bar',
+ ),
+ ),
+ );
+
+ $this->assertEquals($expected, $filter->toArray());
+ }
+
+ /**
+ * @group unit
+ */
+ public function testExtended()
+ {
+ $query = new QueryString('foo bar');
+ $filter = new Query($query);
+ $filter->setCached(true);
+
+ $expected = array(
+ 'fquery' => array(
+ 'query' => array(
+ 'query_string' => array(
+ 'query' => 'foo bar',
+ ),
+ ),
+ '_cache' => true,
+ ),
+ );
+
+ $this->assertEquals($expected, $filter->toArray());
+ }
+}
diff --git a/vendor/ruflin/elastica/test/lib/Elastica/Test/Filter/RangeTest.php b/vendor/ruflin/elastica/test/lib/Elastica/Test/Filter/RangeTest.php
new file mode 100644
index 00000000..b7cad3ac
--- /dev/null
+++ b/vendor/ruflin/elastica/test/lib/Elastica/Test/Filter/RangeTest.php
@@ -0,0 +1,61 @@
+<?php
+namespace Elastica\Test\Filter;
+
+use Elastica\Filter\Range;
+use Elastica\Test\Base as BaseTest;
+
+class RangeTest extends BaseTest
+{
+ /**
+ * @group unit
+ */
+ public function testAddField()
+ {
+ $rangeFilter = new Range();
+ $returnValue = $rangeFilter->addField('fieldName', array('to' => 'value'));
+ $this->assertInstanceOf('Elastica\Filter\Range', $returnValue);
+ }
+
+ /**
+ * @group unit
+ */
+ public function testToArray()
+ {
+ $field = 'field_name';
+ $range = array('gte' => 10, 'lte' => 99);
+
+ $filter = new Range();
+ $filter->addField($field, $range);
+ $expectedArray = array('range' => array($field => $range));
+ $this->assertEquals($expectedArray, $filter->toArray());
+ }
+
+ /**
+ * @group unit
+ */
+ public function testSetExecution()
+ {
+ $field = 'field_name';
+ $range = array('gte' => 10, 'lte' => 99);
+ $filter = new Range('field_name', $range);
+
+ $filter->setExecution('fielddata');
+ $this->assertEquals('fielddata', $filter->getParam('execution'));
+
+ $returnValue = $filter->setExecution('index');
+ $this->assertInstanceOf('Elastica\Filter\Range', $returnValue);
+ }
+
+ /**
+ * Tests that parent fields are not overwritten by the toArray method.
+ *
+ * @group unit
+ */
+ public function testSetCachedNotOverwritten()
+ {
+ $filter = new Range('field_name', array());
+ $filter->setCached(true);
+ $array = $filter->toArray();
+ $this->assertTrue($array['range']['_cache']);
+ }
+}
diff --git a/vendor/ruflin/elastica/test/lib/Elastica/Test/Filter/RegexpTest.php b/vendor/ruflin/elastica/test/lib/Elastica/Test/Filter/RegexpTest.php
new file mode 100644
index 00000000..6e3a0395
--- /dev/null
+++ b/vendor/ruflin/elastica/test/lib/Elastica/Test/Filter/RegexpTest.php
@@ -0,0 +1,162 @@
+<?php
+namespace Elastica\Test\Filter;
+
+use Elastica\Document;
+use Elastica\Filter\Regexp;
+use Elastica\Test\Base as BaseTest;
+use Elastica\Type\Mapping;
+
+class RegexpTest extends BaseTest
+{
+ /**
+ * @group unit
+ */
+ public function testToArray()
+ {
+ $field = 'name';
+ $regexp = 'ruf';
+
+ $filter = new Regexp($field, $regexp);
+
+ $expectedArray = array(
+ 'regexp' => array(
+ $field => $regexp,
+ ),
+ );
+
+ $this->assertequals($expectedArray, $filter->toArray());
+ }
+
+ /**
+ * @group unit
+ */
+ public function testToArrayWithOptions()
+ {
+ $field = 'name';
+ $regexp = 'ruf';
+ $options = array(
+ 'flags' => 'ALL',
+ );
+
+ $filter = new Regexp($field, $regexp, $options);
+
+ $expectedArray = array(
+ 'regexp' => array(
+ $field => array(
+ 'value' => $regexp,
+ 'flags' => 'ALL',
+ ),
+ ),
+ );
+
+ $this->assertequals($expectedArray, $filter->toArray());
+ }
+
+ /**
+ * @group functional
+ */
+ public function testDifferentRegexp()
+ {
+ $client = $this->_getClient();
+ $index = $client->getIndex('test');
+
+ $index->create(array(), true);
+ $type = $index->getType('test');
+
+ $mapping = new Mapping($type, array(
+ 'name' => array('type' => 'string', 'store' => 'no', 'index' => 'not_analyzed'),
+ )
+ );
+ $type->setMapping($mapping);
+ $type->addDocuments(array(
+ new Document(1, array('name' => 'Basel-Stadt')),
+ new Document(2, array('name' => 'New York')),
+ new Document(3, array('name' => 'Baden')),
+ new Document(4, array('name' => 'Baden Baden')),
+ new Document(5, array('name' => 'New Orleans')),
+ ));
+
+ $index->refresh();
+
+ $query = new Regexp('name', 'Ba.*');
+ $resultSet = $index->search($query);
+ $this->assertEquals(3, $resultSet->count());
+
+ // Lower case should not return a result
+ $query = new Regexp('name', 'ba.*');
+ $resultSet = $index->search($query);
+ $this->assertEquals(0, $resultSet->count());
+
+ $query = new Regexp('name', 'Baden.*');
+ $resultSet = $index->search($query);
+ $this->assertEquals(2, $resultSet->count());
+
+ $query = new Regexp('name', 'Baden B.*');
+ $resultSet = $index->search($query);
+ $this->assertEquals(1, $resultSet->count());
+
+ $query = new Regexp('name', 'Baden Bas.*');
+ $resultSet = $index->search($query);
+ $this->assertEquals(0, $resultSet->count());
+ }
+
+ /**
+ * @group functional
+ */
+ public function testDifferentRegexpLowercase()
+ {
+ $client = $this->_getClient();
+ $index = $client->getIndex('test');
+
+ $indexParams = array(
+ 'analysis' => array(
+ 'analyzer' => array(
+ 'lw' => array(
+ 'type' => 'custom',
+ 'tokenizer' => 'keyword',
+ 'filter' => array('lowercase'),
+ ),
+ ),
+ ),
+ );
+
+ $index->create($indexParams, true);
+ $type = $index->getType('test');
+
+ $mapping = new Mapping($type, array(
+ 'name' => array('type' => 'string', 'store' => 'no', 'analyzer' => 'lw'),
+ )
+ );
+ $type->setMapping($mapping);
+ $type->addDocuments(array(
+ new Document(1, array('name' => 'Basel-Stadt')),
+ new Document(2, array('name' => 'New York')),
+ new Document(3, array('name' => 'Baden')),
+ new Document(4, array('name' => 'Baden Baden')),
+ new Document(5, array('name' => 'New Orleans')),
+ ));
+
+ $index->refresh();
+
+ $query = new Regexp('name', 'ba.*');
+ $resultSet = $index->search($query);
+ $this->assertEquals(3, $resultSet->count());
+
+ // Upper case should not return a result
+ $query = new Regexp('name', 'Ba.*');
+ $resultSet = $index->search($query);
+ $this->assertEquals(0, $resultSet->count());
+
+ $query = new Regexp('name', 'baden.*');
+ $resultSet = $index->search($query);
+ $this->assertEquals(2, $resultSet->count());
+
+ $query = new Regexp('name', 'baden b.*');
+ $resultSet = $index->search($query);
+ $this->assertEquals(1, $resultSet->count());
+
+ $query = new Regexp('name', 'baden bas.*');
+ $resultSet = $index->search($query);
+ $this->assertEquals(0, $resultSet->count());
+ }
+}
diff --git a/vendor/ruflin/elastica/test/lib/Elastica/Test/Filter/ScriptTest.php b/vendor/ruflin/elastica/test/lib/Elastica/Test/Filter/ScriptTest.php
new file mode 100644
index 00000000..fdec0381
--- /dev/null
+++ b/vendor/ruflin/elastica/test/lib/Elastica/Test/Filter/ScriptTest.php
@@ -0,0 +1,57 @@
+<?php
+namespace Elastica\Test\Filter;
+
+use Elastica\Filter\Script as ScriptFilter;
+use Elastica\Script;
+use Elastica\Test\Base as BaseTest;
+
+class ScriptTest extends BaseTest
+{
+ /**
+ * @group unit
+ */
+ public function testToArray()
+ {
+ $string = '_score * 2.0';
+
+ $filter = new ScriptFilter($string);
+
+ $array = $filter->toArray();
+ $this->assertInternalType('array', $array);
+
+ $expected = array(
+ 'script' => array(
+ 'script' => $string,
+ ),
+ );
+ $this->assertEquals($expected, $array);
+ }
+
+ /**
+ * @group unit
+ */
+ public function testSetScript()
+ {
+ $string = '_score * 2.0';
+ $params = array(
+ 'param1' => 'one',
+ 'param2' => 1,
+ );
+ $lang = 'mvel';
+ $script = new Script($string, $params, $lang);
+
+ $filter = new ScriptFilter();
+ $filter->setScript($script);
+
+ $array = $filter->toArray();
+
+ $expected = array(
+ 'script' => array(
+ 'script' => $string,
+ 'params' => $params,
+ 'lang' => $lang,
+ ),
+ );
+ $this->assertEquals($expected, $array);
+ }
+}
diff --git a/vendor/ruflin/elastica/test/lib/Elastica/Test/Filter/TermTest.php b/vendor/ruflin/elastica/test/lib/Elastica/Test/Filter/TermTest.php
new file mode 100644
index 00000000..9c8f5a2a
--- /dev/null
+++ b/vendor/ruflin/elastica/test/lib/Elastica/Test/Filter/TermTest.php
@@ -0,0 +1,24 @@
+<?php
+namespace Elastica\Test\Filter;
+
+use Elastica\Filter\Term;
+use Elastica\Test\Base as BaseTest;
+
+class TermTest extends BaseTest
+{
+ /**
+ * @group unit
+ */
+ public function testToArray()
+ {
+ $query = new Term();
+ $key = 'name';
+ $value = 'ruflin';
+ $query->setTerm($key, $value);
+
+ $data = $query->toArray();
+
+ $this->assertInternalType('array', $data['term']);
+ $this->assertEquals(array($key => $value), $data['term']);
+ }
+}
diff --git a/vendor/ruflin/elastica/test/lib/Elastica/Test/Filter/TermsTest.php b/vendor/ruflin/elastica/test/lib/Elastica/Test/Filter/TermsTest.php
new file mode 100644
index 00000000..bb37ba96
--- /dev/null
+++ b/vendor/ruflin/elastica/test/lib/Elastica/Test/Filter/TermsTest.php
@@ -0,0 +1,129 @@
+<?php
+namespace Elastica\Test\Filter;
+
+use Elastica\Document;
+use Elastica\Filter\Terms;
+use Elastica\Query;
+use Elastica\Test\Base as BaseTest;
+
+class TermsTest extends BaseTest
+{
+ /**
+ * @group functional
+ */
+ public function testLookup()
+ {
+ $index = $this->_createIndex();
+ $type1 = $index->getType('musicians');
+ $type2 = $index->getType('bands');
+
+ //index some test data
+ $type1->addDocuments(array(
+ new Document(1, array('name' => 'robert', 'lastName' => 'plant')),
+ new Document(2, array('name' => 'jimmy', 'lastName' => 'page')),
+ new Document(3, array('name' => 'john paul', 'lastName' => 'jones')),
+ new Document(4, array('name' => 'john', 'lastName' => 'bonham')),
+ new Document(5, array('name' => 'jimi', 'lastName' => 'hendrix')),
+ ));
+
+ $type2->addDocument(new Document('led zeppelin', array('members' => array('plant', 'page', 'jones', 'bonham'))));
+ $index->refresh();
+
+ //use the terms lookup feature to query for some data
+ $termsFilter = new Terms();
+ $termsFilter->setLookup('lastName', $type2, 'led zeppelin', 'members', null);
+ $query = new Query();
+ $query->setPostFilter($termsFilter);
+ $results = $index->search($query);
+ $this->assertEquals($results->count(), 4, 'Terms lookup with null index');
+
+ $termsFilter->setLookup('lastName', $type2, 'led zeppelin', 'members', $index);
+ $query->setPostFilter($termsFilter);
+ $results = $index->search($query);
+ $this->assertEquals($results->count(), 4, 'Terms lookup with index as object');
+
+ //Query with index given as string
+ $termsFilter->setLookup('lastName', $type2, 'led zeppelin', 'members', $index->getName());
+ $query->setPostFilter($termsFilter);
+ $results = $index->search($query);
+ $this->assertEquals($results->count(), 4, 'Terms lookup with index as string');
+
+ //Query with array of options
+ $termsFilter->setLookup('lastName', $type2, 'led zeppelin', 'members', array('index' => $index, 'cache' => false));
+ $query->setPostFilter($termsFilter);
+ $results = $index->search($query);
+ $this->assertEquals($results->count(), 4, 'Terms lookup with options array');
+
+ $index->delete();
+ }
+
+ /**
+ * @group unit
+ */
+ public function testSetExecution()
+ {
+ $filter = new Terms('color', array('blue', 'green'));
+
+ $filter->setExecution('bool');
+ $this->assertEquals('bool', $filter->getParam('execution'));
+
+ $returnValue = $filter->setExecution('bool');
+ $this->assertInstanceOf('Elastica\Filter\Terms', $returnValue);
+ }
+
+ /**
+ * @group unit
+ */
+ public function testSetTerms()
+ {
+ $field = 'color';
+ $terms = array('blue', 'green');
+
+ $filter = new Terms();
+ $filter->setTerms($field, $terms);
+ $expected = array('terms' => array($field => $terms));
+ $this->assertEquals($expected, $filter->toArray());
+
+ $returnValue = $filter->setTerms($field, $terms);
+ $this->assertInstanceOf('Elastica\Filter\Terms', $returnValue);
+ }
+
+ /**
+ * @group unit
+ */
+ public function testAddTerm()
+ {
+ $filter = new Terms('color', array('blue'));
+
+ $filter->addTerm('green');
+ $expected = array('terms' => array('color' => array('blue', 'green')));
+ $this->assertEquals($expected, $filter->toArray());
+
+ $returnValue = $filter->addTerm('cyan');
+ $this->assertInstanceOf('Elastica\Filter\Terms', $returnValue);
+ }
+
+ /**
+ * @group unit
+ */
+ public function testToArray()
+ {
+ $filter = new Terms('color', array());
+ $expected = array('terms' => array('color' => array()));
+ $this->assertEquals($expected, $filter->toArray());
+
+ $filter = new Terms('color', array('cyan'));
+ $expected = array('terms' => array('color' => array('cyan')));
+ $this->assertEquals($expected, $filter->toArray());
+ }
+
+ /**
+ * @group unit
+ * @expectedException \Elastica\Exception\InvalidException
+ */
+ public function testToArrayInvalidException()
+ {
+ $filter = new Terms();
+ $filter->toArray();
+ }
+}
diff --git a/vendor/ruflin/elastica/test/lib/Elastica/Test/Filter/TypeTest.php b/vendor/ruflin/elastica/test/lib/Elastica/Test/Filter/TypeTest.php
new file mode 100644
index 00000000..8da19273
--- /dev/null
+++ b/vendor/ruflin/elastica/test/lib/Elastica/Test/Filter/TypeTest.php
@@ -0,0 +1,32 @@
+<?php
+namespace Elastica\Test\Filter;
+
+use Elastica\Filter\Type;
+use Elastica\Test\Base as BaseTest;
+
+class TypeTest extends BaseTest
+{
+ /**
+ * @group unit
+ */
+ public function testSetType()
+ {
+ $typeFilter = new Type();
+ $returnValue = $typeFilter->setType('type_name');
+ $this->assertInstanceOf('Elastica\Filter\Type', $returnValue);
+ }
+
+ /**
+ * @group unit
+ */
+ public function testToArray()
+ {
+ $typeFilter = new Type('type_name');
+
+ $expectedArray = array(
+ 'type' => array('value' => 'type_name'),
+ );
+
+ $this->assertEquals($expectedArray, $typeFilter->toArray());
+ }
+}
diff --git a/vendor/ruflin/elastica/test/lib/Elastica/Test/Index/SettingsTest.php b/vendor/ruflin/elastica/test/lib/Elastica/Test/Index/SettingsTest.php
new file mode 100644
index 00000000..1562c7a0
--- /dev/null
+++ b/vendor/ruflin/elastica/test/lib/Elastica/Test/Index/SettingsTest.php
@@ -0,0 +1,338 @@
+<?php
+namespace Elastica\Test\Index;
+
+use Elastica\Document;
+use Elastica\Exception\ResponseException;
+use Elastica\Index;
+use Elastica\Index\Settings as IndexSettings;
+use Elastica\Test\Base as BaseTest;
+
+class SettingsTest extends BaseTest
+{
+ /**
+ * @group functional
+ */
+ public function testGet()
+ {
+ $indexName = 'elasticatest';
+
+ $client = $this->_getClient();
+ $index = $client->getIndex($indexName);
+ $index->create(array(), true);
+ $index->refresh();
+ $settings = $index->getSettings();
+
+ $this->assertInternalType('array', $settings->get());
+ $this->assertNotNull($settings->get('number_of_replicas'));
+ $this->assertNotNull($settings->get('number_of_shards'));
+ $this->assertNull($settings->get('kjqwerjlqwer'));
+
+ $index->delete();
+ }
+
+ /**
+ * @group functional
+ */
+ public function testGetWithAlias()
+ {
+ $indexName = 'elasticatest';
+ $aliasName = 'elasticatest_alias';
+
+ $client = $this->_getClient();
+ $index = $client->getIndex($indexName);
+ $index->create(array(), true);
+ $index->refresh();
+
+ $index->addAlias($aliasName);
+ $index = $client->getIndex($aliasName);
+ $settings = $index->getSettings();
+
+ $this->assertInternalType('array', $settings->get());
+ $this->assertNotNull($settings->get('number_of_replicas'));
+ $this->assertNotNull($settings->get('number_of_shards'));
+ $this->assertNull($settings->get('kjqwerjlqwer'));
+
+ $index->delete();
+ }
+
+ /**
+ * @group functional
+ */
+ public function testSetNumberOfReplicas()
+ {
+ $indexName = 'test';
+
+ $client = $this->_getClient();
+ $index = $client->getIndex($indexName);
+ $index->create(array(), true);
+ $settings = $index->getSettings();
+
+ $settings->setNumberOfReplicas(2);
+ $index->refresh();
+ $this->assertEquals(2, $settings->get('number_of_replicas'));
+
+ $settings->setNumberOfReplicas(3);
+ $index->refresh();
+ $this->assertEquals(3, $settings->get('number_of_replicas'));
+
+ $index->delete();
+ }
+
+ /**
+ * @group functional
+ */
+ public function testSetRefreshInterval()
+ {
+ $indexName = 'test';
+
+ $client = $this->_getClient();
+ $index = $client->getIndex($indexName);
+ $index->create(array(), true);
+
+ $settings = $index->getSettings();
+
+ $settings->setRefreshInterval('2s');
+ $index->refresh();
+ $this->assertEquals('2s', $settings->get('refresh_interval'));
+
+ $settings->setRefreshInterval('5s');
+ $index->refresh();
+ $this->assertEquals('5s', $settings->get('refresh_interval'));
+
+ $index->delete();
+ }
+
+ /**
+ * @group functional
+ */
+ public function testGetRefreshInterval()
+ {
+ $indexName = 'test';
+
+ $client = $this->_getClient();
+ $index = $client->getIndex($indexName);
+ $index->create(array(), true);
+
+ $settings = $index->getSettings();
+
+ $this->assertEquals(IndexSettings::DEFAULT_REFRESH_INTERVAL, $settings->getRefreshInterval());
+
+ $interval = '2s';
+ $settings->setRefreshInterval($interval);
+ $index->refresh();
+ $this->assertEquals($interval, $settings->getRefreshInterval());
+ $this->assertEquals($interval, $settings->get('refresh_interval'));
+
+ $index->delete();
+ }
+
+ /**
+ * @group functional
+ */
+ public function testSetMergePolicy()
+ {
+ $indexName = 'test';
+
+ $client = $this->_getClient();
+ $index = $client->getIndex($indexName);
+ $index->create(array(), true);
+ //wait for the shards to be allocated
+ $this->_waitForAllocation($index);
+
+ $settings = $index->getSettings();
+
+ $settings->setMergePolicy('expunge_deletes_allowed', 15);
+ $this->assertEquals(15, $settings->getMergePolicy('expunge_deletes_allowed'));
+
+ $settings->setMergePolicy('expunge_deletes_allowed', 10);
+ $this->assertEquals(10, $settings->getMergePolicy('expunge_deletes_allowed'));
+
+ $index->delete();
+ }
+
+ /**
+ * @group functional
+ */
+ public function testSetMergeFactor()
+ {
+ $indexName = 'test';
+
+ $client = $this->_getClient();
+ $index = $client->getIndex($indexName);
+ $index->create(array(), true);
+
+ //wait for the shards to be allocated
+ $this->_waitForAllocation($index);
+
+ $settings = $index->getSettings();
+
+ $response = $settings->setMergePolicy('merge_factor', 15);
+ $this->assertEquals(15, $settings->getMergePolicy('merge_factor'));
+ $this->assertInstanceOf('Elastica\Response', $response);
+ $this->assertTrue($response->isOk());
+
+ $settings->setMergePolicy('merge_factor', 10);
+ $this->assertEquals(10, $settings->getMergePolicy('merge_factor'));
+
+ $index->delete();
+ }
+
+ /**
+ * @group functional
+ */
+ public function testSetMergePolicyType()
+ {
+ $indexName = 'test';
+
+ $client = $this->_getClient();
+ $index = $client->getIndex($indexName);
+ $index->create(array(), true);
+
+ //wait for the shards to be allocated
+ $this->_waitForAllocation($index);
+
+ $settings = $index->getSettings();
+
+ $settings->setMergePolicyType('log_byte_size');
+ $this->assertEquals('log_byte_size', $settings->getMergePolicyType());
+
+ $response = $settings->setMergePolicy('merge_factor', 15);
+ $this->assertEquals(15, $settings->getMergePolicy('merge_factor'));
+ $this->assertInstanceOf('Elastica\Response', $response);
+ $this->assertTrue($response->isOk());
+
+ $index->delete();
+ }
+
+ /**
+ * @group functional
+ */
+ public function testSetReadOnly()
+ {
+ $index = $this->_createIndex();
+ //wait for the shards to be allocated
+ $this->_waitForAllocation($index);
+ $index->getSettings()->setReadOnly(false);
+
+ // Add document to normal index
+ $doc1 = new Document(null, array('hello' => 'world'));
+ $doc2 = new Document(null, array('hello' => 'world'));
+ $doc3 = new Document(null, array('hello' => 'world'));
+
+ $type = $index->getType('test');
+ $type->addDocument($doc1);
+ $this->assertFalse($index->getSettings()->getReadOnly());
+
+ // Try to add doc to read only index
+ $index->getSettings()->setReadOnly(true);
+ $this->assertTrue($index->getSettings()->getReadOnly());
+
+ try {
+ $type->addDocument($doc2);
+ $this->fail('Should throw exception because of read only');
+ } catch (ResponseException $e) {
+ $message = $e->getMessage();
+ $this->assertContains('ClusterBlockException', $message);
+ $this->assertContains('index write', $message);
+ }
+
+ // Remove read only, add document
+ $response = $index->getSettings()->setReadOnly(false);
+ $this->assertTrue($response->isOk());
+
+ $type->addDocument($doc3);
+ $index->refresh();
+
+ $this->assertEquals(2, $type->count());
+
+ $index->delete();
+ }
+
+ /**
+ * @group functional
+ */
+ public function testGetSetBlocksRead()
+ {
+ $index = $this->_createIndex();
+ $index->refresh();
+ $settings = $index->getSettings();
+
+ $this->assertFalse($settings->getBlocksRead());
+
+ $settings->setBlocksRead(true);
+ $this->assertTrue($settings->getBlocksRead());
+
+ $settings->setBlocksRead(false);
+ $this->assertFalse($settings->getBlocksRead());
+
+ $settings->setBlocksRead();
+ $this->assertTrue($settings->getBlocksRead());
+
+ $index->delete();
+ }
+
+ /**
+ * @group functional
+ */
+ public function testGetSetBlocksWrite()
+ {
+ $index = $this->_createIndex();
+ $index->refresh();
+ $settings = $index->getSettings();
+
+ $this->assertFalse($settings->getBlocksWrite());
+
+ $settings->setBlocksWrite(true);
+ $this->assertTrue($settings->getBlocksWrite());
+
+ $settings->setBlocksWrite(false);
+ $this->assertFalse($settings->getBlocksWrite());
+
+ $settings->setBlocksWrite();
+ $this->assertTrue($settings->getBlocksWrite());
+
+ $index->delete();
+ }
+
+ /**
+ * @group functional
+ */
+ public function testGetSetBlocksMetadata()
+ {
+ $index = $this->_createIndex();
+ $index->refresh();
+ $settings = $index->getSettings();
+
+ $this->assertFalse($settings->getBlocksMetadata());
+
+ $settings->setBlocksMetadata(true);
+ $this->assertTrue($settings->getBlocksMetadata());
+
+ $settings->setBlocksMetadata(false);
+ $this->assertFalse($settings->getBlocksMetadata());
+
+ $settings->setBlocksMetadata();
+ $this->assertTrue($settings->getBlocksMetadata());
+
+ $settings->setBlocksMetadata(false); // Cannot delete index otherwise
+ $index->delete();
+ }
+
+ /**
+ * @group functional
+ */
+ public function testNotFoundIndex()
+ {
+ $client = $this->_getClient();
+ $index = $client->getIndex('not_found_index');
+ //wait for the shards to be allocated
+
+ try {
+ $settings = $index->getSettings()->get();
+ $this->fail('Should throw exception because of index not found');
+ } catch (ResponseException $e) {
+ $message = $e->getMessage();
+ $this->assertContains('IndexMissingException', $message);
+ }
+ }
+}
diff --git a/vendor/ruflin/elastica/test/lib/Elastica/Test/Index/StatsTest.php b/vendor/ruflin/elastica/test/lib/Elastica/Test/Index/StatsTest.php
new file mode 100644
index 00000000..d0bb7838
--- /dev/null
+++ b/vendor/ruflin/elastica/test/lib/Elastica/Test/Index/StatsTest.php
@@ -0,0 +1,24 @@
+<?php
+namespace Elastica\Test\Index;
+
+use Elastica\Test\Base as BaseTest;
+
+class StatsTest extends BaseTest
+{
+ /**
+ * @group functional
+ */
+ public function testGetSettings()
+ {
+ $indexName = 'test';
+
+ $client = $this->_getClient();
+ $index = $client->getIndex($indexName);
+ $index->create(array(), true);
+ $stats = $index->getStats();
+ $this->assertInstanceOf('Elastica\Index\Stats', $stats);
+
+ $this->assertTrue($stats->getResponse()->isOk());
+ $this->assertEquals(0, $stats->get('_all', 'indices', 'test', 'primaries', 'docs', 'count'));
+ }
+}
diff --git a/vendor/ruflin/elastica/test/lib/Elastica/Test/Index/StatusTest.php b/vendor/ruflin/elastica/test/lib/Elastica/Test/Index/StatusTest.php
new file mode 100644
index 00000000..24f22ffd
--- /dev/null
+++ b/vendor/ruflin/elastica/test/lib/Elastica/Test/Index/StatusTest.php
@@ -0,0 +1,74 @@
+<?php
+namespace Elastica\Test\Index;
+
+use Elastica\Index\Status as IndexStatus;
+use Elastica\Test\Base as BaseTest;
+
+class StatusTest extends BaseTest
+{
+ /**
+ * @group functional
+ */
+ public function testGetAliases()
+ {
+ $indexName = 'test';
+ $aliasName = 'test-alias';
+
+ $client = $this->_getClient();
+ $index = $client->getIndex($indexName);
+ $index->create(array(), true);
+
+ $status = new IndexStatus($index);
+
+ $aliases = $status->getAliases();
+
+ $this->assertTrue(empty($aliases));
+ $this->assertInternalType('array', $aliases);
+
+ $index->addAlias($aliasName);
+ $status->refresh();
+
+ $aliases = $status->getAliases();
+
+ $this->assertTrue(in_array($aliasName, $aliases));
+ }
+
+ /**
+ * @group functional
+ */
+ public function testHasAlias()
+ {
+ $indexName = 'test';
+ $aliasName = 'test-alias';
+
+ $client = $this->_getClient();
+ $index = $client->getIndex($indexName);
+ $index->create(array(), true);
+
+ $status = new IndexStatus($index);
+
+ $this->assertFalse($status->hasAlias($aliasName));
+
+ $index->addAlias($aliasName);
+ $status->refresh();
+
+ $this->assertTrue($status->hasAlias($aliasName));
+ }
+
+ /**
+ * @group functional
+ */
+ public function testGetSettings()
+ {
+ $indexName = 'test';
+
+ $client = $this->_getClient();
+ $index = $client->getIndex($indexName);
+ $index->create(array(), true);
+ $status = $index->getStatus();
+
+ $settings = $status->getSettings();
+ $this->assertInternalType('array', $settings);
+ $this->assertTrue(isset($settings['index']['number_of_shards']));
+ }
+}
diff --git a/vendor/ruflin/elastica/test/lib/Elastica/Test/IndexTest.php b/vendor/ruflin/elastica/test/lib/Elastica/Test/IndexTest.php
new file mode 100644
index 00000000..25ac53c2
--- /dev/null
+++ b/vendor/ruflin/elastica/test/lib/Elastica/Test/IndexTest.php
@@ -0,0 +1,901 @@
+<?php
+namespace Elastica\Test;
+
+use Elastica\Document;
+use Elastica\Exception\ResponseException;
+use Elastica\Index;
+use Elastica\Query\HasChild;
+use Elastica\Query\QueryString;
+use Elastica\Query\SimpleQueryString;
+use Elastica\Query\Term;
+use Elastica\Status;
+use Elastica\Test\Base as BaseTest;
+use Elastica\Type;
+use Elastica\Type\Mapping;
+
+class IndexTest extends BaseTest
+{
+ /**
+ * @group functional
+ */
+ public function testMapping()
+ {
+ $index = $this->_createIndex();
+ $doc = new Document(1, array('id' => 1, 'email' => 'test@test.com', 'username' => 'hanswurst', 'test' => array('2', '3', '5')));
+
+ $type = $index->getType('test');
+
+ $mapping = array('id' => array('type' => 'integer', 'store' => true), 'email' => array('type' => 'string', 'store' => 'no'),
+ 'username' => array('type' => 'string', 'store' => 'no'), 'test' => array('type' => 'integer', 'store' => 'no'),);
+ $type->setMapping($mapping);
+
+ $type->addDocument($doc);
+ $index->optimize();
+
+ $storedMapping = $index->getMapping();
+
+ $this->assertEquals($storedMapping['test']['properties']['id']['type'], 'integer');
+ $this->assertEquals($storedMapping['test']['properties']['id']['store'], true);
+ $this->assertEquals($storedMapping['test']['properties']['email']['type'], 'string');
+ $this->assertEquals($storedMapping['test']['properties']['username']['type'], 'string');
+ $this->assertEquals($storedMapping['test']['properties']['test']['type'], 'integer');
+
+ $result = $type->search('hanswurst');
+ }
+
+ /**
+ * @group functional
+ */
+ public function testGetMappingAlias()
+ {
+ $index = $this->_createIndex();
+ $indexName = $index->getName();
+
+ $aliasName = 'test-mapping-alias';
+ $index->addAlias($aliasName);
+
+ $type = new Type($index, 'test');
+ $mapping = new Mapping($type, array(
+ 'id' => array('type' => 'integer', 'store' => 'yes'),
+ ));
+ $type->setMapping($mapping);
+
+ $client = $index->getClient();
+
+ // Index mapping
+ $mapping1 = $client->getIndex($indexName)->getMapping();
+
+ // Alias mapping
+ $mapping2 = $client->getIndex($aliasName)->getMapping();
+
+ // Make sure, a mapping is set
+ $this->assertNotEmpty($mapping1);
+
+ // Alias and index mapping should be identical
+ $this->assertEquals($mapping1, $mapping2);
+ }
+
+ /**
+ * @group functional
+ */
+ public function testParent()
+ {
+ $index = $this->_createIndex();
+
+ $typeBlog = new Type($index, 'blog');
+
+ $typeComment = new Type($index, 'comment');
+
+ $mapping = new Mapping();
+ $mapping->setParam('_parent', array('type' => 'blog'));
+ $typeComment->setMapping($mapping);
+
+ $entry1 = new Document(1);
+ $entry1->set('title', 'Hello world');
+ $typeBlog->addDocument($entry1);
+
+ $entry2 = new Document(2);
+ $entry2->set('title', 'Foo bar');
+ $typeBlog->addDocument($entry2);
+
+ $entry3 = new Document(3);
+ $entry3->set('title', 'Till dawn');
+ $typeBlog->addDocument($entry3);
+
+ $comment = new Document(1);
+ $comment->set('author', 'Max');
+ $comment->setParent(2); // Entry Foo bar
+ $typeComment->addDocument($comment);
+
+ $index->optimize();
+
+ $query = new HasChild('Max', 'comment');
+ $resultSet = $typeBlog->search($query);
+ $this->assertEquals(1, $resultSet->count());
+ $this->assertEquals(array('title' => 'Foo bar'), $resultSet->current()->getData());
+ }
+
+ /**
+ * @group functional
+ */
+ public function testAddPdfFile()
+ {
+ $this->_checkAttachmentsPlugin();
+ $indexMapping = array('file' => array('type' => 'attachment', 'store' => 'no'), 'text' => array('type' => 'string', 'store' => 'no'));
+
+ $indexParams = array('index' => array('number_of_shards' => 1, 'number_of_replicas' => 0));
+
+ $index = $this->_createIndex();
+ $type = new Type($index, 'test');
+
+ $index->create($indexParams, true);
+ $type->setMapping($indexMapping);
+
+ $doc1 = new Document(1);
+ $doc1->addFile('file', BASE_PATH.'/data/test.pdf', 'application/pdf');
+ $doc1->set('text', 'basel world');
+ $type->addDocument($doc1);
+
+ $doc2 = new Document(2);
+ $doc2->set('text', 'running in basel');
+ $type->addDocument($doc2);
+
+ $index->optimize();
+
+ $resultSet = $type->search('xodoa');
+ $this->assertEquals(1, $resultSet->count());
+
+ $resultSet = $type->search('basel');
+ $this->assertEquals(2, $resultSet->count());
+
+ // Author is ruflin
+ $resultSet = $type->search('ruflin');
+ $this->assertEquals(1, $resultSet->count());
+
+ // String does not exist in file
+ $resultSet = $type->search('guschti');
+ $this->assertEquals(0, $resultSet->count());
+ }
+
+ /**
+ * @group functional
+ */
+ public function testAddPdfFileContent()
+ {
+ $this->_checkAttachmentsPlugin();
+ $indexMapping = array('file' => array('type' => 'attachment', 'store' => 'no'), 'text' => array('type' => 'string', 'store' => 'no'));
+
+ $indexParams = array('index' => array('number_of_shards' => 1, 'number_of_replicas' => 0));
+
+ $index = $this->_createIndex();
+ $type = new Type($index, 'test');
+
+ $index->create($indexParams, true);
+ $type->setMapping($indexMapping);
+
+ $doc1 = new Document(1);
+ $doc1->addFileContent('file', file_get_contents(BASE_PATH.'/data/test.pdf'));
+ $doc1->set('text', 'basel world');
+ $type->addDocument($doc1);
+
+ $doc2 = new Document(2);
+ $doc2->set('text', 'running in basel');
+ $type->addDocument($doc2);
+
+ $index->optimize();
+
+ $resultSet = $type->search('xodoa');
+ $this->assertEquals(1, $resultSet->count());
+
+ $resultSet = $type->search('basel');
+ $this->assertEquals(2, $resultSet->count());
+
+ // Author is ruflin
+ $resultSet = $type->search('ruflin');
+ $this->assertEquals(1, $resultSet->count());
+
+ // String does not exist in file
+ $resultSet = $type->search('guschti');
+ $this->assertEquals(0, $resultSet->count());
+ }
+
+ /**
+ * @group functional
+ */
+ public function testAddWordxFile()
+ {
+ $this->_checkAttachmentsPlugin();
+ $indexMapping = array('file' => array('type' => 'attachment'), 'text' => array('type' => 'string', 'store' => 'no'));
+
+ $indexParams = array('index' => array('number_of_shards' => 1, 'number_of_replicas' => 0));
+
+ $index = $this->_createIndex();
+ $type = new Type($index, 'content');
+
+ $index->create($indexParams, true);
+ $type->setMapping($indexMapping);
+
+ $doc1 = new Document(1);
+ $doc1->addFile('file', BASE_PATH.'/data/test.docx');
+ $doc1->set('text', 'basel world');
+ $type->addDocument($doc1);
+
+ $index->optimize();
+ $index->refresh();
+
+ $doc2 = new Document(2);
+ $doc2->set('text', 'running in basel');
+ $type->addDocument($doc2);
+
+ $index->optimize();
+ $index->refresh();
+
+ $resultSet = $type->search('basel');
+ $this->assertEquals(2, $resultSet->count());
+
+ $resultSet = $type->search('ruflin');
+ $this->assertEquals(0, $resultSet->count());
+
+ $resultSet = $type->search('xodoa');
+ $this->assertEquals(1, $resultSet->count());
+ }
+
+ /**
+ * @group functional
+ */
+ public function testExcludeFileSource()
+ {
+ $this->_checkAttachmentsPlugin();
+ $indexMapping = array('file' => array('type' => 'attachment', 'store' => 'yes'), 'text' => array('type' => 'string', 'store' => 'yes'),
+ 'title' => array('type' => 'string', 'store' => 'yes'),);
+
+ $indexParams = array('index' => array('number_of_shards' => 1, 'number_of_replicas' => 0));
+
+ $index = $this->_createIndex();
+ $type = new Type($index, 'content');
+
+ $mapping = Mapping::create($indexMapping);
+ $mapping->setSource(array('excludes' => array('file')));
+
+ $mapping->setType($type);
+
+ $index->create($indexParams, true);
+ $type->setMapping($mapping);
+
+ $docId = 1;
+ $text = 'Basel World';
+ $title = 'No Title';
+
+ $doc1 = new Document($docId);
+ $doc1->addFile('file', BASE_PATH.'/data/test.docx');
+ $doc1->set('text', $text);
+ $doc1->set('title', $title);
+ $type->addDocument($doc1);
+
+ // Optimization necessary, as otherwise source still in realtime get
+ $index->optimize();
+
+ $data = $type->getDocument($docId)->getData();
+ $this->assertEquals($data['title'], $title);
+ $this->assertEquals($data['text'], $text);
+ $this->assertFalse(isset($data['file']));
+ }
+
+ /**
+ * @group functional
+ * @expectedException \Elastica\Exception\ResponseException
+ */
+ public function testAddRemoveAlias()
+ {
+ $client = $this->_getClient();
+
+ $indexName1 = 'test1';
+ $aliasName = 'test-alias';
+ $typeName = 'test';
+
+ $index = $client->getIndex($indexName1);
+ $index->create(array('index' => array('number_of_shards' => 1, 'number_of_replicas' => 0)), true);
+
+ $doc = new Document(1, array('id' => 1, 'email' => 'test@test.com', 'username' => 'ruflin'));
+
+ $type = $index->getType($typeName);
+ $type->addDocument($doc);
+ $index->refresh();
+
+ $resultSet = $type->search('ruflin');
+
+ $this->assertEquals(1, $resultSet->count());
+
+ $data = $index->addAlias($aliasName, true)->getData();
+ $this->assertTrue($data['acknowledged']);
+
+ $index2 = $client->getIndex($aliasName);
+ $type2 = $index2->getType($typeName);
+
+ $resultSet2 = $type2->search('ruflin');
+ $this->assertEquals(1, $resultSet2->count());
+
+ $response = $index->removeAlias($aliasName)->getData();
+ $this->assertTrue($response['acknowledged']);
+
+ $client->getIndex($aliasName)->getType($typeName)->search('ruflin');
+ }
+
+ /**
+ * @group functional
+ */
+ public function testCount()
+ {
+ $index = $this->_createIndex();
+
+ // Add document to normal index
+ $doc1 = new Document(null, array('name' => 'ruflin'));
+ $doc2 = new Document(null, array('name' => 'nicolas'));
+
+ $type = $index->getType('test');
+ $type->addDocument($doc1);
+ $type->addDocument($doc2);
+
+ $index->refresh();
+
+ $this->assertEquals(2, $index->count());
+
+ $query = new Term();
+ $key = 'name';
+ $value = 'nicolas';
+ $query->setTerm($key, $value);
+
+ $this->assertEquals(1, $index->count($query));
+ }
+
+ /**
+ * @group functional
+ */
+ public function testDeleteByQueryWithQueryString()
+ {
+ $index = $this->_createIndex();
+ $type1 = new Type($index, 'test1');
+ $type1->addDocument(new Document(1, array('name' => 'ruflin nicolas')));
+ $type1->addDocument(new Document(2, array('name' => 'ruflin')));
+ $type2 = new Type($index, 'test2');
+ $type2->addDocument(new Document(1, array('name' => 'ruflin nicolas')));
+ $type2->addDocument(new Document(2, array('name' => 'ruflin')));
+ $index->refresh();
+
+ $response = $index->search('ruflin*');
+ $this->assertEquals(4, $response->count());
+
+ $response = $index->search('nicolas');
+ $this->assertEquals(2, $response->count());
+
+ // Delete first document
+ $response = $index->deleteByQuery('nicolas');
+ $this->assertTrue($response->isOk());
+
+ $index->refresh();
+
+ // Makes sure, document is deleted
+ $response = $index->search('ruflin*');
+ $this->assertEquals(2, $response->count());
+
+ $response = $index->search('nicolas');
+ $this->assertEquals(0, $response->count());
+ }
+
+ /**
+ * @group functional
+ */
+ public function testDeleteByQueryWithQuery()
+ {
+ $index = $this->_createIndex();
+ $type1 = new Type($index, 'test1');
+ $type1->addDocument(new Document(1, array('name' => 'ruflin nicolas')));
+ $type1->addDocument(new Document(2, array('name' => 'ruflin')));
+ $type2 = new Type($index, 'test2');
+ $type2->addDocument(new Document(1, array('name' => 'ruflin nicolas')));
+ $type2->addDocument(new Document(2, array('name' => 'ruflin')));
+ $index->refresh();
+
+ $response = $index->search('ruflin*');
+ $this->assertEquals(4, $response->count());
+
+ $response = $index->search('nicolas');
+ $this->assertEquals(2, $response->count());
+
+ // Delete first document
+ $response = $index->deleteByQuery(new SimpleQueryString('nicolas'));
+ $this->assertTrue($response->isOk());
+
+ $index->refresh();
+
+ // Makes sure, document is deleted
+ $response = $index->search('ruflin*');
+ $this->assertEquals(2, $response->count());
+
+ $response = $index->search('nicolas');
+ $this->assertEquals(0, $response->count());
+ }
+
+ /**
+ * @group functional
+ */
+ public function testDeleteByQueryWithQueryAndOptions()
+ {
+ $index = $this->_createIndex(null, true, 2);
+ $type1 = new Type($index, 'test1');
+ $type1->addDocument(new Document(1, array('name' => 'ruflin nicolas')));
+ $type1->addDocument(new Document(2, array('name' => 'ruflin')));
+ $type2 = new Type($index, 'test2');
+ $type2->addDocument(new Document(1, array('name' => 'ruflin nicolas')));
+ $type2->addDocument(new Document(2, array('name' => 'ruflin')));
+ $index->refresh();
+
+ $response = $index->search('ruflin*');
+ $this->assertEquals(4, $response->count());
+
+ $response = $index->search('nicolas');
+ $this->assertEquals(2, $response->count());
+
+ // Route to the wrong document id; should not delete
+ $response = $index->deleteByQuery(new SimpleQueryString('nicolas'), array('routing' => '2'));
+ $this->assertTrue($response->isOk());
+
+ $index->refresh();
+
+ $response = $index->search('ruflin*');
+ $this->assertEquals(4, $response->count());
+
+ $response = $index->search('nicolas');
+ $this->assertEquals(2, $response->count());
+
+ // Delete first document
+ $response = $index->deleteByQuery(new SimpleQueryString('nicolas'), array('routing' => '1'));
+ $this->assertTrue($response->isOk());
+
+ $index->refresh();
+
+ // Makes sure, document is deleted
+ $response = $index->search('ruflin*');
+ $this->assertEquals(2, $response->count());
+
+ $response = $index->search('nicolas');
+ $this->assertEquals(0, $response->count());
+ }
+
+ /**
+ * @group functional
+ */
+ public function testDeleteIndexDeleteAlias()
+ {
+ $indexName = 'test';
+ $aliasName = 'test-aliase';
+
+ $client = $this->_getClient();
+ $index = $client->getIndex($indexName);
+
+ $index->create(array(), true);
+ $index->addAlias($aliasName);
+
+ $status = new Status($client);
+ $this->assertTrue($status->indexExists($indexName));
+ $this->assertTrue($status->aliasExists($aliasName));
+
+ // Deleting index should also remove alias
+ $index->delete();
+
+ $status->refresh();
+ $this->assertFalse($status->indexExists($indexName));
+ $this->assertFalse($status->aliasExists($aliasName));
+ }
+
+ /**
+ * @group functional
+ */
+ public function testAddAliasTwoIndices()
+ {
+ $indexName1 = 'test1';
+ $indexName2 = 'test2';
+ $aliasName = 'test-alias';
+
+ $client = $this->_getClient();
+ $index1 = $client->getIndex($indexName1);
+ $index2 = $client->getIndex($indexName2);
+
+ $index1->create(array(), true);
+ $this->_waitForAllocation($index1);
+ $index1->addAlias($aliasName);
+ $index2->create(array(), true);
+ $this->_waitForAllocation($index2);
+
+ $index1->refresh();
+ $index2->refresh();
+ $index1->optimize();
+ $index2->optimize();
+
+ $status = new Status($client);
+
+ $this->assertTrue($status->indexExists($indexName1));
+ $this->assertTrue($status->indexExists($indexName2));
+
+ $this->assertTrue($status->aliasExists($aliasName));
+ $this->assertTrue($index1->getStatus()->hasAlias($aliasName));
+ $this->assertFalse($index2->getStatus()->hasAlias($aliasName));
+
+ $index2->addAlias($aliasName);
+ $this->assertTrue($index1->getStatus()->hasAlias($aliasName));
+ $this->assertTrue($index2->getStatus()->hasAlias($aliasName));
+ }
+
+ /**
+ * @group functional
+ */
+ public function testReplaceAlias()
+ {
+ $indexName1 = 'test1';
+ $indexName2 = 'test2';
+ $aliasName = 'test-alias';
+
+ $client = $this->_getClient();
+ $index1 = $client->getIndex($indexName1);
+ $index2 = $client->getIndex($indexName2);
+
+ $index1->create(array(), true);
+ $index1->addAlias($aliasName);
+ $index2->create(array(), true);
+
+ $index1->refresh();
+ $index2->refresh();
+
+ $status = new Status($client);
+
+ $this->assertTrue($status->indexExists($indexName1));
+ $this->assertTrue($status->indexExists($indexName2));
+ $this->assertTrue($status->aliasExists($aliasName));
+ $this->assertTrue($index1->getStatus()->hasAlias($aliasName));
+ $this->assertFalse($index2->getStatus()->hasAlias($aliasName));
+
+ $index2->addAlias($aliasName, true);
+ $this->assertFalse($index1->getStatus()->hasAlias($aliasName));
+ $this->assertTrue($index2->getStatus()->hasAlias($aliasName));
+ }
+
+ /**
+ * @group functional
+ */
+ public function testAddDocumentVersion()
+ {
+ $client = $this->_getClient();
+ $index = $client->getIndex('test');
+ $index->create(array(), true);
+ $type = new Type($index, 'test');
+
+ $doc1 = new Document(1);
+ $doc1->set('title', 'Hello world');
+
+ $return = $type->addDocument($doc1);
+ $data = $return->getData();
+ $this->assertEquals(1, $data['_version']);
+
+ $return = $type->addDocument($doc1);
+ $data = $return->getData();
+ $this->assertEquals(2, $data['_version']);
+ }
+
+ /**
+ * @group functional
+ */
+ public function testClearCache()
+ {
+ $index = $this->_createIndex();
+ $response = $index->clearCache();
+ $this->assertFalse($response->hasError());
+ }
+
+ /**
+ * @group functional
+ */
+ public function testFlush()
+ {
+ $index = $this->_createIndex();
+ $response = $index->flush();
+ $this->assertFalse($response->hasError());
+ }
+
+ /**
+ * @group functional
+ */
+ public function testExists()
+ {
+ $index = $this->_createIndex();
+
+ $this->assertTrue($index->exists());
+
+ $index->delete();
+
+ $this->assertFalse($index->exists());
+ }
+
+ /**
+ * Test $index->delete() return value for unknown index.
+ *
+ * Tests if deleting an index that does not exist in Elasticsearch,
+ * correctly returns a boolean true from the hasError() method of
+ * the \Elastica\Response object
+ *
+ * @group functional
+ */
+ public function testDeleteMissingIndexHasError()
+ {
+ $client = $this->_getClient();
+ $index = $client->getIndex('index_does_not_exist');
+
+ try {
+ $index->delete();
+ $this->fail('This should never be reached. Deleting an unknown index will throw an exception');
+ } catch (ResponseException $error) {
+ $response = $error->getResponse();
+ $this->assertTrue($response->hasError());
+ $request = $error->getRequest();
+ $this->assertInstanceOf('Elastica\Request', $request);
+ }
+ }
+
+ /**
+ * Tests to see if the test type mapping exists when calling $index->getMapping().
+ *
+ * @group functional
+ */
+ public function testIndexGetMapping()
+ {
+ $index = $this->_createIndex();
+ $type = $index->getType('test');
+
+ $mapping = array('id' => array('type' => 'integer', 'store' => true), 'email' => array('type' => 'string', 'store' => 'no'),
+ 'username' => array('type' => 'string', 'store' => 'no'), 'test' => array('type' => 'integer', 'store' => 'no'),);
+
+ $type->setMapping($mapping);
+ $index->refresh();
+ $indexMappings = $index->getMapping();
+
+ $this->assertEquals($indexMappings['test']['properties']['id']['type'], 'integer');
+ $this->assertEquals($indexMappings['test']['properties']['id']['store'], true);
+ $this->assertEquals($indexMappings['test']['properties']['email']['type'], 'string');
+ $this->assertEquals($indexMappings['test']['properties']['username']['type'], 'string');
+ $this->assertEquals($indexMappings['test']['properties']['test']['type'], 'integer');
+ }
+
+ /**
+ * Tests to see if the index is empty when there are no types set.
+ *
+ * @group functional
+ */
+ public function testEmptyIndexGetMapping()
+ {
+ $index = $this->_createIndex();
+ $indexMappings = $index->getMapping();
+
+ $this->assertTrue(empty($indexMappings['elastica_test']));
+ }
+
+ /**
+ * Test to see if search Default Limit works.
+ *
+ * @group functional
+ */
+ public function testLimitDefaultIndex()
+ {
+ $client = $this->_getClient();
+ $index = $client->getIndex('zero');
+ $index->create(array('index' => array('number_of_shards' => 1, 'number_of_replicas' => 0)), true);
+
+ $docs = array();
+
+ $docs[] = new Document(1, array('id' => 1, 'email' => 'test@test.com', 'username' => 'farrelley'));
+ $docs[] = new Document(2, array('id' => 1, 'email' => 'test@test.com', 'username' => 'farrelley'));
+ $docs[] = new Document(3, array('id' => 1, 'email' => 'test@test.com', 'username' => 'farrelley'));
+ $docs[] = new Document(4, array('id' => 1, 'email' => 'test@test.com', 'username' => 'farrelley'));
+ $docs[] = new Document(5, array('id' => 1, 'email' => 'test@test.com', 'username' => 'farrelley'));
+ $docs[] = new Document(6, array('id' => 1, 'email' => 'test@test.com', 'username' => 'farrelley'));
+ $docs[] = new Document(7, array('id' => 1, 'email' => 'test@test.com', 'username' => 'farrelley'));
+ $docs[] = new Document(8, array('id' => 1, 'email' => 'test@test.com', 'username' => 'farrelley'));
+ $docs[] = new Document(9, array('id' => 1, 'email' => 'test@test.com', 'username' => 'farrelley'));
+ $docs[] = new Document(10, array('id' => 1, 'email' => 'test@test.com', 'username' => 'farrelley'));
+ $docs[] = new Document(11, array('id' => 1, 'email' => 'test@test.com', 'username' => 'farrelley'));
+
+ $type = $index->getType('zeroType');
+ $type->addDocuments($docs);
+ $index->refresh();
+
+ // default limit results (default limit is 10)
+ $resultSet = $index->search('farrelley');
+ $this->assertEquals(10, $resultSet->count());
+
+ // limit = 1
+ $resultSet = $index->search('farrelley', 1);
+ $this->assertEquals(1, $resultSet->count());
+ }
+
+ /**
+ * @expectedException \Elastica\Exception\InvalidException
+ *
+ * @group functional
+ */
+ public function testCreateArray()
+ {
+ $client = $this->_getClient();
+ $indexName = 'test';
+
+ //Testing recreate (backward compatibility)
+ $index = $client->getIndex($indexName);
+ $index->create(array(), true);
+ $this->_waitForAllocation($index);
+ $status = new Status($client);
+ $this->assertTrue($status->indexExists($indexName));
+
+ //Testing create index with array options
+ $opts = array('recreate' => true, 'routing' => 'r1,r2');
+ $index->create(array(), $opts);
+ $this->_waitForAllocation($index);
+ $status = new Status($client);
+ $this->assertTrue($status->indexExists($indexName));
+
+ //Testing invalid options
+ $opts = array('recreate' => true, 'routing' => 'r1,r2', 'testing_invalid_option' => true);
+ $index->create(array(), $opts);
+ $this->_waitForAllocation($index);
+ $status = new Status($client);
+ $this->assertTrue($status->indexExists($indexName));
+ }
+
+ /**
+ * @group functional
+ */
+ public function testCreateSearch()
+ {
+ $client = $this->_getClient();
+ $index = new Index($client, 'test');
+
+ $query = new QueryString('test');
+ $options = 5;
+
+ $search = $index->createSearch($query, $options);
+
+ $expected = array(
+ 'query' => array(
+ 'query_string' => array(
+ 'query' => 'test',
+ ),
+ ),
+ 'size' => 5,
+ );
+ $this->assertEquals($expected, $search->getQuery()->toArray());
+ $this->assertEquals(array('test'), $search->getIndices());
+ $this->assertTrue($search->hasIndices());
+ $this->assertTrue($search->hasIndex('test'));
+ $this->assertTrue($search->hasIndex($index));
+ $this->assertEquals(array(), $search->getTypes());
+ $this->assertFalse($search->hasTypes());
+ $this->assertFalse($search->hasType('test_type'));
+
+ $type = new Type($index, 'test_type2');
+ $this->assertFalse($search->hasType($type));
+ }
+
+ /**
+ * @group functional
+ */
+ public function testSearch()
+ {
+ $index = $this->_createIndex();
+
+ $type = new Type($index, 'user');
+
+ $docs = array();
+ $docs[] = new Document(1, array('username' => 'hans', 'test' => array('2', '3', '5')));
+ $docs[] = new Document(2, array('username' => 'john', 'test' => array('1', '3', '6')));
+ $docs[] = new Document(3, array('username' => 'rolf', 'test' => array('2', '3', '7')));
+ $type->addDocuments($docs);
+ $index->refresh();
+
+ $resultSet = $index->search('rolf');
+ $this->assertEquals(1, $resultSet->count());
+
+ $count = $index->count('rolf');
+ $this->assertEquals(1, $count);
+
+ // Test if source is returned
+ $result = $resultSet->current();
+ $this->assertEquals(3, $result->getId());
+ $data = $result->getData();
+ $this->assertEquals('rolf', $data['username']);
+
+ $count = $index->count();
+ $this->assertEquals(3, $count);
+ }
+
+ /**
+ * @group functional
+ */
+ public function testOptimize()
+ {
+ $index = $this->_createIndex();
+
+ $type = new Type($index, 'optimize');
+
+ $docs = array();
+ $docs[] = new Document(1, array('foo' => 'bar'));
+ $docs[] = new Document(2, array('foo' => 'bar'));
+ $type->addDocuments($docs);
+ $index->refresh();
+
+ $stats = $index->getStats()->getData();
+ $this->assertEquals(0, $stats['_all']['primaries']['docs']['deleted']);
+
+ $type->deleteById(1);
+ $index->refresh();
+
+ $stats = $index->getStats()->getData();
+ $this->assertEquals(1, $stats['_all']['primaries']['docs']['deleted']);
+
+ $index->optimize(array('max_num_segments' => 1));
+
+ $stats = $index->getStats()->getData();
+ $this->assertEquals(0, $stats['_all']['primaries']['docs']['deleted']);
+ }
+
+ /**
+ * @group functional
+ */
+ public function testAnalyze()
+ {
+ $index = $this->_createIndex();
+ $index->optimize();
+ sleep(2);
+ $returnedTokens = $index->analyze('foo');
+
+ $tokens = array(
+ array(
+ 'token' => 'foo',
+ 'start_offset' => 0,
+ 'end_offset' => 3,
+ 'type' => '<ALPHANUM>',
+ 'position' => 1,
+ ),
+ );
+
+ $this->assertEquals($tokens, $returnedTokens);
+ }
+
+ /**
+ * @group unit
+ * @expectedException \Elastica\Exception\InvalidException
+ */
+ public function testThrowExceptionIfNotScalar()
+ {
+ $client = $this->_getClient();
+ $client->getIndex(new \stdClass());
+ }
+
+ /**
+ * @group unit
+ */
+ public function testConvertScalarsToString()
+ {
+ $client = $this->_getClient();
+ $index = $client->getIndex(1);
+
+ $this->assertEquals('1', $index->getName());
+ $this->assertInternalType('string', $index->getName());
+ }
+
+ /**
+ * Check for the presence of the mapper-attachments plugin and skip the current test if it is not found.
+ */
+ protected function _checkAttachmentsPlugin()
+ {
+ $nodes = $this->_getClient()->getCluster()->getNodes();
+ if (!$nodes[0]->getInfo()->hasPlugin('mapper-attachments')) {
+ $this->markTestSkipped('mapper-attachments plugin not installed');
+ }
+ }
+}
diff --git a/vendor/ruflin/elastica/test/lib/Elastica/Test/LogTest.php b/vendor/ruflin/elastica/test/lib/Elastica/Test/LogTest.php
new file mode 100644
index 00000000..fdfc5c00
--- /dev/null
+++ b/vendor/ruflin/elastica/test/lib/Elastica/Test/LogTest.php
@@ -0,0 +1,196 @@
+<?php
+namespace Elastica\Test;
+
+use Elastica\Log;
+use Elastica\Test\Base as BaseTest;
+use Psr\Log\LogLevel;
+
+class LogTest extends BaseTest
+{
+ private $_context = array();
+ private $_message = 'hello world';
+
+ public static function setUpBeforeClass()
+ {
+ if (!class_exists('Psr\Log\AbstractLogger')) {
+ self::markTestSkipped('The Psr extension is not available.');
+ }
+ }
+
+ /**
+ * @group unit
+ */
+ public function testLogInterface()
+ {
+ $log = new Log();
+ $this->assertInstanceOf('Psr\Log\LoggerInterface', $log);
+ }
+
+ /**
+ * @group unit
+ */
+ public function testSetLogConfigPath()
+ {
+ $logPath = '/tmp/php.log';
+ $client = $this->_getClient(array('log' => $logPath));
+ $this->assertEquals($logPath, $client->getConfig('log'));
+ }
+
+ /**
+ * @group unit
+ */
+ public function testSetLogConfigEnable()
+ {
+ $client = $this->_getClient(array('log' => true));
+ $this->assertTrue($client->getConfig('log'));
+ }
+
+ /**
+ * @group unit
+ */
+ public function testSetLogConfigEnable1()
+ {
+ $client = $this->_getClient();
+ $client->setLogger(new Log());
+ $this->assertFalse($client->getConfig('log'));
+ }
+
+ /**
+ * @group unit
+ */
+ public function testEmptyLogConfig()
+ {
+ $client = $this->_getClient();
+ $this->assertEmpty($client->getConfig('log'));
+ }
+
+ /**
+ * @group unit
+ */
+ public function testGetLastMessage()
+ {
+ $log = new Log('/tmp/php.log');
+
+ $log->log(LogLevel::DEBUG, $this->_message, $this->_context);
+
+ $this->_context['error_message'] = $this->_message;
+ $message = json_encode($this->_context);
+
+ $this->assertEquals($message, $log->getLastMessage());
+ }
+
+ /**
+ * @group unit
+ */
+ public function testGetLastMessage2()
+ {
+ $client = $this->_getClient(array('log' => true));
+ $log = new Log($client);
+
+ // Set log path temp path as otherwise test fails with output
+ $errorLog = ini_get('error_log');
+ ini_set('error_log', sys_get_temp_dir().DIRECTORY_SEPARATOR.'php.log');
+
+ $this->_context['error_message'] = $this->_message;
+ $message = json_encode($this->_context);
+
+ $log->log(LogLevel::DEBUG, $this->_message, $this->_context);
+ ini_set('error_log', $errorLog);
+
+ $this->assertEquals($message, $log->getLastMessage());
+ }
+
+ /**
+ * @group unit
+ */
+ public function testGetLastMessageInfo()
+ {
+ $log = $this->initLog();
+ $log->info($this->_message, $this->_context);
+ $this->assertEquals($this->getMessage(), $log->getLastMessage());
+ }
+
+ /**
+ * @group unit
+ */
+ public function testGetLastMessageCritical()
+ {
+ $log = $this->initLog();
+ $log->critical($this->_message, $this->_context);
+ $this->assertEquals($this->getMessage(), $log->getLastMessage());
+ }
+
+ /**
+ * @group unit
+ */
+ public function testGetLastMessageAlert()
+ {
+ $log = $this->initLog();
+ $log->alert($this->_message, $this->_context);
+ $this->assertEquals($this->getMessage(), $log->getLastMessage());
+ }
+
+ /**
+ * @group unit
+ */
+ public function testGetLastMessageDebug()
+ {
+ $log = $this->initLog();
+ $log->debug($this->_message, $this->_context);
+ $this->assertEquals($this->getMessage(), $log->getLastMessage());
+ }
+
+ /**
+ * @group unit
+ */
+ public function testGetLastMessageEmergency()
+ {
+ $log = $this->initLog();
+ $log->emergency($this->_message, $this->_context);
+ $this->assertEquals($this->getMessage(), $log->getLastMessage());
+ }
+
+ /**
+ * @group unit
+ */
+ public function testGetLastMessageError()
+ {
+ $log = $this->initLog();
+ $log->error($this->_message, $this->_context);
+ $this->assertEquals($this->getMessage(), $log->getLastMessage());
+ }
+
+ /**
+ * @group unit
+ */
+ public function testGetLastMessageNotice()
+ {
+ $log = $this->initLog();
+ $log->notice($this->_message, $this->_context);
+ $this->assertEquals($this->getMessage(), $log->getLastMessage());
+ }
+
+ /**
+ * @group unit
+ */
+ public function testGetLastMessageWarning()
+ {
+ $log = $this->initLog();
+ $log->warning($this->_message, $this->_context);
+ $this->assertEquals($this->getMessage(), $log->getLastMessage());
+ }
+
+ private function initLog()
+ {
+ $log = new Log('/tmp/php.log');
+
+ return $log;
+ }
+
+ private function getMessage()
+ {
+ $this->_context['error_message'] = $this->_message;
+
+ return json_encode($this->_context);
+ }
+}
diff --git a/vendor/ruflin/elastica/test/lib/Elastica/Test/Multi/SearchTest.php b/vendor/ruflin/elastica/test/lib/Elastica/Test/Multi/SearchTest.php
new file mode 100644
index 00000000..765c8c1d
--- /dev/null
+++ b/vendor/ruflin/elastica/test/lib/Elastica/Test/Multi/SearchTest.php
@@ -0,0 +1,575 @@
+<?php
+namespace Elastica\Test\Multi;
+
+use Elastica\Document;
+use Elastica\Multi\Search as MultiSearch;
+use Elastica\Query;
+use Elastica\Query\Range;
+use Elastica\Query\Term;
+use Elastica\Search;
+use Elastica\Test\Base as BaseTest;
+
+class SearchTest extends BaseTest
+{
+ /**
+ * @return \Elastica\Type
+ */
+ protected function _createType()
+ {
+ $client = $this->_getClient();
+
+ $index = $client->getIndex('zero');
+ $index->create(array('index' => array('number_of_shards' => 1, 'number_of_replicas' => 0)), true);
+
+ $docs = array();
+ $docs[] = new Document(1, array('id' => 1, 'email' => 'test@test.com', 'username' => 'farrelley'));
+ $docs[] = new Document(2, array('id' => 1, 'email' => 'test@test.com', 'username' => 'farrelley'));
+ $docs[] = new Document(3, array('id' => 1, 'email' => 'test@test.com', 'username' => 'farrelley'));
+ $docs[] = new Document(4, array('id' => 1, 'email' => 'test@test.com', 'username' => 'kate'));
+ $docs[] = new Document(5, array('id' => 1, 'email' => 'test@test.com', 'username' => 'kate'));
+ $docs[] = new Document(6, array('id' => 1, 'email' => 'test@test.com', 'username' => 'bunny'));
+ $docs[] = new Document(7, array('id' => 1, 'email' => 'test@test.com', 'username' => 'bunny'));
+ $docs[] = new Document(8, array('id' => 1, 'email' => 'test@test.com', 'username' => 'bunny'));
+ $docs[] = new Document(9, array('id' => 1, 'email' => 'test@test.com', 'username' => 'bunny'));
+ $docs[] = new Document(10, array('id' => 1, 'email' => 'test@test.com', 'username' => 'bunny'));
+ $docs[] = new Document(11, array('id' => 1, 'email' => 'test@test.com', 'username' => 'bunny'));
+ $type = $index->getType('zeroType');
+ $type->addDocuments($docs);
+ $index->refresh();
+
+ return $type;
+ }
+
+ /**
+ * @group unit
+ */
+ public function testConstruct()
+ {
+ $client = $this->_getClient();
+ $multiSearch = new MultiSearch($client);
+
+ $this->assertInstanceOf('Elastica\Multi\Search', $multiSearch);
+ $this->assertSame($client, $multiSearch->getClient());
+ }
+
+ /**
+ * @group unit
+ */
+ public function testSetSearches()
+ {
+ $client = $this->_getClient();
+ $multiSearch = new MultiSearch($client);
+
+ $search1 = new Search($client);
+ $search2 = new Search($client);
+ $search3 = new Search($client);
+
+ $multiSearch->setSearches(array($search1, $search2, $search3));
+
+ $searches = $multiSearch->getSearches();
+
+ $this->assertInternalType('array', $searches);
+ $this->assertCount(3, $searches);
+ $this->assertArrayHasKey(0, $searches);
+ $this->assertSame($search1, $searches[0]);
+ $this->assertArrayHasKey(1, $searches);
+ $this->assertSame($search2, $searches[1]);
+ $this->assertArrayHasKey(2, $searches);
+ $this->assertSame($search3, $searches[2]);
+
+ $multiSearch->clearSearches();
+ $searches = $multiSearch->getSearches();
+
+ $this->assertInternalType('array', $searches);
+ $this->assertCount(0, $searches);
+ }
+
+ /**
+ * @group unit
+ */
+ public function testSetSearchesByKeys()
+ {
+ $client = $this->_getClient();
+ $multiSearch = new MultiSearch($client);
+
+ $search1 = new Search($client);
+ $search2 = new Search($client);
+ $search3 = new Search($client);
+
+ $multiSearch->setSearches(array('search1' => $search1, 'search2' => $search2, $search3));
+
+ $searches = $multiSearch->getSearches();
+
+ $this->assertInternalType('array', $searches);
+ $this->assertCount(3, $searches);
+ $this->assertArrayHasKey('search1', $searches);
+ $this->assertSame($search1, $searches['search1']);
+ $this->assertArrayHasKey('search2', $searches);
+ $this->assertSame($search2, $searches['search2']);
+ $this->assertArrayHasKey(0, $searches);
+ $this->assertSame($search3, $searches[0]);
+
+ $multiSearch->clearSearches();
+ $searches = $multiSearch->getSearches();
+
+ $this->assertInternalType('array', $searches);
+ $this->assertCount(0, $searches);
+ }
+
+ /**
+ * @group functional
+ */
+ public function testSearch()
+ {
+ $type = $this->_createType();
+ $index = $type->getIndex();
+ $client = $index->getClient();
+
+ $multiSearch = new MultiSearch($client);
+
+ $search1 = new Search($client);
+ $search1->addIndex($index)->addType($type);
+ $query1 = new Query();
+ $termQuery1 = new Term();
+ $termQuery1->setTerm('username', 'farrelley');
+ $query1->setQuery($termQuery1);
+ $query1->setSize(2);
+ $search1->setQuery($query1);
+
+ $multiSearch->addSearch($search1);
+
+ $this->assertCount(1, $multiSearch->getSearches());
+
+ $search2 = new Search($client);
+ $search2->addIndex($index)->addType($type);
+ $query2 = new Query();
+ $termQuery2 = new Term();
+ $termQuery2->setTerm('username', 'bunny');
+ $query2->setQuery($termQuery2);
+ $query2->setSize(3);
+ $search2->setQuery($query2);
+
+ $multiSearch->addSearch($search2);
+
+ $this->assertCount(2, $multiSearch->getSearches());
+
+ $searches = $multiSearch->getSearches();
+ $this->assertSame($search1, $searches[0]);
+ $this->assertSame($search2, $searches[1]);
+
+ $multiResultSet = $multiSearch->search();
+
+ $this->assertInstanceOf('Elastica\Multi\ResultSet', $multiResultSet);
+ $this->assertCount(2, $multiResultSet);
+ $this->assertInstanceOf('Elastica\Response', $multiResultSet->getResponse());
+
+ foreach ($multiResultSet as $resultSet) {
+ $this->assertInstanceOf('Elastica\ResultSet', $resultSet);
+ }
+
+ $resultSets = $multiResultSet->getResultSets();
+
+ $this->assertInternalType('array', $resultSets);
+
+ $this->assertArrayHasKey(0, $resultSets);
+ $this->assertInstanceOf('Elastica\ResultSet', $resultSets[0]);
+ $this->assertCount(2, $resultSets[0]);
+ $this->assertSame($query1, $resultSets[0]->getQuery());
+ $this->assertEquals(3, $resultSets[0]->getTotalHits());
+
+ $this->assertArrayHasKey(1, $resultSets);
+ $this->assertInstanceOf('Elastica\ResultSet', $resultSets[1]);
+ $this->assertCount(3, $resultSets[1]);
+ $this->assertSame($query2, $resultSets[1]->getQuery());
+ $this->assertEquals(6, $resultSets[1]->getTotalHits());
+
+ $this->assertFalse($multiResultSet->hasError());
+
+ $search1->setOption(Search::OPTION_SEARCH_TYPE, Search::OPTION_SEARCH_TYPE_COUNT);
+ $search2->setOption(Search::OPTION_SEARCH_TYPE, Search::OPTION_SEARCH_TYPE_COUNT);
+
+ $multiResultSet = $multiSearch->search();
+
+ $this->assertInstanceOf('Elastica\Multi\ResultSet', $multiResultSet);
+ $this->assertCount(2, $multiResultSet);
+ $this->assertInstanceOf('Elastica\Response', $multiResultSet->getResponse());
+
+ $resultSets = $multiResultSet->getResultSets();
+
+ $this->assertInternalType('array', $resultSets);
+
+ $this->assertArrayHasKey(0, $resultSets);
+ $this->assertInstanceOf('Elastica\ResultSet', $resultSets[0]);
+ $this->assertCount(0, $resultSets[0]);
+ $this->assertSame($query1, $resultSets[0]->getQuery());
+ $this->assertEquals(3, $resultSets[0]->getTotalHits());
+
+ $this->assertArrayHasKey(1, $resultSets);
+ $this->assertInstanceOf('Elastica\ResultSet', $resultSets[1]);
+ $this->assertCount(0, $resultSets[1]);
+ $this->assertSame($query2, $resultSets[1]->getQuery());
+ $this->assertEquals(6, $resultSets[1]->getTotalHits());
+ }
+
+ /**
+ * @group functional
+ */
+ public function testSearchWithKeys()
+ {
+ $type = $this->_createType();
+ $index = $type->getIndex();
+ $client = $index->getClient();
+
+ $multiSearch = new MultiSearch($client);
+
+ $search1 = new Search($client);
+ $search1->addIndex($index)->addType($type);
+ $query1 = new Query();
+ $termQuery1 = new Term();
+ $termQuery1->setTerm('username', 'farrelley');
+ $query1->setQuery($termQuery1);
+ $query1->setSize(2);
+ $search1->setQuery($query1);
+
+ $multiSearch->addSearch($search1, 'search1');
+
+ $this->assertCount(1, $multiSearch->getSearches());
+
+ $search2 = new Search($client);
+ $search2->addIndex($index)->addType($type);
+ $query2 = new Query();
+ $termQuery2 = new Term();
+ $termQuery2->setTerm('username', 'bunny');
+ $query2->setQuery($termQuery2);
+ $query2->setSize(3);
+ $search2->setQuery($query2);
+
+ $multiSearch->addSearch($search2, 'search2');
+
+ $this->assertCount(2, $multiSearch->getSearches());
+
+ $searches = $multiSearch->getSearches();
+ $this->assertSame($search1, $searches['search1']);
+ $this->assertSame($search2, $searches['search2']);
+
+ $multiResultSet = $multiSearch->search();
+
+ $this->assertInstanceOf('Elastica\Multi\ResultSet', $multiResultSet);
+ $this->assertCount(2, $multiResultSet);
+ $this->assertInstanceOf('Elastica\Response', $multiResultSet->getResponse());
+
+ foreach ($multiResultSet as $resultSet) {
+ $this->assertInstanceOf('Elastica\ResultSet', $resultSet);
+ }
+
+ $this->assertInstanceOf('Elastica\ResultSet', $multiResultSet['search1']);
+ $this->assertInstanceOf('Elastica\ResultSet', $multiResultSet['search2']);
+
+ $resultSets = $multiResultSet->getResultSets();
+
+ $this->assertInternalType('array', $resultSets);
+
+ $this->assertArrayHasKey('search1', $resultSets);
+ $this->assertInstanceOf('Elastica\ResultSet', $resultSets['search1']);
+ $this->assertCount(2, $resultSets['search1']);
+ $this->assertSame($query1, $resultSets['search1']->getQuery());
+ $this->assertEquals(3, $resultSets['search1']->getTotalHits());
+
+ $this->assertArrayHasKey('search2', $resultSets);
+ $this->assertInstanceOf('Elastica\ResultSet', $resultSets['search2']);
+ $this->assertCount(3, $resultSets['search2']);
+ $this->assertSame($query2, $resultSets['search2']->getQuery());
+ $this->assertEquals(6, $resultSets['search2']->getTotalHits());
+
+ $this->assertFalse($multiResultSet->hasError());
+
+ $search1->setOption(Search::OPTION_SEARCH_TYPE, Search::OPTION_SEARCH_TYPE_COUNT);
+ $search2->setOption(Search::OPTION_SEARCH_TYPE, Search::OPTION_SEARCH_TYPE_COUNT);
+
+ $multiResultSet = $multiSearch->search();
+
+ $this->assertInstanceOf('Elastica\Multi\ResultSet', $multiResultSet);
+ $this->assertCount(2, $multiResultSet);
+ $this->assertInstanceOf('Elastica\Response', $multiResultSet->getResponse());
+
+ $resultSets = $multiResultSet->getResultSets();
+
+ $this->assertInternalType('array', $resultSets);
+
+ $this->assertArrayHasKey('search1', $resultSets);
+ $this->assertInstanceOf('Elastica\ResultSet', $resultSets['search1']);
+ $this->assertCount(0, $resultSets['search1']);
+ $this->assertSame($query1, $resultSets['search1']->getQuery());
+ $this->assertEquals(3, $resultSets['search1']->getTotalHits());
+
+ $this->assertArrayHasKey('search2', $resultSets);
+ $this->assertInstanceOf('Elastica\ResultSet', $resultSets['search2']);
+ $this->assertCount(0, $resultSets['search2']);
+ $this->assertSame($query2, $resultSets['search2']->getQuery());
+ $this->assertEquals(6, $resultSets['search2']->getTotalHits());
+ }
+
+ /**
+ * @group functional
+ */
+ public function testSearchWithError()
+ {
+ $type = $this->_createType();
+ $index = $type->getIndex();
+ $client = $index->getClient();
+
+ $multiSearch = new MultiSearch($client);
+
+ $searchGood = new Search($client);
+ $searchGood->setQuery('bunny');
+ $searchGood->addIndex($index)->addType($type);
+
+ $multiSearch->addSearch($searchGood);
+
+ $searchBad = new Search($client);
+ $searchBadQuery = new Range();
+ $searchBadQuery->addField('bad', array('from' => 0));
+ $searchBadQuery->setParam('_cache', true);
+ $searchBad->setQuery($searchBadQuery);
+ $searchBad->addIndex($index)->addType($type);
+
+ $multiSearch->addSearch($searchBad);
+
+ $multiResultSet = $multiSearch->search();
+
+ $this->assertInstanceOf('Elastica\Multi\ResultSet', $multiResultSet);
+ $resultSets = $multiResultSet->getResultSets();
+ $this->assertInternalType('array', $resultSets);
+
+ $this->assertArrayHasKey(0, $resultSets);
+ $this->assertInstanceOf('Elastica\ResultSet', $resultSets[0]);
+ $this->assertSame($searchGood->getQuery(), $resultSets[0]->getQuery());
+ $this->assertSame(6, $resultSets[0]->getTotalHits());
+ $this->assertCount(6, $resultSets[0]);
+
+ $this->assertArrayHasKey(1, $resultSets);
+ $this->assertInstanceOf('Elastica\ResultSet', $resultSets[1]);
+ $this->assertSame($searchBad->getQuery(), $resultSets[1]->getQuery());
+ $this->assertSame(0, $resultSets[1]->getTotalHits());
+ $this->assertCount(0, $resultSets[1]);
+ $this->assertTrue($resultSets[1]->getResponse()->hasError());
+
+ $this->assertTrue($multiResultSet->hasError());
+ }
+
+ /**
+ * @group functional
+ */
+ public function testSearchWithErrorWithKeys()
+ {
+ $type = $this->_createType();
+ $index = $type->getIndex();
+ $client = $index->getClient();
+
+ $multiSearch = new MultiSearch($client);
+
+ $searchGood = new Search($client);
+ $searchGood->setQuery('bunny');
+ $searchGood->addIndex($index)->addType($type);
+
+ $multiSearch->addSearch($searchGood, 'search1');
+
+ $searchBad = new Search($client);
+ $searchBadQuery = new Range();
+ $searchBadQuery->addField('bad', array('from' => 0));
+ $searchBadQuery->setParam('_cache', true);
+ $searchBad->setQuery($searchBadQuery);
+ $searchBad->addIndex($index)->addType($type);
+
+ $multiSearch->addSearch($searchBad);
+
+ $multiResultSet = $multiSearch->search();
+
+ $this->assertInstanceOf('Elastica\Multi\ResultSet', $multiResultSet);
+ $resultSets = $multiResultSet->getResultSets();
+ $this->assertInternalType('array', $resultSets);
+
+ $this->assertArrayHasKey('search1', $resultSets);
+ $this->assertInstanceOf('Elastica\ResultSet', $resultSets['search1']);
+ $this->assertSame($searchGood->getQuery(), $resultSets['search1']->getQuery());
+ $this->assertSame(6, $resultSets['search1']->getTotalHits());
+ $this->assertCount(6, $resultSets['search1']);
+
+ $this->assertArrayHasKey(0, $resultSets);
+ $this->assertInstanceOf('Elastica\ResultSet', $resultSets[0]);
+ $this->assertSame($searchBad->getQuery(), $resultSets[0]->getQuery());
+ $this->assertSame(0, $resultSets[0]->getTotalHits());
+ $this->assertCount(0, $resultSets[0]);
+ $this->assertTrue($resultSets[0]->getResponse()->hasError());
+
+ $this->assertTrue($multiResultSet->hasError());
+ }
+
+ /**
+ * @group functional
+ */
+ public function testGlobalSearchTypeSearch()
+ {
+ $type = $this->_createType();
+ $index = $type->getIndex();
+ $client = $index->getClient();
+
+ $multiSearch = new MultiSearch($client);
+
+ $search1 = new Search($client);
+ $search1->addIndex($index)->addType($type);
+ $query1 = new Query();
+ $termQuery1 = new Term();
+ $termQuery1->setTerm('username', 'farrelley');
+ $query1->setQuery($termQuery1);
+ $query1->setSize(2);
+ $search1->setQuery($query1);
+
+ $multiSearch->addSearch($search1);
+
+ $this->assertCount(1, $multiSearch->getSearches());
+
+ $search2 = new Search($client);
+ $search2->addIndex($index)->addType($type);
+ $query2 = new Query();
+ $termQuery2 = new Term();
+ $termQuery2->setTerm('username', 'bunny');
+ $query2->setQuery($termQuery2);
+ $query2->setSize(3);
+ $search2->setQuery($query2);
+
+ $multiSearch->addSearch($search2);
+
+ $multiSearch->setSearchType(Search::OPTION_SEARCH_TYPE_COUNT);
+
+ $multiResultSet = $multiSearch->search();
+
+ $this->assertInstanceOf('Elastica\Multi\ResultSet', $multiResultSet);
+ $this->assertCount(2, $multiResultSet);
+ $this->assertInstanceOf('Elastica\Response', $multiResultSet->getResponse());
+
+ $resultSets = $multiResultSet->getResultSets();
+
+ $this->assertInternalType('array', $resultSets);
+
+ $this->assertArrayHasKey(0, $resultSets);
+ $this->assertInstanceOf('Elastica\ResultSet', $resultSets[0]);
+ $this->assertCount(0, $resultSets[0]);
+ $this->assertSame($query1, $resultSets[0]->getQuery());
+ $this->assertEquals(3, $resultSets[0]->getTotalHits());
+
+ $this->assertArrayHasKey(1, $resultSets);
+ $this->assertInstanceOf('Elastica\ResultSet', $resultSets[1]);
+ $this->assertCount(0, $resultSets[1]);
+ $this->assertSame($query2, $resultSets[1]->getQuery());
+ $this->assertEquals(6, $resultSets[1]->getTotalHits());
+
+ $search1->setOption(Search::OPTION_SEARCH_TYPE, Search::OPTION_SEARCH_TYPE_QUERY_AND_FETCH);
+
+ $multiResultSet = $multiSearch->search();
+
+ $this->assertInstanceOf('Elastica\Multi\ResultSet', $multiResultSet);
+ $this->assertCount(2, $multiResultSet);
+ $this->assertInstanceOf('Elastica\Response', $multiResultSet->getResponse());
+
+ $resultSets = $multiResultSet->getResultSets();
+
+ $this->assertInternalType('array', $resultSets);
+
+ $this->assertArrayHasKey(0, $resultSets);
+ $this->assertInstanceOf('Elastica\ResultSet', $resultSets[0]);
+ $this->assertCount(2, $resultSets[0]);
+ $this->assertSame($query1, $resultSets[0]->getQuery());
+ $this->assertEquals(3, $resultSets[0]->getTotalHits());
+
+ $this->assertArrayHasKey(1, $resultSets);
+ $this->assertInstanceOf('Elastica\ResultSet', $resultSets[1]);
+ $this->assertCount(0, $resultSets[1]);
+ $this->assertSame($query2, $resultSets[1]->getQuery());
+ $this->assertEquals(6, $resultSets[1]->getTotalHits());
+ }
+
+ /**
+ * @group functional
+ */
+ public function testGlobalSearchTypeSearchWithKeys()
+ {
+ $type = $this->_createType();
+ $index = $type->getIndex();
+ $client = $index->getClient();
+
+ $multiSearch = new MultiSearch($client);
+
+ $search1 = new Search($client);
+ $search1->addIndex($index)->addType($type);
+ $query1 = new Query();
+ $termQuery1 = new Term();
+ $termQuery1->setTerm('username', 'farrelley');
+ $query1->setQuery($termQuery1);
+ $query1->setSize(2);
+ $search1->setQuery($query1);
+
+ $multiSearch->addSearch($search1);
+
+ $this->assertCount(1, $multiSearch->getSearches());
+
+ $search2 = new Search($client);
+ $search2->addIndex($index)->addType($type);
+ $query2 = new Query();
+ $termQuery2 = new Term();
+ $termQuery2->setTerm('username', 'bunny');
+ $query2->setQuery($termQuery2);
+ $query2->setSize(3);
+ $search2->setQuery($query2);
+
+ $multiSearch->addSearch($search2);
+
+ $multiSearch->setSearchType(Search::OPTION_SEARCH_TYPE_COUNT);
+
+ $multiResultSet = $multiSearch->search();
+
+ $this->assertInstanceOf('Elastica\Multi\ResultSet', $multiResultSet);
+ $this->assertCount(2, $multiResultSet);
+ $this->assertInstanceOf('Elastica\Response', $multiResultSet->getResponse());
+
+ $resultSets = $multiResultSet->getResultSets();
+
+ $this->assertInternalType('array', $resultSets);
+
+ $this->assertArrayHasKey(0, $resultSets);
+ $this->assertInstanceOf('Elastica\ResultSet', $resultSets[0]);
+ $this->assertCount(0, $resultSets[0]);
+ $this->assertSame($query1, $resultSets[0]->getQuery());
+ $this->assertEquals(3, $resultSets[0]->getTotalHits());
+
+ $this->assertArrayHasKey(1, $resultSets);
+ $this->assertInstanceOf('Elastica\ResultSet', $resultSets[1]);
+ $this->assertCount(0, $resultSets[1]);
+ $this->assertSame($query2, $resultSets[1]->getQuery());
+ $this->assertEquals(6, $resultSets[1]->getTotalHits());
+
+ $search1->setOption(Search::OPTION_SEARCH_TYPE, Search::OPTION_SEARCH_TYPE_QUERY_AND_FETCH);
+
+ $multiResultSet = $multiSearch->search();
+
+ $this->assertInstanceOf('Elastica\Multi\ResultSet', $multiResultSet);
+ $this->assertCount(2, $multiResultSet);
+ $this->assertInstanceOf('Elastica\Response', $multiResultSet->getResponse());
+
+ $resultSets = $multiResultSet->getResultSets();
+
+ $this->assertInternalType('array', $resultSets);
+
+ $this->assertArrayHasKey(0, $resultSets);
+ $this->assertInstanceOf('Elastica\ResultSet', $resultSets[0]);
+ $this->assertCount(2, $resultSets[0]);
+ $this->assertSame($query1, $resultSets[0]->getQuery());
+ $this->assertEquals(3, $resultSets[0]->getTotalHits());
+
+ $this->assertArrayHasKey(1, $resultSets);
+ $this->assertInstanceOf('Elastica\ResultSet', $resultSets[1]);
+ $this->assertCount(0, $resultSets[1]);
+ $this->assertSame($query2, $resultSets[1]->getQuery());
+ $this->assertEquals(6, $resultSets[1]->getTotalHits());
+ }
+}
diff --git a/vendor/ruflin/elastica/test/lib/Elastica/Test/Node/InfoTest.php b/vendor/ruflin/elastica/test/lib/Elastica/Test/Node/InfoTest.php
new file mode 100644
index 00000000..812f141e
--- /dev/null
+++ b/vendor/ruflin/elastica/test/lib/Elastica/Test/Node/InfoTest.php
@@ -0,0 +1,79 @@
+<?php
+namespace Elastica\Test\Node;
+
+use Elastica\Node;
+use Elastica\Node\Info as NodeInfo;
+use Elastica\Test\Base as BaseTest;
+
+class InfoTest extends BaseTest
+{
+ /**
+ * @group functional
+ */
+ public function testGet()
+ {
+ $client = $this->_getClient();
+ $names = $client->getCluster()->getNodeNames();
+ $name = reset($names);
+
+ $node = new Node($name, $client);
+ $info = new NodeInfo($node);
+
+ $this->assertNull($info->get('os', 'mem', 'total'));
+
+ // Load os infos
+ $info = new NodeInfo($node, array('os'));
+
+ $this->assertNotNull($info->get('os', 'mem', 'total_in_bytes'));
+ $this->assertInternalType('array', $info->get('os', 'mem'));
+ $this->assertNull($info->get('test', 'notest', 'notexist'));
+ }
+
+ /**
+ * @group functional
+ */
+ public function testHasPlugin()
+ {
+ $client = $this->_getClient();
+ $nodes = $client->getCluster()->getNodes();
+ $node = $nodes[0];
+ $info = $node->getInfo();
+
+ $pluginName = 'mapper-attachments';
+
+ $this->assertTrue($info->hasPlugin($pluginName));
+ $this->assertFalse($info->hasPlugin('foo'));
+ }
+
+ /**
+ * @group functional
+ */
+ public function testGetId()
+ {
+ $client = $this->_getClient();
+ $nodes = $client->getCluster()->getNodes();
+
+ $ids = array();
+
+ foreach ($nodes as $node) {
+ $id = $node->getInfo()->getId();
+
+ // Checks that the ids are unique
+ $this->assertFalse(in_array($id, $ids));
+ $ids[] = $id;
+ }
+ }
+
+ /**
+ * @group functional
+ */
+ public function testGetName()
+ {
+ $client = $this->_getClient();
+ $nodes = $client->getCluster()->getNodes();
+
+ foreach ($nodes as $node) {
+ $this->assertEquals('Elastica', $node->getInfo()->getName());
+ }
+ }
+}
diff --git a/vendor/ruflin/elastica/test/lib/Elastica/Test/NodeTest.php b/vendor/ruflin/elastica/test/lib/Elastica/Test/NodeTest.php
new file mode 100644
index 00000000..fbd2d297
--- /dev/null
+++ b/vendor/ruflin/elastica/test/lib/Elastica/Test/NodeTest.php
@@ -0,0 +1,75 @@
+<?php
+namespace Elastica\Test;
+
+use Elastica\Node;
+use Elastica\Test\Base as BaseTest;
+
+class NodeTest extends BaseTest
+{
+ /**
+ * @group functional
+ */
+ public function testCreateNode()
+ {
+ $client = $this->_getClient();
+ $names = $client->getCluster()->getNodeNames();
+ $name = reset($names);
+
+ $node = new Node($name, $client);
+ $this->assertInstanceOf('Elastica\Node', $node);
+ }
+
+ /**
+ * @group functional
+ */
+ public function testGetInfo()
+ {
+ $client = $this->_getClient();
+ $names = $client->getCluster()->getNodeNames();
+ $name = reset($names);
+
+ $node = new Node($name, $client);
+
+ $info = $node->getInfo();
+
+ $this->assertInstanceOf('Elastica\Node\Info', $info);
+ }
+
+ /**
+ * @group functional
+ */
+ public function testGetStats()
+ {
+ $client = $this->_getClient();
+ $names = $client->getCluster()->getNodeNames();
+ $name = reset($names);
+
+ $node = new Node($name, $client);
+
+ $stats = $node->getStats();
+
+ $this->assertInstanceOf('Elastica\Node\Stats', $stats);
+ }
+
+ /**
+ * @group functional
+ */
+ public function testGetName()
+ {
+ $nodes = $this->_getClient()->getCluster()->getNodes();
+ // At least 1 instance must exist
+ $this->assertGreaterThan(0, $nodes);
+
+ foreach ($nodes as $node) {
+ $this->assertEquals($node->getName(), 'Elastica');
+ }
+ }
+
+ /**
+ * @group functional
+ */
+ public function testGetId()
+ {
+ $node = new Node('Elastica', $this->_getClient());
+ }
+}
diff --git a/vendor/ruflin/elastica/test/lib/Elastica/Test/ParamTest.php b/vendor/ruflin/elastica/test/lib/Elastica/Test/ParamTest.php
new file mode 100644
index 00000000..eade8118
--- /dev/null
+++ b/vendor/ruflin/elastica/test/lib/Elastica/Test/ParamTest.php
@@ -0,0 +1,115 @@
+<?php
+namespace Elastica\Test;
+
+use Elastica\Param;
+use Elastica\Test\Base as BaseTest;
+use Elastica\Util;
+
+class ParamTest extends BaseTest
+{
+ /**
+ * @group unit
+ */
+ public function testToArrayEmpty()
+ {
+ $param = new Param();
+ $this->assertInstanceOf('Elastica\Param', $param);
+ $this->assertEquals(array($this->_getFilterName($param) => array()), $param->toArray());
+ }
+
+ /**
+ * @group unit
+ */
+ public function testSetParams()
+ {
+ $param = new Param();
+ $params = array('hello' => 'word', 'nicolas' => 'ruflin');
+ $param->setParams($params);
+
+ $this->assertInstanceOf('Elastica\Param', $param);
+ $this->assertEquals(array($this->_getFilterName($param) => $params), $param->toArray());
+ }
+
+ /**
+ * @group unit
+ */
+ public function testSetGetParam()
+ {
+ $param = new Param();
+
+ $key = 'name';
+ $value = 'nicolas ruflin';
+
+ $params = array($key => $value);
+ $param->setParam($key, $value);
+
+ $this->assertEquals($params, $param->getParams());
+ $this->assertEquals($value, $param->getParam($key));
+ }
+
+ /**
+ * @group unit
+ */
+ public function testAddParam()
+ {
+ $param = new Param();
+
+ $key = 'name';
+ $value = 'nicolas ruflin';
+
+ $param->addParam($key, $value);
+
+ $this->assertEquals(array($key => array($value)), $param->getParams());
+ $this->assertEquals(array($value), $param->getParam($key));
+ }
+
+ /**
+ * @group unit
+ */
+ public function testAddParam2()
+ {
+ $param = new Param();
+
+ $key = 'name';
+ $value1 = 'nicolas';
+ $value2 = 'ruflin';
+
+ $param->addParam($key, $value1);
+ $param->addParam($key, $value2);
+
+ $this->assertEquals(array($key => array($value1, $value2)), $param->getParams());
+ $this->assertEquals(array($value1, $value2), $param->getParam($key));
+ }
+
+ /**
+ * @group unit
+ * @expectedException \Elastica\Exception\InvalidException
+ */
+ public function testGetParamInvalid()
+ {
+ $param = new Param();
+
+ $param->getParam('notest');
+ }
+
+ /**
+ * @group unit
+ */
+ public function testHasParam()
+ {
+ $param = new Param();
+
+ $key = 'name';
+ $value = 'nicolas ruflin';
+
+ $this->assertFalse($param->hasParam($key));
+
+ $param->setParam($key, $value);
+ $this->assertTrue($param->hasParam($key));
+ }
+
+ protected function _getFilterName($filter)
+ {
+ return Util::getParamName($filter);
+ }
+}
diff --git a/vendor/ruflin/elastica/test/lib/Elastica/Test/PercolatorTest.php b/vendor/ruflin/elastica/test/lib/Elastica/Test/PercolatorTest.php
new file mode 100644
index 00000000..2a5a88c3
--- /dev/null
+++ b/vendor/ruflin/elastica/test/lib/Elastica/Test/PercolatorTest.php
@@ -0,0 +1,328 @@
+<?php
+namespace Elastica\Test;
+
+use Elastica\Document;
+use Elastica\Index;
+use Elastica\Percolator;
+use Elastica\Query;
+use Elastica\Query\Term;
+use Elastica\Test\Base as BaseTest;
+use Elastica\Type;
+
+class PercolatorTest extends BaseTest
+{
+ /**
+ * @group functional
+ */
+ public function testConstruct()
+ {
+ $index = $this->_createIndex();
+ $percolatorName = $index->getName();
+
+ $percolator = new Percolator($index);
+
+ $query = new Term(array('field1' => 'value1'));
+ $response = $percolator->registerQuery($percolatorName, $query);
+
+ $data = $response->getData();
+
+ $expectedArray = array(
+ '_type' => '.percolator',
+ '_index' => $index->getName(),
+ '_id' => $percolatorName,
+ '_version' => 1,
+ 'created' => 1,
+ );
+
+ $this->assertEquals($expectedArray, $data);
+
+ $index->delete();
+ }
+
+ /**
+ * @group functional
+ */
+ public function testMatchDoc()
+ {
+ $index = $this->_createIndex();
+
+ $percolator = new Percolator($index);
+
+ $percolatorName = $index->getName();
+
+ $query = new Term(array('name' => 'ruflin'));
+ $response = $percolator->registerQuery($percolatorName, $query);
+
+ $this->assertTrue($response->isOk());
+ $this->assertFalse($response->hasError());
+
+ $doc1 = new Document();
+ $doc1->set('name', 'ruflin');
+
+ $doc2 = new Document();
+ $doc2->set('name', 'nicolas');
+
+ $index->refresh();
+
+ $matches1 = $percolator->matchDoc($doc1);
+
+ $this->assertCount(1, $matches1);
+ $firstPercolatorFound = false;
+ foreach ($matches1 as $match) {
+ if ($match['_id'] == $percolatorName) {
+ $firstPercolatorFound = true;
+ }
+ }
+ $this->assertTrue($firstPercolatorFound);
+
+ $matches2 = $percolator->matchDoc($doc2);
+ $this->assertEmpty($matches2);
+
+ $index->delete();
+ }
+
+ /**
+ * Test case for using filtered percolator queries based on the Elasticsearch documentation examples.
+ *
+ * @group functional
+ */
+ public function testFilteredMatchDoc()
+ {
+ // step one: register create index and setup the percolator query from the ES documentation.
+ $index = $this->_createIndex();
+ $percolator = new Percolator($index);
+ $baseQuery = new Term(array('field1' => 'value1'));
+ $fields = array('color' => 'blue');
+
+ $response = $percolator->registerQuery('kuku', $baseQuery, $fields);
+
+ $this->assertTrue($response->isOk());
+ $this->assertFalse($response->hasError());
+
+ // refreshing is required in order to ensure the query is really ready for execution.
+ $index->refresh();
+
+ // step two: match a document which should match the kuku query when filtered on the blue color
+ $doc = new Document();
+ $doc->set('field1', 'value1');
+
+ $matches = $percolator->matchDoc($doc, new Term(array('color' => 'blue')));
+ $this->assertCount(1, $matches, 'No or too much registered query matched.');
+ $this->assertEquals('kuku', $matches[0]['_id'], 'A wrong registered query has matched.');
+
+ // step three: validate that using a different color, no registered query matches.
+ $matches = $percolator->matchDoc($doc, new Term(array('color' => 'green')));
+ $this->assertCount(0, $matches, 'A registered query matched, although nothing should match at all.');
+
+ $index->delete();
+ }
+
+ /**
+ * Test case for using filtered percolator queries based on the Elasticsearch documentation examples.
+ *
+ * @group functional
+ */
+ public function testRegisterAndUnregisterPercolator()
+ {
+ // step one: register create index and setup the percolator query from the ES documentation.
+ $index = $this->_createIndex();
+ $percolator = new Percolator($index);
+ $baseQuery = new Term(array('field1' => 'value1'));
+ $fields = array('color' => 'blue');
+
+ $response = $percolator->registerQuery('kuku', $baseQuery, $fields);
+
+ $this->assertTrue($response->isOk());
+ $this->assertFalse($response->hasError());
+
+ // refreshing is required in order to ensure the query is really ready for execution.
+ $index->refresh();
+
+ // step two: match a document which should match the kuku query when filtered on the blue color
+ $doc = new Document();
+ $doc->set('field1', 'value1');
+
+ $matches = $percolator->matchDoc($doc, new Term(array('color' => 'blue')));
+ $this->assertCount(1, $matches, 'No or too much registered query matched.');
+ $this->assertEquals('kuku', $matches[0]['_id'], 'A wrong registered query has matched.');
+
+ // step three: validate that using a different color, no registered query matches.
+ $matches = $percolator->matchDoc($doc, new Term(array('color' => 'green')));
+ $this->assertCount(0, $matches, 'A registered query matched, although nothing should match at all.');
+
+ // unregister percolator query
+ $response = $percolator->unregisterQuery('kuku');
+
+ $this->assertTrue($response->isOk());
+ $this->assertFalse($response->hasError());
+
+ // refreshing is required in order to ensure the query is really ready for execution.
+ $index->refresh();
+
+ $matches = $percolator->matchDoc($doc, new Term(array('color' => 'blue')));
+ $this->assertCount(0, $matches, 'Percolator query did not get deleted.');
+
+ $index->delete();
+ }
+
+ protected function _getDefaultPercolator($percolatorName = 'existingDoc')
+ {
+ $index = $this->_createIndex();
+ $percolator = new Percolator($index);
+
+ $query = new Term(array('name' => 'foobar'));
+ $percolator->registerQuery($percolatorName, $query, array('field1' => array('tag1', 'tag2')));
+
+ return $percolator;
+ }
+
+ protected function _addDefaultDocuments($index, $type = 'testing')
+ {
+ $type = $index->getType('testing');
+ $type->addDocuments(array(
+ new Document(1, array('name' => 'foobar')),
+ new Document(2, array('name' => 'barbaz')),
+ ));
+ $index->refresh();
+
+ return $type;
+ }
+
+ /**
+ * @group functional
+ */
+ public function testPercolateExistingDocWithoutAnyParameter()
+ {
+ $percolator = $this->_getDefaultPercolator();
+ $index = $percolator->getIndex();
+ $type = $this->_addDefaultDocuments($index);
+
+ $matches = $percolator->matchExistingDoc(1, $type->getName());
+
+ $this->assertCount(1, $matches);
+ $this->assertEquals('existingDoc', $matches[0]['_id']);
+ $index->delete();
+ }
+
+ /**
+ * @group functional
+ */
+ public function testPercolateExistingDocWithPercolateFormatIds()
+ {
+ $percolator = $this->_getDefaultPercolator();
+ $index = $percolator->getIndex();
+ $type = $this->_addDefaultDocuments($index);
+
+ $parameter = array('percolate_format' => 'ids');
+ $matches = $percolator->matchExistingDoc(1, $type->getName(), null, $parameter);
+
+ $this->assertCount(1, $matches);
+ $this->assertEquals('existingDoc', $matches[0]);
+ $index->delete();
+ }
+
+ /**
+ * @group functional
+ */
+ public function testPercolateExistingDocWithIdThatShouldBeUrlEncoded()
+ {
+ $percolator = $this->_getDefaultPercolator();
+ $index = $percolator->getIndex();
+ $type = $this->_addDefaultDocuments($index);
+
+ // id with whitespace, should be urlencoded
+ $id = 'foo bar 1';
+
+ $type->addDocument(new Document($id, array('name' => 'foobar')));
+ $index->refresh();
+
+ $matches = $percolator->matchExistingDoc($id, $type->getName());
+
+ $this->assertCount(1, $matches);
+ $index->delete();
+ }
+
+ /**
+ * @group functional
+ */
+ public function testPercolateWithAdditionalRequestBodyOptions()
+ {
+ $index = $this->_createIndex();
+ $percolator = new Percolator($index);
+
+ $query = new Term(array('name' => 'foo'));
+ $response = $percolator->registerQuery('percotest', $query, array('field1' => array('tag1', 'tag2')));
+
+ $this->assertTrue($response->isOk());
+ $this->assertFalse($response->hasError());
+
+ $query = new Term(array('name' => 'foo'));
+ $response = $percolator->registerQuery('percotest1', $query, array('field1' => array('tag2')));
+
+ $this->assertTrue($response->isOk());
+ $this->assertFalse($response->hasError());
+
+ $doc1 = new Document();
+ $doc1->set('name', 'foo');
+
+ $index->refresh();
+
+ $options = array(
+ 'track_scores' => true,
+ 'sort' => array('_score' => 'desc'),
+ 'size' => 1,
+ );
+
+ $matches = $percolator->matchDoc($doc1, new Term(array('field1' => 'tag2')), 'type', $options);
+
+ $this->assertCount(1, $matches);
+ $this->assertEquals('percotest1', $matches[0]['_id']);
+ $this->assertArrayHasKey('_score', $matches[0]);
+ }
+
+ /**
+ * @group functional
+ */
+ public function testPercolateExistingDocWithAdditionalRequestBodyOptions()
+ {
+ $percolatorName = 'existingDoc';
+ $percolator = $this->_getDefaultPercolator($percolatorName);
+
+ $query = new Term(array('name' => 'foobar'));
+ $percolator->registerQuery($percolatorName.'1', $query, array('field1' => array('tag2')));
+
+ $index = $percolator->getIndex();
+ $type = $this->_addDefaultDocuments($index);
+
+ $options = array(
+ 'track_scores' => true,
+ 'sort' => array('_score' => 'desc'),
+ 'size' => 1,
+ );
+
+ $matches = $percolator->matchExistingDoc(1, $type->getName(), new Term(array('field1' => 'tag2')), $options);
+
+ $this->assertCount(1, $matches);
+ $this->assertEquals('existingDoc1', $matches[0]['_id']);
+ $this->assertArrayHasKey('_score', $matches[0]);
+ $index->delete();
+ }
+
+ protected function _createIndex($name = null, $delete = true, $shards = 1)
+ {
+ $index = parent::_createIndex($name, $delete, $shards);
+ $type = $index->getType('.percolator');
+
+ $mapping = new Type\Mapping($type,
+ array(
+ 'name' => array('type' => 'string'),
+ 'field1' => array('type' => 'string'),
+ )
+ );
+ $mapping->disableSource();
+
+ $type->setMapping($mapping);
+
+ return $index;
+ }
+}
diff --git a/vendor/ruflin/elastica/test/lib/Elastica/Test/Query/BoolQueryTest.php b/vendor/ruflin/elastica/test/lib/Elastica/Test/Query/BoolQueryTest.php
new file mode 100644
index 00000000..211d0c23
--- /dev/null
+++ b/vendor/ruflin/elastica/test/lib/Elastica/Test/Query/BoolQueryTest.php
@@ -0,0 +1,171 @@
+<?php
+namespace Elastica\Test\Query;
+
+use Elastica\Document;
+use Elastica\Index;
+use Elastica\Query\BoolQuery;
+use Elastica\Query\Ids;
+use Elastica\Query\Term;
+use Elastica\Test\Base as BaseTest;
+use Elastica\Type;
+
+class BoolQueryTest extends BaseTest
+{
+ /**
+ * @group unit
+ */
+ public function testToArray()
+ {
+ $query = new BoolQuery();
+
+ $idsQuery1 = new Ids();
+ $idsQuery1->setIds(1);
+
+ $idsQuery2 = new Ids();
+ $idsQuery2->setIds(2);
+
+ $idsQuery3 = new Ids();
+ $idsQuery3->setIds(3);
+
+ $boost = 1.2;
+ $minMatch = 2;
+
+ $query->setBoost($boost);
+ $query->setMinimumNumberShouldMatch($minMatch);
+ $query->addMust($idsQuery1);
+ $query->addMustNot($idsQuery2);
+ $query->addShould($idsQuery3->toArray());
+
+ $expectedArray = array(
+ 'bool' => array(
+ 'must' => array($idsQuery1->toArray()),
+ 'should' => array($idsQuery3->toArray()),
+ 'minimum_number_should_match' => $minMatch,
+ 'must_not' => array($idsQuery2->toArray()),
+ 'boost' => $boost,
+ ),
+ );
+
+ $this->assertEquals($expectedArray, $query->toArray());
+ }
+
+ /**
+ * Test to resolve the following issue.
+ *
+ * @link https://groups.google.com/forum/?fromgroups#!topic/elastica-php-client/zK_W_hClfvU
+ *
+ * @group unit
+ */
+ public function testToArrayStructure()
+ {
+ $boolQuery = new BoolQuery();
+
+ $term1 = new Term();
+ $term1->setParam('interests', 84);
+
+ $term2 = new Term();
+ $term2->setParam('interests', 92);
+
+ $boolQuery->addShould($term1)->addShould($term2);
+
+ $jsonString = '{"bool":{"should":[{"term":{"interests":84}},{"term":{"interests":92}}]}}';
+ $this->assertEquals($jsonString, json_encode($boolQuery->toArray()));
+ }
+
+ /**
+ * @group functional
+ */
+ public function testSearch()
+ {
+ $client = $this->_getClient();
+ $index = new Index($client, 'test');
+ $index->create(array(), true);
+
+ $type = new Type($index, 'helloworld');
+
+ $doc = new Document(1, array('id' => 1, 'email' => 'hans@test.com', 'username' => 'hans', 'test' => array('2', '3', '5')));
+ $type->addDocument($doc);
+ $doc = new Document(2, array('id' => 2, 'email' => 'emil@test.com', 'username' => 'emil', 'test' => array('1', '3', '6')));
+ $type->addDocument($doc);
+ $doc = new Document(3, array('id' => 3, 'email' => 'ruth@test.com', 'username' => 'ruth', 'test' => array('2', '3', '7')));
+ $type->addDocument($doc);
+
+ // Refresh index
+ $index->refresh();
+
+ $boolQuery = new BoolQuery();
+ $termQuery1 = new Term(array('test' => '2'));
+ $boolQuery->addMust($termQuery1);
+ $resultSet = $type->search($boolQuery);
+
+ $this->assertEquals(2, $resultSet->count());
+
+ $termQuery2 = new Term(array('test' => '5'));
+ $boolQuery->addMust($termQuery2);
+ $resultSet = $type->search($boolQuery);
+
+ $this->assertEquals(1, $resultSet->count());
+
+ $termQuery3 = new Term(array('username' => 'hans'));
+ $boolQuery->addMust($termQuery3);
+ $resultSet = $type->search($boolQuery);
+
+ $this->assertEquals(1, $resultSet->count());
+
+ $termQuery4 = new Term(array('username' => 'emil'));
+ $boolQuery->addMust($termQuery4);
+ $resultSet = $type->search($boolQuery);
+
+ $this->assertEquals(0, $resultSet->count());
+ }
+
+ /**
+ * @group functional
+ */
+ public function testEmptyBoolQuery()
+ {
+ $index = $this->_createIndex();
+ $type = new Type($index, 'test');
+
+ $docNumber = 3;
+ for ($i = 0; $i < $docNumber; $i++) {
+ $doc = new Document($i, array('email' => 'test@test.com'));
+ $type->addDocument($doc);
+ }
+
+ $index->refresh();
+
+ $boolQuery = new BoolQuery();
+
+ $resultSet = $type->search($boolQuery);
+
+ $this->assertEquals($resultSet->count(), $docNumber);
+ }
+
+ /**
+ * @group functional
+ */
+ public function testOldObject()
+ {
+ if (version_compare(phpversion(), 7, '>=')) {
+ self::markTestSkipped('These objects are not supported in PHP 7');
+ }
+
+ $index = $this->_createIndex();
+ $type = new Type($index, 'test');
+
+ $docNumber = 3;
+ for ($i = 0; $i < $docNumber; $i++) {
+ $doc = new Document($i, array('email' => 'test@test.com'));
+ $type->addDocument($doc);
+ }
+
+ $index->refresh();
+
+ $boolQuery = new \Elastica\Query\Bool();
+
+ $resultSet = $type->search($boolQuery);
+
+ $this->assertEquals($resultSet->count(), $docNumber);
+ }
+}
diff --git a/vendor/ruflin/elastica/test/lib/Elastica/Test/Query/BoostingTest.php b/vendor/ruflin/elastica/test/lib/Elastica/Test/Query/BoostingTest.php
new file mode 100644
index 00000000..8133fd37
--- /dev/null
+++ b/vendor/ruflin/elastica/test/lib/Elastica/Test/Query/BoostingTest.php
@@ -0,0 +1,89 @@
+<?php
+namespace Elastica\Test\Query;
+
+use Elastica\Document;
+use Elastica\Query\Boosting;
+use Elastica\Query\Term;
+use Elastica\Test\Base as BaseTest;
+
+class BoostingTest extends BaseTest
+{
+ /**
+ * @var array
+ */
+ protected $sampleData = array(
+ array('name' => 'Vital Lama', 'price' => 5.2),
+ array('name' => 'Vital Match', 'price' => 2.1),
+ array('name' => 'Mercury Vital', 'price' => 7.5),
+ array('name' => 'Fist Mercury', 'price' => 3.8),
+ array('name' => 'Lama Vital 2nd', 'price' => 3.2),
+ );
+
+ protected function _getTestIndex()
+ {
+ $index = $this->_createIndex();
+ $type = $index->getType('test');
+ $type->setMapping(array(
+ 'name' => array('type' => 'string', 'index' => 'analyzed'),
+ 'price' => array('type' => 'float'),
+ ));
+ $docs = array();
+ foreach ($this->sampleData as $key => $value) {
+ $docs[] = new Document($key, $value);
+ }
+ $type->addDocuments($docs);
+
+ $index->refresh();
+
+ return $index;
+ }
+
+ /**
+ * @group unit
+ */
+ public function testToArray()
+ {
+ $keyword = 'vital';
+ $negativeKeyword = 'Mercury';
+
+ $query = new Boosting();
+ $positiveQuery = new Term(array('name' => $keyword));
+ $negativeQuery = new Term(array('name' => $negativeKeyword));
+ $query->setPositiveQuery($positiveQuery);
+ $query->setNegativeQuery($negativeQuery);
+ $query->setNegativeBoost(0.3);
+
+ $expected = array(
+ 'boosting' => array(
+ 'positive' => $positiveQuery->toArray(),
+ 'negative' => $negativeQuery->toArray(),
+ 'negative_boost' => 0.3,
+ ),
+ );
+ $this->assertEquals($expected, $query->toArray());
+ }
+
+ /**
+ * @group functional
+ */
+ public function testNegativeBoost()
+ {
+ $keyword = 'vital';
+ $negativeKeyword = 'mercury';
+
+ $query = new Boosting();
+ $positiveQuery = new Term(array('name' => $keyword));
+ $negativeQuery = new Term(array('name' => $negativeKeyword));
+ $query->setPositiveQuery($positiveQuery);
+ $query->setNegativeQuery($negativeQuery);
+ $query->setNegativeBoost(0.2);
+
+ $response = $this->_getTestIndex()->search($query);
+ $results = $response->getResults();
+
+ $this->assertEquals($response->getTotalHits(), 4);
+
+ $lastResult = $results[3]->getData();
+ $this->assertEquals($lastResult['name'], $this->sampleData[2]['name']);
+ }
+}
diff --git a/vendor/ruflin/elastica/test/lib/Elastica/Test/Query/BuilderTest.php b/vendor/ruflin/elastica/test/lib/Elastica/Test/Query/BuilderTest.php
new file mode 100644
index 00000000..a96e8b3a
--- /dev/null
+++ b/vendor/ruflin/elastica/test/lib/Elastica/Test/Query/BuilderTest.php
@@ -0,0 +1,273 @@
+<?php
+namespace Elastica\Test\Query;
+
+use Elastica\Query\Builder;
+use Elastica\Test\Base as BaseTest;
+
+class BuilderTest extends BaseTest
+{
+ /**
+ * @group unit
+ * @covers \Elastica\Query\Builder::factory
+ * @covers \Elastica\Query\Builder::__construct
+ */
+ public function testFactory()
+ {
+ $this->assertInstanceOf(
+ 'Elastica\Query\Builder',
+ Builder::factory('some string')
+ );
+ }
+
+ public function getQueryData()
+ {
+ return array(
+ array('allowLeadingWildcard', false, '{"allow_leading_wildcard":"false"}'),
+ array('allowLeadingWildcard', true, '{"allow_leading_wildcard":"true"}'),
+ array('analyzeWildcard', false, '{"analyze_wildcard":"false"}'),
+ array('analyzeWildcard', true, '{"analyze_wildcard":"true"}'),
+ array('analyzer', 'someAnalyzer', '{"analyzer":"someAnalyzer"}'),
+ array('autoGeneratePhraseQueries', true, '{"auto_generate_phrase_queries":"true"}'),
+ array('autoGeneratePhraseQueries', false, '{"auto_generate_phrase_queries":"false"}'),
+ array('boost', 2, '{"boost":"2"}'),
+ array('boost', 4.2, '{"boost":"4.2"}'),
+ array('defaultField', 'fieldName', '{"default_field":"fieldName"}'),
+ array('defaultOperator', 'OR', '{"default_operator":"OR"}'),
+ array('defaultOperator', 'AND', '{"default_operator":"AND"}'),
+ array('enablePositionIncrements', true, '{"enable_position_increments":"true"}'),
+ array('enablePositionIncrements', false, '{"enable_position_increments":"false"}'),
+ array('explain', true, '{"explain":"true"}'),
+ array('explain', false, '{"explain":"false"}'),
+ array('from', 42, '{"from":"42"}'),
+ array('fuzzyMinSim', 4.2, '{"fuzzy_min_sim":"4.2"}'),
+ array('fuzzyPrefixLength', 2, '{"fuzzy_prefix_length":"2"}'),
+ array('gt', 10, '{"gt":"10"}'),
+ array('gte', 11, '{"gte":"11"}'),
+ array('lowercaseExpandedTerms', true, '{"lowercase_expanded_terms":"true"}'),
+ array('lt', 10, '{"lt":"10"}'),
+ array('lte', 11, '{"lte":"11"}'),
+ array('minimumNumberShouldMatch', 21, '{"minimum_number_should_match":"21"}'),
+ array('phraseSlop', 6, '{"phrase_slop":"6"}'),
+ array('size', 7, '{"size":"7"}'),
+ array('tieBreakerMultiplier', 7, '{"tie_breaker_multiplier":"7"}'),
+ array('matchAll', 1.1, '{"match_all":{"boost":"1.1"}}'),
+ array('fields', array('age', 'sex', 'location'), '{"fields":["age","sex","location"]}'),
+ );
+ }
+
+ /**
+ * @group unit
+ * @dataProvider getQueryData
+ * @covers \Elastica\Query\Builder::__toString
+ * @covers \Elastica\Query\Builder::allowLeadingWildcard
+ * @covers \Elastica\Query\Builder::analyzeWildcard
+ * @covers \Elastica\Query\Builder::analyzer
+ * @covers \Elastica\Query\Builder::autoGeneratePhraseQueries
+ * @covers \Elastica\Query\Builder::boost
+ * @covers \Elastica\Query\Builder::defaultField
+ * @covers \Elastica\Query\Builder::defaultOperator
+ * @covers \Elastica\Query\Builder::enablePositionIncrements
+ * @covers \Elastica\Query\Builder::explain
+ * @covers \Elastica\Query\Builder::from
+ * @covers \Elastica\Query\Builder::fuzzyMinSim
+ * @covers \Elastica\Query\Builder::fuzzyPrefixLength
+ * @covers \Elastica\Query\Builder::gt
+ * @covers \Elastica\Query\Builder::gte
+ * @covers \Elastica\Query\Builder::lowercaseExpandedTerms
+ * @covers \Elastica\Query\Builder::lt
+ * @covers \Elastica\Query\Builder::lte
+ * @covers \Elastica\Query\Builder::minimumNumberShouldMatch
+ * @covers \Elastica\Query\Builder::phraseSlop
+ * @covers \Elastica\Query\Builder::size
+ * @covers \Elastica\Query\Builder::tieBreakerMultiplier
+ * @covers \Elastica\Query\Builder::matchAll
+ * @covers \Elastica\Query\Builder::fields
+ */
+ public function testAllowLeadingWildcard($method, $argument, $result)
+ {
+ $builder = new Builder();
+ $this->assertSame($builder, $builder->$method($argument));
+ $this->assertSame($result, (string) $builder);
+ }
+
+ public function getQueryTypes()
+ {
+ return array(
+ array('bool', 'bool'),
+ array('constantScore', 'constant_score'),
+ array('disMax', 'dis_max'),
+ array('facets', 'facets'),
+ array('filter', 'filter'),
+ array('filteredQuery', 'filtered'),
+ array('must', 'must'),
+ array('mustNot', 'must_not'),
+ array('prefix', 'prefix'),
+ array('query', 'query'),
+ array('queryString', 'query_string'),
+ array('range', 'range'),
+ array('should', 'should'),
+ array('sort', 'sort'),
+ array('term', 'term'),
+ array('textPhrase', 'text_phrase'),
+ array('wildcard', 'wildcard'),
+ );
+ }
+
+ /**
+ * @group unit
+ * @dataProvider getQueryTypes
+ * @covers \Elastica\Query\Builder::fieldClose
+ * @covers \Elastica\Query\Builder::close
+ * @covers \Elastica\Query\Builder::bool
+ * @covers \Elastica\Query\Builder::boolClose
+ * @covers \Elastica\Query\Builder::constantScore
+ * @covers \Elastica\Query\Builder::constantScoreClose
+ * @covers \Elastica\Query\Builder::disMax
+ * @covers \Elastica\Query\Builder::disMaxClose
+ * @covers \Elastica\Query\Builder::facets
+ * @covers \Elastica\Query\Builder::facetsClose
+ * @covers \Elastica\Query\Builder::filter
+ * @covers \Elastica\Query\Builder::filterClose
+ * @covers \Elastica\Query\Builder::filteredQuery
+ * @covers \Elastica\Query\Builder::filteredQueryClose
+ * @covers \Elastica\Query\Builder::must
+ * @covers \Elastica\Query\Builder::mustClose
+ * @covers \Elastica\Query\Builder::mustNot
+ * @covers \Elastica\Query\Builder::mustNotClose
+ * @covers \Elastica\Query\Builder::prefix
+ * @covers \Elastica\Query\Builder::prefixClose
+ * @covers \Elastica\Query\Builder::query
+ * @covers \Elastica\Query\Builder::queryClose
+ * @covers \Elastica\Query\Builder::queryString
+ * @covers \Elastica\Query\Builder::queryStringClose
+ * @covers \Elastica\Query\Builder::range
+ * @covers \Elastica\Query\Builder::rangeClose
+ * @covers \Elastica\Query\Builder::should
+ * @covers \Elastica\Query\Builder::shouldClose
+ * @covers \Elastica\Query\Builder::sort
+ * @covers \Elastica\Query\Builder::sortClose
+ * @covers \Elastica\Query\Builder::term
+ * @covers \Elastica\Query\Builder::termClose
+ * @covers \Elastica\Query\Builder::textPhrase
+ * @covers \Elastica\Query\Builder::textPhraseClose
+ * @covers \Elastica\Query\Builder::wildcard
+ * @covers \Elastica\Query\Builder::wildcardClose
+ */
+ public function testQueryTypes($method, $queryType)
+ {
+ $builder = new Builder();
+ $this->assertSame($builder, $builder->$method()); // open
+ $this->assertSame($builder, $builder->{$method.'Close'}()); // close
+ $this->assertSame('{"'.$queryType.'":{}}', (string) $builder);
+ }
+
+ /**
+ * @group unit
+ * @covers \Elastica\Query\Builder::fieldOpen
+ * @covers \Elastica\Query\Builder::fieldClose
+ * @covers \Elastica\Query\Builder::open
+ * @covers \Elastica\Query\Builder::close
+ */
+ public function testFieldOpenAndClose()
+ {
+ $builder = new Builder();
+ $this->assertSame($builder, $builder->fieldOpen('someField'));
+ $this->assertSame($builder, $builder->fieldClose());
+ $this->assertSame('{"someField":{}}', (string) $builder);
+ }
+
+ /**
+ * @group unit
+ * @covers \Elastica\Query\Builder::sortField
+ */
+ public function testSortField()
+ {
+ $builder = new Builder();
+ $this->assertSame($builder, $builder->sortField('name', true));
+ $this->assertSame('{"sort":{"name":{"reverse":"true"}}}', (string) $builder);
+ }
+
+ /**
+ * @group unit
+ * @covers \Elastica\Query\Builder::sortFields
+ */
+ public function testSortFields()
+ {
+ $builder = new Builder();
+ $this->assertSame($builder, $builder->sortFields(array('field1' => 'asc', 'field2' => 'desc', 'field3' => 'asc')));
+ $this->assertSame('{"sort":[{"field1":"asc"},{"field2":"desc"},{"field3":"asc"}]}', (string) $builder);
+ }
+
+ /**
+ * @group unit
+ * @covers \Elastica\Query\Builder::queries
+ */
+ public function testQueries()
+ {
+ $queries = array();
+
+ $builder = new Builder();
+ $b1 = clone $builder;
+ $b2 = clone $builder;
+
+ $queries[] = $b1->term()->field('age', 34)->termClose();
+ $queries[] = $b2->term()->field('name', 'christer')->termClose();
+
+ $this->assertSame($builder, $builder->queries($queries));
+ $this->assertSame('{"queries":[{"term":{"age":"34"}},{"term":{"name":"christer"}}]}', (string) $builder);
+ }
+
+ public function getFieldData()
+ {
+ return array(
+ array('name', 'value', '{"name":"value"}'),
+ array('name', true, '{"name":"true"}'),
+ array('name', false, '{"name":"false"}'),
+ array('name', array(1, 2, 3), '{"name":["1","2","3"]}'),
+ array('name', array('foo', 'bar', 'baz'), '{"name":["foo","bar","baz"]}'),
+ );
+ }
+
+ /**
+ * @group unit
+ * @dataProvider getFieldData
+ * @covers \Elastica\Query\Builder::field
+ */
+ public function testField($name, $value, $result)
+ {
+ $builder = new Builder();
+ $this->assertSame($builder, $builder->field($name, $value));
+ $this->assertSame($result, (string) $builder);
+ }
+
+ /**
+ * @group unit
+ * @expectedException \Elastica\Exception\InvalidException
+ * @expectedExceptionMessage The produced query is not a valid json string : "{{}"
+ * @covers \Elastica\Query\Builder::toArray
+ */
+ public function testToArrayWithInvalidData()
+ {
+ $builder = new Builder();
+ $builder->open('foo');
+ $builder->toArray();
+ }
+
+ /**
+ * @group unit
+ * @covers \Elastica\Query\Builder::toArray
+ */
+ public function testToArray()
+ {
+ $builder = new Builder();
+ $builder->query()->term()->field('category.id', array(1, 2, 3))->termClose()->queryClose();
+ $expected = array(
+ 'query' => array(
+ 'term' => array(
+ 'category.id' => array(1, 2, 3),
+ ),
+ ),
+ );
+ $this->assertEquals($expected, $builder->toArray());
+ }
+}
diff --git a/vendor/ruflin/elastica/test/lib/Elastica/Test/Query/CommonTest.php b/vendor/ruflin/elastica/test/lib/Elastica/Test/Query/CommonTest.php
new file mode 100644
index 00000000..016213a8
--- /dev/null
+++ b/vendor/ruflin/elastica/test/lib/Elastica/Test/Query/CommonTest.php
@@ -0,0 +1,63 @@
+<?php
+namespace Elastica\Test\Query;
+
+use Elastica\Document;
+use Elastica\Query\Common;
+use Elastica\Test\Base as BaseTest;
+
+class CommonTest extends BaseTest
+{
+ /**
+ * @group unit
+ */
+ public function testToArray()
+ {
+ $query = new Common('body', 'test query', .001);
+ $query->setLowFrequencyOperator(Common::OPERATOR_AND);
+
+ $expected = array(
+ 'common' => array(
+ 'body' => array(
+ 'query' => 'test query',
+ 'cutoff_frequency' => .001,
+ 'low_freq_operator' => 'and',
+ ),
+ ),
+ );
+
+ $this->assertEquals($expected, $query->toArray());
+ }
+
+ /**
+ * @group functional
+ */
+ public function testQuery()
+ {
+ $index = $this->_createIndex();
+ $type = $index->getType('test');
+
+ $docs = array(
+ new Document(1, array('body' => 'foo baz')),
+ new Document(2, array('body' => 'foo bar baz')),
+ new Document(3, array('body' => 'foo bar baz bat')),
+ );
+ //add documents to create common terms
+ for ($i = 4; $i < 24; $i++) {
+ $docs[] = new Document($i, array('body' => 'foo bar'));
+ }
+ $type->addDocuments($docs);
+ $index->refresh();
+
+ $query = new Common('body', 'foo bar baz bat', .5);
+ $results = $type->search($query)->getResults();
+
+ //documents containing only common words should not be returned
+ $this->assertEquals(3, sizeof($results));
+
+ $query->setMinimumShouldMatch(2);
+ $results = $type->search($query);
+
+ //only the document containing both low frequency terms should match
+ $this->assertEquals(1, $results->count());
+ }
+}
diff --git a/vendor/ruflin/elastica/test/lib/Elastica/Test/Query/ConstantScoreTest.php b/vendor/ruflin/elastica/test/lib/Elastica/Test/Query/ConstantScoreTest.php
new file mode 100644
index 00000000..a3a213b9
--- /dev/null
+++ b/vendor/ruflin/elastica/test/lib/Elastica/Test/Query/ConstantScoreTest.php
@@ -0,0 +1,162 @@
+<?php
+namespace Elastica\Test\Query;
+
+use Elastica\Document;
+use Elastica\Filter\Ids;
+use Elastica\Filter\Term;
+use Elastica\Index;
+use Elastica\Query\ConstantScore;
+use Elastica\Query\MatchAll;
+use Elastica\Test\Base as BaseTest;
+
+class ConstantScoreTest extends BaseTest
+{
+ public function dataProviderSampleQueries()
+ {
+ return array(
+ array(
+ new Term(array('foo', 'bar')),
+ array(
+ 'constant_score' => array(
+ 'filter' => array(
+ 'term' => array(
+ 'foo',
+ 'bar',
+ ),
+ ),
+ ),
+ ),
+ ),
+ array(
+ array(
+ 'and' => array(
+ array(
+ 'query' => array(
+ 'query_string' => array(
+ 'query' => 'foo',
+ 'default_field' => 'something',
+ ),
+ ),
+ ),
+ array(
+ 'query' => array(
+ 'query_string' => array(
+ 'query' => 'bar',
+ 'default_field' => 'something',
+ ),
+ ),
+ ),
+ ),
+ ),
+ '{"constant_score":{"filter":{"and":[{"query":{"query_string":{"query":"foo","default_field":"something"}}},{"query":{"query_string":{"query":"bar","default_field":"something"}}}]}}}',
+ ),
+ );
+ }
+ /**
+ * @group unit
+ * @dataProvider dataProviderSampleQueries
+ */
+ public function testSimple($filter, $expected)
+ {
+ $query = new ConstantScore();
+ $query->setFilter($filter);
+ if (is_string($expected)) {
+ $expected = json_decode($expected, true);
+ }
+ $this->assertEquals($expected, $query->toArray());
+ }
+
+ /**
+ * @group unit
+ */
+ public function testToArray()
+ {
+ $query = new ConstantScore();
+
+ $boost = 1.2;
+ $filter = new Ids();
+ $filter->setIds(array(1));
+
+ $query->setFilter($filter);
+ $query->setBoost($boost);
+
+ $expectedArray = array(
+ 'constant_score' => array(
+ 'filter' => $filter->toArray(),
+ 'boost' => $boost,
+ ),
+ );
+
+ $this->assertEquals($expectedArray, $query->toArray());
+ }
+
+ /**
+ * @group unit
+ */
+ public function testConstruct()
+ {
+ $filter = new Ids();
+ $filter->setIds(array(1));
+
+ $query = new ConstantScore($filter);
+
+ $expectedArray = array(
+ 'constant_score' => array(
+ 'filter' => $filter->toArray(),
+ ),
+ );
+
+ $this->assertEquals($expectedArray, $query->toArray());
+ }
+
+ /**
+ * @group functional
+ */
+ public function testQuery()
+ {
+ $index = $this->_createIndex();
+
+ $type = $index->getType('constant_score');
+ $type->addDocuments(array(
+ new Document(1, array('id' => 1, 'email' => 'hans@test.com', 'username' => 'hans')),
+ new Document(2, array('id' => 2, 'email' => 'emil@test.com', 'username' => 'emil')),
+ new Document(3, array('id' => 3, 'email' => 'ruth@test.com', 'username' => 'ruth')),
+ ));
+
+ // Refresh index
+ $index->refresh();
+
+ $boost = 1.3;
+ $query_match = new MatchAll();
+
+ $query = new ConstantScore();
+ $query->setQuery($query_match);
+ $query->setBoost($boost);
+
+ $expectedArray = array(
+ 'constant_score' => array(
+ 'query' => $query_match->toArray(),
+ 'boost' => $boost,
+ ),
+ );
+
+ $this->assertEquals($expectedArray, $query->toArray());
+ $resultSet = $type->search($query);
+
+ $results = $resultSet->getResults();
+
+ $this->assertEquals($resultSet->count(), 3);
+ $this->assertEquals($results[1]->getScore(), 1);
+ }
+
+ /**
+ * @group unit
+ */
+ public function testConstructEmpty()
+ {
+ $query = new ConstantScore();
+ $expectedArray = array('constant_score' => array());
+
+ $this->assertEquals($expectedArray, $query->toArray());
+ }
+}
diff --git a/vendor/ruflin/elastica/test/lib/Elastica/Test/Query/DisMaxTest.php b/vendor/ruflin/elastica/test/lib/Elastica/Test/Query/DisMaxTest.php
new file mode 100644
index 00000000..2c128018
--- /dev/null
+++ b/vendor/ruflin/elastica/test/lib/Elastica/Test/Query/DisMaxTest.php
@@ -0,0 +1,84 @@
+<?php
+namespace Elastica\Test\Query;
+
+use Elastica\Document;
+use Elastica\Query\DisMax;
+use Elastica\Query\Ids;
+use Elastica\Query\QueryString;
+use Elastica\Test\Base as BaseTest;
+
+class DisMaxTest extends BaseTest
+{
+ /**
+ * @group unit
+ */
+ public function testToArray()
+ {
+ $query = new DisMax();
+
+ $idsQuery1 = new Ids();
+ $idsQuery1->setIds(1);
+
+ $idsQuery2 = new Ids();
+ $idsQuery2->setIds(2);
+
+ $idsQuery3 = new Ids();
+ $idsQuery3->setIds(3);
+
+ $boost = 1.2;
+ $tieBreaker = 2;
+
+ $query->setBoost($boost);
+ $query->setTieBreaker($tieBreaker);
+ $query->addQuery($idsQuery1);
+ $query->addQuery($idsQuery2);
+ $query->addQuery($idsQuery3->toArray());
+
+ $expectedArray = array(
+ 'dis_max' => array(
+ 'tie_breaker' => $tieBreaker,
+ 'boost' => $boost,
+ 'queries' => array(
+ $idsQuery1->toArray(),
+ $idsQuery2->toArray(),
+ $idsQuery3->toArray(),
+ ),
+ ),
+ );
+
+ $this->assertEquals($expectedArray, $query->toArray());
+ }
+
+ /**
+ * @group functional
+ */
+ public function testQuery()
+ {
+ $index = $this->_createIndex();
+ $type = $index->getType('test');
+
+ $type->addDocuments(array(
+ new Document(1, array('name' => 'Basel-Stadt')),
+ new Document(2, array('name' => 'New York')),
+ new Document(3, array('name' => 'Baden')),
+ new Document(4, array('name' => 'Baden Baden')),
+ ));
+
+ $index->refresh();
+
+ $queryString1 = new QueryString('Bade*');
+ $queryString2 = new QueryString('Base*');
+
+ $boost = 1.2;
+ $tieBreaker = 2;
+
+ $query = new DisMax();
+ $query->setBoost($boost);
+ $query->setTieBreaker($tieBreaker);
+ $query->addQuery($queryString1);
+ $query->addQuery($queryString2);
+ $resultSet = $type->search($query);
+
+ $this->assertEquals(3, $resultSet->count());
+ }
+}
diff --git a/vendor/ruflin/elastica/test/lib/Elastica/Test/Query/EscapeStringTest.php b/vendor/ruflin/elastica/test/lib/Elastica/Test/Query/EscapeStringTest.php
new file mode 100644
index 00000000..536a7bb3
--- /dev/null
+++ b/vendor/ruflin/elastica/test/lib/Elastica/Test/Query/EscapeStringTest.php
@@ -0,0 +1,36 @@
+<?php
+namespace Elastica\Test\Query;
+
+use Elastica\Document;
+use Elastica\Index;
+use Elastica\Query\QueryString;
+use Elastica\Test\Base as BaseTest;
+use Elastica\Type;
+use Elastica\Util;
+
+class EscapeStringTest extends BaseTest
+{
+ /**
+ * @group functional
+ */
+ public function testSearch()
+ {
+ $index = $this->_createIndex();
+ $index->getSettings()->setNumberOfReplicas(0);
+
+ $type = new Type($index, 'helloworld');
+
+ $doc = new Document(1, array(
+ 'email' => 'test@test.com', 'username' => 'test 7/6 123', 'test' => array('2', '3', '5'), )
+ );
+ $type->addDocument($doc);
+
+ // Refresh index
+ $index->refresh();
+
+ $queryString = new QueryString(Util::escapeTerm('test 7/6'));
+ $resultSet = $type->search($queryString);
+
+ $this->assertEquals(1, $resultSet->count());
+ }
+}
diff --git a/vendor/ruflin/elastica/test/lib/Elastica/Test/Query/FilteredTest.php b/vendor/ruflin/elastica/test/lib/Elastica/Test/Query/FilteredTest.php
new file mode 100644
index 00000000..c4bea6f2
--- /dev/null
+++ b/vendor/ruflin/elastica/test/lib/Elastica/Test/Query/FilteredTest.php
@@ -0,0 +1,124 @@
+<?php
+namespace Elastica\Test\Query;
+
+use Elastica\Document;
+use Elastica\Filter\Term;
+use Elastica\Query\Filtered;
+use Elastica\Query\QueryString;
+use Elastica\Test\Base as BaseTest;
+
+class FilteredTest extends BaseTest
+{
+ /**
+ * @group functional
+ */
+ public function testFilteredSearch()
+ {
+ $index = $this->_createIndex();
+ $type = $index->getType('helloworld');
+
+ $type->addDocuments(array(
+ new Document(1, array('id' => 1, 'email' => 'test@test.com', 'username' => 'hanswurst', 'test' => array('2', '3', '5'))),
+ new Document(2, array('id' => 2, 'email' => 'test@test.com', 'username' => 'peter', 'test' => array('2', '3', '5'))),
+ ));
+
+ $queryString = new QueryString('test*');
+
+ $filter1 = new Term();
+ $filter1->setTerm('username', 'peter');
+
+ $filter2 = new Term();
+ $filter2->setTerm('username', 'qwerqwer');
+
+ $query1 = new Filtered($queryString, $filter1);
+ $query2 = new Filtered($queryString, $filter2);
+ $index->refresh();
+
+ $resultSet = $type->search($queryString);
+ $this->assertEquals(2, $resultSet->count());
+
+ $resultSet = $type->search($query1);
+ $this->assertEquals(1, $resultSet->count());
+
+ $resultSet = $type->search($query2);
+ $this->assertEquals(0, $resultSet->count());
+ }
+
+ /**
+ * @group unit
+ */
+ public function testFilteredGetter()
+ {
+ $queryString = new QueryString('test*');
+
+ $filter1 = new Term();
+ $filter1->setTerm('username', 'peter');
+
+ $filter2 = new Term();
+ $filter2->setTerm('username', 'qwerqwer');
+
+ $query1 = new Filtered($queryString, $filter1);
+ $query2 = new Filtered($queryString, $filter2);
+
+ $this->assertEquals($query1->getQuery(), $queryString);
+ $this->assertEquals($query2->getQuery(), $queryString);
+ $this->assertEquals($query1->getFilter(), $filter1);
+ $this->assertEquals($query2->getFilter(), $filter2);
+ }
+
+ /**
+ * @group unit
+ * @expectedException \Elastica\Exception\InvalidException
+ */
+ public function testFilteredWithoutArgumentsShouldRaiseException()
+ {
+ $query = new Filtered();
+ $query->toArray();
+ }
+
+ /**
+ * @group functional
+ */
+ public function testFilteredSearchNoQuery()
+ {
+ $index = $this->_createIndex();
+ $type = $index->getType('helloworld');
+
+ $type->addDocuments(array(
+ new Document(1, array('id' => 1, 'email' => 'test@test.com', 'username' => 'hanswurst', 'test' => array('2', '3', '5'))),
+ new Document(2, array('id' => 2, 'email' => 'test@test.com', 'username' => 'peter', 'test' => array('2', '3', '5'))),
+ ));
+
+ $index->refresh();
+
+ $filter = new Term();
+ $filter->setTerm('username', 'peter');
+
+ $query = new Filtered(null, $filter);
+
+ $resultSet = $type->search($query);
+ $this->assertEquals(1, $resultSet->count());
+ }
+
+ /**
+ * @group functional
+ */
+ public function testFilteredSearchNoFilter()
+ {
+ $index = $this->_createIndex();
+ $type = $index->getType('helloworld');
+
+ $doc = new Document(1, array('id' => 1, 'email' => 'test@test.com', 'username' => 'hanswurst', 'test' => array('2', '3', '5')));
+ $type->addDocument($doc);
+ $doc = new Document(2, array('id' => 2, 'email' => 'test@test.com', 'username' => 'peter', 'test' => array('2', '3', '5')));
+ $type->addDocument($doc);
+
+ $queryString = new QueryString('hans*');
+
+ $query = new Filtered($queryString);
+ $index->refresh();
+
+ $resultSet = $type->search($query);
+ $this->assertEquals(1, $resultSet->count());
+ }
+}
diff --git a/vendor/ruflin/elastica/test/lib/Elastica/Test/Query/FunctionScoreTest.php b/vendor/ruflin/elastica/test/lib/Elastica/Test/Query/FunctionScoreTest.php
new file mode 100644
index 00000000..25600034
--- /dev/null
+++ b/vendor/ruflin/elastica/test/lib/Elastica/Test/Query/FunctionScoreTest.php
@@ -0,0 +1,324 @@
+<?php
+namespace Elastica\Test\Query;
+
+use Elastica\Document;
+use Elastica\Filter\Term;
+use Elastica\Query\FunctionScore;
+use Elastica\Query\MatchAll;
+use Elastica\Script;
+use Elastica\Test\Base as BaseTest;
+
+class FunctionScoreTest extends BaseTest
+{
+ protected $locationOrigin = '32.804654, -117.242594';
+
+ protected function _getIndexForTest()
+ {
+ $index = $this->_createIndex();
+ $type = $index->getType('test');
+
+ $type->setMapping(array(
+ 'name' => array('type' => 'string', 'index' => 'not_analyzed'),
+ 'location' => array('type' => 'geo_point'),
+ 'price' => array('type' => 'float'),
+ ));
+
+ $type->addDocuments(array(
+ new Document(1, array(
+ 'name' => "Mr. Frostie's",
+ 'location' => array('lat' => 32.799605, 'lon' => -117.243027),
+ 'price' => 4.5,
+ )),
+ new Document(2, array(
+ 'name' => "Miller's Field",
+ 'location' => array('lat' => 32.795964, 'lon' => -117.255028),
+ 'price' => 9.5,
+ )),
+ ));
+
+ $index->refresh();
+
+ return $index;
+ }
+
+ /**
+ * @group unit
+ */
+ public function testToArray()
+ {
+ $priceOrigin = 0;
+ $locationScale = '2mi';
+ $priceScale = 9.25;
+ $query = new FunctionScore();
+ $childQuery = new MatchAll();
+ $query->setQuery($childQuery);
+ $query->addDecayFunction(FunctionScore::DECAY_GAUSS, 'location', $this->locationOrigin, $locationScale);
+ $query->addDecayFunction(FunctionScore::DECAY_GAUSS, 'price', $priceOrigin, $priceScale);
+ $expected = array(
+ 'function_score' => array(
+ 'query' => $childQuery->toArray(),
+ 'functions' => array(
+ array(
+ 'gauss' => array(
+ 'location' => array(
+ 'origin' => $this->locationOrigin,
+ 'scale' => $locationScale,
+ ),
+ ),
+ ),
+ array(
+ 'gauss' => array(
+ 'price' => array(
+ 'origin' => $priceOrigin,
+ 'scale' => $priceScale,
+ ),
+ ),
+ ),
+ ),
+ ),
+ );
+ $this->assertEquals($expected, $query->toArray());
+ }
+
+ /**
+ * @group unit
+ */
+ public function testDecayWeight()
+ {
+ $priceOrigin = 0;
+ $locationScale = '2mi';
+ $priceScale = 9.25;
+ $query = new FunctionScore();
+ $childQuery = new MatchAll();
+ $query->setQuery($childQuery);
+ $query->addDecayFunction(
+ FunctionScore::DECAY_GAUSS,
+ 'location',
+ $this->locationOrigin,
+ $locationScale,
+ null,
+ null,
+ .5
+ );
+ $query->addDecayFunction(FunctionScore::DECAY_GAUSS, 'price', $priceOrigin, $priceScale, null, null, 2);
+ $expected = array(
+ 'function_score' => array(
+ 'query' => $childQuery->toArray(),
+ 'functions' => array(
+ array(
+ 'gauss' => array(
+ 'location' => array(
+ 'origin' => $this->locationOrigin,
+ 'scale' => $locationScale,
+ ),
+ ),
+ 'weight' => .5,
+ ),
+ array(
+ 'gauss' => array(
+ 'price' => array(
+ 'origin' => $priceOrigin,
+ 'scale' => $priceScale,
+ ),
+ ),
+ 'weight' => 2,
+ ),
+ ),
+ ),
+ );
+ $this->assertEquals($expected, $query->toArray());
+ }
+
+ /**
+ * @group functional
+ */
+ public function testGauss()
+ {
+ $query = new FunctionScore();
+ $query->addDecayFunction(FunctionScore::DECAY_GAUSS, 'location', $this->locationOrigin, '4mi');
+ $query->addDecayFunction(FunctionScore::DECAY_GAUSS, 'price', 0, 10);
+ $response = $this->_getIndexForTest()->search($query);
+ $results = $response->getResults();
+
+ // the document with the closest location and lowest price should be scored highest
+ $result0 = $results[0]->getData();
+ $this->assertEquals("Mr. Frostie's", $result0['name']);
+ }
+
+ /**
+ * @group functional
+ */
+ public function testWeight()
+ {
+ $filter = new Term(array('price' => 4.5));
+ $query = new FunctionScore();
+ $query->addBoostFactorFunction(5.0, $filter);
+ $expected = array(
+ 'function_score' => array(
+ 'functions' => array(
+ array(
+ 'weight' => 5.0,
+ 'filter' => array(
+ 'term' => array(
+ 'price' => 4.5,
+ ),
+ ),
+ ),
+ ),
+ ),
+ );
+
+ $this->assertEquals($expected, $query->toArray());
+
+ $response = $this->_getIndexForTest()->search($query);
+ $results = $response->getResults();
+
+ // the document with price = 4.5 should be scored highest
+ $result0 = $results[0]->getData();
+ $this->assertEquals("Mr. Frostie's", $result0['name']);
+ }
+
+ /**
+ * @group functional
+ */
+ public function testRandomScore()
+ {
+ $filter = new Term(array('price' => 4.5));
+ $query = new FunctionScore();
+ $query->addRandomScoreFunction(2, $filter);
+ $expected = array(
+ 'function_score' => array(
+ 'functions' => array(
+ array(
+ 'random_score' => array(
+ 'seed' => 2,
+ ),
+ 'filter' => array(
+ 'term' => array(
+ 'price' => 4.5,
+ ),
+ ),
+ ),
+ ),
+ ),
+ );
+
+ $this->assertEquals($expected, $query->toArray());
+
+ $response = $this->_getIndexForTest()->search($query);
+ $results = $response->getResults();
+
+ // the document with the random score should have a score > 1, means it is the first result
+ $result0 = $results[0]->getData();
+
+ $this->assertEquals("Miller's Field", $result0['name']);
+ }
+
+ /**
+ * @group unit
+ */
+ public function testRandomScoreWeight()
+ {
+ $filter = new Term(array('price' => 4.5));
+ $query = new FunctionScore();
+ $query->addRandomScoreFunction(2, $filter, 2);
+ $expected = array(
+ 'function_score' => array(
+ 'functions' => array(
+ array(
+ 'random_score' => array(
+ 'seed' => 2,
+ ),
+ 'filter' => array(
+ 'term' => array(
+ 'price' => 4.5,
+ ),
+ ),
+ 'weight' => 2,
+ ),
+ ),
+ ),
+ );
+
+ $this->assertEquals($expected, $query->toArray());
+ }
+
+ /**
+ * @group functional
+ */
+ public function testRandomScoreWithoutSeed()
+ {
+ $query = new FunctionScore();
+ $query->setRandomScore();
+
+ $response = $this->_getIndexForTest()->search($query);
+
+ $this->assertEquals(2, $response->count());
+ }
+
+ /**
+ * @group functional
+ */
+ public function testScriptScore()
+ {
+ $scriptString = "_score * doc['price'].value";
+ $script = new Script($scriptString);
+ $query = new FunctionScore();
+ $query->addScriptScoreFunction($script);
+ $expected = array(
+ 'function_score' => array(
+ 'functions' => array(
+ array(
+ 'script_score' => array(
+ 'script' => $scriptString,
+ ),
+ ),
+ ),
+ ),
+ );
+
+ $this->assertEquals($expected, $query->toArray());
+
+ $response = $this->_getIndexForTest()->search($query);
+ $results = $response->getResults();
+
+ // the document the highest price should be scored highest
+ $result0 = $results[0]->getData();
+ $this->assertEquals("Miller's Field", $result0['name']);
+ }
+
+ /**
+ * @group functional
+ */
+ public function testSetMinScore()
+ {
+ $expected = array(
+ 'function_score' => array(
+ 'min_score' => 0.8,
+ 'functions' => array(
+ array(
+ 'gauss' => array(
+ 'price' => array(
+ 'origin' => 0,
+ 'scale' => 10,
+ ),
+ ),
+ ),
+ ),
+ ),
+ );
+
+ $query = new FunctionScore();
+ $query->addDecayFunction(FunctionScore::DECAY_GAUSS, 'price', 0, 10);
+ $returnedValue = $query->setMinScore(0.8);
+
+ $this->assertEquals($expected, $query->toArray());
+ $this->assertInstanceOf('Elastica\Query\FunctionScore', $returnedValue);
+
+ $response = $this->_getIndexForTest()->search($query);
+ $results = $response->getResults();
+
+ $this->assertCount(1, $results);
+ $this->assertEquals(1, $results[0]->getId());
+ }
+}
diff --git a/vendor/ruflin/elastica/test/lib/Elastica/Test/Query/FuzzyLikeThisTest.php b/vendor/ruflin/elastica/test/lib/Elastica/Test/Query/FuzzyLikeThisTest.php
new file mode 100644
index 00000000..fe11e788
--- /dev/null
+++ b/vendor/ruflin/elastica/test/lib/Elastica/Test/Query/FuzzyLikeThisTest.php
@@ -0,0 +1,300 @@
+<?php
+namespace Elastica\Test\Query;
+
+use Elastica\Document;
+use Elastica\Index;
+use Elastica\Query\FuzzyLikeThis;
+use Elastica\Test\Base as BaseTest;
+use Elastica\Type;
+use Elastica\Type\Mapping;
+
+class FuzzyLikeThisTest extends BaseTest
+{
+ /**
+ * @group functional
+ */
+ public function testSearch()
+ {
+ $client = $this->_getClient();
+ $index = new Index($client, 'test');
+ $index->create(array(), true);
+ $index->getSettings()->setNumberOfReplicas(0);
+ //$index->getSettings()->setNumberOfShards(1);
+
+ $type = new Type($index, 'helloworldfuzzy');
+ $mapping = new Mapping($type, array(
+ 'email' => array('store' => 'yes', 'type' => 'string', 'index' => 'analyzed'),
+ 'content' => array('store' => 'yes', 'type' => 'string', 'index' => 'analyzed'),
+ ));
+
+ $mapping->setSource(array('enabled' => false));
+ $type->setMapping($mapping);
+
+ $doc = new Document(1000, array('email' => 'testemail@gmail.com', 'content' => 'This is a sample post. Hello World Fuzzy Like This!'));
+ $type->addDocument($doc);
+
+ // Refresh index
+ $index->refresh();
+
+ $fltQuery = new FuzzyLikeThis();
+ $fltQuery->setLikeText('sample gmail');
+ $fltQuery->addFields(array('email', 'content'));
+ $fltQuery->setMinSimilarity(0.3);
+ $fltQuery->setMaxQueryTerms(3);
+ $resultSet = $type->search($fltQuery);
+ $this->assertEquals(1, $resultSet->count());
+ }
+
+ /**
+ * @group unit
+ */
+ public function testSetPrefixLength()
+ {
+ $query = new FuzzyLikeThis();
+
+ $length = 3;
+ $query->setPrefixLength($length);
+
+ $data = $query->toArray();
+
+ $this->assertEquals($length, $data['fuzzy_like_this']['prefix_length']);
+ }
+
+ /**
+ * @group unit
+ */
+ public function testAddFields()
+ {
+ $query = new FuzzyLikeThis();
+
+ $fields = array('test1', 'test2');
+ $query->addFields($fields);
+
+ $data = $query->toArray();
+
+ $this->assertEquals($fields, $data['fuzzy_like_this']['fields']);
+ }
+
+ /**
+ * @group unit
+ */
+ public function testSetLikeText()
+ {
+ $query = new FuzzyLikeThis();
+
+ $text = ' hello world';
+ $query->setLikeText($text);
+
+ $data = $query->toArray();
+
+ $this->assertEquals(trim($text), $data['fuzzy_like_this']['like_text']);
+ }
+
+ /**
+ * @group unit
+ */
+ public function testSetIgnoreTF()
+ {
+ $query = new FuzzyLikeThis();
+
+ $ignoreTF = false;
+ $query->setIgnoreTF($ignoreTF);
+ $data = $query->toArray();
+ $this->assertEquals($ignoreTF, $data['fuzzy_like_this']['ignore_tf']);
+
+ $ignoreTF = true;
+ $query->setIgnoreTF($ignoreTF);
+ $data = $query->toArray();
+ $this->assertEquals($ignoreTF, $data['fuzzy_like_this']['ignore_tf']);
+ }
+
+ /**
+ * @group unit
+ */
+ public function testSetIgnoreTFDefault()
+ {
+ $query = new FuzzyLikeThis();
+
+ $data = $query->toArray();
+
+ $defaultIgnoreTF = false;
+ $this->assertEquals($defaultIgnoreTF, $data['fuzzy_like_this']['ignore_tf']);
+ }
+
+ /**
+ * @group unit
+ */
+ public function testSetMinSimilarity()
+ {
+ $query = new FuzzyLikeThis();
+
+ $similarity = 2;
+ $query->setMinSimilarity($similarity);
+
+ $data = $query->toArray();
+
+ $this->assertEquals($similarity, $data['fuzzy_like_this']['min_similarity']);
+ }
+
+ /**
+ * @group unit
+ */
+ public function testSetBoost()
+ {
+ $query = new FuzzyLikeThis();
+
+ $boost = 2.2;
+ $query->setBoost($boost);
+
+ $data = $query->toArray();
+
+ $this->assertEquals($boost, $data['fuzzy_like_this']['boost']);
+ }
+
+ /**
+ * @group unit
+ */
+ public function testAddAnalyzerViasetParam()
+ {
+ $analyzer = 'snowball';
+
+ $query = new FuzzyLikeThis();
+ $query->setParam('analyzer', $analyzer);
+
+ $data = $query->toArray();
+ $this->assertEquals($analyzer, $data['fuzzy_like_this']['analyzer']);
+ }
+
+ /**
+ * @group unit
+ */
+ public function testSetAnalyzer()
+ {
+ $analyzer = 'snowball';
+
+ $query = new FuzzyLikeThis();
+ $query->setAnalyzer($analyzer);
+
+ $data = $query->toArray();
+ $this->assertEquals($analyzer, $data['fuzzy_like_this']['analyzer']);
+ }
+
+ /**
+ * @group unit
+ */
+ public function testAnalyzerNotPresentInArrayToMaintainDefaultOfField()
+ {
+ $query = new FuzzyLikeThis();
+
+ $data = $query->toArray();
+ $this->assertArrayNotHasKey('analyzer', $data);
+ }
+
+ /**
+ * @group unit
+ */
+ public function testArgArrayFieldsOverwrittenBySetParams()
+ {
+ $query = new FuzzyLikeThis();
+ $query->setMaxQueryTerms(100);
+ $query->setParam('max_query_terms', 200);
+
+ $data = $query->toArray();
+ $this->assertEquals(200, $data['fuzzy_like_this']['max_query_terms']);
+ }
+
+ /**
+ * @group functional
+ */
+ public function testSearchSetAnalyzer()
+ {
+ $client = $this->_getClient();
+ $index = new Index($client, 'test');
+ $index->create(array('analysis' => array(
+ 'analyzer' => array(
+ 'searchAnalyzer' => array(
+ 'type' => 'custom',
+ 'tokenizer' => 'standard',
+ 'filter' => array('myStopWords'),
+ ),
+ ),
+ 'filter' => array(
+ 'myStopWords' => array(
+ 'type' => 'stop',
+ 'stopwords' => array('The'),
+ ),
+ ),
+ )), true);
+
+ $index->getSettings()->setNumberOfReplicas(0);
+ //$index->getSettings()->setNumberOfShards(1);
+
+ $type = new Type($index, 'helloworldfuzzy');
+ $mapping = new Mapping($type, array(
+ 'email' => array('store' => 'yes', 'type' => 'string', 'index' => 'analyzed'),
+ 'content' => array('store' => 'yes', 'type' => 'string', 'index' => 'analyzed'),
+ ));
+
+ $mapping->setSource(array('enabled' => false));
+ $type->setMapping($mapping);
+
+ $type->addDocuments(array(
+ new Document(1000, array('email' => 'testemail@gmail.com', 'content' => 'The Fuzzy Test!')),
+ new Document(1001, array('email' => 'testemail@gmail.com', 'content' => 'Elastica Fuzzy Test')),
+ ));
+
+ // Refresh index
+ $index->refresh();
+
+ $fltQuery = new FuzzyLikeThis();
+ $fltQuery->addFields(array('email', 'content'));
+ $fltQuery->setLikeText('The');
+
+ $fltQuery->setMinSimilarity(0.1);
+ $fltQuery->setMaxQueryTerms(3);
+
+ // Test before analyzer applied, should return 1 result
+ $resultSet = $type->search($fltQuery);
+ $this->assertEquals(1, $resultSet->count());
+
+ $fltQuery->setParam('analyzer', 'searchAnalyzer');
+
+ $resultSet = $type->search($fltQuery);
+ $this->assertEquals(0, $resultSet->count());
+ }
+
+ /**
+ * @group functional
+ */
+ public function testNoLikeTextProvidedShouldReturnNoResults()
+ {
+ $client = $this->_getClient();
+ $index = new Index($client, 'test');
+ $index->create(array(), true);
+ $index->getSettings()->setNumberOfReplicas(0);
+
+ $type = new Type($index, 'helloworldfuzzy');
+ $mapping = new Mapping($type, array(
+ 'email' => array('store' => 'yes', 'type' => 'string', 'index' => 'analyzed'),
+ 'content' => array('store' => 'yes', 'type' => 'string', 'index' => 'analyzed'),
+ ));
+
+ $mapping->setSource(array('enabled' => false));
+ $type->setMapping($mapping);
+
+ $doc = new Document(1000, array('email' => 'testemail@gmail.com', 'content' => 'This is a sample post. Hello World Fuzzy Like This!'));
+ $type->addDocument($doc);
+
+ // Refresh index
+ $index->refresh();
+
+ $fltQuery = new FuzzyLikeThis();
+ $fltQuery->setLikeText('');
+ $fltQuery->addFields(array('email', 'content'));
+ $fltQuery->setMinSimilarity(0.3);
+ $fltQuery->setMaxQueryTerms(3);
+ $resultSet = $type->search($fltQuery);
+
+ $this->assertEquals(0, $resultSet->count());
+ }
+}
diff --git a/vendor/ruflin/elastica/test/lib/Elastica/Test/Query/FuzzyTest.php b/vendor/ruflin/elastica/test/lib/Elastica/Test/Query/FuzzyTest.php
new file mode 100644
index 00000000..e9107232
--- /dev/null
+++ b/vendor/ruflin/elastica/test/lib/Elastica/Test/Query/FuzzyTest.php
@@ -0,0 +1,136 @@
+<?php
+namespace Elastica\Test\Query;
+
+use Elastica\Document;
+use Elastica\Query\Fuzzy;
+use Elastica\Test\Base as BaseTest;
+
+class FuzzyTest extends BaseTest
+{
+ /**
+ * @group unit
+ */
+ public function testToArray()
+ {
+ $fuzzy = new Fuzzy();
+ $fuzzy->addField('user', array('value' => 'Nicolas', 'boost' => 1.0));
+ $expectedArray = array(
+ 'fuzzy' => array(
+ 'user' => array(
+ 'value' => 'Nicolas',
+ 'boost' => 1.0,
+ ),
+ ),
+ );
+ $this->assertEquals($expectedArray, $fuzzy->toArray(), 'Deprecated method failed');
+
+ $fuzzy = new Fuzzy('user', 'Nicolas');
+ $expectedArray = array(
+ 'fuzzy' => array(
+ 'user' => array(
+ 'value' => 'Nicolas',
+ ),
+ ),
+ );
+ $this->assertEquals($expectedArray, $fuzzy->toArray());
+
+ $fuzzy = new Fuzzy();
+ $fuzzy->setField('user', 'Nicolas')->setFieldOption('boost', 1.0);
+ $expectedArray = array(
+ 'fuzzy' => array(
+ 'user' => array(
+ 'value' => 'Nicolas',
+ 'boost' => 1.0,
+ ),
+ ),
+ );
+ $this->assertEquals($expectedArray, $fuzzy->toArray());
+ }
+
+ /**
+ * @group functional
+ */
+ public function testQuery()
+ {
+ $client = $this->_getClient();
+ $index = $client->getIndex('test');
+ $index->create(array(), true);
+ $type = $index->getType('test');
+
+ $type->addDocuments(array(
+ new Document(1, array('name' => 'Basel-Stadt')),
+ new Document(2, array('name' => 'New York')),
+ new Document(3, array('name' => 'Baden')),
+ new Document(4, array('name' => 'Baden Baden')),
+ ));
+
+ $index->refresh();
+
+ $field = 'name';
+
+ $query = new Fuzzy();
+ $query->setField($field, 'Baden');
+
+ $resultSet = $index->search($query);
+
+ $this->assertEquals(2, $resultSet->count());
+ }
+
+ /**
+ * @group unit
+ */
+ public function testBadArguments()
+ {
+ $this->setExpectedException('Elastica\Exception\InvalidException');
+ $query = new Fuzzy();
+ $query->addField('name', array(array('value' => 'Baden')));
+
+ $this->setExpectedException('Elastica\Exception\InvalidException');
+ $query = new Fuzzy();
+ $query->setField('name', array());
+
+ $this->setExpectedException('Elastica\Exception\InvalidException');
+ $query = new Fuzzy();
+ $query->setField('name', 'value');
+ $query->setField('name1', 'value1');
+ }
+
+ /**
+ * @group functional
+ */
+ public function testFuzzyWithFacets()
+ {
+ $index = $this->_createIndex();
+ $type = $index->getType('test');
+
+ $type->addDocuments(array(
+ new Document(1, array('name' => 'Basel-Stadt')),
+ new Document(2, array('name' => 'New York')),
+ new Document(3, array('name' => 'Baden')),
+ new Document(4, array('name' => 'Baden Baden')),
+ ));
+
+ $index->refresh();
+
+ $field = 'name';
+
+ $fuzzyQuery = new Fuzzy();
+ $fuzzyQuery->setField($field, 'Baden');
+
+ $facet = new \Elastica\Facet\Terms('test');
+ $facet->setField('name');
+
+ $query = new \Elastica\Query($fuzzyQuery);
+ $query->addFacet($facet);
+
+ $resultSet = $index->search($query);
+
+ // Assert query worked ok
+ $this->assertEquals(2, $resultSet->count());
+
+ // Check Facets
+ $this->assertTrue($resultSet->hasFacets());
+ $facets = $resultSet->getFacets();
+ $this->assertEquals(2, $facets['test']['total']);
+ }
+}
diff --git a/vendor/ruflin/elastica/test/lib/Elastica/Test/Query/HasChildTest.php b/vendor/ruflin/elastica/test/lib/Elastica/Test/Query/HasChildTest.php
new file mode 100644
index 00000000..a717b1ab
--- /dev/null
+++ b/vendor/ruflin/elastica/test/lib/Elastica/Test/Query/HasChildTest.php
@@ -0,0 +1,117 @@
+<?php
+namespace Elastica\Test\Query;
+
+use Elastica\Document;
+use Elastica\Query;
+use Elastica\Query\HasChild;
+use Elastica\Query\Match;
+use Elastica\Query\MatchAll;
+use Elastica\Test\Base as BaseTest;
+use Elastica\Type\Mapping;
+
+class HasChildTest extends BaseTest
+{
+ /**
+ * @group unit
+ */
+ public function testToArray()
+ {
+ $q = new MatchAll();
+
+ $type = 'test';
+
+ $query = new HasChild($q, $type);
+
+ $expectedArray = array(
+ 'has_child' => array(
+ 'query' => $q->toArray(),
+ 'type' => $type,
+ ),
+ );
+
+ $this->assertEquals($expectedArray, $query->toArray());
+ }
+
+ /**
+ * @group unit
+ */
+ public function testSetScope()
+ {
+ $q = new MatchAll();
+
+ $type = 'test';
+
+ $scope = 'foo';
+
+ $query = new HasChild($q, $type);
+ $query->setScope($scope);
+
+ $expectedArray = array(
+ 'has_child' => array(
+ 'query' => $q->toArray(),
+ 'type' => $type,
+ '_scope' => $scope,
+ ),
+ );
+
+ $this->assertEquals($expectedArray, $query->toArray());
+ }
+
+ /**
+ * @group functional
+ */
+ public function testTypeInsideHasChildSearch()
+ {
+ $index = $this->_getTestIndex();
+
+ $f = new Match();
+ $f->setField('alt.name', 'testname');
+ $query = new HasChild($f, 'child');
+
+ $searchQuery = new Query();
+ $searchQuery->setQuery($query);
+ $searchResults = $index->search($searchQuery);
+
+ $this->assertEquals(1, $searchResults->count());
+
+ $result = $searchResults->current()->getData();
+ $expected = array('id' => 'parent2', 'user' => 'parent2', 'email' => 'parent2@test.com');
+
+ $this->assertEquals($expected, $result);
+ }
+
+ protected function _getTestIndex()
+ {
+ $index = $this->_createIndex('has_child_test');
+
+ $parentType = $index->getType('parent');
+
+ $childType = $index->getType('child');
+ $childMapping = new Mapping($childType);
+ $childMapping->setParent('parent');
+ $childMapping->send();
+
+ $altType = $index->getType('alt');
+ $altDoc = new Document('alt1', array('name' => 'altname'));
+ $altType->addDocument($altDoc);
+
+ $parent1 = new Document('parent1', array('id' => 'parent1', 'user' => 'parent1', 'email' => 'parent1@test.com'));
+ $parentType->addDocument($parent1);
+ $parent2 = new Document('parent2', array('id' => 'parent2', 'user' => 'parent2', 'email' => 'parent2@test.com'));
+ $parentType->addDocument($parent2);
+
+ $child1 = new Document('child1', array('id' => 'child1', 'user' => 'child1', 'email' => 'child1@test.com'));
+ $child1->setParent('parent1');
+ $childType->addDocument($child1);
+ $child2 = new Document('child2', array('id' => 'child2', 'user' => 'child2', 'email' => 'child2@test.com'));
+ $child2->setParent('parent2');
+ $childType->addDocument($child2);
+ $child3 = new Document('child3', array('id' => 'child3', 'user' => 'child3', 'email' => 'child3@test.com', 'alt' => array(array('name' => 'testname'))));
+ $child3->setParent('parent2');
+ $childType->addDocument($child3);
+
+ $index->refresh();
+
+ return $index;
+ }
+}
diff --git a/vendor/ruflin/elastica/test/lib/Elastica/Test/Query/HasParentTest.php b/vendor/ruflin/elastica/test/lib/Elastica/Test/Query/HasParentTest.php
new file mode 100644
index 00000000..31a89852
--- /dev/null
+++ b/vendor/ruflin/elastica/test/lib/Elastica/Test/Query/HasParentTest.php
@@ -0,0 +1,108 @@
+<?php
+namespace Elastica\Test\Query;
+
+use Elastica\Document;
+use Elastica\Query\HasParent;
+use Elastica\Query\Match;
+use Elastica\Query\MatchAll;
+use Elastica\Search;
+use Elastica\Test\Base as BaseTest;
+use Elastica\Type\Mapping;
+
+class HasParentTest extends BaseTest
+{
+ /**
+ * @group unit
+ */
+ public function testToArray()
+ {
+ $q = new MatchAll();
+
+ $type = 'test';
+
+ $query = new HasParent($q, $type);
+
+ $expectedArray = array(
+ 'has_parent' => array(
+ 'query' => $q->toArray(),
+ 'type' => $type,
+ ),
+ );
+
+ $this->assertEquals($expectedArray, $query->toArray());
+ }
+
+ /**
+ * @group unit
+ */
+ public function testSetScope()
+ {
+ $q = new MatchAll();
+
+ $type = 'test';
+
+ $scope = 'foo';
+
+ $query = new HasParent($q, $type);
+ $query->setScope($scope);
+
+ $expectedArray = array(
+ 'has_parent' => array(
+ 'query' => $q->toArray(),
+ 'type' => $type,
+ '_scope' => $scope,
+ ),
+ );
+
+ $this->assertEquals($expectedArray, $query->toArray());
+ }
+
+ /**
+ * @group functional
+ */
+ public function testHasParent()
+ {
+ $index = $this->_createIndex();
+
+ $shopType = $index->getType('shop');
+ $productType = $index->getType('product');
+ $mapping = new Mapping();
+ $mapping->setParent('shop');
+ $productType->setMapping($mapping);
+
+ $shopType->addDocuments(
+ array(
+ new Document('zurich', array('brand' => 'google')),
+ new Document('london', array('brand' => 'apple')),
+ )
+ );
+
+ $doc1 = new Document(1, array('device' => 'chromebook'));
+ $doc1->setParent('zurich');
+
+ $doc2 = new Document(2, array('device' => 'macmini'));
+ $doc2->setParent('london');
+
+ $productType->addDocument($doc1);
+ $productType->addDocument($doc2);
+
+ $index->refresh();
+
+ // All documents
+ $parentQuery = new HasParent(new MatchAll(), $shopType->getName());
+ $search = new Search($index->getClient());
+ $results = $search->search($parentQuery);
+ $this->assertEquals(2, $results->count());
+
+ $match = new Match();
+ $match->setField('brand', 'google');
+
+ $parentQuery = new HasParent($match, $shopType->getName());
+ $search = new Search($index->getClient());
+ $results = $search->search($parentQuery);
+ $this->assertEquals(1, $results->count());
+ $result = $results->current();
+ $data = $result->getData();
+ $this->assertEquals($data['device'], 'chromebook');
+ }
+}
diff --git a/vendor/ruflin/elastica/test/lib/Elastica/Test/Query/HighlightTest.php b/vendor/ruflin/elastica/test/lib/Elastica/Test/Query/HighlightTest.php
new file mode 100644
index 00000000..c6850019
--- /dev/null
+++ b/vendor/ruflin/elastica/test/lib/Elastica/Test/Query/HighlightTest.php
@@ -0,0 +1,48 @@
+<?php
+namespace Elastica\Test\Query;
+
+use Elastica\Document;
+use Elastica\Query;
+use Elastica\Query\QueryString;
+use Elastica\Test\Base as BaseTest;
+
+class HighlightTest extends BaseTest
+{
+ /**
+ * @group functional
+ */
+ public function testHightlightSearch()
+ {
+ $index = $this->_createIndex();
+ $type = $index->getType('helloworld');
+
+ $phrase = 'My name is ruflin';
+
+ $type->addDocuments(array(
+ new Document(1, array('id' => 1, 'phrase' => $phrase, 'username' => 'hanswurst', 'test' => array('2', '3', '5'))),
+ new Document(2, array('id' => 2, 'phrase' => $phrase, 'username' => 'peter', 'test' => array('2', '3', '5'))),
+ ));
+
+ $queryString = new QueryString('rufl*');
+ $query = new Query($queryString);
+ $query->setHighlight(array(
+ 'pre_tags' => array('<em class="highlight">'),
+ 'post_tags' => array('</em>'),
+ 'fields' => array(
+ 'phrase' => array(
+ 'fragment_size' => 200,
+ 'number_of_fragments' => 1,
+ ),
+ ),
+ ));
+
+ $index->refresh();
+
+ $resultSet = $type->search($query);
+ foreach ($resultSet as $result) {
+ $highlight = $result->getHighlights();
+ $this->assertEquals(array('phrase' => array(0 => 'My name is <em class="highlight">ruflin</em>')), $highlight);
+ }
+ $this->assertEquals(2, $resultSet->count());
+ }
+}
diff --git a/vendor/ruflin/elastica/test/lib/Elastica/Test/Query/IdsTest.php b/vendor/ruflin/elastica/test/lib/Elastica/Test/Query/IdsTest.php
new file mode 100644
index 00000000..7b39020f
--- /dev/null
+++ b/vendor/ruflin/elastica/test/lib/Elastica/Test/Query/IdsTest.php
@@ -0,0 +1,187 @@
+<?php
+namespace Elastica\Test\Query;
+
+use Elastica\Document;
+use Elastica\Query\Ids;
+use Elastica\Test\Base as BaseTest;
+
+class IdsTest extends BaseTest
+{
+ protected $_index;
+ protected $_type;
+
+ protected function setUp()
+ {
+ parent::setUp();
+
+ $index = $this->_createIndex();
+
+ $type1 = $index->getType('helloworld1');
+ $type2 = $index->getType('helloworld2');
+
+ $doc = new Document(1, array('name' => 'hello world'));
+ $type1->addDocument($doc);
+
+ $doc = new Document(2, array('name' => 'nicolas ruflin'));
+ $type1->addDocument($doc);
+
+ $doc = new Document(3, array('name' => 'ruflin'));
+ $type1->addDocument($doc);
+
+ $doc = new Document(4, array('name' => 'hello world again'));
+ $type2->addDocument($doc);
+
+ $index->refresh();
+
+ $this->_type = $type1;
+ $this->_index = $index;
+ }
+
+ /**
+ * @group functional
+ */
+ public function testSetIdsSearchSingle()
+ {
+ $query = new Ids();
+ $query->setIds('1');
+
+ $resultSet = $this->_type->search($query);
+
+ $this->assertEquals(1, $resultSet->count());
+ }
+
+ /**
+ * @group functional
+ */
+ public function testSetIdsSearchArray()
+ {
+ $query = new Ids();
+ $query->setIds(array('1', '2'));
+
+ $resultSet = $this->_type->search($query);
+
+ $this->assertEquals(2, $resultSet->count());
+ }
+
+ /**
+ * @group functional
+ */
+ public function testAddIdsSearchSingle()
+ {
+ $query = new Ids();
+ $query->addId('3');
+
+ $resultSet = $this->_type->search($query);
+
+ $this->assertEquals(1, $resultSet->count());
+ }
+
+ /**
+ * @group functional
+ */
+ public function testComboIdsSearchArray()
+ {
+ $query = new Ids();
+
+ $query->setIds(array('1', '2'));
+ $query->addId('3');
+
+ $resultSet = $this->_type->search($query);
+
+ $this->assertEquals(3, $resultSet->count());
+ }
+
+ /**
+ * @group functional
+ */
+ public function testSetTypeSingleSearchSingle()
+ {
+ $query = new Ids();
+
+ $query->setIds('1');
+ $query->setType('helloworld1');
+
+ $resultSet = $this->_index->search($query);
+
+ $this->assertEquals(1, $resultSet->count());
+ }
+
+ /**
+ * @group functional
+ */
+ public function testSetTypeSingleSearchArray()
+ {
+ $query = new Ids();
+
+ $query->setIds(array('1', '2'));
+ $query->setType('helloworld1');
+
+ $resultSet = $this->_index->search($query);
+
+ $this->assertEquals(2, $resultSet->count());
+ }
+
+ /**
+ * @group functional
+ */
+ public function testSetTypeSingleSearchSingleDocInOtherType()
+ {
+ $query = new Ids();
+
+ // Doc 4 is in the second type...
+ $query->setIds('4');
+ $query->setType('helloworld1');
+
+ $resultSet = $this->_index->search($query);
+
+ // ...therefore 0 results should be returned
+ $this->assertEquals(0, $resultSet->count());
+ }
+
+ /**
+ * @group functional
+ */
+ public function testSetTypeSingleSearchArrayDocInOtherType()
+ {
+ $query = new Ids();
+
+ // Doc 4 is in the second type...
+ $query->setIds(array('1', '4'));
+ $query->setType('helloworld1');
+
+ $resultSet = $this->_index->search($query);
+
+ // ...therefore only 1 result should be returned
+ $this->assertEquals(1, $resultSet->count());
+ }
+
+ /**
+ * @group functional
+ */
+ public function testSetTypeArraySearchArray()
+ {
+ $query = new Ids();
+
+ $query->setIds(array('1', '4'));
+ $query->setType(array('helloworld1', 'helloworld2'));
+
+ $resultSet = $this->_index->search($query);
+
+ $this->assertEquals(2, $resultSet->count());
+ }
+
+ /**
+ * @group functional
+ */
+ public function testSetTypeArraySearchSingle()
+ {
+ $query = new Ids();
+
+ $query->setIds('4');
+ $query->setType(array('helloworld1', 'helloworld2'));
+
+ $resultSet = $this->_index->search($query);
+
+ $this->assertEquals(1, $resultSet->count());
+ }
+}
diff --git a/vendor/ruflin/elastica/test/lib/Elastica/Test/Query/ImageTest.php b/vendor/ruflin/elastica/test/lib/Elastica/Test/Query/ImageTest.php
new file mode 100644
index 00000000..989e4e4a
--- /dev/null
+++ b/vendor/ruflin/elastica/test/lib/Elastica/Test/Query/ImageTest.php
@@ -0,0 +1,159 @@
+<?php
+namespace Elastica\Test\Query;
+
+use Elastica\Document;
+use Elastica\Index;
+use Elastica\Query\Image;
+use Elastica\Test\Base as BaseTest;
+use Elastica\Type;
+use Elastica\Type\Mapping;
+
+class ImageTest extends BaseTest
+{
+ /**
+ * @var string
+ */
+ protected $_testFileContent;
+
+ protected function setUp()
+ {
+ parent::setUp();
+ $this->_testFileContent = base64_encode(file_get_contents(BASE_PATH.'/data/test.jpg'));
+ }
+
+ /**
+ * @group unit
+ */
+ public function testToArrayFromReference()
+ {
+ $client = $this->_getClient();
+ $index = new Index($client, 'test');
+ $type = new Type($index, 'helloworld');
+ $field = 'image';
+
+ $query = new Image();
+ $query->setFieldFeature($field, 'CEDD');
+ $query->setFieldHash($field, 'BIT_SAMPLING');
+ $query->setFieldBoost($field, 100);
+
+ $query->setImageByReference($field, $index->getName(), $type->getName(), 10);
+
+ $jsonString = '{"image":{"image":{"feature":"CEDD","hash":"BIT_SAMPLING","boost":100,"index":"test","type":"helloworld","id":10,"path":"image"}}}';
+ $this->assertEquals($jsonString, json_encode($query->toArray()));
+ }
+
+ /**
+ * @group unit
+ */
+ public function testToArrayFromImage()
+ {
+ $field = 'image';
+
+ $query = new Image();
+ $query->setFieldFeature($field, 'CEDD');
+ $query->setFieldHash($field, 'BIT_SAMPLING');
+ $query->setFieldBoost($field, 100);
+
+ $query->setFieldImage($field, BASE_PATH.'/data/test.jpg');
+
+ $jsonString = '{"image":{"image":{"feature":"CEDD","hash":"BIT_SAMPLING","boost":100,"image":"\/9j\/4QAYRXhpZgAASUkqAAgAAAAAAAAAAAAAAP\/sABFEdWNreQABAAQAAAA8AAD\/4QN6aHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wLwA8P3hwYWNrZXQgYmVnaW49Iu+7vyIgaWQ9Ilc1TTBNcENlaGlIenJlU3pOVGN6a2M5ZCI\/PiA8eDp4bXBtZXRhIHhtbG5zOng9ImFkb2JlOm5zOm1ldGEvIiB4OnhtcHRrPSJBZG9iZSBYTVAgQ29yZSA1LjUtYzAyMSA3OS4xNTQ5MTEsIDIwMTMvMTAvMjktMTE6NDc6MTYgICAgICAgICI+IDxyZGY6UkRGIHhtbG5zOnJkZj0iaHR0cDovL3d3dy53My5vcmcvMTk5OS8wMi8yMi1yZGYtc3ludGF4LW5zIyI+IDxyZGY6RGVzY3JpcHRpb24gcmRmOmFib3V0PSIiIHhtbG5zOnhtcE1NPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvbW0vIiB4bWxuczpzdFJlZj0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL3NUeXBlL1Jlc291cmNlUmVmIyIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bXBNTTpPcmlnaW5hbERvY3VtZW50SUQ9InhtcC5kaWQ6OWQ4MjQ5N2MtNzViMS0wYzQ5LTg4ZjMtMDdiNmRhMjU0ZWRhIiB4bXBNTTpEb2N1bWVudElEPSJ4bXAuZGlkOjA4NjBGM0Y1QkJGQTExRTM4MjQ0QzMzNjU2MjUxOEJGIiB4bXBNTTpJbnN0YW5jZUlEPSJ4bXAuaWlkOjA4NjBGM0Y0QkJGQTExRTM4MjQ0QzMzNjU2MjUxOEJGIiB4bXA6Q3JlYXRvclRvb2w9IkFkb2JlIFBob3Rvc2hvcCBDQyAoV2luZG93cykiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDo5ZDgyNDk3Yy03NWIxLTBjNDktODhmMy0wN2I2ZGEyNTRlZGEiIHN0UmVmOmRvY3VtZW50SUQ9InhtcC5kaWQ6OWQ4MjQ5N2MtNzViMS0wYzQ5LTg4ZjMtMDdiNmRhMjU0ZWRhIi8+IDwvcmRmOkRlc2NyaXB0aW9uPiA8L3JkZjpSREY+IDwveDp4bXBtZXRhPiA8P3hwYWNrZXQgZW5kPSJyIj8+\/+4ADkFkb2JlAGTAAAAAAf\/bAIQABgQEBAUEBgUFBgkGBQYJCwgGBggLDAoKCwoKDBAMDAwMDAwQDA4PEA8ODBMTFBQTExwbGxscHx8fHx8fHx8fHwEHBwcNDA0YEBAYGhURFRofHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8f\/8AAEQgAZABkAwERAAIRAQMRAf\/EAKwAAAEFAQEBAQAAAAAAAAAAAAgAAwQFBwYCAQkBAQEAAwEBAAAAAAAAAAAAAAABAgQFAwYQAAEDAgMCBQwOCQQDAAAAAAIBAwQABRESBiEHMUFhExRRcYEisnPDNIQVRRaRodEyQlJikiOzVGYnCLFyo9NklKQlGIIzQ2VTdhcRAAIBAgQEBAYDAQAAAAAAAAABAhEDITESBEFRMgVhcZFCgaHR4SITsVJiFf\/aAAwDAQACEQMRAD8AJyHDhlDYImG1JWwVVUBVVVRTkqge6DC+ztfMH3KgF0GF9na+YPuUAugwvs7XzB9ygF0GF9na+YPuUBR6n1NpDTTAuXUmgdcTFmK22JvuYfFbRMcOVdnLXje3MLa\/JmEpqOZmty32GbiparFGaa24OS1QzXlyNoiJ85a50+5y9q9Tyd7kiva3v6jQ8xwraY\/E5gh9tDrBdxueBP2s6ax74rK6YtXq0DFx2LJjIjzafrAooaJ1sa2LfcU+pUM1eXE0i3nY7jEblwUjyYzqYg62gEK+wnDyV0IzUlVOqPVNMkdBhfZ2vmD7lZFF0GF9na+YPuUBD6JF88c3zIc30fNkyphjnwxwwqkJkHxKP3oO5SoUfoBUAqA47eXr5rSlqEY6C7eJuIwmC2iKJ755xE+AGPZXZWpu9z+qOHU8jzuXNK8Qe813vd2UlV243WaWJmvbOGqcarsQQHsCKVw4Qnclh+UmamLZ3dn3UKQCd1lkprwx42CCnIrpIqqvWSuva7Uve\/Q9la5l0W6rT6hgCSQPiLnlL2iTCth9ss+PqX9aOcv27W725spEEimsDtJpRyvoicaInan2NvJWjf7dKKrB6l8\/uYuDRWaT1fdNN3BJcIlNhxU6XCVcG3hTh\/VcT4Jdhdlali+7bqsiRk0ETZrvBvFsj3KCfORZI5wVdipxKJJxEK7FSu9bmpxTWRtJ1VSbWZSF6b8m8JVA9B8Sj96DuUqAfoDNdab+dKaZvDtnGPIuk6MqDMSNkRtolTHIpuEKKaIqYoOOHHtoCz3bb07frsriMO3yIPm7ms\/SCbLPz2bDLkIuDJx0Bh2u9SHf9VXG5kalHEyYhp8WOwqiOCfKXE+zXzO4u67jkaM5VdTSt3ulAtdrB54E84zBFyUfGIr2wMovUFOHqlX0Gy2ytQ\/08\/oe8I0R3LTIinBW6ZEphGxLthx61Ggiw6Mw8zwIQrXk20zMxXexpMLZLG7xRysSTyShRMERxdouf68MC5a5HcLCi9a45+fP4nhcjTEsdx2oTbuEywun9DIBZcUV4nAVBdRP1kUS7FTt12jcfiWzLgbJXWNghem\/JvCVQPQfEo\/eg7lKgH6AC1m2u6h3hnajeVty63h9hySqZlFDkGpHgvCqCi4VQEvp3dvYNA2a+yLI7KcclxlN1ZTgubY7ZqCjlEMPfLjXncdIvyI8gfbLGR+4W1hzaDzzAn1lMca+b28azinzRoxWISEIUwxw4Vxr642mTxSqQfbCowTI+IqvUVNtYSM4nI70GG39JXNC4W2VcFeoQEhItae9VbMjG50syPdfKNnXtmUOFxxxov1TZPH9FcfaOl2J423+SCVr6A2yF6b8m8JVA9B8Sj96DuUqAfoAOtGF+MtrT\/v3vrXaoDAmRhlRH4x+9fbJsusYqK\/prGSqqBgjgj9ul82YqMm3vZCBeHPHcwVOyoV8zGsJeMX\/AAaGQRdjlNTobctgkJl4BdbVOMTTH2uCvrIyUkmsmbWZbtJjtrMhKbGsWyj2wRxrBmSM73v3lqHpd+Pm+muBDHaHjUcUJxewKVz+43KW6cZYfUwuukfM4PczbHJuuor+XFm3tOyHC6iqPNB7Z1ztjGt1eB5WlWQRdd42yF6b8m8JVA9B8Sj96DuUqA5jeTvJtWhLSzMnMPSn5hmzBjsiioTwgpojhqqIA7Npe1QA2borLf77vMtFwYiOOMx5x3C5TEAkjtoucyTnFTLiRnlEccaoDBqAH7fhpB60X71jihjbLqSJLUU2NS8MMS6gvImxfjJypXG31jTLWsma16NHUh7ud4Q2VUt1wNUtxkqsv7V5kiXFUJE282q7dnvV5Kz2W9UFon08Hy+xjCdDaIdyYkNi82Ym04mIOAqEJIvGhJsrtp1VVkexYDLbRMcajZUVWotV2qzQilXGQLDSJ2grtM1+K2HCS14Xr0barJ\/V+RXJLMH7VWp52qr10lwVajtpzcONjjzbeOOK4cJku0q+d3O4c5apYcvBGpOdXU3XdTo0tPWJX5LeS43DK48K++BtE+jbXl2qq8q11e3bdwhql1S+S4GzZhRVZ21dA9SF6b8m8JVA9B8Sj96DuUqA5feRu0tOvLbGh3CVIhlCcJ+K7GUNjhAoduJiWYUx4NnXoAbdz+p9R6f3m2yyx5riwJVwdt1wgqZLGcwU2+dFtVwE0IEJCTbxLilUBg1AVmpVsnmKYF7Fpy1uN83IbfVEA0NUERxXjIlRE5axkk1R5ElSmIKWoLQ9Y7m9HUSSOhKraEqkQCq4oKl8LBNmbjrlbrt8oOsMY\/NGq7b4Huz6juduPC2z3IxLtVts+1XrguI+1WjC7KHS3EwToXbu8PWxt5EupgnxgFsS9lBr1e8vP3My1y5lCy1e7\/cubYGTd7ia4YBmePsrtQE66ola6UpvCsn6mGLZtu7XdAtoNu66gyOXAVQmIIKhtslxEZcBmnFh2qcvDXT23b6PVcz4I2LdmmLNTrqnuKgIXpvybwlUD0HxKP3oO5SoB+gAo0Qf43WlPvC\/9c9VAa9QGC79NZjcLoOnIp5oVtJHJypwHKVO1DlRoVxX5S8lcff39UtCyWZq35VwMrLUN3Pmbc235yJ0xYhxDxJxTNcoNtn75MVWvXbbqcaLqRhCbQTunN2OloOmIlquFriy3hHnJTjrYuKr57XMDVMcEXYmHEldCduM+pI29KeZIa3XbvWjQwsETMm3aGZPYVVSvJbS1\/VE\/XHkYlvp3zav3fa8LTWlQtsK2JDjyBZKIiqrjqmhe8NtPgJxV7xilkZJULrcV+Ya86v1H6ranjRxnyGnHrdPiCTYuKymZxpxsiPAsmJCQrhs4KpTfKAVAQvTfk3hKoHoPiUfvQdylQD9ABHoYvxxtP8A7E\/9c9VAW28PV7WltNPzhUSnO\/QW5lfhPmi5VVPignbFyJWvub6twb48DCc9KqChcZZqpm44rjpkRuOltIzJcxEvKSrjXz0at1ZpGk\/l10Ot0vD2sZ7eMO2kUe0iSYoclUwdewX\/AMQrkH5Sr1K7Gzte5nvZhxCMroGyKgOe1ToPR2o4stLzZ4cx6QwrBynGGykICIuXK8qZxUVXEcF2LQAafl6JR3zaYRSXY7KDMvCuEV5NvXwoA7KAVAQvTfk3hKoHoPiUfvQdylQD9AA9oUvx0tKfeN\/656qAjN48yyXqZJ09emnIc+P9JalLATNvKirJil71xMVyOBwphtTai15XbMbkaSMZxTWJiZ7utS3a+x7PazbkdKcQFliuVGWse3dMC29oO3BMcV2Vzf8Anzi+aNd2WFhp2w27T9jhWW3BzcKA0LLI8aonCRdUiXElXq11IxSVEbKVFQsayKKgESISKK7UXYqUAAmu7A9uz1+o2K\/xJsq2yykQXoh85IikJqoty21Hm0MUVRIcxIqcOHBQBhblNb3bW+7i16juwMNz5ZPg8MUSFr6F82kVBMjVMUDFdvDQHc0BC9N+TeEqgeg+JR+9B3KVAP0ADOgy\/Ha0J95H\/rnqoDT1Fpiwajt62+9wm50VVQxFxFQgNOA2zFUNs04iBUWoCn0Xu4tGkpEx+HMmTSlZRBZ7ovkyCYrkBzKJqir8dSXZw0B1dAKgFQHl1VFo1HhQVVOvhQH567obLA1XvYsNnvIrJhzpjzs0CVfpUaBx9RNeHAyDAuSgP0Et9ut9tiNwrdFZhQ2UwajR2xaaBFXHtQBEFNvUSgJFAQvTfk3hKoHoPiUfvQdylQD9AABrKPedG7y7o2RlBu1tujs6A+qIiqJPq8w+CFsICEk9tKoO2\/yy3qIiY+aNibV6M5t5f9+oD5\/lpvV\/6j+Wc\/f0B5X82u9Xi80fyzn7+gPJfm43qim3zR\/LOfv6AZP83+9ZODzP\/LO\/v6Ag3P8ANvvZm2+TC5y2xkktk0siPHNHQQ0wUm1N0xQuoqitARPyqafn3XfDbJ0dslhWRqRJmPInaijjJstipcGYzc2Jx4L1KAO2gFQEL035N4SqBmJ546KzzfR+byDkzZ8cMEwxwoQe\/vf8N+0oU5bWfqdjH9c\/V7NgvRfO3NZsMdvN8\/twx4cKA5j8BuP1K\/pKA+fgL9yv6OgF+An3J\/o6A8r\/APAOP1I7PQ6A8F\/j1x+o\/Z6FQHgv8deP1F7PQqA7rRnq\/wCal9S\/MfmrOubzRzfMc5gmObo\/a5sOrtoC\/wD73\/DftKAX97\/hv2lARP7p50\/4Of5j5eTJn9nHGhD\/2Q=="}}}';
+ $this->assertEquals($jsonString, json_encode($query->toArray()));
+ }
+
+ /**
+ * @group functional
+ */
+ public function testFromReference()
+ {
+ $this->markTestSkipped('Tests skipped as plugin not working properly with ES 1.6.0. See https://github.com/ruflin/Elastica/pull/881');
+ $field = 'image';
+
+ $client = $this->_getClient();
+ $index = $client->getIndex('test');
+ $index->create(array(), true);
+
+ $type = $index->getType('test');
+
+ $mapping = new Mapping($type, array(
+ $field => array(
+ 'type' => 'image',
+ 'store' => false,
+ 'include_in_all' => false,
+ 'feature' => array(
+ 'CEDD' => array(
+ 'hash' => 'BIT_SAMPLING',
+ ),
+ ),
+ ),
+ )
+ );
+
+ $type->setMapping($mapping);
+
+ $type->addDocuments(array(
+ new Document(1, array($field => $this->_testFileContent)),
+ new Document(2, array($field => $this->_testFileContent)),
+ new Document(3, array($field => $this->_testFileContent)),
+ ));
+
+ $index->refresh();
+
+ $query = new Image();
+ $query->setFieldFeature($field, 'CEDD');
+ $query->setFieldHash($field, 'BIT_SAMPLING');
+ $query->setFieldBoost($field, 100);
+ $query->setImageByReference($field, $index->getName(), $type->getName(), 1);
+
+ $resultSet = $index->search($query);
+ $this->assertEquals(3, $resultSet->count());
+ }
+
+ /**
+ * @group functional
+ */
+ public function testFromImage()
+ {
+ $this->markTestSkipped('Tests skipped as plugin not working properly with ES 1.6.0. See https://github.com/ruflin/Elastica/pull/881');
+
+ $field = 'image';
+
+ $client = $this->_getClient();
+ $index = $client->getIndex('test');
+ $index->create(array(), true);
+
+ $type = $index->getType('test');
+
+ $mapping = new Mapping($type, array(
+ $field => array(
+ 'type' => 'image',
+ 'store' => false,
+ 'include_in_all' => false,
+ 'feature' => array(
+ 'CEDD' => array(
+ 'hash' => 'BIT_SAMPLING',
+ ),
+ ),
+ ),
+ )
+ );
+
+ $type->setMapping($mapping);
+
+ $type->addDocuments(array(
+ new Document(1, array($field => $this->_testFileContent)),
+ new Document(2, array($field => $this->_testFileContent)),
+ new Document(3, array($field => $this->_testFileContent)),
+ ));
+
+ $index->refresh();
+
+ $query = new Image();
+ $query->setFieldFeature($field, 'CEDD');
+ $query->setFieldHash($field, 'BIT_SAMPLING');
+ $query->setFieldBoost($field, 100);
+ $query->setFieldImage($field, BASE_PATH.'/data/test.jpg');
+
+ $resultSet = $index->search($query);
+ $this->assertEquals(3, $resultSet->count());
+ }
+}
diff --git a/vendor/ruflin/elastica/test/lib/Elastica/Test/Query/MatchAllTest.php b/vendor/ruflin/elastica/test/lib/Elastica/Test/Query/MatchAllTest.php
new file mode 100644
index 00000000..7eb0fae0
--- /dev/null
+++ b/vendor/ruflin/elastica/test/lib/Elastica/Test/Query/MatchAllTest.php
@@ -0,0 +1,49 @@
+<?php
+namespace Elastica\Test\Query;
+
+use Elastica\Document;
+use Elastica\Query\MatchAll;
+use Elastica\Search;
+use Elastica\Test\Base as BaseTest;
+
+class MatchAllTest extends BaseTest
+{
+ /**
+ * @group unit
+ */
+ public function testToArray()
+ {
+ $query = new MatchAll();
+
+ $expectedArray = array('match_all' => new \stdClass());
+
+ $this->assertEquals($expectedArray, $query->toArray());
+ }
+
+ /**
+ * @group functional
+ */
+ public function testMatchAllIndicesTypes()
+ {
+ $index1 = $this->_createIndex();
+ $index2 = $this->_createIndex();
+
+ $client = $index1->getClient();
+
+ $search1 = new Search($client);
+ $resultSet1 = $search1->search(new MatchAll());
+
+ $doc1 = new Document(1, array('name' => 'ruflin'));
+ $doc2 = new Document(1, array('name' => 'ruflin'));
+ $index1->getType('test')->addDocument($doc1);
+ $index2->getType('test')->addDocument($doc2);
+
+ $index1->refresh();
+ $index2->refresh();
+
+ $search2 = new Search($client);
+ $resultSet2 = $search2->search(new MatchAll());
+
+ $this->assertEquals($resultSet1->getTotalHits() + 2, $resultSet2->getTotalHits());
+ }
+}
diff --git a/vendor/ruflin/elastica/test/lib/Elastica/Test/Query/MatchTest.php b/vendor/ruflin/elastica/test/lib/Elastica/Test/Query/MatchTest.php
new file mode 100644
index 00000000..98fdf26a
--- /dev/null
+++ b/vendor/ruflin/elastica/test/lib/Elastica/Test/Query/MatchTest.php
@@ -0,0 +1,339 @@
+<?php
+namespace Elastica\Test\Query;
+
+use Elastica\Document;
+use Elastica\Query\Match;
+use Elastica\Query\MatchPhrase;
+use Elastica\Query\MatchPhrasePrefix;
+use Elastica\Test\Base as BaseTest;
+
+class MatchTest extends BaseTest
+{
+ /**
+ * @group unit
+ */
+ public function testToArray()
+ {
+ $field = 'test';
+ $testQuery = 'Nicolas Ruflin';
+ $type = 'phrase';
+ $operator = 'and';
+ $analyzer = 'myanalyzer';
+ $boost = 2.0;
+ $minimumShouldMatch = 2;
+ $fuzziness = 0.3;
+ $fuzzyRewrite = 'constant_score_boolean';
+ $prefixLength = 3;
+ $maxExpansions = 12;
+
+ $query = new Match();
+ $query->setFieldQuery($field, $testQuery);
+ $query->setFieldType($field, $type);
+ $query->setFieldOperator($field, $operator);
+ $query->setFieldAnalyzer($field, $analyzer);
+ $query->setFieldBoost($field, $boost);
+ $query->setFieldMinimumShouldMatch($field, $minimumShouldMatch);
+ $query->setFieldFuzziness($field, $fuzziness);
+ $query->setFieldFuzzyRewrite($field, $fuzzyRewrite);
+ $query->setFieldPrefixLength($field, $prefixLength);
+ $query->setFieldMaxExpansions($field, $maxExpansions);
+
+ $expectedArray = array(
+ 'match' => array(
+ $field => array(
+ 'query' => $testQuery,
+ 'type' => $type,
+ 'operator' => $operator,
+ 'analyzer' => $analyzer,
+ 'boost' => $boost,
+ 'minimum_should_match' => $minimumShouldMatch,
+ 'fuzziness' => $fuzziness,
+ 'fuzzy_rewrite' => $fuzzyRewrite,
+ 'prefix_length' => $prefixLength,
+ 'max_expansions' => $maxExpansions,
+ ),
+ ),
+ );
+
+ $this->assertEquals($expectedArray, $query->toArray());
+ }
+
+ /**
+ * @group functional
+ */
+ public function testMatch()
+ {
+ $client = $this->_getClient();
+ $index = $client->getIndex('test');
+ $index->create(array(), true);
+ $type = $index->getType('test');
+
+ $type->addDocuments(array(
+ new Document(1, array('name' => 'Basel-Stadt')),
+ new Document(2, array('name' => 'New York')),
+ new Document(3, array('name' => 'New Hampshire')),
+ new Document(4, array('name' => 'Basel Land')),
+ ));
+
+ $index->refresh();
+
+ $field = 'name';
+ $operator = 'or';
+
+ $query = new Match();
+ $query->setFieldQuery($field, 'Basel New');
+ $query->setFieldOperator($field, $operator);
+
+ $resultSet = $index->search($query);
+
+ $this->assertEquals(4, $resultSet->count());
+ }
+
+ /**
+ * @group functional
+ */
+ public function testMatchSetFieldBoost()
+ {
+ $client = $this->_getClient();
+ $index = $client->getIndex('test');
+ $index->create(array(), true);
+ $type = $index->getType('test');
+
+ $type->addDocuments(array(
+ new Document(1, array('name' => 'Basel-Stadt')),
+ new Document(2, array('name' => 'New York')),
+ new Document(3, array('name' => 'New Hampshire')),
+ new Document(4, array('name' => 'Basel Land')),
+ ));
+
+ $index->refresh();
+
+ $field = 'name';
+ $operator = 'or';
+
+ $query = new Match();
+ $query->setFieldQuery($field, 'Basel New');
+ $query->setFieldOperator($field, $operator);
+ $query->setFieldBoost($field, 1.2);
+
+ $resultSet = $index->search($query);
+
+ $this->assertEquals(4, $resultSet->count());
+ }
+
+ /**
+ * @group functional
+ */
+ public function testMatchSetFieldBoostWithString()
+ {
+ $client = $this->_getClient();
+ $index = $client->getIndex('test');
+ $index->create(array(), true);
+ $type = $index->getType('test');
+
+ $type->addDocuments(array(
+ new Document(1, array('name' => 'Basel-Stadt')),
+ new Document(2, array('name' => 'New York')),
+ new Document(3, array('name' => 'New Hampshire')),
+ new Document(4, array('name' => 'Basel Land')),
+ ));
+
+ $index->refresh();
+
+ $field = 'name';
+ $operator = 'or';
+
+ $query = new Match();
+ $query->setFieldQuery($field, 'Basel New');
+ $query->setFieldOperator($field, $operator);
+ $query->setFieldBoost($field, '1.2');
+
+ $resultSet = $index->search($query);
+
+ $this->assertEquals(4, $resultSet->count());
+ }
+
+ /**
+ * @group functional
+ */
+ public function testMatchZeroTerm()
+ {
+ $client = $this->_getClient();
+ $index = $client->getIndex('test');
+ $index->create(array(), true);
+ $type = $index->getType('test');
+
+ $type->addDocuments(array(
+ new Document(1, array('name' => 'Basel-Stadt')),
+ new Document(2, array('name' => 'New York')),
+ ));
+
+ $index->refresh();
+
+ $query = new Match();
+ $query->setFieldQuery('name', '');
+ $query->setFieldZeroTermsQuery('name', Match::ZERO_TERM_ALL);
+
+ $resultSet = $index->search($query);
+
+ $this->assertEquals(2, $resultSet->count());
+ }
+
+ /**
+ * @group functional
+ */
+ public function testMatchPhrase()
+ {
+ $client = $this->_getClient();
+ $index = $client->getIndex('test');
+ $index->create(array(), true);
+ $type = $index->getType('test');
+
+ $type->addDocuments(array(
+ new Document(1, array('name' => 'Basel-Stadt')),
+ new Document(2, array('name' => 'New York')),
+ new Document(3, array('name' => 'New Hampshire')),
+ new Document(4, array('name' => 'Basel Land')),
+ ));
+
+ $index->refresh();
+
+ $field = 'name';
+ $type = 'phrase';
+
+ $query = new Match();
+ $query->setFieldQuery($field, 'New York');
+ $query->setFieldType($field, $type);
+
+ $resultSet = $index->search($query);
+
+ $this->assertEquals(1, $resultSet->count());
+ }
+
+ /**
+ * @group functional
+ */
+ public function testMatchPhraseAlias()
+ {
+ $client = $this->_getClient();
+ $index = $client->getIndex('test');
+ $index->create(array(), true);
+ $type = $index->getType('test');
+
+ $type->addDocuments(array(
+ new Document(1, array('name' => 'Basel-Stadt')),
+ new Document(2, array('name' => 'New York')),
+ new Document(3, array('name' => 'New Hampshire')),
+ new Document(4, array('name' => 'Basel Land')),
+ ));
+
+ $index->refresh();
+
+ $field = 'name';
+
+ $query = new MatchPhrase();
+ $query->setFieldQuery($field, 'New York');
+
+ $resultSet = $index->search($query);
+
+ $this->assertEquals(1, $resultSet->count());
+ }
+
+ /**
+ * @group functional
+ */
+ public function testMatchPhrasePrefix()
+ {
+ $client = $this->_getClient();
+ $index = $client->getIndex('test');
+ $index->create(array(), true);
+ $type = $index->getType('test');
+
+ $type->addDocuments(array(
+ new Document(1, array('name' => 'Basel-Stadt')),
+ new Document(2, array('name' => 'New York')),
+ new Document(3, array('name' => 'New Hampshire')),
+ new Document(4, array('name' => 'Basel Land')),
+ ));
+
+ $index->refresh();
+
+ $field = 'name';
+ $type = 'phrase_prefix';
+
+ $query = new Match();
+ $query->setFieldQuery($field, 'New');
+ $query->setFieldType($field, $type);
+
+ $resultSet = $index->search($query);
+
+ $this->assertEquals(2, $resultSet->count());
+ }
+
+ /**
+ * @group functional
+ */
+ public function testMatchPhrasePrefixAlias()
+ {
+ $client = $this->_getClient();
+ $index = $client->getIndex('test');
+ $index->create(array(), true);
+ $type = $index->getType('test');
+
+ $type->addDocuments(array(
+ new Document(1, array('name' => 'Basel-Stadt')),
+ new Document(2, array('name' => 'New York')),
+ new Document(3, array('name' => 'New Hampshire')),
+ new Document(4, array('name' => 'Basel Land')),
+ ));
+
+ $index->refresh();
+
+ $field = 'name';
+
+ $query = new MatchPhrasePrefix();
+ $query->setFieldQuery($field, 'New');
+
+ $resultSet = $index->search($query);
+
+ $this->assertEquals(2, $resultSet->count());
+ }
+
+ /**
+ * @group unit
+ */
+ public function testMatchFuzzinessType()
+ {
+ $field = 'test';
+ $query = new Match();
+
+ $fuzziness = 'AUTO';
+ $query->setFieldFuzziness($field, $fuzziness);
+
+ $parameters = $query->getParam($field);
+ $this->assertEquals($fuzziness, $parameters['fuzziness']);
+
+ $fuzziness = 0.3;
+ $query->setFieldFuzziness($field, $fuzziness);
+
+ $parameters = $query->getParam($field);
+ $this->assertEquals($fuzziness, $parameters['fuzziness']);
+ }
+
+ /**
+ * @group unit
+ */
+ public function testConstruct()
+ {
+ $match = new Match(null, 'values');
+ $this->assertEquals(array('match' => array()), $match->toArray());
+
+ $match = new Match('field', null);
+ $this->assertEquals(array('match' => array()), $match->toArray());
+
+ $match1 = new Match('field', 'values');
+ $match2 = new Match();
+ $match2->setField('field', 'values');
+ $this->assertEquals($match1->toArray(), $match2->toArray());
+ }
+}
diff --git a/vendor/ruflin/elastica/test/lib/Elastica/Test/Query/MoreLikeThisTest.php b/vendor/ruflin/elastica/test/lib/Elastica/Test/Query/MoreLikeThisTest.php
new file mode 100644
index 00000000..5dfe9379
--- /dev/null
+++ b/vendor/ruflin/elastica/test/lib/Elastica/Test/Query/MoreLikeThisTest.php
@@ -0,0 +1,240 @@
+<?php
+namespace Elastica\Test\Query;
+
+use Elastica\Document;
+use Elastica\Index;
+use Elastica\Query;
+use Elastica\Query\MoreLikeThis;
+use Elastica\Test\Base as BaseTest;
+use Elastica\Type;
+use Elastica\Type\Mapping;
+
+class MoreLikeThisTest extends BaseTest
+{
+ /**
+ * @group functional
+ */
+ public function testSearch()
+ {
+ $client = $this->_getClient();
+ $index = new Index($client, 'test');
+ $index->create(array(), true);
+ $index->getSettings()->setNumberOfReplicas(0);
+ //$index->getSettings()->setNumberOfShards(1);
+
+ $type = new Type($index, 'helloworldmlt');
+ $mapping = new Mapping($type, array(
+ 'email' => array('store' => 'yes', 'type' => 'string', 'index' => 'analyzed'),
+ 'content' => array('store' => 'yes', 'type' => 'string', 'index' => 'analyzed'),
+ ));
+
+ $mapping->setSource(array('enabled' => false));
+ $type->setMapping($mapping);
+
+ $doc = new Document(1000, array('email' => 'testemail@gmail.com', 'content' => 'This is a sample post. Hello World Fuzzy Like This!'));
+ $type->addDocument($doc);
+
+ $doc = new Document(1001, array('email' => 'nospam@gmail.com', 'content' => 'This is a fake nospam email address for gmail'));
+ $type->addDocument($doc);
+
+ // Refresh index
+ $index->refresh();
+
+ $mltQuery = new MoreLikeThis();
+ $mltQuery->setLikeText('fake gmail sample');
+ $mltQuery->setFields(array('email', 'content'));
+ $mltQuery->setMaxQueryTerms(1);
+ $mltQuery->setMinDocFrequency(1);
+ $mltQuery->setMinTermFrequency(1);
+
+ $query = new Query();
+ $query->setFields(array('email', 'content'));
+ $query->setQuery($mltQuery);
+
+ $resultSet = $type->search($query);
+ $resultSet->getResponse()->getData();
+ $this->assertEquals(2, $resultSet->count());
+ }
+
+ /**
+ * @group unit
+ */
+ public function testSetFields()
+ {
+ $query = new MoreLikeThis();
+
+ $fields = array('firstname', 'lastname');
+ $query->setFields($fields);
+
+ $data = $query->toArray();
+ $this->assertEquals($fields, $data['more_like_this']['fields']);
+ }
+
+ /**
+ * @group unit
+ */
+ public function testSetIds()
+ {
+ $query = new MoreLikeThis();
+ $ids = array(1, 2, 3);
+ $query->setIds($ids);
+
+ $data = $query->toArray();
+ $this->assertEquals($ids, $data['more_like_this']['ids']);
+ }
+
+ /**
+ * @group unit
+ */
+ public function testSetLikeText()
+ {
+ $query = new MoreLikeThis();
+ $query->setLikeText(' hello world');
+
+ $data = $query->toArray();
+ $this->assertEquals('hello world', $data['more_like_this']['like_text']);
+ }
+
+ /**
+ * @group unit
+ */
+ public function testSetBoost()
+ {
+ $query = new MoreLikeThis();
+
+ $boost = 1.3;
+ $query->setBoost($boost);
+
+ $this->assertEquals($boost, $query->getParam('boost'));
+ }
+
+ /**
+ * @group unit
+ */
+ public function testSetMaxQueryTerms()
+ {
+ $query = new MoreLikeThis();
+
+ $max = 3;
+ $query->setMaxQueryTerms($max);
+
+ $this->assertEquals($max, $query->getParam('max_query_terms'));
+ }
+
+ /**
+ * @group unit
+ */
+ public function testSetPercentTermsToMatch()
+ {
+ $query = new MoreLikeThis();
+
+ $match = 0.8;
+ $query->setPercentTermsToMatch($match);
+
+ $this->assertEquals($match, $query->getParam('percent_terms_to_match'));
+ }
+
+ /**
+ * @group unit
+ */
+ public function testSetMinimumShouldMatch()
+ {
+ $query = new MoreLikeThis();
+
+ $match = '80%';
+ $query->setMinimumShouldMatch($match);
+
+ $this->assertEquals($match, $query->getParam('minimum_should_match'));
+ }
+
+ /**
+ * @group unit
+ */
+ public function testSetMinDocFrequency()
+ {
+ $query = new MoreLikeThis();
+
+ $freq = 2;
+ $query->setMinDocFrequency($freq);
+
+ $this->assertEquals($freq, $query->getParam('min_doc_freq'));
+ }
+
+ /**
+ * @group unit
+ */
+ public function testSetMaxDocFrequency()
+ {
+ $query = new MoreLikeThis();
+
+ $freq = 2;
+ $query->setMaxDocFrequency($freq);
+
+ $this->assertEquals($freq, $query->getParam('max_doc_freq'));
+ }
+
+ /**
+ * @group unit
+ */
+ public function testSetMinWordLength()
+ {
+ $query = new MoreLikeThis();
+
+ $length = 4;
+ $query->setMinWordLength($length);
+
+ $this->assertEquals($length, $query->getParam('min_word_length'));
+ }
+
+ /**
+ * @group unit
+ */
+ public function testSetMaxWordLength()
+ {
+ $query = new MoreLikeThis();
+
+ $length = 5;
+ $query->setMaxWordLength($length);
+
+ $this->assertEquals($length, $query->getParam('max_word_length'));
+ }
+
+ /**
+ * @group unit
+ */
+ public function testSetBoostTerms()
+ {
+ $query = new MoreLikeThis();
+
+ $boost = false;
+ $query->setBoostTerms($boost);
+
+ $this->assertEquals($boost, $query->getParam('boost_terms'));
+ }
+
+ /**
+ * @group unit
+ */
+ public function testSetAnalyzer()
+ {
+ $query = new MoreLikeThis();
+
+ $analyzer = 'UpperCase';
+ $query->setAnalyzer($analyzer);
+
+ $this->assertEquals($analyzer, $query->getParam('analyzer'));
+ }
+
+ /**
+ * @group unit
+ */
+ public function testSetStopWords()
+ {
+ $query = new MoreLikeThis();
+
+ $stopWords = array('no', 'yes', 'test');
+ $query->setStopWords($stopWords);
+
+ $this->assertEquals($stopWords, $query->getParam('stop_words'));
+ }
+}
diff --git a/vendor/ruflin/elastica/test/lib/Elastica/Test/Query/MultiMatchTest.php b/vendor/ruflin/elastica/test/lib/Elastica/Test/Query/MultiMatchTest.php
new file mode 100644
index 00000000..e32f91af
--- /dev/null
+++ b/vendor/ruflin/elastica/test/lib/Elastica/Test/Query/MultiMatchTest.php
@@ -0,0 +1,214 @@
+<?php
+namespace Elastica\Test\Query;
+
+use Elastica\Document;
+use Elastica\Index;
+use Elastica\Query;
+use Elastica\Query\MultiMatch;
+use Elastica\Test\Base as BaseTest;
+use Elastica\Type;
+use Elastica\Type\Mapping;
+
+class MultiMatchTest extends BaseTest
+{
+ private $index;
+ private $multiMatch;
+
+ private static $data = array(
+ array('id' => 1, 'name' => 'Rodolfo', 'last_name' => 'Moraes', 'full_name' => 'Rodolfo Moraes'),
+ array('id' => 2, 'name' => 'Tristan', 'last_name' => 'Maindron', 'full_name' => 'Tristan Maindron'),
+ array('id' => 3, 'name' => 'Monique', 'last_name' => 'Maindron', 'full_name' => 'Monique Maindron'),
+ array('id' => 4, 'name' => 'John', 'last_name' => 'not Doe', 'full_name' => 'John not Doe'),
+ );
+
+ /**
+ * @group functional
+ */
+ public function testMinimumShouldMatch()
+ {
+ $multiMatch = new MultiMatch();
+ $multiMatch->setQuery('Tristan Maindron');
+ $multiMatch->setFields(array('full_name', 'name'));
+ $multiMatch->setMinimumShouldMatch('2<100%');
+ $resultSet = $this->_getResults($multiMatch);
+
+ $this->assertEquals(1, $resultSet->count());
+ }
+
+ /**
+ * @group functional
+ */
+ public function testAndOperator()
+ {
+ $multiMatch = new MultiMatch();
+ $multiMatch->setQuery('Monique Maindron');
+ $multiMatch->setFields(array('full_name', 'name'));
+ $multiMatch->setOperator(MultiMatch::OPERATOR_AND);
+ $resultSet = $this->_getResults($multiMatch);
+
+ $this->assertEquals(1, $resultSet->count());
+ }
+
+ /**
+ * @group functional
+ */
+ public function testType()
+ {
+ $multiMatch = new MultiMatch();
+ $multiMatch->setQuery('Trist');
+ $multiMatch->setFields(array('full_name', 'name'));
+ $multiMatch->setType(MultiMatch::TYPE_PHRASE_PREFIX);
+ $resultSet = $this->_getResults($multiMatch);
+
+ $this->assertEquals(1, $resultSet->count());
+ }
+
+ /**
+ * @group functional
+ */
+ public function testFuzzy()
+ {
+ $multiMatch = new MultiMatch();
+ $multiMatch->setQuery('Tritsan'); // Mispell on purpose
+ $multiMatch->setFields(array('full_name', 'name'));
+ $multiMatch->setFuzziness(2);
+ $resultSet = $this->_getResults($multiMatch);
+
+ $this->assertEquals(1, $resultSet->count());
+
+ $multiMatch = new MultiMatch();
+ $multiMatch->setQuery('Tritsan'); // Mispell on purpose
+ $multiMatch->setFields(array('full_name', 'name'));
+ $multiMatch->setFuzziness(0);
+ $resultSet = $this->_getResults($multiMatch);
+
+ $this->assertEquals(0, $resultSet->count());
+ }
+
+ /**
+ * @group functional
+ */
+ public function testFuzzyWithOptions1()
+ {
+ // Here Elasticsearch will not accept mispells
+ // on the first 6 letters.
+ $multiMatch = new MultiMatch();
+ $multiMatch->setQuery('Tritsan'); // Mispell on purpose
+ $multiMatch->setFields(array('full_name', 'name'));
+ $multiMatch->setFuzziness(2);
+ $multiMatch->setPrefixLength(6);
+ $resultSet = $this->_getResults($multiMatch);
+
+ $this->assertEquals(0, $resultSet->count());
+ }
+
+ /**
+ * @group functional
+ */
+ public function testFuzzyWithOptions2()
+ {
+ // Here with a 'M' search we should hit 'Moraes' first
+ // and then stop because MaxExpansion = 1.
+ // If MaxExpansion was set to 2, we could hit "Maindron" too.
+ $multiMatch = new MultiMatch();
+ $multiMatch->setQuery('M');
+ $multiMatch->setFields(array('name'));
+ $multiMatch->setType(MultiMatch::TYPE_PHRASE_PREFIX);
+ $multiMatch->setPrefixLength(0);
+ $multiMatch->setMaxExpansions(1);
+ $resultSet = $this->_getResults($multiMatch);
+
+ $this->assertEquals(1, $resultSet->count());
+ }
+
+ /**
+ * @group functional
+ */
+ public function testZeroTerm()
+ {
+ $multiMatch = new MultiMatch();
+ $multiMatch->setQuery('not'); // This is a stopword.
+ $multiMatch->setFields(array('full_name', 'last_name'));
+ $multiMatch->setZeroTermsQuery(MultiMatch::ZERO_TERM_NONE);
+ $multiMatch->setAnalyzer('stops');
+ $resultSet = $this->_getResults($multiMatch);
+
+ $this->assertEquals(0, $resultSet->count());
+
+ $multiMatch->setZeroTermsQuery(MultiMatch::ZERO_TERM_ALL);
+ $resultSet = $this->_getResults($multiMatch);
+
+ $this->assertEquals(4, $resultSet->count());
+ }
+
+ /**
+ * @group functional
+ */
+ public function testBaseMultiMatch()
+ {
+ $multiMatch = new MultiMatch();
+ $multiMatch->setQuery('Rodolfo');
+ $multiMatch->setFields(array('name', 'last_name'));
+ $resultSet = $this->_getResults($multiMatch);
+
+ $this->assertEquals(1, $resultSet->count());
+
+ $multiMatch = new MultiMatch();
+ $multiMatch->setQuery('Moraes');
+ $multiMatch->setFields(array('name', 'last_name'));
+ $resultSet = $this->_getResults($multiMatch);
+
+ $this->assertEquals(1, $resultSet->count());
+ }
+
+ /**
+ * Executes the query with the current multimatch.
+ */
+ private function _getResults(MultiMatch $multiMatch)
+ {
+ return $this->_generateIndex()->search(new Query($multiMatch));
+ }
+
+ /**
+ * Builds an index for testing.
+ */
+ private function _generateIndex()
+ {
+ $client = $this->_getClient();
+ $index = $client->getIndex('test');
+
+ $index->create(array(
+ 'analysis' => array(
+ 'analyzer' => array(
+ 'noStops' => array(
+ 'type' => 'standard',
+ 'stopwords' => '_none_',
+ ),
+ 'stops' => array(
+ 'type' => 'standard',
+ 'stopwords' => array('not'),
+ ),
+ ),
+ ),
+ ), true);
+
+ $type = $index->getType('test');
+
+ $mapping = new Mapping($type, array(
+ 'name' => array('type' => 'string', 'store' => 'no', 'analyzer' => 'noStops'),
+ 'last_name' => array('type' => 'string', 'store' => 'no', 'analyzer' => 'noStops'),
+ 'full_name' => array('type' => 'string', 'store' => 'no', 'analyzer' => 'noStops'),
+ ));
+
+ $type->setMapping($mapping);
+
+ foreach (self::$data as $key => $docData) {
+ $type->addDocument(new Document($key, $docData));
+ }
+
+ // Refresh index
+ $index->refresh();
+
+ return $index;
+ }
+}
diff --git a/vendor/ruflin/elastica/test/lib/Elastica/Test/Query/NestedTest.php b/vendor/ruflin/elastica/test/lib/Elastica/Test/Query/NestedTest.php
new file mode 100644
index 00000000..1b5fc368
--- /dev/null
+++ b/vendor/ruflin/elastica/test/lib/Elastica/Test/Query/NestedTest.php
@@ -0,0 +1,30 @@
+<?php
+namespace Elastica\Test\Query;
+
+use Elastica\Query\Nested;
+use Elastica\Query\QueryString;
+use Elastica\Test\Base as BaseTest;
+
+class NestedTest extends BaseTest
+{
+ /**
+ * @group unit
+ */
+ public function testSetQuery()
+ {
+ $nested = new Nested();
+ $path = 'test1';
+
+ $queryString = new QueryString('test');
+ $this->assertInstanceOf('Elastica\Query\Nested', $nested->setQuery($queryString));
+ $this->assertInstanceOf('Elastica\Query\Nested', $nested->setPath($path));
+ $expected = array(
+ 'nested' => array(
+ 'query' => $queryString->toArray(),
+ 'path' => $path,
+ ),
+ );
+
+ $this->assertEquals($expected, $nested->toArray());
+ }
+}
diff --git a/vendor/ruflin/elastica/test/lib/Elastica/Test/Query/PostFilterTest.php b/vendor/ruflin/elastica/test/lib/Elastica/Test/Query/PostFilterTest.php
new file mode 100644
index 00000000..178c803e
--- /dev/null
+++ b/vendor/ruflin/elastica/test/lib/Elastica/Test/Query/PostFilterTest.php
@@ -0,0 +1,64 @@
+<?php
+namespace Elastica\Test\Query;
+
+use Elastica\Document;
+use Elastica\Filter\Term;
+use Elastica\Query;
+use Elastica\Query\Match;
+use Elastica\Test\Base as BaseTest;
+
+class PostFilterTest extends BaseTest
+{
+ protected function _getTestIndex()
+ {
+ $index = $this->_createIndex();
+ $docs = array(
+ new Document(1, array('color' => 'green', 'make' => 'ford')),
+ new Document(2, array('color' => 'blue', 'make' => 'volvo')),
+ new Document(3, array('color' => 'red', 'make' => 'ford')),
+ new Document(4, array('color' => 'green', 'make' => 'renault')),
+ );
+ $index->getType('test')->addDocuments($docs);
+ $index->refresh();
+
+ return $index;
+ }
+
+ /**
+ * @group unit
+ */
+ public function testToArray()
+ {
+ $query = new Query();
+
+ $post_filter = new Term(array('color' => 'green'));
+ $query->setPostFilter($post_filter);
+
+ $data = $query->toArray();
+
+ $this->assertArrayHasKey('post_filter', $data);
+ $this->assertEquals(array('term' => array('color' => 'green')), $data['post_filter']);
+ }
+
+ /**
+ * @group functional
+ */
+ public function testQuery()
+ {
+ $query = new Query();
+
+ $match = new Match();
+ $match->setField('make', 'ford');
+
+ $query->setQuery($match);
+
+ $filter = new Term();
+ $filter->setTerm('color', 'green');
+
+ $query->setPostFilter($filter);
+
+ $results = $this->_getTestIndex()->search($query);
+
+ $this->assertEquals(1, $results->getTotalHits());
+ }
+}
diff --git a/vendor/ruflin/elastica/test/lib/Elastica/Test/Query/PrefixTest.php b/vendor/ruflin/elastica/test/lib/Elastica/Test/Query/PrefixTest.php
new file mode 100644
index 00000000..e12ead05
--- /dev/null
+++ b/vendor/ruflin/elastica/test/lib/Elastica/Test/Query/PrefixTest.php
@@ -0,0 +1,27 @@
+<?php
+namespace Elastica\Test\Query;
+
+use Elastica\Query\Prefix;
+use Elastica\Test\Base as BaseTest;
+
+class PrefixTest extends BaseTest
+{
+ /**
+ * @group unit
+ */
+ public function testToArray()
+ {
+ $query = new Prefix();
+ $key = 'name';
+ $value = 'ni';
+ $boost = 2;
+ $query->setPrefix($key, $value, $boost);
+
+ $data = $query->toArray();
+
+ $this->assertInternalType('array', $data['prefix']);
+ $this->assertInternalType('array', $data['prefix'][$key]);
+ $this->assertEquals($data['prefix'][$key]['value'], $value);
+ $this->assertEquals($data['prefix'][$key]['boost'], $boost);
+ }
+}
diff --git a/vendor/ruflin/elastica/test/lib/Elastica/Test/Query/QueryStringTest.php b/vendor/ruflin/elastica/test/lib/Elastica/Test/Query/QueryStringTest.php
new file mode 100644
index 00000000..5b549a30
--- /dev/null
+++ b/vendor/ruflin/elastica/test/lib/Elastica/Test/Query/QueryStringTest.php
@@ -0,0 +1,189 @@
+<?php
+namespace Elastica\Test\Query;
+
+use Elastica\Document;
+use Elastica\Query\QueryString;
+use Elastica\Test\Base as BaseTest;
+
+class QueryStringTest extends BaseTest
+{
+ /**
+ * @group unit
+ */
+ public function testSearchMultipleFields()
+ {
+ $str = md5(rand());
+ $query = new QueryString($str);
+
+ $expected = array(
+ 'query' => $str,
+ );
+
+ $this->assertEquals(array('query_string' => $expected), $query->toArray());
+
+ $fields = array();
+ $max = rand() % 10 + 1;
+ for ($i = 0; $i < $max; $i++) {
+ $fields[] = md5(rand());
+ }
+
+ $query->setFields($fields);
+ $expected['fields'] = $fields;
+ $this->assertEquals(array('query_string' => $expected), $query->toArray());
+
+ foreach (array(false, true) as $val) {
+ $query->setUseDisMax($val);
+ $expected['use_dis_max'] = $val;
+
+ $this->assertEquals(array('query_string' => $expected), $query->toArray());
+ }
+ }
+
+ /**
+ * @group functional
+ */
+ public function testSearch()
+ {
+ $index = $this->_createIndex();
+ $index->getSettings()->setNumberOfReplicas(0);
+ $type = $index->getType('helloworld');
+
+ $doc = new Document(1, array('email' => 'test@test.com', 'username' => 'hanswurst', 'test' => array('2', '3', '5')));
+ $type->addDocument($doc);
+ $index->refresh();
+
+ $queryString = new QueryString('test*');
+ $resultSet = $type->search($queryString);
+
+ $this->assertEquals(1, $resultSet->count());
+ }
+
+ /**
+ * Tests if search in multiple fields is possible.
+ *
+ * @group functional
+ */
+ public function testSearchFields()
+ {
+ $index = $this->_createIndex();
+ $type = $index->getType('test');
+
+ $doc = new Document(1, array('title' => 'hello world', 'firstname' => 'nicolas', 'lastname' => 'ruflin', 'price' => '102', 'year' => '2012'));
+ $type->addDocument($doc);
+ $index->refresh();
+
+ $query = new QueryString();
+ $query = $query->setQuery('ruf*');
+ $query = $query->setDefaultField('title');
+ $query = $query->setFields(array('title', 'firstname', 'lastname', 'price', 'year'));
+
+ $resultSet = $type->search($query);
+ $this->assertEquals(1, $resultSet->count());
+ }
+
+ /**
+ * @group unit
+ */
+ public function testSetDefaultOperator()
+ {
+ $operator = 'AND';
+ $query = new QueryString('test');
+ $query->setDefaultOperator($operator);
+
+ $data = $query->toArray();
+
+ $this->assertEquals($data['query_string']['default_operator'], $operator);
+ }
+
+ /**
+ * @group unit
+ */
+ public function testSetDefaultField()
+ {
+ $default = 'field1';
+ $query = new QueryString('test');
+ $query->setDefaultField($default);
+
+ $data = $query->toArray();
+
+ $this->assertEquals($data['query_string']['default_field'], $default);
+ }
+
+ /**
+ * @group unit
+ */
+ public function testSetRewrite()
+ {
+ $rewrite = 'scoring_boolean';
+ $query = new QueryString('test');
+ $query->setRewrite($rewrite);
+
+ $data = $query->toArray();
+
+ $this->assertEquals($data['query_string']['rewrite'], $rewrite);
+ }
+
+ /**
+ * @group unit
+ * @expectedException \Elastica\Exception\InvalidException
+ */
+ public function testSetQueryInvalid()
+ {
+ $query = new QueryString();
+ $query->setQuery(array());
+ }
+
+ /**
+ * @group unit
+ */
+ public function testSetTimezone()
+ {
+ $timezone = 'Europe/Paris';
+ $text = 'date:[2012 TO 2014]';
+
+ $query = new QueryString($text);
+ $query->setTimezone($timezone);
+
+ $expected = array(
+ 'query_string' => array(
+ 'query' => $text,
+ 'time_zone' => $timezone,
+ ),
+ );
+
+ $this->assertEquals($expected, $query->toArray());
+ $this->assertInstanceOf('Elastica\Query\QueryString', $query->setTimezone($timezone));
+ }
+
+ /**
+ * @group unit
+ */
+ public function testSetPhraseSlop()
+ {
+ $phraseSlop = 9;
+
+ $query = new QueryString('test');
+ $query->setPhraseSlop($phraseSlop);
+
+ $data = $query->toArray();
+ $this->assertEquals($phraseSlop, $data['query_string']['phrase_slop']);
+ }
+
+ /**
+ * @group functional
+ */
+ public function testSetBoost()
+ {
+ $index = $this->_createIndex();
+ $query = new QueryString('test');
+ $query->setBoost(9.3);
+
+ $doc = new Document('', array('name' => 'test'));
+ $index->getType('test')->addDocument($doc);
+ $index->refresh();
+
+ $resultSet = $index->search($query);
+
+ $this->assertEquals(1, $resultSet->count());
+ }
+}
diff --git a/vendor/ruflin/elastica/test/lib/Elastica/Test/Query/RangeTest.php b/vendor/ruflin/elastica/test/lib/Elastica/Test/Query/RangeTest.php
new file mode 100644
index 00000000..108ef0c9
--- /dev/null
+++ b/vendor/ruflin/elastica/test/lib/Elastica/Test/Query/RangeTest.php
@@ -0,0 +1,79 @@
+<?php
+namespace Elastica\Test\Query;
+
+use Elastica\Document;
+use Elastica\Query\Range;
+use Elastica\Test\Base as BaseTest;
+
+class RangeTest extends BaseTest
+{
+ /**
+ * @group functional
+ */
+ public function testQuery()
+ {
+ $client = $this->_getClient();
+ $index = $client->getIndex('test');
+ $index->create(array(), true);
+ $type = $index->getType('test');
+
+ $type->addDocuments(array(
+ new Document(1, array('age' => 16, 'height' => 140)),
+ new Document(2, array('age' => 21, 'height' => 155)),
+ new Document(3, array('age' => 33, 'height' => 160)),
+ new Document(4, array('age' => 68, 'height' => 160)),
+ ));
+
+ $index->optimize();
+ $index->refresh();
+
+ $query = new Range('age', array('from' => 10, 'to' => 20));
+ $result = $type->search($query)->count();
+ $this->assertEquals(1, $result);
+
+ $query = new Range();
+ $query->addField('height', array('gte' => 160));
+
+ $result = $type->search($query)->count();
+ $this->assertEquals(2, $result);
+ }
+
+ /**
+ * @group unit
+ */
+ public function testToArray()
+ {
+ $range = new Range();
+
+ $field = array('from' => 20, 'to' => 40);
+ $range->addField('age', $field);
+
+ $expectedArray = array(
+ 'range' => array(
+ 'age' => $field,
+ ),
+ );
+
+ $this->assertEquals($expectedArray, $range->toArray());
+ }
+
+ /**
+ * @group unit
+ */
+ public function testConstruct()
+ {
+ $ranges = array('from' => 20, 'to' => 40);
+ $range = new Range(
+ 'age',
+ $ranges
+ );
+
+ $expectedArray = array(
+ 'range' => array(
+ 'age' => $ranges,
+ ),
+ );
+
+ $this->assertEquals($expectedArray, $range->toArray());
+ }
+}
diff --git a/vendor/ruflin/elastica/test/lib/Elastica/Test/Query/RegexpTest.php b/vendor/ruflin/elastica/test/lib/Elastica/Test/Query/RegexpTest.php
new file mode 100644
index 00000000..c67e6317
--- /dev/null
+++ b/vendor/ruflin/elastica/test/lib/Elastica/Test/Query/RegexpTest.php
@@ -0,0 +1,31 @@
+<?php
+namespace Elastica\Test\Query;
+
+use Elastica\Query\Regexp;
+use Elastica\Test\Base as BaseTest;
+
+class RegexpTest extends BaseTest
+{
+ /**
+ * @group unit
+ */
+ public function testToArray()
+ {
+ $field = 'name';
+ $value = 'ruf';
+ $boost = 2;
+
+ $query = new Regexp($field, $value, $boost);
+
+ $expectedArray = array(
+ 'regexp' => array(
+ $field => array(
+ 'value' => $value,
+ 'boost' => $boost,
+ ),
+ ),
+ );
+
+ $this->assertequals($expectedArray, $query->toArray());
+ }
+}
diff --git a/vendor/ruflin/elastica/test/lib/Elastica/Test/Query/RescoreTest.php b/vendor/ruflin/elastica/test/lib/Elastica/Test/Query/RescoreTest.php
new file mode 100644
index 00000000..87842b0f
--- /dev/null
+++ b/vendor/ruflin/elastica/test/lib/Elastica/Test/Query/RescoreTest.php
@@ -0,0 +1,236 @@
+<?php
+namespace Elastica\Test\Query;
+
+use Elastica\Query;
+use Elastica\Query\Match;
+use Elastica\Query\Term;
+use Elastica\Rescore\Query as QueryRescore;
+use Elastica\Test\Base as BaseTest;
+
+class RescoreTest extends BaseTest
+{
+ /**
+ * @group unit
+ */
+ public function testToArray()
+ {
+ $query = new Query();
+ $mainQuery = new Match();
+ $mainQuery = $mainQuery->setFieldQuery('test1', 'foo');
+ $secQuery = new Term();
+ $secQuery = $secQuery->setTerm('test2', 'bar', 2);
+ $queryRescore = new QueryRescore($secQuery);
+ $query->setQuery($mainQuery);
+ $query->setRescore($queryRescore);
+ $data = $query->toArray();
+
+ $expected = array(
+ 'query' => array(
+ 'match' => array(
+ 'test1' => array(
+ 'query' => 'foo',
+ ),
+ ),
+ ),
+ 'rescore' => array(
+ 'query' => array(
+ 'rescore_query' => array(
+ 'term' => array(
+ 'test2' => array(
+ 'value' => 'bar',
+ 'boost' => 2,
+ ),
+ ),
+ ),
+ ),
+ ),
+ );
+
+ $this->assertEquals($expected, $data);
+ }
+
+ /**
+ * @group unit
+ */
+ public function testSetSize()
+ {
+ $query = new Query();
+ $mainQuery = new Match();
+ $mainQuery = $mainQuery->setFieldQuery('test1', 'foo');
+ $secQuery = new Term();
+ $secQuery = $secQuery->setTerm('test2', 'bar', 2);
+ $queryRescore = new QueryRescore($secQuery);
+ $queryRescore->setWindowSize(50);
+ $query->setQuery($mainQuery);
+ $query->setRescore($queryRescore);
+ $data = $query->toArray();
+
+ $expected = array(
+ 'query' => array(
+ 'match' => array(
+ 'test1' => array(
+ 'query' => 'foo',
+ ),
+ ),
+ ),
+ 'rescore' => array(
+ 'window_size' => 50,
+ 'query' => array(
+ 'rescore_query' => array(
+ 'term' => array(
+ 'test2' => array(
+ 'value' => 'bar',
+ 'boost' => 2,
+ ),
+ ),
+ ),
+ ),
+ ),
+ );
+
+ $this->assertEquals($expected, $data);
+ }
+
+ /**
+ * @group unit
+ */
+ public function testSetWeights()
+ {
+ $query = new Query();
+ $mainQuery = new Match();
+ $mainQuery = $mainQuery->setFieldQuery('test1', 'foo');
+ $secQuery = new Term();
+ $secQuery = $secQuery->setTerm('test2', 'bar', 2);
+ $queryRescore = new QueryRescore($secQuery);
+ $queryRescore->setWindowSize(50);
+ $queryRescore->setQueryWeight(.7);
+ $queryRescore->setRescoreQueryWeight(1.2);
+ $query->setQuery($mainQuery);
+ $query->setRescore($queryRescore);
+ $data = $query->toArray();
+
+ $expected = array(
+ 'query' => array(
+ 'match' => array(
+ 'test1' => array(
+ 'query' => 'foo',
+ ),
+ ),
+ ),
+ 'rescore' => array(
+ 'window_size' => 50,
+ 'query' => array(
+ 'rescore_query' => array(
+ 'term' => array(
+ 'test2' => array(
+ 'value' => 'bar',
+ 'boost' => 2,
+ ),
+ ),
+ ),
+ 'query_weight' => 0.7,
+ 'rescore_query_weight' => 1.2,
+ ),
+ ),
+ );
+
+ $this->assertEquals($expected, $data);
+ }
+
+ /**
+ * @group functional
+ */
+ public function testMultipleQueries()
+ {
+ $query = new Query();
+ $mainQuery = new Match();
+ $mainQuery = $mainQuery->setFieldQuery('test1', 'foo');
+
+ $secQuery1 = new Term();
+ $secQuery1 = $secQuery1->setTerm('test2', 'bar', 1);
+ $rescoreQuery1 = new QueryRescore();
+ $rescoreQuery1->setRescoreQuery($secQuery1);
+
+ $secQuery2 = new Term();
+ $secQuery2 = $secQuery2->setTerm('test2', 'tom', 2);
+ $rescoreQuery2 = new QueryRescore();
+ $rescoreQuery2->setRescoreQuery($secQuery2);
+
+ $query->setQuery($mainQuery);
+ $query->setRescore(array($rescoreQuery1, $rescoreQuery2));
+ $data = $query->toArray();
+
+ $expected = array(
+ 'query' => array(
+ 'match' => array(
+ 'test1' => array(
+ 'query' => 'foo',
+ ),
+ ),
+ ),
+ 'rescore' => array(
+ array(
+ 'query' => array(
+ 'rescore_query' => array(
+ 'term' => array(
+ 'test2' => array(
+ 'value' => 'bar',
+ 'boost' => 1,
+ ),
+ ),
+ ),
+ ),
+ ),
+ array(
+ 'query' => array(
+ 'rescore_query' => array(
+ 'term' => array(
+ 'test2' => array(
+ 'value' => 'tom',
+ 'boost' => 2,
+ ),
+ ),
+ ),
+ ),
+ ),
+ ),
+ );
+
+ $this->assertEquals($expected, $data);
+
+ $index = $this->_createIndex();
+ $index->refresh();
+ $results = $index->search($query);
+ $response = $results->getResponse();
+
+ $this->assertEquals(true, $response->isOk());
+ $this->assertEquals(0, $results->getTotalHits());
+ }
+
+ /**
+ * @group functional
+ */
+ public function testQuery()
+ {
+ $query = new Query();
+ $mainQuery = new Match();
+ $mainQuery = $mainQuery->setFieldQuery('test1', 'foo');
+ $secQuery = new Term();
+ $secQuery = $secQuery->setTerm('test2', 'bar', 2);
+ $queryRescore = new QueryRescore($secQuery);
+ $queryRescore->setWindowSize(50);
+ $queryRescore->setQueryWeight(.7);
+ $queryRescore->setRescoreQueryWeight(1.2);
+ $query->setQuery($mainQuery);
+ $query->setRescore($queryRescore);
+ $data = $query->toArray();
+
+ $index = $this->_createIndex();
+ $index->refresh();
+ $results = $index->search($query);
+ $response = $results->getResponse();
+
+ $this->assertEquals(true, $response->isOk());
+ $this->assertEquals(0, $results->getTotalHits());
+ }
+}
diff --git a/vendor/ruflin/elastica/test/lib/Elastica/Test/Query/SimpleQueryStringTest.php b/vendor/ruflin/elastica/test/lib/Elastica/Test/Query/SimpleQueryStringTest.php
new file mode 100644
index 00000000..80316547
--- /dev/null
+++ b/vendor/ruflin/elastica/test/lib/Elastica/Test/Query/SimpleQueryStringTest.php
@@ -0,0 +1,103 @@
+<?php
+namespace Elastica\Test\Query;
+
+use Elastica\Document;
+use Elastica\Query\SimpleQueryString;
+use Elastica\Test\Base;
+
+class SimpleQueryStringTest extends Base
+{
+ /**
+ * @group unit
+ */
+ public function testToArray()
+ {
+ $string = 'this is a test';
+ $fields = array('field1', 'field2');
+ $query = new SimpleQueryString($string, $fields);
+ $query->setDefaultOperator(SimpleQueryString::OPERATOR_OR);
+ $query->setAnalyzer('whitespace');
+
+ $expected = array(
+ 'simple_query_string' => array(
+ 'query' => $string,
+ 'fields' => $fields,
+ 'analyzer' => 'whitespace',
+ 'default_operator' => SimpleQueryString::OPERATOR_OR,
+ ),
+ );
+
+ $this->assertEquals($expected, $query->toArray());
+ }
+
+ /**
+ * @group functional
+ */
+ public function testQuery()
+ {
+ $index = $this->_createIndex();
+ $docs = array(
+ new Document(1, array('make' => 'Gibson', 'model' => 'Les Paul')),
+ new Document(2, array('make' => 'Gibson', 'model' => 'SG Standard')),
+ new Document(3, array('make' => 'Gibson', 'model' => 'SG Supreme')),
+ new Document(4, array('make' => 'Gibson', 'model' => 'SG Faded')),
+ new Document(5, array('make' => 'Fender', 'model' => 'Stratocaster')),
+ );
+ $index->getType('guitars')->addDocuments($docs);
+ $index->refresh();
+
+ $query = new SimpleQueryString('gibson +sg +-faded', array('make', 'model'));
+ $results = $index->search($query);
+
+ $this->assertEquals(2, $results->getTotalHits());
+
+ $query->setFields(array('model'));
+ $results = $index->search($query);
+
+ // We should not get any hits, since the "make" field was not included in the query.
+ $this->assertEquals(0, $results->getTotalHits());
+ }
+
+ /**
+ * @group unit
+ */
+ public function testSetMinimumShouldMatch()
+ {
+ $expected = array(
+ 'simple_query_string' => array(
+ 'query' => 'DONT PANIC',
+ 'minimum_should_match' => '75%',
+ ),
+ );
+
+ $query = new SimpleQueryString($expected['simple_query_string']['query']);
+ $query->setMinimumShouldMatch($expected['simple_query_string']['minimum_should_match']);
+
+ $this->assertEquals($expected, $query->toArray());
+ $this->assertInstanceOf('Elastica\Query\SimpleQueryString', $query->setMinimumShouldMatch('75%'));
+ }
+
+ /**
+ * @group functional
+ */
+ public function testSetMinimumShouldMatchWorks()
+ {
+ $index = $this->_createIndex();
+ $type = $index->getType('foobars');
+ $type->addDocuments(array(
+ new Document(1, array('body' => 'foo')),
+ new Document(2, array('body' => 'bar')),
+ new Document(3, array('body' => 'foo bar')),
+ new Document(4, array('body' => 'foo baz bar')),
+ ));
+ $index->refresh();
+
+ $query = new SimpleQueryString('foo bar');
+ $query->setMinimumShouldMatch(2);
+ $results = $type->search($query);
+
+ $this->assertCount(2, $results);
+ $this->assertEquals(3, $results[0]->getId());
+ $this->assertEquals(4, $results[1]->getId());
+ }
+}
diff --git a/vendor/ruflin/elastica/test/lib/Elastica/Test/Query/SimpleTest.php b/vendor/ruflin/elastica/test/lib/Elastica/Test/Query/SimpleTest.php
new file mode 100644
index 00000000..b4f1dc8d
--- /dev/null
+++ b/vendor/ruflin/elastica/test/lib/Elastica/Test/Query/SimpleTest.php
@@ -0,0 +1,19 @@
+<?php
+namespace Elastica\Test\Query;
+
+use Elastica\Query\Simple;
+use Elastica\Test\Base as BaseTest;
+
+class SimpleTest extends BaseTest
+{
+ /**
+ * @group unit
+ */
+ public function testToArray()
+ {
+ $testQuery = array('hello' => array('world'), 'name' => 'ruflin');
+ $query = new Simple($testQuery);
+
+ $this->assertEquals($testQuery, $query->toArray());
+ }
+}
diff --git a/vendor/ruflin/elastica/test/lib/Elastica/Test/Query/TermTest.php b/vendor/ruflin/elastica/test/lib/Elastica/Test/Query/TermTest.php
new file mode 100644
index 00000000..da15f0f2
--- /dev/null
+++ b/vendor/ruflin/elastica/test/lib/Elastica/Test/Query/TermTest.php
@@ -0,0 +1,27 @@
+<?php
+namespace Elastica\Test\Query;
+
+use Elastica\Query\Term;
+use Elastica\Test\Base as BaseTest;
+
+class TermTest extends BaseTest
+{
+ /**
+ * @group unit
+ */
+ public function testToArray()
+ {
+ $query = new Term();
+ $key = 'name';
+ $value = 'nicolas';
+ $boost = 2;
+ $query->setTerm($key, $value, $boost);
+
+ $data = $query->toArray();
+
+ $this->assertInternalType('array', $data['term']);
+ $this->assertInternalType('array', $data['term'][$key]);
+ $this->assertEquals($data['term'][$key]['value'], $value);
+ $this->assertEquals($data['term'][$key]['boost'], $boost);
+ }
+}
diff --git a/vendor/ruflin/elastica/test/lib/Elastica/Test/Query/TermsTest.php b/vendor/ruflin/elastica/test/lib/Elastica/Test/Query/TermsTest.php
new file mode 100644
index 00000000..f0c2b4b4
--- /dev/null
+++ b/vendor/ruflin/elastica/test/lib/Elastica/Test/Query/TermsTest.php
@@ -0,0 +1,65 @@
+<?php
+namespace Elastica\Test\Query;
+
+use Elastica\Document;
+use Elastica\Query\Terms;
+use Elastica\Test\Base as BaseTest;
+
+class TermsTest extends BaseTest
+{
+ /**
+ * @group functional
+ */
+ public function testFilteredSearch()
+ {
+ $index = $this->_createIndex();
+ $type = $index->getType('helloworld');
+
+ $type->addDocuments(array(
+ new Document(1, array('name' => 'hello world')),
+ new Document(2, array('name' => 'nicolas ruflin')),
+ new Document(3, array('name' => 'ruflin')),
+ ));
+
+ $query = new Terms();
+ $query->setTerms('name', array('nicolas', 'hello'));
+
+ $index->refresh();
+
+ $resultSet = $type->search($query);
+
+ $this->assertEquals(2, $resultSet->count());
+
+ $query->addTerm('ruflin');
+ $resultSet = $type->search($query);
+
+ $this->assertEquals(3, $resultSet->count());
+ }
+
+ /**
+ * @group unit
+ */
+ public function testSetMinimum()
+ {
+ $key = 'name';
+ $terms = array('nicolas', 'ruflin');
+ $minimum = 2;
+
+ $query = new Terms($key, $terms);
+ $query->setMinimumMatch($minimum);
+
+ $data = $query->toArray();
+ $this->assertEquals($minimum, $data['terms']['minimum_match']);
+ }
+
+ /**
+ * @group unit
+ * @expectedException \Elastica\Exception\InvalidException
+ */
+ public function testInvalidParams()
+ {
+ $query = new Terms();
+
+ $query->toArray();
+ }
+}
diff --git a/vendor/ruflin/elastica/test/lib/Elastica/Test/Query/WildcardTest.php b/vendor/ruflin/elastica/test/lib/Elastica/Test/Query/WildcardTest.php
new file mode 100644
index 00000000..7a0c379e
--- /dev/null
+++ b/vendor/ruflin/elastica/test/lib/Elastica/Test/Query/WildcardTest.php
@@ -0,0 +1,106 @@
+<?php
+namespace Elastica\Test\Query;
+
+use Elastica\Document;
+use Elastica\Query\Wildcard;
+use Elastica\Test\Base as BaseTest;
+use Elastica\Type\Mapping;
+
+class WildcardTest extends BaseTest
+{
+ /**
+ * @group unit
+ */
+ public function testConstructEmpty()
+ {
+ $wildcard = new Wildcard();
+ $this->assertEmpty($wildcard->getParams());
+ }
+
+ /**
+ * @group unit
+ */
+ public function testToArray()
+ {
+ $key = 'name';
+ $value = 'Ru*lin';
+ $boost = 2.0;
+
+ $wildcard = new Wildcard($key, $value, $boost);
+
+ $expectedArray = array(
+ 'wildcard' => array(
+ $key => array(
+ 'value' => $value,
+ 'boost' => $boost,
+ ),
+ ),
+ );
+
+ $this->assertEquals($expectedArray, $wildcard->toArray());
+ }
+
+ /**
+ * @group functional
+ */
+ public function testSearchWithAnalyzer()
+ {
+ $client = $this->_getClient();
+ $index = $client->getIndex('test');
+
+ $indexParams = array(
+ 'analysis' => array(
+ 'analyzer' => array(
+ 'lw' => array(
+ 'type' => 'custom',
+ 'tokenizer' => 'keyword',
+ 'filter' => array('lowercase'),
+ ),
+ ),
+ ),
+ );
+
+ $index->create($indexParams, true);
+ $type = $index->getType('test');
+
+ $mapping = new Mapping($type, array(
+ 'name' => array('type' => 'string', 'store' => 'no', 'analyzer' => 'lw'),
+ )
+ );
+ $type->setMapping($mapping);
+
+ $type->addDocuments(array(
+ new Document(1, array('name' => 'Basel-Stadt')),
+ new Document(2, array('name' => 'New York')),
+ new Document(3, array('name' => 'Baden')),
+ new Document(4, array('name' => 'Baden Baden')),
+ new Document(5, array('name' => 'New Orleans')),
+ ));
+
+ $index->refresh();
+
+ $query = new Wildcard();
+ $query->setValue('name', 'ba*');
+ $resultSet = $index->search($query);
+
+ $this->assertEquals(3, $resultSet->count());
+
+ $query = new Wildcard();
+ $query->setValue('name', 'baden*');
+ $resultSet = $index->search($query);
+
+ $this->assertEquals(2, $resultSet->count());
+
+ $query = new Wildcard();
+ $query->setValue('name', 'baden b*');
+ $resultSet = $index->search($query);
+
+ $this->assertEquals(1, $resultSet->count());
+
+ $query = new Wildcard();
+ $query->setValue('name', 'baden bas*');
+ $resultSet = $index->search($query);
+
+ $this->assertEquals(0, $resultSet->count());
+ }
+}
diff --git a/vendor/ruflin/elastica/test/lib/Elastica/Test/QueryBuilder/DSL/AbstractDSLTest.php b/vendor/ruflin/elastica/test/lib/Elastica/Test/QueryBuilder/DSL/AbstractDSLTest.php
new file mode 100644
index 00000000..3e44f463
--- /dev/null
+++ b/vendor/ruflin/elastica/test/lib/Elastica/Test/QueryBuilder/DSL/AbstractDSLTest.php
@@ -0,0 +1,97 @@
+<?php
+namespace Elastica\Test\QueryBuilder\DSL;
+
+use Elastica\Exception\NotImplementedException;
+use Elastica\QueryBuilder\DSL;
+use Elastica\Test\Base as BaseTest;
+
+abstract class AbstractDSLTest extends BaseTest
+{
+ /**
+ * @param DSL $dsl
+ * @param string $methodName
+ * @param string $className
+ * @param array $arguments
+ */
+ protected function _assertImplemented(DSL $dsl, $methodName, $className, $arguments)
+ {
+ // Check method existence
+ $this->assertTrue(method_exists($dsl, $methodName));
+
+ // Check returned value
+ $return = call_user_func_array(array($dsl, $methodName), $arguments);
+ $this->assertTrue(class_exists($className), 'Class not exists but NotImplementedException is not thrown');
+ $this->assertInstanceOf($className, $return);
+
+ // Check method signature
+ $class = new \ReflectionClass($className);
+ $method = new \ReflectionMethod(get_class($dsl), $methodName);
+ if (!$class->hasMethod('__construct')) {
+ $this->assertEmpty($method->getParameters(), 'Constructor is not defined, but method has some parameters');
+ } else {
+ $this->_assertParametersEquals($class->getMethod('__construct')->getParameters(), $method->getParameters());
+ }
+ }
+
+ /**
+ * @param DSL $dsl
+ * @param string $name
+ */
+ protected function _assertNotImplemented(DSL $dsl, $methodName, $arguments)
+ {
+ try {
+ call_user_func(array($dsl, $methodName), $arguments);
+ $this->fail('NotImplementedException is not thrown');
+ } catch (NotImplementedException $ex) {
+ // expected
+ }
+ }
+
+ /**
+ * @param \ReflectionParameter[] $left
+ * @param \ReflectionParameter[] $right
+ */
+ protected function _assertParametersEquals($left, $right)
+ {
+ $this->assertEquals(count($left), count($right), 'Parameters count mismatch');
+
+ for ($i = 0; $i < count($left); $i++) {
+ $this->assertEquals($left[$i]->getName(), $right[$i]->getName(), 'Parameters names mismatch');
+ $this->assertEquals($left[$i]->isOptional(), $right[$i]->isOptional(), 'Parameters optionality mismatch');
+ $this->assertEquals($this->_getHintName($left[$i]), $this->_getHintName($right[$i]), 'Parameters typehints mismatch');
+ $this->assertEquals($this->_getDefaultValue($left[$i]), $this->_getDefaultValue($right[$i]), 'Default values mismatch');
+ }
+ }
+
+ /**
+ * @param \ReflectionParameter $param
+ *
+ * @return string|null
+ */
+ protected function _getDefaultValue(\ReflectionParameter $param)
+ {
+ if ($param->isOptional()) {
+ return $param->getDefaultValue();
+ }
+ }
+
+ /**
+ * @param \ReflectionParameter $param
+ *
+ * @return string|null
+ */
+ protected function _getHintName(\ReflectionParameter $param)
+ {
+ if (version_compare(phpversion(), '5.4', '>=') && $param->isCallable()) {
+ return 'callable';
+ }
+
+ if ($param->isArray()) {
+ return 'array';
+ }
+
+ if ($class = $param->getClass()) {
+ return $class->getName();
+ }
+ }
+}
diff --git a/vendor/ruflin/elastica/test/lib/Elastica/Test/QueryBuilder/DSL/AggregationTest.php b/vendor/ruflin/elastica/test/lib/Elastica/Test/QueryBuilder/DSL/AggregationTest.php
new file mode 100644
index 00000000..67c70862
--- /dev/null
+++ b/vendor/ruflin/elastica/test/lib/Elastica/Test/QueryBuilder/DSL/AggregationTest.php
@@ -0,0 +1,58 @@
+<?php
+namespace Elastica\Test\QueryBuilder\DSL;
+
+use Elastica\Filter\Exists;
+use Elastica\QueryBuilder\DSL;
+
+class AggregationTest extends AbstractDSLTest
+{
+ /**
+ * @group unit
+ */
+ public function testType()
+ {
+ $aggregationDSL = new DSL\Aggregation();
+
+ $this->assertInstanceOf('Elastica\QueryBuilder\DSL', $aggregationDSL);
+ $this->assertEquals(DSL::TYPE_AGGREGATION, $aggregationDSL->getType());
+ }
+
+ /**
+ * @group unit
+ */
+ public function testInterface()
+ {
+ $aggregationDSL = new DSL\Aggregation();
+
+ $this->_assertImplemented($aggregationDSL, 'avg', 'Elastica\Aggregation\Avg', array('name'));
+ $this->_assertImplemented($aggregationDSL, 'cardinality', 'Elastica\Aggregation\Cardinality', array('name'));
+ $this->_assertImplemented($aggregationDSL, 'date_histogram', 'Elastica\Aggregation\DateHistogram', array('name', 'field', 1));
+ $this->_assertImplemented($aggregationDSL, 'date_range', 'Elastica\Aggregation\DateRange', array('name'));
+ $this->_assertImplemented($aggregationDSL, 'extended_stats', 'Elastica\Aggregation\ExtendedStats', array('name'));
+ $this->_assertImplemented($aggregationDSL, 'filter', 'Elastica\Aggregation\Filter', array('name', new Exists('field')));
+ $this->_assertImplemented($aggregationDSL, 'filters', 'Elastica\Aggregation\Filters', array('name'));
+ $this->_assertImplemented($aggregationDSL, 'geo_distance', 'Elastica\Aggregation\GeoDistance', array('name', 'field', 'origin'));
+ $this->_assertImplemented($aggregationDSL, 'geohash_grid', 'Elastica\Aggregation\GeohashGrid', array('name', 'field'));
+ $this->_assertImplemented($aggregationDSL, 'global_agg', 'Elastica\Aggregation\GlobalAggregation', array('name'));
+ $this->_assertImplemented($aggregationDSL, 'histogram', 'Elastica\Aggregation\Histogram', array('name', 'field', 1));
+ $this->_assertImplemented($aggregationDSL, 'ipv4_range', 'Elastica\Aggregation\IpRange', array('name', 'field'));
+ $this->_assertImplemented($aggregationDSL, 'max', 'Elastica\Aggregation\Max', array('name'));
+ $this->_assertImplemented($aggregationDSL, 'min', 'Elastica\Aggregation\Min', array('name'));
+ $this->_assertImplemented($aggregationDSL, 'missing', 'Elastica\Aggregation\Missing', array('name', 'field'));
+ $this->_assertImplemented($aggregationDSL, 'nested', 'Elastica\Aggregation\Nested', array('name', 'path'));
+ $this->_assertImplemented($aggregationDSL, 'percentiles', 'Elastica\Aggregation\Percentiles', array('name'));
+ $this->_assertImplemented($aggregationDSL, 'range', 'Elastica\Aggregation\Range', array('name'));
+ $this->_assertImplemented($aggregationDSL, 'reverse_nested', 'Elastica\Aggregation\ReverseNested', array('name'));
+ $this->_assertImplemented($aggregationDSL, 'scripted_metric', 'Elastica\Aggregation\ScriptedMetric', array('name'));
+ $this->_assertImplemented($aggregationDSL, 'significant_terms', 'Elastica\Aggregation\SignificantTerms', array('name'));
+ $this->_assertImplemented($aggregationDSL, 'stats', 'Elastica\Aggregation\Stats', array('name'));
+ $this->_assertImplemented($aggregationDSL, 'sum', 'Elastica\Aggregation\Sum', array('name'));
+ $this->_assertImplemented($aggregationDSL, 'terms', 'Elastica\Aggregation\Terms', array('name'));
+ $this->_assertImplemented($aggregationDSL, 'top_hits', 'Elastica\Aggregation\TopHits', array('name'));
+ $this->_assertImplemented($aggregationDSL, 'value_count', 'Elastica\Aggregation\ValueCount', array('name', 'field'));
+
+ $this->_assertNotImplemented($aggregationDSL, 'children', array('name'));
+ $this->_assertNotImplemented($aggregationDSL, 'geo_bounds', array('name'));
+ $this->_assertNotImplemented($aggregationDSL, 'percentile_ranks', array('name'));
+ }
+}
diff --git a/vendor/ruflin/elastica/test/lib/Elastica/Test/QueryBuilder/DSL/FilterTest.php b/vendor/ruflin/elastica/test/lib/Elastica/Test/QueryBuilder/DSL/FilterTest.php
new file mode 100644
index 00000000..755bd18a
--- /dev/null
+++ b/vendor/ruflin/elastica/test/lib/Elastica/Test/QueryBuilder/DSL/FilterTest.php
@@ -0,0 +1,58 @@
+<?php
+namespace Elastica\Test\QueryBuilder\DSL;
+
+use Elastica\Filter\Exists;
+use Elastica\Query\Match;
+use Elastica\QueryBuilder\DSL;
+
+class FilterTest extends AbstractDSLTest
+{
+ /**
+ * @group unit
+ */
+ public function testType()
+ {
+ $filterDSL = new DSL\Filter();
+
+ $this->assertInstanceOf('Elastica\QueryBuilder\DSL', $filterDSL);
+ $this->assertEquals(DSL::TYPE_FILTER, $filterDSL->getType());
+ }
+
+ /**
+ * @group unit
+ */
+ public function testInterface()
+ {
+ $filterDSL = new DSL\Filter();
+
+ $this->_assertImplemented($filterDSL, 'bool', 'Elastica\Filter\BoolFilter', array());
+ $this->_assertImplemented($filterDSL, 'bool_and', 'Elastica\Filter\BoolAnd', array(array(new Exists('field'))));
+ $this->_assertImplemented($filterDSL, 'bool_not', 'Elastica\Filter\BoolNot', array(new Exists('field')));
+ $this->_assertImplemented($filterDSL, 'bool_or', 'Elastica\Filter\BoolOr', array(array(new Exists('field'))));
+ $this->_assertImplemented($filterDSL, 'exists', 'Elastica\Filter\Exists', array('field'));
+ $this->_assertImplemented($filterDSL, 'geo_bounding_box', 'Elastica\Filter\GeoBoundingBox', array('field', array(1, 2)));
+ $this->_assertImplemented($filterDSL, 'geo_distance', 'Elastica\Filter\GeoDistance', array('key', 'location', 'distance'));
+ $this->_assertImplemented($filterDSL, 'geo_distance_range', 'Elastica\Filter\GeoDistanceRange', array('key', 'location'));
+ $this->_assertImplemented($filterDSL, 'geo_polygon', 'Elastica\Filter\GeoPolygon', array('key', array()));
+ $this->_assertImplemented($filterDSL, 'geo_shape_pre_indexed', 'Elastica\Filter\GeoShapePreIndexed', array('path', 'indexedId', 'indexedType', 'indexedIndex', 'indexedPath'));
+ $this->_assertImplemented($filterDSL, 'geo_shape_provided', 'Elastica\Filter\GeoShapeProvided', array('path', array()));
+ $this->_assertImplemented($filterDSL, 'geohash_cell', 'Elastica\Filter\GeohashCell', array('field', 'location'));
+ $this->_assertImplemented($filterDSL, 'has_child', 'Elastica\Filter\HasChild', array(new Match(), 'type'));
+ $this->_assertImplemented($filterDSL, 'has_parent', 'Elastica\Filter\HasParent', array(new Match(), 'type'));
+ $this->_assertImplemented($filterDSL, 'ids', 'Elastica\Filter\Ids', array('type', array()));
+ $this->_assertImplemented($filterDSL, 'indices', 'Elastica\Filter\Indices', array(new Exists('field'), array()));
+ $this->_assertImplemented($filterDSL, 'limit', 'Elastica\Filter\Limit', array(1));
+ $this->_assertImplemented($filterDSL, 'match_all', 'Elastica\Filter\MatchAll', array());
+ $this->_assertImplemented($filterDSL, 'missing', 'Elastica\Filter\Missing', array('field'));
+ $this->_assertImplemented($filterDSL, 'nested', 'Elastica\Filter\Nested', array());
+ $this->_assertImplemented($filterDSL, 'numeric_range', 'Elastica\Filter\NumericRange', array());
+ $this->_assertImplemented($filterDSL, 'prefix', 'Elastica\Filter\Prefix', array('field', 'prefix'));
+ $this->_assertImplemented($filterDSL, 'query', 'Elastica\Filter\Query', array(new Match()));
+ $this->_assertImplemented($filterDSL, 'range', 'Elastica\Filter\Range', array('field', array()));
+ $this->_assertImplemented($filterDSL, 'regexp', 'Elastica\Filter\Regexp', array('field', 'regex'));
+ $this->_assertImplemented($filterDSL, 'script', 'Elastica\Filter\Script', array('script'));
+ $this->_assertImplemented($filterDSL, 'term', 'Elastica\Filter\Term', array());
+ $this->_assertImplemented($filterDSL, 'terms', 'Elastica\Filter\Terms', array('field', array()));
+ $this->_assertImplemented($filterDSL, 'type', 'Elastica\Filter\Type', array('type'));
+ }
+}
diff --git a/vendor/ruflin/elastica/test/lib/Elastica/Test/QueryBuilder/DSL/QueryTest.php b/vendor/ruflin/elastica/test/lib/Elastica/Test/QueryBuilder/DSL/QueryTest.php
new file mode 100644
index 00000000..d4669119
--- /dev/null
+++ b/vendor/ruflin/elastica/test/lib/Elastica/Test/QueryBuilder/DSL/QueryTest.php
@@ -0,0 +1,85 @@
+<?php
+namespace Elastica\Test\QueryBuilder\DSL;
+
+use Elastica\Filter\Exists;
+use Elastica\Query\Match;
+use Elastica\QueryBuilder\DSL;
+
+class QueryTest extends AbstractDSLTest
+{
+ /**
+ * @group unit
+ */
+ public function testType()
+ {
+ $queryDSL = new DSL\Query();
+
+ $this->assertInstanceOf('Elastica\QueryBuilder\DSL', $queryDSL);
+ $this->assertEquals(DSL::TYPE_QUERY, $queryDSL->getType());
+ }
+
+ /**
+ * @group unit
+ */
+ public function testMatch()
+ {
+ $queryDSL = new DSL\Query();
+
+ $match = $queryDSL->match('field', 'match');
+ $this->assertEquals('match', $match->getParam('field'));
+ $this->assertInstanceOf('Elastica\Query\Match', $match);
+ }
+
+ /**
+ * @group unit
+ */
+ public function testInterface()
+ {
+ $queryDSL = new DSL\Query();
+
+ $this->_assertImplemented($queryDSL, 'bool', 'Elastica\Query\BoolQuery', array());
+ $this->_assertImplemented($queryDSL, 'boosting', 'Elastica\Query\Boosting', array());
+ $this->_assertImplemented($queryDSL, 'common_terms', 'Elastica\Query\Common', array('field', 'query', 0.001));
+ $this->_assertImplemented($queryDSL, 'constant_score', 'Elastica\Query\ConstantScore', array(new Match()));
+ $this->_assertImplemented($queryDSL, 'dis_max', 'Elastica\Query\DisMax', array());
+ $this->_assertImplemented($queryDSL, 'filtered', 'Elastica\Query\Filtered', array(new Match(), new Exists('field')));
+ $this->_assertImplemented($queryDSL, 'function_score', 'Elastica\Query\FunctionScore', array());
+ $this->_assertImplemented($queryDSL, 'fuzzy', 'Elastica\Query\Fuzzy', array('field', 'type'));
+ $this->_assertImplemented($queryDSL, 'fuzzy_like_this', 'Elastica\Query\FuzzyLikeThis', array());
+ $this->_assertImplemented($queryDSL, 'has_child', 'Elastica\Query\HasChild', array(new Match()));
+ $this->_assertImplemented($queryDSL, 'has_parent', 'Elastica\Query\HasParent', array(new Match(), 'type'));
+ $this->_assertImplemented($queryDSL, 'ids', 'Elastica\Query\Ids', array('type', array()));
+ $this->_assertImplemented($queryDSL, 'match', 'Elastica\Query\Match', array('field', 'values'));
+ $this->_assertImplemented($queryDSL, 'match_all', 'Elastica\Query\MatchAll', array());
+ $this->_assertImplemented($queryDSL, 'more_like_this', 'Elastica\Query\MoreLikeThis', array());
+ $this->_assertImplemented($queryDSL, 'multi_match', 'Elastica\Query\MultiMatch', array());
+ $this->_assertImplemented($queryDSL, 'nested', 'Elastica\Query\Nested', array());
+ $this->_assertImplemented($queryDSL, 'prefix', 'Elastica\Query\Prefix', array());
+ $this->_assertImplemented($queryDSL, 'query_string', 'Elastica\Query\QueryString', array());
+ $this->_assertImplemented($queryDSL, 'range', 'Elastica\Query\Range', array('field', array()));
+ $this->_assertImplemented($queryDSL, 'regexp', 'Elastica\Query\Regexp', array('field', 'value', 1.0));
+ $this->_assertImplemented($queryDSL, 'simple_query_string', 'Elastica\Query\SimpleQueryString', array('query'));
+ $this->_assertImplemented($queryDSL, 'term', 'Elastica\Query\Term', array());
+ $this->_assertImplemented($queryDSL, 'terms', 'Elastica\Query\Terms', array('field', array()));
+ $this->_assertImplemented($queryDSL, 'top_children', 'Elastica\Query\TopChildren', array(new Match(), 'type'));
+ $this->_assertImplemented($queryDSL, 'wildcard', 'Elastica\Query\Wildcard', array());
+
+ $this->_assertNotImplemented($queryDSL, 'custom_boost_factor', array());
+ $this->_assertNotImplemented($queryDSL, 'custom_filters_score', array());
+ $this->_assertNotImplemented($queryDSL, 'custom_score', array());
+ $this->_assertNotImplemented($queryDSL, 'field', array());
+ $this->_assertNotImplemented($queryDSL, 'fuzzy_like_this_field', array());
+ $this->_assertNotImplemented($queryDSL, 'geo_shape', array());
+ $this->_assertNotImplemented($queryDSL, 'indices', array());
+ $this->_assertNotImplemented($queryDSL, 'minimum_should_match', array());
+ $this->_assertNotImplemented($queryDSL, 'more_like_this_field', array());
+ $this->_assertNotImplemented($queryDSL, 'span_first', array());
+ $this->_assertNotImplemented($queryDSL, 'span_multi_term', array());
+ $this->_assertNotImplemented($queryDSL, 'span_near', array());
+ $this->_assertNotImplemented($queryDSL, 'span_not', array());
+ $this->_assertNotImplemented($queryDSL, 'span_or', array());
+ $this->_assertNotImplemented($queryDSL, 'span_term', array());
+ $this->_assertNotImplemented($queryDSL, 'template', array());
+ $this->_assertNotImplemented($queryDSL, 'text', array());
+ }
+}
diff --git a/vendor/ruflin/elastica/test/lib/Elastica/Test/QueryBuilder/DSL/SuggestTest.php b/vendor/ruflin/elastica/test/lib/Elastica/Test/QueryBuilder/DSL/SuggestTest.php
new file mode 100644
index 00000000..b70e0ba7
--- /dev/null
+++ b/vendor/ruflin/elastica/test/lib/Elastica/Test/QueryBuilder/DSL/SuggestTest.php
@@ -0,0 +1,32 @@
+<?php
+namespace Elastica\Test\QueryBuilder\DSL;
+
+use Elastica\QueryBuilder\DSL;
+
+class SuggestTest extends AbstractDSLTest
+{
+ /**
+ * @group unit
+ */
+ public function testType()
+ {
+ $suggestDSL = new DSL\Suggest();
+
+ $this->assertInstanceOf('Elastica\QueryBuilder\DSL', $suggestDSL);
+ $this->assertEquals(DSL::TYPE_SUGGEST, $suggestDSL->getType());
+ }
+
+ /**
+ * @group unit
+ */
+ public function testInterface()
+ {
+ $suggestDSL = new DSL\Suggest();
+
+ $this->_assertImplemented($suggestDSL, 'completion', 'Elastica\Suggest\Completion', array('name', 'field'));
+ $this->_assertImplemented($suggestDSL, 'phrase', 'Elastica\Suggest\Phrase', array('name', 'field'));
+ $this->_assertImplemented($suggestDSL, 'term', 'Elastica\Suggest\Term', array('name', 'field'));
+
+ $this->_assertNotImplemented($suggestDSL, 'context', array());
+ }
+}
diff --git a/vendor/ruflin/elastica/test/lib/Elastica/Test/QueryBuilder/VersionTest.php b/vendor/ruflin/elastica/test/lib/Elastica/Test/QueryBuilder/VersionTest.php
new file mode 100644
index 00000000..d92848a7
--- /dev/null
+++ b/vendor/ruflin/elastica/test/lib/Elastica/Test/QueryBuilder/VersionTest.php
@@ -0,0 +1,67 @@
+<?php
+namespace Elastica\Test\QueryBuilder;
+
+use Elastica\QueryBuilder\DSL;
+use Elastica\QueryBuilder\Version;
+use Elastica\Test\Base as BaseTest;
+
+class VersionTest extends BaseTest
+{
+ /**
+ * @group unit
+ */
+ public function testVersions()
+ {
+ $dsl = array(
+ new DSL\Query(),
+ new DSL\Filter(),
+ new DSL\Aggregation(),
+ new DSL\Suggest(),
+ );
+
+ $versions = array(
+ new Version\Version090(),
+ new Version\Version100(),
+ new Version\Version110(),
+ new Version\Version120(),
+ new Version\Version130(),
+ new Version\Version140(),
+ new Version\Version150(),
+ );
+
+ foreach ($versions as $version) {
+ $this->assertVersions($version, $dsl);
+ }
+ }
+
+ private function assertVersions(Version $version, array $dsl)
+ {
+ foreach ($version->getQueries() as $query) {
+ $this->assertTrue(
+ method_exists($dsl[0], $query),
+ 'query "'.$query.'" in '.get_class($version).' must be defined in '.get_class($dsl[0])
+ );
+ }
+
+ foreach ($version->getFilters() as $filter) {
+ $this->assertTrue(
+ method_exists($dsl[1], $filter),
+ 'filter "'.$filter.'" in '.get_class($version).' must be defined in '.get_class($dsl[1])
+ );
+ }
+
+ foreach ($version->getAggregations() as $aggregation) {
+ $this->assertTrue(
+ method_exists($dsl[2], $aggregation),
+ 'aggregation "'.$aggregation.'" in '.get_class($version).' must be defined in '.get_class($dsl[2])
+ );
+ }
+
+ foreach ($version->getSuggesters() as $suggester) {
+ $this->assertTrue(
+ method_exists($dsl[3], $suggester),
+ 'suggester "'.$suggester.'" in '.get_class($version).' must be defined in '.get_class($dsl[3])
+ );
+ }
+ }
+}
diff --git a/vendor/ruflin/elastica/test/lib/Elastica/Test/QueryBuilderTest.php b/vendor/ruflin/elastica/test/lib/Elastica/Test/QueryBuilderTest.php
new file mode 100644
index 00000000..6cbfd37b
--- /dev/null
+++ b/vendor/ruflin/elastica/test/lib/Elastica/Test/QueryBuilderTest.php
@@ -0,0 +1,88 @@
+<?php
+namespace Elastica\Test;
+
+use Elastica\Exception\QueryBuilderException;
+use Elastica\Query;
+use Elastica\QueryBuilder;
+use Elastica\Suggest;
+
+class QueryBuilderTest extends \PHPUnit_Framework_TestCase
+{
+ /**
+ * @group unit
+ */
+ public function testCustomDSL()
+ {
+ $qb = new QueryBuilder();
+
+ // test custom DSL
+ $qb->addDSL(new CustomDSL());
+
+ $this->assertTrue($qb->custom()->custom_method(), 'custom DSL execution failed');
+
+ // test custom DSL exception message
+ $exceptionMessage = '';
+ try {
+ $qb->invalid();
+ } catch (QueryBuilderException $exception) {
+ $exceptionMessage = $exception->getMessage();
+ }
+
+ $this->assertEquals('DSL "invalid" not supported', $exceptionMessage);
+ }
+
+ /**
+ * @group unit
+ */
+ public function testFacade()
+ {
+ $qb = new QueryBuilder();
+
+ // test one example QueryBuilder flow for each default DSL type
+ $this->assertInstanceOf('Elastica\Query\AbstractQuery', $qb->query()->match());
+ $this->assertInstanceOf('Elastica\Filter\AbstractFilter', $qb->filter()->bool());
+ $this->assertInstanceOf('Elastica\Aggregation\AbstractAggregation', $qb->aggregation()->avg('name'));
+ $this->assertInstanceOf('Elastica\Suggest\AbstractSuggest', $qb->suggest()->term('name', 'field'));
+ }
+
+ /**
+ * @group unit
+ */
+ public function testFacadeException()
+ {
+ $qb = new QueryBuilder(new QueryBuilder\Version\Version100());
+
+ // undefined
+ $exceptionMessage = '';
+ try {
+ $qb->query()->invalid();
+ } catch (QueryBuilderException $exception) {
+ $exceptionMessage = $exception->getMessage();
+ }
+
+ $this->assertEquals('undefined query "invalid"', $exceptionMessage);
+
+ // unsupported
+ $exceptionMessage = '';
+ try {
+ $qb->aggregation()->top_hits('top_hits');
+ } catch (QueryBuilderException $exception) {
+ $exceptionMessage = $exception->getMessage();
+ }
+
+ $this->assertEquals('aggregation "top_hits" in Version100 not supported', $exceptionMessage);
+ }
+}
+
+class CustomDSL implements QueryBuilder\DSL
+{
+ public function getType()
+ {
+ return 'custom';
+ }
+
+ public function custom_method()
+ {
+ return true;
+ }
+}
diff --git a/vendor/ruflin/elastica/test/lib/Elastica/Test/QueryTest.php b/vendor/ruflin/elastica/test/lib/Elastica/Test/QueryTest.php
new file mode 100644
index 00000000..a39ab23a
--- /dev/null
+++ b/vendor/ruflin/elastica/test/lib/Elastica/Test/QueryTest.php
@@ -0,0 +1,458 @@
+<?php
+namespace Elastica\Test;
+
+use Elastica\Document;
+use Elastica\Exception\InvalidException;
+use Elastica\Facet\Terms;
+use Elastica\Query;
+use Elastica\Query\Builder;
+use Elastica\Query\Term;
+use Elastica\Query\Text;
+use Elastica\Script;
+use Elastica\ScriptFields;
+use Elastica\Suggest;
+use Elastica\Test\Base as BaseTest;
+use Elastica\Type;
+
+class QueryTest extends BaseTest
+{
+ /**
+ * @group unit
+ */
+ public function testStringConversion()
+ {
+ $queryString = '{
+ "query" : {
+ "filtered" : {
+ "filter" : {
+ "range" : {
+ "due" : {
+ "gte" : "2011-07-18 00:00:00",
+ "lt" : "2011-07-25 00:00:00"
+ }
+ }
+ },
+ "query" : {
+ "text_phrase" : {
+ "title" : "Call back request"
+ }
+ }
+ }
+ },
+ "sort" : {
+ "due" : {
+ "reverse" : true
+ }
+ },
+ "fields" : [
+ "created", "assigned_to"
+ ]
+ }';
+
+ $query = new Builder($queryString);
+ $queryArray = $query->toArray();
+
+ $this->assertInternalType('array', $queryArray);
+
+ $this->assertEquals('2011-07-18 00:00:00', $queryArray['query']['filtered']['filter']['range']['due']['gte']);
+ }
+
+ /**
+ * @group unit
+ */
+ public function testRawQuery()
+ {
+ $textQuery = new Term(array('title' => 'test'));
+
+ $query1 = Query::create($textQuery);
+
+ $query2 = new Query();
+ $query2->setRawQuery(array('query' => array('term' => array('title' => 'test'))));
+
+ $this->assertEquals($query1->toArray(), $query2->toArray());
+ }
+
+ /**
+ * @group unit
+ */
+ public function testSuggestShouldNotRemoveOtherParameters()
+ {
+ $query1 = new Query();
+ $query2 = new Query();
+
+ $suggest = new Suggest();
+ $suggest->setGlobalText('test');
+
+ $query1->setSize(40);
+ $query1->setSuggest($suggest);
+
+ $query2->setSuggest($suggest);
+ $query2->setSize(40);
+
+ $this->assertEquals($query1->toArray(), $query2->toArray());
+ }
+
+ /**
+ * @group unit
+ */
+ public function testSetSuggestMustReturnQueryInstance()
+ {
+ $query = new Query();
+ $suggest = new Suggest();
+ $this->assertInstanceOf('Elastica\Query', $query->setSuggest($suggest));
+ }
+
+ /**
+ * @group unit
+ */
+ public function testArrayQuery()
+ {
+ $query = array(
+ 'query' => array(
+ 'text' => array(
+ 'title' => 'test',
+ ),
+ ),
+ );
+
+ $query1 = Query::create($query);
+
+ $query2 = new Query();
+ $query2->setRawQuery(array('query' => array('text' => array('title' => 'test'))));
+
+ $this->assertEquals($query1->toArray(), $query2->toArray());
+ }
+
+ /**
+ * @group functional
+ */
+ public function testSetSort()
+ {
+ $index = $this->_createIndex();
+ $type = $index->getType('test');
+
+ $type->addDocuments(array(
+ new Document(1, array('name' => 'hello world')),
+ new Document(2, array('firstname' => 'guschti', 'lastname' => 'ruflin')),
+ new Document(3, array('firstname' => 'nicolas', 'lastname' => 'ruflin')),
+ ));
+
+ $queryTerm = new Term();
+ $queryTerm->setTerm('lastname', 'ruflin');
+
+ $index->refresh();
+
+ $query = Query::create($queryTerm);
+
+ // ASC order
+ $query->setSort(array(array('firstname' => array('order' => 'asc'))));
+ $resultSet = $type->search($query);
+ $this->assertEquals(2, $resultSet->count());
+
+ $first = $resultSet->current()->getData();
+ $second = $resultSet->next()->getData();
+
+ $this->assertEquals('guschti', $first['firstname']);
+ $this->assertEquals('nicolas', $second['firstname']);
+
+ // DESC order
+ $query->setSort(array('firstname' => array('order' => 'desc')));
+ $resultSet = $type->search($query);
+ $this->assertEquals(2, $resultSet->count());
+
+ $first = $resultSet->current()->getData();
+ $second = $resultSet->next()->getData();
+
+ $this->assertEquals('nicolas', $first['firstname']);
+ $this->assertEquals('guschti', $second['firstname']);
+ }
+
+ /**
+ * @group unit
+ */
+ public function testAddSort()
+ {
+ $query = new Query();
+ $sortParam = array('firstname' => array('order' => 'asc'));
+ $query->addSort($sortParam);
+
+ $this->assertEquals($query->getParam('sort'), array($sortParam));
+ }
+
+ /**
+ * @group unit
+ */
+ public function testSetRawQuery()
+ {
+ $query = new Query();
+
+ $params = array('query' => 'test');
+ $query->setRawQuery($params);
+
+ $this->assertEquals($params, $query->toArray());
+ }
+
+ /**
+ * @group unit
+ */
+ public function testSetFields()
+ {
+ $query = new Query();
+
+ $params = array('query' => 'test');
+
+ $query->setFields(array('firstname', 'lastname'));
+
+ $data = $query->toArray();
+
+ $this->assertContains('firstname', $data['fields']);
+ $this->assertContains('lastname', $data['fields']);
+ $this->assertCount(2, $data['fields']);
+ }
+
+ /**
+ * @group unit
+ */
+ public function testGetQuery()
+ {
+ $query = new Query();
+
+ try {
+ $query->getQuery();
+ $this->fail('should throw exception because query does not exist');
+ } catch (InvalidException $e) {
+ $this->assertTrue(true);
+ }
+
+ $termQuery = new Term();
+ $termQuery->setTerm('text', 'value');
+ $query->setQuery($termQuery);
+
+ $this->assertEquals($termQuery->toArray(), $query->getQuery());
+ }
+
+ /**
+ * @group unit
+ */
+ public function testSetFacets()
+ {
+ $query = new Query();
+
+ $facet = new Terms('text');
+ $query->setFacets(array($facet));
+
+ $data = $query->toArray();
+
+ $this->assertArrayHasKey('facets', $data);
+ $this->assertEquals(array('text' => array('terms' => array())), $data['facets']);
+
+ $query->setFacets(array());
+
+ $this->assertArrayNotHasKey('facets', $query->toArray());
+ }
+
+ /**
+ * @group unit
+ */
+ public function testSetQueryToArrayCast()
+ {
+ $query = new Query();
+ $termQuery = new Term();
+ $termQuery->setTerm('text', 'value');
+ $query->setQuery($termQuery);
+
+ $termQuery->setTerm('text', 'another value');
+
+ $anotherQuery = new Query();
+ $anotherQuery->setQuery($termQuery);
+
+ $this->assertNotEquals($query->toArray(), $anotherQuery->toArray());
+ }
+
+ /**
+ * @group unit
+ */
+ public function testSetQueryToArrayChangeQuery()
+ {
+ $query = new Query();
+ $termQuery = new Term();
+ $termQuery->setTerm('text', 'value');
+ $query->setQuery($termQuery);
+
+ $queryArray = $query->toArray();
+
+ $termQuery = $query->getQuery();
+ $termQuery['term']['text']['value'] = 'another value';
+
+ $this->assertEquals($queryArray, $query->toArray());
+ }
+
+ /**
+ * @group unit
+ */
+ public function testSetScriptFieldsToArrayCast()
+ {
+ $query = new Query();
+ $scriptFields = new ScriptFields();
+ $scriptFields->addScript('script', new Script('script'));
+
+ $query->setScriptFields($scriptFields);
+
+ $scriptFields->addScript('another script', new Script('another script'));
+
+ $anotherQuery = new Query();
+ $anotherQuery->setScriptFields($scriptFields);
+
+ $this->assertNotEquals($query->toArray(), $anotherQuery->toArray());
+ }
+
+ /**
+ * @group unit
+ */
+ public function testAddScriptFieldsToArrayCast()
+ {
+ $query = new Query();
+ $scriptField = new Script('script');
+
+ $query->addScriptField('script', $scriptField);
+
+ $scriptField->setScript('another script');
+
+ $anotherQuery = new Query();
+ $anotherQuery->addScriptField('script', $scriptField);
+
+ $this->assertNotEquals($query->toArray(), $anotherQuery->toArray());
+ }
+
+ /**
+ * @group unit
+ */
+ public function testAddFacetToArrayCast()
+ {
+ $query = new Query();
+ $facet = new Terms('text');
+
+ $query->addFacet($facet);
+
+ $facet->setName('another text');
+
+ $anotherQuery = new Query();
+ $anotherQuery->addFacet($facet);
+
+ $this->assertNotEquals($query->toArray(), $anotherQuery->toArray());
+ }
+
+ /**
+ * @group unit
+ */
+ public function testAddAggregationToArrayCast()
+ {
+ $query = new Query();
+ $aggregation = new \Elastica\Aggregation\Terms('text');
+
+ $query->addAggregation($aggregation);
+
+ $aggregation->setName('another text');
+
+ $anotherQuery = new Query();
+ $anotherQuery->addAggregation($aggregation);
+
+ $this->assertNotEquals($query->toArray(), $anotherQuery->toArray());
+ }
+
+ /**
+ * @group unit
+ */
+ public function testSetSuggestToArrayCast()
+ {
+ $query = new Query();
+ $suggest = new Suggest();
+ $suggest->setGlobalText('text');
+
+ $query->setSuggest($suggest);
+
+ $suggest->setGlobalText('another text');
+
+ $anotherQuery = new Query();
+ $anotherQuery->setSuggest($suggest);
+
+ $this->assertNotEquals($query->toArray(), $anotherQuery->toArray());
+ }
+
+ /**
+ * @group unit
+ */
+ public function testSetRescoreToArrayCast()
+ {
+ $query = new Query();
+ $rescore = new \Elastica\Rescore\Query();
+ $rescore->setQueryWeight(1);
+
+ $query->setRescore($rescore);
+
+ $rescore->setQueryWeight(2);
+
+ $anotherQuery = new Query();
+ $anotherQuery->setRescore($rescore);
+
+ $this->assertNotEquals($query->toArray(), $anotherQuery->toArray());
+ }
+
+ /**
+ * @group unit
+ */
+ public function testSetPostFilterToArrayCast()
+ {
+ $query = new Query();
+ $postFilter = new \Elastica\Filter\Terms();
+ $postFilter->setTerms('key', array('term'));
+ $query->setPostFilter($postFilter);
+
+ $postFilter->setTerms('another key', array('another term'));
+
+ $anotherQuery = new Query();
+ $anotherQuery->setPostFilter($postFilter);
+
+ $this->assertNotEquals($query->toArray(), $anotherQuery->toArray());
+ }
+
+ /**
+ * @group functional
+ */
+ public function testNoSource()
+ {
+ $index = $this->_createIndex();
+
+ $type = new Type($index, 'user');
+
+ // Adds 1 document to the index
+ $doc1 = new Document(1,
+ array('username' => 'ruflin', 'test' => array('2', '3', '5'))
+ );
+ $type->addDocument($doc1);
+
+ // To update index
+ $index->refresh();
+
+ $query = Query::create('ruflin');
+ $resultSet = $type->search($query);
+
+ // Disable source
+ $query->setSource(false);
+
+ $resultSetNoSource = $type->search($query);
+
+ $this->assertEquals(1, $resultSet->count());
+ $this->assertEquals(1, $resultSetNoSource->count());
+
+ // Tests if no source is in response except id
+ $result = $resultSetNoSource->current();
+ $this->assertEquals(1, $result->getId());
+ $this->assertEmpty($result->getData());
+
+ // Tests if source is in response except id
+ $result = $resultSet->current();
+ $this->assertEquals(1, $result->getId());
+ $this->assertNotEmpty($result->getData());
+ }
+}
diff --git a/vendor/ruflin/elastica/test/lib/Elastica/Test/RequestTest.php b/vendor/ruflin/elastica/test/lib/Elastica/Test/RequestTest.php
new file mode 100644
index 00000000..987f2391
--- /dev/null
+++ b/vendor/ruflin/elastica/test/lib/Elastica/Test/RequestTest.php
@@ -0,0 +1,95 @@
+<?php
+namespace Elastica\Test;
+
+use Elastica\Connection;
+use Elastica\Request;
+use Elastica\Test\Base as BaseTest;
+
+class RequestTest extends BaseTest
+{
+ /**
+ * @group unit
+ */
+ public function testConstructor()
+ {
+ $path = 'test';
+ $method = Request::POST;
+ $query = array('no' => 'params');
+ $data = array('key' => 'value');
+
+ $request = new Request($path, $method, $data, $query);
+
+ $this->assertEquals($path, $request->getPath());
+ $this->assertEquals($method, $request->getMethod());
+ $this->assertEquals($query, $request->getQuery());
+ $this->assertEquals($data, $request->getData());
+ }
+
+ /**
+ * @group unit
+ * @expectedException \Elastica\Exception\InvalidException
+ */
+ public function testInvalidConnection()
+ {
+ $request = new Request('', Request::GET);
+ $request->send();
+ }
+
+ /**
+ * @group functional
+ */
+ public function testSend()
+ {
+ $connection = new Connection();
+ $connection->setHost($this->_getHost());
+ $connection->setPort('9200');
+
+ $request = new Request('_status', Request::GET, array(), array(), $connection);
+
+ $response = $request->send();
+
+ $this->assertInstanceOf('Elastica\Response', $response);
+ }
+
+ /**
+ * @group unit
+ */
+ public function testToString()
+ {
+ $path = 'test';
+ $method = Request::POST;
+ $query = array('no' => 'params');
+ $data = array('key' => 'value');
+
+ $connection = new Connection();
+ $connection->setHost($this->_getHost());
+ $connection->setPort('9200');
+
+ $request = new Request($path, $method, $data, $query, $connection);
+
+ $data = $request->toArray();
+
+ $this->assertInternalType('array', $data);
+ $this->assertArrayHasKey('method', $data);
+ $this->assertArrayHasKey('path', $data);
+ $this->assertArrayHasKey('query', $data);
+ $this->assertArrayHasKey('data', $data);
+ $this->assertArrayHasKey('connection', $data);
+ $this->assertEquals($request->getMethod(), $data['method']);
+ $this->assertEquals($request->getPath(), $data['path']);
+ $this->assertEquals($request->getQuery(), $data['query']);
+ $this->assertEquals($request->getData(), $data['data']);
+ $this->assertInternalType('array', $data['connection']);
+ $this->assertArrayHasKey('host', $data['connection']);
+ $this->assertArrayHasKey('port', $data['connection']);
+ $this->assertEquals($request->getConnection()->getHost(), $data['connection']['host']);
+ $this->assertEquals($request->getConnection()->getPort(), $data['connection']['port']);
+
+ $string = $request->toString();
+
+ $this->assertInternalType('string', $string);
+
+ $string = (string) $request;
+ $this->assertInternalType('string', $string);
+ }
+}
diff --git a/vendor/ruflin/elastica/test/lib/Elastica/Test/ResponseTest.php b/vendor/ruflin/elastica/test/lib/Elastica/Test/ResponseTest.php
new file mode 100644
index 00000000..e7b83ade
--- /dev/null
+++ b/vendor/ruflin/elastica/test/lib/Elastica/Test/ResponseTest.php
@@ -0,0 +1,205 @@
+<?php
+namespace Elastica\Test;
+
+use Elastica\Document;
+use Elastica\Facet\DateHistogram;
+use Elastica\Query;
+use Elastica\Query\MatchAll;
+use Elastica\Request;
+use Elastica\Response;
+use Elastica\Test\Base as BaseTest;
+use Elastica\Type\Mapping;
+
+class ResponseTest extends BaseTest
+{
+ /**
+ * @group unit
+ */
+ public function testClassHierarchy()
+ {
+ $facet = new DateHistogram('dateHist1');
+ $this->assertInstanceOf('Elastica\Facet\Histogram', $facet);
+ $this->assertInstanceOf('Elastica\Facet\AbstractFacet', $facet);
+ unset($facet);
+ }
+
+ /**
+ * @group functional
+ */
+ public function testResponse()
+ {
+ $index = $this->_createIndex();
+ $type = $index->getType('helloworld');
+
+ $mapping = new Mapping($type, array(
+ 'name' => array('type' => 'string', 'store' => 'no'),
+ 'dtmPosted' => array('type' => 'date', 'store' => 'no', 'format' => 'yyyy-MM-dd HH:mm:ss'),
+ ));
+ $type->setMapping($mapping);
+
+ $type->addDocuments(array(
+ new Document(1, array('name' => 'nicolas ruflin', 'dtmPosted' => '2011-06-23 21:53:00')),
+ new Document(2, array('name' => 'raul martinez jr', 'dtmPosted' => '2011-06-23 09:53:00')),
+ new Document(3, array('name' => 'rachelle clemente', 'dtmPosted' => '2011-07-08 08:53:00')),
+ new Document(4, array('name' => 'elastica search', 'dtmPosted' => '2011-07-08 01:53:00')),
+ ));
+
+ $query = new Query();
+ $query->setQuery(new MatchAll());
+ $index->refresh();
+
+ $resultSet = $type->search($query);
+
+ $engineTime = $resultSet->getResponse()->getEngineTime();
+ $shardsStats = $resultSet->getResponse()->getShardsStatistics();
+
+ $this->assertInternalType('int', $engineTime);
+ $this->assertTrue(is_array($shardsStats));
+ $this->assertArrayHasKey('total', $shardsStats);
+ $this->assertArrayHasKey('successful', $shardsStats);
+ }
+
+ /**
+ * @group functional
+ */
+ public function testIsOk()
+ {
+ $index = $this->_createIndex();
+ $type = $index->getType('test');
+
+ $doc = new Document(1, array('name' => 'ruflin'));
+ $response = $type->addDocument($doc);
+
+ $this->assertTrue($response->isOk());
+ }
+
+ /**
+ * @group functional
+ */
+ public function testIsOkMultiple()
+ {
+ $index = $this->_createIndex();
+ $type = $index->getType('test');
+
+ $docs = array(
+ new Document(1, array('name' => 'ruflin')),
+ new Document(2, array('name' => 'ruflin')),
+ );
+ $response = $type->addDocuments($docs);
+
+ $this->assertTrue($response->isOk());
+ }
+
+ /**
+ * @group unit
+ */
+ public function testIsOkBulkWithErrorsField()
+ {
+ $response = new Response(json_encode(array(
+ 'took' => 213,
+ 'errors' => false,
+ 'items' => array(
+ array('index' => array('_index' => 'rohlik', '_type' => 'grocery', '_id' => '707891', '_version' => 4, 'status' => 200)),
+ array('index' => array('_index' => 'rohlik', '_type' => 'grocery', '_id' => '707893', '_version' => 4, 'status' => 200)),
+ ),
+ )));
+
+ $this->assertTrue($response->isOk());
+ }
+
+ /**
+ * @group unit
+ */
+ public function testIsNotOkBulkWithErrorsField()
+ {
+ $response = new Response(json_encode(array(
+ 'took' => 213,
+ 'errors' => true,
+ 'items' => array(
+ array('index' => array('_index' => 'rohlik', '_type' => 'grocery', '_id' => '707891', '_version' => 4, 'status' => 200)),
+ array('index' => array('_index' => 'rohlik', '_type' => 'grocery', '_id' => '707893', '_version' => 4, 'status' => 200)),
+ ),
+ )));
+
+ $this->assertFalse($response->isOk());
+ }
+
+ /**
+ * @group unit
+ */
+ public function testIsOkBulkItemsWithOkField()
+ {
+ $response = new Response(json_encode(array(
+ 'took' => 213,
+ 'items' => array(
+ array('index' => array('_index' => 'rohlik', '_type' => 'grocery', '_id' => '707891', '_version' => 4, 'ok' => true)),
+ array('index' => array('_index' => 'rohlik', '_type' => 'grocery', '_id' => '707893', '_version' => 4, 'ok' => true)),
+ ),
+ )));
+
+ $this->assertTrue($response->isOk());
+ }
+
+ /**
+ * @group unit
+ */
+ public function testIsNotOkBulkItemsWithOkField()
+ {
+ $response = new Response(json_encode(array(
+ 'took' => 213,
+ 'items' => array(
+ array('index' => array('_index' => 'rohlik', '_type' => 'grocery', '_id' => '707891', '_version' => 4, 'ok' => true)),
+ array('index' => array('_index' => 'rohlik', '_type' => 'grocery', '_id' => '707893', '_version' => 4, 'ok' => false)),
+ ),
+ )));
+
+ $this->assertFalse($response->isOk());
+ }
+
+ /**
+ * @group unit
+ */
+ public function testIsOkBulkItemsWithStatusField()
+ {
+ $response = new Response(json_encode(array(
+ 'took' => 213,
+ 'items' => array(
+ array('index' => array('_index' => 'rohlik', '_type' => 'grocery', '_id' => '707891', '_version' => 4, 'status' => 200)),
+ array('index' => array('_index' => 'rohlik', '_type' => 'grocery', '_id' => '707893', '_version' => 4, 'status' => 200)),
+ ),
+ )));
+
+ $this->assertTrue($response->isOk());
+ }
+
+ /**
+ * @group unit
+ */
+ public function testIsNotOkBulkItemsWithStatusField()
+ {
+ $response = new Response(json_encode(array(
+ 'took' => 213,
+ 'items' => array(
+ array('index' => array('_index' => 'rohlik', '_type' => 'grocery', '_id' => '707891', '_version' => 4, 'status' => 200)),
+ array('index' => array('_index' => 'rohlik', '_type' => 'grocery', '_id' => '707893', '_version' => 4, 'status' => 301)),
+ ),
+ )));
+
+ $this->assertFalse($response->isOk());
+ }
+
+ /**
+ * @group functional
+ */
+ public function testGetDataEmpty()
+ {
+ $index = $this->_createIndex();
+
+ $response = $index->request(
+ 'non-existant-type/_mapping',
+ Request::GET
+ )->getData();
+
+ $this->assertEquals(0, count($response));
+ }
+}
diff --git a/vendor/ruflin/elastica/test/lib/Elastica/Test/ResultSetTest.php b/vendor/ruflin/elastica/test/lib/Elastica/Test/ResultSetTest.php
new file mode 100644
index 00000000..be76d4a2
--- /dev/null
+++ b/vendor/ruflin/elastica/test/lib/Elastica/Test/ResultSetTest.php
@@ -0,0 +1,95 @@
+<?php
+namespace Elastica\Test;
+
+use Elastica\Document;
+use Elastica\Result;
+use Elastica\Test\Base as BaseTest;
+
+class ResultSetTest extends BaseTest
+{
+ /**
+ * @group functional
+ */
+ public function testGetters()
+ {
+ $index = $this->_createIndex();
+ $type = $index->getType('test');
+
+ $type->addDocuments(array(
+ new Document(1, array('name' => 'elastica search')),
+ new Document(2, array('name' => 'elastica library')),
+ new Document(3, array('name' => 'elastica test')),
+ ));
+ $index->refresh();
+
+ $resultSet = $type->search('elastica search');
+
+ $this->assertInstanceOf('Elastica\ResultSet', $resultSet);
+ $this->assertEquals(3, $resultSet->getTotalHits());
+ $this->assertGreaterThan(0, $resultSet->getMaxScore());
+ $this->assertInternalType('array', $resultSet->getResults());
+ $this->assertEquals(3, count($resultSet));
+ }
+
+ /**
+ * @group functional
+ */
+ public function testArrayAccess()
+ {
+ $index = $this->_createIndex();
+ $type = $index->getType('test');
+
+ $type->addDocuments(array(
+ new Document(1, array('name' => 'elastica search')),
+ new Document(2, array('name' => 'elastica library')),
+ new Document(3, array('name' => 'elastica test')),
+ ));
+ $index->refresh();
+
+ $resultSet = $type->search('elastica search');
+
+ $this->assertInstanceOf('Elastica\ResultSet', $resultSet);
+ $this->assertInstanceOf('Elastica\Result', $resultSet[0]);
+ $this->assertInstanceOf('Elastica\Result', $resultSet[1]);
+ $this->assertInstanceOf('Elastica\Result', $resultSet[2]);
+
+ $this->assertFalse(isset($resultSet[3]));
+ }
+
+ /**
+ * @group functional
+ * @expectedException \Elastica\Exception\InvalidException
+ */
+ public function testInvalidOffsetCreation()
+ {
+ $index = $this->_createIndex();
+ $type = $index->getType('test');
+
+ $doc = new Document(1, array('name' => 'elastica search'));
+ $type->addDocument($doc);
+ $index->refresh();
+
+ $resultSet = $type->search('elastica search');
+
+ $result = new Result(array('_id' => 'fakeresult'));
+ $resultSet[1] = $result;
+ }
+
+ /**
+ * @group functional
+ * @expectedException \Elastica\Exception\InvalidException
+ */
+ public function testInvalidOffsetGet()
+ {
+ $index = $this->_createIndex();
+ $type = $index->getType('test');
+
+ $doc = new Document(1, array('name' => 'elastica search'));
+ $type->addDocument($doc);
+ $index->refresh();
+
+ $resultSet = $type->search('elastica search');
+
+ return $resultSet[3];
+ }
+}
diff --git a/vendor/ruflin/elastica/test/lib/Elastica/Test/ResultTest.php b/vendor/ruflin/elastica/test/lib/Elastica/Test/ResultTest.php
new file mode 100644
index 00000000..a905fcc5
--- /dev/null
+++ b/vendor/ruflin/elastica/test/lib/Elastica/Test/ResultTest.php
@@ -0,0 +1,131 @@
+<?php
+namespace Elastica\Test;
+
+use Elastica\Document;
+use Elastica\Result;
+use Elastica\Test\Base as BaseTest;
+use Elastica\Type\Mapping;
+
+class ResultTest extends BaseTest
+{
+ /**
+ * @group functional
+ */
+ public function testGetters()
+ {
+ // Creates a new index 'xodoa' and a type 'user' inside this index
+ $typeName = 'user';
+
+ $index = $this->_createIndex();
+ $type = $index->getType($typeName);
+
+ // Adds 1 document to the index
+ $docId = 3;
+ $doc1 = new Document($docId, array('username' => 'hans'));
+ $type->addDocument($doc1);
+
+ // Refreshes index
+ $index->refresh();
+
+ $resultSet = $type->search('hans');
+
+ $this->assertEquals(1, $resultSet->count());
+
+ $result = $resultSet->current();
+
+ $this->assertInstanceOf('Elastica\Result', $result);
+ $this->assertEquals($index->getName(), $result->getIndex());
+ $this->assertEquals($typeName, $result->getType());
+ $this->assertEquals($docId, $result->getId());
+ $this->assertGreaterThan(0, $result->getScore());
+ $this->assertInternalType('array', $result->getData());
+ $this->assertTrue(isset($result->username));
+ $this->assertEquals('hans', $result->username);
+ }
+
+ /**
+ * @group functional
+ */
+ public function testGetIdNoSource()
+ {
+ // Creates a new index 'xodoa' and a type 'user' inside this index
+ $indexName = 'xodoa';
+ $typeName = 'user';
+
+ $client = $this->_getClient();
+ $index = $client->getIndex($indexName);
+ $index->create(array(), true);
+ $type = $index->getType($typeName);
+
+ $mapping = new Mapping($type);
+ $mapping->disableSource();
+ $mapping->send();
+
+ // Adds 1 document to the index
+ $docId = 3;
+ $doc1 = new Document($docId, array('username' => 'hans'));
+ $type->addDocument($doc1);
+
+ // Refreshes index
+ $index->refresh();
+
+ $resultSet = $type->search('hans');
+
+ $this->assertEquals(1, $resultSet->count());
+
+ $result = $resultSet->current();
+
+ $this->assertEquals(array(), $result->getSource());
+ $this->assertInstanceOf('Elastica\Result', $result);
+ $this->assertEquals($indexName, $result->getIndex());
+ $this->assertEquals($typeName, $result->getType());
+ $this->assertEquals($docId, $result->getId());
+ $this->assertGreaterThan(0, $result->getScore());
+ $this->assertInternalType('array', $result->getData());
+ }
+
+ /**
+ * @group functional
+ */
+ public function testGetTotalTimeReturnsExpectedResults()
+ {
+ $typeName = 'user';
+ $index = $this->_createIndex();
+ $type = $index->getType($typeName);
+
+ // Adds 1 document to the index
+ $docId = 3;
+ $doc1 = new Document($docId, array('username' => 'hans'));
+ $type->addDocument($doc1);
+
+ // Refreshes index
+ $index->refresh();
+
+ $resultSet = $type->search('hans');
+
+ $this->assertNotNull($resultSet->getTotalTime(), 'Get Total Time should never be a null value');
+ $this->assertEquals(
+ 'integer',
+ getType($resultSet->getTotalTime()),
+ 'Total Time should be an integer'
+ );
+ }
+
+ /**
+ * @group unit
+ */
+ public function testHasFields()
+ {
+ $data = array('value set');
+
+ $result = new Result(array());
+ $this->assertFalse($result->hasFields());
+
+ $result = new Result(array('_source' => $data));
+ $this->assertFalse($result->hasFields());
+
+ $result = new Result(array('fields' => $data));
+ $this->assertTrue($result->hasFields());
+ $this->assertEquals($data, $result->getFields());
+ }
+}
diff --git a/vendor/ruflin/elastica/test/lib/Elastica/Test/ScanAndScrollTest.php b/vendor/ruflin/elastica/test/lib/Elastica/Test/ScanAndScrollTest.php
new file mode 100644
index 00000000..9f06f9e6
--- /dev/null
+++ b/vendor/ruflin/elastica/test/lib/Elastica/Test/ScanAndScrollTest.php
@@ -0,0 +1,78 @@
+<?php
+namespace Elastica\Test;
+
+use Elastica\Document;
+use Elastica\Query;
+use Elastica\ResultSet;
+use Elastica\ScanAndScroll;
+use Elastica\Search;
+use Elastica\Test\Base as BaseTest;
+
+class ScanAndScrollTest extends BaseTest
+{
+ /**
+ * Full foreach test.
+ *
+ * @gropu functional
+ */
+ public function testForeach()
+ {
+ $scanAndScroll = new ScanAndScroll($this->_prepareSearch(), '1m', 2);
+ $docCount = 0;
+
+ /** @var ResultSet $resultSet */
+ foreach ($scanAndScroll as $scrollId => $resultSet) {
+ $docCount += $resultSet->count();
+ }
+
+ /*
+ * number of loops and documents per iteration may fluctuate
+ * => only test end results
+ */
+ $this->assertEquals(12, $docCount);
+ }
+
+ /**
+ * query size revert options.
+ *
+ * @group functional
+ */
+ public function testQuerySizeRevert()
+ {
+ $search = $this->_prepareSearch();
+ $search->getQuery()->setSize(9);
+
+ $scanAndScroll = new ScanAndScroll($search);
+
+ $scanAndScroll->rewind();
+ $this->assertEquals(9, $search->getQuery()->getParam('size'));
+
+ $scanAndScroll->next();
+ $this->assertEquals(9, $search->getQuery()->getParam('size'));
+ }
+
+ /**
+ * index: 12 docs, 2 shards.
+ *
+ * @return Search
+ */
+ private function _prepareSearch()
+ {
+ $index = $this->_createIndex('', true, 2);
+ $index->refresh();
+
+ $docs = array();
+ for ($x = 1; $x <= 12; $x++) {
+ $docs[] = new Document($x, array('id' => $x, 'key' => 'value'));
+ }
+
+ $type = $index->getType('scanAndScrollTest');
+ $type->addDocuments($docs);
+ $index->refresh();
+
+ $search = new Search($this->_getClient());
+ $search->addIndex($index)->addType($type);
+
+ return $search;
+ }
+}
diff --git a/vendor/ruflin/elastica/test/lib/Elastica/Test/ScriptFieldsTest.php b/vendor/ruflin/elastica/test/lib/Elastica/Test/ScriptFieldsTest.php
new file mode 100644
index 00000000..5448209d
--- /dev/null
+++ b/vendor/ruflin/elastica/test/lib/Elastica/Test/ScriptFieldsTest.php
@@ -0,0 +1,93 @@
+<?php
+namespace Elastica\Test;
+
+use Elastica\Document;
+use Elastica\Query;
+use Elastica\Script;
+use Elastica\ScriptFields;
+use Elastica\Test\Base as BaseTest;
+
+class ScriptFieldsTest extends BaseTest
+{
+ /**
+ * @group unit
+ */
+ public function testNewScriptFields()
+ {
+ $script = new Script('1 + 2');
+
+ // addScript
+ $scriptFields = new ScriptFields();
+ $scriptFields->addScript('test', $script);
+ $this->assertEquals($scriptFields->getParam('test'), $script->toArray());
+
+ // setScripts
+ $scriptFields = new ScriptFields();
+ $scriptFields->setScripts(array(
+ 'test' => $script,
+ ));
+ $this->assertEquals($scriptFields->getParam('test'), $script->toArray());
+
+ // Constructor
+ $scriptFields = new ScriptFields(array(
+ 'test' => $script,
+ ));
+ $this->assertEquals($scriptFields->getParam('test'), $script->toArray());
+ }
+
+ /**
+ * @group unit
+ */
+ public function testSetScriptFields()
+ {
+ $query = new Query();
+ $script = new Script('1 + 2');
+
+ $scriptFields = new ScriptFields(array(
+ 'test' => $script,
+ ));
+ $query->setScriptFields($scriptFields);
+ $this->assertEquals($query->getParam('script_fields'), $scriptFields->toArray());
+
+ $query->setScriptFields(array(
+ 'test' => $script,
+ ));
+ $this->assertEquals($query->getParam('script_fields'), $scriptFields->toArray());
+ }
+
+ /**
+ * @group unit
+ * @expectedException \Elastica\Exception\InvalidException
+ */
+ public function testNameException()
+ {
+ $script = new Script('1 + 2');
+ $scriptFields = new ScriptFields(array($script));
+ }
+
+ /**
+ * @group functional
+ */
+ public function testQuery()
+ {
+ $index = $this->_createIndex();
+ $type = $index->getType('test');
+
+ $doc = new Document(1, array('firstname' => 'guschti', 'lastname' => 'ruflin'));
+ $type->addDocument($doc);
+ $index->refresh();
+
+ $query = new Query();
+ $script = new Script('1 + 2');
+ $scriptFields = new ScriptFields(array(
+ 'test' => $script,
+ ));
+ $query->setScriptFields($scriptFields);
+
+ $resultSet = $type->search($query);
+ $first = $resultSet->current()->getData();
+
+ // 1 + 2
+ $this->assertEquals(3, $first['test'][0]);
+ }
+}
diff --git a/vendor/ruflin/elastica/test/lib/Elastica/Test/ScriptTest.php b/vendor/ruflin/elastica/test/lib/Elastica/Test/ScriptTest.php
new file mode 100644
index 00000000..b42d8646
--- /dev/null
+++ b/vendor/ruflin/elastica/test/lib/Elastica/Test/ScriptTest.php
@@ -0,0 +1,169 @@
+<?php
+namespace Elastica\Test;
+
+use Elastica\Script;
+use Elastica\Test\Base as BaseTest;
+
+class ScriptTest extends BaseTest
+{
+ /**
+ * @group unit
+ */
+ public function testConstructor()
+ {
+ $value = "_score * doc['my_numeric_field'].value";
+ $script = new Script($value);
+
+ $expected = array(
+ 'script' => $value,
+ );
+ $this->assertEquals($value, $script->getScript());
+ $this->assertEquals($expected, $script->toArray());
+
+ $params = array(
+ 'param1' => 'one',
+ 'param2' => 10,
+ );
+
+ $script = new Script($value, $params);
+
+ $expected = array(
+ 'script' => $value,
+ 'params' => $params,
+ );
+
+ $this->assertEquals($value, $script->getScript());
+ $this->assertEquals($params, $script->getParams());
+ $this->assertEquals($expected, $script->toArray());
+
+ $lang = 'mvel';
+
+ $script = new Script($value, $params, $lang);
+
+ $expected = array(
+ 'script' => $value,
+ 'params' => $params,
+ 'lang' => $lang,
+ );
+
+ $this->assertEquals($value, $script->getScript());
+ $this->assertEquals($params, $script->getParams());
+ $this->assertEquals($lang, $script->getLang());
+ $this->assertEquals($expected, $script->toArray());
+ }
+
+ /**
+ * @group unit
+ */
+ public function testCreateString()
+ {
+ $string = '_score * 2.0';
+ $script = Script::create($string);
+
+ $this->assertInstanceOf('Elastica\Script', $script);
+
+ $this->assertEquals($string, $script->getScript());
+
+ $expected = array(
+ 'script' => $string,
+ );
+ $this->assertEquals($expected, $script->toArray());
+ }
+
+ /**
+ * @group unit
+ */
+ public function testCreateScript()
+ {
+ $data = new Script('_score * 2.0');
+
+ $script = Script::create($data);
+
+ $this->assertInstanceOf('Elastica\Script', $script);
+ $this->assertSame($data, $script);
+ }
+
+ /**
+ * @group unit
+ */
+ public function testCreateArray()
+ {
+ $string = '_score * 2.0';
+ $lang = 'mvel';
+ $params = array(
+ 'param1' => 'one',
+ 'param2' => 1,
+ );
+ $array = array(
+ 'script' => $string,
+ 'lang' => $lang,
+ 'params' => $params,
+ );
+
+ $script = Script::create($array);
+
+ $this->assertInstanceOf('Elastica\Script', $script);
+
+ $this->assertEquals($string, $script->getScript());
+ $this->assertEquals($params, $script->getParams());
+ $this->assertEquals($lang, $script->getLang());
+
+ $this->assertEquals($array, $script->toArray());
+ }
+
+ /**
+ * @group unit
+ * @dataProvider dataProviderCreateInvalid
+ * @expectedException \Elastica\Exception\InvalidException
+ */
+ public function testCreateInvalid($data)
+ {
+ Script::create($data);
+ }
+
+ /**
+ * @return array
+ */
+ public function dataProviderCreateInvalid()
+ {
+ return array(
+ array(
+ new \stdClass(),
+ ),
+ array(
+ array('params' => array('param1' => 'one')),
+ ),
+ array(
+ array('script' => '_score * 2.0', 'params' => 'param'),
+ ),
+ );
+ }
+
+ /**
+ * @group unit
+ */
+ public function testSetLang()
+ {
+ $script = new Script('foo', array(), Script::LANG_GROOVY);
+ $this->assertEquals(Script::LANG_GROOVY, $script->getLang());
+
+ $script->setLang(Script::LANG_PYTHON);
+ $this->assertEquals(Script::LANG_PYTHON, $script->getLang());
+
+ $this->assertInstanceOf('Elastica\Script', $script->setLang(Script::LANG_PYTHON));
+ }
+
+ /**
+ * @group unit
+ */
+ public function testSetScript()
+ {
+ $script = new Script('foo');
+ $this->assertEquals('foo', $script->getScript());
+
+ $script->setScript('bar');
+ $this->assertEquals('bar', $script->getScript());
+
+ $this->assertInstanceOf('Elastica\Script', $script->setScript('foo'));
+ }
+}
diff --git a/vendor/ruflin/elastica/test/lib/Elastica/Test/ScrollTest.php b/vendor/ruflin/elastica/test/lib/Elastica/Test/ScrollTest.php
new file mode 100644
index 00000000..df5b0317
--- /dev/null
+++ b/vendor/ruflin/elastica/test/lib/Elastica/Test/ScrollTest.php
@@ -0,0 +1,105 @@
+<?php
+namespace Elastica\Test;
+
+use Elastica\Document;
+use Elastica\Query;
+use Elastica\ResultSet;
+use Elastica\Scroll;
+use Elastica\Search;
+
+class ScrollTest extends Base
+{
+ /**
+ * Full foreach test.
+ *
+ * @group functional
+ */
+ public function testForeach()
+ {
+ $scroll = new Scroll($this->_prepareSearch());
+ $count = 1;
+
+ /** @var ResultSet $resultSet */
+ foreach ($scroll as $scrollId => $resultSet) {
+ $this->assertNotEmpty($scrollId);
+
+ $results = $resultSet->getResults();
+ switch (true) {
+ case $count === 1:
+ // hits: 1 - 5
+ $this->assertEquals(5, $resultSet->count());
+ $this->assertEquals('1', $results[0]->getId());
+ $this->assertEquals('5', $results[4]->getId());
+ break;
+ case $count === 2:
+ // hits: 6 - 10
+ $this->assertEquals(5, $resultSet->count());
+ $this->assertEquals('6', $results[0]->getId());
+ $this->assertEquals('10', $results[4]->getId());
+ break;
+ case $count === 3:
+ // hit: 11
+ $this->assertEquals(1, $resultSet->count());
+ $this->assertEquals('11', $results[0]->getId());
+ break;
+ case $count === 4:
+ $this->assertEquals(0, $resultSet->count());
+ break;
+ default:
+ $this->fail('too many iterations');
+ }
+
+ $count++;
+ }
+ }
+
+ /**
+ * Scroll must not overwrite options.
+ *
+ * @group functional
+ */
+ public function testSearchRevert()
+ {
+ $search = $this->_prepareSearch();
+
+ $search->setOption(Search::OPTION_SCROLL, 'must');
+ $search->setOption(Search::OPTION_SCROLL_ID, 'not');
+ $search->setOption(Search::OPTION_SEARCH_TYPE, 'change');
+ $old = $search->getOptions();
+
+ $scroll = new Scroll($search);
+
+ $scroll->rewind();
+ $this->assertEquals($old, $search->getOptions());
+
+ $scroll->next();
+ $this->assertEquals($old, $search->getOptions());
+ }
+
+ /**
+ * index: 11 docs
+ * query size: 5.
+ *
+ * @return Search
+ */
+ private function _prepareSearch()
+ {
+ $index = $this->_createIndex();
+ $index->refresh();
+
+ $docs = array();
+ for ($x = 1; $x <= 11; $x++) {
+ $docs[] = new Document($x, array('id' => $x, 'key' => 'value'));
+ }
+
+ $type = $index->getType('scrollTest');
+ $type->addDocuments($docs);
+ $index->refresh();
+
+ $search = new Search($this->_getClient());
+ $search->addIndex($index)->addType($type);
+ $search->getQuery()->setSize(5);
+
+ return $search;
+ }
+}
diff --git a/vendor/ruflin/elastica/test/lib/Elastica/Test/SearchTest.php b/vendor/ruflin/elastica/test/lib/Elastica/Test/SearchTest.php
new file mode 100644
index 00000000..905f8462
--- /dev/null
+++ b/vendor/ruflin/elastica/test/lib/Elastica/Test/SearchTest.php
@@ -0,0 +1,647 @@
+<?php
+namespace Elastica\Test;
+
+use Elastica\Aggregation;
+use Elastica\Document;
+use Elastica\Exception\ResponseException;
+use Elastica\Index;
+use Elastica\Query;
+use Elastica\Query\FunctionScore;
+use Elastica\Query\MatchAll;
+use Elastica\Query\QueryString;
+use Elastica\Script;
+use Elastica\Search;
+use Elastica\Test\Base as BaseTest;
+use Elastica\Type;
+
+class SearchTest extends BaseTest
+{
+ /**
+ * @group unit
+ */
+ public function testConstruct()
+ {
+ $client = $this->_getClient();
+ $search = new Search($client);
+
+ $this->assertInstanceOf('Elastica\Search', $search);
+ $this->assertSame($client, $search->getClient());
+ }
+
+ /**
+ * @group functional
+ */
+ public function testAddIndex()
+ {
+ $client = $this->_getClient();
+ $search = new Search($client);
+
+ $index1 = $this->_createIndex();
+ $index2 = $this->_createIndex();
+
+ $search->addIndex($index1);
+ $indices = $search->getIndices();
+
+ $this->assertEquals(1, count($indices));
+
+ $search->addIndex($index2);
+ $indices = $search->getIndices();
+
+ $this->assertEquals(2, count($indices));
+
+ $this->assertTrue(in_array($index1->getName(), $indices));
+ $this->assertTrue(in_array($index2->getName(), $indices));
+
+ // Add string
+ $search->addIndex('test3');
+ $indices = $search->getIndices();
+
+ $this->assertEquals(3, count($indices));
+ $this->assertTrue(in_array('test3', $indices));
+ }
+
+ /**
+ * @group unit
+ */
+ public function testAddIndices()
+ {
+ $client = $this->_getClient();
+ $search = new Search($client);
+
+ $indices = array();
+ $indices[] = $client->getIndex('elastica_test1');
+ $indices[] = $client->getIndex('elastica_test2');
+
+ $search->addIndices($indices);
+
+ $this->assertEquals(2, count($search->getIndices()));
+ }
+
+ /**
+ * @group functional
+ */
+ public function testAddType()
+ {
+ $client = $this->_getClient();
+ $search = new Search($client);
+
+ $index = $this->_createIndex();
+
+ $type1 = $index->getType('type1');
+ $type2 = $index->getType('type2');
+
+ $this->assertEquals(array(), $search->getTypes());
+
+ $search->addType($type1);
+ $types = $search->getTypes();
+
+ $this->assertEquals(1, count($types));
+
+ $search->addType($type2);
+ $types = $search->getTypes();
+
+ $this->assertEquals(2, count($types));
+
+ $this->assertTrue(in_array($type1->getName(), $types));
+ $this->assertTrue(in_array($type2->getName(), $types));
+
+ // Add string
+ $search->addType('test3');
+ $types = $search->getTypes();
+
+ $this->assertEquals(3, count($types));
+ $this->assertTrue(in_array('test3', $types));
+ }
+
+ /**
+ * @group unit
+ */
+ public function testAddTypes()
+ {
+ $client = $this->_getClient();
+ $search = new Search($client);
+
+ $index = $client->getIndex('foo');
+
+ $types = array();
+ $types[] = $index->getType('type1');
+ $types[] = $index->getType('type2');
+
+ $search->addTypes($types);
+
+ $this->assertEquals(2, count($search->getTypes()));
+ }
+
+ /**
+ * @group unit
+ * @expectedException \Elastica\Exception\InvalidException
+ */
+ public function testAddTypeInvalid()
+ {
+ $client = $this->_getClient();
+ $search = new Search($client);
+
+ $search->addType(new \stdClass());
+ }
+
+ /**
+ * @group unit
+ * @expectedException \Elastica\Exception\InvalidException
+ */
+ public function testAddIndexInvalid()
+ {
+ $client = $this->_getClient();
+ $search = new Search($client);
+
+ $search->addIndex(new \stdClass());
+ }
+
+ /**
+ * @group unit
+ */
+ public function testAddNumericIndex()
+ {
+ $client = $this->_getClient();
+ $search = new Search($client);
+
+ $search->addIndex(1);
+
+ $this->assertContains('1', $search->getIndices(), 'Make sure it has been added and converted to string');
+ }
+
+ /**
+ * @group functional
+ */
+ public function testGetPath()
+ {
+ $client = $this->_getClient();
+ $search1 = new Search($client);
+ $search2 = new Search($client);
+
+ $index1 = $this->_createIndex();
+ $index2 = $this->_createIndex();
+
+ $type1 = $index1->getType('type1');
+ $type2 = $index1->getType('type2');
+
+ // No index
+ $this->assertEquals('/_search', $search1->getPath());
+
+ // Only index
+ $search1->addIndex($index1);
+ $this->assertEquals($index1->getName().'/_search', $search1->getPath());
+
+ // MUltiple index, no types
+ $search1->addIndex($index2);
+ $this->assertEquals($index1->getName().','.$index2->getName().'/_search', $search1->getPath());
+
+ // Single type, no index
+ $search2->addType($type1);
+ $this->assertEquals('_all/'.$type1->getName().'/_search', $search2->getPath());
+
+ // Multiple types
+ $search2->addType($type2);
+ $this->assertEquals('_all/'.$type1->getName().','.$type2->getName().'/_search', $search2->getPath());
+
+ // Combine index and types
+ $search2->addIndex($index1);
+ $this->assertEquals($index1->getName().'/'.$type1->getName().','.$type2->getName().'/_search', $search2->getPath());
+ }
+
+ /**
+ * @group functional
+ */
+ public function testSearchRequest()
+ {
+ $client = $this->_getClient();
+ $search1 = new Search($client);
+
+ $index1 = $this->_createIndex();
+ $index2 = $this->_createIndex();
+
+ $type1 = $index1->getType('hello1');
+
+ $result = $search1->search(array());
+ $this->assertFalse($result->getResponse()->hasError());
+
+ $search1->addIndex($index1);
+
+ $result = $search1->search(array());
+ $this->assertFalse($result->getResponse()->hasError());
+
+ $search1->addIndex($index2);
+
+ $result = $search1->search(array());
+ $this->assertFalse($result->getResponse()->hasError());
+
+ $search1->addType($type1);
+
+ $result = $search1->search(array());
+ $this->assertFalse($result->getResponse()->hasError());
+ }
+
+ /**
+ * @group functional
+ */
+ public function testSearchScrollRequest()
+ {
+ $client = $this->_getClient();
+
+ $index = $this->_createIndex();
+ $type = $index->getType('scrolltest');
+
+ $docs = array();
+ for ($x = 1; $x <= 10; $x++) {
+ $docs[] = new Document($x, array('id' => $x, 'testscroll' => 'jbafford'));
+ }
+
+ $type->addDocuments($docs);
+ $index->refresh();
+
+ $search = new Search($client);
+ $search->addIndex($index)->addType($type);
+ $result = $search->search(array(), array(
+ Search::OPTION_SEARCH_TYPE => Search::OPTION_SEARCH_TYPE_SCAN,
+ Search::OPTION_SCROLL => '5m',
+ Search::OPTION_SIZE => 5,
+ ));
+ $this->assertFalse($result->getResponse()->hasError());
+
+ $scrollId = $result->getResponse()->getScrollId();
+ $this->assertNotEmpty($scrollId);
+
+ //There are 10 items, and we're scrolling with a size of 5
+ //So we should get two results of 5 items, and then no items
+ //We should also have sent the raw scroll_id as the HTTP request body
+ $search = new Search($client);
+ $result = $search->search(array(), array(
+ Search::OPTION_SCROLL => '5m',
+ Search::OPTION_SCROLL_ID => $scrollId,
+ ));
+ $this->assertFalse($result->getResponse()->hasError());
+ $this->assertEquals(5, count($result->getResults()));
+ $this->assertArrayNotHasKey(Search::OPTION_SCROLL_ID, $search->getClient()->getLastRequest()->getQuery());
+ $this->assertEquals($scrollId, $search->getClient()->getLastRequest()->getData());
+
+ $result = $search->search(array(), array(
+ Search::OPTION_SCROLL => '5m',
+ Search::OPTION_SCROLL_ID => $scrollId,
+ ));
+ $this->assertFalse($result->getResponse()->hasError());
+ $this->assertEquals(5, count($result->getResults()));
+ $this->assertArrayNotHasKey(Search::OPTION_SCROLL_ID, $search->getClient()->getLastRequest()->getQuery());
+ $this->assertEquals($scrollId, $search->getClient()->getLastRequest()->getData());
+
+ $result = $search->search(array(), array(
+ Search::OPTION_SCROLL => '5m',
+ Search::OPTION_SCROLL_ID => $scrollId,
+ ));
+ $this->assertFalse($result->getResponse()->hasError());
+ $this->assertEquals(0, count($result->getResults()));
+ $this->assertArrayNotHasKey(Search::OPTION_SCROLL_ID, $search->getClient()->getLastRequest()->getQuery());
+ $this->assertEquals($scrollId, $search->getClient()->getLastRequest()->getData());
+ }
+
+ /**
+ * Default Limit tests for \Elastica\Search.
+ *
+ * @group functional
+ */
+ public function testLimitDefaultSearch()
+ {
+ $client = $this->_getClient();
+ $search = new Search($client);
+
+ $index = $client->getIndex('zero');
+ $index->create(array('index' => array('number_of_shards' => 1, 'number_of_replicas' => 0)), true);
+
+ $type = $index->getType('zeroType');
+ $type->addDocuments(array(
+ new Document(1, array('id' => 1, 'email' => 'test@test.com', 'username' => 'farrelley')),
+ new Document(2, array('id' => 1, 'email' => 'test@test.com', 'username' => 'farrelley')),
+ new Document(3, array('id' => 1, 'email' => 'test@test.com', 'username' => 'farrelley')),
+ new Document(4, array('id' => 1, 'email' => 'test@test.com', 'username' => 'farrelley')),
+ new Document(5, array('id' => 1, 'email' => 'test@test.com', 'username' => 'farrelley')),
+ new Document(6, array('id' => 1, 'email' => 'test@test.com', 'username' => 'farrelley')),
+ new Document(7, array('id' => 1, 'email' => 'test@test.com', 'username' => 'farrelley')),
+ new Document(8, array('id' => 1, 'email' => 'test@test.com', 'username' => 'farrelley')),
+ new Document(9, array('id' => 1, 'email' => 'test@test.com', 'username' => 'farrelley')),
+ new Document(10, array('id' => 1, 'email' => 'test@test.com', 'username' => 'farrelley')),
+ new Document(11, array('id' => 1, 'email' => 'test@test.com', 'username' => 'farrelley')),
+ ));
+ $index->refresh();
+
+ $search->addIndex($index)->addType($type);
+
+ // default limit results (default limit is 10)
+ $resultSet = $search->search('farrelley');
+ $this->assertEquals(10, $resultSet->count());
+
+ // limit = 1
+ $resultSet = $search->search('farrelley', 1);
+ $this->assertEquals(1, $resultSet->count());
+ }
+
+ /**
+ * @group functional
+ * @expectedException \Elastica\Exception\InvalidException
+ */
+ public function testArrayConfigSearch()
+ {
+ $client = $this->_getClient();
+ $search = new Search($client);
+
+ $index = $client->getIndex('zero');
+ $index->create(array('index' => array('number_of_shards' => 1, 'number_of_replicas' => 0)), true);
+
+ $docs = array();
+ for ($i = 0; $i < 11; $i++) {
+ $docs[] = new Document($i, array('id' => 1, 'email' => 'test@test.com', 'username' => 'test'));
+ }
+
+ $type = $index->getType('zeroType');
+ $type->addDocuments($docs);
+ $index->refresh();
+
+ $search->addIndex($index)->addType($type);
+ //Backward compatibility, integer => limit
+ // default limit results (default limit is 10)
+ $resultSet = $search->search('test');
+ $this->assertEquals(10, $resultSet->count());
+
+ // limit = 1
+ $resultSet = $search->search('test', 1);
+ $this->assertEquals(1, $resultSet->count());
+
+ //Array with limit
+ $resultSet = $search->search('test', array('limit' => 2));
+ $this->assertEquals(2, $resultSet->count());
+
+ //Array with size
+ $resultSet = $search->search('test', array('size' => 2));
+ $this->assertEquals(2, $resultSet->count());
+
+ //Array with from
+ $resultSet = $search->search('test', array('from' => 10));
+ $this->assertEquals(10, $resultSet->current()->getId());
+
+ //Array with routing
+ $resultSet = $search->search('test', array('routing' => 'r1,r2'));
+ $this->assertEquals(10, $resultSet->count());
+
+ //Array with limit and routing
+ $resultSet = $search->search('test', array('limit' => 5, 'routing' => 'r1,r2'));
+ $this->assertEquals(5, $resultSet->count());
+
+ //Search types
+ $resultSet = $search->search('test', array('limit' => 5, 'search_type' => 'count'));
+ $this->assertTrue(($resultSet->count() === 0) && $resultSet->getTotalHits() === 11);
+
+ //Timeout - this one is a bit more tricky to test
+ $mockResponse = new \Elastica\Response(json_encode(array('timed_out' => true)));
+ $client = $this->getMockBuilder('Elastica\\Client')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $client->method('request')
+ ->will($this->returnValue($mockResponse));
+ $search = new Search($client);
+ $script = new Script('Thread.sleep(100); return _score;');
+ $query = new FunctionScore();
+ $query->addScriptScoreFunction($script);
+ $resultSet = $search->search($query, array('timeout' => 50));
+ $this->assertTrue($resultSet->hasTimedOut());
+
+ // Throws InvalidException
+ $resultSet = $search->search('test', array('invalid_option' => 'invalid_option_value'));
+ }
+
+ /**
+ * @group functional
+ */
+ public function testSearchWithVersionOption()
+ {
+ $index = $this->_createIndex();
+ $doc = new Document(1, array('id' => 1, 'email' => 'test@test.com', 'username' => 'ruflin'));
+ $index->getType('test')->addDocument($doc);
+ $index->refresh();
+
+ $search = new Search($index->getClient());
+ $search->addIndex($index);
+
+ // Version param should not be inside by default
+ $results = $search->search(new MatchAll());
+ $hit = $results->current();
+ $this->assertEquals(array(), $hit->getParam('_version'));
+
+ // Added version param to result
+ $results = $search->search(new MatchAll(), array('version' => true));
+ $hit = $results->current();
+ $this->assertEquals(1, $hit->getParam('_version'));
+ }
+
+ /**
+ * @group functional
+ */
+ public function testCountRequest()
+ {
+ $client = $this->_getClient();
+ $search = new Search($client);
+
+ $index = $client->getIndex('zero');
+ $index->create(array('index' => array('number_of_shards' => 1, 'number_of_replicas' => 0)), true);
+
+ $type = $index->getType('zeroType');
+ $type->addDocuments(array(
+ new Document(1, array('id' => 1, 'email' => 'test@test.com', 'username' => 'farrelley')),
+ new Document(2, array('id' => 1, 'email' => 'test@test.com', 'username' => 'farrelley')),
+ new Document(3, array('id' => 1, 'email' => 'test@test.com', 'username' => 'farrelley')),
+ new Document(4, array('id' => 1, 'email' => 'test@test.com', 'username' => 'farrelley')),
+ new Document(5, array('id' => 1, 'email' => 'test@test.com', 'username' => 'farrelley')),
+ new Document(6, array('id' => 1, 'email' => 'test@test.com', 'username' => 'marley')),
+ new Document(7, array('id' => 1, 'email' => 'test@test.com', 'username' => 'marley')),
+ new Document(8, array('id' => 1, 'email' => 'test@test.com', 'username' => 'marley')),
+ new Document(9, array('id' => 1, 'email' => 'test@test.com', 'username' => 'marley')),
+ new Document(10, array('id' => 1, 'email' => 'test@test.com', 'username' => 'marley')),
+ new Document(11, array('id' => 1, 'email' => 'test@test.com', 'username' => 'marley')),
+ ));
+ $index->refresh();
+
+ $search->addIndex($index)->addType($type);
+
+ $count = $search->count('farrelley');
+ $this->assertEquals(5, $count);
+
+ $count = $search->count('marley');
+ $this->assertEquals(6, $count);
+
+ $count = $search->count();
+ $this->assertEquals(6, $count, 'Uses previous query set');
+
+ $count = $search->count(new MatchAll());
+ $this->assertEquals(11, $count);
+
+ $count = $search->count('bunny');
+ $this->assertEquals(0, $count);
+ }
+
+ /**
+ * @group functional
+ */
+ public function testEmptySearch()
+ {
+ $client = $this->_getClient();
+ $search = new Search($client);
+
+ $index = $client->getIndex('zero');
+ $index->create(array('index' => array('number_of_shards' => 1, 'number_of_replicas' => 0)), true);
+ $type = $index->getType('zeroType');
+ $type->addDocuments(array(
+ new Document(1, array('id' => 1, 'email' => 'test@test.com', 'username' => 'farrelley')),
+ new Document(2, array('id' => 1, 'email' => 'test@test.com', 'username' => 'farrelley')),
+ new Document(3, array('id' => 1, 'email' => 'test@test.com', 'username' => 'farrelley')),
+ new Document(4, array('id' => 1, 'email' => 'test@test.com', 'username' => 'farrelley')),
+ new Document(5, array('id' => 1, 'email' => 'test@test.com', 'username' => 'farrelley')),
+ new Document(6, array('id' => 1, 'email' => 'test@test.com', 'username' => 'farrelley')),
+ new Document(7, array('id' => 1, 'email' => 'test@test.com', 'username' => 'farrelley')),
+ new Document(8, array('id' => 1, 'email' => 'test@test.com', 'username' => 'bunny')),
+ new Document(9, array('id' => 1, 'email' => 'test@test.com', 'username' => 'bunny')),
+ new Document(10, array('id' => 1, 'email' => 'test@test.com', 'username' => 'bunny')),
+ new Document(11, array('id' => 1, 'email' => 'test@test.com', 'username' => 'bunny')),
+ ));
+ $index->refresh();
+
+ $search->addIndex($index)->addType($type);
+ $resultSet = $search->search();
+ $this->assertInstanceOf('Elastica\ResultSet', $resultSet);
+ $this->assertCount(10, $resultSet);
+ $this->assertEquals(11, $resultSet->getTotalHits());
+
+ $query = new QueryString('bunny');
+ $search->setQuery($query);
+
+ $resultSet = $search->search();
+
+ $this->assertCount(4, $resultSet);
+ $this->assertEquals(4, $resultSet->getTotalHits());
+ $source = $resultSet->current()->getSource();
+ $this->assertEquals('bunny', $source['username']);
+ }
+
+ /**
+ * @group functional
+ */
+ public function testCount()
+ {
+ $index = $this->_createIndex();
+ $search = new Search($index->getClient());
+ $type = $index->getType('test');
+
+ $doc = new Document(1, array('id' => 1, 'username' => 'ruflin'));
+
+ $type->addDocument($doc);
+ $index->refresh();
+
+ $search->addIndex($index);
+ $search->addType($type);
+
+ $result1 = $search->count(new \Elastica\Query\MatchAll());
+ $this->assertEquals(1, $result1);
+
+ $result2 = $search->count(new \Elastica\Query\MatchAll(), true);
+ $this->assertInstanceOf('\Elastica\ResultSet', $result2);
+ $this->assertEquals(1, $result2->getTotalHits());
+ }
+
+ /**
+ * @group functional
+ */
+ public function testScanAndScroll()
+ {
+ $search = new Search($this->_getClient());
+ $this->assertInstanceOf('Elastica\ScanAndScroll', $search->scanAndScroll());
+ }
+
+ /**
+ * @group functional
+ */
+ public function testIgnoreUnavailableOption()
+ {
+ $client = $this->_getClient();
+ $index = $client->getIndex('elastica_7086b4c2ee585bbb6740ece5ed7ece01');
+ $query = new MatchAll();
+
+ $search = new Search($client);
+ $search->addIndex($index);
+
+ $exception = null;
+ try {
+ $search->search($query);
+ } catch (ResponseException $e) {
+ $exception = $e;
+ }
+ $this->assertEquals('IndexMissingException', $exception->getElasticsearchException()->getExceptionName());
+
+ $results = $search->search($query, array(Search::OPTION_SEARCH_IGNORE_UNAVAILABLE => true));
+ $this->assertInstanceOf('\Elastica\ResultSet', $results);
+ }
+
+ /**
+ * @group functional
+ */
+ public function testQueryCacheOption()
+ {
+ $client = $this->_getClient();
+
+ $index = $client->getIndex('zero');
+ $index->create(array('index' => array('number_of_shards' => 1, 'number_of_replicas' => 0)), true);
+ $type = $index->getType('zeroType');
+ $type->addDocuments(array(
+ new Document(1, array('id' => 1, 'username' => 'farrelley')),
+ new Document(2, array('id' => 2, 'username' => 'bunny')),
+ ));
+ $index->refresh();
+
+ $aggregation = new Aggregation\Terms('username');
+ $aggregation->setField('username');
+
+ $query = new Query();
+ $query->addAggregation($aggregation);
+
+ $search = new Search($client);
+ $search->addIndex($index);
+ $search->setQuery($query);
+ $search->setOption(Search::OPTION_SEARCH_TYPE, Search::OPTION_SEARCH_TYPE_COUNT);
+ $search->setOption(Search::OPTION_QUERY_CACHE, true);
+
+ // before search query cache should be empty
+ $statsData = $index->getStats()->getData();
+ $queryCache = $statsData['_all']['primaries']['query_cache'];
+
+ $this->assertEquals(0, $queryCache['memory_size_in_bytes']);
+ $this->assertEquals(0, $queryCache['evictions']);
+ $this->assertEquals(0, $queryCache['hit_count']);
+ $this->assertEquals(0, $queryCache['miss_count']);
+
+ // first search should result in cache miss and save data to cache
+ $search->search();
+ $index->getStats()->refresh();
+ $statsData = $index->getStats()->getData();
+ $queryCache = $statsData['_all']['primaries']['query_cache'];
+
+ $this->assertNotEquals(0, $queryCache['memory_size_in_bytes']);
+ $this->assertEquals(0, $queryCache['evictions']);
+ $this->assertEquals(0, $queryCache['hit_count']);
+ $this->assertEquals(1, $queryCache['miss_count']);
+
+ // next search should result in cache hit
+ $search->search();
+ $index->getStats()->refresh();
+ $statsData = $index->getStats()->getData();
+ $queryCache = $statsData['_all']['primaries']['query_cache'];
+
+ $this->assertNotEquals(0, $queryCache['memory_size_in_bytes']);
+ $this->assertEquals(0, $queryCache['evictions']);
+ $this->assertEquals(1, $queryCache['hit_count']);
+ $this->assertEquals(1, $queryCache['miss_count']);
+ }
+}
diff --git a/vendor/ruflin/elastica/test/lib/Elastica/Test/ShutdownTest.php b/vendor/ruflin/elastica/test/lib/Elastica/Test/ShutdownTest.php
new file mode 100644
index 00000000..93d6e32b
--- /dev/null
+++ b/vendor/ruflin/elastica/test/lib/Elastica/Test/ShutdownTest.php
@@ -0,0 +1,74 @@
+<?php
+
+use Elastica\Test\Base as BaseTest;
+
+/**
+ * These tests shuts down node/cluster, so can't be executed with rest testsuite
+ * Please use `sudo service elasticsearch restart` after every run of these tests.
+ */
+class ShutdownTest extends BaseTest
+{
+ /**
+ * @group shutdown
+ */
+ public function testNodeShutdown()
+ {
+ // Get cluster nodes
+ $client = $this->_getClient();
+ $cluster = $client->getCluster();
+ $nodes = $cluster->getNodes();
+
+ $nodesCount = count($nodes);
+
+ if ($nodesCount < 2) {
+ $this->markTestIncomplete('At least two nodes have to be running, because 1 node is shutdown');
+ }
+
+ $portFound = false;
+ // sayonara, wolverine, we'd never love you
+ foreach ($nodes as $node) {
+ if ((int) $node->getInfo()->getPort() === 9201) {
+ $portFound = true;
+ $node->shutdown('1s');
+ break;
+ }
+ }
+
+ if (!$portFound) {
+ $this->markTestSkipped('This test was skipped as in the new docker environment all elasticsearch instances run on the same port');
+ }
+
+ // Wait until node is shutdown
+ sleep(5);
+
+ // Get nodes again
+ $client = $this->_getClient();
+ $cluster = $client->getCluster();
+ $nodes = $cluster->getNodes();
+
+ // Only one left
+ $this->assertCount($nodesCount - 1, $nodes);
+ }
+
+ /**
+ * @group shutdown
+ * @depends testNodeShutdown
+ * @expectedException \Elastica\Exception\Connection\HttpException
+ */
+ public function testClusterShutdown()
+ {
+ // Get cluster nodes
+ $client = $this->_getClient();
+ $cluster = $client->getCluster();
+ $nodes = $cluster->getNodes();
+
+ // Shutdown cluster
+ $cluster->shutdown('1s');
+
+ // Wait...
+ sleep(5);
+
+ // Now exception must be thrown
+ $client->getStatus();
+ }
+}
diff --git a/vendor/ruflin/elastica/test/lib/Elastica/Test/SnapshotTest.php b/vendor/ruflin/elastica/test/lib/Elastica/Test/SnapshotTest.php
new file mode 100644
index 00000000..fa190e8c
--- /dev/null
+++ b/vendor/ruflin/elastica/test/lib/Elastica/Test/SnapshotTest.php
@@ -0,0 +1,109 @@
+<?php
+namespace Elastica\Test;
+
+use Elastica\Document;
+use Elastica\Index;
+use Elastica\Snapshot;
+
+class SnapshotTest extends Base
+{
+ /**
+ * @var Snapshot
+ */
+ protected $_snapshot;
+
+ /**
+ * @var Index
+ */
+ protected $_index;
+
+ /**
+ * @var Document[]
+ */
+ protected $_docs;
+
+ protected function setUp()
+ {
+ parent::setUp();
+ $this->_snapshot = new Snapshot($this->_getClient());
+
+ $this->_index = $this->_createIndex();
+ $this->_docs = array(
+ new Document('1', array('city' => 'San Diego')),
+ new Document('2', array('city' => 'San Luis Obispo')),
+ new Document('3', array('city' => 'San Francisco')),
+ );
+ $this->_index->getType('test')->addDocuments($this->_docs);
+ $this->_index->refresh();
+ }
+
+ /**
+ * @group functional
+ */
+ public function testRegisterRepository()
+ {
+ $name = 'test_register';
+ $location = '/tmp/test_register';
+
+ $response = $this->_snapshot->registerRepository($name, 'fs', array('location' => $location));
+ $this->assertTrue($response->isOk());
+
+ $response = $this->_snapshot->getRepository($name);
+ $this->assertEquals($location, $response['settings']['location']);
+
+ // attempt to retrieve a repository which does not exist
+ $this->setExpectedException('Elastica\Exception\NotFoundException');
+ $this->_snapshot->getRepository('foobar');
+ }
+
+ /**
+ * @group functional
+ */
+ public function testSnapshotAndRestore()
+ {
+ $repositoryName = 'test_repository';
+ $location = "/tmp/{$repositoryName}";
+
+ // register the repository
+ $response = $this->_snapshot->registerRepository($repositoryName, 'fs', array('location' => $location));
+ $this->assertTrue($response->isOk());
+
+ // create a snapshot of our test index
+ $snapshotName = 'test_snapshot_1';
+ $response = $this->_snapshot->createSnapshot($repositoryName, $snapshotName, array('indices' => $this->_index->getName()), true);
+
+ // ensure that the snapshot was created properly
+ $this->assertTrue($response->isOk());
+ $this->assertArrayHasKey('snapshot', $response->getData());
+ $data = $response->getData();
+ $this->assertContains($this->_index->getName(), $data['snapshot']['indices']);
+ $this->assertEquals(1, sizeof($data['snapshot']['indices'])); // only the specified index should be present
+ $this->assertEquals($snapshotName, $data['snapshot']['snapshot']);
+
+ // retrieve data regarding the snapshot
+ $response = $this->_snapshot->getSnapshot($repositoryName, $snapshotName);
+ $this->assertContains($this->_index->getName(), $response['indices']);
+
+ // delete our test index
+ $this->_index->delete();
+
+ // restore the index from our snapshot
+ $response = $this->_snapshot->restoreSnapshot($repositoryName, $snapshotName, array(), true);
+ $this->assertTrue($response->isOk());
+
+ $this->_index->refresh();
+ $this->_index->optimize();
+
+ // ensure that the index has been restored
+ $count = $this->_index->getType('test')->count();
+ $this->assertEquals(sizeof($this->_docs), $count);
+
+ // delete the snapshot
+ $response = $this->_snapshot->deleteSnapshot($repositoryName, $snapshotName);
+ $this->assertTrue($response->isOk());
+
+ // ensure that the snapshot has been deleted
+ $this->setExpectedException('Elastica\Exception\NotFoundException');
+ $this->_snapshot->getSnapshot($repositoryName, $snapshotName);
+ }
+}
diff --git a/vendor/ruflin/elastica/test/lib/Elastica/Test/StatusTest.php b/vendor/ruflin/elastica/test/lib/Elastica/Test/StatusTest.php
new file mode 100644
index 00000000..fe6bb091
--- /dev/null
+++ b/vendor/ruflin/elastica/test/lib/Elastica/Test/StatusTest.php
@@ -0,0 +1,133 @@
+<?php
+namespace Elastica\Test;
+
+use Elastica\Exception\ResponseException;
+use Elastica\Status;
+use Elastica\Test\Base as BaseTest;
+
+class StatusTest extends BaseTest
+{
+ /**
+ * @group functional
+ */
+ public function testGetResponse()
+ {
+ $index = $this->_createIndex();
+ $status = new Status($index->getClient());
+ $this->assertInstanceOf('Elastica\Response', $status->getResponse());
+ }
+
+ /**
+ * @group functional
+ */
+ public function testGetIndexStatuses()
+ {
+ $index = $this->_createIndex();
+
+ $status = new Status($index->getClient());
+ $statuses = $status->getIndexStatuses();
+
+ $this->assertInternalType('array', $statuses);
+
+ foreach ($statuses as $indexStatus) {
+ $this->assertInstanceOf('Elastica\Index\Status', $indexStatus);
+ }
+ }
+
+ /**
+ * @group functional
+ */
+ public function testGetIndexNames()
+ {
+ $indexName = 'test';
+ $client = $this->_getClient();
+ $index = $client->getIndex($indexName);
+ $index->create(array(), true);
+ $index = $this->_createIndex();
+ $index->refresh();
+ $index->optimize();
+
+ $status = new Status($index->getClient());
+ $names = $status->getIndexNames();
+
+ $this->assertInternalType('array', $names);
+ $this->assertContains($index->getName(), $names);
+
+ foreach ($names as $name) {
+ $this->assertInternalType('string', $name);
+ }
+ }
+
+ /**
+ * @group functional
+ */
+ public function testIndexExists()
+ {
+ $indexName = 'elastica_test';
+ $aliasName = 'elastica_test-alias';
+
+ $client = $this->_getClient();
+ $index = $client->getIndex($indexName);
+
+ try {
+ // Make sure index is deleted first
+ $index->delete();
+ } catch (ResponseException $e) {
+ }
+
+ $status = new Status($client);
+ $this->assertFalse($status->indexExists($indexName));
+ $index->create();
+
+ $status->refresh();
+ $this->assertTrue($status->indexExists($indexName));
+ }
+
+ /**
+ * @group functional
+ */
+ public function testAliasExists()
+ {
+ $aliasName = 'elastica_test-alias';
+
+ $index1 = $this->_createIndex();
+ $indexName = $index1->getName();
+
+ $status = new Status($index1->getClient());
+
+ foreach ($status->getIndicesWithAlias($aliasName) as $tmpIndex) {
+ $tmpIndex->removeAlias($aliasName);
+ }
+
+ $this->assertFalse($status->aliasExists($aliasName));
+
+ $index1->addAlias($aliasName);
+ $status->refresh();
+ $this->assertTrue($status->aliasExists($aliasName));
+
+ $indicesWithAlias = $status->getIndicesWithAlias($aliasName);
+ $this->assertEquals(array($indexName), array_map(
+ function ($index) {
+ return $index->getName();
+ }, $indicesWithAlias));
+ }
+
+ /**
+ * @group functional
+ */
+ public function testServerStatus()
+ {
+ $client = $this->_getClient();
+ $status = $client->getStatus();
+ $serverStatus = $status->getServerStatus();
+
+ $this->assertTrue(!empty($serverStatus));
+ $this->assertTrue('array' == gettype($serverStatus));
+ $this->assertArrayHasKey('status', $serverStatus);
+ $this->assertTrue($serverStatus['status'] == 200);
+ $this->assertArrayHasKey('version', $serverStatus);
+
+ $versionInfo = $serverStatus['version'];
+ $this->assertArrayHasKey('number', $versionInfo);
+ }
+}
diff --git a/vendor/ruflin/elastica/test/lib/Elastica/Test/Suggest/CompletionTest.php b/vendor/ruflin/elastica/test/lib/Elastica/Test/Suggest/CompletionTest.php
new file mode 100644
index 00000000..6120743c
--- /dev/null
+++ b/vendor/ruflin/elastica/test/lib/Elastica/Test/Suggest/CompletionTest.php
@@ -0,0 +1,140 @@
+<?php
+namespace Elastica\Test\Suggest;
+
+use Elastica\Document;
+use Elastica\Index;
+use Elastica\Query;
+use Elastica\Suggest\Completion;
+use Elastica\Test\Base as BaseTest;
+
+class CompletionTest extends BaseTest
+{
+ /**
+ * @return Index
+ */
+ protected function _getIndexForTest()
+ {
+ $index = $this->_createIndex();
+ $type = $index->getType('song');
+
+ $type->setMapping(array(
+ 'fieldName' => array(
+ 'type' => 'completion',
+ 'payloads' => true,
+ ),
+ ));
+
+ $type->addDocuments(array(
+ new Document(1, array(
+ 'fieldName' => array(
+ 'input' => array('Nevermind', 'Nirvana'),
+ 'output' => 'Nevermind - Nirvana',
+ 'payload' => array(
+ 'year' => 1991,
+ ),
+ ),
+ )),
+ new Document(2, array(
+ 'fieldName' => array(
+ 'input' => array('Bleach', 'Nirvana'),
+ 'output' => 'Bleach - Nirvana',
+ 'payload' => array(
+ 'year' => 1989,
+ ),
+ ),
+ )),
+ new Document(3, array(
+ 'fieldName' => array(
+ 'input' => array('Incesticide', 'Nirvana'),
+ 'output' => 'Incesticide - Nirvana',
+ 'payload' => array(
+ 'year' => 1992,
+ ),
+ ),
+ )),
+ ));
+
+ $index->refresh();
+
+ return $index;
+ }
+
+ /**
+ * @group unit
+ */
+ public function testToArray()
+ {
+ $suggest = new Completion('suggestName', 'fieldName');
+ $suggest->setText('foo');
+ $suggest->setSize(10);
+ $expected = array(
+ 'text' => 'foo',
+ 'completion' => array(
+ 'size' => 10,
+ 'field' => 'fieldName',
+ ),
+ );
+ $this->assertEquals($expected, $suggest->toArray());
+ }
+
+ /**
+ * @group functional
+ */
+ public function testSuggestWorks()
+ {
+ $suggest = new Completion('suggestName', 'fieldName');
+ $suggest->setText('Never');
+
+ $index = $this->_getIndexForTest();
+ $resultSet = $index->search(Query::create($suggest));
+
+ $this->assertTrue($resultSet->hasSuggests());
+
+ $suggests = $resultSet->getSuggests();
+ $options = $suggests['suggestName'][0]['options'];
+
+ $this->assertCount(1, $options);
+ $this->assertEquals('Nevermind - Nirvana', $options[0]['text']);
+ $this->assertEquals(1991, $options[0]['payload']['year']);
+ }
+
+ /**
+ * @group functional
+ */
+ public function testFuzzySuggestWorks()
+ {
+ $suggest = new Completion('suggestName', 'fieldName');
+ $suggest->setFuzzy(array('fuzziness' => 2));
+ $suggest->setText('Neavermint');
+
+ $index = $this->_getIndexForTest();
+ $resultSet = $index->search(Query::create($suggest));
+
+ $this->assertTrue($resultSet->hasSuggests());
+
+ $suggests = $resultSet->getSuggests();
+ $options = $suggests['suggestName'][0]['options'];
+
+ $this->assertCount(1, $options);
+ $this->assertEquals('Nevermind - Nirvana', $options[0]['text']);
+ }
+
+ /**
+ * @group unit
+ */
+ public function testSetFuzzy()
+ {
+ $suggest = new Completion('suggestName', 'fieldName');
+
+ $fuzzy = array(
+ 'unicode_aware' => true,
+ 'fuzziness' => 3,
+ );
+
+ $suggest->setFuzzy($fuzzy);
+
+ $this->assertEquals($fuzzy, $suggest->getParam('fuzzy'));
+
+ $this->assertInstanceOf('Elastica\\Suggest\\Completion', $suggest->setFuzzy($fuzzy));
+ }
+}
diff --git a/vendor/ruflin/elastica/test/lib/Elastica/Test/Suggest/PhraseTest.php b/vendor/ruflin/elastica/test/lib/Elastica/Test/Suggest/PhraseTest.php
new file mode 100644
index 00000000..9ce345d4
--- /dev/null
+++ b/vendor/ruflin/elastica/test/lib/Elastica/Test/Suggest/PhraseTest.php
@@ -0,0 +1,82 @@
+<?php
+namespace Elastica\Test\Suggest;
+
+use Elastica\Document;
+use Elastica\Index;
+use Elastica\Suggest;
+use Elastica\Suggest\CandidateGenerator\DirectGenerator;
+use Elastica\Suggest\Phrase;
+use Elastica\Test\Base as BaseTest;
+
+class PhraseTest extends BaseTest
+{
+ /**
+ * @return Index
+ */
+ protected function _getIndexForTest()
+ {
+ $index = $this->_createIndex();
+ $type = $index->getType('testSuggestType');
+ $type->addDocuments(array(
+ new Document(1, array('text' => 'Github is pretty cool')),
+ new Document(2, array('text' => 'Elasticsearch is bonsai cool')),
+ new Document(3, array('text' => 'This is a test phrase')),
+ new Document(4, array('text' => 'Another sentence for testing')),
+ new Document(5, array('text' => 'Some more words here')),
+ ));
+ $index->refresh();
+
+ return $index;
+ }
+
+ /**
+ * @group unit
+ */
+ public function testToArray()
+ {
+ $suggest = new Suggest();
+ $phraseSuggest = new Phrase('suggest1', 'text');
+ $phraseSuggest->setText('elasticsearch is bansai coor');
+ $phraseSuggest->setAnalyzer('simple');
+ $suggest->addSuggestion($phraseSuggest);
+ $suggest->setGlobalText('global!');
+
+ $expected = array(
+ 'suggest' => array(
+ 'text' => 'global!',
+ 'suggest1' => array(
+ 'text' => 'elasticsearch is bansai coor',
+ 'phrase' => array(
+ 'field' => 'text',
+ 'analyzer' => 'simple',
+ ),
+ ),
+ ),
+ );
+
+ $this->assertEquals($expected, $suggest->toArray());
+ }
+
+ /**
+ * @group functional
+ */
+ public function testPhraseSuggest()
+ {
+ $suggest = new Suggest();
+ $phraseSuggest = new Phrase('suggest1', 'text');
+ $phraseSuggest->setText('elasticsearch is bansai coor');
+ $phraseSuggest->setAnalyzer('simple')->setHighlight('<suggest>', '</suggest>')->setStupidBackoffSmoothing(0.4);
+ $phraseSuggest->addCandidateGenerator(new DirectGenerator('text'));
+ $suggest->addSuggestion($phraseSuggest);
+
+ $index = $this->_getIndexForTest();
+ $result = $index->search($suggest);
+ $suggests = $result->getSuggests();
+
+ // 3 suggestions should be returned: One in which both misspellings are corrected, and two in which only one misspelling is corrected.
+ $this->assertEquals(3, sizeof($suggests['suggest1'][0]['options']));
+
+ $this->assertEquals('elasticsearch is <suggest>bonsai cool</suggest>', $suggests['suggest1'][0]['options'][0]['highlighted']);
+ $this->assertEquals('elasticsearch is bonsai cool', $suggests['suggest1'][0]['options'][0]['text']);
+ }
+}
diff --git a/vendor/ruflin/elastica/test/lib/Elastica/Test/Suggest/TermTest.php b/vendor/ruflin/elastica/test/lib/Elastica/Test/Suggest/TermTest.php
new file mode 100644
index 00000000..f1250e6f
--- /dev/null
+++ b/vendor/ruflin/elastica/test/lib/Elastica/Test/Suggest/TermTest.php
@@ -0,0 +1,105 @@
+<?php
+namespace Elastica\Test\Suggest;
+
+use Elastica\Document;
+use Elastica\Index;
+use Elastica\Suggest;
+use Elastica\Suggest\Term;
+use Elastica\Test\Base as BaseTest;
+
+class TermTest extends BaseTest
+{
+ /**
+ * @return Index
+ */
+ protected function _getIndexForTest()
+ {
+ $index = $this->_createIndex();
+ $type = $index->getType('testSuggestType');
+ $type->addDocuments(array(
+ new Document(1, array('id' => 1, 'text' => 'GitHub')),
+ new Document(2, array('id' => 1, 'text' => 'Elastic')),
+ new Document(3, array('id' => 1, 'text' => 'Search')),
+ new Document(4, array('id' => 1, 'text' => 'Food')),
+ new Document(5, array('id' => 1, 'text' => 'Flood')),
+ new Document(6, array('id' => 1, 'text' => 'Folks')),
+ ));
+ $index->refresh();
+
+ return $index;
+ }
+
+ /**
+ * @group unit
+ */
+ public function testToArray()
+ {
+ $suggest = new Suggest();
+ $suggest1 = new Term('suggest1', '_all');
+ $suggest->addSuggestion($suggest1->setText('Foor'));
+ $suggest2 = new Term('suggest2', '_all');
+ $suggest->addSuggestion($suggest2->setText('Girhub'));
+
+ $expected = array(
+ 'suggest' => array(
+ 'suggest1' => array(
+ 'term' => array(
+ 'field' => '_all',
+ ),
+ 'text' => 'Foor',
+ ),
+ 'suggest2' => array(
+ 'term' => array(
+ 'field' => '_all',
+ ),
+ 'text' => 'Girhub',
+ ),
+ ),
+ );
+
+ $this->assertEquals($expected, $suggest->toArray());
+ }
+
+ /**
+ * @group functional
+ */
+ public function testSuggestResults()
+ {
+ $suggest = new Suggest();
+ $suggest1 = new Term('suggest1', '_all');
+ $suggest->addSuggestion($suggest1->setText('Foor seach'));
+ $suggest2 = new Term('suggest2', '_all');
+ $suggest->addSuggestion($suggest2->setText('Girhub'));
+
+ $index = $this->_getIndexForTest();
+ $result = $index->search($suggest);
+
+ $this->assertEquals(2, $result->countSuggests());
+
+ $suggests = $result->getSuggests();
+
+ // Ensure that two suggestion results are returned for suggest1
+ $this->assertEquals(2, sizeof($suggests['suggest1']));
+
+ $this->assertEquals('github', $suggests['suggest2'][0]['options'][0]['text']);
+ $this->assertEquals('food', $suggests['suggest1'][0]['options'][0]['text']);
+ }
+
+ /**
+ * @group functional
+ */
+ public function testSuggestNoResults()
+ {
+ $termSuggest = new Term('suggest1', '_all');
+ $termSuggest->setText('Foobar')->setSize(4);
+
+ $index = $this->_getIndexForTest();
+ $result = $index->search($termSuggest);
+
+ $this->assertEquals(1, $result->countSuggests());
+
+ // Assert that no suggestions were returned
+ $suggests = $result->getSuggests();
+ $this->assertEquals(0, sizeof($suggests['suggest1'][0]['options']));
+ }
+}
diff --git a/vendor/ruflin/elastica/test/lib/Elastica/Test/Tool/CrossIndexTest.php b/vendor/ruflin/elastica/test/lib/Elastica/Test/Tool/CrossIndexTest.php
new file mode 100644
index 00000000..f8fbf280
--- /dev/null
+++ b/vendor/ruflin/elastica/test/lib/Elastica/Test/Tool/CrossIndexTest.php
@@ -0,0 +1,135 @@
+<?php
+namespace Elastica\Test\Tool;
+
+use Elastica\Document;
+use Elastica\Test\Base;
+use Elastica\Tool\CrossIndex;
+use Elastica\Type;
+
+class CrossIndexTest extends Base
+{
+ /**
+ * Test default reindex.
+ */
+ public function testReindex()
+ {
+ $oldIndex = $this->_createIndex(null, true, 2);
+ $this->_addDocs($oldIndex->getType('crossIndexTest'), 10);
+
+ $newIndex = $this->_createIndex(null, true, 2);
+
+ $this->assertInstanceOf(
+ 'Elastica\Index',
+ CrossIndex::reindex($oldIndex, $newIndex)
+ );
+
+ $this->assertEquals(10, $newIndex->count());
+ }
+
+ /**
+ * Test reindex type option.
+ */
+ public function testReindexTypeOption()
+ {
+ $oldIndex = $this->_createIndex('', true, 2);
+ $type1 = $oldIndex->getType('crossIndexTest_1');
+ $type2 = $oldIndex->getType('crossIndexTest_2');
+
+ $docs1 = $this->_addDocs($type1, 10);
+ $docs2 = $this->_addDocs($type2, 10);
+
+ $newIndex = $this->_createIndex(null, true, 2);
+
+ // \Elastica\Type
+ CrossIndex::reindex($oldIndex, $newIndex, array(
+ CrossIndex::OPTION_TYPE => $type1,
+ ));
+ $this->assertEquals(10, $newIndex->count());
+ $newIndex->deleteDocuments($docs1);
+
+ // string
+ CrossIndex::reindex($oldIndex, $newIndex, array(
+ CrossIndex::OPTION_TYPE => 'crossIndexTest_2',
+ ));
+ $this->assertEquals(10, $newIndex->count());
+ $newIndex->deleteDocuments($docs2);
+
+ // array
+ CrossIndex::reindex($oldIndex, $newIndex, array(
+ CrossIndex::OPTION_TYPE => array(
+ 'crossIndexTest_1',
+ $type2,
+ ),
+ ));
+ $this->assertEquals(20, $newIndex->count());
+ }
+
+ /**
+ * Test default copy.
+ */
+ public function testCopy()
+ {
+ $oldIndex = $this->_createIndex(null, true, 2);
+ $newIndex = $this->_createIndex(null, true, 2);
+
+ $oldType = $oldIndex->getType('copy_test');
+ $oldMapping = array(
+ 'name' => array(
+ 'type' => 'string',
+ 'store' => true,
+ ),
+ );
+ $oldType->setMapping($oldMapping);
+ $docs = $this->_addDocs($oldType, 10);
+
+ // mapping
+ $this->assertInstanceOf(
+ 'Elastica\Index',
+ CrossIndex::copy($oldIndex, $newIndex)
+ );
+
+ $newMapping = $newIndex->getType('copy_test')->getMapping();
+ if (!isset($newMapping['copy_test']['properties']['name'])) {
+ $this->fail('could not request new mapping');
+ }
+
+ $this->assertEquals(
+ $oldMapping['name'],
+ $newMapping['copy_test']['properties']['name']
+ );
+
+ // document copy
+ $this->assertEquals(10, $newIndex->count());
+ $newIndex->deleteDocuments($docs);
+
+ // ignore mapping
+ $ignoredType = $oldIndex->getType('copy_test_1');
+ $this->_addDocs($ignoredType, 10);
+
+ CrossIndex::copy($oldIndex, $newIndex, array(
+ CrossIndex::OPTION_TYPE => $oldType,
+ ));
+
+ $this->assertFalse($newIndex->getType($ignoredType->getName())->exists());
+ $this->assertEquals(10, $newIndex->count());
+ }
+
+ /**
+ * @param Type $type
+ * @param int $docs
+ *
+ * @return array
+ */
+ private function _addDocs(Type $type, $docs)
+ {
+ $insert = array();
+ for ($i = 1; $i <= $docs; $i++) {
+ $insert[] = new Document($i, array('_id' => $i, 'key' => 'value'));
+ }
+
+ $type->addDocuments($insert);
+ $type->getIndex()->refresh();
+
+ return $insert;
+ }
+}
diff --git a/vendor/ruflin/elastica/test/lib/Elastica/Test/Transport/AbstractTransportTest.php b/vendor/ruflin/elastica/test/lib/Elastica/Test/Transport/AbstractTransportTest.php
new file mode 100644
index 00000000..20573cc7
--- /dev/null
+++ b/vendor/ruflin/elastica/test/lib/Elastica/Test/Transport/AbstractTransportTest.php
@@ -0,0 +1,80 @@
+<?php
+namespace Elastica\Test\Transport;
+
+use Elastica\Connection;
+use Elastica\Transport\AbstractTransport;
+use Elastica\Transport\Http;
+
+class AbstractTransportTest extends \PHPUnit_Framework_TestCase
+{
+ /**
+ * Return transport configuration and the expected HTTP method.
+ *
+ * @return array[]
+ */
+ public function getValidDefinitions()
+ {
+ $connection = new Connection();
+
+ return array(
+ array('Http'),
+ array(array('type' => 'Http')),
+ array(array('type' => new Http())),
+ array(new Http()),
+ );
+ }
+
+ /**
+ * @group unit
+ * @dataProvider getValidDefinitions
+ */
+ public function testCanCreateTransportInstances($transport)
+ {
+ $connection = new Connection();
+ $params = array();
+ $transport = AbstractTransport::create($transport, $connection, $params);
+ $this->assertInstanceOf('Elastica\Transport\AbstractTransport', $transport);
+ $this->assertSame($connection, $transport->getConnection());
+ }
+
+ public function getInvalidDefinitions()
+ {
+ return array(
+ array(array('transport' => 'Http')),
+ array('InvalidTransport'),
+ );
+ }
+
+ /**
+ * @group unit
+ * @dataProvider getInvalidDefinitions
+ * @expectedException Elastica\Exception\InvalidException
+ * @expectedExceptionMessage Invalid transport
+ */
+ public function testThrowsExecptionOnInvalidTransportDefinition($transport)
+ {
+ AbstractTransport::create($transport, new Connection());
+ }
+
+ /**
+ * @group unit
+ */
+ public function testCanInjectParamsWhenUsingArray()
+ {
+ $connection = new Connection();
+ $params = array(
+ 'param1' => 'some value',
+ 'param3' => 'value3',
+ );
+
+ $transport = AbstractTransport::create(array(
+ 'type' => 'Http',
+ 'param1' => 'value1',
+ 'param2' => 'value2',
+ ), $connection, $params);
+
+ $this->assertSame('value1', $transport->getParam('param1'));
+ $this->assertSame('value2', $transport->getParam('param2'));
+ $this->assertSame('value3', $transport->getParam('param3'));
+ }
+}
diff --git a/vendor/ruflin/elastica/test/lib/Elastica/Test/Transport/GuzzleTest.php b/vendor/ruflin/elastica/test/lib/Elastica/Test/Transport/GuzzleTest.php
new file mode 100644
index 00000000..04e7ee2d
--- /dev/null
+++ b/vendor/ruflin/elastica/test/lib/Elastica/Test/Transport/GuzzleTest.php
@@ -0,0 +1,180 @@
+<?php
+namespace Elastica\Test\Transport;
+
+use Elastica\Document;
+use Elastica\Query;
+use Elastica\ResultSet;
+use Elastica\Test\Base as BaseTest;
+
+class GuzzleTest extends BaseTest
+{
+ public static function setUpBeforeClass()
+ {
+ if (!class_exists('GuzzleHttp\\Client')) {
+ self::markTestSkipped('guzzlehttp/guzzle package should be installed to run guzzle transport tests');
+ }
+ }
+
+ /**
+ * Return transport configuration and the expected HTTP method.
+ *
+ * @return array[]
+ */
+ public function getConfig()
+ {
+ return array(
+ array(
+ array('persistent' => false, 'transport' => 'Guzzle'),
+ 'GET',
+ ),
+ array(
+ array('persistent' => false, 'transport' => array('type' => 'Guzzle', 'postWithRequestBody' => false)),
+ 'GET',
+ ),
+ array(
+ array('persistent' => false, 'transport' => array('type' => 'Guzzle', 'postWithRequestBody' => true)),
+ 'POST',
+ ),
+ );
+ }
+
+ /**
+ * @group functional
+ * @dataProvider getConfig
+ */
+ public function testDynamicHttpMethodBasedOnConfigParameter(array $config, $httpMethod)
+ {
+ $client = $this->_getClient($config);
+
+ $index = $client->getIndex('dynamic_http_method_test');
+ $index->create(array(), true);
+ $type = $index->getType('test');
+ $type->addDocument(new Document(1, array('test' => 'test')));
+ $index->refresh();
+ $resultSet = $index->search('test');
+ $info = $resultSet->getResponse()->getTransferInfo();
+ $this->assertStringStartsWith($httpMethod, $info['request_header']);
+ }
+
+ /**
+ * @group functional
+ * @dataProvider getConfig
+ */
+ public function testDynamicHttpMethodOnlyAffectsRequestsWithBody(array $config, $httpMethod)
+ {
+ $client = $this->_getClient($config);
+
+ $status = $client->getStatus();
+ $info = $status->getResponse()->getTransferInfo();
+ $this->assertStringStartsWith('GET', $info['request_header']);
+ }
+
+ /**
+ * @group functional
+ */
+ public function testWithEnvironmentalProxy()
+ {
+ putenv('http_proxy='.$this->_getProxyUrl().'/');
+
+ $client = $this->_getClient(array('transport' => 'Guzzle', 'persistent' => false));
+ $transferInfo = $client->request('/_nodes')->getTransferInfo();
+ $this->assertEquals(200, $transferInfo['http_code']);
+
+ $client->getConnection()->setProxy(null); // will not change anything
+ $transferInfo = $client->request('/_nodes')->getTransferInfo();
+ $this->assertEquals(200, $transferInfo['http_code']);
+
+ putenv('http_proxy=');
+ }
+
+ /**
+ * @group functional
+ */
+ public function testWithEnabledEnvironmentalProxy()
+ {
+ putenv('http_proxy='.$this->_getProxyUrl403().'/');
+
+ $client = $this->_getClient(array('transport' => 'Guzzle', 'persistent' => false));
+ $transferInfo = $client->request('/_nodes')->getTransferInfo();
+ $this->assertEquals(403, $transferInfo['http_code']);
+
+ $client = $this->_getClient(array('transport' => 'Guzzle', 'persistent' => false));
+ $client->getConnection()->setProxy('');
+ $transferInfo = $client->request('/_nodes')->getTransferInfo();
+ $this->assertEquals(200, $transferInfo['http_code']);
+
+ putenv('http_proxy=');
+ }
+
+ /**
+ * @group functional
+ */
+ public function testWithProxy()
+ {
+ $client = $this->_getClient(array('transport' => 'Guzzle', 'persistent' => false));
+ $client->getConnection()->setProxy($this->_getProxyUrl());
+
+ $transferInfo = $client->request('/_nodes')->getTransferInfo();
+ $this->assertEquals(200, $transferInfo['http_code']);
+ }
+
+ /**
+ * @group functional
+ */
+ public function testWithoutProxy()
+ {
+ $client = $this->_getClient(array('transport' => 'Guzzle', 'persistent' => false));
+ $client->getConnection()->setProxy('');
+
+ $transferInfo = $client->request('/_nodes')->getTransferInfo();
+ $this->assertEquals(200, $transferInfo['http_code']);
+ }
+
+ /**
+ * @group functional
+ */
+ public function testBodyReuse()
+ {
+ $client = $this->_getClient(array('transport' => 'Guzzle', 'persistent' => false));
+
+ $index = $client->getIndex('elastica_body_reuse_test');
+ $index->create(array(), true);
+ $this->_waitForAllocation($index);
+
+ $type = $index->getType('test');
+ $type->addDocument(new Document(1, array('test' => 'test')));
+
+ $index->refresh();
+
+ $resultSet = $index->search(array(
+ 'query' => array(
+ 'query_string' => array(
+ 'query' => 'pew pew pew',
+ ),
+ ),
+ ));
+
+ $this->assertEquals(0, $resultSet->getTotalHits());
+
+ $response = $index->request('/_search', 'POST');
+ $resultSet = new ResultSet($response, Query::create(array()));
+
+ $this->assertEquals(1, $resultSet->getTotalHits());
+ }
+
+ /**
+ * @group unit
+ * @expectedException Elastica\Exception\Connection\GuzzleException
+ */
+ public function testInvalidConnection()
+ {
+ $client = $this->_getClient(array('transport' => 'Guzzle', 'port' => 4500, 'persistent' => false));
+ $response = $client->request('_status', 'GET');
+ }
+
+ protected function tearDown()
+ {
+ parent::tearDown();
+ putenv('http_proxy=');
+ }
+}
diff --git a/vendor/ruflin/elastica/test/lib/Elastica/Test/Transport/HttpTest.php b/vendor/ruflin/elastica/test/lib/Elastica/Test/Transport/HttpTest.php
new file mode 100644
index 00000000..53ee105f
--- /dev/null
+++ b/vendor/ruflin/elastica/test/lib/Elastica/Test/Transport/HttpTest.php
@@ -0,0 +1,246 @@
+<?php
+namespace Elastica\Test\Transport;
+
+use Elastica\Document;
+use Elastica\Query;
+use Elastica\ResultSet;
+use Elastica\Test\Base as BaseTest;
+
+class HttpTest extends BaseTest
+{
+ /**
+ * Return transport configuration and the expected HTTP method.
+ *
+ * @return array[]
+ */
+ public function getConfig()
+ {
+ return array(
+ array(
+ array('transport' => 'Http', 'curl' => array(CURLINFO_HEADER_OUT => true)),
+ 'GET',
+ ),
+ array(
+ array('transport' => array('type' => 'Http', 'postWithRequestBody' => false, 'curl' => array(CURLINFO_HEADER_OUT => true))),
+ 'GET',
+ ),
+ array(
+ array('transport' => array('type' => 'Http', 'postWithRequestBody' => true, 'curl' => array(CURLINFO_HEADER_OUT => true))),
+ 'POST',
+ ),
+ );
+ }
+
+ /**
+ * @group functional
+ * @dataProvider getConfig
+ */
+ public function testDynamicHttpMethodBasedOnConfigParameter(array $config, $httpMethod)
+ {
+ $client = $this->_getClient($config);
+
+ $index = $client->getIndex('dynamic_http_method_test');
+ $index->create(array(), true);
+ $this->_waitForAllocation($index);
+
+ $type = $index->getType('test');
+ $type->addDocument(new Document(1, array('test' => 'test')));
+
+ $index->refresh();
+
+ $resultSet = $index->search('test');
+
+ $info = $resultSet->getResponse()->getTransferInfo();
+ $this->assertStringStartsWith($httpMethod, $info['request_header']);
+ }
+
+ /**
+ * @group functional
+ * @dataProvider getConfig
+ */
+ public function testDynamicHttpMethodOnlyAffectsRequestsWithBody(array $config, $httpMethod)
+ {
+ $client = $this->_getClient($config);
+
+ $status = $client->getStatus();
+ $info = $status->getResponse()->getTransferInfo();
+ $this->assertStringStartsWith('GET', $info['request_header']);
+ }
+
+ /**
+ * @group functional
+ */
+ public function testCurlNobodyOptionIsResetAfterHeadRequest()
+ {
+ $client = $this->_getClient();
+ $index = $client->getIndex('curl_test');
+ $index->create(array(), true);
+ $this->_waitForAllocation($index);
+
+ $type = $index->getType('item');
+ // Force HEAD request to set CURLOPT_NOBODY = true
+ $index->exists();
+
+ $id = 1;
+ $data = array('id' => $id, 'name' => 'Item 1');
+ $doc = new \Elastica\Document($id, $data);
+
+ $type->addDocument($doc);
+
+ $index->refresh();
+
+ $doc = $type->getDocument($id);
+
+ // Document should be retrieved correctly
+ $this->assertSame($data, $doc->getData());
+ $this->assertEquals($id, $doc->getId());
+ }
+
+ /**
+ * @group functional
+ */
+ public function testUnicodeData()
+ {
+ $client = $this->_getClient();
+ $index = $client->getIndex('curl_test');
+ $index->create(array(), true);
+ $this->_waitForAllocation($index);
+
+ $type = $index->getType('item');
+
+ // Force HEAD request to set CURLOPT_NOBODY = true
+ $index->exists();
+
+ $id = 22;
+ $data = array('id' => $id, 'name' => '
+ Сегодня, я вижу, особенно грустен твой взгляд, /
+ И руки особенно тонки, колени обняв. /
+ Послушай: далеко, далеко, на озере Чад /
+ Изысканный бродит жираф.');
+
+ $doc = new \Elastica\Document($id, $data);
+
+ $type->addDocument($doc);
+
+ $index->refresh();
+
+ $doc = $type->getDocument($id);
+
+ // Document should be retrieved correctly
+ $this->assertSame($data, $doc->getData());
+ $this->assertEquals($id, $doc->getId());
+ }
+
+ /**
+ * @group functional
+ */
+ public function testWithEnvironmentalProxy()
+ {
+ putenv('http_proxy='.$this->_getProxyUrl().'/');
+
+ $client = $this->_getClient();
+ $transferInfo = $client->request('/_nodes')->getTransferInfo();
+ $this->assertEquals(200, $transferInfo['http_code']);
+
+ $client->getConnection()->setProxy(null); // will not change anything
+ $transferInfo = $client->request('/_nodes')->getTransferInfo();
+ $this->assertEquals(200, $transferInfo['http_code']);
+
+ putenv('http_proxy=');
+ }
+
+ /**
+ * @group functional
+ */
+ public function testWithEnabledEnvironmentalProxy()
+ {
+ putenv('http_proxy='.$this->_getProxyUrl403().'/');
+ $client = $this->_getClient();
+ $transferInfo = $client->request('/_nodes')->getTransferInfo();
+ $this->assertEquals(403, $transferInfo['http_code']);
+ $client = $this->_getClient();
+ $client->getConnection()->setProxy('');
+ $transferInfo = $client->request('/_nodes')->getTransferInfo();
+ $this->assertEquals(200, $transferInfo['http_code']);
+ putenv('http_proxy=');
+ }
+
+ /**
+ * @group functional
+ */
+ public function testWithProxy()
+ {
+ $client = $this->_getClient();
+ $client->getConnection()->setProxy($this->_getProxyUrl());
+
+ $transferInfo = $client->request('/_nodes')->getTransferInfo();
+ $this->assertEquals(200, $transferInfo['http_code']);
+ }
+
+ /**
+ * @group functional
+ */
+ public function testWithoutProxy()
+ {
+ $client = $this->_getClient();
+ $client->getConnection()->setProxy('');
+
+ $transferInfo = $client->request('/_nodes')->getTransferInfo();
+ $this->assertEquals(200, $transferInfo['http_code']);
+ }
+
+ /**
+ * @group functional
+ */
+ public function testBodyReuse()
+ {
+ $client = $this->_getClient();
+
+ $index = $client->getIndex('elastica_body_reuse_test');
+ $index->create(array(), true);
+ $this->_waitForAllocation($index);
+
+ $type = $index->getType('test');
+ $type->addDocument(new Document(1, array('test' => 'test')));
+
+ $index->refresh();
+
+ $resultSet = $index->search(array(
+ 'query' => array(
+ 'query_string' => array(
+ 'query' => 'pew pew pew',
+ ),
+ ),
+ ));
+
+ $this->assertEquals(0, $resultSet->getTotalHits());
+
+ $response = $index->request('/_search', 'POST');
+ $resultSet = new ResultSet($response, Query::create(array()));
+
+ $this->assertEquals(1, $resultSet->getTotalHits());
+ }
+
+ /**
+ * @group functional
+ */
+ public function testPostWith0Body()
+ {
+ $client = $this->_getClient();
+
+ $index = $client->getIndex('elastica_0_body');
+ $index->create(array(), true);
+ $this->_waitForAllocation($index);
+ $index->refresh();
+
+ $tokens = $index->analyze('0');
+
+ $this->assertNotEmpty($tokens);
+ }
+
+ protected function tearDown()
+ {
+ parent::tearDown();
+ putenv('http_proxy=');
+ }
+}
diff --git a/vendor/ruflin/elastica/test/lib/Elastica/Test/Transport/MemcacheTest.php b/vendor/ruflin/elastica/test/lib/Elastica/Test/Transport/MemcacheTest.php
new file mode 100644
index 00000000..30897073
--- /dev/null
+++ b/vendor/ruflin/elastica/test/lib/Elastica/Test/Transport/MemcacheTest.php
@@ -0,0 +1,176 @@
+<?php
+namespace Elastica\Test\Transport;
+
+use Elastica\Document;
+use Elastica\Query;
+use Elastica\Query\QueryString;
+use Elastica\Request;
+use Elastica\Test\Base as BaseTest;
+
+class MemcacheTest extends BaseTest
+{
+ public static function setUpBeforeClass()
+ {
+ if (!extension_loaded('Memcache')) {
+ self::markTestSkipped('pecl/memcache must be installed to run this test case');
+ }
+ }
+
+ protected function _getMemcacheClient()
+ {
+ return $this->_getClient(array(
+ 'host' => $this->_getHost(),
+ 'port' => 11211,
+ 'transport' => 'Memcache',
+ ));
+ }
+
+ /**
+ * @group functional
+ */
+ public function testConstruct()
+ {
+ $client = $this->_getMemcacheClient();
+ $this->assertEquals($this->_getHost(), $client->getConnection()->getHost());
+ $this->assertEquals(11211, $client->getConnection()->getPort());
+ }
+
+ /**
+ * @group functional
+ */
+ public function testCreateDocument()
+ {
+ $index = $this->_createIndex();
+ $this->_waitForAllocation($index);
+ $type = $index->getType('foo');
+
+ // Create document
+ $document = new Document(1, array('username' => 'John Doe'));
+ $type->addDocument($document);
+ $index->refresh();
+
+ // Check it was saved
+ $document = $type->getDocument(1);
+ $this->assertEquals('John Doe', $document->get('username'));
+ }
+
+ /**
+ * @group functional
+ * @expectedException Elastica\Exception\NotFoundException
+ */
+ public function testDeleteDocument()
+ {
+ $index = $this->_createIndex();
+ $this->_waitForAllocation($index);
+ $type = $index->getType('foo');
+
+ // Create document
+ $document = new Document(1, array('username' => 'John Doe'));
+ $type->addDocument($document);
+ $index->refresh();
+
+ // Delete document
+ $type->deleteById(1);
+
+ // Check if document is not exists
+ $document = $type->getDocument(1);
+ }
+
+ /**
+ * @group functional
+ */
+ public function testUpdateDocument()
+ {
+ $index = $this->_createIndex();
+ $this->_waitForAllocation($index);
+ $type = $index->getType('foo');
+
+ // Create document
+ $document = new Document(1, array('username' => 'John Doe'));
+ $type->addDocument($document);
+ $index->refresh();
+
+ // Check it was saved
+ $savedDocument = $type->getDocument(1);
+ $this->assertEquals('John Doe', $savedDocument->get('username'));
+
+ // Update document
+ $newDocument = new Document(1, array('username' => 'Doe John'));
+ $type->updateDocument($newDocument);
+ $index->refresh();
+
+ // Check it was updated
+ $newSavedDocument = $type->getDocument(1);
+ $this->assertEquals('Doe John', $newSavedDocument->get('username'));
+ }
+
+ /**
+ * @group functional
+ */
+ public function testSearchDocument()
+ {
+ $index = $this->_createIndex();
+ $this->_waitForAllocation($index);
+ $type = $index->getType('fruits');
+
+ // Create documents
+ $docs = array(
+ new Document(1, array('name' => 'banana')),
+ new Document(2, array('name' => 'apple')),
+ new Document(3, array('name' => 'orange')),
+ );
+ $type->addDocuments($docs);
+ $index->refresh();
+
+ // Search documents
+ $queryString = new QueryString('orange');
+ $query = new Query($queryString);
+ $resultSet = $type->search($query);
+
+ // Check if correct document was found
+ $this->assertEquals(1, $resultSet->getTotalHits());
+ $this->assertEquals(3, $resultSet[0]->getId());
+ $data = $resultSet[0]->getData();
+ $this->assertEquals('orange', $data['name']);
+ }
+
+ /**
+ * @group functional
+ * @expectedException Elastica\Exception\InvalidException
+ * @expectedExceptionMessage is not supported in memcache transport
+ */
+ public function testHeadRequest()
+ {
+ $client = $this->_getMemcacheClient();
+ $client->request('foo', Request::HEAD);
+ }
+
+ /**
+ * @group functional
+ * @expectedException Elastica\Exception\InvalidException
+ * @expectedExceptionMessage is not supported in memcache transport
+ */
+ public function testInvalidRequest()
+ {
+ $client = $this->_getMemcacheClient();
+ $client->request('foo', 'its_fail');
+ }
+
+ /**
+ * @group functional
+ * @expectedException Elastica\Exception\Connection\MemcacheException
+ * @expectedExceptionMessage is too long
+ */
+ public function testRequestWithLongPath()
+ {
+ $client = $this->_getMemcacheClient();
+ $index = $client->getIndex('memcache-test');
+ $index->create();
+
+ $this->_waitForAllocation($index);
+
+ $queryString = new QueryString(str_repeat('z', 300));
+ $query = new Query($queryString);
+ $index->search($query);
+ }
+}
diff --git a/vendor/ruflin/elastica/test/lib/Elastica/Test/Transport/NullTransportTest.php b/vendor/ruflin/elastica/test/lib/Elastica/Test/Transport/NullTransportTest.php
new file mode 100644
index 00000000..cea3e3ba
--- /dev/null
+++ b/vendor/ruflin/elastica/test/lib/Elastica/Test/Transport/NullTransportTest.php
@@ -0,0 +1,96 @@
+<?php
+namespace Elastica\Test\Transport;
+
+use Elastica\Connection;
+use Elastica\Query;
+use Elastica\Request;
+use Elastica\Test\Base as BaseTest;
+use Elastica\Transport\NullTransport;
+
+/**
+ * Elastica Null Transport Test.
+ *
+ * @author James Boehmer <james.boehmer@jamesboehmer.com>
+ */
+class NullTransportTest extends BaseTest
+{
+ /**
+ * @group functional
+ */
+ public function testEmptyResult()
+ {
+ // Creates a client with any destination, and verify it returns a response object when executed
+ $client = $this->_getClient();
+ $connection = new Connection(array('transport' => 'NullTransport'));
+ $client->setConnections(array($connection));
+
+ $index = $client->getIndex('elasticaNullTransportTest1');
+
+ $resultSet = $index->search(new Query());
+ $this->assertNotNull($resultSet);
+
+ $response = $resultSet->getResponse();
+ $this->assertNotNull($response);
+
+ // Validate most of the expected fields in the response data. Consumers of the response
+ // object have a reasonable expectation of finding "hits", "took", etc
+ $responseData = $response->getData();
+ $this->assertContains('took', $responseData);
+ $this->assertEquals(0, $responseData['took']);
+ $this->assertContains('_shards', $responseData);
+ $this->assertContains('hits', $responseData);
+ $this->assertContains('total', $responseData['hits']);
+ $this->assertEquals(0, $responseData['hits']['total']);
+ $this->assertContains('params', $responseData);
+
+ $took = $response->getEngineTime();
+ $this->assertEquals(0, $took);
+
+ $errorString = $response->getError();
+ $this->assertEmpty($errorString);
+
+ $shards = $response->getShardsStatistics();
+ $this->assertContains('total', $shards);
+ $this->assertEquals(0, $shards['total']);
+ $this->assertContains('successful', $shards);
+ $this->assertEquals(0, $shards['successful']);
+ $this->assertContains('failed', $shards);
+ $this->assertEquals(0, $shards['failed']);
+ }
+
+ /**
+ * @group functional
+ */
+ public function testExec()
+ {
+ $request = new Request('/test');
+ $params = array('name' => 'ruflin');
+ $transport = new NullTransport();
+ $response = $transport->exec($request, $params);
+
+ $this->assertInstanceOf('\Elastica\Response', $response);
+
+ $data = $response->getData();
+ $this->assertEquals($params, $data['params']);
+ }
+
+ /**
+ * @group functional
+ */
+ public function testOldObject()
+ {
+ if (version_compare(phpversion(), 7, '>=')) {
+ self::markTestSkipped('These objects are not supported in PHP 7');
+ }
+
+ $request = new Request('/test');
+ $params = array('name' => 'ruflin');
+ $transport = new \Elastica\Transport\Null();
+ $response = $transport->exec($request, $params);
+
+ $this->assertInstanceOf('\Elastica\Response', $response);
+
+ $data = $response->getData();
+ $this->assertEquals($params, $data['params']);
+ }
+}
diff --git a/vendor/ruflin/elastica/test/lib/Elastica/Test/Transport/ThriftTest.php b/vendor/ruflin/elastica/test/lib/Elastica/Test/Transport/ThriftTest.php
new file mode 100644
index 00000000..b73ef4f7
--- /dev/null
+++ b/vendor/ruflin/elastica/test/lib/Elastica/Test/Transport/ThriftTest.php
@@ -0,0 +1,135 @@
+<?php
+namespace Elastica\Test\Transport;
+
+use Elastica\Connection;
+use Elastica\Document;
+use Elastica\Index;
+use Elastica\Test\Base as BaseTest;
+
+class ThriftTest extends BaseTest
+{
+ public static function setUpBeforeClass()
+ {
+ if (!class_exists('Elasticsearch\\RestClient')) {
+ self::markTestSkipped('munkie/elasticsearch-thrift-php package should be installed to run thrift transport tests');
+ }
+ }
+
+ /**
+ * @group unit
+ */
+ public function testConstruct()
+ {
+ $host = $this->_getHost();
+ $port = 9500;
+ $client = $this->_getClient(array('host' => $host, 'port' => $port, 'transport' => 'Thrift'));
+
+ $this->assertEquals($host, $client->getConnection()->getHost());
+ $this->assertEquals($port, $client->getConnection()->getPort());
+ }
+
+ /**
+ * @group functional
+ * @dataProvider configProvider
+ */
+ public function testSearchRequest($config)
+ {
+ $this->_checkPlugin();
+
+ // Creates a new index 'xodoa' and a type 'user' inside this index
+ $client = $this->_getClient($config);
+
+ $index = $client->getIndex('elastica_test1');
+ $index->create(array(), true);
+
+ $type = $index->getType('user');
+
+ // Adds 1 document to the index
+ $doc1 = new Document(1,
+ array('username' => 'hans', 'test' => array('2', '3', '5'))
+ );
+ $doc1->setVersion(0);
+ $type->addDocument($doc1);
+
+ // Adds a list of documents with _bulk upload to the index
+ $docs = array();
+ $docs[] = new Document(2,
+ array('username' => 'john', 'test' => array('1', '3', '6'))
+ );
+ $docs[] = new Document(3,
+ array('username' => 'rolf', 'test' => array('2', '3', '7'))
+ );
+ $type->addDocuments($docs);
+
+ // Refresh index
+ $index->refresh();
+ $resultSet = $type->search('rolf');
+
+ $this->assertEquals(1, $resultSet->getTotalHits());
+ }
+
+ /**
+ * @group unit
+ * @expectedException \Elastica\Exception\ConnectionException
+ */
+ public function testInvalidHostRequest()
+ {
+ $this->_checkPlugin();
+
+ $client = $this->_getClient(array('host' => 'unknown', 'port' => 9555, 'transport' => 'Thrift'));
+ $client->getStatus();
+ }
+
+ /**
+ * @group functional
+ * @expectedException \Elastica\Exception\ResponseException
+ */
+ public function testInvalidElasticRequest()
+ {
+ $this->_checkPlugin();
+
+ $connection = new Connection();
+ $connection->setHost($this->_getHost());
+ $connection->setPort(9500);
+ $connection->setTransport('Thrift');
+
+ $client = $this->_getClient();
+ $client->addConnection($connection);
+
+ $index = new Index($client, 'missing_index');
+ $index->getStatus();
+ }
+
+ public function configProvider()
+ {
+ return array(
+ array(
+ array(
+ 'host' => $this->_getHost(),
+ 'port' => 9500,
+ 'transport' => 'Thrift',
+ ),
+ ),
+ array(
+ array(
+ 'host' => $this->_getHost(),
+ 'port' => 9500,
+ 'transport' => 'Thrift',
+ 'config' => array(
+ 'framedTransport' => false,
+ 'sendTimeout' => 10000,
+ 'recvTimeout' => 20000,
+ ),
+ ),
+ ),
+ );
+ }
+
+ protected function _checkPlugin()
+ {
+ $nodes = $this->_getClient()->getCluster()->getNodes();
+ if (!$nodes[0]->getInfo()->hasPlugin('transport-thrift')) {
+ $this->markTestSkipped('transport-thrift plugin not installed.');
+ }
+ }
+}
diff --git a/vendor/ruflin/elastica/test/lib/Elastica/Test/Transport/TransportBenchmarkTest.php b/vendor/ruflin/elastica/test/lib/Elastica/Test/Transport/TransportBenchmarkTest.php
new file mode 100644
index 00000000..11a16a34
--- /dev/null
+++ b/vendor/ruflin/elastica/test/lib/Elastica/Test/Transport/TransportBenchmarkTest.php
@@ -0,0 +1,261 @@
+<?php
+namespace Elastica\Test\Transport;
+
+use Elastica\Document;
+use Elastica\Index;
+use Elastica\Query;
+use Elastica\Test\Base as BaseTest;
+
+class TransportBenchmarkTest extends BaseTest
+{
+ protected $_max = 1000;
+
+ protected $_maxData = 20;
+
+ protected static $_results = array();
+
+ public static function tearDownAfterClass()
+ {
+ self::printResults();
+ }
+
+ /**
+ * @param array $config
+ *
+ * @return \Elastica\Type
+ */
+ protected function getType(array $config)
+ {
+ $client = $this->_getClient($config);
+ $index = $client->getIndex('benchmark'.uniqid());
+ $index->create(array('index' => array('number_of_shards' => 1, 'number_of_replicas' => 0)), true);
+
+ return $index->getType('benchmark');
+ }
+
+ /**
+ * @dataProvider providerTransport
+ * @group benchmark
+ */
+ public function testAddDocument(array $config, $transport)
+ {
+ $this->_checkThrift($transport);
+
+ $type = $this->getType($config);
+ $index = $type->getIndex();
+ $index->create(array(), true);
+
+ $times = array();
+ for ($i = 0; $i < $this->_max; $i++) {
+ $data = $this->getData($i);
+ $doc = new Document($i, $data);
+ $result = $type->addDocument($doc);
+ $times[] = $result->getQueryTime();
+ $this->assertTrue($result->isOk());
+ }
+
+ $index->refresh();
+
+ self::logResults('insert', $transport, $times);
+ }
+
+ /**
+ * @depends testAddDocument
+ * @dataProvider providerTransport
+ * @group benchmark
+ */
+ public function testRandomRead(array $config, $transport)
+ {
+ $this->_checkThrift($transport);
+
+ $type = $this->getType($config);
+
+ $type->search('test');
+
+ $times = array();
+ for ($i = 0; $i < $this->_max; $i++) {
+ $test = rand(1, $this->_max);
+ $query = new Query();
+ $query->setQuery(new \Elastica\Query\MatchAll());
+ $query->setPostFilter(new \Elastica\Filter\Term(array('test' => $test)));
+ $result = $type->search($query);
+ $times[] = $result->getResponse()->getQueryTime();
+ }
+
+ self::logResults('random read', $transport, $times);
+ }
+
+ /**
+ * @depends testAddDocument
+ * @dataProvider providerTransport
+ * @group benchmark
+ */
+ public function testBulk(array $config, $transport)
+ {
+ $type = $this->getType($config);
+
+ $times = array();
+ for ($i = 0; $i < $this->_max; $i++) {
+ $docs = array();
+ for ($j = 0; $j < 10; $j++) {
+ $data = $this->getData($i.$j);
+ $docs[] = new Document($i, $data);
+ }
+
+ $result = $type->addDocuments($docs);
+ $times[] = $result->getQueryTime();
+ }
+
+ self::logResults('bulk', $transport, $times);
+ }
+
+ /**
+ * @dataProvider providerTransport
+ * @group benchmark
+ */
+ public function testGetMapping(array $config, $transport)
+ {
+ $client = $this->_getClient($config);
+ $index = $client->getIndex('benchmark');
+ $index->create(array(), true);
+ $type = $index->getType('mappingTest');
+
+ // Define mapping
+ $mapping = new \Elastica\Type\Mapping();
+ $mapping->setParam('_boost', array('name' => '_boost', 'null_value' => 1.0));
+ $mapping->setProperties(array(
+ 'id' => array('type' => 'integer', 'include_in_all' => false),
+ 'user' => array(
+ 'type' => 'object',
+ 'properties' => array(
+ 'name' => array('type' => 'string', 'include_in_all' => true),
+ 'fullName' => array('type' => 'string', 'include_in_all' => true),
+ ),
+ ),
+ 'msg' => array('type' => 'string', 'include_in_all' => true),
+ 'tstamp' => array('type' => 'date', 'include_in_all' => false),
+ 'location' => array('type' => 'geo_point', 'include_in_all' => false),
+ '_boost' => array('type' => 'float', 'include_in_all' => false),
+ ));
+
+ $type->setMapping($mapping);
+ $index->refresh();
+
+ $times = array();
+ for ($i = 0; $i < $this->_max; $i++) {
+ $response = $type->request('_mapping', \Elastica\Request::GET);
+ $times[] = $response->getQueryTime();
+ }
+ self::logResults('get mapping', $transport, $times);
+ }
+
+ public function providerTransport()
+ {
+ return array(
+ array(
+ array(
+ 'transport' => 'Http',
+ 'host' => $this->_getHost(),
+ 'port' => $this->_getPort(),
+ 'persistent' => false,
+ ),
+ 'Http:NotPersistent',
+ ),
+ array(
+ array(
+ 'transport' => 'Http',
+ 'host' => $this->_getHost(),
+ 'port' => $this->_getPort(),
+ 'persistent' => true,
+ ),
+ 'Http:Persistent',
+ ),
+ array(
+ array(
+ 'transport' => 'Thrift',
+ 'host' => $this->_getHost(),
+ 'port' => 9500,
+ 'config' => array(
+ 'framedTransport' => false,
+ ),
+ ),
+ 'Thrift:Buffered',
+ ),
+ );
+ }
+
+ /**
+ * @param string $test
+ *
+ * @return array
+ */
+ protected function getData($test)
+ {
+ $data = array(
+ 'test' => $test,
+ 'name' => array(),
+ );
+ for ($i = 0; $i < $this->_maxData; $i++) {
+ $data['name'][] = uniqid();
+ }
+
+ return $data;
+ }
+
+ /**
+ * @param $name
+ * @param $transport
+ * @param array $times
+ */
+ protected static function logResults($name, $transport, array $times)
+ {
+ self::$_results[$name][$transport] = array(
+ 'count' => count($times),
+ 'max' => max($times) * 1000,
+ 'min' => min($times) * 1000,
+ 'mean' => (array_sum($times) / count($times)) * 1000,
+ );
+ }
+
+ protected static function printResults()
+ {
+ echo sprintf(
+ "\n%-12s | %-20s | %-12s | %-12s | %-12s | %-12s\n\n",
+ 'NAME',
+ 'TRANSPORT',
+ 'COUNT',
+ 'MAX',
+ 'MIN',
+ 'MEAN',
+ '%'
+ );
+ foreach (self::$_results as $name => $values) {
+ $means = array();
+ foreach ($values as $times) {
+ $means[] = $times['mean'];
+ }
+ $minMean = min($means);
+ foreach ($values as $transport => $times) {
+ $perc = (($times['mean'] - $minMean) / $minMean) * 100;
+ echo sprintf(
+ "%-12s | %-20s | %-12d | %-12.2f | %-12.2f | %-12.2f | %+03.2f\n",
+ $name,
+ $transport,
+ $times['count'],
+ $times['max'],
+ $times['min'],
+ $times['mean'],
+ $perc
+ );
+ }
+ echo "\n";
+ }
+ }
+
+ protected function _checkThrift($transport)
+ {
+ if (strpos($transport, 'Thrift') !== false && !class_exists('Elasticsearch\\RestClient')) {
+ self::markTestSkipped('munkie/elasticsearch-thrift-php package should be installed to run thrift transport tests');
+ }
+ }
+}
diff --git a/vendor/ruflin/elastica/test/lib/Elastica/Test/Type/MappingTest.php b/vendor/ruflin/elastica/test/lib/Elastica/Test/Type/MappingTest.php
new file mode 100644
index 00000000..925c23bb
--- /dev/null
+++ b/vendor/ruflin/elastica/test/lib/Elastica/Test/Type/MappingTest.php
@@ -0,0 +1,331 @@
+<?php
+namespace Elastica\Test\Type;
+
+use Elastica\Document;
+use Elastica\Query;
+use Elastica\Query\QueryString;
+use Elastica\Test\Base as BaseTest;
+use Elastica\Type;
+use Elastica\Type\Mapping;
+
+class MappingTest extends BaseTest
+{
+ /**
+ * @group functional
+ */
+ public function testMappingStoreFields()
+ {
+ $client = $this->_getClient();
+ $index = $client->getIndex('test');
+
+ $index->create(array(), true);
+ $type = $index->getType('test');
+
+ $mapping = new Mapping($type,
+ array(
+ 'firstname' => array('type' => 'string', 'store' => 'yes'),
+ // default is store => no expected
+ 'lastname' => array('type' => 'string'),
+ )
+ );
+ $mapping->disableSource();
+
+ $type->setMapping($mapping);
+
+ $firstname = 'Nicolas';
+ $doc = new Document(1,
+ array(
+ 'firstname' => $firstname,
+ 'lastname' => 'Ruflin',
+ )
+ );
+
+ $type->addDocument($doc);
+
+ $index->refresh();
+ $queryString = new QueryString('ruflin');
+ $query = Query::create($queryString);
+ $query->setFields(array('*'));
+
+ $resultSet = $type->search($query);
+ $result = $resultSet->current();
+ $fields = $result->getFields();
+
+ $this->assertEquals($firstname, $fields['firstname'][0]);
+ $this->assertArrayNotHasKey('lastname', $fields);
+ $this->assertEquals(1, count($fields));
+
+ $index->flush();
+ $document = $type->getDocument(1);
+
+ $this->assertEmpty($document->getData());
+
+ $index->delete();
+ }
+
+ /**
+ * @group functional
+ */
+ public function testEnableAllField()
+ {
+ $index = $this->_createIndex();
+ $type = $index->getType('test');
+
+ $mapping = new Mapping($type, array());
+
+ $mapping->enableAllField();
+
+ $data = $mapping->toArray();
+ $this->assertTrue($data[$type->getName()]['_all']['enabled']);
+
+ $response = $mapping->send();
+ $this->assertTrue($response->isOk());
+
+ $index->delete();
+ }
+
+ /**
+ * @group functional
+ */
+ public function testEnableTtl()
+ {
+ $client = $this->_getClient();
+ $index = $client->getIndex('test');
+
+ $index->create(array(), true);
+ $type = $index->getType('test');
+
+ $mapping = new Mapping($type, array());
+
+ $mapping->enableTtl();
+
+ $data = $mapping->toArray();
+ $this->assertTrue($data[$type->getName()]['_ttl']['enabled']);
+
+ $index->delete();
+ }
+
+ /**
+ * @group functional
+ */
+ public function testNestedMapping()
+ {
+ $client = $this->_getClient();
+ $index = $client->getIndex('test');
+
+ $index->create(array(), true);
+ $type = $index->getType('test');
+
+ //$this->markTestIncomplete('nested mapping is not set right yet');
+ $mapping = new Mapping($type,
+ array(
+ 'test' => array(
+ 'type' => 'object', 'store' => 'yes', 'properties' => array(
+ 'user' => array(
+ 'properties' => array(
+ 'firstname' => array('type' => 'string', 'store' => 'yes'),
+ 'lastname' => array('type' => 'string', 'store' => 'yes'),
+ 'age' => array('type' => 'integer', 'store' => 'yes'),
+ ),
+ ),
+ ),
+ ),
+ )
+ );
+
+ $response = $type->setMapping($mapping);
+ $this->assertFalse($response->hasError());
+
+ $doc = new Document(1, array(
+ 'user' => array(
+ 'firstname' => 'Nicolas',
+ 'lastname' => 'Ruflin',
+ 'age' => 9,
+ ),
+ ));
+
+ $type->addDocument($doc);
+
+ $index->refresh();
+ $resultSet = $type->search('ruflin');
+ $this->assertEquals($resultSet->count(), 1);
+
+ $index->delete();
+ }
+
+ /**
+ * @group functional
+ */
+ public function testParentMapping()
+ {
+ $index = $this->_createIndex();
+ $parenttype = new Type($index, 'parenttype');
+ $parentmapping = new Mapping($parenttype,
+ array(
+ 'name' => array('type' => 'string', 'store' => 'yes'),
+ )
+ );
+
+ $parenttype->setMapping($parentmapping);
+
+ $childtype = new Type($index, 'childtype');
+ $childmapping = new Mapping($childtype,
+ array(
+ 'name' => array('type' => 'string', 'store' => 'yes'),
+ )
+ );
+ $childmapping->setParent('parenttype');
+
+ $childtype->setMapping($childmapping);
+
+ $data = $childmapping->toArray();
+ $this->assertEquals('parenttype', $data[$childtype->getName()]['_parent']['type']);
+
+ $index->delete();
+ }
+
+ /**
+ * @group functional
+ */
+ public function testMappingExample()
+ {
+ $index = $this->_createIndex();
+ $type = $index->getType('notes');
+
+ $mapping = new Mapping($type,
+ array(
+ 'note' => array(
+ 'store' => 'yes', 'properties' => array(
+ 'titulo' => array('type' => 'string', 'store' => 'no', 'include_in_all' => true, 'boost' => 1.0),
+ 'contenido' => array('type' => 'string', 'store' => 'no', 'include_in_all' => true, 'boost' => 1.0),
+ ),
+ ),
+ )
+ );
+
+ $type->setMapping($mapping);
+
+ $doc = new Document(1, array(
+ 'note' => array(
+ array(
+ 'titulo' => 'nota1',
+ 'contenido' => 'contenido1',
+ ),
+ array(
+ 'titulo' => 'nota2',
+ 'contenido' => 'contenido2',
+ ),
+ ),
+ )
+ );
+
+ $type->addDocument($doc);
+
+ $index->delete();
+ }
+
+ /**
+ * @group functional
+ *
+ * Test setting a dynamic template and validate whether the right mapping is applied after adding a document which
+ * should match the dynamic template. The example is the template_1 from the Elasticsearch documentation.
+ *
+ * @link http://www.elastic.co/guide/en/elasticsearch/reference/current/mapping-root-object-type.html
+ */
+ public function testDynamicTemplate()
+ {
+ $index = $this->_createIndex();
+ $type = $index->getType('person');
+
+ // set a dynamic template "template_1" which creates a multi field for multi* matches.
+ $mapping = new Mapping($type);
+ $mapping->setParam('dynamic_templates', array(
+ array('template_1' => array(
+ 'match' => 'multi*',
+ 'mapping' => array(
+ 'type' => 'multi_field',
+ 'fields' => array(
+ '{name}' => array('type' => '{dynamic_type}', 'index' => 'analyzed'),
+ 'org' => array('type' => '{dynamic_type}', 'index' => 'not_analyzed'),
+ ),
+ ),
+ )),
+ ));
+
+ $mapping->send();
+
+ // when running the tests, the mapping sometimes isn't available yet. Optimize index to enforce reload mapping.
+ $index->optimize();
+
+ // create a document which should create a mapping for the field: multiname.
+ $testDoc = new Document('person1', array('multiname' => 'Jasper van Wanrooy'), $type);
+ $index->addDocuments(array($testDoc));
+ sleep(1); //sleep 1 to ensure that the test passes every time
+
+ // read the mapping from Elasticsearch and assert that the multiname.org field is "not_analyzed"
+ $newMapping = $type->getMapping();
+ $this->assertArrayHasKey('person', $newMapping,
+ 'Person type not available in mapping from ES. Mapping set at all?');
+ $this->assertArrayHasKey('properties', $newMapping['person'],
+ 'Person type doesnt have any properties. Document properly added?');
+ $this->assertArrayHasKey('multiname', $newMapping['person']['properties'],
+ 'The multiname property is not added to the mapping. Document properly added?');
+ $this->assertArrayHasKey('fields', $newMapping['person']['properties']['multiname'],
+ 'The multiname field of the Person type is presumably not a multi_field type. Dynamic mapping not applied?');
+ $this->assertArrayHasKey('org', $newMapping['person']['properties']['multiname']['fields'],
+ 'The multi* matcher did not create a mapping for the multiname.org property when indexing the document.');
+ $this->assertArrayHasKey('index', $newMapping['person']['properties']['multiname']['fields']['org'],
+ 'Indexing status of the multiname.org not available. Dynamic mapping not fully applied!');
+ $this->assertEquals('not_analyzed', $newMapping['person']['properties']['multiname']['fields']['org']['index']);
+
+ $index->delete();
+ }
+
+ /**
+ * @group functional
+ */
+ public function testSetMeta()
+ {
+ $index = $this->_createIndex();
+ $type = $index->getType('test');
+ $mapping = new Mapping($type, array(
+ 'firstname' => array('type' => 'string', 'store' => 'yes'),
+ 'lastname' => array('type' => 'string'),
+ ));
+ $mapping->setMeta(array('class' => 'test'));
+ $type->setMapping($mapping);
+
+ $mappingData = $type->getMapping();
+ $this->assertEquals('test', $mappingData['test']['_meta']['class']);
+
+ $index->delete();
+ }
+
+ /**
+ * @group functional
+ */
+ public function testGetters()
+ {
+ $index = $this->_createIndex();
+ $type = $index->getType('test');
+ $properties = array(
+ 'firstname' => array('type' => 'string', 'store' => 'yes'),
+ 'lastname' => array('type' => 'string'),
+ );
+ $mapping = new Mapping($type, $properties);
+ $all = array(
+ 'enabled' => true,
+ 'store' => 'yes',
+ );
+ $mapping->setParam('_all', $all);
+ $get_all = $mapping->getParam('_all');
+
+ $this->assertEquals($get_all, $all);
+
+ $this->assertNull($mapping->getParam('_boost', $all));
+
+ $this->assertEquals($properties, $mapping->getProperties());
+
+ $index->delete();
+ }
+}
diff --git a/vendor/ruflin/elastica/test/lib/Elastica/Test/TypeTest.php b/vendor/ruflin/elastica/test/lib/Elastica/Test/TypeTest.php
new file mode 100644
index 00000000..dcb74ac5
--- /dev/null
+++ b/vendor/ruflin/elastica/test/lib/Elastica/Test/TypeTest.php
@@ -0,0 +1,968 @@
+<?php
+namespace Elastica\Test;
+
+use Elastica\Document;
+use Elastica\Exception\NotFoundException;
+use Elastica\Exception\ResponseException;
+use Elastica\Filter\Term;
+use Elastica\Index;
+use Elastica\Query;
+use Elastica\Query\MatchAll;
+use Elastica\Query\SimpleQueryString;
+use Elastica\Script;
+use Elastica\Search;
+use Elastica\Test\Base as BaseTest;
+use Elastica\Type;
+use Elastica\Type\Mapping;
+
+class TypeTest extends BaseTest
+{
+ /**
+ * @group functional
+ */
+ public function testSearch()
+ {
+ $index = $this->_createIndex();
+
+ $type = new Type($index, 'user');
+
+ // Adds 1 document to the index
+ $doc1 = new Document(1,
+ array('username' => 'hans', 'test' => array('2', '3', '5'))
+ );
+ $type->addDocument($doc1);
+
+ // Adds a list of documents with _bulk upload to the index
+ $docs = array();
+ $docs[] = new Document(2,
+ array('username' => 'john', 'test' => array('1', '3', '6'))
+ );
+ $docs[] = new Document(3,
+ array('username' => 'rolf', 'test' => array('2', '3', '7'))
+ );
+ $type->addDocuments($docs);
+ $index->refresh();
+
+ $resultSet = $type->search('rolf');
+ $this->assertEquals(1, $resultSet->count());
+
+ $count = $type->count('rolf');
+ $this->assertEquals(1, $count);
+
+ // Test if source is returned
+ $result = $resultSet->current();
+ $this->assertEquals(3, $result->getId());
+ $data = $result->getData();
+ $this->assertEquals('rolf', $data['username']);
+ }
+
+ /**
+ * @group functional
+ */
+ public function testCreateSearch()
+ {
+ $client = $this->_getClient();
+ $index = new Index($client, 'test_index');
+ $type = new Type($index, 'test_type');
+
+ $query = new Query\QueryString('test');
+ $options = array(
+ 'limit' => 5,
+ 'explain' => true,
+ );
+
+ $search = $type->createSearch($query, $options);
+
+ $expected = array(
+ 'query' => array(
+ 'query_string' => array(
+ 'query' => 'test',
+ ),
+ ),
+ 'size' => 5,
+ 'explain' => true,
+ );
+ $this->assertEquals($expected, $search->getQuery()->toArray());
+ $this->assertEquals(array('test_index'), $search->getIndices());
+ $this->assertTrue($search->hasIndices());
+ $this->assertTrue($search->hasIndex($index));
+ $this->assertTrue($search->hasIndex('test_index'));
+ $this->assertFalse($search->hasIndex('test'));
+ $this->assertEquals(array('test_type'), $search->getTypes());
+ $this->assertTrue($search->hasTypes());
+ $this->assertTrue($search->hasType($type));
+ $this->assertTrue($search->hasType('test_type'));
+ $this->assertFalse($search->hasType('test_type2'));
+ }
+
+ /**
+ * @group functional
+ */
+ public function testCreateSearchWithArray()
+ {
+ $client = $this->_getClient();
+ $index = new Index($client, 'test_index');
+ $type = new Type($index, 'test_type');
+
+ $query = array(
+ 'query' => array(
+ 'query_string' => array(
+ 'query' => 'test',
+ ),
+ ),
+ );
+
+ $options = array(
+ 'limit' => 5,
+ 'explain' => true,
+ );
+
+ $search = $type->createSearch($query, $options);
+
+ $expected = array(
+ 'query' => array(
+ 'query_string' => array(
+ 'query' => 'test',
+ ),
+ ),
+ 'size' => 5,
+ 'explain' => true,
+ );
+ $this->assertEquals($expected, $search->getQuery()->toArray());
+ $this->assertEquals(array('test_index'), $search->getIndices());
+ $this->assertTrue($search->hasIndices());
+ $this->assertTrue($search->hasIndex($index));
+ $this->assertTrue($search->hasIndex('test_index'));
+ $this->assertFalse($search->hasIndex('test'));
+ $this->assertEquals(array('test_type'), $search->getTypes());
+ $this->assertTrue($search->hasTypes());
+ $this->assertTrue($search->hasType($type));
+ $this->assertTrue($search->hasType('test_type'));
+ $this->assertFalse($search->hasType('test_type2'));
+ }
+
+ /**
+ * @group functional
+ */
+ public function testNoSource()
+ {
+ $index = $this->_createIndex();
+
+ $type = new Type($index, 'user');
+ $mapping = new Mapping($type, array(
+ 'id' => array('type' => 'integer', 'store' => 'yes'),
+ 'username' => array('type' => 'string', 'store' => 'no'),
+ ));
+ $mapping->setSource(array('enabled' => false));
+ $type->setMapping($mapping);
+
+ $mapping = $type->getMapping();
+
+ $this->assertArrayHasKey('user', $mapping);
+ $this->assertArrayHasKey('properties', $mapping['user']);
+ $this->assertArrayHasKey('id', $mapping['user']['properties']);
+ $this->assertArrayHasKey('type', $mapping['user']['properties']['id']);
+ $this->assertEquals('integer', $mapping['user']['properties']['id']['type']);
+
+ // Adds 1 document to the index
+ $doc1 = new Document(1,
+ array('username' => 'hans', 'test' => array('2', '3', '5'))
+ );
+ $type->addDocument($doc1);
+
+ // Adds a list of documents with _bulk upload to the index
+ $docs = array();
+ $docs[] = new Document(2,
+ array('username' => 'john', 'test' => array('1', '3', '6'))
+ );
+ $docs[] = new Document(3,
+ array('username' => 'rolf', 'test' => array('2', '3', '7'))
+ );
+ $type->addDocuments($docs);
+
+ // To update index
+ $index->refresh();
+
+ $resultSet = $type->search('rolf');
+
+ $this->assertEquals(1, $resultSet->count());
+
+ // Tests if no source is in response except id
+ $result = $resultSet->current();
+ $this->assertEquals(3, $result->getId());
+ $this->assertEmpty($result->getData());
+ }
+
+ /**
+ * @group functional
+ */
+ public function testDeleteById()
+ {
+ $index = $this->_createIndex();
+ $type = new Type($index, 'user');
+
+ // Adds hans, john and rolf to the index
+ $docs = array(
+ new Document(1, array('username' => 'hans', 'test' => array('2', '3', '5'))),
+ new Document(2, array('username' => 'john', 'test' => array('1', '3', '6'))),
+ new Document(3, array('username' => 'rolf', 'test' => array('2', '3', '7'))),
+ new Document('foo/bar', array('username' => 'georg', 'test' => array('4', '2', '5'))),
+ );
+ $type->addDocuments($docs);
+ $index->refresh();
+
+ // sanity check for rolf
+ $resultSet = $type->search('rolf');
+ $this->assertEquals(1, $resultSet->count());
+ $data = $resultSet->current()->getData();
+ $this->assertEquals('rolf', $data['username']);
+
+ // delete rolf
+ $type->deleteById(3);
+ $index->refresh();
+
+ // rolf should no longer be there
+ $resultSet = $type->search('rolf');
+ $this->assertEquals(0, $resultSet->count());
+
+ // sanity check for id with slash
+ $resultSet = $type->search('georg');
+ $this->assertEquals(1, $resultSet->count());
+
+ // delete georg
+ $type->deleteById('foo/bar');
+ $index->refresh();
+
+ // georg should no longer be there
+ $resultSet = $type->search('georg');
+ $this->assertEquals(0, $resultSet->count());
+
+ // it should not be possible to delete the entire type with this method
+ try {
+ $type->deleteById('');
+ $this->fail('Delete with empty string id should fail');
+ } catch (\InvalidArgumentException $e) {
+ $this->assertTrue(true);
+ }
+
+ try {
+ $type->deleteById(' ');
+ $this->fail('Delete with one space string id should fail');
+ } catch (\InvalidArgumentException $e) {
+ $this->assertTrue(true);
+ }
+
+ try {
+ $type->deleteById(null);
+ $this->fail('Delete with null id should fail');
+ } catch (\InvalidArgumentException $e) {
+ $this->assertTrue(true);
+ }
+
+ try {
+ $type->deleteById(array());
+ $this->fail('Delete with empty array id should fail');
+ } catch (\InvalidArgumentException $e) {
+ $this->assertTrue(true);
+ }
+
+ try {
+ $type->deleteById('*');
+ $this->fail('Delete request should fail because of invalid id: *');
+ } catch (NotFoundException $e) {
+ $this->assertTrue(true);
+ }
+
+ try {
+ $type->deleteById('*:*');
+ $this->fail('Delete request should fail because document with id *.* does not exist');
+ } catch (NotFoundException $e) {
+ $this->assertTrue(true);
+ }
+
+ try {
+ $type->deleteById('!');
+ $this->fail('Delete request should fail because document with id ! does not exist');
+ } catch (NotFoundException $e) {
+ $this->assertTrue(true);
+ }
+
+ $index->refresh();
+
+ // rolf should no longer be there
+ $resultSet = $type->search('john');
+ $this->assertEquals(1, $resultSet->count());
+ }
+
+ /**
+ * @group functional
+ */
+ public function testDeleteDocument()
+ {
+ $index = $this->_createIndex();
+ $type = new Type($index, 'user');
+
+ // Adds hans, john and rolf to the index
+ $docs = array(
+ new Document(1, array('username' => 'hans', 'test' => array('2', '3', '5'))),
+ new Document(2, array('username' => 'john', 'test' => array('1', '3', '6'))),
+ new Document(3, array('username' => 'rolf', 'test' => array('2', '3', '7'))),
+ );
+ $type->addDocuments($docs);
+ $index->refresh();
+
+ $document = $type->getDocument(1);
+ $this->assertEquals(1, $document->getId());
+ $this->assertEquals('hans', $document->get('username'));
+
+ $this->assertEquals(3, $type->count());
+
+ $type->deleteDocument($document);
+ $index->refresh();
+
+ try {
+ $type->getDocument(1);
+ $this->fail('Document was not deleted');
+ } catch (NotFoundException $e) {
+ $this->assertTrue(true);
+ $this->assertEquals(2, $type->count(), 'Documents count in type should be 2');
+ }
+ }
+
+ /**
+ * @group functional
+ * @expectedException \Elastica\Exception\NotFoundException
+ */
+ public function testGetDocumentNotExist()
+ {
+ $index = $this->_createIndex();
+ $type = new Type($index, 'test');
+ $type->addDocument(new Document(1, array('name' => 'ruflin')));
+ $index->refresh();
+
+ $type->getDocument(1);
+
+ $type->getDocument(2);
+ }
+
+ /**
+ * @group functional
+ * @expectedException \Elastica\Exception\ResponseException
+ */
+ public function testGetDocumentNotExistingIndex()
+ {
+ $client = $this->_getClient();
+ $index = new Index($client, 'index');
+ $type = new Type($index, 'type');
+
+ $type->getDocument(1);
+ }
+
+ /**
+ * @group functional
+ */
+ public function testDeleteByQueryWithQueryString()
+ {
+ $index = $this->_createIndex();
+ $type = new Type($index, 'test');
+ $type->addDocument(new Document(1, array('name' => 'ruflin nicolas')));
+ $type->addDocument(new Document(2, array('name' => 'ruflin')));
+ $index->refresh();
+
+ $response = $index->search('ruflin*');
+ $this->assertEquals(2, $response->count());
+
+ $response = $index->search('nicolas');
+ $this->assertEquals(1, $response->count());
+
+ // Delete first document
+ $response = $type->deleteByQuery('nicolas');
+ $this->assertTrue($response->isOk());
+
+ $index->refresh();
+
+ // Makes sure, document is deleted
+ $response = $index->search('ruflin*');
+ $this->assertEquals(1, $response->count());
+
+ $response = $index->search('nicolas');
+ $this->assertEquals(0, $response->count());
+ }
+
+ /**
+ * @group functional
+ */
+ public function testDeleteByQueryWithQuery()
+ {
+ $index = $this->_createIndex();
+ $type = new Type($index, 'test');
+ $type->addDocument(new Document(1, array('name' => 'ruflin nicolas')));
+ $type->addDocument(new Document(2, array('name' => 'ruflin')));
+ $index->refresh();
+
+ $response = $index->search('ruflin*');
+ $this->assertEquals(2, $response->count());
+
+ $response = $index->search('nicolas');
+ $this->assertEquals(1, $response->count());
+
+ // Delete first document
+ $response = $type->deleteByQuery(new SimpleQueryString('nicolas'));
+ $this->assertTrue($response->isOk());
+
+ $index->refresh();
+
+ // Makes sure, document is deleted
+ $response = $index->search('ruflin*');
+ $this->assertEquals(1, $response->count());
+
+ $response = $index->search('nicolas');
+ $this->assertEquals(0, $response->count());
+ }
+
+ /**
+ * @group functional
+ */
+ public function testDeleteByQueryWithQueryAndOptions()
+ {
+ $index = $this->_createIndex(null, true, 2);
+ $type = new Type($index, 'test');
+ $type->addDocument(new Document(1, array('name' => 'ruflin nicolas')));
+ $type->addDocument(new Document(2, array('name' => 'ruflin')));
+ $index->refresh();
+
+ $response = $index->search('ruflin*');
+ $this->assertEquals(2, $response->count());
+
+ $response = $index->search('nicolas');
+ $this->assertEquals(1, $response->count());
+
+ // Route to the wrong document id; should not delete
+ $response = $type->deleteByQuery(new SimpleQueryString('nicolas'), array('routing' => '2'));
+ $this->assertTrue($response->isOk());
+
+ $index->refresh();
+
+ $response = $index->search('ruflin*');
+ $this->assertEquals(2, $response->count());
+
+ $response = $index->search('nicolas');
+ $this->assertEquals(1, $response->count());
+
+ // Delete first document
+ $response = $type->deleteByQuery(new SimpleQueryString('nicolas'), array('routing' => '1'));
+ $this->assertTrue($response->isOk());
+
+ $index->refresh();
+
+ // Makes sure, document is deleted
+ $response = $index->search('ruflin*');
+ $this->assertEquals(1, $response->count());
+
+ $response = $index->search('nicolas');
+ $this->assertEquals(0, $response->count());
+ }
+
+ /**
+ * Test to see if Elastica_Type::getDocument() is properly using
+ * the fields array when available instead of _source.
+ *
+ * @group functional
+ */
+ public function testGetDocumentWithFieldsSelection()
+ {
+ $index = $this->_createIndex();
+ $type = new Type($index, 'test');
+ $type->addDocument(new Document(1, array('name' => 'loris', 'country' => 'FR', 'email' => 'test@test.com')));
+ $index->refresh();
+
+ $document = $type->getDocument(1, array('fields' => 'name,email'));
+ $data = $document->getData();
+
+ $this->assertArrayHasKey('name', $data);
+ $this->assertArrayHasKey('email', $data);
+ $this->assertArrayNotHasKey('country', $data);
+ }
+
+ /**
+ * Test to see if search Default Limit works.
+ *
+ * @group functional
+ */
+ public function testLimitDefaultType()
+ {
+ $client = $this->_getClient();
+ $index = $client->getIndex('zero');
+ $index->create(array('index' => array('number_of_shards' => 1, 'number_of_replicas' => 0)), true);
+
+ $docs = array();
+ $docs[] = new Document(1, array('id' => 1, 'email' => 'test@test.com', 'username' => 'farrelley'));
+ $docs[] = new Document(2, array('id' => 1, 'email' => 'test@test.com', 'username' => 'farrelley'));
+ $docs[] = new Document(3, array('id' => 1, 'email' => 'test@test.com', 'username' => 'farrelley'));
+ $docs[] = new Document(4, array('id' => 1, 'email' => 'test@test.com', 'username' => 'farrelley'));
+ $docs[] = new Document(5, array('id' => 1, 'email' => 'test@test.com', 'username' => 'farrelley'));
+ $docs[] = new Document(6, array('id' => 1, 'email' => 'test@test.com', 'username' => 'farrelley'));
+ $docs[] = new Document(7, array('id' => 1, 'email' => 'test@test.com', 'username' => 'farrelley'));
+ $docs[] = new Document(8, array('id' => 1, 'email' => 'test@test.com', 'username' => 'farrelley'));
+ $docs[] = new Document(9, array('id' => 1, 'email' => 'test@test.com', 'username' => 'farrelley'));
+ $docs[] = new Document(10, array('id' => 1, 'email' => 'test@test.com', 'username' => 'farrelley'));
+ $docs[] = new Document(11, array('id' => 1, 'email' => 'test@test.com', 'username' => 'farrelley'));
+
+ $type = $index->getType('zeroType');
+ $type->addDocuments($docs);
+ $index->refresh();
+
+ // default results (limit default is 10)
+ $resultSet = $type->search('farrelley');
+ $this->assertEquals(10, $resultSet->count());
+
+ // limit = 1
+ $resultSet = $type->search('farrelley', 1);
+ $this->assertEquals(1, $resultSet->count());
+ }
+
+ /**
+ * Test Delete of index type. After delete will check for type mapping.
+ *
+ * @group functional
+ */
+ public function testDeleteType()
+ {
+ $index = $this->_createIndex();
+ $type = new Type($index, 'test');
+ $type->addDocuments(array(
+ new Document(1, array('name' => 'ruflin nicolas')),
+ new Document(2, array('name' => 'ruflin')),
+ ));
+ $index->refresh();
+
+ // sleep a moment to be sure that all nodes in cluster has new type
+ sleep(5);
+
+ $type->delete();
+ $index->optimize();
+
+ $this->assertFalse($type->exists());
+ }
+
+ /**
+ * @group functional
+ */
+ public function testMoreLikeThisApi()
+ {
+ $client = $this->_getClient(array('persistent' => false));
+ $index = $client->getIndex('elastica_test');
+ $index->create(array('index' => array('number_of_shards' => 1, 'number_of_replicas' => 0)), true);
+
+ $type = new Type($index, 'mlt_test');
+ $type->addDocuments(array(
+ new Document(1, array('visible' => true, 'name' => 'bruce wayne batman')),
+ new Document(2, array('visible' => true, 'name' => 'bruce wayne')),
+ new Document(3, array('visible' => false, 'name' => 'bruce wayne')),
+ new Document(4, array('visible' => true, 'name' => 'batman')),
+ new Document(5, array('visible' => false, 'name' => 'batman')),
+ new Document(6, array('visible' => true, 'name' => 'superman')),
+ new Document(7, array('visible' => true, 'name' => 'spiderman')),
+ ));
+ $index->refresh();
+
+ $document = $type->getDocument(1);
+
+ // Return all similar
+ $resultSet = $type->moreLikeThis($document, array('min_term_freq' => '1', 'min_doc_freq' => '1'));
+ $this->assertEquals(4, $resultSet->count());
+
+ // Return just the visible similar
+ $query = new Query();
+ $filterTerm = new Term();
+ $filterTerm->setTerm('visible', true);
+ $query->setPostFilter($filterTerm);
+
+ $resultSet = $type->moreLikeThis($document, array('min_term_freq' => '1', 'min_doc_freq' => '1'), $query);
+ $this->assertEquals(2, $resultSet->count());
+ }
+
+ /**
+ * @group functional
+ */
+ public function testUpdateDocument()
+ {
+ $client = $this->_getClient();
+ $index = $client->getIndex('elastica_test');
+ $type = $index->getType('update_type');
+ $id = 1;
+ $type->addDocument(new Document($id, array('name' => 'bruce wayne batman', 'counter' => 1)));
+ $newName = 'batman';
+
+ $document = new Document();
+ $script = new Script(
+ 'ctx._source.name = name; ctx._source.counter += count',
+ array(
+ 'name' => $newName,
+ 'count' => 2,
+ ),
+ null,
+ $id
+ );
+ $script->setUpsert($document);
+
+ $type->updateDocument($script, array('refresh' => true));
+ $updatedDoc = $type->getDocument($id)->getData();
+ $this->assertEquals($newName, $updatedDoc['name'], 'Name was not updated');
+ $this->assertEquals(3, $updatedDoc['counter'], 'Counter was not incremented');
+ }
+
+ /**
+ * @group functional
+ */
+ public function testUpdateDocumentWithIdForwardSlashes()
+ {
+ $client = $this->_getClient();
+ $index = $client->getIndex('elastica_test');
+ $type = $index->getType('update_type');
+ $id = '/id/with/forward/slashes';
+ $type->addDocument(new Document($id, array('name' => 'bruce wayne batman', 'counter' => 1)));
+ $newName = 'batman';
+
+ $document = new Document();
+ $script = new Script(
+ 'ctx._source.name = name; ctx._source.counter += count',
+ array(
+ 'name' => $newName,
+ 'count' => 2,
+ ),
+ null,
+ $id
+ );
+ $script->setUpsert($document);
+
+ $type->updateDocument($script, array('refresh' => true));
+ $updatedDoc = $type->getDocument($id)->getData();
+ $this->assertEquals($newName, $updatedDoc['name'], 'Name was not updated');
+ $this->assertEquals(3, $updatedDoc['counter'], 'Counter was not incremented');
+ }
+
+ /**
+ * @group functional
+ */
+ public function testUpdateDocumentWithParameter()
+ {
+ $client = $this->_getClient();
+ $index = $client->getIndex('elastica_test');
+ $type = $index->getType('update_type');
+ $id = 1;
+ $type->addDocument(new Document($id, array('name' => 'bruce wayne batman', 'counter' => 1)));
+ $newName = 'batman';
+
+ $document = new Document();
+ $script = new Script(
+ 'ctx._source.name = name; ctx._source.counter += count',
+ array(
+ 'name' => $newName,
+ 'count' => 2,
+ ),
+ null,
+ $id
+ );
+ $script->setUpsert($document);
+
+ try {
+ $type->updateDocument($script, array('version' => 999)); // Wrong version number to make the update fail
+ } catch (ResponseException $e) {
+ $this->assertContains('VersionConflictEngineException', $e->getMessage());
+ }
+ $updatedDoc = $type->getDocument($id)->getData();
+ $this->assertNotEquals($newName, $updatedDoc['name'], 'Name was updated');
+ $this->assertNotEquals(3, $updatedDoc['counter'], 'Counter was incremented');
+ }
+
+ /**
+ * @group functional
+ */
+ public function testUpdateDocumentWithFieldsSource()
+ {
+ $client = $this->_getClient();
+ $index = $client->getIndex('elastica_test');
+ $type = $index->getType('update_type');
+
+ $client->setConfigValue('document', array('autoPopulate' => true));
+
+ $newDocument = new Document(null, array('counter' => 5, 'name' => 'Batman'));
+
+ $this->assertFalse($newDocument->hasVersion());
+
+ $response = $type->addDocument($newDocument);
+ $responseData = $response->getData();
+
+ $this->assertTrue($newDocument->hasVersion());
+ $this->assertArrayHasKey('_version', $responseData, '_version is missing in response data it is weird');
+ $this->assertEquals(1, $responseData['_version']);
+ $this->assertEquals($responseData['_version'], $newDocument->getVersion());
+
+ $this->assertTrue($newDocument->hasId());
+
+ $script = new Script('ctx._source.counter += count; ctx._source.realName = realName');
+ $script->setId($newDocument->getId());
+ $script->setParam('count', 7);
+ $script->setParam('realName', 'Bruce Wayne');
+ $script->setUpsert($newDocument);
+
+ $newDocument->setFieldsSource();
+
+ $response = $type->updateDocument($script);
+ $responseData = $response->getData();
+
+ $data = $type->getDocument($newDocument->getId())->getData();
+
+ $this->assertEquals(12, $data['counter']);
+ $this->assertEquals('Batman', $data['name']);
+ $this->assertEquals('Bruce Wayne', $data['realName']);
+
+ $this->assertTrue($newDocument->hasVersion());
+ $this->assertArrayHasKey('_version', $responseData, '_version is missing in response data it is weird');
+ $this->assertEquals(2, $responseData['_version']);
+
+ $document = $type->getDocument($newDocument->getId());
+ }
+
+ /**
+ * @group functional
+ * @expectedException \Elastica\Exception\InvalidException
+ */
+ public function testUpdateDocumentWithoutId()
+ {
+ $index = $this->_createIndex();
+ $this->_waitForAllocation($index);
+ $type = $index->getType('elastica_type');
+
+ $document = new Document();
+
+ $type->updateDocument($document);
+ }
+
+ /**
+ * @group functional
+ */
+ public function testUpdateDocumentWithoutSource()
+ {
+ $index = $this->_createIndex();
+ $type = $index->getType('elastica_type');
+
+ $mapping = new Mapping();
+ $mapping->setProperties(array(
+ 'name' => array(
+ 'type' => 'string',
+ 'store' => 'yes', ),
+ 'counter' => array(
+ 'type' => 'integer',
+ 'store' => 'no',
+ ),
+ ));
+ $mapping->disableSource();
+ $type->setMapping($mapping);
+
+ $newDocument = new Document();
+ $newDocument->setAutoPopulate();
+ $newDocument->set('name', 'Batman');
+ $newDocument->set('counter', 1);
+
+ $type->addDocument($newDocument);
+
+ $script = new Script('ctx._source.counter += count; ctx._source.name = name');
+ $script->setId($newDocument->getId());
+ $script->setParam('count', 2);
+ $script->setParam('name', 'robin');
+
+ $script->setUpsert($newDocument);
+
+ try {
+ $type->updateDocument($script);
+ $this->fail('Update request should fail because source is disabled. Fields param is not set');
+ } catch (ResponseException $e) {
+ $this->assertContains('DocumentSourceMissingException', $e->getMessage());
+ }
+
+ $newDocument->setFieldsSource();
+
+ try {
+ $type->updateDocument($newDocument);
+ $this->fail('Update request should fail because source is disabled. Fields param is set to _source');
+ } catch (ResponseException $e) {
+ $this->assertContains('DocumentSourceMissingException', $e->getMessage());
+ }
+ }
+
+ /**
+ * @group functional
+ */
+ public function testAddDocumentHashId()
+ {
+ $index = $this->_createIndex();
+ $type = $index->getType('test2');
+
+ $hashId = '#1';
+
+ $doc = new Document($hashId, array('name' => 'ruflin'));
+ $type->addDocument($doc);
+
+ $index->refresh();
+
+ $search = new Search($index->getClient());
+ $search->addIndex($index);
+ $resultSet = $search->search(new MatchAll());
+ $this->assertEquals($hashId, $resultSet->current()->getId());
+
+ $doc = $type->getDocument($hashId);
+ $this->assertEquals($hashId, $doc->getId());
+ }
+
+ /**
+ * @group functional
+ */
+ public function testAddDocumentAutoGeneratedId()
+ {
+ $index = $this->_createIndex();
+ $type = $index->getType('elastica_type');
+
+ $document = new Document();
+ $document->setAutoPopulate();
+ $document->set('name', 'ruflin');
+ $this->assertEquals('', $document->getId());
+ $this->assertFalse($document->hasId());
+
+ $type->addDocument($document);
+
+ $this->assertNotEquals('', $document->getId());
+ $this->assertTrue($document->hasId());
+
+ $foundDoc = $type->getDocument($document->getId());
+ $this->assertInstanceOf('Elastica\Document', $foundDoc);
+ $this->assertEquals($document->getId(), $foundDoc->getId());
+ $data = $foundDoc->getData();
+ $this->assertArrayHasKey('name', $data);
+ $this->assertEquals('ruflin', $data['name']);
+ }
+
+ /**
+ * @group functional
+ * @expectedException \Elastica\Exception\RuntimeException
+ */
+ public function testAddDocumentWithoutSerializer()
+ {
+ $index = $this->_createIndex();
+ $this->_waitForAllocation($index);
+
+ $type = new Type($index, 'user');
+
+ $type->addObject(new \stdClass());
+ }
+
+ /**
+ * @group functional
+ */
+ public function testAddObject()
+ {
+ $index = $this->_createIndex();
+
+ $type = new Type($index, 'user');
+ $type->setSerializer('get_object_vars');
+
+ $userObject = new \stdClass();
+ $userObject->username = 'hans';
+ $userObject->test = array('2', '3', '5');
+
+ $type->addObject($userObject);
+
+ $index->refresh();
+
+ $resultSet = $type->search('hans');
+ $this->assertEquals(1, $resultSet->count());
+
+ // Test if source is returned
+ $result = $resultSet->current();
+ $data = $result->getData();
+ $this->assertEquals('hans', $data['username']);
+ }
+
+ /**
+ * @group unit
+ */
+ public function testSetSerializer()
+ {
+ $index = $this->_getClient()->getIndex('foo');
+ $type = $index->getType('user');
+ $ret = $type->setSerializer('get_object_vars');
+ $this->assertInstanceOf('Elastica\Type', $ret);
+ }
+
+ /**
+ * @group functional
+ */
+ public function testExists()
+ {
+ $index = $this->_createIndex();
+ $this->assertTrue($index->exists());
+
+ $type = new Type($index, 'user');
+ $this->assertFalse($type->exists());
+
+ $type->addDocument(new Document(1, array('name' => 'test name')));
+ $index->optimize();
+
+ // sleep a moment to be sure that all nodes in cluster has new type
+ sleep(5);
+
+ //Test if type exists
+ $this->assertTrue($type->exists());
+
+ $index->delete();
+ $this->assertFalse($index->exists());
+ }
+
+ /**
+ * @group functional
+ */
+ public function testGetMapping()
+ {
+ $typeName = 'test-type';
+
+ $index = $this->_createIndex();
+ $indexName = $index->getName();
+ $type = new Type($index, $typeName);
+ $mapping = new Mapping($type, $expect = array(
+ 'id' => array('type' => 'integer', 'store' => true),
+ ));
+ $type->setMapping($mapping);
+
+ $client = $index->getClient();
+
+ $this->assertEquals(
+ array('test-type' => array('properties' => $expect)),
+ $client->getIndex($indexName)->getType($typeName)->getMapping()
+ );
+ }
+
+ /**
+ * @group functional
+ */
+ public function testGetMappingAlias()
+ {
+ $aliasName = 'test-alias';
+ $typeName = 'test-alias-type';
+
+ $index = $this->_createIndex();
+ $index->addAlias($aliasName);
+ $type = new Type($index, $typeName);
+ $mapping = new Mapping($type, $expect = array(
+ 'id' => array('type' => 'integer', 'store' => true),
+ ));
+ $type->setMapping($mapping);
+
+ $client = $index->getClient();
+
+ $this->assertEquals(
+ array('test-alias-type' => array('properties' => $expect)),
+ $client->getIndex($aliasName)->getType($typeName)->getMapping()
+ );
+ }
+}
diff --git a/vendor/ruflin/elastica/test/lib/Elastica/Test/UtilTest.php b/vendor/ruflin/elastica/test/lib/Elastica/Test/UtilTest.php
new file mode 100644
index 00000000..a5b0f42e
--- /dev/null
+++ b/vendor/ruflin/elastica/test/lib/Elastica/Test/UtilTest.php
@@ -0,0 +1,139 @@
+<?php
+namespace Elastica\Test;
+
+use Elastica\Connection;
+use Elastica\Request;
+use Elastica\Test\Base as BaseTest;
+use Elastica\Util;
+
+class UtilTest extends BaseTest
+{
+ /**
+ * @group unit
+ * @dataProvider getEscapeTermPairs
+ */
+ public function testEscapeTerm($unescaped, $escaped)
+ {
+ $this->assertEquals($escaped, Util::escapeTerm($unescaped));
+ }
+
+ public function getEscapeTermPairs()
+ {
+ return array(
+ array('', ''),
+ array('pragmatic banana', 'pragmatic banana'),
+ array('oh yeah!', 'oh yeah\\!'),
+ // Seperate test below because phpunit seems to have some problems
+ //array('\\+-&&||!(){}[]^"~*?:', '\\\\\\+\\-\\&&\\||\\!\\(\\)\\{\\}\\[\\]\\^\\"\\~\\*\\?\\:'),
+ array('some signs, can stay.', 'some signs, can stay.'),
+ );
+ }
+
+ /**
+ * @group unit
+ * @dataProvider getReplaceBooleanWordsPairs
+ */
+ public function testReplaceBooleanWords($before, $after)
+ {
+ $this->assertEquals($after, Util::replaceBooleanWords($before));
+ }
+
+ public function getReplaceBooleanWordsPairs()
+ {
+ return array(
+ array('to be OR not to be', 'to be || not to be'),
+ array('ORIGINAL GIFTS', 'ORIGINAL GIFTS'),
+ array('Black AND White', 'Black && White'),
+ array('TIMBERLAND Men`s', 'TIMBERLAND Men`s'),
+ array('hello NOT kitty', 'hello !kitty'),
+ array('SEND NOTIFICATION', 'SEND NOTIFICATION'),
+ );
+ }
+
+ /**
+ * @group unit
+ */
+ public function testEscapeTermSpecialCharacters()
+ {
+ $before = '\\+-&&||!(){}[]^"~*?:/<>';
+ $after = '\\\\\\+\\-\\&&\\||\\!\\(\\)\\{\\}\\[\\]\\^\\"\\~\\*\\?\\:\\/\<\>';
+
+ $this->assertEquals(Util::escapeTerm($before), $after);
+ }
+
+ /**
+ * @group unit
+ */
+ public function testToCamelCase()
+ {
+ $string = 'hello_world';
+ $this->assertEquals('HelloWorld', Util::toCamelCase($string));
+
+ $string = 'how_are_you_today';
+ $this->assertEquals('HowAreYouToday', Util::toCamelCase($string));
+ }
+
+ /**
+ * @group unit
+ */
+ public function testToSnakeCase()
+ {
+ $string = 'HelloWorld';
+ $this->assertEquals('hello_world', Util::toSnakeCase($string));
+
+ $string = 'HowAreYouToday';
+ $this->assertEquals('how_are_you_today', Util::toSnakeCase($string));
+ }
+
+ /**
+ * @group unit
+ */
+ public function testConvertRequestToCurlCommand()
+ {
+ $path = 'test';
+ $method = Request::POST;
+ $query = array('no' => 'params');
+ $data = array('key' => 'value');
+
+ $connection = new Connection();
+ $connection->setHost($this->_getHost());
+ $connection->setPort('9200');
+
+ $request = new Request($path, $method, $data, $query, $connection);
+
+ $curlCommand = Util::convertRequestToCurlCommand($request);
+
+ $expected = 'curl -XPOST \'http://'.$this->_getHost().':9200/test?no=params\' -d \'{"key":"value"}\'';
+ $this->assertEquals($expected, $curlCommand);
+ }
+
+ /**
+ * @group unit
+ */
+ public function testConvertDateTimeObjectWithTimezone()
+ {
+ $dateTimeObject = new \DateTime();
+ $timestamp = $dateTimeObject->getTimestamp();
+
+ $convertedString = Util::convertDateTimeObject($dateTimeObject);
+
+ $date = date('Y-m-d\TH:i:sP', $timestamp);
+
+ $this->assertEquals($convertedString, $date);
+ }
+
+ /**
+ * @group unit
+ */
+ public function testConvertDateTimeObjectWithoutTimezone()
+ {
+ $dateTimeObject = new \DateTime();
+ $timestamp = $dateTimeObject->getTimestamp();
+
+ $convertedString = Util::convertDateTimeObject($dateTimeObject, false);
+
+ $date = date('Y-m-d\TH:i:s\Z', $timestamp);
+
+ $this->assertEquals($convertedString, $date);
+ }
+}
diff --git a/vendor/ruflin/elastica/test/phpunit.xhprof.xml b/vendor/ruflin/elastica/test/phpunit.xhprof.xml
new file mode 100644
index 00000000..59878cc2
--- /dev/null
+++ b/vendor/ruflin/elastica/test/phpunit.xhprof.xml
@@ -0,0 +1,39 @@
+<phpunit backupGlobals="false"
+ backupStaticAttributes="true"
+ bootstrap="../bootstrap.php"
+ colors="true">
+ <testsuites>
+ <testsuite name="Transport">
+ <file>lib/Elastica/Test/Transport/TransportBenchmarkTest.php</file>
+ </testsuite>
+ </testsuites>
+ <listeners>
+ <listener class="PHPUnit_Util_Log_XHProf" file="/home/munkie/Projects/phpunit-testlistener-xhprof/PHPUnit/Util/Log/XHProf.php">
+ <arguments>
+ <array>
+ <element key="xhprofLibFile">
+ <string>/var/www/xhprof/xhprof_lib/utils/xhprof_lib.php</string>
+ </element>
+ <element key="xhprofRunsFile">
+ <string>/var/www/xhprof/xhprof_lib/utils/xhprof_runs.php</string>
+ </element>
+ <element key="xhprofWeb">
+ <string>http://xhprof.local/</string>
+ </element>
+ <element key="appNamespace">
+ <string>Elastica</string>
+ </element>
+ <element key="xhprofFlags">
+ <string>XHPROF_FLAGS_CPU,XHPROF_FLAGS_MEMORY</string>
+ </element>
+ <element key="xhprofConfigFile">
+ <string>/var/www/xhprof/xhprof_lib/config.php</string>
+ </element>
+ <element key="xhprofIgnore">
+ <string>call_user_func,call_user_func_array</string>
+ </element>
+ </array>
+ </arguments>
+ </listener>
+ </listeners>
+</phpunit>
diff --git a/vendor/ruflin/elastica/test/phpunit.xml.dist b/vendor/ruflin/elastica/test/phpunit.xml.dist
new file mode 100644
index 00000000..51993e0a
--- /dev/null
+++ b/vendor/ruflin/elastica/test/phpunit.xml.dist
@@ -0,0 +1,27 @@
+<?xml version="1.0"?>
+<phpunit
+ backupGlobals="false"
+ backupStaticAttributes="false"
+ bootstrap="./bootstrap.php"
+ convertErrorsToExceptions="true"
+ convertNoticesToExceptions="true"
+ convertWarningsToExceptions="true"
+ processIsolation="false"
+ stopOnError="false"
+ stopOnFailure="false"
+ stopOnIncomplete="false"
+ stopOnSkipped="false"
+ syntaxCheck="false"
+ verbose="true"
+ >
+ <filter>
+ <whitelist>
+ <directory suffix=".php">../lib/</directory>
+ </whitelist>
+ </filter>
+ <testsuites>
+ <testsuite name="default">
+ <directory>./lib/Elastica/</directory>
+ </testsuite>
+ </testsuites>
+</phpunit>
diff --git a/vendor/symfony/process/CHANGELOG.md b/vendor/symfony/process/CHANGELOG.md
new file mode 100644
index 00000000..2f3c1beb
--- /dev/null
+++ b/vendor/symfony/process/CHANGELOG.md
@@ -0,0 +1,40 @@
+CHANGELOG
+=========
+
+2.5.0
+-----
+
+ * added support for PTY mode
+ * added the convenience method "mustRun"
+ * deprecation: Process::setStdin() is deprecated in favor of Process::setInput()
+ * deprecation: Process::getStdin() is deprecated in favor of Process::getInput()
+ * deprecation: Process::setInput() and ProcessBuilder::setInput() do not accept non-scalar types
+
+2.4.0
+-----
+
+ * added the ability to define an idle timeout
+
+2.3.0
+-----
+
+ * added ProcessUtils::escapeArgument() to fix the bug in escapeshellarg() function on Windows
+ * added Process::signal()
+ * added Process::getPid()
+ * added support for a TTY mode
+
+2.2.0
+-----
+
+ * added ProcessBuilder::setArguments() to reset the arguments on a builder
+ * added a way to retrieve the standard and error output incrementally
+ * added Process:restart()
+
+2.1.0
+-----
+
+ * added support for non-blocking processes (start(), wait(), isRunning(), stop())
+ * enhanced Windows compatibility
+ * added Process::getExitCodeText() that returns a string representation for
+ the exit code returned by the process
+ * added ProcessBuilder
diff --git a/vendor/symfony/process/Exception/ExceptionInterface.php b/vendor/symfony/process/Exception/ExceptionInterface.php
new file mode 100644
index 00000000..75c1c9e5
--- /dev/null
+++ b/vendor/symfony/process/Exception/ExceptionInterface.php
@@ -0,0 +1,21 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Process\Exception;
+
+/**
+ * Marker Interface for the Process Component.
+ *
+ * @author Johannes M. Schmitt <schmittjoh@gmail.com>
+ */
+interface ExceptionInterface
+{
+}
diff --git a/vendor/symfony/process/Exception/InvalidArgumentException.php b/vendor/symfony/process/Exception/InvalidArgumentException.php
new file mode 100644
index 00000000..926ee211
--- /dev/null
+++ b/vendor/symfony/process/Exception/InvalidArgumentException.php
@@ -0,0 +1,21 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Process\Exception;
+
+/**
+ * InvalidArgumentException for the Process Component.
+ *
+ * @author Romain Neutron <imprec@gmail.com>
+ */
+class InvalidArgumentException extends \InvalidArgumentException implements ExceptionInterface
+{
+}
diff --git a/vendor/symfony/process/Exception/LogicException.php b/vendor/symfony/process/Exception/LogicException.php
new file mode 100644
index 00000000..be3d490d
--- /dev/null
+++ b/vendor/symfony/process/Exception/LogicException.php
@@ -0,0 +1,21 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Process\Exception;
+
+/**
+ * LogicException for the Process Component.
+ *
+ * @author Romain Neutron <imprec@gmail.com>
+ */
+class LogicException extends \LogicException implements ExceptionInterface
+{
+}
diff --git a/vendor/symfony/process/Exception/ProcessFailedException.php b/vendor/symfony/process/Exception/ProcessFailedException.php
new file mode 100644
index 00000000..7523a5e9
--- /dev/null
+++ b/vendor/symfony/process/Exception/ProcessFailedException.php
@@ -0,0 +1,53 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Process\Exception;
+
+use Symfony\Component\Process\Process;
+
+/**
+ * Exception for failed processes.
+ *
+ * @author Johannes M. Schmitt <schmittjoh@gmail.com>
+ */
+class ProcessFailedException extends RuntimeException
+{
+ private $process;
+
+ public function __construct(Process $process)
+ {
+ if ($process->isSuccessful()) {
+ throw new InvalidArgumentException('Expected a failed process, but the given process was successful.');
+ }
+
+ $error = sprintf('The command "%s" failed.'."\nExit Code: %s(%s)",
+ $process->getCommandLine(),
+ $process->getExitCode(),
+ $process->getExitCodeText()
+ );
+
+ if (!$process->isOutputDisabled()) {
+ $error .= sprintf("\n\nOutput:\n================\n%s\n\nError Output:\n================\n%s",
+ $process->getOutput(),
+ $process->getErrorOutput()
+ );
+ }
+
+ parent::__construct($error);
+
+ $this->process = $process;
+ }
+
+ public function getProcess()
+ {
+ return $this->process;
+ }
+}
diff --git a/vendor/symfony/process/Exception/ProcessTimedOutException.php b/vendor/symfony/process/Exception/ProcessTimedOutException.php
new file mode 100644
index 00000000..d4511469
--- /dev/null
+++ b/vendor/symfony/process/Exception/ProcessTimedOutException.php
@@ -0,0 +1,69 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Process\Exception;
+
+use Symfony\Component\Process\Process;
+
+/**
+ * Exception that is thrown when a process times out.
+ *
+ * @author Johannes M. Schmitt <schmittjoh@gmail.com>
+ */
+class ProcessTimedOutException extends RuntimeException
+{
+ const TYPE_GENERAL = 1;
+ const TYPE_IDLE = 2;
+
+ private $process;
+ private $timeoutType;
+
+ public function __construct(Process $process, $timeoutType)
+ {
+ $this->process = $process;
+ $this->timeoutType = $timeoutType;
+
+ parent::__construct(sprintf(
+ 'The process "%s" exceeded the timeout of %s seconds.',
+ $process->getCommandLine(),
+ $this->getExceededTimeout()
+ ));
+ }
+
+ public function getProcess()
+ {
+ return $this->process;
+ }
+
+ public function isGeneralTimeout()
+ {
+ return $this->timeoutType === self::TYPE_GENERAL;
+ }
+
+ public function isIdleTimeout()
+ {
+ return $this->timeoutType === self::TYPE_IDLE;
+ }
+
+ public function getExceededTimeout()
+ {
+ switch ($this->timeoutType) {
+ case self::TYPE_GENERAL:
+ return $this->process->getTimeout();
+
+ case self::TYPE_IDLE:
+ return $this->process->getIdleTimeout();
+
+ default:
+ throw new \LogicException(sprintf('Unknown timeout type "%d".', $this->timeoutType));
+ }
+ }
+}
diff --git a/vendor/symfony/process/Exception/RuntimeException.php b/vendor/symfony/process/Exception/RuntimeException.php
new file mode 100644
index 00000000..adead253
--- /dev/null
+++ b/vendor/symfony/process/Exception/RuntimeException.php
@@ -0,0 +1,21 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Process\Exception;
+
+/**
+ * RuntimeException for the Process Component.
+ *
+ * @author Johannes M. Schmitt <schmittjoh@gmail.com>
+ */
+class RuntimeException extends \RuntimeException implements ExceptionInterface
+{
+}
diff --git a/vendor/symfony/process/ExecutableFinder.php b/vendor/symfony/process/ExecutableFinder.php
new file mode 100644
index 00000000..a9c0a5c8
--- /dev/null
+++ b/vendor/symfony/process/ExecutableFinder.php
@@ -0,0 +1,89 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Process;
+
+/**
+ * Generic executable finder.
+ *
+ * @author Fabien Potencier <fabien@symfony.com>
+ * @author Johannes M. Schmitt <schmittjoh@gmail.com>
+ */
+class ExecutableFinder
+{
+ private $suffixes = array('.exe', '.bat', '.cmd', '.com');
+
+ /**
+ * Replaces default suffixes of executable.
+ *
+ * @param array $suffixes
+ */
+ public function setSuffixes(array $suffixes)
+ {
+ $this->suffixes = $suffixes;
+ }
+
+ /**
+ * Adds new possible suffix to check for executable.
+ *
+ * @param string $suffix
+ */
+ public function addSuffix($suffix)
+ {
+ $this->suffixes[] = $suffix;
+ }
+
+ /**
+ * Finds an executable by name.
+ *
+ * @param string $name The executable name (without the extension)
+ * @param string $default The default to return if no executable is found
+ * @param array $extraDirs Additional dirs to check into
+ *
+ * @return string The executable path or default value
+ */
+ public function find($name, $default = null, array $extraDirs = array())
+ {
+ if (ini_get('open_basedir')) {
+ $searchPath = explode(PATH_SEPARATOR, ini_get('open_basedir'));
+ $dirs = array();
+ foreach ($searchPath as $path) {
+ if (is_dir($path)) {
+ $dirs[] = $path;
+ } else {
+ if (basename($path) == $name && is_executable($path)) {
+ return $path;
+ }
+ }
+ }
+ } else {
+ $dirs = array_merge(
+ explode(PATH_SEPARATOR, getenv('PATH') ?: getenv('Path')),
+ $extraDirs
+ );
+ }
+
+ $suffixes = array('');
+ if ('\\' === DIRECTORY_SEPARATOR) {
+ $pathExt = getenv('PATHEXT');
+ $suffixes = $pathExt ? explode(PATH_SEPARATOR, $pathExt) : $this->suffixes;
+ }
+ foreach ($suffixes as $suffix) {
+ foreach ($dirs as $dir) {
+ if (is_file($file = $dir.DIRECTORY_SEPARATOR.$name.$suffix) && ('\\' === DIRECTORY_SEPARATOR || is_executable($file))) {
+ return $file;
+ }
+ }
+ }
+
+ return $default;
+ }
+}
diff --git a/vendor/symfony/process/LICENSE b/vendor/symfony/process/LICENSE
new file mode 100644
index 00000000..43028bc6
--- /dev/null
+++ b/vendor/symfony/process/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/process/PhpExecutableFinder.php b/vendor/symfony/process/PhpExecutableFinder.php
new file mode 100644
index 00000000..f8f57cc5
--- /dev/null
+++ b/vendor/symfony/process/PhpExecutableFinder.php
@@ -0,0 +1,86 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Process;
+
+/**
+ * An executable finder specifically designed for the PHP executable.
+ *
+ * @author Fabien Potencier <fabien@symfony.com>
+ * @author Johannes M. Schmitt <schmittjoh@gmail.com>
+ */
+class PhpExecutableFinder
+{
+ private $executableFinder;
+
+ public function __construct()
+ {
+ $this->executableFinder = new ExecutableFinder();
+ }
+
+ /**
+ * Finds The PHP executable.
+ *
+ * @param bool $includeArgs Whether or not include command arguments
+ *
+ * @return string|false The PHP executable path or false if it cannot be found
+ */
+ public function find($includeArgs = true)
+ {
+ // HHVM support
+ if (defined('HHVM_VERSION')) {
+ return (getenv('PHP_BINARY') ?: PHP_BINARY).($includeArgs ? ' '.implode(' ', $this->findArguments()) : '');
+ }
+
+ // PHP_BINARY return the current sapi executable
+ if (defined('PHP_BINARY') && PHP_BINARY && in_array(PHP_SAPI, array('cli', 'cli-server')) && is_file(PHP_BINARY)) {
+ return PHP_BINARY;
+ }
+
+ if ($php = getenv('PHP_PATH')) {
+ if (!is_executable($php)) {
+ return false;
+ }
+
+ return $php;
+ }
+
+ if ($php = getenv('PHP_PEAR_PHP_BIN')) {
+ if (is_executable($php)) {
+ return $php;
+ }
+ }
+
+ $dirs = array(PHP_BINDIR);
+ if ('\\' === DIRECTORY_SEPARATOR) {
+ $dirs[] = 'C:\xampp\php\\';
+ }
+
+ return $this->executableFinder->find('php', false, $dirs);
+ }
+
+ /**
+ * Finds the PHP executable arguments.
+ *
+ * @return array The PHP executable arguments
+ */
+ public function findArguments()
+ {
+ $arguments = array();
+
+ // HHVM support
+ if (defined('HHVM_VERSION')) {
+ $arguments[] = '--php';
+ }
+
+ return $arguments;
+ }
+}
diff --git a/vendor/symfony/process/PhpProcess.php b/vendor/symfony/process/PhpProcess.php
new file mode 100644
index 00000000..6a585874
--- /dev/null
+++ b/vendor/symfony/process/PhpProcess.php
@@ -0,0 +1,71 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Process;
+
+use Symfony\Component\Process\Exception\RuntimeException;
+
+/**
+ * PhpProcess runs a PHP script in an independent process.
+ *
+ * $p = new PhpProcess('<?php echo "foo"; ?>');
+ * $p->run();
+ * print $p->getOutput()."\n";
+ *
+ * @author Fabien Potencier <fabien@symfony.com>
+ *
+ * @api
+ */
+class PhpProcess extends Process
+{
+ /**
+ * Constructor.
+ *
+ * @param string $script The PHP script to run (as a string)
+ * @param string $cwd The working directory
+ * @param array $env The environment variables
+ * @param int $timeout The timeout in seconds
+ * @param array $options An array of options for proc_open
+ *
+ * @api
+ */
+ public function __construct($script, $cwd = null, array $env = array(), $timeout = 60, array $options = array())
+ {
+ $executableFinder = new PhpExecutableFinder();
+ if (false === $php = $executableFinder->find()) {
+ $php = null;
+ }
+
+ parent::__construct($php, $cwd, $env, $script, $timeout, $options);
+ }
+
+ /**
+ * Sets the path to the PHP binary to use.
+ *
+ * @api
+ */
+ public function setPhpBinary($php)
+ {
+ $this->setCommandLine($php);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function start($callback = null)
+ {
+ if (null === $this->getCommandLine()) {
+ throw new RuntimeException('Unable to find the PHP executable.');
+ }
+
+ parent::start($callback);
+ }
+}
diff --git a/vendor/symfony/process/Pipes/AbstractPipes.php b/vendor/symfony/process/Pipes/AbstractPipes.php
new file mode 100644
index 00000000..d8b57d07
--- /dev/null
+++ b/vendor/symfony/process/Pipes/AbstractPipes.php
@@ -0,0 +1,74 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Process\Pipes;
+
+/**
+ * @author Romain Neutron <imprec@gmail.com>
+ *
+ * @internal
+ */
+abstract class AbstractPipes implements PipesInterface
+{
+ /** @var array */
+ public $pipes = array();
+
+ /** @var string */
+ protected $inputBuffer = '';
+ /** @var resource|null */
+ protected $input;
+
+ /** @var bool */
+ private $blocked = true;
+
+ /**
+ * {@inheritdoc}
+ */
+ public function close()
+ {
+ foreach ($this->pipes as $pipe) {
+ fclose($pipe);
+ }
+ $this->pipes = array();
+ }
+
+ /**
+ * Returns true if a system call has been interrupted.
+ *
+ * @return bool
+ */
+ protected function hasSystemCallBeenInterrupted()
+ {
+ $lastError = error_get_last();
+
+ // stream_select returns false when the `select` system call is interrupted by an incoming signal
+ return isset($lastError['message']) && false !== stripos($lastError['message'], 'interrupted system call');
+ }
+
+ /**
+ * Unblocks streams
+ */
+ protected function unblock()
+ {
+ if (!$this->blocked) {
+ return;
+ }
+
+ foreach ($this->pipes as $pipe) {
+ stream_set_blocking($pipe, 0);
+ }
+ if (null !== $this->input) {
+ stream_set_blocking($this->input, 0);
+ }
+
+ $this->blocked = false;
+ }
+}
diff --git a/vendor/symfony/process/Pipes/PipesInterface.php b/vendor/symfony/process/Pipes/PipesInterface.php
new file mode 100644
index 00000000..09d3f61d
--- /dev/null
+++ b/vendor/symfony/process/Pipes/PipesInterface.php
@@ -0,0 +1,60 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Process\Pipes;
+
+/**
+ * PipesInterface manages descriptors and pipes for the use of proc_open.
+ *
+ * @author Romain Neutron <imprec@gmail.com>
+ *
+ * @internal
+ */
+interface PipesInterface
+{
+ const CHUNK_SIZE = 16384;
+
+ /**
+ * Returns an array of descriptors for the use of proc_open.
+ *
+ * @return array
+ */
+ public function getDescriptors();
+
+ /**
+ * Returns an array of filenames indexed by their related stream in case these pipes use temporary files.
+ *
+ * @return string[]
+ */
+ public function getFiles();
+
+ /**
+ * Reads data in file handles and pipes.
+ *
+ * @param bool $blocking Whether to use blocking calls or not.
+ * @param bool $close Whether to close pipes if they've reached EOF.
+ *
+ * @return string[] An array of read data indexed by their fd.
+ */
+ public function readAndWrite($blocking, $close = false);
+
+ /**
+ * Returns if the current state has open file handles or pipes.
+ *
+ * @return bool
+ */
+ public function areOpen();
+
+ /**
+ * Closes file handles and pipes.
+ */
+ public function close();
+}
diff --git a/vendor/symfony/process/Pipes/UnixPipes.php b/vendor/symfony/process/Pipes/UnixPipes.php
new file mode 100644
index 00000000..b3841031
--- /dev/null
+++ b/vendor/symfony/process/Pipes/UnixPipes.php
@@ -0,0 +1,214 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Process\Pipes;
+
+use Symfony\Component\Process\Process;
+
+/**
+ * UnixPipes implementation uses unix pipes as handles.
+ *
+ * @author Romain Neutron <imprec@gmail.com>
+ *
+ * @internal
+ */
+class UnixPipes extends AbstractPipes
+{
+ /** @var bool */
+ private $ttyMode;
+ /** @var bool */
+ private $ptyMode;
+ /** @var bool */
+ private $disableOutput;
+
+ public function __construct($ttyMode, $ptyMode, $input, $disableOutput)
+ {
+ $this->ttyMode = (bool) $ttyMode;
+ $this->ptyMode = (bool) $ptyMode;
+ $this->disableOutput = (bool) $disableOutput;
+
+ if (is_resource($input)) {
+ $this->input = $input;
+ } else {
+ $this->inputBuffer = (string) $input;
+ }
+ }
+
+ public function __destruct()
+ {
+ $this->close();
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getDescriptors()
+ {
+ if ($this->disableOutput) {
+ $nullstream = fopen('/dev/null', 'c');
+
+ return array(
+ array('pipe', 'r'),
+ $nullstream,
+ $nullstream,
+ );
+ }
+
+ if ($this->ttyMode) {
+ return array(
+ array('file', '/dev/tty', 'r'),
+ array('file', '/dev/tty', 'w'),
+ array('file', '/dev/tty', 'w'),
+ );
+ }
+
+ if ($this->ptyMode && Process::isPtySupported()) {
+ return array(
+ array('pty'),
+ array('pty'),
+ array('pty'),
+ );
+ }
+
+ return array(
+ array('pipe', 'r'),
+ array('pipe', 'w'), // stdout
+ array('pipe', 'w'), // stderr
+ );
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getFiles()
+ {
+ return array();
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function readAndWrite($blocking, $close = false)
+ {
+ // only stdin is left open, job has been done !
+ // we can now close it
+ if (1 === count($this->pipes) && array(0) === array_keys($this->pipes)) {
+ fclose($this->pipes[0]);
+ unset($this->pipes[0]);
+ }
+
+ if (empty($this->pipes)) {
+ return array();
+ }
+
+ $this->unblock();
+
+ $read = array();
+
+ if (null !== $this->input) {
+ // if input is a resource, let's add it to stream_select argument to
+ // fill a buffer
+ $r = array_merge($this->pipes, array('input' => $this->input));
+ } else {
+ $r = $this->pipes;
+ }
+ // discard read on stdin
+ unset($r[0]);
+
+ $w = isset($this->pipes[0]) ? array($this->pipes[0]) : null;
+ $e = null;
+
+ // let's have a look if something changed in streams
+ if (false === $n = @stream_select($r, $w, $e, 0, $blocking ? Process::TIMEOUT_PRECISION * 1E6 : 0)) {
+ // if a system call has been interrupted, forget about it, let's try again
+ // otherwise, an error occurred, let's reset pipes
+ if (!$this->hasSystemCallBeenInterrupted()) {
+ $this->pipes = array();
+ }
+
+ return $read;
+ }
+
+ // nothing has changed
+ if (0 === $n) {
+ return $read;
+ }
+
+ foreach ($r as $pipe) {
+ // prior PHP 5.4 the array passed to stream_select is modified and
+ // lose key association, we have to find back the key
+ $type = (false !== $found = array_search($pipe, $this->pipes)) ? $found : 'input';
+ $data = '';
+ while ('' !== $dataread = (string) fread($pipe, self::CHUNK_SIZE)) {
+ $data .= $dataread;
+ }
+
+ if ('' !== $data) {
+ if ($type === 'input') {
+ $this->inputBuffer .= $data;
+ } else {
+ $read[$type] = $data;
+ }
+ }
+
+ if (false === $data || (true === $close && feof($pipe) && '' === $data)) {
+ if ($type === 'input') {
+ // no more data to read on input resource
+ // use an empty buffer in the next reads
+ $this->input = null;
+ } else {
+ fclose($this->pipes[$type]);
+ unset($this->pipes[$type]);
+ }
+ }
+ }
+
+ if (null !== $w && 0 < count($w)) {
+ while (strlen($this->inputBuffer)) {
+ $written = fwrite($w[0], $this->inputBuffer, 2 << 18); // write 512k
+ if ($written > 0) {
+ $this->inputBuffer = (string) substr($this->inputBuffer, $written);
+ } else {
+ break;
+ }
+ }
+ }
+
+ // no input to read on resource, buffer is empty and stdin still open
+ if ('' === $this->inputBuffer && null === $this->input && isset($this->pipes[0])) {
+ fclose($this->pipes[0]);
+ unset($this->pipes[0]);
+ }
+
+ return $read;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function areOpen()
+ {
+ return (bool) $this->pipes;
+ }
+
+ /**
+ * Creates a new UnixPipes instance
+ *
+ * @param Process $process
+ * @param string|resource $input
+ *
+ * @return UnixPipes
+ */
+ public static function create(Process $process, $input)
+ {
+ return new static($process->isTty(), $process->isPty(), $input, $process->isOutputDisabled());
+ }
+}
diff --git a/vendor/symfony/process/Pipes/WindowsPipes.php b/vendor/symfony/process/Pipes/WindowsPipes.php
new file mode 100644
index 00000000..01dd5d06
--- /dev/null
+++ b/vendor/symfony/process/Pipes/WindowsPipes.php
@@ -0,0 +1,254 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Process\Pipes;
+
+use Symfony\Component\Process\Process;
+use Symfony\Component\Process\Exception\RuntimeException;
+
+/**
+ * WindowsPipes implementation uses temporary files as handles.
+ *
+ * @see https://bugs.php.net/bug.php?id=51800
+ * @see https://bugs.php.net/bug.php?id=65650
+ *
+ * @author Romain Neutron <imprec@gmail.com>
+ *
+ * @internal
+ */
+class WindowsPipes extends AbstractPipes
+{
+ /** @var array */
+ private $files = array();
+ /** @var array */
+ private $fileHandles = array();
+ /** @var array */
+ private $readBytes = array(
+ Process::STDOUT => 0,
+ Process::STDERR => 0,
+ );
+ /** @var bool */
+ private $disableOutput;
+
+ public function __construct($disableOutput, $input)
+ {
+ $this->disableOutput = (bool) $disableOutput;
+
+ if (!$this->disableOutput) {
+ // Fix for PHP bug #51800: reading from STDOUT pipe hangs forever on Windows if the output is too big.
+ // Workaround for this problem is to use temporary files instead of pipes on Windows platform.
+ //
+ // @see https://bugs.php.net/bug.php?id=51800
+ $this->files = array(
+ Process::STDOUT => tempnam(sys_get_temp_dir(), 'sf_proc_stdout'),
+ Process::STDERR => tempnam(sys_get_temp_dir(), 'sf_proc_stderr'),
+ );
+ foreach ($this->files as $offset => $file) {
+ $this->fileHandles[$offset] = fopen($this->files[$offset], 'rb');
+ if (false === $this->fileHandles[$offset]) {
+ throw new RuntimeException('A temporary file could not be opened to write the process output to, verify that your TEMP environment variable is writable');
+ }
+ }
+ }
+
+ if (is_resource($input)) {
+ $this->input = $input;
+ } else {
+ $this->inputBuffer = $input;
+ }
+ }
+
+ public function __destruct()
+ {
+ $this->close();
+ $this->removeFiles();
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getDescriptors()
+ {
+ if ($this->disableOutput) {
+ $nullstream = fopen('NUL', 'c');
+
+ return array(
+ array('pipe', 'r'),
+ $nullstream,
+ $nullstream,
+ );
+ }
+
+ // We're not using pipe on Windows platform as it hangs (https://bugs.php.net/bug.php?id=51800)
+ // We're not using file handles as it can produce corrupted output https://bugs.php.net/bug.php?id=65650
+ // So we redirect output within the commandline and pass the nul device to the process
+ return array(
+ array('pipe', 'r'),
+ array('file', 'NUL', 'w'),
+ array('file', 'NUL', 'w'),
+ );
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getFiles()
+ {
+ return $this->files;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function readAndWrite($blocking, $close = false)
+ {
+ $this->write($blocking, $close);
+
+ $read = array();
+ $fh = $this->fileHandles;
+ foreach ($fh as $type => $fileHandle) {
+ if (0 !== fseek($fileHandle, $this->readBytes[$type])) {
+ continue;
+ }
+ $data = '';
+ $dataread = null;
+ while (!feof($fileHandle)) {
+ if (false !== $dataread = fread($fileHandle, self::CHUNK_SIZE)) {
+ $data .= $dataread;
+ }
+ }
+ if (0 < $length = strlen($data)) {
+ $this->readBytes[$type] += $length;
+ $read[$type] = $data;
+ }
+
+ if (false === $dataread || (true === $close && feof($fileHandle) && '' === $data)) {
+ fclose($this->fileHandles[$type]);
+ unset($this->fileHandles[$type]);
+ }
+ }
+
+ return $read;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function areOpen()
+ {
+ return (bool) $this->pipes && (bool) $this->fileHandles;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function close()
+ {
+ parent::close();
+ foreach ($this->fileHandles as $handle) {
+ fclose($handle);
+ }
+ $this->fileHandles = array();
+ }
+
+ /**
+ * Creates a new WindowsPipes instance.
+ *
+ * @param Process $process The process
+ * @param $input
+ *
+ * @return WindowsPipes
+ */
+ public static function create(Process $process, $input)
+ {
+ return new static($process->isOutputDisabled(), $input);
+ }
+
+ /**
+ * Removes temporary files
+ */
+ private function removeFiles()
+ {
+ foreach ($this->files as $filename) {
+ if (file_exists($filename)) {
+ @unlink($filename);
+ }
+ }
+ $this->files = array();
+ }
+
+ /**
+ * Writes input to stdin
+ *
+ * @param bool $blocking
+ * @param bool $close
+ */
+ private function write($blocking, $close)
+ {
+ if (empty($this->pipes)) {
+ return;
+ }
+
+ $this->unblock();
+
+ $r = null !== $this->input ? array('input' => $this->input) : null;
+ $w = isset($this->pipes[0]) ? array($this->pipes[0]) : null;
+ $e = null;
+
+ // let's have a look if something changed in streams
+ if (false === $n = @stream_select($r, $w, $e, 0, $blocking ? Process::TIMEOUT_PRECISION * 1E6 : 0)) {
+ // if a system call has been interrupted, forget about it, let's try again
+ // otherwise, an error occurred, let's reset pipes
+ if (!$this->hasSystemCallBeenInterrupted()) {
+ $this->pipes = array();
+ }
+
+ return;
+ }
+
+ // nothing has changed
+ if (0 === $n) {
+ return;
+ }
+
+ if (null !== $w && 0 < count($r)) {
+ $data = '';
+ while ($dataread = fread($r['input'], self::CHUNK_SIZE)) {
+ $data .= $dataread;
+ }
+
+ $this->inputBuffer .= $data;
+
+ if (false === $data || (true === $close && feof($r['input']) && '' === $data)) {
+ // no more data to read on input resource
+ // use an empty buffer in the next reads
+ $this->input = null;
+ }
+ }
+
+ if (null !== $w && 0 < count($w)) {
+ while (strlen($this->inputBuffer)) {
+ $written = fwrite($w[0], $this->inputBuffer, 2 << 18);
+ if ($written > 0) {
+ $this->inputBuffer = (string) substr($this->inputBuffer, $written);
+ } else {
+ break;
+ }
+ }
+ }
+
+ // no input to read on resource, buffer is empty and stdin still open
+ if ('' === $this->inputBuffer && null === $this->input && isset($this->pipes[0])) {
+ fclose($this->pipes[0]);
+ unset($this->pipes[0]);
+ }
+ }
+}
diff --git a/vendor/symfony/process/Process.php b/vendor/symfony/process/Process.php
new file mode 100644
index 00000000..1474d698
--- /dev/null
+++ b/vendor/symfony/process/Process.php
@@ -0,0 +1,1526 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Process;
+
+use Symfony\Component\Process\Exception\InvalidArgumentException;
+use Symfony\Component\Process\Exception\LogicException;
+use Symfony\Component\Process\Exception\ProcessFailedException;
+use Symfony\Component\Process\Exception\ProcessTimedOutException;
+use Symfony\Component\Process\Exception\RuntimeException;
+use Symfony\Component\Process\Pipes\PipesInterface;
+use Symfony\Component\Process\Pipes\UnixPipes;
+use Symfony\Component\Process\Pipes\WindowsPipes;
+
+/**
+ * Process is a thin wrapper around proc_* functions to easily
+ * start independent PHP processes.
+ *
+ * @author Fabien Potencier <fabien@symfony.com>
+ * @author Romain Neutron <imprec@gmail.com>
+ *
+ * @api
+ */
+class Process
+{
+ const ERR = 'err';
+ const OUT = 'out';
+
+ const STATUS_READY = 'ready';
+ const STATUS_STARTED = 'started';
+ const STATUS_TERMINATED = 'terminated';
+
+ const STDIN = 0;
+ const STDOUT = 1;
+ const STDERR = 2;
+
+ // Timeout Precision in seconds.
+ const TIMEOUT_PRECISION = 0.2;
+
+ private $callback;
+ private $commandline;
+ private $cwd;
+ private $env;
+ private $input;
+ private $starttime;
+ private $lastOutputTime;
+ private $timeout;
+ private $idleTimeout;
+ private $options;
+ private $exitcode;
+ private $fallbackExitcode;
+ private $processInformation;
+ private $outputDisabled = false;
+ private $stdout;
+ private $stderr;
+ private $enhanceWindowsCompatibility = true;
+ private $enhanceSigchildCompatibility;
+ private $process;
+ private $status = self::STATUS_READY;
+ private $incrementalOutputOffset = 0;
+ private $incrementalErrorOutputOffset = 0;
+ private $tty;
+ private $pty;
+
+ private $useFileHandles = false;
+ /** @var PipesInterface */
+ private $processPipes;
+
+ private $latestSignal;
+
+ private static $sigchild;
+
+ /**
+ * Exit codes translation table.
+ *
+ * User-defined errors must use exit codes in the 64-113 range.
+ *
+ * @var array
+ */
+ public static $exitCodes = array(
+ 0 => 'OK',
+ 1 => 'General error',
+ 2 => 'Misuse of shell builtins',
+
+ 126 => 'Invoked command cannot execute',
+ 127 => 'Command not found',
+ 128 => 'Invalid exit argument',
+
+ // signals
+ 129 => 'Hangup',
+ 130 => 'Interrupt',
+ 131 => 'Quit and dump core',
+ 132 => 'Illegal instruction',
+ 133 => 'Trace/breakpoint trap',
+ 134 => 'Process aborted',
+ 135 => 'Bus error: "access to undefined portion of memory object"',
+ 136 => 'Floating point exception: "erroneous arithmetic operation"',
+ 137 => 'Kill (terminate immediately)',
+ 138 => 'User-defined 1',
+ 139 => 'Segmentation violation',
+ 140 => 'User-defined 2',
+ 141 => 'Write to pipe with no one reading',
+ 142 => 'Signal raised by alarm',
+ 143 => 'Termination (request to terminate)',
+ // 144 - not defined
+ 145 => 'Child process terminated, stopped (or continued*)',
+ 146 => 'Continue if stopped',
+ 147 => 'Stop executing temporarily',
+ 148 => 'Terminal stop signal',
+ 149 => 'Background process attempting to read from tty ("in")',
+ 150 => 'Background process attempting to write to tty ("out")',
+ 151 => 'Urgent data available on socket',
+ 152 => 'CPU time limit exceeded',
+ 153 => 'File size limit exceeded',
+ 154 => 'Signal raised by timer counting virtual time: "virtual timer expired"',
+ 155 => 'Profiling timer expired',
+ // 156 - not defined
+ 157 => 'Pollable event',
+ // 158 - not defined
+ 159 => 'Bad syscall',
+ );
+
+ /**
+ * Constructor.
+ *
+ * @param string $commandline The command line to run
+ * @param string|null $cwd The working directory or null to use the working dir of the current PHP process
+ * @param array|null $env The environment variables or null to inherit
+ * @param string|null $input The input
+ * @param int|float|null $timeout The timeout in seconds or null to disable
+ * @param array $options An array of options for proc_open
+ *
+ * @throws RuntimeException When proc_open is not installed
+ *
+ * @api
+ */
+ public function __construct($commandline, $cwd = null, array $env = null, $input = null, $timeout = 60, array $options = array())
+ {
+ if (!function_exists('proc_open')) {
+ throw new RuntimeException('The Process class relies on proc_open, which is not available on your PHP installation.');
+ }
+
+ $this->commandline = $commandline;
+ $this->cwd = $cwd;
+
+ // on Windows, if the cwd changed via chdir(), proc_open defaults to the dir where PHP was started
+ // on Gnu/Linux, PHP builds with --enable-maintainer-zts are also affected
+ // @see : https://bugs.php.net/bug.php?id=51800
+ // @see : https://bugs.php.net/bug.php?id=50524
+ if (null === $this->cwd && (defined('ZEND_THREAD_SAFE') || '\\' === DIRECTORY_SEPARATOR)) {
+ $this->cwd = getcwd();
+ }
+ if (null !== $env) {
+ $this->setEnv($env);
+ }
+
+ $this->input = $input;
+ $this->setTimeout($timeout);
+ $this->useFileHandles = '\\' === DIRECTORY_SEPARATOR;
+ $this->pty = false;
+ $this->enhanceWindowsCompatibility = true;
+ $this->enhanceSigchildCompatibility = '\\' !== DIRECTORY_SEPARATOR && $this->isSigchildEnabled();
+ $this->options = array_replace(array('suppress_errors' => true, 'binary_pipes' => true), $options);
+ }
+
+ public function __destruct()
+ {
+ // stop() will check if we have a process running.
+ $this->stop();
+ }
+
+ public function __clone()
+ {
+ $this->resetProcessData();
+ }
+
+ /**
+ * Runs the process.
+ *
+ * The callback receives the type of output (out or err) and
+ * some bytes from the output in real-time. It allows to have feedback
+ * from the independent process during execution.
+ *
+ * The STDOUT and STDERR are also available after the process is finished
+ * via the getOutput() and getErrorOutput() methods.
+ *
+ * @param callable|null $callback A PHP callback to run whenever there is some
+ * output available on STDOUT or STDERR
+ *
+ * @return int The exit status code
+ *
+ * @throws RuntimeException When process can't be launched
+ * @throws RuntimeException When process stopped after receiving signal
+ * @throws LogicException In case a callback is provided and output has been disabled
+ *
+ * @api
+ */
+ public function run($callback = null)
+ {
+ $this->start($callback);
+
+ return $this->wait();
+ }
+
+ /**
+ * 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 callable|null $callback
+ *
+ * @return self
+ *
+ * @throws RuntimeException if PHP was compiled with --enable-sigchild and the enhanced sigchild compatibility mode is not enabled
+ * @throws ProcessFailedException if the process didn't terminate successfully
+ */
+ public function mustRun($callback = null)
+ {
+ if ($this->isSigchildEnabled() && !$this->enhanceSigchildCompatibility) {
+ throw new RuntimeException('This PHP has been compiled with --enable-sigchild. You must use setEnhanceSigchildCompatibility() to use this method.');
+ }
+
+ if (0 !== $this->run($callback)) {
+ throw new ProcessFailedException($this);
+ }
+
+ return $this;
+ }
+
+ /**
+ * Starts the process and returns after writing the input to STDIN.
+ *
+ * This method blocks until all STDIN data is sent to the process then it
+ * returns while the process runs in the background.
+ *
+ * The termination of the process can be awaited with wait().
+ *
+ * The callback receives the type of output (out or err) and some bytes from
+ * the output in real-time while writing the standard input to the process.
+ * It allows to have feedback from the independent process during execution.
+ * If there is no callback passed, the wait() method can be called
+ * with true as a second parameter then the callback will get all data occurred
+ * in (and since) the start call.
+ *
+ * @param callable|null $callback A PHP callback to run whenever there is some
+ * output available on STDOUT or STDERR
+ *
+ * @throws RuntimeException When process can't be launched
+ * @throws RuntimeException When process is already running
+ * @throws LogicException In case a callback is provided and output has been disabled
+ */
+ public function start($callback = null)
+ {
+ if ($this->isRunning()) {
+ throw new RuntimeException('Process is already running');
+ }
+ if ($this->outputDisabled && null !== $callback) {
+ throw new LogicException('Output has been disabled, enable it to allow the use of a callback.');
+ }
+
+ $this->resetProcessData();
+ $this->starttime = $this->lastOutputTime = microtime(true);
+ $this->callback = $this->buildCallback($callback);
+ $descriptors = $this->getDescriptors();
+
+ $commandline = $this->commandline;
+
+ if ('\\' === DIRECTORY_SEPARATOR && $this->enhanceWindowsCompatibility) {
+ $commandline = 'cmd /V:ON /E:ON /C "('.$commandline.')';
+ foreach ($this->processPipes->getFiles() as $offset => $filename) {
+ $commandline .= ' '.$offset.'>'.ProcessUtils::escapeArgument($filename);
+ }
+ $commandline .= '"';
+
+ if (!isset($this->options['bypass_shell'])) {
+ $this->options['bypass_shell'] = true;
+ }
+ }
+
+ $this->process = proc_open($commandline, $descriptors, $this->processPipes->pipes, $this->cwd, $this->env, $this->options);
+
+ if (!is_resource($this->process)) {
+ throw new RuntimeException('Unable to launch a new process.');
+ }
+ $this->status = self::STATUS_STARTED;
+
+ if ($this->tty) {
+ return;
+ }
+
+ $this->updateStatus(false);
+ $this->checkTimeout();
+ }
+
+ /**
+ * Restarts the process.
+ *
+ * Be warned that the process is cloned before being started.
+ *
+ * @param callable|null $callback A PHP callback to run whenever there is some
+ * output available on STDOUT or STDERR
+ *
+ * @return Process The new process
+ *
+ * @throws RuntimeException When process can't be launched
+ * @throws RuntimeException When process is already running
+ *
+ * @see start()
+ */
+ public function restart($callback = null)
+ {
+ if ($this->isRunning()) {
+ throw new RuntimeException('Process is already running');
+ }
+
+ $process = clone $this;
+ $process->start($callback);
+
+ return $process;
+ }
+
+ /**
+ * Waits for the process to terminate.
+ *
+ * The callback receives the type of output (out or err) and some bytes
+ * from the output in real-time while writing the standard input to the process.
+ * It allows to have feedback from the independent process during execution.
+ *
+ * @param callable|null $callback A valid PHP callback
+ *
+ * @return int The exitcode of the process
+ *
+ * @throws RuntimeException When process timed out
+ * @throws RuntimeException When process stopped after receiving signal
+ * @throws LogicException When process is not yet started
+ */
+ public function wait($callback = null)
+ {
+ $this->requireProcessIsStarted(__FUNCTION__);
+
+ $this->updateStatus(false);
+ if (null !== $callback) {
+ $this->callback = $this->buildCallback($callback);
+ }
+
+ do {
+ $this->checkTimeout();
+ $running = '\\' === DIRECTORY_SEPARATOR ? $this->isRunning() : $this->processPipes->areOpen();
+ $close = '\\' !== DIRECTORY_SEPARATOR || !$running;
+ $this->readPipes(true, $close);
+ } while ($running);
+
+ while ($this->isRunning()) {
+ usleep(1000);
+ }
+
+ if ($this->processInformation['signaled'] && $this->processInformation['termsig'] !== $this->latestSignal) {
+ throw new RuntimeException(sprintf('The process has been signaled with signal "%s".', $this->processInformation['termsig']));
+ }
+
+ return $this->exitcode;
+ }
+
+ /**
+ * Returns the Pid (process identifier), if applicable.
+ *
+ * @return int|null The process id if running, null otherwise
+ *
+ * @throws RuntimeException In case --enable-sigchild is activated
+ */
+ public function getPid()
+ {
+ if ($this->isSigchildEnabled()) {
+ throw new RuntimeException('This PHP has been compiled with --enable-sigchild. The process identifier can not be retrieved.');
+ }
+
+ $this->updateStatus(false);
+
+ return $this->isRunning() ? $this->processInformation['pid'] : null;
+ }
+
+ /**
+ * Sends a POSIX signal to the process.
+ *
+ * @param int $signal A valid POSIX signal (see http://www.php.net/manual/en/pcntl.constants.php)
+ *
+ * @return Process
+ *
+ * @throws LogicException In case the process is not running
+ * @throws RuntimeException In case --enable-sigchild is activated
+ * @throws RuntimeException In case of failure
+ */
+ public function signal($signal)
+ {
+ $this->doSignal($signal, true);
+
+ return $this;
+ }
+
+ /**
+ * Disables fetching output and error output from the underlying process.
+ *
+ * @return Process
+ *
+ * @throws RuntimeException In case the process is already running
+ * @throws LogicException if an idle timeout is set
+ */
+ public function disableOutput()
+ {
+ if ($this->isRunning()) {
+ throw new RuntimeException('Disabling output while the process is running is not possible.');
+ }
+ if (null !== $this->idleTimeout) {
+ throw new LogicException('Output can not be disabled while an idle timeout is set.');
+ }
+
+ $this->outputDisabled = true;
+
+ return $this;
+ }
+
+ /**
+ * Enables fetching output and error output from the underlying process.
+ *
+ * @return Process
+ *
+ * @throws RuntimeException In case the process is already running
+ */
+ public function enableOutput()
+ {
+ if ($this->isRunning()) {
+ throw new RuntimeException('Enabling output while the process is running is not possible.');
+ }
+
+ $this->outputDisabled = false;
+
+ return $this;
+ }
+
+ /**
+ * Returns true in case the output is disabled, false otherwise.
+ *
+ * @return bool
+ */
+ public function isOutputDisabled()
+ {
+ return $this->outputDisabled;
+ }
+
+ /**
+ * Returns the current output of the process (STDOUT).
+ *
+ * @return string The process output
+ *
+ * @throws LogicException in case the output has been disabled
+ * @throws LogicException In case the process is not started
+ *
+ * @api
+ */
+ public function getOutput()
+ {
+ if ($this->outputDisabled) {
+ throw new LogicException('Output has been disabled.');
+ }
+
+ $this->requireProcessIsStarted(__FUNCTION__);
+
+ $this->readPipes(false, '\\' === DIRECTORY_SEPARATOR ? !$this->processInformation['running'] : true);
+
+ return $this->stdout;
+ }
+
+ /**
+ * Returns the output incrementally.
+ *
+ * In comparison with the getOutput method which always return the whole
+ * output, this one returns the new output since the last call.
+ *
+ * @throws LogicException in case the output has been disabled
+ * @throws LogicException In case the process is not started
+ *
+ * @return string The process output since the last call
+ */
+ public function getIncrementalOutput()
+ {
+ $this->requireProcessIsStarted(__FUNCTION__);
+
+ $data = $this->getOutput();
+
+ $latest = substr($data, $this->incrementalOutputOffset);
+
+ if (false === $latest) {
+ return '';
+ }
+
+ $this->incrementalOutputOffset = strlen($data);
+
+ return $latest;
+ }
+
+ /**
+ * Clears the process output.
+ *
+ * @return Process
+ */
+ public function clearOutput()
+ {
+ $this->stdout = '';
+ $this->incrementalOutputOffset = 0;
+
+ return $this;
+ }
+
+ /**
+ * Returns the current error output of the process (STDERR).
+ *
+ * @return string The process error output
+ *
+ * @throws LogicException in case the output has been disabled
+ * @throws LogicException In case the process is not started
+ *
+ * @api
+ */
+ public function getErrorOutput()
+ {
+ if ($this->outputDisabled) {
+ throw new LogicException('Output has been disabled.');
+ }
+
+ $this->requireProcessIsStarted(__FUNCTION__);
+
+ $this->readPipes(false, '\\' === DIRECTORY_SEPARATOR ? !$this->processInformation['running'] : true);
+
+ return $this->stderr;
+ }
+
+ /**
+ * Returns the errorOutput incrementally.
+ *
+ * In comparison with the getErrorOutput method which always return the
+ * whole error output, this one returns the new error output since the last
+ * call.
+ *
+ * @throws LogicException in case the output has been disabled
+ * @throws LogicException In case the process is not started
+ *
+ * @return string The process error output since the last call
+ */
+ public function getIncrementalErrorOutput()
+ {
+ $this->requireProcessIsStarted(__FUNCTION__);
+
+ $data = $this->getErrorOutput();
+
+ $latest = substr($data, $this->incrementalErrorOutputOffset);
+
+ if (false === $latest) {
+ return '';
+ }
+
+ $this->incrementalErrorOutputOffset = strlen($data);
+
+ return $latest;
+ }
+
+ /**
+ * Clears the process output.
+ *
+ * @return Process
+ */
+ public function clearErrorOutput()
+ {
+ $this->stderr = '';
+ $this->incrementalErrorOutputOffset = 0;
+
+ return $this;
+ }
+
+ /**
+ * Returns the exit code returned by the process.
+ *
+ * @return null|int The exit status code, null if the Process is not terminated
+ *
+ * @throws RuntimeException In case --enable-sigchild is activated and the sigchild compatibility mode is disabled
+ *
+ * @api
+ */
+ public function getExitCode()
+ {
+ if ($this->isSigchildEnabled() && !$this->enhanceSigchildCompatibility) {
+ throw new RuntimeException('This PHP has been compiled with --enable-sigchild. You must use setEnhanceSigchildCompatibility() to use this method.');
+ }
+
+ $this->updateStatus(false);
+
+ return $this->exitcode;
+ }
+
+ /**
+ * Returns a string representation for the exit code returned by the process.
+ *
+ * This method relies on the Unix exit code status standardization
+ * and might not be relevant for other operating systems.
+ *
+ * @return null|string A string representation for the exit status code, null if the Process is not terminated.
+ *
+ * @throws RuntimeException In case --enable-sigchild is activated and the sigchild compatibility mode is disabled
+ *
+ * @see http://tldp.org/LDP/abs/html/exitcodes.html
+ * @see http://en.wikipedia.org/wiki/Unix_signal
+ */
+ public function getExitCodeText()
+ {
+ if (null === $exitcode = $this->getExitCode()) {
+ return;
+ }
+
+ return isset(self::$exitCodes[$exitcode]) ? self::$exitCodes[$exitcode] : 'Unknown error';
+ }
+
+ /**
+ * Checks if the process ended successfully.
+ *
+ * @return bool true if the process ended successfully, false otherwise
+ *
+ * @api
+ */
+ public function isSuccessful()
+ {
+ return 0 === $this->getExitCode();
+ }
+
+ /**
+ * Returns true if the child process has been terminated by an uncaught signal.
+ *
+ * It always returns false on Windows.
+ *
+ * @return bool
+ *
+ * @throws RuntimeException In case --enable-sigchild is activated
+ * @throws LogicException In case the process is not terminated
+ *
+ * @api
+ */
+ public function hasBeenSignaled()
+ {
+ $this->requireProcessIsTerminated(__FUNCTION__);
+
+ if ($this->isSigchildEnabled()) {
+ throw new RuntimeException('This PHP has been compiled with --enable-sigchild. Term signal can not be retrieved.');
+ }
+
+ $this->updateStatus(false);
+
+ return $this->processInformation['signaled'];
+ }
+
+ /**
+ * Returns the number of the signal that caused the child process to terminate its execution.
+ *
+ * It is only meaningful if hasBeenSignaled() returns true.
+ *
+ * @return int
+ *
+ * @throws RuntimeException In case --enable-sigchild is activated
+ * @throws LogicException In case the process is not terminated
+ *
+ * @api
+ */
+ public function getTermSignal()
+ {
+ $this->requireProcessIsTerminated(__FUNCTION__);
+
+ if ($this->isSigchildEnabled()) {
+ throw new RuntimeException('This PHP has been compiled with --enable-sigchild. Term signal can not be retrieved.');
+ }
+
+ $this->updateStatus(false);
+
+ return $this->processInformation['termsig'];
+ }
+
+ /**
+ * Returns true if the child process has been stopped by a signal.
+ *
+ * It always returns false on Windows.
+ *
+ * @return bool
+ *
+ * @throws LogicException In case the process is not terminated
+ *
+ * @api
+ */
+ public function hasBeenStopped()
+ {
+ $this->requireProcessIsTerminated(__FUNCTION__);
+
+ $this->updateStatus(false);
+
+ return $this->processInformation['stopped'];
+ }
+
+ /**
+ * Returns the number of the signal that caused the child process to stop its execution.
+ *
+ * It is only meaningful if hasBeenStopped() returns true.
+ *
+ * @return int
+ *
+ * @throws LogicException In case the process is not terminated
+ *
+ * @api
+ */
+ public function getStopSignal()
+ {
+ $this->requireProcessIsTerminated(__FUNCTION__);
+
+ $this->updateStatus(false);
+
+ return $this->processInformation['stopsig'];
+ }
+
+ /**
+ * Checks if the process is currently running.
+ *
+ * @return bool true if the process is currently running, false otherwise
+ */
+ public function isRunning()
+ {
+ if (self::STATUS_STARTED !== $this->status) {
+ return false;
+ }
+
+ $this->updateStatus(false);
+
+ return $this->processInformation['running'];
+ }
+
+ /**
+ * Checks if the process has been started with no regard to the current state.
+ *
+ * @return bool true if status is ready, false otherwise
+ */
+ public function isStarted()
+ {
+ return $this->status != self::STATUS_READY;
+ }
+
+ /**
+ * Checks if the process is terminated.
+ *
+ * @return bool true if process is terminated, false otherwise
+ */
+ public function isTerminated()
+ {
+ $this->updateStatus(false);
+
+ return $this->status == self::STATUS_TERMINATED;
+ }
+
+ /**
+ * Gets the process status.
+ *
+ * The status is one of: ready, started, terminated.
+ *
+ * @return string The current process status
+ */
+ public function getStatus()
+ {
+ $this->updateStatus(false);
+
+ return $this->status;
+ }
+
+ /**
+ * Stops the process.
+ *
+ * @param int|float $timeout The timeout in seconds
+ * @param int $signal A POSIX signal to send in case the process has not stop at timeout, default is SIGKILL
+ *
+ * @return int The exit-code of the process
+ *
+ * @throws RuntimeException if the process got signaled
+ */
+ public function stop($timeout = 10, $signal = null)
+ {
+ $timeoutMicro = microtime(true) + $timeout;
+ if ($this->isRunning()) {
+ if ('\\' === DIRECTORY_SEPARATOR && !$this->isSigchildEnabled()) {
+ exec(sprintf('taskkill /F /T /PID %d 2>&1', $this->getPid()), $output, $exitCode);
+ if ($exitCode > 0) {
+ throw new RuntimeException('Unable to kill the process');
+ }
+ }
+ // given `SIGTERM` may not be defined and that `proc_terminate` uses the constant value and not the constant itself, we use the same here
+ $this->doSignal(15, false);
+ do {
+ usleep(1000);
+ } while ($this->isRunning() && microtime(true) < $timeoutMicro);
+
+ if ($this->isRunning() && !$this->isSigchildEnabled()) {
+ if (null !== $signal || defined('SIGKILL')) {
+ // avoid exception here :
+ // process is supposed to be running, but it might have stop
+ // just after this line.
+ // in any case, let's silently discard the error, we can not do anything
+ $this->doSignal($signal ?: SIGKILL, false);
+ }
+ }
+ }
+
+ $this->updateStatus(false);
+ if ($this->processInformation['running']) {
+ $this->close();
+ }
+
+ return $this->exitcode;
+ }
+
+ /**
+ * Adds a line to the STDOUT stream.
+ *
+ * @param string $line The line to append
+ */
+ public function addOutput($line)
+ {
+ $this->lastOutputTime = microtime(true);
+ $this->stdout .= $line;
+ }
+
+ /**
+ * Adds a line to the STDERR stream.
+ *
+ * @param string $line The line to append
+ */
+ public function addErrorOutput($line)
+ {
+ $this->lastOutputTime = microtime(true);
+ $this->stderr .= $line;
+ }
+
+ /**
+ * Gets the command line to be executed.
+ *
+ * @return string The command to execute
+ */
+ public function getCommandLine()
+ {
+ return $this->commandline;
+ }
+
+ /**
+ * Sets the command line to be executed.
+ *
+ * @param string $commandline The command to execute
+ *
+ * @return self The current Process instance
+ */
+ public function setCommandLine($commandline)
+ {
+ $this->commandline = $commandline;
+
+ return $this;
+ }
+
+ /**
+ * Gets the process timeout (max. runtime).
+ *
+ * @return float|null The timeout in seconds or null if it's disabled
+ */
+ public function getTimeout()
+ {
+ return $this->timeout;
+ }
+
+ /**
+ * Gets the process idle timeout (max. time since last output).
+ *
+ * @return float|null The timeout in seconds or null if it's disabled
+ */
+ public function getIdleTimeout()
+ {
+ return $this->idleTimeout;
+ }
+
+ /**
+ * Sets the process timeout (max. runtime).
+ *
+ * To disable the timeout, set this value to null.
+ *
+ * @param int|float|null $timeout The timeout in seconds
+ *
+ * @return self The current Process instance
+ *
+ * @throws InvalidArgumentException if the timeout is negative
+ */
+ public function setTimeout($timeout)
+ {
+ $this->timeout = $this->validateTimeout($timeout);
+
+ return $this;
+ }
+
+ /**
+ * Sets the process idle timeout (max. time since last output).
+ *
+ * To disable the timeout, set this value to null.
+ *
+ * @param int|float|null $timeout The timeout in seconds
+ *
+ * @return self The current Process instance.
+ *
+ * @throws LogicException if the output is disabled
+ * @throws InvalidArgumentException if the timeout is negative
+ */
+ public function setIdleTimeout($timeout)
+ {
+ if (null !== $timeout && $this->outputDisabled) {
+ throw new LogicException('Idle timeout can not be set while the output is disabled.');
+ }
+
+ $this->idleTimeout = $this->validateTimeout($timeout);
+
+ return $this;
+ }
+
+ /**
+ * Enables or disables the TTY mode.
+ *
+ * @param bool $tty True to enabled and false to disable
+ *
+ * @return self The current Process instance
+ *
+ * @throws RuntimeException In case the TTY mode is not supported
+ */
+ public function setTty($tty)
+ {
+ if ('\\' === DIRECTORY_SEPARATOR && $tty) {
+ throw new RuntimeException('TTY mode is not supported on Windows platform.');
+ }
+ if ($tty && (!file_exists('/dev/tty') || !is_readable('/dev/tty'))) {
+ throw new RuntimeException('TTY mode requires /dev/tty to be readable.');
+ }
+
+ $this->tty = (bool) $tty;
+
+ return $this;
+ }
+
+ /**
+ * Checks if the TTY mode is enabled.
+ *
+ * @return bool true if the TTY mode is enabled, false otherwise
+ */
+ public function isTty()
+ {
+ return $this->tty;
+ }
+
+ /**
+ * Sets PTY mode.
+ *
+ * @param bool $bool
+ *
+ * @return self
+ */
+ public function setPty($bool)
+ {
+ $this->pty = (bool) $bool;
+
+ return $this;
+ }
+
+ /**
+ * Returns PTY state.
+ *
+ * @return bool
+ */
+ public function isPty()
+ {
+ return $this->pty;
+ }
+
+ /**
+ * Gets the working directory.
+ *
+ * @return string|null The current working directory or null on failure
+ */
+ public function getWorkingDirectory()
+ {
+ if (null === $this->cwd) {
+ // getcwd() will return false if any one of the parent directories does not have
+ // the readable or search mode set, even if the current directory does
+ return getcwd() ?: null;
+ }
+
+ return $this->cwd;
+ }
+
+ /**
+ * Sets the current working directory.
+ *
+ * @param string $cwd The new working directory
+ *
+ * @return self The current Process instance
+ */
+ public function setWorkingDirectory($cwd)
+ {
+ $this->cwd = $cwd;
+
+ return $this;
+ }
+
+ /**
+ * Gets the environment variables.
+ *
+ * @return array The current environment variables
+ */
+ public function getEnv()
+ {
+ return $this->env;
+ }
+
+ /**
+ * Sets the environment variables.
+ *
+ * An environment variable value should be a string.
+ * If it is an array, the variable is ignored.
+ *
+ * That happens in PHP when 'argv' is registered into
+ * the $_ENV array for instance.
+ *
+ * @param array $env The new environment variables
+ *
+ * @return self The current Process instance
+ */
+ public function setEnv(array $env)
+ {
+ // Process can not handle env values that are arrays
+ $env = array_filter($env, function ($value) {
+ return !is_array($value);
+ });
+
+ $this->env = array();
+ foreach ($env as $key => $value) {
+ $this->env[(binary) $key] = (binary) $value;
+ }
+
+ return $this;
+ }
+
+ /**
+ * Gets the contents of STDIN.
+ *
+ * @return string|null The current contents
+ *
+ * @deprecated since version 2.5, to be removed in 3.0.
+ * Use setInput() instead.
+ * This method is deprecated in favor of getInput.
+ */
+ public function getStdin()
+ {
+ @trigger_error('The '.__METHOD__.' method is deprecated since version 2.5 and will be removed in 3.0. Use the getInput() method instead.', E_USER_DEPRECATED);
+
+ return $this->getInput();
+ }
+
+ /**
+ * Gets the Process input.
+ *
+ * @return null|string The Process input
+ */
+ public function getInput()
+ {
+ return $this->input;
+ }
+
+ /**
+ * Sets the contents of STDIN.
+ *
+ * @param string|null $stdin The new contents
+ *
+ * @return self The current Process instance
+ *
+ * @deprecated since version 2.5, to be removed in 3.0.
+ * Use setInput() instead.
+ *
+ * @throws LogicException In case the process is running
+ * @throws InvalidArgumentException In case the argument is invalid
+ */
+ public function setStdin($stdin)
+ {
+ @trigger_error('The '.__METHOD__.' method is deprecated since version 2.5 and will be removed in 3.0. Use the setInput() method instead.', E_USER_DEPRECATED);
+
+ return $this->setInput($stdin);
+ }
+
+ /**
+ * Sets the input.
+ *
+ * This content will be passed to the underlying process standard input.
+ *
+ * @param mixed $input The content
+ *
+ * @return self The current Process instance
+ *
+ * @throws LogicException In case the process is running
+ *
+ * Passing an object as an input is deprecated since version 2.5 and will be removed in 3.0.
+ */
+ public function setInput($input)
+ {
+ if ($this->isRunning()) {
+ throw new LogicException('Input can not be set while the process is running.');
+ }
+
+ $this->input = ProcessUtils::validateInput(sprintf('%s::%s', __CLASS__, __FUNCTION__), $input);
+
+ return $this;
+ }
+
+ /**
+ * Gets the options for proc_open.
+ *
+ * @return array The current options
+ */
+ public function getOptions()
+ {
+ return $this->options;
+ }
+
+ /**
+ * Sets the options for proc_open.
+ *
+ * @param array $options The new options
+ *
+ * @return self The current Process instance
+ */
+ public function setOptions(array $options)
+ {
+ $this->options = $options;
+
+ return $this;
+ }
+
+ /**
+ * Gets whether or not Windows compatibility is enabled.
+ *
+ * This is true by default.
+ *
+ * @return bool
+ */
+ public function getEnhanceWindowsCompatibility()
+ {
+ return $this->enhanceWindowsCompatibility;
+ }
+
+ /**
+ * Sets whether or not Windows compatibility is enabled.
+ *
+ * @param bool $enhance
+ *
+ * @return self The current Process instance
+ */
+ public function setEnhanceWindowsCompatibility($enhance)
+ {
+ $this->enhanceWindowsCompatibility = (bool) $enhance;
+
+ return $this;
+ }
+
+ /**
+ * Returns whether sigchild compatibility mode is activated or not.
+ *
+ * @return bool
+ */
+ public function getEnhanceSigchildCompatibility()
+ {
+ return $this->enhanceSigchildCompatibility;
+ }
+
+ /**
+ * Activates sigchild compatibility mode.
+ *
+ * Sigchild compatibility mode is required to get the exit code and
+ * determine the success of a process when PHP has been compiled with
+ * the --enable-sigchild option
+ *
+ * @param bool $enhance
+ *
+ * @return self The current Process instance
+ */
+ public function setEnhanceSigchildCompatibility($enhance)
+ {
+ $this->enhanceSigchildCompatibility = (bool) $enhance;
+
+ return $this;
+ }
+
+ /**
+ * Performs a check between the timeout definition and the time the process started.
+ *
+ * In case you run a background process (with the start method), you should
+ * trigger this method regularly to ensure the process timeout
+ *
+ * @throws ProcessTimedOutException In case the timeout was reached
+ */
+ public function checkTimeout()
+ {
+ if ($this->status !== self::STATUS_STARTED) {
+ return;
+ }
+
+ if (null !== $this->timeout && $this->timeout < microtime(true) - $this->starttime) {
+ $this->stop(0);
+
+ throw new ProcessTimedOutException($this, ProcessTimedOutException::TYPE_GENERAL);
+ }
+
+ if (null !== $this->idleTimeout && $this->idleTimeout < microtime(true) - $this->lastOutputTime) {
+ $this->stop(0);
+
+ throw new ProcessTimedOutException($this, ProcessTimedOutException::TYPE_IDLE);
+ }
+ }
+
+ /**
+ * Returns whether PTY is supported on the current operating system.
+ *
+ * @return bool
+ */
+ public static function isPtySupported()
+ {
+ static $result;
+
+ if (null !== $result) {
+ return $result;
+ }
+
+ if ('\\' === DIRECTORY_SEPARATOR) {
+ return $result = false;
+ }
+
+ $proc = @proc_open('echo 1', array(array('pty'), array('pty'), array('pty')), $pipes);
+ if (is_resource($proc)) {
+ proc_close($proc);
+
+ return $result = true;
+ }
+
+ return $result = false;
+ }
+
+ /**
+ * Creates the descriptors needed by the proc_open.
+ *
+ * @return array
+ */
+ private function getDescriptors()
+ {
+ if ('\\' === DIRECTORY_SEPARATOR) {
+ $this->processPipes = WindowsPipes::create($this, $this->input);
+ } else {
+ $this->processPipes = UnixPipes::create($this, $this->input);
+ }
+ $descriptors = $this->processPipes->getDescriptors($this->outputDisabled);
+
+ if (!$this->useFileHandles && $this->enhanceSigchildCompatibility && $this->isSigchildEnabled()) {
+ // last exit code is output on the fourth pipe and caught to work around --enable-sigchild
+ $descriptors = array_merge($descriptors, array(array('pipe', 'w')));
+
+ $this->commandline = '('.$this->commandline.') 3>/dev/null; code=$?; echo $code >&3; exit $code';
+ }
+
+ return $descriptors;
+ }
+
+ /**
+ * Builds up the callback used by wait().
+ *
+ * The callbacks adds all occurred output to the specific buffer and calls
+ * the user callback (if present) with the received output.
+ *
+ * @param callable|null $callback The user defined PHP callback
+ *
+ * @return callable A PHP callable
+ */
+ protected function buildCallback($callback)
+ {
+ $that = $this;
+ $out = self::OUT;
+ $callback = function ($type, $data) use ($that, $callback, $out) {
+ if ($out == $type) {
+ $that->addOutput($data);
+ } else {
+ $that->addErrorOutput($data);
+ }
+
+ if (null !== $callback) {
+ call_user_func($callback, $type, $data);
+ }
+ };
+
+ return $callback;
+ }
+
+ /**
+ * Updates the status of the process, reads pipes.
+ *
+ * @param bool $blocking Whether to use a blocking read call.
+ */
+ protected function updateStatus($blocking)
+ {
+ if (self::STATUS_STARTED !== $this->status) {
+ return;
+ }
+
+ $this->processInformation = proc_get_status($this->process);
+ $this->captureExitCode();
+
+ $this->readPipes($blocking, '\\' === DIRECTORY_SEPARATOR ? !$this->processInformation['running'] : true);
+
+ if (!$this->processInformation['running']) {
+ $this->close();
+ }
+ }
+
+ /**
+ * Returns whether PHP has been compiled with the '--enable-sigchild' option or not.
+ *
+ * @return bool
+ */
+ protected function isSigchildEnabled()
+ {
+ if (null !== self::$sigchild) {
+ return self::$sigchild;
+ }
+
+ if (!function_exists('phpinfo')) {
+ return self::$sigchild = false;
+ }
+
+ ob_start();
+ phpinfo(INFO_GENERAL);
+
+ return self::$sigchild = false !== strpos(ob_get_clean(), '--enable-sigchild');
+ }
+
+ /**
+ * Validates and returns the filtered timeout.
+ *
+ * @param int|float|null $timeout
+ *
+ * @return float|null
+ *
+ * @throws InvalidArgumentException if the given timeout is a negative number
+ */
+ private function validateTimeout($timeout)
+ {
+ $timeout = (float) $timeout;
+
+ if (0.0 === $timeout) {
+ $timeout = null;
+ } elseif ($timeout < 0) {
+ throw new InvalidArgumentException('The timeout value must be a valid positive integer or float number.');
+ }
+
+ return $timeout;
+ }
+
+ /**
+ * Reads pipes, executes callback.
+ *
+ * @param bool $blocking Whether to use blocking calls or not.
+ * @param bool $close Whether to close file handles or not.
+ */
+ private function readPipes($blocking, $close)
+ {
+ $result = $this->processPipes->readAndWrite($blocking, $close);
+
+ $callback = $this->callback;
+ foreach ($result as $type => $data) {
+ if (3 == $type) {
+ $this->fallbackExitcode = (int) $data;
+ } else {
+ $callback($type === self::STDOUT ? self::OUT : self::ERR, $data);
+ }
+ }
+ }
+
+ /**
+ * Captures the exitcode if mentioned in the process information.
+ */
+ private function captureExitCode()
+ {
+ if (isset($this->processInformation['exitcode']) && -1 != $this->processInformation['exitcode']) {
+ $this->exitcode = $this->processInformation['exitcode'];
+ }
+ }
+
+ /**
+ * Closes process resource, closes file handles, sets the exitcode.
+ *
+ * @return int The exitcode
+ */
+ private function close()
+ {
+ $this->processPipes->close();
+ if (is_resource($this->process)) {
+ $exitcode = proc_close($this->process);
+ } else {
+ $exitcode = -1;
+ }
+
+ $this->exitcode = -1 !== $exitcode ? $exitcode : (null !== $this->exitcode ? $this->exitcode : -1);
+ $this->status = self::STATUS_TERMINATED;
+
+ if (-1 === $this->exitcode && null !== $this->fallbackExitcode) {
+ $this->exitcode = $this->fallbackExitcode;
+ } elseif (-1 === $this->exitcode && $this->processInformation['signaled'] && 0 < $this->processInformation['termsig']) {
+ // if process has been signaled, no exitcode but a valid termsig, apply Unix convention
+ $this->exitcode = 128 + $this->processInformation['termsig'];
+ }
+
+ return $this->exitcode;
+ }
+
+ /**
+ * Resets data related to the latest run of the process.
+ */
+ private function resetProcessData()
+ {
+ $this->starttime = null;
+ $this->callback = null;
+ $this->exitcode = null;
+ $this->fallbackExitcode = null;
+ $this->processInformation = null;
+ $this->stdout = null;
+ $this->stderr = null;
+ $this->process = null;
+ $this->latestSignal = null;
+ $this->status = self::STATUS_READY;
+ $this->incrementalOutputOffset = 0;
+ $this->incrementalErrorOutputOffset = 0;
+ }
+
+ /**
+ * Sends a POSIX signal to the process.
+ *
+ * @param int $signal A valid POSIX signal (see http://www.php.net/manual/en/pcntl.constants.php)
+ * @param bool $throwException Whether to throw exception in case signal failed
+ *
+ * @return bool True if the signal was sent successfully, false otherwise
+ *
+ * @throws LogicException In case the process is not running
+ * @throws RuntimeException In case --enable-sigchild is activated
+ * @throws RuntimeException In case of failure
+ */
+ private function doSignal($signal, $throwException)
+ {
+ if (!$this->isRunning()) {
+ if ($throwException) {
+ throw new LogicException('Can not send signal on a non running process.');
+ }
+
+ return false;
+ }
+
+ if ($this->isSigchildEnabled()) {
+ if ($throwException) {
+ throw new RuntimeException('This PHP has been compiled with --enable-sigchild. The process can not be signaled.');
+ }
+
+ return false;
+ }
+
+ if (true !== @proc_terminate($this->process, $signal)) {
+ if ($throwException) {
+ throw new RuntimeException(sprintf('Error while sending signal `%s`.', $signal));
+ }
+
+ return false;
+ }
+
+ $this->latestSignal = $signal;
+
+ return true;
+ }
+
+ /**
+ * Ensures the process is running or terminated, throws a LogicException if the process has a not started.
+ *
+ * @param string $functionName The function name that was called.
+ *
+ * @throws LogicException If the process has not run.
+ */
+ private function requireProcessIsStarted($functionName)
+ {
+ if (!$this->isStarted()) {
+ throw new LogicException(sprintf('Process must be started before calling %s.', $functionName));
+ }
+ }
+
+ /**
+ * Ensures the process is terminated, throws a LogicException if the process has a status different than `terminated`.
+ *
+ * @param string $functionName The function name that was called.
+ *
+ * @throws LogicException If the process is not yet terminated.
+ */
+ private function requireProcessIsTerminated($functionName)
+ {
+ if (!$this->isTerminated()) {
+ throw new LogicException(sprintf('Process must be terminated before calling %s.', $functionName));
+ }
+ }
+}
diff --git a/vendor/symfony/process/ProcessBuilder.php b/vendor/symfony/process/ProcessBuilder.php
new file mode 100644
index 00000000..a782fd69
--- /dev/null
+++ b/vendor/symfony/process/ProcessBuilder.php
@@ -0,0 +1,287 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Process;
+
+use Symfony\Component\Process\Exception\InvalidArgumentException;
+use Symfony\Component\Process\Exception\LogicException;
+
+/**
+ * Process builder.
+ *
+ * @author Kris Wallsmith <kris@symfony.com>
+ */
+class ProcessBuilder
+{
+ private $arguments;
+ private $cwd;
+ private $env = array();
+ private $input;
+ private $timeout = 60;
+ private $options = array();
+ private $inheritEnv = true;
+ private $prefix = array();
+ private $outputDisabled = false;
+
+ /**
+ * Constructor.
+ *
+ * @param string[] $arguments An array of arguments
+ */
+ public function __construct(array $arguments = array())
+ {
+ $this->arguments = $arguments;
+ }
+
+ /**
+ * Creates a process builder instance.
+ *
+ * @param string[] $arguments An array of arguments
+ *
+ * @return ProcessBuilder
+ */
+ public static function create(array $arguments = array())
+ {
+ return new static($arguments);
+ }
+
+ /**
+ * Adds an unescaped argument to the command string.
+ *
+ * @param string $argument A command argument
+ *
+ * @return ProcessBuilder
+ */
+ public function add($argument)
+ {
+ $this->arguments[] = $argument;
+
+ return $this;
+ }
+
+ /**
+ * Adds a prefix to the command string.
+ *
+ * The prefix is preserved when resetting arguments.
+ *
+ * @param string|array $prefix A command prefix or an array of command prefixes
+ *
+ * @return ProcessBuilder
+ */
+ public function setPrefix($prefix)
+ {
+ $this->prefix = is_array($prefix) ? $prefix : array($prefix);
+
+ return $this;
+ }
+
+ /**
+ * Sets the arguments of the process.
+ *
+ * Arguments must not be escaped.
+ * Previous arguments are removed.
+ *
+ * @param string[] $arguments
+ *
+ * @return ProcessBuilder
+ */
+ public function setArguments(array $arguments)
+ {
+ $this->arguments = $arguments;
+
+ return $this;
+ }
+
+ /**
+ * Sets the working directory.
+ *
+ * @param null|string $cwd The working directory
+ *
+ * @return ProcessBuilder
+ */
+ public function setWorkingDirectory($cwd)
+ {
+ $this->cwd = $cwd;
+
+ return $this;
+ }
+
+ /**
+ * Sets whether environment variables will be inherited or not.
+ *
+ * @param bool $inheritEnv
+ *
+ * @return ProcessBuilder
+ */
+ public function inheritEnvironmentVariables($inheritEnv = true)
+ {
+ $this->inheritEnv = $inheritEnv;
+
+ return $this;
+ }
+
+ /**
+ * Sets an environment variable.
+ *
+ * Setting a variable overrides its previous value. Use `null` to unset a
+ * defined environment variable.
+ *
+ * @param string $name The variable name
+ * @param null|string $value The variable value
+ *
+ * @return ProcessBuilder
+ */
+ public function setEnv($name, $value)
+ {
+ $this->env[$name] = $value;
+
+ return $this;
+ }
+
+ /**
+ * Adds a set of environment variables.
+ *
+ * Already existing environment variables with the same name will be
+ * overridden by the new values passed to this method. Pass `null` to unset
+ * a variable.
+ *
+ * @param array $variables The variables
+ *
+ * @return ProcessBuilder
+ */
+ public function addEnvironmentVariables(array $variables)
+ {
+ $this->env = array_replace($this->env, $variables);
+
+ return $this;
+ }
+
+ /**
+ * Sets the input of the process.
+ *
+ * @param mixed $input The input as a string
+ *
+ * @return ProcessBuilder
+ *
+ * @throws InvalidArgumentException In case the argument is invalid
+ *
+ * Passing an object as an input is deprecated since version 2.5 and will be removed in 3.0.
+ */
+ public function setInput($input)
+ {
+ $this->input = ProcessUtils::validateInput(sprintf('%s::%s', __CLASS__, __FUNCTION__), $input);
+
+ return $this;
+ }
+
+ /**
+ * Sets the process timeout.
+ *
+ * To disable the timeout, set this value to null.
+ *
+ * @param float|null $timeout
+ *
+ * @return ProcessBuilder
+ *
+ * @throws InvalidArgumentException
+ */
+ public function setTimeout($timeout)
+ {
+ if (null === $timeout) {
+ $this->timeout = null;
+
+ return $this;
+ }
+
+ $timeout = (float) $timeout;
+
+ if ($timeout < 0) {
+ throw new InvalidArgumentException('The timeout value must be a valid positive integer or float number.');
+ }
+
+ $this->timeout = $timeout;
+
+ return $this;
+ }
+
+ /**
+ * Adds a proc_open option.
+ *
+ * @param string $name The option name
+ * @param string $value The option value
+ *
+ * @return ProcessBuilder
+ */
+ public function setOption($name, $value)
+ {
+ $this->options[$name] = $value;
+
+ return $this;
+ }
+
+ /**
+ * Disables fetching output and error output from the underlying process.
+ *
+ * @return ProcessBuilder
+ */
+ public function disableOutput()
+ {
+ $this->outputDisabled = true;
+
+ return $this;
+ }
+
+ /**
+ * Enables fetching output and error output from the underlying process.
+ *
+ * @return ProcessBuilder
+ */
+ public function enableOutput()
+ {
+ $this->outputDisabled = false;
+
+ return $this;
+ }
+
+ /**
+ * Creates a Process instance and returns it.
+ *
+ * @return Process
+ *
+ * @throws LogicException In case no arguments have been provided
+ */
+ public function getProcess()
+ {
+ if (0 === count($this->prefix) && 0 === count($this->arguments)) {
+ throw new LogicException('You must add() command arguments before calling getProcess().');
+ }
+
+ $options = $this->options;
+
+ $arguments = array_merge($this->prefix, $this->arguments);
+ $script = implode(' ', array_map(array(__NAMESPACE__.'\\ProcessUtils', 'escapeArgument'), $arguments));
+
+ if ($this->inheritEnv) {
+ // include $_ENV for BC purposes
+ $env = array_replace($_ENV, $_SERVER, $this->env);
+ } else {
+ $env = $this->env;
+ }
+
+ $process = new Process($script, $this->cwd, $env, $this->input, $this->timeout, $options);
+
+ if ($this->outputDisabled) {
+ $process->disableOutput();
+ }
+
+ return $process;
+ }
+}
diff --git a/vendor/symfony/process/ProcessUtils.php b/vendor/symfony/process/ProcessUtils.php
new file mode 100644
index 00000000..4f30b630
--- /dev/null
+++ b/vendor/symfony/process/ProcessUtils.php
@@ -0,0 +1,115 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Process;
+
+use Symfony\Component\Process\Exception\InvalidArgumentException;
+
+/**
+ * ProcessUtils is a bunch of utility methods.
+ *
+ * This class contains static methods only and is not meant to be instantiated.
+ *
+ * @author Martin Hasoň <martin.hason@gmail.com>
+ */
+class ProcessUtils
+{
+ /**
+ * This class should not be instantiated.
+ */
+ private function __construct()
+ {
+ }
+
+ /**
+ * Escapes a string to be used as a shell argument.
+ *
+ * @param string $argument The argument that will be escaped
+ *
+ * @return string The escaped argument
+ */
+ public static function escapeArgument($argument)
+ {
+ //Fix for PHP bug #43784 escapeshellarg removes % from given string
+ //Fix for PHP bug #49446 escapeshellarg doesn't work on Windows
+ //@see https://bugs.php.net/bug.php?id=43784
+ //@see https://bugs.php.net/bug.php?id=49446
+ if ('\\' === DIRECTORY_SEPARATOR) {
+ if ('' === $argument) {
+ return escapeshellarg($argument);
+ }
+
+ $escapedArgument = '';
+ $quote = false;
+ foreach (preg_split('/(")/', $argument, -1, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE) as $part) {
+ if ('"' === $part) {
+ $escapedArgument .= '\\"';
+ } elseif (self::isSurroundedBy($part, '%')) {
+ // Avoid environment variable expansion
+ $escapedArgument .= '^%"'.substr($part, 1, -1).'"^%';
+ } else {
+ // escape trailing backslash
+ if ('\\' === substr($part, -1)) {
+ $part .= '\\';
+ }
+ $quote = true;
+ $escapedArgument .= $part;
+ }
+ }
+ if ($quote) {
+ $escapedArgument = '"'.$escapedArgument.'"';
+ }
+
+ return $escapedArgument;
+ }
+
+ return escapeshellarg($argument);
+ }
+
+ /**
+ * Validates and normalizes a Process input.
+ *
+ * @param string $caller The name of method call that validates the input
+ * @param mixed $input The input to validate
+ *
+ * @return string The validated input
+ *
+ * @throws InvalidArgumentException In case the input is not valid
+ *
+ * Passing an object as an input is deprecated since version 2.5 and will be removed in 3.0.
+ */
+ public static function validateInput($caller, $input)
+ {
+ if (null !== $input) {
+ if (is_resource($input)) {
+ return $input;
+ }
+ if (is_scalar($input)) {
+ return (string) $input;
+ }
+ // deprecated as of Symfony 2.5, to be removed in 3.0
+ if (is_object($input) && method_exists($input, '__toString')) {
+ @trigger_error('Passing an object as an input is deprecated since version 2.5 and will be removed in 3.0.', E_USER_DEPRECATED);
+
+ return (string) $input;
+ }
+
+ throw new InvalidArgumentException(sprintf('%s only accepts strings or stream resources.', $caller));
+ }
+
+ return $input;
+ }
+
+ private static function isSurroundedBy($arg, $char)
+ {
+ return 2 < strlen($arg) && $char === $arg[0] && $char === $arg[strlen($arg) - 1];
+ }
+}
diff --git a/vendor/symfony/process/README.md b/vendor/symfony/process/README.md
new file mode 100644
index 00000000..7c83ed41
--- /dev/null
+++ b/vendor/symfony/process/README.md
@@ -0,0 +1,51 @@
+Process Component
+=================
+
+Process executes commands in sub-processes.
+
+In this example, we run a simple directory listing and get the result back:
+
+```php
+use Symfony\Component\Process\Process;
+
+$process = new Process('ls -lsa');
+$process->setTimeout(3600);
+$process->run();
+if (!$process->isSuccessful()) {
+ throw new RuntimeException($process->getErrorOutput());
+}
+
+print $process->getOutput();
+```
+
+You can think that this is easy to achieve with plain PHP but it's not especially
+if you want to take care of the subtle differences between the different platforms.
+
+And if you want to be able to get some feedback in real-time, just pass an
+anonymous function to the ``run()`` method and you will get the output buffer
+as it becomes available:
+
+```php
+use Symfony\Component\Process\Process;
+
+$process = new Process('ls -lsa');
+$process->run(function ($type, $buffer) {
+ if (Process::ERR === $type) {
+ echo 'ERR > '.$buffer;
+ } else {
+ echo 'OUT > '.$buffer;
+ }
+});
+```
+
+That's great if you want to execute a long running command (like rsync-ing files to a
+remote server) and give feedback to the user in real-time.
+
+Resources
+---------
+
+You can run the unit tests with the following command:
+
+ $ cd path/to/Symfony/Component/Process/
+ $ composer install
+ $ phpunit
diff --git a/vendor/symfony/process/Tests/AbstractProcessTest.php b/vendor/symfony/process/Tests/AbstractProcessTest.php
new file mode 100644
index 00000000..2add8cc9
--- /dev/null
+++ b/vendor/symfony/process/Tests/AbstractProcessTest.php
@@ -0,0 +1,1205 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Process\Tests;
+
+use Symfony\Component\Process\Exception\LogicException;
+use Symfony\Component\Process\Exception\ProcessTimedOutException;
+use Symfony\Component\Process\Exception\RuntimeException;
+use Symfony\Component\Process\PhpExecutableFinder;
+use Symfony\Component\Process\Pipes\PipesInterface;
+use Symfony\Component\Process\Process;
+
+/**
+ * @author Robert Schönthal <seroscho@googlemail.com>
+ */
+abstract class AbstractProcessTest extends \PHPUnit_Framework_TestCase
+{
+ protected static $phpBin;
+
+ public static function setUpBeforeClass()
+ {
+ $phpBin = new PhpExecutableFinder();
+ self::$phpBin = $phpBin->find();
+ }
+
+ public function testThatProcessDoesNotThrowWarningDuringRun()
+ {
+ @trigger_error('Test Error', E_USER_NOTICE);
+ $process = $this->getProcess(self::$phpBin." -r 'sleep(3)'");
+ $process->run();
+ $actualError = error_get_last();
+ $this->assertEquals('Test Error', $actualError['message']);
+ $this->assertEquals(E_USER_NOTICE, $actualError['type']);
+ }
+
+ /**
+ * @expectedException \Symfony\Component\Process\Exception\InvalidArgumentException
+ */
+ public function testNegativeTimeoutFromConstructor()
+ {
+ $this->getProcess('', null, null, null, -1);
+ }
+
+ /**
+ * @expectedException \Symfony\Component\Process\Exception\InvalidArgumentException
+ */
+ public function testNegativeTimeoutFromSetter()
+ {
+ $p = $this->getProcess('');
+ $p->setTimeout(-1);
+ }
+
+ public function testFloatAndNullTimeout()
+ {
+ $p = $this->getProcess('');
+
+ $p->setTimeout(10);
+ $this->assertSame(10.0, $p->getTimeout());
+
+ $p->setTimeout(null);
+ $this->assertNull($p->getTimeout());
+
+ $p->setTimeout(0.0);
+ $this->assertNull($p->getTimeout());
+ }
+
+ public function testStopWithTimeoutIsActuallyWorking()
+ {
+ $this->verifyPosixIsEnabled();
+
+ // exec is mandatory here since we send a signal to the process
+ // see https://github.com/symfony/symfony/issues/5030 about prepending
+ // command with exec
+ $p = $this->getProcess('exec php '.__DIR__.'/NonStopableProcess.php 3');
+ $p->start();
+ usleep(100000);
+ $start = microtime(true);
+ $p->stop(1.1, SIGKILL);
+ while ($p->isRunning()) {
+ usleep(1000);
+ }
+ $duration = microtime(true) - $start;
+
+ $this->assertLessThan(4, $duration);
+ }
+
+ public function testAllOutputIsActuallyReadOnTermination()
+ {
+ // this code will result in a maximum of 2 reads of 8192 bytes by calling
+ // start() and isRunning(). by the time getOutput() is called the process
+ // has terminated so the internal pipes array is already empty. normally
+ // the call to start() will not read any data as the process will not have
+ // generated output, but this is non-deterministic so we must count it as
+ // a possibility. therefore we need 2 * PipesInterface::CHUNK_SIZE plus
+ // another byte which will never be read.
+ $expectedOutputSize = PipesInterface::CHUNK_SIZE * 2 + 2;
+
+ $code = sprintf('echo str_repeat(\'*\', %d);', $expectedOutputSize);
+ $p = $this->getProcess(sprintf('%s -r %s', self::$phpBin, escapeshellarg($code)));
+
+ $p->start();
+ // Let's wait enough time for process to finish...
+ // Here we don't call Process::run or Process::wait to avoid any read of pipes
+ usleep(500000);
+
+ if ($p->isRunning()) {
+ $this->markTestSkipped('Process execution did not complete in the required time frame');
+ }
+
+ $o = $p->getOutput();
+
+ $this->assertEquals($expectedOutputSize, strlen($o));
+ }
+
+ public function testCallbacksAreExecutedWithStart()
+ {
+ $data = '';
+
+ $process = $this->getProcess('echo foo && php -r "sleep(1);" && echo foo');
+ $process->start(function ($type, $buffer) use (&$data) {
+ $data .= $buffer;
+ });
+
+ while ($process->isRunning()) {
+ usleep(10000);
+ }
+
+ $this->assertEquals(2, preg_match_all('/foo/', $data, $matches));
+ }
+
+ /**
+ * tests results from sub processes.
+ *
+ * @dataProvider responsesCodeProvider
+ */
+ public function testProcessResponses($expected, $getter, $code)
+ {
+ $p = $this->getProcess(sprintf('%s -r %s', self::$phpBin, escapeshellarg($code)));
+ $p->run();
+
+ $this->assertSame($expected, $p->$getter());
+ }
+
+ /**
+ * tests results from sub processes.
+ *
+ * @dataProvider pipesCodeProvider
+ */
+ public function testProcessPipes($code, $size)
+ {
+ $expected = str_repeat(str_repeat('*', 1024), $size).'!';
+ $expectedLength = (1024 * $size) + 1;
+
+ $p = $this->getProcess(sprintf('%s -r %s', self::$phpBin, escapeshellarg($code)));
+ $p->setInput($expected);
+ $p->run();
+
+ $this->assertEquals($expectedLength, strlen($p->getOutput()));
+ $this->assertEquals($expectedLength, strlen($p->getErrorOutput()));
+ }
+
+ /**
+ * @dataProvider pipesCodeProvider
+ */
+ public function testSetStreamAsInput($code, $size)
+ {
+ $expected = str_repeat(str_repeat('*', 1024), $size).'!';
+ $expectedLength = (1024 * $size) + 1;
+
+ $stream = fopen('php://temporary', 'w+');
+ fwrite($stream, $expected);
+ rewind($stream);
+
+ $p = $this->getProcess(sprintf('%s -r %s', self::$phpBin, escapeshellarg($code)));
+ $p->setInput($stream);
+ $p->run();
+
+ fclose($stream);
+
+ $this->assertEquals($expectedLength, strlen($p->getOutput()));
+ $this->assertEquals($expectedLength, strlen($p->getErrorOutput()));
+ }
+
+ public function testSetInputWhileRunningThrowsAnException()
+ {
+ $process = $this->getProcess(self::$phpBin.' -r "usleep(500000);"');
+ $process->start();
+ try {
+ $process->setInput('foobar');
+ $process->stop();
+ $this->fail('A LogicException should have been raised.');
+ } catch (LogicException $e) {
+ $this->assertEquals('Input can not be set while the process is running.', $e->getMessage());
+ }
+ $process->stop();
+ }
+
+ /**
+ * @dataProvider provideInvalidInputValues
+ * @expectedException \Symfony\Component\Process\Exception\InvalidArgumentException
+ * @expectedExceptionMessage Symfony\Component\Process\Process::setInput only accepts strings or stream resources.
+ */
+ public function testInvalidInput($value)
+ {
+ $process = $this->getProcess(self::$phpBin.' -v');
+ $process->setInput($value);
+ }
+
+ public function provideInvalidInputValues()
+ {
+ return array(
+ array(array()),
+ array(new NonStringifiable()),
+ );
+ }
+
+ /**
+ * @dataProvider provideInputValues
+ */
+ public function testValidInput($expected, $value)
+ {
+ $process = $this->getProcess(self::$phpBin.' -v');
+ $process->setInput($value);
+ $this->assertSame($expected, $process->getInput());
+ }
+
+ public function provideInputValues()
+ {
+ return array(
+ array(null, null),
+ array('24.5', 24.5),
+ array('input data', 'input data'),
+ );
+ }
+
+ /**
+ * @dataProvider provideLegacyInputValues
+ * @group legacy
+ */
+ public function testLegacyValidInput($expected, $value)
+ {
+ $process = $this->getProcess(self::$phpBin.' -v');
+ $process->setInput($value);
+ $this->assertSame($expected, $process->getInput());
+ }
+
+ public function provideLegacyInputValues()
+ {
+ return array(
+ array('stringifiable', new Stringifiable()),
+ );
+ }
+
+ public function chainedCommandsOutputProvider()
+ {
+ if ('\\' === DIRECTORY_SEPARATOR) {
+ return array(
+ array("2 \r\n2\r\n", '&&', '2'),
+ );
+ }
+
+ return array(
+ array("1\n1\n", ';', '1'),
+ array("2\n2\n", '&&', '2'),
+ );
+ }
+
+ /**
+ * @dataProvider chainedCommandsOutputProvider
+ */
+ public function testChainedCommandsOutput($expected, $operator, $input)
+ {
+ $process = $this->getProcess(sprintf('echo %s %s echo %s', $input, $operator, $input));
+ $process->run();
+ $this->assertEquals($expected, $process->getOutput());
+ }
+
+ public function testCallbackIsExecutedForOutput()
+ {
+ $p = $this->getProcess(sprintf('%s -r %s', self::$phpBin, escapeshellarg('echo \'foo\';')));
+
+ $called = false;
+ $p->run(function ($type, $buffer) use (&$called) {
+ $called = $buffer === 'foo';
+ });
+
+ $this->assertTrue($called, 'The callback should be executed with the output');
+ }
+
+ public function testGetErrorOutput()
+ {
+ $p = $this->getProcess(sprintf('%s -r %s', self::$phpBin, escapeshellarg('$n = 0; while ($n < 3) { file_put_contents(\'php://stderr\', \'ERROR\'); $n++; }')));
+
+ $p->run();
+ $this->assertEquals(3, preg_match_all('/ERROR/', $p->getErrorOutput(), $matches));
+ }
+
+ public function testGetIncrementalErrorOutput()
+ {
+ // use a lock file to toggle between writing ("W") and reading ("R") the
+ // error stream
+ $lock = tempnam(sys_get_temp_dir(), get_class($this).'Lock');
+ file_put_contents($lock, 'W');
+
+ $p = $this->getProcess(sprintf('%s -r %s', self::$phpBin, escapeshellarg('$n = 0; while ($n < 3) { if (\'W\' === file_get_contents('.var_export($lock, true).')) { file_put_contents(\'php://stderr\', \'ERROR\'); $n++; file_put_contents('.var_export($lock, true).', \'R\'); } usleep(100); }')));
+
+ $p->start();
+ while ($p->isRunning()) {
+ if ('R' === file_get_contents($lock)) {
+ $this->assertLessThanOrEqual(1, preg_match_all('/ERROR/', $p->getIncrementalErrorOutput(), $matches));
+ file_put_contents($lock, 'W');
+ }
+ usleep(100);
+ }
+
+ unlink($lock);
+ }
+
+ public function testFlushErrorOutput()
+ {
+ $p = $this->getProcess(sprintf('%s -r %s', self::$phpBin, escapeshellarg('$n = 0; while ($n < 3) { file_put_contents(\'php://stderr\', \'ERROR\'); $n++; }')));
+
+ $p->run();
+ $p->clearErrorOutput();
+ $this->assertEmpty($p->getErrorOutput());
+ }
+
+ public function testGetEmptyIncrementalErrorOutput()
+ {
+ // use a lock file to toggle between writing ("W") and reading ("R") the
+ // output stream
+ $lock = tempnam(sys_get_temp_dir(), get_class($this).'Lock');
+ file_put_contents($lock, 'W');
+
+ $p = $this->getProcess(sprintf('%s -r %s', self::$phpBin, escapeshellarg('$n = 0; while ($n < 3) { if (\'W\' === file_get_contents('.var_export($lock, true).')) { file_put_contents(\'php://stderr\', \'ERROR\'); $n++; file_put_contents('.var_export($lock, true).', \'R\'); } usleep(100); }')));
+
+ $p->start();
+
+ $shouldWrite = false;
+
+ while ($p->isRunning()) {
+ if ('R' === file_get_contents($lock)) {
+ if (!$shouldWrite) {
+ $this->assertLessThanOrEqual(1, preg_match_all('/ERROR/', $p->getIncrementalOutput(), $matches));
+ $shouldWrite = true;
+ } else {
+ $this->assertSame('', $p->getIncrementalOutput());
+
+ file_put_contents($lock, 'W');
+ $shouldWrite = false;
+ }
+ }
+ usleep(100);
+ }
+
+ unlink($lock);
+ }
+
+ public function testGetOutput()
+ {
+ $p = $this->getProcess(sprintf('%s -r %s', self::$phpBin, escapeshellarg('$n = 0; while ($n < 3) { echo \' foo \'; $n++; }')));
+
+ $p->run();
+ $this->assertEquals(3, preg_match_all('/foo/', $p->getOutput(), $matches));
+ }
+
+ public function testGetIncrementalOutput()
+ {
+ // use a lock file to toggle between writing ("W") and reading ("R") the
+ // output stream
+ $lock = tempnam(sys_get_temp_dir(), get_class($this).'Lock');
+ file_put_contents($lock, 'W');
+
+ $p = $this->getProcess(sprintf('%s -r %s', self::$phpBin, escapeshellarg('$n = 0; while ($n < 3) { if (\'W\' === file_get_contents('.var_export($lock, true).')) { echo \' foo \'; $n++; file_put_contents('.var_export($lock, true).', \'R\'); } usleep(100); }')));
+
+ $p->start();
+ while ($p->isRunning()) {
+ if ('R' === file_get_contents($lock)) {
+ $this->assertLessThanOrEqual(1, preg_match_all('/foo/', $p->getIncrementalOutput(), $matches));
+ file_put_contents($lock, 'W');
+ }
+ usleep(100);
+ }
+
+ unlink($lock);
+ }
+
+ public function testFlushOutput()
+ {
+ $p = $this->getProcess(sprintf('%s -r %s', self::$phpBin, escapeshellarg('$n=0;while ($n<3) {echo \' foo \';$n++;}')));
+
+ $p->run();
+ $p->clearOutput();
+ $this->assertEmpty($p->getOutput());
+ }
+
+ public function testGetEmptyIncrementalOutput()
+ {
+ // use a lock file to toggle between writing ("W") and reading ("R") the
+ // output stream
+ $lock = tempnam(sys_get_temp_dir(), get_class($this).'Lock');
+ file_put_contents($lock, 'W');
+
+ $p = $this->getProcess(sprintf('%s -r %s', self::$phpBin, escapeshellarg('$n = 0; while ($n < 3) { if (\'W\' === file_get_contents('.var_export($lock, true).')) { echo \' foo \'; $n++; file_put_contents('.var_export($lock, true).', \'R\'); } usleep(100); }')));
+
+ $p->start();
+
+ $shouldWrite = false;
+
+ while ($p->isRunning()) {
+ if ('R' === file_get_contents($lock)) {
+ if (!$shouldWrite) {
+ $this->assertLessThanOrEqual(1, preg_match_all('/foo/', $p->getIncrementalOutput(), $matches));
+ $shouldWrite = true;
+ } else {
+ $this->assertSame('', $p->getIncrementalOutput());
+
+ file_put_contents($lock, 'W');
+ $shouldWrite = false;
+ }
+ }
+ usleep(100);
+ }
+
+ unlink($lock);
+ }
+
+ public function testZeroAsOutput()
+ {
+ if ('\\' === DIRECTORY_SEPARATOR) {
+ // see http://stackoverflow.com/questions/7105433/windows-batch-echo-without-new-line
+ $p = $this->getProcess('echo | set /p dummyName=0');
+ } else {
+ $p = $this->getProcess('printf 0');
+ }
+
+ $p->run();
+ $this->assertSame('0', $p->getOutput());
+ }
+
+ public function testExitCodeCommandFailed()
+ {
+ if ('\\' === DIRECTORY_SEPARATOR) {
+ $this->markTestSkipped('Windows does not support POSIX exit code');
+ }
+
+ // such command run in bash return an exitcode 127
+ $process = $this->getProcess('nonexistingcommandIhopeneversomeonewouldnameacommandlikethis');
+ $process->run();
+
+ $this->assertGreaterThan(0, $process->getExitCode());
+ }
+
+ public function testTTYCommand()
+ {
+ if ('\\' === DIRECTORY_SEPARATOR) {
+ $this->markTestSkipped('Windows does have /dev/tty support');
+ }
+
+ $process = $this->getProcess('echo "foo" >> /dev/null && php -r "usleep(100000);"');
+ $process->setTty(true);
+ $process->start();
+ $this->assertTrue($process->isRunning());
+ $process->wait();
+
+ $this->assertSame(Process::STATUS_TERMINATED, $process->getStatus());
+ }
+
+ public function testTTYCommandExitCode()
+ {
+ if ('\\' === DIRECTORY_SEPARATOR) {
+ $this->markTestSkipped('Windows does have /dev/tty support');
+ }
+
+ $process = $this->getProcess('echo "foo" >> /dev/null');
+ $process->setTty(true);
+ $process->run();
+
+ $this->assertTrue($process->isSuccessful());
+ }
+
+ public function testTTYInWindowsEnvironment()
+ {
+ if ('\\' !== DIRECTORY_SEPARATOR) {
+ $this->markTestSkipped('This test is for Windows platform only');
+ }
+
+ $process = $this->getProcess('echo "foo" >> /dev/null');
+ $process->setTty(false);
+ $this->setExpectedException('Symfony\Component\Process\Exception\RuntimeException', 'TTY mode is not supported on Windows platform.');
+ $process->setTty(true);
+ }
+
+ public function testExitCodeTextIsNullWhenExitCodeIsNull()
+ {
+ $process = $this->getProcess('');
+ $this->assertNull($process->getExitCodeText());
+ }
+
+ public function testPTYCommand()
+ {
+ if (!Process::isPtySupported()) {
+ $this->markTestSkipped('PTY is not supported on this operating system.');
+ }
+
+ $process = $this->getProcess('echo "foo"');
+ $process->setPty(true);
+ $process->run();
+
+ $this->assertSame(Process::STATUS_TERMINATED, $process->getStatus());
+ $this->assertEquals("foo\r\n", $process->getOutput());
+ }
+
+ public function testMustRun()
+ {
+ $process = $this->getProcess('echo foo');
+
+ $this->assertSame($process, $process->mustRun());
+ $this->assertEquals("foo".PHP_EOL, $process->getOutput());
+ }
+
+ public function testSuccessfulMustRunHasCorrectExitCode()
+ {
+ $process = $this->getProcess('echo foo')->mustRun();
+ $this->assertEquals(0, $process->getExitCode());
+ }
+
+ /**
+ * @expectedException \Symfony\Component\Process\Exception\ProcessFailedException
+ */
+ public function testMustRunThrowsException()
+ {
+ $process = $this->getProcess('exit 1');
+ $process->mustRun();
+ }
+
+ public function testExitCodeText()
+ {
+ $process = $this->getProcess('');
+ $r = new \ReflectionObject($process);
+ $p = $r->getProperty('exitcode');
+ $p->setAccessible(true);
+
+ $p->setValue($process, 2);
+ $this->assertEquals('Misuse of shell builtins', $process->getExitCodeText());
+ }
+
+ public function testStartIsNonBlocking()
+ {
+ $process = $this->getProcess(self::$phpBin.' -r "usleep(500000);"');
+ $start = microtime(true);
+ $process->start();
+ $end = microtime(true);
+ $this->assertLessThan(0.2, $end-$start);
+ $process->wait();
+ }
+
+ public function testUpdateStatus()
+ {
+ $process = $this->getProcess(self::$phpBin.' -v');
+ $process->run();
+ $this->assertTrue(strlen($process->getOutput()) > 0);
+ }
+
+ public function testGetExitCodeIsNullOnStart()
+ {
+ $process = $this->getProcess(self::$phpBin.' -r "usleep(200000);"');
+ $this->assertNull($process->getExitCode());
+ $process->start();
+ $this->assertNull($process->getExitCode());
+ $process->wait();
+ $this->assertEquals(0, $process->getExitCode());
+ }
+
+ public function testGetExitCodeIsNullOnWhenStartingAgain()
+ {
+ $process = $this->getProcess(self::$phpBin.' -r "usleep(200000);"');
+ $process->run();
+ $this->assertEquals(0, $process->getExitCode());
+ $process->start();
+ $this->assertNull($process->getExitCode());
+ $process->wait();
+ $this->assertEquals(0, $process->getExitCode());
+ }
+
+ public function testGetExitCode()
+ {
+ $process = $this->getProcess(self::$phpBin.' -v');
+ $process->run();
+ $this->assertSame(0, $process->getExitCode());
+ }
+
+ public function testStatus()
+ {
+ $process = $this->getProcess(self::$phpBin.' -r "usleep(500000);"');
+ $this->assertFalse($process->isRunning());
+ $this->assertFalse($process->isStarted());
+ $this->assertFalse($process->isTerminated());
+ $this->assertSame(Process::STATUS_READY, $process->getStatus());
+ $process->start();
+ $this->assertTrue($process->isRunning());
+ $this->assertTrue($process->isStarted());
+ $this->assertFalse($process->isTerminated());
+ $this->assertSame(Process::STATUS_STARTED, $process->getStatus());
+ $process->wait();
+ $this->assertFalse($process->isRunning());
+ $this->assertTrue($process->isStarted());
+ $this->assertTrue($process->isTerminated());
+ $this->assertSame(Process::STATUS_TERMINATED, $process->getStatus());
+ }
+
+ public function testStop()
+ {
+ $process = $this->getProcess(self::$phpBin.' -r "sleep(4);"');
+ $process->start();
+ $this->assertTrue($process->isRunning());
+ $process->stop();
+ $this->assertFalse($process->isRunning());
+ }
+
+ public function testIsSuccessful()
+ {
+ $process = $this->getProcess(self::$phpBin.' -v');
+ $process->run();
+ $this->assertTrue($process->isSuccessful());
+ }
+
+ public function testIsSuccessfulOnlyAfterTerminated()
+ {
+ $process = $this->getProcess(self::$phpBin.' -r "sleep(1);"');
+ $process->start();
+ while ($process->isRunning()) {
+ $this->assertFalse($process->isSuccessful());
+ usleep(300000);
+ }
+
+ $this->assertTrue($process->isSuccessful());
+ }
+
+ public function testIsNotSuccessful()
+ {
+ $process = $this->getProcess(self::$phpBin.' -r "usleep(500000);throw new \Exception(\'BOUM\');"');
+ $process->start();
+ $this->assertTrue($process->isRunning());
+ $process->wait();
+ $this->assertFalse($process->isSuccessful());
+ }
+
+ public function testProcessIsNotSignaled()
+ {
+ if ('\\' === DIRECTORY_SEPARATOR) {
+ $this->markTestSkipped('Windows does not support POSIX signals');
+ }
+
+ $process = $this->getProcess(self::$phpBin.' -v');
+ $process->run();
+ $this->assertFalse($process->hasBeenSignaled());
+ }
+
+ public function testProcessWithoutTermSignalIsNotSignaled()
+ {
+ if ('\\' === DIRECTORY_SEPARATOR) {
+ $this->markTestSkipped('Windows does not support POSIX signals');
+ }
+
+ $process = $this->getProcess(self::$phpBin.' -v');
+ $process->run();
+ $this->assertFalse($process->hasBeenSignaled());
+ }
+
+ public function testProcessWithoutTermSignal()
+ {
+ if ('\\' === DIRECTORY_SEPARATOR) {
+ $this->markTestSkipped('Windows does not support POSIX signals');
+ }
+
+ $process = $this->getProcess(self::$phpBin.' -v');
+ $process->run();
+ $this->assertEquals(0, $process->getTermSignal());
+ }
+
+ public function testProcessIsSignaledIfStopped()
+ {
+ if ('\\' === DIRECTORY_SEPARATOR) {
+ $this->markTestSkipped('Windows does not support POSIX signals');
+ }
+
+ $process = $this->getProcess(self::$phpBin.' -r "sleep(4);"');
+ $process->start();
+ $process->stop();
+ $this->assertTrue($process->hasBeenSignaled());
+ }
+
+ public function testProcessWithTermSignal()
+ {
+ if ('\\' === DIRECTORY_SEPARATOR) {
+ $this->markTestSkipped('Windows does not support POSIX signals');
+ }
+
+ // SIGTERM is only defined if pcntl extension is present
+ $termSignal = defined('SIGTERM') ? SIGTERM : 15;
+
+ $process = $this->getProcess(self::$phpBin.' -r "sleep(4);"');
+ $process->start();
+ $process->stop();
+
+ $this->assertEquals($termSignal, $process->getTermSignal());
+ }
+
+ public function testProcessThrowsExceptionWhenExternallySignaled()
+ {
+ if ('\\' === DIRECTORY_SEPARATOR) {
+ $this->markTestSkipped('Windows does not support POSIX signals');
+ }
+
+ if (!function_exists('posix_kill')) {
+ $this->markTestSkipped('posix_kill is required for this test');
+ }
+
+ $termSignal = defined('SIGKILL') ? SIGKILL : 9;
+
+ $process = $this->getProcess('exec php -r "while (true) {}"');
+ $process->start();
+ posix_kill($process->getPid(), $termSignal);
+
+ $this->setExpectedException('Symfony\Component\Process\Exception\RuntimeException', 'The process has been signaled with signal "9".');
+ $process->wait();
+ }
+
+ public function testRestart()
+ {
+ $process1 = $this->getProcess(self::$phpBin.' -r "echo getmypid();"');
+ $process1->run();
+ $process2 = $process1->restart();
+
+ $process2->wait(); // wait for output
+
+ // Ensure that both processed finished and the output is numeric
+ $this->assertFalse($process1->isRunning());
+ $this->assertFalse($process2->isRunning());
+ $this->assertTrue(is_numeric($process1->getOutput()));
+ $this->assertTrue(is_numeric($process2->getOutput()));
+
+ // Ensure that restart returned a new process by check that the output is different
+ $this->assertNotEquals($process1->getOutput(), $process2->getOutput());
+ }
+
+ public function testPhpDeadlock()
+ {
+ $this->markTestSkipped('Can cause PHP to hang');
+
+ // Sleep doesn't work as it will allow the process to handle signals and close
+ // file handles from the other end.
+ $process = $this->getProcess(self::$phpBin.' -r "while (true) {}"');
+ $process->start();
+
+ // PHP will deadlock when it tries to cleanup $process
+ }
+
+ public function testRunProcessWithTimeout()
+ {
+ $timeout = 0.5;
+ $process = $this->getProcess(self::$phpBin.' -r "usleep(600000);"');
+ $process->setTimeout($timeout);
+ $start = microtime(true);
+ try {
+ $process->run();
+ $this->fail('A RuntimeException should have been raised');
+ } catch (RuntimeException $e) {
+ }
+ $duration = microtime(true) - $start;
+
+ if ('\\' === DIRECTORY_SEPARATOR) {
+ // Windows is a bit slower as it read file handles, then allow twice the precision
+ $maxDuration = $timeout + 2 * Process::TIMEOUT_PRECISION;
+ } else {
+ $maxDuration = $timeout + Process::TIMEOUT_PRECISION;
+ }
+
+ $this->assertLessThan($maxDuration, $duration);
+ }
+
+ public function testCheckTimeoutOnNonStartedProcess()
+ {
+ $process = $this->getProcess(self::$phpBin.' -r "sleep(3);"');
+ $process->checkTimeout();
+ }
+
+ public function testCheckTimeoutOnTerminatedProcess()
+ {
+ $process = $this->getProcess(self::$phpBin.' -v');
+ $process->run();
+ $process->checkTimeout();
+ }
+
+ public function testCheckTimeoutOnStartedProcess()
+ {
+ $timeout = 0.5;
+ $precision = 100000;
+ $process = $this->getProcess(self::$phpBin.' -r "sleep(3);"');
+ $process->setTimeout($timeout);
+ $start = microtime(true);
+
+ $process->start();
+
+ try {
+ while ($process->isRunning()) {
+ $process->checkTimeout();
+ usleep($precision);
+ }
+ $this->fail('A RuntimeException should have been raised');
+ } catch (RuntimeException $e) {
+ }
+ $duration = microtime(true) - $start;
+
+ $this->assertLessThan($timeout + $precision, $duration);
+ $this->assertFalse($process->isSuccessful());
+ }
+
+ public function testIdleTimeout()
+ {
+ $process = $this->getProcess(self::$phpBin.' -r "sleep(3);"');
+ $process->setTimeout(10);
+ $process->setIdleTimeout(0.5);
+
+ try {
+ $process->run();
+
+ $this->fail('A timeout exception was expected.');
+ } catch (ProcessTimedOutException $ex) {
+ $this->assertTrue($ex->isIdleTimeout());
+ $this->assertFalse($ex->isGeneralTimeout());
+ $this->assertEquals(0.5, $ex->getExceededTimeout());
+ }
+ }
+
+ public function testIdleTimeoutNotExceededWhenOutputIsSent()
+ {
+ $process = $this->getProcess(sprintf('%s -r %s', self::$phpBin, escapeshellarg('$n = 30; while ($n--) {echo "foo\n"; usleep(100000); }')));
+ $process->setTimeout(2);
+ $process->setIdleTimeout(1);
+
+ try {
+ $process->run();
+ $this->fail('A timeout exception was expected.');
+ } catch (ProcessTimedOutException $ex) {
+ $this->assertTrue($ex->isGeneralTimeout(), 'A general timeout is expected.');
+ $this->assertFalse($ex->isIdleTimeout(), 'No idle timeout is expected.');
+ $this->assertEquals(2, $ex->getExceededTimeout());
+ }
+ }
+
+ public function testStartAfterATimeout()
+ {
+ $process = $this->getProcess(sprintf('%s -r %s', self::$phpBin, escapeshellarg('$n = 1000; while ($n--) {echo \'\'; usleep(1000); }')));
+ $process->setTimeout(0.1);
+
+ try {
+ $process->run();
+ $this->fail('A RuntimeException should have been raised.');
+ } catch (RuntimeException $e) {
+ }
+ $process->start();
+ usleep(1000);
+ $process->stop();
+ }
+
+ public function testGetPid()
+ {
+ $process = $this->getProcess(self::$phpBin.' -r "usleep(500000);"');
+ $process->start();
+ $this->assertGreaterThan(0, $process->getPid());
+ $process->wait();
+ }
+
+ public function testGetPidIsNullBeforeStart()
+ {
+ $process = $this->getProcess(self::$phpBin.' -r "sleep(1);"');
+ $this->assertNull($process->getPid());
+ }
+
+ public function testGetPidIsNullAfterRun()
+ {
+ $process = $this->getProcess(self::$phpBin.' -v');
+ $process->run();
+ $this->assertNull($process->getPid());
+ }
+
+ public function testSignal()
+ {
+ $this->verifyPosixIsEnabled();
+
+ $process = $this->getProcess('exec php -f '.__DIR__.'/SignalListener.php');
+ $process->start();
+ usleep(500000);
+ $process->signal(SIGUSR1);
+
+ while ($process->isRunning() && false === strpos($process->getOutput(), 'Caught SIGUSR1')) {
+ usleep(10000);
+ }
+
+ $this->assertEquals('Caught SIGUSR1', $process->getOutput());
+ }
+
+ public function testExitCodeIsAvailableAfterSignal()
+ {
+ $this->verifyPosixIsEnabled();
+
+ $process = $this->getProcess('sleep 4');
+ $process->start();
+ $process->signal(SIGKILL);
+
+ while ($process->isRunning()) {
+ usleep(10000);
+ }
+
+ $this->assertFalse($process->isRunning());
+ $this->assertTrue($process->hasBeenSignaled());
+ $this->assertFalse($process->isSuccessful());
+ $this->assertEquals(137, $process->getExitCode());
+ }
+
+ /**
+ * @expectedException \Symfony\Component\Process\Exception\LogicException
+ */
+ public function testSignalProcessNotRunning()
+ {
+ $this->verifyPosixIsEnabled();
+ $process = $this->getProcess(self::$phpBin.' -v');
+ $process->signal(SIGHUP);
+ }
+
+ /**
+ * @dataProvider provideMethodsThatNeedARunningProcess
+ */
+ public function testMethodsThatNeedARunningProcess($method)
+ {
+ $process = $this->getProcess(self::$phpBin.' -v');
+ $this->setExpectedException('Symfony\Component\Process\Exception\LogicException', sprintf('Process must be started before calling %s.', $method));
+ $process->{$method}();
+ }
+
+ public function provideMethodsThatNeedARunningProcess()
+ {
+ return array(
+ array('getOutput'),
+ array('getIncrementalOutput'),
+ array('getErrorOutput'),
+ array('getIncrementalErrorOutput'),
+ array('wait'),
+ );
+ }
+
+ /**
+ * @dataProvider provideMethodsThatNeedATerminatedProcess
+ */
+ public function testMethodsThatNeedATerminatedProcess($method)
+ {
+ $process = $this->getProcess(self::$phpBin.' -r "sleep(1);"');
+ $process->start();
+ try {
+ $process->{$method}();
+ $process->stop(0);
+ $this->fail('A LogicException must have been thrown');
+ } catch (\Exception $e) {
+ $this->assertInstanceOf('Symfony\Component\Process\Exception\LogicException', $e);
+ $this->assertEquals(sprintf('Process must be terminated before calling %s.', $method), $e->getMessage());
+ }
+ $process->stop(0);
+ }
+
+ public function provideMethodsThatNeedATerminatedProcess()
+ {
+ return array(
+ array('hasBeenSignaled'),
+ array('getTermSignal'),
+ array('hasBeenStopped'),
+ array('getStopSignal'),
+ );
+ }
+
+ private function verifyPosixIsEnabled()
+ {
+ if ('\\' === DIRECTORY_SEPARATOR) {
+ $this->markTestSkipped('POSIX signals do not work on Windows');
+ }
+ if (!defined('SIGUSR1')) {
+ $this->markTestSkipped('The pcntl extension is not enabled');
+ }
+ }
+
+ /**
+ * @expectedException \Symfony\Component\Process\Exception\RuntimeException
+ */
+ public function testSignalWithWrongIntSignal()
+ {
+ if ('\\' === DIRECTORY_SEPARATOR) {
+ $this->markTestSkipped('POSIX signals do not work on Windows');
+ }
+
+ $process = $this->getProcess(self::$phpBin.' -r "sleep(3);"');
+ $process->start();
+ $process->signal(-4);
+ }
+
+ /**
+ * @expectedException \Symfony\Component\Process\Exception\RuntimeException
+ */
+ public function testSignalWithWrongNonIntSignal()
+ {
+ if ('\\' === DIRECTORY_SEPARATOR) {
+ $this->markTestSkipped('POSIX signals do not work on Windows');
+ }
+
+ $process = $this->getProcess(self::$phpBin.' -r "sleep(3);"');
+ $process->start();
+ $process->signal('Céphalopodes');
+ }
+
+ public function testDisableOutputDisablesTheOutput()
+ {
+ $p = $this->getProcess(self::$phpBin.' -r "usleep(500000);"');
+ $this->assertFalse($p->isOutputDisabled());
+ $p->disableOutput();
+ $this->assertTrue($p->isOutputDisabled());
+ $p->enableOutput();
+ $this->assertFalse($p->isOutputDisabled());
+ }
+
+ public function testDisableOutputWhileRunningThrowsException()
+ {
+ $p = $this->getProcess(self::$phpBin.' -r "usleep(500000);"');
+ $p->start();
+ $this->setExpectedException('Symfony\Component\Process\Exception\RuntimeException', 'Disabling output while the process is running is not possible.');
+ $p->disableOutput();
+ }
+
+ public function testEnableOutputWhileRunningThrowsException()
+ {
+ $p = $this->getProcess(self::$phpBin.' -r "usleep(500000);"');
+ $p->disableOutput();
+ $p->start();
+ $this->setExpectedException('Symfony\Component\Process\Exception\RuntimeException', 'Enabling output while the process is running is not possible.');
+ $p->enableOutput();
+ }
+
+ public function testEnableOrDisableOutputAfterRunDoesNotThrowException()
+ {
+ $p = $this->getProcess(self::$phpBin.' -r "usleep(500000);"');
+ $p->disableOutput();
+ $p->start();
+ $p->wait();
+ $p->enableOutput();
+ $p->disableOutput();
+ }
+
+ public function testDisableOutputWhileIdleTimeoutIsSet()
+ {
+ $process = $this->getProcess('sleep 3');
+ $process->setIdleTimeout(1);
+ $this->setExpectedException('Symfony\Component\Process\Exception\LogicException', 'Output can not be disabled while an idle timeout is set.');
+ $process->disableOutput();
+ }
+
+ public function testSetIdleTimeoutWhileOutputIsDisabled()
+ {
+ $process = $this->getProcess('sleep 3');
+ $process->disableOutput();
+ $this->setExpectedException('Symfony\Component\Process\Exception\LogicException', 'Idle timeout can not be set while the output is disabled.');
+ $process->setIdleTimeout(1);
+ }
+
+ public function testSetNullIdleTimeoutWhileOutputIsDisabled()
+ {
+ $process = $this->getProcess('sleep 3');
+ $process->disableOutput();
+ $process->setIdleTimeout(null);
+ }
+
+ /**
+ * @dataProvider provideStartMethods
+ */
+ public function testStartWithACallbackAndDisabledOutput($startMethod, $exception, $exceptionMessage)
+ {
+ $p = $this->getProcess(self::$phpBin.' -r "usleep(500000);"');
+ $p->disableOutput();
+ $this->setExpectedException($exception, $exceptionMessage);
+ $p->{$startMethod}(function () {});
+ }
+
+ public function provideStartMethods()
+ {
+ return array(
+ array('start', 'Symfony\Component\Process\Exception\LogicException', 'Output has been disabled, enable it to allow the use of a callback.'),
+ array('run', 'Symfony\Component\Process\Exception\LogicException', 'Output has been disabled, enable it to allow the use of a callback.'),
+ array('mustRun', 'Symfony\Component\Process\Exception\LogicException', 'Output has been disabled, enable it to allow the use of a callback.'),
+ );
+ }
+
+ /**
+ * @dataProvider provideOutputFetchingMethods
+ */
+ public function testGetOutputWhileDisabled($fetchMethod)
+ {
+ $p = $this->getProcess(self::$phpBin.' -r "usleep(500000);"');
+ $p->disableOutput();
+ $p->start();
+ $this->setExpectedException('Symfony\Component\Process\Exception\LogicException', 'Output has been disabled.');
+ $p->{$fetchMethod}();
+ }
+
+ public function provideOutputFetchingMethods()
+ {
+ return array(
+ array('getOutput'),
+ array('getIncrementalOutput'),
+ array('getErrorOutput'),
+ array('getIncrementalErrorOutput'),
+ );
+ }
+
+ public function responsesCodeProvider()
+ {
+ return array(
+ //expected output / getter / code to execute
+ //array(1,'getExitCode','exit(1);'),
+ //array(true,'isSuccessful','exit();'),
+ array('output', 'getOutput', 'echo \'output\';'),
+ );
+ }
+
+ public function pipesCodeProvider()
+ {
+ $variations = array(
+ 'fwrite(STDOUT, $in = file_get_contents(\'php://stdin\')); fwrite(STDERR, $in);',
+ 'include \''.__DIR__.'/PipeStdinInStdoutStdErrStreamSelect.php\';',
+ );
+
+ if ('\\' === DIRECTORY_SEPARATOR) {
+ // Avoid XL buffers on Windows because of https://bugs.php.net/bug.php?id=65650
+ $sizes = array(1, 2, 4, 8);
+ } else {
+ $sizes = array(1, 16, 64, 1024, 4096);
+ }
+
+ $codes = array();
+ foreach ($sizes as $size) {
+ foreach ($variations as $code) {
+ $codes[] = array($code, $size);
+ }
+ }
+
+ return $codes;
+ }
+
+ /**
+ * provides default method names for simple getter/setter.
+ */
+ public function methodProvider()
+ {
+ $defaults = array(
+ array('CommandLine'),
+ array('Timeout'),
+ array('WorkingDirectory'),
+ array('Env'),
+ array('Stdin'),
+ array('Input'),
+ array('Options'),
+ );
+
+ return $defaults;
+ }
+
+ /**
+ * @param string $commandline
+ * @param null|string $cwd
+ * @param null|array $env
+ * @param null|string $input
+ * @param int $timeout
+ * @param array $options
+ *
+ * @return Process
+ */
+ abstract protected function getProcess($commandline, $cwd = null, array $env = null, $input = null, $timeout = 60, array $options = array());
+}
+
+class Stringifiable
+{
+ public function __toString()
+ {
+ return 'stringifiable';
+ }
+}
+
+class NonStringifiable
+{
+}
diff --git a/vendor/symfony/process/Tests/ExecutableFinderTest.php b/vendor/symfony/process/Tests/ExecutableFinderTest.php
new file mode 100644
index 00000000..61a471b4
--- /dev/null
+++ b/vendor/symfony/process/Tests/ExecutableFinderTest.php
@@ -0,0 +1,149 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Process\Tests;
+
+use Symfony\Component\Process\ExecutableFinder;
+
+/**
+ * @author Chris Smith <chris@cs278.org>
+ */
+class ExecutableFinderTest extends \PHPUnit_Framework_TestCase
+{
+ private $path;
+
+ protected function tearDown()
+ {
+ if ($this->path) {
+ // Restore path if it was changed.
+ putenv('PATH='.$this->path);
+ }
+ }
+
+ private function setPath($path)
+ {
+ $this->path = getenv('PATH');
+ putenv('PATH='.$path);
+ }
+
+ public function testFind()
+ {
+ if (!defined('PHP_BINARY')) {
+ $this->markTestSkipped('Requires the PHP_BINARY constant');
+ }
+
+ if (ini_get('open_basedir')) {
+ $this->markTestSkipped('Cannot test when open_basedir is set');
+ }
+
+ $this->setPath(dirname(PHP_BINARY));
+
+ $finder = new ExecutableFinder();
+ $result = $finder->find($this->getPhpBinaryName());
+
+ $this->assertSamePath(PHP_BINARY, $result);
+ }
+
+ public function testFindWithDefault()
+ {
+ if (ini_get('open_basedir')) {
+ $this->markTestSkipped('Cannot test when open_basedir is set');
+ }
+
+ $expected = 'defaultValue';
+
+ $this->setPath('');
+
+ $finder = new ExecutableFinder();
+ $result = $finder->find('foo', $expected);
+
+ $this->assertEquals($expected, $result);
+ }
+
+ public function testFindWithExtraDirs()
+ {
+ if (!defined('PHP_BINARY')) {
+ $this->markTestSkipped('Requires the PHP_BINARY constant');
+ }
+
+ if (ini_get('open_basedir')) {
+ $this->markTestSkipped('Cannot test when open_basedir is set');
+ }
+
+ $this->setPath('');
+
+ $extraDirs = array(dirname(PHP_BINARY));
+
+ $finder = new ExecutableFinder();
+ $result = $finder->find($this->getPhpBinaryName(), null, $extraDirs);
+
+ $this->assertSamePath(PHP_BINARY, $result);
+ }
+
+ public function testFindWithOpenBaseDir()
+ {
+ if (!defined('PHP_BINARY')) {
+ $this->markTestSkipped('Requires the PHP_BINARY constant');
+ }
+
+ if ('\\' === DIRECTORY_SEPARATOR) {
+ $this->markTestSkipped('Cannot run test on windows');
+ }
+
+ if (ini_get('open_basedir')) {
+ $this->markTestSkipped('Cannot test when open_basedir is set');
+ }
+
+ $this->iniSet('open_basedir', dirname(PHP_BINARY).(!defined('HHVM_VERSION') ? PATH_SEPARATOR.'/' : ''));
+
+ $finder = new ExecutableFinder();
+ $result = $finder->find($this->getPhpBinaryName());
+
+ $this->assertSamePath(PHP_BINARY, $result);
+ }
+
+ public function testFindProcessInOpenBasedir()
+ {
+ if (ini_get('open_basedir')) {
+ $this->markTestSkipped('Cannot test when open_basedir is set');
+ }
+
+ if (!defined('PHP_BINARY')) {
+ $this->markTestSkipped('Requires the PHP_BINARY constant');
+ }
+
+ if ('\\' === DIRECTORY_SEPARATOR) {
+ $this->markTestSkipped('Cannot run test on windows');
+ }
+
+ $this->setPath('');
+ $this->iniSet('open_basedir', PHP_BINARY.(!defined('HHVM_VERSION') ? PATH_SEPARATOR.'/' : ''));
+
+ $finder = new ExecutableFinder();
+ $result = $finder->find($this->getPhpBinaryName(), false);
+
+ $this->assertSamePath(PHP_BINARY, $result);
+ }
+
+ private function assertSamePath($expected, $tested)
+ {
+ if ('\\' === DIRECTORY_SEPARATOR) {
+ $this->assertEquals(strtolower($expected), strtolower($tested));
+ } else {
+ $this->assertEquals($expected, $tested);
+ }
+ }
+
+ private function getPhpBinaryName()
+ {
+ return basename(PHP_BINARY, '\\' === DIRECTORY_SEPARATOR ? '.exe' : '');
+ }
+}
diff --git a/vendor/symfony/process/Tests/NonStopableProcess.php b/vendor/symfony/process/Tests/NonStopableProcess.php
new file mode 100644
index 00000000..692feebb
--- /dev/null
+++ b/vendor/symfony/process/Tests/NonStopableProcess.php
@@ -0,0 +1,36 @@
+<?php
+
+/**
+ * Runs a PHP script that can be stopped only with a SIGKILL (9) signal for 3 seconds.
+ *
+ * @args duration Run this script with a custom duration
+ *
+ * @example `php NonStopableProcess.php 42` will run the script for 42 seconds
+ */
+function handleSignal($signal)
+{
+ switch ($signal) {
+ case SIGTERM:
+ $name = 'SIGTERM';
+ break;
+ case SIGINT:
+ $name = 'SIGINT';
+ break;
+ default:
+ $name = $signal.' (unknown)';
+ break;
+ }
+
+ echo "received signal $name\n";
+}
+
+declare (ticks = 1);
+pcntl_signal(SIGTERM, 'handleSignal');
+pcntl_signal(SIGINT, 'handleSignal');
+
+$duration = isset($argv[1]) ? (int) $argv[1] : 3;
+$start = microtime(true);
+
+while ($duration > (microtime(true) - $start)) {
+ usleep(1000);
+}
diff --git a/vendor/symfony/process/Tests/PhpExecutableFinderTest.php b/vendor/symfony/process/Tests/PhpExecutableFinderTest.php
new file mode 100644
index 00000000..cd4abedc
--- /dev/null
+++ b/vendor/symfony/process/Tests/PhpExecutableFinderTest.php
@@ -0,0 +1,97 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Process\Tests;
+
+use Symfony\Component\Process\PhpExecutableFinder;
+
+/**
+ * @author Robert Schönthal <seroscho@googlemail.com>
+ */
+class PhpExecutableFinderTest extends \PHPUnit_Framework_TestCase
+{
+ /**
+ * tests find() with the env var PHP_PATH.
+ */
+ public function testFindWithPhpPath()
+ {
+ if (defined('PHP_BINARY')) {
+ $this->markTestSkipped('The PHP binary is easily available as of PHP 5.4');
+ }
+
+ $f = new PhpExecutableFinder();
+
+ $current = $f->find();
+
+ //not executable PHP_PATH
+ putenv('PHP_PATH=/not/executable/php');
+ $this->assertFalse($f->find(), '::find() returns false for not executable PHP');
+ $this->assertFalse($f->find(false), '::find() returns false for not executable PHP');
+
+ //executable PHP_PATH
+ putenv('PHP_PATH='.$current);
+ $this->assertEquals($f->find(), $current, '::find() returns the executable PHP');
+ $this->assertEquals($f->find(false), $current, '::find() returns the executable PHP');
+ }
+
+ /**
+ * tests find() with the env var PHP_PATH.
+ */
+ public function testFindWithHHVM()
+ {
+ if (!defined('HHVM_VERSION')) {
+ $this->markTestSkipped('Should be executed in HHVM context.');
+ }
+
+ $f = new PhpExecutableFinder();
+
+ $current = getenv('PHP_BINARY') ?: PHP_BINARY;
+
+ $this->assertEquals($current.' --php', $f->find(), '::find() returns the executable PHP');
+ $this->assertEquals($current, $f->find(false), '::find() returns the executable PHP');
+ }
+
+ /**
+ * tests find() with the env var PHP_PATH.
+ */
+ public function testFindArguments()
+ {
+ $f = new PhpExecutableFinder();
+
+ if (defined('HHVM_VERSION')) {
+ $this->assertEquals($f->findArguments(), array('--php'), '::findArguments() returns HHVM arguments');
+ } else {
+ $this->assertEquals($f->findArguments(), array(), '::findArguments() returns no arguments');
+ }
+ }
+
+ /**
+ * tests find() with default executable.
+ */
+ public function testFindWithSuffix()
+ {
+ if (defined('PHP_BINARY')) {
+ $this->markTestSkipped('The PHP binary is easily available as of PHP 5.4');
+ }
+
+ putenv('PHP_PATH=');
+ putenv('PHP_PEAR_PHP_BIN=');
+ $f = new PhpExecutableFinder();
+
+ $current = $f->find();
+
+ //TODO maybe php executable is custom or even Windows
+ if ('\\' === DIRECTORY_SEPARATOR) {
+ $this->assertTrue(is_executable($current));
+ $this->assertTrue((bool) preg_match('/'.addslashes(DIRECTORY_SEPARATOR).'php\.(exe|bat|cmd|com)$/i', $current), '::find() returns the executable PHP with suffixes');
+ }
+ }
+}
diff --git a/vendor/symfony/process/Tests/PhpProcessTest.php b/vendor/symfony/process/Tests/PhpProcessTest.php
new file mode 100644
index 00000000..5dc546cc
--- /dev/null
+++ b/vendor/symfony/process/Tests/PhpProcessTest.php
@@ -0,0 +1,49 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Process\Tests;
+
+use Symfony\Component\Process\PhpExecutableFinder;
+use Symfony\Component\Process\PhpProcess;
+
+class PhpProcessTest extends \PHPUnit_Framework_TestCase
+{
+ public function testNonBlockingWorks()
+ {
+ $expected = 'hello world!';
+ $process = new PhpProcess(<<<PHP
+<?php echo '$expected';
+PHP
+ );
+ $process->start();
+ $process->wait();
+ $this->assertEquals($expected, $process->getOutput());
+ }
+
+ public function testCommandLine()
+ {
+ $process = new PhpProcess(<<<PHP
+<?php echo 'foobar';
+PHP
+ );
+
+ $f = new PhpExecutableFinder();
+ $commandLine = $f->find();
+
+ $this->assertSame($commandLine, $process->getCommandLine(), '::getCommandLine() returns the command line of PHP before start');
+
+ $process->start();
+ $this->assertSame($commandLine, $process->getCommandLine(), '::getCommandLine() returns the command line of PHP after start');
+
+ $process->wait();
+ $this->assertSame($commandLine, $process->getCommandLine(), '::getCommandLine() returns the command line of PHP after wait');
+ }
+}
diff --git a/vendor/symfony/process/Tests/PipeStdinInStdoutStdErrStreamSelect.php b/vendor/symfony/process/Tests/PipeStdinInStdoutStdErrStreamSelect.php
new file mode 100644
index 00000000..26673ea4
--- /dev/null
+++ b/vendor/symfony/process/Tests/PipeStdinInStdoutStdErrStreamSelect.php
@@ -0,0 +1,63 @@
+<?php
+
+define('ERR_SELECT_FAILED', 1);
+define('ERR_TIMEOUT', 2);
+define('ERR_READ_FAILED', 3);
+define('ERR_WRITE_FAILED', 4);
+
+$read = array(STDIN);
+$write = array(STDOUT, STDERR);
+
+stream_set_blocking(STDIN, 0);
+stream_set_blocking(STDOUT, 0);
+stream_set_blocking(STDERR, 0);
+
+$out = $err = '';
+while ($read || $write) {
+ $r = $read;
+ $w = $write;
+ $e = null;
+ $n = stream_select($r, $w, $e, 5);
+
+ if (false === $n) {
+ die(ERR_SELECT_FAILED);
+ } elseif ($n < 1) {
+ die(ERR_TIMEOUT);
+ }
+
+ if (in_array(STDOUT, $w) && strlen($out) > 0) {
+ $written = fwrite(STDOUT, (binary) $out, 32768);
+ if (false === $written) {
+ die(ERR_WRITE_FAILED);
+ }
+ $out = (binary) substr($out, $written);
+ }
+ if (null === $read && '' === $out) {
+ $write = array_diff($write, array(STDOUT));
+ }
+
+ if (in_array(STDERR, $w) && strlen($err) > 0) {
+ $written = fwrite(STDERR, (binary) $err, 32768);
+ if (false === $written) {
+ die(ERR_WRITE_FAILED);
+ }
+ $err = (binary) substr($err, $written);
+ }
+ if (null === $read && '' === $err) {
+ $write = array_diff($write, array(STDERR));
+ }
+
+ if ($r) {
+ $str = fread(STDIN, 32768);
+ if (false !== $str) {
+ $out .= $str;
+ $err .= $str;
+ }
+ if (false === $str || feof(STDIN)) {
+ $read = null;
+ if (!feof(STDIN)) {
+ die(ERR_READ_FAILED);
+ }
+ }
+ }
+}
diff --git a/vendor/symfony/process/Tests/ProcessBuilderTest.php b/vendor/symfony/process/Tests/ProcessBuilderTest.php
new file mode 100644
index 00000000..1b5056d1
--- /dev/null
+++ b/vendor/symfony/process/Tests/ProcessBuilderTest.php
@@ -0,0 +1,225 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Process\Tests;
+
+use Symfony\Component\Process\ProcessBuilder;
+
+class ProcessBuilderTest extends \PHPUnit_Framework_TestCase
+{
+ public function testInheritEnvironmentVars()
+ {
+ $_ENV['MY_VAR_1'] = 'foo';
+
+ $proc = ProcessBuilder::create()
+ ->add('foo')
+ ->getProcess();
+
+ unset($_ENV['MY_VAR_1']);
+
+ $env = $proc->getEnv();
+ $this->assertArrayHasKey('MY_VAR_1', $env);
+ $this->assertEquals('foo', $env['MY_VAR_1']);
+ }
+
+ public function testAddEnvironmentVariables()
+ {
+ $pb = new ProcessBuilder();
+ $env = array(
+ 'foo' => 'bar',
+ 'foo2' => 'bar2',
+ );
+ $proc = $pb
+ ->add('command')
+ ->setEnv('foo', 'bar2')
+ ->addEnvironmentVariables($env)
+ ->inheritEnvironmentVariables(false)
+ ->getProcess()
+ ;
+
+ $this->assertSame($env, $proc->getEnv());
+ }
+
+ public function testProcessShouldInheritAndOverrideEnvironmentVars()
+ {
+ $_ENV['MY_VAR_1'] = 'foo';
+
+ $proc = ProcessBuilder::create()
+ ->setEnv('MY_VAR_1', 'bar')
+ ->add('foo')
+ ->getProcess();
+
+ unset($_ENV['MY_VAR_1']);
+
+ $env = $proc->getEnv();
+ $this->assertArrayHasKey('MY_VAR_1', $env);
+ $this->assertEquals('bar', $env['MY_VAR_1']);
+ }
+
+ /**
+ * @expectedException \Symfony\Component\Process\Exception\InvalidArgumentException
+ */
+ public function testNegativeTimeoutFromSetter()
+ {
+ $pb = new ProcessBuilder();
+ $pb->setTimeout(-1);
+ }
+
+ public function testNullTimeout()
+ {
+ $pb = new ProcessBuilder();
+ $pb->setTimeout(10);
+ $pb->setTimeout(null);
+
+ $r = new \ReflectionObject($pb);
+ $p = $r->getProperty('timeout');
+ $p->setAccessible(true);
+
+ $this->assertNull($p->getValue($pb));
+ }
+
+ public function testShouldSetArguments()
+ {
+ $pb = new ProcessBuilder(array('initial'));
+ $pb->setArguments(array('second'));
+
+ $proc = $pb->getProcess();
+
+ $this->assertContains('second', $proc->getCommandLine());
+ }
+
+ public function testPrefixIsPrependedToAllGeneratedProcess()
+ {
+ $pb = new ProcessBuilder();
+ $pb->setPrefix('/usr/bin/php');
+
+ $proc = $pb->setArguments(array('-v'))->getProcess();
+ if ('\\' === DIRECTORY_SEPARATOR) {
+ $this->assertEquals('"/usr/bin/php" "-v"', $proc->getCommandLine());
+ } else {
+ $this->assertEquals("'/usr/bin/php' '-v'", $proc->getCommandLine());
+ }
+
+ $proc = $pb->setArguments(array('-i'))->getProcess();
+ if ('\\' === DIRECTORY_SEPARATOR) {
+ $this->assertEquals('"/usr/bin/php" "-i"', $proc->getCommandLine());
+ } else {
+ $this->assertEquals("'/usr/bin/php' '-i'", $proc->getCommandLine());
+ }
+ }
+
+ public function testArrayPrefixesArePrependedToAllGeneratedProcess()
+ {
+ $pb = new ProcessBuilder();
+ $pb->setPrefix(array('/usr/bin/php', 'composer.phar'));
+
+ $proc = $pb->setArguments(array('-v'))->getProcess();
+ if ('\\' === DIRECTORY_SEPARATOR) {
+ $this->assertEquals('"/usr/bin/php" "composer.phar" "-v"', $proc->getCommandLine());
+ } else {
+ $this->assertEquals("'/usr/bin/php' 'composer.phar' '-v'", $proc->getCommandLine());
+ }
+
+ $proc = $pb->setArguments(array('-i'))->getProcess();
+ if ('\\' === DIRECTORY_SEPARATOR) {
+ $this->assertEquals('"/usr/bin/php" "composer.phar" "-i"', $proc->getCommandLine());
+ } else {
+ $this->assertEquals("'/usr/bin/php' 'composer.phar' '-i'", $proc->getCommandLine());
+ }
+ }
+
+ public function testShouldEscapeArguments()
+ {
+ $pb = new ProcessBuilder(array('%path%', 'foo " bar', '%baz%baz'));
+ $proc = $pb->getProcess();
+
+ if ('\\' === DIRECTORY_SEPARATOR) {
+ $this->assertSame('^%"path"^% "foo \\" bar" "%baz%baz"', $proc->getCommandLine());
+ } else {
+ $this->assertSame("'%path%' 'foo \" bar' '%baz%baz'", $proc->getCommandLine());
+ }
+ }
+
+ public function testShouldEscapeArgumentsAndPrefix()
+ {
+ $pb = new ProcessBuilder(array('arg'));
+ $pb->setPrefix('%prefix%');
+ $proc = $pb->getProcess();
+
+ if ('\\' === DIRECTORY_SEPARATOR) {
+ $this->assertSame('^%"prefix"^% "arg"', $proc->getCommandLine());
+ } else {
+ $this->assertSame("'%prefix%' 'arg'", $proc->getCommandLine());
+ }
+ }
+
+ /**
+ * @expectedException \Symfony\Component\Process\Exception\LogicException
+ */
+ public function testShouldThrowALogicExceptionIfNoPrefixAndNoArgument()
+ {
+ ProcessBuilder::create()->getProcess();
+ }
+
+ public function testShouldNotThrowALogicExceptionIfNoArgument()
+ {
+ $process = ProcessBuilder::create()
+ ->setPrefix('/usr/bin/php')
+ ->getProcess();
+
+ if ('\\' === DIRECTORY_SEPARATOR) {
+ $this->assertEquals('"/usr/bin/php"', $process->getCommandLine());
+ } else {
+ $this->assertEquals("'/usr/bin/php'", $process->getCommandLine());
+ }
+ }
+
+ public function testShouldNotThrowALogicExceptionIfNoPrefix()
+ {
+ $process = ProcessBuilder::create(array('/usr/bin/php'))
+ ->getProcess();
+
+ if ('\\' === DIRECTORY_SEPARATOR) {
+ $this->assertEquals('"/usr/bin/php"', $process->getCommandLine());
+ } else {
+ $this->assertEquals("'/usr/bin/php'", $process->getCommandLine());
+ }
+ }
+
+ public function testShouldReturnProcessWithDisabledOutput()
+ {
+ $process = ProcessBuilder::create(array('/usr/bin/php'))
+ ->disableOutput()
+ ->getProcess();
+
+ $this->assertTrue($process->isOutputDisabled());
+ }
+
+ public function testShouldReturnProcessWithEnabledOutput()
+ {
+ $process = ProcessBuilder::create(array('/usr/bin/php'))
+ ->disableOutput()
+ ->enableOutput()
+ ->getProcess();
+
+ $this->assertFalse($process->isOutputDisabled());
+ }
+
+ /**
+ * @expectedException \Symfony\Component\Process\Exception\InvalidArgumentException
+ * @expectedExceptionMessage Symfony\Component\Process\ProcessBuilder::setInput only accepts strings or stream resources.
+ */
+ public function testInvalidInput()
+ {
+ $builder = ProcessBuilder::create();
+ $builder->setInput(array());
+ }
+}
diff --git a/vendor/symfony/process/Tests/ProcessFailedExceptionTest.php b/vendor/symfony/process/Tests/ProcessFailedExceptionTest.php
new file mode 100644
index 00000000..b028395f
--- /dev/null
+++ b/vendor/symfony/process/Tests/ProcessFailedExceptionTest.php
@@ -0,0 +1,136 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Process\Tests;
+
+use Symfony\Component\Process\Exception\ProcessFailedException;
+
+/**
+ * @author Sebastian Marek <proofek@gmail.com>
+ */
+class ProcessFailedExceptionTest extends \PHPUnit_Framework_TestCase
+{
+ /**
+ * tests ProcessFailedException throws exception if the process was successful.
+ */
+ public function testProcessFailedExceptionThrowsException()
+ {
+ $process = $this->getMock(
+ 'Symfony\Component\Process\Process',
+ array('isSuccessful'),
+ array('php')
+ );
+ $process->expects($this->once())
+ ->method('isSuccessful')
+ ->will($this->returnValue(true));
+
+ $this->setExpectedException(
+ '\InvalidArgumentException',
+ 'Expected a failed process, but the given process was successful.'
+ );
+
+ new ProcessFailedException($process);
+ }
+
+ /**
+ * tests ProcessFailedException uses information from process output
+ * to generate exception message.
+ */
+ public function testProcessFailedExceptionPopulatesInformationFromProcessOutput()
+ {
+ $cmd = 'php';
+ $exitCode = 1;
+ $exitText = 'General error';
+ $output = 'Command output';
+ $errorOutput = 'FATAL: Unexpected error';
+
+ $process = $this->getMock(
+ 'Symfony\Component\Process\Process',
+ array('isSuccessful', 'getOutput', 'getErrorOutput', 'getExitCode', 'getExitCodeText', 'isOutputDisabled'),
+ array($cmd)
+ );
+ $process->expects($this->once())
+ ->method('isSuccessful')
+ ->will($this->returnValue(false));
+
+ $process->expects($this->once())
+ ->method('getOutput')
+ ->will($this->returnValue($output));
+
+ $process->expects($this->once())
+ ->method('getErrorOutput')
+ ->will($this->returnValue($errorOutput));
+
+ $process->expects($this->once())
+ ->method('getExitCode')
+ ->will($this->returnValue($exitCode));
+
+ $process->expects($this->once())
+ ->method('getExitCodeText')
+ ->will($this->returnValue($exitText));
+
+ $process->expects($this->once())
+ ->method('isOutputDisabled')
+ ->will($this->returnValue(false));
+
+ $exception = new ProcessFailedException($process);
+
+ $this->assertEquals(
+ "The command \"$cmd\" failed.\nExit Code: $exitCode($exitText)\n\nOutput:\n================\n{$output}\n\nError Output:\n================\n{$errorOutput}",
+ $exception->getMessage()
+ );
+ }
+
+ /**
+ * Tests that ProcessFailedException does not extract information from
+ * process output if it was previously disabled
+ */
+ public function testDisabledOutputInFailedExceptionDoesNotPopulateOutput()
+ {
+ $cmd = 'php';
+ $exitCode = 1;
+ $exitText = 'General error';
+
+ $process = $this->getMock(
+ 'Symfony\Component\Process\Process',
+ array('isSuccessful', 'isOutputDisabled', 'getExitCode', 'getExitCodeText', 'getOutput', 'getErrorOutput'),
+ array($cmd)
+ );
+ $process->expects($this->once())
+ ->method('isSuccessful')
+ ->will($this->returnValue(false));
+
+ $process->expects($this->never())
+ ->method('getOutput');
+
+ $process->expects($this->never())
+ ->method('getErrorOutput');
+
+ $process->expects($this->once())
+ ->method('getExitCode')
+ ->will($this->returnValue($exitCode));
+
+ $process->expects($this->once())
+ ->method('getExitCodeText')
+ ->will($this->returnValue($exitText));
+
+ $process->expects($this->once())
+ ->method('isOutputDisabled')
+ ->will($this->returnValue(true));
+
+ $exception = new ProcessFailedException($process);
+
+ $this->assertEquals(
+ "The command \"$cmd\" failed.\nExit Code: $exitCode($exitText)",
+ $exception->getMessage()
+ );
+ }
+}
diff --git a/vendor/symfony/process/Tests/ProcessInSigchildEnvironment.php b/vendor/symfony/process/Tests/ProcessInSigchildEnvironment.php
new file mode 100644
index 00000000..3977bcdc
--- /dev/null
+++ b/vendor/symfony/process/Tests/ProcessInSigchildEnvironment.php
@@ -0,0 +1,22 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Process\Tests;
+
+use Symfony\Component\Process\Process;
+
+class ProcessInSigchildEnvironment extends Process
+{
+ protected function isSigchildEnabled()
+ {
+ return true;
+ }
+}
diff --git a/vendor/symfony/process/Tests/ProcessUtilsTest.php b/vendor/symfony/process/Tests/ProcessUtilsTest.php
new file mode 100644
index 00000000..e6564cde
--- /dev/null
+++ b/vendor/symfony/process/Tests/ProcessUtilsTest.php
@@ -0,0 +1,48 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Process\Tests;
+
+use Symfony\Component\Process\ProcessUtils;
+
+class ProcessUtilsTest extends \PHPUnit_Framework_TestCase
+{
+ /**
+ * @dataProvider dataArguments
+ */
+ public function testEscapeArgument($result, $argument)
+ {
+ $this->assertSame($result, ProcessUtils::escapeArgument($argument));
+ }
+
+ public function dataArguments()
+ {
+ if ('\\' === DIRECTORY_SEPARATOR) {
+ return array(
+ array('"\"php\" \"-v\""', '"php" "-v"'),
+ array('"foo bar"', 'foo bar'),
+ array('^%"path"^%', '%path%'),
+ array('"<|>\\" \\"\'f"', '<|>" "\'f'),
+ array('""', ''),
+ array('"with\trailingbs\\\\"', 'with\trailingbs\\'),
+ );
+ }
+
+ return array(
+ array("'\"php\" \"-v\"'", '"php" "-v"'),
+ array("'foo bar'", 'foo bar'),
+ array("'%path%'", '%path%'),
+ array("'<|>\" \"'\\''f'", '<|>" "\'f'),
+ array("''", ''),
+ array("'with\\trailingbs\\'", 'with\trailingbs\\'),
+ );
+ }
+}
diff --git a/vendor/symfony/process/Tests/SigchildDisabledProcessTest.php b/vendor/symfony/process/Tests/SigchildDisabledProcessTest.php
new file mode 100644
index 00000000..fdae5ec2
--- /dev/null
+++ b/vendor/symfony/process/Tests/SigchildDisabledProcessTest.php
@@ -0,0 +1,263 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Process\Tests;
+
+class SigchildDisabledProcessTest extends AbstractProcessTest
+{
+ /**
+ * @expectedException \Symfony\Component\Process\Exception\RuntimeException
+ * @expectedExceptionMessage This PHP has been compiled with --enable-sigchild. You must use setEnhanceSigchildCompatibility() to use this method.
+ */
+ public function testGetExitCode()
+ {
+ parent::testGetExitCode();
+ }
+
+ /**
+ * @expectedException \Symfony\Component\Process\Exception\RuntimeException
+ * @expectedExceptionMessage This PHP has been compiled with --enable-sigchild. You must use setEnhanceSigchildCompatibility() to use this method.
+ */
+ public function testGetExitCodeIsNullOnStart()
+ {
+ parent::testGetExitCodeIsNullOnStart();
+ }
+
+ /**
+ * @expectedException \Symfony\Component\Process\Exception\RuntimeException
+ * @expectedExceptionMessage This PHP has been compiled with --enable-sigchild. You must use setEnhanceSigchildCompatibility() to use this method.
+ */
+ public function testGetExitCodeIsNullOnWhenStartingAgain()
+ {
+ parent::testGetExitCodeIsNullOnWhenStartingAgain();
+ }
+
+ /**
+ * @expectedException \Symfony\Component\Process\Exception\RuntimeException
+ * @expectedExceptionMessage This PHP has been compiled with --enable-sigchild. You must use setEnhanceSigchildCompatibility() to use this method.
+ */
+ public function testExitCodeCommandFailed()
+ {
+ parent::testExitCodeCommandFailed();
+ }
+
+ /**
+ * @expectedException \Symfony\Component\Process\Exception\RuntimeException
+ * @expectedExceptionMessage This PHP has been compiled with --enable-sigchild. You must use setEnhanceSigchildCompatibility() to use this method.
+ */
+ public function testMustRun()
+ {
+ parent::testMustRun();
+ }
+
+ /**
+ * @expectedException \Symfony\Component\Process\Exception\RuntimeException
+ * @expectedExceptionMessage This PHP has been compiled with --enable-sigchild. You must use setEnhanceSigchildCompatibility() to use this method.
+ */
+ public function testSuccessfulMustRunHasCorrectExitCode()
+ {
+ parent::testSuccessfulMustRunHasCorrectExitCode();
+ }
+
+ /**
+ * @expectedException \Symfony\Component\Process\Exception\RuntimeException
+ */
+ public function testMustRunThrowsException()
+ {
+ parent::testMustRunThrowsException();
+ }
+
+ /**
+ * @expectedException \Symfony\Component\Process\Exception\RuntimeException
+ */
+ public function testProcessIsSignaledIfStopped()
+ {
+ parent::testProcessIsSignaledIfStopped();
+ }
+
+ /**
+ * @expectedException \Symfony\Component\Process\Exception\RuntimeException
+ * @expectedExceptionMessage This PHP has been compiled with --enable-sigchild. Term signal can not be retrieved.
+ */
+ public function testProcessWithTermSignal()
+ {
+ parent::testProcessWithTermSignal();
+ }
+
+ /**
+ * @expectedException \Symfony\Component\Process\Exception\RuntimeException
+ * @expectedExceptionMessage This PHP has been compiled with --enable-sigchild. Term signal can not be retrieved.
+ */
+ public function testProcessIsNotSignaled()
+ {
+ parent::testProcessIsNotSignaled();
+ }
+
+ /**
+ * @expectedException \Symfony\Component\Process\Exception\RuntimeException
+ * @expectedExceptionMessage This PHP has been compiled with --enable-sigchild. Term signal can not be retrieved.
+ */
+ public function testProcessWithoutTermSignal()
+ {
+ parent::testProcessWithoutTermSignal();
+ }
+
+ /**
+ * @expectedException \Symfony\Component\Process\Exception\RuntimeException
+ * @expectedExceptionMessage This PHP has been compiled with --enable-sigchild. You must use setEnhanceSigchildCompatibility() to use this method.
+ */
+ public function testCheckTimeoutOnStartedProcess()
+ {
+ parent::testCheckTimeoutOnStartedProcess();
+ }
+
+ /**
+ * @expectedException \Symfony\Component\Process\Exception\RuntimeException
+ * @expectedExceptionMessage This PHP has been compiled with --enable-sigchild. The process identifier can not be retrieved.
+ */
+ public function testGetPid()
+ {
+ parent::testGetPid();
+ }
+
+ /**
+ * @expectedException \Symfony\Component\Process\Exception\RuntimeException
+ * @expectedExceptionMessage This PHP has been compiled with --enable-sigchild. The process identifier can not be retrieved.
+ */
+ public function testGetPidIsNullBeforeStart()
+ {
+ parent::testGetPidIsNullBeforeStart();
+ }
+
+ /**
+ * @expectedException \Symfony\Component\Process\Exception\RuntimeException
+ * @expectedExceptionMessage This PHP has been compiled with --enable-sigchild. The process identifier can not be retrieved.
+ */
+ public function testGetPidIsNullAfterRun()
+ {
+ parent::testGetPidIsNullAfterRun();
+ }
+
+ /**
+ * @expectedException \Symfony\Component\Process\Exception\RuntimeException
+ * @expectedExceptionMessage This PHP has been compiled with --enable-sigchild. You must use setEnhanceSigchildCompatibility() to use this method.
+ */
+ public function testExitCodeText()
+ {
+ $process = $this->getProcess('qdfsmfkqsdfmqmsd');
+ $process->run();
+
+ $process->getExitCodeText();
+ }
+
+ /**
+ * @expectedException \Symfony\Component\Process\Exception\RuntimeException
+ * @expectedExceptionMessage This PHP has been compiled with --enable-sigchild. You must use setEnhanceSigchildCompatibility() to use this method.
+ */
+ public function testExitCodeTextIsNullWhenExitCodeIsNull()
+ {
+ parent::testExitCodeTextIsNullWhenExitCodeIsNull();
+ }
+
+ /**
+ * @expectedException \Symfony\Component\Process\Exception\RuntimeException
+ * @expectedExceptionMessage This PHP has been compiled with --enable-sigchild. You must use setEnhanceSigchildCompatibility() to use this method.
+ */
+ public function testIsSuccessful()
+ {
+ parent::testIsSuccessful();
+ }
+
+ /**
+ * @expectedException \Symfony\Component\Process\Exception\RuntimeException
+ * @expectedExceptionMessage This PHP has been compiled with --enable-sigchild. You must use setEnhanceSigchildCompatibility() to use this method.
+ */
+ public function testIsSuccessfulOnlyAfterTerminated()
+ {
+ parent::testIsSuccessfulOnlyAfterTerminated();
+ }
+
+ /**
+ * @expectedException \Symfony\Component\Process\Exception\RuntimeException
+ * @expectedExceptionMessage This PHP has been compiled with --enable-sigchild. You must use setEnhanceSigchildCompatibility() to use this method.
+ */
+ public function testIsNotSuccessful()
+ {
+ parent::testIsNotSuccessful();
+ }
+
+ /**
+ * @expectedException \Symfony\Component\Process\Exception\RuntimeException
+ * @expectedExceptionMessage This PHP has been compiled with --enable-sigchild. You must use setEnhanceSigchildCompatibility() to use this method.
+ */
+ public function testTTYCommandExitCode()
+ {
+ parent::testTTYCommandExitCode();
+ }
+
+ /**
+ * @expectedException \Symfony\Component\Process\Exception\RuntimeException
+ * @expectedExceptionMessage This PHP has been compiled with --enable-sigchild. The process can not be signaled.
+ */
+ public function testSignal()
+ {
+ parent::testSignal();
+ }
+
+ /**
+ * @expectedException \Symfony\Component\Process\Exception\RuntimeException
+ * @expectedExceptionMessage This PHP has been compiled with --enable-sigchild. Term signal can not be retrieved.
+ */
+ public function testProcessWithoutTermSignalIsNotSignaled()
+ {
+ parent::testProcessWithoutTermSignalIsNotSignaled();
+ }
+
+ public function testStopWithTimeoutIsActuallyWorking()
+ {
+ $this->markTestSkipped('Stopping with signal is not supported in sigchild environment');
+ }
+
+ public function testProcessThrowsExceptionWhenExternallySignaled()
+ {
+ $this->markTestSkipped('Retrieving Pid is not supported in sigchild environment');
+ }
+
+ public function testExitCodeIsAvailableAfterSignal()
+ {
+ $this->markTestSkipped('Signal is not supported in sigchild environment');
+ }
+
+ public function testRunProcessWithTimeout()
+ {
+ $this->markTestSkipped('Signal (required for timeout) is not supported in sigchild environment');
+ }
+
+ public function provideStartMethods()
+ {
+ return array(
+ array('start', 'Symfony\Component\Process\Exception\LogicException', 'Output has been disabled, enable it to allow the use of a callback.'),
+ array('run', 'Symfony\Component\Process\Exception\LogicException', 'Output has been disabled, enable it to allow the use of a callback.'),
+ array('mustRun', 'Symfony\Component\Process\Exception\RuntimeException', 'This PHP has been compiled with --enable-sigchild. You must use setEnhanceSigchildCompatibility() to use this method.'),
+ );
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function getProcess($commandline, $cwd = null, array $env = null, $input = null, $timeout = 60, array $options = array())
+ {
+ $process = new ProcessInSigchildEnvironment($commandline, $cwd, $env, $input, $timeout, $options);
+ $process->setEnhanceSigchildCompatibility(false);
+
+ return $process;
+ }
+}
diff --git a/vendor/symfony/process/Tests/SigchildEnabledProcessTest.php b/vendor/symfony/process/Tests/SigchildEnabledProcessTest.php
new file mode 100644
index 00000000..2668a9b4
--- /dev/null
+++ b/vendor/symfony/process/Tests/SigchildEnabledProcessTest.php
@@ -0,0 +1,148 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Process\Tests;
+
+class SigchildEnabledProcessTest extends AbstractProcessTest
+{
+ /**
+ * @expectedException \Symfony\Component\Process\Exception\RuntimeException
+ * @expectedExceptionMessage This PHP has been compiled with --enable-sigchild. Term signal can not be retrieved.
+ */
+ public function testProcessIsSignaledIfStopped()
+ {
+ parent::testProcessIsSignaledIfStopped();
+ }
+
+ /**
+ * @expectedException \Symfony\Component\Process\Exception\RuntimeException
+ * @expectedExceptionMessage This PHP has been compiled with --enable-sigchild. Term signal can not be retrieved.
+ */
+ public function testProcessWithTermSignal()
+ {
+ parent::testProcessWithTermSignal();
+ }
+
+ /**
+ * @expectedException \Symfony\Component\Process\Exception\RuntimeException
+ * @expectedExceptionMessage This PHP has been compiled with --enable-sigchild. Term signal can not be retrieved.
+ */
+ public function testProcessIsNotSignaled()
+ {
+ parent::testProcessIsNotSignaled();
+ }
+
+ /**
+ * @expectedException \Symfony\Component\Process\Exception\RuntimeException
+ * @expectedExceptionMessage This PHP has been compiled with --enable-sigchild. Term signal can not be retrieved.
+ */
+ public function testProcessWithoutTermSignal()
+ {
+ parent::testProcessWithoutTermSignal();
+ }
+
+ /**
+ * @expectedException \Symfony\Component\Process\Exception\RuntimeException
+ * @expectedExceptionMessage This PHP has been compiled with --enable-sigchild. The process identifier can not be retrieved.
+ */
+ public function testGetPid()
+ {
+ parent::testGetPid();
+ }
+
+ /**
+ * @expectedException \Symfony\Component\Process\Exception\RuntimeException
+ * @expectedExceptionMessage This PHP has been compiled with --enable-sigchild. The process identifier can not be retrieved.
+ */
+ public function testGetPidIsNullBeforeStart()
+ {
+ parent::testGetPidIsNullBeforeStart();
+ }
+
+ /**
+ * @expectedException \Symfony\Component\Process\Exception\RuntimeException
+ * @expectedExceptionMessage This PHP has been compiled with --enable-sigchild. The process identifier can not be retrieved.
+ */
+ public function testGetPidIsNullAfterRun()
+ {
+ parent::testGetPidIsNullAfterRun();
+ }
+
+ public function testExitCodeText()
+ {
+ $process = $this->getProcess('qdfsmfkqsdfmqmsd');
+ $process->run();
+
+ $this->assertInternalType('string', $process->getExitCodeText());
+ }
+
+ /**
+ * @expectedException \Symfony\Component\Process\Exception\RuntimeException
+ * @expectedExceptionMessage This PHP has been compiled with --enable-sigchild. The process can not be signaled.
+ */
+ public function testSignal()
+ {
+ parent::testSignal();
+ }
+
+ /**
+ * @expectedException \Symfony\Component\Process\Exception\RuntimeException
+ * @expectedExceptionMessage This PHP has been compiled with --enable-sigchild. Term signal can not be retrieved.
+ */
+ public function testProcessWithoutTermSignalIsNotSignaled()
+ {
+ parent::testProcessWithoutTermSignalIsNotSignaled();
+ }
+
+ public function testProcessThrowsExceptionWhenExternallySignaled()
+ {
+ $this->markTestSkipped('Retrieving Pid is not supported in sigchild environment');
+ }
+
+ public function testExitCodeIsAvailableAfterSignal()
+ {
+ $this->markTestSkipped('Signal is not supported in sigchild environment');
+ }
+
+ public function testStartAfterATimeout()
+ {
+ if ('\\' === DIRECTORY_SEPARATOR) {
+ $this->markTestSkipped('Restarting a timed-out process on Windows is not supported in sigchild environment');
+ }
+ parent::testStartAfterATimeout();
+ }
+
+ public function testStopWithTimeoutIsActuallyWorking()
+ {
+ $this->markTestSkipped('Stopping with signal is not supported in sigchild environment');
+ }
+
+ public function testRunProcessWithTimeout()
+ {
+ $this->markTestSkipped('Signal (required for timeout) is not supported in sigchild environment');
+ }
+
+ public function testCheckTimeoutOnStartedProcess()
+ {
+ $this->markTestSkipped('Signal (required for timeout) is not supported in sigchild environment');
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function getProcess($commandline, $cwd = null, array $env = null, $input = null, $timeout = 60, array $options = array())
+ {
+ $process = new ProcessInSigchildEnvironment($commandline, $cwd, $env, $input, $timeout, $options);
+ $process->setEnhanceSigchildCompatibility(true);
+
+ return $process;
+ }
+}
diff --git a/vendor/symfony/process/Tests/SignalListener.php b/vendor/symfony/process/Tests/SignalListener.php
new file mode 100644
index 00000000..bd4d138b
--- /dev/null
+++ b/vendor/symfony/process/Tests/SignalListener.php
@@ -0,0 +1,16 @@
+<?php
+
+// required for signal handling
+declare (ticks = 1);
+
+pcntl_signal(SIGUSR1, function () {echo 'Caught SIGUSR1'; exit;});
+
+$n = 0;
+
+// ticks require activity to work - sleep(4); does not work
+while ($n < 400) {
+ usleep(10000);
+ ++$n;
+}
+
+return;
diff --git a/vendor/symfony/process/Tests/SimpleProcessTest.php b/vendor/symfony/process/Tests/SimpleProcessTest.php
new file mode 100644
index 00000000..98eeb0ec
--- /dev/null
+++ b/vendor/symfony/process/Tests/SimpleProcessTest.php
@@ -0,0 +1,222 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Process\Tests;
+
+use Symfony\Component\Process\Process;
+
+class SimpleProcessTest extends AbstractProcessTest
+{
+ private $enabledSigchild = false;
+
+ protected function setUp()
+ {
+ ob_start();
+ phpinfo(INFO_GENERAL);
+
+ $this->enabledSigchild = false !== strpos(ob_get_clean(), '--enable-sigchild');
+ }
+
+ public function testGetExitCode()
+ {
+ $this->skipIfPHPSigchild(); // This test use exitcode that is not available in this case
+ parent::testGetExitCode();
+ }
+
+ public function testExitCodeCommandFailed()
+ {
+ $this->skipIfPHPSigchild(); // This test use exitcode that is not available in this case
+ parent::testExitCodeCommandFailed();
+ }
+
+ public function testProcessIsSignaledIfStopped()
+ {
+ $this->expectExceptionIfPHPSigchild('Symfony\Component\Process\Exception\RuntimeException', 'This PHP has been compiled with --enable-sigchild. Term signal can not be retrieved');
+ parent::testProcessIsSignaledIfStopped();
+ }
+
+ public function testProcessWithTermSignal()
+ {
+ $this->expectExceptionIfPHPSigchild('Symfony\Component\Process\Exception\RuntimeException', 'This PHP has been compiled with --enable-sigchild. Term signal can not be retrieved');
+ parent::testProcessWithTermSignal();
+ }
+
+ public function testProcessIsNotSignaled()
+ {
+ $this->expectExceptionIfPHPSigchild('Symfony\Component\Process\Exception\RuntimeException', 'This PHP has been compiled with --enable-sigchild. Term signal can not be retrieved');
+ parent::testProcessIsNotSignaled();
+ }
+
+ public function testProcessWithoutTermSignal()
+ {
+ $this->expectExceptionIfPHPSigchild('Symfony\Component\Process\Exception\RuntimeException', 'This PHP has been compiled with --enable-sigchild. Term signal can not be retrieved');
+ parent::testProcessWithoutTermSignal();
+ }
+
+ public function testExitCodeText()
+ {
+ $this->skipIfPHPSigchild(); // This test use exitcode that is not available in this case
+ parent::testExitCodeText();
+ }
+
+ public function testIsSuccessful()
+ {
+ $this->skipIfPHPSigchild(); // This test use PID that is not available in this case
+ parent::testIsSuccessful();
+ }
+
+ public function testIsNotSuccessful()
+ {
+ $this->skipIfPHPSigchild(); // This test use PID that is not available in this case
+ parent::testIsNotSuccessful();
+ }
+
+ public function testGetPid()
+ {
+ $this->skipIfPHPSigchild(); // This test use PID that is not available in this case
+ parent::testGetPid();
+ }
+
+ public function testGetPidIsNullBeforeStart()
+ {
+ $this->skipIfPHPSigchild(); // This test use PID that is not available in this case
+ parent::testGetPidIsNullBeforeStart();
+ }
+
+ public function testGetPidIsNullAfterRun()
+ {
+ $this->skipIfPHPSigchild(); // This test use PID that is not available in this case
+ parent::testGetPidIsNullAfterRun();
+ }
+
+ public function testSignal()
+ {
+ $this->expectExceptionIfPHPSigchild('Symfony\Component\Process\Exception\RuntimeException', 'This PHP has been compiled with --enable-sigchild. The process can not be signaled.');
+ parent::testSignal();
+ }
+
+ public function testProcessWithoutTermSignalIsNotSignaled()
+ {
+ $this->expectExceptionIfPHPSigchild('Symfony\Component\Process\Exception\RuntimeException', 'This PHP has been compiled with --enable-sigchild. Term signal can not be retrieved');
+ parent::testProcessWithoutTermSignalIsNotSignaled();
+ }
+
+ public function testProcessThrowsExceptionWhenExternallySignaled()
+ {
+ $this->skipIfPHPSigchild(); // This test use PID that is not available in this case
+ parent::testProcessThrowsExceptionWhenExternallySignaled();
+ }
+
+ public function testExitCodeIsAvailableAfterSignal()
+ {
+ $this->expectExceptionIfPHPSigchild('Symfony\Component\Process\Exception\RuntimeException', 'This PHP has been compiled with --enable-sigchild. The process can not be signaled.');
+ parent::testExitCodeIsAvailableAfterSignal();
+ }
+
+ public function testSignalProcessNotRunning()
+ {
+ $this->setExpectedException('Symfony\Component\Process\Exception\LogicException', 'Can not send signal on a non running process.');
+ parent::testSignalProcessNotRunning();
+ }
+
+ public function testSignalWithWrongIntSignal()
+ {
+ if ($this->enabledSigchild) {
+ $this->expectExceptionIfPHPSigchild('Symfony\Component\Process\Exception\RuntimeException', 'This PHP has been compiled with --enable-sigchild. The process can not be signaled.');
+ } else {
+ $this->setExpectedException('Symfony\Component\Process\Exception\RuntimeException', 'Error while sending signal `-4`.');
+ }
+ parent::testSignalWithWrongIntSignal();
+ }
+
+ public function testSignalWithWrongNonIntSignal()
+ {
+ if ($this->enabledSigchild) {
+ $this->expectExceptionIfPHPSigchild('Symfony\Component\Process\Exception\RuntimeException', 'This PHP has been compiled with --enable-sigchild. The process can not be signaled.');
+ } else {
+ $this->setExpectedException('Symfony\Component\Process\Exception\RuntimeException', 'Error while sending signal `Céphalopodes`.');
+ }
+ parent::testSignalWithWrongNonIntSignal();
+ }
+
+ public function testStopTerminatesProcessCleanly()
+ {
+ try {
+ $process = $this->getProcess(self::$phpBin.' -r "echo \'foo\'; sleep(1); echo \'bar\';"');
+ $process->run(function () use ($process) {
+ $process->stop();
+ });
+ } catch (\RuntimeException $e) {
+ $this->fail('A call to stop() is not expected to cause wait() to throw a RuntimeException');
+ }
+ }
+
+ public function testKillSignalTerminatesProcessCleanly()
+ {
+ $this->expectExceptionIfPHPSigchild('Symfony\Component\Process\Exception\RuntimeException', 'This PHP has been compiled with --enable-sigchild. The process can not be signaled.');
+
+ try {
+ $process = $this->getProcess(self::$phpBin.' -r "echo \'foo\'; sleep(1); echo \'bar\';"');
+ $process->run(function () use ($process) {
+ if ($process->isRunning()) {
+ $process->signal(defined('SIGKILL') ? SIGKILL : 9);
+ }
+ });
+ } catch (\RuntimeException $e) {
+ $this->fail('A call to signal() is not expected to cause wait() to throw a RuntimeException');
+ }
+ }
+
+ public function testTermSignalTerminatesProcessCleanly()
+ {
+ $this->expectExceptionIfPHPSigchild('Symfony\Component\Process\Exception\RuntimeException', 'This PHP has been compiled with --enable-sigchild. The process can not be signaled.');
+
+ try {
+ $process = $this->getProcess(self::$phpBin.' -r "echo \'foo\'; sleep(1); echo \'bar\';"');
+ $process->run(function () use ($process) {
+ if ($process->isRunning()) {
+ $process->signal(defined('SIGTERM') ? SIGTERM : 15);
+ }
+ });
+ } catch (\RuntimeException $e) {
+ $this->fail('A call to signal() is not expected to cause wait() to throw a RuntimeException');
+ }
+ }
+
+ public function testStopWithTimeoutIsActuallyWorking()
+ {
+ $this->skipIfPHPSigchild();
+
+ parent::testStopWithTimeoutIsActuallyWorking();
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function getProcess($commandline, $cwd = null, array $env = null, $input = null, $timeout = 60, array $options = array())
+ {
+ return new Process($commandline, $cwd, $env, $input, $timeout, $options);
+ }
+
+ private function skipIfPHPSigchild()
+ {
+ if ($this->enabledSigchild) {
+ $this->markTestSkipped('Your PHP has been compiled with --enable-sigchild, this test can not be executed');
+ }
+ }
+
+ private function expectExceptionIfPHPSigchild($classname, $message)
+ {
+ if ($this->enabledSigchild) {
+ $this->setExpectedException($classname, $message);
+ }
+ }
+}
diff --git a/vendor/symfony/process/composer.json b/vendor/symfony/process/composer.json
new file mode 100644
index 00000000..d0cae4d8
--- /dev/null
+++ b/vendor/symfony/process/composer.json
@@ -0,0 +1,33 @@
+{
+ "name": "symfony/process",
+ "type": "library",
+ "description": "Symfony Process 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"
+ },
+ "autoload": {
+ "psr-4": { "Symfony\\Component\\Process\\": "" }
+ },
+ "minimum-stability": "dev",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "2.7-dev"
+ }
+ }
+}
diff --git a/vendor/symfony/process/phpunit.xml.dist b/vendor/symfony/process/phpunit.xml.dist
new file mode 100644
index 00000000..b5d605c2
--- /dev/null
+++ b/vendor/symfony/process/phpunit.xml.dist
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:noNamespaceSchemaLocation="http://schema.phpunit.de/4.1/phpunit.xsd"
+ backupGlobals="false"
+ colors="true"
+ bootstrap="vendor/autoload.php"
+>
+ <php>
+ <ini name="error_reporting" value="-1" />
+ </php>
+
+ <testsuites>
+ <testsuite name="Symfony Process Component Test Suite">
+ <directory>./Tests/</directory>
+ </testsuite>
+ </testsuites>
+
+ <filter>
+ <whitelist>
+ <directory>./</directory>
+ <exclude>
+ <directory>./Tests</directory>
+ </exclude>
+ </whitelist>
+ </filter>
+</phpunit>
diff --git a/vendor/wikimedia/assert/COPYING b/vendor/wikimedia/assert/COPYING
new file mode 100644
index 00000000..56f0386f
--- /dev/null
+++ b/vendor/wikimedia/assert/COPYING
@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) 2014 Wikimedia Deutschland e.V.
+
+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/wikimedia/assert/README.md b/vendor/wikimedia/assert/README.md
new file mode 100644
index 00000000..6fa9b4d2
--- /dev/null
+++ b/vendor/wikimedia/assert/README.md
@@ -0,0 +1,43 @@
+This package provides an alternative to PHP's `assert()` that allows for an simple and reliable way
+to check preconditions and postconditions in PHP code. It was proposed [as a MediaWiki RFC](https://www.mediawiki.org/wiki/Requests_for_comment/Assert),
+but is completely generic and can be used by any PHP program or library. It is published under the
+MIT license, see the COPYING file.
+
+Usage
+-------
+
+The Assert class provides several static methods for checking various kinds of assertions.
+The most common kind is to check the type of a parameter, typically in a constructor or a
+setter method:
+
+ function setFoo( $foo ) {
+ Assert::parameterType( 'integer', $foo, 'foo' );
+ Assert::parameter( $foo > 0, 'foo', 'must be greater than 0' );
+ }
+
+ function __construct( $bar, array $bazz ) {
+ Assert::parameterType( 'Me\MyApp\SomeClass', $bar );
+ Assert::parameterElementType( 'int', $bazz );
+ }
+
+Checking parameters, or other assertions such as pre- or postconditions, is not recommended for
+performance critical regions of the code, since evaluating expressions and calling the assertion
+functions costs time.
+
+
+Rationale
+-----------
+The background of this proposal is the recurring discussions about whether PHP's `assert()`
+can and should be used in MediaWiki code. Two relevant threads:
+* [Using PHP's assert in MediaWiki code](http://www.gossamer-threads.com/lists/wiki/wikitech/275737)
+* [Is assert() allowed?](http://www.gossamer-threads.com/lists/wiki/wikitech/378676)
+
+The outcome appears to be that
+* assertions are generally a good way to improve code quality
+* but PHP's ''assert()'' is broken by design
+
+Following a [suggestion by Tim Starling](http://www.gossamer-threads.com/lists/wiki/wikitech/378815#378815),
+this package provides an alternative to PHP's built in `assert()`.
+
+[![Build Status](https://secure.travis-ci.org/wmde/Assert.svg)](https://travis-ci.org/wmde/Assert)
+[![Scrutinizer Code Quality](https://scrutinizer-ci.com/g/wmde/Assert/badges/quality-score.png?b=master)](https://scrutinizer-ci.com/g/wmde/Assert/?branch=master)
diff --git a/vendor/wikimedia/assert/composer.json b/vendor/wikimedia/assert/composer.json
new file mode 100644
index 00000000..121f7162
--- /dev/null
+++ b/vendor/wikimedia/assert/composer.json
@@ -0,0 +1,24 @@
+{
+ "name": "wikimedia/assert",
+ "description": "Provides runtime assertions",
+ "keywords": ["PHP", "QA", "assert", "assertions", "precondition", "postcondition"],
+ "homepage": "https://github.com/wmde/Assert",
+ "license": "MIT",
+ "authors": [
+ {
+ "name": "Daniel Kinzler"
+ }
+ ],
+
+ "require-dev": {
+ "phpunit/phpunit": "3.7.*"
+ },
+
+ "autoload": {
+ "psr-4": {
+ "Wikimedia\\Assert\\": "src/",
+ "Wikimedia\\Assert\\Test\\": "tests/phpunit/"
+ }
+ }
+
+}
diff --git a/vendor/wikimedia/assert/phpunit.xml.dist b/vendor/wikimedia/assert/phpunit.xml.dist
new file mode 100644
index 00000000..49a2f87d
--- /dev/null
+++ b/vendor/wikimedia/assert/phpunit.xml.dist
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<phpunit bootstrap="./vendor/autoload.php"
+ backupGlobals="false"
+ backupStaticAttributes="false"
+ cacheTokens="false"
+ colors="true"
+ convertErrorsToExceptions="true"
+ convertNoticesToExceptions="true"
+ convertWarningsToExceptions="true"
+ stopOnError="false"
+ stopOnFailure="false"
+ stopOnIncomplete="false"
+ stopOnSkipped="false"
+ verbose="true">
+
+ <testsuites>
+ <testsuite name="Assert">
+ <directory>./tests/phpunit</directory>
+ </testsuite>
+ </testsuites>
+ <filter>
+ <whitelist addUncoveredFilesFromWhitelist="true">
+ <directory suffix=".php">src</directory>
+ </whitelist>
+ </filter>
+
+</phpunit> \ No newline at end of file
diff --git a/vendor/wikimedia/assert/src/Assert.php b/vendor/wikimedia/assert/src/Assert.php
new file mode 100644
index 00000000..53b438a5
--- /dev/null
+++ b/vendor/wikimedia/assert/src/Assert.php
@@ -0,0 +1,204 @@
+<?php
+
+namespace Wikimedia\Assert;
+
+/**
+ * Assert provides functions for assorting preconditions (such as parameter types) and
+ * postconditions. It is intended as a safer alternative to PHP's assert() function.
+ *
+ * Note that assertions evaluate expressions and add function calls, so using assertions
+ * may have a negative impact on performance when used in performance hotspots. The idea
+ * if this class is to have a neat tool for assertions if and when they are needed.
+ * It is not recommended to place assertions all over the code indiscriminately.
+ *
+ * For more information, see the the README file.
+ *
+ * @license MIT
+ * @author Daniel Kinzler
+ * @copyright Wikimedia Deutschland e.V.
+ */
+class Assert {
+
+ /**
+ * Checks a precondition, that is, throws a PreconditionException if $condition is false.
+ * For checking call parameters, use Assert::parameter() instead.
+ *
+ * This is provided for completeness, most preconditions should be covered by
+ * Assert::parameter() and related assertions.
+ *
+ * @see parameter()
+ *
+ * @note This is intended mostly for checking preconditions in constructors and setters,
+ * or before using parameters in complex computations.
+ * Checking preconditions in every function call is not recommended, since it may have a
+ * negative impact on performance.
+ *
+ * @param bool $condition
+ * @param string $description The message to include in the exception if the condition fails.
+ *
+ * @throws PreconditionException if $condition is not true.
+ */
+ public static function precondition( $condition, $description ) {
+ if ( !$condition ) {
+ throw new PreconditionException( "Precondition failed: $description" );
+ }
+ }
+
+ /**
+ * Checks a parameter, that is, throws a ParameterAssertionException if $condition is false.
+ * This is similar to Assert::precondition().
+ *
+ * @note This is intended for checking parameters in constructors and setters.
+ * Checking parameters in every function call is not recommended, since it may have a
+ * negative impact on performance.
+ *
+ * @param bool $condition
+ * @param string $name The name of the parameter that was checked.
+ * @param string $description The message to include in the exception if the condition fails.
+ *
+ * @throws ParameterAssertionException if $condition is not true.
+ */
+ public static function parameter( $condition, $name, $description ) {
+ if ( !$condition ) {
+ throw new ParameterAssertionException( $name, $description );
+ }
+ }
+
+ /**
+ * Checks an parameter's type, that is, throws a InvalidArgumentException if $condition is false.
+ * This is really a special case of Assert::precondition().
+ *
+ * @note This is intended for checking parameters in constructors and setters.
+ * Checking parameters in every function call is not recommended, since it may have a
+ * negative impact on performance.
+ *
+ * @note If possible, type hints should be used instead of calling this function.
+ * It is intended for cases where type hints to not work, e.g. for checking primitive types.
+ *
+ * @param string $type The parameter's expected type. Can be the name of a native type or a
+ * class or interface. If multiple types are allowed, they can be given separated by
+ * a pipe character ("|").
+ * @param mixed $value The parameter's actual value.
+ * @param string $name The name of the parameter that was checked.
+ *
+ * @throws ParameterTypeException if $value is not of type (or, for objects, is not an
+ * instance of) $type.
+ */
+ public static function parameterType( $type, $value, $name ) {
+ if ( !self::hasType( $value, explode( '|', $type ) ) ) {
+ throw new ParameterTypeException( $name, $type );
+ }
+ }
+
+ /**
+ * Checks the type of all elements of an parameter, assuming the parameter is an array,
+ * that is, throws a ParameterElementTypeException if $value
+ *
+ * @note This is intended for checking parameters in constructors and setters.
+ * Checking parameters in every function call is not recommended, since it may have a
+ * negative impact on performance.
+ *
+ * @param string $type The elements' expected type. Can be the name of a native type or a
+ * class or interface. If multiple types are allowed, they can be given separated by
+ * a pipe character ("|").
+ * @param mixed $value The parameter's actual value. If this is not an array,
+ * a ParameterTypeException is raised.
+ * @param string $name The name of the parameter that was checked.
+ *
+ * @throws ParameterTypeException If $value is not an array.
+ * @throws ParameterElementTypeException If an element of $value is not of type
+ * (or, for objects, is not an instance of) $type.
+ */
+ public static function parameterElementType( $type, $value, $name ) {
+ self::parameterType( 'array', $value, $name );
+
+ $allowedTypes = explode( '|', $type );
+
+ foreach ( $value as $element ) {
+ if ( !self::hasType( $element, $allowedTypes ) ) {
+ throw new ParameterElementTypeException( $name, $type );
+ }
+ }
+ }
+
+ /**
+ * Checks a postcondition, that is, throws a PostconditionException if $condition is false.
+ * This is very similar Assert::invariant() but is intended for use only after a computation
+ * is complete.
+ *
+ * @note This is intended for sanity-checks in the implementation of complex algorithms.
+ * Note however that it should not be used in performance hotspots, since evaluating
+ * $condition and calling postcondition() costs time.
+ *
+ * @param bool $condition
+ * @param string $description The message to include in the exception if the condition fails.
+ *
+ * @throws PostconditionException
+ */
+ public static function postcondition( $condition, $description ) {
+ if ( !$condition ) {
+ throw new PostconditionException( "Postcondition failed: $description" );
+ }
+ }
+
+ /**
+ * Checks an invariant, that is, throws a InvariantException if $condition is false.
+ * This is very similar Assert::postcondition() but is intended for use throughout the code.
+ *
+ * @note This is intended for sanity-checks in the implementation of complex algorithms.
+ * Note however that it should not be used in performance hotspots, since evaluating
+ * $condition and calling postcondition() costs time.
+ *
+ * @param bool $condition
+ * @param string $description The message to include in the exception if the condition fails.
+ *
+ * @throws InvariantException
+ */
+ public static function invariant( $condition, $description ) {
+ if ( !$condition ) {
+ throw new InvariantException( "Invariant failed: $description" );
+ }
+ }
+
+ /**
+ * @param mixed $value
+ * @param array $allowedTypes
+ *
+ * @return bool
+ */
+ private static function hasType( $value, array $allowedTypes ) {
+ // Apply strtolower because gettype returns "NULL" for null values.
+ $type = strtolower( gettype( $value ) );
+
+ if ( in_array( $type, $allowedTypes ) ) {
+ return true;
+ }
+
+ if ( is_callable( $value ) && in_array( 'callable', $allowedTypes ) ) {
+ return true;
+ }
+
+ if ( is_object( $value ) && self::isInstanceOf( $value, $allowedTypes ) ) {
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * @param mixed $value
+ * @param array $allowedTypes
+ *
+ * @return bool
+ */
+ private static function isInstanceOf( $value, array $allowedTypes ) {
+ foreach ( $allowedTypes as $type ) {
+ if ( $value instanceof $type ) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+}
diff --git a/vendor/wikimedia/assert/src/AssertionException.php b/vendor/wikimedia/assert/src/AssertionException.php
new file mode 100644
index 00000000..488c3135
--- /dev/null
+++ b/vendor/wikimedia/assert/src/AssertionException.php
@@ -0,0 +1,16 @@
+<?php
+
+namespace Wikimedia\Assert;
+
+/**
+ * Marker interface for exceptions thrown by Assert. Since the exceptions thrown by Assert
+ * use different standard exceptions as base classes, the marker interface is needed to be
+ * able to catch them all at once.
+ *
+ * @license MIT
+ * @author Daniel Kinzler
+ * @copyright Wikimedia Deutschland e.V.
+ */
+interface AssertionException {
+
+}
diff --git a/vendor/wikimedia/assert/src/InvariantException.php b/vendor/wikimedia/assert/src/InvariantException.php
new file mode 100644
index 00000000..870ce1a0
--- /dev/null
+++ b/vendor/wikimedia/assert/src/InvariantException.php
@@ -0,0 +1,18 @@
+<?php
+
+namespace Wikimedia\Assert;
+
+use LogicException;
+
+/**
+ * Exception indicating that an invariant assertion failed.
+ * This generally means an error in the internal logic of a function, or a serious problem
+ * in the runtime environment.
+ *
+ * @license MIT
+ * @author Daniel Kinzler
+ * @copyright Wikimedia Deutschland e.V.
+ */
+class InvariantException extends LogicException implements AssertionException {
+
+}
diff --git a/vendor/wikimedia/assert/src/ParameterAssertionException.php b/vendor/wikimedia/assert/src/ParameterAssertionException.php
new file mode 100644
index 00000000..cb42cc6f
--- /dev/null
+++ b/vendor/wikimedia/assert/src/ParameterAssertionException.php
@@ -0,0 +1,49 @@
+<?php
+
+namespace Wikimedia\Assert;
+
+use InvalidArgumentException;
+
+/**
+ * Exception indicating that an parameter assertion failed.
+ * This generally means a disagreement between the caller and the implementation of a function.
+ *
+ * @license MIT
+ * @author Daniel Kinzler
+ * @copyright Wikimedia Deutschland e.V.
+ */
+class ParameterAssertionException extends InvalidArgumentException implements AssertionException {
+
+ /**
+ * @var string
+ */
+ private $parameterName;
+
+ /**
+ * @param string $parameterName
+ * @param string $description
+ *
+ * @throws ParameterTypeException
+ */
+ public function __construct( $parameterName, $description ) {
+ if ( !is_string( $parameterName ) ) {
+ throw new ParameterTypeException( 'parameterName', 'string' );
+ }
+
+ if ( !is_string( $description ) ) {
+ throw new ParameterTypeException( 'description', 'string' );
+ }
+
+ parent::__construct( "Bad value for parameter $parameterName: $description" );
+
+ $this->parameterName = $parameterName;
+ }
+
+ /**
+ * @return string
+ */
+ public function getParameterName() {
+ return $this->parameterName;
+ }
+
+}
diff --git a/vendor/wikimedia/assert/src/ParameterElementTypeException.php b/vendor/wikimedia/assert/src/ParameterElementTypeException.php
new file mode 100644
index 00000000..eaaa663f
--- /dev/null
+++ b/vendor/wikimedia/assert/src/ParameterElementTypeException.php
@@ -0,0 +1,43 @@
+<?php
+
+namespace Wikimedia\Assert;
+
+/**
+ * Exception indicating that a parameter element type assertion failed.
+ * This generally means a disagreement between the caller and the implementation of a function.
+ *
+ * @license MIT
+ * @author Daniel Kinzler
+ * @copyright Wikimedia Deutschland e.V.
+ */
+class ParameterElementTypeException extends ParameterAssertionException {
+
+ /**
+ * @var string
+ */
+ private $elementType;
+
+ /**
+ * @param string $parameterName
+ * @param string $elementType
+ *
+ * @throws ParameterTypeException
+ */
+ public function __construct( $parameterName, $elementType ) {
+ if ( !is_string( $elementType ) ) {
+ throw new ParameterTypeException( 'elementType', 'string' );
+ }
+
+ parent::__construct( $parameterName, "all elements must be $elementType" );
+
+ $this->elementType = $elementType;
+ }
+
+ /**
+ * @return string
+ */
+ public function getElementType() {
+ return $this->elementType;
+ }
+
+}
diff --git a/vendor/wikimedia/assert/src/ParameterTypeException.php b/vendor/wikimedia/assert/src/ParameterTypeException.php
new file mode 100644
index 00000000..943f6c08
--- /dev/null
+++ b/vendor/wikimedia/assert/src/ParameterTypeException.php
@@ -0,0 +1,43 @@
+<?php
+
+namespace Wikimedia\Assert;
+
+/**
+ * Exception indicating that a parameter type assertion failed.
+ * This generally means a disagreement between the caller and the implementation of a function.
+ *
+ * @license MIT
+ * @author Daniel Kinzler
+ * @copyright Wikimedia Deutschland e.V.
+ */
+class ParameterTypeException extends ParameterAssertionException {
+
+ /**
+ * @var string
+ */
+ private $parameterType;
+
+ /**
+ * @param string $parameterName
+ * @param string $parameterType
+ *
+ * @throws ParameterTypeException
+ */
+ public function __construct( $parameterName, $parameterType ) {
+ if ( !is_string( $parameterType ) ) {
+ throw new ParameterTypeException( 'parameterType', 'string' );
+ }
+
+ parent::__construct( $parameterName, "must be a $parameterType" );
+
+ $this->parameterType = $parameterType;
+ }
+
+ /**
+ * @return string
+ */
+ public function getParameterType() {
+ return $this->parameterType;
+ }
+
+}
diff --git a/vendor/wikimedia/assert/src/PostconditionException.php b/vendor/wikimedia/assert/src/PostconditionException.php
new file mode 100644
index 00000000..a7753ef0
--- /dev/null
+++ b/vendor/wikimedia/assert/src/PostconditionException.php
@@ -0,0 +1,18 @@
+<?php
+
+namespace Wikimedia\Assert;
+
+use LogicException;
+
+/**
+ * Exception indicating that a postcondition assertion failed.
+ * This generally means an error in the internal logic of a function, or a serious problem
+ * in the runtime environment.
+ *
+ * @license MIT
+ * @author Daniel Kinzler
+ * @copyright Wikimedia Deutschland e.V.
+ */
+class PostconditionException extends LogicException implements AssertionException {
+
+}
diff --git a/vendor/wikimedia/assert/src/PreconditionException.php b/vendor/wikimedia/assert/src/PreconditionException.php
new file mode 100644
index 00000000..97e98035
--- /dev/null
+++ b/vendor/wikimedia/assert/src/PreconditionException.php
@@ -0,0 +1,17 @@
+<?php
+
+namespace Wikimedia\Assert;
+
+use RuntimeException;
+
+/**
+ * Exception indicating that an precondition assertion failed.
+ * This generally means a disagreement between the caller and the implementation of a function.
+ *
+ * @license MIT
+ * @author Daniel Kinzler
+ * @copyright Wikimedia Deutschland e.V.
+ */
+class PreconditionException extends RuntimeException implements AssertionException {
+
+}
diff --git a/vendor/wikimedia/assert/tests/phpunit/AssertTest.php b/vendor/wikimedia/assert/tests/phpunit/AssertTest.php
new file mode 100644
index 00000000..038bc1c1
--- /dev/null
+++ b/vendor/wikimedia/assert/tests/phpunit/AssertTest.php
@@ -0,0 +1,156 @@
+<?php
+
+namespace Wikimedia\Assert\Test;
+
+use LogicException;
+use PHPUnit_Framework_TestCase;
+use RuntimeException;
+use Wikimedia\Assert\Assert;
+use Wikimedia\Assert\AssertionException;
+use Wikimedia\Assert\ParameterAssertionException;
+use Wikimedia\Assert\ParameterElementTypeException;
+use Wikimedia\Assert\ParameterTypeException;
+
+/**
+ * @covers Wikimedia\Assert\Assert
+ *
+ * @license MIT
+ * @author Daniel Kinzler
+ * @copyright Wikimedia Deutschland e.V.
+ */
+
+class AssertTest extends PHPUnit_Framework_TestCase {
+
+ public function testPrecondition_pass() {
+ Assert::precondition( true, 'test' );
+ }
+
+ public function testPrecondition_fail() {
+ $this->setExpectedException( 'Wikimedia\Assert\PreconditionException' );
+ Assert::precondition( false, 'test' );
+ }
+
+ public function testParameter_pass() {
+ Assert::parameter( true, 'foo', 'test' );
+ }
+
+ public function testParameter_fail() {
+ try {
+ Assert::parameter( false, 'test', 'testing' );
+ } catch ( ParameterAssertionException $ex ) {
+ $this->assertEquals( 'test', $ex->getParameterName() );
+ }
+ }
+
+ public function validParameterTypeProvider() {
+ return array(
+ 'simple' => array( 'string', 'hello' ),
+ 'class' => array( 'RuntimeException', new RuntimeException() ),
+ 'multi' => array( 'string|array|Closure', function() {} ),
+ 'null' => array( 'integer|null', null ),
+ 'callable' => array( 'null|callable', 'time' ),
+ );
+ }
+
+ /**
+ * @dataProvider validParameterTypeProvider
+ */
+ public function testParameterType_pass( $type, $value ) {
+ Assert::parameterType( $type, $value, 'test' );
+ }
+
+ public function invalidParameterTypeProvider() {
+ return array(
+ 'simple' => array( 'string', 5 ),
+ 'class' => array( 'RuntimeException', new LogicException() ),
+ 'multi' => array( 'string|integer|Closure', array() ),
+ 'null' => array( 'integer|string', null ),
+ 'callable' => array( 'null|callable', array() ),
+ );
+ }
+
+ /**
+ * @dataProvider invalidParameterTypeProvider
+ */
+ public function testParameterType_fail( $type, $value ) {
+ try {
+ Assert::parameterType( $type, $value, 'test' );
+ $this->fail( 'Expected ParameterTypeException' );
+ } catch ( ParameterTypeException $ex ) {
+ $this->assertEquals( $type, $ex->getParameterType() );
+ $this->assertEquals( 'test', $ex->getParameterName() );
+ }
+ }
+
+ public function testParameterType_catch() {
+ try {
+ Assert::parameterType( 'string', 17, 'test' );
+ $this->fail( 'Expected exception' );
+ } catch ( AssertionException $ex ) {
+ // ok
+ }
+ }
+
+ public function validParameterElementTypeProvider() {
+ return array(
+ 'empty' => array( 'string', array() ),
+ 'simple' => array( 'string', array( 'hello', 'world' ) ),
+ 'class' => array( 'RuntimeException', array( new RuntimeException() ) ),
+ 'multi' => array( 'string|array|Closure', array( array(), function() {} ) ),
+ 'null' => array( 'integer|null', array( null, 3, null ) ),
+ );
+ }
+
+ /**
+ * @dataProvider validParameterElementTypeProvider
+ */
+ public function testParameterElementType_pass( $type, $value ) {
+ Assert::parameterElementType( $type, $value, 'test' );
+ }
+
+ public function invalidParameterElementTypeProvider() {
+ return array(
+ 'simple' => array( 'string', array( 'hello', 5 ) ),
+ 'class' => array( 'RuntimeException', array( new LogicException() ) ),
+ 'multi' => array( 'string|array|Closure', array( array(), function() {}, 5 ) ),
+ 'null' => array( 'integer|string', array( null, 3, null ) ),
+ );
+ }
+
+ /**
+ * @dataProvider invalidParameterElementTypeProvider
+ */
+ public function testParameterElementType_fail( $type, $value ) {
+ try {
+ Assert::parameterElementType( $type, $value, 'test' );
+ $this->fail( 'Expected ParameterElementTypeException' );
+ } catch ( ParameterElementTypeException $ex ) {
+ $this->assertEquals( $type, $ex->getElementType() );
+ $this->assertEquals( 'test', $ex->getParameterName() );
+ }
+ }
+
+ public function testParameterElementType_bad() {
+ $this->setExpectedException( 'Wikimedia\Assert\ParameterTypeException' );
+ Assert::parameterElementType( 'string', 'foo', 'test' );
+ }
+
+ public function testInvariant_pass() {
+ Assert::invariant( true, 'test' );
+ }
+
+ public function testInvariant_fail() {
+ $this->setExpectedException( 'Wikimedia\Assert\InvariantException' );
+ Assert::invariant( false, 'test' );
+ }
+
+ public function testPostcondition_pass() {
+ Assert::postcondition( true, 'test' );
+ }
+
+ public function testPostcondition_fail() {
+ $this->setExpectedException( 'Wikimedia\Assert\PostconditionException' );
+ Assert::postcondition( false, 'test' );
+ }
+
+}
diff --git a/vendor/wikimedia/avro/LICENSE.txt b/vendor/wikimedia/avro/LICENSE.txt
new file mode 100644
index 00000000..6d3f211b
--- /dev/null
+++ b/vendor/wikimedia/avro/LICENSE.txt
@@ -0,0 +1,308 @@
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+----------------------------------------------------------------------
+License for the Jansson C JSON parser used in the C implementation:
+
+Copyright (c) 2009 Petri Lehtinen <petri@digip.org>
+
+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.
+
+----------------------------------------------------------------------
+License for the Json.NET used in the C# implementation:
+
+Copyright (c) 2007 James Newton-King
+
+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.
+
+----------------------------------------------------------------------
+License for msinttypes used in the C implementation:
+Source from:
+http://code.google.com/p/msinttypes/downloads/detail?name=msinttypes-r26.zip
+
+Copyright (c) 2006-2008 Alexander Chemeris
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ 3. The name of the author may be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+----------------------------------------------------------------------
+License for Dirent API for Microsoft Visual Studio used in the C implementation:
+Source from:
+http://www.softagalleria.net/download/dirent/dirent-1.11.zip
+
+Copyright (C) 2006 Toni Ronkko
+
+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 TONI RONKKO 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/wikimedia/avro/NOTICE.txt b/vendor/wikimedia/avro/NOTICE.txt
new file mode 100644
index 00000000..e601a8e9
--- /dev/null
+++ b/vendor/wikimedia/avro/NOTICE.txt
@@ -0,0 +1,9 @@
+Apache Avro
+Copyright 2010 The Apache Software Foundation
+
+This product includes software developed at
+The Apache Software Foundation (http://www.apache.org/).
+
+C JSON parsing provided by Jansson and
+written by Petri Lehtinen. The original software is
+available from http://www.digip.org/jansson/.
diff --git a/vendor/wikimedia/avro/README.md b/vendor/wikimedia/avro/README.md
new file mode 100644
index 00000000..5604baf2
--- /dev/null
+++ b/vendor/wikimedia/avro/README.md
@@ -0,0 +1,23 @@
+What the Avro PHP library is
+============================
+
+A library for using [Avro](http://avro.apache.org/) with PHP.
+
+Requirements
+------------
+ * PHP 5
+ * On 32-bit platforms, the [GMP PHP extension](http://php.net/gmp)
+ * For testing, [PHPUnit](http://www.phpunit.de/)
+
+Both GMP and PHPUnit are often available via package management
+systems as `php5-gmp` and `phpunit`, respectively.
+
+Getting started
+---------------
+```
+$ composer require wikimedia/avro
+```
+
+History
+-------
+Extracted from https://github.com/apache/avro using `git subtree`.
diff --git a/vendor/wikimedia/avro/lib/avro.php b/vendor/wikimedia/avro/lib/avro.php
new file mode 100644
index 00000000..4805fb7a
--- /dev/null
+++ b/vendor/wikimedia/avro/lib/avro.php
@@ -0,0 +1,195 @@
+<?php
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * Avro library top-level file.
+ *
+ * This file in turn includes all files supporting the
+ * Avro implementation.
+ *
+ * @package Avro
+ */
+
+/**
+ * General Avro exceptions.
+ * @package Avro
+ */
+class AvroException extends Exception {}
+
+/**
+ * Library-level class for PHP Avro port.
+ *
+ * Contains library details such as version number and platform checks.
+ *
+ * This port is an implementation of the
+ * {@link http://avro.apache.org/docs/1.3.3/spec.html Avro 1.3.3 Specification}
+ *
+ * @package Avro
+ *
+ */
+class Avro
+{
+ /**
+ * @var string version number of Avro specification to which
+ * this implemenation complies
+ */
+ const SPEC_VERSION = '1.3.3';
+
+ /**#@+
+ * Constant to enumerate endianness.
+ * @access private
+ * @var int
+ */
+ const BIG_ENDIAN = 0x00;
+ const LITTLE_ENDIAN = 0x01;
+ /**#@-*/
+
+ /**
+ * Memoized result of self::set_endianness()
+ * @var int self::BIG_ENDIAN or self::LITTLE_ENDIAN
+ * @see self::set_endianness()
+ */
+ private static $endianness;
+
+ /**#@+
+ * Constant to enumerate biginteger handling mode.
+ * GMP is used, if available, on 32-bit platforms.
+ */
+ const PHP_BIGINTEGER_MODE = 0x00;
+ const GMP_BIGINTEGER_MODE = 0x01;
+ /**#@-*/
+
+ /**
+ * @var int
+ * Mode used to handle bigintegers. After Avro::check_64_bit() has been called,
+ * (usually via a call to Avro::check_platform(), set to
+ * self::GMP_BIGINTEGER_MODE on 32-bit platforms that have GMP available,
+ * and to self::PHP_BIGINTEGER_MODE otherwise.
+ */
+ private static $biginteger_mode;
+
+ /**
+ * Wrapper method to call each required check.
+ *
+ */
+ public static function check_platform()
+ {
+ self::check_64_bit();
+ self::check_little_endian();
+ }
+
+ /**
+ * Determines if the host platform can encode and decode long integer data.
+ *
+ * @throws AvroException if the platform cannot handle long integers.
+ */
+ private static function check_64_bit()
+ {
+ if (8 != PHP_INT_SIZE)
+ if (extension_loaded('gmp'))
+ self::$biginteger_mode = self::GMP_BIGINTEGER_MODE;
+ else
+ throw new AvroException('This platform cannot handle a 64-bit operations. '
+ . 'Please install the GMP PHP extension.');
+ else
+ self::$biginteger_mode = self::PHP_BIGINTEGER_MODE;
+
+ }
+
+ /**
+ * @returns boolean true if the PHP GMP extension is used and false otherwise.
+ * @internal Requires Avro::check_64_bit() (exposed via Avro::check_platform())
+ * to have been called to set Avro::$biginteger_mode.
+ */
+ static function uses_gmp()
+ {
+ return (self::GMP_BIGINTEGER_MODE == self::$biginteger_mode);
+ }
+
+ /**
+ * Determines if the host platform is little endian,
+ * required for processing double and float data.
+ *
+ * @throws AvroException if the platform is not little endian.
+ */
+ private static function check_little_endian()
+ {
+ if (!self::is_little_endian_platform())
+ throw new AvroException('This is not a little-endian platform');
+ }
+
+ /**
+ * Determines the endianness of the host platform and memoizes
+ * the result to Avro::$endianness.
+ *
+ * Based on a similar check perfomed in http://pear.php.net/package/Math_BinaryUtils
+ *
+ * @throws AvroException if the endianness cannot be determined.
+ */
+ private static function set_endianness()
+ {
+ $packed = pack('d', 1);
+ switch ($packed)
+ {
+ case "\77\360\0\0\0\0\0\0":
+ self::$endianness = self::BIG_ENDIAN;
+ break;
+ case "\0\0\0\0\0\0\360\77":
+ self::$endianness = self::LITTLE_ENDIAN;
+ break;
+ default:
+ throw new AvroException(
+ sprintf('Error determining platform endianness: %s',
+ AvroDebug::hex_string($packed)));
+ }
+ }
+
+ /**
+ * @returns boolean true if the host platform is big endian
+ * and false otherwise.
+ * @uses self::set_endianness()
+ */
+ private static function is_big_endian_platform()
+ {
+ if (is_null(self::$endianness))
+ self::set_endianness();
+
+ return (self::BIG_ENDIAN == self::$endianness);
+ }
+
+ /**
+ * @returns boolean true if the host platform is little endian,
+ * and false otherwise.
+ * @uses self::is_bin_endian_platform()
+ */
+ private static function is_little_endian_platform()
+ {
+ return !self::is_big_endian_platform();
+ }
+
+}
+
+require_once('avro/util.php');
+require_once('avro/debug.php');
+require_once('avro/schema.php');
+require_once('avro/io.php');
+require_once('avro/gmp.php');
+require_once('avro/datum.php');
+require_once('avro/data_file.php');
+require_once('avro/protocol.php');
diff --git a/vendor/wikimedia/avro/lib/avro/data_file.php b/vendor/wikimedia/avro/lib/avro/data_file.php
new file mode 100644
index 00000000..e8e089f5
--- /dev/null
+++ b/vendor/wikimedia/avro/lib/avro/data_file.php
@@ -0,0 +1,535 @@
+<?php
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * Classes handling reading and writing from and to AvroIO objects
+ * @package Avro
+ */
+
+/**
+ * Raised when something unkind happens with respect to AvroDataIO.
+ * @package Avro
+ */
+class AvroDataIOException extends AvroException {}
+
+/**
+ * @package Avro
+ */
+class AvroDataIO
+{
+ /**
+ * @var int used in file header
+ */
+ const VERSION = 1;
+
+ /**
+ * @var int count of bytes in synchronization marker
+ */
+ const SYNC_SIZE = 16;
+
+ /**
+ * @var int count of items per block, arbitrarily set to 4000 * SYNC_SIZE
+ * @todo make this value configurable
+ */
+ const SYNC_INTERVAL = 64000;
+
+ /**
+ * @var string map key for datafile metadata codec value
+ */
+ const METADATA_CODEC_ATTR = 'avro.codec';
+
+ /**
+ * @var string map key for datafile metadata schema value
+ */
+ const METADATA_SCHEMA_ATTR = 'avro.schema';
+ /**
+ * @var string JSON for datafile metadata schema
+ */
+ const METADATA_SCHEMA_JSON = '{"type":"map","values":"bytes"}';
+
+ /**
+ * @var string codec value for NULL codec
+ */
+ const NULL_CODEC = 'null';
+
+ /**
+ * @var string codec value for deflate codec
+ */
+ const DEFLATE_CODEC = 'deflate';
+
+ /**
+ * @var array array of valid codec names
+ * @todo Avro implementations are required to implement deflate codec as well,
+ * so implement it already!
+ */
+ private static $valid_codecs = array(self::NULL_CODEC);
+
+ /**
+ * @var AvroSchema cached version of metadata schema object
+ */
+ private static $metadata_schema;
+
+ /**
+ * @returns the initial "magic" segment of an Avro container file header.
+ */
+ public static function magic() { return ('Obj' . pack('c', self::VERSION)); }
+
+ /**
+ * @returns int count of bytes in the initial "magic" segment of the
+ * Avro container file header
+ */
+ public static function magic_size() { return strlen(self::magic()); }
+
+
+ /**
+ * @returns AvroSchema object of Avro container file metadata.
+ */
+ public static function metadata_schema()
+ {
+ if (is_null(self::$metadata_schema))
+ self::$metadata_schema = AvroSchema::parse(self::METADATA_SCHEMA_JSON);
+ return self::$metadata_schema;
+ }
+
+ /**
+ * @param string $file_path file_path of file to open
+ * @param string $mode one of AvroFile::READ_MODE or AvroFile::WRITE_MODE
+ * @param string $schema_json JSON of writer's schema
+ * @returns AvroDataIOWriter instance of AvroDataIOWriter
+ *
+ * @throws AvroDataIOException if $writers_schema is not provided
+ * or if an invalid $mode is given.
+ */
+ public static function open_file($file_path, $mode=AvroFile::READ_MODE,
+ $schema_json=null)
+ {
+ $schema = !is_null($schema_json)
+ ? AvroSchema::parse($schema_json) : null;
+
+ $io = false;
+ switch ($mode)
+ {
+ case AvroFile::WRITE_MODE:
+ if (is_null($schema))
+ throw new AvroDataIOException('Writing an Avro file requires a schema.');
+ $file = new AvroFile($file_path, AvroFile::WRITE_MODE);
+ $io = self::open_writer($file, $schema);
+ break;
+ case AvroFile::READ_MODE:
+ $file = new AvroFile($file_path, AvroFile::READ_MODE);
+ $io = self::open_reader($file, $schema);
+ break;
+ default:
+ throw new AvroDataIOException(
+ sprintf("Only modes '%s' and '%s' allowed. You gave '%s'.",
+ AvroFile::READ_MODE, AvroFile::WRITE_MODE, $mode));
+ }
+ return $io;
+ }
+
+ /**
+ * @returns array array of valid codecs
+ */
+ private static function valid_codecs()
+ {
+ return self::$valid_codecs;
+ }
+
+ /**
+ * @param string $codec
+ * @returns boolean true if $codec is a valid codec value and false otherwise
+ */
+ public static function is_valid_codec($codec)
+ {
+ return in_array($codec, self::valid_codecs());
+ }
+
+ /**
+ * @param AvroIO $io
+ * @param AvroSchema $schema
+ * @returns AvroDataIOWriter
+ */
+ protected function open_writer($io, $schema)
+ {
+ $writer = new AvroIODatumWriter($schema);
+ return new AvroDataIOWriter($io, $writer, $schema);
+ }
+
+ /**
+ * @param AvroIO $io
+ * @param AvroSchema $schema
+ * @returns AvroDataIOReader
+ */
+ protected function open_reader($io, $schema)
+ {
+ $reader = new AvroIODatumReader(null, $schema);
+ return new AvroDataIOReader($io, $reader);
+ }
+
+}
+
+/**
+ *
+ * Reads Avro data from an AvroIO source using an AvroSchema.
+ * @package Avro
+ */
+class AvroDataIOReader
+{
+ /**
+ * @var AvroIO
+ */
+ private $io;
+
+ /**
+ * @var AvroIOBinaryDecoder
+ */
+ private $decoder;
+
+ /**
+ * @var AvroIODatumReader
+ */
+ private $datum_reader;
+
+ /**
+ * @var string
+ */
+ private $sync_marker;
+
+ /**
+ * @var array object container metadata
+ */
+ private $metadata;
+
+ /**
+ * @var int count of items in block
+ */
+ private $block_count;
+
+ /**
+ * @param AvroIO $io source from which to read
+ * @param AvroIODatumReader $datum_reader reader that understands
+ * the data schema
+ * @throws AvroDataIOException if $io is not an instance of AvroIO
+ * @uses read_header()
+ */
+ public function __construct($io, $datum_reader)
+ {
+
+ if (!($io instanceof AvroIO))
+ throw new AvroDataIOException('io must be instance of AvroIO');
+
+ $this->io = $io;
+ $this->decoder = new AvroIOBinaryDecoder($this->io);
+ $this->datum_reader = $datum_reader;
+ $this->read_header();
+
+ $codec = AvroUtil::array_value($this->metadata,
+ AvroDataIO::METADATA_CODEC_ATTR);
+ if ($codec && !AvroDataIO::is_valid_codec($codec))
+ throw new AvroDataIOException(sprintf('Uknown codec: %s', $codec));
+
+ $this->block_count = 0;
+ // FIXME: Seems unsanitary to set writers_schema here.
+ // Can't constructor take it as an argument?
+ $this->datum_reader->set_writers_schema(
+ AvroSchema::parse($this->metadata[AvroDataIO::METADATA_SCHEMA_ATTR]));
+ }
+
+ /**
+ * Reads header of object container
+ * @throws AvroDataIOException if the file is not an Avro data file.
+ */
+ private function read_header()
+ {
+ $this->seek(0, AvroIO::SEEK_SET);
+
+ $magic = $this->read(AvroDataIO::magic_size());
+
+ if (strlen($magic) < AvroDataIO::magic_size())
+ throw new AvroDataIOException(
+ 'Not an Avro data file: shorter than the Avro magic block');
+
+ if (AvroDataIO::magic() != $magic)
+ throw new AvroDataIOException(
+ sprintf('Not an Avro data file: %s does not match %s',
+ $magic, AvroDataIO::magic()));
+
+ $this->metadata = $this->datum_reader->read_data(AvroDataIO::metadata_schema(),
+ AvroDataIO::metadata_schema(),
+ $this->decoder);
+ $this->sync_marker = $this->read(AvroDataIO::SYNC_SIZE);
+ }
+
+ /**
+ * @internal Would be nice to implement data() as an iterator, I think
+ * @returns array of data from object container.
+ */
+ public function data()
+ {
+ $data = array();
+ while (true)
+ {
+ if (0 == $this->block_count)
+ {
+ if ($this->is_eof())
+ break;
+
+ if ($this->skip_sync())
+ if ($this->is_eof())
+ break;
+
+ $this->read_block_header();
+ }
+ $data []= $this->datum_reader->read($this->decoder);
+ $this->block_count -= 1;
+ }
+ return $data;
+ }
+
+ /**
+ * Closes this writer (and its AvroIO object.)
+ * @uses AvroIO::close()
+ */
+ public function close() { return $this->io->close(); }
+
+ /**
+ * @uses AvroIO::seek()
+ */
+ private function seek($offset, $whence)
+ {
+ return $this->io->seek($offset, $whence);
+ }
+
+ /**
+ * @uses AvroIO::read()
+ */
+ private function read($len) { return $this->io->read($len); }
+
+ /**
+ * @uses AvroIO::is_eof()
+ */
+ private function is_eof() { return $this->io->is_eof(); }
+
+ private function skip_sync()
+ {
+ $proposed_sync_marker = $this->read(AvroDataIO::SYNC_SIZE);
+ if ($proposed_sync_marker != $this->sync_marker)
+ {
+ $this->seek(-AvroDataIO::SYNC_SIZE, AvroIO::SEEK_CUR);
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Reads the block header (which includes the count of items in the block
+ * and the length in bytes of the block)
+ * @returns int length in bytes of the block.
+ */
+ private function read_block_header()
+ {
+ $this->block_count = $this->decoder->read_long();
+ return $this->decoder->read_long();
+ }
+
+}
+
+/**
+ * Writes Avro data to an AvroIO source using an AvroSchema
+ * @package Avro
+ */
+class AvroDataIOWriter
+{
+ /**
+ * @returns string a new, unique sync marker.
+ */
+ private static function generate_sync_marker()
+ {
+ // From http://php.net/manual/en/function.mt-rand.php comments
+ return pack('S8',
+ mt_rand(0, 0xffff), mt_rand(0, 0xffff),
+ mt_rand(0, 0xffff),
+ mt_rand(0, 0xffff) | 0x4000,
+ mt_rand(0, 0xffff) | 0x8000,
+ mt_rand(0, 0xffff), mt_rand(0, 0xffff), mt_rand(0, 0xffff));
+ }
+
+ /**
+ * @var AvroIO object container where data is written
+ */
+ private $io;
+
+ /**
+ * @var AvroIOBinaryEncoder encoder for object container
+ */
+ private $encoder;
+
+ /**
+ * @var AvroDatumWriter
+ */
+ private $datum_writer;
+
+ /**
+ * @var AvroStringIO buffer for writing
+ */
+ private $buffer;
+
+ /**
+ * @var AvroIOBinaryEncoder encoder for buffer
+ */
+ private $buffer_encoder; // AvroIOBinaryEncoder
+
+ /**
+ * @var int count of items written to block
+ */
+ private $block_count;
+
+ /**
+ * @var array map of object container metadata
+ */
+ private $metadata;
+
+ /**
+ * @param AvroIO $io
+ * @param AvroIODatumWriter $datum_writer
+ * @param AvroSchema $writers_schema
+ */
+ public function __construct($io, $datum_writer, $writers_schema=null)
+ {
+ if (!($io instanceof AvroIO))
+ throw new AvroDataIOException('io must be instance of AvroIO');
+
+ $this->io = $io;
+ $this->encoder = new AvroIOBinaryEncoder($this->io);
+ $this->datum_writer = $datum_writer;
+ $this->buffer = new AvroStringIO();
+ $this->buffer_encoder = new AvroIOBinaryEncoder($this->buffer);
+ $this->block_count = 0;
+ $this->metadata = array();
+
+ if ($writers_schema)
+ {
+ $this->sync_marker = self::generate_sync_marker();
+ $this->metadata[AvroDataIO::METADATA_CODEC_ATTR] = AvroDataIO::NULL_CODEC;
+ $this->metadata[AvroDataIO::METADATA_SCHEMA_ATTR] = strval($writers_schema);
+ $this->write_header();
+ }
+ else
+ {
+ $dfr = new AvroDataIOReader($this->io, new AvroIODatumReader());
+ $this->sync_marker = $dfr->sync_marker;
+ $this->metadata[AvroDataIO::METADATA_CODEC_ATTR] = $dfr->metadata[AvroDataIO::METADATA_CODEC_ATTR];
+
+ $schema_from_file = $dfr->metadata[AvroDataIO::METADATA_SCHEMA_ATTR];
+ $this->metadata[AvroDataIO::METADATA_SCHEMA_ATTR] = $schema_from_file;
+ $this->datum_writer->writers_schema = AvroSchema::parse($schema_from_file);
+ $this->seek(0, SEEK_END);
+ }
+ }
+
+ /**
+ * @param mixed $datum
+ */
+ public function append($datum)
+ {
+ $this->datum_writer->write($datum, $this->buffer_encoder);
+ $this->block_count++;
+
+ if ($this->buffer->length() >= AvroDataIO::SYNC_INTERVAL)
+ $this->write_block();
+ }
+
+ /**
+ * Flushes buffer to AvroIO object container and closes it.
+ * @return mixed value of $io->close()
+ * @see AvroIO::close()
+ */
+ public function close()
+ {
+ $this->flush();
+ return $this->io->close();
+ }
+
+ /**
+ * Flushes biffer to AvroIO object container.
+ * @returns mixed value of $io->flush()
+ * @see AvroIO::flush()
+ */
+ private function flush()
+ {
+ $this->write_block();
+ return $this->io->flush();
+ }
+
+ /**
+ * Writes a block of data to the AvroIO object container.
+ * @throws AvroDataIOException if the codec provided by the encoder
+ * is not supported
+ * @internal Should the codec check happen in the constructor?
+ * Why wait until we're writing data?
+ */
+ private function write_block()
+ {
+ if ($this->block_count > 0)
+ {
+ $this->encoder->write_long($this->block_count);
+ $to_write = strval($this->buffer);
+ $this->encoder->write_long(strlen($to_write));
+
+ if (AvroDataIO::is_valid_codec(
+ $this->metadata[AvroDataIO::METADATA_CODEC_ATTR]))
+ $this->write($to_write);
+ else
+ throw new AvroDataIOException(
+ sprintf('codec %s is not supported',
+ $this->metadata[AvroDataIO::METADATA_CODEC_ATTR]));
+
+ $this->write($this->sync_marker);
+ $this->buffer->truncate();
+ $this->block_count = 0;
+ }
+ }
+
+ /**
+ * Writes the header of the AvroIO object container
+ */
+ private function write_header()
+ {
+ $this->write(AvroDataIO::magic());
+ $this->datum_writer->write_data(AvroDataIO::metadata_schema(),
+ $this->metadata, $this->encoder);
+ $this->write($this->sync_marker);
+ }
+
+ /**
+ * @param string $bytes
+ * @uses AvroIO::write()
+ */
+ private function write($bytes) { return $this->io->write($bytes); }
+
+ /**
+ * @param int $offset
+ * @param int $whence
+ * @uses AvroIO::seek()
+ */
+ private function seek($offset, $whence)
+ {
+ return $this->io->seek($offset, $whence);
+ }
+}
diff --git a/vendor/wikimedia/avro/lib/avro/datum.php b/vendor/wikimedia/avro/lib/avro/datum.php
new file mode 100644
index 00000000..ea275faf
--- /dev/null
+++ b/vendor/wikimedia/avro/lib/avro/datum.php
@@ -0,0 +1,984 @@
+<?php
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * Classes for reading and writing Avro data to AvroIO objects.
+ *
+ * @package Avro
+ *
+ * @todo Implement JSON encoding, as is required by the Avro spec.
+ */
+
+/**
+ * Exceptions arising from writing or reading Avro data.
+ *
+ * @package Avro
+ */
+class AvroIOTypeException extends AvroException
+{
+ /**
+ * @param AvroSchema $expected_schema
+ * @param mixed $datum
+ */
+ public function __construct($expected_schema, $datum)
+ {
+ parent::__construct(sprintf('The datum %s is not an example of schema %s',
+ var_export($datum, true), $expected_schema));
+ }
+}
+
+/**
+ * Exceptions arising from incompatibility between
+ * reader and writer schemas.
+ *
+ * @package Avro
+ */
+class AvroIOSchemaMatchException extends AvroException
+{
+ /**
+ * @param AvroSchema $writers_schema
+ * @param AvroSchema $readers_schema
+ */
+ function __construct($writers_schema, $readers_schema)
+ {
+ parent::__construct(
+ sprintf("Writer's schema %s and Reader's schema %s do not match.",
+ $writers_schema, $readers_schema));
+ }
+}
+
+/**
+ * Handles schema-specific writing of data to the encoder.
+ *
+ * Ensures that each datum written is consistent with the writer's schema.
+ *
+ * @package Avro
+ */
+class AvroIODatumWriter
+{
+ /**
+ * Schema used by this instance to write Avro data.
+ * @var AvroSchema
+ */
+ private $writers_schema;
+
+ /**
+ * @param AvroSchema $writers_schema
+ */
+ function __construct($writers_schema=null)
+ {
+ $this->writers_schema = $writers_schema;
+ }
+
+ /**
+ * @param AvroSchema $writers_schema
+ * @param $datum
+ * @param AvroIOBinaryEncoder $encoder
+ * @returns mixed
+ *
+ * @throws AvroIOTypeException if $datum is invalid for $writers_schema
+ */
+ function write_data($writers_schema, $datum, $encoder)
+ {
+ if (!AvroSchema::is_valid_datum($writers_schema, $datum))
+ throw new AvroIOTypeException($writers_schema, $datum);
+
+ switch ($writers_schema->type())
+ {
+ case AvroSchema::NULL_TYPE:
+ return $encoder->write_null($datum);
+ case AvroSchema::BOOLEAN_TYPE:
+ return $encoder->write_boolean($datum);
+ case AvroSchema::INT_TYPE:
+ return $encoder->write_int($datum);
+ case AvroSchema::LONG_TYPE:
+ return $encoder->write_long($datum);
+ case AvroSchema::FLOAT_TYPE:
+ return $encoder->write_float($datum);
+ case AvroSchema::DOUBLE_TYPE:
+ return $encoder->write_double($datum);
+ case AvroSchema::STRING_TYPE:
+ return $encoder->write_string($datum);
+ case AvroSchema::BYTES_TYPE:
+ return $encoder->write_bytes($datum);
+ case AvroSchema::ARRAY_SCHEMA:
+ return $this->write_array($writers_schema, $datum, $encoder);
+ case AvroSchema::MAP_SCHEMA:
+ return $this->write_map($writers_schema, $datum, $encoder);
+ case AvroSchema::FIXED_SCHEMA:
+ return $this->write_fixed($writers_schema, $datum, $encoder);
+ case AvroSchema::ENUM_SCHEMA:
+ return $this->write_enum($writers_schema, $datum, $encoder);
+ case AvroSchema::RECORD_SCHEMA:
+ case AvroSchema::ERROR_SCHEMA:
+ case AvroSchema::REQUEST_SCHEMA:
+ return $this->write_record($writers_schema, $datum, $encoder);
+ case AvroSchema::UNION_SCHEMA:
+ return $this->write_union($writers_schema, $datum, $encoder);
+ default:
+ throw new AvroException(sprintf('Uknown type: %s',
+ $writers_schema->type));
+ }
+ }
+
+ /**
+ * @param $datum
+ * @param AvroIOBinaryEncoder $encoder
+ */
+ function write($datum, $encoder)
+ {
+ $this->write_data($this->writers_schema, $datum, $encoder);
+ }
+
+ /**#@+
+ * @param AvroSchema $writers_schema
+ * @param null|boolean|int|float|string|array $datum item to be written
+ * @param AvroIOBinaryEncoder $encoder
+ */
+ private function write_array($writers_schema, $datum, $encoder)
+ {
+ $datum_count = count($datum);
+ if (0 < $datum_count)
+ {
+ $encoder->write_long($datum_count);
+ $items = $writers_schema->items();
+ foreach ($datum as $item)
+ $this->write_data($items, $item, $encoder);
+ }
+ return $encoder->write_long(0);
+ }
+
+ private function write_map($writers_schema, $datum, $encoder)
+ {
+ $datum_count = count($datum);
+ if ($datum_count > 0)
+ {
+ $encoder->write_long($datum_count);
+ foreach ($datum as $k => $v)
+ {
+ $encoder->write_string($k);
+ $this->write_data($writers_schema->values(), $v, $encoder);
+ }
+ }
+ $encoder->write_long(0);
+ }
+
+ private function write_union($writers_schema, $datum, $encoder)
+ {
+ $datum_schema_index = -1;
+ $datum_schema = null;
+ foreach ($writers_schema->schemas() as $index => $schema)
+ if (AvroSchema::is_valid_datum($schema, $datum))
+ {
+ $datum_schema_index = $index;
+ $datum_schema = $schema;
+ break;
+ }
+
+ if (is_null($datum_schema))
+ throw new AvroIOTypeException($writers_schema, $datum);
+
+ $encoder->write_long($datum_schema_index);
+ $this->write_data($datum_schema, $datum, $encoder);
+ }
+
+ private function write_enum($writers_schema, $datum, $encoder)
+ {
+ $datum_index = $writers_schema->symbol_index($datum);
+ return $encoder->write_int($datum_index);
+ }
+
+ private function write_fixed($writers_schema, $datum, $encoder)
+ {
+ /**
+ * NOTE Unused $writers_schema parameter included for consistency
+ * with other write_* methods.
+ */
+ return $encoder->write($datum);
+ }
+
+ private function write_record($writers_schema, $datum, $encoder)
+ {
+ foreach ($writers_schema->fields() as $field)
+ $this->write_data($field->type(), $datum[$field->name()], $encoder);
+ }
+
+ /**#@-*/
+}
+
+/**
+ * Encodes and writes Avro data to an AvroIO object using
+ * Avro binary encoding.
+ *
+ * @package Avro
+ */
+class AvroIOBinaryEncoder
+{
+ /**
+ * Performs encoding of the given float value to a binary string
+ *
+ * XXX: This is <b>not</b> endian-aware! The {@link Avro::check_platform()}
+ * called in {@link AvroIOBinaryEncoder::__construct()} should ensure the
+ * library is only used on little-endian platforms, which ensure the little-endian
+ * encoding required by the Avro spec.
+ *
+ * @param float $float
+ * @returns string bytes
+ * @see Avro::check_platform()
+ */
+ static function float_to_int_bits($float)
+ {
+ return pack('f', (float) $float);
+ }
+
+ /**
+ * Performs encoding of the given double value to a binary string
+ *
+ * XXX: This is <b>not</b> endian-aware! See comments in
+ * {@link AvroIOBinaryEncoder::float_to_int_bits()} for details.
+ *
+ * @param double $double
+ * @returns string bytes
+ */
+ static function double_to_long_bits($double)
+ {
+ return pack('d', (double) $double);
+ }
+
+ /**
+ * @param int|string $n
+ * @returns string long $n encoded as bytes
+ * @internal This relies on 64-bit PHP.
+ */
+ static public function encode_long($n)
+ {
+ $n = (int) $n;
+ $n = ($n << 1) ^ ($n >> 63);
+ $str = '';
+ while (0 != ($n & ~0x7F))
+ {
+ $str .= chr(($n & 0x7F) | 0x80);
+ $n >>= 7;
+ }
+ $str .= chr($n);
+ return $str;
+ }
+
+ /**
+ * @var AvroIO
+ */
+ private $io;
+
+ /**
+ * @param AvroIO $io object to which data is to be written.
+ *
+ */
+ function __construct($io)
+ {
+ Avro::check_platform();
+ $this->io = $io;
+ }
+
+ /**
+ * @param null $datum actual value is ignored
+ */
+ function write_null($datum) { return null; }
+
+ /**
+ * @param boolean $datum
+ */
+ function write_boolean($datum)
+ {
+ $byte = $datum ? chr(1) : chr(0);
+ $this->write($byte);
+ }
+
+ /**
+ * @param int $datum
+ */
+ function write_int($datum) { $this->write_long($datum); }
+
+ /**
+ * @param int $n
+ */
+ function write_long($n)
+ {
+ if (Avro::uses_gmp())
+ $this->write(AvroGMP::encode_long($n));
+ else
+ $this->write(self::encode_long($n));
+ }
+
+ /**
+ * @param float $datum
+ * @uses self::float_to_int_bits()
+ */
+ public function write_float($datum)
+ {
+ $this->write(self::float_to_int_bits($datum));
+ }
+
+ /**
+ * @param float $datum
+ * @uses self::double_to_long_bits()
+ */
+ public function write_double($datum)
+ {
+ $this->write(self::double_to_long_bits($datum));
+ }
+
+ /**
+ * @param string $str
+ * @uses self::write_bytes()
+ */
+ function write_string($str) { $this->write_bytes($str); }
+
+ /**
+ * @param string $bytes
+ */
+ function write_bytes($bytes)
+ {
+ $this->write_long(strlen($bytes));
+ $this->write($bytes);
+ }
+
+ /**
+ * @param string $datum
+ */
+ function write($datum) { $this->io->write($datum); }
+}
+
+/**
+ * Handles schema-specifc reading of data from the decoder.
+ *
+ * Also handles schema resolution between the reader and writer
+ * schemas (if a writer's schema is provided).
+ *
+ * @package Avro
+ */
+class AvroIODatumReader
+{
+ /**
+ *
+ * @param AvroSchema $writers_schema
+ * @param AvroSchema $readers_schema
+ * @returns boolean true if the schemas are consistent with
+ * each other and false otherwise.
+ */
+ static function schemas_match($writers_schema, $readers_schema)
+ {
+ $writers_schema_type = $writers_schema->type;
+ $readers_schema_type = $readers_schema->type;
+
+ if (AvroSchema::UNION_SCHEMA == $writers_schema_type
+ || AvroSchema::UNION_SCHEMA == $readers_schema_type)
+ return true;
+
+ if ($writers_schema_type == $readers_schema_type)
+ {
+ if (AvroSchema::is_primitive_type($writers_schema_type))
+ return true;
+
+ switch ($readers_schema_type)
+ {
+ case AvroSchema::MAP_SCHEMA:
+ return self::attributes_match($writers_schema->values(),
+ $readers_schema->values(),
+ array(AvroSchema::TYPE_ATTR));
+ case AvroSchema::ARRAY_SCHEMA:
+ return self::attributes_match($writers_schema->items(),
+ $readers_schema->items(),
+ array(AvroSchema::TYPE_ATTR));
+ case AvroSchema::ENUM_SCHEMA:
+ return self::attributes_match($writers_schema, $readers_schema,
+ array(AvroSchema::FULLNAME_ATTR));
+ case AvroSchema::FIXED_SCHEMA:
+ return self::attributes_match($writers_schema, $readers_schema,
+ array(AvroSchema::FULLNAME_ATTR,
+ AvroSchema::SIZE_ATTR));
+ case AvroSchema::RECORD_SCHEMA:
+ case AvroSchema::ERROR_SCHEMA:
+ return self::attributes_match($writers_schema, $readers_schema,
+ array(AvroSchema::FULLNAME_ATTR));
+ case AvroSchema::REQUEST_SCHEMA:
+ // XXX: This seems wrong
+ return true;
+ // XXX: no default
+ }
+
+ if (AvroSchema::INT_TYPE == $writers_schema_type
+ && in_array($readers_schema_type, array(AvroSchema::LONG_TYPE,
+ AvroSchema::FLOAT_TYPE,
+ AvroSchema::DOUBLE_TYPE)))
+ return true;
+
+ if (AvroSchema::LONG_TYPE == $writers_schema_type
+ && in_array($readers_schema_type, array(AvroSchema::FLOAT_TYPE,
+ AvroSchema::DOUBLE_TYPE)))
+ return true;
+
+ if (AvroSchema::FLOAT_TYPE == $writers_schema_type
+ && AvroSchema::DOUBLE_TYPE == $readers_schema_type)
+ return true;
+
+ return false;
+ }
+
+ }
+
+ /**
+ * Checks equivalence of the given attributes of the two given schemas.
+ *
+ * @param AvroSchema $schema_one
+ * @param AvroSchema $schema_two
+ * @param string[] $attribute_names array of string attribute names to compare
+ *
+ * @returns boolean true if the attributes match and false otherwise.
+ */
+ static function attributes_match($schema_one, $schema_two, $attribute_names)
+ {
+ foreach ($attribute_names as $attribute_name)
+ if ($schema_one->attribute($attribute_name)
+ != $schema_two->attribute($attribute_name))
+ return false;
+ return true;
+ }
+
+ /**
+ * @var AvroSchema
+ */
+ private $writers_schema;
+
+ /**
+ * @var AvroSchema
+ */
+ private $readers_schema;
+
+ /**
+ * @param AvroSchema $writers_schema
+ * @param AvroSchema $readers_schema
+ */
+ function __construct($writers_schema=null, $readers_schema=null)
+ {
+ $this->writers_schema = $writers_schema;
+ $this->readers_schema = $readers_schema;
+ }
+
+ /**
+ * @param AvroSchema $readers_schema
+ */
+ public function set_writers_schema($readers_schema)
+ {
+ $this->writers_schema = $readers_schema;
+ }
+
+ /**
+ * @param AvroIOBinaryDecoder $decoder
+ * @returns string
+ */
+ public function read($decoder)
+ {
+ if (is_null($this->readers_schema))
+ $this->readers_schema = $this->writers_schema;
+ return $this->read_data($this->writers_schema, $this->readers_schema,
+ $decoder);
+ }
+
+ /**#@+
+ * @param AvroSchema $writers_schema
+ * @param AvroSchema $readers_schema
+ * @param AvroIOBinaryDecoder $decoder
+ */
+ /**
+ * @returns mixed
+ */
+ public function read_data($writers_schema, $readers_schema, $decoder)
+ {
+ if (!self::schemas_match($writers_schema, $readers_schema))
+ throw new AvroIOSchemaMatchException($writers_schema, $readers_schema);
+
+ // Schema resolution: reader's schema is a union, writer's schema is not
+ if (AvroSchema::UNION_SCHEMA == $readers_schema->type()
+ && AvroSchema::UNION_SCHEMA != $writers_schema->type())
+ {
+ foreach ($readers_schema->schemas() as $schema)
+ if (self::schemas_match($writers_schema, $schema))
+ return $this->read_data($writers_schema, $schema, $decoder);
+ throw new AvroIOSchemaMatchException($writers_schema, $readers_schema);
+ }
+
+ switch ($writers_schema->type())
+ {
+ case AvroSchema::NULL_TYPE:
+ return $decoder->read_null();
+ case AvroSchema::BOOLEAN_TYPE:
+ return $decoder->read_boolean();
+ case AvroSchema::INT_TYPE:
+ return $decoder->read_int();
+ case AvroSchema::LONG_TYPE:
+ return $decoder->read_long();
+ case AvroSchema::FLOAT_TYPE:
+ return $decoder->read_float();
+ case AvroSchema::DOUBLE_TYPE:
+ return $decoder->read_double();
+ case AvroSchema::STRING_TYPE:
+ return $decoder->read_string();
+ case AvroSchema::BYTES_TYPE:
+ return $decoder->read_bytes();
+ case AvroSchema::ARRAY_SCHEMA:
+ return $this->read_array($writers_schema, $readers_schema, $decoder);
+ case AvroSchema::MAP_SCHEMA:
+ return $this->read_map($writers_schema, $readers_schema, $decoder);
+ case AvroSchema::UNION_SCHEMA:
+ return $this->read_union($writers_schema, $readers_schema, $decoder);
+ case AvroSchema::ENUM_SCHEMA:
+ return $this->read_enum($writers_schema, $readers_schema, $decoder);
+ case AvroSchema::FIXED_SCHEMA:
+ return $this->read_fixed($writers_schema, $readers_schema, $decoder);
+ case AvroSchema::RECORD_SCHEMA:
+ case AvroSchema::ERROR_SCHEMA:
+ case AvroSchema::REQUEST_SCHEMA:
+ return $this->read_record($writers_schema, $readers_schema, $decoder);
+ default:
+ throw new AvroException(sprintf("Cannot read unknown schema type: %s",
+ $writers_schema->type()));
+ }
+ }
+
+ /**
+ * @returns array
+ */
+ public function read_array($writers_schema, $readers_schema, $decoder)
+ {
+ $items = array();
+ $block_count = $decoder->read_long();
+ while (0 != $block_count)
+ {
+ if ($block_count < 0)
+ {
+ $block_count = -$block_count;
+ $block_size = $decoder->read_long(); // Read (and ignore) block size
+ }
+ for ($i = 0; $i < $block_count; $i++)
+ $items []= $this->read_data($writers_schema->items(),
+ $readers_schema->items(),
+ $decoder);
+ $block_count = $decoder->read_long();
+ }
+ return $items;
+ }
+
+ /**
+ * @returns array
+ */
+ public function read_map($writers_schema, $readers_schema, $decoder)
+ {
+ $items = array();
+ $pair_count = $decoder->read_long();
+ while (0 != $pair_count)
+ {
+ if ($pair_count < 0)
+ {
+ $pair_count = -$pair_count;
+ // Note: we're not doing anything with block_size other than skipping it
+ $block_size = $decoder->read_long();
+ }
+
+ for ($i = 0; $i < $pair_count; $i++)
+ {
+ $key = $decoder->read_string();
+ $items[$key] = $this->read_data($writers_schema->values(),
+ $readers_schema->values(),
+ $decoder);
+ }
+ $pair_count = $decoder->read_long();
+ }
+ return $items;
+ }
+
+ /**
+ * @returns mixed
+ */
+ public function read_union($writers_schema, $readers_schema, $decoder)
+ {
+ $schema_index = $decoder->read_long();
+ $selected_writers_schema = $writers_schema->schema_by_index($schema_index);
+ return $this->read_data($selected_writers_schema, $readers_schema, $decoder);
+ }
+
+ /**
+ * @returns string
+ */
+ public function read_enum($writers_schema, $readers_schema, $decoder)
+ {
+ $symbol_index = $decoder->read_int();
+ $symbol = $writers_schema->symbol_by_index($symbol_index);
+ if (!$readers_schema->has_symbol($symbol))
+ null; // FIXME: unset wrt schema resolution
+ return $symbol;
+ }
+
+ /**
+ * @returns string
+ */
+ public function read_fixed($writers_schema, $readers_schema, $decoder)
+ {
+ return $decoder->read($writers_schema->size());
+ }
+
+ /**
+ * @returns array
+ */
+ public function read_record($writers_schema, $readers_schema, $decoder)
+ {
+ $readers_fields = $readers_schema->fields_hash();
+ $record = array();
+ foreach ($writers_schema->fields() as $writers_field)
+ {
+ $type = $writers_field->type();
+ if (isset($readers_fields[$writers_field->name()]))
+ $record[$writers_field->name()]
+ = $this->read_data($type,
+ $readers_fields[$writers_field->name()]->type(),
+ $decoder);
+ else
+ $this->skip_data($type, $decoder);
+ }
+ // Fill in default values
+ if (count($readers_fields) > count($record))
+ {
+ $writers_fields = $writers_schema->fields_hash();
+ foreach ($readers_fields as $field_name => $field)
+ {
+ if (!isset($writers_fields[$field_name]))
+ {
+ if ($field->has_default_value())
+ $record[$field->name()]
+ = $this->read_default_value($field->type(),
+ $field->default_value());
+ else
+ null; // FIXME: unset
+ }
+ }
+ }
+
+ return $record;
+ }
+ /**#@-*/
+
+ /**
+ * @param AvroSchema $field_schema
+ * @param null|boolean|int|float|string|array $default_value
+ * @returns null|boolean|int|float|string|array
+ *
+ * @throws AvroException if $field_schema type is unknown.
+ */
+ public function read_default_value($field_schema, $default_value)
+ {
+ switch($field_schema->type())
+ {
+ case AvroSchema::NULL_TYPE:
+ return null;
+ case AvroSchema::BOOLEAN_TYPE:
+ return $default_value;
+ case AvroSchema::INT_TYPE:
+ case AvroSchema::LONG_TYPE:
+ return (int) $default_value;
+ case AvroSchema::FLOAT_TYPE:
+ case AvroSchema::DOUBLE_TYPE:
+ return (float) $default_value;
+ case AvroSchema::STRING_TYPE:
+ case AvroSchema::BYTES_TYPE:
+ return $default_value;
+ case AvroSchema::ARRAY_SCHEMA:
+ $array = array();
+ foreach ($default_value as $json_val)
+ {
+ $val = $this->read_default_value($field_schema->items(), $json_val);
+ $array []= $val;
+ }
+ return $array;
+ case AvroSchema::MAP_SCHEMA:
+ $map = array();
+ foreach ($default_value as $key => $json_val)
+ $map[$key] = $this->read_default_value($field_schema->values(),
+ $json_val);
+ return $map;
+ case AvroSchema::UNION_SCHEMA:
+ return $this->read_default_value($field_schema->schema_by_index(0),
+ $default_value);
+ case AvroSchema::ENUM_SCHEMA:
+ case AvroSchema::FIXED_SCHEMA:
+ return $default_value;
+ case AvroSchema::RECORD_SCHEMA:
+ $record = array();
+ foreach ($field_schema->fields() as $field)
+ {
+ $field_name = $field->name();
+ if (!$json_val = $default_value[$field_name])
+ $json_val = $field->default_value();
+
+ $record[$field_name] = $this->read_default_value($field->type(),
+ $json_val);
+ }
+ return $record;
+ default:
+ throw new AvroException(sprintf('Unknown type: %s', $field_schema->type()));
+ }
+ }
+
+ /**
+ * @param AvroSchema $writers_schema
+ * @param AvroIOBinaryDecoder $decoder
+ */
+ private function skip_data($writers_schema, $decoder)
+ {
+ switch ($writers_schema->type())
+ {
+ case AvroSchema::NULL_TYPE:
+ return $decoder->skip_null();
+ case AvroSchema::BOOLEAN_TYPE:
+ return $decoder->skip_boolean();
+ case AvroSchema::INT_TYPE:
+ return $decoder->skip_int();
+ case AvroSchema::LONG_TYPE:
+ return $decoder->skip_long();
+ case AvroSchema::FLOAT_TYPE:
+ return $decoder->skip_float();
+ case AvroSchema::DOUBLE_TYPE:
+ return $decoder->skip_double();
+ case AvroSchema::STRING_TYPE:
+ return $decoder->skip_string();
+ case AvroSchema::BYTES_TYPE:
+ return $decoder->skip_bytes();
+ case AvroSchema::ARRAY_SCHEMA:
+ return $decoder->skip_array($writers_schema, $decoder);
+ case AvroSchema::MAP_SCHEMA:
+ return $decoder->skip_map($writers_schema, $decoder);
+ case AvroSchema::UNION_SCHEMA:
+ return $decoder->skip_union($writers_schema, $decoder);
+ case AvroSchema::ENUM_SCHEMA:
+ return $decoder->skip_enum($writers_schema, $decoder);
+ case AvroSchema::FIXED_SCHEMA:
+ return $decoder->skip_fixed($writers_schema, $decoder);
+ case AvroSchema::RECORD_SCHEMA:
+ case AvroSchema::ERROR_SCHEMA:
+ case AvroSchema::REQUEST_SCHEMA:
+ return $decoder->skip_record($writers_schema, $decoder);
+ default:
+ throw new AvroException(sprintf('Uknown schema type: %s',
+ $writers_schema->type()));
+ }
+ }
+}
+
+/**
+ * Decodes and reads Avro data from an AvroIO object encoded using
+ * Avro binary encoding.
+ *
+ * @package Avro
+ */
+class AvroIOBinaryDecoder
+{
+
+ /**
+ * @param int[] array of byte ascii values
+ * @returns long decoded value
+ * @internal Requires 64-bit platform
+ */
+ public static function decode_long_from_array($bytes)
+ {
+ $b = array_shift($bytes);
+ $n = $b & 0x7f;
+ $shift = 7;
+ while (0 != ($b & 0x80))
+ {
+ $b = array_shift($bytes);
+ $n |= (($b & 0x7f) << $shift);
+ $shift += 7;
+ }
+ return (($n >> 1) ^ -($n & 1));
+ }
+
+ /**
+ * Performs decoding of the binary string to a float value.
+ *
+ * XXX: This is <b>not</b> endian-aware! See comments in
+ * {@link AvroIOBinaryEncoder::float_to_int_bits()} for details.
+ *
+ * @param string $bits
+ * @returns float
+ */
+ static public function int_bits_to_float($bits)
+ {
+ $float = unpack('f', $bits);
+ return (float) $float[1];
+ }
+
+ /**
+ * Performs decoding of the binary string to a double value.
+ *
+ * XXX: This is <b>not</b> endian-aware! See comments in
+ * {@link AvroIOBinaryEncoder::float_to_int_bits()} for details.
+ *
+ * @param string $bits
+ * @returns float
+ */
+ static public function long_bits_to_double($bits)
+ {
+ $double = unpack('d', $bits);
+ return (double) $double[1];
+ }
+
+ /**
+ * @var AvroIO
+ */
+ private $io;
+
+ /**
+ * @param AvroIO $io object from which to read.
+ */
+ public function __construct($io)
+ {
+ Avro::check_platform();
+ $this->io = $io;
+ }
+
+ /**
+ * @returns string the next byte from $this->io.
+ * @throws AvroException if the next byte cannot be read.
+ */
+ private function next_byte() { return $this->read(1); }
+
+ /**
+ * @returns null
+ */
+ public function read_null() { return null; }
+
+ /**
+ * @returns boolean
+ */
+ public function read_boolean()
+ {
+ return (boolean) (1 == ord($this->next_byte()));
+ }
+
+ /**
+ * @returns int
+ */
+ public function read_int() { return (int) $this->read_long(); }
+
+ /**
+ * @returns long
+ */
+ public function read_long()
+ {
+ $byte = ord($this->next_byte());
+ $bytes = array($byte);
+ while (0 != ($byte & 0x80))
+ {
+ $byte = ord($this->next_byte());
+ $bytes []= $byte;
+ }
+
+ if (Avro::uses_gmp())
+ return AvroGMP::decode_long_from_array($bytes);
+
+ return self::decode_long_from_array($bytes);
+ }
+
+ /**
+ * @returns float
+ */
+ public function read_float()
+ {
+ return self::int_bits_to_float($this->read(4));
+ }
+
+ /**
+ * @returns double
+ */
+ public function read_double()
+ {
+ return self::long_bits_to_double($this->read(8));
+ }
+
+ /**
+ * A string is encoded as a long followed by that many bytes
+ * of UTF-8 encoded character data.
+ * @returns string
+ */
+ public function read_string() { return $this->read_bytes(); }
+
+ /**
+ * @returns string
+ */
+ public function read_bytes() { return $this->read($this->read_long()); }
+
+ /**
+ * @param int $len count of bytes to read
+ * @returns string
+ */
+ public function read($len) { return $this->io->read($len); }
+
+ public function skip_null() { return null; }
+
+ public function skip_boolean() { return $this->skip(1); }
+
+ public function skip_int() { return $this->skip_long(); }
+
+ protected function skip_long()
+ {
+ $b = $this->next_byte();
+ while (0 != ($b & 0x80))
+ $b = $this->next_byte();
+ }
+
+ public function skip_float() { return $this->skip(4); }
+
+ public function skip_double() { return $this->skip(8); }
+
+ public function skip_bytes() { return $this->skip($this->read_long()); }
+
+ public function skip_string() { return $this->skip_bytes(); }
+
+ /**
+ * @param int $len count of bytes to skip
+ * @uses AvroIO::seek()
+ */
+ public function skip($len) { $this->seek($len, AvroIO::SEEK_CUR); }
+
+ /**
+ * @returns int position of pointer in AvroIO instance
+ * @uses AvroIO::tell()
+ */
+ private function tell() { return $this->io->tell(); }
+
+ /**
+ * @param int $offset
+ * @param int $whence
+ * @returns boolean true upon success
+ * @uses AvroIO::seek()
+ */
+ private function seek($offset, $whence)
+ {
+ return $this->io->seek($offset, $whence);
+ }
+}
+
diff --git a/vendor/wikimedia/avro/lib/avro/debug.php b/vendor/wikimedia/avro/lib/avro/debug.php
new file mode 100644
index 00000000..2278f19b
--- /dev/null
+++ b/vendor/wikimedia/avro/lib/avro/debug.php
@@ -0,0 +1,194 @@
+<?php
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @package Avro
+ */
+
+/**
+ * Avro library code debugging functions
+ * @package Avro
+ */
+class AvroDebug
+{
+
+ /**
+ * @var int high debug level
+ */
+ const DEBUG5 = 5;
+ /**
+ * @var int low debug level
+ */
+ const DEBUG1 = 1;
+ /**
+ * @var int current debug level
+ */
+ const DEBUG_LEVEL = self::DEBUG1;
+
+ /**
+ * @var int $debug_level
+ * @returns boolean true if the given $debug_level is equivalent
+ * or more verbose than than the current debug level
+ * and false otherwise.
+ */
+ static function is_debug($debug_level=self::DEBUG1)
+ {
+ return (self::DEBUG_LEVEL >= $debug_level);
+ }
+
+ /**
+ * @param string $format format string for the given arguments. Passed as is
+ * to <code>vprintf</code>.
+ * @param array $args array of arguments to pass to vsprinf.
+ * @param int $debug_level debug level at which to print this statement
+ * @returns boolean true
+ */
+ static function debug($format, $args, $debug_level=self::DEBUG1)
+ {
+ if (self::is_debug($debug_level))
+ vprintf($format . "\n", $args);
+ return true;
+ }
+
+ /**
+ * @param string $str
+ * @returns string[] array of hex representation of each byte of $str
+ */
+ static function hex_array($str) { return self::bytes_array($str); }
+
+ /**
+ * @param string $str
+ * @param string $joiner string used to join
+ * @returns string hex-represented bytes of each byte of $str
+ joined by $joiner
+ */
+ static function hex_string($str, $joiner=' ')
+ {
+ return join($joiner, self::hex_array($str));
+ }
+
+ /**
+ * @param string $str
+ * @param string $format format to represent bytes
+ * @returns string[] array of each byte of $str formatted using $format
+ */
+ static function bytes_array($str, $format='x%02x')
+ {
+ $x = array();
+ foreach (str_split($str) as $b)
+ $x []= sprintf($format, ord($b));
+ return $x;
+ }
+
+ /**
+ * @param string $str
+ * @returns string[] array of bytes of $str represented in decimal format ('%3d')
+ */
+ static function dec_array($str) { return self::bytes_array($str, '%3d'); }
+
+ /**
+ * @param string $str
+ * @param string $joiner string to join bytes of $str
+ * @returns string of bytes of $str represented in decimal format
+ * @uses dec_array()
+ */
+ static function dec_string($str, $joiner = ' ')
+ {
+ return join($joiner, self::dec_array($str));
+ }
+
+ /**
+ * @param string $str
+ * @param string $format one of 'ctrl', 'hex', or 'dec' for control,
+ hexadecimal, or decimal format for bytes.
+ - ctrl: ASCII control characters represented as text.
+ For example, the null byte is represented as 'NUL'.
+ Visible ASCII characters represent themselves, and
+ others are represented as a decimal ('%03d')
+ - hex: bytes represented in hexadecimal ('%02X')
+ - dec: bytes represented in decimal ('%03d')
+ * @returns string[] array of bytes represented in the given format.
+ */
+ static function ascii_array($str, $format='ctrl')
+ {
+ if (!in_array($format, array('ctrl', 'hex', 'dec')))
+ throw new AvroException('Unrecognized format specifier');
+
+ $ctrl_chars = array('NUL', 'SOH', 'STX', 'ETX', 'EOT', 'ENQ', 'ACK', 'BEL',
+ 'BS', 'HT', 'LF', 'VT', 'FF', 'CR', 'SO', 'SI',
+ 'DLE', 'DC1', 'DC2', 'DC3', 'DC4', 'NAK', 'SYN', 'ETB',
+ 'CAN', 'EM', 'SUB', 'ESC', 'FS', 'GS', 'RS', 'US');
+ $x = array();
+ foreach (str_split($str) as $b)
+ {
+ $db = ord($b);
+ if ($db < 32)
+ {
+ switch ($format)
+ {
+ case 'ctrl':
+ $x []= str_pad($ctrl_chars[$db], 3, ' ', STR_PAD_LEFT);
+ break;
+ case 'hex':
+ $x []= sprintf("x%02X", $db);
+ break;
+ case 'dec':
+ $x []= str_pad($db, 3, '0', STR_PAD_LEFT);
+ break;
+ }
+ }
+ else if ($db < 127)
+ $x []= " $b";
+ else if ($db == 127)
+ {
+ switch ($format)
+ {
+ case 'ctrl':
+ $x []= 'DEL';
+ break;
+ case 'hex':
+ $x []= sprintf("x%02X", $db);
+ break;
+ case 'dec':
+ $x []= str_pad($db, 3, '0', STR_PAD_LEFT);
+ break;
+ }
+ }
+ else
+ if ('hex' == $format)
+ $x []= sprintf("x%02X", $db);
+ else
+ $x []= str_pad($db, 3, '0', STR_PAD_LEFT);
+ }
+ return $x;
+ }
+
+ /**
+ * @param string $str
+ * @param string $format one of 'ctrl', 'hex', or 'dec'.
+ * See {@link self::ascii_array()} for more description
+ * @param string $joiner
+ * @returns string of bytes joined by $joiner
+ * @uses ascii_array()
+ */
+ static function ascii_string($str, $format='ctrl', $joiner = ' ')
+ {
+ return join($joiner, self::ascii_array($str, $format));
+ }
+}
diff --git a/vendor/wikimedia/avro/lib/avro/gmp.php b/vendor/wikimedia/avro/lib/avro/gmp.php
new file mode 100644
index 00000000..3d41d034
--- /dev/null
+++ b/vendor/wikimedia/avro/lib/avro/gmp.php
@@ -0,0 +1,222 @@
+<?php
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @package Avro
+ */
+
+/**
+ * Methods for handling 64-bit operations using the GMP extension.
+ *
+ * This is a naive and hackish implementation that is intended
+ * to work well enough to support Avro. It has not been tested
+ * beyond what's needed to decode and encode long values.
+ *
+ * @package Avro
+ */
+class AvroGMP {
+
+ /**
+ * @var resource memoized GMP resource for zero
+ */
+ private static $gmp_0;
+
+ /**
+ * @returns resource GMP resource for zero
+ */
+ private static function gmp_0()
+ {
+ if (!isset(self::$gmp_0))
+ self::$gmp_0 = gmp_init('0');
+ return self::$gmp_0;
+ }
+
+ /**
+ * @var resource memoized GMP resource for one (1)
+ */
+ private static $gmp_1;
+
+ /**
+ * @returns resource GMP resource for one (1)
+ */
+ private static function gmp_1()
+ {
+ if (!isset(self::$gmp_1))
+ self::$gmp_1 = gmp_init('1');
+ return self::$gmp_1;
+ }
+
+ /**
+ * @var resource memoized GMP resource for two (2)
+ */
+ private static $gmp_2;
+
+ /**
+ * @returns resource GMP resource for two (2)
+ */
+ private static function gmp_2()
+ {
+ if (!isset(self::$gmp_2))
+ self::$gmp_2 = gmp_init('2');
+ return self::$gmp_2;
+ }
+
+ /**
+ * @var resource memoized GMP resource for 0x7f
+ */
+ private static $gmp_0x7f;
+
+ /**
+ * @returns resource GMP resource for 0x7f
+ */
+ private static function gmp_0x7f()
+ {
+ if (!isset(self::$gmp_0x7f))
+ self::$gmp_0x7f = gmp_init('0x7f');
+ return self::$gmp_0x7f;
+ }
+
+ /**
+ * @var resource memoized GMP resource for 64-bit ~0x7f
+ */
+ private static $gmp_n0x7f;
+
+ /**
+ * @returns resource GMP resource for 64-bit ~0x7f
+ */
+ private static function gmp_n0x7f()
+ {
+ if (!isset(self::$gmp_n0x7f))
+ self::$gmp_n0x7f = gmp_init('0xffffffffffffff80');
+ return self::$gmp_n0x7f;
+ }
+
+ /**
+ * @var resource memoized GMP resource for 64-bits of 1
+ */
+ private static $gmp_0xfs;
+
+ /**
+ * @returns resource GMP resource for 64-bits of 1
+ */
+ private static function gmp_0xfs()
+ {
+ if (!isset(self::$gmp_0xfs))
+ self::$gmp_0xfs = gmp_init('0xffffffffffffffff');
+ return self::$gmp_0xfs;
+ }
+
+ /**
+ * @param GMP resource
+ * @returns GMP resource 64-bit two's complement of input.
+ */
+ static function gmp_twos_complement($g)
+ {
+ return gmp_neg(gmp_sub(gmp_pow(self::gmp_2(), 64), $g));
+ }
+
+ /**
+ * @interal Only works up to shift 63 (doesn't wrap bits around).
+ * @param resource|int|string $g
+ * @param int $shift number of bits to shift left
+ * @returns resource $g shifted left
+ */
+ static function shift_left($g, $shift)
+ {
+ if (0 == $shift)
+ return $g;
+
+ if (0 > gmp_sign($g))
+ $g = self::gmp_twos_complement($g);
+
+ $m = gmp_mul($g, gmp_pow(self::gmp_2(), $shift));
+ $m = gmp_and($m, self::gmp_0xfs());
+ if (gmp_testbit($m, 63))
+ $m = gmp_neg(gmp_add(gmp_and(gmp_com($m), self::gmp_0xfs()),
+ self::gmp_1()));
+ return $m;
+ }
+
+ /**
+ * Arithmetic right shift
+ * @param resource|int|string $g
+ * @param int $shift number of bits to shift right
+ * @returns resource $g shifted right $shift bits
+ */
+ static function shift_right($g, $shift)
+ {
+ if (0 == $shift)
+ return $g;
+
+ if (0 <= gmp_sign($g))
+ $m = gmp_div($g, gmp_pow(self::gmp_2(), $shift));
+ else // negative
+ {
+ $g = gmp_and($g, self::gmp_0xfs());
+ $m = gmp_div($g, gmp_pow(self::gmp_2(), $shift));
+ $m = gmp_and($m, self::gmp_0xfs());
+ for ($i = 63; $i >= (63 - $shift); $i--)
+ gmp_setbit($m, $i);
+
+ $m = gmp_neg(gmp_add(gmp_and(gmp_com($m), self::gmp_0xfs()),
+ self::gmp_1()));
+ }
+
+ return $m;
+ }
+
+ /**
+ * @param int|str $n integer (or string representation of integer) to encode
+ * @return string $bytes of the long $n encoded per the Avro spec
+ */
+ static function encode_long($n)
+ {
+ $g = gmp_init($n);
+ $g = gmp_xor(self::shift_left($g, 1),
+ self::shift_right($g, 63));
+ $bytes = '';
+ while (0 != gmp_cmp(self::gmp_0(), gmp_and($g, self::gmp_n0x7f())))
+ {
+ $bytes .= chr(gmp_intval(gmp_and($g, self::gmp_0x7f())) | 0x80);
+ $g = self::shift_right($g, 7);
+ }
+ $bytes .= chr(gmp_intval($g));
+ return $bytes;
+ }
+
+ /**
+ * @param int[] $bytes array of ascii codes of bytes to decode
+ * @return string represenation of decoded long.
+ */
+ static function decode_long_from_array($bytes)
+ {
+ $b = array_shift($bytes);
+ $g = gmp_init($b & 0x7f);
+ $shift = 7;
+ while (0 != ($b & 0x80))
+ {
+ $b = array_shift($bytes);
+ $g = gmp_or($g, self::shift_left(($b & 0x7f), $shift));
+ $shift += 7;
+ }
+ $val = gmp_xor(self::shift_right($g, 1), gmp_neg(gmp_and($g, 1)));
+ return gmp_strval($val);
+ }
+
+}
diff --git a/vendor/wikimedia/avro/lib/avro/io.php b/vendor/wikimedia/avro/lib/avro/io.php
new file mode 100644
index 00000000..239e53d8
--- /dev/null
+++ b/vendor/wikimedia/avro/lib/avro/io.php
@@ -0,0 +1,494 @@
+<?php
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * Avro IO object classes
+ * @package Avro
+ */
+
+/**
+ * Exceptions associated with AvroIO instances.
+ * @package Avro
+ */
+class AvroIOException extends AvroException {}
+
+/**
+ * Barebones IO base class to provide common interface for file and string
+ * access within the Avro classes.
+ *
+ * @package Avro
+ */
+class AvroIO
+{
+
+ /**
+ * @var string general read mode
+ */
+ const READ_MODE = 'r';
+ /**
+ * @var string general write mode.
+ */
+ const WRITE_MODE = 'w';
+
+ /**
+ * @var int set position equal to $offset bytes
+ */
+ const SEEK_CUR = SEEK_CUR;
+ /**
+ * @var int set position to current index + $offset bytes
+ */
+ const SEEK_SET = SEEK_SET;
+ /**
+ * @var int set position to end of file + $offset bytes
+ */
+ const SEEK_END = SEEK_END;
+
+ /**
+ * Read $len bytes from AvroIO instance
+ * @var int $len
+ * @return string bytes read
+ */
+ public function read($len)
+ {
+ throw new AvroNotImplementedException('Not implemented');
+ }
+
+ /**
+ * Append bytes to this buffer. (Nothing more is needed to support Avro.)
+ * @param str $arg bytes to write
+ * @returns int count of bytes written.
+ * @throws AvroIOException if $args is not a string value.
+ */
+ public function write($arg)
+ {
+ throw new AvroNotImplementedException('Not implemented');
+ }
+
+ /**
+ * Return byte offset within AvroIO instance
+ * @return int
+ */
+ public function tell()
+ {
+ throw new AvroNotImplementedException('Not implemented');
+ }
+
+ /**
+ * Set the position indicator. The new position, measured in bytes
+ * from the beginning of the file, is obtained by adding $offset to
+ * the position specified by $whence.
+ *
+ * @param int $offset
+ * @param int $whence one of AvroIO::SEEK_SET, AvroIO::SEEK_CUR,
+ * or Avro::SEEK_END
+ * @returns boolean true
+ *
+ * @throws AvroIOException
+ */
+ public function seek($offset, $whence=self::SEEK_SET)
+ {
+ throw new AvroNotImplementedException('Not implemented');
+ }
+
+ /**
+ * Flushes any buffered data to the AvroIO object.
+ * @returns boolean true upon success.
+ */
+ public function flush()
+ {
+ throw new AvroNotImplementedException('Not implemented');
+ }
+
+ /**
+ * Returns whether or not the current position at the end of this AvroIO
+ * instance.
+ *
+ * Note is_eof() is <b>not</b> like eof in C or feof in PHP:
+ * it returns TRUE if the *next* read would be end of file,
+ * rather than if the *most recent* read read end of file.
+ * @returns boolean true if at the end of file, and false otherwise
+ */
+ public function is_eof()
+ {
+ throw new AvroNotImplementedException('Not implemented');
+ }
+
+ /**
+ * Closes this AvroIO instance.
+ */
+ public function close()
+ {
+ throw new AvroNotImplementedException('Not implemented');
+ }
+
+}
+
+/**
+ * AvroIO wrapper for string access
+ * @package Avro
+ */
+class AvroStringIO extends AvroIO
+{
+ /**
+ * @var string
+ */
+ private $string_buffer;
+ /**
+ * @var int current position in string
+ */
+ private $current_index;
+ /**
+ * @var boolean whether or not the string is closed.
+ */
+ private $is_closed;
+
+ /**
+ * @param string $str initial value of AvroStringIO buffer. Regardless
+ * of the initial value, the pointer is set to the
+ * beginning of the buffer.
+ * @throws AvroIOException if a non-string value is passed as $str
+ */
+ public function __construct($str = '')
+ {
+ $this->is_closed = false;
+ $this->string_buffer = '';
+ $this->current_index = 0;
+
+ if (is_string($str))
+ $this->string_buffer .= $str;
+ else
+ throw new AvroIOException(
+ sprintf('constructor argument must be a string: %s', gettype($str)));
+ }
+
+ /**
+ * Append bytes to this buffer.
+ * (Nothing more is needed to support Avro.)
+ * @param str $arg bytes to write
+ * @returns int count of bytes written.
+ * @throws AvroIOException if $args is not a string value.
+ */
+ public function write($arg)
+ {
+ $this->check_closed();
+ if (is_string($arg))
+ return $this->append_str($arg);
+ throw new AvroIOException(
+ sprintf('write argument must be a string: (%s) %s',
+ gettype($arg), var_export($arg, true)));
+ }
+
+ /**
+ * @returns string bytes read from buffer
+ * @todo test for fencepost errors wrt updating current_index
+ */
+ public function read($len)
+ {
+ $this->check_closed();
+ $read='';
+ for($i=$this->current_index; $i<($this->current_index+$len); $i++)
+ $read .= $this->string_buffer[$i];
+ if (strlen($read) < $len)
+ $this->current_index = $this->length();
+ else
+ $this->current_index += $len;
+ return $read;
+ }
+
+ /**
+ * @returns boolean true if successful
+ * @throws AvroIOException if the seek failed.
+ */
+ public function seek($offset, $whence=self::SEEK_SET)
+ {
+ if (!is_int($offset))
+ throw new AvroIOException('Seek offset must be an integer.');
+ // Prevent seeking before BOF
+ switch ($whence)
+ {
+ case self::SEEK_SET:
+ if (0 > $offset)
+ throw new AvroIOException('Cannot seek before beginning of file.');
+ $this->current_index = $offset;
+ break;
+ case self::SEEK_CUR:
+ if (0 > $this->current_index + $whence)
+ throw new AvroIOException('Cannot seek before beginning of file.');
+ $this->current_index += $offset;
+ break;
+ case self::SEEK_END:
+ if (0 > $this->length() + $offset)
+ throw new AvroIOException('Cannot seek before beginning of file.');
+ $this->current_index = $this->length() + $offset;
+ break;
+ default:
+ throw new AvroIOException(sprintf('Invalid seek whence %d', $whence));
+ }
+
+ return true;
+ }
+
+ /**
+ * @returns int
+ * @see AvroIO::tell()
+ */
+ public function tell() { return $this->current_index; }
+
+ /**
+ * @returns boolean
+ * @see AvroIO::is_eof()
+ */
+ public function is_eof()
+ {
+ return ($this->current_index >= $this->length());
+ }
+
+ /**
+ * No-op provided for compatibility with AvroIO interface.
+ * @returns boolean true
+ */
+ public function flush() { return true; }
+
+ /**
+ * Marks this buffer as closed.
+ * @returns boolean true
+ */
+ public function close()
+ {
+ $this->check_closed();
+ $this->is_closed = true;
+ return true;
+ }
+
+ /**
+ * @throws AvroIOException if the buffer is closed.
+ */
+ private function check_closed()
+ {
+ if ($this->is_closed())
+ throw new AvroIOException('Buffer is closed');
+ }
+
+ /**
+ * Appends bytes to this buffer.
+ * @param string $str
+ * @returns integer count of bytes written.
+ */
+ private function append_str($str)
+ {
+ $this->check_closed();
+ $this->string_buffer .= $str;
+ $len = strlen($str);
+ $this->current_index += $len;
+ return $len;
+ }
+
+ /**
+ * Truncates the truncate buffer to 0 bytes and returns the pointer
+ * to the beginning of the buffer.
+ * @returns boolean true
+ */
+ public function truncate()
+ {
+ $this->check_closed();
+ $this->string_buffer = '';
+ $this->current_index = 0;
+ return true;
+ }
+
+ /**
+ * @returns int count of bytes in the buffer
+ * @internal Could probably memoize length for performance, but
+ * no need do this yet.
+ */
+ public function length() { return strlen($this->string_buffer); }
+
+ /**
+ * @returns string
+ */
+ public function __toString() { return $this->string_buffer; }
+
+
+ /**
+ * @returns string
+ * @uses self::__toString()
+ */
+ public function string() { return $this->__toString(); }
+
+ /**
+ * @returns boolean true if this buffer is closed and false
+ * otherwise.
+ */
+ public function is_closed() { return $this->is_closed; }
+}
+
+/**
+ * AvroIO wrapper for PHP file access functions
+ * @package Avro
+ */
+class AvroFile extends AvroIO
+{
+ /**
+ * @var string fopen read mode value. Used internally.
+ */
+ const FOPEN_READ_MODE = 'rb';
+
+ /**
+ * @var string fopen write mode value. Used internally.
+ */
+ const FOPEN_WRITE_MODE = 'wb';
+
+ /**
+ * @var string
+ */
+ private $file_path;
+
+ /**
+ * @var resource file handle for AvroFile instance
+ */
+ private $file_handle;
+
+ public function __construct($file_path, $mode = self::READ_MODE)
+ {
+ /**
+ * XXX: should we check for file existence (in case of reading)
+ * or anything else about the provided file_path argument?
+ */
+ $this->file_path = $file_path;
+ switch ($mode)
+ {
+ case self::WRITE_MODE:
+ $this->file_handle = fopen($this->file_path, self::FOPEN_WRITE_MODE);
+ if (false == $this->file_handle)
+ throw new AvroIOException('Could not open file for writing');
+ break;
+ case self::READ_MODE:
+ $this->file_handle = fopen($this->file_path, self::FOPEN_READ_MODE);
+ if (false == $this->file_handle)
+ throw new AvroIOException('Could not open file for reading');
+ break;
+ default:
+ throw new AvroIOException(
+ sprintf("Only modes '%s' and '%s' allowed. You provided '%s'.",
+ self::READ_MODE, self::WRITE_MODE, $mode));
+ }
+ }
+
+ /**
+ * @returns int count of bytes written
+ * @throws AvroIOException if write failed.
+ */
+ public function write($str)
+ {
+ $len = fwrite($this->file_handle, $str);
+ if (false === $len)
+ throw new AvroIOException(sprintf('Could not write to file'));
+ return $len;
+ }
+
+ /**
+ * @param int $len count of bytes to read.
+ * @returns string bytes read
+ * @throws AvroIOException if length value is negative or if the read failed
+ */
+ public function read($len)
+ {
+ if (0 > $len)
+ throw new AvroIOException(
+ sprintf("Invalid length value passed to read: %d", $len));
+
+ if (0 == $len)
+ return '';
+
+ $bytes = fread($this->file_handle, $len);
+ if (false === $bytes)
+ throw new AvroIOException('Could not read from file');
+ return $bytes;
+ }
+
+ /**
+ * @returns int current position within the file
+ * @throws AvroFileExcpetion if tell failed.
+ */
+ public function tell()
+ {
+ $position = ftell($this->file_handle);
+ if (false === $position)
+ throw new AvroIOException('Could not execute tell on reader');
+ return $position;
+ }
+
+ /**
+ * @param int $offset
+ * @param int $whence
+ * @returns boolean true upon success
+ * @throws AvroIOException if seek failed.
+ * @see AvroIO::seek()
+ */
+ public function seek($offset, $whence = SEEK_SET)
+ {
+ $res = fseek($this->file_handle, $offset, $whence);
+ // Note: does not catch seeking beyond end of file
+ if (-1 === $res)
+ throw new AvroIOException(
+ sprintf("Could not execute seek (offset = %d, whence = %d)",
+ $offset, $whence));
+ return true;
+ }
+
+ /**
+ * Closes the file.
+ * @returns boolean true if successful.
+ * @throws AvroIOException if there was an error closing the file.
+ */
+ public function close()
+ {
+ $res = fclose($this->file_handle);
+ if (false === $res)
+ throw new AvroIOException('Error closing file.');
+ return $res;
+ }
+
+ /**
+ * @returns boolean true if the pointer is at the end of the file,
+ * and false otherwise.
+ * @see AvroIO::is_eof() as behavior differs from feof()
+ */
+ public function is_eof()
+ {
+ $this->read(1);
+ if (feof($this->file_handle))
+ return true;
+ $this->seek(-1, self::SEEK_CUR);
+ return false;
+ }
+
+ /**
+ * @returns boolean true if the flush was successful.
+ * @throws AvroIOException if there was an error flushing the file.
+ */
+ public function flush()
+ {
+ $res = fflush($this->file_handle);
+ if (false === $res)
+ throw new AvroIOException('Could not flush file.');
+ return true;
+ }
+
+}
diff --git a/vendor/wikimedia/avro/lib/avro/protocol.php b/vendor/wikimedia/avro/lib/avro/protocol.php
new file mode 100644
index 00000000..a558e66b
--- /dev/null
+++ b/vendor/wikimedia/avro/lib/avro/protocol.php
@@ -0,0 +1,86 @@
+<?php
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @package Avro
+ */
+
+/**
+ * Avro library for protocols
+ * @package Avro
+ */
+class AvroProtocol
+{
+ public $name;
+ public $namespace;
+ public $schemata;
+
+ public static function parse($json)
+ {
+ if (is_null($json))
+ throw new AvroProtocolParseException( "Protocol can't be null");
+
+ $protocol = new AvroProtocol();
+ $protocol->real_parse(json_decode($json, true));
+ return $protocol;
+ }
+
+ function real_parse($avro) {
+ $this->protocol = $avro["protocol"];
+ $this->namespace = $avro["namespace"];
+ $this->schemata = new AvroNamedSchemata();
+ $this->name = $avro["protocol"];
+
+ if (!is_null($avro["types"])) {
+ $types = AvroSchema::real_parse($avro["types"], $this->namespace, $this->schemata);
+ }
+
+ if (!is_null($avro["messages"])) {
+ foreach ($avro["messages"] as $messageName => $messageAvro) {
+ $message = new AvroProtocolMessage($messageName, $messageAvro, $this);
+ $this->messages{$messageName} = $message;
+ }
+ }
+ }
+}
+
+class AvroProtocolMessage
+{
+ /**
+ * @var AvroRecordSchema $request
+ */
+
+ public $request;
+
+ public $response;
+
+ public function __construct($name, $avro, $protocol)
+ {
+ $this->name = $name;
+ $this->request = new AvroRecordSchema(new AvroName($name, null, $protocol->namespace), null, $avro{'request'}, $protocol->schemata, AvroSchema::REQUEST_SCHEMA);
+
+ if (array_key_exists('response', $avro)) {
+ $this->response = $protocol->schemata->schema_by_name(new AvroName($avro{'response'}, $protocol->namespace, $protocol->namespace));
+ if ($this->response == null)
+ $this->response = new AvroPrimitiveSchema($avro{'response'});
+ }
+ }
+}
+
+class AvroProtocolParseException extends AvroException {};
diff --git a/vendor/wikimedia/avro/lib/avro/schema.php b/vendor/wikimedia/avro/lib/avro/schema.php
new file mode 100644
index 00000000..3d7fbbb8
--- /dev/null
+++ b/vendor/wikimedia/avro/lib/avro/schema.php
@@ -0,0 +1,1457 @@
+<?php
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * Avro Schema and and Avro Schema support classes.
+ * @package Avro
+ */
+
+/** TODO
+ * - ARRAY have only type and item attributes (what about metadata?)
+ * - MAP keys are (assumed?) to be strings
+ * - FIXED size must be integer (must be positive? less than MAXINT?)
+ * - primitive type names cannot have a namespace (so throw an error? or ignore?)
+ * - schema may contain multiple definitions of a named schema
+ * if definitions are equivalent (?)
+ * - Cleanup default namespace and named schemata handling.
+ * - For one, it appears to be *too* global. According to the spec,
+ * we should only be referencing schemas that are named within the
+ * *enclosing* schema, so those in sibling schemas (say, unions or fields)
+ * shouldn't be referenced, if I understand the spec correctly.
+ * - Also, if a named schema is defined more than once in the same schema,
+ * it must have the same definition: so it appears we *do* need to keep
+ * track of named schemata globally as well. (And does this play well
+ * with the requirements regarding enclosing schema?
+ * - default values for bytes and fixed fields are JSON strings,
+ * where unicode code points 0-255 are mapped to unsigned 8-bit byte values 0-255
+ * - make sure other default values for other schema are of appropriate type
+ * - Should AvroField really be an AvroSchema object? Avro Fields have a name
+ * attribute, but not a namespace attribute (and the name can't be namespace
+ * qualified). It also has additional attributes such as doc, which named schemas
+ * enum and record have (though not fixed schemas, which also have names), and
+ * fields also have default and order attributes, shared by no other schema type.
+ */
+
+/**
+ * Exceptions associated with parsing JSON schema represenations
+ * @package Avro
+ */
+class AvroSchemaParseException extends AvroException {};
+
+/**
+ * @package Avro
+ */
+class AvroSchema
+{
+ /**
+ * @var int lower bound of integer values: -(1 << 31)
+ */
+ const INT_MIN_VALUE = -2147483648;
+
+ /**
+ * @var int upper bound of integer values: (1 << 31) - 1
+ */
+ const INT_MAX_VALUE = 2147483647;
+
+ /**
+ * @var long lower bound of long values: -(1 << 63)
+ */
+ const LONG_MIN_VALUE = -9223372036854775808;
+
+ /**
+ * @var long upper bound of long values: (1 << 63) - 1
+ */
+ const LONG_MAX_VALUE = 9223372036854775807;
+
+ /**
+ * @var string null schema type name
+ */
+ const NULL_TYPE = 'null';
+
+ /**
+ * @var string boolean schema type name
+ */
+ const BOOLEAN_TYPE = 'boolean';
+
+ /**
+ * int schema type value is a 32-bit signed int
+ * @var string int schema type name.
+ */
+ const INT_TYPE = 'int';
+
+ /**
+ * long schema type value is a 64-bit signed int
+ * @var string long schema type name
+ */
+ const LONG_TYPE = 'long';
+
+ /**
+ * float schema type value is a 32-bit IEEE 754 floating-point number
+ * @var string float schema type name
+ */
+ const FLOAT_TYPE = 'float';
+
+ /**
+ * double schema type value is a 64-bit IEEE 754 floating-point number
+ * @var string double schema type name
+ */
+ const DOUBLE_TYPE = 'double';
+
+ /**
+ * string schema type value is a Unicode character sequence
+ * @var string string schema type name
+ */
+ const STRING_TYPE = 'string';
+
+ /**
+ * bytes schema type value is a sequence of 8-bit unsigned bytes
+ * @var string bytes schema type name
+ */
+ const BYTES_TYPE = 'bytes';
+
+ // Complex Types
+ // Unnamed Schema
+ /**
+ * @var string array schema type name
+ */
+ const ARRAY_SCHEMA = 'array';
+
+ /**
+ * @var string map schema type name
+ */
+ const MAP_SCHEMA = 'map';
+
+ /**
+ * @var string union schema type name
+ */
+ const UNION_SCHEMA = 'union';
+
+ /**
+ * Unions of error schemas are used by Avro messages
+ * @var string error_union schema type name
+ */
+ const ERROR_UNION_SCHEMA = 'error_union';
+
+ // Named Schema
+
+ /**
+ * @var string enum schema type name
+ */
+ const ENUM_SCHEMA = 'enum';
+
+ /**
+ * @var string fixed schema type name
+ */
+ const FIXED_SCHEMA = 'fixed';
+
+ /**
+ * @var string record schema type name
+ */
+ const RECORD_SCHEMA = 'record';
+ // Other Schema
+
+ /**
+ * @var string error schema type name
+ */
+ const ERROR_SCHEMA = 'error';
+
+ /**
+ * @var string request schema type name
+ */
+ const REQUEST_SCHEMA = 'request';
+
+
+ // Schema attribute names
+ /**
+ * @var string schema type name attribute name
+ */
+ const TYPE_ATTR = 'type';
+
+ /**
+ * @var string named schema name attribute name
+ */
+ const NAME_ATTR = 'name';
+
+ /**
+ * @var string named schema namespace attribute name
+ */
+ const NAMESPACE_ATTR = 'namespace';
+
+ /**
+ * @var string derived attribute: doesn't appear in schema
+ */
+ const FULLNAME_ATTR = 'fullname';
+
+ /**
+ * @var string array schema size attribute name
+ */
+ const SIZE_ATTR = 'size';
+
+ /**
+ * @var string record fields attribute name
+ */
+ const FIELDS_ATTR = 'fields';
+
+ /**
+ * @var string array schema items attribute name
+ */
+ const ITEMS_ATTR = 'items';
+
+ /**
+ * @var string enum schema symbols attribute name
+ */
+ const SYMBOLS_ATTR = 'symbols';
+
+ /**
+ * @var string map schema values attribute name
+ */
+ const VALUES_ATTR = 'values';
+
+ /**
+ * @var string document string attribute name
+ */
+ const DOC_ATTR = 'doc';
+
+ /**
+ * @var array list of primitive schema type names
+ */
+ private static $primitive_types = array(self::NULL_TYPE, self::BOOLEAN_TYPE,
+ self::STRING_TYPE, self::BYTES_TYPE,
+ self::INT_TYPE, self::LONG_TYPE,
+ self::FLOAT_TYPE, self::DOUBLE_TYPE);
+
+ /**
+ * @var array list of named schema type names
+ */
+ private static $named_types = array(self::FIXED_SCHEMA, self::ENUM_SCHEMA,
+ self::RECORD_SCHEMA, self::ERROR_SCHEMA);
+
+ /**
+ * @param string $type a schema type name
+ * @returns boolean true if the given type name is a named schema type name
+ * and false otherwise.
+ */
+ public static function is_named_type($type)
+ {
+ return in_array($type, self::$named_types);
+ }
+
+ /**
+ * @param string $type a schema type name
+ * @returns boolean true if the given type name is a primitive schema type
+ * name and false otherwise.
+ */
+ public static function is_primitive_type($type)
+ {
+ return in_array($type, self::$primitive_types);
+ }
+
+ /**
+ * @param string $type a schema type name
+ * @returns boolean true if the given type name is a valid schema type
+ * name and false otherwise.
+ */
+ public static function is_valid_type($type)
+ {
+ return (self::is_primitive_type($type)
+ || self::is_named_type($type)
+ || in_array($type, array(self::ARRAY_SCHEMA,
+ self::MAP_SCHEMA,
+ self::UNION_SCHEMA,
+ self::REQUEST_SCHEMA,
+ self::ERROR_UNION_SCHEMA)));
+ }
+
+ /**
+ * @var array list of names of reserved attributes
+ */
+ private static $reserved_attrs = array(self::TYPE_ATTR,
+ self::NAME_ATTR,
+ self::NAMESPACE_ATTR,
+ self::FIELDS_ATTR,
+ self::ITEMS_ATTR,
+ self::SIZE_ATTR,
+ self::SYMBOLS_ATTR,
+ self::VALUES_ATTR);
+
+ /**
+ * @param string $json JSON-encoded schema
+ * @uses self::real_parse()
+ * @returns AvroSchema
+ */
+ public static function parse($json)
+ {
+ $schemata = new AvroNamedSchemata();
+ return self::real_parse(json_decode($json, true), null, $schemata);
+ }
+
+ /**
+ * @param mixed $avro JSON-decoded schema
+ * @param string $default_namespace namespace of enclosing schema
+ * @param AvroNamedSchemata &$schemata reference to named schemas
+ * @returns AvroSchema
+ * @throws AvroSchemaParseException
+ */
+ static function real_parse($avro, $default_namespace=null, &$schemata=null)
+ {
+ if (is_null($schemata))
+ $schemata = new AvroNamedSchemata();
+
+ if (is_array($avro))
+ {
+ $type = AvroUtil::array_value($avro, self::TYPE_ATTR);
+
+ if (self::is_primitive_type($type))
+ return new AvroPrimitiveSchema($type);
+
+ elseif (self::is_named_type($type))
+ {
+ $name = AvroUtil::array_value($avro, self::NAME_ATTR);
+ $namespace = AvroUtil::array_value($avro, self::NAMESPACE_ATTR);
+ $new_name = new AvroName($name, $namespace, $default_namespace);
+ $doc = AvroUtil::array_value($avro, self::DOC_ATTR);
+ switch ($type)
+ {
+ case self::FIXED_SCHEMA:
+ $size = AvroUtil::array_value($avro, self::SIZE_ATTR);
+ return new AvroFixedSchema($new_name, $doc,
+ $size,
+ $schemata);
+ case self::ENUM_SCHEMA:
+ $symbols = AvroUtil::array_value($avro, self::SYMBOLS_ATTR);
+ return new AvroEnumSchema($new_name, $doc,
+ $symbols,
+ $schemata);
+ case self::RECORD_SCHEMA:
+ case self::ERROR_SCHEMA:
+ $fields = AvroUtil::array_value($avro, self::FIELDS_ATTR);
+ return new AvroRecordSchema($new_name, $doc,
+ $fields,
+ $schemata, $type);
+ default:
+ throw new AvroSchemaParseException(
+ sprintf('Unknown named type: %s', $type));
+ }
+ }
+ elseif (self::is_valid_type($type))
+ {
+ switch ($type)
+ {
+ case self::ARRAY_SCHEMA:
+ return new AvroArraySchema($avro[self::ITEMS_ATTR],
+ $default_namespace,
+ $schemata);
+ case self::MAP_SCHEMA:
+ return new AvroMapSchema($avro[self::VALUES_ATTR],
+ $default_namespace,
+ $schemata);
+ default:
+ throw new AvroSchemaParseException(
+ sprintf('Unknown valid type: %s', $type));
+ }
+ }
+ elseif (!array_key_exists(self::TYPE_ATTR, $avro)
+ && AvroUtil::is_list($avro))
+ return new AvroUnionSchema($avro, $default_namespace, $schemata);
+ else
+ throw new AvroSchemaParseException(sprintf('Undefined type: %s',
+ $type));
+ }
+ elseif (self::is_primitive_type($avro))
+ return new AvroPrimitiveSchema($avro);
+ else
+ throw new AvroSchemaParseException(
+ sprintf('%s is not a schema we know about.',
+ print_r($avro, true)));
+ }
+
+ /**
+ * @returns boolean true if $datum is valid for $expected_schema
+ * and false otherwise.
+ * @throws AvroSchemaParseException
+ */
+ public static function is_valid_datum($expected_schema, $datum)
+ {
+ switch($expected_schema->type)
+ {
+ case self::NULL_TYPE:
+ return is_null($datum);
+ case self::BOOLEAN_TYPE:
+ return is_bool($datum);
+ case self::STRING_TYPE:
+ case self::BYTES_TYPE:
+ return is_string($datum);
+ case self::INT_TYPE:
+ return (is_int($datum)
+ && (self::INT_MIN_VALUE <= $datum)
+ && ($datum <= self::INT_MAX_VALUE));
+ case self::LONG_TYPE:
+ return (is_int($datum)
+ && (self::LONG_MIN_VALUE <= $datum)
+ && ($datum <= self::LONG_MAX_VALUE));
+ case self::FLOAT_TYPE:
+ case self::DOUBLE_TYPE:
+ return (is_float($datum) || is_int($datum));
+ case self::ARRAY_SCHEMA:
+ if (is_array($datum))
+ {
+ foreach ($datum as $d)
+ if (!self::is_valid_datum($expected_schema->items(), $d))
+ return false;
+ return true;
+ }
+ return false;
+ case self::MAP_SCHEMA:
+ if (is_array($datum))
+ {
+ foreach ($datum as $k => $v)
+ if (!is_string($k)
+ || !self::is_valid_datum($expected_schema->values(), $v))
+ return false;
+ return true;
+ }
+ return false;
+ case self::UNION_SCHEMA:
+ foreach ($expected_schema->schemas() as $schema)
+ if (self::is_valid_datum($schema, $datum))
+ return true;
+ return false;
+ case self::ENUM_SCHEMA:
+ return in_array($datum, $expected_schema->symbols());
+ case self::FIXED_SCHEMA:
+ return (is_string($datum)
+ && (strlen($datum) == $expected_schema->size()));
+ case self::RECORD_SCHEMA:
+ case self::ERROR_SCHEMA:
+ case self::REQUEST_SCHEMA:
+ if (is_array($datum))
+ {
+ foreach ($expected_schema->fields() as $field)
+ if (!array_key_exists($field->name(), $datum) || !self::is_valid_datum($field->type(), $datum[$field->name()]))
+ return false;
+ return true;
+ }
+ return false;
+ default:
+ throw new AvroSchemaParseException(
+ sprintf('%s is not allowed.', $expected_schema));
+ }
+ }
+
+ /**
+ * @internal Should only be called from within the constructor of
+ * a class which extends AvroSchema
+ * @param string $type a schema type name
+ */
+ public function __construct($type)
+ {
+ $this->type = $type;
+ }
+
+ /**
+ * @param mixed $avro
+ * @param string $default_namespace namespace of enclosing schema
+ * @param AvroNamedSchemata &$schemata
+ * @returns AvroSchema
+ * @uses AvroSchema::real_parse()
+ * @throws AvroSchemaParseException
+ */
+ protected static function subparse($avro, $default_namespace, &$schemata=null)
+ {
+ try
+ {
+ return self::real_parse($avro, $default_namespace, $schemata);
+ }
+ catch (AvroSchemaParseException $e)
+ {
+ throw $e;
+ }
+ catch (Exception $e)
+ {
+ throw new AvroSchemaParseException(
+ sprintf('Sub-schema is not a valid Avro schema. Bad schema: %s',
+ print_r($avro, true)));
+ }
+
+ }
+
+ /**
+ * @returns string schema type name of this schema
+ */
+ public function type() { return $this->type; }
+
+ /**
+ * @returns mixed
+ */
+ public function to_avro()
+ {
+ return array(self::TYPE_ATTR => $this->type);
+ }
+
+ /**
+ * @returns string the JSON-encoded representation of this Avro schema.
+ */
+ public function __toString() { return json_encode($this->to_avro()); }
+
+ /**
+ * @returns mixed value of the attribute with the given attribute name
+ */
+ public function attribute($attribute) { return $this->$attribute(); }
+
+}
+
+/**
+ * Avro schema for basic types such as null, int, long, string.
+ * @package Avro
+ */
+class AvroPrimitiveSchema extends AvroSchema
+{
+
+ /**
+ * @param string $type the primitive schema type name
+ * @throws AvroSchemaParseException if the given $type is not a
+ * primitive schema type name
+ */
+ public function __construct($type)
+ {
+ if (self::is_primitive_type($type))
+ return parent::__construct($type);
+ throw new AvroSchemaParseException(
+ sprintf('%s is not a valid primitive type.', $type));
+ }
+
+ /**
+ * @returns mixed
+ */
+ public function to_avro()
+ {
+ $avro = parent::to_avro();
+ // FIXME: Is this if really necessary? When *wouldn't* this be the case?
+ if (1 == count($avro))
+ return $this->type;
+ return $avro;
+ }
+}
+
+/**
+ * Avro array schema, consisting of items of a particular
+ * Avro schema type.
+ * @package Avro
+ */
+class AvroArraySchema extends AvroSchema
+{
+ /**
+ * @var AvroName|AvroSchema named schema name or AvroSchema of
+ * array element
+ */
+ private $items;
+
+ /**
+ * @var boolean true if the items schema
+ * FIXME: couldn't we derive this from whether or not $this->items
+ * is an AvroName or an AvroSchema?
+ */
+ private $is_items_schema_from_schemata;
+
+ /**
+ * @param string|mixed $items AvroNamedSchema name or object form
+ * of decoded JSON schema representation.
+ * @param string $default_namespace namespace of enclosing schema
+ * @param AvroNamedSchemata &$schemata
+ */
+ public function __construct($items, $default_namespace, &$schemata=null)
+ {
+ parent::__construct(AvroSchema::ARRAY_SCHEMA);
+
+ $this->is_items_schema_from_schemata = false;
+ $items_schema = null;
+ if (is_string($items)
+ && $items_schema = $schemata->schema_by_name(
+ new AvroName($items, null, $default_namespace)))
+ $this->is_items_schema_from_schemata = true;
+ else
+ $items_schema = AvroSchema::subparse($items, $default_namespace, $schemata);
+
+ $this->items = $items_schema;
+ }
+
+
+ /**
+ * @returns AvroName|AvroSchema named schema name or AvroSchema
+ * of this array schema's elements.
+ */
+ public function items() { return $this->items; }
+
+ /**
+ * @returns mixed
+ */
+ public function to_avro()
+ {
+ $avro = parent::to_avro();
+ $avro[AvroSchema::ITEMS_ATTR] = $this->is_items_schema_from_schemata
+ ? $this->items->qualified_name() : $this->items->to_avro();
+ return $avro;
+ }
+}
+
+/**
+ * Avro map schema consisting of named values of defined
+ * Avro Schema types.
+ * @package Avro
+ */
+class AvroMapSchema extends AvroSchema
+{
+ /**
+ * @var string|AvroSchema named schema name or AvroSchema
+ * of map schema values.
+ */
+ private $values;
+
+ /**
+ * @var boolean true if the named schema
+ * XXX Couldn't we derive this based on whether or not
+ * $this->values is a string?
+ */
+ private $is_values_schema_from_schemata;
+
+ /**
+ * @param string|AvroSchema $values
+ * @param string $default_namespace namespace of enclosing schema
+ * @param AvroNamedSchemata &$schemata
+ */
+ public function __construct($values, $default_namespace, &$schemata=null)
+ {
+ parent::__construct(AvroSchema::MAP_SCHEMA);
+
+ $this->is_values_schema_from_schemata = false;
+ $values_schema = null;
+ if (is_string($values)
+ && $values_schema = $schemata->schema_by_name(
+ new AvroName($values, null, $default_namespace)))
+ $this->is_values_schema_from_schemata = true;
+ else
+ $values_schema = AvroSchema::subparse($values, $default_namespace,
+ $schemata);
+
+ $this->values = $values_schema;
+ }
+
+ /**
+ * @returns XXX|AvroSchema
+ */
+ public function values() { return $this->values; }
+
+ /**
+ * @returns mixed
+ */
+ public function to_avro()
+ {
+ $avro = parent::to_avro();
+ $avro[AvroSchema::VALUES_ATTR] = $this->is_values_schema_from_schemata
+ ? $this->values->qualified_name() : $this->values->to_avro();
+ return $avro;
+ }
+}
+
+/**
+ * Union of Avro schemas, of which values can be of any of the schema in
+ * the union.
+ * @package Avro
+ */
+class AvroUnionSchema extends AvroSchema
+{
+ /**
+ * @var AvroSchema[] list of schemas of this union
+ */
+ private $schemas;
+
+ /**
+ * @var int[] list of indices of named schemas which
+ * are defined in $schemata
+ */
+ public $schema_from_schemata_indices;
+
+ /**
+ * @param AvroSchema[] $schemas list of schemas in the union
+ * @param string $default_namespace namespace of enclosing schema
+ * @param AvroNamedSchemata &$schemata
+ */
+ public function __construct($schemas, $default_namespace, &$schemata=null)
+ {
+ parent::__construct(AvroSchema::UNION_SCHEMA);
+
+ $this->schema_from_schemata_indices = array();
+ $schema_types = array();
+ foreach ($schemas as $index => $schema)
+ {
+ $is_schema_from_schemata = false;
+ $new_schema = null;
+ if (is_string($schema)
+ && ($new_schema = $schemata->schema_by_name(
+ new AvroName($schema, null, $default_namespace))))
+ $is_schema_from_schemata = true;
+ else
+ $new_schema = self::subparse($schema, $default_namespace, $schemata);
+
+ $schema_type = $new_schema->type;
+ if (self::is_valid_type($schema_type)
+ && !self::is_named_type($schema_type)
+ && in_array($schema_type, $schema_types))
+ throw new AvroSchemaParseException(
+ sprintf('"%s" is already in union', $schema_type));
+ elseif (AvroSchema::UNION_SCHEMA == $schema_type)
+ throw new AvroSchemaParseException('Unions cannot contain other unions');
+ else
+ {
+ $schema_types []= $schema_type;
+ $this->schemas []= $new_schema;
+ if ($is_schema_from_schemata)
+ $this->schema_from_schemata_indices []= $index;
+ }
+ }
+
+ }
+
+ /**
+ * @returns AvroSchema[]
+ */
+ public function schemas() { return $this->schemas; }
+
+ /**
+ * @returns AvroSchema the particular schema from the union for
+ * the given (zero-based) index.
+ * @throws AvroSchemaParseException if the index is invalid for this schema.
+ */
+ public function schema_by_index($index)
+ {
+ if (count($this->schemas) > $index)
+ return $this->schemas[$index];
+
+ throw new AvroSchemaParseException('Invalid union schema index');
+ }
+
+ /**
+ * @returns mixed
+ */
+ public function to_avro()
+ {
+ $avro = array();
+
+ foreach ($this->schemas as $index => $schema)
+ $avro []= (in_array($index, $this->schema_from_schemata_indices))
+ ? $schema->qualified_name() : $schema->to_avro();
+
+ return $avro;
+ }
+}
+
+/**
+ * Parent class of named Avro schema
+ * @package Avro
+ * @todo Refactor AvroNamedSchema to use an AvroName instance
+ * to store name information.
+ */
+class AvroNamedSchema extends AvroSchema
+{
+ /**
+ * @var AvroName $name
+ */
+ private $name;
+
+ /**
+ * @var string documentation string
+ */
+ private $doc;
+
+ /**
+ * @param string $type
+ * @param AvroName $name
+ * @param string $doc documentation string
+ * @param AvroNamedSchemata &$schemata
+ * @throws AvroSchemaParseException
+ */
+ public function __construct($type, $name, $doc=null, &$schemata=null)
+ {
+ parent::__construct($type);
+ $this->name = $name;
+
+ if ($doc && !is_string($doc))
+ throw new AvroSchemaParseException('Schema doc attribute must be a string');
+ $this->doc = $doc;
+
+ if (!is_null($schemata))
+ $schemata = $schemata->clone_with_new_schema($this);
+ }
+
+ /**
+ * @returns mixed
+ */
+ public function to_avro()
+ {
+ $avro = parent::to_avro();
+ list($name, $namespace) = AvroName::extract_namespace($this->qualified_name());
+ $avro[AvroSchema::NAME_ATTR] = $name;
+ if ($namespace)
+ $avro[AvroSchema::NAMESPACE_ATTR] = $namespace;
+ if (!is_null($this->doc))
+ $avro[AvroSchema::DOC_ATTR] = $this->doc;
+ return $avro;
+ }
+
+ /**
+ * @returns string
+ */
+ public function fullname() { return $this->name->fullname(); }
+
+ public function qualified_name() { return $this->name->qualified_name(); }
+
+}
+
+/**
+ * @package Avro
+ */
+class AvroName
+{
+ /**
+ * @var string character used to separate names comprising the fullname
+ */
+ const NAME_SEPARATOR = '.';
+
+ /**
+ * @var string regular expression to validate name values
+ */
+ const NAME_REGEXP = '/^[A-Za-z_][A-Za-z0-9_]*$/';
+
+ /**
+ * @returns string[] array($name, $namespace)
+ */
+ public static function extract_namespace($name, $namespace=null)
+ {
+ $parts = explode(self::NAME_SEPARATOR, $name);
+ if (count($parts) > 1)
+ {
+ $name = array_pop($parts);
+ $namespace = join(self::NAME_SEPARATOR, $parts);
+ }
+ return array($name, $namespace);
+ }
+
+ /**
+ * @returns boolean true if the given name is well-formed
+ * (is a non-null, non-empty string) and false otherwise
+ */
+ public static function is_well_formed_name($name)
+ {
+ return (is_string($name) && !empty($name)
+ && preg_match(self::NAME_REGEXP, $name));
+ }
+
+ /**
+ * @param string $namespace
+ * @returns boolean true if namespace is composed of valid names
+ * @throws AvroSchemaParseException if any of the namespace components
+ * are invalid.
+ */
+ private static function check_namespace_names($namespace)
+ {
+ foreach (explode(self::NAME_SEPARATOR, $namespace) as $n)
+ {
+ if (empty($n) || (0 == preg_match(self::NAME_REGEXP, $n)))
+ throw new AvroSchemaParseException(sprintf('Invalid name "%s"', $n));
+ }
+ return true;
+ }
+
+ /**
+ * @param string $name
+ * @param string $namespace
+ * @returns string
+ * @throws AvroSchemaParseException if any of the names are not valid.
+ */
+ private static function parse_fullname($name, $namespace)
+ {
+ if (!is_string($namespace) || empty($namespace))
+ throw new AvroSchemaParseException('Namespace must be a non-empty string.');
+ self::check_namespace_names($namespace);
+ return $namespace . '.' . $name;
+ }
+
+ /**
+ * @var string valid names are matched by self::NAME_REGEXP
+ */
+ private $name;
+
+ /**
+ * @var string
+ */
+ private $namespace;
+
+ /**
+ * @var string
+ */
+ private $fullname;
+
+ /**
+ * @var string Name qualified as necessary given its default namespace.
+ */
+ private $qualified_name;
+
+ /**
+ * @param string $name
+ * @param string $namespace
+ * @param string $default_namespace
+ */
+ public function __construct($name, $namespace, $default_namespace)
+ {
+ if (!is_string($name) || empty($name))
+ throw new AvroSchemaParseException('Name must be a non-empty string.');
+
+ if (strpos($name, self::NAME_SEPARATOR)
+ && self::check_namespace_names($name))
+ $this->fullname = $name;
+ elseif (0 == preg_match(self::NAME_REGEXP, $name))
+ throw new AvroSchemaParseException(sprintf('Invalid name "%s"', $name));
+ elseif (!is_null($namespace))
+ $this->fullname = self::parse_fullname($name, $namespace);
+ elseif (!is_null($default_namespace))
+ $this->fullname = self::parse_fullname($name, $default_namespace);
+ else
+ $this->fullname = $name;
+
+ list($this->name, $this->namespace) = self::extract_namespace($this->fullname);
+ $this->qualified_name = (is_null($this->namespace)
+ || $this->namespace == $default_namespace)
+ ? $this->name : $this->fullname;
+ }
+
+ /**
+ * @returns array array($name, $namespace)
+ */
+ public function name_and_namespace()
+ {
+ return array($this->name, $this->namespace);
+ }
+
+ /**
+ * @returns string
+ */
+ public function fullname() { return $this->fullname; }
+
+ /**
+ * @returns string fullname
+ * @uses $this->fullname()
+ */
+ public function __toString() { return $this->fullname(); }
+
+ /**
+ * @returns string name qualified for its context
+ */
+ public function qualified_name() { return $this->qualified_name; }
+
+}
+
+/**
+ * Keeps track of AvroNamedSchema which have been observed so far,
+ * as well as the default namespace.
+ *
+ * @package Avro
+ */
+class AvroNamedSchemata
+{
+ /**
+ * @var AvroNamedSchema[]
+ */
+ private $schemata;
+
+ /**
+ * @param AvroNamedSchemata[]
+ */
+ public function __construct($schemata=array())
+ {
+ $this->schemata = $schemata;
+ }
+
+ public function list_schemas() {
+ var_export($this->schemata);
+ foreach($this->schemata as $sch)
+ print('Schema '.$sch->__toString()."\n");
+ }
+
+ /**
+ * @param string $fullname
+ * @returns boolean true if there exists a schema with the given name
+ * and false otherwise.
+ */
+ public function has_name($fullname)
+ {
+ return array_key_exists($fullname, $this->schemata);
+ }
+
+ /**
+ * @param string $fullname
+ * @returns AvroSchema|null the schema which has the given name,
+ * or null if there is no schema with the given name.
+ */
+ public function schema($fullname)
+ {
+ if (isset($this->schemata[$fullname]))
+ return $this->schemata[$fullname];
+ return null;
+ }
+
+ /**
+ * @param AvroName $name
+ * @returns AvroSchema|null
+ */
+ public function schema_by_name($name)
+ {
+ return $this->schema($name->fullname());
+ }
+
+ /**
+ * Creates a new AvroNamedSchemata instance of this schemata instance
+ * with the given $schema appended.
+ * @param AvroNamedSchema schema to add to this existing schemata
+ * @returns AvroNamedSchemata
+ */
+ public function clone_with_new_schema($schema)
+ {
+ $name = $schema->fullname();
+ if (AvroSchema::is_valid_type($name))
+ throw new AvroSchemaParseException(
+ sprintf('Name "%s" is a reserved type name', $name));
+ else if ($this->has_name($name))
+ throw new AvroSchemaParseException(
+ sprintf('Name "%s" is already in use', $name));
+ $schemata = new AvroNamedSchemata($this->schemata);
+ $schemata->schemata[$name] = $schema;
+ return $schemata;
+ }
+}
+
+/**
+ * @package Avro
+ */
+class AvroEnumSchema extends AvroNamedSchema
+{
+ /**
+ * @var string[] array of symbols
+ */
+ private $symbols;
+
+ /**
+ * @param AvroName $name
+ * @param string $doc
+ * @param string[] $symbols
+ * @param AvroNamedSchemata &$schemata
+ * @throws AvroSchemaParseException
+ */
+ public function __construct($name, $doc, $symbols, &$schemata=null)
+ {
+ if (!AvroUtil::is_list($symbols))
+ throw new AvroSchemaParseException('Enum Schema symbols are not a list');
+
+ if (count(array_unique($symbols)) > count($symbols))
+ throw new AvroSchemaParseException(
+ sprintf('Duplicate symbols: %s', $symbols));
+
+ foreach ($symbols as $symbol)
+ if (!is_string($symbol) || empty($symbol))
+ throw new AvroSchemaParseException(
+ sprintf('Enum schema symbol must be a string %',
+ print_r($symbol, true)));
+
+ parent::__construct(AvroSchema::ENUM_SCHEMA, $name, $doc, $schemata);
+ $this->symbols = $symbols;
+ }
+
+ /**
+ * @returns string[] this enum schema's symbols
+ */
+ public function symbols() { return $this->symbols; }
+
+ /**
+ * @param string $symbol
+ * @returns boolean true if the given symbol exists in this
+ * enum schema and false otherwise
+ */
+ public function has_symbol($symbol)
+ {
+ return in_array($symbol, $this->symbols);
+ }
+
+ /**
+ * @param int $index
+ * @returns string enum schema symbol with the given (zero-based) index
+ */
+ public function symbol_by_index($index)
+ {
+ if (array_key_exists($index, $this->symbols))
+ return $this->symbols[$index];
+ throw new AvroException(sprintf('Invalid symbol index %d', $index));
+ }
+
+ /**
+ * @param string $symbol
+ * @returns int the index of the given $symbol in the enum schema
+ */
+ public function symbol_index($symbol)
+ {
+ $idx = array_search($symbol, $this->symbols, true);
+ if (false !== $idx)
+ return $idx;
+ throw new AvroException(sprintf("Invalid symbol value '%s'", $symbol));
+ }
+
+ /**
+ * @returns mixed
+ */
+ public function to_avro()
+ {
+ $avro = parent::to_avro();
+ $avro[AvroSchema::SYMBOLS_ATTR] = $this->symbols;
+ return $avro;
+ }
+}
+
+/**
+ * AvroNamedSchema with fixed-length data values
+ * @package Avro
+ */
+class AvroFixedSchema extends AvroNamedSchema
+{
+
+ /**
+ * @var int byte count of this fixed schema data value
+ */
+ private $size;
+
+ /**
+ * @param AvroName $name
+ * @param string $doc Set to null, as fixed schemas don't have doc strings
+ * @param int $size byte count of this fixed schema data value
+ * @param AvroNamedSchemata &$schemata
+ */
+ public function __construct($name, $doc, $size, &$schemata=null)
+ {
+ $doc = null; // Fixed schemas don't have doc strings.
+ if (!is_integer($size))
+ throw new AvroSchemaParseException(
+ 'Fixed Schema requires a valid integer for "size" attribute');
+ parent::__construct(AvroSchema::FIXED_SCHEMA, $name, $doc, $schemata);
+ return $this->size = $size;
+ }
+
+ /**
+ * @returns int byte count of this fixed schema data value
+ */
+ public function size() { return $this->size; }
+
+ /**
+ * @returns mixed
+ */
+ public function to_avro()
+ {
+ $avro = parent::to_avro();
+ $avro[AvroSchema::SIZE_ATTR] = $this->size;
+ return $avro;
+ }
+}
+
+/**
+ * @package Avro
+ */
+class AvroRecordSchema extends AvroNamedSchema
+{
+ /**
+ * @param mixed $field_data
+ * @param string $default_namespace namespace of enclosing schema
+ * @param AvroNamedSchemata &$schemata
+ * @returns AvroField[]
+ * @throws AvroSchemaParseException
+ */
+ static function parse_fields($field_data, $default_namespace, &$schemata)
+ {
+ $fields = array();
+ $field_names = array();
+ foreach ($field_data as $index => $field)
+ {
+ $name = AvroUtil::array_value($field, AvroField::FIELD_NAME_ATTR);
+ $type = AvroUtil::array_value($field, AvroSchema::TYPE_ATTR);
+ $order = AvroUtil::array_value($field, AvroField::ORDER_ATTR);
+
+ $default = null;
+ $has_default = false;
+ if (array_key_exists(AvroField::DEFAULT_ATTR, $field))
+ {
+ $default = $field[AvroField::DEFAULT_ATTR];
+ $has_default = true;
+ }
+
+ if (in_array($name, $field_names))
+ throw new AvroSchemaParseException(
+ sprintf("Field name %s is already in use", $name));
+
+ $is_schema_from_schemata = false;
+ $field_schema = null;
+ if (is_string($type)
+ && $field_schema = $schemata->schema_by_name(
+ new AvroName($type, null, $default_namespace)))
+ $is_schema_from_schemata = true;
+ else
+ $field_schema = self::subparse($type, $default_namespace, $schemata);
+
+ $new_field = new AvroField($name, $field_schema, $is_schema_from_schemata,
+ $has_default, $default, $order);
+ $field_names []= $name;
+ $fields []= $new_field;
+ }
+ return $fields;
+ }
+
+ /**
+ * @var AvroSchema[] array of AvroNamedSchema field definitions of
+ * this AvroRecordSchema
+ */
+ private $fields;
+
+ /**
+ * @var array map of field names to field objects.
+ * @internal Not called directly. Memoization of AvroRecordSchema->fields_hash()
+ */
+ private $fields_hash;
+
+ /**
+ * @param string $name
+ * @param string $namespace
+ * @param string $doc
+ * @param array $fields
+ * @param AvroNamedSchemata &$schemata
+ * @param string $schema_type schema type name
+ * @throws AvroSchemaParseException
+ */
+ public function __construct($name, $doc, $fields, &$schemata=null,
+ $schema_type=AvroSchema::RECORD_SCHEMA)
+ {
+ if (is_null($fields))
+ throw new AvroSchemaParseException(
+ 'Record schema requires a non-empty fields attribute');
+
+ if (AvroSchema::REQUEST_SCHEMA == $schema_type)
+ parent::__construct($schema_type, $name);
+ else
+ parent::__construct($schema_type, $name, $doc, $schemata);
+
+ list($x, $namespace) = $name->name_and_namespace();
+ $this->fields = self::parse_fields($fields, $namespace, $schemata);
+ }
+
+ /**
+ * @returns mixed
+ */
+ public function to_avro()
+ {
+ $avro = parent::to_avro();
+
+ $fields_avro = array();
+ foreach ($this->fields as $field)
+ $fields_avro [] = $field->to_avro();
+
+ if (AvroSchema::REQUEST_SCHEMA == $this->type)
+ return $fields_avro;
+
+ $avro[AvroSchema::FIELDS_ATTR] = $fields_avro;
+
+ return $avro;
+ }
+
+ /**
+ * @returns array the schema definitions of the fields of this AvroRecordSchema
+ */
+ public function fields() { return $this->fields; }
+
+ /**
+ * @returns array a hash table of the fields of this AvroRecordSchema fields
+ * keyed by each field's name
+ */
+ public function fields_hash()
+ {
+ if (is_null($this->fields_hash))
+ {
+ $hash = array();
+ foreach ($this->fields as $field)
+ $hash[$field->name()] = $field;
+ $this->fields_hash = $hash;
+ }
+ return $this->fields_hash;
+ }
+}
+
+/**
+ * Field of an {@link AvroRecordSchema}
+ * @package Avro
+ */
+class AvroField extends AvroSchema
+{
+
+ /**
+ * @var string fields name attribute name
+ */
+ const FIELD_NAME_ATTR = 'name';
+
+ /**
+ * @var string
+ */
+ const DEFAULT_ATTR = 'default';
+
+ /**
+ * @var string
+ */
+ const ORDER_ATTR = 'order';
+
+ /**
+ * @var string
+ */
+ const ASC_SORT_ORDER = 'ascending';
+
+ /**
+ * @var string
+ */
+ const DESC_SORT_ORDER = 'descending';
+
+ /**
+ * @var string
+ */
+ const IGNORE_SORT_ORDER = 'ignore';
+
+ /**
+ * @var array list of valid field sort order values
+ */
+ private static $valid_field_sort_orders = array(self::ASC_SORT_ORDER,
+ self::DESC_SORT_ORDER,
+ self::IGNORE_SORT_ORDER);
+
+
+ /**
+ * @param string $order
+ * @returns boolean
+ */
+ private static function is_valid_field_sort_order($order)
+ {
+ return in_array($order, self::$valid_field_sort_orders);
+ }
+
+ /**
+ * @param string $order
+ * @throws AvroSchemaParseException if $order is not a valid
+ * field order value.
+ */
+ private static function check_order_value($order)
+ {
+ if (!is_null($order) && !self::is_valid_field_sort_order($order))
+ throw new AvroSchemaParseException(
+ sprintf('Invalid field sort order %s', $order));
+ }
+
+ /**
+ * @var string
+ */
+ private $name;
+
+ /**
+ * @var boolean whether or no there is a default value
+ */
+ private $has_default;
+
+ /**
+ * @var string field default value
+ */
+ private $default;
+
+ /**
+ * @var string sort order of this field
+ */
+ private $order;
+
+ /**
+ * @var boolean whether or not the AvroNamedSchema of this field is
+ * defined in the AvroNamedSchemata instance
+ */
+ private $is_type_from_schemata;
+
+ /**
+ * @param string $type
+ * @param string $name
+ * @param AvroSchema $schema
+ * @param boolean $is_type_from_schemata
+ * @param string $default
+ * @param string $order
+ * @todo Check validity of $default value
+ * @todo Check validity of $order value
+ */
+ public function __construct($name, $schema, $is_type_from_schemata,
+ $has_default, $default, $order=null)
+ {
+ if (!AvroName::is_well_formed_name($name))
+ throw new AvroSchemaParseException('Field requires a "name" attribute');
+
+ $this->type = $schema;
+ $this->is_type_from_schemata = $is_type_from_schemata;
+ $this->name = $name;
+ $this->has_default = $has_default;
+ if ($this->has_default)
+ $this->default = $default;
+ $this->check_order_value($order);
+ $this->order = $order;
+ }
+
+ /**
+ * @returns mixed
+ */
+ public function to_avro()
+ {
+ $avro = array(AvroField::FIELD_NAME_ATTR => $this->name);
+
+ $avro[AvroSchema::TYPE_ATTR] = ($this->is_type_from_schemata)
+ ? $this->type->qualified_name() : $this->type->to_avro();
+
+ if (isset($this->default))
+ $avro[AvroField::DEFAULT_ATTR] = $this->default;
+
+ if ($this->order)
+ $avro[AvroField::ORDER_ATTR] = $this->order;
+
+ return $avro;
+ }
+
+ /**
+ * @returns string the name of this field
+ */
+ public function name() { return $this->name; }
+
+ /**
+ * @returns mixed the default value of this field
+ */
+ public function default_value() { return $this->default; }
+
+ /**
+ * @returns boolean true if the field has a default and false otherwise
+ */
+ public function has_default_value() { return $this->has_default; }
+}
diff --git a/vendor/wikimedia/avro/lib/avro/util.php b/vendor/wikimedia/avro/lib/avro/util.php
new file mode 100644
index 00000000..a43613e9
--- /dev/null
+++ b/vendor/wikimedia/avro/lib/avro/util.php
@@ -0,0 +1,67 @@
+<?php
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @package Avro
+ */
+
+/**
+ * Class for static utility methods used in Avro.
+ *
+ * @package Avro
+ */
+class AvroUtil
+{
+ /**
+ * Determines whether the given array is an associative array
+ * (what is termed a map, hash, or dictionary in other languages)
+ * or a list (an array with monotonically increasing integer indicies
+ * starting with zero).
+ *
+ * @param array $ary array to test
+ * @returns true if the array is a list and false otherwise.
+ *
+ */
+ static function is_list($ary)
+ {
+ if (is_array($ary))
+ {
+ $i = 0;
+ foreach ($ary as $k => $v)
+ {
+ if ($i !== $k)
+ return false;
+ $i++;
+ }
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * @param array $ary
+ * @param string $key
+ * @returns mixed the value of $ary[$key] if it is set,
+ * and null otherwise.
+ */
+ static function array_value($ary, $key)
+ {
+ return isset($ary[$key]) ? $ary[$key] : null;
+ }
+}
diff --git a/vendor/wikimedia/cdb/COPYING b/vendor/wikimedia/cdb/COPYING
index 019694a9..d159169d 100644
--- a/vendor/wikimedia/cdb/COPYING
+++ b/vendor/wikimedia/cdb/COPYING
@@ -1,65 +1,65 @@
-== GNU GENERAL PUBLIC LICENSE ==
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
-Version 2, June 1991
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
-Copyright (C) 1989, 1991 Free Software Foundation, Inc.
-51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
-Everyone is permitted to copy and distribute verbatim copies
-of this license document, but changing it is not allowed.
+ Preamble
-=== Preamble ===
-
-The licenses for most software are designed to take away your
+ The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
-the GNU Library General Public License instead.) You can apply it to
+the GNU Lesser General Public License instead.) You can apply it to
your programs, too.
-When we speak of free software, we are referring to freedom, not
+ When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
-To protect your rights, we need to make restrictions that forbid
+ To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
-For example, if you distribute copies of such a program, whether
+ For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
-We protect your rights with two steps: (1) copyright the software, and
+ We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
-Also, for each author's protection and ours, we want to make certain
+ Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
-Finally, any free program is threatened constantly by software
+ Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
-The precise terms and conditions for copying, distribution and
+ The precise terms and conditions for copying, distribution and
modification follow.
-== TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION ==
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
-'''0.''' This License applies to any program or other work which contains
+ 0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
@@ -76,7 +76,7 @@ is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
-'''1.''' You may copy and distribute verbatim copies of the Program's
+ 1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
@@ -87,29 +87,29 @@ along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
-'''2.''' You may modify your copy or copies of the Program or any portion
+ 2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
- '''a)''' You must cause the modified files to carry prominent notices
- stating that you changed the files and the date of any change.
-
- '''b)''' You must cause any work that you distribute or publish, that in
- whole or in part contains or is derived from the Program or any
- part thereof, to be licensed as a whole at no charge to all third
- parties under the terms of this License.
-
- '''c)''' If the modified program normally reads commands interactively
- when run, you must cause it, when started running for such
- interactive use in the most ordinary way, to print or display an
- announcement including an appropriate copyright notice and a
- notice that there is no warranty (or else, saying that you provide
- a warranty) and that users may redistribute the program under
- these conditions, and telling the user how to view a copy of this
- License. (Exception: if the Program itself is interactive but
- does not normally print such an announcement, your work based on
- the Program is not required to print an announcement.)
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
@@ -131,26 +131,26 @@ with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
-'''3.''' You may copy and distribute the Program (or a work based on it,
+ 3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
- '''a)''' Accompany it with the complete corresponding machine-readable
- source code, which must be distributed under the terms of Sections
- 1 and 2 above on a medium customarily used for software interchange; or,
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
- '''b)''' Accompany it with a written offer, valid for at least three
- years, to give any third party, for a charge no more than your
- cost of physically performing source distribution, a complete
- machine-readable copy of the corresponding source code, to be
- distributed under the terms of Sections 1 and 2 above on a medium
- customarily used for software interchange; or,
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
- '''c)''' Accompany it with the information you received as to the offer
- to distribute corresponding source code. (This alternative is
- allowed only for noncommercial distribution and only if you
- received the program in object code or executable form with such
- an offer, in accord with Subsection b above.)
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
@@ -169,7 +169,7 @@ access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
-'''4.''' You may not copy, modify, sublicense, or distribute the Program
+ 4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
@@ -177,7 +177,7 @@ However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
-'''5.''' You are not required to accept this License, since you have not
+ 5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
@@ -186,7 +186,7 @@ Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
-'''6.''' Each time you redistribute the Program (or any work based on the
+ 6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
@@ -194,7 +194,7 @@ restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
-'''7.''' If, as a consequence of a court judgment or allegation of patent
+ 7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
@@ -226,7 +226,7 @@ impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
-'''8.''' If the distribution and/or use of the Program is restricted in
+ 8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
@@ -234,7 +234,7 @@ those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
-'''9.''' The Free Software Foundation may publish revised and/or new versions
+ 9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
@@ -247,7 +247,7 @@ Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
-'''10.''' If you wish to incorporate parts of the Program into other free
+ 10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
@@ -255,9 +255,9 @@ make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
-=== NO WARRANTY ===
+ NO WARRANTY
-'''11.''' BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
@@ -267,7 +267,7 @@ TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
-'''12.''' IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
@@ -277,47 +277,45 @@ YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
- '''END OF TERMS AND CONDITIONS'''
+ END OF TERMS AND CONDITIONS
-== How to Apply These Terms to Your New Programs ==
+ How to Apply These Terms to Your New Programs
-If you develop a new program, and you want it to be of the greatest
+ If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
-To do so, attach the following notices to the program. It is safest
+ To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
- <one line to give the program's name and a brief idea of what it does.>
-
- Copyright (C) <year> <name of author>
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
- Gnomovision version 69, Copyright (C) year name of author
- Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
- This is free software, and you are welcome to redistribute it
- under certain conditions; type `show c' for details.
+ Gnomovision version 69, Copyright (C) year name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, the commands you use may
@@ -328,15 +326,14 @@ You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here is a sample; alter the names:
- Yoyodyne, Inc., hereby disclaims all copyright interest in the program
- `Gnomovision' (which makes passes at compilers) written by James Hacker.
-
- <signature of Ty Coon>, 1 April 1989
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
- Ty Coon, President of Vice
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
-library. If this is what you want to do, use the GNU Library General
+library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License.
diff --git a/vendor/wikimedia/cdb/Doxyfile b/vendor/wikimedia/cdb/Doxyfile
deleted file mode 100644
index e77e75ae..00000000
--- a/vendor/wikimedia/cdb/Doxyfile
+++ /dev/null
@@ -1,32 +0,0 @@
-# Configuration file for Doxygen
-
-PROJECT_NAME = CDB
-PROJECT_BRIEF = CDB functions for PHP
-
-OUTPUT_DIRECTORY = doc
-
-JAVADOC_AUTOBRIEF = YES
-QT_AUTOBRIEF = YES
-
-WARN_NO_PARAMDOC = YES
-
-INPUT = README.md src/
-FILE_PATTERNS = *.php
-RECURSIVE = YES
-# Requires doxygen 1.8.3+
-USE_MDFILE_AS_MAINPAGE = README.md
-
-HTML_DYNAMIC_SECTIONS = YES
-GENERATE_TREEVIEW = YES
-TREEVIEW_WIDTH = 250
-
-GENERATE_LATEX = NO
-
-HAVE_DOT = YES
-DOT_FONTNAME = Helvetica
-DOT_FONTSIZE = 10
-TEMPLATE_RELATIONS = YES
-CALL_GRAPH = NO
-CALLER_GRAPH = NO
-# Makes dot run faster. Requires graphviz >1.8.10
-DOT_MULTI_TARGETS = YES
diff --git a/vendor/wikimedia/cdb/README.md b/vendor/wikimedia/cdb/README.md
index e4ef4498..02c1b94c 100644
--- a/vendor/wikimedia/cdb/README.md
+++ b/vendor/wikimedia/cdb/README.md
@@ -1,4 +1,4 @@
-[![Latest Stable Version](https://poser.pugx.org/cdb/cdb/v/stable.svg)](https://packagist.org/packages/cdb/cdb) [![License](https://poser.pugx.org/cdb/cdb/license.svg)](https://packagist.org/packages/cdb/cdb)
+[![Latest Stable Version]](https://packagist.org/packages/wikimedia/cdb) [![License]](https://packagist.org/packages/wikimedia/cdb)
CDB functions for PHP
=====================
@@ -9,30 +9,28 @@ library wraps the CDB functionality exposed in PHP via the `dba_*` functions.
In cases where `dba_*` functions are not present or are not compiled with CDB
support, a pure-PHP implementation is provided for falling back.
-Additional documentation about the library can be found on [MediaWiki.org](https://www.mediawiki.org/wiki/CDB).
+Additional documentation about the library can be found on
+[MediaWiki.org](https://www.mediawiki.org/wiki/CDB).
Usage
-----
-```
-// Reading a CDB file
-$cdb = \Cdb\Reader::open( 'db.cdb' );
-$foo = $cdb->get( 'somekey' );
+ // Reading a CDB file
+ $cdb = \Cdb\Reader::open( 'db.cdb' );
+ $foo = $cdb->get( 'somekey' );
+
+ // Writing to a CDB file
+ $cdb = \Cdb\Writer::open( 'anotherdb.cdb' );
+ $cdb->set( 'somekey', $foo );
-// Writing to a CDB file
-$cdb = \Cdb\Writer::open( 'anotherdb.cdb' );
-$cdb->set( 'somekey', $foo );
-```
Running tests
-------------
-```
-composer install --prefer-dist
-cd test
-../vendor/phpunit/phpunit/phpunit .
-```
+ composer install --prefer-dist
+ composer test
+
History
-------
@@ -41,8 +39,11 @@ This library was first introduced in [MediaWiki 1.16][] ([r52203][]). It was
split out of the MediaWiki codebase and published as an independent library
during the [MediaWiki 1.25][] development cycle.
+
---
[CDB]: https://en.wikipedia.org/wiki/cdb_(software)
[MediaWiki 1.16]: https://www.mediawiki.org/wiki/MediaWiki_1.16
[r52203]: https://www.mediawiki.org/wiki/Special:Code/MediaWiki/52203
[MediaWiki 1.25]: https://www.mediawiki.org/wiki/MediaWiki_1.25
+[Latest Stable Version]: https://poser.pugx.org/wikimedia/cdb/v/stable.svg
+[License]: https://poser.pugx.org/wikimedia/cdb/license.svg
diff --git a/vendor/wikimedia/cdb/composer.json b/vendor/wikimedia/cdb/composer.json
deleted file mode 100644
index 2134d2f7..00000000
--- a/vendor/wikimedia/cdb/composer.json
+++ /dev/null
@@ -1,26 +0,0 @@
-{
- "name": "wikimedia/cdb",
- "description": "Constant Database (CDB) wrapper library for PHP. Provides pure-PHP fallback when dba_* functions are absent.",
- "license": "GPL-2.0",
- "homepage": "https://www.mediawiki.org/wiki/CDB",
- "authors": [
- {
- "name": "Tim Starling",
- "email": "tstarling@wikimedia.org"
- },
- {
- "name": "Chad Horohoe",
- "email": "chad@wikimedia.org"
- }
- ],
- "minimum-stability": "dev",
- "require": {
- "php": ">=5.3.2"
- },
- "require-dev": {
- "phpunit/phpunit": "*"
- },
- "autoload": {
- "classmap": ["src/"]
- }
-}
diff --git a/vendor/wikimedia/cdb/doc/README b/vendor/wikimedia/cdb/doc/README
deleted file mode 100644
index 15ee3b71..00000000
--- a/vendor/wikimedia/cdb/doc/README
+++ /dev/null
@@ -1 +0,0 @@
-Placeholder for doxygen documentation
diff --git a/vendor/wikimedia/cdb/src/Reader.php b/vendor/wikimedia/cdb/src/Reader.php
index 2df06ab3..b1aaa022 100644
--- a/vendor/wikimedia/cdb/src/Reader.php
+++ b/vendor/wikimedia/cdb/src/Reader.php
@@ -82,4 +82,21 @@ abstract class Reader {
* @param string $key
*/
abstract public function get( $key );
+
+ /**
+ * Check whether key exists
+ *
+ * @param string $key
+ */
+ abstract public function exists( $key );
+
+ /**
+ * Fetch first key
+ */
+ abstract public function firstkey();
+
+ /**
+ * Fetch next key
+ */
+ abstract public function nextkey();
}
diff --git a/vendor/wikimedia/cdb/src/Reader/DBA.php b/vendor/wikimedia/cdb/src/Reader/DBA.php
index 838bf6e0..62f1ad99 100644
--- a/vendor/wikimedia/cdb/src/Reader/DBA.php
+++ b/vendor/wikimedia/cdb/src/Reader/DBA.php
@@ -1,6 +1,7 @@
<?php
namespace Cdb\Reader;
+
use Cdb\Exception;
use Cdb\Reader;
@@ -46,4 +47,16 @@ class DBA extends Reader {
public function get( $key ) {
return dba_fetch( $key, $this->handle );
}
+
+ public function exists( $key ) {
+ return dba_exists( $key, $this->handle );
+ }
+
+ public function firstkey() {
+ return dba_firstkey( $this->handle );
+ }
+
+ public function nextkey() {
+ return dba_nextkey( $this->handle );
+ }
}
diff --git a/vendor/wikimedia/cdb/src/Reader/PHP.php b/vendor/wikimedia/cdb/src/Reader/PHP.php
index 57b7d8ca..0f0d36ef 100644
--- a/vendor/wikimedia/cdb/src/Reader/PHP.php
+++ b/vendor/wikimedia/cdb/src/Reader/PHP.php
@@ -1,16 +1,14 @@
<?php
namespace Cdb\Reader;
+
use Cdb\Exception;
use Cdb\Reader;
use Cdb\Util;
/**
* This is a port of D.J. Bernstein's CDB to PHP. It's based on the copy that
- * appears in PHP 5.3. Changes are:
- * * Error returns replaced with exceptions
- * * Exception thrown if sizes or offsets are between 2GB and 4GB
- * * Some variables renamed
+ * appears in PHP 5.3.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -34,33 +32,37 @@ use Cdb\Util;
* CDB reader class
*/
class PHP extends Reader {
- /** The filename */
+
+ /** @var string The file name of the CDB file. **/
protected $fileName;
- /* number of hash slots searched under this key */
- protected $loop;
+ /** @var string First 2048b of CDB file, containing the hash table. **/
+ protected $hashTable;
- /* initialized if loop is nonzero */
- protected $khash;
+ /** @var int Offset in file where value of found key starts. **/
+ protected $dataPos;
- /* initialized if loop is nonzero */
- protected $kpos;
+ /** @var int Byte length of found key's value. **/
+ protected $dataLen;
- /* initialized if loop is nonzero */
- protected $hpos;
+ /** @var int File position indicator when iterating over keys. **/
+ protected $keyIterPos = 2048;
- /* initialized if loop is nonzero */
- protected $hslots;
+ /** @var string Read buffer for CDB file. **/
+ protected $buf;
- /* initialized if findNext() returns true */
- protected $dpos;
+ /** @var int File offset where read buffer starts. **/
+ protected $bufStart;
- /* initialized if cdb_findnext() returns 1 */
- protected $dlen;
+ /** @var int File handle position indicator **/
+ protected $filePos = 2048;
/**
+ * Constructor.
+ *
* @param string $fileName
- * @throws Exception
+ * @throws Exception If CDB file cannot be opened or if it contains fewer
+ * than 2048 bytes of data.
*/
public function __construct( $fileName ) {
$this->fileName = $fileName;
@@ -68,9 +70,15 @@ class PHP extends Reader {
if ( !$this->handle ) {
throw new Exception( 'Unable to open CDB file "' . $this->fileName . '".' );
}
- $this->findStart();
+ $this->hashTable = fread( $this->handle, 2048 );
+ if ( strlen( $this->hashTable ) !== 2048 ) {
+ throw new Exception( 'CDB file contains fewer than 2048 bytes of data.' );
+ }
}
+ /**
+ * Close the handle on the CDB file.
+ */
public function close() {
if ( isset( $this->handle ) ) {
fclose( $this->handle );
@@ -79,127 +87,180 @@ class PHP extends Reader {
}
/**
+ * Get the value of a key.
+ *
* @param mixed $key
- * @return bool|string
+ * @return bool|string The key's value or false if not found.
*/
public function get( $key ) {
// strval is required
if ( $this->find( strval( $key ) ) ) {
- return $this->read( $this->dlen, $this->dpos );
+ return $this->read( $this->dataPos, $this->dataLen );
}
return false;
}
/**
- * @param string $key
- * @param int $pos
- * @return bool
+ * Read data from the CDB file.
+ *
+ * @throws Exception When attempting to read past the end of the file.
+ * @param int $start Start reading from this position.
+ * @param int $len Number of bytes to read.
+ * @return string Read data.
*/
- protected function match( $key, $pos ) {
- $buf = $this->read( strlen( $key ), $pos );
+ protected function read( $start, $len ) {
+ $end = $start + $len;
- return $buf === $key;
- }
+ // The first 2048 bytes are the lookup table, which is read into
+ // memory on initialization.
+ if ( $end <= 2048 ) {
+ return substr( $this->hashTable, $start, $len );
+ }
- protected function findStart() {
- $this->loop = 0;
- }
+ // Read data from the internal buffer first.
+ $bytes = '';
+ if ( $this->buf && $start >= $this->bufStart ) {
+ $bytes .= substr( $this->buf, $start - $this->bufStart, $len );
+ $bytesRead = strlen( $bytes );
+ $len -= $bytesRead;
+ $start += $bytesRead;
+ } else {
+ $bytesRead = 0;
+ }
- /**
- * @throws Exception
- * @param int $length
- * @param int $pos
- * @return string
- */
- protected function read( $length, $pos ) {
- if ( fseek( $this->handle, $pos ) == -1 ) {
- // This can easily happen if the internal pointers are incorrect
- throw new Exception(
- 'Seek failed, file "' . $this->fileName . '" may be corrupted.' );
+ if ( !$len ) {
+ return $bytes;
+ }
+
+ // Many reads are sequential, so the file position indicator may
+ // already be in the right place, in which case we can avoid the
+ // call to fseek().
+ if ( $start !== $this->filePos ) {
+ if ( fseek( $this->handle, $start ) === -1 ) {
+ // This can easily happen if the internal pointers are incorrect
+ throw new Exception(
+ 'Seek failed, file "' . $this->fileName . '" may be corrupted.' );
+ }
}
- if ( $length == 0 ) {
- return '';
+ $buf = fread( $this->handle, max( $len, 1024 ) );
+ if ( $buf === false ) {
+ $buf = '';
}
- $buf = fread( $this->handle, $length );
- if ( $buf === false || strlen( $buf ) !== $length ) {
+ $bytes .= substr( $buf, 0, $len );
+ if ( strlen( $bytes ) !== $len + $bytesRead ) {
throw new Exception(
'Read from CDB file failed, file "' . $this->fileName . '" may be corrupted.' );
}
- return $buf;
+ $this->filePos = $end;
+ $this->bufStart = $start;
+ $this->buf = $buf;
+
+ return $bytes;
}
/**
- * Unpack an unsigned integer and throw an exception if it needs more than 31 bits
- * @param string $s
- * @throws Exception
- * @return mixed
+ * Unpack an unsigned integer and throw an exception if it needs more than 31 bits.
+ *
+ * @param int $pos Position to read from.
+ * @throws Exception When the integer cannot be represented in 31 bits.
+ * @return int
*/
- protected function unpack31( $s ) {
- $data = unpack( 'V', $s );
- if ( $data[1] > 0x7fffffff ) {
+ protected function readInt31( $pos = 0 ) {
+ $uint31 = $this->readInt32( $pos );
+ if ( $uint31 > 0x7fffffff ) {
throw new Exception(
'Error in CDB file "' . $this->fileName . '", integer too big.' );
}
- return $data[1];
+ return $uint31;
}
/**
- * Unpack a 32-bit signed integer
- * @param string $s
+ * Unpack a 32-bit integer.
+ *
+ * @param int $pos
* @return int
*/
- protected function unpackSigned( $s ) {
- $data = unpack( 'va/vb', $s );
+ protected function readInt32( $pos = 0 ) {
+ static $lookups;
+
+ if ( !$lookups ) {
+ $lookups = array();
+ for ( $i = 1; $i < 256; $i++ ) {
+ $lookups[ chr( $i ) ] = $i;
+ }
+ }
- return $data['a'] | ( $data['b'] << 16 );
+ $buf = $this->read( $pos, 4 );
+
+ $rv = 0;
+
+ if ( $buf[0] !== "\x0" ) {
+ $rv = $lookups[ $buf[0] ];
+ }
+ if ( $buf[1] !== "\x0" ) {
+ $rv |= ( $lookups[ $buf[1] ] << 8 );
+ }
+ if ( $buf[2] !== "\x0" ) {
+ $rv |= ( $lookups[ $buf[2] ] << 16 );
+ }
+ if ( $buf[3] !== "\x0" ) {
+ $rv |= ( $lookups[ $buf[3] ] << 24 );
+ }
+
+ return $rv;
}
/**
+ * Search the CDB file for a key.
+ *
+ * Sets `dataLen` and `dataPos` properties if successful.
+ *
* @param string $key
- * @return bool
+ * @return bool Whether the key was found.
*/
- protected function findNext( $key ) {
- if ( !$this->loop ) {
- $u = Util::hash( $key );
- $buf = $this->read( 8, ( $u << 3 ) & 2047 );
- $this->hslots = $this->unpack31( substr( $buf, 4 ) );
- if ( !$this->hslots ) {
- return false;
- }
- $this->hpos = $this->unpack31( substr( $buf, 0, 4 ) );
- $this->khash = $u;
- $u = Util::unsignedShiftRight( $u, 8 );
- $u = Util::unsignedMod( $u, $this->hslots );
- $u <<= 3;
- $this->kpos = $this->hpos + $u;
- }
+ protected function find( $key ) {
+ $keyLen = strlen( $key );
- while ( $this->loop < $this->hslots ) {
- $buf = $this->read( 8, $this->kpos );
- $pos = $this->unpack31( substr( $buf, 4 ) );
+ $u = Util::hash( $key );
+ $upos = ( $u << 3 ) & 2047;
+ $hashSlots = $this->readInt31( $upos + 4 );
+ if ( !$hashSlots ) {
+ return false;
+ }
+ $hashPos = $this->readInt31( $upos );
+ $keyHash = $u;
+ $u = Util::unsignedShiftRight( $u, 8 );
+ $u = Util::unsignedMod( $u, $hashSlots );
+ $u <<= 3;
+ $keyPos = $hashPos + $u;
+
+ for ( $i = 0; $i < $hashSlots; $i++ ) {
+ $hash = $this->readInt32( $keyPos );
+ $pos = $this->readInt31( $keyPos + 4 );
if ( !$pos ) {
return false;
}
- $this->loop += 1;
- $this->kpos += 8;
- if ( $this->kpos == $this->hpos + ( $this->hslots << 3 ) ) {
- $this->kpos = $this->hpos;
+ $keyPos += 8;
+ if ( $keyPos == $hashPos + ( $hashSlots << 3 ) ) {
+ $keyPos = $hashPos;
}
- $u = $this->unpackSigned( substr( $buf, 0, 4 ) );
- if ( $u === $this->khash ) {
- $buf = $this->read( 8, $pos );
- $keyLen = $this->unpack31( substr( $buf, 0, 4 ) );
- if ( $keyLen == strlen( $key ) && $this->match( $key, $pos + 8 ) ) {
- // Found
- $this->dlen = $this->unpack31( substr( $buf, 4 ) );
- $this->dpos = $pos + 8 + $keyLen;
-
- return true;
+ if ( $hash === $keyHash ) {
+ if ( $keyLen === $this->readInt31( $pos ) ) {
+ $dataLen = $this->readInt31( $pos + 4 );
+ $dataPos = $pos + 8 + $keyLen;
+ $foundKey = $this->read( $pos + 8, $keyLen );
+ if ( $foundKey === $key ) {
+ // Found
+ $this->dataLen = $dataLen;
+ $this->dataPos = $dataPos;
+
+ return true;
+ }
}
}
}
@@ -208,13 +269,36 @@ class PHP extends Reader {
}
/**
- * @param mixed $key
- * @return bool
+ * Check if a key exists in the CDB file.
+ *
+ * @param string $key
+ * @return bool Whether the key exists.
*/
- protected function find( $key ) {
- $this->findStart();
+ public function exists( $key ) {
+ return $this->find( strval( $key ) );
+ }
+
+ /**
+ * Get the first key from the CDB file and reset the key iterator.
+ *
+ * @return string Key.
+ */
+ public function firstkey() {
+ $this->keyIterPos = 2048;
+ return $this->nextkey();
+ }
+
+ /**
+ * Get the next key from the CDB file.
+ *
+ * @return string Key.
+ */
+ public function nextkey() {
+ $keyLen = $this->readInt31( $this->keyIterPos );
+ $dataLen = $this->readInt31( $this->keyIterPos + 4 );
+ $key = $this->read( $this->keyIterPos + 8, $keyLen );
+ $this->keyIterPos += 8 + $keyLen + $dataLen;
- return $this->findNext( $key );
+ return $key;
}
}
-
diff --git a/vendor/wikimedia/cdb/src/Writer.php b/vendor/wikimedia/cdb/src/Writer.php
index b994ec67..53216041 100644
--- a/vendor/wikimedia/cdb/src/Writer.php
+++ b/vendor/wikimedia/cdb/src/Writer.php
@@ -94,6 +94,6 @@ abstract class Writer {
* @return bool
*/
protected function isWindows() {
- return substr( php_uname(), 0, 7 ) == 'Windows';
+ return strtoupper( substr( PHP_OS, 0, 3 ) ) === 'WIN';
}
}
diff --git a/vendor/wikimedia/cdb/src/Writer/DBA.php b/vendor/wikimedia/cdb/src/Writer/DBA.php
index eb525f4c..20d0adfb 100644
--- a/vendor/wikimedia/cdb/src/Writer/DBA.php
+++ b/vendor/wikimedia/cdb/src/Writer/DBA.php
@@ -1,6 +1,7 @@
<?php
namespace Cdb\Writer;
+
use Cdb\Exception;
use Cdb\Writer;
diff --git a/vendor/wikimedia/cdb/src/Writer/PHP.php b/vendor/wikimedia/cdb/src/Writer/PHP.php
index 68c6b760..4676b5e4 100644
--- a/vendor/wikimedia/cdb/src/Writer/PHP.php
+++ b/vendor/wikimedia/cdb/src/Writer/PHP.php
@@ -1,6 +1,7 @@
<?php
namespace Cdb\Writer;
+
use Cdb\Exception;
use Cdb\Util;
use Cdb\Writer;
diff --git a/vendor/wikimedia/cdb/test/CdbTest.php b/vendor/wikimedia/cdb/test/CdbTest.php
deleted file mode 100644
index 920fc111..00000000
--- a/vendor/wikimedia/cdb/test/CdbTest.php
+++ /dev/null
@@ -1,95 +0,0 @@
-<?php
-
-namespace Cdb\Test;
-use Cdb\Reader;
-use Cdb\Writer;
-
-/**
- * Test the CDB reader/writer
- * @covers Cdb\Writer\PHP
- * @covers Cdb\Writer\DBA
- */
-class CdbTest extends \PHPUnit_Framework_TestCase {
- /** @var string */
- private $phpCdbFile, $dbaCdbFile;
-
- protected function setUp() {
- parent::setUp();
- if ( !Reader::haveExtension() ) {
- $this->markTestSkipped( 'Native CDB support is not available.' );
- }
- $temp = sys_get_temp_dir();
- if ( !is_writable( $temp ) ) {
- $this->markTestSkipped( "Temp dir [$temp] isn't writable." );
- }
- $this->phpCdbFile = tempnam( $temp, get_class( $this ) . '_' );
- $this->dbaCdbFile = tempnam( $temp, get_class( $this ) . '_' );
- }
-
- /**
- * Make a random-ish string
- * @return string
- */
- private static function randomString() {
- $len = mt_rand( 0, 10 );
- $s = '';
- for ( $j = 0; $j < $len; $j++ ) {
- $s .= chr( mt_rand( 0, 255 ) );
- }
-
- return $s;
- }
-
- public function testCdbWrite() {
- $w1 = new Writer\PHP( $this->phpCdbFile );
- $w2 = new Writer\DBA( $this->dbaCdbFile );
-
- $data = array();
- for ( $i = 0; $i < 1000; $i++ ) {
- $key = self::randomString();
- $value = self::randomString();
- $w1->set( $key, $value );
- $w2->set( $key, $value );
-
- if ( !isset( $data[$key] ) ) {
- $data[$key] = $value;
- }
- }
-
- $w1->close();
- $w2->close();
-
- $this->assertEquals(
- md5_file( $this->phpCdbFile ),
- md5_file( $this->dbaCdbFile ),
- 'same hash'
- );
-
- $r1 = new Reader\PHP( $this->phpCdbFile );
- $r2 = new Reader\DBA( $this->dbaCdbFile );
-
- foreach ( $data as $key => $value ) {
- if ( $key === '' ) {
- // Known bug
- continue;
- }
- $v1 = $r1->get( $key );
- $v2 = $r2->get( $key );
-
- $v1 = $v1 === false ? '(not found)' : $v1;
- $v2 = $v2 === false ? '(not found)' : $v2;
-
- # cdbAssert( 'Mismatch', $key, $v1, $v2 );
- $this->cdbAssert( "PHP error", $key, $v1, $value );
- $this->cdbAssert( "DBA error", $key, $v2, $value );
- }
- }
-
- private function cdbAssert( $msg, $key, $v1, $v2 ) {
- $this->assertEquals(
- $v2,
- $v1,
- $msg . ', k=' . bin2hex( $key )
- );
- }
-}
diff --git a/vendor/wikimedia/composer-merge-plugin/.arcconfig b/vendor/wikimedia/composer-merge-plugin/.arcconfig
new file mode 100644
index 00000000..3dfae3d9
--- /dev/null
+++ b/vendor/wikimedia/composer-merge-plugin/.arcconfig
@@ -0,0 +1,6 @@
+{
+ "phabricator.uri" : "https://phabricator.wikimedia.org/",
+ "repository.callsign" : "GCMP",
+ "history.immutable" : false,
+ "unit.engine": "PhpunitTestEngine"
+}
diff --git a/vendor/wikimedia/composer-merge-plugin/.arclint b/vendor/wikimedia/composer-merge-plugin/.arclint
new file mode 100644
index 00000000..da42f29a
--- /dev/null
+++ b/vendor/wikimedia/composer-merge-plugin/.arclint
@@ -0,0 +1,13 @@
+{
+ "exclude": "(^vendor/)",
+ "linters": {
+ "php": {
+ "type": "php",
+ "include": "(\\.php$)"
+ },
+ "json": {
+ "type": "json",
+ "include": "(\\.json$)"
+ }
+ }
+}
diff --git a/vendor/wikimedia/composer-merge-plugin/LICENSE b/vendor/wikimedia/composer-merge-plugin/LICENSE
index 55e376b4..3c9804a6 100644
--- a/vendor/wikimedia/composer-merge-plugin/LICENSE
+++ b/vendor/wikimedia/composer-merge-plugin/LICENSE
@@ -1,4 +1,4 @@
-Copyright (c) 2014 Bryan Davis, Wikimedia Foundation, and contributors
+Copyright (c) 2015 Bryan Davis, Wikimedia Foundation, and contributors
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
diff --git a/vendor/wikimedia/composer-merge-plugin/README.md b/vendor/wikimedia/composer-merge-plugin/README.md
index 53d64579..f020d40a 100644
--- a/vendor/wikimedia/composer-merge-plugin/README.md
+++ b/vendor/wikimedia/composer-merge-plugin/README.md
@@ -1,18 +1,34 @@
-[![Latest Stable Version](https://img.shields.io/packagist/v/wikimedia/composer-merge-plugin.svg?style=flat)](https://packagist.org/packages/wikimedia/composer-merge-plugin) [![License](https://img.shields.io/packagist/l/wikimedia/composer-merge-plugin.svg?style=flat)](https://github.com/wikimedia/composer-merge-plugin/blob/master/LICENSE)
-[![Build Status](https://img.shields.io/travis/wikimedia/composer-merge-plugin.svg?style=flat)](https://travis-ci.org/wikimedia/composer-merge-plugin)
-[![Code Coverage](https://img.shields.io/scrutinizer/coverage/g/wikimedia/composer-merge-plugin/master.svg?style=flat)](https://scrutinizer-ci.com/g/wikimedia/composer-merge-plugin/?branch=master)
+[![Latest Stable Version]](https://packagist.org/packages/wikimedia/composer-merge-plugin) [![License]](https://github.com/wikimedia/composer-merge-plugin/blob/master/LICENSE)
+[![Build Status]](https://travis-ci.org/wikimedia/composer-merge-plugin)
+[![Code Coverage]](https://scrutinizer-ci.com/g/wikimedia/composer-merge-plugin/?branch=master)
Composer Merge Plugin
=====================
-Merge one or more additional composer.json files at runtime.
+Merge multiple composer.json files at [Composer] runtime.
+
+Composer Merge Plugin is intended to allow easier dependency management for
+applications which ship a composer.json file and expect some deployments to
+install additional Composer managed libraries. It does this by allowing the
+application's top level `composer.json` file to provide a list of optional
+additional configuration files. When Composer is run it will parse these files
+and merge their configuration settings into the base configuration. This
+combined configuration will then be used when downloading additional libraries
+and generating the autoloader.
+
+Composer Merge Plugin was created to help with installation of [MediaWiki]
+which has core library requirements as well as optional libraries and
+extensions which may be managed via Composer.
+
Installation
------------
+
```
$ composer require wikimedia/composer-merge-plugin
```
+
Usage
-----
@@ -26,33 +42,111 @@ Usage
"include": [
"composer.local.json",
"extensions/*/composer.json"
- ]
+ ],
+ "require": [
+ "submodule/composer.json"
+ ],
+ "recurse": true,
+ "replace": false,
+ "merge-dev": true,
+ "merge-extra": false
}
}
}
```
-The `include` key can specify either a single value or an array of values.
-Each value is treated as a glob() pattern identifying additional composer.json
-style configuration files to merge into the configuration for the current
-Composer execution. By default the merge plugin is recursive, if an included
-file also has a "merge-plugin" section it will also be processed. This
-functionality can be disabled by setting `"recurse": false` inside the
-"merge-plugin" section.
-The "require", "require-dev", "repositories" and "suggest" sections of the
-found configuration files will be merged into the root package configuration
-as though they were directly included in the top-level composer.json file.
+Plugin configuration
+--------------------
+
+The plugin reads its configuration from the `merge-plugin` section of your
+composer.json's `extra` section. An `include` setting is required to tell
+Composer Merge Plugin which file(s) to merge.
+
+
+### include
+
+The `include` setting can specify either a single value or an array of values.
+Each value is treated as a PHP `glob()` pattern identifying additional
+composer.json style configuration files to merge into the root package
+configuration for the current Composer execution.
+
+The following sections of the found configuration files will be merged into
+the Composer root package configuration as though they were directly included
+in the top-level composer.json file:
+
+* [autoload](https://getcomposer.org/doc/04-schema.md#autoload)
+* [autoload-dev](https://getcomposer.org/doc/04-schema.md#autoload-dev)
+ (optional, see [merge-dev](#merge-dev) below)
+* [conflict](https://getcomposer.org/doc/04-schema.md#conflict)
+* [provide](https://getcomposer.org/doc/04-schema.md#provide)
+* [replace](https://getcomposer.org/doc/04-schema.md#replace)
+* [repositories](https://getcomposer.org/doc/04-schema.md#repositories)
+* [require](https://getcomposer.org/doc/04-schema.md#require)
+* [require-dev](https://getcomposer.org/doc/04-schema.md#require-dev)
+ (optional, see [merge-dev](#merge-dev) below)
+* [suggest](https://getcomposer.org/doc/04-schema.md#suggest)
+* [extra](https://getcomposer.org/doc/04-schema.md#extra)
+ (optional, see [merge-extra](#merge-extra) below)
+
+
+### require
+
+The `require` setting is identical to `[include](#include)` except when
+a pattern fails to match at least one file then it will cause an error.
+
+### recurse
+
+By default the merge plugin is recursive; if an included file has
+a `merge-plugin` section it will also be processed. This functionality can be
+disabled by adding a `"recurse": false` setting.
+
+
+### replace
+
+By default, Composer's conflict resolution engine is used to determine which
+version of a package should be installed when multiple files specify the same
+package. A `"replace": true` setting can be provided to change to a "last
+version specified wins" conflict resolution strategy. In this mode, duplicate
+package declarations found in merged files will overwrite the declarations
+made by earlier files. Files are loaded in the order specified by the
+`include` setting with globbed files being processed in alphabetical order.
+
+
+### merge-dev
+
+By default, `autoload-dev` and `require-dev` sections of included files are
+merged. A `"merge-dev": false` setting will disable this behavior.
+
+
+### merge-extra
+
+A `"merge-extra": true` setting enables the merging the contents of the
+`extra` section of included files as well. The normal merge mode for the extra
+section is to accept the first version of any key found (e.g. a key in the
+master config wins over the version found in any imported config). If
+`replace` mode is active ([see above](#replace)) then this behavior changes
+and the last key found will win (e.g. the key in the master config is replaced
+by the key in the imported config). The usefulness of merging the extra
+section will vary depending on the Composer plugins being used and the order
+in which they are processed by Composer.
+
+Note that `merge-plugin` sections are excluded from the merge process, but are
+always processed by the plugin unless [recursion](#recurse) is disabled.
+
Running tests
-------------
+
```
$ composer install
$ composer test
```
+
Contributing
------------
+
Bug, feature requests and other issues should be reported to the [GitHub
project]. We accept code and documentation contributions via Pull Requests on
GitHub as well.
@@ -69,12 +163,21 @@ GitHub as well.
easier for you to make sure you have updated the necessary tests and
documentation.
+
License
-------
+
Composer Merge plugin is licensed under the MIT license. See the `LICENSE`
file for more details.
+
---
+[Composer]: https://getcomposer.org/
+[MediaWiki]: https://www.mediawiki.org/wiki/MediaWiki
[GitHub project]: https://github.com/wikimedia/composer-merge-plugin
[PSR-2 Coding Standard]: https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-2-coding-style-guide.md
[PHP Code Sniffer]: http://pear.php.net/package/PHP_CodeSniffer
+[Latest Stable Version]: https://img.shields.io/packagist/v/wikimedia/composer-merge-plugin.svg?style=flat
+[License]: https://img.shields.io/packagist/l/wikimedia/composer-merge-plugin.svg?style=flat
+[Build Status]: https://img.shields.io/travis/wikimedia/composer-merge-plugin.svg?style=flat
+[Code Coverage]: https://img.shields.io/scrutinizer/coverage/g/wikimedia/composer-merge-plugin/master.svg?style=flat
diff --git a/vendor/wikimedia/composer-merge-plugin/composer.json b/vendor/wikimedia/composer-merge-plugin/composer.json
index 5ef429ad..dce70e7d 100644
--- a/vendor/wikimedia/composer-merge-plugin/composer.json
+++ b/vendor/wikimedia/composer-merge-plugin/composer.json
@@ -3,18 +3,23 @@
"description": "Composer plugin to merge multiple composer.json files",
"type": "composer-plugin",
"license": "MIT",
+ "authors": [
+ {
+ "name": "Bryan Davis",
+ "email": "bd808@wikimedia.org"
+ }
+ ],
"minimum-stability": "dev",
"prefer-stable": true,
"require": {
- "php": ">=5.3.2",
- "composer-plugin-api": "1.0.0"
+ "composer-plugin-api": "^1.0",
+ "php": ">=5.3.2"
},
"require-dev": {
"composer/composer": "1.0.*@dev",
- "phpunit/phpunit": "~4.0",
"jakub-onderka/php-parallel-lint": "~0.8",
- "squizlabs/php_codesniffer": "~2.1.0",
- "phpspec/prophecy-phpunit": "~1.0"
+ "phpunit/phpunit": "~4.8|~5.0",
+ "squizlabs/php_codesniffer": "~2.1.0"
},
"autoload": {
"psr-4": {
@@ -22,6 +27,9 @@
}
},
"extra": {
+ "branch-alias": {
+ "dev-master": "1.3.x-dev"
+ },
"class": "Wikimedia\\Composer\\MergePlugin"
},
"config": {
diff --git a/vendor/wikimedia/composer-merge-plugin/src/Logger.php b/vendor/wikimedia/composer-merge-plugin/src/Logger.php
new file mode 100644
index 00000000..1635a2b0
--- /dev/null
+++ b/vendor/wikimedia/composer-merge-plugin/src/Logger.php
@@ -0,0 +1,102 @@
+<?php
+/**
+ * This file is part of the Composer Merge plugin.
+ *
+ * Copyright (C) 2015 Bryan Davis, Wikimedia Foundation, and contributors
+ *
+ * This software may be modified and distributed under the terms of the MIT
+ * license. See the LICENSE file for details.
+ */
+
+namespace Wikimedia\Composer;
+
+use Composer\IO\IOInterface;
+
+/**
+ * Simple logging wrapper for Composer\IO\IOInterface
+ *
+ * @author Bryan Davis <bd808@bd808.com>
+ */
+class Logger
+{
+ /**
+ * @var string $name
+ */
+ protected $name;
+
+ /**
+ * @var IOInterface $inputOutput
+ */
+ protected $inputOutput;
+
+ /**
+ * @param string $name
+ * @param IOInterface $io
+ */
+ public function __construct($name, IOInterface $io)
+ {
+ $this->name = $name;
+ $this->inputOutput = $io;
+ }
+
+ /**
+ * Log a debug message
+ *
+ * Messages will be output at the "very verbose" logging level (eg `-vv`
+ * needed on the Composer command).
+ *
+ * @param string $message
+ */
+ public function debug($message)
+ {
+ if ($this->inputOutput->isVeryVerbose()) {
+ $message = " <info>[{$this->name}]</info> {$message}";
+ $this->log($message);
+ }
+ }
+
+ /**
+ * Log an informative message
+ *
+ * Messages will be output at the "verbose" logging level (eg `-v` needed
+ * on the Composer command).
+ *
+ * @param string $message
+ */
+ public function info($message)
+ {
+ if ($this->inputOutput->isVerbose()) {
+ $message = " <info>[{$this->name}]</info> {$message}";
+ $this->log($message);
+ }
+ }
+
+ /**
+ * Log a warning message
+ *
+ * @param string $message
+ */
+ public function warning($message)
+ {
+ $message = " <error>[{$this->name}]</error> {$message}";
+ $this->log($message);
+ }
+
+ /**
+ * Write a message
+ *
+ * @param string $message
+ */
+ protected function log($message)
+ {
+ if (method_exists($this->inputOutput, 'writeError')) {
+ $this->inputOutput->writeError($message);
+ } else {
+ // @codeCoverageIgnoreStart
+ // Backwards compatiblity for Composer before cb336a5
+ $this->inputOutput->write($message);
+ // @codeCoverageIgnoreEnd
+ }
+ }
+}
+// vim:sw=4:ts=4:sts=4:et:
diff --git a/vendor/wikimedia/composer-merge-plugin/src/Merge/ExtraPackage.php b/vendor/wikimedia/composer-merge-plugin/src/Merge/ExtraPackage.php
new file mode 100644
index 00000000..ebecdff5
--- /dev/null
+++ b/vendor/wikimedia/composer-merge-plugin/src/Merge/ExtraPackage.php
@@ -0,0 +1,487 @@
+<?php
+/**
+ * This file is part of the Composer Merge plugin.
+ *
+ * Copyright (C) 2015 Bryan Davis, Wikimedia Foundation, and contributors
+ *
+ * This software may be modified and distributed under the terms of the MIT
+ * license. See the LICENSE file for details.
+ */
+
+namespace Wikimedia\Composer\Merge;
+
+use Wikimedia\Composer\Logger;
+
+use Composer\Composer;
+use Composer\Json\JsonFile;
+use Composer\Package\BasePackage;
+use Composer\Package\CompletePackage;
+use Composer\Package\Link;
+use Composer\Package\Loader\ArrayLoader;
+use Composer\Package\RootAliasPackage;
+use Composer\Package\RootPackage;
+use Composer\Package\RootPackageInterface;
+use Composer\Package\Version\VersionParser;
+use UnexpectedValueException;
+
+/**
+ * Processing for a composer.json file that will be merged into
+ * a RootPackageInterface
+ *
+ * @author Bryan Davis <bd808@bd808.com>
+ */
+class ExtraPackage
+{
+
+ /**
+ * @var Composer $composer
+ */
+ protected $composer;
+
+ /**
+ * @var Logger $logger
+ */
+ protected $logger;
+
+ /**
+ * @var string $path
+ */
+ protected $path;
+
+ /**
+ * @var array $json
+ */
+ protected $json;
+
+ /**
+ * @var CompletePackage $package
+ */
+ protected $package;
+
+ /**
+ * @param string $path Path to composer.json file
+ * @param Composer $composer
+ * @param Logger $logger
+ */
+ public function __construct($path, Composer $composer, Logger $logger)
+ {
+ $this->path = $path;
+ $this->composer = $composer;
+ $this->logger = $logger;
+ $this->json = $this->readPackageJson($path);
+ $this->package = $this->loadPackage($this->json);
+ }
+
+ /**
+ * Get list of additional packages to include if precessing recursively.
+ *
+ * @return array
+ */
+ public function getIncludes()
+ {
+ return isset($this->json['extra']['merge-plugin']['include']) ?
+ $this->json['extra']['merge-plugin']['include'] : array();
+ }
+
+ /**
+ * Get list of additional packages to require if precessing recursively.
+ *
+ * @return array
+ */
+ public function getRequires()
+ {
+ return isset($this->json['extra']['merge-plugin']['require']) ?
+ $this->json['extra']['merge-plugin']['require'] : array();
+ }
+
+ /**
+ * Read the contents of a composer.json style file into an array.
+ *
+ * The package contents are fixed up to be usable to create a Package
+ * object by providing dummy "name" and "version" values if they have not
+ * been provided in the file. This is consistent with the default root
+ * package loading behavior of Composer.
+ *
+ * @param string $path
+ * @return array
+ */
+ protected function readPackageJson($path)
+ {
+ $file = new JsonFile($path);
+ $json = $file->read();
+ if (!isset($json['name'])) {
+ $json['name'] = 'merge-plugin/' .
+ strtr($path, DIRECTORY_SEPARATOR, '-');
+ }
+ if (!isset($json['version'])) {
+ $json['version'] = '1.0.0';
+ }
+ return $json;
+ }
+
+ /**
+ * @return CompletePackage
+ */
+ protected function loadPackage($json)
+ {
+ $loader = new ArrayLoader();
+ $package = $loader->load($json);
+ // @codeCoverageIgnoreStart
+ if (!$package instanceof CompletePackage) {
+ throw new UnexpectedValueException(
+ 'Expected instance of CompletePackage, got ' .
+ get_class($package)
+ );
+ }
+ // @codeCoverageIgnoreEnd
+ return $package;
+ }
+
+ /**
+ * Merge this package into a RootPackageInterface
+ *
+ * @param RootPackageInterface $root
+ * @param PluginState $state
+ */
+ public function mergeInto(RootPackageInterface $root, PluginState $state)
+ {
+ $this->addRepositories($root);
+
+ $this->mergeRequires('require', $root, $state);
+ if ($state->isDevMode()) {
+ $this->mergeRequires('require-dev', $root, $state);
+ }
+
+ $this->mergePackageLinks('conflict', $root);
+ $this->mergePackageLinks('replace', $root);
+ $this->mergePackageLinks('provide', $root);
+
+ $this->mergeSuggests($root);
+
+ $this->mergeAutoload('autoload', $root);
+ if ($state->isDevMode()) {
+ $this->mergeAutoload('devAutoload', $root);
+ }
+
+ $this->mergeExtra($root, $state);
+ }
+
+ /**
+ * Add a collection of repositories described by the given configuration
+ * to the given package and the global repository manager.
+ *
+ * @param RootPackageInterface $root
+ */
+ protected function addRepositories(RootPackageInterface $root)
+ {
+ if (!isset($this->json['repositories'])) {
+ return;
+ }
+ $repoManager = $this->composer->getRepositoryManager();
+ $newRepos = array();
+
+ foreach ($this->json['repositories'] as $repoJson) {
+ if (!isset($repoJson['type'])) {
+ continue;
+ }
+ $this->logger->info("Adding {$repoJson['type']} repository");
+ $repo = $repoManager->createRepository(
+ $repoJson['type'],
+ $repoJson
+ );
+ $repoManager->addRepository($repo);
+ $newRepos[] = $repo;
+ }
+
+ $unwrapped = self::unwrapIfNeeded($root, 'setRepositories');
+ $unwrapped->setRepositories(array_merge(
+ $newRepos,
+ $root->getRepositories()
+ ));
+ }
+
+ /**
+ * Merge require or require-dev into a RootPackageInterface
+ *
+ * @param string $type 'require' or 'require-dev'
+ * @param RootPackageInterface $root
+ * @param PluginState $state
+ */
+ protected function mergeRequires(
+ $type,
+ RootPackageInterface $root,
+ PluginState $state
+ ) {
+ $linkType = BasePackage::$supportedLinkTypes[$type];
+ $getter = 'get' . ucfirst($linkType['method']);
+ $setter = 'set' . ucfirst($linkType['method']);
+
+ $requires = $this->package->{$getter}();
+ if (empty($requires)) {
+ return;
+ }
+
+ $this->mergeStabilityFlags($root, $requires);
+
+ $requires = $this->replaceSelfVersionDependencies(
+ $type,
+ $requires,
+ $root
+ );
+
+ $root->{$setter}($this->mergeOrDefer(
+ $type,
+ $root->{$getter}(),
+ $requires,
+ $state
+ ));
+ }
+
+ /**
+ * Merge two collections of package links and collect duplicates for
+ * subsequent processing.
+ *
+ * @param string $type 'require' or 'require-dev'
+ * @param array $origin Primary collection
+ * @param array $merge Additional collection
+ * @param PluginState $state
+ * @return array Merged collection
+ */
+ protected function mergeOrDefer(
+ $type,
+ array $origin,
+ array $merge,
+ $state
+ ) {
+ $dups = array();
+ foreach ($merge as $name => $link) {
+ if (!isset($origin[$name]) || $state->replaceDuplicateLinks()) {
+ $this->logger->info("Merging <comment>{$name}</comment>");
+ $origin[$name] = $link;
+ } else {
+ // Defer to solver.
+ $this->logger->info(
+ "Deferring duplicate <comment>{$name}</comment>"
+ );
+ $dups[] = $link;
+ }
+ }
+ $state->addDuplicateLinks($type, $dups);
+ return $origin;
+ }
+
+ /**
+ * Merge autoload or autoload-dev into a RootPackageInterface
+ *
+ * @param string $type 'autoload' or 'devAutoload'
+ * @param RootPackageInterface $root
+ */
+ protected function mergeAutoload($type, RootPackageInterface $root)
+ {
+ $getter = 'get' . ucfirst($type);
+ $setter = 'set' . ucfirst($type);
+
+ $autoload = $this->package->{$getter}();
+ if (empty($autoload)) {
+ return;
+ }
+
+ $unwrapped = self::unwrapIfNeeded($root, $setter);
+ $unwrapped->{$setter}(array_merge_recursive(
+ $root->{$getter}(),
+ $this->fixRelativePaths($autoload)
+ ));
+ }
+
+ /**
+ * Fix a collection of paths that are relative to this package to be
+ * relative to the base package.
+ *
+ * @param array $paths
+ * @return array
+ */
+ protected function fixRelativePaths(array $paths)
+ {
+ $base = dirname($this->path);
+ $base = ($base === '.') ? '' : "{$base}/";
+
+ array_walk_recursive(
+ $paths,
+ function (&$path) use ($base) {
+ $path = "{$base}{$path}";
+ }
+ );
+ return $paths;
+ }
+
+ /**
+ * Extract and merge stability flags from the given collection of
+ * requires and merge them into a RootPackageInterface
+ *
+ * @param RootPackageInterface $root
+ * @param array $requires
+ */
+ protected function mergeStabilityFlags(
+ RootPackageInterface $root,
+ array $requires
+ ) {
+ $flags = $root->getStabilityFlags();
+ $sf = new StabilityFlags($flags, $root->getMinimumStability());
+
+ $unwrapped = self::unwrapIfNeeded($root, 'setStabilityFlags');
+ $unwrapped->setStabilityFlags(array_merge(
+ $flags,
+ $sf->extractAll($requires)
+ ));
+ }
+
+ /**
+ * Merge package links of the given type into a RootPackageInterface
+ *
+ * @param string $type 'conflict', 'replace' or 'provide'
+ * @param RootPackageInterface $root
+ */
+ protected function mergePackageLinks($type, RootPackageInterface $root)
+ {
+ $linkType = BasePackage::$supportedLinkTypes[$type];
+ $getter = 'get' . ucfirst($linkType['method']);
+ $setter = 'set' . ucfirst($linkType['method']);
+
+ $links = $this->package->{$getter}();
+ if (!empty($links)) {
+ $unwrapped = self::unwrapIfNeeded($root, $setter);
+ if ($root !== $unwrapped) {
+ $this->logger->warning(
+ 'This Composer version does not support ' .
+ "'{$type}' merging for aliased packages."
+ );
+ }
+ $unwrapped->{$setter}(array_merge(
+ $root->{$getter}(),
+ $this->replaceSelfVersionDependencies($type, $links, $root)
+ ));
+ }
+ }
+
+ /**
+ * Merge suggested packages into a RootPackageInterface
+ *
+ * @param RootPackageInterface $root
+ */
+ protected function mergeSuggests(RootPackageInterface $root)
+ {
+ $suggests = $this->package->getSuggests();
+ if (!empty($suggests)) {
+ $unwrapped = self::unwrapIfNeeded($root, 'setSuggests');
+ $unwrapped->setSuggests(array_merge(
+ $root->getSuggests(),
+ $suggests
+ ));
+ }
+ }
+
+ /**
+ * Merge extra config into a RootPackageInterface
+ *
+ * @param RootPackageInterface $root
+ * @param PluginState $state
+ */
+ public function mergeExtra(RootPackageInterface $root, PluginState $state)
+ {
+ $extra = $this->package->getExtra();
+ unset($extra['merge-plugin']);
+ if (!$state->shouldMergeExtra() || empty($extra)) {
+ return;
+ }
+
+ $rootExtra = $root->getExtra();
+ $unwrapped = self::unwrapIfNeeded($root, 'setExtra');
+
+ if ($state->replaceDuplicateLinks()) {
+ $unwrapped->setExtra(
+ array_merge($rootExtra, $extra)
+ );
+
+ } else {
+ foreach (array_intersect(
+ array_keys($extra),
+ array_keys($rootExtra)
+ ) as $key) {
+ $this->logger->info(
+ "Ignoring duplicate <comment>{$key}</comment> in ".
+ "<comment>{$this->path}</comment> extra config."
+ );
+ }
+ $unwrapped->setExtra(
+ array_merge($extra, $rootExtra)
+ );
+ }
+ }
+
+ /**
+ * Update Links with a 'self.version' constraint with the root package's
+ * version.
+ *
+ * @param string $type Link type
+ * @param array $links
+ * @param RootPackageInterface $root
+ * @return array
+ */
+ protected function replaceSelfVersionDependencies(
+ $type,
+ array $links,
+ RootPackageInterface $root
+ ) {
+ $linkType = BasePackage::$supportedLinkTypes[$type];
+ $version = $root->getVersion();
+ $prettyVersion = $root->getPrettyVersion();
+ $vp = new VersionParser();
+
+ return array_map(
+ function ($link) use ($linkType, $version, $prettyVersion, $vp) {
+ if ('self.version' === $link->getPrettyConstraint()) {
+ return new Link(
+ $link->getSource(),
+ $link->getTarget(),
+ $vp->parseConstraints($version),
+ $linkType['description'],
+ $prettyVersion
+ );
+ }
+ return $link;
+ },
+ $links
+ );
+ }
+
+ /**
+ * Get a full featured Package from a RootPackageInterface.
+ *
+ * In Composer versions before 599ad77 the RootPackageInterface only
+ * defines a sub-set of operations needed by composer-merge-plugin and
+ * RootAliasPackage only implemented those methods defined by the
+ * interface. Most of the unimplemented methods in RootAliasPackage can be
+ * worked around because the getter methods that are implemented proxy to
+ * the aliased package which we can modify by unwrapping. The exception
+ * being modifying the 'conflicts', 'provides' and 'replaces' collections.
+ * We have no way to actually modify those collections unfortunately in
+ * older versions of Composer.
+ *
+ * @param RootPackageInterface $root
+ * @param string $method Method needed
+ * @return RootPackageInterface|RootPackage
+ */
+ public static function unwrapIfNeeded(
+ RootPackageInterface $root,
+ $method = 'setExtra'
+ ) {
+ if ($root instanceof RootAliasPackage &&
+ !method_exists($root, $method)
+ ) {
+ // Unwrap and return the aliased RootPackage.
+ $root = $root->getAliasOf();
+ }
+ return $root;
+ }
+}
+// vim:sw=4:ts=4:sts=4:et:
diff --git a/vendor/wikimedia/composer-merge-plugin/src/Merge/MissingFileException.php b/vendor/wikimedia/composer-merge-plugin/src/Merge/MissingFileException.php
new file mode 100644
index 00000000..873719d7
--- /dev/null
+++ b/vendor/wikimedia/composer-merge-plugin/src/Merge/MissingFileException.php
@@ -0,0 +1,18 @@
+<?php
+/**
+ * This file is part of the Composer Merge plugin.
+ *
+ * Copyright (C) 2015 Bryan Davis, Wikimedia Foundation, and contributors
+ *
+ * This software may be modified and distributed under the terms of the MIT
+ * license. See the LICENSE file for details.
+ */
+
+namespace Wikimedia\Composer\Merge;
+
+/**
+ * @author Bryan Davis <bd808@bd808.com>
+ */
+class MissingFileException extends \RuntimeException
+{
+}
diff --git a/vendor/wikimedia/composer-merge-plugin/src/Merge/PluginState.php b/vendor/wikimedia/composer-merge-plugin/src/Merge/PluginState.php
new file mode 100644
index 00000000..a191c1e8
--- /dev/null
+++ b/vendor/wikimedia/composer-merge-plugin/src/Merge/PluginState.php
@@ -0,0 +1,327 @@
+<?php
+/**
+ * This file is part of the Composer Merge plugin.
+ *
+ * Copyright (C) 2015 Bryan Davis, Wikimedia Foundation, and contributors
+ *
+ * This software may be modified and distributed under the terms of the MIT
+ * license. See the LICENSE file for details.
+ */
+
+namespace Wikimedia\Composer\Merge;
+
+use Composer\Composer;
+
+/**
+ * Mutable plugin state
+ *
+ * @author Bryan Davis <bd808@bd808.com>
+ */
+class PluginState
+{
+ /**
+ * @var Composer $composer
+ */
+ protected $composer;
+
+ /**
+ * @var array $includes
+ */
+ protected $includes = array();
+
+ /**
+ * @var array $requires
+ */
+ protected $requires = array();
+
+ /**
+ * @var array $duplicateLinks
+ */
+ protected $duplicateLinks = array();
+
+ /**
+ * @var bool $devMode
+ */
+ protected $devMode = false;
+
+ /**
+ * @var bool $recurse
+ */
+ protected $recurse = true;
+
+ /**
+ * @var bool $replace
+ */
+ protected $replace = false;
+
+ /**
+ * Whether to merge the -dev sections.
+ * @var bool $mergeDev
+ */
+ protected $mergeDev = true;
+
+ /**
+ * Whether to merge the extra section.
+ *
+ * By default, the extra section is not merged and there will be many
+ * cases where the merge of the extra section is performed too late
+ * to be of use to other plugins. When enabled, merging uses one of
+ * two strategies - either 'first wins' or 'last wins'. When enabled,
+ * 'first wins' is the default behaviour. If Replace mode is activated
+ * then 'last wins' is used.
+ *
+ * @var bool $mergeExtra
+ */
+ protected $mergeExtra = false;
+
+ /**
+ * @var bool $firstInstall
+ */
+ protected $firstInstall = false;
+
+ /**
+ * @var bool $locked
+ */
+ protected $locked = false;
+
+ /**
+ * @var bool $dumpAutoloader
+ */
+ protected $dumpAutoloader = false;
+
+ /**
+ * @var bool $optimizeAutoloader
+ */
+ protected $optimizeAutoloader = false;
+
+ /**
+ * @param Composer $composer
+ */
+ public function __construct(Composer $composer)
+ {
+ $this->composer = $composer;
+ }
+
+ /**
+ * Load plugin settings
+ */
+ public function loadSettings()
+ {
+ $extra = $this->composer->getPackage()->getExtra();
+ $config = array_merge(
+ array(
+ 'include' => array(),
+ 'require' => array(),
+ 'recurse' => true,
+ 'replace' => false,
+ 'merge-dev' => true,
+ 'merge-extra' => false,
+ ),
+ isset($extra['merge-plugin']) ? $extra['merge-plugin'] : array()
+ );
+
+ $this->includes = (is_array($config['include'])) ?
+ $config['include'] : array($config['include']);
+ $this->requires = (is_array($config['require'])) ?
+ $config['require'] : array($config['require']);
+ $this->recurse = (bool)$config['recurse'];
+ $this->replace = (bool)$config['replace'];
+ $this->mergeDev = (bool)$config['merge-dev'];
+ $this->mergeExtra = (bool)$config['merge-extra'];
+ }
+
+ /**
+ * Get list of filenames and/or glob patterns to include
+ *
+ * @return array
+ */
+ public function getIncludes()
+ {
+ return $this->includes;
+ }
+
+ /**
+ * Get list of filenames and/or glob patterns to require
+ *
+ * @return array
+ */
+ public function getRequires()
+ {
+ return $this->requires;
+ }
+
+ /**
+ * Set the first install flag
+ *
+ * @param bool $flag
+ */
+ public function setFirstInstall($flag)
+ {
+ $this->firstInstall = (bool)$flag;
+ }
+
+ /**
+ * Is this the first time that the plugin has been installed?
+ *
+ * @return bool
+ */
+ public function isFirstInstall()
+ {
+ return $this->firstInstall;
+ }
+
+ /**
+ * Set the locked flag
+ *
+ * @param bool $flag
+ */
+ public function setLocked($flag)
+ {
+ $this->locked = (bool)$flag;
+ }
+
+ /**
+ * Was a lockfile present when the plugin was installed?
+ *
+ * @return bool
+ */
+ public function isLocked()
+ {
+ return $this->locked;
+ }
+
+ /**
+ * Should an update be forced?
+ *
+ * @return true If packages are not locked
+ */
+ public function forceUpdate()
+ {
+ return !$this->locked;
+ }
+
+ /**
+ * Set the devMode flag
+ *
+ * @param bool $flag
+ */
+ public function setDevMode($flag)
+ {
+ $this->devMode = (bool)$flag;
+ }
+
+ /**
+ * Should devMode settings be processed?
+ *
+ * @return bool
+ */
+ public function isDevMode()
+ {
+ return $this->mergeDev && $this->devMode;
+ }
+
+ /**
+ * Set the dumpAutoloader flag
+ *
+ * @param bool $flag
+ */
+ public function setDumpAutoloader($flag)
+ {
+ $this->dumpAutoloader = (bool)$flag;
+ }
+
+ /**
+ * Is the autoloader file supposed to be written out?
+ *
+ * @return bool
+ */
+ public function shouldDumpAutoloader()
+ {
+ return $this->dumpAutoloader;
+ }
+
+ /**
+ * Set the optimizeAutoloader flag
+ *
+ * @param bool $flag
+ */
+ public function setOptimizeAutoloader($flag)
+ {
+ $this->optimizeAutoloader = (bool)$flag;
+ }
+
+ /**
+ * Should the autoloader be optimized?
+ *
+ * @return bool
+ */
+ public function shouldOptimizeAutoloader()
+ {
+ return $this->optimizeAutoloader;
+ }
+
+ /**
+ * Add duplicate packages
+ *
+ * @param string $type Package type
+ * @param array $packages
+ */
+ public function addDuplicateLinks($type, array $packages)
+ {
+ if (!isset($this->duplicateLinks[$type])) {
+ $this->duplicateLinks[$type] = array();
+ }
+ $this->duplicateLinks[$type] =
+ array_merge($this->duplicateLinks[$type], $packages);
+ }
+
+ /**
+ * Get duplicate packages
+ *
+ * @param string $type Package type
+ * @return array
+ */
+ public function getDuplicateLinks($type)
+ {
+ return isset($this->duplicateLinks[$type]) ?
+ $this->duplicateLinks[$type] : array();
+ }
+
+ /**
+ * Should includes be recursively processed?
+ *
+ * @return bool
+ */
+ public function recurseIncludes()
+ {
+ return $this->recurse;
+ }
+
+ /**
+ * Should duplicate links be replaced in a 'last definition wins' order?
+ *
+ * @return bool
+ */
+ public function replaceDuplicateLinks()
+ {
+ return $this->replace;
+ }
+
+ /**
+ * Should the extra section be merged?
+ *
+ * By default, the extra section is not merged and there will be many
+ * cases where the merge of the extra section is performed too late
+ * to be of use to other plugins. When enabled, merging uses one of
+ * two strategies - either 'first wins' or 'last wins'. When enabled,
+ * 'first wins' is the default behaviour. If Replace mode is activated
+ * then 'last wins' is used.
+ *
+ * @return bool
+ */
+ public function shouldMergeExtra()
+ {
+ return $this->mergeExtra;
+ }
+}
+// vim:sw=4:ts=4:sts=4:et:
diff --git a/vendor/wikimedia/composer-merge-plugin/src/Merge/StabilityFlags.php b/vendor/wikimedia/composer-merge-plugin/src/Merge/StabilityFlags.php
new file mode 100644
index 00000000..1c106e02
--- /dev/null
+++ b/vendor/wikimedia/composer-merge-plugin/src/Merge/StabilityFlags.php
@@ -0,0 +1,181 @@
+<?php
+/**
+ * This file is part of the Composer Merge plugin.
+ *
+ * Copyright (C) 2015 Bryan Davis, Wikimedia Foundation, and contributors
+ *
+ * This software may be modified and distributed under the terms of the MIT
+ * license. See the LICENSE file for details.
+ */
+
+namespace Wikimedia\Composer\Merge;
+
+use Composer\Package\BasePackage;
+use Composer\Package\Version\VersionParser;
+
+/**
+ * Adapted from Composer's RootPackageLoader::extractStabilityFlags
+ * @author Bryan Davis <bd808@bd808.com>
+ */
+class StabilityFlags
+{
+
+ /**
+ * @var array Current package name => stability mappings
+ */
+ protected $stabilityFlags;
+
+ /**
+ * @var int Current default minimum stability
+ */
+ protected $minimumStability;
+
+ /**
+ * @var string Regex to extract an explict stability flag (eg '@dev')
+ */
+ protected $explicitStabilityRe;
+
+
+ /**
+ * @param array $stabilityFlags Current package name => stability mappings
+ * @param int $minimumStability Current default minimum stability
+ */
+ public function __construct(
+ array $stabilityFlags = array(),
+ $minimumStability = BasePackage::STABILITY_STABLE
+ ) {
+ $this->stabilityFlags = $stabilityFlags;
+ $this->minimumStability = $this->getStabilityInt($minimumStability);
+ $this->explicitStabilityRe = '/^[^@]*?@(' .
+ implode('|', array_keys(BasePackage::$stabilities)) .
+ ')$/i';
+ }
+
+ /**
+ * Get the stability value for a given string.
+ *
+ * @param string $name Stability name
+ * @return int Stability value
+ */
+ protected function getStabilityInt($name)
+ {
+ $name = VersionParser::normalizeStability($name);
+ return isset(BasePackage::$stabilities[$name]) ?
+ BasePackage::$stabilities[$name] :
+ BasePackage::STABILITY_STABLE;
+ }
+
+ /**
+ * Extract and merge stability flags from the given collection of
+ * requires with another collection of stability flags.
+ *
+ * @param array $requires New package name => link mappings
+ * @return array Unified package name => stability mappings
+ */
+ public function extractAll(array $requires)
+ {
+ $flags = array();
+
+ foreach ($requires as $name => $link) {
+ $name = strtolower($name);
+ $version = $link->getPrettyConstraint();
+
+ $stability = $this->getExplicitStability($version);
+
+ if ($stability === null) {
+ $stability = $this->getParsedStability($version);
+ }
+
+ $flags[$name] = max($stability, $this->getCurrentStability($name));
+ }
+
+ // Filter out null stability values
+ return array_filter($flags, function ($v) {
+ return $v !== null;
+ });
+ }
+
+
+ /**
+ * Extract the most unstable explicit stability (eg '@dev') from a version
+ * specification.
+ *
+ * @param string $version
+ * @return int|null Stability or null if no explict stability found
+ */
+ protected function getExplicitStability($version)
+ {
+ $found = null;
+ $constraints = $this->splitConstraints($version);
+ foreach ($constraints as $constraint) {
+ if (preg_match($this->explicitStabilityRe, $constraint, $match)) {
+ $stability = $this->getStabilityInt($match[1]);
+ $found = max($stability, $found);
+ }
+ }
+ return $found;
+ }
+
+
+ /**
+ * Split a version specification into a list of version constraints.
+ *
+ * @param string $version
+ * @return array
+ */
+ protected function splitConstraints($version)
+ {
+ $found = array();
+ $orConstraints = preg_split('/\s*\|\|?\s*/', trim($version));
+ foreach ($orConstraints as $constraints) {
+ $andConstraints = preg_split(
+ '/(?<!^|as|[=>< ,]) *(?<!-)[, ](?!-) *(?!,|as|$)/',
+ $constraints
+ );
+ foreach ($andConstraints as $constraint) {
+ $found[] = $constraint;
+ }
+ }
+ return $found;
+ }
+
+
+ /**
+ * Get the stability of a version
+ *
+ * @param string $version
+ * @return int|null Stability or null if STABLE or less than minimum
+ */
+ protected function getParsedStability($version)
+ {
+ // Drop aliasing if used
+ $version = preg_replace('/^([^,\s@]+) as .+$/', '$1', $version);
+ $stability = $this->getStabilityInt(
+ VersionParser::parseStability($version)
+ );
+
+ if ($stability === BasePackage::STABILITY_STABLE ||
+ $this->minimumStability > $stability
+ ) {
+ // Ignore if 'stable' or more stable than the global
+ // minimum
+ $stability = null;
+ }
+
+ return $stability;
+ }
+
+
+ /**
+ * Get the current stability of a given package.
+ *
+ * @param string $name
+ * @return int|null Stability of null if not set
+ */
+ protected function getCurrentStability($name)
+ {
+ return isset($this->stabilityFlags[$name]) ?
+ $this->stabilityFlags[$name] : null;
+ }
+}
+// vim:sw=4:ts=4:sts=4:et:
diff --git a/vendor/wikimedia/composer-merge-plugin/src/MergePlugin.php b/vendor/wikimedia/composer-merge-plugin/src/MergePlugin.php
index 04c55886..ea41d41a 100644
--- a/vendor/wikimedia/composer-merge-plugin/src/MergePlugin.php
+++ b/vendor/wikimedia/composer-merge-plugin/src/MergePlugin.php
@@ -2,7 +2,7 @@
/**
* This file is part of the Composer Merge plugin.
*
- * Copyright (C) 2014 Bryan Davis, Wikimedia Foundation, and contributors
+ * Copyright (C) 2015 Bryan Davis, Wikimedia Foundation, and contributors
*
* This software may be modified and distributed under the terms of the MIT
* license. See the LICENSE file for details.
@@ -10,39 +10,56 @@
namespace Wikimedia\Composer;
+use Wikimedia\Composer\Merge\ExtraPackage;
+use Wikimedia\Composer\Merge\MissingFileException;
+use Wikimedia\Composer\Merge\PluginState;
+
use Composer\Composer;
-use Composer\Config;
+use Composer\DependencyResolver\Operation\InstallOperation;
use Composer\EventDispatcher\EventSubscriberInterface;
+use Composer\Factory;
+use Composer\Installer;
use Composer\Installer\InstallerEvent;
use Composer\Installer\InstallerEvents;
+use Composer\Installer\PackageEvent;
+use Composer\Installer\PackageEvents;
use Composer\IO\IOInterface;
-use Composer\Json\JsonFile;
-use Composer\Package\BasePackage;
-use Composer\Package\CompletePackage;
-use Composer\Package\Loader\ArrayLoader;
use Composer\Package\RootPackageInterface;
-use Composer\Package\Version\VersionParser;
use Composer\Plugin\PluginInterface;
-use Composer\Script\CommandEvent;
+use Composer\Script\Event;
use Composer\Script\ScriptEvents;
/**
* Composer plugin that allows merging multiple composer.json files.
*
- * When installed, this plugin will look for a "merge-patterns" key in the
- * composer configuration's "extra" section. The value of this setting can be
- * either a single value or an array of values. Each value is treated as
- * a glob() pattern identifying additional composer.json style configuration
- * files to merge into the configuration for the current compser execution.
+ * When installed, this plugin will look for a "merge-plugin" key in the
+ * composer configuration's "extra" section. The value for this key is
+ * a set of options configuring the plugin.
+ *
+ * An "include" setting is required. The value of this setting can be either
+ * a single value or an array of values. Each value is treated as a glob()
+ * pattern identifying additional composer.json style configuration files to
+ * merge into the configuration for the current compser execution.
*
- * The "require", "require-dev", "repositories" and "suggest" sections of the
+ * The "autoload", "autoload-dev", "conflict", "provide", "replace",
+ * "repositories", "require", "require-dev", and "suggest" sections of the
* found configuration files will be merged into the root package
* configuration as though they were directly included in the top-level
* composer.json file.
*
* If included files specify conflicting package versions for "require" or
* "require-dev", the normal Composer dependency solver process will be used
- * to attempt to resolve the conflict.
+ * to attempt to resolve the conflict. Specifying the 'replace' key as true will
+ * change this default behaviour so that the last-defined version of a package
+ * will win, allowing for force-overrides of package defines.
+ *
+ * By default the "extra" section is not merged. This can be enabled by
+ * setitng the 'merge-extra' key to true. In normal mode, when the same key is
+ * found in both the original and the imported extra section, the version in
+ * the original config is used and the imported version is skipped. If
+ * 'replace' mode is active, this behaviour changes so the imported version of
+ * the key is used, replacing the version in the original config.
+ *
*
* @code
* {
@@ -65,36 +82,24 @@ class MergePlugin implements PluginInterface, EventSubscriberInterface
{
/**
- * @var Composer $composer
+ * Offical package name
*/
- protected $composer;
+ const PACKAGE_NAME = 'wikimedia/composer-merge-plugin';
/**
- * @var IOInterface $inputOutput
- */
- protected $inputOutput;
-
- /**
- * @var ArrayLoader $loader
- */
- protected $loader;
-
- /**
- * @var array $duplicateLinks
+ * @var Composer $composer
*/
- protected $duplicateLinks;
+ protected $composer;
/**
- * @var bool $devMode
+ * @var PluginState $state
*/
- protected $devMode;
+ protected $state;
/**
- * Whether to recursively include dependencies
- *
- * @var bool $recurse
+ * @var Logger $logger
*/
- protected $recurse = true;
+ protected $logger;
/**
* Files that have already been processed
@@ -109,7 +114,8 @@ class MergePlugin implements PluginInterface, EventSubscriberInterface
public function activate(Composer $composer, IOInterface $io)
{
$this->composer = $composer;
- $this->inputOutput = $io;
+ $this->state = new PluginState($this->composer);
+ $this->logger = new Logger('merge-plugin', $io);
}
/**
@@ -119,69 +125,66 @@ class MergePlugin implements PluginInterface, EventSubscriberInterface
{
return array(
InstallerEvents::PRE_DEPENDENCIES_SOLVING => 'onDependencySolve',
- ScriptEvents::PRE_INSTALL_CMD => 'onInstallOrUpdate',
- ScriptEvents::PRE_UPDATE_CMD => 'onInstallOrUpdate',
+ PackageEvents::POST_PACKAGE_INSTALL => 'onPostPackageInstall',
+ ScriptEvents::POST_INSTALL_CMD => 'onPostInstallOrUpdate',
+ ScriptEvents::POST_UPDATE_CMD => 'onPostInstallOrUpdate',
+ ScriptEvents::PRE_AUTOLOAD_DUMP => 'onInstallUpdateOrDump',
+ ScriptEvents::PRE_INSTALL_CMD => 'onInstallUpdateOrDump',
+ ScriptEvents::PRE_UPDATE_CMD => 'onInstallUpdateOrDump',
);
}
/**
- * Handle an event callback for an install or update command by checking
- * for "merge-patterns" in the "extra" data and merging package contents
- * if found.
+ * Handle an event callback for an install, update or dump command by
+ * checking for "merge-plugin" in the "extra" data and merging package
+ * contents if found.
*
- * @param CommandEvent $event
+ * @param Event $event
*/
- public function onInstallOrUpdate(CommandEvent $event)
+ public function onInstallUpdateOrDump(Event $event)
{
- $config = $this->readConfig($this->composer->getPackage());
- if (isset($config['recurse'])) {
- $this->recurse = (bool)$config['recurse'];
- }
- if ($config['include']) {
- $this->loader = new ArrayLoader();
- $this->duplicateLinks = array(
- 'require' => array(),
- 'require-dev' => array(),
- );
- $this->devMode = $event->isDevMode();
- $this->mergePackages($config);
- }
- }
-
- /**
- * @param RootPackageInterface $package
- * @return array
- */
- protected function readConfig(RootPackageInterface $package)
- {
- $config = array(
- 'include' => array(),
- );
- $extra = $package->getExtra();
- if (isset($extra['merge-plugin'])) {
- $config = array_merge($config, $extra['merge-plugin']);
- if (!is_array($config['include'])) {
- $config['include'] = array($config['include']);
+ $this->state->loadSettings();
+ $this->state->setDevMode($event->isDevMode());
+ $this->mergeFiles($this->state->getIncludes(), false);
+ $this->mergeFiles($this->state->getRequires(), true);
+
+ if ($event->getName() === ScriptEvents::PRE_AUTOLOAD_DUMP) {
+ $this->state->setDumpAutoloader(true);
+ $flags = $event->getFlags();
+ if (isset($flags['optimize'])) {
+ $this->state->setOptimizeAutoloader($flags['optimize']);
}
}
- return $config;
}
/**
* Find configuration files matching the configured glob patterns and
* merge their contents with the master package.
*
- * @param array $config
+ * @param array $patterns List of files/glob patterns
+ * @param bool $required Are the patterns required to match files?
+ * @throws MissingFileException when required and a pattern returns no
+ * results
*/
- protected function mergePackages(array $config)
+ protected function mergeFiles(array $patterns, $required = false)
{
$root = $this->composer->getPackage();
- foreach (array_reduce(
- array_map('glob', $config['include']),
- 'array_merge',
- array()
- ) as $path) {
- $this->loadFile($root, $path);
+
+ $files = array_map(
+ function ($files, $pattern) use ($required) {
+ if ($required && !$files) {
+ throw new MissingFileException(
+ "merge-plugin: No files matched required '{$pattern}'"
+ );
+ }
+ return $files;
+ },
+ array_map('glob', $patterns),
+ $patterns
+ );
+
+ foreach (array_reduce($files, 'array_merge', array()) as $path) {
+ $this->mergeFile($root, $path);
}
}
@@ -191,221 +194,121 @@ class MergePlugin implements PluginInterface, EventSubscriberInterface
* @param RootPackageInterface $root
* @param string $path
*/
- protected function loadFile($root, $path)
+ protected function mergeFile(RootPackageInterface $root, $path)
{
- if (in_array($path, $this->loadedFiles)) {
- $this->debug("Skipping duplicate <comment>$path</comment>...");
+ if (isset($this->loadedFiles[$path])) {
+ $this->logger->debug("Already merged <comment>$path</comment>");
return;
} else {
- $this->loadedFiles[] = $path;
+ $this->loadedFiles[$path] = true;
}
- $this->debug("Loading <comment>{$path}</comment>...");
- $json = $this->readPackageJson($path);
- $package = $this->loader->load($json);
-
- $this->mergeRequires($root, $package);
- $this->mergeDevRequires($root, $package);
+ $this->logger->info("Loading <comment>{$path}</comment>...");
- if (isset($json['repositories'])) {
- $this->addRepositories($json['repositories'], $root);
- }
+ $package = new ExtraPackage($path, $this->composer, $this->logger);
+ $package->mergeInto($root, $this->state);
- if ($package->getSuggests()) {
- $root->setSuggests(array_merge(
- $root->getSuggests(),
- $package->getSuggests()
- ));
- }
-
- if ($this->recurse && isset($json['extra']['merge-plugin'])) {
- $this->mergePackages($json['extra']['merge-plugin']);
+ if ($this->state->recurseIncludes()) {
+ $this->mergeFiles($package->getIncludes(), false);
+ $this->mergeFiles($package->getRequires(), true);
}
}
/**
- * Read the contents of a composer.json style file into an array.
- *
- * The package contents are fixed up to be usable to create a Package
- * object by providing dummy "name" and "version" values if they have not
- * been provided in the file. This is consistent with the default root
- * package loading behavior of Composer.
+ * Handle an event callback for pre-dependency solving phase of an install
+ * or update by adding any duplicate package dependencies found during
+ * initial merge processing to the request that will be processed by the
+ * dependency solver.
*
- * @param string $path
- * @return array
+ * @param InstallerEvent $event
*/
- protected function readPackageJson($path)
+ public function onDependencySolve(InstallerEvent $event)
{
- $file = new JsonFile($path);
- $json = $file->read();
- if (!isset($json['name'])) {
- $json['name'] = 'merge-plugin/' .
- strtr($path, DIRECTORY_SEPARATOR, '-');
- }
- if (!isset($json['version'])) {
- $json['version'] = '1.0.0';
- }
- return $json;
- }
-
- /**
- * @param RootPackageInterface $root
- * @param CompletePackage $package
- */
- protected function mergeRequires(
- RootPackageInterface $root,
- CompletePackage $package
- ) {
- $requires = $package->getRequires();
- if (!$requires) {
- return;
+ $request = $event->getRequest();
+ foreach ($this->state->getDuplicateLinks('require') as $link) {
+ $this->logger->info(
+ "Adding dependency <comment>{$link}</comment>"
+ );
+ $request->install($link->getTarget(), $link->getConstraint());
}
-
- $this->mergeStabilityFlags($root, $requires);
-
- $root->setRequires($this->mergeLinks(
- $root->getRequires(),
- $requires,
- $this->duplicateLinks['require']
- ));
- }
-
- /**
- * @param RootPackageInterface $root
- * @param CompletePackage $package
- */
- protected function mergeDevRequires(
- RootPackageInterface $root,
- CompletePackage $package
- ) {
- $requires = $package->getDevRequires();
- if (!$requires) {
- return;
+ if ($this->state->isDevMode()) {
+ foreach ($this->state->getDuplicateLinks('require-dev') as $link) {
+ $this->logger->info(
+ "Adding dev dependency <comment>{$link}</comment>"
+ );
+ $request->install($link->getTarget(), $link->getConstraint());
+ }
}
-
- $this->mergeStabilityFlags($root, $requires);
-
- $root->setDevRequires($this->mergeLinks(
- $root->getDevRequires(),
- $requires,
- $this->duplicateLinks['require-dev']
- ));
}
/**
- * Extract and merge stability flags from the given collection of
- * requires.
+ * Handle an event callback following installation of a new package by
+ * checking to see if the package that was installed was our plugin.
*
- * @param RootPackageInterface $root
- * @param array $requires
+ * @param PackageEvent $event
*/
- protected function mergeStabilityFlags(
- RootPackageInterface $root,
- array $requires
- ) {
- $flags = $root->getStabilityFlags();
- foreach ($requires as $name => $link) {
- $name = strtolower($name);
- $version = $link->getPrettyConstraint();
- $stability = VersionParser::parseStability($version);
- $flags[$name] = BasePackage::$stabilities[$stability];
+ public function onPostPackageInstall(PackageEvent $event)
+ {
+ $op = $event->getOperation();
+ if ($op instanceof InstallOperation) {
+ $package = $op->getPackage()->getName();
+ if ($package === self::PACKAGE_NAME) {
+ $this->logger->info('composer-merge-plugin installed');
+ $this->state->setFirstInstall(true);
+ $this->state->setLocked(
+ $event->getComposer()->getLocker()->isLocked()
+ );
+ }
}
- $root->setStabilityFlags($flags);
}
/**
- * Add a collection of repositories described by the given configuration
- * to the given package and the global repository manager.
+ * Handle an event callback following an install or update command. If our
+ * plugin was installed during the run then trigger an update command to
+ * process any merge-patterns in the current config.
*
- * @param array $repositories
- * @param RootPackageInterface $root
+ * @param Event $event
*/
- protected function addRepositories(
- array $repositories,
- RootPackageInterface $root
- ) {
- $repoManager = $this->composer->getRepositoryManager();
- $newRepos = array();
-
- foreach ($repositories as $repoJson) {
- $this->debug("Adding {$repoJson['type']} repository");
- $repo = $repoManager->createRepository(
- $repoJson['type'],
- $repoJson
+ public function onPostInstallOrUpdate(Event $event)
+ {
+ // @codeCoverageIgnoreStart
+ if ($this->state->isFirstInstall()) {
+ $this->state->setFirstInstall(false);
+ $this->logger->info(
+ '<comment>' .
+ 'Running additional update to apply merge settings' .
+ '</comment>'
);
- $repoManager->addRepository($repo);
- $newRepos[] = $repo;
- }
- $root->setRepositories(array_merge(
- $newRepos,
- $root->getRepositories()
- ));
- }
+ $config = $this->composer->getConfig();
- /**
- * Merge two collections of package links and collect duplicates for
- * subsequent processing.
- *
- * @param array $origin Primary collection
- * @param array $merge Additional collection
- * @param array &dups Duplicate storage
- * @return array Merged collection
- */
- protected function mergeLinks(array $origin, array $merge, array &$dups)
- {
- foreach ($merge as $name => $link) {
- if (!isset($origin[$name])) {
- $this->debug("Merging <comment>{$name}</comment>");
- $origin[$name] = $link;
- } else {
- // Defer to solver.
- $this->debug("Deferring duplicate <comment>{$name}</comment>");
- $dups[] = $link;
- }
- }
- return $origin;
- }
+ $preferSource = $config->get('preferred-install') == 'source';
+ $preferDist = $config->get('preferred-install') == 'dist';
- /**
- * Handle an event callback for pre-dependency solving phase of an install
- * or update by adding any duplicate package dependencies found during
- * initial merge processing to the request that will be processed by the
- * dependency solver.
- *
- * @param InstallerEvent $event
- */
- public function onDependencySolve(InstallerEvent $event)
- {
- if (!$this->duplicateLinks) {
- return;
- }
+ $installer = Installer::create(
+ $event->getIO(),
+ // Create a new Composer instance to ensure full processing of
+ // the merged files.
+ Factory::create($event->getIO(), null, false)
+ );
- $request = $event->getRequest();
- foreach ($this->duplicateLinks['require'] as $link) {
- $this->debug("Adding dependency <comment>{$link}</comment>");
- $request->install($link->getTarget(), $link->getConstraint());
- }
- if ($this->devMode) {
- foreach ($this->duplicateLinks['require-dev'] as $link) {
- $this->debug("Adding dev dependency <comment>{$link}</comment>");
- $request->install($link->getTarget(), $link->getConstraint());
+ $installer->setPreferSource($preferSource);
+ $installer->setPreferDist($preferDist);
+ $installer->setDevMode($event->isDevMode());
+ $installer->setDumpAutoloader($this->state->shouldDumpAutoloader());
+ $installer->setOptimizeAutoloader(
+ $this->state->shouldOptimizeAutoloader()
+ );
+
+ if ($this->state->forceUpdate()) {
+ // Force update mode so that new packages are processed rather
+ // than just telling the user that composer.json and
+ // composer.lock don't match.
+ $installer->setUpdate(true);
}
- }
- }
- /**
- * Log a debug message
- *
- * Messages will be output at the "verbose" logging level (eg `-v` needed
- * on the Composer command).
- *
- * @param string $message
- */
- protected function debug($message)
- {
- if ($this->inputOutput->isVerbose()) {
- $this->inputOutput->write(" <info>[merge]</info> {$message}");
+ $installer->run();
}
+ // @codeCoverageIgnoreEnd
}
}
// vim:sw=4:ts=4:sts=4:et:
diff --git a/vendor/wikimedia/ip-set/COPYING b/vendor/wikimedia/ip-set/COPYING
new file mode 100644
index 00000000..d159169d
--- /dev/null
+++ b/vendor/wikimedia/ip-set/COPYING
@@ -0,0 +1,339 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Lesser General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) year name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.
diff --git a/vendor/wikimedia/ip-set/README.md b/vendor/wikimedia/ip-set/README.md
new file mode 100644
index 00000000..480e1678
--- /dev/null
+++ b/vendor/wikimedia/ip-set/README.md
@@ -0,0 +1,83 @@
+IPSet
+=====
+
+IPSet is a PHP library for matching IP addresses against a set of CIDR
+specifications.
+
+Here is how you use it:
+
+<pre lang="php">
+// At startup, calculate the optimized data structure for the set:
+$ipset = new IPSet( array(
+ '208.80.154.0/26',
+ '2620:0:861:1::/64',
+ '10.64.0.0/22',
+) );
+
+// Runtime check against cached set (returns bool):
+if ( $ipset->match( $ip ) ) {
+ // ...
+}
+</pre>
+
+In rough benchmarking, this takes about 80% more time than `in_array()` checks
+on a short (a couple hundred at most) array of addresses. It's fast either way
+at those levels, though, and IPSet would scale better than in_array if the
+array were much larger.
+
+For mixed-family CIDR sets, however, this code gives well over 100x speedup vs
+iterating `IP::isInRange()` over an array of CIDR specs.
+
+The basic implementation is two separate binary trees (IPv4 and IPv6) as nested
+php arrays with keys named 0 and 1. The values false and true are terminal
+match-fail and match-success, otherwise the value is a deeper node in the tree.
+
+A simple depth-compression scheme is also implemented: whole-byte tree
+compression at whole-byte boundaries only, where no branching occurs during
+that whole byte of depth. A compressed node has keys 'comp' (the byte to
+compare) and 'next' (the next node to recurse into if 'comp' matched successfully).
+
+For example, given these inputs:
+
+<pre>
+25.0.0.0/9
+25.192.0.0/10
+</pre>
+
+The v4 tree would look like:
+
+<pre lang="php">
+root4 => array(
+ 'comp' => 25,
+ 'next' => array(
+ 0 => true,
+ 1 => array(
+ 0 => false,
+ 1 => true,
+ ),
+ ),
+);
+</pre>
+
+(multi-byte compression nodes were attempted as well, but were
+a net loss in my test scenarios due to additional match complexity)
+
+
+License
+-------
+Copyright 2014, 2015 Brandon Black <blblack@gmail.com>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along
+with this program; if not, write to the Free Software Foundation, Inc.,
+51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+<http://www.gnu.org/copyleft/gpl.html>
diff --git a/vendor/wikimedia/ip-set/src/IPSet.php b/vendor/wikimedia/ip-set/src/IPSet.php
new file mode 100644
index 00000000..1c79f067
--- /dev/null
+++ b/vendor/wikimedia/ip-set/src/IPSet.php
@@ -0,0 +1,284 @@
+<?php
+/**
+ * Copyright 2014, 2015 Brandon Black <blblack@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ * @author Brandon Black <blblack@gmail.com>
+ */
+namespace IPSet;
+
+/**
+ * Matches IP addresses against a set of CIDR specifications
+ *
+ * Usage:
+ *
+ * // At startup, calculate the optimized data structure for the set:
+ * $ipset = new IPSet( array(
+ * '208.80.154.0/26',
+ * '2620:0:861:1::/64',
+ * '10.64.0.0/22',
+ * ) );
+ *
+ * // Runtime check against cached set (returns bool):
+ * $allowme = $ipset->match( $ip );
+ *
+ * In rough benchmarking, this takes about 80% more time than
+ * in_array() checks on a short (a couple hundred at most) array
+ * of addresses. It's fast either way at those levels, though,
+ * and IPSet would scale better than in_array if the array were
+ * much larger.
+ *
+ * For mixed-family CIDR sets, however, this code gives well over
+ * 100x speedup vs iterating IP::isInRange() over an array
+ * of CIDR specs.
+ *
+ * The basic implementation is two separate binary trees
+ * (IPv4 and IPv6) as nested php arrays with keys named 0 and 1.
+ * The values false and true are terminal match-fail and match-success,
+ * otherwise the value is a deeper node in the tree.
+ *
+ * A simple depth-compression scheme is also implemented: whole-byte
+ * tree compression at whole-byte boundaries only, where no branching
+ * occurs during that whole byte of depth. A compressed node has
+ * keys 'comp' (the byte to compare) and 'next' (the next node to
+ * recurse into if 'comp' matched successfully).
+ *
+ * For example, given these inputs:
+ *
+ * 25.0.0.0/9
+ * 25.192.0.0/10
+ *
+ * The v4 tree would look like:
+ *
+ * root4 => array(
+ * 'comp' => 25,
+ * 'next' => array(
+ * 0 => true,
+ * 1 => array(
+ * 0 => false,
+ * 1 => true,
+ * ),
+ * ),
+ * );
+ *
+ * (multi-byte compression nodes were attempted as well, but were
+ * a net loss in my test scenarios due to additional match complexity)
+ */
+class IPSet {
+ /** @var array $root4 The root of the IPv4 matching tree */
+ private $root4 = array( false, false );
+
+ /** @var array $root6 The root of the IPv6 matching tree */
+ private $root6 = array( false, false );
+
+ /**
+ * Instantiate the object from an array of CIDR specs
+ *
+ * Invalid input network/mask values in $cfg will result in issuing
+ * E_WARNING and/or E_USER_WARNING and the bad values being ignored.
+ *
+ * @param array $cfg Array of IPv[46] CIDR specs as strings
+ */
+ public function __construct( array $cfg ) {
+ foreach ( $cfg as $cidr ) {
+ $this->addCidr( $cidr );
+ }
+
+ self::recOptimize( $this->root4 );
+ self::recCompress( $this->root4, 0, 24 );
+ self::recOptimize( $this->root6 );
+ self::recCompress( $this->root6, 0, 120 );
+ }
+
+ /**
+ * Add a single CIDR spec to the internal matching trees
+ *
+ * @param string $cidr String CIDR spec, IPv[46], optional /mask (def all-1's)
+ */
+ private function addCidr( $cidr ) {
+ // v4 or v6 check
+ if ( strpos( $cidr, ':' ) === false ) {
+ $node =& $this->root4;
+ $defMask = '32';
+ } else {
+ $node =& $this->root6;
+ $defMask = '128';
+ }
+
+ // Default to all-1's mask if no netmask in the input
+ if ( strpos( $cidr, '/' ) === false ) {
+ $net = $cidr;
+ $mask = $defMask;
+ } else {
+ list( $net, $mask ) = explode( '/', $cidr, 2 );
+ if ( !ctype_digit( $mask ) || intval( $mask ) > $defMask ) {
+ trigger_error( "IPSet: Bad mask '$mask' from '$cidr', ignored", E_USER_WARNING );
+ return;
+ }
+ }
+ $mask = intval( $mask ); // explicit integer convert, checked above
+
+ // convert $net to an array of integer bytes, length 4 or 16:
+ $raw = inet_pton( $net );
+ if ( $raw === false ) {
+ return; // inet_pton() sends an E_WARNING for us
+ }
+ $rawOrd = array_map( 'ord', str_split( $raw ) );
+
+ // special-case: zero mask overwrites the whole tree with a pair of terminal successes
+ if ( $mask == 0 ) {
+ $node = array( true, true );
+ return;
+ }
+
+ // iterate the bits of the address while walking the tree structure for inserts
+ $curBit = 0;
+ while ( 1 ) {
+ $maskShift = 7 - ( $curBit & 7 );
+ $node =& $node[( $rawOrd[$curBit >> 3] & ( 1 << $maskShift ) ) >> $maskShift];
+ ++$curBit;
+ if ( $node === true ) {
+ // already added a larger supernet, no need to go deeper
+ return;
+ } elseif ( $curBit == $mask ) {
+ // this may wipe out deeper subnets from earlier
+ $node = true;
+ return;
+ } elseif ( $node === false ) {
+ // create new subarray to go deeper
+ $node = array( false, false );
+ }
+ }
+ }
+
+ /**
+ * Match an IP address against the set
+ *
+ * If $ip is unparseable, inet_pton may issue an E_WARNING to that effect
+ *
+ * @param string $ip string IPv[46] address
+ * @return bool True is match success, false is match failure
+ */
+ public function match( $ip ) {
+ $raw = inet_pton( $ip );
+ if ( $raw === false ) {
+ return false; // inet_pton() sends an E_WARNING for us
+ }
+
+ $rawOrd = array_map( 'ord', str_split( $raw ) );
+ if ( count( $rawOrd ) == 4 ) {
+ $node =& $this->root4;
+ } else {
+ $node =& $this->root6;
+ }
+
+ $curBit = 0;
+ while ( 1 ) {
+ if ( isset( $node['comp'] ) ) {
+ // compressed node, matches 1 whole byte on a byte boundary
+ if ( $rawOrd[$curBit >> 3] != $node['comp'] ) {
+ return false;
+ }
+ $curBit += 8;
+ $node =& $node['next'];
+ } else {
+ // uncompressed node, walk in the correct direction for the current bit-value
+ $maskShift = 7 - ( $curBit & 7 );
+ $node =& $node[( $rawOrd[$curBit >> 3] & ( 1 << $maskShift ) ) >> $maskShift];
+ ++$curBit;
+ }
+
+ if ( $node === true || $node === false ) {
+ return $node;
+ }
+ }
+ }
+
+ /**
+ * Recursively merges adjacent nets into larger supernets
+ *
+ * @param array &$node Tree node to optimize, by-reference
+ *
+ * e.g.: 8.0.0.0/8 + 9.0.0.0/8 -> 8.0.0.0/7
+ */
+ private static function recOptimize( &$node ) {
+ if ( $node[0] !== false && $node[0] !== true && self::recOptimize( $node[0] ) ) {
+ $node[0] = true;
+ }
+ if ( $node[1] !== false && $node[1] !== true && self::recOptimize( $node[1] ) ) {
+ $node[1] = true;
+ }
+ if ( $node[0] === true && $node[1] === true ) {
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Recursively compresses a tree
+ *
+ * @param array &$node Tree node to compress, by-reference
+ * @param integer $curBit current depth in the tree
+ * @param integer $maxCompStart maximum depth at which compression can start, family-specific
+ *
+ * This is a very simplistic compression scheme: if we go through a whole
+ * byte of address starting at a byte boundary with no real branching
+ * other than immediate false-vs-(node|true), compress that subtree down to a single
+ * byte-matching node.
+ * The $maxCompStart check elides recursing the final 7 levels of depth (family-dependent)
+ */
+ private static function recCompress( &$node, $curBit, $maxCompStart ) {
+ if ( !( $curBit & 7 ) ) { // byte boundary, check for depth-8 single path(s)
+ $byte = 0;
+ $cnode =& $node;
+ $i = 8;
+ while ( $i-- ) {
+ if ( $cnode[0] === false ) {
+ $byte |= 1 << $i;
+ $cnode =& $cnode[1];
+ } elseif ( $cnode[1] === false ) {
+ $cnode =& $cnode[0];
+ } else {
+ // partial-byte branching, give up
+ break;
+ }
+ }
+ if ( $i == -1 ) { // means we did not exit the while() via break
+ $node = array(
+ 'comp' => $byte,
+ 'next' => &$cnode,
+ );
+ $curBit += 8;
+ if ( $cnode !== true ) {
+ self::recCompress( $cnode, $curBit, $maxCompStart );
+ }
+ return;
+ }
+ }
+
+ ++$curBit;
+ if ( $curBit <= $maxCompStart ) {
+ if ( $node[0] !== false && $node[0] !== true ) {
+ self::recCompress( $node[0], $curBit, $maxCompStart );
+ }
+ if ( $node[1] !== false && $node[1] !== true ) {
+ self::recCompress( $node[1], $curBit, $maxCompStart );
+ }
+ }
+ }
+}
diff --git a/vendor/wikimedia/utfnormal/COPYING b/vendor/wikimedia/utfnormal/COPYING
new file mode 100644
index 00000000..019694a9
--- /dev/null
+++ b/vendor/wikimedia/utfnormal/COPYING
@@ -0,0 +1,342 @@
+== GNU GENERAL PUBLIC LICENSE ==
+
+Version 2, June 1991
+
+Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+Everyone is permitted to copy and distribute verbatim copies
+of this license document, but changing it is not allowed.
+
+=== Preamble ===
+
+The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+The precise terms and conditions for copying, distribution and
+modification follow.
+
+== TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION ==
+
+'''0.''' This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+'''1.''' You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+'''2.''' You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ '''a)''' You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ '''b)''' You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ '''c)''' If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+'''3.''' You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ '''a)''' Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ '''b)''' Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ '''c)''' Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+'''4.''' You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+'''5.''' You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+'''6.''' Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+'''7.''' If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+'''8.''' If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+'''9.''' The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+'''10.''' If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+=== NO WARRANTY ===
+
+'''11.''' BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+'''12.''' IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ '''END OF TERMS AND CONDITIONS'''
+
+== How to Apply These Terms to Your New Programs ==
+
+If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+
+ Copyright (C) <year> <name of author>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) year name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/vendor/wikimedia/utfnormal/Doxyfile b/vendor/wikimedia/utfnormal/Doxyfile
new file mode 100644
index 00000000..c091ecb7
--- /dev/null
+++ b/vendor/wikimedia/utfnormal/Doxyfile
@@ -0,0 +1,32 @@
+# Configuration file for Doxygen
+
+PROJECT_NAME = utfnormal
+PROJECT_BRIEF = "Unicode normalization for PHP"
+
+OUTPUT_DIRECTORY = doc
+
+JAVADOC_AUTOBRIEF = YES
+QT_AUTOBRIEF = YES
+
+WARN_NO_PARAMDOC = YES
+
+INPUT = README.md src/
+FILE_PATTERNS = *.php
+RECURSIVE = YES
+# Requires doxygen 1.8.3+
+USE_MDFILE_AS_MAINPAGE = README.md
+
+HTML_DYNAMIC_SECTIONS = YES
+GENERATE_TREEVIEW = YES
+TREEVIEW_WIDTH = 250
+
+GENERATE_LATEX = NO
+
+HAVE_DOT = YES
+DOT_FONTNAME = Helvetica
+DOT_FONTSIZE = 10
+TEMPLATE_RELATIONS = YES
+CALL_GRAPH = NO
+CALLER_GRAPH = NO
+# Makes dot run faster. Requires graphviz >1.8.10
+DOT_MULTI_TARGETS = YES
diff --git a/vendor/wikimedia/wrappedstring/LICENSE b/vendor/wikimedia/wrappedstring/LICENSE
new file mode 100644
index 00000000..5d34a4b3
--- /dev/null
+++ b/vendor/wikimedia/wrappedstring/LICENSE
@@ -0,0 +1,19 @@
+Copyright (c) 2015 Timo Tijhof <krinklemail@gmail.com>
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
diff --git a/vendor/wikimedia/wrappedstring/README.md b/vendor/wikimedia/wrappedstring/README.md
new file mode 100644
index 00000000..5c8b8fb0
--- /dev/null
+++ b/vendor/wikimedia/wrappedstring/README.md
@@ -0,0 +1,24 @@
+WrappedString
+=============
+
+WrappedString is a small PHP library for compacting redundant string-wrapping
+code in text output. The most common use-case is to eliminate redundant runs of
+HTML open/close tags and JavaScript boilerplate.
+
+Here is how you use it:
+
+<pre lang="php">
+use WrappedString\WrappedString;
+
+$buffer = array(
+ new WrappedString( '[foo]', '[', ']' ),
+ new WrappedString( '[bar]', '[', ']' ),
+);
+$output = WrappedString::join( "\n", $buffer );
+// Result: '[foobar]'
+</pre>
+
+License
+-------
+
+The project is licensed under the MIT license.
diff --git a/vendor/wikimedia/wrappedstring/src/WrappedString.php b/vendor/wikimedia/wrappedstring/src/WrappedString.php
new file mode 100644
index 00000000..ed2593de
--- /dev/null
+++ b/vendor/wikimedia/wrappedstring/src/WrappedString.php
@@ -0,0 +1,110 @@
+<?php
+/**
+ * Copyright (c) 2015 Timo Tijhof <krinklemail@gmail.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * @file
+ */
+
+namespace WrappedString;
+
+class WrappedString {
+ /** @var string */
+ protected $value;
+
+ /** @var string */
+ protected $prefix;
+
+ /** @var string */
+ protected $suffix;
+
+ /**
+ * @param string $value
+ * @param string $prefix
+ * @param string $suffix
+ */
+ public function __construct( $value, $prefix = null, $suffix = null ) {
+ $this->value = $value;
+ $this->prefix = $prefix;
+ $this->suffix = $suffix;
+ }
+
+ /**
+ * @param string $content
+ * @return WrappedString Newly wrapped string
+ */
+ protected function extend( $value ) {
+ $wrap = clone $this;
+ $suffixlen = strlen( $this->suffix );
+ if ( $suffixlen ) {
+ $wrap->value = substr( $this->value, 0, -$suffixlen );
+ }
+ $wrap->value .= substr( $value, strlen( $this->prefix ) );
+ return $wrap;
+ }
+
+ /**
+ * Merge consecutive wrapped strings with the same before/after values.
+ *
+ * Does not modify the array or the WrappedString objects.
+ *
+ * @param WrappedString[] $wraps
+ * @return WrappedString[]
+ */
+ protected static function compact( array &$wraps ) {
+ $consolidated = array();
+ $prev = current( $wraps );
+ while ( ( $wrap = next( $wraps ) ) !== false ) {
+ if ( $prev instanceof WrappedString
+ && $wrap instanceof WrappedString
+ && $prev->prefix !== null
+ && $prev->prefix === $wrap->prefix
+ && $prev->suffix !== null
+ && $prev->suffix === $wrap->suffix
+ ) {
+ $prev = $prev->extend( $wrap->value );
+ } else {
+ $consolidated[] = $prev;
+ $prev = $wrap;
+ }
+ }
+ // Add last one
+ $consolidated[] = $prev;
+
+ return $consolidated;
+ }
+
+ /**
+ * Join a several wrapped strings with a separator between each.
+ *
+ * @param string $sep
+ * @param WrappedString[] $wraps
+ * @return string
+ */
+ public static function join( $sep, array $wraps ) {
+ return implode( $sep, self::compact( $wraps ) );
+ }
+
+ /** @return string */
+ public function __toString() {
+ return $this->value;
+ }
+}
diff --git a/vendor/zordius/lightncandy/HISTORY.md b/vendor/zordius/lightncandy/HISTORY.md
index 577f953d..60237bbb 100644
--- a/vendor/zordius/lightncandy/HISTORY.md
+++ b/vendor/zordius/lightncandy/HISTORY.md
@@ -4,106 +4,145 @@ HISTORY
master current trunk
* align with handlebars.js master
-v0.17 https://github.com/zordius/lightncandy/tree/v0.17
- * 7bcce4c1a7 support {{@last}} for {{#each}} on both object and array.
+v0.21 https://github.com/zordius/lightncandy/tree/v0.21
+ * align with handlebars.js 3.0.3
+ * 9f24268d57 support FLAG_BARE to remove PHP start/end tags
+ * 60d5a46c55 handle object/propery merge when deal with partial
+ * d0130bf7e5 support undefined `{{helper undefined}}`
+ * 8d228606f7 support `lcrun` to use customized render library when compile()
+ * d0bad115f0 remove tmp PHP file when prepare() now
+ * d84bbb4519 support keeping tmp PHP file when prepare()
+ * ee833ae2f8 fix syntax validator bug on `{{helper "foo[]"}}`
+ * 30b891ab28 fix syntax validator bug on `{{helper 'foo[]'}}`
+ * 1867f1cc37 now count subexpression usage correctly
+ * 78ef9b8a89 new syntax validator on handlebars variable name
+
+v0.20 https://github.com/zordius/lightncandy/tree/v0.20
+ * align with handlebars.js 3.0.0
+ * 3d9a557af9 fix `{{foo (bar ../abc)}}` compile bug
+ * 7dc16ac255 refine custom helper error detection logic
+ * 72d32dc299 fix subexpression parsing bug inside `{{#each}}`
+ * d1f1b93130 support context access inside a hbhelper by `$options['_this']`
+
+v0.19 https://github.com/zordius/lightncandy/tree/v0.19
+ * align with handlebars.js 3.0.0
+ * 5703851e49 fix `{{foo bar=['abc=123']}}` parsing bug
+ * 7b4e36a1e3 fix `{{foo bar=["abc=123"]}}` parsing bug
+ * c710c8349b fix `{{foo bar=(helper a b c)}}` parsing bug
+ * 4bda1c6f41 fix subexpression+builtin block helper (EX: `{{#if (foo bar)}}`) parsing bug
+ * 6fdba10fc6 fix `{{foo ( bar) or " car" or ' cat' or [ cage]}}` pasing bug
+ * 0cd5f2d5e2 fix indent issue when custom helper inside a partial
+ * 296ea89267 support dynamic partial `{{> (foo)}}`
+ * f491d04bd5 fix `{{../foo}}` look up inside root scope issue
+ * 38fba8a5a5 fix scope issue for hbhelpers
+ * a24a0473e2 change internal variable structure and fix for `{{number}}`
+ * 7ae8289b7e fix escape in double quoted string bug
+ * 90adb5531b fix `{{#if 0.0}}` logic to behave as false
+ * 004a6ddffe fix `{{../foo}}` double usage count bug
+ * 9d55f12c5a fix subexpression parsing bug when line change inside it
+
+v0.18 https://github.com/zordius/lightncandy/tree/v0.18
+ * align with handlebars.js 2.0.0
+ * 7bcce4c1a7 support `{{@last}}` for `{{#each}}` on both object and array
* b0c44c3b40 remove ending \n in lightncandy.php
- * e130875d5a support single quoted string input: {{foo 'bar'}}.
- * c603aa39d8 support `renderex` to extend anything in render function.
- * f063e5302c now render function debug constants works well in standalone mode.
- * 53f6a6816d fix parsing bug when there is a `=` inside single quoted string.
- * 2f16c0c393 now really autoload when installed with composer.
- * c4da1f576c supports {{^myHelper}}.
+ * e130875d5a support single quoted string input: `{{foo 'bar'}}`
+ * c603aa39d8 support `renderex` to extend anything in render function
+ * f063e5302c now render function debug constants works well in standalone mode
+ * 53f6a6816d fix parsing bug when there is a `=` inside single quoted string
+ * 2f16c0c393 now really autoload when installed with composer
+ * c4da1f576c supports `{{^myHelper}}`
v0.17 https://github.com/zordius/lightncandy/tree/v0.17
+ * align with handlebars.js 2.0.0
* 3b48a0acf7 fix parsing bug when FLAG_NOESCAPE enabled
* 5c774b1b08 fix hbhelpers response error with options['fn'] when FLAG_BESTPERFORMANCE enabled
* c60fe70bdb fix hbhelpers response error with options['inverse'] when FLAG_BESTPERFORMANCE enabled
* e19b3e3426 provide options['root'] and options['_parent'] to hbhelpers
- * d8a288e83b refine variable parsing logic to support {{@../index}}, {{@../key}}, etc.
+ * d8a288e83b refine variable parsing logic to support `{{@../index}}`, `{{@../key}}`, etc.
v0.16 https://github.com/zordius/lightncandy/tree/v0.16
* align with handlebars.js 2.0.0
- * 4f036aff62 better error message for named arguments.
- * 0b462a387b support {{#with var}} ... {{else}} ... {{/with}}.
- * 4ca624f651 fix 1 ANSI code error.
- * 01ea3e9f42 support instances with PHP __call magic funciton.
- * 38059036a7 support {{#foo}} or {{#each foo}} on PHP Traversable instance.
- * 366f5ec0ac add FLAG_MUSTACHESP and FLAG_MUSTACHEPAIN into FLAG_HANDLEBARS and FLAG_HANDLEBARSJS now.
- * b61d7b4a81 align with handlebars.js standalone tags behavior.
- * b211e1742e now render false as 'false'.
- * 655a2485be fix bug for {{helper "==="}}
+ * 4f036aff62 better error message for named arguments
+ * 0b462a387b support `{{#with var}}` ... `{{else}}` ... `{{/with}}`
+ * 4ca624f651 fix 1 ANSI code error
+ * 01ea3e9f42 support instances with PHP __call magic funciton
+ * 38059036a7 support `{{#foo}}` or `{{#each foo}}` on PHP Traversable instance
+ * 366f5ec0ac add FLAG_MUSTACHESP and FLAG_MUSTACHEPAIN into FLAG_HANDLEBARS and FLAG_HANDLEBARSJS now
+ * b61d7b4a81 align with handlebars.js standalone tags behavior
+ * b211e1742e now render false as 'false'
+ * 655a2485be fix bug for `{{helper "==="}}`
* bb58669162 support FLAG_NOESCAPE
v0.15 https://github.com/zordius/lightncandy/tree/v0.15
* align with handlebars.js 2.0.0
- * 4c750806e8 fix for \ in template
- * 12ab6626d6 support escape. \{{foo}} will be rendered as is. ( handlebars spec , require FLAG_SLASH )
+ * 4c750806e8 fix for `\` in template
+ * 12ab6626d6 support escape. `\{{foo}}` will be rendered as is. ( handlebars spec , require FLAG_SLASH )
* 876bd44d9c escape &#x60; to &amp;#x60; ( require FLAG_JSQUOTE )
- * f1f388ed79 support {{^}} as {{else}} ( require FLAG_ELSE )
- * d5e17204b6 support {{#each}} == {{#each .}} now.
- * 742126b440 fix {{>foo/bar}} partial not found bug.
- * d62c261ff9 support numbers as helper input {{helper 0.1 -1.2}}
- * d40c76b84f support escape in string arguments {{helper "test \" double quote"}}
- * ecb57a2348 fix for missing partial in partial bug.
- * 1adad5dbfa fix {{#with}} error when FLAG_WITH not used.
- * ffd5e35c2d fix error when rendering array value as {{.}} without FLAG_JSOBJECT.
- * bd4987adbd support changing context on partial {{>foo bar}} ( require FLAG_RUNTIMEPARTIAL )
- * f5decaa7e3 support name sarguments on partial {{>foo bar name=tee}} . fix {{..}} bug.
- * c20bb36457 support `partials` in options.
- * e8779dbe8c change default `basedir` hehavior, stop partial files lookup when do not prodive `basedir` in options.
- * c4e3401fe4 fix {{>"test"}} or {{>[test]}} or {{>1234}} bug.
- * e59f62ea9b fix seciton behavior when input is object, and add one new flag: FLAG_MUSTACHESEC.
- * 80eaf8e007 use static::method not self::method for subclass.
+ * f1f388ed79 support `{{^}}` as `{{else}}` ( require FLAG_ELSE )
+ * d5e17204b6 support `{{#each}}` == `{{#each .}}` now
+ * 742126b440 fix `{{>foo/bar}} partial not found bug
+ * d62c261ff9 support numbers as helper input `{{helper 0.1 -1.2}}`
+ * d40c76b84f support escape in string arguments `{{helper "test \" double quote"}}`
+ * ecb57a2348 fix for missing partial in partial bug
+ * 1adad5dbfa fix `{{#with}}` error when FLAG_WITH not used
+ * ffd5e35c2d fix error when rendering array value as `{{.}}` without FLAG_JSOBJECT
+ * bd4987adbd support changing context on partial `{{>foo bar}}` ( require FLAG_RUNTIMEPARTIAL )
+ * f5decaa7e3 support name sarguments on partial `{{>foo bar name=tee}}` . fix `{{..}}` bug
+ * c20bb36457 support `partials` in options
+ * e8779dbe8c change default `basedir` hehavior, stop partial files lookup when do not prodive `basedir` in options
+ * c4e3401fe4 fix `{{>"test"}}` or `{{>[test]}}` or `{{>1234}}` bug
+ * e59f62ea9b fix seciton behavior when input is object, and add one new flag: FLAG_MUSTACHESEC
+ * 80eaf8e007 use static::method not self::method for subclass
* 0bad5c8f20 fix usedFeature generation bugs
v0.14 https://github.com/zordius/lightncandy/tree/v0.14
* align with handlebars.js 2.0.0-alpha.4
* fa6225f278 support boolen value in named arguments for cusotm helper
- * 160743e1c8 better error message when unmatch {{/foo}} tag detected
- * d9a9416907 support {{&foo}}
- * 8797485cfa fix {{^foo}} logic when foo is empty list
+ * 160743e1c8 better error message when unmatch `{{/foo}}` tag detected
+ * d9a9416907 support `{{&foo}}`
+ * 8797485cfa fix `{{^foo}}` logic when foo is empty list
* 523b1373c4 fix handlebars custom helper interface
* a744a2d522 fix bad syntax when FLAG_RENDER_DEBUG + helpers
* 0044f7bd10 change FLAG_THIS behavoir
* b5b0739b68 support recursive context lookup now ( mustache spec , require FLAG_MUSTACHELOOKUP )
* 096c241fce support standalone tag detection now ( mustache spec , require FLAG_MUSTACHESP )
- * cea46c9a67 support {{=<% %>=}} to set delimiter
- * 131696af11 support subexpression {{helper (helper2 foo) bar}}
+ * cea46c9a67 support `{{=<% %>=}}` to set delimiter
+ * 131696af11 support subexpression `{{helper (helper2 foo) bar}}`
* 5184d41be6 support runtime/recursive partial ( require FLAG_RUNTIMEPARTIAL )
* 6408917f76 support partial indent ( mustache spec , require FLAG_MUSTACHEPAIN )
v0.13 https://github.com/zordius/lightncandy/tree/v0.13
* align with handlebars.js 2.0.0-alpha.4
- * e5a8fe3833 fix issue #46 ( error with {{this.foo.bar}} )
+ * e5a8fe3833 fix issue #46 ( error with `{{this.foo.bar}}` )
* ea131512f9 fix issue #44 ( error with some helper inline function PHP code syntax )
* 522591a0c6 fix issue #49 ( error with some helper user function PHP code syntax )
- * c4f7e1eaac support {{foo.bar}} lookup on instance foo then property/method bar ( flagd FLAG_PROPERTY or FLAG_METHOD required )
+ * c4f7e1eaac support `{{foo.bar}} lookup on instance foo then property/method bar ( flagd FLAG_PROPERTY or FLAG_METHOD required )
* 0f4c0daa4b stop simulate Javascript output for array when pass input to custom helpers
* 22d07e5f0f BIG CHANGE of custom helper interface
v0.12 https://github.com/zordius/lightncandy/tree/v0.12
* align with handlebars.js 2.0.0-alpha.2
- * 64db34cf65 support {{@first}} and {{@last}}
+ * 64db34cf65 support `{{@first}}` and `{{@last}}`
* bfa1fbef97 add new flag FLAG_SPVARS
* 10a4623dc1 remove json schema support
* 240d9fa290 only export used LCRun2 functions when compile() with FLAG_STANDALONE now
- * 3fa897c98c rename LCRun2 to LCRun3 for interface changed, old none standalone templates will error with newer version.
+ * 3fa897c98c rename LCRun2 to LCRun3 for interface changed, old none standalone templates will error with newer version
* e0838c7418 now can output debug template map with ANSI color
* 80dbeab63d fix php warning when compile with custom helper or block custom helper
* 8ce6268b64 support Handlebars.js style custom helper
v0.11 https://github.com/zordius/lightncandy/tree/v0.11
* align with handlebars.js 2.0.0-alpha.2
- * a275d52c97 use php array, remove val().
+ * a275d52c97 use php array, remove val()
* 8834914c2a only export used custom helper into render function now
* eb6d82d871 refine option flag consts
* fc437295ed refine comments for phpdoc
* fbf116c3e2 fix for tailing ; after helper functions
- * f47a2d5014 fix for wrong param when new Exception
+ * f47a2d5014 fix for wrong param when new Exception
* 94e71ebcbd add isset() check for input value
- * a826b8a1ab support {{else}} in {{#each}} now
- * 25dac11bb7 support {{!-- comments --}} now (this extension allow }} apperas in the comments)
- * e142b6e116 support {{@root}} or {{@root.foo.bar}} now
+ * a826b8a1ab support `{{else}}` in `{{#each}}` now
+ * 25dac11bb7 support `{{!-- comments --}}` now (this handlebars.js extension allow `}}` apperas in the comments)
+ * e142b6e116 support `{{@root}}` or `{{@root.foo.bar}}` now
* 58c8d84aa2 custom helper can return extra flag to change html encoded behavior now
v0.10 https://github.com/zordius/lightncandy/tree/v0.10
@@ -111,10 +150,10 @@ v0.10 https://github.com/zordius/lightncandy/tree/v0.10
* 4c9f681080 file name changed: lightncandy.inc => lightncandy.php
* e3de01081c some minor fix for json schema
* 1feec458c7 new variable handling logic, save variable name parsing time when render() . rendering performance improved 10~30%!
- * 3fa897c98c rename LCRun to LCRun2 for interface changed, old none standalone templates will error with newer version.
- * 43a6d33717 fix for {{../}} php warning message
+ * 3fa897c98c rename LCRun to LCRun2 for interface changed, old none standalone templates will error with newer version
+ * 43a6d33717 fix for `{{../}}` php warning message
* 9189ebc1e4 now auto push documents from Travis CI
- * e077d0b631 support named arguments for custom helpers {{helper name=value}}
+ * e077d0b631 support named arguments for custom helpers `{{helper name=value}}`
* 2331b6fe55 support block custom helpers
* 4fedaa25f7 support number value as named arguments
* 6a91ab93d2 fix for default options and php warnings
@@ -122,13 +161,13 @@ v0.10 https://github.com/zordius/lightncandy/tree/v0.10
v0.9 https://github.com/zordius/lightncandy/tree/v0.9
* align with handlebars.js 1.3
- * a55f2dd067 support both {{@index}} and {{@key}} when {{#each an_object}}
+ * a55f2dd067 support both `{{@index}}` and `{{@key}}` when `{{#each an_object}}`
* e59f931ea7 add FLAG_JSQUOTE support
* 92b3cf58af report more than 1 error when compile()
* 93cc121bcf test for wrong variable name format in test/error.php
- * 41c1b431b4 support advanced variable naming {{foo.[bar].10}} now
+ * 41c1b431b4 support advanced variable naming `{{foo.[bar].10}}` now
* 15ce1a00a8 add FLAG_EXTHELPER option
- * f51337bde2 support space control {{~sometag}} or {{sometag~}}
+ * f51337bde2 support space control `{{~sometag}}` or `{{sometag~}}`
* fe3d67802e add FLAG_SPACECTL option
* 920fbb3039 support custom helper
* 07ae71a1bf migrate into Travis CI
@@ -141,30 +180,31 @@ v0.9 https://github.com/zordius/lightncandy/tree/v0.9
v0.8 https://github.com/zordius/lightncandy/tree/v0.8
* align with handlebars.js 1.0.12
* aaec049 fix partial in partial not works bug
- * 52706cc fix for {{#var}} and {{^var}} , now when var === 0 means true
- * 4f7f816 support {{@key}} and {{@index}} in {{#each var}}
- * 63aef2a prevent array_diff_key() PHP warning when {{#each}} on none array value
- * 10f3d73 add more is_array() check when {{#each}} and {{#var}}
- * 367247b fix {{#if}} and {{#unless}} when value is an empty array
+ * 52706cc fix for `{{#var}}` and `{{^var}}` , now when var === 0 means true
+ * 4f7f816 support `{{@key}}` and `{{@index}}` in `{{#each var}}`
+ * 63aef2a prevent array_diff_key() PHP warning when `{{#each}}` on none array value
+ * 10f3d73 add more is_array() check when `{{#each}}` and `{{#var}}`
+ * 367247b fix `{{#if}}` and `{{#unless}}` when value is an empty array
* c76c0bb returns null if var is not exist in a template [contributed by dtelyukh@github.com]
* d18bb6d add FLAG_ECHO support
- * aec2b2b fix {{#if}} and {{#unless}} when value is an empty string
+ * aec2b2b fix `{{#if}}` and `{{#unless}}` when value is an empty string
* 8924604 fix variable output when false in an array
* e82c324 fix for ifv and ifvar logic difference
- * 1e38e47 better logic on var name checking. now support {{0}} in the loop, but it is not handlebars.js standard
+ * 1e38e47 better logic on var name checking. now support `{{0}}` in the loop, but it is not handlebars.js standard
v0.7 https://github.com/zordius/lightncandy/tree/v0.7
+ * align with handlebarsjs 1.0.11
* add HISTORY.md
* 777304c change compile format to include in val, isec, ifvar
- * 55de127 support {{../}} in {{#each}}
+ * 55de127 support `{{../}}` in `{{#each}}`
* 57e90af fix parent levels detection bug
- * 96bb4d7 fix bugs for {{#.}} and {{#this}}
+ * 96bb4d7 fix bugs for `{{#.}}` and `{{#this}}`
* f4217d1 add ifv and unl 2 new methods for LCRun
- * 3f1014c fix {{#this}} and {{#.}} bug when used with {{../var}}
- * cbf0b28 fix {{#if}} logic error when using {{../}}
- * 2b20ef8 fix {{#with}} + {{../}} bug
+ * 3f1014c fix `{{#this}}` and `{{#.}}` bug when used with `{{../var}}`
+ * cbf0b28 fix `{{#if}}` logic error when using `{{../}}`
+ * 2b20ef8 fix `{{#with}}` + `{{../}}` bug
* 540cd44 now support FLAG_STANDALONE
- * 67ac5ff support {{>partial}}
+ * 67ac5ff support `{{>partial}}`
* 98c7bb1 detect unclosed token now
v0.6 https://github.com/zordius/lightncandy/tree/v0.6
@@ -174,8 +214,8 @@ v0.6 https://github.com/zordius/lightncandy/tree/v0.6
* fdc753b fix #each and section logic for 018-hb-withwith-006
* e6cc95a add FLAG_PARENT, detect template error when scan()
* 1980691 make new LCRun::val() method to normal path.val logic
- * 110d24f {{#if path.var}} bug fixed
- * d6ae2e6 fix {{#with path.val}} when input value is null
+ * 110d24f `{{#if path.var}}` bug fixed
+ * d6ae2e6 fix `{{#with path.val}}` when input value is null
* 71cf074 fix for 020-hb-doteach testcase
v0.5 https://github.com/zordius/lightncandy/tree/v0.5
diff --git a/vendor/zordius/lightncandy/LICENSE.txt b/vendor/zordius/lightncandy/LICENSE.txt
index 3df560d4..069e6cef 100644
--- a/vendor/zordius/lightncandy/LICENSE.txt
+++ b/vendor/zordius/lightncandy/LICENSE.txt
@@ -1,7 +1,7 @@
Copyrights for code authored by Yahoo! Inc. is licensed under the following
terms:
MIT License
-Copyright (c) 2013, 2014 Yahoo! Inc. All Rights Reserved.
+Copyright (c) 2013-2015 Yahoo! Inc. All Rights Reserved.
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
diff --git a/vendor/zordius/lightncandy/README.md b/vendor/zordius/lightncandy/README.md
index 2afd6b9c..d5a3a5bc 100644
--- a/vendor/zordius/lightncandy/README.md
+++ b/vendor/zordius/lightncandy/README.md
@@ -7,7 +7,7 @@ Travis CI status: [![Unit testing](https://travis-ci.org/zordius/lightncandy.svg
Scrutinizer CI status: [![Code Coverage](https://img.shields.io/scrutinizer/coverage/g/zordius/lightncandy.svg)](https://scrutinizer-ci.com/g/zordius/lightncandy/)
-Package on packagist: [![Latest Stable Version](https://poser.pugx.org/zordius/lightncandy/v/stable.svg)](https://packagist.org/packages/zordius/lightncandy) [![License](https://poser.pugx.org/zordius/lightncandy/license.svg)](https://github.com/zordius/lightncandy/blob/master/LICENSE.txt) [![Total Downloads](https://poser.pugx.org/zordius/lightncandy/downloads.svg)](https://packagist.org/packages/zordius/lightncandy) [![HHVM Status](http://hhvm.h4cc.de/badge/zordius/lightncandy.svg)](http://hhvm.h4cc.de/package/zordius/lightncandy)
+Package on packagist: [![Latest Stable Version](https://poser.pugx.org/zordius/lightncandy/v/stable.svg)](https://packagist.org/packages/zordius/lightncandy) [![License](https://poser.pugx.org/zordius/lightncandy/license.svg)](https://github.com/zordius/lightncandy/blob/master/LICENSE.txt) [![Total Downloads](https://poser.pugx.org/zordius/lightncandy/downloads)](https://packagist.org/packages/zordius/lightncandy) [![HHVM Status](http://hhvm.h4cc.de/badge/zordius/lightncandy.svg)](http://hhvm.h4cc.de/package/zordius/lightncandy)
Features
--------
@@ -21,7 +21,7 @@ Features
* Runs 4~10 times faster than <a href="https://github.com/dingram/mustache-php">mustache-php</a>.
* Runs 10~30 times faster than <a href="https://github.com/XaminProject/handlebars.php">handlebars.php</a>.
* Detail performance test reports can be found <a href="https://github.com/zordius/HandlebarsTest">here</a>, go http://zordius.github.io/HandlebarsTest/ to see charts.
-* **SMALL!** single PHP file, only 110K!
+* **SMALL!** single PHP file, only 120K!
* **ROBUST!**
* 100% support <a href="https://github.com/mustache/spec">mustache spec v1.1.2</a> (without lambda module)
* Supports almost all <a href="https://github.com/kasperisager/handlebars-spec">handlebars.js spec</a>
@@ -133,8 +133,8 @@ Default is to compile the template as PHP, which can be run as fast as possible
* `FLAG_RUNTIMEPARTIAL` : compile partial as runtime function, This enables recursive partials or context change for partials.
* `FLAG_SLASH` : Skip a delimiter when it behind `\` .
* `FLAG_ELSE` : support `{{else}}` or `{{^}}` as handlebars specification. Otherwise, `{{else}}` will be resolved as normal variable , and {{^}} will cause template error.
-* `FLAG_PROPERTY` : support object instance attribute access.
-* `FLAG_METHOD` : support object instance method access.
+* `FLAG_PROPERTY` : support object instance attribute access. You MUST apply this if your data contains object. And, the rendering performance will be worse.
+* `FLAG_METHOD` : support object instance method access. You MUST apply this if your data contains object. And, the rendering performance will be worse.
* `FLAG_INSTANCE` : same with `FLAG_PROPERTY` + `FLAG_METHOD`
* `FLAG_SPACECTL` : support space control `{{~ }}` or `{{ ~}}` in template. Otherwise, `{{~ }}` or `{{ ~}}` will cause template error.
* `FLAG_SPVARS` : support special variables include @root, @index, @key, @first, @last. Otherwise, compile these variable names with default parsing logic.
@@ -142,13 +142,13 @@ Default is to compile the template as PHP, which can be run as fast as possible
* `FLAG_HANDLEBARS` : support all handlebars extensions (which mustache do not supports) , same with `FLAG_THIS` + `FLAG_WITH` + `FLAG_PARENT` + `FLAG_JSQUOTE` + `FLAG_ADVARNAME` + `FLAG_NAMEDARG` + `FLAG_SLASH` + `FLAG_ELSE` + `FLAG_MUSTACHESP` + `FLAG_MUSTACHEPAIN`.
* `FLAG_HANDLEBARSJS` : align with handlebars.js behaviors, same with `FLAG_JS` + `FLAG_HANDLEBARS`.
* `FLAG_MUSTACHESP` : align line change and spacing behaviors with mustache specification.
-* `FLAG_MUSTACHELOOKUP` : align recursive lookup up behaviors with mustache specification.
+* `FLAG_MUSTACHELOOKUP` : align recursive lookup up behaviors with mustache specification. And, the rendering performance will be worse.
* `FLAG_MUSTACHEPAIN` : align partial indent behavior with mustache specification.
-* `FLAG_MUSTACHESEC` : align section `{{#foo}}` context behavior with mustache specification.
-* `FLAG_MUSTACHE` : support all mustache specification, same with `FLAG_ERROR_SKIPPARTIAL` + `FLAG_MUSTACHESP` + `FLAG_MUSTACHELOOKUP` + `FLAG_MUSTACHEPAIN` + `FLAG_MUSTACHESEC`.
+* `FLAG_MUSTACHE` : support all mustache specification, same with `FLAG_ERROR_SKIPPARTIAL` + `FLAG_MUSTACHESP` + `FLAG_MUSTACHELOOKUP` + `FLAG_MUSTACHEPAIN`.
* `FLAG_ECHO` : compile to `echo 'a', $b, 'c';` to improve performance. This will slow down rendering when the template and data are simple, but will improve 1% ~ 7% when the data is big and looping in the template.
* `FLAG_BESTPERFORMANCE` : same with `FLAG_ECHO` now. This flag may be changed base on performance testing result in the future.
* `FLAG_RENDER_DEBUG` : generate debug template to show error when rendering. With this flag, the performance of rendering may be slowed.
+* `FLAG_BARE`: generate PHP code without PHP tags `<?php` and `?>`
Partial Support
---------------
@@ -205,8 +205,13 @@ By default, partial uses the same context with original template. If you want to
{{>partial_name .}} // Same as {{>partial_name}}
{{>partial_name foo}} // Change input context to foo, FLAG_RUNTIMEPARTIAL required
{{>partial_name ..}} // use {{..}} as new input context, FLAG_RUNTIMEPARTIAL required
+
+{{>partial_name .. key=bar}} // use {{..}} as new input context, FLAG_RUNTIMEPARTIAL required
+ // also merge key into new context.
```
+You can use dynamic partial name by passing a custom helper as subexpression syntax, for example: `{{> (foo)}}` . the return value of custom helper `foo` will be the partial name. When you using dynamic partial, LightnCandy will compile all partial inside the `partials` option into template. (**TODO: add an example to show how to provide partials across templates to reduce size**)
+
Custom Helper
-------------
@@ -321,6 +326,19 @@ return Array('Not&Same output \' " Ya!', 'enc');
return Array('Not&Same output \' " Ya!', 'encq');
```
+In most case, a custom helper should always return a string. If you design a custom helper to be executed inside a subexpression, you can return an object or an array by this way:
+
+```php
+// return an object
+return Array($anObject, 'asis');
+
+// in another way
+return Array($anObject, 'raw');
+
+// return Array(1, 3, 5)
+return Array(Array(1, 3, 5), 'any_string_but_not_enc_nor_encq');
+```
+
Block Custom Helper
-------------------
@@ -400,7 +418,7 @@ The mission of a block custom helper is only focus on providing different contex
Handlebars.js' Custom Helper
----------------------------
-You can implement helpers more like Handlebars.js way with `hbhelpers` option, all matched single custom helper and block custom helper will be handled. In Handlebars.js, a block custom helper can rendener child block by executing options->fn, and change context by send new context as first parameter. Here are some examples to explain the behavior of `hbhelpers` custom helper:
+You can implement helpers more like Handlebars.js way with `hbhelpers` option, all matched single custom helper and block custom helper will be handled. In Handlebars.js, a block custom helper can rendener child block by executing `options.fn`; or change context by send new context as first parameter. Here are some examples to explain the behavior of `hbhelpers` custom helper:
**#mywith (context change)**
* LightnCandy
@@ -504,6 +522,30 @@ Handlebars.registerHelper('sample', function(arg1, arg2, options) {
});
```
+**Data variables and context**
+
+You can get special data variables from `$options['data']`. Using `$options['_this']` to receive current context.
+
+```php
+$php = LightnCandy::compile($template, Array(
+ 'flags' => LightnCandy::FLAG_HANDLEBARSJS,
+ 'hbhelpers' => Array(
+ 'getRoot' => function ($options) {
+ print_($options['_this']); // dump current context
+ return $options['data']['root']; // same as {{@root}}
+ }
+ )
+));
+```
+
+* Handlebars.js
+```javascript
+Handlebars.registerHelper('getRoot', function(options) {
+ console.log(this); // dump current context
+ return options.data.root; // same as {{@root}}
+});
+```
+
**Escaping**
When a Handlebars.js style custom helper be used as block tags, LightnCandy will not escape the result. When it is a single {{...}} tag, LightnCandy will escape the result. To change the escape behavior, you can return extended information by Array(), please read <a href="#custom-helper-escaping">Custom Helper Escaping</a> for more.
@@ -589,10 +631,32 @@ function ($in) {$
Please make sure the passed in `renderex` is valid PHP, LightnCandy will not check it.
+Customize Rendering Runtime Class
+---------------------------------
+
+If you want to extend `LCRun3` class and replace default rendering runtime library, you may use `lcrun` when `compile()` . For example, this sample will generate render function based on your extended `MyLCRunClass`:
+
+```php
+// Customized rendering runtime library to debug {{{foo}}}
+class MyLCRunClass extends LCRun3 {
+ public static function raw($cx, $v) {
+ return '[[DEBUG:raw()=>' . var_export($v, true) . ']]';
+ }
+}
+
+// Use MyLCRunClass as rendering runtime library
+$php = LightnCandy::compile($template, Array(
+ 'flags' => LightnCandy::FLAG_HANDLEBARSJS,
+ 'lcrun' => 'MyLCRunClass'
+));
+```
+
+Please make sure `MyLCRunClass` exists when compile() or rendering based on your `FLAG_STANDALONE` .
+
Unsupported Feature (so far)
----------------------------
-* [NEVER] `{{foo/bar}}` style variable name, it is deprecated in official handlebars.js document.
+* [NEVER] `{{foo/bar}}` style variable name, it is deprecated in official handlebars.js document, please use this style: `{{foo.bar}}`.
* [maybe] mustache lambda : runtime time compile based on input value is far from lightncandy nature, not in the plan now.
Suggested Handlebars Template Practices
@@ -651,6 +715,8 @@ Go http://handlebarsjs.com/ to see more feature description about handlebars.js.
* `{{../var}}` : parent template scope. (require `FLAG_PARENT`)
* `{{>file}}` : partial; include another template inside a template.
* `{{>file foo}}` : partial with new context (require `FLAG_RUNTIMEPARTIAL`)
+* `{{>file foo bar=another}}` : partial with new context which mixed with followed key value (require `FLAG_RUNTIMEPARTIAL`)
+* `{{>(helper) foo}}` : include dynamic partial by name provided from a helper (require `FLAG_RUNTIMEPARTIAL`)
* `{{@index}}` : references to current index in a `{{#each}}` loop on an array. (require `FLAG_SPVARS`)
* `{{@key}}` : references to current key in a `{{#each}}` loop on an object. (require `FLAG_SPVARS`)
* `{{@root}}` : references to root context. (require `FLAG_SPVARS`)
@@ -665,6 +731,13 @@ Go http://handlebarsjs.com/ to see more feature description about handlebars.js.
* `{{{helper var}}}` : Execute custom helper then render the result
* `{{helper var}}` : Execute custom helper then render the HTML escaped result
* `{{helper "str"}}` or `{{helper 'str'}}` : Execute custom helper with string arguments (require `FLAG_ADVARNAME`)
+* `{{helper 123 null true false undefined}}` : Pass number, true, false, null or undefined into helper
* `{{helper name1=var name2=var2}}` : Execute custom helper with named arguments (require `FLAG_NAMEDARG`)
* `{{#helper ...}}...{{/helper}}` : Execute block custom helper
* `{{helper (helper2 foo) bar}}` : Execute custom helpers as subexpression (require `FLAG_ADVARNAME`)
+
+Framework Integration
+---------------------
+
+- [Slim 3.0.x](https://github.com/endel/slim-lightncandy-view)
+- [Laravel 4](https://github.com/samwalshnz/lightncandy-l4)
diff --git a/vendor/zordius/lightncandy/UPGRADE.md b/vendor/zordius/lightncandy/UPGRADE.md
index 01f4c15b..680137be 100644
--- a/vendor/zordius/lightncandy/UPGRADE.md
+++ b/vendor/zordius/lightncandy/UPGRADE.md
@@ -5,6 +5,10 @@ Upgrade Notice
* Recompile your none standalone templates when you upgrade LightnCandy.
+CURRENT MASTER
+--------------
+* Option FLAG_MUSTACHESEC removed, no need to use this flag anymore.
+
Version v0.13
-------------
* The interface of custom helpers was changed from v0.13 . if you use this feature you may need to modify your custom helper functions.
diff --git a/vendor/zordius/lightncandy/build/gen_doc b/vendor/zordius/lightncandy/build/gen_doc
index 428e619d..807bc21a 100644
--- a/vendor/zordius/lightncandy/build/gen_doc
+++ b/vendor/zordius/lightncandy/build/gen_doc
@@ -1,5 +1,5 @@
#!/bin/sh
-curl -O https://cloud.github.com/downloads/apigen/apigen/ApiGen-2.8.0-standalone.zip
+curl -O https://cloud.github.com/downloads/ApiGen/ApiGen/ApiGen-2.8.0-standalone.zip
unzip -oq ApiGen-2.8.0-standalone.zip
rm ApiGen-2.8.0-standalone.zip
php -dopen_basedir=/ apigen/apigen.php --source src/ --destination build/result/docs/ --template-config apigen/templates/bootstrap/config.neon --deprecated yes
diff --git a/vendor/zordius/lightncandy/src/lightncandy.php b/vendor/zordius/lightncandy/src/lightncandy.php
index d7a62e57..bc62781c 100644
--- a/vendor/zordius/lightncandy/src/lightncandy.php
+++ b/vendor/zordius/lightncandy/src/lightncandy.php
@@ -3,7 +3,7 @@
Copyrights for code authored by Yahoo! Inc. is licensed under the following terms:
MIT License
-Copyright (c) 2013 Yahoo! Inc. All Rights Reserved.
+Copyright (c) 2013-2015 Yahoo! Inc. All Rights Reserved.
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.
@@ -29,6 +29,7 @@ class LightnCandy {
// Compile the template as standalone PHP code which can execute without including LightnCandy
const FLAG_STANDALONE = 4;
+ const FLAG_BARE = 33554432;
const FLAG_NOESCAPE = 67108864;
// JavaScript compatibility
@@ -58,7 +59,6 @@ class LightnCandy {
const FLAG_MUSTACHESP = 131072;
const FLAG_MUSTACHELOOKUP = 262144;
const FLAG_MUSTACHEPAIN = 2097152;
- const FLAG_MUSTACHESEC = 33554432;
// Template rendering time debug flags
const FLAG_RENDER_DEBUG = 524288;
@@ -66,7 +66,7 @@ class LightnCandy {
// alias flags
const FLAG_BESTPERFORMANCE = 16384; // FLAG_ECHO
const FLAG_JS = 24; // FLAG_JSTRUE + FLAG_JSOBJECT
- const FLAG_MUSTACHE = 40239104; // FLAG_ERROR_SKIPPARTIAL + FLAG_MUSTACHESP + FLAG_MUSTACHELOOKUP + FLAG_MUSTACHEPAIN + FLAG_MUSTACHESEC
+ const FLAG_MUSTACHE = 6684672; // FLAG_ERROR_SKIPPARTIAL + FLAG_MUSTACHESP + FLAG_MUSTACHELOOKUP + FLAG_MUSTACHEPAIN
const FLAG_HANDLEBARS = 27402208; // FLAG_THIS + FLAG_WITH + FLAG_PARENT + FLAG_JSQUOTE + FLAG_ADVARNAME + FLAG_SPACECTL + FLAG_NAMEDARG + FLAG_SPVARS + FLAG_SLASH + FLAG_ELSE + FLAG_MUSTACHESP + FLAG_MUSTACHEPAIN
const FLAG_HANDLEBARSJS = 27402232; // FLAG_JS + FLAG_HANDLEBARS
const FLAG_INSTANCE = 98304; // FLAG_PROPERTY + FLAG_METHOD
@@ -74,6 +74,7 @@ class LightnCandy {
// RegExps
const VARNAME_SEARCH = '/(\\[[^\\]]+\\]|[^\\[\\]\\.]+)/';
const EXTENDED_COMMENT_SEARCH = '/{{!--.*?--}}/s';
+ const IS_SUBEXP_SEARCH = '/^\(.+\)$/s';
// Positions of matched token
const POS_LOTHER = 1;
@@ -105,7 +106,7 @@ class LightnCandy {
}
// Strip extended comments
- $template = preg_replace(static::EXTENDED_COMMENT_SEARCH, '{{!*}}', $template);
+ $template = preg_replace(static::EXTENDED_COMMENT_SEARCH, '{{! }}', $template);
// Do first time scan to find out used feature, detect template error.
static::setupToken($context);
@@ -115,8 +116,14 @@ class LightnCandy {
return false;
}
+ $context['scan'] = false;
+
// Do PHP code generation.
static::setupToken($context);
+
+ // Handle dynamic partials
+ static::handleDynamicPartial($context);
+
$code = static::compileTemplate($context, static::escapeTemplate($template));
// return false when fatal error
@@ -128,7 +135,20 @@ class LightnCandy {
return static::composePHPRender($context, $code);
}
- /*
+ /**
+ * Include all partials when using dynamic partials
+ */
+ protected static function handleDynamicPartial(&$context) {
+ if ($context['usedFeature']['dynpartial'] == 0) {
+ return;
+ }
+
+ foreach ($context['partials'] as $name => $code) {
+ static::readPartial($name, $context);
+ }
+ }
+
+ /**
* Escape template
*
* @param string $template handlebars template string
@@ -136,7 +156,7 @@ class LightnCandy {
* @return string Escaped template
*
* @expect 'abc' when input 'abc'
- * @expect 'a\\bc' when input 'a\bc'
+ * @expect 'a\\\\bc' when input 'a\bc'
* @expect 'a\\\'bc' when input 'a\'bc'
*/
protected static function escapeTemplate($template) {
@@ -255,7 +275,6 @@ class LightnCandy {
$flagProp = static::getBoolStr($context['flags']['prop']);
$flagMethod = static::getBoolStr($context['flags']['method']);
$flagMustlok = static::getBoolStr($context['flags']['mustlok']);
- $flagMustsec = static::getBoolStr($context['flags']['mustsec']);
$flagEcho = static::getBoolStr($context['flags']['echo']);
$libstr = static::exportLCRun($context);
@@ -264,9 +283,11 @@ class LightnCandy {
$bhelpers = static::exportHelper($context, 'blockhelpers');
$hbhelpers = static::exportHelper($context, 'hbhelpers');
$debug = LCRun3::DEBUG_ERROR_LOG;
+ $phpstart = $context['flags']['bare'] ? '' : '<?php ';
+ $phpend = $context['flags']['bare'] ? '' : "\n?>";
// Return generated PHP code string.
- return "<?php return function (\$in, \$debugopt = $debug) {
+ return "{$phpstart}return function (\$in, \$debugopt = $debug) {
\$cx = array(
'flags' => array(
'jstrue' => $flagJStrue,
@@ -275,7 +296,6 @@ class LightnCandy {
'prop' => $flagProp,
'method' => $flagMethod,
'mustlok' => $flagMustlok,
- 'mustsec' => $flagMustsec,
'echo' => $flagEcho,
'debug' => \$debugopt,
),
@@ -284,14 +304,14 @@ class LightnCandy {
'blockhelpers' => $bhelpers,
'hbhelpers' => $hbhelpers,
'partials' => array({$context['partialCode']}),
- 'scopes' => array(\$in),
+ 'scopes' => array(),
'sp_vars' => array('root' => \$in),
+ 'lcrun' => '{$context['lcrun']}',
$libstr
);
{$context['renderex']}
{$context['ops']['op_start']}'$code'{$context['ops']['op_end']}
-}
-?>";
+}$phpend";
}
/**
@@ -314,6 +334,7 @@ $libstr
'exception' => $flags & self::FLAG_ERROR_EXCEPTION,
'skippartial' => $flags & self::FLAG_ERROR_SKIPPARTIAL,
'standalone' => $flags & self::FLAG_STANDALONE,
+ 'bare' => $flags & self::FLAG_BARE,
'noesc' => $flags & self::FLAG_NOESCAPE,
'jstrue' => $flags & self::FLAG_JSTRUE,
'jsobj' => $flags & self::FLAG_JSOBJECT,
@@ -331,13 +352,13 @@ $libstr
'mustsp' => $flags & self::FLAG_MUSTACHESP,
'mustlok' => $flags & self::FLAG_MUSTACHELOOKUP,
'mustpi' => $flags & self::FLAG_MUSTACHEPAIN,
- 'mustsec' => $flags & self::FLAG_MUSTACHESEC,
'debug' => $flags & self::FLAG_RENDER_DEBUG,
'prop' => $flags & self::FLAG_PROPERTY,
'method' => $flags & self::FLAG_METHOD,
'runpart' => $flags & self::FLAG_RUNTIMEPARTIAL,
),
'level' => 0,
+ 'scan' => true,
'stack' => array(),
'error' => array(),
'basedir' => static::buildCXBasedir($options),
@@ -365,13 +386,14 @@ $libstr
'this' => 0,
'parent' => 0,
'with' => 0,
- 'dot' => 0,
'comment' => 0,
'partial' => 0,
+ 'dynpartial' => 0,
'helper' => 0,
'bhelper' => 0,
'hbhelper' => 0,
'delimiter' => 0,
+ 'subexp' => 0,
),
'usedCount' => array(
'var' => array(),
@@ -385,6 +407,7 @@ $libstr
'blockhelpers' => array(),
'hbhelpers' => array(),
'renderex' => isset($options['renderex']) ? $options['renderex'] : '',
+ 'lcrun' => isset($options['lcrun']) ? $options['lcrun'] : 'LCRun3',
);
$context['ops'] = $context['flags']['echo'] ? array(
@@ -470,6 +493,16 @@ $libstr
return static::compilePartial($name, $context, $cnt);
}
+ if (preg_match(static::IS_SUBEXP_SEARCH, $name)) {
+ if ($context['flags']['runpart']) {
+ $context['usedFeature']['dynpartial']++;
+ return;
+ } else {
+ $context['error'][] = "You use dynamic partial name as '$name', this only works with option FLAG_RUNTIMEPARTIAL enabled";
+ return;
+ }
+ }
+
if (!$context['flags']['skippartial']) {
$context['error'][] = "Can not find partial file for '$name', you should set correct basedir and fileext in options";
}
@@ -525,6 +558,8 @@ $libstr
if ($context['flags']['mustpi']) {
$sp = ', $sp';
$code = preg_replace('/^/m', "'{$context['ops']['seperator']}\$sp{$context['ops']['seperator']}'", $code);
+ // callbacks inside partial should be aware of $sp
+ $code = preg_replace('/\bfunction\s*\((.*?)\)\s*{/', 'function(\\1)use($sp){', $code);
} else {
$sp = '';
}
@@ -640,7 +675,7 @@ $libstr
return '';
}
- $class = new ReflectionClass('LCRun3');
+ $class = new ReflectionClass($context['lcrun']);
$fname = $class->getFileName();
$lines = file_get_contents($fname);
$file = new SplFileObject($fname);
@@ -693,7 +728,7 @@ $libstr
return 'array()';
}
- $class = new ReflectionClass('LCRun3');
+ $class = new ReflectionClass($context['lcrun']);
$constants = $class->getConstants();
$ret = " array(\n";
foreach($constants as $name => $value) {
@@ -790,19 +825,20 @@ $libstr
*
* @param string $php PHP code
* @param string|null $tmpDir Optional, change temp directory for php include file saved by prepare() when cannot include PHP code with data:// format.
+ * @param boolean $delete Optional, delete temp php file when set to tru. Default is true, set it to false for debug propose
*
* @return Closure|false result of include()
*
* @deprecated
*/
- public static function prepare($php, $tmpDir = null) {
+ public static function prepare($php, $tmpDir = null, $delete = true) {
if (!ini_get('allow_url_include') || !ini_get('allow_url_fopen')) {
- if (!$tmpDir || !is_dir($tmpDir)) {
+ if (!is_string($tmpDir) || !is_dir($tmpDir)) {
$tmpDir = sys_get_temp_dir();
}
}
- if ($tmpDir) {
+ if (is_dir($tmpDir)) {
$fn = tempnam($tmpDir, 'lci_');
if (!$fn) {
error_log("Can not generate tmp file under $tmpDir!!\n");
@@ -812,7 +848,14 @@ $libstr
error_log("Can not include saved temp php code from $fn, you should add $tmpDir into open_basedir!!\n");
return false;
}
- return include($fn);
+
+ $phpfunc = include($fn);
+
+ if ($delete) {
+ unlink($fn);
+ }
+
+ return $phpfunc;
}
return include('data://text/plain,' . urlencode($php));
@@ -827,10 +870,10 @@ $libstr
*
* @return string compiled Function name
*
- * @expect 'LCRun3::test(' when input array('flags' => array('standalone' => 0, 'debug' => 0)), 'test', ''
- * @expect 'LCRun3::test2(' when input array('flags' => array('standalone' => 0, 'debug' => 0)), 'test2', ''
- * @expect "\$cx['funcs']['test3'](" when input array('flags' => array('standalone' => 1, 'debug' => 0)), 'test3', ''
- * @expect 'LCRun3::debug(\'abc\', \'test\', ' when input array('flags' => array('standalone' => 0, 'debug' => 1)), 'test', 'abc'
+ * @expect 'LCRun3::test(' when input array('flags' => array('standalone' => 0, 'debug' => 0), 'lcrun' => 'LCRun3'), 'test', ''
+ * @expect 'LCRun3::test2(' when input array('flags' => array('standalone' => 0, 'debug' => 0), 'lcrun' => 'LCRun3'), 'test2', ''
+ * @expect "\$cx['funcs']['test3'](" when input array('flags' => array('standalone' => 1, 'debug' => 0), 'lcrun' => 'LCRun3'), 'test3', ''
+ * @expect 'LCRun3::debug(\'abc\', \'test\', ' when input array('flags' => array('standalone' => 0, 'debug' => 1), 'lcrun' => 'LCRun3'), 'test', 'abc'
*/
protected static function getFuncName(&$context, $name, $tag) {
static::addUsageCount($context, 'lcrun', $name);
@@ -843,7 +886,7 @@ $libstr
$dbg = '';
}
- return $context['flags']['standalone'] ? "\$cx['funcs']['$name']($dbg" : "LCRun3::$name($dbg";
+ return $context['flags']['standalone'] ? "\$cx['funcs']['$name']($dbg" : "{$context['lcrun']}::$name($dbg";
}
/**
@@ -883,7 +926,6 @@ $libstr
*
* @param array<array> $vn variable name array.
* @param array<string,array|string|integer> $context current compile context
- * @param boolean $ishelper true when compile for helper
*
* @return array<string|array> variable names
*
@@ -891,15 +933,11 @@ $libstr
* @expect array('array(array($in,$in),array())', array('this', 'this')) when input array(null, null), array('flags'=>array('spvar'=>true))
* @expect array('array(array(),array(\'a\'=>$in))', array('this')) when input array('a' => null), array('flags'=>array('spvar'=>true))
*/
- protected static function getVariableNames($vn, &$context, $ishelper = false) {
+ protected static function getVariableNames($vn, &$context) {
$vars = array(array(), array());
$exps = array();
foreach ($vn as $i => $v) {
- if (isset($v[0]) && preg_match('/^\(.+\)$/', $v[0])) {
- $V = static::compileSubExpression($v[0], $context);
- } else {
- $V = static::getVariableName($v, $context, $ishelper);
- }
+ $V = static::getVariableNameOrSubExpression($v, $context);
if (is_string($i)) {
$vars[1][] = "'$i'=>{$V[0]}";
} else {
@@ -915,16 +953,17 @@ $libstr
*
* @param string $subExpression subExpression to compile
* @param array<string,array|string|integer> $context current compile context
+ * @param boolean $keepCount keep original usage count
*
* @return array<string> code representing passed expression
*/
- protected static function compileSubExpression($subExpression, &$context) {
+ protected static function compileSubExpression($subExpression, &$context, $keepCount = false) {
// mock up a token for this expression
$token = array_fill(self::POS_LOTHER, self::POS_ROTHER, '');
// strip outer ( ) from subexpression
$token[self::POS_INNERTAG] = substr($subExpression, 1, -1);
-
+ $oldCount = $context['usedFeature'];
list(, $vars) = static::parseTokenArgs($token, $context);
// no separator is needed, this code will be used as a function argument
@@ -934,6 +973,21 @@ $libstr
$ret = static::compileCustomHelper($context, $vars, true, true);
$context['ops']['seperator'] = $origSeperator;
+ if ($keepCount) {
+ $context['usedFeature'] = $oldCount;
+ } else {
+ $context['usedFeature']['subexp']++;
+ // detect handlebars custom helpers.
+ if (isset($context['hbhelpers'][$vars[0][0]])) {
+ $context['usedFeature']['hbhelper']++;
+ } else {
+ // detect custom helpers.
+ if (isset($context['helpers'][$vars[0][0]])) {
+ $context['usedFeature']['helper']++;
+ }
+ }
+ }
+
return array($ret ? $ret : '', $subExpression);
}
@@ -942,47 +996,47 @@ $libstr
*
* @param array<array|string|integer> $var variable parsed path
* @param array<array|string|integer> $context current compile context
- * @param boolean $ishelper true when compile for helper$
+ *
+ * @return array<string> variable names
+ */
+ protected static function getVariableNameOrSubExpression($var, &$context) {
+ if (isset($var[0]) && preg_match(static::IS_SUBEXP_SEARCH, $var[0])) {
+ return static::compileSubExpression($var[0], $context, true);
+ }
+ return static::getVariableName($var, $context);
+ }
+
+ /**
+ * Internal method used by compile().
+ *
+ * @param array<array|string|integer> $var variable parsed path
+ * @param array<array|string|integer> $context current compile context
*
* @return array<string> variable names
*
* @expect array('$in', 'this') when input array(null), array('flags'=>array('spvar'=>true,'debug'=>0))
- * @expect array('true', 'true') when input array('true'), array('flags'=>array('spvar'=>true,'debug'=>0)), true
- * @expect array('false', 'false') when input array('false'), array('flags'=>array('spvar'=>true,'debug'=>0)), true
- * @expect array(2, '2') when input array('2'), array('flags'=>array('spvar'=>true,'debug'=>0)), true
+ * @expect array('((isset($in[\'true\']) && is_array($in)) ? $in[\'true\'] : null)', '[true]') when input array('true'), array('flags'=>array('spvar'=>true,'debug'=>0,'prop'=>0,'method'=>0,'mustlok'=>0))
+ * @expect array('((isset($in[\'false\']) && is_array($in)) ? $in[\'false\'] : null)', '[false]') when input array('false'), array('flags'=>array('spvar'=>true,'debug'=>0,'prop'=>0,'method'=>0,'mustlok'=>0))
+ * @expect array('true', 'true') when input array(0, 'true'), array('flags'=>array('spvar'=>true,'debug'=>0))
+ * @expect array('false', 'false') when input array(0, 'false'), array('flags'=>array('spvar'=>true,'debug'=>0))
+ * @expect array('((isset($in[\'2\']) && is_array($in)) ? $in[\'2\'] : null)', '[2]') when input array('2'), array('flags'=>array('spvar'=>true,'debug'=>0,'prop'=>0,'method'=>0,'mustlok'=>0))
+ * @expect array('2', '2') when input array(0, '2'), array('flags'=>array('spvar'=>true,'debug'=>0,'prop'=>0,'method'=>0))
* @expect array('((isset($in[\'@index\']) && is_array($in)) ? $in[\'@index\'] : null)', '[@index]') when input array('@index'), array('flags'=>array('spvar'=>false,'debug'=>0,'prop'=>0,'method'=>0,'mustlok'=>0))
- * @expect array("((isset(\$cx['sp_vars']['index']) && is_array(\$cx['sp_vars'])) ? \$cx['sp_vars']['index'] : null)", '@[index]') when input array('@index'), array('flags'=>array('spvar'=>true,'debug'=>0))
- * @expect array("((isset(\$cx['sp_vars']['key']) && is_array(\$cx['sp_vars'])) ? \$cx['sp_vars']['key'] : null)", '@[key]') when input array('@key'), array('flags'=>array('spvar'=>true,'debug'=>0))
- * @expect array("((isset(\$cx['sp_vars']['first']) && is_array(\$cx['sp_vars'])) ? \$cx['sp_vars']['first'] : null)", '@[first]') when input array('@first'), array('flags'=>array('spvar'=>true,'debug'=>0))
- * @expect array("((isset(\$cx['sp_vars']['last']) && is_array(\$cx['sp_vars'])) ? \$cx['sp_vars']['last'] : null)", '@[last]') when input array('@last'), array('flags'=>array('spvar'=>true,'debug'=>0))
- * @expect array('\'a\'', '"a"') when input array('"a"'), array('flags'=>array('spvar'=>true,'debug'=>0))
+ * @expect array("((isset(\$cx['sp_vars']['index']) && is_array(\$cx['sp_vars'])) ? \$cx['sp_vars']['index'] : null)", '@[index]') when input array('@index'), array('flags'=>array('spvar'=>true,'debug'=>0,'prop'=>0,'method'=>0,'mustlok'=>0))
+ * @expect array("((isset(\$cx['sp_vars']['key']) && is_array(\$cx['sp_vars'])) ? \$cx['sp_vars']['key'] : null)", '@[key]') when input array('@key'), array('flags'=>array('spvar'=>true,'debug'=>0,'prop'=>0,'method'=>0,'mustlok'=>0))
+ * @expect array("((isset(\$cx['sp_vars']['first']) && is_array(\$cx['sp_vars'])) ? \$cx['sp_vars']['first'] : null)", '@[first]') when input array('@first'), array('flags'=>array('spvar'=>true,'debug'=>0,'prop'=>0,'method'=>0,'mustlok'=>0))
+ * @expect array("((isset(\$cx['sp_vars']['last']) && is_array(\$cx['sp_vars'])) ? \$cx['sp_vars']['last'] : null)", '@[last]') when input array('@last'), array('flags'=>array('spvar'=>true,'debug'=>0,'prop'=>0,'method'=>0,'mustlok'=>0))
+ * @expect array('((isset($in[\'"a"\']) && is_array($in)) ? $in[\'"a"\'] : null)', '["a"]') when input array('"a"'), array('flags'=>array('spvar'=>true,'debug'=>0,'prop'=>0,'method'=>0,'mustlok'=>0))
+ * @expect array('"a"', '"a"') when input array(0, '"a"'), array('flags'=>array('spvar'=>true,'debug'=>0))
* @expect array('((isset($in[\'a\']) && is_array($in)) ? $in[\'a\'] : null)', '[a]') when input array('a'), array('flags'=>array('spvar'=>true,'debug'=>0,'prop'=>0,'method'=>0,'mustlok'=>0))
* @expect array('((isset($cx[\'scopes\'][count($cx[\'scopes\'])-1][\'a\']) && is_array($cx[\'scopes\'][count($cx[\'scopes\'])-1])) ? $cx[\'scopes\'][count($cx[\'scopes\'])-1][\'a\'] : null)', '../[a]') when input array(1,'a'), array('flags'=>array('spvar'=>true,'debug'=>0,'prop'=>0,'method'=>0,'mustlok'=>0))
* @expect array('((isset($cx[\'scopes\'][count($cx[\'scopes\'])-3][\'a\']) && is_array($cx[\'scopes\'][count($cx[\'scopes\'])-3])) ? $cx[\'scopes\'][count($cx[\'scopes\'])-3][\'a\'] : null)', '../../../[a]') when input array(3,'a'), array('flags'=>array('spvar'=>true,'debug'=>0,'prop'=>0,'method'=>0,'mustlok'=>0))
* @expect array('((isset($in[\'id\']) && is_array($in)) ? $in[\'id\'] : null)', 'this.[id]') when input array(null, 'id'), array('flags'=>array('spvar'=>true,'debug'=>0,'prop'=>0,'method'=>0,'mustlok'=>0))
- * @expect array('LCRun3::v($cx, $in, array(\'id\'))', 'this.[id]') when input array(null, 'id'), array('flags'=>array('prop'=>true,'spvar'=>true,'debug'=>0,'method'=>0,'mustlok'=>0,'standalone'=>0))
+ * @expect array('LCRun3::v($cx, $in, array(\'id\'))', 'this.[id]') when input array(null, 'id'), array('flags'=>array('prop'=>true,'spvar'=>true,'debug'=>0,'method'=>0,'mustlok'=>0,'standalone'=>0), 'lcrun' => 'LCRun3')
*/
- protected static function getVariableName($var, &$context, $ishelper = false) {
- if (isset($var[0])) {
- // Handle language constants or number , only for helpers
- if ($ishelper) {
- if ((count($var) == 1) && is_numeric($var[0])) {
- // convert 0x00 or 0b00 numbers to decimal
- return array((string) 1 * $var[0], $var[0]);
- }
- switch ($var[0]) {
- case 'true':
- return array('true', 'true');
- case 'false':
- return array('false', 'false');
- }
- }
-
- // Handle double quoted string
- if (preg_match('/^"(.*)"$/', $var[0], $matched)) {
- $t = addcslashes(stripslashes(preg_replace('/\\\\\\\\/', '\\', $matched[1])), "'");
- return array("'{$t}'", "\"{$t}\"");
- }
+ protected static function getVariableName($var, &$context) {
+ if (isset($var[0]) && ($var[0] === 0)) {
+ return array($var[1], preg_replace('/\'(.*)\'/', '$1', $var[1]));
}
$levels = 0;
@@ -994,7 +1048,9 @@ $libstr
if (!is_string($var[0]) && is_int($var[0])) {
$levels = array_shift($var);
}
+ }
+ if (isset($var[0])) {
// handle @root, @index, @key, @last, etc
if ($context['flags']['spvar']) {
if (substr($var[0], 0, 1) === '@') {
@@ -1003,14 +1059,14 @@ $libstr
$var[0] = substr($var[0], 1);
}
}
+ }
- // change base when trace to parent
- if ($levels > 0) {
- if ($spvar) {
- $base .= str_repeat("['_parent']", $levels);
- } else {
- $base = "\$cx['scopes'][count(\$cx['scopes'])-$levels]";
- }
+ // change base when trace to parent
+ if ($levels > 0) {
+ if ($spvar) {
+ $base .= str_repeat("['_parent']", $levels);
+ } else {
+ $base = "\$cx['scopes'][count(\$cx['scopes'])-$levels]";
}
}
@@ -1073,31 +1129,44 @@ $libstr
* @return array<integer,string> Return variable name array
*
* @expect array('this') when input 'this', array('flags' => array('advar' => 0, 'this' => 0))
- * @expect array(null) when input 'this', array('flags' => array('advar' => 0, 'this' => 1))
- * @expect array(1, null) when input '../', array('flags' => array('advar' => 0, 'this' => 1, 'parent' => 1), 'usedFeature' => array('parent' => 0))
- * @expect array(1, null) when input '../.', array('flags' => array('advar' => 0, 'this' => 1, 'parent' => 1), 'usedFeature' => array('parent' => 0))
- * @expect array(1, null) when input '../this', array('flags' => array('advar' => 0, 'this' => 1, 'parent' => 1), 'usedFeature' => array('parent' => 0))
- * @expect array(1, 'a') when input '../a', array('flags' => array('advar' => 0, 'this' => 1, 'parent' => 1), 'usedFeature' => array('parent' => 0))
- * @expect array(2, 'a', 'b') when input '../../a.b', array('flags' => array('advar' => 0, 'this' => 0, 'parent' => 1), 'usedFeature' => array('parent' => 0))
- * @expect array(2, '[a]', 'b') when input '../../[a].b', array('flags' => array('advar' => 0, 'this' => 0, 'parent' => 1), 'usedFeature' => array('parent' => 0))
- * @expect array(2, 'a', 'b') when input '../../[a].b', array('flags' => array('advar' => 1, 'this' => 0, 'parent' => 1), 'usedFeature' => array('parent' => 0))
- * @expect array('"a.b"') when input '"a.b"', array('flags' => array('advar' => 1, 'this' => 0, 'parent' => 1), 'usedFeature' => array('parent' => 0))
- * @expect array(null, 'id') when input 'this.id', array('flags' => array('advar' => 1, 'this' => 1, 'parent' => 1), 'usedFeature' => array('parent' => 0))
+ * @expect array() when input 'this', array('flags' => array('advar' => 0, 'this' => 1))
+ * @expect array(1) when input '../', array('flags' => array('advar' => 0, 'this' => 1, 'parent' => 1), 'usedFeature' => array('parent' => 0), 'scan' => true)
+ * @expect array(1) when input '../.', array('flags' => array('advar' => 0, 'this' => 1, 'parent' => 1), 'usedFeature' => array('parent' => 0), 'scan' => true)
+ * @expect array(1) when input '../this', array('flags' => array('advar' => 0, 'this' => 1, 'parent' => 1), 'usedFeature' => array('parent' => 0), 'scan' => true)
+ * @expect array(1, 'a') when input '../a', array('flags' => array('advar' => 0, 'this' => 1, 'parent' => 1), 'usedFeature' => array('parent' => 0), 'scan' => true)
+ * @expect array(2, 'a', 'b') when input '../../a.b', array('flags' => array('advar' => 0, 'this' => 0, 'parent' => 1), 'usedFeature' => array('parent' => 0), 'scan' => true)
+ * @expect array(2, '[a]', 'b') when input '../../[a].b', array('flags' => array('advar' => 0, 'this' => 0, 'parent' => 1), 'usedFeature' => array('parent' => 0), 'scan' => true)
+ * @expect array(2, 'a', 'b') when input '../../[a].b', array('flags' => array('advar' => 1, 'this' => 0, 'parent' => 1), 'usedFeature' => array('parent' => 0), 'scan' => true)
+ * @expect array('id') when input 'this.id', array('flags' => array('advar' => 1, 'this' => 1, 'parent' => 1), 'usedFeature' => array('parent' => 0))
+ * @expect array(0, '\'a.b\'') when input '"a.b"', array('flags' => array('advar' => 1, 'this' => 0, 'parent' => 1), 'usedFeature' => array('parent' => 0))
+ * @expect array(0, '123') when input '123', array('flags' => array('advar' => 1, 'this' => 0, 'parent' => 1), 'usedFeature' => array('parent' => 0))
+ * @expect array(0, 'null') when input 'null', array('flags' => array('advar' => 1, 'this' => 0, 'parent' => 1), 'usedFeature' => array('parent' => 0))
*/
protected static function fixVariable($v, &$context) {
- $ret = array();
- $levels = 0;
+ // handle number
+ if (is_numeric($v)) {
+ // convert 0x00 or 0b00 numbers to decimal
+ return array(0, (string) 1 * $v);
+ }
// handle double quoted string
if (preg_match('/^"(.*)"$/', $v, $matched)) {
- return array($v);
+ return array(0, "'" . preg_replace('/([^\\\\])\\\\\\\\"/', '$1"', preg_replace('/^\\\\\\\\"/', '"', $matched[1])) . "'");
}
// handle single quoted string
if (preg_match('/^\\\\\'(.*)\\\\\'$/', $v, $matched)) {
- return array("\"{$matched[1]}\"");
+ return array(0, "'$matched[1]'");
}
+ // handle boolean, null and undefined
+ if (preg_match('/^(true|false|null|undefined)$/', $v)) {
+ return array(0, ($v === 'undefined') ? 'null' : $v);
+ }
+
+ $ret = array();
+ $levels = 0;
+
// handle ..
if ($v === '..') {
$v = '../';
@@ -1114,7 +1183,7 @@ $libstr
if (!$context['flags']['parent']) {
$context['error'][] = 'Do not support {{../var}}, you should do compile with LightnCandy::FLAG_PARENT flag';
}
- $context['usedFeature']['parent']++;
+ $context['usedFeature']['parent'] += ($context['scan'] ? 1 : 0);
}
if ($context['flags']['advar'] && preg_match('/\\]/', $v)) {
@@ -1123,15 +1192,11 @@ $libstr
preg_match_all('/([^\\.\\/]+)/', $v, $matchedall);
}
- if (($v === '.') || ($v === '')) {
- $matchedall = array(array('.'), array('.'));
- }
-
foreach ($matchedall[1] as $m) {
if ($context['flags']['advar'] && substr($m, 0, 1) === '[') {
$ret[] = substr($m, 1, -1);
- } else {
- $ret[] = (($context['flags']['this'] && ($m === 'this')) || ($m === '.')) ? null : $m;
+ } else if ((!$context['flags']['this'] || ($m !== 'this')) && ($m !== '.')) {
+ $ret[] = $m;
}
}
@@ -1146,24 +1211,31 @@ $libstr
*
* @return array<boolean|array> Return parsed result
*
- * @expect array(false, array(array(null))) when input array(0,0,0,0,0,0,''), array('flags' => array('advar' => 0, 'this' => 1, 'namev' => 0, 'noesc' => 0))
- * @expect array(true, array(array(null))) when input array(0,0,0,'{{{',0,0,''), array('flags' => array('advar' => 0, 'this' => 1, 'namev' => 0, 'noesc' => 0))
- * @expect array(true, array(array(null))) when input array(0,0,0,0,0,0,''), array('flags' => array('advar' => 0, 'this' => 1, 'namev' => 0, 'noesc' => 1))
- * @expect array(false, array(array('a'))) when input array(0,0,0,0,0,0,'a'), array('flags' => array('advar' => 0, 'this' => 1, 'namev' => 0, 'noesc' => 0))
- * @expect array(false, array(array('a'), array('b'))) when input array(0,0,0,0,0,0,'a b'), array('flags' => array('advar' => 0, 'this' => 1, 'namev' => 0, 'noesc' => 0))
- * @expect array(false, array(array('a'), array('"b'), array('c"'))) when input array(0,0,0,0,0,0,'a "b c"'), array('flags' => array('advar' => 0, 'this' => 1, 'namev' => 0, 'noesc' => 0))
- * @expect array(false, array(array('a'), array('"b c"'))) when input array(0,0,0,0,0,0,'a "b c"'), array('flags' => array('advar' => 1, 'this' => 1, 'namev' => 0, 'noesc' => 0))
- * @expect array(false, array(array('a'), array('[b'), array('c]'))) when input array(0,0,0,0,0,0,'a [b c]'), array('flags' => array('advar' => 0, 'this' => 1, 'namev' => 0, 'noesc' => 0))
- * @expect array(false, array(array('a'), array('[b'), array('c]'))) when input array(0,0,0,0,0,0,'a [b c]'), array('flags' => array('advar' => 0, 'this' => 1, 'namev' => 1, 'noesc' => 0))
- * @expect array(false, array(array('a'), array('b c'))) when input array(0,0,0,0,0,0,'a [b c]'), array('flags' => array('advar' => 1, 'this' => 1, 'namev' => 0, 'noesc' => 0))
- * @expect array(false, array(array('a'), array('b c'))) when input array(0,0,0,0,0,0,'a [b c]'), array('flags' => array('advar' => 1, 'this' => 1, 'namev' => 1, 'noesc' => 0))
- * @expect array(false, array(array('a'), 'q' => array('b c'))) when input array(0,0,0,0,0,0,'a q=[b c]'), array('flags' => array('advar' => 1, 'this' => 1, 'namev' => 1, 'noesc' => 0))
- * @expect array(false, array(array('a'), array('q=[b c'))) when input array(0,0,0,0,0,0,'a [q=[b c]'), array('flags' => array('advar' => 1, 'this' => 1, 'namev' => 1, 'noesc' => 0))
- * @expect array(false, array(array('a'), 'q' => array('[b'), array('c]'))) when input array(0,0,0,0,0,0,'a q=[b c]'), array('flags' => array('advar' => 0, 'this' => 1, 'namev' => 1, 'noesc' => 0))
- * @expect array(false, array(array('a'), 'q' => array('b'), array('c'))) when input array(0,0,0,0,0,0,'a [q]=b c'), array('flags' => array('advar' => 0, 'this' => 1, 'namev' => 1, 'noesc' => 0))
- * @expect array(false, array(array('a'), 'q' => array('"b c"'))) when input array(0,0,0,0,0,0,'a q="b c"'), array('flags' => array('advar' => 1, 'this' => 1, 'namev' => 1, 'noesc' => 0))
- * @expect array(false, array(array('(foo bar)'))) when input array(0,0,0,0,0,0,'(foo bar)'), array('flags' => array('advar' => 1, 'this' => 1, 'namev' => 1, 'noesc' => 0))
- * @expect array(false, array(array('foo'), array("'=='"), array('bar'))) when input array(0,0,0,0,0,0,"foo '==' bar"), array('flags' => array('advar' => 1, 'namev' => 1))
+ * @expect array(false, array(array())) when input array(0,0,0,0,0,0,''), array('flags' => array('advar' => 0, 'this' => 1, 'namev' => 0, 'noesc' => 0), 'scan' => false)
+ * @expect array(true, array(array())) when input array(0,0,0,'{{{',0,0,''), array('flags' => array('advar' => 0, 'this' => 1, 'namev' => 0, 'noesc' => 0), 'scan' => false)
+ * @expect array(true, array(array())) when input array(0,0,0,0,0,0,''), array('flags' => array('advar' => 0, 'this' => 1, 'namev' => 0, 'noesc' => 1), 'scan' => false)
+ * @expect array(false, array(array('a'))) when input array(0,0,0,0,0,0,'a'), array('flags' => array('advar' => 0, 'this' => 1, 'namev' => 0, 'noesc' => 0), 'scan' => false)
+ * @expect array(false, array(array('a'), array('b'))) when input array(0,0,0,0,0,0,'a b'), array('flags' => array('advar' => 0, 'this' => 1, 'namev' => 0, 'noesc' => 0), 'scan' => false)
+ * @expect array(false, array(array('a'), array('"b'), array('c"'))) when input array(0,0,0,0,0,0,'a "b c"'), array('flags' => array('advar' => 0, 'this' => 1, 'namev' => 0, 'noesc' => 0), 'scan' => false)
+ * @expect array(false, array(array('a'), array(0, '\'b c\''))) when input array(0,0,0,0,0,0,'a "b c"'), array('flags' => array('advar' => 1, 'this' => 1, 'namev' => 0, 'noesc' => 0), 'scan' => false)
+ * @expect array(false, array(array('a'), array('[b'), array('c]'))) when input array(0,0,0,0,0,0,'a [b c]'), array('flags' => array('advar' => 0, 'this' => 1, 'namev' => 0, 'noesc' => 0), 'scan' => false)
+ * @expect array(false, array(array('a'), array('[b'), array('c]'))) when input array(0,0,0,0,0,0,'a [b c]'), array('flags' => array('advar' => 0, 'this' => 1, 'namev' => 1, 'noesc' => 0), 'scan' => false)
+ * @expect array(false, array(array('a'), array('b c'))) when input array(0,0,0,0,0,0,'a [b c]'), array('flags' => array('advar' => 1, 'this' => 1, 'namev' => 0, 'noesc' => 0), 'scan' => false)
+ * @expect array(false, array(array('a'), array('b c'))) when input array(0,0,0,0,0,0,'a [b c]'), array('flags' => array('advar' => 1, 'this' => 1, 'namev' => 1, 'noesc' => 0), 'scan' => false)
+ * @expect array(false, array(array('a'), 'q' => array('b c'))) when input array(0,0,0,0,0,0,'a q=[b c]'), array('flags' => array('advar' => 1, 'this' => 1, 'namev' => 1, 'noesc' => 0), 'scan' => false)
+ * @expect array(false, array(array('a'), array('q=[b c'))) when input array(0,0,0,0,0,0,'a [q=[b c]'), array('flags' => array('advar' => 1, 'this' => 1, 'namev' => 1, 'noesc' => 0), 'scan' => false)
+ * @expect array(false, array(array('a'), 'q' => array('[b'), array('c]'))) when input array(0,0,0,0,0,0,'a q=[b c]'), array('flags' => array('advar' => 0, 'this' => 1, 'namev' => 1, 'noesc' => 0), 'scan' => false)
+ * @expect array(false, array(array('a'), 'q' => array('b'), array('c'))) when input array(0,0,0,0,0,0,'a [q]=b c'), array('flags' => array('advar' => 0, 'this' => 1, 'namev' => 1, 'noesc' => 0), 'scan' => false)
+ * @expect array(false, array(array('a'), 'q' => array(0, '\'b c\''))) when input array(0,0,0,0,0,0,'a q="b c"'), array('flags' => array('advar' => 1, 'this' => 1, 'namev' => 1, 'noesc' => 0), 'scan' => false)
+ * @expect array(false, array(array('(foo bar)'))) when input array(0,0,0,0,0,0,'(foo bar)'), array('flags' => array('advar' => 1, 'this' => 1, 'namev' => 1, 'noesc' => 0, 'exhlp' => 1), 'ops' => array('seperator' => ''), 'usedFeature' => array('subexp' => 0), 'scan' => false)
+ * @expect array(false, array(array('foo'), array("'=='"), array('bar'))) when input array(0,0,0,0,0,0,"foo '==' bar"), array('flags' => array('advar' => 1, 'namev' => 1, 'noesc' => 0, 'this' => 0), 'scan' => false)
+ * @expect array(false, array(array('( foo bar)'))) when input array(0,0,0,0,0,0,'( foo bar)'), array('flags' => array('advar' => 1, 'this' => 1, 'namev' => 1, 'noesc' => 0, 'exhlp' => 1), 'ops' => array('seperator' => ''), 'usedFeature' => array('subexp' => 0), 'scan' => false)
+ * @expect array(false, array(array('a'), array(0, '\' b c\''))) when input array(0,0,0,0,0,0,'a " b c"'), array('flags' => array('advar' => 1, 'this' => 1, 'namev' => 0, 'noesc' => 0), 'scan' => false)
+ * @expect array(false, array(array('a'), 'q' => array(0, '\' b c\''))) when input array(0,0,0,0,0,0,'a q=" b c"'), array('flags' => array('advar' => 1, 'this' => 1, 'namev' => 1, 'noesc' => 0), 'scan' => false)
+ * @expect array(false, array(array('foo'), array(0, "' =='"), array('bar'))) when input array(0,0,0,0,0,0,"foo \' ==\' bar"), array('flags' => array('advar' => 1, 'namev' => 1, 'noesc' => 0, 'this' => 0), 'scan' => false)
+ * @expect array(false, array(array('a'), array(' b c'))) when input array(0,0,0,0,0,0,'a [ b c]'), array('flags' => array('advar' => 1, 'this' => 1, 'namev' => 1, 'noesc' => 0), 'scan' => false)
+ * @expect array(false, array(array('a'), 'q' => array(0, "' d e'"))) when input array(0,0,0,0,0,0,"a q=\' d e\'"), array('flags' => array('advar' => 1, 'this' => 1, 'namev' => 1, 'noesc' => 0), 'scan' => false)
+ * @expect array(false, array('q' => array('( foo bar)'))) when input array(0,0,0,0,0,0,'q=( foo bar)'), array('flags' => array('advar' => 1, 'this' => 1, 'namev' => 1, 'noesc' => 0), 'scan' => false)
*/
protected static function parseTokenArgs(&$token, &$context) {
trim($token[self::POS_INNERTAG]);
@@ -1175,6 +1247,11 @@ $libstr
return array(false, array());
}
+ // Skip validation on comments
+ if ($token[self::POS_OP] === '!') {
+ return array(false, array());
+ }
+
$vars = array();
$count = preg_match_all('/(\s*)([^\s]+)/', $token[self::POS_INNERTAG], $matchedall);
@@ -1196,46 +1273,54 @@ $libstr
}
// continue to next match when begin with '(' without ending ')'
- if (preg_match('/^\([^\)]+$/', $t)) {
+ if (preg_match('/^\([^\)]*$/', $t)) {
$prev = $t;
$expect = ')';
continue;
}
// continue to next match when begin with '"' without ending '"'
- if (preg_match('/^"[^"]+$/', $t)) {
+ if (preg_match('/^"[^"]*$/', $t)) {
$prev = $t;
$expect = '"';
continue;
}
+ // continue to next match when begin with \' without ending '
+ if (preg_match('/^\\\\\'[^\']*$/', $t)) {
+ $prev = $t;
+ $expect = '\'';
+ continue;
+ }
+
// continue to next match when '="' exists without ending '"'
- if (preg_match('/="[^"]+$/', $t)) {
+ if (preg_match('/^[^"]*="[^"]*$/', $t)) {
$prev = $t;
$expect = '"';
continue;
}
- // continue to next match when begin with \' without ending '
- if (preg_match('/^\\\\\'[^\']+$/', $t)) {
+ // continue to next match when '[' exists without ending ']'
+ if (preg_match('/\\[[^\\]]*$/', $t)) {
$prev = $t;
- $expect = '\'';
+ $expect = ']';
continue;
}
// continue to next match when =\' exists without ending '
- if (preg_match('/=\\\\\'[^\']+$/', $t)) {
+ if (preg_match('/^[^\']*=\\\\\'[^\']*$/', $t)) {
$prev = $t;
$expect = '\'';
continue;
}
- // continue to next match when '[' exists without ending ']'
- if (preg_match('/\\[[^\\]]+$/', $t)) {
+ // continue to next match when =( exists without ending )
+ if (preg_match('/.+\([^\)]*$/', $t)) {
$prev = $t;
- $expect = ']';
+ $expect = ')';
continue;
}
+
$vars[] = $t;
}
} else {
@@ -1247,7 +1332,8 @@ $libstr
$i = 0;
foreach ($vars as $idx => $var) {
// Skip advanced processing for subexpressions
- if (preg_match('/^\(.+\)$/', $var)) {
+ if (preg_match(static::IS_SUBEXP_SEARCH, $var)) {
+ static::compileSubExpression($var, $context, !$context['scan']);
$ret[$i] = array($var);
$i++;
continue;
@@ -1262,7 +1348,9 @@ $libstr
$var = $m[5];
}
}
- if ($context['flags']['advar']) {
+
+ $esc = $context['scan'] ? '' : '\\\\';
+ if ($context['flags']['advar'] && !preg_match("/^(\"|$esc')(.*)(\"|$esc')$/", $var)) {
// foo] Rule 1: no starting [ or [ not start from head
if (preg_match('/^[^\\[\\.]+[\\]\\[]/', $var)
// [bar Rule 2: no ending ] or ] not in the end
@@ -1273,13 +1361,22 @@ $libstr
|| preg_match('/\\.[^\\]\\[\\.]+\\[/', preg_replace('/^(..\\/)+/', '', preg_replace('/\\[[^\\]]+\\]/', '[XXX]', $var)))
) {
$context['error'][] = "Wrong variable naming as '$var' in " . static::tokenString($token) . ' !';
+ } else {
+ if (!$context['scan']) {
+ $name = preg_replace('/(\\[.+?\\])/', '', $var);
+ // Scan for invalid charactors which not be protected by [ ]
+ // now make ( and ) pass, later fix
+ if (preg_match('/[!"#%\'*+,;<=>{|}~]/', $name)) {
+ $context['error'][] = "Wrong variable naming as '$var' in " . static::tokenString($token) . ' ! You should wrap ! " # % & \' * + , ; < = > { | } ~ into [ ]';
+ }
+ }
}
}
if (($idx === 0) && ($token[self::POS_OP] === '>')) {
$var = array(preg_replace('/^("(.+)")|(\\[(.+)\\])$/', '$2$4', $var));
- } else if (is_numeric($var)) {
- $var = array('"' . $var . '"');
+ } else if (preg_match('/^\(.+\)$/', $var)) {
+ $var = array($var);
} else {
$var = static::fixVariable($var, $context);
}
@@ -1368,7 +1465,7 @@ $libstr
return ++$context['usedFeature']['delimiter'];
case '^':
- if ($vars[0][0]) {
+ if (isset($vars[0][0])) {
$context['stack'][] = $token[self::POS_INNERTAG];
$context['level']++;
return ++$context['usedFeature']['isec'];
@@ -1391,14 +1488,20 @@ $libstr
$context['stack'][] = $token[self::POS_INNERTAG];
$context['level']++;
- // detect handlebars custom helpers.
- if (isset($context['hbhelpers'][$vars[0][0]])) {
- return ++$context['usedFeature']['hbhelper'];
+ if (!isset($vars[0][0])) {
+ return;
}
- // detect block custom helpers.
- if (isset($context['blockhelpers'][$vars[0][0]])) {
- return ++$context['usedFeature']['bhelper'];
+ if (is_string($vars[0][0])) {
+ // detect handlebars custom helpers.
+ if (isset($context['hbhelpers'][$vars[0][0]])) {
+ return ++$context['usedFeature']['hbhelper'];
+ }
+
+ // detect block custom helpers.
+ if (isset($context['blockhelpers'][$vars[0][0]])) {
+ return ++$context['usedFeature']['bhelper'];
+ }
}
switch ($vars[0][0]) {
@@ -1457,20 +1560,23 @@ $libstr
$context['usedFeature'][$raw ? 'raw' : 'enc']++;
}
- // validate else and this.
- switch ($vars[0][0]) {
- case 'else':
- if ($context['flags']['else']) {
- return $context['usedFeature']['else']++;
- }
- break;
-
- case 'this':
- case '.':
+ foreach ($vars as $var) {
+ if (!isset($var[0])) {
if ($context['level'] == 0) {
$context['usedFeature']['rootthis']++;
}
- return $context['usedFeature'][($vars[0] == '.') ? 'dot' : 'this']++;
+ $context['usedFeature']['this']++;
+ }
+ }
+
+ if (!isset($vars[0][0])) {
+ return;
+ }
+
+ if ($vars[0][0] === 'else') {
+ if ($context['flags']['else']) {
+ return $context['usedFeature']['else']++;
+ }
}
// detect handlebars custom helpers.
@@ -1592,12 +1698,13 @@ $libstr
return $ret;
}
- if ($ret = static::compileCustomHelper($context, $vars, $raw)) {
- return $ret;
- }
-
- if ($ret = static::compileElse($context, $vars)) {
- return $ret;
+ if (isset($vars[0][0])) {
+ if ($ret = static::compileCustomHelper($context, $vars, $raw)) {
+ return $ret;
+ }
+ if ($ret = static::compileElse($context, $vars)) {
+ return $ret;
+ }
}
static::noNamedArguments($token, $context, $named, ', maybe you missing the custom helper?');
@@ -1619,27 +1726,31 @@ $libstr
switch ($token[self::POS_OP]) {
case '>':
// mustache spec: ignore missing partial
- if (!isset($context['usedPartial'][$vars[0][0]])) {
+ if (($context['usedFeature']['dynpartial'] === 0) && !isset($context['usedPartial'][$vars[0][0]])) {
return $context['ops']['seperator'];
}
$p = array_shift($vars);
if (!isset($vars[0])) {
$vars[0] = array();
}
- $v = static::getVariableNames($vars, $context, true);
+ $v = static::getVariableNames($vars, $context);
$tag = ">$p[0] " .implode(' ', $v[1]);
if ($context['flags']['runpart']) {
- $sp = $context['tokens']['partialind'] ? ", '{$context['tokens']['partialind']}'" : '';
- return $context['ops']['seperator'] . static::getFuncName($context, 'p', $tag) . "\$cx, '$p[0]', $v[0]$sp){$context['ops']['seperator']}";
- } else {
- if ($named || $v[0] !== 'array(array($in),array())') {
- $context['error'][] = "Do not support {{{$tag}}}, you should do compile with LightnCandy::FLAG_RUNTIMEPARTIAL flag";
+ if (preg_match(static::IS_SUBEXP_SEARCH, $p[0])) {
+ list($p) = static::compileSubExpression($p[0], $context);
+ } else {
+ $p = "'$p[0]'";
}
- return "{$context['ops']['seperator']}'" . static::compileTemplate($context, preg_replace('/^/m', $context['tokens']['partialind'], $context['usedPartial'][$p[0]]), $p[0]) . "'{$context['ops']['seperator']}";
+ $sp = $context['tokens']['partialind'] ? ", '{$context['tokens']['partialind']}'" : '';
+ return $context['ops']['seperator'] . static::getFuncName($context, 'p', $tag) . "\$cx, $p, $v[0]$sp){$context['ops']['seperator']}";
}
+ if ($named || $v[0] !== 'array(array($in),array())') {
+ $context['error'][] = "Do not support {{{$tag}}}, you should do compile with LightnCandy::FLAG_RUNTIMEPARTIAL flag";
+ }
+ return "{$context['ops']['seperator']}'" . static::compileTemplate($context, preg_replace('/^/m', $context['tokens']['partialind'], $context['usedPartial'][$p[0]]), $p[0]) . "'{$context['ops']['seperator']}";
case '^':
// {{^}} means {{else}}
- if (!$vars[0][0]) {
+ if (!isset($vars[0][0])) {
$vars[0][0] = 'else';
$token[self::POS_OP] = '';
return;
@@ -1647,7 +1758,7 @@ $libstr
// Try to compile as custom helper {{^myHelper}}
$r = static::compileBlockCustomHelper($context, $vars, true);
- if ($r) {
+ if ($r !== null) {
return $r;
}
@@ -1665,7 +1776,7 @@ $libstr
case '#':
// Try to compile as custom helper {{#myHelper}}
$r = static::compileBlockCustomHelper($context, $vars);
- if ($r) {
+ if ($r !== null) {
return $r;
}
static::noNamedArguments($token, $context, $named, ', maybe you missing the block custom helper?');
@@ -1684,6 +1795,9 @@ $libstr
* @return string|null Return compiled code segment for the token
*/
protected static function compileBlockCustomHelper(&$context, $vars, $inverted = false) {
+ if (!isset($vars[0][0])) {
+ return;
+ }
$notHBCH = !isset($context['hbhelpers'][$vars[0][0]]);
if (!isset($context['blockhelpers'][$vars[0][0]]) && $notHBCH) {
@@ -1697,7 +1811,7 @@ $libstr
$inverted = $inverted ? 'true' : 'false';
static::addUsageCount($context, $notHBCH ? 'blockhelpers' : 'hbhelpers', $ch[0]);
- $v = static::getVariableNames($vars, $context, true);
+ $v = static::getVariableNames($vars, $context);
return $context['ops']['seperator'] . static::getFuncName($context, $notHBCH ? 'bch' : 'hbch', ($inverted ? '^' : '#') . implode(' ', $v[1])) . "\$cx, '$ch[0]', {$v[0]}, \$in, $inverted, function(\$cx, \$in) {{$context['ops']['f_start']}";
}
@@ -1763,8 +1877,8 @@ $libstr
*/
protected static function compileBlockBegin(&$context, $vars) {
$each = 'false';
- $v = isset($vars[1]) ? static::getVariableName($vars[1], $context, true) : array(null, array());
- switch ($vars[0][0]) {
+ $v = isset($vars[1]) ? static::getVariableNameOrSubExpression($vars[1], $context) : array(null, array());
+ switch (isset($vars[0][0]) ? $vars[0][0] : null) {
case 'if':
$context['stack'][] = 'if';
return $context['usedFeature']['parent']
@@ -1789,7 +1903,7 @@ $libstr
}
}
- $v = static::getVariableName($vars[0], $context);
+ $v = static::getVariableNameOrSubExpression($vars[0], $context);
$context['stack'][] = $v[1];
$context['stack'][] = '#';
return $context['ops']['seperator'] . static::getFuncName($context, 'sec', (($each == 'true') ? 'each ' : '') . $v[1]) . "\$cx, {$v[0]}, \$in, $each, function(\$cx, \$in) {{$context['ops']['f_start']}";
@@ -1805,20 +1919,22 @@ $libstr
*
* @return string|null Return compiled code segment for the token when the token is custom helper
*/
- protected static function compileCustomHelper(&$context, &$vars, $raw, $err = false) {
+ protected static function compileCustomHelper(&$context, $vars, $raw, $err = false) {
$notHH = !isset($context['hbhelpers'][$vars[0][0]]);
if (!isset($context['helpers'][$vars[0][0]]) && $notHH) {
if ($err) {
- $context['error'][] = "Custom helper '{$vars[0][0]}' not found!";
+ if (!$context['flags']['exhlp']) {
+ $context['error'][] = "Can not find custom helper function defination {$vars[0][0]}() !";
+ }
}
return;
}
$fn = $raw ? 'raw' : $context['ops']['enc'];
$ch = array_shift($vars);
- $v = static::getVariableNames($vars, $context, true);
+ $v = static::getVariableNames($vars, $context);
static::addUsageCount($context, $notHH ? 'helpers' : 'hbhelpers', $ch[0]);
- return $context['ops']['seperator'] . static::getFuncName($context, $notHH ? 'ch' : 'hbch', "$ch[0] " . implode(' ', $v[1])) . "\$cx, '$ch[0]', {$v[0]}, '$fn'" . ($notHH ? '' : ', \'$in\'') . "){$context['ops']['seperator']}";
+ return $context['ops']['seperator'] . static::getFuncName($context, $notHH ? 'ch' : 'hbch', "$ch[0] " . implode(' ', $v[1])) . "\$cx, '$ch[0]', {$v[0]}, '$fn'" . ($notHH ? '' : ', $in') . "){$context['ops']['seperator']}";
}
/**
@@ -1842,6 +1958,7 @@ $libstr
case 'each':
case '#':
return "{$context['ops']['f_end']}}, function(\$cx, \$in) {{$context['ops']['f_start']}";
+ default:
}
}
$context['error'][] = '{{else}} only valid in if, unless, each, and #section context';
@@ -1903,12 +2020,12 @@ class LCRun3 {
* @param string $f runtime function name
* @param array<string,array|string|integer> $cx render time context
*
- * @expect '{{123}}' when input '123', 'miss', array('flags' => array('debug' => LCRun3::DEBUG_TAGS)), ''
- * @expect '<!--MISSED((-->{{#123}}<!--))--><!--SKIPPED--><!--MISSED((-->{{/123}}<!--))-->' when input '123', 'wi', array('flags' => array('debug' => LCRun3::DEBUG_TAGS_HTML)), false, false, function () {return 'A';}
+ * @expect '{{123}}' when input '123', 'miss', array('flags' => array('debug' => LCRun3::DEBUG_TAGS), 'lcrun' => 'LCRun3'), ''
+ * @expect '<!--MISSED((-->{{#123}}<!--))--><!--SKIPPED--><!--MISSED((-->{{/123}}<!--))-->' when input '123', 'wi', array('flags' => array('debug' => LCRun3::DEBUG_TAGS_HTML), 'lcrun' => 'LCRun3'), false, false, function () {return 'A';}
*/
public static function debug($v, $f, $cx) {
$params = array_slice(func_get_args(), 2);
- $r = call_user_func_array((isset($cx['funcs'][$f]) ? $cx['funcs'][$f] : "LCRun3::$f"), $params);
+ $r = call_user_func_array((isset($cx['funcs'][$f]) ? $cx['funcs'][$f] : "{$cx['lcrun']}::$f"), $params);
if ($cx['flags']['debug'] & self::DEBUG_TAGS) {
$ansi = $cx['flags']['debug'] & (self::DEBUG_TAGS_ANSI - self::DEBUG_TAGS);
@@ -1999,10 +2116,14 @@ class LCRun3 {
return $v;
}
$count--;
- if ($count >= 0) {
- $base = $cx['scopes'][$count];
- } else {
- return null;
+ switch ($count) {
+ case -1:
+ $base = $cx['sp_vars']['root'];
+ break;
+ case -2:
+ return null;
+ default:
+ $base = $cx['scopes'][$count];
}
}
}
@@ -2026,7 +2147,7 @@ class LCRun3 {
* @expect true when input array(), array(0)
*/
public static function ifvar($cx, $v) {
- return !is_null($v) && ($v !== false) && ($v !== 0) && ($v !== '') && (is_array($v) ? (count($v) > 0) : true);
+ return !is_null($v) && ($v !== false) && ($v !== 0) && ($v !== 0.0) && ($v !== '') && (is_array($v) ? (count($v) > 0) : true);
}
/**
@@ -2149,6 +2270,8 @@ class LCRun3 {
}
return join(',', $ret);
}
+ } else {
+ return 'Array';
}
}
@@ -2207,11 +2330,11 @@ class LCRun3 {
* @expect '-a=' when input array('flags' => array('spvar' => 0)), array('a'), array('a'), false, function ($c, $i) {return "-$i=";}
* @expect '-a=-b=' when input array('flags' => array('spvar' => 0)), array('a','b'), array('a','b'), false, function ($c, $i) {return "-$i=";}
* @expect '' when input array('flags' => array('spvar' => 0)), 'abc', 'abc', true, function ($c, $i) {return "-$i=";}
- * @expect '-b=' when input array('flags' => array('spvar' => 0, 'mustsec' => 0)), array('a' => 'b'), array('a' => 'b'), true, function ($c, $i) {return "-$i=";}
+ * @expect '-b=' when input array('flags' => array('spvar' => 0)), array('a' => 'b'), array('a' => 'b'), true, function ($c, $i) {return "-$i=";}
* @expect '1' when input array('flags' => array('spvar' => 0)), 'b', 'b', false, function ($c, $i) {return count($i);}
* @expect '1' when input array('flags' => array('spvar' => 0)), 1, 1, false, function ($c, $i) {return print_r($i, true);}
* @expect '0' when input array('flags' => array('spvar' => 0)), 0, 0, false, function ($c, $i) {return print_r($i, true);}
- * @expect '{"b":"c"}' when input array('flags' => array('spvar' => 0, 'mustsec' => 0)), array('b' => 'c'), array('b' => 'c'), false, function ($c, $i) {return json_encode($i);}
+ * @expect '{"b":"c"}' when input array('flags' => array('spvar' => 0)), array('b' => 'c'), array('b' => 'c'), false, function ($c, $i) {return json_encode($i);}
* @expect 'inv' when input array('flags' => array('spvar' => 0)), array(), 0, true, function ($c, $i) {return 'cb';}, function ($c, $i) {return 'inv';}
* @expect 'inv' when input array('flags' => array('spvar' => 0)), array(), 0, false, function ($c, $i) {return 'cb';}, function ($c, $i) {return 'inv';}
* @expect 'inv' when input array('flags' => array('spvar' => 0)), false, 0, true, function ($c, $i) {return 'cb';}, function ($c, $i) {return 'inv';}
@@ -2222,8 +2345,8 @@ class LCRun3 {
* @expect 'cb' when input array('flags' => array('spvar' => 0)), 0, 0, false, function ($c, $i) {return 'cb';}, function ($c, $i) {return 'inv';}
* @expect 'inv' when input array('flags' => array('spvar' => 0)), new stdClass, 0, true, function ($c, $i) {return 'cb';}, function ($c, $i) {return 'inv';}
* @expect 'cb' when input array('flags' => array('spvar' => 0)), new stdClass, 0, false, function ($c, $i) {return 'cb';}, function ($c, $i) {return 'inv';}
- * @expect '268' when input array('flags' => array('spvar' => 1)), array(1,3,4), 0, false, function ($c, $i) {return $i * 2;}
- * @expect '038' when input array('flags' => array('spvar' => 1), 'sp_vars'=>array()), array(1,3,'a'=>4), 0, true, function ($c, $i) {return $i * $c['sp_vars']['index'];}
+ * @expect '268' when input array('flags' => array('spvar' => 1), 'sp_vars'=>array('root' => 0)), array(1,3,4), 0, false, function ($c, $i) {return $i * 2;}
+ * @expect '038' when input array('flags' => array('spvar' => 1), 'sp_vars'=>array('root' => 0)), array(1,3,'a'=>4), 0, true, function ($c, $i) {return $i * $c['sp_vars']['index'];}
*/
public static function sec($cx, $v, $in, $each, $cb, $else = null) {
$isAry = is_array($v);
@@ -2234,7 +2357,10 @@ class LCRun3 {
$isObj = false;
if ($isAry && $else !== null && count($v) === 0) {
- return $else($cx, $in);
+ $cx['scopes'][] = $in;
+ $ret = $else($cx, $in);
+ array_pop($cx['scopes']);
+ return $ret;
}
// #var, detect input type is object or not
@@ -2298,13 +2424,9 @@ class LCRun3 {
return '';
}
if ($isAry) {
- if ($cx['flags']['mustsec']) {
- $cx['scopes'][] = $v;
- }
+ $cx['scopes'][] = $in;
$ret = $cb($cx, $v);
- if ($cx['flags']['mustsec']) {
- array_pop($cx['scopes']);
- }
+ array_pop($cx['scopes']);
return $ret;
}
@@ -2317,7 +2439,10 @@ class LCRun3 {
}
if ($else !== null) {
- return $else($cx, $in);
+ $cx['scopes'][] = $in;
+ $ret = $else($cx, $in);
+ array_pop($cx['scopes']);
+ return $ret;
}
return '';
@@ -2336,8 +2461,8 @@ class LCRun3 {
*
* @expect '' when input array(), false, false, function () {return 'A';}
* @expect '' when input array(), null, null, function () {return 'A';}
- * @expect '-Array=' when input array(), array('a'=>'b'), array('a' => 'b'), function ($c, $i) {return "-$i=";}
- * @expect '-b=' when input array(), 'b', array('a' => 'b'), function ($c, $i) {return "-$i=";}
+ * @expect '{"a":"b"}' when input array(), array('a'=>'b'), array('a'=>'c'), function ($c, $i) {return json_encode($i);}
+ * @expect '-b=' when input array(), 'b', array('a'=>'b'), function ($c, $i) {return "-$i=";}
*/
public static function wi($cx, $v, $in, $cb, $else = null) {
if (($v === false) || ($v === null)) {
@@ -2360,7 +2485,19 @@ class LCRun3 {
*
*/
public static function p($cx, $p, $v, $sp = '') {
- return call_user_func($cx['partials'][$p], $cx, is_array($v[0][0]) ? array_merge($v[0][0], $v[1]) : $v[0][0], $sp);
+ $param = $v[0][0];
+
+ if (is_array($v[1])) {
+ if (is_array($v[0][0])) {
+ $param = array_merge($v[0][0], $v[1]);
+ } else if (($cx['flags']['method'] || $cx['flags']['prop']) && is_object($v[0][0])) {
+ foreach ($v[1] as $i => $v) {
+ $param->$i = $v;
+ }
+ }
+ }
+
+ return call_user_func($cx['partials'][$p], $cx, $param, $sp);
}
/**
@@ -2425,17 +2562,18 @@ class LCRun3 {
* @param array<array|string|integer>|string|integer|null $vars variables for the helper
* @param string $op the name of variable resolver. should be one of: 'raw', 'enc', or 'encq'.
* @param boolean $inverted the logic will be inverted
- * @param Closure $cb callback function to render child context
+ * @param Closure|null $cb callback function to render child context
* @param Closure|null $else callback function to render child context when {{else}}
*
* @return string The rendered string of the token
*/
- public static function hbch($cx, $ch, $vars, $op, $inverted, $cb = false, $else = false) {
+ public static function hbch($cx, $ch, $vars, $op, $inverted, $cb = null, $else = null) {
$isBlock = (is_object($cb) && ($cb instanceof Closure));
$args = $vars[0];
$options = array(
'name' => $ch,
- 'hash' => $vars[1]
+ 'hash' => $vars[1],
+ '_this' => $isBlock ? $op : $inverted,
);
// $invert the logic
@@ -2451,12 +2589,13 @@ class LCRun3 {
ob_start();
}
if ($context === '_NO_INPUT_HERE_') {
+ $cx['scopes'][] = $op;
$ret = $cb($cx, $op);
} else {
$cx['scopes'][] = $op;
$ret = $cb($cx, $context);
- array_pop($cx['scopes']);
}
+ array_pop($cx['scopes']);
return $cx['flags']['echo'] ? ob_get_clean() : $ret;
};
}
@@ -2480,7 +2619,6 @@ class LCRun3 {
// prepare $options['data']
if ($cx['flags']['spvar']) {
$options['data'] = $cx['sp_vars'];
- $options['data']['root'] = $cx['scopes'][0];
}
$args[] = $options;
@@ -2493,12 +2631,6 @@ class LCRun3 {
$e = "LCRun3: call custom helper '$ch' error: " . $E->getMessage();
}
- if ($r === false) {
- if ($e === null) {
- $e = "LCRun3: call custom helper '$ch' error";
- }
- }
-
if($e !== null) {
if ($cx['flags']['debug'] & self::DEBUG_ERROR_LOG) {
error_log($e);
@@ -2528,7 +2660,7 @@ class LCRun3 {
* @expect '2.6.5' when input array('blockhelpers' => array('a' => function ($cx,$in) {return array($cx,$in[0],5);})), 'a', array('6', 0), 2, false, function($cx, $i) {return implode('.', $i);}
* @expect '' when input array('blockhelpers' => array('a' => function ($cx,$in) {})), 'a', array('6', 0), 2, false, function($cx, $i) {return implode('.', $i);}
*/
- public static function bch($cx, $ch, $vars, $in, $inverted, $cb, $else = false) {
+ public static function bch($cx, $ch, $vars, $in, $inverted, $cb, $else = null) {
$r = call_user_func($cx['blockhelpers'][$ch], $in, $vars[0], $vars[1]);
// $invert the logic
@@ -2556,5 +2688,3 @@ class LCRun3 {
return $ret;
}
}
-
-?> \ No newline at end of file
diff --git a/vendor/zordius/lightncandy/tests/LCRun3Test.php b/vendor/zordius/lightncandy/tests/LCRun3Test.php
index 63d6348e..03595298 100644
--- a/vendor/zordius/lightncandy/tests/LCRun3Test.php
+++ b/vendor/zordius/lightncandy/tests/LCRun3Test.php
@@ -12,10 +12,10 @@ class LCRun3Test extends PHPUnit_Framework_TestCase
public function testOn_debug() {
$method = new ReflectionMethod('LCRun3', 'debug');
$this->assertEquals('{{123}}', $method->invoke(null,
- '123', 'miss', array('flags' => array('debug' => LCRun3::DEBUG_TAGS)), ''
+ '123', 'miss', array('flags' => array('debug' => LCRun3::DEBUG_TAGS), 'lcrun' => 'LCRun3'), ''
));
$this->assertEquals('<!--MISSED((-->{{#123}}<!--))--><!--SKIPPED--><!--MISSED((-->{{/123}}<!--))-->', $method->invoke(null,
- '123', 'wi', array('flags' => array('debug' => LCRun3::DEBUG_TAGS_HTML)), false, false, function () {return 'A';}
+ '123', 'wi', array('flags' => array('debug' => LCRun3::DEBUG_TAGS_HTML), 'lcrun' => 'LCRun3'), false, false, function () {return 'A';}
));
}
/**
@@ -237,7 +237,7 @@ class LCRun3Test extends PHPUnit_Framework_TestCase
array('flags' => array('spvar' => 0)), 'abc', 'abc', true, function ($c, $i) {return "-$i=";}
));
$this->assertEquals('-b=', $method->invoke(null,
- array('flags' => array('spvar' => 0, 'mustsec' => 0)), array('a' => 'b'), array('a' => 'b'), true, function ($c, $i) {return "-$i=";}
+ array('flags' => array('spvar' => 0)), array('a' => 'b'), array('a' => 'b'), true, function ($c, $i) {return "-$i=";}
));
$this->assertEquals('1', $method->invoke(null,
array('flags' => array('spvar' => 0)), 'b', 'b', false, function ($c, $i) {return count($i);}
@@ -249,7 +249,7 @@ class LCRun3Test extends PHPUnit_Framework_TestCase
array('flags' => array('spvar' => 0)), 0, 0, false, function ($c, $i) {return print_r($i, true);}
));
$this->assertEquals('{"b":"c"}', $method->invoke(null,
- array('flags' => array('spvar' => 0, 'mustsec' => 0)), array('b' => 'c'), array('b' => 'c'), false, function ($c, $i) {return json_encode($i);}
+ array('flags' => array('spvar' => 0)), array('b' => 'c'), array('b' => 'c'), false, function ($c, $i) {return json_encode($i);}
));
$this->assertEquals('inv', $method->invoke(null,
array('flags' => array('spvar' => 0)), array(), 0, true, function ($c, $i) {return 'cb';}, function ($c, $i) {return 'inv';}
@@ -282,10 +282,10 @@ class LCRun3Test extends PHPUnit_Framework_TestCase
array('flags' => array('spvar' => 0)), new stdClass, 0, false, function ($c, $i) {return 'cb';}, function ($c, $i) {return 'inv';}
));
$this->assertEquals('268', $method->invoke(null,
- array('flags' => array('spvar' => 1)), array(1,3,4), 0, false, function ($c, $i) {return $i * 2;}
+ array('flags' => array('spvar' => 1), 'sp_vars'=>array('root' => 0)), array(1,3,4), 0, false, function ($c, $i) {return $i * 2;}
));
$this->assertEquals('038', $method->invoke(null,
- array('flags' => array('spvar' => 1), 'sp_vars'=>array()), array(1,3,'a'=>4), 0, true, function ($c, $i) {return $i * $c['sp_vars']['index'];}
+ array('flags' => array('spvar' => 1), 'sp_vars'=>array('root' => 0)), array(1,3,'a'=>4), 0, true, function ($c, $i) {return $i * $c['sp_vars']['index'];}
));
}
/**
@@ -299,11 +299,11 @@ class LCRun3Test extends PHPUnit_Framework_TestCase
$this->assertEquals('', $method->invoke(null,
array(), null, null, function () {return 'A';}
));
- $this->assertEquals('-Array=', $method->invoke(null,
- array(), array('a'=>'b'), array('a' => 'b'), function ($c, $i) {return "-$i=";}
+ $this->assertEquals('{"a":"b"}', $method->invoke(null,
+ array(), array('a'=>'b'), array('a'=>'c'), function ($c, $i) {return json_encode($i);}
));
$this->assertEquals('-b=', $method->invoke(null,
- array(), 'b', array('a' => 'b'), function ($c, $i) {return "-$i=";}
+ array(), 'b', array('a'=>'b'), function ($c, $i) {return "-$i=";}
));
}
/**
diff --git a/vendor/zordius/lightncandy/tests/LightnCandyTest.php b/vendor/zordius/lightncandy/tests/LightnCandyTest.php
index 6f82f2bd..9c82aac3 100644
--- a/vendor/zordius/lightncandy/tests/LightnCandyTest.php
+++ b/vendor/zordius/lightncandy/tests/LightnCandyTest.php
@@ -7,6 +7,22 @@ require_once('src/lightncandy.php');
class LightnCandyTest extends PHPUnit_Framework_TestCase
{
/**
+ * @covers LightnCandy::escapeTemplate
+ */
+ public function testOn_escapeTemplate() {
+ $method = new ReflectionMethod('LightnCandy', 'escapeTemplate');
+ $method->setAccessible(true);
+ $this->assertEquals('abc', $method->invoke(null,
+ 'abc'
+ ));
+ $this->assertEquals('a\\\\bc', $method->invoke(null,
+ 'a\bc'
+ ));
+ $this->assertEquals('a\\\'bc', $method->invoke(null,
+ 'a\'bc'
+ ));
+ }
+ /**
* @covers LightnCandy::buildHelperTable
*/
public function testOn_buildHelperTable() {
@@ -124,16 +140,16 @@ class LightnCandyTest extends PHPUnit_Framework_TestCase
$method = new ReflectionMethod('LightnCandy', 'getFuncName');
$method->setAccessible(true);
$this->assertEquals('LCRun3::test(', $method->invoke(null,
- array('flags' => array('standalone' => 0, 'debug' => 0)), 'test', ''
+ array('flags' => array('standalone' => 0, 'debug' => 0), 'lcrun' => 'LCRun3'), 'test', ''
));
$this->assertEquals('LCRun3::test2(', $method->invoke(null,
- array('flags' => array('standalone' => 0, 'debug' => 0)), 'test2', ''
+ array('flags' => array('standalone' => 0, 'debug' => 0), 'lcrun' => 'LCRun3'), 'test2', ''
));
$this->assertEquals("\$cx['funcs']['test3'](", $method->invoke(null,
- array('flags' => array('standalone' => 1, 'debug' => 0)), 'test3', ''
+ array('flags' => array('standalone' => 1, 'debug' => 0), 'lcrun' => 'LCRun3'), 'test3', ''
));
$this->assertEquals('LCRun3::debug(\'abc\', \'test\', ', $method->invoke(null,
- array('flags' => array('standalone' => 0, 'debug' => 1)), 'test', 'abc'
+ array('flags' => array('standalone' => 0, 'debug' => 1), 'lcrun' => 'LCRun3'), 'test', 'abc'
));
}
/**
@@ -193,32 +209,44 @@ class LightnCandyTest extends PHPUnit_Framework_TestCase
$this->assertEquals(array('$in', 'this'), $method->invoke(null,
array(null), array('flags'=>array('spvar'=>true,'debug'=>0))
));
+ $this->assertEquals(array('((isset($in[\'true\']) && is_array($in)) ? $in[\'true\'] : null)', '[true]'), $method->invoke(null,
+ array('true'), array('flags'=>array('spvar'=>true,'debug'=>0,'prop'=>0,'method'=>0,'mustlok'=>0))
+ ));
+ $this->assertEquals(array('((isset($in[\'false\']) && is_array($in)) ? $in[\'false\'] : null)', '[false]'), $method->invoke(null,
+ array('false'), array('flags'=>array('spvar'=>true,'debug'=>0,'prop'=>0,'method'=>0,'mustlok'=>0))
+ ));
$this->assertEquals(array('true', 'true'), $method->invoke(null,
- array('true'), array('flags'=>array('spvar'=>true,'debug'=>0)), true
+ array(0, 'true'), array('flags'=>array('spvar'=>true,'debug'=>0))
));
$this->assertEquals(array('false', 'false'), $method->invoke(null,
- array('false'), array('flags'=>array('spvar'=>true,'debug'=>0)), true
+ array(0, 'false'), array('flags'=>array('spvar'=>true,'debug'=>0))
));
- $this->assertEquals(array(2, '2'), $method->invoke(null,
- array('2'), array('flags'=>array('spvar'=>true,'debug'=>0)), true
+ $this->assertEquals(array('((isset($in[\'2\']) && is_array($in)) ? $in[\'2\'] : null)', '[2]'), $method->invoke(null,
+ array('2'), array('flags'=>array('spvar'=>true,'debug'=>0,'prop'=>0,'method'=>0,'mustlok'=>0))
+ ));
+ $this->assertEquals(array('2', '2'), $method->invoke(null,
+ array(0, '2'), array('flags'=>array('spvar'=>true,'debug'=>0,'prop'=>0,'method'=>0))
));
$this->assertEquals(array('((isset($in[\'@index\']) && is_array($in)) ? $in[\'@index\'] : null)', '[@index]'), $method->invoke(null,
array('@index'), array('flags'=>array('spvar'=>false,'debug'=>0,'prop'=>0,'method'=>0,'mustlok'=>0))
));
$this->assertEquals(array("((isset(\$cx['sp_vars']['index']) && is_array(\$cx['sp_vars'])) ? \$cx['sp_vars']['index'] : null)", '@[index]'), $method->invoke(null,
- array('@index'), array('flags'=>array('spvar'=>true,'debug'=>0))
+ array('@index'), array('flags'=>array('spvar'=>true,'debug'=>0,'prop'=>0,'method'=>0,'mustlok'=>0))
));
$this->assertEquals(array("((isset(\$cx['sp_vars']['key']) && is_array(\$cx['sp_vars'])) ? \$cx['sp_vars']['key'] : null)", '@[key]'), $method->invoke(null,
- array('@key'), array('flags'=>array('spvar'=>true,'debug'=>0))
+ array('@key'), array('flags'=>array('spvar'=>true,'debug'=>0,'prop'=>0,'method'=>0,'mustlok'=>0))
));
$this->assertEquals(array("((isset(\$cx['sp_vars']['first']) && is_array(\$cx['sp_vars'])) ? \$cx['sp_vars']['first'] : null)", '@[first]'), $method->invoke(null,
- array('@first'), array('flags'=>array('spvar'=>true,'debug'=>0))
+ array('@first'), array('flags'=>array('spvar'=>true,'debug'=>0,'prop'=>0,'method'=>0,'mustlok'=>0))
));
$this->assertEquals(array("((isset(\$cx['sp_vars']['last']) && is_array(\$cx['sp_vars'])) ? \$cx['sp_vars']['last'] : null)", '@[last]'), $method->invoke(null,
- array('@last'), array('flags'=>array('spvar'=>true,'debug'=>0))
+ array('@last'), array('flags'=>array('spvar'=>true,'debug'=>0,'prop'=>0,'method'=>0,'mustlok'=>0))
+ ));
+ $this->assertEquals(array('((isset($in[\'"a"\']) && is_array($in)) ? $in[\'"a"\'] : null)', '["a"]'), $method->invoke(null,
+ array('"a"'), array('flags'=>array('spvar'=>true,'debug'=>0,'prop'=>0,'method'=>0,'mustlok'=>0))
));
- $this->assertEquals(array('\'a\'', '"a"'), $method->invoke(null,
- array('"a"'), array('flags'=>array('spvar'=>true,'debug'=>0))
+ $this->assertEquals(array('"a"', '"a"'), $method->invoke(null,
+ array(0, '"a"'), array('flags'=>array('spvar'=>true,'debug'=>0))
));
$this->assertEquals(array('((isset($in[\'a\']) && is_array($in)) ? $in[\'a\'] : null)', '[a]'), $method->invoke(null,
array('a'), array('flags'=>array('spvar'=>true,'debug'=>0,'prop'=>0,'method'=>0,'mustlok'=>0))
@@ -233,7 +261,7 @@ class LightnCandyTest extends PHPUnit_Framework_TestCase
array(null, 'id'), array('flags'=>array('spvar'=>true,'debug'=>0,'prop'=>0,'method'=>0,'mustlok'=>0))
));
$this->assertEquals(array('LCRun3::v($cx, $in, array(\'id\'))', 'this.[id]'), $method->invoke(null,
- array(null, 'id'), array('flags'=>array('prop'=>true,'spvar'=>true,'debug'=>0,'method'=>0,'mustlok'=>0,'standalone'=>0))
+ array(null, 'id'), array('flags'=>array('prop'=>true,'spvar'=>true,'debug'=>0,'method'=>0,'mustlok'=>0,'standalone'=>0), 'lcrun' => 'LCRun3')
));
}
/**
@@ -273,35 +301,41 @@ class LightnCandyTest extends PHPUnit_Framework_TestCase
$this->assertEquals(array('this'), $method->invoke(null,
'this', array('flags' => array('advar' => 0, 'this' => 0))
));
- $this->assertEquals(array(null), $method->invoke(null,
+ $this->assertEquals(array(), $method->invoke(null,
'this', array('flags' => array('advar' => 0, 'this' => 1))
));
- $this->assertEquals(array(1, null), $method->invoke(null,
- '../', array('flags' => array('advar' => 0, 'this' => 1, 'parent' => 1), 'usedFeature' => array('parent' => 0))
+ $this->assertEquals(array(1), $method->invoke(null,
+ '../', array('flags' => array('advar' => 0, 'this' => 1, 'parent' => 1), 'usedFeature' => array('parent' => 0), 'scan' => true)
));
- $this->assertEquals(array(1, null), $method->invoke(null,
- '../.', array('flags' => array('advar' => 0, 'this' => 1, 'parent' => 1), 'usedFeature' => array('parent' => 0))
+ $this->assertEquals(array(1), $method->invoke(null,
+ '../.', array('flags' => array('advar' => 0, 'this' => 1, 'parent' => 1), 'usedFeature' => array('parent' => 0), 'scan' => true)
));
- $this->assertEquals(array(1, null), $method->invoke(null,
- '../this', array('flags' => array('advar' => 0, 'this' => 1, 'parent' => 1), 'usedFeature' => array('parent' => 0))
+ $this->assertEquals(array(1), $method->invoke(null,
+ '../this', array('flags' => array('advar' => 0, 'this' => 1, 'parent' => 1), 'usedFeature' => array('parent' => 0), 'scan' => true)
));
$this->assertEquals(array(1, 'a'), $method->invoke(null,
- '../a', array('flags' => array('advar' => 0, 'this' => 1, 'parent' => 1), 'usedFeature' => array('parent' => 0))
+ '../a', array('flags' => array('advar' => 0, 'this' => 1, 'parent' => 1), 'usedFeature' => array('parent' => 0), 'scan' => true)
));
$this->assertEquals(array(2, 'a', 'b'), $method->invoke(null,
- '../../a.b', array('flags' => array('advar' => 0, 'this' => 0, 'parent' => 1), 'usedFeature' => array('parent' => 0))
+ '../../a.b', array('flags' => array('advar' => 0, 'this' => 0, 'parent' => 1), 'usedFeature' => array('parent' => 0), 'scan' => true)
));
$this->assertEquals(array(2, '[a]', 'b'), $method->invoke(null,
- '../../[a].b', array('flags' => array('advar' => 0, 'this' => 0, 'parent' => 1), 'usedFeature' => array('parent' => 0))
+ '../../[a].b', array('flags' => array('advar' => 0, 'this' => 0, 'parent' => 1), 'usedFeature' => array('parent' => 0), 'scan' => true)
));
$this->assertEquals(array(2, 'a', 'b'), $method->invoke(null,
- '../../[a].b', array('flags' => array('advar' => 1, 'this' => 0, 'parent' => 1), 'usedFeature' => array('parent' => 0))
+ '../../[a].b', array('flags' => array('advar' => 1, 'this' => 0, 'parent' => 1), 'usedFeature' => array('parent' => 0), 'scan' => true)
));
- $this->assertEquals(array('"a.b"'), $method->invoke(null,
+ $this->assertEquals(array('id'), $method->invoke(null,
+ 'this.id', array('flags' => array('advar' => 1, 'this' => 1, 'parent' => 1), 'usedFeature' => array('parent' => 0))
+ ));
+ $this->assertEquals(array(0, '\'a.b\''), $method->invoke(null,
'"a.b"', array('flags' => array('advar' => 1, 'this' => 0, 'parent' => 1), 'usedFeature' => array('parent' => 0))
));
- $this->assertEquals(array(null, 'id'), $method->invoke(null,
- 'this.id', array('flags' => array('advar' => 1, 'this' => 1, 'parent' => 1), 'usedFeature' => array('parent' => 0))
+ $this->assertEquals(array(0, '123'), $method->invoke(null,
+ '123', array('flags' => array('advar' => 1, 'this' => 0, 'parent' => 1), 'usedFeature' => array('parent' => 0))
+ ));
+ $this->assertEquals(array(0, 'null'), $method->invoke(null,
+ 'null', array('flags' => array('advar' => 1, 'this' => 0, 'parent' => 1), 'usedFeature' => array('parent' => 0))
));
}
/**
@@ -310,59 +344,80 @@ class LightnCandyTest extends PHPUnit_Framework_TestCase
public function testOn_parseTokenArgs() {
$method = new ReflectionMethod('LightnCandy', 'parseTokenArgs');
$method->setAccessible(true);
- $this->assertEquals(array(false, array(array(null))), $method->invoke(null,
- array(0,0,0,0,0,0,''), array('flags' => array('advar' => 0, 'this' => 1, 'namev' => 0, 'noesc' => 0))
+ $this->assertEquals(array(false, array(array())), $method->invoke(null,
+ array(0,0,0,0,0,0,''), array('flags' => array('advar' => 0, 'this' => 1, 'namev' => 0, 'noesc' => 0), 'scan' => false)
));
- $this->assertEquals(array(true, array(array(null))), $method->invoke(null,
- array(0,0,0,'{{{',0,0,''), array('flags' => array('advar' => 0, 'this' => 1, 'namev' => 0, 'noesc' => 0))
+ $this->assertEquals(array(true, array(array())), $method->invoke(null,
+ array(0,0,0,'{{{',0,0,''), array('flags' => array('advar' => 0, 'this' => 1, 'namev' => 0, 'noesc' => 0), 'scan' => false)
));
- $this->assertEquals(array(true, array(array(null))), $method->invoke(null,
- array(0,0,0,0,0,0,''), array('flags' => array('advar' => 0, 'this' => 1, 'namev' => 0, 'noesc' => 1))
+ $this->assertEquals(array(true, array(array())), $method->invoke(null,
+ array(0,0,0,0,0,0,''), array('flags' => array('advar' => 0, 'this' => 1, 'namev' => 0, 'noesc' => 1), 'scan' => false)
));
$this->assertEquals(array(false, array(array('a'))), $method->invoke(null,
- array(0,0,0,0,0,0,'a'), array('flags' => array('advar' => 0, 'this' => 1, 'namev' => 0, 'noesc' => 0))
+ array(0,0,0,0,0,0,'a'), array('flags' => array('advar' => 0, 'this' => 1, 'namev' => 0, 'noesc' => 0), 'scan' => false)
));
$this->assertEquals(array(false, array(array('a'), array('b'))), $method->invoke(null,
- array(0,0,0,0,0,0,'a b'), array('flags' => array('advar' => 0, 'this' => 1, 'namev' => 0, 'noesc' => 0))
+ array(0,0,0,0,0,0,'a b'), array('flags' => array('advar' => 0, 'this' => 1, 'namev' => 0, 'noesc' => 0), 'scan' => false)
));
$this->assertEquals(array(false, array(array('a'), array('"b'), array('c"'))), $method->invoke(null,
- array(0,0,0,0,0,0,'a "b c"'), array('flags' => array('advar' => 0, 'this' => 1, 'namev' => 0, 'noesc' => 0))
+ array(0,0,0,0,0,0,'a "b c"'), array('flags' => array('advar' => 0, 'this' => 1, 'namev' => 0, 'noesc' => 0), 'scan' => false)
));
- $this->assertEquals(array(false, array(array('a'), array('"b c"'))), $method->invoke(null,
- array(0,0,0,0,0,0,'a "b c"'), array('flags' => array('advar' => 1, 'this' => 1, 'namev' => 0, 'noesc' => 0))
+ $this->assertEquals(array(false, array(array('a'), array(0, '\'b c\''))), $method->invoke(null,
+ array(0,0,0,0,0,0,'a "b c"'), array('flags' => array('advar' => 1, 'this' => 1, 'namev' => 0, 'noesc' => 0), 'scan' => false)
));
$this->assertEquals(array(false, array(array('a'), array('[b'), array('c]'))), $method->invoke(null,
- array(0,0,0,0,0,0,'a [b c]'), array('flags' => array('advar' => 0, 'this' => 1, 'namev' => 0, 'noesc' => 0))
+ array(0,0,0,0,0,0,'a [b c]'), array('flags' => array('advar' => 0, 'this' => 1, 'namev' => 0, 'noesc' => 0), 'scan' => false)
));
$this->assertEquals(array(false, array(array('a'), array('[b'), array('c]'))), $method->invoke(null,
- array(0,0,0,0,0,0,'a [b c]'), array('flags' => array('advar' => 0, 'this' => 1, 'namev' => 1, 'noesc' => 0))
+ array(0,0,0,0,0,0,'a [b c]'), array('flags' => array('advar' => 0, 'this' => 1, 'namev' => 1, 'noesc' => 0), 'scan' => false)
));
$this->assertEquals(array(false, array(array('a'), array('b c'))), $method->invoke(null,
- array(0,0,0,0,0,0,'a [b c]'), array('flags' => array('advar' => 1, 'this' => 1, 'namev' => 0, 'noesc' => 0))
+ array(0,0,0,0,0,0,'a [b c]'), array('flags' => array('advar' => 1, 'this' => 1, 'namev' => 0, 'noesc' => 0), 'scan' => false)
));
$this->assertEquals(array(false, array(array('a'), array('b c'))), $method->invoke(null,
- array(0,0,0,0,0,0,'a [b c]'), array('flags' => array('advar' => 1, 'this' => 1, 'namev' => 1, 'noesc' => 0))
+ array(0,0,0,0,0,0,'a [b c]'), array('flags' => array('advar' => 1, 'this' => 1, 'namev' => 1, 'noesc' => 0), 'scan' => false)
));
$this->assertEquals(array(false, array(array('a'), 'q' => array('b c'))), $method->invoke(null,
- array(0,0,0,0,0,0,'a q=[b c]'), array('flags' => array('advar' => 1, 'this' => 1, 'namev' => 1, 'noesc' => 0))
+ array(0,0,0,0,0,0,'a q=[b c]'), array('flags' => array('advar' => 1, 'this' => 1, 'namev' => 1, 'noesc' => 0), 'scan' => false)
));
$this->assertEquals(array(false, array(array('a'), array('q=[b c'))), $method->invoke(null,
- array(0,0,0,0,0,0,'a [q=[b c]'), array('flags' => array('advar' => 1, 'this' => 1, 'namev' => 1, 'noesc' => 0))
+ array(0,0,0,0,0,0,'a [q=[b c]'), array('flags' => array('advar' => 1, 'this' => 1, 'namev' => 1, 'noesc' => 0), 'scan' => false)
));
$this->assertEquals(array(false, array(array('a'), 'q' => array('[b'), array('c]'))), $method->invoke(null,
- array(0,0,0,0,0,0,'a q=[b c]'), array('flags' => array('advar' => 0, 'this' => 1, 'namev' => 1, 'noesc' => 0))
+ array(0,0,0,0,0,0,'a q=[b c]'), array('flags' => array('advar' => 0, 'this' => 1, 'namev' => 1, 'noesc' => 0), 'scan' => false)
));
$this->assertEquals(array(false, array(array('a'), 'q' => array('b'), array('c'))), $method->invoke(null,
- array(0,0,0,0,0,0,'a [q]=b c'), array('flags' => array('advar' => 0, 'this' => 1, 'namev' => 1, 'noesc' => 0))
+ array(0,0,0,0,0,0,'a [q]=b c'), array('flags' => array('advar' => 0, 'this' => 1, 'namev' => 1, 'noesc' => 0), 'scan' => false)
));
- $this->assertEquals(array(false, array(array('a'), 'q' => array('"b c"'))), $method->invoke(null,
- array(0,0,0,0,0,0,'a q="b c"'), array('flags' => array('advar' => 1, 'this' => 1, 'namev' => 1, 'noesc' => 0))
+ $this->assertEquals(array(false, array(array('a'), 'q' => array(0, '\'b c\''))), $method->invoke(null,
+ array(0,0,0,0,0,0,'a q="b c"'), array('flags' => array('advar' => 1, 'this' => 1, 'namev' => 1, 'noesc' => 0), 'scan' => false)
));
$this->assertEquals(array(false, array(array('(foo bar)'))), $method->invoke(null,
- array(0,0,0,0,0,0,'(foo bar)'), array('flags' => array('advar' => 1, 'this' => 1, 'namev' => 1, 'noesc' => 0))
+ array(0,0,0,0,0,0,'(foo bar)'), array('flags' => array('advar' => 1, 'this' => 1, 'namev' => 1, 'noesc' => 0, 'exhlp' => 1), 'ops' => array('seperator' => ''), 'usedFeature' => array('subexp' => 0), 'scan' => false)
));
$this->assertEquals(array(false, array(array('foo'), array("'=='"), array('bar'))), $method->invoke(null,
- array(0,0,0,0,0,0,"foo '==' bar"), array('flags' => array('advar' => 1, 'namev' => 1))
+ array(0,0,0,0,0,0,"foo '==' bar"), array('flags' => array('advar' => 1, 'namev' => 1, 'noesc' => 0, 'this' => 0), 'scan' => false)
+ ));
+ $this->assertEquals(array(false, array(array('( foo bar)'))), $method->invoke(null,
+ array(0,0,0,0,0,0,'( foo bar)'), array('flags' => array('advar' => 1, 'this' => 1, 'namev' => 1, 'noesc' => 0, 'exhlp' => 1), 'ops' => array('seperator' => ''), 'usedFeature' => array('subexp' => 0), 'scan' => false)
+ ));
+ $this->assertEquals(array(false, array(array('a'), array(0, '\' b c\''))), $method->invoke(null,
+ array(0,0,0,0,0,0,'a " b c"'), array('flags' => array('advar' => 1, 'this' => 1, 'namev' => 0, 'noesc' => 0), 'scan' => false)
+ ));
+ $this->assertEquals(array(false, array(array('a'), 'q' => array(0, '\' b c\''))), $method->invoke(null,
+ array(0,0,0,0,0,0,'a q=" b c"'), array('flags' => array('advar' => 1, 'this' => 1, 'namev' => 1, 'noesc' => 0), 'scan' => false)
+ ));
+ $this->assertEquals(array(false, array(array('foo'), array(0, "' =='"), array('bar'))), $method->invoke(null,
+ array(0,0,0,0,0,0,"foo \' ==\' bar"), array('flags' => array('advar' => 1, 'namev' => 1, 'noesc' => 0, 'this' => 0), 'scan' => false)
+ ));
+ $this->assertEquals(array(false, array(array('a'), array(' b c'))), $method->invoke(null,
+ array(0,0,0,0,0,0,'a [ b c]'), array('flags' => array('advar' => 1, 'this' => 1, 'namev' => 1, 'noesc' => 0), 'scan' => false)
+ ));
+ $this->assertEquals(array(false, array(array('a'), 'q' => array(0, "' d e'"))), $method->invoke(null,
+ array(0,0,0,0,0,0,"a q=\' d e\'"), array('flags' => array('advar' => 1, 'this' => 1, 'namev' => 1, 'noesc' => 0), 'scan' => false)
+ ));
+ $this->assertEquals(array(false, array('q' => array('( foo bar)'))), $method->invoke(null,
+ array(0,0,0,0,0,0,'q=( foo bar)'), array('flags' => array('advar' => 1, 'this' => 1, 'namev' => 1, 'noesc' => 0), 'scan' => false)
));
}
/**
diff --git a/vendor/zordius/lightncandy/tests/contextTest.php b/vendor/zordius/lightncandy/tests/contextTest.php
new file mode 100644
index 00000000..8fa88d88
--- /dev/null
+++ b/vendor/zordius/lightncandy/tests/contextTest.php
@@ -0,0 +1,300 @@
+<?php
+
+require_once('src/lightncandy.php');
+require_once('tests/helpers_for_test.php');
+
+class contextTest extends PHPUnit_Framework_TestCase
+{
+ /**
+ * @dataProvider compileProvider
+ */
+ public function testUsedFeature($test)
+ {
+ LightnCandy::compile($test['template'], $test['options']);
+ $context = LightnCandy::getContext();
+ $this->assertEquals($test['expected'], $context['usedFeature']);
+ }
+
+ public function compileProvider()
+ {
+ $default = Array(
+ 'rootthis' => 0,
+ 'enc' => 0,
+ 'raw' => 0,
+ 'sec' => 0,
+ 'isec' => 0,
+ 'if' => 0,
+ 'else' => 0,
+ 'unless' => 0,
+ 'each' => 0,
+ 'this' => 0,
+ 'parent' => 0,
+ 'with' => 0,
+ 'comment' => 0,
+ 'partial' => 0,
+ 'dynpartial' => 0,
+ 'helper' => 0,
+ 'bhelper' => 0,
+ 'hbhelper' => 0,
+ 'delimiter' => 0,
+ 'subexp' => 0,
+ );
+
+ $compileCases = Array(
+ Array(
+ 'template' => 'abc',
+ ),
+
+ Array(
+ 'template' => 'abc{{def',
+ ),
+
+ Array(
+ 'template' => 'abc{{def}}',
+ 'expected' => Array(
+ 'enc' => 1
+ ),
+ ),
+
+ Array(
+ 'template' => 'abc{{{def}}}',
+ 'expected' => Array(
+ 'raw' => 1
+ ),
+ ),
+
+ Array(
+ 'template' => 'abc{{&def}}',
+ 'expected' => Array(
+ 'raw' => 1
+ ),
+ ),
+
+ Array(
+ 'template' => 'abc{{this}}',
+ 'expected' => Array(
+ 'enc' => 1
+ ),
+ ),
+
+ Array(
+ 'template' => 'abc{{this}}',
+ 'options' => Array('flags' => LightnCandy::FLAG_THIS),
+ 'expected' => Array(
+ 'enc' => 1,
+ 'this' => 1,
+ 'rootthis' => 1,
+ ),
+ ),
+
+ Array(
+ 'template' => '{{#if abc}}OK!{{/if}}',
+ 'expected' => Array(
+ 'if' => 1
+ ),
+ ),
+
+ Array(
+ 'template' => '{{#unless abc}}OK!{{/unless}}',
+ 'expected' => Array(
+ 'unless' => 1
+ ),
+ ),
+
+ Array(
+ 'template' => '{{#with abc}}OK!{{/with}}',
+ 'expected' => Array(
+ 'with' => 1
+ ),
+ ),
+
+ Array(
+ 'template' => '{{#abc}}OK!{{/abc}}',
+ 'expected' => Array(
+ 'sec' => 1
+ ),
+ ),
+
+ Array(
+ 'template' => '{{^abc}}OK!{{/abc}}',
+ 'expected' => Array(
+ 'isec' => 1
+ ),
+ ),
+
+ Array(
+ 'template' => '{{#each abc}}OK!{{/each}}',
+ 'expected' => Array(
+ 'each' => 1
+ ),
+ ),
+
+ Array(
+ 'template' => '{{! test}}OK!{{! done}}',
+ 'expected' => Array(
+ 'comment' => 2
+ ),
+ ),
+
+ Array(
+ 'template' => '{{../OK}}',
+ 'expected' => Array(
+ 'parent' => 1,
+ 'enc' => 1,
+ ),
+ ),
+
+ Array(
+ 'template' => '{{&../../OK}}',
+ 'expected' => Array(
+ 'parent' => 1,
+ 'raw' => 1,
+ ),
+ ),
+
+ Array(
+ 'template' => '{{&../../../OK}} {{../OK}}',
+ 'options' => Array(
+ 'flags' => LightnCandy::FLAG_HANDLEBARSJS,
+ 'hbhelpers' => Array(
+ 'mytest' => function ($context) {
+ return $context;
+ }
+ )
+ ),
+ 'expected' => Array(
+ 'parent' => 2,
+ 'enc' => 1,
+ 'raw' => 1,
+ ),
+ ),
+
+ Array(
+ 'template' => '{{mytest ../../../OK}} {{../OK}}',
+ 'options' => Array(
+ 'flags' => LightnCandy::FLAG_HANDLEBARSJS,
+ 'hbhelpers' => Array(
+ 'mytest' => function ($context) {
+ return $context;
+ }
+ )
+ ),
+ 'expected' => Array(
+ 'parent' => 2,
+ 'enc' => 2,
+ 'hbhelper' => 1,
+ ),
+ ),
+
+ Array(
+ 'template' => '{{mytest . .}}',
+ 'options' => Array(
+ 'flags' => LightnCandy::FLAG_HANDLEBARSJS,
+ 'hbhelpers' => Array(
+ 'mytest' => function ($a, $b) {
+ return '';
+ }
+ )
+ ),
+ 'expected' => Array(
+ 'rootthis' => 2,
+ 'this' => 2,
+ 'enc' => 1,
+ 'hbhelper' => 1,
+ ),
+ ),
+
+ Array(
+ 'template' => '{{mytest (mytest ..)}}',
+ 'options' => Array(
+ 'flags' => LightnCandy::FLAG_HANDLEBARSJS,
+ 'hbhelpers' => Array(
+ 'mytest' => function ($context) {
+ return $context;
+ }
+ )
+ ),
+ 'expected' => Array(
+ 'parent' => 1,
+ 'enc' => 1,
+ 'hbhelper' => 2,
+ 'subexp' => 1,
+ ),
+ ),
+
+ Array(
+ 'template' => '{{mytest (mytest ..) .}}',
+ 'options' => Array(
+ 'flags' => LightnCandy::FLAG_HANDLEBARSJS,
+ 'hbhelpers' => Array(
+ 'mytest' => function ($context) {
+ return $context;
+ }
+ )
+ ),
+ 'expected' => Array(
+ 'parent' => 1,
+ 'rootthis' => 1,
+ 'this' => 1,
+ 'enc' => 1,
+ 'hbhelper' => 2,
+ 'subexp' => 1,
+ ),
+ ),
+
+ Array(
+ 'template' => '{{mytest (mytest (mytest ..)) .}}',
+ 'options' => Array(
+ 'flags' => LightnCandy::FLAG_HANDLEBARSJS,
+ 'hbhelpers' => Array(
+ 'mytest' => function ($context) {
+ return $context;
+ }
+ )
+ ),
+ 'expected' => Array(
+ 'parent' => 1,
+ 'rootthis' => 1,
+ 'this' => 1,
+ 'enc' => 1,
+ 'hbhelper' => 3,
+ 'subexp' => 2,
+ ),
+ ),
+
+ Array(
+ 'id' => '134',
+ 'template' => '{{#if 1}}{{keys (keys ../names)}}{{/if}}',
+ 'options' => Array(
+ 'flags' => LightnCandy::FLAG_HANDLEBARSJS,
+ 'hbhelpers' => Array(
+ 'keys' => function ($context) {
+ return $context;
+ }
+ )
+ ),
+ 'expected' => Array(
+ 'parent' => 1,
+ 'enc' => 1,
+ 'if' => 1,
+ 'hbhelper' => 2,
+ 'subexp' => 1,
+ ),
+ ),
+ );
+
+ return array_map(function($i) use ($default) {
+ if (!isset($i['options'])) {
+ $i['options'] = Array('flags' => 0);
+ }
+ if (!isset($i['options']['flags'])) {
+ $i['options']['flags'] = 0;
+ }
+ $i['expected'] = array_merge($default, isset($i['expected']) ? $i['expected'] : array());
+ return Array($i);
+ }, $compileCases);
+ }
+}
+
+
+?>
diff --git a/vendor/zordius/lightncandy/tests/errorTest.php b/vendor/zordius/lightncandy/tests/errorTest.php
index 30ecd97d..8c1cbbf1 100644
--- a/vendor/zordius/lightncandy/tests/errorTest.php
+++ b/vendor/zordius/lightncandy/tests/errorTest.php
@@ -197,7 +197,7 @@ class errorTest extends PHPUnit_Framework_TestCase
Array(
'template' => '{{testA[}}',
'options' => Array('flags' => LightnCandy::FLAG_ADVARNAME),
- 'expected' => 'Wrong variable naming as \'testA[\' in {{testA[}} !',
+ 'expected' => 'Wrong variable naming in {{testA[}}',
),
Array(
'template' => '{{[testB}}',
@@ -387,8 +387,27 @@ class errorTest extends PHPUnit_Framework_TestCase
'flags' => LightnCandy::FLAG_ADVARNAME,
'helpers' => Array('test_join'),
),
- 'expected' => "Custom helper 'foo' not found!",
+ 'expected' => "Can not find custom helper function defination foo() !",
),
+ Array(
+ 'template' => '{{1 + 2}}',
+ 'options' => Array(
+ 'flags' => LightnCandy::FLAG_HANDLEBARSJS,
+ 'helpers' => Array('test_join'),
+ ),
+ 'expected' => "Wrong variable naming as '+' in {{1 + 2}} ! You should wrap ! \" # % & ' * + , ; < = > { | } ~ into [ ]",
+ ),
+ Array(
+ 'template' => '{{> (foo) bar}}',
+ 'options' => Array(
+ 'flags' => LightnCandy::FLAG_HANDLEBARSJS,
+ 'basedir' => '.',
+ ),
+ 'expected' => Array(
+ "Can not find custom helper function defination foo() !",
+ "You use dynamic partial name as '(foo)', this only works with option FLAG_RUNTIMEPARTIAL enabled",
+ )
+ ),
);
return array_map(function($i) {
diff --git a/vendor/zordius/lightncandy/tests/helpers_for_test.php b/vendor/zordius/lightncandy/tests/helpers_for_test.php
index 93a1dbc7..80c3e860 100644
--- a/vendor/zordius/lightncandy/tests/helpers_for_test.php
+++ b/vendor/zordius/lightncandy/tests/helpers_for_test.php
@@ -1,5 +1,12 @@
<?php
+// Class for customized LCRun
+class MyLCRunClass extends LCRun3 {
+ public static function raw($cx, $v) {
+ return '[[DEBUG:raw()=>' . var_export($v, true) . ']]';
+ }
+}
+
// Classes for inputs or helpers
class myClass {
function test() {
@@ -7,7 +14,7 @@ class myClass {
}
function helper2($arg) {
- return "=$arg=";
+ return is_array($arg) ? '=Array=' : "=$arg=";
}
function __call($method, $args) {
@@ -63,9 +70,12 @@ class twoDimensionIterator implements Iterator {
// Custom helpers
function helper1($arg) {
+ $arg = is_array($arg) ? 'Array' : $arg;
return "-$arg-";
}
function alink($u, $t) {
+ $u = is_array($u) ? 'Array' : $u;
+ $t = is_array($t) ? 'Array' : $t;
return "<a href=\"$u\">$t</a>";
}
diff --git a/vendor/zordius/lightncandy/tests/regressionTest.php b/vendor/zordius/lightncandy/tests/regressionTest.php
index bf591536..d7b6b96d 100644
--- a/vendor/zordius/lightncandy/tests/regressionTest.php
+++ b/vendor/zordius/lightncandy/tests/regressionTest.php
@@ -282,6 +282,612 @@ class regressionTest extends PHPUnit_Framework_TestCase
),
Array(
+ 'id' => 114,
+ 'template' => '{{^myeach .}}OK:{{.}},{{else}}NOT GOOD{{/myeach}}',
+ 'options' => Array(
+ 'flags' => LightnCandy::FLAG_HANDLEBARSJS | LightnCandy::FLAG_BESTPERFORMANCE,
+ 'blockhelpers' => Array(
+ 'myeach' => function ($input) {
+ return $input;
+ }
+ ),
+ ),
+ 'data' => Array(1, 'foo', 3, 'bar'),
+ 'expected' => 'NOT GOOD',
+ ),
+
+ Array(
+ 'id' => 114,
+ 'template' => '{{^myeach .}}OK:{{.}},{{else}}NOT GOOD{{/myeach}}',
+ 'options' => Array(
+ 'flags' => LightnCandy::FLAG_HANDLEBARSJS | LightnCandy::FLAG_BESTPERFORMANCE,
+ 'blockhelpers' => Array(
+ 'myeach' => function ($input) {
+ return;
+ }
+ ),
+ ),
+ 'data' => Array(1, 'foo', 3, 'bar'),
+ 'expected' => 'OK:,',
+ ),
+
+ Array(
+ 'id' => 124,
+ 'template' => '{{list foo bar abc=(lt 10 3) def=(lt 3 10)}}',
+ 'options' => Array(
+ 'flags' => LightnCandy::FLAG_HANDLEBARSJS,
+ 'hbhelpers' => Array(
+ 'lt' => function ($a, $b) {
+ return ($a > $b) ? Array("$a>$b", 'raw') : '';
+ },
+ 'list' => function () {
+ $out = 'List:';
+ $args = func_get_args();
+ $opts = array_pop($args);
+
+ foreach ($args as $v) {
+ if ($v) {
+ $out .= ")$v , ";
+ }
+ }
+
+ foreach ($opts['hash'] as $k => $v) {
+ if ($v) {
+ $out .= "]$k=$v , ";
+ }
+ }
+ return array($out, 'raw');
+ }
+ ),
+ ),
+ 'data' => Array('foo' => 'OK!', 'bar' => 'OK2', 'abc' => false, 'def' => 123),
+ 'expected' => 'List:)OK! , )OK2 , ]abc=10>3 , ',
+ ),
+
+ Array(
+ 'id' => 124,
+ 'template' => '{{#if (equal \'OK\' cde)}}YES!{{/if}}',
+ 'options' => Array(
+ 'flags' => LightnCandy::FLAG_HANDLEBARSJS,
+ 'hbhelpers' => Array(
+ 'equal' => function ($a, $b) {
+ return $a === $b;
+ }
+ ),
+ ),
+ 'data' => Array('cde' => 'OK'),
+ 'expected' => 'YES!'
+ ),
+
+ Array(
+ 'id' => 124,
+ 'template' => '{{#if (equal true (equal \'OK\' cde))}}YES!{{/if}}',
+ 'options' => Array(
+ 'flags' => LightnCandy::FLAG_HANDLEBARSJS,
+ 'hbhelpers' => Array(
+ 'equal' => function ($a, $b) {
+ return $a === $b;
+ }
+ ),
+ ),
+ 'data' => Array('cde' => 'OK'),
+ 'expected' => 'YES!'
+ ),
+
+ Array(
+ 'id' => 125,
+ 'template' => '{{#if (equal true ( equal \'OK\' cde))}}YES!{{/if}}',
+ 'options' => Array(
+ 'flags' => LightnCandy::FLAG_HANDLEBARSJS,
+ 'hbhelpers' => Array(
+ 'equal' => function ($a, $b) {
+ return $a === $b;
+ }
+ ),
+ ),
+ 'data' => Array('cde' => 'OK'),
+ 'expected' => 'YES!'
+ ),
+
+ Array(
+ 'id' => 125,
+ 'template' => '{{#if (equal true (equal \' OK\' cde))}}YES!{{/if}}',
+ 'options' => Array(
+ 'flags' => LightnCandy::FLAG_HANDLEBARSJS,
+ 'hbhelpers' => Array(
+ 'equal' => function ($a, $b) {
+ return $a === $b;
+ }
+ ),
+ ),
+ 'data' => Array('cde' => ' OK'),
+ 'expected' => 'YES!'
+ ),
+
+ Array(
+ 'id' => 125,
+ 'template' => '{{#if (equal true (equal \' ==\' cde))}}YES!{{/if}}',
+ 'options' => Array(
+ 'flags' => LightnCandy::FLAG_HANDLEBARSJS,
+ 'hbhelpers' => Array(
+ 'equal' => function ($a, $b) {
+ return $a === $b;
+ }
+ ),
+ ),
+ 'data' => Array('cde' => ' =='),
+ 'expected' => 'YES!'
+ ),
+
+ Array(
+ 'id' => 125,
+ 'template' => '{{#if (equal true (equal " ==" cde))}}YES!{{/if}}',
+ 'options' => Array(
+ 'flags' => LightnCandy::FLAG_HANDLEBARSJS,
+ 'hbhelpers' => Array(
+ 'equal' => function ($a, $b) {
+ return $a === $b;
+ }
+ ),
+ ),
+ 'data' => Array('cde' => ' =='),
+ 'expected' => 'YES!'
+ ),
+
+ Array(
+ 'id' => 125,
+ 'template' => '{{[ abc]}}',
+ 'options' => Array(
+ 'flags' => LightnCandy::FLAG_HANDLEBARSJS,
+ 'hbhelpers' => Array(
+ 'equal' => function ($a, $b) {
+ return $a === $b;
+ }
+ ),
+ ),
+ 'data' => Array(' abc' => 'YES!'),
+ 'expected' => 'YES!'
+ ),
+
+ Array(
+ 'id' => 125,
+ 'template' => '{{list [ abc] " xyz" \' def\' "==" \'==\' "OK"}}',
+ 'options' => Array(
+ 'flags' => LightnCandy::FLAG_HANDLEBARSJS,
+ 'hbhelpers' => Array(
+ 'list' => function ($a, $b) {
+ $out = 'List:';
+ $args = func_get_args();
+ $opts = array_pop($args);
+ foreach ($args as $v) {
+ if ($v) {
+ $out .= ")$v , ";
+ }
+ }
+ return $out;
+ }
+ ),
+ ),
+ 'data' => Array(' abc' => 'YES!'),
+ 'expected' => 'List:)YES! , ) xyz , ) def , )== , )== , )OK , '
+ ),
+
+ Array(
+ 'id' => 127,
+ 'template' => '{{#each array}}#{{#if true}}{{name}}-{{../name}}-{{../../name}}-{{../../../name}}{{/if}}##{{#myif true}}{{name}}={{../name}}={{../../name}}={{../../../name}}{{/myif}}###{{#mywith true}}{{name}}~{{../name}}~{{../../name}}~{{../../../name}}{{/mywith}}{{/each}}',
+ 'data' => Array('name' => 'john', 'array' => Array(1,2,3)),
+ 'options' => Array(
+ 'flags' => LightnCandy::FLAG_HANDLEBARSJS,
+ 'hbhelpers' => Array('myif', 'mywith'),
+ ),
+ 'expected' => '#--john-##==john=###~~john~#--john-##==john=###~~john~#--john-##==john=###~~john~',
+ ),
+
+ Array(
+ 'id' => 128,
+ 'template' => 'foo: {{foo}} , parent foo: {{../foo}}',
+ 'data' => Array('foo' => 'OK'),
+ 'options' => Array(
+ 'flags' => LightnCandy::FLAG_HANDLEBARSJS,
+ ),
+ 'expected' => 'foo: OK , parent foo: ',
+ ),
+
+ Array(
+ 'id' => 132,
+ 'template' => '{{list (keys .)}}',
+ 'data' => Array('foo' => 'bar', 'test' => 'ok'),
+ 'options' => Array(
+ 'flags' => LightnCandy::FLAG_HANDLEBARSJS,
+ 'helpers' => Array(
+ 'keys' => function($arg) {
+ return Array(array_keys($arg[0]), 'asis');
+ },
+ 'list' => function($arg) {
+ return join(',', $arg[0]);
+ }
+ ),
+ ),
+ 'expected' => 'foo,test',
+ ),
+
+ Array(
+ 'id' => 133,
+ 'template' => "{{list (keys\n .\n ) \n}}",
+ 'data' => Array('foo' => 'bar', 'test' => 'ok'),
+ 'options' => Array(
+ 'flags' => LightnCandy::FLAG_HANDLEBARSJS,
+ 'helpers' => Array(
+ 'keys' => function($arg) {
+ return Array(array_keys($arg[0]), 'asis');
+ },
+ 'list' => function($arg) {
+ return join(',', $arg[0]);
+ }
+ ),
+ ),
+ 'expected' => 'foo,test',
+ ),
+
+ Array(
+ 'id' => 133,
+ 'template' => "{{list\n .\n \n \n}}",
+ 'data' => Array('foo', 'bar', 'test'),
+ 'options' => Array(
+ 'flags' => LightnCandy::FLAG_HANDLEBARSJS,
+ 'helpers' => Array(
+ 'list' => function($arg) {
+ return join(',', $arg[0]);
+ }
+ ),
+ ),
+ 'expected' => 'foo,bar,test',
+ ),
+
+ Array(
+ 'id' => 134,
+ 'template' => "{{#if 1}}{{list (keys ../names)}}{{/if}}",
+ 'data' => Array('names' => Array('foo' => 'bar', 'test' => 'ok')),
+ 'options' => Array(
+ 'flags' => LightnCandy::FLAG_HANDLEBARSJS,
+ 'helpers' => Array(
+ 'keys' => function($arg) {
+ return Array(array_keys($arg[0]), 'asis');
+ },
+ 'list' => function($arg) {
+ return join(',', $arg[0]);
+ }
+ ),
+ ),
+ 'expected' => 'foo,test',
+ ),
+
+ Array(
+ 'id' => 138,
+ 'template' => "{{#each (keys .)}}={{.}}{{/each}}",
+ 'data' => Array('foo' => 'bar', 'test' => 'ok', 'Haha'),
+ 'options' => Array(
+ 'flags' => LightnCandy::FLAG_HANDLEBARSJS,
+ 'helpers' => Array(
+ 'keys' => function($arg) {
+ return Array(array_keys($arg[0]), 'asis');
+ }
+ ),
+ ),
+ 'expected' => '=foo=test=0',
+ ),
+
+ Array(
+ 'id' => 140,
+ 'template' => "{{[a.good.helper] .}}",
+ 'data' => Array('ha', 'hey', 'ho'),
+ 'options' => Array(
+ 'flags' => LightnCandy::FLAG_HANDLEBARSJS,
+ 'helpers' => Array(
+ 'a.good.helper' => function($arg) {
+ return join(',', $arg[0]);
+ }
+ ),
+ ),
+ 'expected' => 'ha,hey,ho',
+ ),
+
+ Array(
+ 'id' => 141,
+ 'template' => "{{#with foo}}{{#getThis bar}}{{/getThis}}{{/with}}",
+ 'data' => Array('foo' => Array('bar' => 'Good!')),
+ 'options' => Array(
+ 'flags' => LightnCandy::FLAG_HANDLEBARSJS,
+ 'hbhelpers' => Array(
+ 'getThis' => function($input, $options) {
+ return $input . '-' . $options['_this']['bar'];
+ }
+ ),
+ ),
+ 'expected' => 'Good!-Good!',
+ ),
+
+ Array(
+ 'id' => 141,
+ 'template' => "{{#with foo}}{{getThis bar}}{{/with}}",
+ 'data' => Array('foo' => Array('bar' => 'Good!')),
+ 'options' => Array(
+ 'flags' => LightnCandy::FLAG_HANDLEBARSJS,
+ 'hbhelpers' => Array(
+ 'getThis' => function($input, $options) {
+ return $input . '-' . $options['_this']['bar'];
+ }
+ ),
+ ),
+ 'expected' => 'Good!-Good!',
+ ),
+
+ Array(
+ 'id' => 143,
+ 'template' => "{{testString foo bar=\" \"}}",
+ 'data' => Array('foo' => 'good!'),
+ 'options' => Array(
+ 'flags' => LightnCandy::FLAG_HANDLEBARSJS,
+ 'helpers' => Array(
+ 'testString' => function($args, $named) {
+ return $args[0] . '-' . $named['bar'];
+ }
+ ),
+ ),
+ 'expected' => 'good!- ',
+ ),
+
+ Array(
+ 'id' => 143,
+ 'template' => "{{testString foo bar=\"\"}}",
+ 'data' => Array('foo' => 'good!'),
+ 'options' => Array(
+ 'flags' => LightnCandy::FLAG_HANDLEBARSJS,
+ 'helpers' => Array(
+ 'testString' => function($args, $named) {
+ return $args[0] . '-' . $named['bar'];
+ }
+ ),
+ ),
+ 'expected' => 'good!-',
+ ),
+
+ Array(
+ 'id' => 143,
+ 'template' => "{{testString foo bar=' '}}",
+ 'data' => Array('foo' => 'good!'),
+ 'options' => Array(
+ 'flags' => LightnCandy::FLAG_HANDLEBARSJS,
+ 'helpers' => Array(
+ 'testString' => function($args, $named) {
+ return $args[0] . '-' . $named['bar'];
+ }
+ ),
+ ),
+ 'expected' => 'good!- ',
+ ),
+
+ Array(
+ 'id' => 143,
+ 'template' => "{{testString foo bar=''}}",
+ 'data' => Array('foo' => 'good!'),
+ 'options' => Array(
+ 'flags' => LightnCandy::FLAG_HANDLEBARSJS,
+ 'helpers' => Array(
+ 'testString' => function($args, $named) {
+ return $args[0] . '-' . $named['bar'];
+ }
+ ),
+ ),
+ 'expected' => 'good!-',
+ ),
+
+ Array(
+ 'id' => 143,
+ 'template' => "{{testString foo bar=\" \"}}",
+ 'data' => Array('foo' => 'good!'),
+ 'options' => Array(
+ 'flags' => LightnCandy::FLAG_HANDLEBARSJS,
+ 'hbhelpers' => Array(
+ 'testString' => function($arg1, $options) {
+ return $arg1 . '-' . $options['hash']['bar'];
+ }
+ ),
+ ),
+ 'expected' => 'good!- ',
+ ),
+
+ Array(
+ 'id' => 147,
+ 'template' => '{{> test/test3 foo="bar"}}',
+ 'data' => Array('test' => 'OK!', 'foo' => 'error'),
+ 'options' => Array(
+ 'flags' => LightnCandy::FLAG_HANDLEBARSJS | LightnCandy::FLAG_RUNTIMEPARTIAL,
+ 'partials' => Array('test/test3' => '{{test}}, {{foo}}'),
+ ),
+ 'expected' => 'OK!, bar'
+ ),
+
+ Array(
+ 'id' => 147,
+ 'template' => '{{> test/test3 foo="bar"}}',
+ 'data' => new foo(),
+ 'options' => Array(
+ 'flags' => LightnCandy::FLAG_HANDLEBARSJS | LightnCandy::FLAG_RUNTIMEPARTIAL | LightnCandy::FLAG_INSTANCE,
+ 'partials' => Array('test/test3' => '{{bar}}, {{foo}}'),
+ ),
+ 'expected' => 'OK!, bar'
+ ),
+
+ Array(
+ 'id' => 150,
+ 'template' => '{{{.}}}',
+ 'data' => Array('hello' => 'world'),
+ 'options' => Array(
+ 'flags' => LightnCandy::FLAG_HANDLEBARSJS,
+ 'lcrun' => 'MyLCRunClass',
+ ),
+ 'expected' => "[[DEBUG:raw()=>array (\n 'hello' => 'world',\n)]]",
+ ),
+
+ Array(
+ 'id' => 153,
+ 'template' => '{{echo "test[]"}}',
+ 'data' => null,
+ 'options' => Array(
+ 'flags' => LightnCandy::FLAG_HANDLEBARSJS,
+ 'helpers' => Array(
+ 'echo' => function ($in) {
+ return "-$in[0]-";
+ }
+ )
+ ),
+ 'expected' => "-test[]-",
+ ),
+
+ Array(
+ 'id' => 153,
+ 'template' => '{{echo \'test[]\'}}',
+ 'data' => null,
+ 'options' => Array(
+ 'flags' => LightnCandy::FLAG_HANDLEBARSJS,
+ 'helpers' => Array(
+ 'echo' => function ($in) {
+ return "-$in[0]-";
+ }
+ )
+ ),
+ 'expected' => "-test[]-",
+ ),
+
+ Array(
+ 'id' => 154,
+ 'template' => 'O{{! this is comment ! ... }}K!',
+ 'data' => null,
+ 'options' => Array(
+ 'flags' => LightnCandy::FLAG_HANDLEBARSJS,
+ ),
+ 'expected' => "OK!"
+ ),
+
+ Array(
+ 'template' => '{{testNull null undefined 1}}',
+ 'data' => 'test',
+ 'options' => Array(
+ 'flags' => LightnCandy::FLAG_HANDLEBARSJS,
+ 'hbhelpers' => Array(
+ 'testNull' => function($arg1, $arg2) {
+ return (($arg1 === null) && ($arg2 === null)) ? 'YES!' : 'no';
+ }
+ )
+ ),
+ 'expected' => 'YES!'
+ ),
+
+ Array(
+ 'template' => '{{> (pname foo) bar}}',
+ 'data' => Array('bar' => 'OK! SUBEXP+PARTIAL!', 'foo' => Array('test/test3')),
+ 'options' => Array(
+ 'helpers' => Array(
+ 'pname' => function($arg) {
+ return $arg[0];
+ }
+ ),
+ 'flags' => LightnCandy::FLAG_HANDLEBARSJS | LightnCandy::FLAG_RUNTIMEPARTIAL,
+ 'partials' => Array('test/test3' => '{{.}}'),
+ ),
+ 'expected' => 'OK! SUBEXP+PARTIAL!'
+ ),
+
+ Array(
+ 'template' => '{{> testpartial newcontext mixed=foo}}',
+ 'data' => Array('foo' => 'OK!', 'newcontext' => Array('bar' => 'test')),
+ 'options' => Array(
+ 'flags' => LightnCandy::FLAG_HANDLEBARSJS | LightnCandy::FLAG_RUNTIMEPARTIAL,
+ 'partials' => Array('testpartial' => '{{bar}}-{{mixed}}'),
+ ),
+ 'expected' => 'test-OK!'
+ ),
+
+ Array(
+ 'template' => '{{[helper]}}',
+ 'options' => Array(
+ 'flags' => LightnCandy::FLAG_HANDLEBARSJS,
+ 'hbhelpers' => Array(
+ 'helper' => function () {
+ return 'DEF';
+ }
+ )
+ ),
+ 'data' => Array(),
+ 'expected' => 'DEF'
+ ),
+
+ Array(
+ 'template' => '{{#[helper3]}}ABC{{/[helper3]}}',
+ 'options' => Array(
+ 'flags' => LightnCandy::FLAG_HANDLEBARSJS,
+ 'hbhelpers' => Array(
+ 'helper3' => function () {
+ return 'DEF';
+ }
+ )
+ ),
+ 'data' => Array(),
+ 'expected' => 'DEF'
+ ),
+
+ Array(
+ 'template' => '{{#[helper3]}}ABC{{/[helper3]}}',
+ 'options' => Array(
+ 'flags' => LightnCandy::FLAG_HANDLEBARSJS,
+ 'blockhelpers' => Array(
+ 'helper3' => function () {
+ return Array('a', 'b', 'c');
+ }
+ )
+ ),
+ 'data' => Array(),
+ 'expected' => 'ABC'
+ ),
+
+ Array(
+ 'template' => '{{hash abc=["def=123"]}}',
+ 'options' => Array(
+ 'flags' => LightnCandy::FLAG_HANDLEBARSJS | LightnCandy::FLAG_BESTPERFORMANCE,
+ 'hbhelpers' => Array(
+ 'hash' => function ($options) {
+ $ret = '';
+ foreach ($options['hash'] as $k => $v) {
+ $ret .= "$k : $v,";
+ }
+ return $ret;
+ }
+ ),
+ ),
+ 'data' => Array('"def=123"' => 'La!'),
+ 'expected' => 'abc : La!,',
+ ),
+
+ Array(
+ 'template' => '{{hash abc=[\'def=123\']}}',
+ 'options' => Array(
+ 'flags' => LightnCandy::FLAG_HANDLEBARSJS | LightnCandy::FLAG_BESTPERFORMANCE,
+ 'hbhelpers' => Array(
+ 'hash' => function ($options) {
+ $ret = '';
+ foreach ($options['hash'] as $k => $v) {
+ $ret .= "$k : $v,";
+ }
+ return $ret;
+ }
+ ),
+ ),
+ 'data' => Array("'def=123'" => 'La!'),
+ 'expected' => 'abc : La!,',
+ ),
+
+ Array(
'template' => 'ABC{{#block "YES!"}}DEF{{foo}}GHI{{else}}NO~{{/block}}JKL',
'options' => Array(
'flags' => LightnCandy::FLAG_HANDLEBARSJS | LightnCandy::FLAG_BESTPERFORMANCE,
@@ -558,6 +1164,9 @@ VAREND
'he' => 'helper1',
'h2' => 'myClass::helper2',
'link' => function ($arg) {
+ if (is_array($arg)) {
+ $arg = 'Array';
+ }
return "<a href=\"{$arg}\">click here</a>";
},
'alink',