From d7c0ed12353231bc3425117b62ed56d9a9862628 Mon Sep 17 00:00:00 2001
From: Demian Katz <demian.katz@villanova.edu>
Date: Fri, 24 Oct 2014 14:14:05 -0400
Subject: [PATCH] Installed Mink w/ Zombie driver.

---
 composer.json                                 |    4 +
 composer.lock                                 |  216 ++-
 vendor/autoload.php                           |    2 +-
 vendor/behat/mink-zombie-driver/.gitignore    |    5 +
 vendor/behat/mink-zombie-driver/.travis.yml   |   25 +
 vendor/behat/mink-zombie-driver/CHANGELOG.md  |   35 +
 vendor/behat/mink-zombie-driver/README.md     |   81 +
 vendor/behat/mink-zombie-driver/composer.json |   45 +
 .../behat/mink-zombie-driver/phpunit.xml.dist |   23 +
 .../Behat/Mink/Driver/NodeJS/Connection.php   |   97 ++
 .../src/Behat/Mink/Driver/NodeJS/Server.php   |  441 +++++
 .../Driver/NodeJS/Server/ZombieServer.php     |  197 +++
 .../src/Behat/Mink/Driver/ZombieDriver.php    |  945 +++++++++++
 .../tests/Custom/ExtraTest.php                |   29 +
 .../tests/Custom/NodeJS/ServerTest.php        |  281 +++
 .../NodeJS/server-fixtures/empty_server.js    |    2 +
 .../NodeJS/server-fixtures/test_server.js     |   10 +
 .../mink-zombie-driver/tests/ZombieConfig.php |   60 +
 vendor/behat/mink/.gitignore                  |    5 +
 vendor/behat/mink/.travis.yml                 |   12 +
 vendor/behat/mink/CHANGES.md                  |  238 +++
 vendor/behat/mink/CONTRIBUTING.md             |   22 +
 vendor/behat/mink/LICENSE                     |   22 +
 vendor/behat/mink/README.md                   |   72 +
 vendor/behat/mink/composer.json               |   46 +
 vendor/behat/mink/driver-testsuite/README.md  |   93 +
 .../behat/mink/driver-testsuite/bootstrap.php |   28 +
 .../driver-testsuite/tests/AbstractConfig.php |   83 +
 .../tests/Basic/BasicAuthTest.php             |   64 +
 .../tests/Basic/ContentTest.php               |   74 +
 .../tests/Basic/CookieTest.php                |  167 ++
 .../tests/Basic/ErrorHandlingTest.php         |  262 +++
 .../tests/Basic/HeaderTest.php                |   77 +
 .../tests/Basic/IFrameTest.php                |   27 +
 .../tests/Basic/NavigationTest.php            |   69 +
 .../tests/Basic/ScreenshotTest.php            |   30 +
 .../tests/Basic/StatusCodeTest.php            |   22 +
 .../tests/Basic/TraversingTest.php            |  129 ++
 .../tests/Basic/VisibilityTest.php            |   20 +
 .../driver-testsuite/tests/Css/HoverTest.php  |   76 +
 .../tests/Form/CheckboxTest.php               |   73 +
 .../tests/Form/GeneralTest.php                |  312 ++++
 .../driver-testsuite/tests/Form/Html5Test.php |  128 ++
 .../driver-testsuite/tests/Form/RadioTest.php |   84 +
 .../tests/Form/SelectTest.php                 |  135 ++
 .../tests/Js/ChangeEventTest.php              |  152 ++
 .../driver-testsuite/tests/Js/EventsTest.php  |  122 ++
 .../tests/Js/JavascriptEvaluationTest.php     |   85 +
 .../tests/Js/JavascriptTest.php               |   42 +
 .../driver-testsuite/tests/Js/WindowTest.php  |   83 +
 .../mink/driver-testsuite/tests/TestCase.php  |  156 ++
 .../driver-testsuite/web-fixtures/404.php     |    2 +
 .../driver-testsuite/web-fixtures/500.php     |    2 +
 .../web-fixtures/advanced_form.html           |   40 +
 .../web-fixtures/advanced_form_post.php       |   26 +
 .../web-fixtures/aria_roles.html              |   30 +
 .../web-fixtures/basic_auth.php               |   12 +
 .../web-fixtures/basic_form.html              |   22 +
 .../web-fixtures/basic_form_post.php          |   13 +
 .../web-fixtures/basic_get_form.php           |   20 +
 .../web-fixtures/cookie_page1.php             |   21 +
 .../web-fixtures/cookie_page2.php             |   10 +
 .../web-fixtures/cookie_page3.php             |   16 +
 .../web-fixtures/css_mouse_events.html        |   36 +
 .../web-fixtures/element_change_detector.html |   65 +
 .../web-fixtures/empty_textarea.html          |   14 +
 .../web-fixtures/form_without_button.html     |   13 +
 .../driver-testsuite/web-fixtures/headers.php |   10 +
 .../web-fixtures/html5_form.html              |   18 +
 .../web-fixtures/html5_radio.html             |   16 +
 .../web-fixtures/html5_types.html             |   18 +
 .../web-fixtures/html_decoding.html           |   17 +
 .../driver-testsuite/web-fixtures/iframe.html |   12 +
 .../web-fixtures/iframe_inner.html            |   10 +
 .../driver-testsuite/web-fixtures/index.html  |   51 +
 .../web-fixtures/issue130.php                 |   11 +
 .../web-fixtures/issue131.html                |   17 +
 .../web-fixtures/issue140.php                 |   16 +
 .../web-fixtures/issue178.html                |   19 +
 .../web-fixtures/issue193.html                |   26 +
 .../web-fixtures/issue211.html                |   23 +
 .../web-fixtures/issue212.html                |    9 +
 .../web-fixtures/issue215.html                |   17 +
 .../web-fixtures/issue225.html                |   20 +
 .../web-fixtures/issue255.html                |   33 +
 .../web-fixtures/js/jquery-1.6.2-min.js       |   18 +
 .../js/jquery-ui-1.8.14.custom.min.js         |  127 ++
 .../web-fixtures/js_test.html                 |  110 ++
 .../driver-testsuite/web-fixtures/json.php    |    7 +
 .../driver-testsuite/web-fixtures/links.html  |   15 +
 .../web-fixtures/multi_input_form.html        |   27 +
 .../web-fixtures/multicheckbox_form.html      |   17 +
 .../web-fixtures/multiselect_form.html        |   32 +
 .../driver-testsuite/web-fixtures/popup1.html |   13 +
 .../driver-testsuite/web-fixtures/popup2.html |   13 +
 .../web-fixtures/print_cookies.php            |   10 +
 .../driver-testsuite/web-fixtures/radio.html  |   21 +
 .../web-fixtures/randomizer.php               |   12 +
 .../web-fixtures/redirect_destination.html    |   10 +
 .../web-fixtures/redirector.php               |    3 +
 .../web-fixtures/response_headers.php         |   15 +
 .../web-fixtures/session_test.php             |   18 +
 .../web-fixtures/some_file.txt                |    1 +
 .../web-fixtures/sub-folder/cookie_page1.php  |    4 +
 .../web-fixtures/sub-folder/cookie_page2.php  |    2 +
 .../driver-testsuite/web-fixtures/window.html |   26 +
 vendor/behat/mink/phpdoc.ini.dist             |  125 ++
 vendor/behat/mink/phpunit.xml.dist            |   15 +
 .../mink/src/Behat/Mink/Driver/CoreDriver.php |  447 +++++
 .../src/Behat/Mink/Driver/DriverInterface.php |  637 +++++++
 .../Behat/Mink/Element/DocumentElement.php    |   53 +
 .../mink/src/Behat/Mink/Element/Element.php   |  207 +++
 .../Behat/Mink/Element/ElementInterface.php   |  114 ++
 .../src/Behat/Mink/Element/NodeElement.php    |  352 ++++
 .../Behat/Mink/Element/TraversableElement.php |  309 ++++
 .../Behat/Mink/Exception/DriverException.php  |   31 +
 .../Behat/Mink/Exception/ElementException.php |   58 +
 .../Mink/Exception/ElementHtmlException.php   |   49 +
 .../Exception/ElementNotFoundException.php    |   53 +
 .../Mink/Exception/ElementTextException.php   |   24 +
 .../src/Behat/Mink/Exception/Exception.php    |   20 +
 .../Mink/Exception/ExpectationException.php   |  145 ++
 .../Mink/Exception/ResponseTextException.php  |   24 +
 .../UnsupportedDriverActionException.php      |   35 +
 vendor/behat/mink/src/Behat/Mink/Mink.php     |  216 +++
 .../src/Behat/Mink/Selector/CssSelector.php   |   37 +
 .../Mink/Selector/ExactNamedSelector.php      |   29 +
 .../src/Behat/Mink/Selector/NamedSelector.php |  238 +++
 .../Mink/Selector/PartialNamedSelector.php    |   31 +
 .../Behat/Mink/Selector/SelectorInterface.php |   28 +
 .../Behat/Mink/Selector/SelectorsHandler.php  |  125 ++
 .../src/Behat/Mink/Selector/Xpath/Escaper.php |   52 +
 .../Behat/Mink/Selector/Xpath/Manipulator.php |   69 +
 vendor/behat/mink/src/Behat/Mink/Session.php  |  352 ++++
 .../behat/mink/src/Behat/Mink/WebAssert.php   |  748 ++++++++
 .../mink/tests/Driver/CoreDriverTest.php      |   76 +
 .../tests/Element/DocumentElementTest.php     |  446 +++++
 .../behat/mink/tests/Element/ElementTest.php  |   76 +
 .../mink/tests/Element/NodeElementTest.php    |  593 +++++++
 .../tests/Exception/ElementExceptionTest.php  |   39 +
 .../Exception/ElementHtmlExceptionTest.php    |   61 +
 .../ElementNotFoundExceptionTest.php          |   34 +
 .../Exception/ElementTextExceptionTest.php    |   59 +
 .../Exception/ExpectationExceptionTest.php    |   84 +
 .../Exception/ResponseTextExceptionTest.php   |   62 +
 vendor/behat/mink/tests/MinkTest.php          |  246 +++
 .../mink/tests/Selector/CssSelectorTest.php   |   41 +
 .../tests/Selector/ExactNamedSelectorTest.php |   18 +
 .../mink/tests/Selector/NamedSelectorTest.php |  157 ++
 .../Selector/PartialNamedSelectorTest.php     |   18 +
 .../tests/Selector/SelectorsHandlerTest.php   |   80 +
 .../mink/tests/Selector/Xpath/EscaperTest.php |   31 +
 .../tests/Selector/Xpath/ManipulatorTest.php  |   64 +
 .../mink/tests/Selector/fixtures/test.html    |  310 ++++
 vendor/behat/mink/tests/SessionTest.php       |  282 +++
 vendor/behat/mink/tests/WebAssertTest.php     | 1123 ++++++++++++
 vendor/composer/autoload_namespaces.php       |    4 +
 vendor/composer/autoload_real.php             |    8 +-
 vendor/composer/installed.json                |  219 +++
 .../Symfony/Component/CssSelector/.gitignore  |    3 +
 .../Component/CssSelector/CHANGELOG.md        |    7 +
 .../Component/CssSelector/CssSelector.php     |   83 +
 .../Exception/ExceptionInterface.php          |   24 +
 .../Exception/ExpressionErrorException.php    |   24 +
 .../Exception/InternalErrorException.php      |   24 +
 .../CssSelector/Exception/ParseException.php  |   24 +
 .../Exception/SyntaxErrorException.php        |   73 +
 .../Symfony/Component/CssSelector/LICENSE     |   19 +
 .../CssSelector/Node/AbstractNode.php         |   40 +
 .../CssSelector/Node/AttributeNode.php        |  124 ++
 .../Component/CssSelector/Node/ClassNode.php  |   75 +
 .../CssSelector/Node/CombinedSelectorNode.php |   92 +
 .../CssSelector/Node/ElementNode.php          |   77 +
 .../CssSelector/Node/FunctionNode.php         |   96 ++
 .../Component/CssSelector/Node/HashNode.php   |   75 +
 .../CssSelector/Node/NegationNode.php         |   75 +
 .../CssSelector/Node/NodeInterface.php        |   44 +
 .../Component/CssSelector/Node/PseudoNode.php |   75 +
 .../CssSelector/Node/SelectorNode.php         |   75 +
 .../CssSelector/Node/Specificity.php          |   78 +
 .../Parser/Handler/CommentHandler.php         |   46 +
 .../Parser/Handler/HandlerInterface.php       |   34 +
 .../Parser/Handler/HashHandler.php            |   67 +
 .../Parser/Handler/IdentifierHandler.php      |   67 +
 .../Parser/Handler/NumberHandler.php          |   58 +
 .../Parser/Handler/StringHandler.php          |   86 +
 .../Parser/Handler/WhitespaceHandler.php      |   44 +
 .../Component/CssSelector/Parser/Parser.php   |  399 +++++
 .../CssSelector/Parser/ParserInterface.php    |   34 +
 .../Component/CssSelector/Parser/Reader.php   |  125 ++
 .../Parser/Shortcut/ClassParser.php           |   50 +
 .../Parser/Shortcut/ElementParser.php         |   46 +
 .../Parser/Shortcut/EmptyStringParser.php     |   44 +
 .../Parser/Shortcut/HashParser.php            |   50 +
 .../Component/CssSelector/Parser/Token.php    |  160 ++
 .../CssSelector/Parser/TokenStream.php        |  182 ++
 .../Parser/Tokenizer/Tokenizer.php            |   78 +
 .../Parser/Tokenizer/TokenizerEscaping.php    |   82 +
 .../Parser/Tokenizer/TokenizerPatterns.php    |  160 ++
 .../Symfony/Component/CssSelector/README.md   |   48 +
 .../CssSelector/Tests/CssSelectorTest.php     |   64 +
 .../Tests/Node/AbstractNodeTest.php           |   32 +
 .../Tests/Node/AttributeNodeTest.php          |   37 +
 .../CssSelector/Tests/Node/ClassNodeTest.php  |   33 +
 .../Tests/Node/CombinedSelectorNodeTest.php   |   35 +
 .../Tests/Node/ElementNodeTest.php            |   35 +
 .../Tests/Node/FunctionNodeTest.php           |   47 +
 .../CssSelector/Tests/Node/HashNodeTest.php   |   33 +
 .../Tests/Node/NegationNodeTest.php           |   33 +
 .../CssSelector/Tests/Node/PseudoNodeTest.php |   32 +
 .../Tests/Node/SelectorNodeTest.php           |   34 +
 .../Tests/Node/SpecificityTest.php            |   40 +
 .../Parser/Handler/AbstractHandlerTest.php    |   67 +
 .../Parser/Handler/CommentHandlerTest.php     |   55 +
 .../Tests/Parser/Handler/HashHandlerTest.php  |   49 +
 .../Parser/Handler/IdentifierHandlerTest.php  |   49 +
 .../Parser/Handler/NumberHandlerTest.php      |   50 +
 .../Parser/Handler/StringHandlerTest.php      |   50 +
 .../Parser/Handler/WhitespaceHandlerTest.php  |   44 +
 .../CssSelector/Tests/Parser/ParserTest.php   |  248 +++
 .../CssSelector/Tests/Parser/ReaderTest.php   |  101 ++
 .../Tests/Parser/Shortcut/ClassParserTest.php |   44 +
 .../Parser/Shortcut/ElementParserTest.php     |   43 +
 .../Parser/Shortcut/EmptyStringParserTest.php |   35 +
 .../Tests/Parser/Shortcut/HashParserTest.php  |   44 +
 .../Tests/Parser/TokenStreamTest.php          |   95 ++
 .../CssSelector/Tests/XPath/Fixtures/ids.html |   48 +
 .../CssSelector/Tests/XPath/Fixtures/lang.xml |   11 +
 .../Tests/XPath/Fixtures/shakespear.html      |  308 ++++
 .../Tests/XPath/TranslatorTest.php            |  324 ++++
 .../XPath/Extension/AbstractExtension.php     |   63 +
 .../Extension/AttributeMatchingExtension.php  |  173 ++
 .../XPath/Extension/CombinationExtension.php  |   93 +
 .../XPath/Extension/ExtensionInterface.php    |   67 +
 .../XPath/Extension/FunctionExtension.php     |  209 +++
 .../XPath/Extension/HtmlExtension.php         |  238 +++
 .../XPath/Extension/NodeExtension.php         |  271 +++
 .../XPath/Extension/PseudoClassExtension.php  |  162 ++
 .../CssSelector/XPath/Translator.php          |  299 ++++
 .../CssSelector/XPath/TranslatorInterface.php |   45 +
 .../Component/CssSelector/XPath/XPathExpr.php |  140 ++
 .../Component/CssSelector/composer.json       |   35 +
 .../Component/CssSelector/phpunit.xml.dist    |   25 +
 .../Symfony/Component/Process/.gitignore      |    3 +
 .../Symfony/Component/Process/CHANGELOG.md    |   40 +
 .../Process/Exception/ExceptionInterface.php  |   21 +
 .../Exception/InvalidArgumentException.php    |   21 +
 .../Process/Exception/LogicException.php      |   21 +
 .../Exception/ProcessFailedException.php      |   53 +
 .../Exception/ProcessTimedOutException.php    |   69 +
 .../Process/Exception/RuntimeException.php    |   21 +
 .../Component/Process/ExecutableFinder.php    |   89 +
 .../process/Symfony/Component/Process/LICENSE |   19 +
 .../Component/Process/PhpExecutableFinder.php |   86 +
 .../Symfony/Component/Process/PhpProcess.php  |   73 +
 .../Symfony/Component/Process/Process.php     | 1509 +++++++++++++++++
 .../Component/Process/ProcessBuilder.php      |  287 ++++
 .../Component/Process/ProcessPipes.php        |  382 +++++
 .../Component/Process/ProcessUtils.php        |  108 ++
 .../Symfony/Component/Process/README.md       |   51 +
 .../Process/Tests/AbstractProcessTest.php     | 1104 ++++++++++++
 .../Process/Tests/ExecutableFinderTest.php    |  147 ++
 .../Process/Tests/NonStopableProcess.php      |   37 +
 .../Process/Tests/PhpExecutableFinderTest.php |   97 ++
 .../Process/Tests/PhpProcessTest.php          |   29 +
 .../PipeStdinInStdoutStdErrStreamSelect.php   |   63 +
 .../Process/Tests/ProcessBuilderTest.php      |  225 +++
 .../Tests/ProcessFailedExceptionTest.php      |  136 ++
 .../Tests/ProcessInSigchildEnvironment.php    |   22 +
 .../Process/Tests/ProcessUtilsTest.php        |   48 +
 .../Tests/SigchildDisabledProcessTest.php     |  263 +++
 .../Tests/SigchildEnabledProcessTest.php      |  148 ++
 .../Process/Tests/SignalListener.php          |   16 +
 .../Process/Tests/SimpleProcessTest.php       |  222 +++
 .../Symfony/Component/Process/composer.json   |   31 +
 .../Component/Process/phpunit.xml.dist        |   23 +
 276 files changed, 27912 insertions(+), 7 deletions(-)
 create mode 100644 vendor/behat/mink-zombie-driver/.gitignore
 create mode 100644 vendor/behat/mink-zombie-driver/.travis.yml
 create mode 100644 vendor/behat/mink-zombie-driver/CHANGELOG.md
 create mode 100755 vendor/behat/mink-zombie-driver/README.md
 create mode 100644 vendor/behat/mink-zombie-driver/composer.json
 create mode 100644 vendor/behat/mink-zombie-driver/phpunit.xml.dist
 create mode 100644 vendor/behat/mink-zombie-driver/src/Behat/Mink/Driver/NodeJS/Connection.php
 create mode 100644 vendor/behat/mink-zombie-driver/src/Behat/Mink/Driver/NodeJS/Server.php
 create mode 100644 vendor/behat/mink-zombie-driver/src/Behat/Mink/Driver/NodeJS/Server/ZombieServer.php
 create mode 100644 vendor/behat/mink-zombie-driver/src/Behat/Mink/Driver/ZombieDriver.php
 create mode 100644 vendor/behat/mink-zombie-driver/tests/Custom/ExtraTest.php
 create mode 100644 vendor/behat/mink-zombie-driver/tests/Custom/NodeJS/ServerTest.php
 create mode 100644 vendor/behat/mink-zombie-driver/tests/Custom/NodeJS/server-fixtures/empty_server.js
 create mode 100644 vendor/behat/mink-zombie-driver/tests/Custom/NodeJS/server-fixtures/test_server.js
 create mode 100644 vendor/behat/mink-zombie-driver/tests/ZombieConfig.php
 create mode 100644 vendor/behat/mink/.gitignore
 create mode 100644 vendor/behat/mink/.travis.yml
 create mode 100644 vendor/behat/mink/CHANGES.md
 create mode 100644 vendor/behat/mink/CONTRIBUTING.md
 create mode 100644 vendor/behat/mink/LICENSE
 create mode 100644 vendor/behat/mink/README.md
 create mode 100644 vendor/behat/mink/composer.json
 create mode 100644 vendor/behat/mink/driver-testsuite/README.md
 create mode 100644 vendor/behat/mink/driver-testsuite/bootstrap.php
 create mode 100644 vendor/behat/mink/driver-testsuite/tests/AbstractConfig.php
 create mode 100644 vendor/behat/mink/driver-testsuite/tests/Basic/BasicAuthTest.php
 create mode 100644 vendor/behat/mink/driver-testsuite/tests/Basic/ContentTest.php
 create mode 100644 vendor/behat/mink/driver-testsuite/tests/Basic/CookieTest.php
 create mode 100644 vendor/behat/mink/driver-testsuite/tests/Basic/ErrorHandlingTest.php
 create mode 100644 vendor/behat/mink/driver-testsuite/tests/Basic/HeaderTest.php
 create mode 100644 vendor/behat/mink/driver-testsuite/tests/Basic/IFrameTest.php
 create mode 100644 vendor/behat/mink/driver-testsuite/tests/Basic/NavigationTest.php
 create mode 100644 vendor/behat/mink/driver-testsuite/tests/Basic/ScreenshotTest.php
 create mode 100644 vendor/behat/mink/driver-testsuite/tests/Basic/StatusCodeTest.php
 create mode 100644 vendor/behat/mink/driver-testsuite/tests/Basic/TraversingTest.php
 create mode 100644 vendor/behat/mink/driver-testsuite/tests/Basic/VisibilityTest.php
 create mode 100644 vendor/behat/mink/driver-testsuite/tests/Css/HoverTest.php
 create mode 100644 vendor/behat/mink/driver-testsuite/tests/Form/CheckboxTest.php
 create mode 100644 vendor/behat/mink/driver-testsuite/tests/Form/GeneralTest.php
 create mode 100644 vendor/behat/mink/driver-testsuite/tests/Form/Html5Test.php
 create mode 100644 vendor/behat/mink/driver-testsuite/tests/Form/RadioTest.php
 create mode 100644 vendor/behat/mink/driver-testsuite/tests/Form/SelectTest.php
 create mode 100644 vendor/behat/mink/driver-testsuite/tests/Js/ChangeEventTest.php
 create mode 100644 vendor/behat/mink/driver-testsuite/tests/Js/EventsTest.php
 create mode 100644 vendor/behat/mink/driver-testsuite/tests/Js/JavascriptEvaluationTest.php
 create mode 100644 vendor/behat/mink/driver-testsuite/tests/Js/JavascriptTest.php
 create mode 100644 vendor/behat/mink/driver-testsuite/tests/Js/WindowTest.php
 create mode 100644 vendor/behat/mink/driver-testsuite/tests/TestCase.php
 create mode 100644 vendor/behat/mink/driver-testsuite/web-fixtures/404.php
 create mode 100644 vendor/behat/mink/driver-testsuite/web-fixtures/500.php
 create mode 100644 vendor/behat/mink/driver-testsuite/web-fixtures/advanced_form.html
 create mode 100644 vendor/behat/mink/driver-testsuite/web-fixtures/advanced_form_post.php
 create mode 100644 vendor/behat/mink/driver-testsuite/web-fixtures/aria_roles.html
 create mode 100644 vendor/behat/mink/driver-testsuite/web-fixtures/basic_auth.php
 create mode 100644 vendor/behat/mink/driver-testsuite/web-fixtures/basic_form.html
 create mode 100644 vendor/behat/mink/driver-testsuite/web-fixtures/basic_form_post.php
 create mode 100644 vendor/behat/mink/driver-testsuite/web-fixtures/basic_get_form.php
 create mode 100644 vendor/behat/mink/driver-testsuite/web-fixtures/cookie_page1.php
 create mode 100644 vendor/behat/mink/driver-testsuite/web-fixtures/cookie_page2.php
 create mode 100644 vendor/behat/mink/driver-testsuite/web-fixtures/cookie_page3.php
 create mode 100644 vendor/behat/mink/driver-testsuite/web-fixtures/css_mouse_events.html
 create mode 100644 vendor/behat/mink/driver-testsuite/web-fixtures/element_change_detector.html
 create mode 100644 vendor/behat/mink/driver-testsuite/web-fixtures/empty_textarea.html
 create mode 100644 vendor/behat/mink/driver-testsuite/web-fixtures/form_without_button.html
 create mode 100644 vendor/behat/mink/driver-testsuite/web-fixtures/headers.php
 create mode 100644 vendor/behat/mink/driver-testsuite/web-fixtures/html5_form.html
 create mode 100644 vendor/behat/mink/driver-testsuite/web-fixtures/html5_radio.html
 create mode 100644 vendor/behat/mink/driver-testsuite/web-fixtures/html5_types.html
 create mode 100644 vendor/behat/mink/driver-testsuite/web-fixtures/html_decoding.html
 create mode 100644 vendor/behat/mink/driver-testsuite/web-fixtures/iframe.html
 create mode 100644 vendor/behat/mink/driver-testsuite/web-fixtures/iframe_inner.html
 create mode 100644 vendor/behat/mink/driver-testsuite/web-fixtures/index.html
 create mode 100644 vendor/behat/mink/driver-testsuite/web-fixtures/issue130.php
 create mode 100644 vendor/behat/mink/driver-testsuite/web-fixtures/issue131.html
 create mode 100644 vendor/behat/mink/driver-testsuite/web-fixtures/issue140.php
 create mode 100644 vendor/behat/mink/driver-testsuite/web-fixtures/issue178.html
 create mode 100644 vendor/behat/mink/driver-testsuite/web-fixtures/issue193.html
 create mode 100644 vendor/behat/mink/driver-testsuite/web-fixtures/issue211.html
 create mode 100644 vendor/behat/mink/driver-testsuite/web-fixtures/issue212.html
 create mode 100644 vendor/behat/mink/driver-testsuite/web-fixtures/issue215.html
 create mode 100644 vendor/behat/mink/driver-testsuite/web-fixtures/issue225.html
 create mode 100644 vendor/behat/mink/driver-testsuite/web-fixtures/issue255.html
 create mode 100644 vendor/behat/mink/driver-testsuite/web-fixtures/js/jquery-1.6.2-min.js
 create mode 100644 vendor/behat/mink/driver-testsuite/web-fixtures/js/jquery-ui-1.8.14.custom.min.js
 create mode 100644 vendor/behat/mink/driver-testsuite/web-fixtures/js_test.html
 create mode 100644 vendor/behat/mink/driver-testsuite/web-fixtures/json.php
 create mode 100644 vendor/behat/mink/driver-testsuite/web-fixtures/links.html
 create mode 100644 vendor/behat/mink/driver-testsuite/web-fixtures/multi_input_form.html
 create mode 100644 vendor/behat/mink/driver-testsuite/web-fixtures/multicheckbox_form.html
 create mode 100644 vendor/behat/mink/driver-testsuite/web-fixtures/multiselect_form.html
 create mode 100644 vendor/behat/mink/driver-testsuite/web-fixtures/popup1.html
 create mode 100644 vendor/behat/mink/driver-testsuite/web-fixtures/popup2.html
 create mode 100644 vendor/behat/mink/driver-testsuite/web-fixtures/print_cookies.php
 create mode 100644 vendor/behat/mink/driver-testsuite/web-fixtures/radio.html
 create mode 100644 vendor/behat/mink/driver-testsuite/web-fixtures/randomizer.php
 create mode 100644 vendor/behat/mink/driver-testsuite/web-fixtures/redirect_destination.html
 create mode 100644 vendor/behat/mink/driver-testsuite/web-fixtures/redirector.php
 create mode 100644 vendor/behat/mink/driver-testsuite/web-fixtures/response_headers.php
 create mode 100644 vendor/behat/mink/driver-testsuite/web-fixtures/session_test.php
 create mode 100644 vendor/behat/mink/driver-testsuite/web-fixtures/some_file.txt
 create mode 100644 vendor/behat/mink/driver-testsuite/web-fixtures/sub-folder/cookie_page1.php
 create mode 100644 vendor/behat/mink/driver-testsuite/web-fixtures/sub-folder/cookie_page2.php
 create mode 100644 vendor/behat/mink/driver-testsuite/web-fixtures/window.html
 create mode 100644 vendor/behat/mink/phpdoc.ini.dist
 create mode 100644 vendor/behat/mink/phpunit.xml.dist
 create mode 100644 vendor/behat/mink/src/Behat/Mink/Driver/CoreDriver.php
 create mode 100644 vendor/behat/mink/src/Behat/Mink/Driver/DriverInterface.php
 create mode 100644 vendor/behat/mink/src/Behat/Mink/Element/DocumentElement.php
 create mode 100644 vendor/behat/mink/src/Behat/Mink/Element/Element.php
 create mode 100644 vendor/behat/mink/src/Behat/Mink/Element/ElementInterface.php
 create mode 100644 vendor/behat/mink/src/Behat/Mink/Element/NodeElement.php
 create mode 100644 vendor/behat/mink/src/Behat/Mink/Element/TraversableElement.php
 create mode 100644 vendor/behat/mink/src/Behat/Mink/Exception/DriverException.php
 create mode 100644 vendor/behat/mink/src/Behat/Mink/Exception/ElementException.php
 create mode 100644 vendor/behat/mink/src/Behat/Mink/Exception/ElementHtmlException.php
 create mode 100644 vendor/behat/mink/src/Behat/Mink/Exception/ElementNotFoundException.php
 create mode 100644 vendor/behat/mink/src/Behat/Mink/Exception/ElementTextException.php
 create mode 100644 vendor/behat/mink/src/Behat/Mink/Exception/Exception.php
 create mode 100644 vendor/behat/mink/src/Behat/Mink/Exception/ExpectationException.php
 create mode 100644 vendor/behat/mink/src/Behat/Mink/Exception/ResponseTextException.php
 create mode 100644 vendor/behat/mink/src/Behat/Mink/Exception/UnsupportedDriverActionException.php
 create mode 100644 vendor/behat/mink/src/Behat/Mink/Mink.php
 create mode 100644 vendor/behat/mink/src/Behat/Mink/Selector/CssSelector.php
 create mode 100644 vendor/behat/mink/src/Behat/Mink/Selector/ExactNamedSelector.php
 create mode 100644 vendor/behat/mink/src/Behat/Mink/Selector/NamedSelector.php
 create mode 100644 vendor/behat/mink/src/Behat/Mink/Selector/PartialNamedSelector.php
 create mode 100644 vendor/behat/mink/src/Behat/Mink/Selector/SelectorInterface.php
 create mode 100644 vendor/behat/mink/src/Behat/Mink/Selector/SelectorsHandler.php
 create mode 100644 vendor/behat/mink/src/Behat/Mink/Selector/Xpath/Escaper.php
 create mode 100644 vendor/behat/mink/src/Behat/Mink/Selector/Xpath/Manipulator.php
 create mode 100644 vendor/behat/mink/src/Behat/Mink/Session.php
 create mode 100644 vendor/behat/mink/src/Behat/Mink/WebAssert.php
 create mode 100644 vendor/behat/mink/tests/Driver/CoreDriverTest.php
 create mode 100644 vendor/behat/mink/tests/Element/DocumentElementTest.php
 create mode 100644 vendor/behat/mink/tests/Element/ElementTest.php
 create mode 100644 vendor/behat/mink/tests/Element/NodeElementTest.php
 create mode 100644 vendor/behat/mink/tests/Exception/ElementExceptionTest.php
 create mode 100644 vendor/behat/mink/tests/Exception/ElementHtmlExceptionTest.php
 create mode 100644 vendor/behat/mink/tests/Exception/ElementNotFoundExceptionTest.php
 create mode 100644 vendor/behat/mink/tests/Exception/ElementTextExceptionTest.php
 create mode 100644 vendor/behat/mink/tests/Exception/ExpectationExceptionTest.php
 create mode 100644 vendor/behat/mink/tests/Exception/ResponseTextExceptionTest.php
 create mode 100644 vendor/behat/mink/tests/MinkTest.php
 create mode 100644 vendor/behat/mink/tests/Selector/CssSelectorTest.php
 create mode 100644 vendor/behat/mink/tests/Selector/ExactNamedSelectorTest.php
 create mode 100644 vendor/behat/mink/tests/Selector/NamedSelectorTest.php
 create mode 100644 vendor/behat/mink/tests/Selector/PartialNamedSelectorTest.php
 create mode 100644 vendor/behat/mink/tests/Selector/SelectorsHandlerTest.php
 create mode 100644 vendor/behat/mink/tests/Selector/Xpath/EscaperTest.php
 create mode 100644 vendor/behat/mink/tests/Selector/Xpath/ManipulatorTest.php
 create mode 100644 vendor/behat/mink/tests/Selector/fixtures/test.html
 create mode 100644 vendor/behat/mink/tests/SessionTest.php
 create mode 100644 vendor/behat/mink/tests/WebAssertTest.php
 create mode 100644 vendor/symfony/css-selector/Symfony/Component/CssSelector/.gitignore
 create mode 100644 vendor/symfony/css-selector/Symfony/Component/CssSelector/CHANGELOG.md
 create mode 100644 vendor/symfony/css-selector/Symfony/Component/CssSelector/CssSelector.php
 create mode 100644 vendor/symfony/css-selector/Symfony/Component/CssSelector/Exception/ExceptionInterface.php
 create mode 100644 vendor/symfony/css-selector/Symfony/Component/CssSelector/Exception/ExpressionErrorException.php
 create mode 100644 vendor/symfony/css-selector/Symfony/Component/CssSelector/Exception/InternalErrorException.php
 create mode 100644 vendor/symfony/css-selector/Symfony/Component/CssSelector/Exception/ParseException.php
 create mode 100644 vendor/symfony/css-selector/Symfony/Component/CssSelector/Exception/SyntaxErrorException.php
 create mode 100644 vendor/symfony/css-selector/Symfony/Component/CssSelector/LICENSE
 create mode 100644 vendor/symfony/css-selector/Symfony/Component/CssSelector/Node/AbstractNode.php
 create mode 100644 vendor/symfony/css-selector/Symfony/Component/CssSelector/Node/AttributeNode.php
 create mode 100644 vendor/symfony/css-selector/Symfony/Component/CssSelector/Node/ClassNode.php
 create mode 100644 vendor/symfony/css-selector/Symfony/Component/CssSelector/Node/CombinedSelectorNode.php
 create mode 100644 vendor/symfony/css-selector/Symfony/Component/CssSelector/Node/ElementNode.php
 create mode 100644 vendor/symfony/css-selector/Symfony/Component/CssSelector/Node/FunctionNode.php
 create mode 100644 vendor/symfony/css-selector/Symfony/Component/CssSelector/Node/HashNode.php
 create mode 100644 vendor/symfony/css-selector/Symfony/Component/CssSelector/Node/NegationNode.php
 create mode 100644 vendor/symfony/css-selector/Symfony/Component/CssSelector/Node/NodeInterface.php
 create mode 100644 vendor/symfony/css-selector/Symfony/Component/CssSelector/Node/PseudoNode.php
 create mode 100644 vendor/symfony/css-selector/Symfony/Component/CssSelector/Node/SelectorNode.php
 create mode 100644 vendor/symfony/css-selector/Symfony/Component/CssSelector/Node/Specificity.php
 create mode 100644 vendor/symfony/css-selector/Symfony/Component/CssSelector/Parser/Handler/CommentHandler.php
 create mode 100644 vendor/symfony/css-selector/Symfony/Component/CssSelector/Parser/Handler/HandlerInterface.php
 create mode 100644 vendor/symfony/css-selector/Symfony/Component/CssSelector/Parser/Handler/HashHandler.php
 create mode 100644 vendor/symfony/css-selector/Symfony/Component/CssSelector/Parser/Handler/IdentifierHandler.php
 create mode 100644 vendor/symfony/css-selector/Symfony/Component/CssSelector/Parser/Handler/NumberHandler.php
 create mode 100644 vendor/symfony/css-selector/Symfony/Component/CssSelector/Parser/Handler/StringHandler.php
 create mode 100644 vendor/symfony/css-selector/Symfony/Component/CssSelector/Parser/Handler/WhitespaceHandler.php
 create mode 100644 vendor/symfony/css-selector/Symfony/Component/CssSelector/Parser/Parser.php
 create mode 100644 vendor/symfony/css-selector/Symfony/Component/CssSelector/Parser/ParserInterface.php
 create mode 100644 vendor/symfony/css-selector/Symfony/Component/CssSelector/Parser/Reader.php
 create mode 100644 vendor/symfony/css-selector/Symfony/Component/CssSelector/Parser/Shortcut/ClassParser.php
 create mode 100644 vendor/symfony/css-selector/Symfony/Component/CssSelector/Parser/Shortcut/ElementParser.php
 create mode 100644 vendor/symfony/css-selector/Symfony/Component/CssSelector/Parser/Shortcut/EmptyStringParser.php
 create mode 100644 vendor/symfony/css-selector/Symfony/Component/CssSelector/Parser/Shortcut/HashParser.php
 create mode 100644 vendor/symfony/css-selector/Symfony/Component/CssSelector/Parser/Token.php
 create mode 100644 vendor/symfony/css-selector/Symfony/Component/CssSelector/Parser/TokenStream.php
 create mode 100644 vendor/symfony/css-selector/Symfony/Component/CssSelector/Parser/Tokenizer/Tokenizer.php
 create mode 100644 vendor/symfony/css-selector/Symfony/Component/CssSelector/Parser/Tokenizer/TokenizerEscaping.php
 create mode 100644 vendor/symfony/css-selector/Symfony/Component/CssSelector/Parser/Tokenizer/TokenizerPatterns.php
 create mode 100644 vendor/symfony/css-selector/Symfony/Component/CssSelector/README.md
 create mode 100644 vendor/symfony/css-selector/Symfony/Component/CssSelector/Tests/CssSelectorTest.php
 create mode 100644 vendor/symfony/css-selector/Symfony/Component/CssSelector/Tests/Node/AbstractNodeTest.php
 create mode 100644 vendor/symfony/css-selector/Symfony/Component/CssSelector/Tests/Node/AttributeNodeTest.php
 create mode 100644 vendor/symfony/css-selector/Symfony/Component/CssSelector/Tests/Node/ClassNodeTest.php
 create mode 100644 vendor/symfony/css-selector/Symfony/Component/CssSelector/Tests/Node/CombinedSelectorNodeTest.php
 create mode 100644 vendor/symfony/css-selector/Symfony/Component/CssSelector/Tests/Node/ElementNodeTest.php
 create mode 100644 vendor/symfony/css-selector/Symfony/Component/CssSelector/Tests/Node/FunctionNodeTest.php
 create mode 100644 vendor/symfony/css-selector/Symfony/Component/CssSelector/Tests/Node/HashNodeTest.php
 create mode 100644 vendor/symfony/css-selector/Symfony/Component/CssSelector/Tests/Node/NegationNodeTest.php
 create mode 100644 vendor/symfony/css-selector/Symfony/Component/CssSelector/Tests/Node/PseudoNodeTest.php
 create mode 100644 vendor/symfony/css-selector/Symfony/Component/CssSelector/Tests/Node/SelectorNodeTest.php
 create mode 100644 vendor/symfony/css-selector/Symfony/Component/CssSelector/Tests/Node/SpecificityTest.php
 create mode 100644 vendor/symfony/css-selector/Symfony/Component/CssSelector/Tests/Parser/Handler/AbstractHandlerTest.php
 create mode 100644 vendor/symfony/css-selector/Symfony/Component/CssSelector/Tests/Parser/Handler/CommentHandlerTest.php
 create mode 100644 vendor/symfony/css-selector/Symfony/Component/CssSelector/Tests/Parser/Handler/HashHandlerTest.php
 create mode 100644 vendor/symfony/css-selector/Symfony/Component/CssSelector/Tests/Parser/Handler/IdentifierHandlerTest.php
 create mode 100644 vendor/symfony/css-selector/Symfony/Component/CssSelector/Tests/Parser/Handler/NumberHandlerTest.php
 create mode 100644 vendor/symfony/css-selector/Symfony/Component/CssSelector/Tests/Parser/Handler/StringHandlerTest.php
 create mode 100644 vendor/symfony/css-selector/Symfony/Component/CssSelector/Tests/Parser/Handler/WhitespaceHandlerTest.php
 create mode 100644 vendor/symfony/css-selector/Symfony/Component/CssSelector/Tests/Parser/ParserTest.php
 create mode 100644 vendor/symfony/css-selector/Symfony/Component/CssSelector/Tests/Parser/ReaderTest.php
 create mode 100644 vendor/symfony/css-selector/Symfony/Component/CssSelector/Tests/Parser/Shortcut/ClassParserTest.php
 create mode 100644 vendor/symfony/css-selector/Symfony/Component/CssSelector/Tests/Parser/Shortcut/ElementParserTest.php
 create mode 100644 vendor/symfony/css-selector/Symfony/Component/CssSelector/Tests/Parser/Shortcut/EmptyStringParserTest.php
 create mode 100644 vendor/symfony/css-selector/Symfony/Component/CssSelector/Tests/Parser/Shortcut/HashParserTest.php
 create mode 100644 vendor/symfony/css-selector/Symfony/Component/CssSelector/Tests/Parser/TokenStreamTest.php
 create mode 100644 vendor/symfony/css-selector/Symfony/Component/CssSelector/Tests/XPath/Fixtures/ids.html
 create mode 100644 vendor/symfony/css-selector/Symfony/Component/CssSelector/Tests/XPath/Fixtures/lang.xml
 create mode 100644 vendor/symfony/css-selector/Symfony/Component/CssSelector/Tests/XPath/Fixtures/shakespear.html
 create mode 100644 vendor/symfony/css-selector/Symfony/Component/CssSelector/Tests/XPath/TranslatorTest.php
 create mode 100644 vendor/symfony/css-selector/Symfony/Component/CssSelector/XPath/Extension/AbstractExtension.php
 create mode 100644 vendor/symfony/css-selector/Symfony/Component/CssSelector/XPath/Extension/AttributeMatchingExtension.php
 create mode 100644 vendor/symfony/css-selector/Symfony/Component/CssSelector/XPath/Extension/CombinationExtension.php
 create mode 100644 vendor/symfony/css-selector/Symfony/Component/CssSelector/XPath/Extension/ExtensionInterface.php
 create mode 100644 vendor/symfony/css-selector/Symfony/Component/CssSelector/XPath/Extension/FunctionExtension.php
 create mode 100644 vendor/symfony/css-selector/Symfony/Component/CssSelector/XPath/Extension/HtmlExtension.php
 create mode 100644 vendor/symfony/css-selector/Symfony/Component/CssSelector/XPath/Extension/NodeExtension.php
 create mode 100644 vendor/symfony/css-selector/Symfony/Component/CssSelector/XPath/Extension/PseudoClassExtension.php
 create mode 100644 vendor/symfony/css-selector/Symfony/Component/CssSelector/XPath/Translator.php
 create mode 100644 vendor/symfony/css-selector/Symfony/Component/CssSelector/XPath/TranslatorInterface.php
 create mode 100644 vendor/symfony/css-selector/Symfony/Component/CssSelector/XPath/XPathExpr.php
 create mode 100644 vendor/symfony/css-selector/Symfony/Component/CssSelector/composer.json
 create mode 100644 vendor/symfony/css-selector/Symfony/Component/CssSelector/phpunit.xml.dist
 create mode 100644 vendor/symfony/process/Symfony/Component/Process/.gitignore
 create mode 100644 vendor/symfony/process/Symfony/Component/Process/CHANGELOG.md
 create mode 100644 vendor/symfony/process/Symfony/Component/Process/Exception/ExceptionInterface.php
 create mode 100644 vendor/symfony/process/Symfony/Component/Process/Exception/InvalidArgumentException.php
 create mode 100644 vendor/symfony/process/Symfony/Component/Process/Exception/LogicException.php
 create mode 100644 vendor/symfony/process/Symfony/Component/Process/Exception/ProcessFailedException.php
 create mode 100644 vendor/symfony/process/Symfony/Component/Process/Exception/ProcessTimedOutException.php
 create mode 100644 vendor/symfony/process/Symfony/Component/Process/Exception/RuntimeException.php
 create mode 100644 vendor/symfony/process/Symfony/Component/Process/ExecutableFinder.php
 create mode 100644 vendor/symfony/process/Symfony/Component/Process/LICENSE
 create mode 100644 vendor/symfony/process/Symfony/Component/Process/PhpExecutableFinder.php
 create mode 100644 vendor/symfony/process/Symfony/Component/Process/PhpProcess.php
 create mode 100644 vendor/symfony/process/Symfony/Component/Process/Process.php
 create mode 100644 vendor/symfony/process/Symfony/Component/Process/ProcessBuilder.php
 create mode 100644 vendor/symfony/process/Symfony/Component/Process/ProcessPipes.php
 create mode 100644 vendor/symfony/process/Symfony/Component/Process/ProcessUtils.php
 create mode 100644 vendor/symfony/process/Symfony/Component/Process/README.md
 create mode 100644 vendor/symfony/process/Symfony/Component/Process/Tests/AbstractProcessTest.php
 create mode 100644 vendor/symfony/process/Symfony/Component/Process/Tests/ExecutableFinderTest.php
 create mode 100644 vendor/symfony/process/Symfony/Component/Process/Tests/NonStopableProcess.php
 create mode 100644 vendor/symfony/process/Symfony/Component/Process/Tests/PhpExecutableFinderTest.php
 create mode 100644 vendor/symfony/process/Symfony/Component/Process/Tests/PhpProcessTest.php
 create mode 100644 vendor/symfony/process/Symfony/Component/Process/Tests/PipeStdinInStdoutStdErrStreamSelect.php
 create mode 100644 vendor/symfony/process/Symfony/Component/Process/Tests/ProcessBuilderTest.php
 create mode 100644 vendor/symfony/process/Symfony/Component/Process/Tests/ProcessFailedExceptionTest.php
 create mode 100644 vendor/symfony/process/Symfony/Component/Process/Tests/ProcessInSigchildEnvironment.php
 create mode 100644 vendor/symfony/process/Symfony/Component/Process/Tests/ProcessUtilsTest.php
 create mode 100644 vendor/symfony/process/Symfony/Component/Process/Tests/SigchildDisabledProcessTest.php
 create mode 100644 vendor/symfony/process/Symfony/Component/Process/Tests/SigchildEnabledProcessTest.php
 create mode 100644 vendor/symfony/process/Symfony/Component/Process/Tests/SignalListener.php
 create mode 100644 vendor/symfony/process/Symfony/Component/Process/Tests/SimpleProcessTest.php
 create mode 100644 vendor/symfony/process/Symfony/Component/Process/composer.json
 create mode 100644 vendor/symfony/process/Symfony/Component/Process/phpunit.xml.dist

diff --git a/composer.json b/composer.json
index e2af12dbd17..ea3e48a0c9b 100644
--- a/composer.json
+++ b/composer.json
@@ -64,5 +64,9 @@
         "zendframework/zendrest": "2.*",
         "zendframework/zendservice-amazon": "2.*",
         "zendframework/zendservice-recaptcha": "2.*"
+    },
+    "require-dev": {
+        "behat/mink": "1.6.*",
+        "behat/mink-zombie-driver": "*"
     }
 }
diff --git a/composer.lock b/composer.lock
index 9886fa2f3c9..e7c82166ee1 100644
--- a/composer.lock
+++ b/composer.lock
@@ -4,7 +4,7 @@
         "Read more about it at http://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
         "This file is @generated automatically"
     ],
-    "hash": "828ea6c9391fbecaa3c42071bdcfe98a",
+    "hash": "d5901d4c84a7e286ec6f2076c447928c",
     "packages": [
         {
             "name": "aferrandini/phpqrcode",
@@ -952,7 +952,219 @@
             "time": "2014-03-05 22:25:44"
         }
     ],
-    "packages-dev": [],
+    "packages-dev": [
+        {
+            "name": "behat/mink",
+            "version": "v1.6.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/Behat/Mink.git",
+                "reference": "090900a0049c441f1e072bbd837db4079b2250c5"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/Behat/Mink/zipball/090900a0049c441f1e072bbd837db4079b2250c5",
+                "reference": "090900a0049c441f1e072bbd837db4079b2250c5",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.3.1",
+                "symfony/css-selector": "~2.0"
+            },
+            "suggest": {
+                "behat/mink-browserkit-driver": "extremely fast headless driver for Symfony\\Kernel-based apps (Sf2, Silex)",
+                "behat/mink-goutte-driver": "fast headless driver for any app without JS emulation",
+                "behat/mink-selenium2-driver": "slow, but JS-enabled driver for any app (requires Selenium2)",
+                "behat/mink-zombie-driver": "fast and JS-enabled headless driver for any app (requires node.js)"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "1.6.x-dev"
+                }
+            },
+            "autoload": {
+                "psr-0": {
+                    "Behat\\Mink": "src/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Konstantin Kudryashov",
+                    "email": "ever.zet@gmail.com",
+                    "homepage": "http://everzet.com"
+                }
+            ],
+            "description": "Web acceptance testing framework for PHP 5.3",
+            "homepage": "http://mink.behat.org/",
+            "keywords": [
+                "browser",
+                "testing",
+                "web"
+            ],
+            "time": "2014-09-26 09:25:05"
+        },
+        {
+            "name": "behat/mink-zombie-driver",
+            "version": "v1.2.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/Behat/MinkZombieDriver.git",
+                "reference": "cf15a3a0cc4865bb55253cd033a03a20cee6d2d1"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/Behat/MinkZombieDriver/zipball/cf15a3a0cc4865bb55253cd033a03a20cee6d2d1",
+                "reference": "cf15a3a0cc4865bb55253cd033a03a20cee6d2d1",
+                "shasum": ""
+            },
+            "require": {
+                "behat/mink": "~1.6@dev",
+                "php": ">=5.3.1",
+                "symfony/process": "~2.1"
+            },
+            "type": "mink-driver",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "1.2.x-dev"
+                }
+            },
+            "autoload": {
+                "psr-0": {
+                    "Behat\\Mink\\Driver": "src/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Konstantin Kudryashov",
+                    "email": "ever.zet@gmail.com",
+                    "homepage": "http://everzet.com"
+                },
+                {
+                    "name": "Pascal Cremer",
+                    "email": "b00gizm@gmail.com",
+                    "homepage": "http://github.com/b00gizm"
+                }
+            ],
+            "description": "Zombie.js driver for Mink framework",
+            "homepage": "http://mink.behat.org/",
+            "keywords": [
+                "ajax",
+                "browser",
+                "headless",
+                "javascript",
+                "testing",
+                "zombie"
+            ],
+            "time": "2014-09-26 12:26:25"
+        },
+        {
+            "name": "symfony/css-selector",
+            "version": "v2.5.6",
+            "target-dir": "Symfony/Component/CssSelector",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/symfony/CssSelector.git",
+                "reference": "7cdf543a3f31935aae58de4e6e607d4bdeb3f5dc"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/symfony/CssSelector/zipball/7cdf543a3f31935aae58de4e6e607d4bdeb3f5dc",
+                "reference": "7cdf543a3f31935aae58de4e6e607d4bdeb3f5dc",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.3.3"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "2.5-dev"
+                }
+            },
+            "autoload": {
+                "psr-0": {
+                    "Symfony\\Component\\CssSelector\\": ""
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Symfony Community",
+                    "homepage": "http://symfony.com/contributors"
+                },
+                {
+                    "name": "Jean-François Simon",
+                    "email": "jeanfrancois.simon@sensiolabs.com"
+                },
+                {
+                    "name": "Fabien Potencier",
+                    "email": "fabien@symfony.com"
+                }
+            ],
+            "description": "Symfony CssSelector Component",
+            "homepage": "http://symfony.com",
+            "time": "2014-10-09 16:00:03"
+        },
+        {
+            "name": "symfony/process",
+            "version": "v2.5.6",
+            "target-dir": "Symfony/Component/Process",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/symfony/Process.git",
+                "reference": "9bbacbb3a7a27b17c0d51e2f126f59e0e588ad3a"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/symfony/Process/zipball/9bbacbb3a7a27b17c0d51e2f126f59e0e588ad3a",
+                "reference": "9bbacbb3a7a27b17c0d51e2f126f59e0e588ad3a",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.3.3"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "2.5-dev"
+                }
+            },
+            "autoload": {
+                "psr-0": {
+                    "Symfony\\Component\\Process\\": ""
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Symfony Community",
+                    "homepage": "http://symfony.com/contributors"
+                },
+                {
+                    "name": "Fabien Potencier",
+                    "email": "fabien@symfony.com"
+                }
+            ],
+            "description": "Symfony Process Component",
+            "homepage": "http://symfony.com",
+            "time": "2014-10-01 05:50:18"
+        }
+    ],
     "aliases": [],
     "minimum-stability": "stable",
     "stability-flags": {
diff --git a/vendor/autoload.php b/vendor/autoload.php
index c91827b063c..83ec3a8ef3e 100644
--- a/vendor/autoload.php
+++ b/vendor/autoload.php
@@ -4,4 +4,4 @@
 
 require_once __DIR__ . '/composer' . '/autoload_real.php';
 
-return ComposerAutoloaderInitc013b6451947464e0d11177f185bf9eb::getLoader();
+return ComposerAutoloaderInitc4a65bc36a0c8ed2b8f3216ed09d18dc::getLoader();
diff --git a/vendor/behat/mink-zombie-driver/.gitignore b/vendor/behat/mink-zombie-driver/.gitignore
new file mode 100644
index 00000000000..a8f93a2270e
--- /dev/null
+++ b/vendor/behat/mink-zombie-driver/.gitignore
@@ -0,0 +1,5 @@
+vendor
+composer.phar
+composer.lock
+phpunit.xml
+node_modules
diff --git a/vendor/behat/mink-zombie-driver/.travis.yml b/vendor/behat/mink-zombie-driver/.travis.yml
new file mode 100644
index 00000000000..2eae42a3834
--- /dev/null
+++ b/vendor/behat/mink-zombie-driver/.travis.yml
@@ -0,0 +1,25 @@
+language: php
+
+php: [5.3, 5.4, 5.5, 5.6, hhvm]
+
+before_script:
+  - export WEB_FIXTURES_HOST=http://localhost
+
+  # Install deps
+  - composer install --dev --prefer-source
+
+  - sudo apt-get update > /dev/null
+  - sudo apt-get install -y --force-yes apache2 libapache2-mod-php5
+  - sudo sed -i -e "s,/var/www,$(pwd)/vendor/behat/mink/driver-testsuite/web-fixtures,g" /etc/apache2/sites-available/default
+  - sudo /etc/init.d/apache2 restart
+
+  - npm install zombie
+
+  - export NODE_PATH="$(pwd)/node_modules"
+  - export PATH="/usr/local/share/npm/bin:$PATH"
+
+script: phpunit -v --coverage-clover=coverage.clover
+
+after_script:
+  - wget https://scrutinizer-ci.com/ocular.phar
+  - php ocular.phar code-coverage:upload --format=php-clover coverage.clover
diff --git a/vendor/behat/mink-zombie-driver/CHANGELOG.md b/vendor/behat/mink-zombie-driver/CHANGELOG.md
new file mode 100644
index 00000000000..a3981779ac6
--- /dev/null
+++ b/vendor/behat/mink-zombie-driver/CHANGELOG.md
@@ -0,0 +1,35 @@
+1.2.0 / 2014-09-26
+==================
+
+BC break:
+
+* Rewrote the driver based on Zombie 2.0 rather than the old 1.x versions
+* Changed the behavior of `getValue` for checkboxes according to the BC break in Mink 1.6
+
+New features:
+
+* Added the support of select elements in `setValue`
+* Implemented `getOuterHtml`
+* Added support for request headers
+* Implemented `submitForm`
+* Implemented `isSelected`
+
+Bug fixes:
+
+* Fixed the selection of options for multiple selects to ensure the change event is triggered only once
+* Fixed the selection of options for radio groups
+* Fixed `getValue` for radio groups
+* Fixed the retrieval of response headers
+* Fixed a leak of outdated references in the node server when changing page
+* Fixed the resetting of the driver to reset everything
+* Fixed the code to throw exceptions for invalid usages of the driver
+* Fixed handling of errors to throw exceptions in the driver rather than crashing the node server
+* Fixed `evaluateScript` and `executeScript` to support all syntaxes required by the Mink API
+* Fixed `getContent` to return the source of the page without decoding entities
+* Fixed the removal of cookies
+* Fixed the basic auth implementation
+
+Testing:
+
+* Updated the testsuite to use the new Mink 1.6 driver testsuite
+* Added testing on HHVM
diff --git a/vendor/behat/mink-zombie-driver/README.md b/vendor/behat/mink-zombie-driver/README.md
new file mode 100755
index 00000000000..74f125bda20
--- /dev/null
+++ b/vendor/behat/mink-zombie-driver/README.md
@@ -0,0 +1,81 @@
+Mink Zombie.js Driver
+=====================
+
+[![Latest Stable Version](https://poser.pugx.org/behat/mink-zombie-driver/v/stable.svg)](https://packagist.org/packages/behat/mink-zombie-driver)
+[![Latest Unstable Version](https://poser.pugx.org/behat/mink-zombie-driver/v/unstable.svg)](https://packagist.org/packages/behat/mink-zombie-driver)
+[![Total Downloads](https://poser.pugx.org/behat/mink-zombie-driver/downloads.svg)](https://packagist.org/packages/behat/mink-zombie-driver)
+[![Build Status](https://travis-ci.org/Behat/MinkZombieDriver.svg?branch=master)](https://travis-ci.org/Behat/MinkZombieDriver)
+[![Scrutinizer Quality Score](https://scrutinizer-ci.com/g/Behat/MinkZombieDriver/badges/quality-score.png?s=2e166ed0bc0d8bfde427fb9af2a93aaabbc09723)](https://scrutinizer-ci.com/g/Behat/MinkZombieDriver/)
+[![Code Coverage](https://scrutinizer-ci.com/g/Behat/MinkZombieDriver/badges/coverage.png?s=f271ed5a203ed036c6ce093e5269b60a76951f4f)](https://scrutinizer-ci.com/g/Behat/MinkZombieDriver/)
+[![License](https://poser.pugx.org/behat/mink-zombie-driver/license.svg)](https://packagist.org/packages/behat/mink-zombie-driver)
+
+Installation & Compatibility
+----------------------------
+
+You need a working installation of [NodeJS](http://nodejs.org/) and
+[npm](https://npmjs.org/). Install the
+[zombie.js](http://zombie.labnotes.org) library through npm:
+
+``` bash
+npm install -g zombie
+```
+
+The driver requires zombie.js __version 2.0.0 or higher__.
+
+Use [Composer](https://getcomposer.org/) to install all required PHP dependencies:
+
+```json
+{
+    "require": {
+        "behat/mink":               "~1.6",
+        "behat/mink-zombie-driver": "~1.2"
+    }
+}
+```
+
+```bash
+$> curl -sS https://getcomposer.org/installer | php
+$> php composer.phar install
+```
+
+Usage Example
+-------------
+
+```php
+<?php
+
+use Behat\Mink\Mink,
+    Behat\Mink\Session,
+    Behat\Mink\Driver\ZombieDriver,
+    Behat\Mink\Driver\NodeJS\Server\ZombieServer;
+
+$host       = '127.0.0.1';
+$port       = '8124';
+$nodeBinary = '/usr/local/bin/node';
+
+$mink = new Mink(array(
+    'zombie' => new Session(new ZombieDriver(new ZombieServer(
+        $host, $port, $nodeBinary
+    ))),
+));
+
+$mink->setDefaultSessionName('zombie');
+
+$session = $mink->getSession();
+$session->visit('http://example.org');
+
+$page = $session->getPage();
+$elem = $page->find('css', 'h1');
+
+echo $elem->getText();
+```
+
+Copyright
+---------
+
+Copyright (c) 2011-2012 Pascal Cremer <b00gizm@gmail.com>
+
+Maintainers
+-----------
+
+* Alexander Obuhovich [aik099](http://github.com/aik099)
diff --git a/vendor/behat/mink-zombie-driver/composer.json b/vendor/behat/mink-zombie-driver/composer.json
new file mode 100644
index 00000000000..172c8c1f88b
--- /dev/null
+++ b/vendor/behat/mink-zombie-driver/composer.json
@@ -0,0 +1,45 @@
+{
+    "name":         "behat/mink-zombie-driver",
+    "description":  "Zombie.js driver for Mink framework",
+    "keywords":     ["zombie", "headless", "javascript", "ajax", "testing", "browser"],
+    "homepage":     "http://mink.behat.org/",
+    "type":         "mink-driver",
+    "license":      "MIT",
+
+    "authors": [
+        {
+            "name":      "Pascal Cremer",
+            "email":     "b00gizm@gmail.com",
+            "homepage":  "http://github.com/b00gizm"
+        },
+        {
+            "name":      "Konstantin Kudryashov",
+            "email":     "ever.zet@gmail.com",
+            "homepage":  "http://everzet.com"
+        }
+    ],
+
+    "require": {
+        "php":              ">=5.3.1",
+        "behat/mink":       "~1.6@dev",
+        "symfony/process":  "~2.1"
+    },
+
+    "autoload": {
+        "psr-0": {
+            "Behat\\Mink\\Driver": "src/"
+        }
+    },
+
+    "autoload-dev": {
+        "psr-4": {
+            "Behat\\Mink\\Tests\\Driver\\": "tests"
+        }
+    },
+
+    "extra": {
+        "branch-alias": {
+            "dev-master": "1.2.x-dev"
+        }
+    }
+}
diff --git a/vendor/behat/mink-zombie-driver/phpunit.xml.dist b/vendor/behat/mink-zombie-driver/phpunit.xml.dist
new file mode 100644
index 00000000000..cd5862fbeab
--- /dev/null
+++ b/vendor/behat/mink-zombie-driver/phpunit.xml.dist
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<phpunit colors="true" bootstrap="vendor/behat/mink/driver-testsuite/bootstrap.php">
+    <testsuites>
+        <testsuite name="Driver test suite">
+            <directory>tests</directory>
+            <directory>vendor/behat/mink/driver-testsuite/tests</directory>
+        </testsuite>
+    </testsuites>
+
+    <php>
+        <var name="driver_config_factory" value="Behat\Mink\Tests\Driver\ZombieConfig::getInstance" />
+
+        <!--server name="WEB_FIXTURES_HOST" value="http://test.mink.dev" /-->
+        <!--server name="NODE_MODULES_PATH" value="path/to/ZombieDriver/node_modules/" /-->
+    </php>
+
+    <filter>
+        <whitelist>
+            <directory>./src/Behat/Mink/Driver</directory>
+        </whitelist>
+    </filter>
+</phpunit>
diff --git a/vendor/behat/mink-zombie-driver/src/Behat/Mink/Driver/NodeJS/Connection.php b/vendor/behat/mink-zombie-driver/src/Behat/Mink/Driver/NodeJS/Connection.php
new file mode 100644
index 00000000000..d0de3e973a8
--- /dev/null
+++ b/vendor/behat/mink-zombie-driver/src/Behat/Mink/Driver/NodeJS/Connection.php
@@ -0,0 +1,97 @@
+<?php
+
+/*
+ * This file is part of the Behat\Mink.
+ * (c) Konstantin Kudryashov <ever.zet@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Behat\Mink\Driver\NodeJS;
+
+/**
+ * The connection to the node TCP server.
+ *
+ * @author Pascal Cremer <b00gizm@gmail.com>
+ */
+class Connection
+{
+    /**
+     * @var string
+     */
+    private $host = null;
+
+    /**
+     * @var integer
+     */
+    private $port = null;
+
+    /**
+     * Initializes connection instance.
+     *
+     * @param string  $host zombie.js server host
+     * @param integer $port zombie.js server port
+     */
+    public function __construct($host = '127.0.0.1', $port = 8124)
+    {
+        $this->host = $host;
+        $this->port = intval($port);
+    }
+
+    /**
+     * Returns connection host.
+     *
+     * @return string
+     */
+    public function getHost()
+    {
+        return $this->host;
+    }
+
+    /**
+     * Returns connection port.
+     *
+     * @return int
+     */
+    public function getPort()
+    {
+        return $this->port;
+    }
+
+    /**
+     * Sends a payload string of Javascript code to the Zombie Node.js server.
+     *
+     * @param string $js String of Javascript code
+     *
+     * @return string
+     *
+     * @throws \RuntimeException Could not establish connection
+     */
+    public function socketSend($js)
+    {
+        $socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
+        if (false === @socket_connect($socket, $this->host, $this->port)) {
+            $errno = socket_last_error();
+            throw new \RuntimeException(
+                sprintf(
+                    "Could not establish connection: %s (%s)",
+                    socket_strerror($errno),
+                    $errno
+                )
+            );
+        }
+
+        socket_write($socket, $js, strlen($js));
+        socket_shutdown($socket, 1);
+
+        $out = '';
+        while ($o = socket_read($socket, 2048)) {
+            $out .= $o;
+        }
+
+        socket_close($socket);
+
+        return $out;
+    }
+}
diff --git a/vendor/behat/mink-zombie-driver/src/Behat/Mink/Driver/NodeJS/Server.php b/vendor/behat/mink-zombie-driver/src/Behat/Mink/Driver/NodeJS/Server.php
new file mode 100644
index 00000000000..94c9fb7cd6f
--- /dev/null
+++ b/vendor/behat/mink-zombie-driver/src/Behat/Mink/Driver/NodeJS/Server.php
@@ -0,0 +1,441 @@
+<?php
+
+/*
+ * This file is part of the Behat\Mink.
+ * (c) Konstantin Kudryashov <ever.zet@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Behat\Mink\Driver\NodeJS;
+
+use Symfony\Component\Process\ProcessBuilder;
+use Symfony\Component\Process\Process;
+
+/**
+ * Abstract base class to start and connect to a NodeJS server process.
+ *
+ * @author Pascal Cremer <b00gizm@gmail.com>
+ */
+abstract class Server
+{
+    /**
+     * @var string
+     */
+    protected $host;
+
+    /**
+     * @var int
+     */
+    protected $port;
+
+    /**
+     * @var string
+     */
+    protected $nodeBin;
+
+    /**
+     * @var string
+     */
+    protected $serverPath;
+
+    /**
+     * @var int
+     */
+    protected $threshold;
+
+    /**
+     * @var string The full path to the NodeJS modules directory.
+     */
+    protected $nodeModulesPath;
+
+    /**
+     * @var Process
+     */
+    protected $process;
+
+    /**
+     * @var Connection
+     */
+    protected $connection;
+
+    /**
+     * Constructor
+     *
+     * @param string $host            The server host
+     * @param int    $port            The server port
+     * @param string $nodeBin         Path to NodeJS binary
+     * @param string $serverPath      Path to server script
+     * @param int    $threshold       Threshold value in micro seconds
+     * @param string $nodeModulesPath Path to node_modules directory
+     */
+    public function __construct(
+        $host = '127.0.0.1',
+        $port = 8124,
+        $nodeBin = null,
+        $serverPath = null,
+        $threshold = 2000000,
+        $nodeModulesPath = ''
+    ) {
+        if (null === $nodeBin) {
+            $nodeBin = 'node';
+        }
+
+        $this->host            = $host;
+        $this->port            = intval($port);
+        $this->nodeBin         = $nodeBin;
+        $this->nodeModulesPath = $nodeModulesPath;
+
+        if (null === $serverPath) {
+            $serverPath = $this->createTemporaryServer();
+        }
+
+        $this->serverPath      = $serverPath;
+        $this->threshold       = intval($threshold);
+    }
+
+    /**
+     * Destructor
+     *
+     * Make sure that current process is stopped
+     */
+    public function __destruct()
+    {
+        $this->stop();
+    }
+
+    /**
+     * Setter host
+     *
+     * @param string $host The server host
+     */
+    public function setHost($host)
+    {
+        $this->host = $host;
+    }
+
+    /**
+     * Getter host
+     *
+     * @return string The server host
+     */
+    public function getHost()
+    {
+        return $this->host;
+    }
+
+    /**
+     * Setter port
+     *
+     * @param int $port The server port
+     */
+    public function setPort($port)
+    {
+        $this->port = intval($port);
+    }
+
+    /**
+     * Getter port
+     *
+     * @return int The server port
+     */
+    public function getPort()
+    {
+        return $this->port;
+    }
+
+    /**
+     * Setter NodeJS binary path
+     *
+     * @param string $nodeBin Path to NodeJS binary
+     */
+    public function setNodeBin($nodeBin)
+    {
+        $this->nodeBin = $nodeBin;
+    }
+
+    /**
+     * Getter NodeJS binary path
+     *
+     * @return string Path to NodeJS binary
+     */
+    public function getNodeBin()
+    {
+        return $this->nodeBin;
+    }
+
+    /**
+     * Setter NodeJS modules path
+     *
+     * @param  string                    $nodeModulesPath Path to NodeJS modules.
+     * @throws \InvalidArgumentException Invalid path
+     */
+    public function setNodeModulesPath($nodeModulesPath)
+    {
+        if (!is_dir($nodeModulesPath) || !preg_match('/\/$/', $nodeModulesPath)) {
+            throw new \InvalidArgumentException(sprintf(
+                "Node modules path '%s' is not a directory and/or does not end with a trailing '/'",
+                $nodeModulesPath
+            ));
+        }
+        $this->nodeModulesPath = $nodeModulesPath;
+        $this->serverPath = $this->createTemporaryServer();
+    }
+
+    /**
+     * Getter NodeJS modules path.
+     *
+     * @return string Path to NodeJS binary.
+     */
+    public function getNodeModulesPath()
+    {
+        return $this->nodeModulesPath;
+    }
+
+    /**
+     * Setter server script path
+     *
+     * @param string $serverPath Path to server script
+     */
+    public function setServerPath($serverPath)
+    {
+        $this->serverPath = $serverPath;
+    }
+
+    /**
+     * Getter server script path
+     *
+     * @return string Path to server script
+     */
+    public function getServerPath()
+    {
+        return $this->serverPath;
+    }
+
+    /**
+     * Setter threshold value
+     *
+     * @param int $threshold Threshold value in micro seconds
+     */
+    public function setThreshold($threshold)
+    {
+        $this->threshold = intval($threshold);
+    }
+
+    /**
+     * Getter threshold value
+     *
+     * @return int Threshold value in micro seconds
+     */
+    public function getThreshold()
+    {
+        return $this->threshold;
+    }
+
+    /**
+     * Getter process object
+     *
+     * @return Process The process object
+     */
+    public function getProcess()
+    {
+        return $this->process;
+    }
+
+    /**
+     * Getter connection object
+     *
+     * @return Connection
+     */
+    public function getConnection()
+    {
+        return $this->connection;
+    }
+
+    /**
+     * Starts the server process
+     *
+     * @param Process $process A process object
+     *
+     * @throws \RuntimeException
+     */
+    public function start(Process $process = null)
+    {
+        // Check if the server script exists at given path
+        if (false === $this->serverPath || false === is_file($this->serverPath)) {
+            throw new \RuntimeException(sprintf(
+                "Could not find server script at path '%s'",
+                $this->serverPath
+            ));
+        }
+
+        // Create process object if neccessary
+        if (null === $process) {
+            $processBuilder = new ProcessBuilder(array(
+                $this->nodeBin,
+                $this->serverPath,
+            ));
+            $process = $processBuilder->getProcess();
+        }
+        $this->process = $process;
+
+        // Start server process
+        $this->process->start();
+        $this->connection = null;
+
+        // Wait for the server to start up
+        $time = 0;
+        $successString = sprintf("server started on %s:%s", $this->host, $this->port);
+        while ($this->process->isRunning() && $time < $this->threshold) {
+            if ($successString == trim($this->process->getOutput())) {
+                $this->connection = new Connection($this->host, $this->port);
+                break;
+            }
+            usleep(1000);
+            $time += 1000;
+        }
+
+        // Make sure the server is ready or throw an exception otherwise
+        $this->checkAvailability();
+    }
+
+    /**
+     * Stops the server process
+     * @link https://github.com/symfony/Process
+     */
+    public function stop()
+    {
+        if (null === $this->process) {
+            return;
+        }
+
+        if (!$this->isRunning()) {
+            return;
+        }
+
+        if (null !== $this->getConnection()) {
+            // Force a 'clean' exit
+            // See: http://stackoverflow.com/a/5266208/187954
+            $this->doEvalJS($this->getConnection(), 'process.exit(0);');
+            $this->process->stop();
+            $this->process = null;
+        }
+    }
+
+    /**
+     * Restarts the server process
+     *
+     * @param Process $process A process object
+     */
+    public function restart(Process $process = null)
+    {
+        $this->stop();
+        $this->start($process);
+    }
+
+    /**
+     * Checks if the server process is running
+     *
+     * @link https://github.com/symfony/Process
+     *
+     * @return bool
+     */
+    public function isRunning()
+    {
+        if (null === $this->process) {
+            return false;
+        }
+
+        return $this->process->isRunning();
+    }
+
+    /**
+     * Checks the availability of the server triggers the evaluation
+     * of a string of JavaScript code by {{Behat\Mink\Driver\NodeJS\Server::doEvalJS()}}
+     *
+     * @param string $str        String of JavaScript code
+     * @param string $returnType Whether it should be eval'ed as JavaScript or wrapped in a JSON response
+     *
+     * @return mixed The eval'ed response
+     */
+    public function evalJS($str, $returnType = 'js')
+    {
+        $this->checkAvailability();
+
+        return $this->doEvalJS($this->connection, $str, $returnType);
+    }
+
+    /**
+     * Inherited classes will implement this method to prepare a string of
+     * JavaScript code for evaluation by the server and sending it over
+     * the server connection socket
+     *
+     * @param Connection $conn       The server connection
+     * @param string     $str        String of JavaScript code
+     * @param string     $returnType The return type
+     *
+     * @return mixed The eval'ed response
+     *
+     * @throws \InvalidArgumentException When unsupported $returnType given.
+     */
+    abstract protected function doEvalJS(Connection $conn, $str, $returnType = 'js');
+
+    /**
+     * Checks whether server connection and server process are still available
+     * and running
+     *
+     * @throws \RuntimeException
+     */
+    protected function checkAvailability()
+    {
+        if (null === $this->connection) {
+            if (null === $this->process) {
+                throw new \RuntimeException('No connection available. Did you start the server?');
+            }
+
+            if ($this->process->isRunning()) {
+                $this->stop();
+                throw new \RuntimeException(sprintf(
+                    'Server did not respond in time: (%s) [Stopped]',
+                    $this->process->getExitCode()
+                ));
+            }
+        }
+
+        if (!$this->process->isRunning()) {
+            throw new \RuntimeException(sprintf(
+                'Server process has been terminated: (%s) [%s]',
+                $this->process->getExitCode(),
+                $this->process->getErrorOutput()
+            ));
+        }
+    }
+
+    /**
+     * Creates a temporary server script
+     *
+     * @return string Path to the temporary server script
+     */
+    protected function createTemporaryServer()
+    {
+        $serverScript = strtr($this->getServerScript(), array(
+            '%host%'         => $this->host,
+            '%port%'         => $this->port,
+            '%modules_path%' => $this->nodeModulesPath,
+        ));
+
+        $serverPath = tempnam(sys_get_temp_dir(), 'mink_nodejs_server');
+        file_put_contents($serverPath, $serverScript);
+
+        return $serverPath;
+    }
+
+    /**
+     * Inherited classes will implement this method to provide the JavaScript
+     * code which powers the server script
+     *
+     * @return string The server's JavaScript code
+     */
+    abstract protected function getServerScript();
+}
diff --git a/vendor/behat/mink-zombie-driver/src/Behat/Mink/Driver/NodeJS/Server/ZombieServer.php b/vendor/behat/mink-zombie-driver/src/Behat/Mink/Driver/NodeJS/Server/ZombieServer.php
new file mode 100644
index 00000000000..becc0ba7d43
--- /dev/null
+++ b/vendor/behat/mink-zombie-driver/src/Behat/Mink/Driver/NodeJS/Server/ZombieServer.php
@@ -0,0 +1,197 @@
+<?php
+
+/*
+ * This file is part of the Behat\Mink.
+ * (c) Konstantin Kudryashov <ever.zet@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Behat\Mink\Driver\NodeJS\Server;
+
+use Behat\Mink\Driver\NodeJS\Connection;
+use Behat\Mink\Driver\NodeJS\Server;
+use Behat\Mink\Exception\DriverException;
+
+class ZombieServer extends Server
+{
+    const ERROR_PREFIX = 'CAUGHT_ERROR:';
+
+    /**
+     * {@inheritdoc}
+     */
+    protected function doEvalJS(Connection $conn, $str, $returnType = 'js')
+    {
+        switch ($returnType) {
+            case 'js':
+                $result = $conn->socketSend($str);
+                break;
+
+            case 'json':
+                $result = $conn->socketSend("stream.end(JSON.stringify({$str}))");
+                break;
+
+            default:
+                throw new \InvalidArgumentException(sprintf('Invalid return type "%s"', $returnType));
+        }
+
+        $errorPrefixLength = strlen(self::ERROR_PREFIX);
+
+        if (self::ERROR_PREFIX === substr($result, 0, $errorPrefixLength)) {
+            $errorMessage = json_decode(substr($result, $errorPrefixLength), true);
+
+            throw new DriverException(sprintf('Error "%s" while executing code: %s', $errorMessage, $str));
+        }
+
+        if ('json' === $returnType) {
+            return json_decode($result);
+        }
+
+        return $result;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    protected function getServerScript()
+    {
+        $errorPrefix = self::ERROR_PREFIX;
+
+        $js = <<<JS
+var net      = require('net')
+  , zombie   = require('%modules_path%zombie')
+  , Tough = require('%modules_path%zombie/node_modules/tough-cookie')
+  , browser  = null
+  , pointers = []
+  , buffer   = ''
+  , host     = '%host%'
+  , port     = %port%;
+
+Tough.Cookie.prototype.cookieString = function cookieString() {
+  return this.key + '=' + (this.value == null ? '' : this.value);
+};
+
+var zombieVersionCompare = function (v2, op) {
+  var version_compare = function (v1, v2, operator) {
+    var i = 0,
+        x = 0,
+        compare = 0,
+        vm = {
+          'dev': -6,
+          'alpha': -5,
+          'a': -5,
+          'beta': -4,
+          'b': -4,
+          'RC': -3,
+          'rc': -3,
+          '#': -2,
+          'p': 1,
+          'pl': 1
+        },
+        prepVersion = function (v) {
+          v = ('' + v).replace(/[_\-+]/g, '.');
+          v = v.replace(/([^.\d]+)/g, '.$1.').replace(/\.{2,}/g, '.');
+
+          return (!v.length ? [-8] : v.split('.'));
+        },
+        numVersion = function (v) {
+          return !v ? 0 : (isNaN(v) ? vm[v] || -7 : parseInt(v, 10));
+        };
+
+      v1 = prepVersion(v1);
+      v2 = prepVersion(v2);
+      x = Math.max(v1.length, v2.length);
+
+      for (i = 0; i < x; i++) {
+        if (v1[i] == v2[i]) {
+          continue;
+        }
+
+        v1[i] = numVersion(v1[i]);
+        v2[i] = numVersion(v2[i]);
+
+        if (v1[i] < v2[i]) {
+          compare = -1;
+          break;
+        } else if (v1[i] > v2[i]) {
+          compare = 1;
+          break;
+        }
+      }
+
+      if (!operator) {
+        return compare;
+      }
+
+      switch (operator) {
+        case '>':
+        case 'gt':
+          return (compare > 0);
+
+        case '>=':
+        case 'ge':
+          return (compare >= 0);
+
+        case '<=':
+        case 'le':
+          return (compare <= 0);
+
+        case '==':
+        case '=':
+        case 'eq':
+          return (compare === 0);
+
+        case '<>':
+        case '!=':
+        case 'ne':
+          return (compare !== 0);
+
+        case '':
+        case '<':
+        case 'lt':
+          return (compare < 0);
+      }
+
+      return null;
+  };
+
+  return version_compare(require('%modules_path%zombie/package').version, v2, op);
+};
+
+if (false == zombieVersionCompare('2.0.0', '>=')) {
+  throw new Error("Your zombie.js version is not compatible with this driver. Please use a version >= 2.0.0");
+}
+
+net.createServer(function (stream) {
+  stream.setEncoding('utf8');
+  stream.allowHalfOpen = true;
+
+  stream.on('data', function (data) {
+    buffer += data;
+  });
+
+  stream.on('end', function () {
+    if (browser == null) {
+      browser = new zombie();
+
+      // Clean up old pointers
+      pointers = [];
+    }
+
+    try {
+      eval(buffer);
+      buffer = '';
+    } catch (e) {
+      buffer = '';
+      stream.end('{$errorPrefix}' + JSON.stringify(e.message));
+    }
+  });
+}).listen(port, host, function () {
+  console.log('server started on ' + host + ':' + port);
+});
+JS;
+
+        return $js;
+    }
+}
diff --git a/vendor/behat/mink-zombie-driver/src/Behat/Mink/Driver/ZombieDriver.php b/vendor/behat/mink-zombie-driver/src/Behat/Mink/Driver/ZombieDriver.php
new file mode 100644
index 00000000000..84a1742dec3
--- /dev/null
+++ b/vendor/behat/mink-zombie-driver/src/Behat/Mink/Driver/ZombieDriver.php
@@ -0,0 +1,945 @@
+<?php
+
+/*
+ * This file is part of the Behat\Mink.
+ * (c) Konstantin Kudryashov <ever.zet@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Behat\Mink\Driver;
+
+use Behat\Mink\Driver\NodeJS\Server\ZombieServer;
+use Behat\Mink\Element\NodeElement;
+use Behat\Mink\Exception\DriverException;
+use Behat\Mink\Session;
+
+/**
+ * Zombie (JS) driver.
+ *
+ * @author Pascal Cremer <b00gizm@gmail.com>
+ */
+class ZombieDriver extends CoreDriver
+{
+    /**
+     * @var Session
+     */
+    private $session;
+    private $started = false;
+    private $nativeRefs = array();
+    private $server = null;
+
+    /**
+     * Constructor.
+     *
+     * @param ZombieServer|string $serverOrHost A server instance, or the host to connect to
+     * @param int|null            $port         The port to connect to when using the host (default to 8124)
+     */
+    public function __construct($serverOrHost, $port = null)
+    {
+        if ($serverOrHost instanceof ZombieServer) {
+            $this->server = $serverOrHost;
+
+            return;
+        }
+
+        if (null === $port) {
+            $port = 8124;
+        }
+
+        $this->server = new ZombieServer((string) $serverOrHost, $port);
+    }
+
+    /**
+     * Returns Zombie.js server.
+     *
+     * @return ZombieServer
+     */
+    public function getServer()
+    {
+        return $this->server;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function setSession(Session $session)
+    {
+        $this->session = $session;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function start()
+    {
+        if ($this->server) {
+            $this->server->start();
+        }
+
+        $this->started = true;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function isStarted()
+    {
+        return $this->started;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function stop()
+    {
+        if ($this->server) {
+            $this->server->stop();
+        }
+
+        $this->started = false;
+        $this->nativeRefs = array();
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function reset()
+    {
+        $js = <<<JS
+browser.destroy();
+browser = null;
+stream.end();
+JS;
+
+        $this->server->evalJS($js);
+        $this->nativeRefs = array();
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function visit($url)
+    {
+        // Cleanup cached references
+        $this->nativeRefs = array();
+
+        $js = <<<JS
+pointers = [];
+browser.visit("{$url}", function (err) {
+  if (err) {
+    stream.end(JSON.stringify(err.stack));
+  } else {
+    stream.end();
+  }
+});
+JS;
+        $this->server->evalJS($js);
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function getCurrentUrl()
+    {
+        return $this->server->evalJS('browser.location.toString()', 'json');
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function reload()
+    {
+        $this->visit($this->getCurrentUrl());
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function forward()
+    {
+        $this->server->evalJS("browser.window.history.forward(); browser.wait(function () { stream.end(); })");
+        $this->nativeRefs = array();
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function back()
+    {
+        $this->server->evalJS("browser.window.history.back(); browser.wait(function () { stream.end(); })");
+        $this->nativeRefs = array();
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function setBasicAuth($user, $password)
+    {
+        if (false === $user) {
+            $this->server->evalJS("browser.authenticate().reset();stream.end();");
+
+            return;
+        }
+
+        $userEscaped = json_encode($user);
+        $passwordEscaped = json_encode($password);
+
+        $this->server->evalJS("browser.authenticate().basic({$userEscaped}, {$passwordEscaped});stream.end();");
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function switchToWindow($name = null)
+    {
+        if ($name === null) {
+            $name = '';
+        }
+
+        $nameEscaped = json_encode($name);
+
+        $this->server->evalJS("browser.tabs.current = {$nameEscaped}; stream.end();");
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function setRequestHeader($name, $value)
+    {
+        $nameEscaped = json_encode($name);
+        $valueEscaped = json_encode($value);
+
+        if (strtolower($name) === 'user-agent') {
+            $this->server->evalJS("browser.userAgent = {$valueEscaped};stream.end();");
+
+            return;
+        }
+
+        $js = <<<JS
+if (!browser.headers) {
+  browser.headers = {};
+}
+browser.headers[{$nameEscaped}] = {$valueEscaped};
+stream.end();
+JS;
+        $this->server->evalJS($js);
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function getResponseHeaders()
+    {
+        return (array) $this->server->evalJS('browser.window._response.headers', 'json');
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function setCookie($name, $value = null)
+    {
+        if ($value === null) {
+            $this->deleteCookie($name);
+
+            return;
+        }
+
+        $nameEscaped = json_encode($name);
+        $valueEscaped = json_encode($value);
+
+        $js = <<<JS
+var cookieId = {name: {$nameEscaped}, domain: browser.window.location.hostname, path: '/'};
+
+browser.setCookie(cookieId, {$valueEscaped});
+stream.end();
+JS;
+
+        $this->server->evalJS($js);
+    }
+
+    private function deleteCookie($name)
+    {
+        $nameEscaped = json_encode($name);
+
+        $js = <<<JS
+var path = browser.window.location.pathname;
+
+do {
+    browser.deleteCookie({name: {$nameEscaped}, domain: browser.window.location.hostname, path: path});
+    path = path.replace(/.$/, '');
+} while (path);
+
+stream.end();
+JS;
+
+        $this->server->evalJS($js);
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function getCookie($name)
+    {
+        $nameEscaped = json_encode($name);
+
+        $js = <<<JS
+var cookieId = {name: {$nameEscaped}, domain: browser.window.location.hostname},
+    cookieVal = browser.getCookie(cookieId, false);
+
+if (cookieVal) {
+    stream.end(JSON.stringify(decodeURIComponent(cookieVal)));
+} else {
+    stream.end(JSON.stringify(null));
+}
+JS;
+
+        return json_decode($this->server->evalJS($js));
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function getStatusCode()
+    {
+        return (int) $this->server->evalJS('browser.statusCode', 'json');
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function getContent()
+    {
+        return $this->server->evalJS('browser.source', 'json');
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function find($xpath)
+    {
+        $xpathEncoded = json_encode($xpath);
+        $js = <<<JS
+var node,
+    refs = [],
+    result = browser.xpath({$xpathEncoded});
+
+while (node = result.iterateNext()) {
+    if (node.nodeType !== 10) {
+        pointers.push(node);
+        refs.push(pointers.length - 1);
+    }
+}
+stream.end(JSON.stringify(refs));
+JS;
+
+        $refs = json_decode($this->server->evalJS($js), true);
+
+        if (!$refs) {
+            return array();
+        }
+
+        $elements = array();
+        foreach ($refs as $i => $ref) {
+            $subXpath = sprintf('(%s)[%d]', $xpath, $i + 1);
+            $this->nativeRefs[md5($subXpath)] = $ref;
+            $elements[] = new NodeElement($subXpath, $this->session);
+
+            // first node ref also matches the original xpath
+            if (0 === $i) {
+                $this->nativeRefs[md5($xpath)] = $ref;
+            }
+        }
+
+        return $elements;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function getTagName($xpath)
+    {
+        $ref = $this->getNativeRefForXPath($xpath);
+
+        return strtolower($this->server->evalJS("{$ref}.tagName", 'json'));
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function getText($xpath)
+    {
+        $ref = $this->getNativeRefForXPath($xpath);
+
+        return trim($this->server->evalJS("{$ref}.textContent.replace(/\s+/g, ' ')", 'json'));
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function getHtml($xpath)
+    {
+        $ref = $this->getNativeRefForXPath($xpath);
+
+        return $this->server->evalJS("{$ref}.innerHTML", 'json');
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function getOuterHtml($xpath)
+    {
+        $ref = $this->getNativeRefForXPath($xpath);
+
+        return $this->server->evalJS("{$ref}.outerHTML", 'json');
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function getAttribute($xpath, $name)
+    {
+        $ref = $this->getNativeRefForXPath($xpath);
+
+        return $this->server->evalJS("{$ref}.getAttribute('{$name}')", 'json');
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function getValue($xpath)
+    {
+        $ref = $this->getNativeRefForXPath($xpath);
+
+        $js = <<<JS
+var node = {$ref},
+    tagName = node.tagName.toLowerCase(),
+    value = null;
+if (tagName == "input") {
+  var type = node.type.toLowerCase();
+  if (type == "checkbox") {
+    value = node.checked ? node.value : null;
+  } else if (type == "radio") {
+    if (node.checked) {
+      value = node.value;
+    } else {
+      var name = node.getAttribute('name');
+      if (name) {
+        var formElements = node.form.elements,
+            element;
+        for (var i = 0; i < formElements.length; i++) {
+          element = formElements[i];
+          if (element.type.toLowerCase() == 'radio' && element.getAttribute('name') === name && element.checked) {
+            value = element.value;
+            break;
+          }
+        }
+      }
+    }
+  } else {
+    value = node.value;
+  }
+} else if (tagName == "textarea") {
+  value = node.value;
+} else if (tagName == "select") {
+  if (node.multiple) {
+    value = [];
+    for (var i = 0; i < node.options.length; i++) {
+      if (node.options[i].selected) {
+        value.push(node.options[ i ].value);
+      }
+    }
+  } else {
+    var idx = node.selectedIndex;
+    if (idx >= 0) {
+      value = node.options.item(idx).value;
+    } else {
+      value = null;
+    }
+  }
+} else {
+  value = node.value;
+}
+stream.end(JSON.stringify(value));
+JS;
+
+        return json_decode($this->server->evalJS($js));
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function setValue($xpath, $value)
+    {
+        $ref = $this->getNativeRefForXPath($xpath);
+
+        $value = json_encode($value);
+
+        $js = <<<JS
+var node = {$ref},
+    value = {$value},
+    tagName = node.tagName.toLowerCase(),
+    type = node.type.toLowerCase();
+if (tagName == 'select') {
+  if (node.multiple) {
+    var toSelect = [];
+    var toUnselect = [];
+    var option;
+    for (var i = 0; i < node.options.length; i++) {
+      option = node.options[i];
+      if (option.selected && -1 === value.indexOf(option.value)) {
+        toUnselect.push(option);
+      } else if (!option.selected && -1 !== value.indexOf(option.value)) {
+        toSelect.push(option);
+      }
+    }
+
+    if (0 === toSelect.length && toUnselect.length > 0) {
+      for (i = 1; i < toUnselect.length; i++) {
+        toUnselect[i].selected = false;
+      }
+      browser.unselectOption(toUnselect[0]);
+    } else if (toSelect.length) {
+      for (i = 0; i < toUnselect.length; i++) {
+        toUnselect[i].selected = false;
+      }
+      for (i = 1; i < toSelect.length; i++) {
+        toUnselect[i].selected = true;
+      }
+      browser.selectOption(toSelect[0]);
+    }
+  } else {
+    browser.select(node, value);
+  }
+} else if (type == 'checkbox') {
+  value ? browser.check(node) : browser.uncheck(node);
+} else if (type == 'radio') {
+  if (node.value === value) {
+    browser.choose(node);
+  } else {
+    var formElements = node.form.elements,
+        name = node.getAttribute('name'),
+        found = false,
+        element;
+
+    if (!name) {
+      throw new Error('The radio button does not have the value "' + value + '"');
+    }
+
+    for (var i = 0; i < formElements.length; i++) {
+      element = formElements[i];
+      if (element.tagName.toLowerCase() == 'input' && element.type.toLowerCase() == 'radio' && element.name === name) {
+        if (value === element.value) {
+          found = true;
+          browser.choose(element);
+          break;
+        }
+      }
+    }
+
+    if (!found) {
+      throw new Error('The radio group "' + name + '" does not have an option "' + value + '"');
+    }
+  }
+} else {
+  browser.fill(node, value);
+}
+stream.end();
+JS;
+        $this->server->evalJS($js);
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function check($xpath)
+    {
+        $ref = $this->getNativeRefForXPath($xpath);
+
+        $this->server->evalJS("browser.check({$ref});stream.end();");
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function uncheck($xpath)
+    {
+        $ref = $this->getNativeRefForXPath($xpath);
+
+        $this->server->evalJS("browser.uncheck({$ref});stream.end();");
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function isChecked($xpath)
+    {
+        $ref = $this->getNativeRefForXPath($xpath);
+
+        return (boolean) $this->server->evalJS("{$ref}.checked", 'json');
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function selectOption($xpath, $value, $multiple = false)
+    {
+        $ref = $this->getNativeRefForXPath($xpath);
+        $value = json_encode($value);
+        $multiple = json_encode($multiple);
+        $js = <<<JS
+var node = {$ref},
+    value = {$value},
+    tagName = node.tagName.toLowerCase();
+if (tagName == "select") {
+  if (node.multiple && !{$multiple}) {
+    var toSelect,
+      option,
+      toUnselect = [];
+    for (var i = 0; i < node.options.length; i++) {
+      option = node.options[i];
+      if (option.selected && option.value !== value) {
+        toUnselect.push(option);
+      } else if (!option.selected && option.value === value) {
+        toSelect = option;
+      }
+    }
+
+    if (toSelect) {
+      for (i = 0; i < toUnselect.length; i++) {
+        toUnselect[i].selected = false;
+      }
+      browser.selectOption(toSelect);
+    } else if (toUnselect.length) {
+      for (i = 1; i < toUnselect.length; i++) {
+        toUnselect[i].selected = false;
+      }
+      browser.unselectOption(toUnselect[0]);
+    }
+  } else {
+    browser.select(node, value);
+  }
+} else if (tagName == "input" && node.type.toLowerCase() == 'radio') {
+  if (node.value === value) {
+    browser.choose(node);
+  } else {
+    var formElements = node.form.elements,
+        name = node.getAttribute('name'),
+        found = false,
+        element;
+
+    if (!name) {
+      throw new Error('The radio button does not have the value "' + value + '"');
+    }
+
+    for (var i = 0; i < formElements.length; i++) {
+      element = formElements[i];
+      if (element.tagName.toLowerCase() == 'input' && element.type.toLowerCase() == 'radio' && element.name === name) {
+        if (value === element.value) {
+          found = true;
+          browser.choose(element);
+          break;
+        }
+      }
+    }
+
+    if (!found) {
+      throw new Error('The radio group "' + name + '" does not have an option "' + value + '"');
+    }
+  }
+} else {
+  throw 'The element is not a select or radio input';
+}
+stream.end();
+JS;
+        $this->server->evalJS($js);
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function isSelected($xpath)
+    {
+        $ref = $this->getNativeRefForXPath($xpath);
+
+        return (boolean) $this->server->evalJS("{$ref}.selected", 'json');
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function click($xpath)
+    {
+        $ref = $this->getNativeRefForXPath($xpath);
+
+        $js = <<<JS
+var node    = {$ref},
+    tagName = node.tagName.toLowerCase(),
+    type    = (node.type || '').toLowerCase();
+
+if (tagName == "button" || (tagName == "input" && (type == "button" || type == "submit"))) {
+  if (node.disabled) {
+    stream.end('This button is disabled');
+  }
+}
+stream.end();
+JS;
+        $out = $this->server->evalJS($js);
+        if (!empty($out)) {
+            throw new DriverException(sprintf('Error while clicking button: [%s]', $out));
+        }
+
+        $this->triggerBrowserEvent('click', $xpath);
+        // Resets the cached references as the click action can go to a different page
+        // This ensures we don't have outdated refs on the new page if the same XPath is requested
+        // at the expense of loosing the know reference in case the click does not change page
+        $this->nativeRefs = array();
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function doubleClick($xpath)
+    {
+        $this->triggerBrowserEvent("dblclick", $xpath);
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function rightClick($xpath)
+    {
+        $this->triggerBrowserEvent("contextmenu", $xpath);
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function attachFile($xpath, $path)
+    {
+        $ref = $this->getNativeRefForXPath($xpath);
+        $path = json_encode($path);
+        $this->server->evalJS("browser.attach({$ref}, {$path});stream.end();");
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function mouseOver($xpath)
+    {
+        $this->triggerBrowserEvent("mouseover", $xpath);
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function focus($xpath)
+    {
+        $this->triggerBrowserEvent("focus", $xpath);
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function blur($xpath)
+    {
+        $this->triggerBrowserEvent("blur", $xpath);
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function keyPress($xpath, $char, $modifier = null)
+    {
+        $this->triggerKeyEvent("keypress", $xpath, $char, $modifier);
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function keyDown($xpath, $char, $modifier = null)
+    {
+        $this->triggerKeyEvent("keydown", $xpath, $char, $modifier);
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function keyUp($xpath, $char, $modifier = null)
+    {
+        $this->triggerKeyEvent("keyup", $xpath, $char, $modifier);
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function executeScript($script)
+    {
+        $script = json_encode($this->fixSelfExecutingFunction($script));
+        $this->server->evalJS("browser.evaluate({$script});stream.end();");
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function evaluateScript($script)
+    {
+        $script = preg_replace('/^return\s+/', '', $script);
+
+        $script = json_encode($this->fixSelfExecutingFunction($script));
+
+        return $this->server->evalJS("browser.evaluate({$script})", 'json');
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function wait($timeout, $condition)
+    {
+        $conditionEscaped = json_encode($condition);
+
+        $js = <<<JS
+(function () {
+  var checkCondition = function () {
+    return browser.evaluate($conditionEscaped);
+  };
+
+  browser.wait({function: checkCondition, duration: $timeout}, function () {
+    stream.end(JSON.stringify(checkCondition()));
+  });
+}());
+JS;
+
+        return json_decode($this->server->evalJS($js));
+    }
+
+    /**
+     * Returns last error.
+     *
+     * @return array
+     */
+    protected function getLastError()
+    {
+        return $this->server->evalJS('browser.lastError', 'json');
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function submitForm($xpath)
+    {
+        $ref = $this->getNativeRefForXPath($xpath);
+
+        $this->server->evalJS("{$ref}.submit();stream.end();");
+        $this->nativeRefs = array();
+    }
+
+    /**
+     * Triggers (fires) a Zombie.js browser event.
+     *
+     * @param string $event The name of the event
+     * @param string $xpath The xpath of the element to trigger this event
+     *
+     * @throws DriverException
+     */
+    protected function triggerBrowserEvent($event, $xpath)
+    {
+        $ref = $this->getNativeRefForXPath($xpath);
+
+        $js = <<<JS
+browser.fire({$ref}, "{$event}", function (err) {
+  if (err) {
+    stream.end(JSON.stringify(err.stack));
+  } else {
+    stream.end();
+  }
+});
+JS;
+        $out = $this->server->evalJS($js);
+        if (!empty($out)) {
+            throw new DriverException(sprintf("Error while processing event '%s'", $event));
+        }
+    }
+
+    /**
+     * Triggers a keyboard event
+     *
+     * @param string $name     The event name
+     * @param string $xpath    The xpath of the element to trigger this event on
+     * @param mixed  $char     could be either char ('b') or char-code (98)
+     * @param string $modifier keyboard modifier (could be 'ctrl', 'alt', 'shift' or 'meta')
+     */
+    protected function triggerKeyEvent($name, $xpath, $char, $modifier)
+    {
+        $ref = $this->getNativeRefForXPath($xpath);
+
+        $char = is_numeric($char) ? $char : ord($char);
+
+        $isCtrlKeyArg  = ($modifier == 'ctrl')  ? "true" : "false";
+        $isAltKeyArg   = ($modifier == 'alt')   ? "true" : "false";
+        $isShiftKeyArg = ($modifier == 'shift') ? "true" : "false";
+        $isMetaKeyArg  = ($modifier == 'meta')  ? "true" : "false";
+
+        $js = <<<JS
+var node = {$ref},
+    window = browser.window,
+    e = window.document.createEvent("UIEvents");
+e.initUIEvent("{$name}", true, true, window, 1);
+e.ctrlKey = {$isCtrlKeyArg};
+e.altKey = {$isAltKeyArg};
+e.shiftKey = {$isShiftKeyArg};
+e.metaKey = {$isMetaKeyArg};
+e.keyCode = {$char};
+node.dispatchEvent(e);
+stream.end();
+JS;
+        $this->server->evalJS($js);
+    }
+
+    /**
+     * Tries to fetch a native reference to a node that might have been cached
+     * by the server. If it can't be found, the method performs a search.
+     *
+     * Searching the native reference by the MD5 hash of its xpath feels kinda
+     * hackish, but it'll boost performance and prevents a lot of boilerplate
+     * Javascript code.
+     *
+     * @param string $xpath
+     *
+     * @return string
+     *
+     * @throws DriverException when there is no element matching the XPath
+     */
+    protected function getNativeRefForXPath($xpath)
+    {
+        $hash = md5($xpath);
+        if (!isset($this->nativeRefs[$hash])) {
+            $res = $this->find($xpath);
+            if (empty($res)) {
+                throw new DriverException(sprintf('There is no element matching XPath "%s"', $xpath));
+            }
+        }
+
+        return sprintf('pointers[%s]', $this->nativeRefs[$hash]);
+    }
+
+    /**
+     * Fixes self-executing functions to allow evaluating them.
+     *
+     * The self-executing function must be wrapped in braces to work.
+     *
+     * @param string $script
+     *
+     * @return string
+     */
+    private function fixSelfExecutingFunction($script)
+    {
+        if (preg_match('/^function[\s\(]/', $script)) {
+            $script = preg_replace('/;$/', '', $script);
+            $script = '(' . $script . ')';
+        }
+
+        return $script;
+    }
+}
diff --git a/vendor/behat/mink-zombie-driver/tests/Custom/ExtraTest.php b/vendor/behat/mink-zombie-driver/tests/Custom/ExtraTest.php
new file mode 100644
index 00000000000..d3af01f3e19
--- /dev/null
+++ b/vendor/behat/mink-zombie-driver/tests/Custom/ExtraTest.php
@@ -0,0 +1,29 @@
+<?php
+
+namespace Behat\Mink\Tests\Driver\Custom;
+
+use Behat\Mink\Tests\Driver\TestCase;
+
+/**
+ * @group zombiedriver
+ */
+class ExtraTest extends TestCase
+{
+    // TODO move upstream
+    public function testSetUserAgent()
+    {
+        $session = $this->getSession();
+
+        $session->setRequestHeader('user-agent', 'foo bar');
+        $session->visit($this->pathTo('/headers.php'));
+        $this->assertContains('foo bar', $session->getPage()->getText());
+    }
+
+    // TODO check whether this is covered by upstream test
+    public function testSetRequestHeader()
+    {
+        $this->getSession()->setRequestHeader('foo', 'bar');
+        $this->getSession()->visit($this->pathTo('/headers.php'));
+        $this->assertContains('[HTTP_FOO] => bar', $this->getSession()->getPage()->getText());
+    }
+}
diff --git a/vendor/behat/mink-zombie-driver/tests/Custom/NodeJS/ServerTest.php b/vendor/behat/mink-zombie-driver/tests/Custom/NodeJS/ServerTest.php
new file mode 100644
index 00000000000..852cb76f3d9
--- /dev/null
+++ b/vendor/behat/mink-zombie-driver/tests/Custom/NodeJS/ServerTest.php
@@ -0,0 +1,281 @@
+<?php
+
+namespace Behat\Mink\Tests\Driver\Custom\NodeJS;
+
+use Behat\Mink\Driver\NodeJS\Connection;
+use Behat\Mink\Driver\NodeJS\Server as BaseServer;
+
+class TestServer extends BaseServer
+{
+    public $serverScript = null;
+
+    protected function doEvalJS(Connection $conn, $str, $returnType = 'js')
+    {
+        return '';
+    }
+
+    protected function getServerScript()
+    {
+        return <<<JS
+var zombie = require('%modules_path%zombie')
+  , host   = '%host%'
+  , port   = %port%;
+JS;
+    }
+
+    protected function createTemporaryServer()
+    {
+        $this->serverScript = strtr($this->getServerScript(), array(
+            '%host%'         => $this->host,
+            '%port%'         => $this->port,
+            '%modules_path%' => $this->nodeModulesPath,
+          ));
+
+        return '/path/to/server';
+    }
+}
+
+class ServerTest extends \PHPUnit_Framework_TestCase
+{
+    public function testCreateServerWithDefaults()
+    {
+        $server = new TestServer();
+
+        $this->assertEquals('127.0.0.1', $server->getHost());
+        $this->assertEquals(8124, $server->getPort());
+        $this->assertEquals('node', $server->getNodeBin());
+        $this->assertEquals('/path/to/server', $server->getServerPath());
+        $this->assertEquals(2000000, $server->getThreshold());
+        $this->assertEquals('', $server->getNodeModulesPath());
+
+        $expected = <<<JS
+var zombie = require('zombie')
+  , host   = '127.0.0.1'
+  , port   = 8124;
+JS;
+        $this->assertEquals($expected, $server->serverScript);
+    }
+
+    public function testCreateCustomServer()
+    {
+        $server = new TestServer(
+            '123.123.123.123',
+            1234,
+            null,
+            null,
+            5000000,
+            '../../'
+        );
+
+        $this->assertEquals('123.123.123.123', $server->getHost());
+        $this->assertEquals(1234, $server->getPort());
+        $this->assertEquals('node', $server->getNodeBin());
+        $this->assertEquals('/path/to/server', $server->getServerPath());
+        $this->assertEquals(5000000, $server->getThreshold());
+        $this->assertEquals('../../', $server->getNodeModulesPath());
+
+        $expected = <<<JS
+var zombie = require('../../zombie')
+  , host   = '123.123.123.123'
+  , port   = 1234;
+JS;
+        $this->assertEquals($expected, $server->serverScript);
+    }
+
+    public function testSetNodeModulesPath()
+    {
+        $server = new TestServer();
+        $server->setNodeModulesPath('../../');
+
+        $this->assertEquals('../../', $server->getNodeModulesPath());
+
+        $expected = <<<JS
+var zombie = require('../../zombie')
+  , host   = '127.0.0.1'
+  , port   = 8124;
+JS;
+        $this->assertEquals($expected, $server->serverScript);
+    }
+
+    /**
+     * @expectedException  \InvalidArgumentException
+     */
+    public function testSetNodeModulesPathWithInvalidPath()
+    {
+        $server = new TestServer();
+        $server->setNodeModulesPath('/does/not/exist/');
+    }
+
+    /**
+     * @expectedException  \InvalidArgumentException
+     */
+    public function testSetNodeModulesPathWithoutTrailingSlash()
+    {
+        $server = new TestServer();
+        $server->setNodeModulesPath('../..');
+    }
+
+    /**
+     * @expectedException  \RuntimeException
+     */
+    public function testStartServerWithNonExistingServerScript()
+    {
+        $server = new TestServer('127.0.0.1', 8124, null, '/does/not/exist');
+        $server->start();
+    }
+
+    /**
+     * @expectedException \RuntimeException
+     * @expectedExceptionMessage Server did not respond in time: (1) [Stopped]
+     */
+    public function testStartServerThatDoesNotRespondInTime()
+    {
+        $process = $this->getNotRespondingServerProcessMock();
+        $process->expects($this->once())
+                ->method('start');
+
+        $serverPath = __DIR__.'/server-fixtures/test_server.js';
+        $server = new TestServer('127.0.0.1', 8124, null, $serverPath, 10000);
+
+        $server->start($process);
+    }
+
+    /**
+     * @expectedException \RuntimeException
+     * @expectedExceptionMessage Server process has been terminated: (1) [TROLOLOLO]
+     */
+    public function testStartServerThatWasTerminated()
+    {
+        $process = $this->getTerminatedServerProcessMock();
+        $process->expects($this->once())
+                ->method('start');
+
+        $serverPath = __DIR__.'/server-fixtures/test_server.js';
+        $server = new TestServer('127.0.0.1', 8124, null, $serverPath, 10000);
+
+        $server->start($process);
+    }
+
+    public function testStartServerSuccessfully()
+    {
+        $host = '127.0.0.1';
+        $port = 8124;
+
+        $process = $this->getWorkingServerProcessMock($host, $port);
+        $process->expects($this->once())
+                ->method('start');
+
+        $serverPath = __DIR__.'/server-fixtures/test_server.js';
+        $server = new TestServer($host, $port, null, $serverPath, 10000);
+
+        try {
+            $server->start($process);
+            $this->assertInstanceOf(
+                'Behat\Mink\Driver\NodeJS\Connection',
+                $server->getConnection()
+            );
+        } catch (\RuntimeException $ex) {
+            $this->fail('No exception should have been thrown here');
+        }
+    }
+
+    public function testStopServer()
+    {
+        $host = '127.0.0.1';
+        $port = 8124;
+
+        $process = $this->getWorkingServerProcessMock($host, $port);
+        $process->expects($this->atLeastOnce())
+                ->method('stop');
+
+        $serverPath = __DIR__.'/server-fixtures/test_server.js';
+        $server = new TestServer($host, $port, null, $serverPath, 10000);
+        $server->start($process);
+        $server->stop();
+    }
+
+    public function testIsRunning()
+    {
+        $host = '127.0.0.1';
+        $port = 8124;
+
+        $serverPath = __DIR__.'/server-fixtures/test_server.js';
+        $server = new TestServer($host, $port, null, $serverPath, 10000);
+
+        $this->assertFalse($server->isRunning());
+
+        $process = $this->getWorkingServerProcessMock($host, $port);
+        $server->start($process);
+
+        $this->assertTrue($server->isRunning());
+
+        $process = $this->getTerminatedServerProcessMock();
+
+        try {
+            $server->start($process);
+        } catch (\RuntimeException $ex) {
+            // ignore error
+        }
+
+        $this->assertFalse($server->isRunning());
+    }
+
+    protected function getNotRespondingServerProcessMock()
+    {
+        $process = $this->getMockBuilder('Symfony\Component\Process\Process')
+                        ->disableOriginalConstructor()
+                        ->getMock();
+
+        $process->expects($this->any())
+                ->method('isRunning')
+                ->will($this->returnValue(true));
+
+        $process->expects($this->any())
+                ->method('getOutput')
+                ->will($this->returnValue(''));
+
+        $process->expects($this->any())
+                ->method('getExitCode')
+                ->will($this->returnValue(1));
+
+        return $process;
+    }
+
+    protected function getTerminatedServerProcessMock()
+    {
+        $process = $this->getMockBuilder('Symfony\Component\Process\Process')
+                        ->disableOriginalConstructor()
+                        ->getMock();
+
+        $process->expects($this->any())
+                ->method('isRunning')
+                ->will($this->returnValue(false));
+
+        $process->expects($this->any())
+                ->method('getErrorOutput')
+                ->will($this->returnValue('TROLOLOLO'));
+
+        $process->expects($this->any())
+                ->method('getExitCode')
+                ->will($this->returnValue(1));
+
+        return $process;
+    }
+
+    protected function getWorkingServerProcessMock($host, $port)
+    {
+        $process = $this->getMockBuilder('Symfony\Component\Process\Process')
+                        ->disableOriginalConstructor()
+                        ->getMock();
+
+        $process->expects($this->any())
+                ->method('isRunning')
+                ->will($this->returnValue(true));
+
+        $process->expects($this->once())
+                ->method('getOutput')
+                ->will($this->returnValue(sprintf("server started on %s:%s", $host, $port)));
+
+        return $process;
+    }
+}
diff --git a/vendor/behat/mink-zombie-driver/tests/Custom/NodeJS/server-fixtures/empty_server.js b/vendor/behat/mink-zombie-driver/tests/Custom/NodeJS/server-fixtures/empty_server.js
new file mode 100644
index 00000000000..b36e7528d8d
--- /dev/null
+++ b/vendor/behat/mink-zombie-driver/tests/Custom/NodeJS/server-fixtures/empty_server.js
@@ -0,0 +1,2 @@
+// Nothing in here.
+
diff --git a/vendor/behat/mink-zombie-driver/tests/Custom/NodeJS/server-fixtures/test_server.js b/vendor/behat/mink-zombie-driver/tests/Custom/NodeJS/server-fixtures/test_server.js
new file mode 100644
index 00000000000..d1d63e24bd9
--- /dev/null
+++ b/vendor/behat/mink-zombie-driver/tests/Custom/NodeJS/server-fixtures/test_server.js
@@ -0,0 +1,10 @@
+var net = require('net');
+
+net.createServer(function (stream) {
+
+  // This server does nothing.
+
+}).listen(8124, '127.0.0.1');
+
+console.log('Server running at 127.0.0.1:8124');
+
diff --git a/vendor/behat/mink-zombie-driver/tests/ZombieConfig.php b/vendor/behat/mink-zombie-driver/tests/ZombieConfig.php
new file mode 100644
index 00000000000..fad98e4bbe0
--- /dev/null
+++ b/vendor/behat/mink-zombie-driver/tests/ZombieConfig.php
@@ -0,0 +1,60 @@
+<?php
+
+namespace Behat\Mink\Tests\Driver;
+
+use Behat\Mink\Driver\NodeJS\Server\ZombieServer;
+use Behat\Mink\Driver\ZombieDriver;
+
+class ZombieConfig extends AbstractConfig
+{
+    public static function getInstance()
+    {
+        return new self();
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function createDriver()
+    {
+        $server = new ZombieServer('127.0.0.1', 8124, 'node');
+
+        if (isset($_SERVER['NODE_MODULES_PATH'])) {
+            $server->setNodeModulesPath($_SERVER['NODE_MODULES_PATH']);
+        }
+
+        return new ZombieDriver($server);
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function skipMessage($testCase, $test)
+    {
+        if (
+            'Behat\Mink\Tests\Driver\Form\Html5Test' === $testCase
+            && in_array($test, array(
+                'testHtml5FormInputAttribute',
+                'testHtml5FormButtonAttribute',
+                'testHtml5FormOutside',
+                'testHtml5FormRadioAttribute',
+            ))
+        ) {
+            return 'Zombie.js doesn\'t HTML5 form attributes. See https://github.com/assaf/zombie/issues/635';
+        }
+
+        if (
+            'Behat\Mink\Tests\Driver\Js\JavascriptEvaluationTest' === $testCase
+            && 'testWait' === $test
+        ) {
+            return 'Zombie automatically waits for events to fire, so the wait test is irrelevant';
+        }
+
+        if ('Behat\Mink\Tests\Driver\Js\ChangeEventTest' === $testCase && 'testIssue178' === $test) {
+            return 'Zombie does not trigger the keyup event when writing a value in a text input to simulate keyboard';
+        }
+
+
+        return parent::skipMessage($testCase, $test);
+    }
+}
diff --git a/vendor/behat/mink/.gitignore b/vendor/behat/mink/.gitignore
new file mode 100644
index 00000000000..66de342a111
--- /dev/null
+++ b/vendor/behat/mink/.gitignore
@@ -0,0 +1,5 @@
+*.tgz
+*.phar
+phpunit.xml
+composer.lock
+vendor
diff --git a/vendor/behat/mink/.travis.yml b/vendor/behat/mink/.travis.yml
new file mode 100644
index 00000000000..74ea58cc9c1
--- /dev/null
+++ b/vendor/behat/mink/.travis.yml
@@ -0,0 +1,12 @@
+language: php
+
+php: [5.3, 5.4, 5.5, 5.6, hhvm]
+
+before_script:
+  - composer install --dev --prefer-source
+
+script: phpunit -v --coverage-clover=coverage.clover
+
+after_script:
+  - wget https://scrutinizer-ci.com/ocular.phar
+  - php ocular.phar code-coverage:upload --format=php-clover coverage.clover
diff --git a/vendor/behat/mink/CHANGES.md b/vendor/behat/mink/CHANGES.md
new file mode 100644
index 00000000000..3404cad5286
--- /dev/null
+++ b/vendor/behat/mink/CHANGES.md
@@ -0,0 +1,238 @@
+1.6.0 / 2014-09-26
+==================
+
+  * [BC break] Changed the named selector to prefer exact matches over partial matches
+  * [BC break] Changed `NodeElement::getValue` for checkboxes to return the value rather than the checked state (use `isChecked` for that)
+  * Fixed the XPath prefixing when searching inside an existing element
+  * Refactored the driver testsuite entirely and expand it to cover drivers entirely (covering many more cases for consistency)
+  * Changed `NodeElement::setValue` to support any fields rather than only input elements
+  * Removed the wrapping of any driver-level exception in a MinkException on invalid usage as it was making the code too complex
+  * Fixed the matching of the input type in the named selector to be case insensitive according to the HTML spec
+  * Introduced `Behat\Mink\Selector\Xpath\Escaper` to allow reusing the XPath escaping
+  * Deprecated `Element::getSession`. Code needing the session should get it from outside rather than the element
+  * Changed ElementNotFoundException to extend from ExpectationException
+  * Added `Element::getOuterHtml` to get the HTML code of the element including itself
+  * Fixed the name selectors to match on the `placeholder` only for textual inputs
+  * Enforced consistent behavior for drivers on 4xx and 5xx response to return the response rather than throwing an exception
+  * Added `Element::waitFor` to allow retrying some code until it succeeds or the timeout is reached
+  * Added `Element::isValid` to check whether an element still exists in the page
+  * Made `Session::executeScript` compatible across drivers by ensuring they all support the same syntaxes for the JS expression
+  * Made `Session::evaluateScript` compatible across drivers by ensuring they all support the same syntaxes for the JS expression
+  * Removed `hasClass` from `DocumentElement` (instead of triggering a fatal error)
+  * Added testing on HHVM to ensure consistency
+  * Fixed `NodeElement::getTagName` to ensure that the tag name is lowercase for all drivers
+  * Fixed `Element::hasAttribute` to ensure it supports attributes with an empty value
+  * Fixed the `field` selector to avoid matching inputs with the type `submit` or `reset`
+  * Changed the button XPath selection to accept `reset` buttons as well
+  * Changed `Session::wait` to return the condition value rather than nothing
+  * Added `Session::getWindowName` and `Session::getWindowNames` to get the name of the current and of all windows
+  * Added `Session::maximizeWindow` to maximize the window
+  * Added `NodeElement::isSelected` to check whether an `<option>` is selected
+  * Added `NodeElement::submitForm` to allow submitting a form without using a button
+  * Added assertions about the value of an attribute
+  * Added the anchor in the assertion on the URL in `WebAssert`
+
+1.5.0 / 2013-04-14
+==================
+
+  * Add `CoreDriver` to simplify future drivers improvements
+  * Add `Mink::isSessionStarted()` method
+  * Fix multibite string `preg_replace` bugs
+  * Fix handling of whitespaces in `WebAssert::pageText...()` methods
+
+1.4.3 / 2013-03-02
+==================
+
+  * Bump dependencies constraints
+
+1.4.2 / 2013-02-13
+==================
+
+  * Fix wrong test case to ensure that core drivers work as expected
+
+1.4.1 / 2013-02-10
+==================
+
+  * Update dependencies
+  * Add ElementException to element actions
+  * Rel attribute support for named selectors
+  * Add hasClass() helper to traversable elements
+  * Add getScreenshot() method to session
+  * Name attr support in named selector for button
+  * Fix for bunch of bugs
+
+1.4.0 / 2012-05-40
+==================
+
+  * New `Session::selectWindow()` and `Session::selectIFrame()` methods
+  * New built-in `WebAssert` class
+  * Fixed DocBlocks (autocompletion in any IDE now should just work)
+  * Moved Behat-related code into `Behat\MinkExtension`
+  * Removed PHPUnit test case class
+  * Updated composer dependencies to not require custom repository anymore
+  * All drivers moved into separate packages
+
+1.3.3 / 2012-03-23
+==================
+
+  * Prevent exceptions in `__toString()`
+  * Added couple of useful step definitions for Behat
+  * Fixed issues #168, #211, #212, #208
+  * Lot of small bug fixes and improvements
+  * Fixed dependencies and composer installation routine
+
+1.3.2 / 2011-12-21
+==================
+
+  * Fixed webdriver registration in MinkContext
+
+1.3.1 / 2011-12-21
+==================
+
+  * Fixed Composer package
+
+1.3.0 / 2011-12-21
+==================
+
+  * Brand new Selenium2Driver (webdriver session)
+  * Multiselect bugfixes
+  * ZombieDriver back in the business
+  * Composer now manages dependencies
+  * Some MinkContext steps got fixes
+  * Lots of bug fixes and cleanup
+
+1.2.0 / 2011-11-04
+==================
+
+  * Brand new SeleniumDriver (thanks @alexandresalome)
+  * Multiselect support (multiple options selection), including new Behat steps
+  * Ability to select option by it's text (in addition to value)
+  * ZombieDriver updates
+  * Use SuiteHooks to populate parameters (no need to call parent __construct anymore)
+  * Updated Goutte and all vendors
+  * Lot of bugfixes and new tests
+
+1.1.1 / 2011-08-12
+==================
+
+  * Fixed Zombie.js server termination on Linux
+  * Fixed base_url usage for external URLs
+
+1.1.0 / 2011-08-08
+==================
+
+  * Added Zombie.js driver (thanks @b00giZm)
+  * Added pt translation (thanks Daniel Gomes)
+  * Refactored MinkContext and MinkTestCase
+
+1.0.3 / 2011-08-02
+==================
+
+  * File uploads for empty fields fixed (GoutteDriver)
+  * Lazy sessions restart
+  * `show_tmp_dir` option in MinkContext
+  * Updated to stable Symfony2 components
+  * SahiClient connection limit bumped to 60 seconds
+  * Dutch language support
+
+1.0.2 / 2011-07-22
+==================
+
+  * ElementHtmlException fixed (thanks @Stof)
+
+1.0.1 / 2011-07-21
+==================
+
+  * Fixed buggy assertions in MinkContext
+
+1.0.0 / 2011-07-20
+==================
+
+  * Added missing tests for almost everything
+  * Hude speedup for SahiDriver
+  * Support for Behat 2.0 contexts
+  * Bundled PHPUnit TestCase
+  * Deep element traversing
+  * Correct behavior of getText() method
+  * New getHtml() method
+  * Basic HTTP auth support
+  * Soft and hard session resetting
+  * Cookies management
+  * Browser history interactions (reload(), back(), forward())
+  * Weaverryan'd exception messages
+  * Huge amount of bugfixes and small additions
+
+0.3.2 / 2011-06-20
+==================
+
+  * Fixed file uploads in Goutte driver
+  * Fixed setting of long texts into fields
+  * Added getPlainText() (returns text without tags and whitespaces) method to the element's API
+  * Start_url is now optional parameter
+  * Default session (if needed) name now need to be always specified by hands with setDefaultSessionName()
+  * default_driver => default_session
+  * Updated Symfony Components
+
+0.3.1 / 2011-05-17
+==================
+
+  * Small SahiClient update (it generates SID now if no provided)
+  * setActiveSessionName => setDefaultSessionName method rename
+
+0.3.0 / 2011-05-17
+==================
+
+  * Rewritten from scratch Mink drivers handler. Now it's sessions handler. And Mink now
+    sessions-centric tool. See examples in readme. Much cleaner API now.
+
+0.2.4 / 2011-05-12
+==================
+
+  * Fixed wrong url locator function
+  * Fixed wrong regex in `should see` step
+  * Fixed delimiters use in `should see` step
+  * Added url-match step for checking urls against regex
+
+0.2.3 / 2011-05-01
+==================
+
+  * Updated SahiClient with new version, which is faster and cleaner with it's exceptions
+
+0.2.2 / 2011-05-01
+==================
+
+  * Ability to use already started browser as SahiDriver aim
+  * Added japanese translation for bundled steps (thanks @hidenorigoto)
+  * 10 seconds limit for browser connection in SahiDriver
+
+0.2.1 / 2011-04-21
+==================
+
+  * Fixed some bundled step definitions
+
+0.2.0 / 2011-04-21
+==================
+
+  * Additional step definitions
+  * Support for extended drivers configuration through behat.yml environment parameters
+  * Lots of new named selectors
+  * Bug fixes
+  * Small improvements
+
+0.1.2 / 2011-04-08
+==================
+
+  * Fixed Sahi url escaping
+
+0.1.1 / 2011-04-06
+==================
+
+  * Fixed should/should_not steps
+  * Added spanish translation
+  * Fixed forms to use <base> element
+  * Fixed small UnsupportedByDriverException issue
+
+0.1.0 / 2011-04-04
+==================
+
+  * Initial release
diff --git a/vendor/behat/mink/CONTRIBUTING.md b/vendor/behat/mink/CONTRIBUTING.md
new file mode 100644
index 00000000000..5db4d856eb9
--- /dev/null
+++ b/vendor/behat/mink/CONTRIBUTING.md
@@ -0,0 +1,22 @@
+# Contributing
+Mink is an open source, community-driven project. If you'd like to contribute, feel free to do this, but remember to follow these few simple rules:
+
+## Submitting an issues
+- __Driver-related__ issues must be reported in the corresponding driver repository
+- A reproducible example is required for every bug report, otherwise it will most probably be __closed without warning__
+- If you are going to make a big, substantial change, let's discuss it first
+
+## Working with Pull Requests
+1. Create your feature addition or a bug fix branch based on `master` branch in your repository's fork.
+2. Make necessary changes, but __don't mix__ code reformatting with code changes on topic.
+3. Add tests for those changes (please look into `tests/` folder for some examples). This is important so we don't break it in a future version unintentionally.
+4. Commit your code, but do not mess with `CHANGES.md`.
+5. Squash your commits by topic to preserve a clean and readable log.
+6. Create Pull Request.
+
+# Running tests
+Make sure that you don't break anything with your changes by running:
+
+```bash
+$> phpunit
+```
diff --git a/vendor/behat/mink/LICENSE b/vendor/behat/mink/LICENSE
new file mode 100644
index 00000000000..14f15e8b483
--- /dev/null
+++ b/vendor/behat/mink/LICENSE
@@ -0,0 +1,22 @@
+Copyright (c) 2011-2013 Konstantin Kudryashov <ever.zet@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/behat/mink/README.md b/vendor/behat/mink/README.md
new file mode 100644
index 00000000000..d87cf3a06ac
--- /dev/null
+++ b/vendor/behat/mink/README.md
@@ -0,0 +1,72 @@
+Mink
+====
+[![Latest Stable Version](https://poser.pugx.org/behat/mink/v/stable.svg)](https://packagist.org/packages/behat/mink)
+[![Latest Unstable Version](https://poser.pugx.org/behat/mink/v/unstable.svg)](https://packagist.org/packages/behat/mink)
+[![Total Downloads](https://poser.pugx.org/behat/mink/downloads.svg)](https://packagist.org/packages/behat/mink)
+[![Scrutinizer Quality Score](https://scrutinizer-ci.com/g/Behat/Mink/badges/quality-score.png?s=d4faf469d6b399df121deed6070390800722ada0)](https://scrutinizer-ci.com/g/Behat/Mink/)
+[![Code Coverage](https://scrutinizer-ci.com/g/Behat/Mink/badges/coverage.png?s=88ab1cee4e131f4ef595f17ae4837001ef2aec3b)](https://scrutinizer-ci.com/g/Behat/Mink/)
+[![Build Status](https://travis-ci.org/Behat/Mink.svg?branch=master)](https://travis-ci.org/Behat/Mink)
+[![SensioLabsInsight](https://insight.sensiolabs.com/projects/5bb8fab0-978f-428a-ae23-44ee4e129fbc/mini.png)](https://insight.sensiolabs.com/projects/5bb8fab0-978f-428a-ae23-44ee4e129fbc)
+[![License](https://poser.pugx.org/behat/mink/license.svg)](https://packagist.org/packages/behat/mink)
+
+
+Useful Links
+------------
+
+- The main website with documentation is at [http://mink.behat.org](http://mink.behat.org)
+- Official Google Group is at [http://groups.google.com/group/behat](http://groups.google.com/group/behat)
+- IRC channel on [#freenode](http://freenode.net/) is `#behat`
+- [Note on Patches/Pull Requests](CONTRIBUTING.md)
+
+Usage Example
+-------------
+
+``` php
+<?php
+
+use Behat\Mink\Mink,
+    Behat\Mink\Session,
+    Behat\Mink\Driver\GoutteDriver,
+    Behat\Mink\Driver\Goutte\Client as GoutteClient;
+
+$startUrl = 'http://example.com';
+
+// init Mink and register sessions
+$mink = new Mink(array(
+    'goutte1' => new Session(new GoutteDriver(new GoutteClient())),
+    'goutte2' => new Session(new GoutteDriver(new GoutteClient())),
+    'custom'  => new Session(new MyCustomDriver($startUrl))
+));
+
+// set the default session name
+$mink->setDefaultSessionName('goutte2');
+
+// visit a page
+$mink->getSession()->visit($startUrl);
+
+// call to getSession() without argument will always return a default session if has one (goutte2 here)
+$mink->getSession()->getPage()->findLink('Downloads')->click();
+echo $mink->getSession()->getPage()->getContent();
+
+// call to getSession() with argument will return session by its name
+$mink->getSession('custom')->getPage()->findLink('Downloads')->click();
+echo $mink->getSession('custom')->getPage()->getContent();
+
+// this all is done to make possible mixing sessions
+$mink->getSession('goutte1')->getPage()->findLink('Chat')->click();
+$mink->getSession('goutte2')->getPage()->findLink('Chat')->click();
+```
+
+Install Dependencies
+--------------------
+
+``` bash
+$> curl -sS https://getcomposer.org/installer | php
+$> php composer.phar install
+```
+
+Contributors
+------------
+
+* Konstantin Kudryashov [everzet](http://github.com/everzet) [lead developer]
+* Other [awesome developers](https://github.com/Behat/Mink/graphs/contributors)
diff --git a/vendor/behat/mink/composer.json b/vendor/behat/mink/composer.json
new file mode 100644
index 00000000000..0aeee7bfbe6
--- /dev/null
+++ b/vendor/behat/mink/composer.json
@@ -0,0 +1,46 @@
+{
+    "name":         "behat/mink",
+    "description":  "Web acceptance testing framework for PHP 5.3",
+    "keywords":     ["web", "testing", "browser"],
+    "homepage":     "http://mink.behat.org/",
+    "type":         "library",
+    "license":      "MIT",
+
+    "authors": [
+        {
+            "name":      "Konstantin Kudryashov",
+            "email":     "ever.zet@gmail.com",
+            "homepage":  "http://everzet.com"
+        }
+    ],
+
+    "require": {
+        "php":                   ">=5.3.1",
+        "symfony/css-selector":  "~2.0"
+    },
+
+    "suggest": {
+        "behat/mink-browserkit-driver": "extremely fast headless driver for Symfony\\Kernel-based apps (Sf2, Silex)",
+        "behat/mink-goutte-driver":     "fast headless driver for any app without JS emulation",
+        "behat/mink-selenium2-driver":  "slow, but JS-enabled driver for any app (requires Selenium2)",
+        "behat/mink-zombie-driver":     "fast and JS-enabled headless driver for any app (requires node.js)"
+    },
+
+    "autoload": {
+        "psr-0": {
+            "Behat\\Mink": "src/"
+        }
+    },
+
+    "autoload-dev": {
+        "psr-4": {
+            "Behat\\Mink\\Tests\\": "tests"
+        }
+    },
+
+    "extra": {
+        "branch-alias": {
+            "dev-master": "1.6.x-dev"
+        }
+    }
+}
diff --git a/vendor/behat/mink/driver-testsuite/README.md b/vendor/behat/mink/driver-testsuite/README.md
new file mode 100644
index 00000000000..d21a7472a83
--- /dev/null
+++ b/vendor/behat/mink/driver-testsuite/README.md
@@ -0,0 +1,93 @@
+Mink Driver testsuite
+=====================
+
+This is the common testsuite for Mink drivers to ensure consistency among implementations.
+
+Usage
+-----
+
+The testsuite of a driver should be based as follow:
+
+```json
+{
+    "require": {
+        "behat/mink": "~1.6@dev"
+    },
+
+    "autoload-dev": {
+        "psr-4": {
+            "Acme\MyDriver\Tests\\": "tests"
+        }
+    }
+}
+```
+
+```xml
+<!-- phpunit.xml.dist -->
+<?xml version="1.0" encoding="UTF-8"?>
+
+<phpunit colors="true" bootstrap="vendor/behat/mink/driver-testsuite/bootstrap.php">
+    <php>
+        <var name="driver_config_factory" value="Acme\MyDriver\Tests\Config::getInstance" />
+
+        <server name="WEB_FIXTURES_HOST" value="http://test.mink.dev" />
+    </php>
+
+    <testsuites>
+        <testsuite name="Driver test suite">
+            <directory>./tests/</directory><!-- if needed to add more tests -->
+            <directory>vendor/behat/mink/driver-testsuite/tests</directory>
+        </testsuite>
+    </testsuites>
+
+    <filter>
+        <whitelist>
+            <directory>./src/Acme/MyDriver</directory>
+        </whitelist>
+    </filter>
+</phpunit>
+```
+
+Then create the driver config for the testsuite:
+
+```php
+// tests/Config.php
+
+namespace Acme\MyDriver\Tests;
+
+use Behat\Mink\Tests\Driver\AbstractConfig;
+
+class Config extends AbstractConfig
+{
+    /**
+     * Creates an instance of the config.
+     *
+     * This is the callable registered as a php variable in the phpunit.xml config file.
+     * It could be outside the class but this is convenient.
+     */
+    public static function getInstance()
+    {
+        return new self();
+    }
+
+    /**
+     * Creates driver instance.
+     *
+     * @return \Behat\Mink\Driver\DriverInterface
+     */
+    public function createDriver()
+    {
+        return new \Acme\MyDriver\MyDriver();
+    }
+}
+```
+
+Some other methods are available in the AbstractConfig which can be overwritten to adapt the testsuite to
+the needs of the driver (skipping some tests for instance).
+
+Adding Driver-specific Tests
+----------------------------
+
+When adding extra test cases specific to the driver, either use your own namespace or put them in the
+``Behat\Mink\Tests\Driver\Custom`` subnamespace to ensure that you will not create conflicts with test cases
+added in the driver testsuite in the future.
diff --git a/vendor/behat/mink/driver-testsuite/bootstrap.php b/vendor/behat/mink/driver-testsuite/bootstrap.php
new file mode 100644
index 00000000000..f69a45bd3fb
--- /dev/null
+++ b/vendor/behat/mink/driver-testsuite/bootstrap.php
@@ -0,0 +1,28 @@
+<?php
+
+$file = __DIR__.'/../../../autoload.php';
+
+if (!file_exists($file)) {
+    echo PHP_EOL.'The Mink driver testsuite expects Mink to be installed as a composer dependency of your project'.PHP_EOL;
+    exit(1);
+}
+
+/** @var \Composer\Autoload\ClassLoader $loader */
+$loader = require $file;
+
+$loader->addPsr4('Behat\Mink\Tests\Driver\\', __DIR__.'/tests');
+
+// Clean the global variables
+unset($file);
+unset($loader);
+
+// Check the definition of the driverLoaderFactory
+
+if (!isset($GLOBALS['driver_config_factory'])) {
+    echo PHP_EOL.'The "driver_config_factory" global variable must be set.'.PHP_EOL;
+    exit(1);
+}
+if (!is_callable($GLOBALS['driver_config_factory'])) {
+    echo PHP_EOL.'The "driver_config_factory" global variable must be a callable.'.PHP_EOL;
+    exit(1);
+}
diff --git a/vendor/behat/mink/driver-testsuite/tests/AbstractConfig.php b/vendor/behat/mink/driver-testsuite/tests/AbstractConfig.php
new file mode 100644
index 00000000000..5d02df2c11e
--- /dev/null
+++ b/vendor/behat/mink/driver-testsuite/tests/AbstractConfig.php
@@ -0,0 +1,83 @@
+<?php
+
+namespace Behat\Mink\Tests\Driver;
+
+use Behat\Mink\Driver\DriverInterface;
+
+abstract class AbstractConfig
+{
+    /**
+     * Creates driver instance.
+     *
+     * @return DriverInterface
+     */
+    abstract public function createDriver();
+
+    /**
+     * Map remote file path.
+     *
+     * @param string $file File path.
+     *
+     * @return string
+     */
+    public function mapRemoteFilePath($file)
+    {
+        if (!isset($_SERVER['TEST_MACHINE_BASE_PATH']) || !isset($_SERVER['DRIVER_MACHINE_BASE_PATH'])) {
+            return $file;
+        }
+
+        $pattern = '/^' . preg_quote($_SERVER['TEST_MACHINE_BASE_PATH'], '/') . '/';
+        $basePath = $_SERVER['DRIVER_MACHINE_BASE_PATH'];
+
+        return preg_replace($pattern, $basePath, $file, 1);
+    }
+
+    /**
+     * Gets the base url to the fixture folder
+     *
+     * @return string
+     */
+    public function getWebFixturesUrl()
+    {
+        return $_SERVER['WEB_FIXTURES_HOST'];
+    }
+
+    /**
+     * @param string $testCase The name of the TestCase class
+     * @param string $test     The name of the test method
+     *
+     * @return string|null A message explaining why the test should be skipped, or null to run the test.
+     */
+    public function skipMessage($testCase, $test)
+    {
+        if (!$this->supportsCss() && 0 === strpos($testCase, 'Behat\Mink\Tests\Driver\Css\\')) {
+            return 'This driver does not support CSS.';
+        }
+
+        if (!$this->supportsJs() && 0 === strpos($testCase, 'Behat\Mink\Tests\Driver\Js\\')) {
+            return 'This driver does not support JavaScript.';
+        }
+
+        return null;
+    }
+
+    /**
+     * Whether the JS tests should run or no.
+     *
+     * @return bool
+     */
+    protected function supportsJs()
+    {
+        return true;
+    }
+
+    /**
+     * Whether the CSS tests should run or no.
+     *
+     * @return bool
+     */
+    protected function supportsCss()
+    {
+        return false;
+    }
+}
diff --git a/vendor/behat/mink/driver-testsuite/tests/Basic/BasicAuthTest.php b/vendor/behat/mink/driver-testsuite/tests/Basic/BasicAuthTest.php
new file mode 100644
index 00000000000..40d932d0d73
--- /dev/null
+++ b/vendor/behat/mink/driver-testsuite/tests/Basic/BasicAuthTest.php
@@ -0,0 +1,64 @@
+<?php
+
+namespace Behat\Mink\Tests\Driver\Basic;
+
+use Behat\Mink\Tests\Driver\TestCase;
+
+class BasicAuthTest extends TestCase
+{
+    /**
+     * @dataProvider setBasicAuthDataProvider
+     */
+    public function testSetBasicAuth($user, $pass, $pageText)
+    {
+        $session = $this->getSession();
+
+        $session->setBasicAuth($user, $pass);
+
+        $session->visit($this->pathTo('/basic_auth.php'));
+
+        $this->assertContains($pageText, $session->getPage()->getContent());
+    }
+
+    public function setBasicAuthDataProvider()
+    {
+        return array(
+            array('mink-user', 'mink-password', 'is authenticated'),
+            array('', '', 'is not authenticated'),
+        );
+    }
+
+    public function testResetBasicAuth()
+    {
+        $session = $this->getSession();
+
+        $session->setBasicAuth('mink-user', 'mink-password');
+
+        $session->visit($this->pathTo('/basic_auth.php'));
+
+        $this->assertContains('is authenticated', $session->getPage()->getContent());
+
+        $session->setBasicAuth(false);
+
+        $session->visit($this->pathTo('/headers.php'));
+
+        $this->assertNotContains('PHP_AUTH_USER', $session->getPage()->getContent());
+    }
+
+    public function testResetWithBasicAuth()
+    {
+        $session = $this->getSession();
+
+        $session->setBasicAuth('mink-user', 'mink-password');
+
+        $session->visit($this->pathTo('/basic_auth.php'));
+
+        $this->assertContains('is authenticated', $session->getPage()->getContent());
+
+        $session->reset();
+
+        $session->visit($this->pathTo('/headers.php'));
+
+        $this->assertNotContains('PHP_AUTH_USER', $session->getPage()->getContent());
+    }
+}
diff --git a/vendor/behat/mink/driver-testsuite/tests/Basic/ContentTest.php b/vendor/behat/mink/driver-testsuite/tests/Basic/ContentTest.php
new file mode 100644
index 00000000000..e68e8d0ebb2
--- /dev/null
+++ b/vendor/behat/mink/driver-testsuite/tests/Basic/ContentTest.php
@@ -0,0 +1,74 @@
+<?php
+
+namespace Behat\Mink\Tests\Driver\Basic;
+
+use Behat\Mink\Tests\Driver\TestCase;
+
+class ContentTest extends TestCase
+{
+    public function testOuterHtml()
+    {
+        $this->getSession()->visit($this->pathTo('/index.html'));
+
+        $element = $this->getAssertSession()->elementExists('css', '.travers');
+
+        $this->assertEquals(
+            "<div class=\"travers\">\n            <div class=\"sub\">el1</div>\n".
+            "            <div class=\"sub\">el2</div>\n            <div class=\"sub\">\n".
+            "                <a href=\"some_url\">some <strong>deep</strong> url</a>\n".
+            "            </div>\n        </div>",
+            $element->getOuterHtml()
+        );
+    }
+
+    /**
+     * @dataProvider getAttributeDataProvider
+     */
+    public function testGetAttribute($attributeName, $attributeValue)
+    {
+        $this->getSession()->visit($this->pathTo('/index.html'));
+
+        $element = $this->getSession()->getPage()->findById('attr-elem[' . $attributeName . ']');
+
+        $this->assertNotNull($element);
+        $this->assertSame($attributeValue, $element->getAttribute($attributeName));
+    }
+
+    public function getAttributeDataProvider()
+    {
+        return array(
+            array('with-value', 'some-value'),
+            array('without-value', ''),
+            array('with-empty-value', ''),
+            array('with-missing', null),
+        );
+    }
+
+    public function testJson()
+    {
+        $this->getSession()->visit($this->pathTo('/json.php'));
+        $this->assertContains(
+            '{"key1":"val1","key2":234,"key3":[1,2,3]}',
+            $this->getSession()->getPage()->getContent()
+        );
+    }
+
+    public function testHtmlDecodingNotPerformed()
+    {
+        $session = $this->getSession();
+        $webAssert = $this->getAssertSession();
+        $session->visit($this->pathTo('/html_decoding.html'));
+        $page = $session->getPage();
+
+        $span = $webAssert->elementExists('css', 'span');
+        $input = $webAssert->elementExists('css', 'input');
+
+        $expectedHtml = '<span custom-attr="&amp;">some text</span>';
+        $this->assertContains($expectedHtml, $page->getHtml(), '.innerHTML is returned as-is');
+        $this->assertContains($expectedHtml, $page->getContent(), '.outerHTML is returned as-is');
+
+        $this->assertEquals('&', $span->getAttribute('custom-attr'), '.getAttribute value is decoded');
+        $this->assertEquals('&', $input->getAttribute('value'), '.getAttribute value is decoded');
+        $this->assertEquals('&', $input->getValue(), 'node value is decoded');
+    }
+}
diff --git a/vendor/behat/mink/driver-testsuite/tests/Basic/CookieTest.php b/vendor/behat/mink/driver-testsuite/tests/Basic/CookieTest.php
new file mode 100644
index 00000000000..355dd717af3
--- /dev/null
+++ b/vendor/behat/mink/driver-testsuite/tests/Basic/CookieTest.php
@@ -0,0 +1,167 @@
+<?php
+
+namespace Behat\Mink\Tests\Driver\Basic;
+
+use Behat\Mink\Tests\Driver\TestCase;
+
+class CookieTest extends TestCase
+{
+    /**
+     * test cookie decoding
+     * @group issue140
+     */
+    public function testIssue140()
+    {
+        $this->getSession()->visit($this->pathTo('/issue140.php'));
+
+        $this->getSession()->getPage()->fillField('cookie_value', 'some:value;');
+        $this->getSession()->getPage()->pressButton('Set cookie');
+
+        $this->getSession()->visit($this->pathTo('/issue140.php?show_value'));
+        $this->assertEquals('some:value;', $this->getSession()->getCookie('tc'));
+        $this->assertEquals('some:value;', $this->getSession()->getPage()->getText());
+    }
+
+    public function testCookie()
+    {
+        $this->getSession()->visit($this->pathTo('/cookie_page2.php'));
+        $this->assertContains('Previous cookie: NO', $this->getSession()->getPage()->getText());
+        $this->assertNull($this->getSession()->getCookie('srvr_cookie'));
+
+        $this->getSession()->setCookie('srvr_cookie', 'client cookie set');
+        $this->getSession()->reload();
+        $this->assertContains('Previous cookie: client cookie set', $this->getSession()->getPage()->getText());
+        $this->assertEquals('client cookie set', $this->getSession()->getCookie('srvr_cookie'));
+
+        $this->getSession()->setCookie('srvr_cookie', null);
+        $this->getSession()->reload();
+        $this->assertContains('Previous cookie: NO', $this->getSession()->getPage()->getText());
+
+        $this->getSession()->visit($this->pathTo('/cookie_page1.php'));
+        $this->getSession()->visit($this->pathTo('/cookie_page2.php'));
+
+        $this->assertContains('Previous cookie: srv_var_is_set', $this->getSession()->getPage()->getText());
+        $this->getSession()->setCookie('srvr_cookie', null);
+        $this->getSession()->reload();
+        $this->assertContains('Previous cookie: NO', $this->getSession()->getPage()->getText());
+    }
+
+    /**
+     * @dataProvider cookieWithPathsDataProvider
+     */
+    public function testCookieWithPaths($cookieRemovalMode)
+    {
+        // start clean
+        $session = $this->getSession();
+        $session->visit($this->pathTo('/sub-folder/cookie_page2.php'));
+        $this->assertContains('Previous cookie: NO', $session->getPage()->getText());
+
+        // cookie from root path is accessible in sub-folder
+        $session->visit($this->pathTo('/cookie_page1.php'));
+        $session->visit($this->pathTo('/sub-folder/cookie_page2.php'));
+        $this->assertContains('Previous cookie: srv_var_is_set', $session->getPage()->getText());
+
+        // cookie from sub-folder overrides cookie from root path
+        $session->visit($this->pathTo('/sub-folder/cookie_page1.php'));
+        $session->visit($this->pathTo('/sub-folder/cookie_page2.php'));
+        $this->assertContains('Previous cookie: srv_var_is_set_sub_folder', $session->getPage()->getText());
+
+        if ($cookieRemovalMode == 'session_reset') {
+            $session->reset();
+        } elseif ($cookieRemovalMode == 'cookie_delete') {
+            $session->setCookie('srvr_cookie', null);
+        }
+
+        // cookie is removed from all paths
+        $session->visit($this->pathTo('/sub-folder/cookie_page2.php'));
+        $this->assertContains('Previous cookie: NO', $session->getPage()->getText());
+    }
+
+    public function cookieWithPathsDataProvider()
+    {
+        return array(
+            array('session_reset'),
+            array('cookie_delete'),
+        );
+    }
+
+    public function testReset()
+    {
+        $this->getSession()->visit($this->pathTo('/cookie_page1.php'));
+        $this->getSession()->visit($this->pathTo('/cookie_page2.php'));
+        $this->assertContains('Previous cookie: srv_var_is_set', $this->getSession()->getPage()->getText());
+
+        $this->getSession()->reset();
+        $this->getSession()->visit($this->pathTo('/cookie_page2.php'));
+
+        $this->assertContains('Previous cookie: NO', $this->getSession()->getPage()->getText());
+
+        $this->getSession()->setCookie('srvr_cookie', 'test_cookie');
+        $this->getSession()->visit($this->pathTo('/cookie_page2.php'));
+        $this->assertContains('Previous cookie: test_cookie', $this->getSession()->getPage()->getText());
+        $this->getSession()->reset();
+        $this->getSession()->visit($this->pathTo('/cookie_page2.php'));
+        $this->assertContains('Previous cookie: NO', $this->getSession()->getPage()->getText());
+
+        $this->getSession()->setCookie('client_cookie1', 'some_val');
+        $this->getSession()->setCookie('client_cookie2', 123);
+        $this->getSession()->visit($this->pathTo('/session_test.php'));
+        $this->getSession()->visit($this->pathTo('/cookie_page1.php'));
+
+        $this->getSession()->visit($this->pathTo('/print_cookies.php'));
+        $this->assertContains(
+            "'client_cookie1' = 'some_val'",
+            $this->getSession()->getPage()->getText()
+        );
+        $this->assertContains(
+            "'client_cookie2' = '123'",
+            $this->getSession()->getPage()->getText()
+        );
+        $this->assertContains(
+            "_SESS' = ",
+            $this->getSession()->getPage()->getText()
+        );
+        $this->assertContains(
+            " 'srvr_cookie' = 'srv_var_is_set'",
+            $this->getSession()->getPage()->getText()
+        );
+
+        $this->getSession()->reset();
+        $this->getSession()->visit($this->pathTo('/print_cookies.php'));
+        $this->assertContains('array ( )', $this->getSession()->getPage()->getText());
+    }
+
+    public function testHttpOnlyCookieIsDeleted()
+    {
+        $this->getSession()->restart();
+        $this->getSession()->visit($this->pathTo('/cookie_page3.php'));
+        $this->assertEquals('Has Cookie: false', $this->findById('cookie-status')->getText());
+
+        $this->getSession()->reload();
+        $this->assertEquals('Has Cookie: true', $this->findById('cookie-status')->getText());
+
+        $this->getSession()->restart();
+        $this->getSession()->visit($this->pathTo('/cookie_page3.php'));
+        $this->assertEquals('Has Cookie: false', $this->findById('cookie-status')->getText());
+    }
+
+    public function testSessionPersistsBetweenRequests()
+    {
+        $this->getSession()->visit($this->pathTo('/session_test.php'));
+        $webAssert = $this->getAssertSession();
+        $node = $webAssert->elementExists('css', '#session-id');
+        $sessionId = $node->getText();
+
+        $this->getSession()->visit($this->pathTo('/session_test.php'));
+        $node = $webAssert->elementExists('css', '#session-id');
+        $this->assertEquals($sessionId, $node->getText());
+
+        $this->getSession()->visit($this->pathTo('/session_test.php?login'));
+        $node = $webAssert->elementExists('css', '#session-id');
+        $this->assertNotEquals($sessionId, $newSessionId = $node->getText());
+
+        $this->getSession()->visit($this->pathTo('/session_test.php'));
+        $node = $webAssert->elementExists('css', '#session-id');
+        $this->assertEquals($newSessionId, $node->getText());
+    }
+}
diff --git a/vendor/behat/mink/driver-testsuite/tests/Basic/ErrorHandlingTest.php b/vendor/behat/mink/driver-testsuite/tests/Basic/ErrorHandlingTest.php
new file mode 100644
index 00000000000..440585ac12d
--- /dev/null
+++ b/vendor/behat/mink/driver-testsuite/tests/Basic/ErrorHandlingTest.php
@@ -0,0 +1,262 @@
+<?php
+
+namespace Behat\Mink\Tests\Driver\Basic;
+
+use Behat\Mink\Tests\Driver\TestCase;
+
+class ErrorHandlingTest extends TestCase
+{
+    const NOT_FOUND_XPATH = '//html/./invalid';
+
+    const NOT_FOUND_EXCEPTION = 'Exception';
+
+    const INVALID_EXCEPTION = 'Exception';
+
+    public function testVisitErrorPage()
+    {
+        $this->getSession()->visit($this->pathTo('/500.php'));
+
+        $this->assertContains(
+            'Sorry, a server error happened',
+            $this->getSession()->getPage()->getContent(),
+            'Drivers allow loading pages with a 500 status code'
+        );
+    }
+
+    public function testCheckInvalidElement()
+    {
+        $this->getSession()->visit($this->pathTo('/index.html'));
+        $element = $this->findById('user-name');
+
+        $this->setExpectedException(self::INVALID_EXCEPTION);
+        $this->getSession()->getDriver()->check($element->getXpath());
+    }
+
+    public function testCheckNotFoundElement()
+    {
+        $this->getSession()->visit($this->pathTo('/index.html'));
+
+        $this->setExpectedException(self::NOT_FOUND_EXCEPTION);
+        $this->getSession()->getDriver()->check(self::NOT_FOUND_XPATH);
+    }
+
+    public function testUncheckInvalidElement()
+    {
+        $this->getSession()->visit($this->pathTo('/index.html'));
+        $element = $this->findById('user-name');
+
+        $this->setExpectedException(self::INVALID_EXCEPTION);
+        $this->getSession()->getDriver()->uncheck($element->getXpath());
+    }
+
+    public function testUncheckNotFoundElement()
+    {
+        $this->getSession()->visit($this->pathTo('/index.html'));
+
+        $this->setExpectedException(self::NOT_FOUND_EXCEPTION);
+        $this->getSession()->getDriver()->uncheck(self::NOT_FOUND_XPATH);
+    }
+
+    public function testSelectOptionInvalidElement()
+    {
+        $this->getSession()->visit($this->pathTo('/index.html'));
+        $element = $this->findById('user-name');
+
+        $this->setExpectedException(self::INVALID_EXCEPTION);
+        $this->getSession()->getDriver()->selectOption($element->getXpath(), 'test');
+    }
+
+    public function testSelectOptionNotFoundElement()
+    {
+        $this->getSession()->visit($this->pathTo('/index.html'));
+
+        $this->setExpectedException(self::NOT_FOUND_EXCEPTION);
+        $this->getSession()->getDriver()->selectOption(self::NOT_FOUND_XPATH, 'test');
+    }
+
+    public function testAttachFileInvalidElement()
+    {
+        $this->getSession()->visit($this->pathTo('/index.html'));
+        $element = $this->findById('user-name');
+
+        $this->setExpectedException(self::INVALID_EXCEPTION);
+        $this->getSession()->getDriver()->attachFile($element->getXpath(), __FILE__);
+    }
+
+    public function testAttachFileNotFoundElement()
+    {
+        $this->getSession()->visit($this->pathTo('/index.html'));
+
+        $this->setExpectedException(self::NOT_FOUND_EXCEPTION);
+        $this->getSession()->getDriver()->attachFile(self::NOT_FOUND_XPATH, __FILE__);
+    }
+
+    public function testSubmitFormInvalidElement()
+    {
+        $this->getSession()->visit($this->pathTo('/index.html'));
+        $element = $this->findById('core');
+
+        $this->setExpectedException(self::INVALID_EXCEPTION);
+        $this->getSession()->getDriver()->submitForm($element->getXpath());
+    }
+
+    public function testSubmitFormNotFoundElement()
+    {
+        $this->getSession()->visit($this->pathTo('/index.html'));
+
+        $this->setExpectedException(self::NOT_FOUND_EXCEPTION);
+        $this->getSession()->getDriver()->submitForm(self::NOT_FOUND_XPATH);
+    }
+
+    public function testGetTagNameNotFoundElement()
+    {
+        $this->getSession()->visit($this->pathTo('/index.html'));
+
+        $this->setExpectedException(self::NOT_FOUND_EXCEPTION);
+        $this->getSession()->getDriver()->getTagName(self::NOT_FOUND_XPATH);
+    }
+
+    public function testGetTextNotFoundElement()
+    {
+        $this->getSession()->visit($this->pathTo('/index.html'));
+
+        $this->setExpectedException(self::NOT_FOUND_EXCEPTION);
+        $this->getSession()->getDriver()->getText(self::NOT_FOUND_XPATH);
+    }
+
+    public function testGetHtmlNotFoundElement()
+    {
+        $this->getSession()->visit($this->pathTo('/index.html'));
+
+        $this->setExpectedException(self::NOT_FOUND_EXCEPTION);
+        $this->getSession()->getDriver()->getHtml(self::NOT_FOUND_XPATH);
+    }
+
+    public function testGetOuterHtmlNotFoundElement()
+    {
+        $this->getSession()->visit($this->pathTo('/index.html'));
+
+        $this->setExpectedException(self::NOT_FOUND_EXCEPTION);
+        $this->getSession()->getDriver()->getOuterHtml(self::NOT_FOUND_XPATH);
+    }
+
+    public function testGetValueNotFoundElement()
+    {
+        $this->getSession()->visit($this->pathTo('/index.html'));
+
+        $this->setExpectedException(self::NOT_FOUND_EXCEPTION);
+        $this->getSession()->getDriver()->getValue(self::NOT_FOUND_XPATH);
+    }
+
+    public function testSetValueNotFoundElement()
+    {
+        $this->getSession()->visit($this->pathTo('/index.html'));
+
+        $this->setExpectedException(self::NOT_FOUND_EXCEPTION);
+        $this->getSession()->getDriver()->setValue(self::NOT_FOUND_XPATH, 'test');
+    }
+
+    public function testIsSelectedNotFoundElement()
+    {
+        $this->getSession()->visit($this->pathTo('/index.html'));
+
+        $this->setExpectedException(self::NOT_FOUND_EXCEPTION);
+        $this->getSession()->getDriver()->isSelected(self::NOT_FOUND_XPATH);
+    }
+
+    public function testIsCheckedNotFoundElement()
+    {
+        $this->getSession()->visit($this->pathTo('/index.html'));
+
+        $this->setExpectedException(self::NOT_FOUND_EXCEPTION);
+        $this->getSession()->getDriver()->isChecked(self::NOT_FOUND_XPATH);
+    }
+
+    public function testIsVisibleNotFoundElement()
+    {
+        $this->getSession()->visit($this->pathTo('/index.html'));
+
+        $this->setExpectedException(self::NOT_FOUND_EXCEPTION);
+        $this->getSession()->getDriver()->isVisible(self::NOT_FOUND_XPATH);
+    }
+
+    public function testClickNotFoundElement()
+    {
+        $this->getSession()->visit($this->pathTo('/index.html'));
+
+        $this->setExpectedException(self::NOT_FOUND_EXCEPTION);
+        $this->getSession()->getDriver()->click(self::NOT_FOUND_XPATH);
+    }
+
+    public function testDoubleClickNotFoundElement()
+    {
+        $this->getSession()->visit($this->pathTo('/index.html'));
+
+        $this->setExpectedException(self::NOT_FOUND_EXCEPTION);
+        $this->getSession()->getDriver()->doubleClick(self::NOT_FOUND_XPATH);
+    }
+
+    public function testRightClickNotFoundElement()
+    {
+        $this->getSession()->visit($this->pathTo('/index.html'));
+
+        $this->setExpectedException(self::NOT_FOUND_EXCEPTION);
+        $this->getSession()->getDriver()->rightClick(self::NOT_FOUND_XPATH);
+    }
+
+    public function testGetAttributeNotFoundElement()
+    {
+        $this->getSession()->visit($this->pathTo('/index.html'));
+
+        $this->setExpectedException(self::NOT_FOUND_EXCEPTION);
+        $this->getSession()->getDriver()->getAttribute(self::NOT_FOUND_XPATH, 'id');
+    }
+
+    public function testMouseOverNotFoundElement()
+    {
+        $this->getSession()->visit($this->pathTo('/index.html'));
+
+        $this->setExpectedException(self::NOT_FOUND_EXCEPTION);
+        $this->getSession()->getDriver()->mouseOver(self::NOT_FOUND_XPATH);
+    }
+
+    public function testFocusNotFoundElement()
+    {
+        $this->getSession()->visit($this->pathTo('/index.html'));
+
+        $this->setExpectedException(self::NOT_FOUND_EXCEPTION);
+        $this->getSession()->getDriver()->focus(self::NOT_FOUND_XPATH);
+    }
+
+    public function testBlurNotFoundElement()
+    {
+        $this->getSession()->visit($this->pathTo('/index.html'));
+
+        $this->setExpectedException(self::NOT_FOUND_EXCEPTION);
+        $this->getSession()->getDriver()->blur(self::NOT_FOUND_XPATH);
+    }
+
+    public function testKeyPressNotFoundElement()
+    {
+        $this->getSession()->visit($this->pathTo('/index.html'));
+
+        $this->setExpectedException(self::NOT_FOUND_EXCEPTION);
+        $this->getSession()->getDriver()->keyPress(self::NOT_FOUND_XPATH, 'a');
+    }
+
+    public function testKeyDownNotFoundElement()
+    {
+        $this->getSession()->visit($this->pathTo('/index.html'));
+
+        $this->setExpectedException(self::NOT_FOUND_EXCEPTION);
+        $this->getSession()->getDriver()->keyDown(self::NOT_FOUND_XPATH, 'a');
+    }
+
+    public function testKeyUpNotFoundElement()
+    {
+        $this->getSession()->visit($this->pathTo('/index.html'));
+
+        $this->setExpectedException(self::NOT_FOUND_EXCEPTION);
+        $this->getSession()->getDriver()->keyUp(self::NOT_FOUND_XPATH, 'a');
+    }
+}
diff --git a/vendor/behat/mink/driver-testsuite/tests/Basic/HeaderTest.php b/vendor/behat/mink/driver-testsuite/tests/Basic/HeaderTest.php
new file mode 100644
index 00000000000..0288ff14ac0
--- /dev/null
+++ b/vendor/behat/mink/driver-testsuite/tests/Basic/HeaderTest.php
@@ -0,0 +1,77 @@
+<?php
+
+namespace Behat\Mink\Tests\Driver\Basic;
+
+use Behat\Mink\Tests\Driver\TestCase;
+
+class HeaderTest extends TestCase
+{
+    /**
+     * test referrer
+     * @group issue130
+     */
+    public function testIssue130()
+    {
+        $this->getSession()->visit($this->pathTo('/issue130.php?p=1'));
+        $page = $this->getSession()->getPage();
+
+        $page->clickLink('Go to 2');
+        $this->assertEquals($this->pathTo('/issue130.php?p=1'), $page->getText());
+    }
+
+    public function testHeaders()
+    {
+        $this->getSession()->setRequestHeader('Accept-Language', 'fr');
+        $this->getSession()->visit($this->pathTo('/headers.php'));
+
+        $this->assertContains('[HTTP_ACCEPT_LANGUAGE] => fr', $this->getSession()->getPage()->getContent());
+    }
+
+    public function testSetUserAgent()
+    {
+        $session = $this->getSession();
+
+        $session->setRequestHeader('user-agent', 'foo bar');
+        $session->visit($this->pathTo('/headers.php'));
+        $this->assertContains('[HTTP_USER_AGENT] => foo bar', $session->getPage()->getContent());
+    }
+
+    public function testResetHeaders()
+    {
+        $session = $this->getSession();
+
+        $session->setRequestHeader('X-Mink-Test', 'test');
+        $session->visit($this->pathTo('/headers.php'));
+
+        $this->assertContains(
+            '[HTTP_X_MINK_TEST] => test',
+            $session->getPage()->getContent(),
+            'The custom header should be sent',
+            true
+        );
+
+        $session->reset();
+        $session->visit($this->pathTo('/headers.php'));
+
+        $this->assertNotContains(
+            '[HTTP_X_MINK_TEST] => test',
+            $session->getPage()->getContent(),
+            'The custom header should not be sent after resetting',
+            true
+        );
+    }
+
+    public function testResponseHeaders()
+    {
+        $this->getSession()->visit($this->pathTo('/response_headers.php'));
+
+        $headers = $this->getSession()->getResponseHeaders();
+
+        $lowercasedHeaders = array();
+        foreach ($headers as $name => $value) {
+            $lowercasedHeaders[str_replace('_', '-', strtolower($name))] = $value;
+        }
+
+        $this->assertArrayHasKey('x-mink-test', $lowercasedHeaders);
+    }
+}
diff --git a/vendor/behat/mink/driver-testsuite/tests/Basic/IFrameTest.php b/vendor/behat/mink/driver-testsuite/tests/Basic/IFrameTest.php
new file mode 100644
index 00000000000..0ed0f9ef5f2
--- /dev/null
+++ b/vendor/behat/mink/driver-testsuite/tests/Basic/IFrameTest.php
@@ -0,0 +1,27 @@
+<?php
+
+namespace Behat\Mink\Tests\Driver\Basic;
+
+use Behat\Mink\Tests\Driver\TestCase;
+
+class IFrameTest extends TestCase
+{
+    public function testIFrame()
+    {
+        $this->getSession()->visit($this->pathTo('/iframe.html'));
+        $webAssert = $this->getAssertSession();
+
+        $el = $webAssert->elementExists('css', '#text');
+        $this->assertSame('Main window div text', $el->getText());
+
+        $this->getSession()->switchToIFrame('subframe');
+
+        $el = $webAssert->elementExists('css', '#text');
+        $this->assertSame('iFrame div text', $el->getText());
+
+        $this->getSession()->switchToIFrame();
+
+        $el = $webAssert->elementExists('css', '#text');
+        $this->assertSame('Main window div text', $el->getText());
+    }
+}
diff --git a/vendor/behat/mink/driver-testsuite/tests/Basic/NavigationTest.php b/vendor/behat/mink/driver-testsuite/tests/Basic/NavigationTest.php
new file mode 100644
index 00000000000..8ecb1395a4b
--- /dev/null
+++ b/vendor/behat/mink/driver-testsuite/tests/Basic/NavigationTest.php
@@ -0,0 +1,69 @@
+<?php
+
+namespace Behat\Mink\Tests\Driver\Basic;
+
+use Behat\Mink\Tests\Driver\TestCase;
+
+class NavigationTest extends TestCase
+{
+    public function testRedirect()
+    {
+        $this->getSession()->visit($this->pathTo('/redirector.php'));
+        $this->assertEquals($this->pathTo('/redirect_destination.html'), $this->getSession()->getCurrentUrl());
+    }
+
+    public function testPageControlls()
+    {
+        $this->getSession()->visit($this->pathTo('/randomizer.php'));
+        $number1 = $this->getSession()->getPage()->find('css', '#number')->getText();
+
+        $this->getSession()->reload();
+        $number2 = $this->getSession()->getPage()->find('css', '#number')->getText();
+
+        $this->assertNotEquals($number1, $number2);
+
+        $this->getSession()->visit($this->pathTo('/links.html'));
+        $this->getSession()->getPage()->clickLink('Random number page');
+
+        $this->assertEquals($this->pathTo('/randomizer.php'), $this->getSession()->getCurrentUrl());
+
+        $this->getSession()->back();
+        $this->assertEquals($this->pathTo('/links.html'), $this->getSession()->getCurrentUrl());
+
+        $this->getSession()->forward();
+        $this->assertEquals($this->pathTo('/randomizer.php'), $this->getSession()->getCurrentUrl());
+    }
+
+    public function testLinks()
+    {
+        $this->getSession()->visit($this->pathTo('/links.html'));
+        $page = $this->getSession()->getPage();
+        $link = $page->findLink('Redirect me to');
+
+        $this->assertNotNull($link);
+        $this->assertRegExp('/redirector\.php$/', $link->getAttribute('href'));
+        $link->click();
+
+        $this->assertEquals($this->pathTo('/redirect_destination.html'), $this->getSession()->getCurrentUrl());
+
+        $this->getSession()->visit($this->pathTo('/links.html'));
+        $page = $this->getSession()->getPage();
+        $link = $page->findLink('basic form image');
+
+        $this->assertNotNull($link);
+        $this->assertRegExp('/basic_form\.html$/', $link->getAttribute('href'));
+        $link->click();
+
+        $this->assertEquals($this->pathTo('/basic_form.html'), $this->getSession()->getCurrentUrl());
+
+        $this->getSession()->visit($this->pathTo('/links.html'));
+        $page = $this->getSession()->getPage();
+        $link = $page->findLink("Link with a ");
+
+        $this->assertNotNull($link);
+        $this->assertRegExp('/links\.html\?quoted$/', $link->getAttribute('href'));
+        $link->click();
+
+        $this->assertEquals($this->pathTo('/links.html?quoted'), $this->getSession()->getCurrentUrl());
+    }
+}
diff --git a/vendor/behat/mink/driver-testsuite/tests/Basic/ScreenshotTest.php b/vendor/behat/mink/driver-testsuite/tests/Basic/ScreenshotTest.php
new file mode 100644
index 00000000000..329f2d3e1f5
--- /dev/null
+++ b/vendor/behat/mink/driver-testsuite/tests/Basic/ScreenshotTest.php
@@ -0,0 +1,30 @@
+<?php
+
+namespace Behat\Mink\Tests\Driver\Basic;
+
+use Behat\Mink\Tests\Driver\TestCase;
+
+class ScreenshotTest extends TestCase
+{
+    public function testScreenshot()
+    {
+        if (!extension_loaded('gd')) {
+            $this->markTestSkipped('Testing screenshots requires the GD extension');
+        }
+
+        $this->getSession()->visit($this->pathTo('/index.html'));
+
+        $screenShot = $this->getSession()->getScreenshot();
+
+        $this->assertInternalType('string', $screenShot);
+        $this->assertFalse(base64_decode($screenShot, true), 'The returned screenshot should not be base64-encoded');
+
+        $img = imagecreatefromstring($screenShot);
+
+        if (false === $img) {
+            $this->fail('The screenshot should be a valid image');
+        }
+
+        imagedestroy($img);
+    }
+}
diff --git a/vendor/behat/mink/driver-testsuite/tests/Basic/StatusCodeTest.php b/vendor/behat/mink/driver-testsuite/tests/Basic/StatusCodeTest.php
new file mode 100644
index 00000000000..34ca7f0f163
--- /dev/null
+++ b/vendor/behat/mink/driver-testsuite/tests/Basic/StatusCodeTest.php
@@ -0,0 +1,22 @@
+<?php
+
+namespace Behat\Mink\Tests\Driver\Basic;
+
+use Behat\Mink\Tests\Driver\TestCase;
+
+class StatusCodeTest extends TestCase
+{
+    public function testStatuses()
+    {
+        $this->getSession()->visit($this->pathTo('/index.html'));
+
+        $this->assertEquals(200, $this->getSession()->getStatusCode());
+        $this->assertEquals($this->pathTo('/index.html'), $this->getSession()->getCurrentUrl());
+
+        $this->getSession()->visit($this->pathTo('/404.php'));
+
+        $this->assertEquals($this->pathTo('/404.php'), $this->getSession()->getCurrentUrl());
+        $this->assertEquals(404, $this->getSession()->getStatusCode());
+        $this->assertEquals('Sorry, page not found', $this->getSession()->getPage()->getContent());
+    }
+}
diff --git a/vendor/behat/mink/driver-testsuite/tests/Basic/TraversingTest.php b/vendor/behat/mink/driver-testsuite/tests/Basic/TraversingTest.php
new file mode 100644
index 00000000000..b31f7fc954b
--- /dev/null
+++ b/vendor/behat/mink/driver-testsuite/tests/Basic/TraversingTest.php
@@ -0,0 +1,129 @@
+<?php
+
+namespace Behat\Mink\Tests\Driver\Basic;
+
+use Behat\Mink\Tests\Driver\TestCase;
+
+class TraversingTest extends TestCase
+{
+    /**
+     * find by label
+     * @group issue211
+     */
+    public function testIssue211()
+    {
+        $this->getSession()->visit($this->pathTo('/issue211.html'));
+        $field = $this->getSession()->getPage()->findField('Téléphone');
+
+        $this->assertNotNull($field);
+    }
+
+    public function testElementsTraversing()
+    {
+        $this->getSession()->visit($this->pathTo('/index.html'));
+
+        $page = $this->getSession()->getPage();
+
+        $this->assertNotNull($page->find('css', 'h1'));
+        $this->assertEquals('Extremely useless page', $page->find('css', 'h1')->getText());
+        $this->assertEquals('h1', $page->find('css', 'h1')->getTagName());
+
+        $this->assertNotNull($page->find('xpath', '//div/strong[3]'));
+        $this->assertEquals('pariatur', $page->find('xpath', '//div/strong[3]')->getText());
+        $this->assertEquals('super-duper', $page->find('xpath', '//div/strong[3]')->getAttribute('class'));
+        $this->assertTrue($page->find('xpath', '//div/strong[3]')->hasAttribute('class'));
+
+        $this->assertNotNull($page->find('xpath', '//div/strong[2]'));
+        $this->assertEquals('veniam', $page->find('xpath', '//div/strong[2]')->getText());
+        $this->assertEquals('strong', $page->find('xpath', '//div/strong[2]')->getTagName());
+        $this->assertNull($page->find('xpath', '//div/strong[2]')->getAttribute('class'));
+        $this->assertFalse($page->find('xpath', '//div/strong[2]')->hasAttribute('class'));
+
+        $strongs = $page->findAll('css', 'div#core > strong');
+        $this->assertCount(3, $strongs);
+        $this->assertEquals('Lorem', $strongs[0]->getText());
+        $this->assertEquals('pariatur', $strongs[2]->getText());
+
+        $element = $page->find('css', '#some-element');
+
+        $this->assertEquals('some very interesting text', $element->getText());
+        $this->assertEquals(
+            "\n            some <div>very\n            </div>\n".
+            "<em>interesting</em>      text\n        ",
+            $element->getHtml()
+        );
+
+        $this->assertTrue($element->hasAttribute('data-href'));
+        $this->assertFalse($element->hasAttribute('data-url'));
+        $this->assertEquals('http://mink.behat.org', $element->getAttribute('data-href'));
+        $this->assertNull($element->getAttribute('data-url'));
+        $this->assertEquals('div', $element->getTagName());
+    }
+
+    public function testVeryDeepElementsTraversing()
+    {
+        $this->getSession()->visit($this->pathTo('/index.html'));
+
+        $page = $this->getSession()->getPage();
+
+        $footer = $page->find('css', 'footer');
+        $this->assertNotNull($footer);
+
+        $searchForm = $footer->find('css', 'form#search-form');
+        $this->assertNotNull($searchForm);
+        $this->assertEquals('search-form', $searchForm->getAttribute('id'));
+
+        $searchInput = $searchForm->findField('Search site...');
+        $this->assertNotNull($searchInput);
+        $this->assertEquals('text', $searchInput->getAttribute('type'));
+
+        $searchInput = $searchForm->findField('Search site...');
+        $this->assertNotNull($searchInput);
+        $this->assertEquals('text', $searchInput->getAttribute('type'));
+
+        $profileForm = $footer->find('css', '#profile');
+        $this->assertNotNull($profileForm);
+
+        $profileFormDiv = $profileForm->find('css', 'div');
+        $this->assertNotNull($profileFormDiv);
+
+        $profileFormDivLabel = $profileFormDiv->find('css', 'label');
+        $this->assertNotNull($profileFormDivLabel);
+
+        $profileFormDivParent = $profileFormDivLabel->getParent();
+        $this->assertNotNull($profileFormDivParent);
+
+        $profileFormDivParent = $profileFormDivLabel->getParent();
+        $this->assertEquals('something', $profileFormDivParent->getAttribute('data-custom'));
+
+        $profileFormInput = $profileFormDivLabel->findField('user-name');
+        $this->assertNotNull($profileFormInput);
+        $this->assertEquals('username', $profileFormInput->getAttribute('name'));
+    }
+
+    public function testDeepTraversing()
+    {
+        $this->getSession()->visit($this->pathTo('/index.html'));
+
+        $traversDiv = $this->getSession()->getPage()->findAll('css', 'div.travers');
+
+        $this->assertCount(1, $traversDiv);
+        $traversDiv = $traversDiv[0];
+
+        $subDivs = $traversDiv->findAll('css', 'div.sub');
+        $this->assertCount(3, $subDivs);
+
+        $this->assertTrue($subDivs[2]->hasLink('some deep url'));
+        $this->assertFalse($subDivs[2]->hasLink('come deep url'));
+        $subUrl = $subDivs[2]->findLink('some deep url');
+        $this->assertNotNull($subUrl);
+
+        $this->assertRegExp('/some_url$/', $subUrl->getAttribute('href'));
+        $this->assertEquals('some deep url', $subUrl->getText());
+        $this->assertEquals('some <strong>deep</strong> url', $subUrl->getHtml());
+
+        $this->assertTrue($subUrl->has('css', 'strong'));
+        $this->assertFalse($subUrl->has('css', 'em'));
+        $this->assertEquals('deep', $subUrl->find('css', 'strong')->getText());
+    }
+}
diff --git a/vendor/behat/mink/driver-testsuite/tests/Basic/VisibilityTest.php b/vendor/behat/mink/driver-testsuite/tests/Basic/VisibilityTest.php
new file mode 100644
index 00000000000..b3daf316a38
--- /dev/null
+++ b/vendor/behat/mink/driver-testsuite/tests/Basic/VisibilityTest.php
@@ -0,0 +1,20 @@
+<?php
+
+namespace Behat\Mink\Tests\Driver\Basic;
+
+use Behat\Mink\Tests\Driver\TestCase;
+
+class VisibilityTest extends TestCase
+{
+    public function testVisibility()
+    {
+        $this->getSession()->visit($this->pathTo('/js_test.html'));
+        $webAssert = $this->getAssertSession();
+
+        $clicker   = $webAssert->elementExists('css', '.elements div#clicker');
+        $invisible = $webAssert->elementExists('css', '#invisible');
+
+        $this->assertFalse($invisible->isVisible());
+        $this->assertTrue($clicker->isVisible());
+    }
+}
diff --git a/vendor/behat/mink/driver-testsuite/tests/Css/HoverTest.php b/vendor/behat/mink/driver-testsuite/tests/Css/HoverTest.php
new file mode 100644
index 00000000000..87041d4f289
--- /dev/null
+++ b/vendor/behat/mink/driver-testsuite/tests/Css/HoverTest.php
@@ -0,0 +1,76 @@
+<?php
+
+namespace Behat\Mink\Tests\Driver\Css;
+
+use Behat\Mink\Tests\Driver\TestCase;
+
+class HoverTest extends TestCase
+{
+    /**
+     * @group mouse-events
+     */
+    public function testMouseOverHover()
+    {
+        $this->getSession()->visit($this->pathTo('/css_mouse_events.html'));
+
+        $this->findById('reset-square')->mouseOver();
+        $this->assertActionSquareHeight(100);
+
+        $this->findById('action-square')->mouseOver();
+        $this->assertActionSquareHeight(200);
+    }
+
+    /**
+     * @group mouse-events
+     * @depends testMouseOverHover
+     */
+    public function testClickHover()
+    {
+        $this->getSession()->visit($this->pathTo('/css_mouse_events.html'));
+
+        $this->findById('reset-square')->mouseOver();
+        $this->assertActionSquareHeight(100);
+
+        $this->findById('action-square')->click();
+        $this->assertActionSquareHeight(200);
+    }
+
+    /**
+     * @group mouse-events
+     * @depends testMouseOverHover
+     */
+    public function testDoubleClickHover()
+    {
+        $this->getSession()->visit($this->pathTo('/css_mouse_events.html'));
+
+        $this->findById('reset-square')->mouseOver();
+        $this->assertActionSquareHeight(100);
+
+        $this->findById('action-square')->doubleClick();
+        $this->assertActionSquareHeight(200);
+    }
+
+    /**
+     * @group mouse-events
+     * @depends testMouseOverHover
+     */
+    public function testRightClickHover()
+    {
+        $this->getSession()->visit($this->pathTo('/css_mouse_events.html'));
+
+        $this->findById('reset-square')->mouseOver();
+        $this->assertActionSquareHeight(100);
+
+        $this->findById('action-square')->rightClick();
+        $this->assertActionSquareHeight(200);
+    }
+
+    private function assertActionSquareHeight($expected)
+    {
+        $this->assertEquals(
+            $expected,
+            $this->getSession()->evaluateScript("return window.$('#action-square').height();"),
+            'Mouse is located over the object when mouse-related action is performed'
+        );
+    }
+}
diff --git a/vendor/behat/mink/driver-testsuite/tests/Form/CheckboxTest.php b/vendor/behat/mink/driver-testsuite/tests/Form/CheckboxTest.php
new file mode 100644
index 00000000000..e1ce4ab16fa
--- /dev/null
+++ b/vendor/behat/mink/driver-testsuite/tests/Form/CheckboxTest.php
@@ -0,0 +1,73 @@
+<?php
+
+namespace Behat\Mink\Tests\Driver\Form;
+
+use Behat\Mink\Tests\Driver\TestCase;
+
+class CheckboxTest extends TestCase
+{
+    public function testManipulate()
+    {
+        $this->getSession()->visit($this->pathTo('advanced_form.html'));
+
+        $checkbox = $this->getAssertSession()->fieldExists('agreement');
+
+        $this->assertNull($checkbox->getValue());
+        $this->assertFalse($checkbox->isChecked());
+
+        $checkbox->check();
+
+        $this->assertEquals('yes', $checkbox->getValue());
+        $this->assertTrue($checkbox->isChecked());
+
+        $checkbox->uncheck();
+
+        $this->assertNull($checkbox->getValue());
+        $this->assertFalse($checkbox->isChecked());
+    }
+
+    public function testSetValue()
+    {
+        $this->getSession()->visit($this->pathTo('advanced_form.html'));
+
+        $checkbox = $this->getAssertSession()->fieldExists('agreement');
+
+        $this->assertNull($checkbox->getValue());
+        $this->assertFalse($checkbox->isChecked());
+
+        $checkbox->setValue(true);
+
+        $this->assertEquals('yes', $checkbox->getValue());
+        $this->assertTrue($checkbox->isChecked());
+
+        $checkbox->setValue(false);
+
+        $this->assertNull($checkbox->getValue());
+        $this->assertFalse($checkbox->isChecked());
+    }
+
+    public function testCheckboxMultiple()
+    {
+        $this->getSession()->visit($this->pathTo('/multicheckbox_form.html'));
+        $webAssert = $this->getAssertSession();
+
+        $this->assertEquals('Multicheckbox Test', $webAssert->elementExists('css', 'h1')->getText());
+
+        $updateMail  = $webAssert->elementExists('css', '[name="mail_types[]"][value="update"]');
+        $spamMail    = $webAssert->elementExists('css', '[name="mail_types[]"][value="spam"]');
+
+        $this->assertEquals('update', $updateMail->getValue());
+        $this->assertNull($spamMail->getValue());
+
+        $this->assertTrue($updateMail->isChecked());
+        $this->assertFalse($spamMail->isChecked());
+
+        $updateMail->uncheck();
+        $this->assertFalse($updateMail->isChecked());
+        $this->assertFalse($spamMail->isChecked());
+
+        $spamMail->check();
+        $this->assertFalse($updateMail->isChecked());
+        $this->assertTrue($spamMail->isChecked());
+    }
+}
diff --git a/vendor/behat/mink/driver-testsuite/tests/Form/GeneralTest.php b/vendor/behat/mink/driver-testsuite/tests/Form/GeneralTest.php
new file mode 100644
index 00000000000..263be70baef
--- /dev/null
+++ b/vendor/behat/mink/driver-testsuite/tests/Form/GeneralTest.php
@@ -0,0 +1,312 @@
+<?php
+
+namespace Behat\Mink\Tests\Driver\Form;
+
+use Behat\Mink\Tests\Driver\TestCase;
+
+class GeneralTest extends TestCase
+{
+    // test multiple submit buttons
+    public function testIssue212()
+    {
+        $session = $this->getSession();
+
+        $session->visit($this->pathTo('/issue212.html'));
+
+        $field = $this->findById('poney-button');
+        $this->assertEquals('poney', $field->getValue());
+    }
+
+    public function testBasicForm()
+    {
+        $this->getSession()->visit($this->pathTo('/basic_form.html'));
+
+        $webAssert = $this->getAssertSession();
+        $page = $this->getSession()->getPage();
+        $this->assertEquals('Basic Form Page', $webAssert->elementExists('css', 'h1')->getText());
+
+        $firstname  = $webAssert->fieldExists('first_name');
+        $lastname   = $webAssert->fieldExists('lastn');
+
+        $this->assertEquals('Firstname', $firstname->getValue());
+        $this->assertEquals('Lastname', $lastname->getValue());
+
+        $firstname->setValue('Konstantin');
+        $page->fillField('last_name', 'Kudryashov');
+
+        $this->assertEquals('Konstantin', $firstname->getValue());
+        $this->assertEquals('Kudryashov', $lastname->getValue());
+
+        $page->findButton('Reset')->click();
+
+        $this->assertEquals('Firstname', $firstname->getValue());
+        $this->assertEquals('Lastname', $lastname->getValue());
+
+        $firstname->setValue('Konstantin');
+        $page->fillField('last_name', 'Kudryashov');
+
+        $page->findButton('Save')->click();
+
+        if ($this->safePageWait(5000, 'document.getElementById("first") !== null')) {
+            $this->assertEquals('Anket for Konstantin', $webAssert->elementExists('css', 'h1')->getText());
+            $this->assertEquals('Firstname: Konstantin', $webAssert->elementExists('css', '#first')->getText());
+            $this->assertEquals('Lastname: Kudryashov', $webAssert->elementExists('css', '#last')->getText());
+        }
+    }
+
+    /**
+     * @dataProvider formSubmitWaysDataProvider
+     */
+    public function testFormSubmitWays($submitVia)
+    {
+        $session = $this->getSession();
+        $session->visit($this->pathTo('/basic_form.html'));
+        $page = $session->getPage();
+        $webAssert = $this->getAssertSession();
+
+        $firstname = $webAssert->fieldExists('first_name');
+        $firstname->setValue('Konstantin');
+
+        $page->findButton($submitVia)->click();
+
+        if ($this->safePageWait(5000, 'document.getElementById("first") !== null')) {
+            $this->assertEquals('Firstname: Konstantin', $webAssert->elementExists('css', '#first')->getText());
+        } else {
+            $this->fail('Form was never submitted');
+        }
+    }
+
+    public function formSubmitWaysDataProvider()
+    {
+        return array(
+            array('Save'),
+            array('input-type-image'),
+            array('button-without-type'),
+            array('button-type-submit'),
+        );
+    }
+
+    public function testFormSubmit()
+    {
+        $session = $this->getSession();
+        $session->visit($this->pathTo('/basic_form.html'));
+
+        $webAssert = $this->getAssertSession();
+        $webAssert->fieldExists('first_name')->setValue('Konstantin');
+
+        $webAssert->elementExists('xpath', 'descendant-or-self::form[1]')->submit();
+
+        if ($this->safePageWait(5000, 'document.getElementById("first") !== null')) {
+            $this->assertEquals('Firstname: Konstantin', $webAssert->elementExists('css', '#first')->getText());
+        };
+    }
+
+    public function testFormSubmitWithoutButton()
+    {
+        $session = $this->getSession();
+        $session->visit($this->pathTo('/form_without_button.html'));
+
+        $webAssert = $this->getAssertSession();
+        $webAssert->fieldExists('first_name')->setValue('Konstantin');
+
+        $webAssert->elementExists('xpath', 'descendant-or-self::form[1]')->submit();
+
+        if ($this->safePageWait(5000, 'document.getElementById("first") !== null')) {
+            $this->assertEquals('Firstname: Konstantin', $webAssert->elementExists('css', '#first')->getText());
+        };
+    }
+
+    public function testBasicGetForm()
+    {
+        $this->getSession()->visit($this->pathTo('/basic_get_form.php'));
+        $webAssert = $this->getAssertSession();
+
+        $page = $this->getSession()->getPage();
+        $this->assertEquals('Basic Get Form Page', $webAssert->elementExists('css', 'h1')->getText());
+
+        $search = $webAssert->fieldExists('q');
+        $search->setValue('some#query');
+        $page->pressButton('Find');
+
+        $div = $webAssert->elementExists('css', 'div');
+        $this->assertEquals('some#query', $div->getText());
+    }
+
+    public function testAdvancedForm()
+    {
+        $this->getSession()->visit($this->pathTo('/advanced_form.html'));
+        $page = $this->getSession()->getPage();
+
+        $page->fillField('first_name', 'ever');
+        $page->fillField('last_name', 'zet');
+
+        $page->pressButton('Register');
+
+        $this->assertContains('no file', $page->getContent());
+
+        $this->getSession()->visit($this->pathTo('/advanced_form.html'));
+
+        $webAssert = $this->getAssertSession();
+        $page = $this->getSession()->getPage();
+        $this->assertEquals('ADvanced Form Page', $webAssert->elementExists('css', 'h1')->getText());
+
+        $firstname   = $webAssert->fieldExists('first_name');
+        $lastname    = $webAssert->fieldExists('lastn');
+        $email       = $webAssert->fieldExists('Your email:');
+        $select      = $webAssert->fieldExists('select_number');
+        $sex         = $webAssert->fieldExists('sex');
+        $maillist    = $webAssert->fieldExists('mail_list');
+        $agreement   = $webAssert->fieldExists('agreement');
+        $notes       = $webAssert->fieldExists('notes');
+        $about       = $webAssert->fieldExists('about');
+
+        $this->assertEquals('Firstname', $firstname->getValue());
+        $this->assertEquals('Lastname', $lastname->getValue());
+        $this->assertEquals('your@email.com', $email->getValue());
+        $this->assertEquals('20', $select->getValue());
+        $this->assertEquals('w', $sex->getValue());
+        $this->assertEquals('original notes', $notes->getValue());
+
+        $this->assertEquals('on', $maillist->getValue());
+        $this->assertNull($agreement->getValue());
+
+        $this->assertTrue($maillist->isChecked());
+        $this->assertFalse($agreement->isChecked());
+
+        $agreement->check();
+        $this->assertTrue($agreement->isChecked());
+
+        $maillist->uncheck();
+        $this->assertFalse($maillist->isChecked());
+
+        $select->selectOption('thirty');
+        $this->assertEquals('30', $select->getValue());
+
+        $sex->selectOption('m');
+        $this->assertEquals('m', $sex->getValue());
+
+        $notes->setValue('new notes');
+        $this->assertEquals('new notes', $notes->getValue());
+
+        $about->attachFile($this->mapRemoteFilePath(__DIR__ . '/../../web-fixtures/some_file.txt'));
+
+        $button = $page->findButton('Register');
+        $this->assertNotNull($button);
+
+        $page->fillField('first_name', 'Foo "item"');
+        $page->fillField('last_name', 'Bar');
+        $page->fillField('Your email:', 'ever.zet@gmail.com');
+
+        $this->assertEquals('Foo "item"', $firstname->getValue());
+        $this->assertEquals('Bar', $lastname->getValue());
+
+        $button->press();
+
+        if ($this->safePageWait(5000, 'document.getElementsByTagName("title") !== null')) {
+            $out = <<<OUT
+array (
+  'agreement' = 'on',
+  'email' = 'ever.zet@gmail.com',
+  'first_name' = 'Foo "item"',
+  'last_name' = 'Bar',
+  'notes' = 'new notes',
+  'select_number' = '30',
+  'sex' = 'm',
+  'submit' = 'Register',
+)
+some_file.txt
+1 uploaded file
+OUT;
+            $this->assertContains($out, $page->getContent());
+        }
+    }
+
+    public function testMultiInput()
+    {
+        $this->getSession()->visit($this->pathTo('/multi_input_form.html'));
+        $page = $this->getSession()->getPage();
+        $webAssert = $this->getAssertSession();
+        $this->assertEquals('Multi input Test', $webAssert->elementExists('css', 'h1')->getText());
+
+        $first = $webAssert->fieldExists('First');
+        $second = $webAssert->fieldExists('Second');
+        $third = $webAssert->fieldExists('Third');
+
+        $this->assertEquals('tag1', $first->getValue());
+        $this->assertSame('tag2', $second->getValue());
+        $this->assertEquals('tag1', $third->getValue());
+
+        $first->setValue('tag2');
+        $this->assertEquals('tag2', $first->getValue());
+        $this->assertSame('tag2', $second->getValue());
+        $this->assertEquals('tag1', $third->getValue());
+
+        $second->setValue('one');
+
+        $this->assertEquals('tag2', $first->getValue());
+        $this->assertSame('one', $second->getValue());
+
+        $third->setValue('tag3');
+
+        $this->assertEquals('tag2', $first->getValue());
+        $this->assertSame('one', $second->getValue());
+        $this->assertEquals('tag3', $third->getValue());
+
+        $button = $page->findButton('Register');
+        $this->assertNotNull($button);
+        $button->press();
+
+        $space = ' ';
+        $out = <<<OUT
+  'tags' =$space
+  array (
+    0 = 'tag2',
+    1 = 'one',
+    2 = 'tag3',
+  ),
+OUT;
+        $this->assertContains($out, $page->getContent());
+    }
+
+    public function testAdvancedFormSecondSubmit()
+    {
+        $this->getSession()->visit($this->pathTo('/advanced_form.html'));
+        $page = $this->getSession()->getPage();
+
+        $button = $page->findButton('Login');
+        $this->assertNotNull($button);
+        $button->press();
+
+        $toSearch = array(
+            "'agreement' = 'off',",
+            "'submit' = 'Login',",
+            'no file',
+        );
+
+        $pageContent = $page->getContent();
+
+        foreach ($toSearch as $searchString) {
+            $this->assertContains($searchString, $pageContent);
+        }
+    }
+
+    public function testSubmitEmptyTextarea()
+    {
+        $this->getSession()->visit($this->pathTo('/empty_textarea.html'));
+        $page = $this->getSession()->getPage();
+
+        $page->pressButton('Save');
+
+        $toSearch = array(
+            "'textarea' = '',",
+            "'submit' = 'Save',",
+            'no file',
+        );
+
+        $pageContent = $page->getContent();
+
+        foreach ($toSearch as $searchString) {
+            $this->assertContains($searchString, $pageContent);
+        }
+    }
+}
diff --git a/vendor/behat/mink/driver-testsuite/tests/Form/Html5Test.php b/vendor/behat/mink/driver-testsuite/tests/Form/Html5Test.php
new file mode 100644
index 00000000000..b7f4716d310
--- /dev/null
+++ b/vendor/behat/mink/driver-testsuite/tests/Form/Html5Test.php
@@ -0,0 +1,128 @@
+<?php
+
+namespace Behat\Mink\Tests\Driver\Form;
+
+use Behat\Mink\Tests\Driver\TestCase;
+
+class Html5Test extends TestCase
+{
+    public function testHtml5FormInputAttribute()
+    {
+        $this->getSession()->visit($this->pathTo('/html5_form.html'));
+        $page = $this->getSession()->getPage();
+        $webAssert = $this->getAssertSession();
+
+        $firstName = $webAssert->fieldExists('first_name');
+        $lastName = $webAssert->fieldExists('last_name');
+
+        $this->assertEquals('not set', $lastName->getValue());
+        $firstName->setValue('John');
+        $lastName->setValue('Doe');
+
+        $this->assertEquals('Doe', $lastName->getValue());
+
+        $page->pressButton('Submit in form');
+
+        if ($this->safePageWait(5000, 'document.getElementsByTagName("title") !== null')) {
+            $out = <<<OUT
+  'first_name' = 'John',
+  'last_name' = 'Doe',
+OUT;
+            $this->assertContains($out, $page->getContent());
+            $this->assertNotContains('other_field', $page->getContent());
+        }
+    }
+
+    public function testHtml5FormRadioAttribute()
+    {
+        $this->getSession()->visit($this->pathTo('html5_radio.html'));
+        $page = $this->getSession()->getPage();
+
+        $radio = $this->findById('sex_f');
+        $otherRadio = $this->findById('sex_invalid');
+
+        $this->assertEquals('f', $radio->getValue());
+        $this->assertEquals('invalid', $otherRadio->getValue());
+
+        $radio->selectOption('m');
+
+        $this->assertEquals('m', $radio->getValue());
+        $this->assertEquals('invalid', $otherRadio->getValue());
+
+        $page->pressButton('Submit in form');
+
+        $out = <<<OUT
+  'sex' = 'm',
+OUT;
+        $this->assertContains($out, $page->getContent());
+    }
+
+    public function testHtml5FormButtonAttribute()
+    {
+        $this->getSession()->visit($this->pathTo('/html5_form.html'));
+        $page = $this->getSession()->getPage();
+        $webAssert = $this->getAssertSession();
+
+        $firstName = $webAssert->fieldExists('first_name');
+        $lastName = $webAssert->fieldExists('last_name');
+
+        $firstName->setValue('John');
+        $lastName->setValue('Doe');
+
+        $page->pressButton('Submit outside form');
+
+        if ($this->safePageWait(5000, 'document.getElementsByTagName("title") !== null')) {
+            $out = <<<OUT
+  'first_name' = 'John',
+  'last_name' = 'Doe',
+  'submit_button' = 'test',
+OUT;
+            $this->assertContains($out, $page->getContent());
+        }
+    }
+
+    public function testHtml5FormOutside()
+    {
+        $this->getSession()->visit($this->pathTo('/html5_form.html'));
+        $page = $this->getSession()->getPage();
+
+        $page->fillField('other_field', 'hello');
+
+        $page->pressButton('Submit separate form');
+
+        if ($this->safePageWait(5000, 'document.getElementsByTagName("title") !== null')) {
+            $out = <<<OUT
+  'other_field' = 'hello',
+OUT;
+            $this->assertContains($out, $page->getContent());
+            $this->assertNotContains('first_name', $page->getContent());
+        }
+    }
+
+    public function testHtml5Types()
+    {
+        $this->getSession()->visit($this->pathTo('html5_types.html'));
+        $page = $this->getSession()->getPage();
+
+        $page->fillField('url', 'http://mink.behat.org/');
+        $page->fillField('email', 'mink@example.org');
+        $page->fillField('number', '6');
+        $page->fillField('search', 'mink');
+        $page->fillField('date', '2014-05-19');
+        $page->fillField('color', '#ff00aa');
+
+        $page->pressButton('Submit');
+
+        $out = <<<OUT
+  'color' = '#ff00aa',
+  'date' = '2014-05-19',
+  'email' = 'mink@example.org',
+  'number' = '6',
+  'search' = 'mink',
+  'submit_button' = 'Submit',
+  'url' = 'http://mink.behat.org/',
+OUT;
+
+        $this->assertContains($out, $page->getContent());
+    }
+}
diff --git a/vendor/behat/mink/driver-testsuite/tests/Form/RadioTest.php b/vendor/behat/mink/driver-testsuite/tests/Form/RadioTest.php
new file mode 100644
index 00000000000..39cd743a2a0
--- /dev/null
+++ b/vendor/behat/mink/driver-testsuite/tests/Form/RadioTest.php
@@ -0,0 +1,84 @@
+<?php
+
+namespace Behat\Mink\Tests\Driver\Form;
+
+use Behat\Mink\Tests\Driver\TestCase;
+
+class RadioTest extends TestCase
+{
+    protected function setUp()
+    {
+        $this->getSession()->visit($this->pathTo('radio.html'));
+    }
+
+    public function testIsChecked()
+    {
+        $option = $this->findById('first');
+        $option2 = $this->findById('second');
+
+        $this->assertTrue($option->isChecked());
+        $this->assertFalse($option2->isChecked());
+
+        $option2->selectOption('updated');
+
+        $this->assertFalse($option->isChecked());
+        $this->assertTrue($option2->isChecked());
+    }
+
+    public function testSelectOption()
+    {
+        $option = $this->findById('first');
+
+        $this->assertEquals('set', $option->getValue());
+
+        $option->selectOption('updated');
+
+        $this->assertEquals('updated', $option->getValue());
+
+        $option->selectOption('set');
+
+        $this->assertEquals('set', $option->getValue());
+    }
+
+    public function testSetValue()
+    {
+        $option = $this->findById('first');
+
+        $this->assertEquals('set', $option->getValue());
+
+        $option->setValue('updated');
+
+        $this->assertEquals('updated', $option->getValue());
+        $this->assertFalse($option->isChecked());
+    }
+
+    public function testSameNameInMultipleForms()
+    {
+        $option1 = $this->findById('reused_form1');
+        $option2 = $this->findById('reused_form2');
+
+        $this->assertEquals('test2', $option1->getValue());
+        $this->assertEquals('test3', $option2->getValue());
+
+        $option1->selectOption('test');
+
+        $this->assertEquals('test', $option1->getValue());
+        $this->assertEquals('test3', $option2->getValue());
+    }
+
+    /**
+     * @see https://github.com/Behat/MinkSahiDriver/issues/32
+     */
+    public function testSetValueXPathEscaping()
+    {
+        $session = $this->getSession();
+        $session->visit($this->pathTo('/advanced_form.html'));
+        $page = $session->getPage();
+
+        $sex = $page->find('xpath', '//*[@name = "sex"]' . "\n|\n" . '//*[@id = "sex"]');
+        $this->assertNotNull($sex, 'xpath with line ending works');
+
+        $sex->setValue('m');
+        $this->assertEquals('m', $sex->getValue(), 'no double xpath escaping during radio button value change');
+    }
+}
diff --git a/vendor/behat/mink/driver-testsuite/tests/Form/SelectTest.php b/vendor/behat/mink/driver-testsuite/tests/Form/SelectTest.php
new file mode 100644
index 00000000000..492625a9566
--- /dev/null
+++ b/vendor/behat/mink/driver-testsuite/tests/Form/SelectTest.php
@@ -0,0 +1,135 @@
+<?php
+
+namespace Behat\Mink\Tests\Driver\Form;
+
+use Behat\Mink\Tests\Driver\TestCase;
+
+class SelectTest extends TestCase
+{
+    public function testMultiselect()
+    {
+        $this->getSession()->visit($this->pathTo('/multiselect_form.html'));
+        $webAssert = $this->getAssertSession();
+        $page = $this->getSession()->getPage();
+        $this->assertEquals('Multiselect Test', $webAssert->elementExists('css', 'h1')->getText());
+
+        $select      = $webAssert->fieldExists('select_number');
+        $multiSelect = $webAssert->fieldExists('select_multiple_numbers[]');
+        $secondMultiSelect = $webAssert->fieldExists('select_multiple_values[]');
+
+        $this->assertEquals('20', $select->getValue());
+        $this->assertSame(array(), $multiSelect->getValue());
+        $this->assertSame(array('2', '3'), $secondMultiSelect->getValue());
+
+        $select->selectOption('thirty');
+        $this->assertEquals('30', $select->getValue());
+
+        $multiSelect->selectOption('one', true);
+
+        $this->assertSame(array('1'), $multiSelect->getValue());
+
+        $multiSelect->selectOption('three', true);
+
+        $this->assertEquals(array('1', '3'), $multiSelect->getValue());
+
+        $secondMultiSelect->selectOption('two');
+        $this->assertSame(array('2'), $secondMultiSelect->getValue());
+
+        $button = $page->findButton('Register');
+        $this->assertNotNull($button);
+        $button->press();
+
+        $space = ' ';
+        $out = <<<OUT
+  'agreement' = 'off',
+  'select_multiple_numbers' =$space
+  array (
+    0 = '1',
+    1 = '3',
+  ),
+  'select_multiple_values' =$space
+  array (
+    0 = '2',
+  ),
+  'select_number' = '30',
+OUT;
+        $this->assertContains($out, $page->getContent());
+    }
+
+    /**
+     * @dataProvider testElementSelectedStateCheckDataProvider
+     */
+    public function testElementSelectedStateCheck($selectName, $optionValue, $optionText)
+    {
+        $session = $this->getSession();
+        $webAssert = $this->getAssertSession();
+        $session->visit($this->pathTo('/multiselect_form.html'));
+        $select = $webAssert->fieldExists($selectName);
+
+        $optionValueEscaped = $session->getSelectorsHandler()->xpathLiteral($optionValue);
+        $option = $webAssert->elementExists('named', array('option', $optionValueEscaped));
+
+        $this->assertFalse($option->isSelected());
+        $select->selectOption($optionText);
+        $this->assertTrue($option->isSelected());
+    }
+
+    public function testElementSelectedStateCheckDataProvider()
+    {
+        return array(
+            array('select_number', '30', 'thirty'),
+            array('select_multiple_numbers[]', '2', 'two'),
+        );
+    }
+
+    public function testSetValueSingleSelect()
+    {
+        $session = $this->getSession();
+        $session->visit($this->pathTo('/multiselect_form.html'));
+        $select = $this->getAssertSession()->fieldExists('select_number');
+
+        $select->setValue('10');
+        $this->assertEquals('10', $select->getValue());
+    }
+
+    public function testSetValueMultiSelect()
+    {
+        $session = $this->getSession();
+        $session->visit($this->pathTo('/multiselect_form.html'));
+        $select = $this->getAssertSession()->fieldExists('select_multiple_values[]');
+
+        $select->setValue(array('1', '2'));
+        $this->assertEquals(array('1', '2'), $select->getValue());
+    }
+
+    /**
+     * @see https://github.com/Behat/Mink/issues/193
+     */
+    public function testOptionWithoutValue()
+    {
+        $session = $this->getSession();
+        $session->visit($this->pathTo('/issue193.html'));
+
+        $session->getPage()->selectFieldOption('options-without-values', 'Two');
+        $this->assertEquals('Two', $this->findById('options-without-values')->getValue());
+
+        $this->assertTrue($this->findById('two')->isSelected());
+        $this->assertFalse($this->findById('one')->isSelected());
+
+        $session->getPage()->selectFieldOption('options-with-values', 'two');
+        $this->assertEquals('two', $this->findById('options-with-values')->getValue());
+    }
+
+    /**
+     * @see https://github.com/Behat/Mink/issues/131
+     */
+    public function testAccentuatedOption()
+    {
+        $this->getSession()->visit($this->pathTo('/issue131.html'));
+        $page = $this->getSession()->getPage();
+
+        $page->selectFieldOption('foobar', 'Gimme some accentués characters');
+
+        $this->assertEquals('1', $page->findField('foobar')->getValue());
+    }
+}
diff --git a/vendor/behat/mink/driver-testsuite/tests/Js/ChangeEventTest.php b/vendor/behat/mink/driver-testsuite/tests/Js/ChangeEventTest.php
new file mode 100644
index 00000000000..d1fd3f16762
--- /dev/null
+++ b/vendor/behat/mink/driver-testsuite/tests/Js/ChangeEventTest.php
@@ -0,0 +1,152 @@
+<?php
+
+namespace Behat\Mink\Tests\Driver\Js;
+
+use Behat\Mink\Tests\Driver\TestCase;
+
+class ChangeEventTest extends TestCase
+{
+    /**
+     * 'change' event should be fired after selecting an <option> in a <select>
+     *
+     * TODO check whether this test is redundant with other change event tests.
+     */
+    public function testIssue255()
+    {
+        $session = $this->getSession();
+        $session->visit($this->pathTo('/issue255.html'));
+
+        $session->getPage()->selectFieldOption('foo_select', 'Option 3');
+
+        $session->wait(2000, '$("#output_foo_select").text() != ""');
+        $this->assertEquals('onChangeSelect', $session->getPage()->find('css', '#output_foo_select')->getText());
+    }
+
+    public function testIssue178()
+    {
+        $session = $this->getSession();
+        $session->visit($this->pathTo('/issue178.html'));
+
+        $this->findById('source')->setValue('foo');
+        $this->assertEquals('foo', $this->findById('target')->getText());
+    }
+
+    /**
+     * @dataProvider setValueChangeEventDataProvider
+     * @group change-event-detector
+     */
+    public function testSetValueChangeEvent($elementId, $valueForEmpty, $valueForFilled = '')
+    {
+        $this->getSession()->visit($this->pathTo('/element_change_detector.html'));
+        $page = $this->getSession()->getPage();
+
+        $input = $this->findById($elementId);
+        $this->assertNull($page->findById($elementId.'-result'));
+
+        // Verify setting value, when control is initially empty.
+        $input->setValue($valueForEmpty);
+        $this->assertElementChangeCount($elementId, 'initial value setting triggers change event');
+
+        if ($valueForFilled) {
+            // Verify setting value, when control already has a value.
+            $this->findById('results')->click();
+            $input->setValue($valueForFilled);
+            $this->assertElementChangeCount($elementId, 'value change triggers change event');
+        }
+    }
+
+    public function setValueChangeEventDataProvider()
+    {
+        return array(
+            'input default' => array('the-input-default', 'from empty', 'from existing'),
+            'input text' => array('the-input-text', 'from empty', 'from existing'),
+            'input email' => array('the-email', 'from empty', 'from existing'),
+            'textarea' => array('the-textarea', 'from empty', 'from existing'),
+            'file' => array('the-file', 'from empty', 'from existing'),
+            'select' => array('the-select', '30'),
+            'radio' => array('the-radio-m', 'm'),
+        );
+    }
+
+    /**
+     * @dataProvider selectOptionChangeEventDataProvider
+     * @group change-event-detector
+     */
+    public function testSelectOptionChangeEvent($elementId, $elementValue)
+    {
+        $this->getSession()->visit($this->pathTo('/element_change_detector.html'));
+        $page = $this->getSession()->getPage();
+
+        $input = $this->findById($elementId);
+        $this->assertNull($page->findById($elementId.'-result'));
+
+        $input->selectOption($elementValue);
+        $this->assertElementChangeCount($elementId);
+    }
+
+    public function selectOptionChangeEventDataProvider()
+    {
+        return array(
+            'select' => array('the-select', '30'),
+            'radio' => array('the-radio-m', 'm'),
+        );
+    }
+
+    /**
+     * @dataProvider checkboxTestWayDataProvider
+     * @group change-event-detector
+     */
+    public function testCheckChangeEvent($useSetValue)
+    {
+        $this->getSession()->visit($this->pathTo('/element_change_detector.html'));
+        $page = $this->getSession()->getPage();
+
+        $checkbox = $this->findById('the-unchecked-checkbox');
+        $this->assertNull($page->findById('the-unchecked-checkbox-result'));
+
+        if ($useSetValue) {
+            $checkbox->setValue(true);
+        } else {
+            $checkbox->check();
+        }
+
+        $this->assertElementChangeCount('the-unchecked-checkbox');
+    }
+
+    /**
+     * @dataProvider checkboxTestWayDataProvider
+     * @group change-event-detector
+     */
+    public function testUncheckChangeEvent($useSetValue)
+    {
+        $this->getSession()->visit($this->pathTo('/element_change_detector.html'));
+        $page = $this->getSession()->getPage();
+
+        $checkbox = $this->findById('the-checked-checkbox');
+        $this->assertNull($page->findById('the-checked-checkbox-result'));
+
+        if ($useSetValue) {
+            $checkbox->setValue(false);
+        } else {
+            $checkbox->uncheck();
+        }
+
+        $this->assertElementChangeCount('the-checked-checkbox');
+    }
+
+    public function checkboxTestWayDataProvider()
+    {
+        return array(
+            array(true),
+            array(false),
+        );
+    }
+
+    private function assertElementChangeCount($elementId, $message = '')
+    {
+        $counterElement = $this->getSession()->getPage()->findById($elementId.'-result');
+        $actualCount = null === $counterElement ? 0 : $counterElement->getText();
+
+        $this->assertEquals('1', $actualCount, $message);
+    }
+}
diff --git a/vendor/behat/mink/driver-testsuite/tests/Js/EventsTest.php b/vendor/behat/mink/driver-testsuite/tests/Js/EventsTest.php
new file mode 100644
index 00000000000..00d084b47e0
--- /dev/null
+++ b/vendor/behat/mink/driver-testsuite/tests/Js/EventsTest.php
@@ -0,0 +1,122 @@
+<?php
+
+namespace Behat\Mink\Tests\Driver\Js;
+
+use Behat\Mink\Tests\Driver\TestCase;
+
+class EventsTest extends TestCase
+{
+    /**
+     * @group mouse-events
+     */
+    public function testClick()
+    {
+        $this->getSession()->visit($this->pathTo('/js_test.html'));
+        $clicker = $this->getAssertSession()->elementExists('css', '.elements div#clicker');
+        $this->assertEquals('not clicked', $clicker->getText());
+
+        $clicker->click();
+        $this->assertEquals('single clicked', $clicker->getText());
+    }
+
+    /**
+     * @group mouse-events
+     */
+    public function testDoubleClick()
+    {
+        $this->getSession()->visit($this->pathTo('/js_test.html'));
+        $clicker = $this->getAssertSession()->elementExists('css', '.elements div#clicker');
+        $this->assertEquals('not clicked', $clicker->getText());
+
+        $clicker->doubleClick();
+        $this->assertEquals('double clicked', $clicker->getText());
+    }
+
+    /**
+     * @group mouse-events
+     */
+    public function testRightClick()
+    {
+        $this->getSession()->visit($this->pathTo('/js_test.html'));
+        $clicker = $this->getAssertSession()->elementExists('css', '.elements div#clicker');
+        $this->assertEquals('not clicked', $clicker->getText());
+
+        $clicker->rightClick();
+        $this->assertEquals('right clicked', $clicker->getText());
+    }
+
+    /**
+     * @group mouse-events
+     */
+    public function testFocus()
+    {
+        $this->getSession()->visit($this->pathTo('/js_test.html'));
+        $focusBlurDetector = $this->getAssertSession()->elementExists('css', '.elements input#focus-blur-detector');
+        $this->assertEquals('no action detected', $focusBlurDetector->getValue());
+
+        $focusBlurDetector->focus();
+        $this->assertEquals('focused', $focusBlurDetector->getValue());
+    }
+
+    /**
+     * @group mouse-events
+     * @depends testFocus
+     */
+    public function testBlur()
+    {
+        $this->getSession()->visit($this->pathTo('/js_test.html'));
+        $focusBlurDetector = $this->getAssertSession()->elementExists('css', '.elements input#focus-blur-detector');
+        $this->assertEquals('no action detected', $focusBlurDetector->getValue());
+
+        $focusBlurDetector->blur();
+        $this->assertEquals('blured', $focusBlurDetector->getValue());
+    }
+
+    /**
+     * @group mouse-events
+     */
+    public function testMouseOver()
+    {
+        $this->getSession()->visit($this->pathTo('/js_test.html'));
+        $mouseOverDetector = $this->getAssertSession()->elementExists('css', '.elements div#mouseover-detector');
+        $this->assertEquals('no mouse action detected', $mouseOverDetector->getText());
+
+        $mouseOverDetector->mouseOver();
+        $this->assertEquals('mouse overed', $mouseOverDetector->getText());
+    }
+
+    /**
+     * @dataProvider provideKeyboardEventsModifiers
+     */
+    public function testKeyboardEvents($modifier, $eventProperties)
+    {
+        $this->getSession()->visit($this->pathTo('/js_test.html'));
+        $webAssert = $this->getAssertSession();
+
+        $input1 = $webAssert->elementExists('css', '.elements input.input.first');
+        $input2 = $webAssert->elementExists('css', '.elements input.input.second');
+        $input3 = $webAssert->elementExists('css', '.elements input.input.third');
+        $event  = $webAssert->elementExists('css', '.elements .text-event');
+
+        $input1->keyDown('u', $modifier);
+        $this->assertEquals('key downed:' . $eventProperties, $event->getText());
+
+        $input2->keyPress('r', $modifier);
+        $this->assertEquals('key pressed:114 / ' . $eventProperties, $event->getText());
+
+        $input3->keyUp(78, $modifier);
+        $this->assertEquals('key upped:78 / ' . $eventProperties, $event->getText());
+    }
+
+    public function provideKeyboardEventsModifiers()
+    {
+        return array(
+            'none' => array(null, '0 / 0 / 0 / 0'),
+            'alt' => array('alt', '1 / 0 / 0 / 0'),
+             // jQuery considers ctrl as being a metaKey in the normalized event
+            'ctrl' => array('ctrl', '0 / 1 / 0 / 1'),
+            'shift' => array('shift', '0 / 0 / 1 / 0'),
+            'meta' => array('meta', '0 / 0 / 0 / 1'),
+        );
+    }
+}
diff --git a/vendor/behat/mink/driver-testsuite/tests/Js/JavascriptEvaluationTest.php b/vendor/behat/mink/driver-testsuite/tests/Js/JavascriptEvaluationTest.php
new file mode 100644
index 00000000000..00235d11078
--- /dev/null
+++ b/vendor/behat/mink/driver-testsuite/tests/Js/JavascriptEvaluationTest.php
@@ -0,0 +1,85 @@
+<?php
+
+namespace Behat\Mink\Tests\Driver\Js;
+
+use Behat\Mink\Tests\Driver\TestCase;
+
+class JavascriptEvaluationTest extends TestCase
+{
+    /**
+     * Tests, that `wait` method returns check result after exit.
+     */
+    public function testWaitReturnValue()
+    {
+        $this->getSession()->visit($this->pathTo('/js_test.html'));
+
+        $found = $this->getSession()->wait(5000, '$("#draggable").length == 1');
+        $this->assertTrue($found);
+    }
+
+    public function testWait()
+    {
+        $this->getSession()->visit($this->pathTo('/js_test.html'));
+
+        $waitable = $this->findById('waitable');
+
+        $waitable->click();
+        $this->getSession()->wait(3000, '$("#waitable").has("div").length > 0');
+        $this->assertEquals('arrived', $this->getSession()->getPage()->find('css', '#waitable > div')->getText());
+
+        $waitable->click();
+        $this->getSession()->wait(3000, 'false');
+        $this->assertEquals('timeout', $this->getSession()->getPage()->find('css', '#waitable > div')->getText());
+    }
+
+    /**
+     * @dataProvider provideExecutedScript
+     */
+    public function testExecuteScript($script)
+    {
+        $this->getSession()->visit($this->pathTo('/index.html'));
+
+        $this->getSession()->executeScript($script);
+
+        sleep(1);
+
+        $heading = $this->getAssertSession()->elementExists('css', 'h1');
+        $this->assertEquals('Hello world', $heading->getText());
+    }
+
+    public function provideExecutedScript()
+    {
+        return array(
+            array('document.querySelector("h1").textContent = "Hello world"'),
+            array('document.querySelector("h1").textContent = "Hello world";'),
+            array('function () {document.querySelector("h1").textContent = "Hello world";}()'),
+            array('function () {document.querySelector("h1").textContent = "Hello world";}();'),
+            array('(function () {document.querySelector("h1").textContent = "Hello world";})()'),
+            array('(function () {document.querySelector("h1").textContent = "Hello world";})();'),
+        );
+    }
+
+    /**
+     * @dataProvider provideEvaluatedScript
+     */
+    public function testEvaluateJavascript($script)
+    {
+        $this->getSession()->visit($this->pathTo('/index.html'));
+
+        $this->assertSame(2, $this->getSession()->evaluateScript($script));
+    }
+
+    public function provideEvaluatedScript()
+    {
+        return array(
+            array('1 + 1'),
+            array('1 + 1;'),
+            array('return 1 + 1'),
+            array('return 1 + 1;'),
+            array('function () {return 1+1;}()'),
+            array('(function () {return 1+1;})()'),
+            array('return function () { return 1+1;}()'),
+            array('return (function () {return 1+1;})()'),
+        );
+    }
+}
diff --git a/vendor/behat/mink/driver-testsuite/tests/Js/JavascriptTest.php b/vendor/behat/mink/driver-testsuite/tests/Js/JavascriptTest.php
new file mode 100644
index 00000000000..86cfa65ba67
--- /dev/null
+++ b/vendor/behat/mink/driver-testsuite/tests/Js/JavascriptTest.php
@@ -0,0 +1,42 @@
+<?php
+
+namespace Behat\Mink\Tests\Driver\Js;
+
+use Behat\Mink\Tests\Driver\TestCase;
+
+class JavascriptTest extends TestCase
+{
+    public function testAriaRoles()
+    {
+        $this->getSession()->visit($this->pathTo('/aria_roles.html'));
+
+        $this->getSession()->wait(5000, '$("#hidden-element").is(":visible") === false');
+        $this->getSession()->getPage()->pressButton('Toggle');
+        $this->getSession()->wait(5000, '$("#hidden-element").is(":visible") === true');
+
+        $this->getSession()->getPage()->clickLink('Go to Index');
+        $this->assertEquals($this->pathTo('/index.html'), $this->getSession()->getCurrentUrl());
+    }
+
+    public function testDragDrop()
+    {
+        $this->getSession()->visit($this->pathTo('/js_test.html'));
+        $webAssert = $this->getAssertSession();
+
+        $draggable = $webAssert->elementExists('css', '#draggable');
+        $droppable = $webAssert->elementExists('css', '#droppable');
+
+        $draggable->dragTo($droppable);
+        $this->assertEquals('Dropped!', $droppable->find('css', 'p')->getText());
+    }
+
+    // test accentuated char in button
+    public function testIssue225()
+    {
+        $this->getSession()->visit($this->pathTo('/issue225.html'));
+        $this->getSession()->getPage()->pressButton('Créer un compte');
+        $this->getSession()->wait(5000, '$("#panel").text() != ""');
+
+        $this->assertContains('OH AIH!', $this->getSession()->getPage()->getText());
+    }
+}
diff --git a/vendor/behat/mink/driver-testsuite/tests/Js/WindowTest.php b/vendor/behat/mink/driver-testsuite/tests/Js/WindowTest.php
new file mode 100644
index 00000000000..70b9ed96753
--- /dev/null
+++ b/vendor/behat/mink/driver-testsuite/tests/Js/WindowTest.php
@@ -0,0 +1,83 @@
+<?php
+
+namespace Behat\Mink\Tests\Driver\Js;
+
+use Behat\Mink\Tests\Driver\TestCase;
+
+class WindowTest extends TestCase
+{
+    public function testWindow()
+    {
+        $this->getSession()->visit($this->pathTo('/window.html'));
+        $session = $this->getSession();
+        $page    = $session->getPage();
+        $webAssert = $this->getAssertSession();
+
+        $page->clickLink('Popup #1');
+        $session->switchToWindow(null);
+
+        $page->clickLink('Popup #2');
+        $session->switchToWindow(null);
+
+        $el = $webAssert->elementExists('css', '#text');
+        $this->assertSame('Main window div text', $el->getText());
+
+        $session->switchToWindow('popup_1');
+        $el = $webAssert->elementExists('css', '#text');
+        $this->assertSame('Popup#1 div text', $el->getText());
+
+        $session->switchToWindow('popup_2');
+        $el = $webAssert->elementExists('css', '#text');
+        $this->assertSame('Popup#2 div text', $el->getText());
+
+        $session->switchToWindow(null);
+        $el = $webAssert->elementExists('css', '#text');
+        $this->assertSame('Main window div text', $el->getText());
+    }
+
+    public function testGetWindowNames()
+    {
+        $this->getSession()->visit($this->pathTo('/window.html'));
+        $session = $this->getSession();
+        $page    = $session->getPage();
+
+        $windowName = $this->getSession()->getWindowName();
+
+        $this->assertNotNull($windowName);
+
+        $page->clickLink('Popup #1');
+        $page->clickLink('Popup #2');
+
+        $windowNames = $this->getSession()->getWindowNames();
+
+        $this->assertNotNull($windowNames[0]);
+        $this->assertNotNull($windowNames[1]);
+        $this->assertNotNull($windowNames[2]);
+    }
+
+    public function testResizeWindow()
+    {
+        $this->getSession()->visit($this->pathTo('/index.html'));
+        $session = $this->getSession();
+
+        $session->resizeWindow(400, 300);
+        $session->wait(1000, 'false');
+
+        $script = "return Math.abs(window.outerHeight - 300) <= 100 && Math.abs(window.outerWidth - 400) <= 100;";
+
+        $this->assertTrue($session->evaluateScript($script));
+    }
+
+    public function testWindowMaximize()
+    {
+        $this->getSession()->visit($this->pathTo('/index.html'));
+        $session = $this->getSession();
+
+        $session->maximizeWindow();
+        $session->wait(1000, 'false');
+
+        $script = "return Math.abs(screen.availHeight - window.outerHeight) <= 100;";
+
+        $this->assertTrue($session->evaluateScript($script));
+    }
+}
diff --git a/vendor/behat/mink/driver-testsuite/tests/TestCase.php b/vendor/behat/mink/driver-testsuite/tests/TestCase.php
new file mode 100644
index 00000000000..22860f66081
--- /dev/null
+++ b/vendor/behat/mink/driver-testsuite/tests/TestCase.php
@@ -0,0 +1,156 @@
+<?php
+
+namespace Behat\Mink\Tests\Driver;
+
+use Behat\Mink\Exception\UnsupportedDriverActionException;
+use Behat\Mink\Mink;
+use Behat\Mink\Session;
+use Behat\Mink\WebAssert;
+
+abstract class TestCase extends \PHPUnit_Framework_TestCase
+{
+    /**
+     * Mink session manager.
+     *
+     * @var Mink
+     */
+    private static $mink;
+
+    /**
+     * @var AbstractConfig
+     */
+    private static $config;
+
+    /**
+     * Initializes the test case
+     */
+    public static function setUpBeforeClass()
+    {
+        if (null === self::$mink) {
+            $session = new Session(self::getConfig()->createDriver());
+            self::$mink = new Mink(array('sess' => $session));
+        }
+    }
+
+    /**
+     * @return AbstractConfig
+     *
+     * @throws \UnexpectedValueException if the global driver_config_factory returns an invalid object
+     */
+    private static function getConfig()
+    {
+        if (null === self::$config) {
+            self::$config = call_user_func($GLOBALS['driver_config_factory']);
+
+            if (!self::$config instanceof AbstractConfig) {
+                throw new \UnexpectedValueException('The "driver_config_factory" global variable must return a \Behat\Mink\Tests\Driver\AbstractConfig.');
+            }
+        }
+
+        return self::$config;
+    }
+
+    protected function checkRequirements()
+    {
+        if (null !== $message = self::getConfig()->skipMessage(get_class($this), $this->getName(false))) {
+            $this->markTestSkipped($message);
+        }
+
+        parent::checkRequirements();
+    }
+
+    protected function tearDown()
+    {
+        if (null !== self::$mink) {
+            self::$mink->resetSessions();
+        }
+    }
+
+    protected function onNotSuccessfulTest(\Exception $e)
+    {
+        if ($e instanceof UnsupportedDriverActionException) {
+            $this->markTestSkipped($e->getMessage());
+        }
+
+        parent::onNotSuccessfulTest($e);
+    }
+
+    /**
+     * Returns session.
+     *
+     * @return Session
+     */
+    protected function getSession()
+    {
+        return self::$mink->getSession('sess');
+    }
+
+    /**
+     * Returns assert session.
+     *
+     * @return WebAssert
+     */
+    protected function getAssertSession()
+    {
+        return self::$mink->assertSession('sess');
+    }
+
+    /**
+     * @param string $id
+     *
+     * @return \Behat\Mink\Element\NodeElement
+     */
+    protected function findById($id)
+    {
+        $id = $this->getSession()->getSelectorsHandler()->xpathLiteral($id);
+
+        return $this->getAssertSession()->elementExists('named', array('id', $id));
+    }
+
+    /**
+     * Map remote file path.
+     *
+     * @param string $file File path.
+     *
+     * @return string
+     */
+    protected function mapRemoteFilePath($file)
+    {
+        $realPath = realpath($file);
+
+        if (false !== $realPath) {
+            $file = $realPath;
+        }
+
+        return self::getConfig()->mapRemoteFilePath($file);
+    }
+
+    /**
+     * @param string $path
+     *
+     * @return string
+     */
+    protected function pathTo($path)
+    {
+        return rtrim(self::getConfig()->getWebFixturesUrl(), '/') . '/' . ltrim($path, '/');
+    }
+
+    /**
+     * Waits for a condition to be true, considering than it is successful for drivers not supporting wait()
+     *
+     * @param int    $time
+     * @param string $condition A JS condition to evaluate
+     *
+     * @return bool
+     *
+     * @see \Behat\Mink\Session::wait()
+     */
+    protected function safePageWait($time, $condition)
+    {
+        try {
+            return $this->getSession()->wait($time, $condition);
+        } catch (UnsupportedDriverActionException $e) {
+            return true;
+        }
+    }
+}
diff --git a/vendor/behat/mink/driver-testsuite/web-fixtures/404.php b/vendor/behat/mink/driver-testsuite/web-fixtures/404.php
new file mode 100644
index 00000000000..d16db993d08
--- /dev/null
+++ b/vendor/behat/mink/driver-testsuite/web-fixtures/404.php
@@ -0,0 +1,2 @@
+<?php header("HTTP/1.0 404 Not Found") ?>
+Sorry, page not found
diff --git a/vendor/behat/mink/driver-testsuite/web-fixtures/500.php b/vendor/behat/mink/driver-testsuite/web-fixtures/500.php
new file mode 100644
index 00000000000..c43efcb8f17
--- /dev/null
+++ b/vendor/behat/mink/driver-testsuite/web-fixtures/500.php
@@ -0,0 +1,2 @@
+<?php header("HTTP/1.0 500 Server Error") ?>
+Sorry, a server error happened
diff --git a/vendor/behat/mink/driver-testsuite/web-fixtures/advanced_form.html b/vendor/behat/mink/driver-testsuite/web-fixtures/advanced_form.html
new file mode 100644
index 00000000000..a2392c06c4b
--- /dev/null
+++ b/vendor/behat/mink/driver-testsuite/web-fixtures/advanced_form.html
@@ -0,0 +1,40 @@
+<!DOCTYPE html>
+<html>
+<head>
+    <title>ADvanced Form</title>
+    <meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/>
+</head>
+<body>
+    <h1>ADvanced Form Page</h1>
+
+    <form method="POST" enctype="multipart/form-data" action="advanced_form_post.php">
+        <input name="first_name" value="Firstname" type="text" />
+        <input id="lastn" name="last_name" value="Lastname" type="text" />
+        <label for="email">
+            Your email:
+            <input type="email" id="email" name="email" value="your@email.com" />
+        </label>
+
+        <select name="select_number">
+            <option value="10">ten</option>
+            <option selected="selected" value="20">twenty</option>
+            <option value="30">thirty</option>
+        </select>
+
+        <label>
+            <span><input type="radio" name="sex" value="m" /> m</span>
+            <span><input type="radio" name="sex" value="w" checked="checked" /> w</span>
+        </label>
+
+        <input type="checkbox" name="mail_list" checked="checked" value="on"/>
+        <input type="checkbox" name="agreement" value="yes"/>
+
+        <textarea name="notes">original notes</textarea>
+
+        <input type="file" name="about" />
+
+        <input type="submit" name="submit" value="Register" />
+        <input type="submit" name="submit" value="Login" />
+    </form>
+</body>
+</html>
diff --git a/vendor/behat/mink/driver-testsuite/web-fixtures/advanced_form_post.php b/vendor/behat/mink/driver-testsuite/web-fixtures/advanced_form_post.php
new file mode 100644
index 00000000000..755806dc6f6
--- /dev/null
+++ b/vendor/behat/mink/driver-testsuite/web-fixtures/advanced_form_post.php
@@ -0,0 +1,26 @@
+<!DOCTYPE html>
+<html>
+<head>
+    <title>Advanced form save</title>
+    <meta http-equiv="Content-Type" content="text/html;charset=UTF-8">
+</head>
+<body>
+<?php
+error_reporting(0);
+
+if (isset($_POST['select_multiple_numbers']) && false !== strpos($_POST['select_multiple_numbers'][0], ',')) {
+    $_POST['select_multiple_numbers'] = explode(',', $_POST['select_multiple_numbers'][0]);
+}
+
+$_POST['agreement'] = isset($_POST['agreement']) ? 'on' : 'off';
+ksort($_POST);
+echo str_replace('>', '', var_export($_POST, true)) . "\n";
+if (isset($_FILES['about']) && file_exists($_FILES['about']['tmp_name'])) {
+    echo $_FILES['about']['name'] . "\n";
+    echo file_get_contents($_FILES['about']['tmp_name']);
+} else {
+    echo "no file";
+}
+?>
+</body>
+</html>
diff --git a/vendor/behat/mink/driver-testsuite/web-fixtures/aria_roles.html b/vendor/behat/mink/driver-testsuite/web-fixtures/aria_roles.html
new file mode 100644
index 00000000000..7074e85367d
--- /dev/null
+++ b/vendor/behat/mink/driver-testsuite/web-fixtures/aria_roles.html
@@ -0,0 +1,30 @@
+<!DOCTYPE html>
+<html>
+<head>
+    <title>ARIA roles test</title>
+    <meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/>
+</head>
+<body>
+	This page tests selected ARIA roles<br />
+	(see <a href="http://www.w3.org/TR/wai-aria/">http://www.w3.org/TR/wai-aria/</a>)
+
+	<div id="hidden-element-toggle-button" role="button">Toggle</div>
+	<div id="hidden-element" style="display:none;">This content's visibility is changed by clicking the Toggle Button.</div>
+
+	<!-- This link is created programmatically -->
+	<div id="link-element"></div>
+
+    <script language="javascript" type="text/javascript" src="js/jquery-1.6.2-min.js"></script>
+	<script language="javascript" type="text/javascript">
+		$(document).ready(function() {
+			$('#hidden-element-toggle-button').click(function() {
+				$('#hidden-element').toggle();
+			});
+
+			$('#link-element').attr('role', 'link').text('Go to Index').click(function() {
+        window.location.href = 'index.html';
+			});
+		});
+	</script>
+</body>
+</html>
diff --git a/vendor/behat/mink/driver-testsuite/web-fixtures/basic_auth.php b/vendor/behat/mink/driver-testsuite/web-fixtures/basic_auth.php
new file mode 100644
index 00000000000..9620a0e51b2
--- /dev/null
+++ b/vendor/behat/mink/driver-testsuite/web-fixtures/basic_auth.php
@@ -0,0 +1,12 @@
+<?php
+$username = isset($_SERVER['PHP_AUTH_USER']) ? $_SERVER['PHP_AUTH_USER'] : false;
+$password = isset($_SERVER['PHP_AUTH_PW']) ? $_SERVER['PHP_AUTH_PW'] : false;
+
+if ($username == 'mink-user' && $password == 'mink-password') {
+    echo 'is authenticated';
+} else {
+    header('WWW-Authenticate: Basic realm="Mink Testing Area"');
+    header('HTTP/1.0 401 Unauthorized');
+
+    echo 'is not authenticated';
+}
diff --git a/vendor/behat/mink/driver-testsuite/web-fixtures/basic_form.html b/vendor/behat/mink/driver-testsuite/web-fixtures/basic_form.html
new file mode 100644
index 00000000000..2d330cfe6d5
--- /dev/null
+++ b/vendor/behat/mink/driver-testsuite/web-fixtures/basic_form.html
@@ -0,0 +1,22 @@
+<!DOCTYPE html>
+<html>
+<head>
+    <title>Basic Form</title>
+    <meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/>
+</head>
+<body>
+    <h1>Basic Form Page</h1>
+
+    <form method="POST" action="basic_form_post.php">
+        <input name="first_name" value="Firstname" type="text" />
+        <input id="lastn" name="last_name" value="Lastname" type="text" />
+
+        <input type="reset" id="Reset" />
+
+        <input type="submit" id="Save" />
+        <input type="image" id="input-type-image"/>
+        <button>button-without-type</button>
+        <button type="submit">button-type-submit</button>
+    </form>
+</body>
+</html>
diff --git a/vendor/behat/mink/driver-testsuite/web-fixtures/basic_form_post.php b/vendor/behat/mink/driver-testsuite/web-fixtures/basic_form_post.php
new file mode 100644
index 00000000000..8a5e340ef28
--- /dev/null
+++ b/vendor/behat/mink/driver-testsuite/web-fixtures/basic_form_post.php
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<html>
+<head>
+    <title>Basic Form Saving</title>
+    <meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/>
+</head>
+<body>
+    <h1>Anket for <?php echo $_POST['first_name'] ?></h1>
+
+    <span id="first">Firstname: <?php echo $_POST['first_name'] ?></span>
+    <span id="last">Lastname: <?php echo $_POST['last_name'] ?></span>
+</body>
+</html>
diff --git a/vendor/behat/mink/driver-testsuite/web-fixtures/basic_get_form.php b/vendor/behat/mink/driver-testsuite/web-fixtures/basic_get_form.php
new file mode 100644
index 00000000000..a0b35166ea1
--- /dev/null
+++ b/vendor/behat/mink/driver-testsuite/web-fixtures/basic_get_form.php
@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+<html>
+<head>
+    <title>Basic Get Form</title>
+    <meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/>
+</head>
+<body>
+    <h1>Basic Get Form Page</h1>
+
+    <div id="serach">
+        <?php echo isset($_GET['q']) && $_GET['q'] ? $_GET['q'] : 'No search query' ?>
+    </div>
+
+    <form>
+        <input name="q" value="" type="text" />
+
+        <input type="submit" value="Find" />
+    </form>
+</body>
+</html>
diff --git a/vendor/behat/mink/driver-testsuite/web-fixtures/cookie_page1.php b/vendor/behat/mink/driver-testsuite/web-fixtures/cookie_page1.php
new file mode 100644
index 00000000000..7f128cae8a8
--- /dev/null
+++ b/vendor/behat/mink/driver-testsuite/web-fixtures/cookie_page1.php
@@ -0,0 +1,21 @@
+<?php
+if (!isset($cookieAtRootPath)) {
+    $cookieAtRootPath = true;
+}
+
+if (!isset($cookieValue)) {
+    $cookieValue = 'srv_var_is_set';
+}
+
+setcookie('srvr_cookie', $cookieValue, null, $cookieAtRootPath ? '/' : null);
+?>
+<!DOCTYPE html>
+<html>
+<head>
+    <title>Basic Form</title>
+    <meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/>
+</head>
+<body>
+    Basic Page With Cookie Set from Server Side
+</body>
+</html>
diff --git a/vendor/behat/mink/driver-testsuite/web-fixtures/cookie_page2.php b/vendor/behat/mink/driver-testsuite/web-fixtures/cookie_page2.php
new file mode 100644
index 00000000000..22bcd1be155
--- /dev/null
+++ b/vendor/behat/mink/driver-testsuite/web-fixtures/cookie_page2.php
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<html>
+<head>
+    <title>Basic Form</title>
+    <meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/>
+</head>
+<body>
+    Previous cookie: <?php echo isset($_COOKIE['srvr_cookie']) ? $_COOKIE['srvr_cookie'] : 'NO'; ?>
+</body>
+</html>
diff --git a/vendor/behat/mink/driver-testsuite/web-fixtures/cookie_page3.php b/vendor/behat/mink/driver-testsuite/web-fixtures/cookie_page3.php
new file mode 100644
index 00000000000..caa28bcc1bf
--- /dev/null
+++ b/vendor/behat/mink/driver-testsuite/web-fixtures/cookie_page3.php
@@ -0,0 +1,16 @@
+<?php
+
+$hasCookie = isset($_COOKIE['foo']);
+setcookie('foo', 'bar', 0, '/', null, false, true);
+
+?>
+<!DOCTYPE html>
+<html>
+<head>
+    <title>HttpOnly Cookie Test</title>
+    <meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/>
+</head>
+<body>
+	<div id="cookie-status">Has Cookie: <?php echo json_encode($hasCookie) ?></div>
+</body>
+</html>
diff --git a/vendor/behat/mink/driver-testsuite/web-fixtures/css_mouse_events.html b/vendor/behat/mink/driver-testsuite/web-fixtures/css_mouse_events.html
new file mode 100644
index 00000000000..750ca54ec69
--- /dev/null
+++ b/vendor/behat/mink/driver-testsuite/web-fixtures/css_mouse_events.html
@@ -0,0 +1,36 @@
+<!DOCTYPE html>
+<html lang="en">
+    <head>
+        <title>CSS Mouse Events Testing</title>
+        <style type="text/css">
+            .squares div {
+                width: 100px;
+                height: 100px;
+                border: 1px solid black;
+                margin-right: 4px;
+                float: left;
+            }
+
+            .squares div:hover {
+                height: 200px;
+                background-color: red;
+            }
+        </style>
+
+        <script language="javascript" type="text/javascript" src="js/jquery-1.6.2-min.js"></script>
+    </head>
+
+    <body>
+        <div class="squares">
+            <div id="reset-square">reset</div>
+            <div id="action-square">mouse action</div>
+        </div>
+        <script>
+            $('#action-square').bind('contextmenu', function (e) {
+                // Prevent opening the context menu on right click as the browser might consider the
+                // mouse is in the context menu rather than hovering the element
+                e.preventDefault();
+            });
+        </script>
+    </body>
+</html>
diff --git a/vendor/behat/mink/driver-testsuite/web-fixtures/element_change_detector.html b/vendor/behat/mink/driver-testsuite/web-fixtures/element_change_detector.html
new file mode 100644
index 00000000000..af3032a4610
--- /dev/null
+++ b/vendor/behat/mink/driver-testsuite/web-fixtures/element_change_detector.html
@@ -0,0 +1,65 @@
+<!DOCTYPE html>
+<html>
+<head>
+    <title>ADvanced Form</title>
+    <meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/>
+    <script src="js/jquery-1.6.2-min.js"></script>
+</head>
+<body>
+    <h1>ADvanced Form Page</h1>
+
+    <form method="POST" enctype="multipart/form-data" action="advanced_form_post.php">
+        <input id="the-input-default" value="" />
+        <input type="text" id="the-input-text" value="" />
+        <input type="email" id="the-email" value="" />
+
+        <select id="the-select">
+            <option value="10">ten</option>
+            <option value="20" selected="selected">twenty</option>
+            <option value="30">thirty</option>
+        </select>
+
+        <label>
+            <span><input type="radio" name="sex" id="the-radio-m" value="m" /> m</span>
+            <span><input type="radio" name="sex" id="the-radio-w" value="w" checked="checked" /> w</span>
+        </label>
+
+        <input type="checkbox" id="the-checked-checkbox" value="cb-val" checked/>
+        <input type="checkbox" id="the-unchecked-checkbox" value="cb-val"/>
+
+        <textarea id="the-textarea"></textarea>
+
+        <input type="file" id="the-file" />
+    </form>
+
+    <ul id="results" style="border: 1px solid red;">
+        <li>for easy element location</li>
+    </ul>
+
+    <script type="text/javascript">
+        $(document).ready(function () {
+            var $change_registry = {},
+                $results = $('#results');
+
+            $(':input').change(function ($e) {
+                var $result_id = this.id + '-result';
+
+                if (!$change_registry[this.id]) {
+                    $change_registry[this.id] = 1;
+                    $results.append('<li id="' + $result_id + '"></li>');
+                }
+                else {
+                    $change_registry[this.id]++;
+                }
+
+                $('#' + $result_id).text($change_registry[this.id]);
+            });
+
+            $results.click(function () {
+                $results.empty();
+                $change_registry = {};
+            });
+        });
+    </script>
+</body>
+</html>
diff --git a/vendor/behat/mink/driver-testsuite/web-fixtures/empty_textarea.html b/vendor/behat/mink/driver-testsuite/web-fixtures/empty_textarea.html
new file mode 100644
index 00000000000..f0779ee85e9
--- /dev/null
+++ b/vendor/behat/mink/driver-testsuite/web-fixtures/empty_textarea.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+    <title>Empty textarea submission</title>
+    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+</head>
+<body>
+    <h1>Empty textarea submission</h1>
+    <form method="POST" action="advanced_form_post.php">
+        <textarea name="textarea"></textarea>
+        <input type="submit" name="submit" value="Save" />
+    </form>
+</body>
+</html>
diff --git a/vendor/behat/mink/driver-testsuite/web-fixtures/form_without_button.html b/vendor/behat/mink/driver-testsuite/web-fixtures/form_without_button.html
new file mode 100644
index 00000000000..8063026361c
--- /dev/null
+++ b/vendor/behat/mink/driver-testsuite/web-fixtures/form_without_button.html
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<html>
+<head>
+    <meta charset="UTF-8">
+    <title>Form submission without button test</title>
+</head>
+<body>
+    <form action="basic_form_post.php" method="POST">
+        <input name="first_name" type="text" value="not set">
+        <input name="last_name" type="text" value="not set">
+    </form>
+</body>
+</html>
diff --git a/vendor/behat/mink/driver-testsuite/web-fixtures/headers.php b/vendor/behat/mink/driver-testsuite/web-fixtures/headers.php
new file mode 100644
index 00000000000..25d9b90ec93
--- /dev/null
+++ b/vendor/behat/mink/driver-testsuite/web-fixtures/headers.php
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<html>
+<head>
+    <title>Headers page</title>
+    <meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/>
+</head>
+<body>
+    <?php print_r($_SERVER); ?>
+</body>
+</html>
diff --git a/vendor/behat/mink/driver-testsuite/web-fixtures/html5_form.html b/vendor/behat/mink/driver-testsuite/web-fixtures/html5_form.html
new file mode 100644
index 00000000000..90703531fc9
--- /dev/null
+++ b/vendor/behat/mink/driver-testsuite/web-fixtures/html5_form.html
@@ -0,0 +1,18 @@
+<!DOCTYPE html>
+<html>
+<head>
+    <meta charset="UTF-8">
+    <title>HTML5 form attribute test</title>
+</head>
+<body>
+    <form action="advanced_form_post.php" method="POST" id="test-form">
+        <input name="first_name" type="text" value="not set">
+        <input name="other_field" type="text" value="not submitted" form="another">
+        <input type="submit" value="Submit separate form" form="another">
+        <input type="submit" value="Submit in form">
+    </form>
+    <input name="last_name" type="text" form="test-form" value="not set">
+    <button type="submit" form="test-form" name="submit_button" value="test">Submit outside form</button>
+    <form id="another" method="post" action="advanced_form_post.php"></form>
+</body>
+</html>
diff --git a/vendor/behat/mink/driver-testsuite/web-fixtures/html5_radio.html b/vendor/behat/mink/driver-testsuite/web-fixtures/html5_radio.html
new file mode 100644
index 00000000000..fd54c2dbfaf
--- /dev/null
+++ b/vendor/behat/mink/driver-testsuite/web-fixtures/html5_radio.html
@@ -0,0 +1,16 @@
+<!DOCTYPE html>
+<html>
+<head>
+    <meta charset="UTF-8">
+    <title>HTML5 form attribute test</title>
+</head>
+<body>
+    <form action="advanced_form_post.php" method="POST" id="test-form">
+        <input name="sex" type="radio" value="m" id="sex_m">
+        <input name="sex" type="radio" value="invalid" form="another" id="sex_invalid" checked="checked">
+        <input type="submit" value="Submit in form">
+    </form>
+    <input name="sex" type="radio" form="test-form" value="f" id="sex_f" checked="checked">
+    <form id="another" method="post" action="advanced_form_post.php"></form>
+</body>
+</html>
diff --git a/vendor/behat/mink/driver-testsuite/web-fixtures/html5_types.html b/vendor/behat/mink/driver-testsuite/web-fixtures/html5_types.html
new file mode 100644
index 00000000000..bd46cfa6fff
--- /dev/null
+++ b/vendor/behat/mink/driver-testsuite/web-fixtures/html5_types.html
@@ -0,0 +1,18 @@
+<!DOCTYPE html>
+<html>
+<head>
+    <meta charset="UTF-8">
+    <title>HTML5 form attribute test</title>
+</head>
+<body>
+    <form action="advanced_form_post.php" method="POST">
+        <input name="url" type="url">
+        <input name="email" type="email">
+        <input name="number" type="number">
+        <input name="search" type="search">
+        <input name="color" type="color">
+        <input name="date" type="date">
+        <input type="submit" name="submit_button" value="Submit">
+    </form>
+</body>
+</html>
diff --git a/vendor/behat/mink/driver-testsuite/web-fixtures/html_decoding.html b/vendor/behat/mink/driver-testsuite/web-fixtures/html_decoding.html
new file mode 100644
index 00000000000..341f2269190
--- /dev/null
+++ b/vendor/behat/mink/driver-testsuite/web-fixtures/html_decoding.html
@@ -0,0 +1,17 @@
+<!DOCTYPE html>
+<html>
+<head>
+    <title>HTML Decoding Test</title>
+</head>
+<body>
+    <div>
+        <span custom-attr="&amp;">some text</span>
+
+        <form method="post" action="index.html">
+            <input value="&amp;"/>
+
+            <input type="submit" value="Send"/>
+        </form>
+    </div>
+</body>
+</html>
diff --git a/vendor/behat/mink/driver-testsuite/web-fixtures/iframe.html b/vendor/behat/mink/driver-testsuite/web-fixtures/iframe.html
new file mode 100644
index 00000000000..c54797fa725
--- /dev/null
+++ b/vendor/behat/mink/driver-testsuite/web-fixtures/iframe.html
@@ -0,0 +1,12 @@
+<!DOCTYPE html>
+<html>
+<body>
+
+<iframe src="iframe_inner.html" name="subframe"></iframe>
+
+<div id="text">
+    Main window div text
+</div>
+
+</body>
+</html>
diff --git a/vendor/behat/mink/driver-testsuite/web-fixtures/iframe_inner.html b/vendor/behat/mink/driver-testsuite/web-fixtures/iframe_inner.html
new file mode 100644
index 00000000000..512f058e21e
--- /dev/null
+++ b/vendor/behat/mink/driver-testsuite/web-fixtures/iframe_inner.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<html>
+<body>
+
+    <div id="text">
+        iFrame div text
+    </div>
+
+</body>
+</html>
diff --git a/vendor/behat/mink/driver-testsuite/web-fixtures/index.html b/vendor/behat/mink/driver-testsuite/web-fixtures/index.html
new file mode 100644
index 00000000000..6bb379c1285
--- /dev/null
+++ b/vendor/behat/mink/driver-testsuite/web-fixtures/index.html
@@ -0,0 +1,51 @@
+<!DOCTYPE html>
+<html>
+<head>
+    <title>Index page</title>
+    <meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/>
+</head>
+<body>
+    <h1>Extremely useless page</h1>
+    <div id="core">
+        <strong>Lorem</strong> ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim <strong>veniam</strong>, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla <strong class="super-duper">pariatur</strong>. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
+
+        <div id="some-element" data-href="http://mink.behat.org">
+            some <div>very
+            </div>
+<em>interesting</em>      text
+        </div>
+
+        <div class="attribute-testing">
+            <input type="text" id="attr-elem[with-value]" with-value="some-value"/>
+            <input type="text" id="attr-elem[without-value]" without-value/>
+            <input type="text" id="attr-elem[with-empty-value]" with-empty-value=""/>
+            <input type="text" id="attr-elem[with-missing]"/>
+        </div>
+
+        <div class="travers">
+            <div class="sub">el1</div>
+            <div class="sub">el2</div>
+            <div class="sub">
+                <a href="some_url">some <strong>deep</strong> url</a>
+            </div>
+        </div>
+
+        <div class="sub">el4</div>
+
+    </div>
+
+    <footer>
+        <form id="search-form">
+            <input type="text" placeholder="Search site..." />
+        </form>
+        <form id="profile">
+            <div data-custom="something">
+                <label>
+                    <input type="text" id="user-name" name="username" />
+                </label>
+            </div>
+            <input type="submit" />
+        </form>
+    </footer>
+</body>
+</html>
diff --git a/vendor/behat/mink/driver-testsuite/web-fixtures/issue130.php b/vendor/behat/mink/driver-testsuite/web-fixtures/issue130.php
new file mode 100644
index 00000000000..201d9826ebb
--- /dev/null
+++ b/vendor/behat/mink/driver-testsuite/web-fixtures/issue130.php
@@ -0,0 +1,11 @@
+<!DOCTYPE html>
+<html>
+<body>
+    <?php
+    if ('1' === $_GET['p']) {
+        echo '<a href="issue130.php?p=2">Go to 2</a>';
+    } else {
+        echo '<strong>'.$_SERVER['HTTP_REFERER'].'</strong>';
+    }
+    ?>
+</body>
diff --git a/vendor/behat/mink/driver-testsuite/web-fixtures/issue131.html b/vendor/behat/mink/driver-testsuite/web-fixtures/issue131.html
new file mode 100644
index 00000000000..fa3427a9844
--- /dev/null
+++ b/vendor/behat/mink/driver-testsuite/web-fixtures/issue131.html
@@ -0,0 +1,17 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+    <title>Issue 131</title>
+    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+</head>
+<body>
+    <h1>There is a non breaking&#160;space</h1>
+    <pre id="foobar">Some accentués characters</pre>
+    <form>
+        <select name="foobar">
+          <option value="1">Gimme some accentués characters</option>
+        </select>
+        <input type="submit" />
+    </form>
+</body>
+</html>
diff --git a/vendor/behat/mink/driver-testsuite/web-fixtures/issue140.php b/vendor/behat/mink/driver-testsuite/web-fixtures/issue140.php
new file mode 100644
index 00000000000..04a4cafb726
--- /dev/null
+++ b/vendor/behat/mink/driver-testsuite/web-fixtures/issue140.php
@@ -0,0 +1,16 @@
+<?php
+if (!empty($_POST)) {
+    setcookie("tc", $_POST['cookie_value'], null, '/');
+} elseif (isset($_GET["show_value"])) {
+    echo $_COOKIE["tc"];
+    die();
+}
+?>
+<!DOCTYPE html>
+<html>
+<body>
+    <form method="post">
+        <input name="cookie_value">
+        <input type="submit" value="Set cookie">
+    </form>
+</body>
diff --git a/vendor/behat/mink/driver-testsuite/web-fixtures/issue178.html b/vendor/behat/mink/driver-testsuite/web-fixtures/issue178.html
new file mode 100644
index 00000000000..3efc7432485
--- /dev/null
+++ b/vendor/behat/mink/driver-testsuite/web-fixtures/issue178.html
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<html>
+<head>
+    <meta charset="UTF-8">
+    <title>Index page</title>
+</head>
+<body>
+
+<form action="#">
+	<div>
+		<input type="text" name="source" id="source"
+			onkeyup="document.getElementById('target').innerHTML = this.value" value="bar">
+	</div>
+</form>
+
+<div id="target"></div>
+
+</body>
+</html>
\ No newline at end of file
diff --git a/vendor/behat/mink/driver-testsuite/web-fixtures/issue193.html b/vendor/behat/mink/driver-testsuite/web-fixtures/issue193.html
new file mode 100644
index 00000000000..e722a4303b2
--- /dev/null
+++ b/vendor/behat/mink/driver-testsuite/web-fixtures/issue193.html
@@ -0,0 +1,26 @@
+<!DOCTYPE html>
+<html>
+<head>
+    <title>Index page</title>
+    <meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/>
+</head>
+<body>
+
+<form action="#">
+    <select id="options-without-values" name="without">
+        <option>none selected</option>
+        <option id="one">One</option>
+        <option id="two">Two</option>
+        <option>Three</option>
+    </select>
+
+    <select id="options-with-values" name="with">
+        <option value="none">none selected</option>
+        <option value="one">One</option>
+        <option value="two">Two</option>
+        <option value="three">Three</option>
+    </select>
+</form>
+
+</body>
+</html>
diff --git a/vendor/behat/mink/driver-testsuite/web-fixtures/issue211.html b/vendor/behat/mink/driver-testsuite/web-fixtures/issue211.html
new file mode 100644
index 00000000000..bb977ec2147
--- /dev/null
+++ b/vendor/behat/mink/driver-testsuite/web-fixtures/issue211.html
@@ -0,0 +1,23 @@
+<!DOCTYPE html>
+<html>
+<head>
+    <title>Index page</title>
+    <meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/>
+</head>
+<body>
+
+<form action="#">
+    <p>
+        <label for="phone">Téléphone</label>
+        <input type="text" name="phone" id="phone" />
+    </p>
+    <p>
+        <label for="daphone">DaPhone</label>
+        <input type="text" name="daphone" id="daphone" />
+    </p>
+
+    <input type="submit" value="Send" />
+</form>
+
+</body>
+</html>
diff --git a/vendor/behat/mink/driver-testsuite/web-fixtures/issue212.html b/vendor/behat/mink/driver-testsuite/web-fixtures/issue212.html
new file mode 100644
index 00000000000..24ae62f0667
--- /dev/null
+++ b/vendor/behat/mink/driver-testsuite/web-fixtures/issue212.html
@@ -0,0 +1,9 @@
+<!DOCTYPE html>
+<html>
+<body>
+  <form action="/" method="post" id="user-login-form">
+    <input type="submit" name="toto" id="jaguar-button" value="jaguar"/>
+    <input type="submit" name="toto" id="poney-button" value="poney"/>
+  </form>
+</body>
+</html>
diff --git a/vendor/behat/mink/driver-testsuite/web-fixtures/issue215.html b/vendor/behat/mink/driver-testsuite/web-fixtures/issue215.html
new file mode 100644
index 00000000000..adff3fbba21
--- /dev/null
+++ b/vendor/behat/mink/driver-testsuite/web-fixtures/issue215.html
@@ -0,0 +1,17 @@
+<!DOCTYPE html>
+<html>
+<head>
+    <meta charset="UTF-8">
+    <title>Index page</title>
+</head>
+<body>
+
+<form action="#">
+<textarea rows="10" cols="10" id="textarea">
+foo
+bar
+</textarea>
+</form>
+
+</body>
+</html>
\ No newline at end of file
diff --git a/vendor/behat/mink/driver-testsuite/web-fixtures/issue225.html b/vendor/behat/mink/driver-testsuite/web-fixtures/issue225.html
new file mode 100644
index 00000000000..2178bba9eac
--- /dev/null
+++ b/vendor/behat/mink/driver-testsuite/web-fixtures/issue225.html
@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+<html lang="fr">
+<head>
+    <title>Index page</title>
+    <meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/>
+    <script src="js/jquery-1.6.2-min.js"></script>
+</head>
+<body>
+
+<button id="btn">Créer un compte</button>
+
+<div id="panel"></div>
+
+<script type="text/javascript">
+    $('#btn').click(function (event) {
+        $('#panel').text('OH ' + 'AIH!');
+    });
+</script>
+</body>
+</html>
diff --git a/vendor/behat/mink/driver-testsuite/web-fixtures/issue255.html b/vendor/behat/mink/driver-testsuite/web-fixtures/issue255.html
new file mode 100644
index 00000000000..d56a4279a56
--- /dev/null
+++ b/vendor/behat/mink/driver-testsuite/web-fixtures/issue255.html
@@ -0,0 +1,33 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+    <title>Issue 255</title>
+    <meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/>
+    <script src="js/jquery-1.6.2-min.js"></script>
+</head>
+<body>
+    <form>
+        <label for="foo_select">Foo</label>
+        <select name="foo_select" id="foo_select">
+            <option value="1" selected="selected">Option 1</option>
+            <option value="2">Option 2</option>
+            <option value="3">Option 3</option>
+        </select>
+        <input type="checkbox" id="foo_check" />
+        <input type="submit" />
+        <p id="output_foo_select"></p>
+        <p id="output_foo_check"></p>
+    </form>
+
+    <script type="text/javascript">
+        (function() {
+            $('#foo_select').change(function () {
+                $('#output_foo_select').text("onChangeSelect");
+            });
+            $('#foo_check').change(function () {
+                $('#output_foo_check').text("onChangeCheck");
+            });
+        })();
+    </script>
+</body>
+</html>
diff --git a/vendor/behat/mink/driver-testsuite/web-fixtures/js/jquery-1.6.2-min.js b/vendor/behat/mink/driver-testsuite/web-fixtures/js/jquery-1.6.2-min.js
new file mode 100644
index 00000000000..8cdc80eb85d
--- /dev/null
+++ b/vendor/behat/mink/driver-testsuite/web-fixtures/js/jquery-1.6.2-min.js
@@ -0,0 +1,18 @@
+/*!
+ * jQuery JavaScript Library v1.6.2
+ * http://jquery.com/
+ *
+ * Copyright 2011, John Resig
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * Includes Sizzle.js
+ * http://sizzlejs.com/
+ * Copyright 2011, The Dojo Foundation
+ * Released under the MIT, BSD, and GPL Licenses.
+ *
+ * Date: Thu Jun 30 14:16:56 2011 -0400
+ */
+(function(a,b){function cv(a){return f.isWindow(a)?a:a.nodeType===9?a.defaultView||a.parentWindow:!1}function cs(a){if(!cg[a]){var b=c.body,d=f("<"+a+">").appendTo(b),e=d.css("display");d.remove();if(e==="none"||e===""){ch||(ch=c.createElement("iframe"),ch.frameBorder=ch.width=ch.height=0),b.appendChild(ch);if(!ci||!ch.createElement)ci=(ch.contentWindow||ch.contentDocument).document,ci.write((c.compatMode==="CSS1Compat"?"<!doctype html>":"")+"<html><body>"),ci.close();d=ci.createElement(a),ci.body.appendChild(d),e=f.css(d,"display"),b.removeChild(ch)}cg[a]=e}return cg[a]}function cr(a,b){var c={};f.each(cm.concat.apply([],cm.slice(0,b)),function(){c[this]=a});return c}function cq(){cn=b}function cp(){setTimeout(cq,0);return cn=f.now()}function cf(){try{return new a.ActiveXObject("Microsoft.XMLHTTP")}catch(b){}}function ce(){try{return new a.XMLHttpRequest}catch(b){}}function b$(a,c){a.dataFilter&&(c=a.dataFilter(c,a.dataType));var d=a.dataTypes,e={},g,h,i=d.length,j,k=d[0],l,m,n,o,p;for(g=1;g<i;g++){if(g===1)for(h in a.converters)typeof h=="string"&&(e[h.toLowerCase()]=a.converters[h]);l=k,k=d[g];if(k==="*")k=l;else if(l!=="*"&&l!==k){m=l+" "+k,n=e[m]||e["* "+k];if(!n){p=b;for(o in e){j=o.split(" ");if(j[0]===l||j[0]==="*"){p=e[j[1]+" "+k];if(p){o=e[o],o===!0?n=p:p===!0&&(n=o);break}}}}!n&&!p&&f.error("No conversion from "+m.replace(" "," to ")),n!==!0&&(c=n?n(c):p(o(c)))}}return c}function bZ(a,c,d){var e=a.contents,f=a.dataTypes,g=a.responseFields,h,i,j,k;for(i in g)i in d&&(c[g[i]]=d[i]);while(f[0]==="*")f.shift(),h===b&&(h=a.mimeType||c.getResponseHeader("content-type"));if(h)for(i in e)if(e[i]&&e[i].test(h)){f.unshift(i);break}if(f[0]in d)j=f[0];else{for(i in d){if(!f[0]||a.converters[i+" "+f[0]]){j=i;break}k||(k=i)}j=j||k}if(j){j!==f[0]&&f.unshift(j);return d[j]}}function bY(a,b,c,d){if(f.isArray(b))f.each(b,function(b,e){c||bC.test(a)?d(a,e):bY(a+"["+(typeof e=="object"||f.isArray(e)?b:"")+"]",e,c,d)});else if(!c&&b!=null&&typeof b=="object")for(var e in b)bY(a+"["+e+"]",b[e],c,d);else d(a,b)}function bX(a,c,d,e,f,g){f=f||c.dataTypes[0],g=g||{},g[f]=!0;var h=a[f],i=0,j=h?h.length:0,k=a===bR,l;for(;i<j&&(k||!l);i++)l=h[i](c,d,e),typeof l=="string"&&(!k||g[l]?l=b:(c.dataTypes.unshift(l),l=bX(a,c,d,e,l,g)));(k||!l)&&!g["*"]&&(l=bX(a,c,d,e,"*",g));return l}function bW(a){return function(b,c){typeof b!="string"&&(c=b,b="*");if(f.isFunction(c)){var d=b.toLowerCase().split(bN),e=0,g=d.length,h,i,j;for(;e<g;e++)h=d[e],j=/^\+/.test(h),j&&(h=h.substr(1)||"*"),i=a[h]=a[h]||[],i[j?"unshift":"push"](c)}}}function bA(a,b,c){var d=b==="width"?a.offsetWidth:a.offsetHeight,e=b==="width"?bv:bw;if(d>0){c!=="border"&&f.each(e,function(){c||(d-=parseFloat(f.css(a,"padding"+this))||0),c==="margin"?d+=parseFloat(f.css(a,c+this))||0:d-=parseFloat(f.css(a,"border"+this+"Width"))||0});return d+"px"}d=bx(a,b,b);if(d<0||d==null)d=a.style[b]||0;d=parseFloat(d)||0,c&&f.each(e,function(){d+=parseFloat(f.css(a,"padding"+this))||0,c!=="padding"&&(d+=parseFloat(f.css(a,"border"+this+"Width"))||0),c==="margin"&&(d+=parseFloat(f.css(a,c+this))||0)});return d+"px"}function bm(a,b){b.src?f.ajax({url:b.src,async:!1,dataType:"script"}):f.globalEval((b.text||b.textContent||b.innerHTML||"").replace(be,"/*$0*/")),b.parentNode&&b.parentNode.removeChild(b)}function bl(a){f.nodeName(a,"input")?bk(a):"getElementsByTagName"in a&&f.grep(a.getElementsByTagName("input"),bk)}function bk(a){if(a.type==="checkbox"||a.type==="radio")a.defaultChecked=a.checked}function bj(a){return"getElementsByTagName"in a?a.getElementsByTagName("*"):"querySelectorAll"in a?a.querySelectorAll("*"):[]}function bi(a,b){var c;if(b.nodeType===1){b.clearAttributes&&b.clearAttributes(),b.mergeAttributes&&b.mergeAttributes(a),c=b.nodeName.toLowerCase();if(c==="object")b.outerHTML=a.outerHTML;else if(c!=="input"||a.type!=="checkbox"&&a.type!=="radio"){if(c==="option")b.selected=a.defaultSelected;else if(c==="input"||c==="textarea")b.defaultValue=a.defaultValue}else a.checked&&(b.defaultChecked=b.checked=a.checked),b.value!==a.value&&(b.value=a.value);b.removeAttribute(f.expando)}}function bh(a,b){if(b.nodeType===1&&!!f.hasData(a)){var c=f.expando,d=f.data(a),e=f.data(b,d);if(d=d[c]){var g=d.events;e=e[c]=f.extend({},d);if(g){delete e.handle,e.events={};for(var h in g)for(var i=0,j=g[h].length;i<j;i++)f.event.add(b,h+(g[h][i].namespace?".":"")+g[h][i].namespace,g[h][i],g[h][i].data)}}}}function bg(a,b){return f.nodeName(a,"table")?a.getElementsByTagName("tbody")[0]||a.appendChild(a.ownerDocument.createElement("tbody")):a}function W(a,b,c){b=b||0;if(f.isFunction(b))return f.grep(a,function(a,d){var e=!!b.call(a,d,a);return e===c});if(b.nodeType)return f.grep(a,function(a,d){return a===b===c});if(typeof b=="string"){var d=f.grep(a,function(a){return a.nodeType===1});if(R.test(b))return f.filter(b,d,!c);b=f.filter(b,d)}return f.grep(a,function(a,d){return f.inArray(a,b)>=0===c})}function V(a){return!a||!a.parentNode||a.parentNode.nodeType===11}function N(a,b){return(a&&a!=="*"?a+".":"")+b.replace(z,"`").replace(A,"&")}function M(a){var b,c,d,e,g,h,i,j,k,l,m,n,o,p=[],q=[],r=f._data(this,"events");if(!(a.liveFired===this||!r||!r.live||a.target.disabled||a.button&&a.type==="click")){a.namespace&&(n=new RegExp("(^|\\.)"+a.namespace.split(".").join("\\.(?:.*\\.)?")+"(\\.|$)")),a.liveFired=this;var s=r.live.slice(0);for(i=0;i<s.length;i++)g=s[i],g.origType.replace(x,"")===a.type?q.push(g.selector):s.splice(i--,1);e=f(a.target).closest(q,a.currentTarget);for(j=0,k=e.length;j<k;j++){m=e[j];for(i=0;i<s.length;i++){g=s[i];if(m.selector===g.selector&&(!n||n.test(g.namespace))&&!m.elem.disabled){h=m.elem,d=null;if(g.preType==="mouseenter"||g.preType==="mouseleave")a.type=g.preType,d=f(a.relatedTarget).closest(g.selector)[0],d&&f.contains(h,d)&&(d=h);(!d||d!==h)&&p.push({elem:h,handleObj:g,level:m.level})}}}for(j=0,k=p.length;j<k;j++){e=p[j];if(c&&e.level>c)break;a.currentTarget=e.elem,a.data=e.handleObj.data,a.handleObj=e.handleObj,o=e.handleObj.origHandler.apply(e.elem,arguments);if(o===!1||a.isPropagationStopped()){c=e.level,o===!1&&(b=!1);if(a.isImmediatePropagationStopped())break}}return b}}function K(a,c,d){var e=f.extend({},d[0]);e.type=a,e.originalEvent={},e.liveFired=b,f.event.handle.call(c,e),e.isDefaultPrevented()&&d[0].preventDefault()}function E(){return!0}function D(){return!1}function m(a,c,d){var e=c+"defer",g=c+"queue",h=c+"mark",i=f.data(a,e,b,!0);i&&(d==="queue"||!f.data(a,g,b,!0))&&(d==="mark"||!f.data(a,h,b,!0))&&setTimeout(function(){!f.data(a,g,b,!0)&&!f.data(a,h,b,!0)&&(f.removeData(a,e,!0),i.resolve())},0)}function l(a){for(var b in a)if(b!=="toJSON")return!1;return!0}function k(a,c,d){if(d===b&&a.nodeType===1){var e="data-"+c.replace(j,"$1-$2").toLowerCase();d=a.getAttribute(e);if(typeof d=="string"){try{d=d==="true"?!0:d==="false"?!1:d==="null"?null:f.isNaN(d)?i.test(d)?f.parseJSON(d):d:parseFloat(d)}catch(g){}f.data(a,c,d)}else d=b}return d}var c=a.document,d=a.navigator,e=a.location,f=function(){function J(){if(!e.isReady){try{c.documentElement.doScroll("left")}catch(a){setTimeout(J,1);return}e.ready()}}var e=function(a,b){return new e.fn.init(a,b,h)},f=a.jQuery,g=a.$,h,i=/^(?:[^<]*(<[\w\W]+>)[^>]*$|#([\w\-]*)$)/,j=/\S/,k=/^\s+/,l=/\s+$/,m=/\d/,n=/^<(\w+)\s*\/?>(?:<\/\1>)?$/,o=/^[\],:{}\s]*$/,p=/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,q=/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,r=/(?:^|:|,)(?:\s*\[)+/g,s=/(webkit)[ \/]([\w.]+)/,t=/(opera)(?:.*version)?[ \/]([\w.]+)/,u=/(msie) ([\w.]+)/,v=/(mozilla)(?:.*? rv:([\w.]+))?/,w=/-([a-z])/ig,x=function(a,b){return b.toUpperCase()},y=d.userAgent,z,A,B,C=Object.prototype.toString,D=Object.prototype.hasOwnProperty,E=Array.prototype.push,F=Array.prototype.slice,G=String.prototype.trim,H=Array.prototype.indexOf,I={};e.fn=e.prototype={constructor:e,init:function(a,d,f){var g,h,j,k;if(!a)return this;if(a.nodeType){this.context=this[0]=a,this.length=1;return this}if(a==="body"&&!d&&c.body){this.context=c,this[0]=c.body,this.selector=a,this.length=1;return this}if(typeof a=="string"){a.charAt(0)!=="<"||a.charAt(a.length-1)!==">"||a.length<3?g=i.exec(a):g=[null,a,null];if(g&&(g[1]||!d)){if(g[1]){d=d instanceof e?d[0]:d,k=d?d.ownerDocument||d:c,j=n.exec(a),j?e.isPlainObject(d)?(a=[c.createElement(j[1])],e.fn.attr.call(a,d,!0)):a=[k.createElement(j[1])]:(j=e.buildFragment([g[1]],[k]),a=(j.cacheable?e.clone(j.fragment):j.fragment).childNodes);return e.merge(this,a)}h=c.getElementById(g[2]);if(h&&h.parentNode){if(h.id!==g[2])return f.find(a);this.length=1,this[0]=h}this.context=c,this.selector=a;return this}return!d||d.jquery?(d||f).find(a):this.constructor(d).find(a)}if(e.isFunction(a))return f.ready(a);a.selector!==b&&(this.selector=a.selector,this.context=a.context);return e.makeArray(a,this)},selector:"",jquery:"1.6.2",length:0,size:function(){return this.length},toArray:function(){return F.call(this,0)},get:function(a){return a==null?this.toArray():a<0?this[this.length+a]:this[a]},pushStack:function(a,b,c){var d=this.constructor();e.isArray(a)?E.apply(d,a):e.merge(d,a),d.prevObject=this,d.context=this.context,b==="find"?d.selector=this.selector+(this.selector?" ":"")+c:b&&(d.selector=this.selector+"."+b+"("+c+")");return d},each:function(a,b){return e.each(this,a,b)},ready:function(a){e.bindReady(),A.done(a);return this},eq:function(a){return a===-1?this.slice(a):this.slice(a,+a+1)},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},slice:function(){return this.pushStack(F.apply(this,arguments),"slice",F.call(arguments).join(","))},map:function(a){return this.pushStack(e.map(this,function(b,c){return a.call(b,c,b)}))},end:function(){return this.prevObject||this.constructor(null)},push:E,sort:[].sort,splice:[].splice},e.fn.init.prototype=e.fn,e.extend=e.fn.extend=function(){var a,c,d,f,g,h,i=arguments[0]||{},j=1,k=arguments.length,l=!1;typeof i=="boolean"&&(l=i,i=arguments[1]||{},j=2),typeof i!="object"&&!e.isFunction(i)&&(i={}),k===j&&(i=this,--j);for(;j<k;j++)if((a=arguments[j])!=null)for(c in a){d=i[c],f=a[c];if(i===f)continue;l&&f&&(e.isPlainObject(f)||(g=e.isArray(f)))?(g?(g=!1,h=d&&e.isArray(d)?d:[]):h=d&&e.isPlainObject(d)?d:{},i[c]=e.extend(l,h,f)):f!==b&&(i[c]=f)}return i},e.extend({noConflict:function(b){a.$===e&&(a.$=g),b&&a.jQuery===e&&(a.jQuery=f);return e},isReady:!1,readyWait:1,holdReady:function(a){a?e.readyWait++:e.ready(!0)},ready:function(a){if(a===!0&&!--e.readyWait||a!==!0&&!e.isReady){if(!c.body)return setTimeout(e.ready,1);e.isReady=!0;if(a!==!0&&--e.readyWait>0)return;A.resolveWith(c,[e]),e.fn.trigger&&e(c).trigger("ready").unbind("ready")}},bindReady:function(){if(!A){A=e._Deferred();if(c.readyState==="complete")return setTimeout(e.ready,1);if(c.addEventListener)c.addEventListener("DOMContentLoaded",B,!1),a.addEventListener("load",e.ready,!1);else if(c.attachEvent){c.attachEvent("onreadystatechange",B),a.attachEvent("onload",e.ready);var b=!1;try{b=a.frameElement==null}catch(d){}c.documentElement.doScroll&&b&&J()}}},isFunction:function(a){return e.type(a)==="function"},isArray:Array.isArray||function(a){return e.type(a)==="array"},isWindow:function(a){return a&&typeof a=="object"&&"setInterval"in a},isNaN:function(a){return a==null||!m.test(a)||isNaN(a)},type:function(a){return a==null?String(a):I[C.call(a)]||"object"},isPlainObject:function(a){if(!a||e.type(a)!=="object"||a.nodeType||e.isWindow(a))return!1;if(a.constructor&&!D.call(a,"constructor")&&!D.call(a.constructor.prototype,"isPrototypeOf"))return!1;var c;for(c in a);return c===b||D.call(a,c)},isEmptyObject:function(a){for(var b in a)return!1;return!0},error:function(a){throw a},parseJSON:function(b){if(typeof b!="string"||!b)return null;b=e.trim(b);if(a.JSON&&a.JSON.parse)return a.JSON.parse(b);if(o.test(b.replace(p,"@").replace(q,"]").replace(r,"")))return(new Function("return "+b))();e.error("Invalid JSON: "+b)},parseXML:function(b,c,d){a.DOMParser?(d=new DOMParser,c=d.parseFromString(b,"text/xml")):(c=new ActiveXObject("Microsoft.XMLDOM"),c.async="false",c.loadXML(b)),d=c.documentElement,(!d||!d.nodeName||d.nodeName==="parsererror")&&e.error("Invalid XML: "+b);return c},noop:function(){},globalEval:function(b){b&&j.test(b)&&(a.execScript||function(b){a.eval.call(a,b)})(b)},camelCase:function(a){return a.replace(w,x)},nodeName:function(a,b){return a.nodeName&&a.nodeName.toUpperCase()===b.toUpperCase()},each:function(a,c,d){var f,g=0,h=a.length,i=h===b||e.isFunction(a);if(d){if(i){for(f in a)if(c.apply(a[f],d)===!1)break}else for(;g<h;)if(c.apply(a[g++],d)===!1)break}else if(i){for(f in a)if(c.call(a[f],f,a[f])===!1)break}else for(;g<h;)if(c.call(a[g],g,a[g++])===!1)break;return a},trim:G?function(a){return a==null?"":G.call(a)}:function(a){return a==null?"":(a+"").replace(k,"").replace(l,"")},makeArray:function(a,b){var c=b||[];if(a!=null){var d=e.type(a);a.length==null||d==="string"||d==="function"||d==="regexp"||e.isWindow(a)?E.call(c,a):e.merge(c,a)}return c},inArray:function(a,b){if(H)return H.call(b,a);for(var c=0,d=b.length;c<d;c++)if(b[c]===a)return c;return-1},merge:function(a,c){var d=a.length,e=0;if(typeof c.length=="number")for(var f=c.length;e<f;e++)a[d++]=c[e];else while(c[e]!==b)a[d++]=c[e++];a.length=d;return a},grep:function(a,b,c){var d=[],e;c=!!c;for(var f=0,g=a.length;f<g;f++)e=!!b(a[f],f),c!==e&&d.push(a[f]);return d},map:function(a,c,d){var f,g,h=[],i=0,j=a.length,k=a instanceof e||j!==b&&typeof j=="number"&&(j>0&&a[0]&&a[j-1]||j===0||e.isArray(a));if(k)for(;i<j;i++)f=c(a[i],i,d),f!=null&&(h[h.length]=f);else for(g in a)f=c(a[g],g,d),f!=null&&(h[h.length]=f);return h.concat.apply([],h)},guid:1,proxy:function(a,c){if(typeof c=="string"){var d=a[c];c=a,a=d}if(!e.isFunction(a))return b;var f=F.call(arguments,2),g=function(){return a.apply(c,f.concat(F.call(arguments)))};g.guid=a.guid=a.guid||g.guid||e.guid++;return g},access:function(a,c,d,f,g,h){var i=a.length;if(typeof c=="object"){for(var j in c)e.access(a,j,c[j],f,g,d);return a}if(d!==b){f=!h&&f&&e.isFunction(d);for(var k=0;k<i;k++)g(a[k],c,f?d.call(a[k],k,g(a[k],c)):d,h);return a}return i?g(a[0],c):b},now:function(){return(new Date).getTime()},uaMatch:function(a){a=a.toLowerCase();var b=s.exec(a)||t.exec(a)||u.exec(a)||a.indexOf("compatible")<0&&v.exec(a)||[];return{browser:b[1]||"",version:b[2]||"0"}},sub:function(){function a(b,c){return new a.fn.init(b,c)}e.extend(!0,a,this),a.superclass=this,a.fn=a.prototype=this(),a.fn.constructor=a,a.sub=this.sub,a.fn.init=function(d,f){f&&f instanceof e&&!(f instanceof a)&&(f=a(f));return e.fn.init.call(this,d,f,b)},a.fn.init.prototype=a.fn;var b=a(c);return a},browser:{}}),e.each("Boolean Number String Function Array Date RegExp Object".split(" "),function(a,b){I["[object "+b+"]"]=b.toLowerCase()}),z=e.uaMatch(y),z.browser&&(e.browser[z.browser]=!0,e.browser.version=z.version),e.browser.webkit&&(e.browser.safari=!0),j.test(" ")&&(k=/^[\s\xA0]+/,l=/[\s\xA0]+$/),h=e(c),c.addEventListener?B=function(){c.removeEventListener("DOMContentLoaded",B,!1),e.ready()}:c.attachEvent&&(B=function(){c.readyState==="complete"&&(c.detachEvent("onreadystatechange",B),e.ready())});return e}(),g="done fail isResolved isRejected promise then always pipe".split(" "),h=[].slice;f.extend({_Deferred:function(){var a=[],b,c,d,e={done:function(){if(!d){var c=arguments,g,h,i,j,k;b&&(k=b,b=0);for(g=0,h=c.length;g<h;g++)i=c[g],j=f.type(i),j==="array"?e.done.apply(e,i):j==="function"&&a.push(i);k&&e.resolveWith(k[0],k[1])}return this},resolveWith:function(e,f){if(!d&&!b&&!c){f=f||[],c=1;try{while(a[0])a.shift().apply(e,f)}finally{b=[e,f],c=0}}return this},resolve:function(){e.resolveWith(this,arguments);return this},isResolved:function(){return!!c||!!b},cancel:function(){d=1,a=[];return this}};return e},Deferred:function(a){var b=f._Deferred(),c=f._Deferred(),d;f.extend(b,{then:function(a,c){b.done(a).fail(c);return this},always:function(){return b.done.apply(b,arguments).fail.apply(this,arguments)},fail:c.done,rejectWith:c.resolveWith,reject:c.resolve,isRejected:c.isResolved,pipe:function(a,c){return f.Deferred(function(d){f.each({done:[a,"resolve"],fail:[c,"reject"]},function(a,c){var e=c[0],g=c[1],h;f.isFunction(e)?b[a](function(){h=e.apply(this,arguments),h&&f.isFunction(h.promise)?h.promise().then(d.resolve,d.reject):d[g](h)}):b[a](d[g])})}).promise()},promise:function(a){if(a==null){if(d)return d;d=a={}}var c=g.length;while(c--)a[g[c]]=b[g[c]];return a}}),b.done(c.cancel).fail(b.cancel),delete b.cancel,a&&a.call(b,b);return b},when:function(a){function i(a){return function(c){b[a]=arguments.length>1?h.call(arguments,0):c,--e||g.resolveWith(g,h.call(b,0))}}var b=arguments,c=0,d=b.length,e=d,g=d<=1&&a&&f.isFunction(a.promise)?a:f.Deferred();if(d>1){for(;c<d;c++)b[c]&&f.isFunction(b[c].promise)?b[c].promise().then(i(c),g.reject):--e;e||g.resolveWith(g,b)}else g!==a&&g.resolveWith(g,d?[a]:[]);return g.promise()}}),f.support=function(){var a=c.createElement("div"),b=c.documentElement,d,e,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u;a.setAttribute("className","t"),a.innerHTML="   <link/><table></table><a href='/a' style='top:1px;float:left;opacity:.55;'>a</a><input type='checkbox'/>",d=a.getElementsByTagName("*"),e=a.getElementsByTagName("a")[0];if(!d||!d.length||!e)return{};g=c.createElement("select"),h=g.appendChild(c.createElement("option")),i=a.getElementsByTagName("input")[0],k={leadingWhitespace:a.firstChild.nodeType===3,tbody:!a.getElementsByTagName("tbody").length,htmlSerialize:!!a.getElementsByTagName("link").length,style:/top/.test(e.getAttribute("style")),hrefNormalized:e.getAttribute("href")==="/a",opacity:/^0.55$/.test(e.style.opacity),cssFloat:!!e.style.cssFloat,checkOn:i.value==="on",optSelected:h.selected,getSetAttribute:a.className!=="t",submitBubbles:!0,changeBubbles:!0,focusinBubbles:!1,deleteExpando:!0,noCloneEvent:!0,inlineBlockNeedsLayout:!1,shrinkWrapBlocks:!1,reliableMarginRight:!0},i.checked=!0,k.noCloneChecked=i.cloneNode(!0).checked,g.disabled=!0,k.optDisabled=!h.disabled;try{delete a.test}catch(v){k.deleteExpando=!1}!a.addEventListener&&a.attachEvent&&a.fireEvent&&(a.attachEvent("onclick",function(){k.noCloneEvent=!1}),a.cloneNode(!0).fireEvent("onclick")),i=c.createElement("input"),i.value="t",i.setAttribute("type","radio"),k.radioValue=i.value==="t",i.setAttribute("checked","checked"),a.appendChild(i),l=c.createDocumentFragment(),l.appendChild(a.firstChild),k.checkClone=l.cloneNode(!0).cloneNode(!0).lastChild.checked,a.innerHTML="",a.style.width=a.style.paddingLeft="1px",m=c.getElementsByTagName("body")[0],o=c.createElement(m?"div":"body"),p={visibility:"hidden",width:0,height:0,border:0,margin:0},m&&f.extend(p,{position:"absolute",left:-1e3,top:-1e3});for(t in p)o.style[t]=p[t];o.appendChild(a),n=m||b,n.insertBefore(o,n.firstChild),k.appendChecked=i.checked,k.boxModel=a.offsetWidth===2,"zoom"in a.style&&(a.style.display="inline",a.style.zoom=1,k.inlineBlockNeedsLayout=a.offsetWidth===2,a.style.display="",a.innerHTML="<div style='width:4px;'></div>",k.shrinkWrapBlocks=a.offsetWidth!==2),a.innerHTML="<table><tr><td style='padding:0;border:0;display:none'></td><td>t</td></tr></table>",q=a.getElementsByTagName("td"),u=q[0].offsetHeight===0,q[0].style.display="",q[1].style.display="none",k.reliableHiddenOffsets=u&&q[0].offsetHeight===0,a.innerHTML="",c.defaultView&&c.defaultView.getComputedStyle&&(j=c.createElement("div"),j.style.width="0",j.style.marginRight="0",a.appendChild(j),k.reliableMarginRight=(parseInt((c.defaultView.getComputedStyle(j,null)||{marginRight:0}).marginRight,10)||0)===0),o.innerHTML="",n.removeChild(o);if(a.attachEvent)for(t in{submit:1,change:1,focusin:1})s="on"+t,u=s in a,u||(a.setAttribute(s,"return;"),u=typeof a[s]=="function"),k[t+"Bubbles"]=u;o=l=g=h=m=j=a=i=null;return k}(),f.boxModel=f.support.boxModel;var i=/^(?:\{.*\}|\[.*\])$/,j=/([a-z])([A-Z])/g;f.extend({cache:{},uuid:0,expando:"jQuery"+(f.fn.jquery+Math.random()).replace(/\D/g,""),noData:{embed:!0,object:"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000",applet:!0},hasData:function(a){a=a.nodeType?f.cache[a[f.expando]]:a[f.expando];return!!a&&!l(a)},data:function(a,c,d,e){if(!!f.acceptData(a)){var g=f.expando,h=typeof c=="string",i,j=a.nodeType,k=j?f.cache:a,l=j?a[f.expando]:a[f.expando]&&f.expando;if((!l||e&&l&&!k[l][g])&&h&&d===b)return;l||(j?a[f.expando]=l=++f.uuid:l=f.expando),k[l]||(k[l]={},j||(k[l].toJSON=f.noop));if(typeof c=="object"||typeof c=="function")e?k[l][g]=f.extend(k[l][g],c):k[l]=f.extend(k[l],c);i=k[l],e&&(i[g]||(i[g]={}),i=i[g]),d!==b&&(i[f.camelCase(c)]=d);if(c==="events"&&!i[c])return i[g]&&i[g].events;return h?i[f.camelCase(c)]||i[c]:i}},removeData:function(b,c,d){if(!!f.acceptData(b)){var e=f.expando,g=b.nodeType,h=g?f.cache:b,i=g?b[f.expando]:f.expando;if(!h[i])return;if(c){var j=d?h[i][e]:h[i];if(j){delete j[c];if(!l(j))return}}if(d){delete h[i][e];if(!l(h[i]))return}var k=h[i][e];f.support.deleteExpando||h!=a?delete h[i]:h[i]=null,k?(h[i]={},g||(h[i].toJSON=f.noop),h[i][e]=k):g&&(f.support.deleteExpando?delete b[f.expando]:b.removeAttribute?b.removeAttribute(f.expando):b[f.expando]=null)}},_data:function(a,b,c){return f.data(a,b,c,!0)},acceptData:function(a){if(a.nodeName){var b=f.noData[a.nodeName.toLowerCase()];if(b)return b!==!0&&a.getAttribute("classid")===b}return!0}}),f.fn.extend({data:function(a,c){var d=null;if(typeof a=="undefined"){if(this.length){d=f.data(this[0]);if(this[0].nodeType===1){var e=this[0].attributes,g;for(var h=0,i=e.length;h<i;h++)g=e[h].name,g.indexOf("data-")===0&&(g=f.camelCase(g.substring(5)),k(this[0],g,d[g]))}}return d}if(typeof a=="object")return this.each(function(){f.data(this,a)});var j=a.split(".");j[1]=j[1]?"."+j[1]:"";if(c===b){d=this.triggerHandler("getData"+j[1]+"!",[j[0]]),d===b&&this.length&&(d=f.data(this[0],a),d=k(this[0],a,d));return d===b&&j[1]?this.data(j[0]):d}return this.each(function(){var b=f(this),d=[j[0],c];b.triggerHandler("setData"+j[1]+"!",d),f.data(this,a,c),b.triggerHandler("changeData"+j[1]+"!",d)})},removeData:function(a){return this.each(function(){f.removeData(this,a)})}}),f.extend({_mark:function(a,c){a&&(c=(c||"fx")+"mark",f.data(a,c,(f.data(a,c,b,!0)||0)+1,!0))},_unmark:function(a,c,d){a!==!0&&(d=c,c=a,a=!1);if(c){d=d||"fx";var e=d+"mark",g=a?0:(f.data(c,e,b,!0)||1)-1;g?f.data(c,e,g,!0):(f.removeData(c,e,!0),m(c,d,"mark"))}},queue:function(a,c,d){if(a){c=(c||"fx")+"queue";var e=f.data(a,c,b,!0);d&&(!e||f.isArray(d)?e=f.data(a,c,f.makeArray(d),!0):e.push(d));return e||[]}},dequeue:function(a,b){b=b||"fx";var c=f.queue(a,b),d=c.shift(),e;d==="inprogress"&&(d=c.shift()),d&&(b==="fx"&&c.unshift("inprogress"),d.call(a,function(){f.dequeue(a,b)})),c.length||(f.removeData(a,b+"queue",!0),m(a,b,"queue"))}}),f.fn.extend({queue:function(a,c){typeof a!="string"&&(c=a,a="fx");if(c===b)return f.queue(this[0],a);return this.each(function(){var b=f.queue(this,a,c);a==="fx"&&b[0]!=="inprogress"&&f.dequeue(this,a)})},dequeue:function(a){return this.each(function(){f.dequeue(this,a)})},delay:function(a,b){a=f.fx?f.fx.speeds[a]||a:a,b=b||"fx";return this.queue(b,function(){var c=this;setTimeout(function(){f.dequeue(c,b)},a)})},clearQueue:function(a){return this.queue(a||"fx",[])},promise:function(a,c){function m(){--h||d.resolveWith(e,[e])}typeof a!="string"&&(c=a,a=b),a=a||"fx";var d=f.Deferred(),e=this,g=e.length,h=1,i=a+"defer",j=a+"queue",k=a+"mark",l;while(g--)if(l=f.data(e[g],i,b,!0)||(f.data(e[g],j,b,!0)||f.data(e[g],k,b,!0))&&f.data(e[g],i,f._Deferred(),!0))h++,l.done(m);m();return d.promise()}});var n=/[\n\t\r]/g,o=/\s+/,p=/\r/g,q=/^(?:button|input)$/i,r=/^(?:button|input|object|select|textarea)$/i,s=/^a(?:rea)?$/i,t=/^(?:autofocus|autoplay|async|checked|controls|defer|disabled|hidden|loop|multiple|open|readonly|required|scoped|selected)$/i,u=/\:|^on/,v,w;f.fn.extend({attr:function(a,b){return f.access(this,a,b,!0,f.attr)},removeAttr:function(a){return this.each(function(){f.removeAttr(this,a)})},prop:function(a,b){return f.access(this,a,b,!0,f.prop)},removeProp:function(a){a=f.propFix[a]||a;return this.each(function(){try{this[a]=b,delete this[a]}catch(c){}})},addClass:function(a){var b,c,d,e,g,h,i;if(f.isFunction(a))return this.each(function(b){f(this).addClass(a.call(this,b,this.className))});if(a&&typeof a=="string"){b=a.split(o);for(c=0,d=this.length;c<d;c++){e=this[c];if(e.nodeType===1)if(!e.className&&b.length===1)e.className=a;else{g=" "+e.className+" ";for(h=0,i=b.length;h<i;h++)~g.indexOf(" "+b[h]+" ")||(g+=b[h]+" ");e.className=f.trim(g)}}}return this},removeClass:function(a){var c,d,e,g,h,i,j;if(f.isFunction(a))return this.each(function(b){f(this).removeClass(a.call(this,b,this.className))});if(a&&typeof a=="string"||a===b){c=(a||"").split(o);for(d=0,e=this.length;d<e;d++){g=this[d];if(g.nodeType===1&&g.className)if(a){h=(" "+g.className+" ").replace(n," ");for(i=0,j=c.length;i<j;i++)h=h.replace(" "+c[i]+" "," ");g.className=f.trim(h)}else g.className=""}}return this},toggleClass:function(a,b){var c=typeof a,d=typeof b=="boolean";if(f.isFunction(a))return this.each(function(c){f(this).toggleClass(a.call(this,c,this.className,b),b)});return this.each(function(){if(c==="string"){var e,g=0,h=f(this),i=b,j=a.split(o);while(e=j[g++])i=d?i:!h.hasClass(e),h[i?"addClass":"removeClass"](e)}else if(c==="undefined"||c==="boolean")this.className&&f._data(this,"__className__",this.className),this.className=this.className||a===!1?"":f._data(this,"__className__")||""})},hasClass:function(a){var b=" "+a+" ";for(var c=0,d=this.length;c<d;c++)if((" "+this[c].className+" ").replace(n," ").indexOf(b)>-1)return!0;return!1},val:function(a){var c,d,e=this[0];if(!arguments.length){if(e){c=f.valHooks[e.nodeName.toLowerCase()]||f.valHooks[e.type];if(c&&"get"in c&&(d=c.get(e,"value"))!==b)return d;d=e.value;return typeof d=="string"?d.replace(p,""):d==null?"":d}return b}var g=f.isFunction(a);return this.each(function(d){var e=f(this),h;if(this.nodeType===1){g?h=a.call(this,d,e.val()):h=a,h==null?h="":typeof h=="number"?h+="":f.isArray(h)&&(h=f.map(h,function(a){return a==null?"":a+""})),c=f.valHooks[this.nodeName.toLowerCase()]||f.valHooks[this.type];if(!c||!("set"in c)||c.set(this,h,"value")===b)this.value=h}})}}),f.extend({valHooks:{option:{get:function(a){var b=a.attributes.value;return!b||b.specified?a.value:a.text}},select:{get:function(a){var b,c=a.selectedIndex,d=[],e=a.options,g=a.type==="select-one";if(c<0)return null;for(var h=g?c:0,i=g?c+1:e.length;h<i;h++){var j=e[h];if(j.selected&&(f.support.optDisabled?!j.disabled:j.getAttribute("disabled")===null)&&(!j.parentNode.disabled||!f.nodeName(j.parentNode,"optgroup"))){b=f(j).val();if(g)return b;d.push(b)}}if(g&&!d.length&&e.length)return f(e[c]).val();return d},set:function(a,b){var c=f.makeArray(b);f(a).find("option").each(function(){this.selected=f.inArray(f(this).val(),c)>=0}),c.length||(a.selectedIndex=-1);return c}}},attrFn:{val:!0,css:!0,html:!0,text:!0,data:!0,width:!0,height:!0,offset:!0},attrFix:{tabindex:"tabIndex"},attr:function(a,c,d,e){var g=a.nodeType;if(!a||g===3||g===8||g===2)return b;if(e&&c in f.attrFn)return f(a)[c](d);if(!("getAttribute"in a))return f.prop(a,c,d);var h,i,j=g!==1||!f.isXMLDoc(a);j&&(c=f.attrFix[c]||c,i=f.attrHooks[c],i||(t.test(c)?i=w:v&&c!=="className"&&(f.nodeName(a,"form")||u.test(c))&&(i=v)));if(d!==b){if(d===null){f.removeAttr(a,c);return b}if(i&&"set"in i&&j&&(h=i.set(a,d,c))!==b)return h;a.setAttribute(c,""+d);return d}if(i&&"get"in i&&j&&(h=i.get(a,c))!==null)return h;h=a.getAttribute(c);return h===null?b:h},removeAttr:function(a,b){var c;a.nodeType===1&&(b=f.attrFix[b]||b,f.support.getSetAttribute?a.removeAttribute(b):(f.attr(a,b,""),a.removeAttributeNode(a.getAttributeNode(b))),t.test(b)&&(c=f.propFix[b]||b)in a&&(a[c]=!1))},attrHooks:{type:{set:function(a,b){if(q.test(a.nodeName)&&a.parentNode)f.error("type property can't be changed");else if(!f.support.radioValue&&b==="radio"&&f.nodeName(a,"input")){var c=a.value;a.setAttribute("type",b),c&&(a.value=c);return b}}},tabIndex:{get:function(a){var c=a.getAttributeNode("tabIndex");return c&&c.specified?parseInt(c.value,10):r.test(a.nodeName)||s.test(a.nodeName)&&a.href?0:b}},value:{get:function(a,b){if(v&&f.nodeName(a,"button"))return v.get(a,b);return b in a?a.value:null},set:function(a,b,c){if(v&&f.nodeName(a,"button"))return v.set(a,b,c);a.value=b}}},propFix:{tabindex:"tabIndex",readonly:"readOnly","for":"htmlFor","class":"className",maxlength:"maxLength",cellspacing:"cellSpacing",cellpadding:"cellPadding",rowspan:"rowSpan",colspan:"colSpan",usemap:"useMap",frameborder:"frameBorder",contenteditable:"contentEditable"},prop:function(a,c,d){var e=a.nodeType;if(!a||e===3||e===8||e===2)return b;var g,h,i=e!==1||!f.isXMLDoc(a);i&&(c=f.propFix[c]||c,h=f.propHooks[c]);return d!==b?h&&"set"in h&&(g=h.set(a,d,c))!==b?g:a[c]=d:h&&"get"in h&&(g=h.get(a,c))!==b?g:a[c]},propHooks:{}}),w={get:function(a,c){return f.prop(a,c)?c.toLowerCase():b},set:function(a,b,c){var d;b===!1?f.removeAttr(a,c):(d=f.propFix[c]||c,d in a&&(a[d]=!0),a.setAttribute(c,c.toLowerCase()));return c}},f.support.getSetAttribute||(f.attrFix=f.propFix,v=f.attrHooks.name=f.attrHooks.title=f.valHooks.button={get:function(a,c){var d;d=a.getAttributeNode(c);return d&&d.nodeValue!==""?d.nodeValue:b},set:function(a,b,c){var d=a.getAttributeNode(c);if(d){d.nodeValue=b;return b}}},f.each(["width","height"],function(a,b){f.attrHooks[b]=f.extend(f.attrHooks[b],{set:function(a,c){if(c===""){a.setAttribute(b,"auto");return c}}})})),f.support.hrefNormalized||f.each(["href","src","width","height"],function(a,c){f.attrHooks[c]=f.extend(f.attrHooks[c],{get:function(a){var d=a.getAttribute(c,2);return d===null?b:d}})}),f.support.style||(f.attrHooks.style={get:function(a){return a.style.cssText.toLowerCase()||b},set:function(a,b){return a.style.cssText=""+b}}),f.support.optSelected||(f.propHooks.selected=f.extend(f.propHooks.selected,{get:function(a){var b=a.parentNode;b&&(b.selectedIndex,b.parentNode&&b.parentNode.selectedIndex)}})),f.support.checkOn||f.each(["radio","checkbox"],function(){f.valHooks[this]={get:function(a){return a.getAttribute("value")===null?"on":a.value}}}),f.each(["radio","checkbox"],function(){f.valHooks[this]=f.extend(f.valHooks[this],{set:function(a,b){if(f.isArray(b))return a.checked=f.inArray(f(a).val(),b)>=0}})});var x=/\.(.*)$/,y=/^(?:textarea|input|select)$/i,z=/\./g,A=/ /g,B=/[^\w\s.|`]/g,C=function(a){return a.replace(B,"\\$&")};f.event={add:function(a,c,d,e){if(a.nodeType!==3&&a.nodeType!==8){if(d===!1)d=D;else if(!d)return;var g,h;d.handler&&(g=d,d=g.handler),d.guid||(d.guid=f.guid++);var i=f._data(a);if(!i)return;var j=i.events,k=i.handle;j||(i.events=j={}),k||(i.handle=k=function(a){return typeof f!="undefined"&&(!a||f.event.triggered!==a.type)?f.event.handle.apply(k.elem,arguments):b}),k.elem=a,c=c.split(" ");var l,m=0,n;while(l=c[m++]){h=g?f.extend({},g):{handler:d,data:e},l.indexOf(".")>-1?(n=l.split("."),l=n.shift(),h.namespace=n.slice(0).sort().join(".")):(n=[],h.namespace=""),h.type=l,h.guid||(h.guid=d.guid);var o=j[l],p=f.event.special[l]||{};if(!o){o=j[l]=[];if(!p.setup||p.setup.call(a,e,n,k)===!1)a.addEventListener?a.addEventListener(l,k,!1):a.attachEvent&&a.attachEvent("on"+l,k)}p.add&&(p.add.call(a,h),h.handler.guid||(h.handler.guid=d.guid)),o.push(h),f.event.global[l]=!0}a=null}},global:{},remove:function(a,c,d,e){if(a.nodeType!==3&&a.nodeType!==8){d===!1&&(d=D);var g,h,i,j,k=0,l,m,n,o,p,q,r,s=f.hasData(a)&&f._data(a),t=s&&s.events;if(!s||!t)return;c&&c.type&&(d=c.handler,c=c.type);if(!c||typeof c=="string"&&c.charAt(0)==="."){c=c||"";for(h in t)f.event.remove(a,h+c);return}c=c.split(" ");while(h=c[k++]){r=h,q=null,l=h.indexOf(".")<0,m=[],l||(m=h.split("."),h=m.shift(),n=new RegExp("(^|\\.)"+f.map(m.slice(0).sort(),C).join("\\.(?:.*\\.)?")+"(\\.|$)")),p=t[h];if(!p)continue;if(!d){for(j=0;j<p.length;j++){q=p[j];if(l||n.test(q.namespace))f.event.remove(a,r,q.handler,j),p.splice(j--,1)}continue}o=f.event.special[h]||{};for(j=e||0;j<p.length;j++){q=p[j];if(d.guid===q.guid){if(l||n.test(q.namespace))e==null&&p.splice(j--,1),o.remove&&o.remove.call(a,q);if(e!=null)break}}if(p.length===0||e!=null&&p.length===1)(!o.teardown||o.teardown.call(a,m)===!1)&&f.removeEvent(a,h,s.handle),g=null,delete t[h]}if(f.isEmptyObject(t)){var u=s.handle;u&&(u.elem=null),delete s.events,delete s.handle,f.isEmptyObject(s)&&f.removeData(a,b,!0)}}},customEvent:{getData:!0,setData:!0,changeData:!0},trigger:function(c,d,e,g){var h=c.type||c,i=[],j;h.indexOf("!")>=0&&(h=h.slice(0,-1),j=!0),h.indexOf(".")>=0&&(i=h.split("."),h=i.
+shift(),i.sort());if(!!e&&!f.event.customEvent[h]||!!f.event.global[h]){c=typeof c=="object"?c[f.expando]?c:new f.Event(h,c):new f.Event(h),c.type=h,c.exclusive=j,c.namespace=i.join("."),c.namespace_re=new RegExp("(^|\\.)"+i.join("\\.(?:.*\\.)?")+"(\\.|$)");if(g||!e)c.preventDefault(),c.stopPropagation();if(!e){f.each(f.cache,function(){var a=f.expando,b=this[a];b&&b.events&&b.events[h]&&f.event.trigger(c,d,b.handle.elem)});return}if(e.nodeType===3||e.nodeType===8)return;c.result=b,c.target=e,d=d!=null?f.makeArray(d):[],d.unshift(c);var k=e,l=h.indexOf(":")<0?"on"+h:"";do{var m=f._data(k,"handle");c.currentTarget=k,m&&m.apply(k,d),l&&f.acceptData(k)&&k[l]&&k[l].apply(k,d)===!1&&(c.result=!1,c.preventDefault()),k=k.parentNode||k.ownerDocument||k===c.target.ownerDocument&&a}while(k&&!c.isPropagationStopped());if(!c.isDefaultPrevented()){var n,o=f.event.special[h]||{};if((!o._default||o._default.call(e.ownerDocument,c)===!1)&&(h!=="click"||!f.nodeName(e,"a"))&&f.acceptData(e)){try{l&&e[h]&&(n=e[l],n&&(e[l]=null),f.event.triggered=h,e[h]())}catch(p){}n&&(e[l]=n),f.event.triggered=b}}return c.result}},handle:function(c){c=f.event.fix(c||a.event);var d=((f._data(this,"events")||{})[c.type]||[]).slice(0),e=!c.exclusive&&!c.namespace,g=Array.prototype.slice.call(arguments,0);g[0]=c,c.currentTarget=this;for(var h=0,i=d.length;h<i;h++){var j=d[h];if(e||c.namespace_re.test(j.namespace)){c.handler=j.handler,c.data=j.data,c.handleObj=j;var k=j.handler.apply(this,g);k!==b&&(c.result=k,k===!1&&(c.preventDefault(),c.stopPropagation()));if(c.isImmediatePropagationStopped())break}}return c.result},props:"altKey attrChange attrName bubbles button cancelable charCode clientX clientY ctrlKey currentTarget data detail eventPhase fromElement handler keyCode layerX layerY metaKey newValue offsetX offsetY pageX pageY prevValue relatedNode relatedTarget screenX screenY shiftKey srcElement target toElement view wheelDelta which".split(" "),fix:function(a){if(a[f.expando])return a;var d=a;a=f.Event(d);for(var e=this.props.length,g;e;)g=this.props[--e],a[g]=d[g];a.target||(a.target=a.srcElement||c),a.target.nodeType===3&&(a.target=a.target.parentNode),!a.relatedTarget&&a.fromElement&&(a.relatedTarget=a.fromElement===a.target?a.toElement:a.fromElement);if(a.pageX==null&&a.clientX!=null){var h=a.target.ownerDocument||c,i=h.documentElement,j=h.body;a.pageX=a.clientX+(i&&i.scrollLeft||j&&j.scrollLeft||0)-(i&&i.clientLeft||j&&j.clientLeft||0),a.pageY=a.clientY+(i&&i.scrollTop||j&&j.scrollTop||0)-(i&&i.clientTop||j&&j.clientTop||0)}a.which==null&&(a.charCode!=null||a.keyCode!=null)&&(a.which=a.charCode!=null?a.charCode:a.keyCode),!a.metaKey&&a.ctrlKey&&(a.metaKey=a.ctrlKey),!a.which&&a.button!==b&&(a.which=a.button&1?1:a.button&2?3:a.button&4?2:0);return a},guid:1e8,proxy:f.proxy,special:{ready:{setup:f.bindReady,teardown:f.noop},live:{add:function(a){f.event.add(this,N(a.origType,a.selector),f.extend({},a,{handler:M,guid:a.handler.guid}))},remove:function(a){f.event.remove(this,N(a.origType,a.selector),a)}},beforeunload:{setup:function(a,b,c){f.isWindow(this)&&(this.onbeforeunload=c)},teardown:function(a,b){this.onbeforeunload===b&&(this.onbeforeunload=null)}}}},f.removeEvent=c.removeEventListener?function(a,b,c){a.removeEventListener&&a.removeEventListener(b,c,!1)}:function(a,b,c){a.detachEvent&&a.detachEvent("on"+b,c)},f.Event=function(a,b){if(!this.preventDefault)return new f.Event(a,b);a&&a.type?(this.originalEvent=a,this.type=a.type,this.isDefaultPrevented=a.defaultPrevented||a.returnValue===!1||a.getPreventDefault&&a.getPreventDefault()?E:D):this.type=a,b&&f.extend(this,b),this.timeStamp=f.now(),this[f.expando]=!0},f.Event.prototype={preventDefault:function(){this.isDefaultPrevented=E;var a=this.originalEvent;!a||(a.preventDefault?a.preventDefault():a.returnValue=!1)},stopPropagation:function(){this.isPropagationStopped=E;var a=this.originalEvent;!a||(a.stopPropagation&&a.stopPropagation(),a.cancelBubble=!0)},stopImmediatePropagation:function(){this.isImmediatePropagationStopped=E,this.stopPropagation()},isDefaultPrevented:D,isPropagationStopped:D,isImmediatePropagationStopped:D};var F=function(a){var b=a.relatedTarget,c=!1,d=a.type;a.type=a.data,b!==this&&(b&&(c=f.contains(this,b)),c||(f.event.handle.apply(this,arguments),a.type=d))},G=function(a){a.type=a.data,f.event.handle.apply(this,arguments)};f.each({mouseenter:"mouseover",mouseleave:"mouseout"},function(a,b){f.event.special[a]={setup:function(c){f.event.add(this,b,c&&c.selector?G:F,a)},teardown:function(a){f.event.remove(this,b,a&&a.selector?G:F)}}}),f.support.submitBubbles||(f.event.special.submit={setup:function(a,b){if(!f.nodeName(this,"form"))f.event.add(this,"click.specialSubmit",function(a){var b=a.target,c=b.type;(c==="submit"||c==="image")&&f(b).closest("form").length&&K("submit",this,arguments)}),f.event.add(this,"keypress.specialSubmit",function(a){var b=a.target,c=b.type;(c==="text"||c==="password")&&f(b).closest("form").length&&a.keyCode===13&&K("submit",this,arguments)});else return!1},teardown:function(a){f.event.remove(this,".specialSubmit")}});if(!f.support.changeBubbles){var H,I=function(a){var b=a.type,c=a.value;b==="radio"||b==="checkbox"?c=a.checked:b==="select-multiple"?c=a.selectedIndex>-1?f.map(a.options,function(a){return a.selected}).join("-"):"":f.nodeName(a,"select")&&(c=a.selectedIndex);return c},J=function(c){var d=c.target,e,g;if(!!y.test(d.nodeName)&&!d.readOnly){e=f._data(d,"_change_data"),g=I(d),(c.type!=="focusout"||d.type!=="radio")&&f._data(d,"_change_data",g);if(e===b||g===e)return;if(e!=null||g)c.type="change",c.liveFired=b,f.event.trigger(c,arguments[1],d)}};f.event.special.change={filters:{focusout:J,beforedeactivate:J,click:function(a){var b=a.target,c=f.nodeName(b,"input")?b.type:"";(c==="radio"||c==="checkbox"||f.nodeName(b,"select"))&&J.call(this,a)},keydown:function(a){var b=a.target,c=f.nodeName(b,"input")?b.type:"";(a.keyCode===13&&!f.nodeName(b,"textarea")||a.keyCode===32&&(c==="checkbox"||c==="radio")||c==="select-multiple")&&J.call(this,a)},beforeactivate:function(a){var b=a.target;f._data(b,"_change_data",I(b))}},setup:function(a,b){if(this.type==="file")return!1;for(var c in H)f.event.add(this,c+".specialChange",H[c]);return y.test(this.nodeName)},teardown:function(a){f.event.remove(this,".specialChange");return y.test(this.nodeName)}},H=f.event.special.change.filters,H.focus=H.beforeactivate}f.support.focusinBubbles||f.each({focus:"focusin",blur:"focusout"},function(a,b){function e(a){var c=f.event.fix(a);c.type=b,c.originalEvent={},f.event.trigger(c,null,c.target),c.isDefaultPrevented()&&a.preventDefault()}var d=0;f.event.special[b]={setup:function(){d++===0&&c.addEventListener(a,e,!0)},teardown:function(){--d===0&&c.removeEventListener(a,e,!0)}}}),f.each(["bind","one"],function(a,c){f.fn[c]=function(a,d,e){var g;if(typeof a=="object"){for(var h in a)this[c](h,d,a[h],e);return this}if(arguments.length===2||d===!1)e=d,d=b;c==="one"?(g=function(a){f(this).unbind(a,g);return e.apply(this,arguments)},g.guid=e.guid||f.guid++):g=e;if(a==="unload"&&c!=="one")this.one(a,d,e);else for(var i=0,j=this.length;i<j;i++)f.event.add(this[i],a,g,d);return this}}),f.fn.extend({unbind:function(a,b){if(typeof a=="object"&&!a.preventDefault)for(var c in a)this.unbind(c,a[c]);else for(var d=0,e=this.length;d<e;d++)f.event.remove(this[d],a,b);return this},delegate:function(a,b,c,d){return this.live(b,c,d,a)},undelegate:function(a,b,c){return arguments.length===0?this.unbind("live"):this.die(b,null,c,a)},trigger:function(a,b){return this.each(function(){f.event.trigger(a,b,this)})},triggerHandler:function(a,b){if(this[0])return f.event.trigger(a,b,this[0],!0)},toggle:function(a){var b=arguments,c=a.guid||f.guid++,d=0,e=function(c){var e=(f.data(this,"lastToggle"+a.guid)||0)%d;f.data(this,"lastToggle"+a.guid,e+1),c.preventDefault();return b[e].apply(this,arguments)||!1};e.guid=c;while(d<b.length)b[d++].guid=c;return this.click(e)},hover:function(a,b){return this.mouseenter(a).mouseleave(b||a)}});var L={focus:"focusin",blur:"focusout",mouseenter:"mouseover",mouseleave:"mouseout"};f.each(["live","die"],function(a,c){f.fn[c]=function(a,d,e,g){var h,i=0,j,k,l,m=g||this.selector,n=g?this:f(this.context);if(typeof a=="object"&&!a.preventDefault){for(var o in a)n[c](o,d,a[o],m);return this}if(c==="die"&&!a&&g&&g.charAt(0)==="."){n.unbind(g);return this}if(d===!1||f.isFunction(d))e=d||D,d=b;a=(a||"").split(" ");while((h=a[i++])!=null){j=x.exec(h),k="",j&&(k=j[0],h=h.replace(x,""));if(h==="hover"){a.push("mouseenter"+k,"mouseleave"+k);continue}l=h,L[h]?(a.push(L[h]+k),h=h+k):h=(L[h]||h)+k;if(c==="live")for(var p=0,q=n.length;p<q;p++)f.event.add(n[p],"live."+N(h,m),{data:d,selector:m,handler:e,origType:h,origHandler:e,preType:l});else n.unbind("live."+N(h,m),e)}return this}}),f.each("blur focus focusin focusout load resize scroll unload click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup error".split(" "),function(a,b){f.fn[b]=function(a,c){c==null&&(c=a,a=null);return arguments.length>0?this.bind(b,a,c):this.trigger(b)},f.attrFn&&(f.attrFn[b]=!0)}),function(){function u(a,b,c,d,e,f){for(var g=0,h=d.length;g<h;g++){var i=d[g];if(i){var j=!1;i=i[a];while(i){if(i.sizcache===c){j=d[i.sizset];break}if(i.nodeType===1){f||(i.sizcache=c,i.sizset=g);if(typeof b!="string"){if(i===b){j=!0;break}}else if(k.filter(b,[i]).length>0){j=i;break}}i=i[a]}d[g]=j}}}function t(a,b,c,d,e,f){for(var g=0,h=d.length;g<h;g++){var i=d[g];if(i){var j=!1;i=i[a];while(i){if(i.sizcache===c){j=d[i.sizset];break}i.nodeType===1&&!f&&(i.sizcache=c,i.sizset=g);if(i.nodeName.toLowerCase()===b){j=i;break}i=i[a]}d[g]=j}}}var a=/((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^\[\]]*\]|['"][^'"]*['"]|[^\[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g,d=0,e=Object.prototype.toString,g=!1,h=!0,i=/\\/g,j=/\W/;[0,0].sort(function(){h=!1;return 0});var k=function(b,d,f,g){f=f||[],d=d||c;var h=d;if(d.nodeType!==1&&d.nodeType!==9)return[];if(!b||typeof b!="string")return f;var i,j,n,o,q,r,s,t,u=!0,w=k.isXML(d),x=[],y=b;do{a.exec(""),i=a.exec(y);if(i){y=i[3],x.push(i[1]);if(i[2]){o=i[3];break}}}while(i);if(x.length>1&&m.exec(b))if(x.length===2&&l.relative[x[0]])j=v(x[0]+x[1],d);else{j=l.relative[x[0]]?[d]:k(x.shift(),d);while(x.length)b=x.shift(),l.relative[b]&&(b+=x.shift()),j=v(b,j)}else{!g&&x.length>1&&d.nodeType===9&&!w&&l.match.ID.test(x[0])&&!l.match.ID.test(x[x.length-1])&&(q=k.find(x.shift(),d,w),d=q.expr?k.filter(q.expr,q.set)[0]:q.set[0]);if(d){q=g?{expr:x.pop(),set:p(g)}:k.find(x.pop(),x.length===1&&(x[0]==="~"||x[0]==="+")&&d.parentNode?d.parentNode:d,w),j=q.expr?k.filter(q.expr,q.set):q.set,x.length>0?n=p(j):u=!1;while(x.length)r=x.pop(),s=r,l.relative[r]?s=x.pop():r="",s==null&&(s=d),l.relative[r](n,s,w)}else n=x=[]}n||(n=j),n||k.error(r||b);if(e.call(n)==="[object Array]")if(!u)f.push.apply(f,n);else if(d&&d.nodeType===1)for(t=0;n[t]!=null;t++)n[t]&&(n[t]===!0||n[t].nodeType===1&&k.contains(d,n[t]))&&f.push(j[t]);else for(t=0;n[t]!=null;t++)n[t]&&n[t].nodeType===1&&f.push(j[t]);else p(n,f);o&&(k(o,h,f,g),k.uniqueSort(f));return f};k.uniqueSort=function(a){if(r){g=h,a.sort(r);if(g)for(var b=1;b<a.length;b++)a[b]===a[b-1]&&a.splice(b--,1)}return a},k.matches=function(a,b){return k(a,null,null,b)},k.matchesSelector=function(a,b){return k(b,null,null,[a]).length>0},k.find=function(a,b,c){var d;if(!a)return[];for(var e=0,f=l.order.length;e<f;e++){var g,h=l.order[e];if(g=l.leftMatch[h].exec(a)){var j=g[1];g.splice(1,1);if(j.substr(j.length-1)!=="\\"){g[1]=(g[1]||"").replace(i,""),d=l.find[h](g,b,c);if(d!=null){a=a.replace(l.match[h],"");break}}}}d||(d=typeof b.getElementsByTagName!="undefined"?b.getElementsByTagName("*"):[]);return{set:d,expr:a}},k.filter=function(a,c,d,e){var f,g,h=a,i=[],j=c,m=c&&c[0]&&k.isXML(c[0]);while(a&&c.length){for(var n in l.filter)if((f=l.leftMatch[n].exec(a))!=null&&f[2]){var o,p,q=l.filter[n],r=f[1];g=!1,f.splice(1,1);if(r.substr(r.length-1)==="\\")continue;j===i&&(i=[]);if(l.preFilter[n]){f=l.preFilter[n](f,j,d,i,e,m);if(!f)g=o=!0;else if(f===!0)continue}if(f)for(var s=0;(p=j[s])!=null;s++)if(p){o=q(p,f,s,j);var t=e^!!o;d&&o!=null?t?g=!0:j[s]=!1:t&&(i.push(p),g=!0)}if(o!==b){d||(j=i),a=a.replace(l.match[n],"");if(!g)return[];break}}if(a===h)if(g==null)k.error(a);else break;h=a}return j},k.error=function(a){throw"Syntax error, unrecognized expression: "+a};var l=k.selectors={order:["ID","NAME","TAG"],match:{ID:/#((?:[\w\u00c0-\uFFFF\-]|\\.)+)/,CLASS:/\.((?:[\w\u00c0-\uFFFF\-]|\\.)+)/,NAME:/\[name=['"]*((?:[\w\u00c0-\uFFFF\-]|\\.)+)['"]*\]/,ATTR:/\[\s*((?:[\w\u00c0-\uFFFF\-]|\\.)+)\s*(?:(\S?=)\s*(?:(['"])(.*?)\3|(#?(?:[\w\u00c0-\uFFFF\-]|\\.)*)|)|)\s*\]/,TAG:/^((?:[\w\u00c0-\uFFFF\*\-]|\\.)+)/,CHILD:/:(only|nth|last|first)-child(?:\(\s*(even|odd|(?:[+\-]?\d+|(?:[+\-]?\d*)?n\s*(?:[+\-]\s*\d+)?))\s*\))?/,POS:/:(nth|eq|gt|lt|first|last|even|odd)(?:\((\d*)\))?(?=[^\-]|$)/,PSEUDO:/:((?:[\w\u00c0-\uFFFF\-]|\\.)+)(?:\((['"]?)((?:\([^\)]+\)|[^\(\)]*)+)\2\))?/},leftMatch:{},attrMap:{"class":"className","for":"htmlFor"},attrHandle:{href:function(a){return a.getAttribute("href")},type:function(a){return a.getAttribute("type")}},relative:{"+":function(a,b){var c=typeof b=="string",d=c&&!j.test(b),e=c&&!d;d&&(b=b.toLowerCase());for(var f=0,g=a.length,h;f<g;f++)if(h=a[f]){while((h=h.previousSibling)&&h.nodeType!==1);a[f]=e||h&&h.nodeName.toLowerCase()===b?h||!1:h===b}e&&k.filter(b,a,!0)},">":function(a,b){var c,d=typeof b=="string",e=0,f=a.length;if(d&&!j.test(b)){b=b.toLowerCase();for(;e<f;e++){c=a[e];if(c){var g=c.parentNode;a[e]=g.nodeName.toLowerCase()===b?g:!1}}}else{for(;e<f;e++)c=a[e],c&&(a[e]=d?c.parentNode:c.parentNode===b);d&&k.filter(b,a,!0)}},"":function(a,b,c){var e,f=d++,g=u;typeof b=="string"&&!j.test(b)&&(b=b.toLowerCase(),e=b,g=t),g("parentNode",b,f,a,e,c)},"~":function(a,b,c){var e,f=d++,g=u;typeof b=="string"&&!j.test(b)&&(b=b.toLowerCase(),e=b,g=t),g("previousSibling",b,f,a,e,c)}},find:{ID:function(a,b,c){if(typeof b.getElementById!="undefined"&&!c){var d=b.getElementById(a[1]);return d&&d.parentNode?[d]:[]}},NAME:function(a,b){if(typeof b.getElementsByName!="undefined"){var c=[],d=b.getElementsByName(a[1]);for(var e=0,f=d.length;e<f;e++)d[e].getAttribute("name")===a[1]&&c.push(d[e]);return c.length===0?null:c}},TAG:function(a,b){if(typeof b.getElementsByTagName!="undefined")return b.getElementsByTagName(a[1])}},preFilter:{CLASS:function(a,b,c,d,e,f){a=" "+a[1].replace(i,"")+" ";if(f)return a;for(var g=0,h;(h=b[g])!=null;g++)h&&(e^(h.className&&(" "+h.className+" ").replace(/[\t\n\r]/g," ").indexOf(a)>=0)?c||d.push(h):c&&(b[g]=!1));return!1},ID:function(a){return a[1].replace(i,"")},TAG:function(a,b){return a[1].replace(i,"").toLowerCase()},CHILD:function(a){if(a[1]==="nth"){a[2]||k.error(a[0]),a[2]=a[2].replace(/^\+|\s*/g,"");var b=/(-?)(\d*)(?:n([+\-]?\d*))?/.exec(a[2]==="even"&&"2n"||a[2]==="odd"&&"2n+1"||!/\D/.test(a[2])&&"0n+"+a[2]||a[2]);a[2]=b[1]+(b[2]||1)-0,a[3]=b[3]-0}else a[2]&&k.error(a[0]);a[0]=d++;return a},ATTR:function(a,b,c,d,e,f){var g=a[1]=a[1].replace(i,"");!f&&l.attrMap[g]&&(a[1]=l.attrMap[g]),a[4]=(a[4]||a[5]||"").replace(i,""),a[2]==="~="&&(a[4]=" "+a[4]+" ");return a},PSEUDO:function(b,c,d,e,f){if(b[1]==="not")if((a.exec(b[3])||"").length>1||/^\w/.test(b[3]))b[3]=k(b[3],null,null,c);else{var g=k.filter(b[3],c,d,!0^f);d||e.push.apply(e,g);return!1}else if(l.match.POS.test(b[0])||l.match.CHILD.test(b[0]))return!0;return b},POS:function(a){a.unshift(!0);return a}},filters:{enabled:function(a){return a.disabled===!1&&a.type!=="hidden"},disabled:function(a){return a.disabled===!0},checked:function(a){return a.checked===!0},selected:function(a){a.parentNode&&a.parentNode.selectedIndex;return a.selected===!0},parent:function(a){return!!a.firstChild},empty:function(a){return!a.firstChild},has:function(a,b,c){return!!k(c[3],a).length},header:function(a){return/h\d/i.test(a.nodeName)},text:function(a){var b=a.getAttribute("type"),c=a.type;return a.nodeName.toLowerCase()==="input"&&"text"===c&&(b===c||b===null)},radio:function(a){return a.nodeName.toLowerCase()==="input"&&"radio"===a.type},checkbox:function(a){return a.nodeName.toLowerCase()==="input"&&"checkbox"===a.type},file:function(a){return a.nodeName.toLowerCase()==="input"&&"file"===a.type},password:function(a){return a.nodeName.toLowerCase()==="input"&&"password"===a.type},submit:function(a){var b=a.nodeName.toLowerCase();return(b==="input"||b==="button")&&"submit"===a.type},image:function(a){return a.nodeName.toLowerCase()==="input"&&"image"===a.type},reset:function(a){var b=a.nodeName.toLowerCase();return(b==="input"||b==="button")&&"reset"===a.type},button:function(a){var b=a.nodeName.toLowerCase();return b==="input"&&"button"===a.type||b==="button"},input:function(a){return/input|select|textarea|button/i.test(a.nodeName)},focus:function(a){return a===a.ownerDocument.activeElement}},setFilters:{first:function(a,b){return b===0},last:function(a,b,c,d){return b===d.length-1},even:function(a,b){return b%2===0},odd:function(a,b){return b%2===1},lt:function(a,b,c){return b<c[3]-0},gt:function(a,b,c){return b>c[3]-0},nth:function(a,b,c){return c[3]-0===b},eq:function(a,b,c){return c[3]-0===b}},filter:{PSEUDO:function(a,b,c,d){var e=b[1],f=l.filters[e];if(f)return f(a,c,b,d);if(e==="contains")return(a.textContent||a.innerText||k.getText([a])||"").indexOf(b[3])>=0;if(e==="not"){var g=b[3];for(var h=0,i=g.length;h<i;h++)if(g[h]===a)return!1;return!0}k.error(e)},CHILD:function(a,b){var c=b[1],d=a;switch(c){case"only":case"first":while(d=d.previousSibling)if(d.nodeType===1)return!1;if(c==="first")return!0;d=a;case"last":while(d=d.nextSibling)if(d.nodeType===1)return!1;return!0;case"nth":var e=b[2],f=b[3];if(e===1&&f===0)return!0;var g=b[0],h=a.parentNode;if(h&&(h.sizcache!==g||!a.nodeIndex)){var i=0;for(d=h.firstChild;d;d=d.nextSibling)d.nodeType===1&&(d.nodeIndex=++i);h.sizcache=g}var j=a.nodeIndex-f;return e===0?j===0:j%e===0&&j/e>=0}},ID:function(a,b){return a.nodeType===1&&a.getAttribute("id")===b},TAG:function(a,b){return b==="*"&&a.nodeType===1||a.nodeName.toLowerCase()===b},CLASS:function(a,b){return(" "+(a.className||a.getAttribute("class"))+" ").indexOf(b)>-1},ATTR:function(a,b){var c=b[1],d=l.attrHandle[c]?l.attrHandle[c](a):a[c]!=null?a[c]:a.getAttribute(c),e=d+"",f=b[2],g=b[4];return d==null?f==="!=":f==="="?e===g:f==="*="?e.indexOf(g)>=0:f==="~="?(" "+e+" ").indexOf(g)>=0:g?f==="!="?e!==g:f==="^="?e.indexOf(g)===0:f==="$="?e.substr(e.length-g.length)===g:f==="|="?e===g||e.substr(0,g.length+1)===g+"-":!1:e&&d!==!1},POS:function(a,b,c,d){var e=b[2],f=l.setFilters[e];if(f)return f(a,c,b,d)}}},m=l.match.POS,n=function(a,b){return"\\"+(b-0+1)};for(var o in l.match)l.match[o]=new RegExp(l.match[o].source+/(?![^\[]*\])(?![^\(]*\))/.source),l.leftMatch[o]=new RegExp(/(^(?:.|\r|\n)*?)/.source+l.match[o].source.replace(/\\(\d+)/g,n));var p=function(a,b){a=Array.prototype.slice.call(a,0);if(b){b.push.apply(b,a);return b}return a};try{Array.prototype.slice.call(c.documentElement.childNodes,0)[0].nodeType}catch(q){p=function(a,b){var c=0,d=b||[];if(e.call(a)==="[object Array]")Array.prototype.push.apply(d,a);else if(typeof a.length=="number")for(var f=a.length;c<f;c++)d.push(a[c]);else for(;a[c];c++)d.push(a[c]);return d}}var r,s;c.documentElement.compareDocumentPosition?r=function(a,b){if(a===b){g=!0;return 0}if(!a.compareDocumentPosition||!b.compareDocumentPosition)return a.compareDocumentPosition?-1:1;return a.compareDocumentPosition(b)&4?-1:1}:(r=function(a,b){if(a===b){g=!0;return 0}if(a.sourceIndex&&b.sourceIndex)return a.sourceIndex-b.sourceIndex;var c,d,e=[],f=[],h=a.parentNode,i=b.parentNode,j=h;if(h===i)return s(a,b);if(!h)return-1;if(!i)return 1;while(j)e.unshift(j),j=j.parentNode;j=i;while(j)f.unshift(j),j=j.parentNode;c=e.length,d=f.length;for(var k=0;k<c&&k<d;k++)if(e[k]!==f[k])return s(e[k],f[k]);return k===c?s(a,f[k],-1):s(e[k],b,1)},s=function(a,b,c){if(a===b)return c;var d=a.nextSibling;while(d){if(d===b)return-1;d=d.nextSibling}return 1}),k.getText=function(a){var b="",c;for(var d=0;a[d];d++)c=a[d],c.nodeType===3||c.nodeType===4?b+=c.nodeValue:c.nodeType!==8&&(b+=k.getText(c.childNodes));return b},function(){var a=c.createElement("div"),d="script"+(new Date).getTime(),e=c.documentElement;a.innerHTML="<a name='"+d+"'/>",e.insertBefore(a,e.firstChild),c.getElementById(d)&&(l.find.ID=function(a,c,d){if(typeof c.getElementById!="undefined"&&!d){var e=c.getElementById(a[1]);return e?e.id===a[1]||typeof e.getAttributeNode!="undefined"&&e.getAttributeNode("id").nodeValue===a[1]?[e]:b:[]}},l.filter.ID=function(a,b){var c=typeof a.getAttributeNode!="undefined"&&a.getAttributeNode("id");return a.nodeType===1&&c&&c.nodeValue===b}),e.removeChild(a),e=a=null}(),function(){var a=c.createElement("div");a.appendChild(c.createComment("")),a.getElementsByTagName("*").length>0&&(l.find.TAG=function(a,b){var c=b.getElementsByTagName(a[1]);if(a[1]==="*"){var d=[];for(var e=0;c[e];e++)c[e].nodeType===1&&d.push(c[e]);c=d}return c}),a.innerHTML="<a href='#'></a>",a.firstChild&&typeof a.firstChild.getAttribute!="undefined"&&a.firstChild.getAttribute("href")!=="#"&&(l.attrHandle.href=function(a){return a.getAttribute("href",2)}),a=null}(),c.querySelectorAll&&function(){var a=k,b=c.createElement("div"),d="__sizzle__";b.innerHTML="<p class='TEST'></p>";if(!b.querySelectorAll||b.querySelectorAll(".TEST").length!==0){k=function(b,e,f,g){e=e||c;if(!g&&!k.isXML(e)){var h=/^(\w+$)|^\.([\w\-]+$)|^#([\w\-]+$)/.exec(b);if(h&&(e.nodeType===1||e.nodeType===9)){if(h[1])return p(e.getElementsByTagName(b),f);if(h[2]&&l.find.CLASS&&e.getElementsByClassName)return p(e.getElementsByClassName(h[2]),f)}if(e.nodeType===9){if(b==="body"&&e.body)return p([e.body],f);if(h&&h[3]){var i=e.getElementById(h[3]);if(!i||!i.parentNode)return p([],f);if(i.id===h[3])return p([i],f)}try{return p(e.querySelectorAll(b),f)}catch(j){}}else if(e.nodeType===1&&e.nodeName.toLowerCase()!=="object"){var m=e,n=e.getAttribute("id"),o=n||d,q=e.parentNode,r=/^\s*[+~]/.test(b);n?o=o.replace(/'/g,"\\$&"):e.setAttribute("id",o),r&&q&&(e=e.parentNode);try{if(!r||q)return p(e.querySelectorAll("[id='"+o+"'] "+b),f)}catch(s){}finally{n||m.removeAttribute("id")}}}return a(b,e,f,g)};for(var e in a)k[e]=a[e];b=null}}(),function(){var a=c.documentElement,b=a.matchesSelector||a.mozMatchesSelector||a.webkitMatchesSelector||a.msMatchesSelector;if(b){var d=!b.call(c.createElement("div"),"div"),e=!1;try{b.call(c.documentElement,"[test!='']:sizzle")}catch(f){e=!0}k.matchesSelector=function(a,c){c=c.replace(/\=\s*([^'"\]]*)\s*\]/g,"='$1']");if(!k.isXML(a))try{if(e||!l.match.PSEUDO.test(c)&&!/!=/.test(c)){var f=b.call(a,c);if(f||!d||a.document&&a.document.nodeType!==11)return f}}catch(g){}return k(c,null,null,[a]).length>0}}}(),function(){var a=c.createElement("div");a.innerHTML="<div class='test e'></div><div class='test'></div>";if(!!a.getElementsByClassName&&a.getElementsByClassName("e").length!==0){a.lastChild.className="e";if(a.getElementsByClassName("e").length===1)return;l.order.splice(1,0,"CLASS"),l.find.CLASS=function(a,b,c){if(typeof b.getElementsByClassName!="undefined"&&!c)return b.getElementsByClassName(a[1])},a=null}}(),c.documentElement.contains?k.contains=function(a,b){return a!==b&&(a.contains?a.contains(b):!0)}:c.documentElement.compareDocumentPosition?k.contains=function(a,b){return!!(a.compareDocumentPosition(b)&16)}:k.contains=function(){return!1},k.isXML=function(a){var b=(a?a.ownerDocument||a:0).documentElement;return b?b.nodeName!=="HTML":!1};var v=function(a,b){var c,d=[],e="",f=b.nodeType?[b]:b;while(c=l.match.PSEUDO.exec(a))e+=c[0],a=a.replace(l.match.PSEUDO,"");a=l.relative[a]?a+"*":a;for(var g=0,h=f.length;g<h;g++)k(a,f[g],d);return k.filter(e,d)};f.find=k,f.expr=k.selectors,f.expr[":"]=f.expr.filters,f.unique=k.uniqueSort,f.text=k.getText,f.isXMLDoc=k.isXML,f.contains=k.contains}();var O=/Until$/,P=/^(?:parents|prevUntil|prevAll)/,Q=/,/,R=/^.[^:#\[\.,]*$/,S=Array.prototype.slice,T=f.expr.match.POS,U={children:!0,contents:!0,next:!0,prev:!0};f.fn.extend({find:function(a){var b=this,c,d;if(typeof a!="string")return f(a).filter(function(){for(c=0,d=b.length;c<d;c++)if(f.contains(b[c],this))return!0});var e=this.pushStack("","find",a),g,h,i;for(c=0,d=this.length;c<d;c++){g=e.length,f.find(a,this[c],e);if(c>0)for(h=g;h<e.length;h++)for(i=0;i<g;i++)if(e[i]===e[h]){e.splice(h--,1);break}}return e},has:function(a){var b=f(a);return this.filter(function(){for(var a=0,c=b.length;a<c;a++)if(f.contains(this,b[a]))return!0})},not:function(a){return this.pushStack(W(this,a,!1),"not",a)},filter:function(a){return this.pushStack(W(this,a,!0),"filter",a)},is:function(a){return!!a&&(typeof a=="string"?f.filter(a,this).length>0:this.filter(a).length>0)},closest:function(a,b){var c=[],d,e,g=this[0];if(f.isArray(a)){var h,i,j={},k=1;if(g&&a.length){for(d=0,e=a.length;d<e;d++)i=a[d],j[i]||(j[i]=T.test(i)?f(i,b||this.context):i);while(g&&g.ownerDocument&&g!==b){for(i in j)h=j[i],(h.jquery?h.index(g)>-1:f(g).is(h))&&c.push({selector:i,elem:g,level:k});g=g.parentNode,k++}}return c}var l=T.test(a)||typeof a!="string"?f(a,b||this.context):0;for(d=0,e=this.length;d<e;d++){g=this[d];while(g){if(l?l.index(g)>-1:f.find.matchesSelector(g,a)){c.push(g);break}g=g.parentNode;if(!g||!g.ownerDocument||g===b||g.nodeType===11)break}}c=c.length>1?f.unique(c):c;return this.pushStack(c,"closest",a)},index:function(a){if(!a||typeof a=="string")return f.inArray(this[0],a?f(a):this.parent().children());return f.inArray(a.jquery?a[0]:a,this)},add:function(a,b){var c=typeof a=="string"?f(a,b):f.makeArray(a&&a.nodeType?[a]:a),d=f.merge(this.get(),c);return this.pushStack(V(c[0])||V(d[0])?d:f.unique(d))},andSelf:function(){return this.add(this.prevObject)}}),f.each({parent:function(a){var b=a.parentNode;return b&&b.nodeType!==11?b:null},parents:function(a){return f.dir(a,"parentNode")},parentsUntil:function(a,b,c){return f.dir(a,"parentNode",c)},next:function(a){return f.nth(a,2,"nextSibling")},prev:function(a){return f.nth(a,2,"previousSibling")},nextAll:function(a){return f.dir(a,"nextSibling")},prevAll:function(a){return f.dir(a,"previousSibling")},nextUntil:function(a,b,c){return f.dir(a,"nextSibling",c)},prevUntil:function(a,b,c){return f.dir(a,"previousSibling",c)},siblings:function(a){return f.sibling(a.parentNode.firstChild,a)},children:function(a){return f.sibling(a.firstChild)},contents:function(a){return f.nodeName(a,"iframe")?a.contentDocument||a.contentWindow.document:f.makeArray(a.childNodes)}},function(a,b){f.fn[a]=function(c,d){var e=f.map(this,b,c),g=S.call(arguments);O.test(a)||(d=c),d&&typeof d=="string"&&(e=f.filter(d,e)),e=this.length>1&&!U[a]?f.unique(e):e,(this.length>1||Q.test(d))&&P.test(a)&&(e=e.reverse());return this.pushStack(e,a,g.join(","))}}),f.extend({filter:function(a,b,c){c&&(a=":not("+a+")");return b.length===1?f.find.matchesSelector(b[0],a)?[b[0]]:[]:f.find.matches(a,b)},dir:function(a,c,d){var e=[],g=a[c];while(g&&g.nodeType!==9&&(d===b||g.nodeType!==1||!f(g).is(d)))g.nodeType===1&&e.push(g),g=g[c];return e},nth:function(a,b,c,d){b=b||1;var e=0;for(;a;a=a[c])if(a.nodeType===1&&++e===b)break;return a},sibling:function(a,b){var c=[];for(;a;a=a.nextSibling)a.nodeType===1&&a!==b&&c.push(a);return c}});var X=/ jQuery\d+="(?:\d+|null)"/g,Y=/^\s+/,Z=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/ig,$=/<([\w:]+)/,_=/<tbody/i,ba=/<|&#?\w+;/,bb=/<(?:script|object|embed|option|style)/i,bc=/checked\s*(?:[^=]|=\s*.checked.)/i,bd=/\/(java|ecma)script/i,be=/^\s*<!(?:\[CDATA\[|\-\-)/,bf={option:[1,"<select multiple='multiple'>","</select>"],legend:[1,"<fieldset>","</fieldset>"],thead:[1,"<table>","</table>"],tr:[2,"<table><tbody>","</tbody></table>"],td:[3,"<table><tbody><tr>","</tr></tbody></table>"],col:[2,"<table><tbody></tbody><colgroup>","</colgroup></table>"],area:[1,"<map>","</map>"],_default:[0,"",""]};bf.optgroup=bf.option,bf.tbody=bf.tfoot=bf.colgroup=bf.caption=bf.thead,bf.th=bf.td,f.support.htmlSerialize||(bf._default=[1,"div<div>","</div>"]),f.fn.extend({text:function(a){if(f.isFunction(a))return this.each(function(b){var c=f(this);c.text(a.call(this,b,c.text()))});if(typeof a!="object"&&a!==b)return this.empty().append((this[0]&&this[0].ownerDocument||c).createTextNode(a));return f.text(this)},wrapAll:function(a){if(f.isFunction(a))return this.each(function(b){f(this).wrapAll(a.call(this,b))});if(this[0]){var b=f(a,this[0].ownerDocument).eq(0).clone(!0);this[0].parentNode&&b.insertBefore(this[0]),b.map(function(){var a=this;while(a.firstChild&&a.firstChild.nodeType===1)a=a.firstChild;return a}).append(this)}return this},wrapInner:function(a){if(f.isFunction(a))return this.each(function(b){f(this).wrapInner(a.call(this,b))});return this.each(function(){var b=f(this),c=b.contents();c.length?c.wrapAll(a):b.append(a)})},wrap:function(a){return this.each(function(){f(this).wrapAll(a)})},unwrap:function(){return this.parent().each(function(){f.nodeName(this,"body")||f(this).replaceWith(this.childNodes)}).end()},append:function(){return this.domManip(arguments,!0,function(a){this.nodeType===1&&this.appendChild(a)})},prepend:function(){return this.domManip(arguments,!0,function(a){this.nodeType===1&&this.insertBefore(a,this.firstChild)})},before:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,!1,function(a){this.parentNode.insertBefore(a,this)});if(arguments.length){var a=f(arguments[0]);a.push.apply(a,this.toArray());return this.pushStack(a,"before",arguments)}},after:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,!1,function(a){this.parentNode.insertBefore(a,this.nextSibling)});if(arguments.length){var a=this.pushStack(this,"after",arguments);a.push.apply(a,f(arguments[0]).toArray());return a}},remove:function(a,b){for(var c=0,d;(d=this[c])!=null;c++)if(!a||f.filter(a,[d]).length)!b&&d.nodeType===1&&(f.cleanData(d.getElementsByTagName("*")),f.cleanData([d])),d.parentNode&&d.parentNode.removeChild(d);return this},empty:function(){for(var a=0,b;(b=this[a])!=null;a++){b.nodeType===1&&f.cleanData(b.getElementsByTagName("*"));while(b.firstChild)b.removeChild(b.firstChild)}return this},clone:function(a,b){a=a==null?!1:a,b=b==null?a:b;return this.map(function(){return f.clone(this,a,b)})},html:function(a){if(a===b)return this[0]&&this[0].nodeType===1?this[0].innerHTML.replace(X,""):null;if(typeof a=="string"&&!bb.test(a)&&(f.support.leadingWhitespace||!Y.test(a))&&!bf[($.exec(a)||["",""])[1].toLowerCase()]){a=a.replace(Z,"<$1></$2>");try{for(var c=0,d=this.length;c<d;c++)this[c].nodeType===1&&(f.cleanData(this[c].getElementsByTagName("*")),this[c].innerHTML=a)}catch(e){this.empty().append(a)}}else f.isFunction(a)?this.each(function(b){var c=f(this);c.html(a.call(this,b,c.html()))}):this.empty().append(a);return this},replaceWith:function(a){if(this[0]&&this[0].parentNode){if(f.isFunction(a))return this.each(function(b){var c=f(this),d=c.html();c.replaceWith(a.call(this,b,d))});typeof a!="string"&&(a=f(a).detach());return this.each(function(){var b=this.nextSibling,c=this.parentNode;f(this).remove(),b?f(b).before(a):f(c).append(a)})}return this.length?this.pushStack(f(f.isFunction(a)?a():a),"replaceWith",a):this},detach:function(a){return this.remove(a,!0)},domManip:function(a,c,d){var e,g,h,i,j=a[0],k=[];if(!f.support.checkClone&&arguments.length===3&&typeof j=="string"&&bc.test(j))return this.each(function(){f(this).domManip(a,c,d,!0)});if(f.isFunction(j))return this.each(function(e){var g=f(this);a[0]=j.call(this,e,c?g.html():b),g.domManip(a,c,d)});if(this[0]){i=j&&j.parentNode,f.support.parentNode&&i&&i.nodeType===11&&i.childNodes.length===this.length?e={fragment:i}:e=f.buildFragment(a,this,k),h=e.fragment,h.childNodes.length===1?g=h=h.firstChild:g=h.firstChild;if(g){c=c&&f.nodeName(g,"tr");for(var l=0,m=this.length,n=m-1;l<m;l++)d.call(c?bg(this[l],g):this[l],e.cacheable||m>1&&l<n?f.clone(h,!0,!0):h)}k.length&&f.each(k,bm)}return this}}),f.buildFragment=function(a,b,d){var e,g,h,i;b&&b[0]&&(i=b[0].ownerDocument||b[0]),i.createDocumentFragment||(i=c),a.length===1&&typeof a[0]=="string"&&a[0].length<512&&i===c&&a[0].charAt(0)==="<"&&!bb.test(a[0])&&(f.support.checkClone||!bc.test(a[0]))&&(g=!0,h=f.fragments[a[0]],h&&h!==1&&(e=h)),e||(e=i.createDocumentFragment(),f.clean(a,i,e,d)),g&&(f.fragments[a[0]]=h?e:1);return{fragment:e,cacheable:g}},f.fragments={},f.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(a,b){f.fn[a]=function(c){var d=[],e=f(c),g=this.length===1&&this[0].parentNode;if(g&&g.nodeType===11&&g.childNodes.length===1&&e.length===1){e[b](this[0]);return this}for(var h=0,i=e.length;h<i;h++){var j=(h>0?this.clone(!0):this).get();f(e[h])[b](j),d=d.concat(j
+)}return this.pushStack(d,a,e.selector)}}),f.extend({clone:function(a,b,c){var d=a.cloneNode(!0),e,g,h;if((!f.support.noCloneEvent||!f.support.noCloneChecked)&&(a.nodeType===1||a.nodeType===11)&&!f.isXMLDoc(a)){bi(a,d),e=bj(a),g=bj(d);for(h=0;e[h];++h)bi(e[h],g[h])}if(b){bh(a,d);if(c){e=bj(a),g=bj(d);for(h=0;e[h];++h)bh(e[h],g[h])}}e=g=null;return d},clean:function(a,b,d,e){var g;b=b||c,typeof b.createElement=="undefined"&&(b=b.ownerDocument||b[0]&&b[0].ownerDocument||c);var h=[],i;for(var j=0,k;(k=a[j])!=null;j++){typeof k=="number"&&(k+="");if(!k)continue;if(typeof k=="string")if(!ba.test(k))k=b.createTextNode(k);else{k=k.replace(Z,"<$1></$2>");var l=($.exec(k)||["",""])[1].toLowerCase(),m=bf[l]||bf._default,n=m[0],o=b.createElement("div");o.innerHTML=m[1]+k+m[2];while(n--)o=o.lastChild;if(!f.support.tbody){var p=_.test(k),q=l==="table"&&!p?o.firstChild&&o.firstChild.childNodes:m[1]==="<table>"&&!p?o.childNodes:[];for(i=q.length-1;i>=0;--i)f.nodeName(q[i],"tbody")&&!q[i].childNodes.length&&q[i].parentNode.removeChild(q[i])}!f.support.leadingWhitespace&&Y.test(k)&&o.insertBefore(b.createTextNode(Y.exec(k)[0]),o.firstChild),k=o.childNodes}var r;if(!f.support.appendChecked)if(k[0]&&typeof (r=k.length)=="number")for(i=0;i<r;i++)bl(k[i]);else bl(k);k.nodeType?h.push(k):h=f.merge(h,k)}if(d){g=function(a){return!a.type||bd.test(a.type)};for(j=0;h[j];j++)if(e&&f.nodeName(h[j],"script")&&(!h[j].type||h[j].type.toLowerCase()==="text/javascript"))e.push(h[j].parentNode?h[j].parentNode.removeChild(h[j]):h[j]);else{if(h[j].nodeType===1){var s=f.grep(h[j].getElementsByTagName("script"),g);h.splice.apply(h,[j+1,0].concat(s))}d.appendChild(h[j])}}return h},cleanData:function(a){var b,c,d=f.cache,e=f.expando,g=f.event.special,h=f.support.deleteExpando;for(var i=0,j;(j=a[i])!=null;i++){if(j.nodeName&&f.noData[j.nodeName.toLowerCase()])continue;c=j[f.expando];if(c){b=d[c]&&d[c][e];if(b&&b.events){for(var k in b.events)g[k]?f.event.remove(j,k):f.removeEvent(j,k,b.handle);b.handle&&(b.handle.elem=null)}h?delete j[f.expando]:j.removeAttribute&&j.removeAttribute(f.expando),delete d[c]}}}});var bn=/alpha\([^)]*\)/i,bo=/opacity=([^)]*)/,bp=/([A-Z]|^ms)/g,bq=/^-?\d+(?:px)?$/i,br=/^-?\d/,bs=/^[+\-]=/,bt=/[^+\-\.\de]+/g,bu={position:"absolute",visibility:"hidden",display:"block"},bv=["Left","Right"],bw=["Top","Bottom"],bx,by,bz;f.fn.css=function(a,c){if(arguments.length===2&&c===b)return this;return f.access(this,a,c,!0,function(a,c,d){return d!==b?f.style(a,c,d):f.css(a,c)})},f.extend({cssHooks:{opacity:{get:function(a,b){if(b){var c=bx(a,"opacity","opacity");return c===""?"1":c}return a.style.opacity}}},cssNumber:{fillOpacity:!0,fontWeight:!0,lineHeight:!0,opacity:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{"float":f.support.cssFloat?"cssFloat":"styleFloat"},style:function(a,c,d,e){if(!!a&&a.nodeType!==3&&a.nodeType!==8&&!!a.style){var g,h,i=f.camelCase(c),j=a.style,k=f.cssHooks[i];c=f.cssProps[i]||i;if(d===b){if(k&&"get"in k&&(g=k.get(a,!1,e))!==b)return g;return j[c]}h=typeof d;if(h==="number"&&isNaN(d)||d==null)return;h==="string"&&bs.test(d)&&(d=+d.replace(bt,"")+parseFloat(f.css(a,c)),h="number"),h==="number"&&!f.cssNumber[i]&&(d+="px");if(!k||!("set"in k)||(d=k.set(a,d))!==b)try{j[c]=d}catch(l){}}},css:function(a,c,d){var e,g;c=f.camelCase(c),g=f.cssHooks[c],c=f.cssProps[c]||c,c==="cssFloat"&&(c="float");if(g&&"get"in g&&(e=g.get(a,!0,d))!==b)return e;if(bx)return bx(a,c)},swap:function(a,b,c){var d={};for(var e in b)d[e]=a.style[e],a.style[e]=b[e];c.call(a);for(e in b)a.style[e]=d[e]}}),f.curCSS=f.css,f.each(["height","width"],function(a,b){f.cssHooks[b]={get:function(a,c,d){var e;if(c){if(a.offsetWidth!==0)return bA(a,b,d);f.swap(a,bu,function(){e=bA(a,b,d)});return e}},set:function(a,b){if(!bq.test(b))return b;b=parseFloat(b);if(b>=0)return b+"px"}}}),f.support.opacity||(f.cssHooks.opacity={get:function(a,b){return bo.test((b&&a.currentStyle?a.currentStyle.filter:a.style.filter)||"")?parseFloat(RegExp.$1)/100+"":b?"1":""},set:function(a,b){var c=a.style,d=a.currentStyle;c.zoom=1;var e=f.isNaN(b)?"":"alpha(opacity="+b*100+")",g=d&&d.filter||c.filter||"";c.filter=bn.test(g)?g.replace(bn,e):g+" "+e}}),f(function(){f.support.reliableMarginRight||(f.cssHooks.marginRight={get:function(a,b){var c;f.swap(a,{display:"inline-block"},function(){b?c=bx(a,"margin-right","marginRight"):c=a.style.marginRight});return c}})}),c.defaultView&&c.defaultView.getComputedStyle&&(by=function(a,c){var d,e,g;c=c.replace(bp,"-$1").toLowerCase();if(!(e=a.ownerDocument.defaultView))return b;if(g=e.getComputedStyle(a,null))d=g.getPropertyValue(c),d===""&&!f.contains(a.ownerDocument.documentElement,a)&&(d=f.style(a,c));return d}),c.documentElement.currentStyle&&(bz=function(a,b){var c,d=a.currentStyle&&a.currentStyle[b],e=a.runtimeStyle&&a.runtimeStyle[b],f=a.style;!bq.test(d)&&br.test(d)&&(c=f.left,e&&(a.runtimeStyle.left=a.currentStyle.left),f.left=b==="fontSize"?"1em":d||0,d=f.pixelLeft+"px",f.left=c,e&&(a.runtimeStyle.left=e));return d===""?"auto":d}),bx=by||bz,f.expr&&f.expr.filters&&(f.expr.filters.hidden=function(a){var b=a.offsetWidth,c=a.offsetHeight;return b===0&&c===0||!f.support.reliableHiddenOffsets&&(a.style.display||f.css(a,"display"))==="none"},f.expr.filters.visible=function(a){return!f.expr.filters.hidden(a)});var bB=/%20/g,bC=/\[\]$/,bD=/\r?\n/g,bE=/#.*$/,bF=/^(.*?):[ \t]*([^\r\n]*)\r?$/mg,bG=/^(?:color|date|datetime|email|hidden|month|number|password|range|search|tel|text|time|url|week)$/i,bH=/^(?:about|app|app\-storage|.+\-extension|file|widget):$/,bI=/^(?:GET|HEAD)$/,bJ=/^\/\//,bK=/\?/,bL=/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi,bM=/^(?:select|textarea)/i,bN=/\s+/,bO=/([?&])_=[^&]*/,bP=/^([\w\+\.\-]+:)(?:\/\/([^\/?#:]*)(?::(\d+))?)?/,bQ=f.fn.load,bR={},bS={},bT,bU;try{bT=e.href}catch(bV){bT=c.createElement("a"),bT.href="",bT=bT.href}bU=bP.exec(bT.toLowerCase())||[],f.fn.extend({load:function(a,c,d){if(typeof a!="string"&&bQ)return bQ.apply(this,arguments);if(!this.length)return this;var e=a.indexOf(" ");if(e>=0){var g=a.slice(e,a.length);a=a.slice(0,e)}var h="GET";c&&(f.isFunction(c)?(d=c,c=b):typeof c=="object"&&(c=f.param(c,f.ajaxSettings.traditional),h="POST"));var i=this;f.ajax({url:a,type:h,dataType:"html",data:c,complete:function(a,b,c){c=a.responseText,a.isResolved()&&(a.done(function(a){c=a}),i.html(g?f("<div>").append(c.replace(bL,"")).find(g):c)),d&&i.each(d,[c,b,a])}});return this},serialize:function(){return f.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?f.makeArray(this.elements):this}).filter(function(){return this.name&&!this.disabled&&(this.checked||bM.test(this.nodeName)||bG.test(this.type))}).map(function(a,b){var c=f(this).val();return c==null?null:f.isArray(c)?f.map(c,function(a,c){return{name:b.name,value:a.replace(bD,"\r\n")}}):{name:b.name,value:c.replace(bD,"\r\n")}}).get()}}),f.each("ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split(" "),function(a,b){f.fn[b]=function(a){return this.bind(b,a)}}),f.each(["get","post"],function(a,c){f[c]=function(a,d,e,g){f.isFunction(d)&&(g=g||e,e=d,d=b);return f.ajax({type:c,url:a,data:d,success:e,dataType:g})}}),f.extend({getScript:function(a,c){return f.get(a,b,c,"script")},getJSON:function(a,b,c){return f.get(a,b,c,"json")},ajaxSetup:function(a,b){b?f.extend(!0,a,f.ajaxSettings,b):(b=a,a=f.extend(!0,f.ajaxSettings,b));for(var c in{context:1,url:1})c in b?a[c]=b[c]:c in f.ajaxSettings&&(a[c]=f.ajaxSettings[c]);return a},ajaxSettings:{url:bT,isLocal:bH.test(bU[1]),global:!0,type:"GET",contentType:"application/x-www-form-urlencoded",processData:!0,async:!0,accepts:{xml:"application/xml, text/xml",html:"text/html",text:"text/plain",json:"application/json, text/javascript","*":"*/*"},contents:{xml:/xml/,html:/html/,json:/json/},responseFields:{xml:"responseXML",text:"responseText"},converters:{"* text":a.String,"text html":!0,"text json":f.parseJSON,"text xml":f.parseXML}},ajaxPrefilter:bW(bR),ajaxTransport:bW(bS),ajax:function(a,c){function w(a,c,l,m){if(s!==2){s=2,q&&clearTimeout(q),p=b,n=m||"",v.readyState=a?4:0;var o,r,u,w=l?bZ(d,v,l):b,x,y;if(a>=200&&a<300||a===304){if(d.ifModified){if(x=v.getResponseHeader("Last-Modified"))f.lastModified[k]=x;if(y=v.getResponseHeader("Etag"))f.etag[k]=y}if(a===304)c="notmodified",o=!0;else try{r=b$(d,w),c="success",o=!0}catch(z){c="parsererror",u=z}}else{u=c;if(!c||a)c="error",a<0&&(a=0)}v.status=a,v.statusText=c,o?h.resolveWith(e,[r,c,v]):h.rejectWith(e,[v,c,u]),v.statusCode(j),j=b,t&&g.trigger("ajax"+(o?"Success":"Error"),[v,d,o?r:u]),i.resolveWith(e,[v,c]),t&&(g.trigger("ajaxComplete",[v,d]),--f.active||f.event.trigger("ajaxStop"))}}typeof a=="object"&&(c=a,a=b),c=c||{};var d=f.ajaxSetup({},c),e=d.context||d,g=e!==d&&(e.nodeType||e instanceof f)?f(e):f.event,h=f.Deferred(),i=f._Deferred(),j=d.statusCode||{},k,l={},m={},n,o,p,q,r,s=0,t,u,v={readyState:0,setRequestHeader:function(a,b){if(!s){var c=a.toLowerCase();a=m[c]=m[c]||a,l[a]=b}return this},getAllResponseHeaders:function(){return s===2?n:null},getResponseHeader:function(a){var c;if(s===2){if(!o){o={};while(c=bF.exec(n))o[c[1].toLowerCase()]=c[2]}c=o[a.toLowerCase()]}return c===b?null:c},overrideMimeType:function(a){s||(d.mimeType=a);return this},abort:function(a){a=a||"abort",p&&p.abort(a),w(0,a);return this}};h.promise(v),v.success=v.done,v.error=v.fail,v.complete=i.done,v.statusCode=function(a){if(a){var b;if(s<2)for(b in a)j[b]=[j[b],a[b]];else b=a[v.status],v.then(b,b)}return this},d.url=((a||d.url)+"").replace(bE,"").replace(bJ,bU[1]+"//"),d.dataTypes=f.trim(d.dataType||"*").toLowerCase().split(bN),d.crossDomain==null&&(r=bP.exec(d.url.toLowerCase()),d.crossDomain=!(!r||r[1]==bU[1]&&r[2]==bU[2]&&(r[3]||(r[1]==="http:"?80:443))==(bU[3]||(bU[1]==="http:"?80:443)))),d.data&&d.processData&&typeof d.data!="string"&&(d.data=f.param(d.data,d.traditional)),bX(bR,d,c,v);if(s===2)return!1;t=d.global,d.type=d.type.toUpperCase(),d.hasContent=!bI.test(d.type),t&&f.active++===0&&f.event.trigger("ajaxStart");if(!d.hasContent){d.data&&(d.url+=(bK.test(d.url)?"&":"?")+d.data),k=d.url;if(d.cache===!1){var x=f.now(),y=d.url.replace(bO,"$1_="+x);d.url=y+(y===d.url?(bK.test(d.url)?"&":"?")+"_="+x:"")}}(d.data&&d.hasContent&&d.contentType!==!1||c.contentType)&&v.setRequestHeader("Content-Type",d.contentType),d.ifModified&&(k=k||d.url,f.lastModified[k]&&v.setRequestHeader("If-Modified-Since",f.lastModified[k]),f.etag[k]&&v.setRequestHeader("If-None-Match",f.etag[k])),v.setRequestHeader("Accept",d.dataTypes[0]&&d.accepts[d.dataTypes[0]]?d.accepts[d.dataTypes[0]]+(d.dataTypes[0]!=="*"?", */*; q=0.01":""):d.accepts["*"]);for(u in d.headers)v.setRequestHeader(u,d.headers[u]);if(d.beforeSend&&(d.beforeSend.call(e,v,d)===!1||s===2)){v.abort();return!1}for(u in{success:1,error:1,complete:1})v[u](d[u]);p=bX(bS,d,c,v);if(!p)w(-1,"No Transport");else{v.readyState=1,t&&g.trigger("ajaxSend",[v,d]),d.async&&d.timeout>0&&(q=setTimeout(function(){v.abort("timeout")},d.timeout));try{s=1,p.send(l,w)}catch(z){status<2?w(-1,z):f.error(z)}}return v},param:function(a,c){var d=[],e=function(a,b){b=f.isFunction(b)?b():b,d[d.length]=encodeURIComponent(a)+"="+encodeURIComponent(b)};c===b&&(c=f.ajaxSettings.traditional);if(f.isArray(a)||a.jquery&&!f.isPlainObject(a))f.each(a,function(){e(this.name,this.value)});else for(var g in a)bY(g,a[g],c,e);return d.join("&").replace(bB,"+")}}),f.extend({active:0,lastModified:{},etag:{}});var b_=f.now(),ca=/(\=)\?(&|$)|\?\?/i;f.ajaxSetup({jsonp:"callback",jsonpCallback:function(){return f.expando+"_"+b_++}}),f.ajaxPrefilter("json jsonp",function(b,c,d){var e=b.contentType==="application/x-www-form-urlencoded"&&typeof b.data=="string";if(b.dataTypes[0]==="jsonp"||b.jsonp!==!1&&(ca.test(b.url)||e&&ca.test(b.data))){var g,h=b.jsonpCallback=f.isFunction(b.jsonpCallback)?b.jsonpCallback():b.jsonpCallback,i=a[h],j=b.url,k=b.data,l="$1"+h+"$2";b.jsonp!==!1&&(j=j.replace(ca,l),b.url===j&&(e&&(k=k.replace(ca,l)),b.data===k&&(j+=(/\?/.test(j)?"&":"?")+b.jsonp+"="+h))),b.url=j,b.data=k,a[h]=function(a){g=[a]},d.always(function(){a[h]=i,g&&f.isFunction(i)&&a[h](g[0])}),b.converters["script json"]=function(){g||f.error(h+" was not called");return g[0]},b.dataTypes[0]="json";return"script"}}),f.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/javascript|ecmascript/},converters:{"text script":function(a){f.globalEval(a);return a}}}),f.ajaxPrefilter("script",function(a){a.cache===b&&(a.cache=!1),a.crossDomain&&(a.type="GET",a.global=!1)}),f.ajaxTransport("script",function(a){if(a.crossDomain){var d,e=c.head||c.getElementsByTagName("head")[0]||c.documentElement;return{send:function(f,g){d=c.createElement("script"),d.async="async",a.scriptCharset&&(d.charset=a.scriptCharset),d.src=a.url,d.onload=d.onreadystatechange=function(a,c){if(c||!d.readyState||/loaded|complete/.test(d.readyState))d.onload=d.onreadystatechange=null,e&&d.parentNode&&e.removeChild(d),d=b,c||g(200,"success")},e.insertBefore(d,e.firstChild)},abort:function(){d&&d.onload(0,1)}}}});var cb=a.ActiveXObject?function(){for(var a in cd)cd[a](0,1)}:!1,cc=0,cd;f.ajaxSettings.xhr=a.ActiveXObject?function(){return!this.isLocal&&ce()||cf()}:ce,function(a){f.extend(f.support,{ajax:!!a,cors:!!a&&"withCredentials"in a})}(f.ajaxSettings.xhr()),f.support.ajax&&f.ajaxTransport(function(c){if(!c.crossDomain||f.support.cors){var d;return{send:function(e,g){var h=c.xhr(),i,j;c.username?h.open(c.type,c.url,c.async,c.username,c.password):h.open(c.type,c.url,c.async);if(c.xhrFields)for(j in c.xhrFields)h[j]=c.xhrFields[j];c.mimeType&&h.overrideMimeType&&h.overrideMimeType(c.mimeType),!c.crossDomain&&!e["X-Requested-With"]&&(e["X-Requested-With"]="XMLHttpRequest");try{for(j in e)h.setRequestHeader(j,e[j])}catch(k){}h.send(c.hasContent&&c.data||null),d=function(a,e){var j,k,l,m,n;try{if(d&&(e||h.readyState===4)){d=b,i&&(h.onreadystatechange=f.noop,cb&&delete cd[i]);if(e)h.readyState!==4&&h.abort();else{j=h.status,l=h.getAllResponseHeaders(),m={},n=h.responseXML,n&&n.documentElement&&(m.xml=n),m.text=h.responseText;try{k=h.statusText}catch(o){k=""}!j&&c.isLocal&&!c.crossDomain?j=m.text?200:404:j===1223&&(j=204)}}}catch(p){e||g(-1,p)}m&&g(j,k,m,l)},!c.async||h.readyState===4?d():(i=++cc,cb&&(cd||(cd={},f(a).unload(cb)),cd[i]=d),h.onreadystatechange=d)},abort:function(){d&&d(0,1)}}}});var cg={},ch,ci,cj=/^(?:toggle|show|hide)$/,ck=/^([+\-]=)?([\d+.\-]+)([a-z%]*)$/i,cl,cm=[["height","marginTop","marginBottom","paddingTop","paddingBottom"],["width","marginLeft","marginRight","paddingLeft","paddingRight"],["opacity"]],cn,co=a.webkitRequestAnimationFrame||a.mozRequestAnimationFrame||a.oRequestAnimationFrame;f.fn.extend({show:function(a,b,c){var d,e;if(a||a===0)return this.animate(cr("show",3),a,b,c);for(var g=0,h=this.length;g<h;g++)d=this[g],d.style&&(e=d.style.display,!f._data(d,"olddisplay")&&e==="none"&&(e=d.style.display=""),e===""&&f.css(d,"display")==="none"&&f._data(d,"olddisplay",cs(d.nodeName)));for(g=0;g<h;g++){d=this[g];if(d.style){e=d.style.display;if(e===""||e==="none")d.style.display=f._data(d,"olddisplay")||""}}return this},hide:function(a,b,c){if(a||a===0)return this.animate(cr("hide",3),a,b,c);for(var d=0,e=this.length;d<e;d++)if(this[d].style){var g=f.css(this[d],"display");g!=="none"&&!f._data(this[d],"olddisplay")&&f._data(this[d],"olddisplay",g)}for(d=0;d<e;d++)this[d].style&&(this[d].style.display="none");return this},_toggle:f.fn.toggle,toggle:function(a,b,c){var d=typeof a=="boolean";f.isFunction(a)&&f.isFunction(b)?this._toggle.apply(this,arguments):a==null||d?this.each(function(){var b=d?a:f(this).is(":hidden");f(this)[b?"show":"hide"]()}):this.animate(cr("toggle",3),a,b,c);return this},fadeTo:function(a,b,c,d){return this.filter(":hidden").css("opacity",0).show().end().animate({opacity:b},a,c,d)},animate:function(a,b,c,d){var e=f.speed(b,c,d);if(f.isEmptyObject(a))return this.each(e.complete,[!1]);a=f.extend({},a);return this[e.queue===!1?"each":"queue"](function(){e.queue===!1&&f._mark(this);var b=f.extend({},e),c=this.nodeType===1,d=c&&f(this).is(":hidden"),g,h,i,j,k,l,m,n,o;b.animatedProperties={};for(i in a){g=f.camelCase(i),i!==g&&(a[g]=a[i],delete a[i]),h=a[g],f.isArray(h)?(b.animatedProperties[g]=h[1],h=a[g]=h[0]):b.animatedProperties[g]=b.specialEasing&&b.specialEasing[g]||b.easing||"swing";if(h==="hide"&&d||h==="show"&&!d)return b.complete.call(this);c&&(g==="height"||g==="width")&&(b.overflow=[this.style.overflow,this.style.overflowX,this.style.overflowY],f.css(this,"display")==="inline"&&f.css(this,"float")==="none"&&(f.support.inlineBlockNeedsLayout?(j=cs(this.nodeName),j==="inline"?this.style.display="inline-block":(this.style.display="inline",this.style.zoom=1)):this.style.display="inline-block"))}b.overflow!=null&&(this.style.overflow="hidden");for(i in a)k=new f.fx(this,b,i),h=a[i],cj.test(h)?k[h==="toggle"?d?"show":"hide":h]():(l=ck.exec(h),m=k.cur(),l?(n=parseFloat(l[2]),o=l[3]||(f.cssNumber[i]?"":"px"),o!=="px"&&(f.style(this,i,(n||1)+o),m=(n||1)/k.cur()*m,f.style(this,i,m+o)),l[1]&&(n=(l[1]==="-="?-1:1)*n+m),k.custom(m,n,o)):k.custom(m,h,""));return!0})},stop:function(a,b){a&&this.queue([]),this.each(function(){var a=f.timers,c=a.length;b||f._unmark(!0,this);while(c--)a[c].elem===this&&(b&&a[c](!0),a.splice(c,1))}),b||this.dequeue();return this}}),f.each({slideDown:cr("show",1),slideUp:cr("hide",1),slideToggle:cr("toggle",1),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"},fadeToggle:{opacity:"toggle"}},function(a,b){f.fn[a]=function(a,c,d){return this.animate(b,a,c,d)}}),f.extend({speed:function(a,b,c){var d=a&&typeof a=="object"?f.extend({},a):{complete:c||!c&&b||f.isFunction(a)&&a,duration:a,easing:c&&b||b&&!f.isFunction(b)&&b};d.duration=f.fx.off?0:typeof d.duration=="number"?d.duration:d.duration in f.fx.speeds?f.fx.speeds[d.duration]:f.fx.speeds._default,d.old=d.complete,d.complete=function(a){f.isFunction(d.old)&&d.old.call(this),d.queue!==!1?f.dequeue(this):a!==!1&&f._unmark(this)};return d},easing:{linear:function(a,b,c,d){return c+d*a},swing:function(a,b,c,d){return(-Math.cos(a*Math.PI)/2+.5)*d+c}},timers:[],fx:function(a,b,c){this.options=b,this.elem=a,this.prop=c,b.orig=b.orig||{}}}),f.fx.prototype={update:function(){this.options.step&&this.options.step.call(this.elem,this.now,this),(f.fx.step[this.prop]||f.fx.step._default)(this)},cur:function(){if(this.elem[this.prop]!=null&&(!this.elem.style||this.elem.style[this.prop]==null))return this.elem[this.prop];var a,b=f.css(this.elem,this.prop);return isNaN(a=parseFloat(b))?!b||b==="auto"?0:b:a},custom:function(a,b,c){function h(a){return d.step(a)}var d=this,e=f.fx,g;this.startTime=cn||cp(),this.start=a,this.end=b,this.unit=c||this.unit||(f.cssNumber[this.prop]?"":"px"),this.now=this.start,this.pos=this.state=0,h.elem=this.elem,h()&&f.timers.push(h)&&!cl&&(co?(cl=!0,g=function(){cl&&(co(g),e.tick())},co(g)):cl=setInterval(e.tick,e.interval))},show:function(){this.options.orig[this.prop]=f.style(this.elem,this.prop),this.options.show=!0,this.custom(this.prop==="width"||this.prop==="height"?1:0,this.cur()),f(this.elem).show()},hide:function(){this.options.orig[this.prop]=f.style(this.elem,this.prop),this.options.hide=!0,this.custom(this.cur(),0)},step:function(a){var b=cn||cp(),c=!0,d=this.elem,e=this.options,g,h;if(a||b>=e.duration+this.startTime){this.now=this.end,this.pos=this.state=1,this.update(),e.animatedProperties[this.prop]=!0;for(g in e.animatedProperties)e.animatedProperties[g]!==!0&&(c=!1);if(c){e.overflow!=null&&!f.support.shrinkWrapBlocks&&f.each(["","X","Y"],function(a,b){d.style["overflow"+b]=e.overflow[a]}),e.hide&&f(d).hide();if(e.hide||e.show)for(var i in e.animatedProperties)f.style(d,i,e.orig[i]);e.complete.call(d)}return!1}e.duration==Infinity?this.now=b:(h=b-this.startTime,this.state=h/e.duration,this.pos=f.easing[e.animatedProperties[this.prop]](this.state,h,0,1,e.duration),this.now=this.start+(this.end-this.start)*this.pos),this.update();return!0}},f.extend(f.fx,{tick:function(){for(var a=f.timers,b=0;b<a.length;++b)a[b]()||a.splice(b--,1);a.length||f.fx.stop()},interval:13,stop:function(){clearInterval(cl),cl=null},speeds:{slow:600,fast:200,_default:400},step:{opacity:function(a){f.style(a.elem,"opacity",a.now)},_default:function(a){a.elem.style&&a.elem.style[a.prop]!=null?a.elem.style[a.prop]=(a.prop==="width"||a.prop==="height"?Math.max(0,a.now):a.now)+a.unit:a.elem[a.prop]=a.now}}}),f.expr&&f.expr.filters&&(f.expr.filters.animated=function(a){return f.grep(f.timers,function(b){return a===b.elem}).length});var ct=/^t(?:able|d|h)$/i,cu=/^(?:body|html)$/i;"getBoundingClientRect"in c.documentElement?f.fn.offset=function(a){var b=this[0],c;if(a)return this.each(function(b){f.offset.setOffset(this,a,b)});if(!b||!b.ownerDocument)return null;if(b===b.ownerDocument.body)return f.offset.bodyOffset(b);try{c=b.getBoundingClientRect()}catch(d){}var e=b.ownerDocument,g=e.documentElement;if(!c||!f.contains(g,b))return c?{top:c.top,left:c.left}:{top:0,left:0};var h=e.body,i=cv(e),j=g.clientTop||h.clientTop||0,k=g.clientLeft||h.clientLeft||0,l=i.pageYOffset||f.support.boxModel&&g.scrollTop||h.scrollTop,m=i.pageXOffset||f.support.boxModel&&g.scrollLeft||h.scrollLeft,n=c.top+l-j,o=c.left+m-k;return{top:n,left:o}}:f.fn.offset=function(a){var b=this[0];if(a)return this.each(function(b){f.offset.setOffset(this,a,b)});if(!b||!b.ownerDocument)return null;if(b===b.ownerDocument.body)return f.offset.bodyOffset(b);f.offset.initialize();var c,d=b.offsetParent,e=b,g=b.ownerDocument,h=g.documentElement,i=g.body,j=g.defaultView,k=j?j.getComputedStyle(b,null):b.currentStyle,l=b.offsetTop,m=b.offsetLeft;while((b=b.parentNode)&&b!==i&&b!==h){if(f.offset.supportsFixedPosition&&k.position==="fixed")break;c=j?j.getComputedStyle(b,null):b.currentStyle,l-=b.scrollTop,m-=b.scrollLeft,b===d&&(l+=b.offsetTop,m+=b.offsetLeft,f.offset.doesNotAddBorder&&(!f.offset.doesAddBorderForTableAndCells||!ct.test(b.nodeName))&&(l+=parseFloat(c.borderTopWidth)||0,m+=parseFloat(c.borderLeftWidth)||0),e=d,d=b.offsetParent),f.offset.subtractsBorderForOverflowNotVisible&&c.overflow!=="visible"&&(l+=parseFloat(c.borderTopWidth)||0,m+=parseFloat(c.borderLeftWidth)||0),k=c}if(k.position==="relative"||k.position==="static")l+=i.offsetTop,m+=i.offsetLeft;f.offset.supportsFixedPosition&&k.position==="fixed"&&(l+=Math.max(h.scrollTop,i.scrollTop),m+=Math.max(h.scrollLeft,i.scrollLeft));return{top:l,left:m}},f.offset={initialize:function(){var a=c.body,b=c.createElement("div"),d,e,g,h,i=parseFloat(f.css(a,"marginTop"))||0,j="<div style='position:absolute;top:0;left:0;margin:0;border:5px solid #000;padding:0;width:1px;height:1px;'><div></div></div><table style='position:absolute;top:0;left:0;margin:0;border:5px solid #000;padding:0;width:1px;height:1px;' cellpadding='0' cellspacing='0'><tr><td></td></tr></table>";f.extend(b.style,{position:"absolute",top:0,left:0,margin:0,border:0,width:"1px",height:"1px",visibility:"hidden"}),b.innerHTML=j,a.insertBefore(b,a.firstChild),d=b.firstChild,e=d.firstChild,h=d.nextSibling.firstChild.firstChild,this.doesNotAddBorder=e.offsetTop!==5,this.doesAddBorderForTableAndCells=h.offsetTop===5,e.style.position="fixed",e.style.top="20px",this.supportsFixedPosition=e.offsetTop===20||e.offsetTop===15,e.style.position=e.style.top="",d.style.overflow="hidden",d.style.position="relative",this.subtractsBorderForOverflowNotVisible=e.offsetTop===-5,this.doesNotIncludeMarginInBodyOffset=a.offsetTop!==i,a.removeChild(b),f.offset.initialize=f.noop},bodyOffset:function(a){var b=a.offsetTop,c=a.offsetLeft;f.offset.initialize(),f.offset.doesNotIncludeMarginInBodyOffset&&(b+=parseFloat(f.css(a,"marginTop"))||0,c+=parseFloat(f.css(a,"marginLeft"))||0);return{top:b,left:c}},setOffset:function(a,b,c){var d=f.css(a,"position");d==="static"&&(a.style.position="relative");var e=f(a),g=e.offset(),h=f.css(a,"top"),i=f.css(a,"left"),j=(d==="absolute"||d==="fixed")&&f.inArray("auto",[h,i])>-1,k={},l={},m,n;j?(l=e.position(),m=l.top,n=l.left):(m=parseFloat(h)||0,n=parseFloat(i)||0),f.isFunction(b)&&(b=b.call(a,c,g)),b.top!=null&&(k.top=b.top-g.top+m),b.left!=null&&(k.left=b.left-g.left+n),"using"in b?b.using.call(a,k):e.css(k)}},f.fn.extend({position:function(){if(!this[0])return null;var a=this[0],b=this.offsetParent(),c=this.offset(),d=cu.test(b[0].nodeName)?{top:0,left:0}:b.offset();c.top-=parseFloat(f.css(a,"marginTop"))||0,c.left-=parseFloat(f.css(a,"marginLeft"))||0,d.top+=parseFloat(f.css(b[0],"borderTopWidth"))||0,d.left+=parseFloat(f.css(b[0],"borderLeftWidth"))||0;return{top:c.top-d.top,left:c.left-d.left}},offsetParent:function(){return this.map(function(){var a=this.offsetParent||c.body;while(a&&!cu.test(a.nodeName)&&f.css(a,"position")==="static")a=a.offsetParent;return a})}}),f.each(["Left","Top"],function(a,c){var d="scroll"+c;f.fn[d]=function(c){var e,g;if(c===b){e=this[0];if(!e)return null;g=cv(e);return g?"pageXOffset"in g?g[a?"pageYOffset":"pageXOffset"]:f.support.boxModel&&g.document.documentElement[d]||g.document.body[d]:e[d]}return this.each(function(){g=cv(this),g?g.scrollTo(a?f(g).scrollLeft():c,a?c:f(g).scrollTop()):this[d]=c})}}),f.each(["Height","Width"],function(a,c){var d=c.toLowerCase();f.fn["inner"+c]=function(){var a=this[0];return a&&a.style?parseFloat(f.css(a,d,"padding")):null},f.fn["outer"+c]=function(a){var b=this[0];return b&&b.style?parseFloat(f.css(b,d,a?"margin":"border")):null},f.fn[d]=function(a){var e=this[0];if(!e)return a==null?null:this;if(f.isFunction(a))return this.each(function(b){var c=f(this);c[d](a.call(this,b,c[d]()))});if(f.isWindow(e)){var g=e.document.documentElement["client"+c];return e.document.compatMode==="CSS1Compat"&&g||e.document.body["client"+c]||g}if(e.nodeType===9)return Math.max(e.documentElement["client"+c],e.body["scroll"+c],e.documentElement["scroll"+c],e.body["offset"+c],e.documentElement["offset"+c]);if(a===b){var h=f.css(e,d),i=parseFloat(h);return f.isNaN(i)?h:i}return this.css(d,typeof a=="string"?a:a+"px")}}),a.jQuery=a.$=f})(window);
\ No newline at end of file
diff --git a/vendor/behat/mink/driver-testsuite/web-fixtures/js/jquery-ui-1.8.14.custom.min.js b/vendor/behat/mink/driver-testsuite/web-fixtures/js/jquery-ui-1.8.14.custom.min.js
new file mode 100644
index 00000000000..1764e1129eb
--- /dev/null
+++ b/vendor/behat/mink/driver-testsuite/web-fixtures/js/jquery-ui-1.8.14.custom.min.js
@@ -0,0 +1,127 @@
+/*!
+ * jQuery UI 1.8.14
+ *
+ * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI
+ */
+(function(c,j){function k(a,b){var d=a.nodeName.toLowerCase();if("area"===d){b=a.parentNode;d=b.name;if(!a.href||!d||b.nodeName.toLowerCase()!=="map")return false;a=c("img[usemap=#"+d+"]")[0];return!!a&&l(a)}return(/input|select|textarea|button|object/.test(d)?!a.disabled:"a"==d?a.href||b:b)&&l(a)}function l(a){return!c(a).parents().andSelf().filter(function(){return c.curCSS(this,"visibility")==="hidden"||c.expr.filters.hidden(this)}).length}c.ui=c.ui||{};if(!c.ui.version){c.extend(c.ui,{version:"1.8.14",
+keyCode:{ALT:18,BACKSPACE:8,CAPS_LOCK:20,COMMA:188,COMMAND:91,COMMAND_LEFT:91,COMMAND_RIGHT:93,CONTROL:17,DELETE:46,DOWN:40,END:35,ENTER:13,ESCAPE:27,HOME:36,INSERT:45,LEFT:37,MENU:93,NUMPAD_ADD:107,NUMPAD_DECIMAL:110,NUMPAD_DIVIDE:111,NUMPAD_ENTER:108,NUMPAD_MULTIPLY:106,NUMPAD_SUBTRACT:109,PAGE_DOWN:34,PAGE_UP:33,PERIOD:190,RIGHT:39,SHIFT:16,SPACE:32,TAB:9,UP:38,WINDOWS:91}});c.fn.extend({_focus:c.fn.focus,focus:function(a,b){return typeof a==="number"?this.each(function(){var d=this;setTimeout(function(){c(d).focus();
+b&&b.call(d)},a)}):this._focus.apply(this,arguments)},scrollParent:function(){var a;a=c.browser.msie&&/(static|relative)/.test(this.css("position"))||/absolute/.test(this.css("position"))?this.parents().filter(function(){return/(relative|absolute|fixed)/.test(c.curCSS(this,"position",1))&&/(auto|scroll)/.test(c.curCSS(this,"overflow",1)+c.curCSS(this,"overflow-y",1)+c.curCSS(this,"overflow-x",1))}).eq(0):this.parents().filter(function(){return/(auto|scroll)/.test(c.curCSS(this,"overflow",1)+c.curCSS(this,
+"overflow-y",1)+c.curCSS(this,"overflow-x",1))}).eq(0);return/fixed/.test(this.css("position"))||!a.length?c(document):a},zIndex:function(a){if(a!==j)return this.css("zIndex",a);if(this.length){a=c(this[0]);for(var b;a.length&&a[0]!==document;){b=a.css("position");if(b==="absolute"||b==="relative"||b==="fixed"){b=parseInt(a.css("zIndex"),10);if(!isNaN(b)&&b!==0)return b}a=a.parent()}}return 0},disableSelection:function(){return this.bind((c.support.selectstart?"selectstart":"mousedown")+".ui-disableSelection",
+function(a){a.preventDefault()})},enableSelection:function(){return this.unbind(".ui-disableSelection")}});c.each(["Width","Height"],function(a,b){function d(f,g,m,n){c.each(e,function(){g-=parseFloat(c.curCSS(f,"padding"+this,true))||0;if(m)g-=parseFloat(c.curCSS(f,"border"+this+"Width",true))||0;if(n)g-=parseFloat(c.curCSS(f,"margin"+this,true))||0});return g}var e=b==="Width"?["Left","Right"]:["Top","Bottom"],h=b.toLowerCase(),i={innerWidth:c.fn.innerWidth,innerHeight:c.fn.innerHeight,outerWidth:c.fn.outerWidth,
+outerHeight:c.fn.outerHeight};c.fn["inner"+b]=function(f){if(f===j)return i["inner"+b].call(this);return this.each(function(){c(this).css(h,d(this,f)+"px")})};c.fn["outer"+b]=function(f,g){if(typeof f!=="number")return i["outer"+b].call(this,f);return this.each(function(){c(this).css(h,d(this,f,true,g)+"px")})}});c.extend(c.expr[":"],{data:function(a,b,d){return!!c.data(a,d[3])},focusable:function(a){return k(a,!isNaN(c.attr(a,"tabindex")))},tabbable:function(a){var b=c.attr(a,"tabindex"),d=isNaN(b);
+return(d||b>=0)&&k(a,!d)}});c(function(){var a=document.body,b=a.appendChild(b=document.createElement("div"));c.extend(b.style,{minHeight:"100px",height:"auto",padding:0,borderWidth:0});c.support.minHeight=b.offsetHeight===100;c.support.selectstart="onselectstart"in b;a.removeChild(b).style.display="none"});c.extend(c.ui,{plugin:{add:function(a,b,d){a=c.ui[a].prototype;for(var e in d){a.plugins[e]=a.plugins[e]||[];a.plugins[e].push([b,d[e]])}},call:function(a,b,d){if((b=a.plugins[b])&&a.element[0].parentNode)for(var e=
+0;e<b.length;e++)a.options[b[e][0]]&&b[e][1].apply(a.element,d)}},contains:function(a,b){return document.compareDocumentPosition?a.compareDocumentPosition(b)&16:a!==b&&a.contains(b)},hasScroll:function(a,b){if(c(a).css("overflow")==="hidden")return false;b=b&&b==="left"?"scrollLeft":"scrollTop";var d=false;if(a[b]>0)return true;a[b]=1;d=a[b]>0;a[b]=0;return d},isOverAxis:function(a,b,d){return a>b&&a<b+d},isOver:function(a,b,d,e,h,i){return c.ui.isOverAxis(a,d,h)&&c.ui.isOverAxis(b,e,i)}})}})(jQuery);
+;/*!
+ * jQuery UI Widget 1.8.14
+ *
+ * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI/Widget
+ */
+(function(b,j){if(b.cleanData){var k=b.cleanData;b.cleanData=function(a){for(var c=0,d;(d=a[c])!=null;c++)b(d).triggerHandler("remove");k(a)}}else{var l=b.fn.remove;b.fn.remove=function(a,c){return this.each(function(){if(!c)if(!a||b.filter(a,[this]).length)b("*",this).add([this]).each(function(){b(this).triggerHandler("remove")});return l.call(b(this),a,c)})}}b.widget=function(a,c,d){var e=a.split(".")[0],f;a=a.split(".")[1];f=e+"-"+a;if(!d){d=c;c=b.Widget}b.expr[":"][f]=function(h){return!!b.data(h,
+a)};b[e]=b[e]||{};b[e][a]=function(h,g){arguments.length&&this._createWidget(h,g)};c=new c;c.options=b.extend(true,{},c.options);b[e][a].prototype=b.extend(true,c,{namespace:e,widgetName:a,widgetEventPrefix:b[e][a].prototype.widgetEventPrefix||a,widgetBaseClass:f},d);b.widget.bridge(a,b[e][a])};b.widget.bridge=function(a,c){b.fn[a]=function(d){var e=typeof d==="string",f=Array.prototype.slice.call(arguments,1),h=this;d=!e&&f.length?b.extend.apply(null,[true,d].concat(f)):d;if(e&&d.charAt(0)==="_")return h;
+e?this.each(function(){var g=b.data(this,a),i=g&&b.isFunction(g[d])?g[d].apply(g,f):g;if(i!==g&&i!==j){h=i;return false}}):this.each(function(){var g=b.data(this,a);g?g.option(d||{})._init():b.data(this,a,new c(d,this))});return h}};b.Widget=function(a,c){arguments.length&&this._createWidget(a,c)};b.Widget.prototype={widgetName:"widget",widgetEventPrefix:"",options:{disabled:false},_createWidget:function(a,c){b.data(c,this.widgetName,this);this.element=b(c);this.options=b.extend(true,{},this.options,
+this._getCreateOptions(),a);var d=this;this.element.bind("remove."+this.widgetName,function(){d.destroy()});this._create();this._trigger("create");this._init()},_getCreateOptions:function(){return b.metadata&&b.metadata.get(this.element[0])[this.widgetName]},_create:function(){},_init:function(){},destroy:function(){this.element.unbind("."+this.widgetName).removeData(this.widgetName);this.widget().unbind("."+this.widgetName).removeAttr("aria-disabled").removeClass(this.widgetBaseClass+"-disabled ui-state-disabled")},
+widget:function(){return this.element},option:function(a,c){var d=a;if(arguments.length===0)return b.extend({},this.options);if(typeof a==="string"){if(c===j)return this.options[a];d={};d[a]=c}this._setOptions(d);return this},_setOptions:function(a){var c=this;b.each(a,function(d,e){c._setOption(d,e)});return this},_setOption:function(a,c){this.options[a]=c;if(a==="disabled")this.widget()[c?"addClass":"removeClass"](this.widgetBaseClass+"-disabled ui-state-disabled").attr("aria-disabled",c);return this},
+enable:function(){return this._setOption("disabled",false)},disable:function(){return this._setOption("disabled",true)},_trigger:function(a,c,d){var e=this.options[a];c=b.Event(c);c.type=(a===this.widgetEventPrefix?a:this.widgetEventPrefix+a).toLowerCase();d=d||{};if(c.originalEvent){a=b.event.props.length;for(var f;a;){f=b.event.props[--a];c[f]=c.originalEvent[f]}}this.element.trigger(c,d);return!(b.isFunction(e)&&e.call(this.element[0],c,d)===false||c.isDefaultPrevented())}}})(jQuery);
+;/*!
+ * jQuery UI Mouse 1.8.14
+ *
+ * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI/Mouse
+ *
+ * Depends:
+ *	jquery.ui.widget.js
+ */
+(function(b){var d=false;b(document).mousedown(function(){d=false});b.widget("ui.mouse",{options:{cancel:":input,option",distance:1,delay:0},_mouseInit:function(){var a=this;this.element.bind("mousedown."+this.widgetName,function(c){return a._mouseDown(c)}).bind("click."+this.widgetName,function(c){if(true===b.data(c.target,a.widgetName+".preventClickEvent")){b.removeData(c.target,a.widgetName+".preventClickEvent");c.stopImmediatePropagation();return false}});this.started=false},_mouseDestroy:function(){this.element.unbind("."+
+this.widgetName)},_mouseDown:function(a){if(!d){this._mouseStarted&&this._mouseUp(a);this._mouseDownEvent=a;var c=this,f=a.which==1,g=typeof this.options.cancel=="string"?b(a.target).closest(this.options.cancel).length:false;if(!f||g||!this._mouseCapture(a))return true;this.mouseDelayMet=!this.options.delay;if(!this.mouseDelayMet)this._mouseDelayTimer=setTimeout(function(){c.mouseDelayMet=true},this.options.delay);if(this._mouseDistanceMet(a)&&this._mouseDelayMet(a)){this._mouseStarted=this._mouseStart(a)!==
+false;if(!this._mouseStarted){a.preventDefault();return true}}true===b.data(a.target,this.widgetName+".preventClickEvent")&&b.removeData(a.target,this.widgetName+".preventClickEvent");this._mouseMoveDelegate=function(e){return c._mouseMove(e)};this._mouseUpDelegate=function(e){return c._mouseUp(e)};b(document).bind("mousemove."+this.widgetName,this._mouseMoveDelegate).bind("mouseup."+this.widgetName,this._mouseUpDelegate);a.preventDefault();return d=true}},_mouseMove:function(a){if(b.browser.msie&&
+!(document.documentMode>=9)&&!a.button)return this._mouseUp(a);if(this._mouseStarted){this._mouseDrag(a);return a.preventDefault()}if(this._mouseDistanceMet(a)&&this._mouseDelayMet(a))(this._mouseStarted=this._mouseStart(this._mouseDownEvent,a)!==false)?this._mouseDrag(a):this._mouseUp(a);return!this._mouseStarted},_mouseUp:function(a){b(document).unbind("mousemove."+this.widgetName,this._mouseMoveDelegate).unbind("mouseup."+this.widgetName,this._mouseUpDelegate);if(this._mouseStarted){this._mouseStarted=
+false;a.target==this._mouseDownEvent.target&&b.data(a.target,this.widgetName+".preventClickEvent",true);this._mouseStop(a)}return false},_mouseDistanceMet:function(a){return Math.max(Math.abs(this._mouseDownEvent.pageX-a.pageX),Math.abs(this._mouseDownEvent.pageY-a.pageY))>=this.options.distance},_mouseDelayMet:function(){return this.mouseDelayMet},_mouseStart:function(){},_mouseDrag:function(){},_mouseStop:function(){},_mouseCapture:function(){return true}})})(jQuery);
+;/*
+ * jQuery UI Draggable 1.8.14
+ *
+ * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI/Draggables
+ *
+ * Depends:
+ *	jquery.ui.core.js
+ *	jquery.ui.mouse.js
+ *	jquery.ui.widget.js
+ */
+(function(d){d.widget("ui.draggable",d.ui.mouse,{widgetEventPrefix:"drag",options:{addClasses:true,appendTo:"parent",axis:false,connectToSortable:false,containment:false,cursor:"auto",cursorAt:false,grid:false,handle:false,helper:"original",iframeFix:false,opacity:false,refreshPositions:false,revert:false,revertDuration:500,scope:"default",scroll:true,scrollSensitivity:20,scrollSpeed:20,snap:false,snapMode:"both",snapTolerance:20,stack:false,zIndex:false},_create:function(){if(this.options.helper==
+"original"&&!/^(?:r|a|f)/.test(this.element.css("position")))this.element[0].style.position="relative";this.options.addClasses&&this.element.addClass("ui-draggable");this.options.disabled&&this.element.addClass("ui-draggable-disabled");this._mouseInit()},destroy:function(){if(this.element.data("draggable")){this.element.removeData("draggable").unbind(".draggable").removeClass("ui-draggable ui-draggable-dragging ui-draggable-disabled");this._mouseDestroy();return this}},_mouseCapture:function(a){var b=
+this.options;if(this.helper||b.disabled||d(a.target).is(".ui-resizable-handle"))return false;this.handle=this._getHandle(a);if(!this.handle)return false;d(b.iframeFix===true?"iframe":b.iframeFix).each(function(){d('<div class="ui-draggable-iframeFix" style="background: #fff;"></div>').css({width:this.offsetWidth+"px",height:this.offsetHeight+"px",position:"absolute",opacity:"0.001",zIndex:1E3}).css(d(this).offset()).appendTo("body")});return true},_mouseStart:function(a){var b=this.options;this.helper=
+this._createHelper(a);this._cacheHelperProportions();if(d.ui.ddmanager)d.ui.ddmanager.current=this;this._cacheMargins();this.cssPosition=this.helper.css("position");this.scrollParent=this.helper.scrollParent();this.offset=this.positionAbs=this.element.offset();this.offset={top:this.offset.top-this.margins.top,left:this.offset.left-this.margins.left};d.extend(this.offset,{click:{left:a.pageX-this.offset.left,top:a.pageY-this.offset.top},parent:this._getParentOffset(),relative:this._getRelativeOffset()});
+this.originalPosition=this.position=this._generatePosition(a);this.originalPageX=a.pageX;this.originalPageY=a.pageY;b.cursorAt&&this._adjustOffsetFromHelper(b.cursorAt);b.containment&&this._setContainment();if(this._trigger("start",a)===false){this._clear();return false}this._cacheHelperProportions();d.ui.ddmanager&&!b.dropBehaviour&&d.ui.ddmanager.prepareOffsets(this,a);this.helper.addClass("ui-draggable-dragging");this._mouseDrag(a,true);d.ui.ddmanager&&d.ui.ddmanager.dragStart(this,a);return true},
+_mouseDrag:function(a,b){this.position=this._generatePosition(a);this.positionAbs=this._convertPositionTo("absolute");if(!b){b=this._uiHash();if(this._trigger("drag",a,b)===false){this._mouseUp({});return false}this.position=b.position}if(!this.options.axis||this.options.axis!="y")this.helper[0].style.left=this.position.left+"px";if(!this.options.axis||this.options.axis!="x")this.helper[0].style.top=this.position.top+"px";d.ui.ddmanager&&d.ui.ddmanager.drag(this,a);return false},_mouseStop:function(a){var b=
+false;if(d.ui.ddmanager&&!this.options.dropBehaviour)b=d.ui.ddmanager.drop(this,a);if(this.dropped){b=this.dropped;this.dropped=false}if((!this.element[0]||!this.element[0].parentNode)&&this.options.helper=="original")return false;if(this.options.revert=="invalid"&&!b||this.options.revert=="valid"&&b||this.options.revert===true||d.isFunction(this.options.revert)&&this.options.revert.call(this.element,b)){var c=this;d(this.helper).animate(this.originalPosition,parseInt(this.options.revertDuration,
+10),function(){c._trigger("stop",a)!==false&&c._clear()})}else this._trigger("stop",a)!==false&&this._clear();return false},_mouseUp:function(a){this.options.iframeFix===true&&d("div.ui-draggable-iframeFix").each(function(){this.parentNode.removeChild(this)});d.ui.ddmanager&&d.ui.ddmanager.dragStop(this,a);return d.ui.mouse.prototype._mouseUp.call(this,a)},cancel:function(){this.helper.is(".ui-draggable-dragging")?this._mouseUp({}):this._clear();return this},_getHandle:function(a){var b=!this.options.handle||
+!d(this.options.handle,this.element).length?true:false;d(this.options.handle,this.element).find("*").andSelf().each(function(){if(this==a.target)b=true});return b},_createHelper:function(a){var b=this.options;a=d.isFunction(b.helper)?d(b.helper.apply(this.element[0],[a])):b.helper=="clone"?this.element.clone().removeAttr("id"):this.element;a.parents("body").length||a.appendTo(b.appendTo=="parent"?this.element[0].parentNode:b.appendTo);a[0]!=this.element[0]&&!/(fixed|absolute)/.test(a.css("position"))&&
+a.css("position","absolute");return a},_adjustOffsetFromHelper:function(a){if(typeof a=="string")a=a.split(" ");if(d.isArray(a))a={left:+a[0],top:+a[1]||0};if("left"in a)this.offset.click.left=a.left+this.margins.left;if("right"in a)this.offset.click.left=this.helperProportions.width-a.right+this.margins.left;if("top"in a)this.offset.click.top=a.top+this.margins.top;if("bottom"in a)this.offset.click.top=this.helperProportions.height-a.bottom+this.margins.top},_getParentOffset:function(){this.offsetParent=
+this.helper.offsetParent();var a=this.offsetParent.offset();if(this.cssPosition=="absolute"&&this.scrollParent[0]!=document&&d.ui.contains(this.scrollParent[0],this.offsetParent[0])){a.left+=this.scrollParent.scrollLeft();a.top+=this.scrollParent.scrollTop()}if(this.offsetParent[0]==document.body||this.offsetParent[0].tagName&&this.offsetParent[0].tagName.toLowerCase()=="html"&&d.browser.msie)a={top:0,left:0};return{top:a.top+(parseInt(this.offsetParent.css("borderTopWidth"),10)||0),left:a.left+(parseInt(this.offsetParent.css("borderLeftWidth"),
+10)||0)}},_getRelativeOffset:function(){if(this.cssPosition=="relative"){var a=this.element.position();return{top:a.top-(parseInt(this.helper.css("top"),10)||0)+this.scrollParent.scrollTop(),left:a.left-(parseInt(this.helper.css("left"),10)||0)+this.scrollParent.scrollLeft()}}else return{top:0,left:0}},_cacheMargins:function(){this.margins={left:parseInt(this.element.css("marginLeft"),10)||0,top:parseInt(this.element.css("marginTop"),10)||0,right:parseInt(this.element.css("marginRight"),10)||0,bottom:parseInt(this.element.css("marginBottom"),
+10)||0}},_cacheHelperProportions:function(){this.helperProportions={width:this.helper.outerWidth(),height:this.helper.outerHeight()}},_setContainment:function(){var a=this.options;if(a.containment=="parent")a.containment=this.helper[0].parentNode;if(a.containment=="document"||a.containment=="window")this.containment=[a.containment=="document"?0:d(window).scrollLeft()-this.offset.relative.left-this.offset.parent.left,a.containment=="document"?0:d(window).scrollTop()-this.offset.relative.top-this.offset.parent.top,
+(a.containment=="document"?0:d(window).scrollLeft())+d(a.containment=="document"?document:window).width()-this.helperProportions.width-this.margins.left,(a.containment=="document"?0:d(window).scrollTop())+(d(a.containment=="document"?document:window).height()||document.body.parentNode.scrollHeight)-this.helperProportions.height-this.margins.top];if(!/^(document|window|parent)$/.test(a.containment)&&a.containment.constructor!=Array){a=d(a.containment);var b=a[0];if(b){a.offset();var c=d(b).css("overflow")!=
+"hidden";this.containment=[(parseInt(d(b).css("borderLeftWidth"),10)||0)+(parseInt(d(b).css("paddingLeft"),10)||0),(parseInt(d(b).css("borderTopWidth"),10)||0)+(parseInt(d(b).css("paddingTop"),10)||0),(c?Math.max(b.scrollWidth,b.offsetWidth):b.offsetWidth)-(parseInt(d(b).css("borderLeftWidth"),10)||0)-(parseInt(d(b).css("paddingRight"),10)||0)-this.helperProportions.width-this.margins.left-this.margins.right,(c?Math.max(b.scrollHeight,b.offsetHeight):b.offsetHeight)-(parseInt(d(b).css("borderTopWidth"),
+10)||0)-(parseInt(d(b).css("paddingBottom"),10)||0)-this.helperProportions.height-this.margins.top-this.margins.bottom];this.relative_container=a}}else if(a.containment.constructor==Array)this.containment=a.containment},_convertPositionTo:function(a,b){if(!b)b=this.position;a=a=="absolute"?1:-1;var c=this.cssPosition=="absolute"&&!(this.scrollParent[0]!=document&&d.ui.contains(this.scrollParent[0],this.offsetParent[0]))?this.offsetParent:this.scrollParent,f=/(html|body)/i.test(c[0].tagName);return{top:b.top+
+this.offset.relative.top*a+this.offset.parent.top*a-(d.browser.safari&&d.browser.version<526&&this.cssPosition=="fixed"?0:(this.cssPosition=="fixed"?-this.scrollParent.scrollTop():f?0:c.scrollTop())*a),left:b.left+this.offset.relative.left*a+this.offset.parent.left*a-(d.browser.safari&&d.browser.version<526&&this.cssPosition=="fixed"?0:(this.cssPosition=="fixed"?-this.scrollParent.scrollLeft():f?0:c.scrollLeft())*a)}},_generatePosition:function(a){var b=this.options,c=this.cssPosition=="absolute"&&
+!(this.scrollParent[0]!=document&&d.ui.contains(this.scrollParent[0],this.offsetParent[0]))?this.offsetParent:this.scrollParent,f=/(html|body)/i.test(c[0].tagName),e=a.pageX,h=a.pageY;if(this.originalPosition){var g;if(this.containment){if(this.relative_container){g=this.relative_container.offset();g=[this.containment[0]+g.left,this.containment[1]+g.top,this.containment[2]+g.left,this.containment[3]+g.top]}else g=this.containment;if(a.pageX-this.offset.click.left<g[0])e=g[0]+this.offset.click.left;
+if(a.pageY-this.offset.click.top<g[1])h=g[1]+this.offset.click.top;if(a.pageX-this.offset.click.left>g[2])e=g[2]+this.offset.click.left;if(a.pageY-this.offset.click.top>g[3])h=g[3]+this.offset.click.top}if(b.grid){h=b.grid[1]?this.originalPageY+Math.round((h-this.originalPageY)/b.grid[1])*b.grid[1]:this.originalPageY;h=g?!(h-this.offset.click.top<g[1]||h-this.offset.click.top>g[3])?h:!(h-this.offset.click.top<g[1])?h-b.grid[1]:h+b.grid[1]:h;e=b.grid[0]?this.originalPageX+Math.round((e-this.originalPageX)/
+b.grid[0])*b.grid[0]:this.originalPageX;e=g?!(e-this.offset.click.left<g[0]||e-this.offset.click.left>g[2])?e:!(e-this.offset.click.left<g[0])?e-b.grid[0]:e+b.grid[0]:e}}return{top:h-this.offset.click.top-this.offset.relative.top-this.offset.parent.top+(d.browser.safari&&d.browser.version<526&&this.cssPosition=="fixed"?0:this.cssPosition=="fixed"?-this.scrollParent.scrollTop():f?0:c.scrollTop()),left:e-this.offset.click.left-this.offset.relative.left-this.offset.parent.left+(d.browser.safari&&d.browser.version<
+526&&this.cssPosition=="fixed"?0:this.cssPosition=="fixed"?-this.scrollParent.scrollLeft():f?0:c.scrollLeft())}},_clear:function(){this.helper.removeClass("ui-draggable-dragging");this.helper[0]!=this.element[0]&&!this.cancelHelperRemoval&&this.helper.remove();this.helper=null;this.cancelHelperRemoval=false},_trigger:function(a,b,c){c=c||this._uiHash();d.ui.plugin.call(this,a,[b,c]);if(a=="drag")this.positionAbs=this._convertPositionTo("absolute");return d.Widget.prototype._trigger.call(this,a,b,
+c)},plugins:{},_uiHash:function(){return{helper:this.helper,position:this.position,originalPosition:this.originalPosition,offset:this.positionAbs}}});d.extend(d.ui.draggable,{version:"1.8.14"});d.ui.plugin.add("draggable","connectToSortable",{start:function(a,b){var c=d(this).data("draggable"),f=c.options,e=d.extend({},b,{item:c.element});c.sortables=[];d(f.connectToSortable).each(function(){var h=d.data(this,"sortable");if(h&&!h.options.disabled){c.sortables.push({instance:h,shouldRevert:h.options.revert});
+h.refreshPositions();h._trigger("activate",a,e)}})},stop:function(a,b){var c=d(this).data("draggable"),f=d.extend({},b,{item:c.element});d.each(c.sortables,function(){if(this.instance.isOver){this.instance.isOver=0;c.cancelHelperRemoval=true;this.instance.cancelHelperRemoval=false;if(this.shouldRevert)this.instance.options.revert=true;this.instance._mouseStop(a);this.instance.options.helper=this.instance.options._helper;c.options.helper=="original"&&this.instance.currentItem.css({top:"auto",left:"auto"})}else{this.instance.cancelHelperRemoval=
+false;this.instance._trigger("deactivate",a,f)}})},drag:function(a,b){var c=d(this).data("draggable"),f=this;d.each(c.sortables,function(){this.instance.positionAbs=c.positionAbs;this.instance.helperProportions=c.helperProportions;this.instance.offset.click=c.offset.click;if(this.instance._intersectsWith(this.instance.containerCache)){if(!this.instance.isOver){this.instance.isOver=1;this.instance.currentItem=d(f).clone().removeAttr("id").appendTo(this.instance.element).data("sortable-item",true);
+this.instance.options._helper=this.instance.options.helper;this.instance.options.helper=function(){return b.helper[0]};a.target=this.instance.currentItem[0];this.instance._mouseCapture(a,true);this.instance._mouseStart(a,true,true);this.instance.offset.click.top=c.offset.click.top;this.instance.offset.click.left=c.offset.click.left;this.instance.offset.parent.left-=c.offset.parent.left-this.instance.offset.parent.left;this.instance.offset.parent.top-=c.offset.parent.top-this.instance.offset.parent.top;
+c._trigger("toSortable",a);c.dropped=this.instance.element;c.currentItem=c.element;this.instance.fromOutside=c}this.instance.currentItem&&this.instance._mouseDrag(a)}else if(this.instance.isOver){this.instance.isOver=0;this.instance.cancelHelperRemoval=true;this.instance.options.revert=false;this.instance._trigger("out",a,this.instance._uiHash(this.instance));this.instance._mouseStop(a,true);this.instance.options.helper=this.instance.options._helper;this.instance.currentItem.remove();this.instance.placeholder&&
+this.instance.placeholder.remove();c._trigger("fromSortable",a);c.dropped=false}})}});d.ui.plugin.add("draggable","cursor",{start:function(){var a=d("body"),b=d(this).data("draggable").options;if(a.css("cursor"))b._cursor=a.css("cursor");a.css("cursor",b.cursor)},stop:function(){var a=d(this).data("draggable").options;a._cursor&&d("body").css("cursor",a._cursor)}});d.ui.plugin.add("draggable","opacity",{start:function(a,b){a=d(b.helper);b=d(this).data("draggable").options;if(a.css("opacity"))b._opacity=
+a.css("opacity");a.css("opacity",b.opacity)},stop:function(a,b){a=d(this).data("draggable").options;a._opacity&&d(b.helper).css("opacity",a._opacity)}});d.ui.plugin.add("draggable","scroll",{start:function(){var a=d(this).data("draggable");if(a.scrollParent[0]!=document&&a.scrollParent[0].tagName!="HTML")a.overflowOffset=a.scrollParent.offset()},drag:function(a){var b=d(this).data("draggable"),c=b.options,f=false;if(b.scrollParent[0]!=document&&b.scrollParent[0].tagName!="HTML"){if(!c.axis||c.axis!=
+"x")if(b.overflowOffset.top+b.scrollParent[0].offsetHeight-a.pageY<c.scrollSensitivity)b.scrollParent[0].scrollTop=f=b.scrollParent[0].scrollTop+c.scrollSpeed;else if(a.pageY-b.overflowOffset.top<c.scrollSensitivity)b.scrollParent[0].scrollTop=f=b.scrollParent[0].scrollTop-c.scrollSpeed;if(!c.axis||c.axis!="y")if(b.overflowOffset.left+b.scrollParent[0].offsetWidth-a.pageX<c.scrollSensitivity)b.scrollParent[0].scrollLeft=f=b.scrollParent[0].scrollLeft+c.scrollSpeed;else if(a.pageX-b.overflowOffset.left<
+c.scrollSensitivity)b.scrollParent[0].scrollLeft=f=b.scrollParent[0].scrollLeft-c.scrollSpeed}else{if(!c.axis||c.axis!="x")if(a.pageY-d(document).scrollTop()<c.scrollSensitivity)f=d(document).scrollTop(d(document).scrollTop()-c.scrollSpeed);else if(d(window).height()-(a.pageY-d(document).scrollTop())<c.scrollSensitivity)f=d(document).scrollTop(d(document).scrollTop()+c.scrollSpeed);if(!c.axis||c.axis!="y")if(a.pageX-d(document).scrollLeft()<c.scrollSensitivity)f=d(document).scrollLeft(d(document).scrollLeft()-
+c.scrollSpeed);else if(d(window).width()-(a.pageX-d(document).scrollLeft())<c.scrollSensitivity)f=d(document).scrollLeft(d(document).scrollLeft()+c.scrollSpeed)}f!==false&&d.ui.ddmanager&&!c.dropBehaviour&&d.ui.ddmanager.prepareOffsets(b,a)}});d.ui.plugin.add("draggable","snap",{start:function(){var a=d(this).data("draggable"),b=a.options;a.snapElements=[];d(b.snap.constructor!=String?b.snap.items||":data(draggable)":b.snap).each(function(){var c=d(this),f=c.offset();this!=a.element[0]&&a.snapElements.push({item:this,
+width:c.outerWidth(),height:c.outerHeight(),top:f.top,left:f.left})})},drag:function(a,b){for(var c=d(this).data("draggable"),f=c.options,e=f.snapTolerance,h=b.offset.left,g=h+c.helperProportions.width,n=b.offset.top,o=n+c.helperProportions.height,i=c.snapElements.length-1;i>=0;i--){var j=c.snapElements[i].left,l=j+c.snapElements[i].width,k=c.snapElements[i].top,m=k+c.snapElements[i].height;if(j-e<h&&h<l+e&&k-e<n&&n<m+e||j-e<h&&h<l+e&&k-e<o&&o<m+e||j-e<g&&g<l+e&&k-e<n&&n<m+e||j-e<g&&g<l+e&&k-e<o&&
+o<m+e){if(f.snapMode!="inner"){var p=Math.abs(k-o)<=e,q=Math.abs(m-n)<=e,r=Math.abs(j-g)<=e,s=Math.abs(l-h)<=e;if(p)b.position.top=c._convertPositionTo("relative",{top:k-c.helperProportions.height,left:0}).top-c.margins.top;if(q)b.position.top=c._convertPositionTo("relative",{top:m,left:0}).top-c.margins.top;if(r)b.position.left=c._convertPositionTo("relative",{top:0,left:j-c.helperProportions.width}).left-c.margins.left;if(s)b.position.left=c._convertPositionTo("relative",{top:0,left:l}).left-c.margins.left}var t=
+p||q||r||s;if(f.snapMode!="outer"){p=Math.abs(k-n)<=e;q=Math.abs(m-o)<=e;r=Math.abs(j-h)<=e;s=Math.abs(l-g)<=e;if(p)b.position.top=c._convertPositionTo("relative",{top:k,left:0}).top-c.margins.top;if(q)b.position.top=c._convertPositionTo("relative",{top:m-c.helperProportions.height,left:0}).top-c.margins.top;if(r)b.position.left=c._convertPositionTo("relative",{top:0,left:j}).left-c.margins.left;if(s)b.position.left=c._convertPositionTo("relative",{top:0,left:l-c.helperProportions.width}).left-c.margins.left}if(!c.snapElements[i].snapping&&
+(p||q||r||s||t))c.options.snap.snap&&c.options.snap.snap.call(c.element,a,d.extend(c._uiHash(),{snapItem:c.snapElements[i].item}));c.snapElements[i].snapping=p||q||r||s||t}else{c.snapElements[i].snapping&&c.options.snap.release&&c.options.snap.release.call(c.element,a,d.extend(c._uiHash(),{snapItem:c.snapElements[i].item}));c.snapElements[i].snapping=false}}}});d.ui.plugin.add("draggable","stack",{start:function(){var a=d(this).data("draggable").options;a=d.makeArray(d(a.stack)).sort(function(c,f){return(parseInt(d(c).css("zIndex"),
+10)||0)-(parseInt(d(f).css("zIndex"),10)||0)});if(a.length){var b=parseInt(a[0].style.zIndex)||0;d(a).each(function(c){this.style.zIndex=b+c});this[0].style.zIndex=b+a.length}}});d.ui.plugin.add("draggable","zIndex",{start:function(a,b){a=d(b.helper);b=d(this).data("draggable").options;if(a.css("zIndex"))b._zIndex=a.css("zIndex");a.css("zIndex",b.zIndex)},stop:function(a,b){a=d(this).data("draggable").options;a._zIndex&&d(b.helper).css("zIndex",a._zIndex)}})})(jQuery);
+;/*
+ * jQuery UI Droppable 1.8.14
+ *
+ * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI/Droppables
+ *
+ * Depends:
+ *	jquery.ui.core.js
+ *	jquery.ui.widget.js
+ *	jquery.ui.mouse.js
+ *	jquery.ui.draggable.js
+ */
+(function(d){d.widget("ui.droppable",{widgetEventPrefix:"drop",options:{accept:"*",activeClass:false,addClasses:true,greedy:false,hoverClass:false,scope:"default",tolerance:"intersect"},_create:function(){var a=this.options,b=a.accept;this.isover=0;this.isout=1;this.accept=d.isFunction(b)?b:function(c){return c.is(b)};this.proportions={width:this.element[0].offsetWidth,height:this.element[0].offsetHeight};d.ui.ddmanager.droppables[a.scope]=d.ui.ddmanager.droppables[a.scope]||[];d.ui.ddmanager.droppables[a.scope].push(this);
+a.addClasses&&this.element.addClass("ui-droppable")},destroy:function(){for(var a=d.ui.ddmanager.droppables[this.options.scope],b=0;b<a.length;b++)a[b]==this&&a.splice(b,1);this.element.removeClass("ui-droppable ui-droppable-disabled").removeData("droppable").unbind(".droppable");return this},_setOption:function(a,b){if(a=="accept")this.accept=d.isFunction(b)?b:function(c){return c.is(b)};d.Widget.prototype._setOption.apply(this,arguments)},_activate:function(a){var b=d.ui.ddmanager.current;this.options.activeClass&&
+this.element.addClass(this.options.activeClass);b&&this._trigger("activate",a,this.ui(b))},_deactivate:function(a){var b=d.ui.ddmanager.current;this.options.activeClass&&this.element.removeClass(this.options.activeClass);b&&this._trigger("deactivate",a,this.ui(b))},_over:function(a){var b=d.ui.ddmanager.current;if(!(!b||(b.currentItem||b.element)[0]==this.element[0]))if(this.accept.call(this.element[0],b.currentItem||b.element)){this.options.hoverClass&&this.element.addClass(this.options.hoverClass);
+this._trigger("over",a,this.ui(b))}},_out:function(a){var b=d.ui.ddmanager.current;if(!(!b||(b.currentItem||b.element)[0]==this.element[0]))if(this.accept.call(this.element[0],b.currentItem||b.element)){this.options.hoverClass&&this.element.removeClass(this.options.hoverClass);this._trigger("out",a,this.ui(b))}},_drop:function(a,b){var c=b||d.ui.ddmanager.current;if(!c||(c.currentItem||c.element)[0]==this.element[0])return false;var e=false;this.element.find(":data(droppable)").not(".ui-draggable-dragging").each(function(){var g=
+d.data(this,"droppable");if(g.options.greedy&&!g.options.disabled&&g.options.scope==c.options.scope&&g.accept.call(g.element[0],c.currentItem||c.element)&&d.ui.intersect(c,d.extend(g,{offset:g.element.offset()}),g.options.tolerance)){e=true;return false}});if(e)return false;if(this.accept.call(this.element[0],c.currentItem||c.element)){this.options.activeClass&&this.element.removeClass(this.options.activeClass);this.options.hoverClass&&this.element.removeClass(this.options.hoverClass);this._trigger("drop",
+a,this.ui(c));return this.element}return false},ui:function(a){return{draggable:a.currentItem||a.element,helper:a.helper,position:a.position,offset:a.positionAbs}}});d.extend(d.ui.droppable,{version:"1.8.14"});d.ui.intersect=function(a,b,c){if(!b.offset)return false;var e=(a.positionAbs||a.position.absolute).left,g=e+a.helperProportions.width,f=(a.positionAbs||a.position.absolute).top,h=f+a.helperProportions.height,i=b.offset.left,k=i+b.proportions.width,j=b.offset.top,l=j+b.proportions.height;
+switch(c){case "fit":return i<=e&&g<=k&&j<=f&&h<=l;case "intersect":return i<e+a.helperProportions.width/2&&g-a.helperProportions.width/2<k&&j<f+a.helperProportions.height/2&&h-a.helperProportions.height/2<l;case "pointer":return d.ui.isOver((a.positionAbs||a.position.absolute).top+(a.clickOffset||a.offset.click).top,(a.positionAbs||a.position.absolute).left+(a.clickOffset||a.offset.click).left,j,i,b.proportions.height,b.proportions.width);case "touch":return(f>=j&&f<=l||h>=j&&h<=l||f<j&&h>l)&&(e>=
+i&&e<=k||g>=i&&g<=k||e<i&&g>k);default:return false}};d.ui.ddmanager={current:null,droppables:{"default":[]},prepareOffsets:function(a,b){var c=d.ui.ddmanager.droppables[a.options.scope]||[],e=b?b.type:null,g=(a.currentItem||a.element).find(":data(droppable)").andSelf(),f=0;a:for(;f<c.length;f++)if(!(c[f].options.disabled||a&&!c[f].accept.call(c[f].element[0],a.currentItem||a.element))){for(var h=0;h<g.length;h++)if(g[h]==c[f].element[0]){c[f].proportions.height=0;continue a}c[f].visible=c[f].element.css("display")!=
+"none";if(c[f].visible){e=="mousedown"&&c[f]._activate.call(c[f],b);c[f].offset=c[f].element.offset();c[f].proportions={width:c[f].element[0].offsetWidth,height:c[f].element[0].offsetHeight}}}},drop:function(a,b){var c=false;d.each(d.ui.ddmanager.droppables[a.options.scope]||[],function(){if(this.options){if(!this.options.disabled&&this.visible&&d.ui.intersect(a,this,this.options.tolerance))c=c||this._drop.call(this,b);if(!this.options.disabled&&this.visible&&this.accept.call(this.element[0],a.currentItem||
+a.element)){this.isout=1;this.isover=0;this._deactivate.call(this,b)}}});return c},dragStart:function(a,b){a.element.parentsUntil("body").bind("scroll.droppable",function(){a.options.refreshPositions||d.ui.ddmanager.prepareOffsets(a,b)})},drag:function(a,b){a.options.refreshPositions&&d.ui.ddmanager.prepareOffsets(a,b);d.each(d.ui.ddmanager.droppables[a.options.scope]||[],function(){if(!(this.options.disabled||this.greedyChild||!this.visible)){var c=d.ui.intersect(a,this,this.options.tolerance);if(c=
+!c&&this.isover==1?"isout":c&&this.isover==0?"isover":null){var e;if(this.options.greedy){var g=this.element.parents(":data(droppable):eq(0)");if(g.length){e=d.data(g[0],"droppable");e.greedyChild=c=="isover"?1:0}}if(e&&c=="isover"){e.isover=0;e.isout=1;e._out.call(e,b)}this[c]=1;this[c=="isout"?"isover":"isout"]=0;this[c=="isover"?"_over":"_out"].call(this,b);if(e&&c=="isout"){e.isout=0;e.isover=1;e._over.call(e,b)}}}})},dragStop:function(a,b){a.element.parentsUntil("body").unbind("scroll.droppable");
+a.options.refreshPositions||d.ui.ddmanager.prepareOffsets(a,b)}}})(jQuery);
+;
\ No newline at end of file
diff --git a/vendor/behat/mink/driver-testsuite/web-fixtures/js_test.html b/vendor/behat/mink/driver-testsuite/web-fixtures/js_test.html
new file mode 100644
index 00000000000..e965a40881e
--- /dev/null
+++ b/vendor/behat/mink/driver-testsuite/web-fixtures/js_test.html
@@ -0,0 +1,110 @@
+<!DOCTYPE html>
+<html>
+<head>
+    <title>JS elements test</title>
+    <meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/>
+
+    <style>
+        #draggable {
+            width: 100px; height: 100px; padding: 0.5em; float: left; margin: 10px 10px 10px 0;
+            background:#ccc;
+            opacity:0.5;
+        }
+        #droppable {
+            width: 150px; height: 150px; padding: 0.5em; float: left; margin: 10px;
+            background:#eee;
+        }
+        #waitable {
+            width: 150px; height: 150px; padding: 0.5em; float: left; margin: 10px;
+            background:#eee;
+        }
+    </style>
+</head>
+<body>
+    <div class="elements">
+        <div id="clicker">not clicked</div>
+        <div id="mouseover-detector">no mouse action detected</div>
+        <div id="invisible" style="display: none">invisible man</div>
+        <input id="focus-blur-detector" type="text" value="no action detected"/>
+        <input class="input first" type="text" value="" />
+        <input class="input second" type="text" value="" />
+        <input class="input third" type="text" value="" />
+        <div class="text-event"></div>
+    </div>
+
+    <div id="draggable" class="ui-widget-content"></div>
+
+    <div id="droppable" class="ui-widget-header">
+        <p>Drop here</p>
+    </div>
+
+    <div id="waitable"></div>
+
+    <script src="js/jquery-1.6.2-min.js"></script>
+    <script src="js/jquery-ui-1.8.14.custom.min.js"></script>
+	<script>
+		$(document).ready(function() {
+            $('#clicker').click(function() {
+                $(this).text('single clicked');
+            });
+
+            $('#clicker').dblclick(function() {
+                $(this).text('double clicked');
+            });
+
+            $('#clicker').bind('contextmenu', function() {
+                $(this).text('right clicked');
+            });
+
+            $('#focus-blur-detector').focus(function() {
+                $(this).val('focused');
+            });
+
+            $('#focus-blur-detector').blur(function() {
+                $(this).val('blured');
+            });
+
+            $('#mouseover-detector').mouseover(function() {
+                $(this).text('mouse overed');
+            });
+
+            $('.elements input.input.first').keydown(function(ev) {
+                $('.text-event').text('key downed:' + ev.altKey * 1 + ' / ' + ev.ctrlKey * 1 + ' / ' + ev.shiftKey * 1 + ' / ' + ev.metaKey * 1);
+            });
+
+            $('.elements input.input.second').keypress(function(ev) {
+                $('.text-event').text('key pressed:' + ev.which + ' / ' + ev.altKey * 1 + ' / ' + ev.ctrlKey * 1 + ' / ' + ev.shiftKey * 1 + ' / ' + ev.metaKey * 1);
+            });
+
+            $('.elements input.input.third').keyup(function(ev) {
+                $('.text-event').text('key upped:' + ev.which + ' / ' + ev.altKey * 1 + ' / ' + ev.ctrlKey * 1 + ' / ' + ev.shiftKey * 1 + ' / ' + ev.metaKey * 1);
+            });
+
+            $( "#draggable" ).draggable();
+            $( "#droppable" ).droppable({
+                drop: function( event, ui ) {
+                    $( this ).find( "p" ).html( "Dropped!" );
+                }
+            });
+
+            var t1, t2;
+
+            $('#waitable').click(function() {
+                var el = $(this);
+
+                el.html('');
+                clearTimeout(t1);
+                clearTimeout(t2);
+
+                t1 = setTimeout(function() {
+                    el.html('<div>arrived</div>');
+                }, 1000);
+
+                t2 = setTimeout(function() {
+                    el.html('<div>timeout</div>');
+                }, 2000);
+            });
+		});
+	</script>
+</body>
+</html>
diff --git a/vendor/behat/mink/driver-testsuite/web-fixtures/json.php b/vendor/behat/mink/driver-testsuite/web-fixtures/json.php
new file mode 100644
index 00000000000..173d35820d4
--- /dev/null
+++ b/vendor/behat/mink/driver-testsuite/web-fixtures/json.php
@@ -0,0 +1,7 @@
+<?php
+
+echo json_encode(array(
+    'key1' => 'val1',
+    'key2' => 234,
+    'key3' => array(1, 2, 3)
+));
diff --git a/vendor/behat/mink/driver-testsuite/web-fixtures/links.html b/vendor/behat/mink/driver-testsuite/web-fixtures/links.html
new file mode 100644
index 00000000000..ec626bfa9aa
--- /dev/null
+++ b/vendor/behat/mink/driver-testsuite/web-fixtures/links.html
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<html>
+<head>
+    <title>Links page</title>
+    <meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/>
+</head>
+<body>
+    <a href="redirector.php">Redirect me to</a>
+    <a href="randomizer.php">Random number page</a>
+    <a href="links.html?quoted">Link with a '</a>
+    <a href="basic_form.html">
+        <img src="basic_form" alt="basic form image"/>
+    </a>
+</body>
+</html>
diff --git a/vendor/behat/mink/driver-testsuite/web-fixtures/multi_input_form.html b/vendor/behat/mink/driver-testsuite/web-fixtures/multi_input_form.html
new file mode 100644
index 00000000000..600a500c26a
--- /dev/null
+++ b/vendor/behat/mink/driver-testsuite/web-fixtures/multi_input_form.html
@@ -0,0 +1,27 @@
+<!DOCTYPE html>
+<html>
+<head>
+    <title>Multi input Test</title>
+    <meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/>
+</head>
+<body>
+    <h1>Multi input Test</h1>
+
+    <form method="POST" action="advanced_form_post.php">
+        <label>
+            First
+            <input type="text" name="tags[]" value="tag1">
+        </label>
+        <label>
+            Second
+            <input type="text" name="tags[]" value="tag2">
+        </label>
+        <label>
+            Third
+            <input type="text" name="tags[]" value="tag1">
+        </label>
+
+        <input type="submit" name="submit" value="Register" />
+    </form>
+</body>
+</html>
diff --git a/vendor/behat/mink/driver-testsuite/web-fixtures/multicheckbox_form.html b/vendor/behat/mink/driver-testsuite/web-fixtures/multicheckbox_form.html
new file mode 100644
index 00000000000..a2ae3752270
--- /dev/null
+++ b/vendor/behat/mink/driver-testsuite/web-fixtures/multicheckbox_form.html
@@ -0,0 +1,17 @@
+<!DOCTYPE html>
+<html>
+<head>
+    <title>Multicheckbox Test</title>
+    <meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/>
+</head>
+<body>
+    <h1>Multicheckbox Test</h1>
+
+    <form method="POST" action="advanced_form_post.php">
+        <input type="checkbox" name="mail_types[]" checked="checked" value="update"/>
+        <input type="checkbox" name="mail_types[]" value="spam"/>
+
+        <input type="submit" name="submit" value="Register" />
+    </form>
+</body>
+</html>
diff --git a/vendor/behat/mink/driver-testsuite/web-fixtures/multiselect_form.html b/vendor/behat/mink/driver-testsuite/web-fixtures/multiselect_form.html
new file mode 100644
index 00000000000..0d2898609fc
--- /dev/null
+++ b/vendor/behat/mink/driver-testsuite/web-fixtures/multiselect_form.html
@@ -0,0 +1,32 @@
+<!DOCTYPE html>
+<html>
+<head>
+    <title>Multiselect Test</title>
+    <meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/>
+</head>
+<body>
+    <h1>Multiselect Test</h1>
+
+    <form method="POST" action="advanced_form_post.php">
+        <select name="select_number">
+            <option value="10">ten</option>
+            <option selected="selected" value="20">twenty</option>
+            <option value="30">thirty</option>
+        </select>
+
+        <select name="select_multiple_numbers[]" multiple="multiple">
+            <option value="1">one</option>
+            <option value="2">two</option>
+            <option value="3">three</option>
+        </select>
+
+        <select name="select_multiple_values[]" multiple="multiple">
+            <option value="1">one</option>
+            <option value="2" selected="selected">two</option>
+            <option value="3" selected="selected">three</option>
+        </select>
+
+        <input type="submit" name="submit" value="Register" />
+    </form>
+</body>
+</html>
diff --git a/vendor/behat/mink/driver-testsuite/web-fixtures/popup1.html b/vendor/behat/mink/driver-testsuite/web-fixtures/popup1.html
new file mode 100644
index 00000000000..b8e3fe2ab8b
--- /dev/null
+++ b/vendor/behat/mink/driver-testsuite/web-fixtures/popup1.html
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<html>
+<head>
+    <title>popup_1</title>
+</head>
+<body>
+
+    <div id="text">
+        Popup#1 div text
+    </div>
+
+</body>
+</html>
diff --git a/vendor/behat/mink/driver-testsuite/web-fixtures/popup2.html b/vendor/behat/mink/driver-testsuite/web-fixtures/popup2.html
new file mode 100644
index 00000000000..dae1932c39c
--- /dev/null
+++ b/vendor/behat/mink/driver-testsuite/web-fixtures/popup2.html
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<html>
+<head>
+    <title>popup_2</title>
+</head>
+<body>
+
+    <div id="text">
+        Popup#2 div text
+    </div>
+
+</body>
+</html>
diff --git a/vendor/behat/mink/driver-testsuite/web-fixtures/print_cookies.php b/vendor/behat/mink/driver-testsuite/web-fixtures/print_cookies.php
new file mode 100644
index 00000000000..eef496ec55f
--- /dev/null
+++ b/vendor/behat/mink/driver-testsuite/web-fixtures/print_cookies.php
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<html>
+<head>
+    <title>Cookies page</title>
+    <meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/>
+</head>
+<body>
+    <?php echo str_replace('>', '', var_export($_COOKIE, true)); ?>
+</body>
+</html>
diff --git a/vendor/behat/mink/driver-testsuite/web-fixtures/radio.html b/vendor/behat/mink/driver-testsuite/web-fixtures/radio.html
new file mode 100644
index 00000000000..69a916a53d5
--- /dev/null
+++ b/vendor/behat/mink/driver-testsuite/web-fixtures/radio.html
@@ -0,0 +1,21 @@
+<!DOCTYPE html>
+<html>
+<head>
+    <meta charset="utf-8">
+    <title>Radio group</title>
+</head>
+<body>
+    <form id="form1">
+        <input name="group1" type="radio" value="set" id="first" checked="checked">
+        <input name="group1" type="radio" value="updated" id="second">
+
+        <input name="reused" type="radio" value="test" id="reused_form1">
+        <input name="reused" type="radio" value="test2" id="reused2_form1" checked="checked">
+    </form>
+
+    <form id="form2">
+        <input name="reused" type="radio" value="test3" id="reused_form2" checked="checked">
+        <input name="reused" type="radio" value="test4" id="reused2_form2">
+    </form>
+</body>
+</html>
diff --git a/vendor/behat/mink/driver-testsuite/web-fixtures/randomizer.php b/vendor/behat/mink/driver-testsuite/web-fixtures/randomizer.php
new file mode 100644
index 00000000000..07a73ec7af8
--- /dev/null
+++ b/vendor/behat/mink/driver-testsuite/web-fixtures/randomizer.php
@@ -0,0 +1,12 @@
+<!DOCTYPE html>
+<html>
+<head>
+    <title>Index page</title>
+    <meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/>
+</head>
+<body>
+
+    <h1 id="number"><?php echo rand() ?></h1>
+
+</body>
+</html>
diff --git a/vendor/behat/mink/driver-testsuite/web-fixtures/redirect_destination.html b/vendor/behat/mink/driver-testsuite/web-fixtures/redirect_destination.html
new file mode 100644
index 00000000000..3de7481af36
--- /dev/null
+++ b/vendor/behat/mink/driver-testsuite/web-fixtures/redirect_destination.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<html>
+<head>
+    <title>Redirect destination</title>
+    <meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/>
+</head>
+<body>
+    You were redirected!
+</body>
+</html>
diff --git a/vendor/behat/mink/driver-testsuite/web-fixtures/redirector.php b/vendor/behat/mink/driver-testsuite/web-fixtures/redirector.php
new file mode 100644
index 00000000000..44ac8f32052
--- /dev/null
+++ b/vendor/behat/mink/driver-testsuite/web-fixtures/redirector.php
@@ -0,0 +1,3 @@
+<?php
+
+header('location: redirect_destination.html');
diff --git a/vendor/behat/mink/driver-testsuite/web-fixtures/response_headers.php b/vendor/behat/mink/driver-testsuite/web-fixtures/response_headers.php
new file mode 100644
index 00000000000..a9166b7a732
--- /dev/null
+++ b/vendor/behat/mink/driver-testsuite/web-fixtures/response_headers.php
@@ -0,0 +1,15 @@
+<?php
+
+header('X-Mink-Test: response-headers');
+
+?>
+<!DOCTYPE html>
+<html lang="en">
+<head>
+    <title>Response headers</title>
+    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+</head>
+<body>
+    <h1>Response headers</h1>
+</body>
+</html>
diff --git a/vendor/behat/mink/driver-testsuite/web-fixtures/session_test.php b/vendor/behat/mink/driver-testsuite/web-fixtures/session_test.php
new file mode 100644
index 00000000000..df1af6f1430
--- /dev/null
+++ b/vendor/behat/mink/driver-testsuite/web-fixtures/session_test.php
@@ -0,0 +1,18 @@
+<?php
+session_name('_SESS');
+session_start();
+
+if (isset($_GET['login'])) {
+    session_regenerate_id();
+}
+?>
+<!DOCTYPE html>
+<html>
+<head>
+    <title>Session Test</title>
+    <meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/>
+</head>
+<body>
+    <div id="session-id"><?php echo session_id() ?></div>
+</body>
+</html>
diff --git a/vendor/behat/mink/driver-testsuite/web-fixtures/some_file.txt b/vendor/behat/mink/driver-testsuite/web-fixtures/some_file.txt
new file mode 100644
index 00000000000..d515a02fe04
--- /dev/null
+++ b/vendor/behat/mink/driver-testsuite/web-fixtures/some_file.txt
@@ -0,0 +1 @@
+1 uploaded file
diff --git a/vendor/behat/mink/driver-testsuite/web-fixtures/sub-folder/cookie_page1.php b/vendor/behat/mink/driver-testsuite/web-fixtures/sub-folder/cookie_page1.php
new file mode 100644
index 00000000000..750249b9976
--- /dev/null
+++ b/vendor/behat/mink/driver-testsuite/web-fixtures/sub-folder/cookie_page1.php
@@ -0,0 +1,4 @@
+<?php
+$cookieAtRootPath = false;
+$cookieValue = 'srv_var_is_set_sub_folder';
+require_once __DIR__ . '/../' . basename(__FILE__);
diff --git a/vendor/behat/mink/driver-testsuite/web-fixtures/sub-folder/cookie_page2.php b/vendor/behat/mink/driver-testsuite/web-fixtures/sub-folder/cookie_page2.php
new file mode 100644
index 00000000000..9747fe8ef8f
--- /dev/null
+++ b/vendor/behat/mink/driver-testsuite/web-fixtures/sub-folder/cookie_page2.php
@@ -0,0 +1,2 @@
+<?php
+require_once __DIR__ . '/../' . basename(__FILE__);
diff --git a/vendor/behat/mink/driver-testsuite/web-fixtures/window.html b/vendor/behat/mink/driver-testsuite/web-fixtures/window.html
new file mode 100644
index 00000000000..d0a45944dbe
--- /dev/null
+++ b/vendor/behat/mink/driver-testsuite/web-fixtures/window.html
@@ -0,0 +1,26 @@
+<!DOCTYPE html>
+<html>
+<body>
+
+<script>
+function newPopup(url, title) {
+    popupWindow = window.open(
+        url, title,'height=100,width=200,left=10,top=10,resizable=yes,scrollbars=yes,toolbar=yes,menubar=no,location=no,directories=no,status=yes'
+    );
+}
+</script>
+
+<a href="popup1.html" onclick="newPopup(this.href, 'popup_1'); return false;">
+    Popup #1
+</a>
+
+<a href="popup2.html" onclick="newPopup(this.href, 'popup_2'); return false;">
+    Popup #2
+</a>
+
+<div id="text">
+    Main window div text
+</div>
+
+</body>
+</html>
diff --git a/vendor/behat/mink/phpdoc.ini.dist b/vendor/behat/mink/phpdoc.ini.dist
new file mode 100644
index 00000000000..3fef75dd0b2
--- /dev/null
+++ b/vendor/behat/mink/phpdoc.ini.dist
@@ -0,0 +1,125 @@
+; Default configuration file for PHPDoctor
+
+; This config file will cause PHPDoctor to generate API documentation of
+; itself.
+
+
+; PHPDoctor settings
+; -----------------------------------------------------------------------------
+
+; Names of files to parse. This can be a single filename, or a comma separated
+; list of filenames. Wildcards are allowed.
+
+files = "*.php"
+
+; Names of files or directories to ignore. This can be a single filename, or a
+; comma separated list of filenames. Wildcards are NOT allowed.
+
+ignore = "CVS, .svn, .git, _compiled"
+
+; The directory to look for files in, if not used the PHPDoctor will look in
+; the current directory (the directory it is run from).
+
+source_path = "./src"
+
+; If you do not want PHPDoctor to look in each sub directory for files
+; uncomment this line.
+
+;subdirs = off
+
+; Set how loud PHPDoctor is as it runs. Quiet mode suppresses all output other
+; than warnings and errors. Verbose mode outputs additional messages during
+; execution.
+
+;quiet = on
+;verbose = on
+
+; Select the doclet to use for generating output.
+
+doclet = standard
+;doclet = debug
+
+; The directory to find the doclet in. Doclets are expected to be in a
+; directory named after themselves at the location given.
+
+;doclet_path = ./doclets
+
+; The directory to find taglets in. Taglets allow you to make PHPDoctor handle
+; new tags and to alter the behavour of existing tags and their output.
+
+;taglet_path = ./taglets
+
+; If the code you are parsing does not use package tags or not all elements
+; have package tags, use this setting to place unbound elements into a
+; particular package.
+
+default_package = "Behat\Mink"
+
+; Specifies the name of a HTML file containing text for the overview
+; documentation to be placed on the overview page. The path is relative to
+; "source_path" unless an absolute path is given.
+
+overview = readme.html
+
+; Package comments will be looked for in a file named package.html in the same
+; directory as the first source file parsed in that package or in the directory
+; given below. If package comments are placed in the directory given below then
+; they should be named "<packageName>.html".
+
+package_comment_dir = ./
+
+; Parse out global variables and/or global constants?
+
+;globals = off
+;constants = off
+
+; Generate documentation for all class members
+
+;private = on
+
+; Generate documentation for public and protected class members
+
+;protected = on
+
+; Generate documentation for only public class members
+
+public = on
+
+; Use the PEAR compatible handling of the docblock first sentence
+
+;pear_compat = on
+
+; Standard doclet settings
+; -----------------------------------------------------------------------------
+
+; The directory to place generated documentation in. If the given path is
+; relative to it will be relative to "source_path".
+
+d = "api"
+
+; Specifies the title to be placed in the HTML <title> tag.
+
+windowtitle = "Behat\Mink"
+
+; Specifies the title to be placed near the top of the overview summary file.
+
+doctitle = "Behat\Mink: browser emulators abstraction library for PHP"
+
+; Specifies the header text to be placed at the top of each output file. The
+; header will be placed to the right of the upper navigation bar. 
+
+header = "Behat\Mink"
+
+; Specifies the footer text to be placed at the bottom of each output file. The
+; footer will be placed to the right of the lower navigation bar.
+
+footer = "Behat\Mink"
+
+; Specifies the text to be placed at the bottom of each output file. The text
+; will be placed at the bottom of the page, below the lower navigation bar.
+
+;bottom = "This document was generated by <a href="http://phpdoctor.sourceforge.net/">PHPDoctor: The PHP Documentation Creator</a>"
+
+; Create a class tree?
+
+tree = on
diff --git a/vendor/behat/mink/phpunit.xml.dist b/vendor/behat/mink/phpunit.xml.dist
new file mode 100644
index 00000000000..bf73a6958fe
--- /dev/null
+++ b/vendor/behat/mink/phpunit.xml.dist
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<phpunit colors="true" bootstrap="vendor/autoload.php">
+    <testsuites>
+        <testsuite name="Behat Mink test suite">
+            <directory>tests</directory>
+        </testsuite>
+    </testsuites>
+
+    <filter>
+        <whitelist>
+            <directory>./src/Behat/Mink/</directory>
+        </whitelist>
+    </filter>
+</phpunit>
diff --git a/vendor/behat/mink/src/Behat/Mink/Driver/CoreDriver.php b/vendor/behat/mink/src/Behat/Mink/Driver/CoreDriver.php
new file mode 100644
index 00000000000..248f291ea68
--- /dev/null
+++ b/vendor/behat/mink/src/Behat/Mink/Driver/CoreDriver.php
@@ -0,0 +1,447 @@
+<?php
+
+/*
+ * This file is part of the Mink package.
+ * (c) Konstantin Kudryashov <ever.zet@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Behat\Mink\Driver;
+
+use Behat\Mink\Exception\UnsupportedDriverActionException;
+use Behat\Mink\Session;
+
+/**
+ * Core driver.
+ * All other drivers should extend this class for future compatibility.
+ *
+ * @author Konstantin Kudryashov <ever.zet@gmail.com>
+ */
+abstract class CoreDriver implements DriverInterface
+{
+    /**
+     * {@inheritdoc}
+     */
+    public function setSession(Session $session)
+    {
+        throw new UnsupportedDriverActionException('Setting the session is not supported by %s', $this);
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function start()
+    {
+        throw new UnsupportedDriverActionException('Starting the driver is not supported by %s', $this);
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function isStarted()
+    {
+        throw new UnsupportedDriverActionException('Checking the driver state is not supported by %s', $this);
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function stop()
+    {
+        throw new UnsupportedDriverActionException('Stopping the driver is not supported by %s', $this);
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function reset()
+    {
+        throw new UnsupportedDriverActionException('Resetting the driver is not supported by %s', $this);
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function visit($url)
+    {
+        throw new UnsupportedDriverActionException('Visiting an url is not supported by %s', $this);
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function getCurrentUrl()
+    {
+        throw new UnsupportedDriverActionException('Getting the current url is not supported by %s', $this);
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function getContent()
+    {
+        throw new UnsupportedDriverActionException('Getting the page content is not supported by %s', $this);
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function find($xpath)
+    {
+        throw new UnsupportedDriverActionException('Finding elements is not supported by %s', $this);
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function getTagName($xpath)
+    {
+        throw new UnsupportedDriverActionException('Getting the tag name is not supported by %s', $this);
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function getText($xpath)
+    {
+        throw new UnsupportedDriverActionException('Getting the element text is not supported by %s', $this);
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function getHtml($xpath)
+    {
+        throw new UnsupportedDriverActionException('Getting the element inner HTML is not supported by %s', $this);
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function getOuterHtml($xpath)
+    {
+        throw new UnsupportedDriverActionException('Getting the element outer HTML is not supported by %s', $this);
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function getAttribute($xpath, $name)
+    {
+        throw new UnsupportedDriverActionException('Getting the element attribute is not supported by %s', $this);
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function getValue($xpath)
+    {
+        throw new UnsupportedDriverActionException('Getting the field value is not supported by %s', $this);
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function setValue($xpath, $value)
+    {
+        throw new UnsupportedDriverActionException('Setting the field value is not supported by %s', $this);
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function check($xpath)
+    {
+        throw new UnsupportedDriverActionException('Checking a checkbox is not supported by %s', $this);
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function uncheck($xpath)
+    {
+        throw new UnsupportedDriverActionException('Unchecking a checkbox is not supported by %s', $this);
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function isChecked($xpath)
+    {
+        throw new UnsupportedDriverActionException('Getting the state of a checkbox is not supported by %s', $this);
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function selectOption($xpath, $value, $multiple = false)
+    {
+        throw new UnsupportedDriverActionException('Selecting an option is not supported by %s', $this);
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function click($xpath)
+    {
+        throw new UnsupportedDriverActionException('Clicking on an element is not supported by %s', $this);
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function attachFile($xpath, $path)
+    {
+        throw new UnsupportedDriverActionException('Attaching a file in an input is not supported by %s', $this);
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function reload()
+    {
+        throw new UnsupportedDriverActionException('Page reloading is not supported by %s', $this);
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function forward()
+    {
+        throw new UnsupportedDriverActionException('Forward action is not supported by %s', $this);
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function back()
+    {
+        throw new UnsupportedDriverActionException('Backward action is not supported by %s', $this);
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function setBasicAuth($user, $password)
+    {
+        throw new UnsupportedDriverActionException('Basic auth setup is not supported by %s', $this);
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function switchToWindow($name = null)
+    {
+        throw new UnsupportedDriverActionException('Windows management is not supported by %s', $this);
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function switchToIFrame($name = null)
+    {
+        throw new UnsupportedDriverActionException('iFrames management is not supported by %s', $this);
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function setRequestHeader($name, $value)
+    {
+        throw new UnsupportedDriverActionException('Request headers manipulation is not supported by %s', $this);
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function getResponseHeaders()
+    {
+        throw new UnsupportedDriverActionException('Response headers are not available from %s', $this);
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function setCookie($name, $value = null)
+    {
+        throw new UnsupportedDriverActionException('Cookies manipulation is not supported by %s', $this);
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function getCookie($name)
+    {
+        throw new UnsupportedDriverActionException('Cookies are not available from %s', $this);
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function getStatusCode()
+    {
+        throw new UnsupportedDriverActionException('Status code is not available from %s', $this);
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function getScreenshot()
+    {
+        throw new UnsupportedDriverActionException('Screenshots are not supported by %s', $this);
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function getWindowNames()
+    {
+        throw new UnsupportedDriverActionException('Listing all window names is not supported by %s', $this);
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function getWindowName()
+    {
+        throw new UnsupportedDriverActionException('Listing this window name is not supported by %s', $this);
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function doubleClick($xpath)
+    {
+        throw new UnsupportedDriverActionException('Double-clicking is not supported by %s', $this);
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function rightClick($xpath)
+    {
+        throw new UnsupportedDriverActionException('Right-clicking is not supported by %s', $this);
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function isVisible($xpath)
+    {
+        throw new UnsupportedDriverActionException('Element visibility check is not supported by %s', $this);
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function isSelected($xpath)
+    {
+        throw new UnsupportedDriverActionException('Element selection check is not supported by %s', $this);
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function mouseOver($xpath)
+    {
+        throw new UnsupportedDriverActionException('Mouse manipulations are not supported by %s', $this);
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function focus($xpath)
+    {
+        throw new UnsupportedDriverActionException('Mouse manipulations are not supported by %s', $this);
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function blur($xpath)
+    {
+        throw new UnsupportedDriverActionException('Mouse manipulations are not supported by %s', $this);
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function keyPress($xpath, $char, $modifier = null)
+    {
+        throw new UnsupportedDriverActionException('Keyboard manipulations are not supported by %s', $this);
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function keyDown($xpath, $char, $modifier = null)
+    {
+        throw new UnsupportedDriverActionException('Keyboard manipulations are not supported by %s', $this);
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function keyUp($xpath, $char, $modifier = null)
+    {
+        throw new UnsupportedDriverActionException('Keyboard manipulations are not supported by %s', $this);
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function dragTo($sourceXpath, $destinationXpath)
+    {
+        throw new UnsupportedDriverActionException('Mouse manipulations are not supported by %s', $this);
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function executeScript($script)
+    {
+        throw new UnsupportedDriverActionException('JS is not supported by %s', $this);
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function evaluateScript($script)
+    {
+        throw new UnsupportedDriverActionException('JS is not supported by %s', $this);
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function wait($timeout, $condition)
+    {
+        throw new UnsupportedDriverActionException('JS is not supported by %s', $this);
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function resizeWindow($width, $height, $name = null)
+    {
+        throw new UnsupportedDriverActionException('Window resizing is not supported by %s', $this);
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function maximizeWindow($name = null)
+    {
+        throw new UnsupportedDriverActionException('Window maximize is not supported by %s', $this);
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function submitForm($xpath)
+    {
+        throw new UnsupportedDriverActionException('Form submission is not supported by %s', $this);
+    }
+}
diff --git a/vendor/behat/mink/src/Behat/Mink/Driver/DriverInterface.php b/vendor/behat/mink/src/Behat/Mink/Driver/DriverInterface.php
new file mode 100644
index 00000000000..831d408d064
--- /dev/null
+++ b/vendor/behat/mink/src/Behat/Mink/Driver/DriverInterface.php
@@ -0,0 +1,637 @@
+<?php
+
+/*
+ * This file is part of the Mink package.
+ * (c) Konstantin Kudryashov <ever.zet@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Behat\Mink\Driver;
+
+use Behat\Mink\Element\NodeElement;
+use Behat\Mink\Exception\DriverException;
+use Behat\Mink\Exception\UnsupportedDriverActionException;
+use Behat\Mink\Session;
+
+/**
+ * Driver interface.
+ *
+ * @author Konstantin Kudryashov <ever.zet@gmail.com>
+ */
+interface DriverInterface
+{
+    /**
+     * Sets driver's current session.
+     *
+     * @param Session $session
+     */
+    public function setSession(Session $session);
+
+    /**
+     * Starts driver.
+     *
+     * Once started, the driver should be ready to visit a page.
+     *
+     * Calling any action before visiting a page is an undefined behavior.
+     * The only supported method calls on a fresh driver are
+     * - visit()
+     * - setRequestHeader()
+     * - setBasicAuth()
+     * - reset()
+     * - stop()
+     *
+     * Calling start on a started driver is an undefined behavior. Driver
+     * implementations are free to handle it silently or to fail with an
+     * exception.
+     *
+     * @throws DriverException When the driver cannot be started
+     */
+    public function start();
+
+    /**
+     * Checks whether driver is started.
+     *
+     * @return Boolean
+     */
+    public function isStarted();
+
+    /**
+     * Stops driver.
+     *
+     * Once stopped, the driver should be started again before using it again.
+     *
+     * Calling any action on a stopped driver is an undefined behavior.
+     * The only supported method call after stopping a driver is starting it again.
+     *
+     * Calling stop on a stopped driver is an undefined behavior. Driver
+     * implementations are free to handle it silently or to fail with an
+     * exception.
+     *
+     * @throws DriverException When the driver cannot be closed
+     */
+    public function stop();
+
+    /**
+     * Resets driver state.
+     *
+     * This should reset cookies, request headers and basic authentication.
+     * When possible, the history should be reset as well, but this is not enforced
+     * as some implementations may not be able to reset it without restarting the
+     * driver entirely. Consumers requiring a clean history should restart the driver
+     * to enforce it.
+     *
+     * Once reset, the driver should be ready to visit a page.
+     * Calling any action before visiting a page is an undefined behavior.
+     * The only supported method calls on a fresh driver are
+     * - visit()
+     * - setRequestHeader()
+     * - setBasicAuth()
+     * - reset()
+     * - stop()
+     *
+     * Calling reset on a stopped driver is an undefined behavior.
+     */
+    public function reset();
+
+    /**
+     * Visit specified URL.
+     *
+     * @param string $url url of the page
+     *
+     * @throws UnsupportedDriverActionException When operation not supported by the driver
+     * @throws DriverException                  When the operation cannot be done
+     */
+    public function visit($url);
+
+    /**
+     * Returns current URL address.
+     *
+     * @return string
+     *
+     * @throws UnsupportedDriverActionException When operation not supported by the driver
+     * @throws DriverException                  When the operation cannot be done
+     */
+    public function getCurrentUrl();
+
+    /**
+     * Reloads current page.
+     *
+     * @throws UnsupportedDriverActionException When operation not supported by the driver
+     * @throws DriverException                  When the operation cannot be done
+     */
+    public function reload();
+
+    /**
+     * Moves browser forward 1 page.
+     *
+     * @throws UnsupportedDriverActionException When operation not supported by the driver
+     * @throws DriverException                  When the operation cannot be done
+     */
+    public function forward();
+
+    /**
+     * Moves browser backward 1 page.
+     *
+     * @throws UnsupportedDriverActionException When operation not supported by the driver
+     * @throws DriverException                  When the operation cannot be done
+     */
+    public function back();
+
+    /**
+     * Sets HTTP Basic authentication parameters
+     *
+     * @param string|Boolean $user     user name or false to disable authentication
+     * @param string         $password password
+     *
+     * @throws UnsupportedDriverActionException When operation not supported by the driver
+     * @throws DriverException                  When the operation cannot be done
+     */
+    public function setBasicAuth($user, $password);
+
+    /**
+     * Switches to specific browser window.
+     *
+     * @param string $name window name (null for switching back to main window)
+     *
+     * @throws UnsupportedDriverActionException When operation not supported by the driver
+     * @throws DriverException                  When the operation cannot be done
+     */
+    public function switchToWindow($name = null);
+
+    /**
+     * Switches to specific iFrame.
+     *
+     * @param string $name iframe name (null for switching back)
+     *
+     * @throws UnsupportedDriverActionException When operation not supported by the driver
+     * @throws DriverException                  When the operation cannot be done
+     */
+    public function switchToIFrame($name = null);
+
+    /**
+     * Sets specific request header on client.
+     *
+     * @param string $name
+     * @param string $value
+     *
+     * @throws UnsupportedDriverActionException When operation not supported by the driver
+     * @throws DriverException                  When the operation cannot be done
+     */
+    public function setRequestHeader($name, $value);
+
+    /**
+     * Returns last response headers.
+     *
+     * @return array
+     *
+     * @throws UnsupportedDriverActionException When operation not supported by the driver
+     * @throws DriverException                  When the operation cannot be done
+     */
+    public function getResponseHeaders();
+
+    /**
+     * Sets cookie.
+     *
+     * @param string $name
+     * @param string $value
+     *
+     * @throws UnsupportedDriverActionException When operation not supported by the driver
+     * @throws DriverException                  When the operation cannot be done
+     */
+    public function setCookie($name, $value = null);
+
+    /**
+     * Returns cookie by name.
+     *
+     * @param string $name
+     *
+     * @return string|null
+     *
+     * @throws UnsupportedDriverActionException When operation not supported by the driver
+     * @throws DriverException                  When the operation cannot be done
+     */
+    public function getCookie($name);
+
+    /**
+     * Returns last response status code.
+     *
+     * @return integer
+     *
+     * @throws UnsupportedDriverActionException When operation not supported by the driver
+     * @throws DriverException                  When the operation cannot be done
+     */
+    public function getStatusCode();
+
+    /**
+     * Returns last response content.
+     *
+     * @return string
+     *
+     * @throws UnsupportedDriverActionException When operation not supported by the driver
+     * @throws DriverException                  When the operation cannot be done
+     */
+    public function getContent();
+
+    /**
+     * Capture a screenshot of the current window.
+     *
+     * @return string screenshot of MIME type image/* depending
+     *                on driver (e.g., image/png, image/jpeg)
+     *
+     * @throws UnsupportedDriverActionException When operation not supported by the driver
+     * @throws DriverException                  When the operation cannot be done
+     */
+    public function getScreenshot();
+
+    /**
+     * Return the names of all open windows.
+     *
+     * @return array array of all open windows
+     *
+     * @throws UnsupportedDriverActionException When operation not supported by the driver
+     * @throws DriverException                  When the operation cannot be done
+     */
+    public function getWindowNames();
+
+    /**
+     * Return the name of the currently active window.
+     *
+     * @return string the name of the current window
+     *
+     * @throws UnsupportedDriverActionException When operation not supported by the driver
+     * @throws DriverException                  When the operation cannot be done
+     */
+    public function getWindowName();
+
+    /**
+     * Finds elements with specified XPath query.
+     *
+     * @param string $xpath
+     *
+     * @return NodeElement[]
+     *
+     * @throws UnsupportedDriverActionException When operation not supported by the driver
+     * @throws DriverException                  When the operation cannot be done
+     */
+    public function find($xpath);
+
+    /**
+     * Returns element's tag name by it's XPath query.
+     *
+     * @param string $xpath
+     *
+     * @return string
+     *
+     * @throws UnsupportedDriverActionException When operation not supported by the driver
+     * @throws DriverException                  When the operation cannot be done
+     */
+    public function getTagName($xpath);
+
+    /**
+     * Returns element's text by it's XPath query.
+     *
+     * @param string $xpath
+     *
+     * @return string
+     *
+     * @throws UnsupportedDriverActionException When operation not supported by the driver
+     * @throws DriverException                  When the operation cannot be done
+     */
+    public function getText($xpath);
+
+    /**
+     * Returns element's inner html by it's XPath query.
+     *
+     * @param string $xpath
+     *
+     * @return string
+     *
+     * @throws UnsupportedDriverActionException When operation not supported by the driver
+     * @throws DriverException                  When the operation cannot be done
+     */
+    public function getHtml($xpath);
+
+    /**
+     * Returns element's outer html by it's XPath query.
+     *
+     * @param string $xpath
+     *
+     * @return string
+     *
+     * @throws UnsupportedDriverActionException When operation not supported by the driver
+     * @throws DriverException                  When the operation cannot be done
+     */
+    public function getOuterHtml($xpath);
+
+    /**
+     * Returns element's attribute by it's XPath query.
+     *
+     * @param string $xpath
+     * @param string $name
+     *
+     * @return string|null
+     *
+     * @throws UnsupportedDriverActionException When operation not supported by the driver
+     * @throws DriverException                  When the operation cannot be done
+     */
+    public function getAttribute($xpath, $name);
+
+    /**
+     * Returns element's value by it's XPath query.
+     *
+     * @param string $xpath
+     *
+     * @return string|bool|array
+     *
+     * @throws UnsupportedDriverActionException When operation not supported by the driver
+     * @throws DriverException                  When the operation cannot be done
+     *
+     * @see \Behat\Mink\Element\NodeElement::getValue
+     */
+    public function getValue($xpath);
+
+    /**
+     * Sets element's value by it's XPath query.
+     *
+     * @param string            $xpath
+     * @param string|bool|array $value
+     *
+     * @throws UnsupportedDriverActionException When operation not supported by the driver
+     * @throws DriverException                  When the operation cannot be done
+     *
+     * @see \Behat\Mink\Element\NodeElement::setValue
+     */
+    public function setValue($xpath, $value);
+
+    /**
+     * Checks checkbox by it's XPath query.
+     *
+     * @param string $xpath
+     *
+     * @throws UnsupportedDriverActionException When operation not supported by the driver
+     * @throws DriverException                  When the operation cannot be done
+     *
+     * @see \Behat\Mink\Element\NodeElement::check
+     */
+    public function check($xpath);
+
+    /**
+     * Unchecks checkbox by it's XPath query.
+     *
+     * @param string $xpath
+     *
+     * @throws UnsupportedDriverActionException When operation not supported by the driver
+     * @throws DriverException                  When the operation cannot be done
+     *
+     * @see \Behat\Mink\Element\NodeElement::uncheck
+     */
+    public function uncheck($xpath);
+
+    /**
+     * Checks whether checkbox or radio button located by it's XPath query is checked.
+     *
+     * @param string $xpath
+     *
+     * @return Boolean
+     *
+     * @throws UnsupportedDriverActionException When operation not supported by the driver
+     * @throws DriverException                  When the operation cannot be done
+     *
+     * @see \Behat\Mink\Element\NodeElement::isChecked
+     */
+    public function isChecked($xpath);
+
+    /**
+     * Selects option from select field or value in radio group located by it's XPath query.
+     *
+     * @param string  $xpath
+     * @param string  $value
+     * @param Boolean $multiple
+     *
+     * @throws UnsupportedDriverActionException When operation not supported by the driver
+     * @throws DriverException                  When the operation cannot be done
+     *
+     * @see \Behat\Mink\Element\NodeElement::selectOption
+     */
+    public function selectOption($xpath, $value, $multiple = false);
+
+    /**
+     * Checks whether select option, located by it's XPath query, is selected.
+     *
+     * @param string $xpath
+     *
+     * @return Boolean
+     *
+     * @throws UnsupportedDriverActionException When operation not supported by the driver
+     * @throws DriverException                  When the operation cannot be done
+     *
+     * @see \Behat\Mink\Element\NodeElement::isSelected
+     */
+    public function isSelected($xpath);
+
+    /**
+     * Clicks button or link located by it's XPath query.
+     *
+     * @param string $xpath
+     *
+     * @throws UnsupportedDriverActionException When operation not supported by the driver
+     * @throws DriverException                  When the operation cannot be done
+     */
+    public function click($xpath);
+
+    /**
+     * Double-clicks button or link located by it's XPath query.
+     *
+     * @param string $xpath
+     *
+     * @throws UnsupportedDriverActionException When operation not supported by the driver
+     * @throws DriverException                  When the operation cannot be done
+     */
+    public function doubleClick($xpath);
+
+    /**
+     * Right-clicks button or link located by it's XPath query.
+     *
+     * @param string $xpath
+     *
+     * @throws UnsupportedDriverActionException When operation not supported by the driver
+     * @throws DriverException                  When the operation cannot be done
+     */
+    public function rightClick($xpath);
+
+    /**
+     * Attaches file path to file field located by it's XPath query.
+     *
+     * @param string $xpath
+     * @param string $path
+     *
+     * @throws UnsupportedDriverActionException When operation not supported by the driver
+     * @throws DriverException                  When the operation cannot be done
+     *
+     * @see \Behat\Mink\Element\NodeElement::attachFile
+     */
+    public function attachFile($xpath, $path);
+
+    /**
+     * Checks whether element visible located by it's XPath query.
+     *
+     * @param string $xpath
+     *
+     * @return Boolean
+     *
+     * @throws UnsupportedDriverActionException When operation not supported by the driver
+     * @throws DriverException                  When the operation cannot be done
+     */
+    public function isVisible($xpath);
+
+    /**
+     * Simulates a mouse over on the element.
+     *
+     * @param string $xpath
+     *
+     * @throws UnsupportedDriverActionException When operation not supported by the driver
+     * @throws DriverException                  When the operation cannot be done
+     */
+    public function mouseOver($xpath);
+
+    /**
+     * Brings focus to element.
+     *
+     * @param string $xpath
+     *
+     * @throws UnsupportedDriverActionException When operation not supported by the driver
+     * @throws DriverException                  When the operation cannot be done
+     */
+    public function focus($xpath);
+
+    /**
+     * Removes focus from element.
+     *
+     * @param string $xpath
+     *
+     * @throws UnsupportedDriverActionException When operation not supported by the driver
+     * @throws DriverException                  When the operation cannot be done
+     */
+    public function blur($xpath);
+
+    /**
+     * Presses specific keyboard key.
+     *
+     * @param string         $xpath
+     * @param string|integer $char     could be either char ('b') or char-code (98)
+     * @param string         $modifier keyboard modifier (could be 'ctrl', 'alt', 'shift' or 'meta')
+     *
+     * @throws UnsupportedDriverActionException When operation not supported by the driver
+     * @throws DriverException                  When the operation cannot be done
+     */
+    public function keyPress($xpath, $char, $modifier = null);
+
+    /**
+     * Pressed down specific keyboard key.
+     *
+     * @param string         $xpath
+     * @param string|integer $char     could be either char ('b') or char-code (98)
+     * @param string         $modifier keyboard modifier (could be 'ctrl', 'alt', 'shift' or 'meta')
+     *
+     * @throws UnsupportedDriverActionException When operation not supported by the driver
+     * @throws DriverException                  When the operation cannot be done
+     */
+    public function keyDown($xpath, $char, $modifier = null);
+
+    /**
+     * Pressed up specific keyboard key.
+     *
+     * @param string         $xpath
+     * @param string|integer $char     could be either char ('b') or char-code (98)
+     * @param string         $modifier keyboard modifier (could be 'ctrl', 'alt', 'shift' or 'meta')
+     *
+     * @throws UnsupportedDriverActionException When operation not supported by the driver
+     * @throws DriverException                  When the operation cannot be done
+     */
+    public function keyUp($xpath, $char, $modifier = null);
+
+    /**
+     * Drag one element onto another.
+     *
+     * @param string $sourceXpath
+     * @param string $destinationXpath
+     *
+     * @throws UnsupportedDriverActionException When operation not supported by the driver
+     * @throws DriverException                  When the operation cannot be done
+     */
+    public function dragTo($sourceXpath, $destinationXpath);
+
+    /**
+     * Executes JS script.
+     *
+     * @param string $script
+     *
+     * @throws UnsupportedDriverActionException When operation not supported by the driver
+     * @throws DriverException                  When the operation cannot be done
+     */
+    public function executeScript($script);
+
+    /**
+     * Evaluates JS script.
+     *
+     * The "return" keyword is optional in the script passed as argument. Driver implementations
+     * must accept the expression both with and without the keyword.
+     *
+     * @param string $script
+     *
+     * @return mixed
+     *
+     * @throws UnsupportedDriverActionException When operation not supported by the driver
+     * @throws DriverException                  When the operation cannot be done
+     */
+    public function evaluateScript($script);
+
+    /**
+     * Waits some time or until JS condition turns true.
+     *
+     * @param integer $timeout   timeout in milliseconds
+     * @param string  $condition JS condition
+     *
+     * @return boolean
+     *
+     * @throws UnsupportedDriverActionException When operation not supported by the driver
+     * @throws DriverException                  When the operation cannot be done
+     */
+    public function wait($timeout, $condition);
+
+    /**
+     * Set the dimensions of the window.
+     *
+     * @param integer $width  set the window width, measured in pixels
+     * @param integer $height set the window height, measured in pixels
+     * @param string  $name   window name (null for the main window)
+     *
+     * @throws UnsupportedDriverActionException When operation not supported by the driver
+     * @throws DriverException                  When the operation cannot be done
+     */
+    public function resizeWindow($width, $height, $name = null);
+
+    /**
+     * Maximize the window if it is not maximized already
+     *
+     * @param string $name window name (null for the main window)
+     *
+     * @throws UnsupportedDriverActionException When operation not supported by the driver
+     * @throws DriverException                  When the operation cannot be done
+     */
+    public function maximizeWindow($name = null);
+
+     /**
+      * Submits the form.
+      *
+      * @param string $xpath Xpath.
+      *
+      * @throws UnsupportedDriverActionException When operation not supported by the driver
+      * @throws DriverException                  When the operation cannot be done
+      *
+      * @see \Behat\Mink\Element\NodeElement::submitForm
+      */
+    public function submitForm($xpath);
+}
diff --git a/vendor/behat/mink/src/Behat/Mink/Element/DocumentElement.php b/vendor/behat/mink/src/Behat/Mink/Element/DocumentElement.php
new file mode 100644
index 00000000000..dc6bc6e1b07
--- /dev/null
+++ b/vendor/behat/mink/src/Behat/Mink/Element/DocumentElement.php
@@ -0,0 +1,53 @@
+<?php
+
+/*
+ * This file is part of the Mink package.
+ * (c) Konstantin Kudryashov <ever.zet@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Behat\Mink\Element;
+
+/**
+ * Document element.
+ *
+ * @author Konstantin Kudryashov <ever.zet@gmail.com>
+ */
+class DocumentElement extends TraversableElement
+{
+    /**
+     * Returns XPath for handled element.
+     *
+     * @return string
+     */
+    public function getXpath()
+    {
+        return '//html';
+    }
+
+    /**
+     * Returns document content.
+     *
+     * @return string
+     */
+    public function getContent()
+    {
+        return trim($this->getDriver()->getContent());
+    }
+
+    /**
+     * Check whether document has specified content.
+     *
+     * @param string $content
+     *
+     * @return Boolean
+     */
+    public function hasContent($content)
+    {
+        return $this->has('named', array(
+            'content', $this->getSelectorsHandler()->xpathLiteral($content)
+        ));
+    }
+}
diff --git a/vendor/behat/mink/src/Behat/Mink/Element/Element.php b/vendor/behat/mink/src/Behat/Mink/Element/Element.php
new file mode 100644
index 00000000000..07e1e119efd
--- /dev/null
+++ b/vendor/behat/mink/src/Behat/Mink/Element/Element.php
@@ -0,0 +1,207 @@
+<?php
+
+/*
+ * This file is part of the Mink package.
+ * (c) Konstantin Kudryashov <ever.zet@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Behat\Mink\Element;
+
+use Behat\Mink\Driver\DriverInterface;
+use Behat\Mink\Exception\ElementNotFoundException;
+use Behat\Mink\Selector\SelectorsHandler;
+use Behat\Mink\Selector\Xpath\Manipulator;
+use Behat\Mink\Session;
+
+/**
+ * Base element.
+ *
+ * @author Konstantin Kudryashov <ever.zet@gmail.com>
+ */
+abstract class Element implements ElementInterface
+{
+    /**
+     * @var Session
+     */
+    private $session;
+
+    /**
+     * Driver.
+     *
+     * @var DriverInterface
+     */
+    private $driver;
+
+    /**
+     * @var SelectorsHandler
+     */
+    private $selectorsHandler;
+
+    /**
+     * @var Manipulator
+     */
+    private $xpathManipulator;
+
+    /**
+     * Initialize element.
+     *
+     * @param Session $session
+     */
+    public function __construct(Session $session)
+    {
+        $this->xpathManipulator = new Manipulator();
+        $this->session = $session;
+
+        $this->driver = $session->getDriver();
+        $this->selectorsHandler = $session->getSelectorsHandler();
+    }
+
+    /**
+     * Returns element session.
+     *
+     * @return Session
+     *
+     * @deprecated Accessing the session from the element is deprecated as of 1.6 and will be impossible in 2.0.
+     */
+    public function getSession()
+    {
+        return $this->session;
+    }
+
+    /**
+     * Returns element's driver.
+     *
+     * @return DriverInterface
+     */
+    protected function getDriver()
+    {
+        return $this->driver;
+    }
+
+    /**
+     * Returns selectors handler.
+     *
+     * @return SelectorsHandler
+     */
+    protected function getSelectorsHandler()
+    {
+        return $this->selectorsHandler;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function has($selector, $locator)
+    {
+        return null !== $this->find($selector, $locator);
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function isValid()
+    {
+        return 1 === count($this->getDriver()->find($this->getXpath()));
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function waitFor($timeout, $callback)
+    {
+        if (!is_callable($callback)) {
+            throw new \InvalidArgumentException('Given callback is not a valid callable');
+        }
+
+        $start = microtime(true);
+        $end = $start + $timeout;
+
+        do {
+            $result = call_user_func($callback, $this);
+
+            if ($result) {
+                break;
+            }
+
+            usleep(100000);
+        } while (microtime(true) < $end);
+
+        return $result;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function find($selector, $locator)
+    {
+        $items = $this->findAll($selector, $locator);
+
+        return count($items) ? current($items) : null;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function findAll($selector, $locator)
+    {
+        if ('named' === $selector) {
+            $items = $this->findAll('named_exact', $locator);
+            if (empty($items)) {
+                $items = $this->findAll('named_partial', $locator);
+            }
+
+            return $items;
+        }
+
+        $xpath = $this->getSelectorsHandler()->selectorToXpath($selector, $locator);
+        $xpath = $this->xpathManipulator->prepend($xpath, $this->getXpath());
+
+        return $this->getDriver()->find($xpath);
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function getText()
+    {
+        return $this->getDriver()->getText($this->getXpath());
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function getHtml()
+    {
+        return $this->getDriver()->getHtml($this->getXpath());
+    }
+
+    /**
+     * Returns element outer html.
+     *
+     * @return string
+     */
+    public function getOuterHtml()
+    {
+        return $this->getDriver()->getOuterHtml($this->getXpath());
+    }
+
+    /**
+     * Builds an ElementNotFoundException
+     *
+     * This is an helper to build the ElementNotFoundException without
+     * needing to use the deprecated getSession accessor in child classes.
+     *
+     * @param string      $type
+     * @param string|null $selector
+     * @param string|null $locator
+     *
+     * @return ElementNotFoundException
+     */
+    protected function elementNotFound($type, $selector = null, $locator = null)
+    {
+        return new ElementNotFoundException($this->session, $type, $selector, $locator);
+    }
+}
diff --git a/vendor/behat/mink/src/Behat/Mink/Element/ElementInterface.php b/vendor/behat/mink/src/Behat/Mink/Element/ElementInterface.php
new file mode 100644
index 00000000000..8c134b96fcd
--- /dev/null
+++ b/vendor/behat/mink/src/Behat/Mink/Element/ElementInterface.php
@@ -0,0 +1,114 @@
+<?php
+
+/*
+ * This file is part of the Mink package.
+ * (c) Konstantin Kudryashov <ever.zet@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Behat\Mink\Element;
+
+use Behat\Mink\Session;
+
+/**
+ * Element interface.
+ *
+ * @author Konstantin Kudryashov <ever.zet@gmail.com>
+ */
+interface ElementInterface
+{
+    /**
+     * Returns XPath for handled element.
+     *
+     * @return string
+     */
+    public function getXpath();
+
+    /**
+     * Returns element's session.
+     *
+     * @return Session
+     *
+     * @deprecated Accessing the session from the element is deprecated as of 1.6 and will be impossible in 2.0.
+     */
+    public function getSession();
+
+    /**
+     * Checks whether element with specified selector exists inside the current element.
+     *
+     * @param string       $selector selector engine name
+     * @param string|array $locator  selector locator
+     *
+     * @return Boolean
+     *
+     * @see ElementInterface::findAll for the supported selectors
+     */
+    public function has($selector, $locator);
+
+    /**
+     * Checks if an element still exists in the DOM.
+     *
+     * @return boolean
+     */
+    public function isValid();
+
+    /**
+     * Waits for an element(-s) to appear and returns it.
+     *
+     * @param int|float $timeout  Maximal allowed waiting time in seconds.
+     * @param callable  $callback Callback, which result is both used as waiting condition and returned.
+     *                            Will receive reference to `this element` as first argument.
+     *
+     * @return mixed
+     * @throws \InvalidArgumentException When invalid callback given.
+     */
+    public function waitFor($timeout, $callback);
+
+    /**
+     * Finds first element with specified selector inside the current element.
+     *
+     * @param string       $selector selector engine name
+     * @param string|array $locator  selector locator
+     *
+     * @return NodeElement|null
+     *
+     * @see ElementInterface::findAll for the supported selectors
+     */
+    public function find($selector, $locator);
+
+    /**
+     * Finds all elements with specified selector inside the current element.
+     *
+     * Valid selector engines are named, xpath, css, named_partial and named_exact.
+     *
+     * 'named' is a pseudo selector engine which prefers an exact match but
+     * will return a partial match if no exact match is found.
+     * 'xpath' is a pseudo selector engine supported by SelectorsHandler.
+     *
+     * More selector engines can be registered in the SelectorsHandler.
+     *
+     * @param string       $selector selector engine name
+     * @param string|array $locator  selector locator
+     *
+     * @return NodeElement[]
+     *
+     * @see NamedSelector for the locators supported by the named selectors
+     */
+    public function findAll($selector, $locator);
+
+    /**
+     * Returns element text (inside tag).
+     *
+     * @return string
+     */
+    public function getText();
+
+    /**
+     * Returns element inner html.
+     *
+     * @return string
+     */
+    public function getHtml();
+}
diff --git a/vendor/behat/mink/src/Behat/Mink/Element/NodeElement.php b/vendor/behat/mink/src/Behat/Mink/Element/NodeElement.php
new file mode 100644
index 00000000000..1f867ed0d0e
--- /dev/null
+++ b/vendor/behat/mink/src/Behat/Mink/Element/NodeElement.php
@@ -0,0 +1,352 @@
+<?php
+
+/*
+ * This file is part of the Mink package.
+ * (c) Konstantin Kudryashov <ever.zet@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Behat\Mink\Element;
+
+use Behat\Mink\Session;
+use Behat\Mink\Exception\ElementNotFoundException;
+
+/**
+ * Page element node.
+ *
+ * @author Konstantin Kudryashov <ever.zet@gmail.com>
+ */
+class NodeElement extends TraversableElement
+{
+    private $xpath;
+
+    /**
+     * Initializes node element.
+     *
+     * @param string  $xpath   element xpath
+     * @param Session $session session instance
+     */
+    public function __construct($xpath, Session $session)
+    {
+        $this->xpath = $xpath;
+
+        parent::__construct($session);
+    }
+
+    /**
+     * Returns XPath for handled element.
+     *
+     * @return string
+     */
+    public function getXpath()
+    {
+        return $this->xpath;
+    }
+
+    /**
+     * Returns parent element to the current one.
+     *
+     * @return NodeElement
+     */
+    public function getParent()
+    {
+        return $this->find('xpath', '..');
+    }
+
+    /**
+     * Returns current node tag name.
+     *
+     * The value is always returned in lowercase to allow an easy comparison.
+     *
+     * @return string
+     */
+    public function getTagName()
+    {
+        return strtolower($this->getDriver()->getTagName($this->getXpath()));
+    }
+
+    /**
+     * Returns the value of the form field or option element.
+     *
+     * For checkbox fields, the value is a boolean indicating whether the checkbox is checked.
+     * For radio buttons, the value is the value of the selected button in the radio group
+     *      or null if no button is selected.
+     * For single select boxes, the value is the value of the selected option.
+     * For multiple select boxes, the value is an array of selected option values.
+     * for file inputs, the return value is undefined given that browsers don't allow accessing
+     *      the value of file inputs for security reasons. Some drivers may allow accessing the
+     *      path of the file set in the field, but this is not required if it cannot be implemented.
+     * For textarea elements and all textual fields, the value is the content of the field.
+     * Form option elements, the value is the value of the option (the value attribute or the text
+     *      content if the attribute is not set).
+     *
+     * Calling this method on other elements than form fields or option elements is not allowed.
+     *
+     * @return string|bool|array
+     */
+    public function getValue()
+    {
+        return $this->getDriver()->getValue($this->getXpath());
+    }
+
+    /**
+     * Sets the value of the form field.
+     *
+     * Calling this method on other elements than form fields is not allowed.
+     *
+     * @param string|bool|array $value
+     *
+     * @see NodeElement::getValue for the format of the value for each type of field
+     */
+    public function setValue($value)
+    {
+        $this->getDriver()->setValue($this->getXpath(), $value);
+    }
+
+    /**
+     * Checks whether element has attribute with specified name.
+     *
+     * @param string $name
+     *
+     * @return Boolean
+     */
+    public function hasAttribute($name)
+    {
+        return null !== $this->getDriver()->getAttribute($this->getXpath(), $name);
+    }
+
+    /**
+     * Returns specified attribute value.
+     *
+     * @param string $name
+     *
+     * @return string|null
+     */
+    public function getAttribute($name)
+    {
+        return $this->getDriver()->getAttribute($this->getXpath(), $name);
+    }
+
+    /**
+     * Checks whether an element has a named CSS class
+     *
+     * @param string $className Name of the class
+     *
+     * @return boolean
+     */
+    public function hasClass($className)
+    {
+        if ($this->hasAttribute('class')) {
+            return in_array($className, explode(' ', $this->getAttribute('class')));
+        }
+
+        return false;
+    }
+
+    /**
+     * Clicks current node.
+     */
+    public function click()
+    {
+        $this->getDriver()->click($this->getXpath());
+    }
+
+    /**
+     * Presses current button.
+     */
+    public function press()
+    {
+        $this->click();
+    }
+
+    /**
+     * Double-clicks current node.
+     */
+    public function doubleClick()
+    {
+        $this->getDriver()->doubleClick($this->getXpath());
+    }
+
+    /**
+     * Right-clicks current node.
+     */
+    public function rightClick()
+    {
+        $this->getDriver()->rightClick($this->getXpath());
+    }
+
+    /**
+     * Checks current node if it's a checkbox field.
+     */
+    public function check()
+    {
+        $this->getDriver()->check($this->getXpath());
+    }
+
+    /**
+     * Unchecks current node if it's a checkbox field.
+     */
+    public function uncheck()
+    {
+        $this->getDriver()->uncheck($this->getXpath());
+    }
+
+    /**
+     * Checks whether current node is checked if it's a checkbox or radio field.
+     *
+     * Calling this method on any other elements is not allowed.
+     *
+     * @return Boolean
+     */
+    public function isChecked()
+    {
+        return (Boolean) $this->getDriver()->isChecked($this->getXpath());
+    }
+
+    /**
+     * Selects specified option for select field or specified radio button in the group
+     *
+     * If the current node is a select box, this selects the option found by its value or
+     * its text.
+     * If the current node is a radio button, this selects the radio button with the given
+     * value in the radio button group of the current node.
+     *
+     * Calling this method on any other elements is not allowed.
+     *
+     * @param string  $option
+     * @param Boolean $multiple whether the option should be added to the selection for multiple selects
+     *
+     * @throws ElementNotFoundException when the option is not found in the select box
+     */
+    public function selectOption($option, $multiple = false)
+    {
+        if ('select' !== $this->getTagName()) {
+            $this->getDriver()->selectOption($this->getXpath(), $option, $multiple);
+
+            return;
+        }
+
+        $opt = $this->find('named', array(
+            'option', $this->getSelectorsHandler()->xpathLiteral($option)
+        ));
+
+        if (null === $opt) {
+            throw $this->elementNotFound('select option', 'value|text', $option);
+        }
+
+        $this->getDriver()->selectOption($this->getXpath(), $opt->getValue(), $multiple);
+    }
+
+    /**
+     * Checks whether current node is selected if it's a option field.
+     *
+     * Calling this method on any other elements is not allowed.
+     *
+     * @return Boolean
+     */
+    public function isSelected()
+    {
+        return (Boolean) $this->getDriver()->isSelected($this->getXpath());
+    }
+
+    /**
+     * Attach file to current node if it's a file input.
+     *
+     * Calling this method on any other elements than file input is not allowed.
+     *
+     * @param string $path path to file (local)
+     */
+    public function attachFile($path)
+    {
+        $this->getDriver()->attachFile($this->getXpath(), $path);
+    }
+
+    /**
+     * Checks whether current node is visible on page.
+     *
+     * @return Boolean
+     */
+    public function isVisible()
+    {
+        return (Boolean) $this->getDriver()->isVisible($this->getXpath());
+    }
+
+    /**
+     * Simulates a mouse over on the element.
+     */
+    public function mouseOver()
+    {
+        $this->getDriver()->mouseOver($this->getXpath());
+    }
+
+    /**
+     * Drags current node onto other node.
+     *
+     * @param ElementInterface $destination other node
+     */
+    public function dragTo(ElementInterface $destination)
+    {
+        $this->getDriver()->dragTo($this->getXpath(), $destination->getXpath());
+    }
+
+    /**
+     * Brings focus to element.
+     */
+    public function focus()
+    {
+        $this->getDriver()->focus($this->getXpath());
+    }
+
+    /**
+     * Removes focus from element.
+     */
+    public function blur()
+    {
+        $this->getDriver()->blur($this->getXpath());
+    }
+
+    /**
+     * Presses specific keyboard key.
+     *
+     * @param string|integer $char     could be either char ('b') or char-code (98)
+     * @param string         $modifier keyboard modifier (could be 'ctrl', 'alt', 'shift' or 'meta')
+     */
+    public function keyPress($char, $modifier = null)
+    {
+        $this->getDriver()->keyPress($this->getXpath(), $char, $modifier);
+    }
+
+    /**
+     * Pressed down specific keyboard key.
+     *
+     * @param string|integer $char     could be either char ('b') or char-code (98)
+     * @param string         $modifier keyboard modifier (could be 'ctrl', 'alt', 'shift' or 'meta')
+     */
+    public function keyDown($char, $modifier = null)
+    {
+        $this->getDriver()->keyDown($this->getXpath(), $char, $modifier);
+    }
+
+    /**
+     * Pressed up specific keyboard key.
+     *
+     * @param string|integer $char     could be either char ('b') or char-code (98)
+     * @param string         $modifier keyboard modifier (could be 'ctrl', 'alt', 'shift' or 'meta')
+     */
+    public function keyUp($char, $modifier = null)
+    {
+        $this->getDriver()->keyUp($this->getXpath(), $char, $modifier);
+    }
+
+    /**
+     * Submits the form.
+     *
+     * Calling this method on anything else than form elements is not allowed.
+     */
+    public function submit()
+    {
+        $this->getDriver()->submitForm($this->getXpath());
+    }
+}
diff --git a/vendor/behat/mink/src/Behat/Mink/Element/TraversableElement.php b/vendor/behat/mink/src/Behat/Mink/Element/TraversableElement.php
new file mode 100644
index 00000000000..27843d2dd65
--- /dev/null
+++ b/vendor/behat/mink/src/Behat/Mink/Element/TraversableElement.php
@@ -0,0 +1,309 @@
+<?php
+
+/*
+ * This file is part of the Mink package.
+ * (c) Konstantin Kudryashov <ever.zet@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Behat\Mink\Element;
+
+use Behat\Mink\Exception\ElementNotFoundException;
+
+/**
+ * Traversable element.
+ *
+ * @author Konstantin Kudryashov <ever.zet@gmail.com>
+ */
+abstract class TraversableElement extends Element
+{
+    /**
+     * Finds element by its id.
+     *
+     * @param string $id element id
+     *
+     * @return NodeElement|null
+     */
+    public function findById($id)
+    {
+        $id = $this->getSelectorsHandler()->xpathLiteral($id);
+
+        return $this->find('named', array('id', $id));
+    }
+
+    /**
+     * Checks whether element has a link with specified locator.
+     *
+     * @param string $locator link id, title, text or image alt
+     *
+     * @return Boolean
+     */
+    public function hasLink($locator)
+    {
+        return null !== $this->findLink($locator);
+    }
+
+    /**
+     * Finds link with specified locator.
+     *
+     * @param string $locator link id, title, text or image alt
+     *
+     * @return NodeElement|null
+     */
+    public function findLink($locator)
+    {
+        return $this->find('named', array(
+            'link', $this->getSelectorsHandler()->xpathLiteral($locator)
+        ));
+    }
+
+    /**
+     * Clicks link with specified locator.
+     *
+     * @param string $locator link id, title, text or image alt
+     *
+     * @throws ElementNotFoundException
+     */
+    public function clickLink($locator)
+    {
+        $link = $this->findLink($locator);
+
+        if (null === $link) {
+            throw $this->elementNotFound('link', 'id|title|alt|text', $locator);
+        }
+
+        $link->click();
+    }
+
+    /**
+     * Checks whether element has a button (input[type=submit|image|button|reset], button) with specified locator.
+     *
+     * @param string $locator button id, value or alt
+     *
+     * @return Boolean
+     */
+    public function hasButton($locator)
+    {
+        return null !== $this->findButton($locator);
+    }
+
+    /**
+     * Finds button (input[type=submit|image|button|reset], button) with specified locator.
+     *
+     * @param string $locator button id, value or alt
+     *
+     * @return NodeElement|null
+     */
+    public function findButton($locator)
+    {
+        return $this->find('named', array(
+            'button', $this->getSelectorsHandler()->xpathLiteral($locator)
+        ));
+    }
+
+    /**
+     * Presses button (input[type=submit|image|button|reset], button) with specified locator.
+     *
+     * @param string $locator button id, value or alt
+     *
+     * @throws ElementNotFoundException
+     */
+    public function pressButton($locator)
+    {
+        $button = $this->findButton($locator);
+
+        if (null === $button) {
+            throw $this->elementNotFound('button', 'id|name|title|alt|value', $locator);
+        }
+
+        $button->press();
+    }
+
+    /**
+     * Checks whether element has a field (input, textarea, select) with specified locator.
+     *
+     * @param string $locator input id, name or label
+     *
+     * @return Boolean
+     */
+    public function hasField($locator)
+    {
+        return null !== $this->findField($locator);
+    }
+
+    /**
+     * Finds field (input, textarea, select) with specified locator.
+     *
+     * @param string $locator input id, name or label
+     *
+     * @return NodeElement|null
+     */
+    public function findField($locator)
+    {
+        return $this->find('named', array(
+            'field', $this->getSelectorsHandler()->xpathLiteral($locator)
+        ));
+    }
+
+    /**
+     * Fills in field (input, textarea, select) with specified locator.
+     *
+     * @param string $locator input id, name or label
+     * @param string $value   value
+     *
+     * @throws ElementNotFoundException
+     *
+     * @see NodeElement::setValue
+     */
+    public function fillField($locator, $value)
+    {
+        $field = $this->findField($locator);
+
+        if (null === $field) {
+            throw $this->elementNotFound('form field', 'id|name|label|value', $locator);
+        }
+
+        $field->setValue($value);
+    }
+
+    /**
+     * Checks whether element has a checkbox with specified locator, which is checked.
+     *
+     * @param string $locator input id, name or label
+     *
+     * @return Boolean
+     *
+     * @see NodeElement::isChecked
+     */
+    public function hasCheckedField($locator)
+    {
+        $field = $this->findField($locator);
+
+        return null !== $field && $field->isChecked();
+    }
+
+    /**
+     * Checks whether element has a checkbox with specified locator, which is unchecked.
+     *
+     * @param string $locator input id, name or label
+     *
+     * @return Boolean
+     *
+     * @see NodeElement::isChecked
+     */
+    public function hasUncheckedField($locator)
+    {
+        $field = $this->findField($locator);
+
+        return null !== $field && !$field->isChecked();
+    }
+
+    /**
+     * Checks checkbox with specified locator.
+     *
+     * @param string $locator input id, name or label
+     *
+     * @throws ElementNotFoundException
+     */
+    public function checkField($locator)
+    {
+        $field = $this->findField($locator);
+
+        if (null === $field) {
+            throw $this->elementNotFound('form field', 'id|name|label|value', $locator);
+        }
+
+        $field->check();
+    }
+
+    /**
+     * Unchecks checkbox with specified locator.
+     *
+     * @param string $locator input id, name or label
+     *
+     * @throws ElementNotFoundException
+     */
+    public function uncheckField($locator)
+    {
+        $field = $this->findField($locator);
+
+        if (null === $field) {
+            throw $this->elementNotFound('form field', 'id|name|label|value', $locator);
+        }
+
+        $field->uncheck();
+    }
+
+    /**
+     * Checks whether element has a select field with specified locator.
+     *
+     * @param string $locator select id, name or label
+     *
+     * @return Boolean
+     */
+    public function hasSelect($locator)
+    {
+        return $this->has('named', array(
+            'select', $this->getSelectorsHandler()->xpathLiteral($locator)
+        ));
+    }
+
+    /**
+     * Selects option from select field with specified locator.
+     *
+     * @param string  $locator  input id, name or label
+     * @param string  $value    option value
+     * @param Boolean $multiple select multiple options
+     *
+     * @throws ElementNotFoundException
+     *
+     * @see NodeElement::selectOption
+     */
+    public function selectFieldOption($locator, $value, $multiple = false)
+    {
+        $field = $this->findField($locator);
+
+        if (null === $field) {
+            throw $this->elementNotFound('form field', 'id|name|label|value', $locator);
+        }
+
+        $field->selectOption($value, $multiple);
+    }
+
+    /**
+     * Checks whether element has a table with specified locator.
+     *
+     * @param string $locator table id or caption
+     *
+     * @return Boolean
+     */
+    public function hasTable($locator)
+    {
+        return $this->has('named', array(
+            'table', $this->getSelectorsHandler()->xpathLiteral($locator)
+        ));
+    }
+
+    /**
+     * Attach file to file field with specified locator.
+     *
+     * @param string $locator input id, name or label
+     * @param string $path    path to file
+     *
+     * @throws ElementNotFoundException
+     *
+     * @see NodeElement::attachFile
+     */
+    public function attachFileToField($locator, $path)
+    {
+        $field = $this->findField($locator);
+
+        if (null === $field) {
+            throw $this->elementNotFound('form field', 'id|name|label|value', $locator);
+        }
+
+        $field->attachFile($path);
+    }
+}
diff --git a/vendor/behat/mink/src/Behat/Mink/Exception/DriverException.php b/vendor/behat/mink/src/Behat/Mink/Exception/DriverException.php
new file mode 100644
index 00000000000..840f8bdeaea
--- /dev/null
+++ b/vendor/behat/mink/src/Behat/Mink/Exception/DriverException.php
@@ -0,0 +1,31 @@
+<?php
+
+/*
+ * This file is part of the Mink package.
+ * (c) Konstantin Kudryashov <ever.zet@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Behat\Mink\Exception;
+
+/**
+ * Exception thrown by drivers when they fail to perform an action.
+ *
+ * @author Konstantin Kudryashov <ever.zet@gmail.com>
+ */
+class DriverException extends Exception
+{
+    /**
+     * Initializes exception.
+     *
+     * @param string          $message
+     * @param int             $code
+     * @param \Exception|null $previous
+     */
+    public function __construct($message, $code = 0, \Exception $previous = null)
+    {
+        parent::__construct($message, $code, $previous);
+    }
+}
diff --git a/vendor/behat/mink/src/Behat/Mink/Exception/ElementException.php b/vendor/behat/mink/src/Behat/Mink/Exception/ElementException.php
new file mode 100644
index 00000000000..49d5c6c9d59
--- /dev/null
+++ b/vendor/behat/mink/src/Behat/Mink/Exception/ElementException.php
@@ -0,0 +1,58 @@
+<?php
+
+/*
+ * This file is part of the Mink package.
+ * (c) Konstantin Kudryashov <ever.zet@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Behat\Mink\Exception;
+
+use Behat\Mink\Element\Element;
+
+/**
+ * A standard way for elements to re-throw exceptions
+ *
+ * @deprecated This exception class is not used anymore in Mink 1.6 and will be removed in 2.0
+ *
+ * @author Chris Worfolk <xmeltrut@gmail.com>
+ */
+class ElementException extends Exception
+{
+    private $element;
+
+    /**
+     * Initialises exception.
+     *
+     * @param Element    $element   optional message
+     * @param \Exception $exception exception
+     */
+    public function __construct(Element $element, \Exception $exception)
+    {
+        $this->element = $element;
+
+        parent::__construct(sprintf("Exception thrown by %s\n%s", $element->getXpath(), $exception->getMessage()));
+    }
+
+    /**
+     * Override default toString so we don't send a full backtrace in verbose mode.
+     *
+     * @return string
+     */
+    public function __toString()
+    {
+        return $this->getMessage();
+    }
+
+    /**
+     * Get the element that caused the exception
+     *
+     * @return Element
+     */
+    public function getElement()
+    {
+        return $this->element;
+    }
+}
diff --git a/vendor/behat/mink/src/Behat/Mink/Exception/ElementHtmlException.php b/vendor/behat/mink/src/Behat/Mink/Exception/ElementHtmlException.php
new file mode 100644
index 00000000000..99e2ea601da
--- /dev/null
+++ b/vendor/behat/mink/src/Behat/Mink/Exception/ElementHtmlException.php
@@ -0,0 +1,49 @@
+<?php
+
+/*
+ * This file is part of the Mink package.
+ * (c) Konstantin Kudryashov <ever.zet@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Behat\Mink\Exception;
+
+use Behat\Mink\Session;
+use Behat\Mink\Element\Element;
+
+/**
+ * Exception thrown when an expectation on the HTML of an element fails.
+ *
+ * @author Konstantin Kudryashov <ever.zet@gmail.com>
+ */
+class ElementHtmlException extends ExpectationException
+{
+    /**
+     * Element instance.
+     *
+     * @var Element
+     */
+    protected $element;
+
+    /**
+     * Initializes exception.
+     *
+     * @param string     $message   optional message
+     * @param Session    $session   session instance
+     * @param Element    $element   element
+     * @param \Exception $exception expectation exception
+     */
+    public function __construct($message, Session $session, Element $element, \Exception $exception = null)
+    {
+        $this->element = $element;
+
+        parent::__construct($message, $session, $exception);
+    }
+
+    protected function getContext()
+    {
+        return $this->element->getOuterHtml();
+    }
+}
diff --git a/vendor/behat/mink/src/Behat/Mink/Exception/ElementNotFoundException.php b/vendor/behat/mink/src/Behat/Mink/Exception/ElementNotFoundException.php
new file mode 100644
index 00000000000..2d379a88c2a
--- /dev/null
+++ b/vendor/behat/mink/src/Behat/Mink/Exception/ElementNotFoundException.php
@@ -0,0 +1,53 @@
+<?php
+
+/*
+ * This file is part of the Mink package.
+ * (c) Konstantin Kudryashov <ever.zet@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Behat\Mink\Exception;
+
+use Behat\Mink\Session;
+
+/**
+ * Exception thrown when an expected element is not found.
+ *
+ * @author Konstantin Kudryashov <ever.zet@gmail.com>
+ */
+class ElementNotFoundException extends ExpectationException
+{
+    /**
+     * Initializes exception.
+     *
+     * @param Session $session  session instance
+     * @param string  $type     element type
+     * @param string  $selector element selector type
+     * @param string  $locator  element locator
+     */
+    public function __construct(Session $session, $type = null, $selector = null, $locator = null)
+    {
+        $message = '';
+
+        if (null !== $type) {
+            $message .= ucfirst($type);
+        } else {
+            $message .= 'Tag';
+        }
+
+        if (null !== $locator) {
+            if (null === $selector || in_array($selector, array('css', 'xpath'))) {
+                $selector = 'matching '.($selector ?: 'locator');
+            } else {
+                $selector = 'with '.$selector;
+            }
+            $message .= ' '.$selector.' "' . $locator . '"';
+        }
+
+        $message .= ' not found.';
+
+        parent::__construct($message, $session);
+    }
+}
diff --git a/vendor/behat/mink/src/Behat/Mink/Exception/ElementTextException.php b/vendor/behat/mink/src/Behat/Mink/Exception/ElementTextException.php
new file mode 100644
index 00000000000..5efff0fc91c
--- /dev/null
+++ b/vendor/behat/mink/src/Behat/Mink/Exception/ElementTextException.php
@@ -0,0 +1,24 @@
+<?php
+
+/*
+ * This file is part of the Mink package.
+ * (c) Konstantin Kudryashov <ever.zet@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Behat\Mink\Exception;
+
+/**
+ * Exception thrown when an expectation on the text of an element fails.
+ *
+ * @author Konstantin Kudryashov <ever.zet@gmail.com>
+ */
+class ElementTextException extends ElementHtmlException
+{
+    protected function getContext()
+    {
+        return $this->element->getText();
+    }
+}
diff --git a/vendor/behat/mink/src/Behat/Mink/Exception/Exception.php b/vendor/behat/mink/src/Behat/Mink/Exception/Exception.php
new file mode 100644
index 00000000000..4662a5ba49b
--- /dev/null
+++ b/vendor/behat/mink/src/Behat/Mink/Exception/Exception.php
@@ -0,0 +1,20 @@
+<?php
+
+/*
+ * This file is part of the Mink package.
+ * (c) Konstantin Kudryashov <ever.zet@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Behat\Mink\Exception;
+
+/**
+ * Mink base exception class.
+ *
+ * @author Konstantin Kudryashov <ever.zet@gmail.com>
+ */
+abstract class Exception extends \Exception
+{
+}
diff --git a/vendor/behat/mink/src/Behat/Mink/Exception/ExpectationException.php b/vendor/behat/mink/src/Behat/Mink/Exception/ExpectationException.php
new file mode 100644
index 00000000000..da1723cbf13
--- /dev/null
+++ b/vendor/behat/mink/src/Behat/Mink/Exception/ExpectationException.php
@@ -0,0 +1,145 @@
+<?php
+
+/*
+ * This file is part of the Mink package.
+ * (c) Konstantin Kudryashov <ever.zet@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Behat\Mink\Exception;
+
+use Behat\Mink\Session;
+
+/**
+ * Exception thrown for failed expectations.
+ *
+ * Some specialized child classes are available to customize the error rendering.
+ *
+ * @author Konstantin Kudryashov <ever.zet@gmail.com>
+ */
+class ExpectationException extends Exception
+{
+    private $session;
+
+    /**
+     * Initializes exception.
+     *
+     * @param string     $message   optional message
+     * @param Session    $session   session instance
+     * @param \Exception $exception expectation exception
+     */
+    public function __construct($message, Session $session, \Exception $exception = null)
+    {
+        $this->session = $session;
+
+        if (!$message && null !== $exception) {
+            $message = $exception->getMessage();
+        }
+
+        parent::__construct($message, 0, $exception);
+    }
+
+    /**
+     * Returns exception message with additional context info.
+     *
+     * @return string
+     */
+    public function __toString()
+    {
+        try {
+            $pageText = $this->pipeString($this->trimString($this->getContext()) . "\n");
+            $string   = sprintf("%s\n\n%s%s", $this->getMessage(), $this->getResponseInfo(), $pageText);
+        } catch (\Exception $e) {
+            return $this->getMessage();
+        }
+
+        return $string;
+    }
+
+    /**
+     * Gets the context rendered for this exception
+     *
+     * @return string
+     */
+    protected function getContext()
+    {
+        return $this->trimBody($this->getSession()->getPage()->getContent());
+    }
+
+    /**
+     * Returns exception session.
+     *
+     * @return Session
+     */
+    protected function getSession()
+    {
+        return $this->session;
+    }
+
+    /**
+     * Prepends every line in a string with pipe (|).
+     *
+     * @param string $string
+     *
+     * @return string
+     */
+    protected function pipeString($string)
+    {
+        return '|  ' . strtr($string, array("\n" => "\n|  "));
+    }
+
+    /**
+     * Removes response header/footer, letting only <body /> content.
+     *
+     * @param string $string response content
+     *
+     * @return string
+     */
+    protected function trimBody($string)
+    {
+        $string = preg_replace(array('/^.*<body>/s', '/<\/body>.*$/s'), array('<body>', '</body>'), $string);
+
+        return $string;
+    }
+
+    /**
+     * Trims string to specified number of chars.
+     *
+     * @param string  $string response content
+     * @param integer $count  trim count
+     *
+     * @return string
+     */
+    protected function trimString($string, $count = 1000)
+    {
+        $string = trim($string);
+
+        if ($count < mb_strlen($string)) {
+            return mb_substr($string, 0, $count - 3) . '...';
+        }
+
+        return $string;
+    }
+
+    /**
+     * Returns response information string.
+     *
+     * @return string
+     */
+    protected function getResponseInfo()
+    {
+        $driver = basename(str_replace('\\', '/', get_class($this->session->getDriver())));
+
+        $info = '+--[ ';
+        try {
+            $info .= 'HTTP/1.1 '.$this->session->getStatusCode().' | ';
+        } catch (UnsupportedDriverActionException $e) {
+            // Ignore the status code when not supported
+        }
+        $info .= $this->session->getCurrentUrl().' | '.$driver." ]\n|\n";
+
+        return $info;
+    }
+}
diff --git a/vendor/behat/mink/src/Behat/Mink/Exception/ResponseTextException.php b/vendor/behat/mink/src/Behat/Mink/Exception/ResponseTextException.php
new file mode 100644
index 00000000000..145ed6da05b
--- /dev/null
+++ b/vendor/behat/mink/src/Behat/Mink/Exception/ResponseTextException.php
@@ -0,0 +1,24 @@
+<?php
+
+/*
+ * This file is part of the Mink package.
+ * (c) Konstantin Kudryashov <ever.zet@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Behat\Mink\Exception;
+
+/**
+ * Exception thrown when an expectation on the response text fails.
+ *
+ * @author Konstantin Kudryashov <ever.zet@gmail.com>
+ */
+class ResponseTextException extends ExpectationException
+{
+    protected function getContext()
+    {
+        return $this->getSession()->getPage()->getText();
+    }
+}
diff --git a/vendor/behat/mink/src/Behat/Mink/Exception/UnsupportedDriverActionException.php b/vendor/behat/mink/src/Behat/Mink/Exception/UnsupportedDriverActionException.php
new file mode 100644
index 00000000000..d02969b6297
--- /dev/null
+++ b/vendor/behat/mink/src/Behat/Mink/Exception/UnsupportedDriverActionException.php
@@ -0,0 +1,35 @@
+<?php
+
+/*
+ * This file is part of the Mink package.
+ * (c) Konstantin Kudryashov <ever.zet@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Behat\Mink\Exception;
+
+use Behat\Mink\Driver\DriverInterface;
+
+/**
+ * Exception thrown by drivers when they don't support the requested action.
+ *
+ * @author Konstantin Kudryashov <ever.zet@gmail.com>
+ */
+class UnsupportedDriverActionException extends DriverException
+{
+    /**
+     * Initializes exception.
+     *
+     * @param string          $template what is unsupported?
+     * @param DriverInterface $driver   driver instance
+     * @param \Exception      $previous previous exception
+     */
+    public function __construct($template, DriverInterface $driver, \Exception $previous = null)
+    {
+        $message = sprintf($template, get_class($driver));
+
+        parent::__construct($message, 0, $previous);
+    }
+}
diff --git a/vendor/behat/mink/src/Behat/Mink/Mink.php b/vendor/behat/mink/src/Behat/Mink/Mink.php
new file mode 100644
index 00000000000..d1621b17443
--- /dev/null
+++ b/vendor/behat/mink/src/Behat/Mink/Mink.php
@@ -0,0 +1,216 @@
+<?php
+
+/*
+ * This file is part of the Mink package.
+ * (c) Konstantin Kudryashov <ever.zet@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Behat\Mink;
+
+/**
+ * Mink sessions manager.
+ *
+ * @author Konstantin Kudryashov <ever.zet@gmail.com>
+ */
+class Mink
+{
+    private $defaultSessionName;
+
+    /**
+     * Sessions.
+     *
+     * @var Session[]
+     */
+    private $sessions = array();
+
+    /**
+     * Initializes manager.
+     *
+     * @param Session[] $sessions
+     */
+    public function __construct(array $sessions = array())
+    {
+        foreach ($sessions as $name => $session) {
+            $this->registerSession($name, $session);
+        }
+    }
+
+    /**
+     * Stops all started sessions.
+     */
+    public function __destruct()
+    {
+        $this->stopSessions();
+    }
+
+    /**
+     * Registers new session.
+     *
+     * @param string  $name
+     * @param Session $session
+     */
+    public function registerSession($name, Session $session)
+    {
+        $name = strtolower($name);
+
+        $this->sessions[$name] = $session;
+    }
+
+    /**
+     * Checks whether session with specified name is registered.
+     *
+     * @param string $name
+     *
+     * @return Boolean
+     */
+    public function hasSession($name)
+    {
+        return isset($this->sessions[strtolower($name)]);
+    }
+
+    /**
+     * Sets default session name to use.
+     *
+     * @param string $name name of the registered session
+     *
+     * @throws \InvalidArgumentException
+     */
+    public function setDefaultSessionName($name)
+    {
+        $name = strtolower($name);
+
+        if (!isset($this->sessions[$name])) {
+            throw new \InvalidArgumentException(sprintf('Session "%s" is not registered.', $name));
+        }
+
+        $this->defaultSessionName = $name;
+    }
+
+    /**
+     * Returns default session name or null if none.
+     *
+     * @return null|string
+     */
+    public function getDefaultSessionName()
+    {
+        return $this->defaultSessionName;
+    }
+
+    /**
+     * Returns registered session by it's name or active one and automatically starts it if required.
+     *
+     * @param string $name session name
+     *
+     * @return Session
+     *
+     * @throws \InvalidArgumentException If the named session is not registered
+     */
+    public function getSession($name = null)
+    {
+        $session = $this->locateSession($name);
+
+        // start session if needed
+        if (!$session->isStarted()) {
+            $session->start();
+        }
+
+        return $session;
+    }
+
+    /**
+     * Checks whether a named session (or the default session) has already been started
+     *
+     * @param string $name session name - if null then the default session will be checked
+     *
+     * @return bool whether the session has been started
+     *
+     * @throws \InvalidArgumentException If the named session is not registered
+     */
+    public function isSessionStarted($name = null)
+    {
+        $session = $this->locateSession($name);
+
+        return $session->isStarted();
+    }
+
+    /**
+     * Returns session asserter.
+     *
+     * @param Session|string $session session object or name
+     *
+     * @return WebAssert
+     */
+    public function assertSession($session = null)
+    {
+        if (!($session instanceof Session)) {
+            $session = $this->getSession($session);
+        }
+
+        return new WebAssert($session);
+    }
+
+    /**
+     * Resets all started sessions.
+     */
+    public function resetSessions()
+    {
+        foreach ($this->sessions as $session) {
+            if ($session->isStarted()) {
+                $session->reset();
+            }
+        }
+    }
+
+    /**
+     * Restarts all started sessions.
+     */
+    public function restartSessions()
+    {
+        foreach ($this->sessions as $session) {
+            if ($session->isStarted()) {
+                $session->restart();
+            }
+        }
+    }
+
+    /**
+     * Stops all started sessions.
+     */
+    public function stopSessions()
+    {
+        foreach ($this->sessions as $session) {
+            if ($session->isStarted()) {
+                $session->stop();
+            }
+        }
+    }
+
+    /**
+     * Returns the named or default session without starting it.
+     *
+     * @param string $name session name
+     *
+     * @return Session
+     *
+     * @throws \InvalidArgumentException If the named session is not registered
+     */
+    protected function locateSession($name = null)
+    {
+        $name = strtolower($name) ?: $this->defaultSessionName;
+
+        if (null === $name) {
+            throw new \InvalidArgumentException('Specify session name to get');
+        }
+
+        if (!isset($this->sessions[$name])) {
+            throw new \InvalidArgumentException(sprintf('Session "%s" is not registered.', $name));
+        }
+
+        $session = $this->sessions[$name];
+
+        return $session;
+    }
+}
diff --git a/vendor/behat/mink/src/Behat/Mink/Selector/CssSelector.php b/vendor/behat/mink/src/Behat/Mink/Selector/CssSelector.php
new file mode 100644
index 00000000000..363658635ca
--- /dev/null
+++ b/vendor/behat/mink/src/Behat/Mink/Selector/CssSelector.php
@@ -0,0 +1,37 @@
+<?php
+
+/*
+ * This file is part of the Mink package.
+ * (c) Konstantin Kudryashov <ever.zet@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Behat\Mink\Selector;
+
+use Symfony\Component\CssSelector\CssSelector as CSS;
+
+/**
+ * CSS selector engine. Transforms CSS to XPath.
+ *
+ * @author Konstantin Kudryashov <ever.zet@gmail.com>
+ */
+class CssSelector implements SelectorInterface
+{
+    /**
+     * Translates CSS into XPath.
+     *
+     * @param string|array $locator current selector locator
+     *
+     * @return string
+     */
+    public function translateToXPath($locator)
+    {
+        if (!is_string($locator)) {
+            throw new \InvalidArgumentException('The CssSelector expects to get a string as locator');
+        }
+
+        return CSS::toXPath($locator);
+    }
+}
diff --git a/vendor/behat/mink/src/Behat/Mink/Selector/ExactNamedSelector.php b/vendor/behat/mink/src/Behat/Mink/Selector/ExactNamedSelector.php
new file mode 100644
index 00000000000..03315a9cffa
--- /dev/null
+++ b/vendor/behat/mink/src/Behat/Mink/Selector/ExactNamedSelector.php
@@ -0,0 +1,29 @@
+<?php
+
+/*
+ * This file is part of the Mink package.
+ * (c) Konstantin Kudryashov <ever.zet@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Behat\Mink\Selector;
+
+/**
+ * Exact match selector engine. Like the Named selector engine but ignores partial matches.
+ */
+class ExactNamedSelector extends NamedSelector
+{
+    public function __construct()
+    {
+        $this->registerReplacement('%tagTextMatch%', 'normalize-space(string(.)) = %locator%');
+        $this->registerReplacement('%valueMatch%', './@value = %locator%');
+        $this->registerReplacement('%titleMatch%', './@title = %locator%');
+        $this->registerReplacement('%altMatch%', './@alt = %locator%');
+        $this->registerReplacement('%relMatch%', './@rel = %locator%');
+        $this->registerReplacement('%labelAttributeMatch%', './@label = %locator%');
+
+        parent::__construct();
+    }
+}
diff --git a/vendor/behat/mink/src/Behat/Mink/Selector/NamedSelector.php b/vendor/behat/mink/src/Behat/Mink/Selector/NamedSelector.php
new file mode 100644
index 00000000000..4845f994f9e
--- /dev/null
+++ b/vendor/behat/mink/src/Behat/Mink/Selector/NamedSelector.php
@@ -0,0 +1,238 @@
+<?php
+
+/*
+ * This file is part of the Mink package.
+ * (c) Konstantin Kudryashov <ever.zet@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Behat\Mink\Selector;
+
+/**
+ * Named selectors engine. Uses registered XPath selectors to create new expressions.
+ *
+ * @author Konstantin Kudryashov <ever.zet@gmail.com>
+ */
+class NamedSelector implements SelectorInterface
+{
+    private $replacements = array(
+        // simple replacements
+        '%lowercaseType%' => "translate(./@type, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz')",
+        '%lowercaseRole%' => "translate(./@role, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz')",
+        '%tagTextMatch%' => 'contains(normalize-space(string(.)), %locator%)',
+        '%labelTextMatch%' => './@id = //label[%tagTextMatch%]/@for',
+        '%idMatch%' => './@id = %locator%',
+        '%valueMatch%' => 'contains(./@value, %locator%)',
+        '%idOrValueMatch%' => '(%idMatch% or %valueMatch%)',
+        '%idOrNameMatch%' => '(%idMatch% or ./@name = %locator%)',
+        '%placeholderMatch%' => './@placeholder = %locator%',
+        '%titleMatch%' => 'contains(./@title, %locator%)',
+        '%altMatch%' => 'contains(./@alt, %locator%)',
+        '%relMatch%' => 'contains(./@rel, %locator%)',
+        '%labelAttributeMatch%' => 'contains(./@label, %locator%)',
+
+        // complex replacements
+        '%inputTypeWithoutPlaceholderFilter%' => "%lowercaseType% = 'radio' or %lowercaseType% = 'checkbox' or %lowercaseType% = 'file'",
+        '%fieldFilterWithPlaceholder%' => 'self::input[not(%inputTypeWithoutPlaceholderFilter%)] | self::textarea',
+        '%fieldMatchWithPlaceholder%' => '(%idOrNameMatch% or %labelTextMatch% or %placeholderMatch%)',
+        '%fieldMatchWithoutPlaceholder%' => '(%idOrNameMatch% or %labelTextMatch%)',
+        '%fieldFilterWithoutPlaceholder%' => 'self::input[%inputTypeWithoutPlaceholderFilter%] | self::select',
+        '%buttonTypeFilter%' => "%lowercaseType% = 'submit' or %lowercaseType% = 'image' or %lowercaseType% = 'button' or %lowercaseType% = 'reset'",
+        '%notFieldTypeFilter%' => "not(%buttonTypeFilter% or %lowercaseType% = 'hidden')",
+        '%buttonMatch%' => '%idOrNameMatch% or %valueMatch% or %titleMatch%',
+        '%linkMatch%' => '(%idMatch% or %tagTextMatch% or %titleMatch% or %relMatch%)',
+        '%imgAltMatch%' => './/img[%altMatch%]',
+    );
+
+    private $selectors = array(
+        'fieldset' => <<<XPATH
+.//fieldset
+[(%idMatch% or .//legend[%tagTextMatch%])]
+XPATH
+
+        ,'field' => <<<XPATH
+.//*
+[%fieldFilterWithPlaceholder%][%notFieldTypeFilter%][%fieldMatchWithPlaceholder%]
+|
+.//label[%tagTextMatch%]//.//*[%fieldFilterWithPlaceholder%][%notFieldTypeFilter%]
+|
+.//*
+[%fieldFilterWithoutPlaceholder%][%notFieldTypeFilter%][%fieldMatchWithoutPlaceholder%]
+|
+.//label[%tagTextMatch%]//.//*[%fieldFilterWithoutPlaceholder%][%notFieldTypeFilter%]
+XPATH
+
+        ,'link' => <<<XPATH
+.//a
+[./@href][(%linkMatch% or %imgAltMatch%)]
+|
+.//*
+[%lowercaseRole% = 'link'][(%idOrValueMatch% or %titleMatch% or %tagTextMatch%)]
+XPATH
+
+        ,'button' => <<<XPATH
+.//input
+[%buttonTypeFilter%][(%buttonMatch%)]
+|
+.//input
+[%lowercaseType% = 'image'][%altMatch%]
+|
+.//button
+[(%buttonMatch% or %tagTextMatch%)]
+|
+.//*
+[%lowercaseRole% = 'button'][(%buttonMatch% or %tagTextMatch%)]
+XPATH
+
+        ,'link_or_button' => <<<XPATH
+.//a
+[./@href][(%linkMatch% or %imgAltMatch%)]
+|
+.//input
+[%buttonTypeFilter%][(%idOrValueMatch% or %titleMatch%)]
+|
+.//input
+[%lowercaseType% = 'image'][%altMatch%]
+|
+.//button
+[(%idOrValueMatch% or %titleMatch% or %tagTextMatch%)]
+|
+.//*
+[(%lowercaseRole% = 'button' or %lowercaseRole% = 'link')][(%idOrValueMatch% or %titleMatch% or %tagTextMatch%)]
+XPATH
+
+        ,'content' => <<<XPATH
+./descendant-or-self::*
+[%tagTextMatch%]
+XPATH
+
+        ,'select' => <<<XPATH
+.//select
+[%fieldMatchWithoutPlaceholder%]
+|
+.//label[%tagTextMatch%]//.//select
+XPATH
+
+        ,'checkbox' => <<<XPATH
+.//input
+[%lowercaseType% = 'checkbox'][%fieldMatchWithoutPlaceholder%]
+|
+.//label[%tagTextMatch%]//.//input[%lowercaseType% = 'checkbox']
+XPATH
+
+        ,'radio' => <<<XPATH
+.//input
+[%lowercaseType% = 'radio'][%fieldMatchWithoutPlaceholder%]
+|
+.//label[%tagTextMatch%]//.//input[%lowercaseType% = 'radio']
+XPATH
+
+        ,'file' => <<<XPATH
+.//input
+[%lowercaseType% = 'file'][%fieldMatchWithoutPlaceholder%]
+|
+.//label[%tagTextMatch%]//.//input[%lowercaseType% = 'file']
+XPATH
+
+        ,'optgroup' => <<<XPATH
+.//optgroup
+[%labelAttributeMatch%]
+XPATH
+
+        ,'option' => <<<XPATH
+.//option
+[(./@value = %locator% or %tagTextMatch%)]
+XPATH
+
+        ,'table' => <<<XPATH
+.//table
+[(%idMatch% or .//caption[%tagTextMatch%])]
+XPATH
+        ,'id' => <<<XPATH
+.//*[%idMatch%]
+XPATH
+    ,'id_or_name' => <<<XPATH
+.//*[%idOrNameMatch%]
+XPATH
+    );
+
+    /**
+     * Creates selector instance.
+     */
+    public function __construct()
+    {
+        foreach ($this->replacements as $from => $to) {
+            $this->replacements[$from] = strtr($to, $this->replacements);
+        }
+
+        foreach ($this->selectors as $alias => $selector) {
+            $this->selectors[$alias] = strtr($selector, $this->replacements);
+        }
+    }
+
+    /**
+     * Registers new XPath selector with specified name.
+     *
+     * @param string $name  name for selector
+     * @param string $xpath xpath expression
+     */
+    public function registerNamedXpath($name, $xpath)
+    {
+        $this->selectors[$name] = $xpath;
+    }
+
+    /**
+     * Translates provided locator into XPath.
+     *
+     * @param string|array $locator selector name or array of (selector_name, locator)
+     *
+     * @return string
+     *
+     * @throws \InvalidArgumentException
+     */
+    public function translateToXPath($locator)
+    {
+        if (2 < count($locator)) {
+            throw new \InvalidArgumentException('NamedSelector expects array(name, locator) as argument');
+        }
+
+        if (2 == count($locator)) {
+            $selector   = $locator[0];
+            $locator    = $locator[1];
+        } else {
+            $selector   = (string) $locator;
+            $locator    = null;
+        }
+
+        if (!isset($this->selectors[$selector])) {
+            throw new \InvalidArgumentException(sprintf(
+                'Unknown named selector provided: "%s". Expected one of (%s)',
+                $selector,
+                implode(', ', array_keys($this->selectors))
+            ));
+        }
+
+        $xpath = $this->selectors[$selector];
+
+        if (null !== $locator) {
+            $xpath = strtr($xpath, array('%locator%' => $locator));
+        }
+
+        return $xpath;
+    }
+
+    /**
+     * Registers a replacement in the list of replacements
+     *
+     * This method must be called in the constructor before calling the parent constructor.
+     *
+     * @param string $from
+     * @param string $to
+     */
+    protected function registerReplacement($from, $to)
+    {
+        $this->replacements[$from] = $to;
+    }
+}
diff --git a/vendor/behat/mink/src/Behat/Mink/Selector/PartialNamedSelector.php b/vendor/behat/mink/src/Behat/Mink/Selector/PartialNamedSelector.php
new file mode 100644
index 00000000000..b864a2265db
--- /dev/null
+++ b/vendor/behat/mink/src/Behat/Mink/Selector/PartialNamedSelector.php
@@ -0,0 +1,31 @@
+<?php
+
+/*
+ * This file is part of the Mink package.
+ * (c) Konstantin Kudryashov <ever.zet@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Behat\Mink\Selector;
+
+/**
+ * Named selectors engine. Uses registered XPath selectors to create new expressions.
+ *
+ * @author Konstantin Kudryashov <ever.zet@gmail.com>
+ */
+class PartialNamedSelector extends NamedSelector
+{
+    public function __construct()
+    {
+        $this->registerReplacement('%tagTextMatch%', 'contains(normalize-space(string(.)), %locator%)');
+        $this->registerReplacement('%valueMatch%', 'contains(./@value, %locator%)');
+        $this->registerReplacement('%titleMatch%', 'contains(./@title, %locator%)');
+        $this->registerReplacement('%altMatch%', 'contains(./@alt, %locator%)');
+        $this->registerReplacement('%relMatch%', 'contains(./@rel, %locator%)');
+        $this->registerReplacement('%labelAttributeMatch%', 'contains(./@label, %locator%)');
+
+        parent::__construct();
+    }
+}
diff --git a/vendor/behat/mink/src/Behat/Mink/Selector/SelectorInterface.php b/vendor/behat/mink/src/Behat/Mink/Selector/SelectorInterface.php
new file mode 100644
index 00000000000..e4f5f17942f
--- /dev/null
+++ b/vendor/behat/mink/src/Behat/Mink/Selector/SelectorInterface.php
@@ -0,0 +1,28 @@
+<?php
+
+/*
+ * This file is part of the Mink package.
+ * (c) Konstantin Kudryashov <ever.zet@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Behat\Mink\Selector;
+
+/**
+ * Mink selector engine interface.
+ *
+ * @author Konstantin Kudryashov <ever.zet@gmail.com>
+ */
+interface SelectorInterface
+{
+    /**
+     * Translates provided locator into XPath.
+     *
+     * @param string|array $locator current selector locator
+     *
+     * @return string
+     */
+    public function translateToXPath($locator);
+}
diff --git a/vendor/behat/mink/src/Behat/Mink/Selector/SelectorsHandler.php b/vendor/behat/mink/src/Behat/Mink/Selector/SelectorsHandler.php
new file mode 100644
index 00000000000..a19de675158
--- /dev/null
+++ b/vendor/behat/mink/src/Behat/Mink/Selector/SelectorsHandler.php
@@ -0,0 +1,125 @@
+<?php
+
+/*
+ * This file is part of the Mink package.
+ * (c) Konstantin Kudryashov <ever.zet@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Behat\Mink\Selector;
+
+use Behat\Mink\Selector\Xpath\Escaper;
+
+/**
+ * Selectors handler.
+ *
+ * @author Konstantin Kudryashov <ever.zet@gmail.com>
+ */
+class SelectorsHandler
+{
+    private $selectors;
+    private $escaper;
+
+    /**
+     * Initializes selectors handler.
+     *
+     * @param SelectorInterface[] $selectors default selectors to register
+     */
+    public function __construct(array $selectors = array())
+    {
+        $this->escaper = new Escaper();
+
+        $this->registerSelector('named_partial', new PartialNamedSelector());
+        $this->registerSelector('named_exact', new ExactNamedSelector());
+        $this->registerSelector('css', new CssSelector());
+
+        foreach ($selectors as $name => $selector) {
+            $this->registerSelector($name, $selector);
+        }
+    }
+
+    /**
+     * Registers new selector engine with specified name.
+     *
+     * @param string            $name     selector engine name
+     * @param SelectorInterface $selector selector engine instance
+     */
+    public function registerSelector($name, SelectorInterface $selector)
+    {
+        $this->selectors[$name] = $selector;
+    }
+
+    /**
+     * Checks whether selector with specified name is registered on handler.
+     *
+     * @param string $name selector engine name
+     *
+     * @return Boolean
+     */
+    public function isSelectorRegistered($name)
+    {
+        return isset($this->selectors[$name]);
+    }
+
+    /**
+     * Returns selector engine with specified name.
+     *
+     * @param string $name selector engine name
+     *
+     * @return SelectorInterface
+     *
+     * @throws \InvalidArgumentException
+     */
+    public function getSelector($name)
+    {
+        if ('named' === $name) {
+            trigger_error(
+                'Using the "named" selector directly from the handler is deprecated as of 1.6 and will be removed in 2.0.'
+                .' Use the "named_partial" or use the "named" selector through the Element API instead.',
+                E_USER_DEPRECATED
+            );
+            $name = 'named_partial';
+        }
+
+        if (!$this->isSelectorRegistered($name)) {
+            throw new \InvalidArgumentException("Selector \"$name\" is not registered.");
+        }
+
+        return $this->selectors[$name];
+    }
+
+    /**
+     * Translates selector with specified name to XPath.
+     *
+     * @param string       $selector selector engine name (registered)
+     * @param string|array $locator  selector locator (an array or a string depending of the selector being used)
+     *
+     * @return string
+     */
+    public function selectorToXpath($selector, $locator)
+    {
+        if ('xpath' === $selector) {
+            if (!is_string($locator)) {
+                throw new \InvalidArgumentException('The xpath selector expects to get a string as locator');
+            }
+
+            return $locator;
+        }
+
+        return $this->getSelector($selector)->translateToXPath($locator);
+    }
+
+    /**
+     * Translates string to XPath literal.
+     *
+     * @param string $s
+     *
+     * @return string
+     */
+    public function xpathLiteral($s)
+    {
+        return $this->escaper->escapeLiteral($s);
+    }
+}
diff --git a/vendor/behat/mink/src/Behat/Mink/Selector/Xpath/Escaper.php b/vendor/behat/mink/src/Behat/Mink/Selector/Xpath/Escaper.php
new file mode 100644
index 00000000000..be3500018dc
--- /dev/null
+++ b/vendor/behat/mink/src/Behat/Mink/Selector/Xpath/Escaper.php
@@ -0,0 +1,52 @@
+<?php
+
+/*
+ * This file is part of the Mink package.
+ * (c) Konstantin Kudryashov <ever.zet@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Behat\Mink\Selector\Xpath;
+
+/**
+ * XPath escaper.
+ *
+ * @author Konstantin Kudryashov <ever.zet@gmail.com>
+ */
+class Escaper
+{
+    /**
+     * Escapes the string as a XPath literal.
+     *
+     * @param string $s
+     *
+     * @return string
+     */
+    public function escapeLiteral($s)
+    {
+        if (false === strpos($s, "'")) {
+            return sprintf("'%s'", $s);
+        }
+
+        if (false === strpos($s, '"')) {
+            return sprintf('"%s"', $s);
+        }
+
+        $string = $s;
+        $parts = array();
+        while (true) {
+            if (false !== $pos = strpos($string, "'")) {
+                $parts[] = sprintf("'%s'", substr($string, 0, $pos));
+                $parts[] = "\"'\"";
+                $string = substr($string, $pos + 1);
+            } else {
+                $parts[] = "'$string'";
+                break;
+            }
+        }
+
+        return sprintf("concat(%s)", implode($parts, ','));
+    }
+}
diff --git a/vendor/behat/mink/src/Behat/Mink/Selector/Xpath/Manipulator.php b/vendor/behat/mink/src/Behat/Mink/Selector/Xpath/Manipulator.php
new file mode 100644
index 00000000000..617b314535d
--- /dev/null
+++ b/vendor/behat/mink/src/Behat/Mink/Selector/Xpath/Manipulator.php
@@ -0,0 +1,69 @@
+<?php
+
+/*
+ * This file is part of the Mink package.
+ * (c) Konstantin Kudryashov <ever.zet@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Behat\Mink\Selector\Xpath;
+
+/**
+ * XPath manipulation utility.
+ *
+ * @author Graham Bates
+ * @author Christophe Coevoet <stof@notk.org>
+ */
+class Manipulator
+{
+    /**
+     * Regex to find union operators not inside brackets.
+     */
+    const UNION_PATTERN = '/\|(?![^\[]*\])/';
+
+    /**
+     * Prepends the XPath prefix to the given XPath.
+     *
+     * The returned XPath will match elements matching the XPath inside an element
+     * matching the prefix.
+     *
+     * @param string $xpath
+     * @param string $prefix
+     *
+     * @return string
+     */
+    public function prepend($xpath, $prefix)
+    {
+        $expressions = array();
+
+        // If the xpath prefix contains a union we need to wrap it in parentheses.
+        if (preg_match(self::UNION_PATTERN, $prefix)) {
+            $prefix = '(' . $prefix . ')';
+        }
+
+        // Split any unions into individual expressions.
+        foreach (preg_split(self::UNION_PATTERN, $xpath) as $expression) {
+            $expression = trim($expression);
+            $parenthesis = '';
+
+            // If the union is inside some braces, we need to preserve the opening braces and apply
+            // the prefix only inside it.
+            if (preg_match('/^[\(\s*]+/', $expression, $matches)) {
+                $parenthesis = $matches[0];
+                $expression = substr($expression, strlen($parenthesis));
+            }
+
+            // add prefix before element selector
+            if (0 === strpos($expression, '/')) {
+                $expression = $prefix . $expression;
+            } else {
+                $expression = $prefix . '/' . $expression;
+            }
+            $expressions[] = $parenthesis . $expression;
+        }
+
+        return implode(' | ', $expressions);
+    }
+}
diff --git a/vendor/behat/mink/src/Behat/Mink/Session.php b/vendor/behat/mink/src/Behat/Mink/Session.php
new file mode 100644
index 00000000000..c67f7f9b4e1
--- /dev/null
+++ b/vendor/behat/mink/src/Behat/Mink/Session.php
@@ -0,0 +1,352 @@
+<?php
+
+/*
+ * This file is part of the Mink package.
+ * (c) Konstantin Kudryashov <ever.zet@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Behat\Mink;
+
+use Behat\Mink\Driver\DriverInterface;
+use Behat\Mink\Selector\SelectorsHandler;
+use Behat\Mink\Element\DocumentElement;
+
+/**
+ * Mink session.
+ *
+ * @author Konstantin Kudryashov <ever.zet@gmail.com>
+ */
+class Session
+{
+    private $driver;
+    private $page;
+    private $selectorsHandler;
+
+    /**
+     * Initializes session.
+     *
+     * @param DriverInterface  $driver
+     * @param SelectorsHandler $selectorsHandler
+     */
+    public function __construct(DriverInterface $driver, SelectorsHandler $selectorsHandler = null)
+    {
+        $driver->setSession($this);
+
+        if (null === $selectorsHandler) {
+            $selectorsHandler = new SelectorsHandler();
+        }
+
+        $this->driver           = $driver;
+        $this->selectorsHandler = $selectorsHandler;
+        $this->page             = new DocumentElement($this);
+    }
+
+    /**
+     * Checks whether session (driver) was started.
+     *
+     * @return Boolean
+     */
+    public function isStarted()
+    {
+        return $this->driver->isStarted();
+    }
+
+    /**
+     * Starts session driver.
+     *
+     * Calling any action before visiting a page is an undefined behavior.
+     * The only supported method calls on a fresh driver are
+     * - visit()
+     * - setRequestHeader()
+     * - setBasicAuth()
+     * - reset()
+     * - stop()
+     */
+    public function start()
+    {
+        $this->driver->start();
+    }
+
+    /**
+     * Stops session driver.
+     */
+    public function stop()
+    {
+        $this->driver->stop();
+    }
+
+    /**
+     * Restart session driver.
+     */
+    public function restart()
+    {
+        $this->driver->stop();
+        $this->driver->start();
+    }
+
+    /**
+     * Reset session driver state.
+     *
+     * Calling any action before visiting a page is an undefined behavior.
+     * The only supported method calls on a fresh driver are
+     * - visit()
+     * - setRequestHeader()
+     * - setBasicAuth()
+     * - reset()
+     * - stop()
+     */
+    public function reset()
+    {
+        $this->driver->reset();
+    }
+
+    /**
+     * Returns session driver.
+     *
+     * @return DriverInterface
+     */
+    public function getDriver()
+    {
+        return $this->driver;
+    }
+
+    /**
+     * Returns page element.
+     *
+     * @return DocumentElement
+     */
+    public function getPage()
+    {
+        return $this->page;
+    }
+
+    /**
+     * Returns selectors handler.
+     *
+     * @return SelectorsHandler
+     */
+    public function getSelectorsHandler()
+    {
+        return $this->selectorsHandler;
+    }
+
+    /**
+     * Visit specified URL.
+     *
+     * @param string $url url of the page
+     */
+    public function visit($url)
+    {
+        $this->driver->visit($url);
+    }
+
+    /**
+     * Sets HTTP Basic authentication parameters
+     *
+     * @param string|Boolean $user     user name or false to disable authentication
+     * @param string         $password password
+     */
+    public function setBasicAuth($user, $password = '')
+    {
+        $this->driver->setBasicAuth($user, $password);
+    }
+
+    /**
+     * Sets specific request header.
+     *
+     * @param string $name
+     * @param string $value
+     */
+    public function setRequestHeader($name, $value)
+    {
+        $this->driver->setRequestHeader($name, $value);
+    }
+
+    /**
+     * Returns all response headers.
+     *
+     * @return array
+     */
+    public function getResponseHeaders()
+    {
+        return $this->driver->getResponseHeaders();
+    }
+
+    /**
+     * Sets cookie.
+     *
+     * @param string $name
+     * @param string $value
+     */
+    public function setCookie($name, $value = null)
+    {
+        $this->driver->setCookie($name, $value);
+    }
+
+    /**
+     * Returns cookie by name.
+     *
+     * @param string $name
+     *
+     * @return string|null
+     */
+    public function getCookie($name)
+    {
+        return $this->driver->getCookie($name);
+    }
+
+    /**
+     * Returns response status code.
+     *
+     * @return integer
+     */
+    public function getStatusCode()
+    {
+        return $this->driver->getStatusCode();
+    }
+
+    /**
+     * Returns current URL address.
+     *
+     * @return string
+     */
+    public function getCurrentUrl()
+    {
+        return $this->driver->getCurrentUrl();
+    }
+
+    /**
+     * Capture a screenshot of the current window.
+     *
+     * @return string screenshot of MIME type image/* depending
+     *                on driver (e.g., image/png, image/jpeg)
+     */
+    public function getScreenshot()
+    {
+        return $this->driver->getScreenshot();
+    }
+
+    /**
+     * Return the names of all open windows
+     *
+     * @return array Array of all open window's names.
+     */
+    public function getWindowNames()
+    {
+        return $this->driver->getWindowNames();
+    }
+
+    /**
+     * Return the name of the currently active window
+     *
+     * @return string The name of the current window.
+     */
+    public function getWindowName()
+    {
+        return $this->driver->getWindowName();
+    }
+
+    /**
+     * Reloads current session page.
+     */
+    public function reload()
+    {
+        $this->driver->reload();
+    }
+
+    /**
+     * Moves backward 1 page in history.
+     */
+    public function back()
+    {
+        $this->driver->back();
+    }
+
+    /**
+     * Moves forward 1 page in history.
+     */
+    public function forward()
+    {
+        $this->driver->forward();
+    }
+
+    /**
+     * Switches to specific browser window.
+     *
+     * @param string $name window name (null for switching back to main window)
+     */
+    public function switchToWindow($name = null)
+    {
+        $this->driver->switchToWindow($name);
+    }
+
+    /**
+     * Switches to specific iFrame.
+     *
+     * @param string $name iframe name (null for switching back)
+     */
+    public function switchToIFrame($name = null)
+    {
+        $this->driver->switchToIFrame($name);
+    }
+
+    /**
+     * Execute JS in browser.
+     *
+     * @param string $script javascript
+     */
+    public function executeScript($script)
+    {
+        $this->driver->executeScript($script);
+    }
+
+    /**
+     * Execute JS in browser and return it's response.
+     *
+     * @param string $script javascript
+     *
+     * @return string
+     */
+    public function evaluateScript($script)
+    {
+        return $this->driver->evaluateScript($script);
+    }
+
+    /**
+     * Waits some time or until JS condition turns true.
+     *
+     * @param integer $time      time in milliseconds
+     * @param string  $condition JS condition
+     *
+     * @return boolean
+     */
+    public function wait($time, $condition = 'false')
+    {
+        return $this->driver->wait($time, $condition);
+    }
+
+    /**
+     * Set the dimensions of the window.
+     *
+     * @param integer $width  set the window width, measured in pixels
+     * @param integer $height set the window height, measured in pixels
+     * @param string  $name   window name (null for the main window)
+     */
+    public function resizeWindow($width, $height, $name = null)
+    {
+        $this->driver->resizeWindow($width, $height, $name);
+    }
+
+    /**
+     * Maximize the window if it is not maximized already
+     *
+     * @param string $name window name (null for the main window)
+     */
+    public function maximizeWindow($name = null)
+    {
+        $this->driver->maximizeWindow($name);
+    }
+}
diff --git a/vendor/behat/mink/src/Behat/Mink/WebAssert.php b/vendor/behat/mink/src/Behat/Mink/WebAssert.php
new file mode 100644
index 00000000000..8cb3659793f
--- /dev/null
+++ b/vendor/behat/mink/src/Behat/Mink/WebAssert.php
@@ -0,0 +1,748 @@
+<?php
+
+/*
+ * This file is part of the Mink package.
+ * (c) Konstantin Kudryashov <ever.zet@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Behat\Mink;
+
+use Behat\Mink\Element\Element;
+use Behat\Mink\Element\ElementInterface;
+use Behat\Mink\Element\NodeElement;
+use Behat\Mink\Element\TraversableElement;
+use Behat\Mink\Exception\ElementNotFoundException;
+use Behat\Mink\Exception\ExpectationException;
+use Behat\Mink\Exception\ResponseTextException;
+use Behat\Mink\Exception\ElementHtmlException;
+use Behat\Mink\Exception\ElementTextException;
+
+/**
+ * Mink web assertions tool.
+ *
+ * @author Konstantin Kudryashov <ever.zet@gmail.com>
+ */
+class WebAssert
+{
+    protected $session;
+
+    /**
+     * Initializes assertion engine.
+     *
+     * @param Session $session
+     */
+    public function __construct(Session $session)
+    {
+        $this->session = $session;
+    }
+
+    /**
+     * Checks that current session address is equals to provided one.
+     *
+     * @param string $page
+     *
+     * @throws ExpectationException
+     */
+    public function addressEquals($page)
+    {
+        $expected = $this->cleanUrl($page);
+        $actual   = $this->getCurrentUrlPath();
+
+        $this->assert($actual === $expected, sprintf('Current page is "%s", but "%s" expected.', $actual, $expected));
+    }
+
+    /**
+     * Checks that current session address is not equals to provided one.
+     *
+     * @param string $page
+     *
+     * @throws ExpectationException
+     */
+    public function addressNotEquals($page)
+    {
+        $expected = $this->cleanUrl($page);
+        $actual   = $this->getCurrentUrlPath();
+
+        $this->assert($actual !== $expected, sprintf('Current page is "%s", but should not be.', $actual));
+    }
+
+    /**
+     * Checks that current session address matches regex.
+     *
+     * @param string $regex
+     *
+     * @throws ExpectationException
+     */
+    public function addressMatches($regex)
+    {
+        $actual = $this->getCurrentUrlPath();
+        $message = sprintf('Current page "%s" does not match the regex "%s".', $actual, $regex);
+
+        $this->assert((bool) preg_match($regex, $actual), $message);
+    }
+
+    /**
+     * Checks that specified cookie exists and its value equals to a given one
+     *
+     * @param string $name  cookie name
+     * @param string $value cookie value
+     *
+     * @throws ExpectationException
+     */
+    public function cookieEquals($name, $value)
+    {
+        $this->cookieExists($name);
+
+        $actualValue = $this->session->getCookie($name);
+        $message = sprintf('Cookie "%s" value is "%s", but should be "%s".', $name, $actualValue, $value);
+
+        $this->assert($actualValue == $value, $message);
+    }
+
+    /**
+     * Checks that specified cookie exists
+     *
+     * @param string $name cookie name
+     *
+     * @throws ExpectationException
+     */
+    public function cookieExists($name)
+    {
+        $message = sprintf('Cookie "%s" is not set, but should be.', $name);
+        $this->assert($this->session->getCookie($name) !== null, $message);
+    }
+
+    /**
+     * Checks that current response code equals to provided one.
+     *
+     * @param integer $code
+     *
+     * @throws ExpectationException
+     */
+    public function statusCodeEquals($code)
+    {
+        $actual = $this->session->getStatusCode();
+        $message = sprintf('Current response status code is %d, but %d expected.', $actual, $code);
+
+        $this->assert(intval($code) === intval($actual), $message);
+    }
+
+    /**
+     * Checks that current response code not equals to provided one.
+     *
+     * @param integer $code
+     *
+     * @throws ExpectationException
+     */
+    public function statusCodeNotEquals($code)
+    {
+        $actual = $this->session->getStatusCode();
+        $message = sprintf('Current response status code is %d, but should not be.', $actual);
+
+        $this->assert(intval($code) !== intval($actual), $message);
+    }
+
+    /**
+     * Checks that current page contains text.
+     *
+     * @param string $text
+     *
+     * @throws ResponseTextException
+     */
+    public function pageTextContains($text)
+    {
+        $actual = $this->session->getPage()->getText();
+        $actual = preg_replace('/\s+/u', ' ', $actual);
+        $regex  = '/'.preg_quote($text, '/').'/ui';
+        $message = sprintf('The text "%s" was not found anywhere in the text of the current page.', $text);
+
+        $this->assertResponseText((bool) preg_match($regex, $actual), $message);
+    }
+
+    /**
+     * Checks that current page does not contains text.
+     *
+     * @param string $text
+     *
+     * @throws ResponseTextException
+     */
+    public function pageTextNotContains($text)
+    {
+        $actual = $this->session->getPage()->getText();
+        $actual = preg_replace('/\s+/u', ' ', $actual);
+        $regex  = '/'.preg_quote($text, '/').'/ui';
+        $message = sprintf('The text "%s" appears in the text of this page, but it should not.', $text);
+
+        $this->assertResponseText(!preg_match($regex, $actual), $message);
+    }
+
+    /**
+     * Checks that current page text matches regex.
+     *
+     * @param string $regex
+     *
+     * @throws ResponseTextException
+     */
+    public function pageTextMatches($regex)
+    {
+        $actual = $this->session->getPage()->getText();
+        $message = sprintf('The pattern %s was not found anywhere in the text of the current page.', $regex);
+
+        $this->assertResponseText((bool) preg_match($regex, $actual), $message);
+    }
+
+    /**
+     * Checks that current page text does not matches regex.
+     *
+     * @param string $regex
+     *
+     * @throws ResponseTextException
+     */
+    public function pageTextNotMatches($regex)
+    {
+        $actual = $this->session->getPage()->getText();
+        $message = sprintf('The pattern %s was found in the text of the current page, but it should not.', $regex);
+
+        $this->assertResponseText(!preg_match($regex, $actual), $message);
+    }
+
+    /**
+     * Checks that page HTML (response content) contains text.
+     *
+     * @param string $text
+     *
+     * @throws ExpectationException
+     */
+    public function responseContains($text)
+    {
+        $actual = $this->session->getPage()->getContent();
+        $regex  = '/'.preg_quote($text, '/').'/ui';
+        $message = sprintf('The string "%s" was not found anywhere in the HTML response of the current page.', $text);
+
+        $this->assert((bool) preg_match($regex, $actual), $message);
+    }
+
+    /**
+     * Checks that page HTML (response content) does not contains text.
+     *
+     * @param string $text
+     *
+     * @throws ExpectationException
+     */
+    public function responseNotContains($text)
+    {
+        $actual = $this->session->getPage()->getContent();
+        $regex  = '/'.preg_quote($text, '/').'/ui';
+        $message = sprintf('The string "%s" appears in the HTML response of this page, but it should not.', $text);
+
+        $this->assert(!preg_match($regex, $actual), $message);
+    }
+
+    /**
+     * Checks that page HTML (response content) matches regex.
+     *
+     * @param string $regex
+     *
+     * @throws ExpectationException
+     */
+    public function responseMatches($regex)
+    {
+        $actual = $this->session->getPage()->getContent();
+        $message = sprintf('The pattern %s was not found anywhere in the HTML response of the page.', $regex);
+
+        $this->assert((bool) preg_match($regex, $actual), $message);
+    }
+
+    /**
+     * Checks that page HTML (response content) does not matches regex.
+     *
+     * @param $regex
+     *
+     * @throws ExpectationException
+     */
+    public function responseNotMatches($regex)
+    {
+        $actual = $this->session->getPage()->getContent();
+        $message = sprintf('The pattern %s was found in the HTML response of the page, but it should not.', $regex);
+
+        $this->assert(!preg_match($regex, $actual), $message);
+    }
+
+    /**
+     * Checks that there is specified number of specific elements on the page.
+     *
+     * @param string           $selectorType element selector type (css, xpath)
+     * @param string|array     $selector     element selector
+     * @param integer          $count        expected count
+     * @param ElementInterface $container    document to check against
+     *
+     * @throws ExpectationException
+     */
+    public function elementsCount($selectorType, $selector, $count, ElementInterface $container = null)
+    {
+        $container = $container ?: $this->session->getPage();
+        $nodes = $container->findAll($selectorType, $selector);
+
+        $message = sprintf(
+            '%d %s found on the page, but should be %d.',
+            count($nodes),
+            $this->getMatchingElementRepresentation($selectorType, $selector, count($nodes) !== 1),
+            $count
+        );
+
+        $this->assert(intval($count) === count($nodes), $message);
+    }
+
+    /**
+     * Checks that specific element exists on the current page.
+     *
+     * @param string           $selectorType element selector type (css, xpath)
+     * @param string|array     $selector     element selector
+     * @param ElementInterface $container    document to check against
+     *
+     * @return NodeElement
+     *
+     * @throws ElementNotFoundException
+     */
+    public function elementExists($selectorType, $selector, ElementInterface $container = null)
+    {
+        $container = $container ?: $this->session->getPage();
+        $node = $container->find($selectorType, $selector);
+
+        if (null === $node) {
+            if (is_array($selector)) {
+                $selector = implode(' ', $selector);
+            }
+
+            throw new ElementNotFoundException($this->session, 'element', $selectorType, $selector);
+        }
+
+        return $node;
+    }
+
+    /**
+     * Checks that specific element does not exists on the current page.
+     *
+     * @param string           $selectorType element selector type (css, xpath)
+     * @param string|array     $selector     element selector
+     * @param ElementInterface $container    document to check against
+     *
+     * @throws ExpectationException
+     */
+    public function elementNotExists($selectorType, $selector, ElementInterface $container = null)
+    {
+        $container = $container ?: $this->session->getPage();
+        $node = $container->find($selectorType, $selector);
+
+        $message = sprintf(
+            'An %s appears on this page, but it should not.',
+            $this->getMatchingElementRepresentation($selectorType, $selector)
+        );
+
+        $this->assert(null === $node, $message);
+    }
+
+    /**
+     * Checks that specific element contains text.
+     *
+     * @param string       $selectorType element selector type (css, xpath)
+     * @param string|array $selector     element selector
+     * @param string       $text         expected text
+     *
+     * @throws ElementTextException
+     */
+    public function elementTextContains($selectorType, $selector, $text)
+    {
+        $element = $this->elementExists($selectorType, $selector);
+        $actual  = $element->getText();
+        $regex   = '/'.preg_quote($text, '/').'/ui';
+
+        $message = sprintf(
+            'The text "%s" was not found in the text of the %s.',
+            $text,
+            $this->getMatchingElementRepresentation($selectorType, $selector)
+        );
+
+        $this->assertElementText((bool) preg_match($regex, $actual), $message, $element);
+    }
+
+    /**
+     * Checks that specific element does not contains text.
+     *
+     * @param string       $selectorType element selector type (css, xpath)
+     * @param string|array $selector     element selector
+     * @param string       $text         expected text
+     *
+     * @throws ElementTextException
+     */
+    public function elementTextNotContains($selectorType, $selector, $text)
+    {
+        $element = $this->elementExists($selectorType, $selector);
+        $actual  = $element->getText();
+        $regex   = '/'.preg_quote($text, '/').'/ui';
+
+        $message = sprintf(
+            'The text "%s" appears in the text of the %s, but it should not.',
+            $text,
+            $this->getMatchingElementRepresentation($selectorType, $selector)
+        );
+
+        $this->assertElementText(!preg_match($regex, $actual), $message, $element);
+    }
+
+    /**
+     * Checks that specific element contains HTML.
+     *
+     * @param string       $selectorType element selector type (css, xpath)
+     * @param string|array $selector     element selector
+     * @param string       $html         expected text
+     *
+     * @throws ElementHtmlException
+     */
+    public function elementContains($selectorType, $selector, $html)
+    {
+        $element = $this->elementExists($selectorType, $selector);
+        $actual  = $element->getHtml();
+        $regex   = '/'.preg_quote($html, '/').'/ui';
+
+        $message = sprintf(
+            'The string "%s" was not found in the HTML of the %s.',
+            $html,
+            $this->getMatchingElementRepresentation($selectorType, $selector)
+        );
+
+        $this->assertElement((bool) preg_match($regex, $actual), $message, $element);
+    }
+
+    /**
+     * Checks that specific element does not contains HTML.
+     *
+     * @param string       $selectorType element selector type (css, xpath)
+     * @param string|array $selector     element selector
+     * @param string       $html         expected text
+     *
+     * @throws ElementHtmlException
+     */
+    public function elementNotContains($selectorType, $selector, $html)
+    {
+        $element = $this->elementExists($selectorType, $selector);
+        $actual  = $element->getHtml();
+        $regex   = '/'.preg_quote($html, '/').'/ui';
+
+        $message = sprintf(
+            'The string "%s" appears in the HTML of the %s, but it should not.',
+            $html,
+            $this->getMatchingElementRepresentation($selectorType, $selector)
+        );
+
+        $this->assertElement(!preg_match($regex, $actual), $message, $element);
+    }
+
+    /**
+     * Checks that an attribute exists in an element.
+     *
+     * @param string       $selectorType
+     * @param string|array $selector
+     * @param string       $attribute
+     *
+     * @return NodeElement
+     *
+     * @throws ElementHtmlException
+     */
+    public function elementAttributeExists($selectorType, $selector, $attribute)
+    {
+        $element = $this->elementExists($selectorType, $selector);
+
+        $message = sprintf(
+            'The attribute "%s" was not found in the %s.',
+            $attribute,
+            $this->getMatchingElementRepresentation($selectorType, $selector)
+        );
+
+        $this->assertElement($element->hasAttribute($attribute), $message, $element);
+
+        return $element;
+    }
+
+    /**
+     * Checks that an attribute of a specific elements contains text.
+     *
+     * @param string       $selectorType
+     * @param string|array $selector
+     * @param string       $attribute
+     * @param string       $text
+     *
+     * @throws ElementHtmlException
+     */
+    public function elementAttributeContains($selectorType, $selector, $attribute, $text)
+    {
+        $element = $this->elementAttributeExists($selectorType, $selector, $attribute);
+        $actual  = $element->getAttribute($attribute);
+        $regex   = '/'.preg_quote($text, '/').'/ui';
+
+        $message = sprintf(
+            'The text "%s" was not found in the attribute "%s" of the %s.',
+            $text,
+            $attribute,
+            $this->getMatchingElementRepresentation($selectorType, $selector)
+        );
+
+        $this->assertElement((bool) preg_match($regex, $actual), $message, $element);
+    }
+
+    /**
+     * Checks that an attribute of a specific elements does not contain text.
+     *
+     * @param string       $selectorType
+     * @param string|array $selector
+     * @param string       $attribute
+     * @param string       $text
+     *
+     * @throws ElementHtmlException
+     */
+    public function elementAttributeNotContains($selectorType, $selector, $attribute, $text)
+    {
+        $element = $this->elementAttributeExists($selectorType, $selector, $attribute);
+        $actual  = $element->getAttribute($attribute);
+        $regex   = '/'.preg_quote($text, '/').'/ui';
+
+        $message = sprintf(
+            'The text "%s" was found in the attribute "%s" of the %s.',
+            $text,
+            $attribute,
+            $this->getMatchingElementRepresentation($selectorType, $selector)
+        );
+
+        $this->assertElement(!preg_match($regex, $actual), $message, $element);
+    }
+
+    /**
+     * Checks that specific field exists on the current page.
+     *
+     * @param string             $field     field id|name|label|value
+     * @param TraversableElement $container document to check against
+     *
+     * @return NodeElement
+     *
+     * @throws ElementNotFoundException
+     */
+    public function fieldExists($field, TraversableElement $container = null)
+    {
+        $container = $container ?: $this->session->getPage();
+        $node = $container->findField($field);
+
+        if (null === $node) {
+            throw new ElementNotFoundException($this->session, 'form field', 'id|name|label|value', $field);
+        }
+
+        return $node;
+    }
+
+    /**
+     * Checks that specific field does not exists on the current page.
+     *
+     * @param string             $field     field id|name|label|value
+     * @param TraversableElement $container document to check against
+     *
+     * @throws ExpectationException
+     */
+    public function fieldNotExists($field, TraversableElement $container = null)
+    {
+        $container = $container ?: $this->session->getPage();
+        $node = $container->findField($field);
+
+        $this->assert(null === $node, sprintf('A field "%s" appears on this page, but it should not.', $field));
+    }
+
+    /**
+     * Checks that specific field have provided value.
+     *
+     * @param string             $field     field id|name|label|value
+     * @param string             $value     field value
+     * @param TraversableElement $container document to check against
+     *
+     * @throws ExpectationException
+     */
+    public function fieldValueEquals($field, $value, TraversableElement $container = null)
+    {
+        $node   = $this->fieldExists($field, $container);
+        $actual = $node->getValue();
+        $regex  = '/^'.preg_quote($value, '/').'$/ui';
+
+        $message = sprintf('The field "%s" value is "%s", but "%s" expected.', $field, $actual, $value);
+
+        $this->assert((bool) preg_match($regex, $actual), $message);
+    }
+
+    /**
+     * Checks that specific field have provided value.
+     *
+     * @param string             $field     field id|name|label|value
+     * @param string             $value     field value
+     * @param TraversableElement $container document to check against
+     *
+     * @throws ExpectationException
+     */
+    public function fieldValueNotEquals($field, $value, TraversableElement $container = null)
+    {
+        $node   = $this->fieldExists($field, $container);
+        $actual = $node->getValue();
+        $regex  = '/^'.preg_quote($value, '/').'$/ui';
+
+        $message = sprintf('The field "%s" value is "%s", but it should not be.', $field, $actual);
+
+        $this->assert(!preg_match($regex, $actual), $message);
+    }
+
+    /**
+     * Checks that specific checkbox is checked.
+     *
+     * @param string             $field     field id|name|label|value
+     * @param TraversableElement $container document to check against
+     *
+     * @throws ExpectationException
+     */
+    public function checkboxChecked($field, TraversableElement $container = null)
+    {
+        $node = $this->fieldExists($field, $container);
+
+        $this->assert($node->isChecked(), sprintf('Checkbox "%s" is not checked, but it should be.', $field));
+    }
+
+    /**
+     * Checks that specific checkbox is unchecked.
+     *
+     * @param string             $field     field id|name|label|value
+     * @param TraversableElement $container document to check against
+     *
+     * @throws ExpectationException
+     */
+    public function checkboxNotChecked($field, TraversableElement $container = null)
+    {
+        $node = $this->fieldExists($field, $container);
+
+        $this->assert(!$node->isChecked(), sprintf('Checkbox "%s" is checked, but it should not be.', $field));
+    }
+
+    /**
+     * Gets current url of the page.
+     *
+     * @return string
+     */
+    protected function getCurrentUrlPath()
+    {
+        return $this->cleanUrl($this->session->getCurrentUrl());
+    }
+
+    /**
+     * Trims scriptname from the URL.
+     *
+     * @param string $url
+     *
+     * @return string
+     */
+    protected function cleanUrl($url)
+    {
+        $parts = parse_url($url);
+        $fragment = empty($parts['fragment']) ? '' : '#' . $parts['fragment'];
+
+        return preg_replace('/^\/[^\.\/]+\.php/', '', $parts['path']) . $fragment;
+    }
+
+    /**
+     * Asserts a condition.
+     *
+     * @param bool   $condition
+     * @param string $message   Failure message
+     *
+     * @throws ExpectationException when the condition is not fulfilled
+     */
+    private function assert($condition, $message)
+    {
+        if ($condition) {
+            return;
+        }
+
+        throw new ExpectationException($message, $this->session);
+    }
+
+    /**
+     * Asserts a condition involving the response text.
+     *
+     * @param bool   $condition
+     * @param string $message   Failure message
+     *
+     * @throws ResponseTextException when the condition is not fulfilled
+     */
+    private function assertResponseText($condition, $message)
+    {
+        if ($condition) {
+            return;
+        }
+
+        throw new ResponseTextException($message, $this->session);
+    }
+
+    /**
+     * Asserts a condition on an element.
+     *
+     * @param bool    $condition
+     * @param string  $message   Failure message
+     * @param Element $element
+     *
+     * @throws ElementHtmlException when the condition is not fulfilled
+     */
+    private function assertElement($condition, $message, Element $element)
+    {
+        if ($condition) {
+            return;
+        }
+
+        throw new ElementHtmlException($message, $this->session, $element);
+    }
+
+    /**
+     * Asserts a condition involving the text of an element.
+     *
+     * @param bool    $condition
+     * @param string  $message   Failure message
+     * @param Element $element
+     *
+     * @throws ElementTextException when the condition is not fulfilled
+     */
+    private function assertElementText($condition, $message, Element $element)
+    {
+        if ($condition) {
+            return;
+        }
+
+        throw new ElementTextException($message, $this->session, $element);
+    }
+
+    /**
+     * @param string       $selectorType
+     * @param string|array $selector
+     * @param boolean      $plural
+     *
+     * @return string
+     */
+    private function getMatchingElementRepresentation($selectorType, $selector, $plural = false)
+    {
+        $pluralization = $plural ? 's' : '';
+
+        if (in_array($selectorType, array('named', 'named_exact', 'named_partial'))
+            && is_array($selector) && 2 === count($selector)
+        ) {
+            return sprintf('%s%s matching locator "%s"', $selector[0], $pluralization, $selector[1]);
+        }
+
+        if (is_array($selector)) {
+            $selector = implode(' ', $selector);
+        }
+
+        return sprintf('element%s matching %s "%s"', $pluralization, $selectorType, $selector);
+    }
+}
diff --git a/vendor/behat/mink/tests/Driver/CoreDriverTest.php b/vendor/behat/mink/tests/Driver/CoreDriverTest.php
new file mode 100644
index 00000000000..d99b17f6e9a
--- /dev/null
+++ b/vendor/behat/mink/tests/Driver/CoreDriverTest.php
@@ -0,0 +1,76 @@
+<?php
+
+namespace Behat\Mink\Tests\Driver;
+
+class CoreDriverTest extends \PHPUnit_Framework_TestCase
+{
+    public function testNoExtraMethods()
+    {
+        $interfaceRef = new \ReflectionClass('Behat\Mink\Driver\DriverInterface');
+        $coreDriverRef = new \ReflectionClass('Behat\Mink\Driver\CoreDriver');
+
+        foreach ($coreDriverRef->getMethods(\ReflectionMethod::IS_PUBLIC) as $method) {
+            $this->assertTrue(
+                $interfaceRef->hasMethod($method->getName()),
+                sprintf('CoreDriver should not implement methods which are not part of the DriverInterface but %s found', $method->getName())
+            );
+        }
+    }
+
+    /**
+     * @dataProvider getDriverInterfaceMethods
+     */
+    public function testInterfaceMethods(\ReflectionMethod $method)
+    {
+        $refl = new \ReflectionClass('Behat\Mink\Driver\CoreDriver');
+
+        $this->assertFalse(
+            $refl->getMethod($method->getName())->isAbstract(),
+            sprintf('CoreDriver should implement a dummy %s method', $method->getName())
+        );
+
+        $driver = $this->getMockForAbstractClass('Behat\Mink\Driver\CoreDriver');
+
+        $this->setExpectedException('Behat\Mink\Exception\UnsupportedDriverActionException');
+        call_user_func_array(array($driver, $method->getName()), $this->getArguments($method));
+    }
+
+    public function getDriverInterfaceMethods()
+    {
+        $ref = new \ReflectionClass('Behat\Mink\Driver\DriverInterface');
+
+        return array_map(function ($method) {
+            return array($method);
+        }, $ref->getMethods());
+    }
+
+    private function getArguments(\ReflectionMethod $method)
+    {
+        $arguments = array();
+
+        foreach ($method->getParameters() as $parameter) {
+            $arguments[] = $this->getArgument($parameter);
+        }
+
+        return $arguments;
+    }
+
+    private function getArgument(\ReflectionParameter $argument)
+    {
+        if ($argument->isOptional()) {
+            return $argument->getDefaultValue();
+        }
+
+        if ($argument->allowsNull()) {
+            return null;
+        }
+
+        if ($argument->getClass()) {
+            return $this->getMockBuilder($argument->getClass()->getName())
+                ->disableOriginalConstructor()
+                ->getMock();
+        }
+
+        return null;
+    }
+}
diff --git a/vendor/behat/mink/tests/Element/DocumentElementTest.php b/vendor/behat/mink/tests/Element/DocumentElementTest.php
new file mode 100644
index 00000000000..bb42b685f8a
--- /dev/null
+++ b/vendor/behat/mink/tests/Element/DocumentElementTest.php
@@ -0,0 +1,446 @@
+<?php
+
+namespace Behat\Mink\Tests\Element;
+
+use Behat\Mink\Element\DocumentElement;
+
+class DocumentElementTest extends ElementTest
+{
+    /**
+     * Page.
+     *
+     * @var DocumentElement
+     */
+    private $document;
+
+    protected function setUp()
+    {
+        parent::setUp();
+        $this->document = new DocumentElement($this->session);
+    }
+
+    public function testGetSession()
+    {
+        $this->assertEquals($this->session, $this->document->getSession());
+    }
+
+    public function testFindAll()
+    {
+        $xpath = 'h3[a]';
+        $css = 'h3 > a';
+
+        $this->driver
+            ->expects($this->exactly(2))
+            ->method('find')
+            ->will($this->returnValueMap(array(
+                array('//html/' . $xpath, array(2, 3, 4)),
+                array('//html/' . $css, array(1, 2)),
+            )));
+
+        $this->selectors
+            ->expects($this->exactly(2))
+            ->method('selectorToXpath')
+            ->will($this->returnValueMap(array(
+                array('xpath', $xpath, $xpath),
+                array('css', $css, $css),
+            )));
+
+        $this->assertEquals(3, count($this->document->findAll('xpath', $xpath)));
+        $this->assertEquals(2, count($this->document->findAll('css', $css)));
+    }
+
+    public function testFind()
+    {
+        $this->driver
+            ->expects($this->exactly(3))
+            ->method('find')
+            ->with('//html/h3[a]')
+            ->will($this->onConsecutiveCalls(array(2, 3, 4), array(1, 2), array()));
+
+        $xpath = 'h3[a]';
+        $css = 'h3 > a';
+
+        $this->selectors
+            ->expects($this->exactly(3))
+            ->method('selectorToXpath')
+            ->will($this->returnValueMap(array(
+                array('xpath', $xpath, $xpath),
+                array('xpath', $xpath, $xpath),
+                array('css', $css, $xpath),
+            )));
+
+        $this->assertEquals(2, $this->document->find('xpath', $xpath));
+        $this->assertEquals(1, $this->document->find('css', $css));
+        $this->assertNull($this->document->find('xpath', $xpath));
+    }
+
+    public function testFindField()
+    {
+        $this->mockNamedFinder(
+            '//field',
+            array('field1', 'field2', 'field3'),
+            array('field', 'some field')
+        );
+
+        $this->assertEquals('field1', $this->document->findField('some field'));
+        $this->assertEquals(null, $this->document->findField('some field'));
+    }
+
+    public function testFindLink()
+    {
+        $this->mockNamedFinder(
+            '//link',
+            array('link1', 'link2', 'link3'),
+            array('link', 'some link')
+        );
+
+        $this->assertEquals('link1', $this->document->findLink('some link'));
+        $this->assertEquals(null, $this->document->findLink('some link'));
+    }
+
+    public function testFindButton()
+    {
+        $this->mockNamedFinder(
+            '//button',
+            array('button1', 'button2', 'button3'),
+            array('button', 'some button')
+        );
+
+        $this->assertEquals('button1', $this->document->findButton('some button'));
+        $this->assertEquals(null, $this->document->findButton('some button'));
+    }
+
+    public function testFindById()
+    {
+        $xpath = '//*[@id=some-item-2]';
+
+        $this->mockNamedFinder($xpath, array(array('id2', 'id3'), array()), array('id', 'some-item-2'));
+
+        $this->assertEquals('id2', $this->document->findById('some-item-2'));
+        $this->assertEquals(null, $this->document->findById('some-item-2'));
+    }
+
+    public function testHasSelector()
+    {
+        $this->driver
+            ->expects($this->exactly(2))
+            ->method('find')
+            ->with('//html/some xpath')
+            ->will($this->onConsecutiveCalls(array('id2', 'id3'), array()));
+
+        $this->selectors
+            ->expects($this->exactly(2))
+            ->method('selectorToXpath')
+            ->with('xpath', 'some xpath')
+            ->will($this->returnValue('some xpath'));
+
+        $this->assertTrue($this->document->has('xpath', 'some xpath'));
+        $this->assertFalse($this->document->has('xpath', 'some xpath'));
+    }
+
+    public function testHasContent()
+    {
+        $this->mockNamedFinder(
+            '//some content',
+            array('item1', 'item2'),
+            array('content', 'some content')
+        );
+
+        $this->assertTrue($this->document->hasContent('some content'));
+        $this->assertFalse($this->document->hasContent('some content'));
+    }
+
+    public function testHasLink()
+    {
+        $this->mockNamedFinder(
+            '//link',
+            array('link1', 'link2', 'link3'),
+            array('link', 'some link')
+        );
+
+        $this->assertTrue($this->document->hasLink('some link'));
+        $this->assertFalse($this->document->hasLink('some link'));
+    }
+
+    public function testHasButton()
+    {
+        $this->mockNamedFinder(
+            '//button',
+            array('button1', 'button2', 'button3'),
+            array('button', 'some button')
+        );
+
+        $this->assertTrue($this->document->hasButton('some button'));
+        $this->assertFalse($this->document->hasButton('some button'));
+    }
+
+    public function testHasField()
+    {
+        $this->mockNamedFinder(
+            '//field',
+            array('field1', 'field2', 'field3'),
+            array('field', 'some field')
+        );
+
+        $this->assertTrue($this->document->hasField('some field'));
+        $this->assertFalse($this->document->hasField('some field'));
+    }
+
+    public function testHasCheckedField()
+    {
+        $checkbox = $this->getMockBuilder('Behat\Mink\Element\NodeElement')
+            ->disableOriginalConstructor()
+            ->getMock();
+        $checkbox
+            ->expects($this->exactly(2))
+            ->method('isChecked')
+            ->will($this->onConsecutiveCalls(true, false));
+
+        $this->mockNamedFinder(
+            '//field',
+            array(array($checkbox), array(), array($checkbox)),
+            array('field', 'some checkbox'),
+            3
+        );
+
+        $this->assertTrue($this->document->hasCheckedField('some checkbox'));
+        $this->assertFalse($this->document->hasCheckedField('some checkbox'));
+        $this->assertFalse($this->document->hasCheckedField('some checkbox'));
+    }
+
+    public function testHasUncheckedField()
+    {
+        $checkbox = $this->getMockBuilder('Behat\Mink\Element\NodeElement')
+            ->disableOriginalConstructor()
+            ->getMock();
+        $checkbox
+            ->expects($this->exactly(2))
+            ->method('isChecked')
+            ->will($this->onConsecutiveCalls(true, false));
+
+        $this->mockNamedFinder(
+            '//field',
+            array(array($checkbox), array(), array($checkbox)),
+            array('field', 'some checkbox'),
+            3
+        );
+
+        $this->assertFalse($this->document->hasUncheckedField('some checkbox'));
+        $this->assertFalse($this->document->hasUncheckedField('some checkbox'));
+        $this->assertTrue($this->document->hasUncheckedField('some checkbox'));
+    }
+
+    public function testHasSelect()
+    {
+        $this->mockNamedFinder(
+            '//select',
+            array('select'),
+            array('select', 'some select field')
+        );
+
+        $this->assertTrue($this->document->hasSelect('some select field'));
+        $this->assertFalse($this->document->hasSelect('some select field'));
+    }
+
+    public function testHasTable()
+    {
+        $this->mockNamedFinder(
+            '//table',
+            array('table'),
+            array('table', 'some table')
+        );
+
+        $this->assertTrue($this->document->hasTable('some table'));
+        $this->assertFalse($this->document->hasTable('some table'));
+    }
+
+    public function testClickLink()
+    {
+        $node = $this->getMockBuilder('Behat\Mink\Element\NodeElement')
+            ->disableOriginalConstructor()
+            ->getMock();
+        $node
+            ->expects($this->once())
+            ->method('click');
+
+        $this->mockNamedFinder(
+            '//link',
+            array($node),
+            array('link', 'some link')
+        );
+
+        $this->document->clickLink('some link');
+        $this->setExpectedException('Behat\Mink\Exception\ElementNotFoundException');
+        $this->document->clickLink('some link');
+    }
+
+    public function testClickButton()
+    {
+        $node = $this->getMockBuilder('Behat\Mink\Element\NodeElement')
+            ->disableOriginalConstructor()
+            ->getMock();
+        $node
+            ->expects($this->once())
+            ->method('press');
+
+        $this->mockNamedFinder(
+            '//button',
+            array($node),
+            array('button', 'some button')
+        );
+
+        $this->document->pressButton('some button');
+        $this->setExpectedException('Behat\Mink\Exception\ElementNotFoundException');
+        $this->document->pressButton('some button');
+    }
+
+    public function testFillField()
+    {
+        $node = $this->getMockBuilder('Behat\Mink\Element\NodeElement')
+            ->disableOriginalConstructor()
+            ->getMock();
+        $node
+            ->expects($this->once())
+            ->method('setValue')
+            ->with('some val');
+
+        $this->mockNamedFinder(
+            '//field',
+            array($node),
+            array('field', 'some field')
+        );
+
+        $this->document->fillField('some field', 'some val');
+        $this->setExpectedException('Behat\Mink\Exception\ElementNotFoundException');
+        $this->document->fillField('some field', 'some val');
+    }
+
+    public function testCheckField()
+    {
+        $node = $this->getMockBuilder('Behat\Mink\Element\NodeElement')
+            ->disableOriginalConstructor()
+            ->getMock();
+        $node
+            ->expects($this->once())
+            ->method('check');
+
+        $this->mockNamedFinder(
+            '//field',
+            array($node),
+            array('field', 'some field')
+        );
+
+        $this->document->checkField('some field');
+        $this->setExpectedException('Behat\Mink\Exception\ElementNotFoundException');
+        $this->document->checkField('some field');
+    }
+
+    public function testUncheckField()
+    {
+        $node = $this->getMockBuilder('Behat\Mink\Element\NodeElement')
+            ->disableOriginalConstructor()
+            ->getMock();
+        $node
+            ->expects($this->once())
+            ->method('uncheck');
+
+        $this->mockNamedFinder(
+            '//field',
+            array($node),
+            array('field', 'some field')
+        );
+
+        $this->document->uncheckField('some field');
+        $this->setExpectedException('Behat\Mink\Exception\ElementNotFoundException');
+        $this->document->uncheckField('some field');
+    }
+
+    public function testSelectField()
+    {
+        $node = $this->getMockBuilder('Behat\Mink\Element\NodeElement')
+            ->disableOriginalConstructor()
+            ->getMock();
+        $node
+            ->expects($this->once())
+            ->method('selectOption')
+            ->with('option2');
+
+        $this->mockNamedFinder(
+            '//field',
+            array($node),
+            array('field', 'some field')
+        );
+
+        $this->document->selectFieldOption('some field', 'option2');
+        $this->setExpectedException('Behat\Mink\Exception\ElementNotFoundException');
+        $this->document->selectFieldOption('some field', 'option2');
+    }
+
+    public function testAttachFileToField()
+    {
+        $node = $this->getMockBuilder('Behat\Mink\Element\NodeElement')
+            ->disableOriginalConstructor()
+            ->getMock();
+        $node
+            ->expects($this->once())
+            ->method('attachFile')
+            ->with('/path/to/file');
+
+        $this->mockNamedFinder(
+            '//field',
+            array($node),
+            array('field', 'some field')
+        );
+
+        $this->document->attachFileToField('some field', '/path/to/file');
+        $this->setExpectedException('Behat\Mink\Exception\ElementNotFoundException');
+        $this->document->attachFileToField('some field', '/path/to/file');
+    }
+
+    public function testGetContent()
+    {
+        $expects = 'page content';
+        $this->driver
+            ->expects($this->once())
+            ->method('getContent')
+            ->will($this->returnValue($expects));
+
+        $this->assertEquals($expects, $this->document->getContent());
+    }
+
+    public function testGetText()
+    {
+        $expects = 'val1';
+        $this->driver
+            ->expects($this->once())
+            ->method('getText')
+            ->with('//html')
+            ->will($this->returnValue($expects));
+
+        $this->assertEquals($expects, $this->document->getText());
+    }
+
+    public function testGetHtml()
+    {
+        $expects = 'val1';
+        $this->driver
+            ->expects($this->once())
+            ->method('getHtml')
+            ->with('//html')
+            ->will($this->returnValue($expects));
+
+        $this->assertEquals($expects, $this->document->getHtml());
+    }
+
+    public function testGetOuterHtml()
+    {
+        $expects = 'val1';
+        $this->driver
+            ->expects($this->once())
+            ->method('getOuterHtml')
+            ->with('//html')
+            ->will($this->returnValue($expects));
+
+        $this->assertEquals($expects, $this->document->getOuterHtml());
+    }
+}
diff --git a/vendor/behat/mink/tests/Element/ElementTest.php b/vendor/behat/mink/tests/Element/ElementTest.php
new file mode 100644
index 00000000000..1f9240a13c1
--- /dev/null
+++ b/vendor/behat/mink/tests/Element/ElementTest.php
@@ -0,0 +1,76 @@
+<?php
+
+namespace Behat\Mink\Tests\Element;
+
+use Behat\Mink\Driver\DriverInterface;
+use Behat\Mink\Session;
+use Behat\Mink\Selector\SelectorsHandler;
+
+abstract class ElementTest extends \PHPUnit_Framework_TestCase
+{
+    /**
+     * Session.
+     *
+     * @var Session
+     */
+    protected $session;
+
+    /**
+     * @var DriverInterface|\PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $driver;
+
+    /**
+     * Selectors.
+     *
+     * @var SelectorsHandler|\PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $selectors;
+
+    protected function setUp()
+    {
+        $this->driver = $this->getMockBuilder('Behat\Mink\Driver\DriverInterface')->getMock();
+        $this->driver
+            ->expects($this->once())
+            ->method('setSession');
+
+        $this->selectors = $this->getMockBuilder('Behat\Mink\Selector\SelectorsHandler')->getMock();
+        $this->session = new Session($this->driver, $this->selectors);
+
+        $this->selectors
+            ->expects($this->any())
+            ->method('xpathLiteral')
+            ->will($this->returnArgument(0));
+    }
+
+    protected function mockNamedFinder($xpath, array $results, $locator, $times = 2)
+    {
+        if (!is_array($results[0])) {
+            $results = array($results, array());
+        }
+
+        // In case of empty results, a second call will be done using the partial selector
+        $processedResults = array();
+        foreach ($results as $result) {
+            $processedResults[] = $result;
+            if (empty($result)) {
+                $processedResults[] = $result;
+                $times++;
+            }
+        }
+
+        $returnValue = call_user_func_array(array($this, 'onConsecutiveCalls'), $processedResults);
+
+        $this->driver
+            ->expects($this->exactly($times))
+            ->method('find')
+            ->with('//html' . $xpath)
+            ->will($returnValue);
+
+        $this->selectors
+            ->expects($this->exactly($times))
+            ->method('selectorToXpath')
+            ->with($this->logicalOr('named_exact', 'named_partial'), $locator)
+            ->will($this->returnValue($xpath));
+    }
+}
diff --git a/vendor/behat/mink/tests/Element/NodeElementTest.php b/vendor/behat/mink/tests/Element/NodeElementTest.php
new file mode 100644
index 00000000000..b6a8bdeb0c9
--- /dev/null
+++ b/vendor/behat/mink/tests/Element/NodeElementTest.php
@@ -0,0 +1,593 @@
+<?php
+
+namespace Behat\Mink\Tests\Element;
+
+use Behat\Mink\Element\NodeElement;
+
+class NodeElementTest extends ElementTest
+{
+    public function testGetXpath()
+    {
+        $node = new NodeElement('some custom xpath', $this->session);
+
+        $this->assertEquals('some custom xpath', $node->getXpath());
+        $this->assertNotEquals('not some custom xpath', $node->getXpath());
+    }
+
+    public function testGetText()
+    {
+        $expected = 'val1';
+        $node = new NodeElement('text_tag', $this->session);
+
+        $this->driver
+            ->expects($this->once())
+            ->method('getText')
+            ->with('text_tag')
+            ->will($this->returnValue($expected));
+
+        $this->assertEquals($expected, $node->getText());
+    }
+
+    public function testGetOuterHtml()
+    {
+        $expected = 'val1';
+        $node = new NodeElement('text_tag', $this->session);
+
+        $this->driver
+            ->expects($this->once())
+            ->method('getOuterHtml')
+            ->with('text_tag')
+            ->will($this->returnValue($expected));
+
+        $this->assertEquals($expected, $node->getOuterHtml());
+    }
+
+    public function testElementIsValid()
+    {
+        $elementXpath = 'some xpath';
+        $node = new NodeElement($elementXpath, $this->session);
+
+        $this->driver
+            ->expects($this->once())
+            ->method('find')
+            ->with($elementXpath)
+            ->will($this->returnValue(array($elementXpath)));
+
+        $this->assertTrue($node->isValid());
+    }
+
+    public function testElementIsNotValid()
+    {
+        $node = new NodeElement('some xpath', $this->session);
+
+        $this->driver
+            ->expects($this->exactly(2))
+            ->method('find')
+            ->with('some xpath')
+            ->will($this->onConsecutiveCalls(array(), array('xpath1', 'xpath2')));
+
+        $this->assertFalse($node->isValid(), 'no elements found is invalid element');
+        $this->assertFalse($node->isValid(), 'more then 1 element found is invalid element');
+    }
+
+    public function testWaitForSuccess()
+    {
+        $callCounter = 0;
+        $node = new NodeElement('some xpath', $this->session);
+
+        $result = $node->waitFor(5, function ($givenNode) use (&$callCounter) {
+            $callCounter++;
+
+            if (1 === $callCounter) {
+                return null;
+            } elseif (2 === $callCounter) {
+                return false;
+            } elseif (3 === $callCounter) {
+                return array();
+            }
+
+            return $givenNode;
+        });
+
+        $this->assertEquals(4, $callCounter, '->waitFor() tries to locate element several times before failing');
+        $this->assertSame($node, $result, '->waitFor() returns node found in callback');
+    }
+
+    public function testWaitForTimeout()
+    {
+        $node = new NodeElement('some xpath', $this->session);
+
+        $expectedTimeout = 2;
+        $startTime = microtime(true);
+        $result = $node->waitFor($expectedTimeout, function () {
+            return null;
+        });
+        $endTime = microtime(true);
+
+        $this->assertNull($result, '->waitFor() returns whatever callback gives');
+        $this->assertEquals($expectedTimeout, round($endTime - $startTime));
+    }
+
+    /**
+     * @expectedException \InvalidArgumentException
+     */
+    public function testWaitForFailure()
+    {
+        $node = new NodeElement('some xpath', $this->session);
+        $node->waitFor(5, 'not a callable');
+    }
+
+    public function testHasAttribute()
+    {
+        $node = new NodeElement('input_tag', $this->session);
+
+        $this->driver
+            ->expects($this->exactly(2))
+            ->method('getAttribute')
+            ->with('input_tag', 'href')
+            ->will($this->onConsecutiveCalls(null, 'http://...'));
+
+        $this->assertFalse($node->hasAttribute('href'));
+        $this->assertTrue($node->hasAttribute('href'));
+    }
+
+    public function testGetAttribute()
+    {
+        $expected = 'http://...';
+        $node = new NodeElement('input_tag', $this->session);
+
+        $this->driver
+            ->expects($this->once())
+            ->method('getAttribute')
+            ->with('input_tag', 'href')
+            ->will($this->returnValue($expected));
+
+        $this->assertEquals($expected, $node->getAttribute('href'));
+    }
+
+    public function testHasClass()
+    {
+        $node = new NodeElement('input_tag', $this->session);
+
+        $this->driver
+            ->expects($this->exactly(6))
+            ->method('getAttribute')
+            ->with('input_tag', 'class')
+            ->will($this->returnValue('class1 class2'));
+
+        $this->assertTrue($node->hasClass('class1'));
+        $this->assertTrue($node->hasClass('class2'));
+        $this->assertFalse($node->hasClass('class3'));
+    }
+
+    public function testHasClassWithoutArgument()
+    {
+        $node = new NodeElement('input_tag', $this->session);
+
+        $this->driver
+            ->expects($this->once())
+            ->method('getAttribute')
+            ->with('input_tag', 'class')
+            ->will($this->returnValue(null));
+
+        $this->assertFalse($node->hasClass('class3'));
+    }
+
+    public function testGetValue()
+    {
+        $expected = 'val1';
+        $node = new NodeElement('input_tag', $this->session);
+
+        $this->driver
+            ->expects($this->once())
+            ->method('getValue')
+            ->with('input_tag')
+            ->will($this->returnValue($expected));
+
+        $this->assertEquals($expected, $node->getValue());
+    }
+
+    public function testSetValue()
+    {
+        $expected = 'new_val';
+        $node = new NodeElement('input_tag', $this->session);
+
+        $this->driver
+            ->expects($this->once())
+            ->method('setValue')
+            ->with('input_tag', $expected);
+
+        $node->setValue($expected);
+    }
+
+    public function testClick()
+    {
+        $node = new NodeElement('link_or_button', $this->session);
+
+        $this->driver
+            ->expects($this->once())
+            ->method('click')
+            ->with('link_or_button');
+
+        $node->click();
+    }
+
+    public function testPress()
+    {
+        $node = new NodeElement('link_or_button', $this->session);
+
+        $this->driver
+            ->expects($this->once())
+            ->method('click')
+            ->with('link_or_button');
+
+        $node->press();
+    }
+
+    public function testRightClick()
+    {
+        $node = new NodeElement('elem', $this->session);
+
+        $this->driver
+            ->expects($this->once())
+            ->method('rightClick')
+            ->with('elem');
+
+        $node->rightClick();
+    }
+
+    public function testDoubleClick()
+    {
+        $node = new NodeElement('elem', $this->session);
+
+        $this->driver
+            ->expects($this->once())
+            ->method('doubleClick')
+            ->with('elem');
+
+        $node->doubleClick();
+    }
+
+    public function testCheck()
+    {
+        $node = new NodeElement('checkbox_or_radio', $this->session);
+
+        $this->driver
+            ->expects($this->once())
+            ->method('check')
+            ->with('checkbox_or_radio');
+
+        $node->check();
+    }
+
+    public function testUncheck()
+    {
+        $node = new NodeElement('checkbox_or_radio', $this->session);
+
+        $this->driver
+            ->expects($this->once())
+            ->method('uncheck')
+            ->with('checkbox_or_radio');
+
+        $node->uncheck();
+    }
+
+    public function testSelectOption()
+    {
+        $node = new NodeElement('select', $this->session);
+        $option = $this->getMockBuilder('Behat\Mink\Element\NodeElement')
+            ->disableOriginalConstructor()
+            ->getMock();
+        $option
+            ->expects($this->once())
+            ->method('getValue')
+            ->will($this->returnValue('item1'));
+
+        $this->driver
+            ->expects($this->once())
+            ->method('getTagName')
+            ->with('select')
+            ->will($this->returnValue('select'));
+
+        $this->driver
+            ->expects($this->once())
+            ->method('find')
+            ->with('select/option')
+            ->will($this->returnValue(array($option)));
+
+        $this->selectors
+            ->expects($this->once())
+            ->method('selectorToXpath')
+            ->with('named_exact', array('option', 'item1'))
+            ->will($this->returnValue('option'));
+
+        $this->driver
+            ->expects($this->once())
+            ->method('selectOption')
+            ->with('select', 'item1', false);
+
+        $node->selectOption('item1');
+    }
+
+    /**
+     * @expectedException \Behat\Mink\Exception\ElementNotFoundException
+     */
+    public function testSelectOptionNotFound()
+    {
+        $node = new NodeElement('select', $this->session);
+
+        $this->driver
+            ->expects($this->once())
+            ->method('getTagName')
+            ->with('select')
+            ->will($this->returnValue('select'));
+
+        $this->driver
+            ->expects($this->exactly(2))
+            ->method('find')
+            ->with('select/option')
+            ->will($this->returnValue(array()));
+
+        $this->selectors
+            ->expects($this->exactly(2))
+            ->method('selectorToXpath')
+            ->with($this->logicalOr('named_exact', 'named_partial'), array('option', 'item1'))
+            ->will($this->returnValue('option'));
+
+        $node->selectOption('item1');
+    }
+
+    public function testSelectOptionOtherTag()
+    {
+        $node = new NodeElement('div', $this->session);
+
+        $this->driver
+            ->expects($this->once())
+            ->method('getTagName')
+            ->with('div')
+            ->will($this->returnValue('div'));
+
+        $this->driver
+            ->expects($this->once())
+            ->method('selectOption')
+            ->with('div', 'item1', false);
+
+        $node->selectOption('item1');
+    }
+
+    public function testGetTagName()
+    {
+        $node = new NodeElement('html//h3', $this->session);
+
+        $this->driver
+            ->expects($this->once())
+            ->method('getTagName')
+            ->with('html//h3')
+            ->will($this->returnValue('h3'));
+
+        $this->assertEquals('h3', $node->getTagName());
+    }
+
+    public function testGetParent()
+    {
+        $node = new NodeElement('elem', $this->session);
+        $parent = $this->getMockBuilder('Behat\Mink\Element\NodeElement')
+            ->disableOriginalConstructor()
+            ->getMock();
+
+        $this->driver
+            ->expects($this->once())
+            ->method('find')
+            ->with('elem/..')
+            ->will($this->returnValue(array($parent)));
+
+        $this->selectors
+            ->expects($this->once())
+            ->method('selectorToXpath')
+            ->with('xpath', '..')
+            ->will($this->returnValue('..'));
+
+        $this->assertSame($parent, $node->getParent());
+    }
+
+    public function testAttachFile()
+    {
+        $node = new NodeElement('elem', $this->session);
+
+        $this->driver
+            ->expects($this->once())
+            ->method('attachFile')
+            ->with('elem', 'path');
+
+        $node->attachFile('path');
+    }
+
+    public function testIsVisible()
+    {
+        $node = new NodeElement('some_xpath', $this->session);
+
+        $this->driver
+            ->expects($this->exactly(2))
+            ->method('isVisible')
+            ->with('some_xpath')
+            ->will($this->onConsecutiveCalls(true, false));
+
+        $this->assertTrue($node->isVisible());
+        $this->assertFalse($node->isVisible());
+    }
+
+    public function testIsChecked()
+    {
+        $node = new NodeElement('some_xpath', $this->session);
+
+        $this->driver
+            ->expects($this->exactly(2))
+            ->method('isChecked')
+            ->with('some_xpath')
+            ->will($this->onConsecutiveCalls(true, false));
+
+        $this->assertTrue($node->isChecked());
+        $this->assertFalse($node->isChecked());
+    }
+
+    public function testIsSelected()
+    {
+        $node = new NodeElement('some_xpath', $this->session);
+
+        $this->driver
+            ->expects($this->exactly(2))
+            ->method('isSelected')
+            ->with('some_xpath')
+            ->will($this->onConsecutiveCalls(true, false));
+
+        $this->assertTrue($node->isSelected());
+        $this->assertFalse($node->isSelected());
+    }
+
+    public function testFocus()
+    {
+        $node = new NodeElement('some-element', $this->session);
+
+        $this->driver
+            ->expects($this->once())
+            ->method('focus')
+            ->with('some-element');
+
+        $node->focus();
+    }
+
+    public function testBlur()
+    {
+        $node = new NodeElement('some-element', $this->session);
+
+        $this->driver
+            ->expects($this->once())
+            ->method('blur')
+            ->with('some-element');
+
+        $node->blur();
+    }
+
+    public function testMouseOver()
+    {
+        $node = new NodeElement('some-element', $this->session);
+
+        $this->driver
+            ->expects($this->once())
+            ->method('mouseOver')
+            ->with('some-element');
+
+        $node->mouseOver();
+    }
+
+    public function testDragTo()
+    {
+        $node = new NodeElement('some_tag1', $this->session);
+
+        $target = $this->getMock('Behat\Mink\Element\ElementInterface');
+        $target->expects($this->any())
+            ->method('getXPath')
+            ->will($this->returnValue('some_tag2'));
+
+        $this->driver
+            ->expects($this->once())
+            ->method('dragTo')
+            ->with('some_tag1', 'some_tag2');
+
+        $node->dragTo($target);
+    }
+
+    public function testKeyPress()
+    {
+        $node = new NodeElement('elem', $this->session);
+
+        $this->driver
+            ->expects($this->once())
+            ->method('keyPress')
+            ->with('elem', 'key');
+
+        $node->keyPress('key');
+    }
+
+    public function testKeyDown()
+    {
+        $node = new NodeElement('elem', $this->session);
+
+        $this->driver
+            ->expects($this->once())
+            ->method('keyDown')
+            ->with('elem', 'key');
+
+        $node->keyDown('key');
+    }
+
+    public function testKeyUp()
+    {
+        $node = new NodeElement('elem', $this->session);
+
+        $this->driver
+            ->expects($this->once())
+            ->method('keyUp')
+            ->with('elem', 'key');
+
+        $node->keyUp('key');
+    }
+
+    public function testSubmitForm()
+    {
+        $node = new NodeElement('some_xpath', $this->session);
+
+        $this->driver
+            ->expects($this->once())
+            ->method('submitForm')
+            ->with('some_xpath');
+
+        $node->submit();
+    }
+
+    public function testFindAllUnion()
+    {
+        $node = new NodeElement('some_xpath', $this->session);
+        $xpath = "some_tag1 | some_tag2[@foo =\n 'bar|'']\n | some_tag3[foo | bar]";
+        $expected = "some_xpath/some_tag1 | some_xpath/some_tag2[@foo =\n 'bar|''] | some_xpath/some_tag3[foo | bar]";
+
+        $this->driver
+            ->expects($this->exactly(1))
+            ->method('find')
+            ->will($this->returnValueMap(array(
+                array($expected, array(2, 3, 4)),
+            )));
+
+        $this->selectors
+            ->expects($this->exactly(1))
+            ->method('selectorToXpath')
+            ->will($this->returnValueMap(array(
+                array('xpath', $xpath, $xpath),
+            )));
+
+        $this->assertEquals(3, count($node->findAll('xpath', $xpath)));
+    }
+
+    public function testFindAllParentUnion()
+    {
+        $node = new NodeElement('some_xpath | another_xpath', $this->session);
+        $xpath = "some_tag1 | some_tag2";
+        $expectedPrefixed = "(some_xpath | another_xpath)/some_tag1 | (some_xpath | another_xpath)/some_tag2";
+
+        $this->driver
+            ->expects($this->exactly(1))
+            ->method('find')
+            ->will($this->returnValueMap(array(
+                array($expectedPrefixed, array(2, 3, 4)),
+            )));
+
+        $this->selectors
+            ->expects($this->exactly(1))
+            ->method('selectorToXpath')
+            ->will($this->returnValueMap(array(
+                array('xpath', $xpath, $xpath),
+            )));
+
+        $this->assertEquals(3, count($node->findAll('xpath', $xpath)));
+    }
+}
diff --git a/vendor/behat/mink/tests/Exception/ElementExceptionTest.php b/vendor/behat/mink/tests/Exception/ElementExceptionTest.php
new file mode 100644
index 00000000000..021e8d58782
--- /dev/null
+++ b/vendor/behat/mink/tests/Exception/ElementExceptionTest.php
@@ -0,0 +1,39 @@
+<?php
+
+namespace Behat\Mink\Tests\Exception;
+
+use Behat\Mink\Exception\ElementException;
+
+class ElementExceptionTest extends \PHPUnit_Framework_TestCase
+{
+    public function testMessage()
+    {
+        $exception = new ElementException($this->getElementMock(), new \Exception('Something went wrong'));
+
+        $expectedMessage = "Exception thrown by element XPath\nSomething went wrong";
+        $this->assertEquals($expectedMessage, $exception->getMessage());
+        $this->assertEquals($expectedMessage, (string) $exception);
+    }
+
+    public function testElement()
+    {
+        $element = $this->getElementMock();
+
+        $exception = new ElementException($element, new \Exception('Something went wrong'));
+
+        $this->assertSame($element, $exception->getElement());
+    }
+
+    private function getElementMock()
+    {
+        $mock = $this->getMockBuilder('Behat\Mink\Element\Element')
+            ->disableOriginalConstructor()
+            ->getMock();
+
+        $mock->expects($this->any())
+            ->method('getXPath')
+            ->will($this->returnValue('element XPath'));
+
+        return $mock;
+    }
+}
diff --git a/vendor/behat/mink/tests/Exception/ElementHtmlExceptionTest.php b/vendor/behat/mink/tests/Exception/ElementHtmlExceptionTest.php
new file mode 100644
index 00000000000..63d39dd0c4c
--- /dev/null
+++ b/vendor/behat/mink/tests/Exception/ElementHtmlExceptionTest.php
@@ -0,0 +1,61 @@
+<?php
+
+namespace Behat\Mink\Tests\Exception;
+
+use Behat\Mink\Exception\ElementHtmlException;
+
+class ElementHtmlExceptionTest extends \PHPUnit_Framework_TestCase
+{
+    public function testExceptionToString()
+    {
+        $driver = $this->getMock('Behat\Mink\Driver\DriverInterface');
+        $element = $this->getElementMock();
+
+        $session = $this->getSessionMock();
+        $session->expects($this->any())
+            ->method('getDriver')
+            ->will($this->returnValue($driver));
+        $session->expects($this->any())
+            ->method('getStatusCode')
+            ->will($this->returnValue(200));
+        $session->expects($this->any())
+            ->method('getCurrentUrl')
+            ->will($this->returnValue('http://localhost/test'));
+
+        $element->expects($this->any())
+            ->method('getOuterHtml')
+            ->will($this->returnValue("<div>\n    <h1>Hello world</h1>\n    <p>Test</p>\n</div>"));
+
+        $expected = <<<'TXT'
+Html error
+
++--[ HTTP/1.1 200 | http://localhost/test | %s ]
+|
+|  <div>
+|      <h1>Hello world</h1>
+|      <p>Test</p>
+|  </div>
+|
+TXT;
+
+        $expected = sprintf($expected.'  ', get_class($driver));
+
+        $exception = new ElementHtmlException('Html error', $session, $element);
+
+        $this->assertEquals($expected, $exception->__toString());
+    }
+
+    private function getSessionMock()
+    {
+        return $this->getMockBuilder('Behat\Mink\Session')
+            ->disableOriginalConstructor()
+            ->getMock();
+    }
+
+    private function getElementMock()
+    {
+        return $this->getMockBuilder('Behat\Mink\Element\NodeElement')
+            ->disableOriginalConstructor()
+            ->getMock();
+    }
+}
diff --git a/vendor/behat/mink/tests/Exception/ElementNotFoundExceptionTest.php b/vendor/behat/mink/tests/Exception/ElementNotFoundExceptionTest.php
new file mode 100644
index 00000000000..8cb4e5d8922
--- /dev/null
+++ b/vendor/behat/mink/tests/Exception/ElementNotFoundExceptionTest.php
@@ -0,0 +1,34 @@
+<?php
+
+namespace Behat\Mink\Tests\Exception;
+
+use Behat\Mink\Exception\ElementNotFoundException;
+
+class ElementNotFoundExceptionTest extends \PHPUnit_Framework_TestCase
+{
+    /**
+     * @dataProvider provideExceptionMessage
+     */
+    public function testBuildMessage($message, $type, $selector = null, $locator = null)
+    {
+        $session = $this->getMockBuilder('Behat\Mink\Session')
+            ->disableOriginalConstructor()
+            ->getMock();
+
+        $exception = new ElementNotFoundException($session, $type, $selector, $locator);
+
+        $this->assertEquals($message, $exception->getMessage());
+    }
+
+    public function provideExceptionMessage()
+    {
+        return array(
+            array('Tag not found.', null),
+            array('Field not found.', 'field'),
+            array('Tag matching locator "foobar" not found.', null, null, 'foobar'),
+            array('Tag matching css "foobar" not found.', null, 'css', 'foobar'),
+            array('Field matching xpath "foobar" not found.', 'Field', 'xpath', 'foobar'),
+            array('Tag with name "foobar" not found.', null, 'name', 'foobar'),
+        );
+    }
+}
diff --git a/vendor/behat/mink/tests/Exception/ElementTextExceptionTest.php b/vendor/behat/mink/tests/Exception/ElementTextExceptionTest.php
new file mode 100644
index 00000000000..73cef5bc346
--- /dev/null
+++ b/vendor/behat/mink/tests/Exception/ElementTextExceptionTest.php
@@ -0,0 +1,59 @@
+<?php
+
+namespace Behat\Mink\Tests\Exception;
+
+use Behat\Mink\Exception\ElementTextException;
+
+class ElementTextExceptionTest extends \PHPUnit_Framework_TestCase
+{
+    public function testExceptionToString()
+    {
+        $driver = $this->getMock('Behat\Mink\Driver\DriverInterface');
+        $element = $this->getElementMock();
+
+        $session = $this->getSessionMock();
+        $session->expects($this->any())
+            ->method('getDriver')
+            ->will($this->returnValue($driver));
+        $session->expects($this->any())
+            ->method('getStatusCode')
+            ->will($this->returnValue(200));
+        $session->expects($this->any())
+            ->method('getCurrentUrl')
+            ->will($this->returnValue('http://localhost/test'));
+
+        $element->expects($this->any())
+            ->method('getText')
+            ->will($this->returnValue("Hello world\nTest\n"));
+
+        $expected = <<<'TXT'
+Text error
+
++--[ HTTP/1.1 200 | http://localhost/test | %s ]
+|
+|  Hello world
+|  Test
+|
+TXT;
+
+        $expected = sprintf($expected.'  ', get_class($driver));
+
+        $exception = new ElementTextException('Text error', $session, $element);
+
+        $this->assertEquals($expected, $exception->__toString());
+    }
+
+    private function getSessionMock()
+    {
+        return $this->getMockBuilder('Behat\Mink\Session')
+            ->disableOriginalConstructor()
+            ->getMock();
+    }
+
+    private function getElementMock()
+    {
+        return $this->getMockBuilder('Behat\Mink\Element\NodeElement')
+            ->disableOriginalConstructor()
+            ->getMock();
+    }
+}
diff --git a/vendor/behat/mink/tests/Exception/ExpectationExceptionTest.php b/vendor/behat/mink/tests/Exception/ExpectationExceptionTest.php
new file mode 100644
index 00000000000..23e53bc77da
--- /dev/null
+++ b/vendor/behat/mink/tests/Exception/ExpectationExceptionTest.php
@@ -0,0 +1,84 @@
+<?php
+
+namespace Behat\Mink\Tests\Exception;
+
+use Behat\Mink\Exception\ExpectationException;
+
+class ExpectationExceptionTest extends \PHPUnit_Framework_TestCase
+{
+    public function testEmptyMessageAndPreviousException()
+    {
+        $exception = new ExpectationException('', $this->getSessionMock(), new \Exception('Something failed'));
+
+        $this->assertEquals('Something failed', $exception->getMessage());
+    }
+
+    public function testExceptionToString()
+    {
+        $driver = $this->getMock('Behat\Mink\Driver\DriverInterface');
+        $page = $this->getPageMock();
+
+        $session = $this->getSessionMock();
+        $session->expects($this->any())
+            ->method('getDriver')
+            ->will($this->returnValue($driver));
+        $session->expects($this->any())
+            ->method('getPage')
+            ->will($this->returnValue($page));
+        $session->expects($this->any())
+            ->method('getStatusCode')
+            ->will($this->returnValue(200));
+        $session->expects($this->any())
+            ->method('getCurrentUrl')
+            ->will($this->returnValue('http://localhost/test'));
+
+        $html = "<html><head><title>Hello</title></head>\n<body>\n<h1>Hello world</h1>\n<p>Test</p>\n</body></html>";
+        $page->expects($this->any())
+            ->method('getContent')
+            ->will($this->returnValue($html));
+
+        $expected = <<<'TXT'
+Expectation failure
+
++--[ HTTP/1.1 200 | http://localhost/test | %s ]
+|
+|  <body>
+|  <h1>Hello world</h1>
+|  <p>Test</p>
+|  </body>
+|
+TXT;
+
+        $expected = sprintf($expected.'  ', get_class($driver));
+
+        $exception = new ExpectationException('Expectation failure', $session);
+
+        $this->assertEquals($expected, $exception->__toString());
+    }
+
+    public function testExceptionWhileRenderingString()
+    {
+        $session = $this->getSessionMock();
+        $session->expects($this->any())
+            ->method('getPage')
+            ->will($this->throwException(new \Exception('Broken page')));
+
+        $exception = new ExpectationException('Expectation failure', $session);
+
+        $this->assertEquals('Expectation failure', $exception->__toString());
+    }
+
+    private function getSessionMock()
+    {
+        return $this->getMockBuilder('Behat\Mink\Session')
+            ->disableOriginalConstructor()
+            ->getMock();
+    }
+
+    private function getPageMock()
+    {
+        return $this->getMockBuilder('Behat\Mink\Element\DocumentElement')
+            ->disableOriginalConstructor()
+            ->getMock();
+    }
+}
diff --git a/vendor/behat/mink/tests/Exception/ResponseTextExceptionTest.php b/vendor/behat/mink/tests/Exception/ResponseTextExceptionTest.php
new file mode 100644
index 00000000000..4651b7cd5aa
--- /dev/null
+++ b/vendor/behat/mink/tests/Exception/ResponseTextExceptionTest.php
@@ -0,0 +1,62 @@
+<?php
+
+namespace Behat\Mink\Tests\Exception;
+
+use Behat\Mink\Exception\ResponseTextException;
+
+class ResponseTextExceptionTest extends \PHPUnit_Framework_TestCase
+{
+    public function testExceptionToString()
+    {
+        $driver = $this->getMock('Behat\Mink\Driver\DriverInterface');
+        $page = $this->getPageMock();
+
+        $session = $this->getSessionMock();
+        $session->expects($this->any())
+            ->method('getDriver')
+            ->will($this->returnValue($driver));
+        $session->expects($this->any())
+            ->method('getPage')
+            ->will($this->returnValue($page));
+        $session->expects($this->any())
+            ->method('getStatusCode')
+            ->will($this->returnValue(200));
+        $session->expects($this->any())
+            ->method('getCurrentUrl')
+            ->will($this->returnValue('http://localhost/test'));
+
+        $page->expects($this->any())
+            ->method('getText')
+            ->will($this->returnValue("Hello world\nTest\n"));
+
+        $expected = <<<'TXT'
+Text error
+
++--[ HTTP/1.1 200 | http://localhost/test | %s ]
+|
+|  Hello world
+|  Test
+|
+TXT;
+
+        $expected = sprintf($expected.'  ', get_class($driver));
+
+        $exception = new ResponseTextException('Text error', $session);
+
+        $this->assertEquals($expected, $exception->__toString());
+    }
+
+    private function getSessionMock()
+    {
+        return $this->getMockBuilder('Behat\Mink\Session')
+            ->disableOriginalConstructor()
+            ->getMock();
+    }
+
+    private function getPageMock()
+    {
+        return $this->getMockBuilder('Behat\Mink\Element\DocumentElement')
+            ->disableOriginalConstructor()
+            ->getMock();
+    }
+}
diff --git a/vendor/behat/mink/tests/MinkTest.php b/vendor/behat/mink/tests/MinkTest.php
new file mode 100644
index 00000000000..11d6466aeef
--- /dev/null
+++ b/vendor/behat/mink/tests/MinkTest.php
@@ -0,0 +1,246 @@
+<?php
+
+namespace Behat\Mink\Tests;
+
+use Behat\Mink\Mink;
+
+class MinkTest extends \PHPUnit_Framework_TestCase
+{
+    /**
+     * @var Mink
+     */
+    private $mink;
+
+    protected function setUp()
+    {
+        $this->mink = new Mink();
+    }
+
+    public function testRegisterSession()
+    {
+        $session = $this->getSessionMock();
+
+        $this->assertFalse($this->mink->hasSession('not_registered'));
+        $this->assertFalse($this->mink->hasSession('js'));
+        $this->assertFalse($this->mink->hasSession('my'));
+
+        $this->mink->registerSession('my', $session);
+
+        $this->assertTrue($this->mink->hasSession('my'));
+        $this->assertFalse($this->mink->hasSession('not_registered'));
+        $this->assertFalse($this->mink->hasSession('js'));
+    }
+
+    public function testRegisterSessionThroughConstructor()
+    {
+        $mink = new Mink(array('my' => $this->getSessionMock()));
+
+        $this->assertTrue($mink->hasSession('my'));
+    }
+
+    public function testSessionAutostop()
+    {
+        $session1 = $this->getSessionMock();
+        $session2 = $this->getSessionMock();
+        $this->mink->registerSession('my1', $session1);
+        $this->mink->registerSession('my2', $session2);
+
+        $session1
+            ->expects($this->once())
+            ->method('isStarted')
+            ->will($this->returnValue(true));
+        $session1
+            ->expects($this->once())
+            ->method('stop');
+        $session2
+            ->expects($this->once())
+            ->method('isStarted')
+            ->will($this->returnValue(false));
+        $session2
+            ->expects($this->never())
+            ->method('stop');
+
+        unset($this->mink);
+    }
+
+    public function testNotStartedSession()
+    {
+        $session = $this->getSessionMock();
+
+        $session
+            ->expects($this->once())
+            ->method('isStarted')
+            ->will($this->returnValue(false));
+        $session
+            ->expects($this->once())
+            ->method('start');
+
+        $this->mink->registerSession('mock_session', $session);
+        $this->assertSame($session, $this->mink->getSession('mock_session'));
+
+        $this->setExpectedException('InvalidArgumentException');
+
+        $this->mink->getSession('not_registered');
+    }
+
+    public function testGetAlreadyStartedSession()
+    {
+        $session = $this->getSessionMock();
+
+        $session
+            ->expects($this->once())
+            ->method('isStarted')
+            ->will($this->returnValue(true));
+        $session
+            ->expects($this->never())
+            ->method('start');
+
+        $this->mink->registerSession('mock_session', $session);
+        $this->assertSame($session, $this->mink->getSession('mock_session'));
+    }
+
+    public function testSetDefaultSessionName()
+    {
+        $this->assertNull($this->mink->getDefaultSessionName());
+
+        $session = $this->getSessionMock();
+        $this->mink->registerSession('session_name', $session);
+        $this->mink->setDefaultSessionName('session_name');
+
+        $this->assertEquals('session_name', $this->mink->getDefaultSessionName());
+
+        $this->setExpectedException('InvalidArgumentException');
+
+        $this->mink->setDefaultSessionName('not_registered');
+    }
+
+    public function testGetDefaultSession()
+    {
+        $session1 = $this->getSessionMock();
+        $session2 = $this->getSessionMock();
+
+        $this->assertNotSame($session1, $session2);
+
+        $this->mink->registerSession('session_1', $session1);
+        $this->mink->registerSession('session_2', $session2);
+        $this->mink->setDefaultSessionName('session_2');
+
+        $this->assertSame($session1, $this->mink->getSession('session_1'));
+        $this->assertSame($session2, $this->mink->getSession('session_2'));
+        $this->assertSame($session2, $this->mink->getSession());
+
+        $this->mink->setDefaultSessionName('session_1');
+
+        $this->assertSame($session1, $this->mink->getSession());
+    }
+
+    public function testGetNoDefaultSession()
+    {
+        $session1 = $this->getSessionMock();
+
+        $this->mink->registerSession('session_1', $session1);
+
+        $this->setExpectedException('InvalidArgumentException');
+
+        $this->mink->getSession();
+    }
+
+    public function testIsSessionStarted()
+    {
+        $session_1 = $this->getSessionMock();
+        $session_2 = $this->getSessionMock();
+
+        $session_1
+            ->expects($this->any())
+            ->method('isStarted')
+            ->will($this->returnValue(false));
+        $session_1
+            ->expects($this->never())
+            ->method('start');
+
+        $session_2
+            ->expects($this->any())
+            ->method('isStarted')
+            ->will($this->returnValue(true));
+        $session_2
+            ->expects($this->never())
+            ->method('start');
+
+        $this->mink->registerSession('not_started', $session_1);
+        $this->assertFalse($this->mink->isSessionStarted('not_started'));
+
+        $this->mink->registerSession('started', $session_2);
+        $this->assertTrue($this->mink->isSessionStarted('started'));
+
+        $this->setExpectedException('InvalidArgumentException');
+
+        $this->mink->getSession('not_registered');
+    }
+
+    public function testAssertSession()
+    {
+        $session = $this->getSessionMock();
+
+        $this->mink->registerSession('my', $session);
+
+        $this->assertInstanceOf('Behat\Mink\WebAssert', $this->mink->assertSession('my'));
+    }
+
+    public function testAssertSessionNotRegistered()
+    {
+        $session = $this->getSessionMock();
+
+        $this->assertInstanceOf('Behat\Mink\WebAssert', $this->mink->assertSession($session));
+    }
+
+    public function testResetSessions()
+    {
+        $session1 = $this->getSessionMock();
+        $session1->expects($this->once())
+            ->method('isStarted')
+            ->will($this->returnValue(false));
+        $session1->expects($this->never())
+            ->method('reset');
+
+        $session2 = $this->getSessionMock();
+        $session2->expects($this->once())
+            ->method('isStarted')
+            ->will($this->returnValue(true));
+        $session2->expects($this->once())
+            ->method('reset');
+
+        $this->mink->registerSession('not started', $session1);
+        $this->mink->registerSession('started', $session2);
+
+        $this->mink->resetSessions();
+    }
+
+    public function testRestartSessions()
+    {
+        $session1 = $this->getSessionMock();
+        $session1->expects($this->once())
+            ->method('isStarted')
+            ->will($this->returnValue(false));
+        $session1->expects($this->never())
+            ->method('restart');
+
+        $session2 = $this->getSessionMock();
+        $session2->expects($this->once())
+            ->method('isStarted')
+            ->will($this->returnValue(true));
+        $session2->expects($this->once())
+            ->method('restart');
+
+        $this->mink->registerSession('not started', $session1);
+        $this->mink->registerSession('started', $session2);
+
+        $this->mink->restartSessions();
+    }
+
+    private function getSessionMock()
+    {
+        return $this->getMockBuilder('Behat\Mink\Session')
+            ->disableOriginalConstructor()
+            ->getMock();
+    }
+}
diff --git a/vendor/behat/mink/tests/Selector/CssSelectorTest.php b/vendor/behat/mink/tests/Selector/CssSelectorTest.php
new file mode 100644
index 00000000000..ea80d93fa1d
--- /dev/null
+++ b/vendor/behat/mink/tests/Selector/CssSelectorTest.php
@@ -0,0 +1,41 @@
+<?php
+
+namespace Behat\Mink\Tests\Selector;
+
+use Behat\Mink\Selector\CssSelector;
+
+class CssSelectorTest extends \PHPUnit_Framework_TestCase
+{
+    protected function setUp()
+    {
+        if (!class_exists('Symfony\Component\CssSelector\CssSelector')) {
+            $this->markTestSkipped('Symfony2 CssSelector component not installed');
+        }
+    }
+
+    public function testSelector()
+    {
+        $selector = new CssSelector();
+
+        $this->assertEquals('descendant-or-self::h3', $selector->translateToXPath('h3'));
+        $this->assertEquals('descendant-or-self::h3/span', $selector->translateToXPath('h3 > span'));
+
+        if (interface_exists('Symfony\Component\CssSelector\XPath\TranslatorInterface')) {
+            // The rewritten component of Symfony 2.3 checks for attribute existence first for the class.
+            $expectation = "descendant-or-self::h3/*[@class and contains(concat(' ', normalize-space(@class), ' '), ' my_div ')]";
+        } else {
+            $expectation = "descendant-or-self::h3/*[contains(concat(' ', normalize-space(@class), ' '), ' my_div ')]";
+        }
+        $this->assertEquals($expectation, $selector->translateToXPath('h3 > .my_div'));
+    }
+
+    /**
+     * @expectedException \InvalidArgumentException
+     */
+    public function testThrowsForArrayLocator()
+    {
+        $selector = new CssSelector();
+
+        $selector->translateToXPath(array('h3'));
+    }
+}
diff --git a/vendor/behat/mink/tests/Selector/ExactNamedSelectorTest.php b/vendor/behat/mink/tests/Selector/ExactNamedSelectorTest.php
new file mode 100644
index 00000000000..df51f0fd73c
--- /dev/null
+++ b/vendor/behat/mink/tests/Selector/ExactNamedSelectorTest.php
@@ -0,0 +1,18 @@
+<?php
+
+namespace Behat\Mink\Tests\Selector;
+
+use Behat\Mink\Selector\ExactNamedSelector;
+
+class ExactNamedSelectorTest extends NamedSelectorTest
+{
+    protected function getSelector()
+    {
+        return new ExactNamedSelector();
+    }
+
+    protected function allowPartialMatch()
+    {
+        return false;
+    }
+}
diff --git a/vendor/behat/mink/tests/Selector/NamedSelectorTest.php b/vendor/behat/mink/tests/Selector/NamedSelectorTest.php
new file mode 100644
index 00000000000..1ce2faa4ea2
--- /dev/null
+++ b/vendor/behat/mink/tests/Selector/NamedSelectorTest.php
@@ -0,0 +1,157 @@
+<?php
+
+namespace Behat\Mink\Tests\Selector;
+
+use Behat\Mink\Selector\NamedSelector;
+use Behat\Mink\Selector\SelectorsHandler;
+
+abstract class NamedSelectorTest extends \PHPUnit_Framework_TestCase
+{
+    public function testRegisterXpath()
+    {
+        $selector = $this->getSelector();
+
+        $selector->registerNamedXpath('some', 'my_xpath');
+        $this->assertEquals('my_xpath', $selector->translateToXPath('some'));
+
+        $this->setExpectedException('InvalidArgumentException');
+
+        $selector->translateToXPath('custom');
+    }
+
+    /**
+     * @expectedException \InvalidArgumentException
+     */
+    public function testInvalidLocator()
+    {
+        $namedSelector = $this->getSelector();
+
+        $namedSelector->translateToXPath(array('foo', 'bar', 'baz'));
+    }
+
+    /**
+     * @dataProvider getSelectorTests
+     */
+    public function testSelectors($fixtureFile, $selector, $locator, $expectedExactCount, $expectedPartialCount = null)
+    {
+        $expectedCount = $this->allowPartialMatch() && null !== $expectedPartialCount
+            ? $expectedPartialCount
+            : $expectedExactCount;
+
+        $dom = new \DOMDocument('1.0', 'UTF-8');
+        $dom->loadHTMLFile(__DIR__.'/fixtures/'.$fixtureFile);
+
+        // Escape the locator as Mink 1.x expects the caller of the NamedSelector to handle it
+        $selectorsHandler = new SelectorsHandler();
+        $locator = $selectorsHandler->xpathLiteral($locator);
+
+        $namedSelector = $this->getSelector();
+
+        $xpath = $namedSelector->translateToXPath(array($selector, $locator));
+
+        $domXpath = new \DOMXPath($dom);
+        $nodeList = $domXpath->query($xpath);
+
+        $this->assertEquals($expectedCount, $nodeList->length);
+    }
+
+    public function getSelectorTests()
+    {
+        $fieldCount = 8; // fields without `type` attribute
+        $fieldCount += 4; // fields with `type=checkbox` attribute
+        $fieldCount += 4; // fields with `type=radio` attribute
+        $fieldCount += 4; // fields with `type=file` attribute
+
+        // Fixture file,  selector name,  locator,  expected number of exact matched elements, expected number of partial matched elements if different
+        return array(
+            'fieldset' => array('test.html', 'fieldset', 'fieldset-text', 2, 3),
+
+            'field (name/placeholder/label)' => array('test.html', 'field', 'the-field', $fieldCount),
+            'field (input, with-id)' => array('test.html', 'field', 'the-field-input', 1),
+            'field (textarea, with-id)' => array('test.html', 'field', 'the-field-textarea', 1),
+            'field (select, with-id)' => array('test.html', 'field', 'the-field-select', 1),
+            'field (input type=submit, with-id) ignored' => array('test.html', 'field', 'the-field-submit-button', 0),
+            'field (input type=image, with-id) ignored' => array('test.html', 'field', 'the-field-image-button', 0),
+            'field (input type=button, with-id) ignored' => array('test.html', 'field', 'the-field-button-button', 0),
+            'field (input type=reset, with-id) ignored' => array('test.html', 'field', 'the-field-reset-button', 0),
+            'field (input type=hidden, with-id) ignored' => array('test.html', 'field', 'the-field-hidden', 0),
+
+            'link (with-href)' => array('test.html', 'link', 'link-text', 5, 9),
+            'link (without-href) ignored' => array('test.html', 'link', 'bad-link-text', 0),
+            'link* (role=link)' => array('test.html', 'link', 'link-role-text', 4, 7),
+
+            'button (input, name/value/title)' => array('test.html', 'button', 'button-text', 25, 42),
+            'button (type=image, with-alt)' => array('test.html', 'button', 'button-alt-text', 1, 2),
+            'button (input type=submit, with-id)' => array('test.html', 'button', 'input-submit-button', 1),
+            'button (input type=image, with-id)' => array('test.html', 'button', 'input-image-button', 1),
+            'button (input type=button, with-id)' => array('test.html', 'button', 'input-button-button', 1),
+            'button (input type=reset, with-id)' => array('test.html', 'button', 'input-reset-button', 1),
+            'button (button type=submit, with-id)' => array('test.html', 'button', 'button-submit-button', 1),
+            'button (button type=image, with-id)' => array('test.html', 'button', 'button-image-button', 1),
+            'button (button type=button, with-id)' => array('test.html', 'button', 'button-button-button', 1),
+            'button (button type=reset, with-id)' => array('test.html', 'button', 'button-reset-button', 1),
+            'button* (role=button, name/value/title)' => array('test.html', 'button', 'button-role-text', 12, 20),
+            'button* (role=button type=submit, with-id)' => array('test.html', 'button', 'role-button-submit-button', 1),
+            'button* (role=button type=image, with-id)' => array('test.html', 'button', 'role-button-image-button', 1),
+            'button* (role=button type=button, with-id)' => array('test.html', 'button', 'role-button-button-button', 1),
+            'button* (role=button type=reset, with-id)' => array('test.html', 'button', 'role-button-reset-button', 1),
+
+            'link_or_button (with-href)' => array('test.html', 'link_or_button', 'link-text', 5, 9),
+            'link_or_button (without-href) ignored' => array('test.html', 'link_or_button', 'bad-link-text', 0),
+            'link_or_button* (role=link)' => array('test.html', 'link_or_button', 'link-role-text', 4, 7),
+
+            // bug in selector: 17 instead of 25 and 34 instead of 42, because 8 buttons with `name` attribute were not matched
+            'link_or_button (input, name/value/title)' => array('test.html', 'link_or_button', 'button-text', 17, 34),
+            'link_or_button (type=image, with-alt)' => array('test.html', 'link_or_button', 'button-alt-text', 1, 2),
+            'link_or_button (input type=submit, with-id)' => array('test.html', 'link_or_button', 'input-submit-button', 1),
+            'link_or_button (input type=image, with-id)' => array('test.html', 'link_or_button', 'input-image-button', 1),
+            'link_or_button (input type=button, with-id)' => array('test.html', 'link_or_button', 'input-button-button', 1),
+            'link_or_button (input type=reset, with-id)' => array('test.html', 'link_or_button', 'input-reset-button', 1),
+            'link_or_button (button type=submit, with-id)' => array('test.html', 'link_or_button', 'button-submit-button', 1),
+            'link_or_button (button type=image, with-id)' => array('test.html', 'link_or_button', 'button-image-button', 1),
+            'link_or_button (button type=button, with-id)' => array('test.html', 'link_or_button', 'button-button-button', 1),
+            'link_or_button (button type=reset, with-id)' => array('test.html', 'link_or_button', 'button-reset-button', 1),
+
+            // bug in selector: 8 instead of 12 and 16 instead of 20, because 4 buttons with `name` attribute were not matched
+            'link_or_button* (role=button, name/value/title)' => array('test.html', 'link_or_button', 'button-role-text', 8, 16),
+            'link_or_button* (role=button type=submit, with-id)' => array('test.html', 'link_or_button', 'role-button-submit-button', 1),
+            'link_or_button* (role=button type=image, with-id)' => array('test.html', 'link_or_button', 'role-button-image-button', 1),
+            'link_or_button* (role=button type=button, with-id)' => array('test.html', 'link_or_button', 'role-button-button-button', 1),
+            'link_or_button* (role=button type=reset, with-id)' => array('test.html', 'link_or_button', 'role-button-reset-button', 1),
+
+            // 3 matches, because matches every HTML node in path: html > body > div
+            'content' => array('test.html', 'content', 'content-text', 1, 4),
+
+            'select (name/label)' => array('test.html', 'select', 'the-field', 3),
+            'select (with-id)' => array('test.html', 'select', 'the-field-select', 1),
+
+            'checkbox (name/label)' => array('test.html', 'checkbox', 'the-field', 3),
+            'checkbox (with-id)' => array('test.html', 'checkbox', 'the-field-checkbox', 1),
+
+            'radio (name/label)' => array('test.html', 'radio', 'the-field', 3),
+            'radio (with-id)' => array('test.html', 'radio', 'the-field-radio', 1),
+
+            'file (name/label)' => array('test.html', 'file', 'the-field', 3),
+            'file (with-id)' => array('test.html', 'file', 'the-field-file', 1),
+
+            'optgroup' => array('test.html', 'optgroup', 'group-label', 1, 2),
+
+            'option' => array('test.html', 'option', 'option-value', 2, 3),
+
+            'table' => array('test.html', 'table', 'the-table', 2, 3),
+
+            'id' => array('test.html', 'id', 'bad-link-text', 1),
+            'id or name' => array('test.html', 'id_or_name', 'the-table', 2),
+        );
+    }
+
+    /**
+     * @return NamedSelector
+     */
+    abstract protected function getSelector();
+
+    /**
+     * @return boolean
+     */
+    abstract protected function allowPartialMatch();
+}
diff --git a/vendor/behat/mink/tests/Selector/PartialNamedSelectorTest.php b/vendor/behat/mink/tests/Selector/PartialNamedSelectorTest.php
new file mode 100644
index 00000000000..c3e631a1124
--- /dev/null
+++ b/vendor/behat/mink/tests/Selector/PartialNamedSelectorTest.php
@@ -0,0 +1,18 @@
+<?php
+
+namespace Behat\Mink\Tests\Selector;
+
+use Behat\Mink\Selector\PartialNamedSelector;
+
+class PartialNamedSelectorTest extends NamedSelectorTest
+{
+    protected function getSelector()
+    {
+        return new PartialNamedSelector();
+    }
+
+    protected function allowPartialMatch()
+    {
+        return true;
+    }
+}
diff --git a/vendor/behat/mink/tests/Selector/SelectorsHandlerTest.php b/vendor/behat/mink/tests/Selector/SelectorsHandlerTest.php
new file mode 100644
index 00000000000..8bcb3799782
--- /dev/null
+++ b/vendor/behat/mink/tests/Selector/SelectorsHandlerTest.php
@@ -0,0 +1,80 @@
+<?php
+
+namespace Behat\Mink\Tests\Selector;
+
+use Behat\Mink\Selector\SelectorsHandler;
+
+class SelectorsHandlerTest extends \PHPUnit_Framework_TestCase
+{
+    public function testRegisterSelector()
+    {
+        $selector = $this->getMockBuilder('Behat\Mink\Selector\SelectorInterface')->getMock();
+        $handler = new SelectorsHandler();
+
+        $this->assertFalse($handler->isSelectorRegistered('custom'));
+
+        $handler->registerSelector('custom', $selector);
+
+        $this->assertTrue($handler->isSelectorRegistered('custom'));
+        $this->assertSame($selector, $handler->getSelector('custom'));
+    }
+
+    public function testRegisterSelectorThroughConstructor()
+    {
+        $selector = $this->getMockBuilder('Behat\Mink\Selector\SelectorInterface')->getMock();
+        $handler = new SelectorsHandler(array('custom' => $selector));
+
+        $this->assertTrue($handler->isSelectorRegistered('custom'));
+        $this->assertSame($selector, $handler->getSelector('custom'));
+    }
+
+    public function testRegisterDefaultSelectors()
+    {
+        $handler = new SelectorsHandler();
+
+        $this->assertTrue($handler->isSelectorRegistered('css'));
+        $this->assertTrue($handler->isSelectorRegistered('named_exact'));
+        $this->assertTrue($handler->isSelectorRegistered('named_partial'));
+    }
+
+    /**
+     * @expectedException \InvalidArgumentException
+     */
+    public function testXpathSelectorThrowsExceptionForArrayLocator()
+    {
+        $handler = new SelectorsHandler();
+        $handler->selectorToXpath('xpath', array('some_xpath'));
+    }
+
+    public function testXpathSelectorIsReturnedAsIs()
+    {
+        $handler = new SelectorsHandler();
+        $this->assertEquals('some_xpath', $handler->selectorToXpath('xpath', 'some_xpath'));
+    }
+
+    public function testSelectorToXpath()
+    {
+        $selector = $this->getMockBuilder('Behat\Mink\Selector\SelectorInterface')->getMock();
+        $handler = new SelectorsHandler();
+
+        $handler->registerSelector('custom_selector', $selector);
+
+        $selector
+            ->expects($this->once())
+            ->method('translateToXPath')
+            ->with($locator = 'some[locator]')
+            ->will($this->returnValue($ret = '[]some[]locator'));
+
+        $this->assertEquals($ret, $handler->selectorToXpath('custom_selector', $locator));
+
+        $this->setExpectedException('InvalidArgumentException');
+        $handler->selectorToXpath('undefined', 'asd');
+    }
+
+    public function testXpathLiteral()
+    {
+        $handler = new SelectorsHandler();
+
+        $this->assertEquals("'some simple string'", $handler->xpathLiteral('some simple string'));
+    }
+}
diff --git a/vendor/behat/mink/tests/Selector/Xpath/EscaperTest.php b/vendor/behat/mink/tests/Selector/Xpath/EscaperTest.php
new file mode 100644
index 00000000000..535dac608be
--- /dev/null
+++ b/vendor/behat/mink/tests/Selector/Xpath/EscaperTest.php
@@ -0,0 +1,31 @@
+<?php
+
+namespace Behat\Mink\Tests\Selector\Xpath;
+
+use Behat\Mink\Selector\Xpath\Escaper;
+
+class EscaperTest extends \PHPUnit_Framework_TestCase
+{
+    /**
+     * @dataProvider getXpathLiterals
+     */
+    public function testXpathLiteral($string, $expected)
+    {
+        $escaper = new Escaper();
+
+        $this->assertEquals($expected, $escaper->escapeLiteral($string));
+    }
+
+    public function getXpathLiterals()
+    {
+        return array(
+            array('some simple string', "'some simple string'"),
+            array('some "d-brackets" string', "'some \"d-brackets\" string'"),
+            array('some \'s-brackets\' string', "\"some 's-brackets' string\""),
+            array(
+                'some \'s-brackets\' and "d-brackets" string',
+                'concat(\'some \',"\'",\'s-brackets\',"\'",\' and "d-brackets" string\')',
+            ),
+        );
+    }
+}
diff --git a/vendor/behat/mink/tests/Selector/Xpath/ManipulatorTest.php b/vendor/behat/mink/tests/Selector/Xpath/ManipulatorTest.php
new file mode 100644
index 00000000000..7c205616ec1
--- /dev/null
+++ b/vendor/behat/mink/tests/Selector/Xpath/ManipulatorTest.php
@@ -0,0 +1,64 @@
+<?php
+
+namespace Behat\Mink\Tests\Selector\Xpath;
+
+use Behat\Mink\Selector\Xpath\Manipulator;
+
+class ManipulatorTest extends \PHPUnit_Framework_TestCase
+{
+    /**
+     * @dataProvider getPrependedXpath
+     */
+    public function testPrepend($prefix, $xpath, $expectedXpath)
+    {
+        $manipulator = new Manipulator();
+
+        $this->assertEquals($expectedXpath, $manipulator->prepend($xpath, $prefix));
+    }
+
+    public function getPrependedXpath()
+    {
+        return array(
+            'simple' => array(
+                'some_xpath',
+                'some_tag1',
+                'some_xpath/some_tag1',
+            ),
+            'with slash' => array(
+                'some_xpath',
+                '/some_tag1',
+                'some_xpath/some_tag1',
+            ),
+            'union' => array(
+                'some_xpath',
+                'some_tag1 | some_tag2',
+                'some_xpath/some_tag1 | some_xpath/some_tag2',
+            ),
+            'wrapped union' => array(
+                'some_xpath',
+                '(some_tag1 | some_tag2)/some_child',
+                '(some_xpath/some_tag1 | some_xpath/some_tag2)/some_child',
+            ),
+            'multiple wrapped union' => array(
+                'some_xpath',
+                '( ( some_tag1 | some_tag2)/some_child | some_tag3)/leaf',
+                '( ( some_xpath/some_tag1 | some_xpath/some_tag2)/some_child | some_xpath/some_tag3)/leaf',
+            ),
+            'parent union' => array(
+                'some_xpath | another_xpath',
+                'some_tag1 | some_tag2',
+                '(some_xpath | another_xpath)/some_tag1 | (some_xpath | another_xpath)/some_tag2',
+            ),
+            'complex condition' => array(
+                'some_xpath',
+                'some_tag1 | some_tag2[@foo = "bar|"] | some_tag3[foo | bar]',
+                'some_xpath/some_tag1 | some_xpath/some_tag2[@foo = "bar|"] | some_xpath/some_tag3[foo | bar]',
+            ),
+            'multiline' => array(
+                'some_xpath',
+                "some_tag1 | some_tag2[@foo =\n 'bar|'']\n | some_tag3[foo | bar]",
+                "some_xpath/some_tag1 | some_xpath/some_tag2[@foo =\n 'bar|''] | some_xpath/some_tag3[foo | bar]",
+            ),
+        );
+    }
+}
diff --git a/vendor/behat/mink/tests/Selector/fixtures/test.html b/vendor/behat/mink/tests/Selector/fixtures/test.html
new file mode 100644
index 00000000000..c64ae103292
--- /dev/null
+++ b/vendor/behat/mink/tests/Selector/fixtures/test.html
@@ -0,0 +1,310 @@
+<!DOCTYPE html>
+<html>
+<head>
+    <title></title>
+</head>
+<body>
+    <div id="test-for-link-selector">
+        <!-- match links with `href` attribute -->
+        <a href="#" id="link-text"></a>
+        <a href="#">link-text</a>
+        <a href="#" title="link-text"></a>
+        <a href="#" rel="link-text"></a>
+        <a href="#">
+            <img src="#" alt="link-text"/>
+        </a>
+        <!-- partial match -->
+        <a href="#">some link-text</a>
+        <a href="#" title="some link-text"></a>
+        <a href="#" rel="some link-text"></a>
+        <a href="#">
+            <img src="#" alt="some link-text"/>
+        </a>
+
+        <!-- don't match links without `href` attribute -->
+        <a id="bad-link-text"></a>
+        <a>bad-link-text</a>
+        <a title="bad-link-text"></a>
+        <a rel="bad-link-text"></a>
+        <a>
+            <img src="#" alt="bad-link-text"/>
+        </a>
+
+        <!-- match links with `role=link` attribute -->
+        <span role="Link" id="link-role-text"></span>
+        <span role="lInk" value="link-role-text"></span>
+        <span role="liNk" title="link-role-text"></span>
+        <span role="linK">link-role-text</span>
+        <!-- partial match -->
+        <span role="link" value="some link-role-text"></span>
+        <span role="link" title="some link-role-text"></span>
+        <span role="link">some link-role-text</span>
+    </div>
+
+    <div id="test-for-fieldset-selector">
+        <!-- match fieldsets -->
+        <fieldset id="fieldset-text"></fieldset>
+
+        <fieldset>
+            <legend>fieldset-text</legend>
+        </fieldset>
+        <!-- partial match -->
+        <fieldset>
+            <legend>fieldset-text sample</legend>
+        </fieldset>
+
+        <!-- don't match fieldsets -->
+        <fieldset>fieldset-text</fieldset>
+        <fieldset></fieldset>
+    </div>
+
+    <div id="test-for-content-selector">
+        content-text
+    </div>
+    <!-- partial match -->
+    <div id="test-for-partial-content-selector">
+        some content-text
+    </div>
+
+    <form>
+        <div id="test-for-field-selector">
+            <!-- match fields by `id` attribute -->
+            <input id="the-field-input"/>
+            <textarea id="the-field-textarea"></textarea>
+            <select id="the-field-select"></select>
+
+            <!-- match fields by `name` attribute -->
+            <input name="the-field"/>
+            <textarea name="the-field"></textarea>
+            <select name="the-field"></select>
+
+            <!-- match fields by `placeholder` attribute -->
+            <input placeholder="the-field"/>
+            <textarea placeholder="the-field"></textarea>
+            <select placeholder="the-field"></select>
+
+            <!-- match fields by associated label -->
+            <label for="label-for-input">the-field</label><input id="label-for-input"/>
+            <label for="label-for-textarea">the-field</label><textarea id="label-for-textarea"></textarea>
+            <label for="label-for-select">the-field</label><select id="label-for-select"></select>
+
+            <!-- match fields, surrounded by matching label -->
+            <label>the-field<input/></label>
+            <label>the-field<textarea></textarea></label>
+            <label>the-field<select></select></label>
+
+            <!-- don't match fields by `id` attribute -->
+            <input type="Submit" id="the-field-submit-button"/>
+            <input type="iMage" id="the-field-image-button"/>
+            <input type="butTon" id="the-field-button-button"/>
+            <input type="resEt" id="the-field-reset-button"/>
+            <input type="hidDen" id="the-field-hidden"/>
+
+            <!-- don't match fields by `name` attribute -->
+            <input type="submit" name="the-field"/>
+            <input type="image" name="the-field"/>
+            <input type="button" name="the-field"/>
+            <input type="reset" name="the-field"/>
+            <input type="hidden" name="the-field"/>
+
+            <!-- don't match fields by `placeholder` attribute -->
+            <input type="submit" placeholder="the-field"/>
+            <input type="image" placeholder="the-field"/>
+            <input type="button" placeholder="the-field"/>
+            <input type="reset" placeholder="the-field"/>
+            <input type="hidden" placeholder="the-field"/>
+
+            <!-- don't match fields by associated label -->
+            <label for="label-for-the-field-submit-button">the-field</label><input type="submit" id="label-for-the-field-submit-button"/>
+            <label for="label-for-the-field-image-button">the-field</label><input type="image" id="label-for-the-field-image-button"/>
+            <label for="label-for-the-field-button-button">the-field</label><input type="button" id="label-for-the-field-button-button"/>
+            <label for="label-for-the-field-reset-button">the-field</label><input type="reset" id="label-for-the-field-reset-button"/>
+            <label for="label-for-the-field-hidden">the-field</label><input type="hidden" id="label-for-the-field-hidden"/>
+
+            <!-- don't match fields, surrounded by matching label -->
+            <label>the-field<input type="submit"/></label>
+            <label>the-field<input type="image"/></label>
+            <label>the-field<input type="button"/></label>
+            <label>the-field<input type="reset"/></label>
+            <label>the-field<input type="hidden"/></label>
+        </div>
+
+        <div id="test-for-button-selector">
+            <!-- match buttons by `id` attribute -->
+            <input type="Submit" id="input-submit-button"/>
+            <input type="iMage" id="input-image-button"/>
+            <input type="butTon" id="input-button-button"/>
+            <input type="resEt" id="input-reset-button"/>
+
+            <button type="submit" id="button-submit-button"></button>
+            <button type="image" id="button-image-button"></button>
+            <button type="button" id="button-button-button"></button>
+            <button type="reset" id="button-reset-button"></button>
+
+            <!-- match buttons by `name` attribute -->
+            <input type="submit" name="button-text"/>
+            <input type="image" name="button-text"/>
+            <input type="button" name="button-text"/>
+            <input type="reset" name="button-text"/>
+            <button type="submit" name="button-text"></button>
+            <button type="image" name="button-text"></button>
+            <button type="button" name="button-text"></button>
+            <button type="reset" name="button-text"></button>
+
+            <!-- match buttons by `value` attribute -->
+            <input type="submit" value="button-text"/>
+            <input type="image" value="button-text"/>
+            <input type="button" value="button-text"/>
+            <input type="reset" value="button-text"/>
+            <button type="submit" value="button-text"></button>
+            <button type="image" value="button-text"></button>
+            <button type="button" value="button-text"></button>
+            <button type="reset" value="button-text"></button>
+            <!-- Partial match -->
+            <input type="submit" value="some button-text"/>
+            <input type="image" value="some button-text"/>
+            <input type="button" value="some button-text"/>
+            <input type="reset" value="some button-text"/>
+            <button type="submit" value="some button-text"></button>
+            <button type="image" value="some button-text"></button>
+            <button type="button" value="some button-text"></button>
+            <button type="reset" value="some button-text"></button>
+
+            <!-- match buttons by `title` attribute -->
+            <input type="submit" title="button-text"/>
+            <input type="image" title="button-text"/>
+            <input type="button" title="button-text"/>
+            <input type="reset" title="button-text"/>
+            <button type="submit" title="button-text"></button>
+            <button type="image" title="button-text"></button>
+            <button type="button" title="button-text"></button>
+            <button type="reset" title="button-text"></button>
+            <!-- partial match -->
+            <input type="submit" title="some button-text"/>
+            <input type="image" title="some button-text"/>
+            <input type="button" title="some button-text"/>
+            <input type="reset" title="some button-text"/>
+            <button type="submit" title="some button-text"></button>
+            <button type="image" title="some button-text"></button>
+            <button type="button" title="some button-text"></button>
+            <button type="reset" title="some button-text"></button>
+
+            <!-- match some buttons by `alt` attribute -->
+            <input type="submit" alt="button-alt-text"/>
+            <input type="imaGe" alt="button-alt-text"/>
+            <input type="button" alt="button-alt-text"/>
+            <input type="reset" alt="button-alt-text"/>
+            <!-- partial match -->
+            <input type="submit" alt="some button-alt-text"/>
+            <input type="image" alt="some button-alt-text"/>
+            <input type="button" alt="some button-alt-text"/>
+            <input type="reset" alt="some button-alt-text"/>
+
+            <!-- match by `button` text -->
+            <button>button-text</button>
+            <!-- partial match -->
+            <button>some button-text</button>
+
+            <!-- match buttons with `role=button` & `id` attribute -->
+            <span role="Button" type="submit" id="role-button-submit-button"></span>
+            <span role="bUtton" type="image" id="role-button-image-button"></span>
+            <span role="buTton" type="button" id="role-button-button-button"></span>
+            <span role="butTon" type="reset" id="role-button-reset-button"></span>
+
+            <!-- match buttons with `role=button` & `name` attribute -->
+            <span role="buttOn" type="submit" name="button-role-text"></span>
+            <span role="buttoN" type="image" name="button-role-text"></span>
+            <span role="button" type="button" name="button-role-text"></span>
+            <span role="button" type="reset" name="button-role-text"></span>
+
+            <!-- match buttons with `role=button` & `value` attribute -->
+            <span role="button" type="submit" value="button-role-text"></span>
+            <span role="button" type="image" value="button-role-text"></span>
+            <span role="button" type="button" value="button-role-text"></span>
+            <span role="button" type="reset" value="button-role-text"></span>
+            <!-- partial match -->
+            <span role="button" type="submit" value="some button-role-text"></span>
+            <span role="button" type="image" value="some button-role-text"></span>
+            <span role="button" type="button" value="some button-role-text"></span>
+            <span role="button" type="reset" value="some button-role-text"></span>
+
+            <!-- match buttons with `role=button` & `title` attribute -->
+            <span role="button" type="submit" title="button-role-text"></span>
+            <span role="button" type="image" title="button-role-text"></span>
+            <span role="button" type="button" title="button-role-text"></span>
+            <span role="button" type="reset" title="button-role-text"></span>
+            <!-- partial match -->
+            <span role="button" type="submit" title="some button-role-text"></span>
+            <span role="button" type="image" title="some button-role-text"></span>
+            <span role="button" type="button" title="some button-role-text"></span>
+            <span role="button" type="reset" title="some button-role-text"></span>
+        </div>
+
+        <div id="test-for-checkbox-selector">
+            <input type="Checkbox" id="the-field-checkbox"/>
+            <input type="checkBox" name="the-field"/>
+            <input type="cheCkbox" placeholder="the-field"/>
+            <label for="label-for-checkbox">the-field</label><input type="checkboX" id="label-for-checkbox"/>
+            <label>the-field<input type="chEckbox"/></label>
+        </div>
+
+        <div id="test-for-radio-selector">
+            <input type="Radio" id="the-field-radio"/>
+            <input type="raDio" name="the-field"/>
+            <input type="radIo" placeholder="the-field"/>
+            <label for="label-for-radio">the-field</label><input type="radiO" id="label-for-radio"/>
+            <label>the-field<input type="radIo"/></label>
+        </div>
+
+        <div id="test-for-file-selector">
+            <input type="File" id="the-field-file"/>
+            <input type="fIle" name="the-field"/>
+            <input type="fiLe" placeholder="the-field"/>
+            <label for="label-for-file">the-field</label><input type="filE" id="label-for-file"/>
+            <label>the-field<input type="fiLe"/></label>
+        </div>
+
+        <div id="test-for-select-related-stuff">
+            <!-- match select stuff -->
+            <select name="the-select-stuff-test">
+                <optgroup label="group-label">
+                    <option value="option-value"></option>
+                </optgroup>
+                <option value="">option-value</option>
+                <!-- partial match -->
+                <optgroup label="some group-label">
+                    <option value="">some option-value</option>
+                </optgroup>
+            </select>
+
+            <!-- don't match select stuff -->
+            <select name="the-select-stuff-test">
+                <optgroup label="">some group-label</optgroup>
+                <option value="some option-value"></option>
+            </select>
+        </div>
+    </form>
+
+    <div id="test-for-table-selector">
+        <!-- match tables -->
+        <table id="the-table"></table>
+        <table>
+            <caption>the-table</caption>
+        </table>
+        <!-- partial match -->
+        <table>
+            <caption>some the-table</caption>
+        </table>
+
+        <!-- don't match tables -->
+        <table>
+            <tr>
+                <th>the-table</th>
+                <td>the-table</td>
+            </tr>
+        </table>
+    </div>
+
+    <input name="the-table"/>
+</body>
+</html>
diff --git a/vendor/behat/mink/tests/SessionTest.php b/vendor/behat/mink/tests/SessionTest.php
new file mode 100644
index 00000000000..b000ba69b5a
--- /dev/null
+++ b/vendor/behat/mink/tests/SessionTest.php
@@ -0,0 +1,282 @@
+<?php
+
+namespace Behat\Mink\Tests;
+
+use Behat\Mink\Session;
+
+class SessionTest extends \PHPUnit_Framework_TestCase
+{
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject
+     */
+    private $driver;
+    private $selectorsHandler;
+
+    /**
+     * Session.
+     *
+     * @var Session
+     */
+    private $session;
+
+    protected function setUp()
+    {
+        $this->driver           = $this->getMockBuilder('Behat\Mink\Driver\DriverInterface')->getMock();
+        $this->selectorsHandler = $this->getMockBuilder('Behat\Mink\Selector\SelectorsHandler')->getMock();
+        $this->session  = new Session($this->driver, $this->selectorsHandler);
+    }
+
+    public function testGetDriver()
+    {
+        $this->assertSame($this->driver, $this->session->getDriver());
+    }
+
+    public function testGetPage()
+    {
+        $this->assertInstanceOf('Behat\Mink\Element\DocumentElement', $this->session->getPage());
+    }
+
+    public function testGetSelectorsHandler()
+    {
+        $this->assertSame($this->selectorsHandler, $this->session->getSelectorsHandler());
+    }
+
+    public function testIsStarted()
+    {
+        $this->driver->expects($this->once())
+            ->method('isStarted')
+            ->will($this->returnValue(true));
+
+        $this->assertTrue($this->session->isStarted());
+    }
+
+    public function testStart()
+    {
+        $this->driver->expects($this->once())
+            ->method('start');
+
+        $this->session->start();
+    }
+
+    public function testStop()
+    {
+        $this->driver->expects($this->once())
+            ->method('stop');
+
+        $this->session->stop();
+    }
+
+    public function testRestart()
+    {
+        $this->driver->expects($this->at(0))
+            ->method('stop');
+        $this->driver->expects($this->at(1))
+            ->method('start');
+
+        $this->session->restart();
+    }
+
+    public function testVisit()
+    {
+        $this->driver
+            ->expects($this->once())
+            ->method('visit')
+            ->with($url = 'some_url');
+
+        $this->session->visit($url);
+    }
+
+    public function testReset()
+    {
+        $this->driver
+            ->expects($this->once())
+            ->method('reset');
+
+        $this->session->reset();
+    }
+
+    public function testSetBasicAuth()
+    {
+        $this->driver->expects($this->once())
+            ->method('setBasicAuth')
+            ->with('user', 'pass');
+
+        $this->session->setBasicAuth('user', 'pass');
+    }
+
+    public function testSetRequestHeader()
+    {
+        $this->driver->expects($this->once())
+            ->method('setRequestHeader')
+            ->with('name', 'value');
+
+        $this->session->setRequestHeader('name', 'value');
+    }
+
+    public function testGetResponseHeaders()
+    {
+        $this->driver
+            ->expects($this->once())
+            ->method('getResponseHeaders')
+            ->will($this->returnValue($ret = array(2, 3, 4)));
+
+        $this->assertEquals($ret, $this->session->getResponseHeaders());
+    }
+
+    public function testSetCookie()
+    {
+        $this->driver->expects($this->once())
+            ->method('setCookie')
+            ->with('name', 'value');
+
+        $this->session->setCookie('name', 'value');
+    }
+
+    public function testGetCookie()
+    {
+        $this->driver->expects($this->once())
+            ->method('getCookie')
+            ->with('name')
+            ->will($this->returnValue('value'));
+
+        $this->assertEquals('value', $this->session->getCookie('name'));
+    }
+
+    public function testGetStatusCode()
+    {
+        $this->driver
+            ->expects($this->once())
+            ->method('getStatusCode')
+            ->will($this->returnValue($ret = 404));
+
+        $this->assertEquals($ret, $this->session->getStatusCode());
+    }
+
+    public function testGetCurrentUrl()
+    {
+        $this->driver
+            ->expects($this->once())
+            ->method('getCurrentUrl')
+            ->will($this->returnValue($ret = 'http://some.url'));
+
+        $this->assertEquals($ret, $this->session->getCurrentUrl());
+    }
+
+    public function testGetScreenshot()
+    {
+        $this->driver->expects($this->once())
+            ->method('getScreenshot')
+            ->will($this->returnValue('screenshot'));
+
+        $this->assertEquals('screenshot', $this->session->getScreenshot());
+    }
+
+    public function testGetWindowNames()
+    {
+        $this->driver->expects($this->once())
+            ->method('getWindowNames')
+            ->will($this->returnValue($names = array('window 1', 'window 2')));
+
+        $this->assertEquals($names, $this->session->getWindowNames());
+    }
+
+    public function testGetWindowName()
+    {
+        $this->driver->expects($this->once())
+            ->method('getWindowName')
+            ->will($this->returnValue('name'));
+
+        $this->assertEquals('name', $this->session->getWindowName());
+    }
+
+    public function testReload()
+    {
+        $this->driver->expects($this->once())
+            ->method('reload');
+
+        $this->session->reload();
+    }
+
+    public function testBack()
+    {
+        $this->driver->expects($this->once())
+            ->method('back');
+
+        $this->session->back();
+    }
+
+    public function testForward()
+    {
+        $this->driver->expects($this->once())
+            ->method('forward');
+
+        $this->session->forward();
+    }
+
+    public function testSwitchToWindow()
+    {
+        $this->driver->expects($this->once())
+            ->method('switchToWindow')
+            ->with('test');
+
+        $this->session->switchToWindow('test');
+    }
+
+    public function testSwitchToIFrame()
+    {
+        $this->driver->expects($this->once())
+            ->method('switchToIFrame')
+            ->with('test');
+
+        $this->session->switchToIFrame('test');
+    }
+
+    public function testExecuteScript()
+    {
+        $this->driver
+            ->expects($this->once())
+            ->method('executeScript')
+            ->with($arg = 'JS');
+
+        $this->session->executeScript($arg);
+    }
+
+    public function testEvaluateScript()
+    {
+        $this->driver
+            ->expects($this->once())
+            ->method('evaluateScript')
+            ->with($arg = 'JS func')
+            ->will($this->returnValue($ret = '23'));
+
+        $this->assertEquals($ret, $this->session->evaluateScript($arg));
+    }
+
+    public function testWait()
+    {
+        $this->driver
+            ->expects($this->once())
+            ->method('wait')
+            ->with(1000, 'function () {}');
+
+        $this->session->wait(1000, 'function () {}');
+    }
+
+    public function testResizeWindow()
+    {
+        $this->driver->expects($this->once())
+            ->method('resizeWindow')
+            ->with(800, 600, 'test');
+
+        $this->session->resizeWindow(800, 600, 'test');
+    }
+
+    public function testMaximizeWindow()
+    {
+        $this->driver->expects($this->once())
+            ->method('maximizeWindow')
+            ->with('test');
+
+        $this->session->maximizeWindow('test');
+    }
+}
diff --git a/vendor/behat/mink/tests/WebAssertTest.php b/vendor/behat/mink/tests/WebAssertTest.php
new file mode 100644
index 00000000000..9ce5d22fc53
--- /dev/null
+++ b/vendor/behat/mink/tests/WebAssertTest.php
@@ -0,0 +1,1123 @@
+<?php
+
+namespace Behat\Mink\Tests;
+
+use Behat\Mink\WebAssert;
+
+class WebAssertTest extends \PHPUnit_Framework_TestCase
+{
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject
+     */
+    private $session;
+    /**
+     * @var WebAssert
+     */
+    private $assert;
+
+    public function setUp()
+    {
+        $this->session = $this->getMockBuilder('Behat\\Mink\\Session')
+            ->disableOriginalConstructor()
+            ->getMock();
+        $this->assert  = new WebAssert($this->session);
+    }
+
+    public function testAddressEquals()
+    {
+        $this->session
+            ->expects($this->exactly(2))
+            ->method('getCurrentUrl')
+            ->will($this->returnValue('http://example.com/script.php/sub/url?param=true#webapp/nav'))
+        ;
+
+        $this->assertCorrectAssertion('addressEquals', array('/sub/url#webapp/nav'));
+        $this->assertWrongAssertion(
+            'addressEquals',
+            array('sub_url'),
+            'Behat\\Mink\\Exception\\ExpectationException',
+            'Current page is "/sub/url#webapp/nav", but "sub_url" expected.'
+        );
+    }
+
+    public function testAddressNotEquals()
+    {
+        $this->session
+            ->expects($this->exactly(2))
+            ->method('getCurrentUrl')
+            ->will($this->returnValue('http://example.com/script.php/sub/url'))
+        ;
+
+        $this->assertCorrectAssertion('addressNotEquals', array('sub_url'));
+        $this->assertWrongAssertion(
+            'addressNotEquals',
+            array('/sub/url'),
+            'Behat\\Mink\\Exception\\ExpectationException',
+            'Current page is "/sub/url", but should not be.'
+        );
+    }
+
+    public function testAddressMatches()
+    {
+        $this->session
+            ->expects($this->exactly(2))
+            ->method('getCurrentUrl')
+            ->will($this->returnValue('http://example.com/script.php/sub/url'))
+        ;
+
+        $this->assertCorrectAssertion('addressMatches', array('/su.*rl/'));
+        $this->assertWrongAssertion(
+            'addressMatches',
+            array('/suburl/'),
+            'Behat\\Mink\\Exception\\ExpectationException',
+            'Current page "/sub/url" does not match the regex "/suburl/".'
+        );
+    }
+
+    /**
+     * @covers Behat\Mink\WebAssert::cookieEquals
+     */
+    public function testCookieEquals()
+    {
+        $this->session->
+            expects($this->any())->
+            method('getCookie')->
+            will($this->returnValueMap(
+                array(
+                    array('foo', 'bar'),
+                    array('bar', 'baz'),
+                )
+            ));
+
+        $this->assertCorrectAssertion('cookieEquals', array('foo', 'bar'));
+        $this->assertWrongAssertion(
+            'cookieEquals',
+            array('bar', 'foo'),
+            'Behat\Mink\Exception\ExpectationException',
+            'Cookie "bar" value is "baz", but should be "foo".'
+        );
+    }
+
+    /**
+     * @covers Behat\Mink\WebAssert::cookieExists
+     */
+    public function testCookieExists()
+    {
+        $this->session->
+            expects($this->any())->
+            method('getCookie')->
+            will($this->returnValueMap(
+                array(
+                    array('foo', '1'),
+                    array('bar', null),
+                )
+            ));
+
+        $this->assertCorrectAssertion('cookieExists', array('foo'));
+        $this->assertWrongAssertion(
+            'cookieExists',
+            array('bar'),
+            'Behat\Mink\Exception\ExpectationException',
+            'Cookie "bar" is not set, but should be.'
+        );
+    }
+
+    public function testStatusCodeEquals()
+    {
+        $this->session
+            ->expects($this->exactly(2))
+            ->method('getStatusCode')
+            ->will($this->returnValue(200))
+        ;
+
+        $this->assertCorrectAssertion('statusCodeEquals', array(200));
+        $this->assertWrongAssertion(
+            'statusCodeEquals',
+            array(404),
+            'Behat\\Mink\\Exception\\ExpectationException',
+            'Current response status code is 200, but 404 expected.'
+        );
+    }
+
+    public function testStatusCodeNotEquals()
+    {
+        $this->session
+            ->expects($this->exactly(2))
+            ->method('getStatusCode')
+            ->will($this->returnValue(404))
+        ;
+
+        $this->assertCorrectAssertion('statusCodeNotEquals', array(200));
+        $this->assertWrongAssertion(
+            'statusCodeNotEquals',
+            array(404),
+            'Behat\\Mink\\Exception\\ExpectationException',
+            'Current response status code is 404, but should not be.'
+        );
+    }
+
+    public function testPageTextContains()
+    {
+        $page = $this->getMockBuilder('Behat\\Mink\\Element\\DocumentElement')
+            ->disableOriginalConstructor()
+            ->getMock()
+        ;
+
+        $this->session
+            ->expects($this->exactly(2))
+            ->method('getPage')
+            ->will($this->returnValue($page))
+        ;
+
+        $page
+            ->expects($this->exactly(2))
+            ->method('getText')
+            ->will($this->returnValue("Some  page\n\ttext"))
+        ;
+
+        $this->assertCorrectAssertion('pageTextContains', array('PAGE text'));
+        $this->assertWrongAssertion(
+            'pageTextContains',
+            array('html text'),
+            'Behat\\Mink\\Exception\\ResponseTextException',
+            'The text "html text" was not found anywhere in the text of the current page.'
+        );
+    }
+
+    public function testPageTextNotContains()
+    {
+        $page = $this->getMockBuilder('Behat\\Mink\\Element\\DocumentElement')
+            ->disableOriginalConstructor()
+            ->getMock()
+        ;
+
+        $this->session
+            ->expects($this->exactly(2))
+            ->method('getPage')
+            ->will($this->returnValue($page))
+        ;
+
+        $page
+            ->expects($this->exactly(2))
+            ->method('getText')
+            ->will($this->returnValue("Some  html\n\ttext"))
+        ;
+
+        $this->assertCorrectAssertion('pageTextNotContains', array('PAGE text'));
+        $this->assertWrongAssertion(
+            'pageTextNotContains',
+            array('HTML text'),
+            'Behat\\Mink\\Exception\\ResponseTextException',
+            'The text "HTML text" appears in the text of this page, but it should not.'
+        );
+    }
+
+    public function testPageTextMatches()
+    {
+        $page = $this->getMockBuilder('Behat\\Mink\\Element\\DocumentElement')
+            ->disableOriginalConstructor()
+            ->getMock()
+        ;
+
+        $this->session
+            ->expects($this->exactly(2))
+            ->method('getPage')
+            ->will($this->returnValue($page))
+        ;
+
+        $page
+            ->expects($this->exactly(2))
+            ->method('getText')
+            ->will($this->returnValue('Some page text'))
+        ;
+
+        $this->assertCorrectAssertion('pageTextMatches', array('/PA.E/i'));
+        $this->assertWrongAssertion(
+            'pageTextMatches',
+            array('/html/'),
+            'Behat\\Mink\\Exception\\ResponseTextException',
+            'The pattern /html/ was not found anywhere in the text of the current page.'
+        );
+    }
+
+    public function testPageTextNotMatches()
+    {
+        $page = $this->getMockBuilder('Behat\\Mink\\Element\\DocumentElement')
+            ->disableOriginalConstructor()
+            ->getMock()
+        ;
+
+        $this->session
+            ->expects($this->exactly(2))
+            ->method('getPage')
+            ->will($this->returnValue($page))
+        ;
+
+        $page
+            ->expects($this->exactly(2))
+            ->method('getText')
+            ->will($this->returnValue('Some html text'))
+        ;
+
+        $this->assertCorrectAssertion('pageTextNotMatches', array('/PA.E/i'));
+        $this->assertWrongAssertion(
+            'pageTextNotMatches',
+            array('/HTML/i'),
+            'Behat\\Mink\\Exception\\ResponseTextException',
+            'The pattern /HTML/i was found in the text of the current page, but it should not.'
+        );
+    }
+
+    public function testResponseContains()
+    {
+        $page = $this->getMockBuilder('Behat\\Mink\\Element\\DocumentElement')
+            ->disableOriginalConstructor()
+            ->getMock()
+        ;
+
+        $this->session
+            ->expects($this->exactly(2))
+            ->method('getPage')
+            ->will($this->returnValue($page))
+        ;
+
+        $page
+            ->expects($this->exactly(2))
+            ->method('getContent')
+            ->will($this->returnValue('Some page text'))
+        ;
+
+        $this->assertCorrectAssertion('responseContains', array('PAGE text'));
+        $this->assertWrongAssertion(
+            'responseContains',
+            array('html text'),
+            'Behat\\Mink\\Exception\\ExpectationException',
+            'The string "html text" was not found anywhere in the HTML response of the current page.'
+        );
+    }
+
+    public function testResponseNotContains()
+    {
+        $page = $this->getMockBuilder('Behat\\Mink\\Element\\DocumentElement')
+            ->disableOriginalConstructor()
+            ->getMock()
+        ;
+
+        $this->session
+            ->expects($this->exactly(2))
+            ->method('getPage')
+            ->will($this->returnValue($page))
+        ;
+
+        $page
+            ->expects($this->exactly(2))
+            ->method('getContent')
+            ->will($this->returnValue('Some html text'))
+        ;
+
+        $this->assertCorrectAssertion('responseNotContains', array('PAGE text'));
+        $this->assertWrongAssertion(
+            'responseNotContains',
+            array('HTML text'),
+            'Behat\\Mink\\Exception\\ExpectationException',
+            'The string "HTML text" appears in the HTML response of this page, but it should not.'
+        );
+    }
+
+    public function testResponseMatches()
+    {
+        $page = $this->getMockBuilder('Behat\\Mink\\Element\\DocumentElement')
+            ->disableOriginalConstructor()
+            ->getMock()
+        ;
+
+        $this->session
+            ->expects($this->exactly(2))
+            ->method('getPage')
+            ->will($this->returnValue($page))
+        ;
+
+        $page
+            ->expects($this->exactly(2))
+            ->method('getContent')
+            ->will($this->returnValue('Some page text'))
+        ;
+
+        $this->assertCorrectAssertion('responseMatches', array('/PA.E/i'));
+        $this->assertWrongAssertion(
+            'responseMatches',
+            array('/html/'),
+            'Behat\\Mink\\Exception\\ExpectationException',
+            'The pattern /html/ was not found anywhere in the HTML response of the page.'
+        );
+    }
+
+    public function testResponseNotMatches()
+    {
+        $page = $this->getMockBuilder('Behat\\Mink\\Element\\DocumentElement')
+            ->disableOriginalConstructor()
+            ->getMock()
+        ;
+
+        $this->session
+            ->expects($this->exactly(2))
+            ->method('getPage')
+            ->will($this->returnValue($page))
+        ;
+
+        $page
+            ->expects($this->exactly(2))
+            ->method('getContent')
+            ->will($this->returnValue('Some html text'))
+        ;
+
+        $this->assertCorrectAssertion('responseNotMatches', array('/PA.E/i'));
+        $this->assertWrongAssertion(
+            'responseNotMatches',
+            array('/HTML/i'),
+            'Behat\\Mink\\Exception\\ExpectationException',
+            'The pattern /HTML/i was found in the HTML response of the page, but it should not.'
+        );
+    }
+
+    public function testElementsCount()
+    {
+        $page = $this->getMockBuilder('Behat\\Mink\\Element\\DocumentElement')
+            ->disableOriginalConstructor()
+            ->getMock()
+        ;
+
+        $this->session
+            ->expects($this->exactly(2))
+            ->method('getPage')
+            ->will($this->returnValue($page))
+        ;
+
+        $page
+            ->expects($this->exactly(2))
+            ->method('findAll')
+            ->with('css', 'h2 > span')
+            ->will($this->returnValue(array(1, 2)))
+        ;
+
+        $this->assertCorrectAssertion('elementsCount', array('css', 'h2 > span', 2));
+        $this->assertWrongAssertion(
+            'elementsCount',
+            array('css', 'h2 > span', 3),
+            'Behat\\Mink\\Exception\\ExpectationException',
+            '2 elements matching css "h2 > span" found on the page, but should be 3.'
+        );
+    }
+
+    public function testElementExists()
+    {
+        $page = $this->getMockBuilder('Behat\\Mink\\Element\\DocumentElement')
+            ->disableOriginalConstructor()
+            ->getMock()
+        ;
+
+        $this->session
+            ->expects($this->exactly(2))
+            ->method('getPage')
+            ->will($this->returnValue($page))
+        ;
+
+        $page
+            ->expects($this->exactly(4))
+            ->method('find')
+            ->with('css', 'h2 > span')
+            ->will($this->onConsecutiveCalls(1, null, 1, null))
+        ;
+
+        $this->assertCorrectAssertion('elementExists', array('css', 'h2 > span'));
+        $this->assertWrongAssertion(
+            'elementExists',
+            array('css', 'h2 > span'),
+            'Behat\\Mink\\Exception\\ElementNotFoundException',
+            'Element matching css "h2 > span" not found.'
+        );
+
+        $this->assertCorrectAssertion('elementExists', array('css', 'h2 > span', $page));
+        $this->assertWrongAssertion(
+            'elementExists',
+            array('css', 'h2 > span', $page),
+            'Behat\\Mink\\Exception\\ElementNotFoundException',
+            'Element matching css "h2 > span" not found.'
+        );
+    }
+
+    public function testElementExistsWithArrayLocator()
+    {
+        $container = $this->getMockBuilder('Behat\\Mink\\Element\\NodeElement')
+            ->disableOriginalConstructor()
+            ->getMock()
+        ;
+
+        $this->session->expects($this->never())
+            ->method('getPage')
+        ;
+
+        $container
+            ->expects($this->exactly(2))
+            ->method('find')
+            ->with('named', array('element', 'Test'))
+            ->will($this->onConsecutiveCalls(1, null))
+        ;
+
+        $this->assertCorrectAssertion('elementExists', array('named', array('element', 'Test'), $container));
+        $this->assertWrongAssertion(
+            'elementExists',
+            array('named', array('element', 'Test'), $container),
+            'Behat\\Mink\\Exception\\ElementNotFoundException',
+            'Element with named "element Test" not found.'
+        );
+    }
+
+    public function testElementNotExists()
+    {
+        $page = $this->getMockBuilder('Behat\\Mink\\Element\\DocumentElement')
+            ->disableOriginalConstructor()
+            ->getMock()
+        ;
+
+        $this->session
+            ->expects($this->exactly(2))
+            ->method('getPage')
+            ->will($this->returnValue($page))
+        ;
+
+        $page
+            ->expects($this->exactly(4))
+            ->method('find')
+            ->with('css', 'h2 > span')
+            ->will($this->onConsecutiveCalls(null, 1, null, 1))
+        ;
+
+        $this->assertCorrectAssertion('elementNotExists', array('css', 'h2 > span'));
+        $this->assertWrongAssertion(
+            'elementNotExists',
+            array('css', 'h2 > span'),
+            'Behat\\Mink\\Exception\\ExpectationException',
+            'An element matching css "h2 > span" appears on this page, but it should not.'
+        );
+
+        $this->assertCorrectAssertion('elementNotExists', array('css', 'h2 > span', $page));
+        $this->assertWrongAssertion(
+            'elementNotExists',
+            array('css', 'h2 > span', $page),
+            'Behat\\Mink\\Exception\\ExpectationException',
+            'An element matching css "h2 > span" appears on this page, but it should not.'
+        );
+    }
+
+    /**
+     * @dataProvider getArrayLocatorFormats
+     */
+    public function testElementNotExistsArrayLocator($selector, $locator, $expectedMessage)
+    {
+        $page = $this->getMockBuilder('Behat\\Mink\\Element\\DocumentElement')
+            ->disableOriginalConstructor()
+            ->getMock()
+        ;
+
+        $this->session
+            ->expects($this->once())
+            ->method('getPage')
+            ->will($this->returnValue($page))
+        ;
+
+        $page
+            ->expects($this->once())
+            ->method('find')
+            ->with($selector, $locator)
+            ->will($this->returnValue(1))
+        ;
+
+        $this->assertWrongAssertion(
+            'elementNotExists',
+            array($selector, $locator),
+            'Behat\\Mink\\Exception\\ExpectationException',
+            $expectedMessage
+        );
+    }
+
+    public function getArrayLocatorFormats()
+    {
+        return array(
+            'named' => array(
+                'named',
+                array('button', 'Test'),
+                'An button matching locator "Test" appears on this page, but it should not.',
+            ),
+            'custom' => array(
+                'custom',
+                array('test', 'foo'),
+                'An element matching custom "test foo" appears on this page, but it should not.',
+            ),
+        );
+    }
+
+    public function testElementTextContains()
+    {
+        $page = $this->getMockBuilder('Behat\\Mink\\Element\\DocumentElement')
+            ->disableOriginalConstructor()
+            ->getMock()
+        ;
+
+        $element = $this->getMockBuilder('Behat\\Mink\\Element\\NodeElement')
+            ->disableOriginalConstructor()
+            ->getMock()
+        ;
+
+        $this->session
+            ->expects($this->exactly(2))
+            ->method('getPage')
+            ->will($this->returnValue($page))
+        ;
+
+        $page
+            ->expects($this->exactly(2))
+            ->method('find')
+            ->with('css', 'h2 > span')
+            ->will($this->returnValue($element))
+        ;
+
+        $element
+            ->expects($this->exactly(2))
+            ->method('getText')
+            ->will($this->returnValue('element text'))
+        ;
+
+        $this->assertCorrectAssertion('elementTextContains', array('css', 'h2 > span', 'text'));
+        $this->assertWrongAssertion(
+            'elementTextContains',
+            array('css', 'h2 > span', 'html'),
+            'Behat\\Mink\\Exception\\ExpectationException',
+            'The text "html" was not found in the text of the element matching css "h2 > span".'
+        );
+    }
+
+    public function testElementTextNotContains()
+    {
+        $page = $this->getMockBuilder('Behat\\Mink\\Element\\DocumentElement')
+            ->disableOriginalConstructor()
+            ->getMock()
+        ;
+
+        $element = $this->getMockBuilder('Behat\\Mink\\Element\\NodeElement')
+            ->disableOriginalConstructor()
+            ->getMock()
+        ;
+
+        $this->session
+            ->expects($this->exactly(2))
+            ->method('getPage')
+            ->will($this->returnValue($page))
+        ;
+
+        $page
+            ->expects($this->exactly(2))
+            ->method('find')
+            ->with('css', 'h2 > span')
+            ->will($this->returnValue($element))
+        ;
+
+        $element
+            ->expects($this->exactly(2))
+            ->method('getText')
+            ->will($this->returnValue('element text'))
+        ;
+
+        $this->assertCorrectAssertion('elementTextNotContains', array('css', 'h2 > span', 'html'));
+        $this->assertWrongAssertion(
+            'elementTextNotContains',
+            array('css', 'h2 > span', 'text'),
+            'Behat\\Mink\\Exception\\ExpectationException',
+            'The text "text" appears in the text of the element matching css "h2 > span", but it should not.'
+        );
+    }
+
+    public function testElementContains()
+    {
+        $page = $this->getMockBuilder('Behat\\Mink\\Element\\DocumentElement')
+            ->disableOriginalConstructor()
+            ->getMock()
+        ;
+
+        $element = $this->getMockBuilder('Behat\\Mink\\Element\\NodeElement')
+            ->disableOriginalConstructor()
+            ->getMock()
+        ;
+
+        $this->session
+            ->expects($this->exactly(2))
+            ->method('getPage')
+            ->will($this->returnValue($page))
+        ;
+
+        $page
+            ->expects($this->exactly(2))
+            ->method('find')
+            ->with('css', 'h2 > span')
+            ->will($this->returnValue($element))
+        ;
+
+        $element
+            ->expects($this->exactly(2))
+            ->method('getHtml')
+            ->will($this->returnValue('element html'))
+        ;
+
+        $this->assertCorrectAssertion('elementContains', array('css', 'h2 > span', 'html'));
+        $this->assertWrongAssertion(
+            'elementContains',
+            array('css', 'h2 > span', 'text'),
+            'Behat\\Mink\\Exception\\ExpectationException',
+            'The string "text" was not found in the HTML of the element matching css "h2 > span".'
+        );
+    }
+
+    public function testElementNotContains()
+    {
+        $page = $this->getMockBuilder('Behat\\Mink\\Element\\DocumentElement')
+            ->disableOriginalConstructor()
+            ->getMock()
+        ;
+
+        $element = $this->getMockBuilder('Behat\\Mink\\Element\\NodeElement')
+            ->disableOriginalConstructor()
+            ->getMock()
+        ;
+
+        $this->session
+            ->expects($this->exactly(2))
+            ->method('getPage')
+            ->will($this->returnValue($page))
+        ;
+
+        $page
+            ->expects($this->exactly(2))
+            ->method('find')
+            ->with('css', 'h2 > span')
+            ->will($this->returnValue($element))
+        ;
+
+        $element
+            ->expects($this->exactly(2))
+            ->method('getHtml')
+            ->will($this->returnValue('element html'))
+        ;
+
+        $this->assertCorrectAssertion('elementNotContains', array('css', 'h2 > span', 'text'));
+        $this->assertWrongAssertion(
+            'elementNotContains',
+            array('css', 'h2 > span', 'html'),
+            'Behat\\Mink\\Exception\\ExpectationException',
+            'The string "html" appears in the HTML of the element matching css "h2 > span", but it should not.'
+        );
+    }
+
+    public function testElementAttributeContains()
+    {
+        $page = $this->getMockBuilder('Behat\\Mink\\Element\\DocumentElement')
+            ->disableOriginalConstructor()
+            ->getMock()
+        ;
+
+        $element = $this->getMockBuilder('Behat\\Mink\\Element\\NodeElement')
+            ->disableOriginalConstructor()
+            ->getMock()
+        ;
+
+        $this->session
+            ->expects($this->exactly(2))
+            ->method('getPage')
+            ->will($this->returnValue($page))
+        ;
+
+        $page
+            ->expects($this->exactly(2))
+            ->method('find')
+            ->with('css', 'h2 > span')
+            ->will($this->returnValue($element))
+        ;
+
+        $element
+            ->expects($this->exactly(2))
+            ->method('hasAttribute')
+            ->will($this->returnValue(true))
+        ;
+
+        $element
+            ->expects($this->exactly(2))
+            ->method('getAttribute')
+            ->with('name')
+            ->will($this->returnValue('foo'))
+        ;
+
+        $this->assertCorrectAssertion('elementAttributeContains', array('css', 'h2 > span', 'name', 'foo'));
+        $this->assertWrongAssertion(
+            'elementAttributeContains',
+            array('css', 'h2 > span', 'name', 'bar'),
+            'Behat\\Mink\\Exception\\ElementHtmlException',
+            'The text "bar" was not found in the attribute "name" of the element matching css "h2 > span".'
+        );
+    }
+
+    public function testElementAttributeExists()
+    {
+        $page = $this->getMockBuilder('Behat\\Mink\\Element\\DocumentElement')
+            ->disableOriginalConstructor()
+            ->getMock()
+        ;
+
+        $element = $this->getMockBuilder('Behat\\Mink\\Element\\NodeElement')
+            ->disableOriginalConstructor()
+            ->getMock()
+        ;
+
+        $this->session
+            ->expects($this->exactly(2))
+            ->method('getPage')
+            ->will($this->returnValue($page))
+        ;
+
+        $page
+            ->expects($this->exactly(2))
+            ->method('find')
+            ->with('css', 'h2 > span')
+            ->will($this->returnValue($element))
+        ;
+
+        $element
+            ->expects($this->at(0))
+            ->method('hasAttribute')
+            ->with('name')
+            ->will($this->returnValue(true))
+        ;
+
+        $element
+            ->expects($this->at(1))
+            ->method('hasAttribute')
+            ->with('name')
+            ->will($this->returnValue(false))
+        ;
+
+        $this->assertCorrectAssertion('elementAttributeExists', array('css', 'h2 > span', 'name'));
+        $this->assertWrongAssertion(
+            'elementAttributeExists',
+            array('css', 'h2 > span', 'name'),
+            'Behat\\Mink\\Exception\\ElementHtmlException',
+            'The attribute "name" was not found in the element matching css "h2 > span".'
+        );
+    }
+
+    public function testElementAttributeNotContains()
+    {
+        $page = $this->getMockBuilder('Behat\\Mink\\Element\\DocumentElement')
+            ->disableOriginalConstructor()
+            ->getMock()
+        ;
+
+        $element = $this->getMockBuilder('Behat\\Mink\\Element\\NodeElement')
+            ->disableOriginalConstructor()
+            ->getMock()
+        ;
+
+        $this->session
+            ->expects($this->exactly(2))
+            ->method('getPage')
+            ->will($this->returnValue($page))
+        ;
+
+        $page
+            ->expects($this->exactly(2))
+            ->method('find')
+            ->with('css', 'h2 > span')
+            ->will($this->returnValue($element))
+        ;
+
+        $element
+            ->expects($this->exactly(2))
+            ->method('hasAttribute')
+            ->will($this->returnValue(true))
+        ;
+
+        $element
+            ->expects($this->exactly(2))
+            ->method('getAttribute')
+            ->with('name')
+            ->will($this->returnValue('foo'))
+        ;
+
+        $this->assertCorrectAssertion('elementAttributeNotContains', array('css', 'h2 > span', 'name', 'bar'));
+        $this->assertWrongAssertion(
+            'elementAttributeNotContains',
+            array('css', 'h2 > span', 'name', 'foo'),
+            'Behat\\Mink\\Exception\\ElementHtmlException',
+            'The text "foo" was found in the attribute "name" of the element matching css "h2 > span".'
+        );
+    }
+
+    public function testFieldExists()
+    {
+        $page = $this->getMockBuilder('Behat\\Mink\\Element\\DocumentElement')
+            ->disableOriginalConstructor()
+            ->getMock()
+        ;
+
+        $element = $this->getMockBuilder('Behat\\Mink\\Element\\NodeElement')
+            ->disableOriginalConstructor()
+            ->getMock()
+        ;
+
+        $this->session
+            ->expects($this->exactly(2))
+            ->method('getPage')
+            ->will($this->returnValue($page))
+        ;
+
+        $page
+            ->expects($this->exactly(2))
+            ->method('findField')
+            ->with('username')
+            ->will($this->onConsecutiveCalls($element, null))
+        ;
+
+        $this->assertCorrectAssertion('fieldExists', array('username'));
+        $this->assertWrongAssertion(
+            'fieldExists',
+            array('username'),
+            'Behat\\Mink\\Exception\\ElementNotFoundException',
+            'Form field with id|name|label|value "username" not found.'
+        );
+    }
+
+    public function testFieldNotExists()
+    {
+        $page = $this->getMockBuilder('Behat\\Mink\\Element\\DocumentElement')
+            ->disableOriginalConstructor()
+            ->getMock()
+        ;
+
+        $element = $this->getMockBuilder('Behat\\Mink\\Element\\NodeElement')
+            ->disableOriginalConstructor()
+            ->getMock()
+        ;
+
+        $this->session
+            ->expects($this->exactly(2))
+            ->method('getPage')
+            ->will($this->returnValue($page))
+        ;
+
+        $page
+            ->expects($this->exactly(2))
+            ->method('findField')
+            ->with('username')
+            ->will($this->onConsecutiveCalls(null, $element))
+        ;
+
+        $this->assertCorrectAssertion('fieldNotExists', array('username'));
+        $this->assertWrongAssertion(
+            'fieldNotExists',
+            array('username'),
+            'Behat\\Mink\\Exception\\ExpectationException',
+            'A field "username" appears on this page, but it should not.'
+        );
+    }
+
+    public function testFieldValueEquals()
+    {
+        $page = $this->getMockBuilder('Behat\\Mink\\Element\\DocumentElement')
+            ->disableOriginalConstructor()
+            ->getMock()
+        ;
+
+        $element = $this->getMockBuilder('Behat\\Mink\\Element\\NodeElement')
+            ->disableOriginalConstructor()
+            ->getMock()
+        ;
+
+        $this->session
+            ->expects($this->exactly(4))
+            ->method('getPage')
+            ->will($this->returnValue($page))
+        ;
+
+        $page
+            ->expects($this->exactly(4))
+            ->method('findField')
+            ->with('username')
+            ->will($this->returnValue($element))
+        ;
+
+        $element
+            ->expects($this->exactly(4))
+            ->method('getValue')
+            ->will($this->returnValue(234))
+        ;
+
+        $this->assertCorrectAssertion('fieldValueEquals', array('username', 234));
+        $this->assertWrongAssertion(
+            'fieldValueEquals',
+            array('username', 235),
+            'Behat\\Mink\\Exception\\ExpectationException',
+            'The field "username" value is "234", but "235" expected.'
+        );
+        $this->assertWrongAssertion(
+            'fieldValueEquals',
+            array('username', 23),
+            'Behat\\Mink\\Exception\\ExpectationException',
+            'The field "username" value is "234", but "23" expected.'
+        );
+        $this->assertWrongAssertion(
+            'fieldValueEquals',
+            array('username', ''),
+            'Behat\\Mink\\Exception\\ExpectationException',
+            'The field "username" value is "234", but "" expected.'
+        );
+    }
+
+    public function testFieldValueNotEquals()
+    {
+        $page = $this->getMockBuilder('Behat\\Mink\\Element\\DocumentElement')
+            ->disableOriginalConstructor()
+            ->getMock()
+        ;
+
+        $element = $this->getMockBuilder('Behat\\Mink\\Element\\NodeElement')
+            ->disableOriginalConstructor()
+            ->getMock()
+        ;
+
+        $this->session
+            ->expects($this->exactly(4))
+            ->method('getPage')
+            ->will($this->returnValue($page))
+        ;
+
+        $page
+            ->expects($this->exactly(4))
+            ->method('findField')
+            ->with('username')
+            ->will($this->returnValue($element))
+        ;
+
+        $element
+            ->expects($this->exactly(4))
+            ->method('getValue')
+            ->will($this->returnValue(235))
+        ;
+
+        $this->assertCorrectAssertion('fieldValueNotEquals', array('username', 234));
+        $this->assertWrongAssertion(
+            'fieldValueNotEquals',
+            array('username', 235),
+            'Behat\\Mink\\Exception\\ExpectationException',
+            'The field "username" value is "235", but it should not be.'
+        );
+        $this->assertCorrectAssertion('fieldValueNotEquals', array('username', 23));
+        $this->assertCorrectAssertion('fieldValueNotEquals', array('username', ''));
+    }
+
+    public function testCheckboxChecked()
+    {
+        $page = $this->getMockBuilder('Behat\\Mink\\Element\\DocumentElement')
+            ->disableOriginalConstructor()
+            ->getMock()
+        ;
+
+        $element = $this->getMockBuilder('Behat\\Mink\\Element\\NodeElement')
+            ->disableOriginalConstructor()
+            ->getMock()
+        ;
+
+        $this->session
+            ->expects($this->exactly(2))
+            ->method('getPage')
+            ->will($this->returnValue($page))
+        ;
+
+        $page
+            ->expects($this->exactly(2))
+            ->method('findField')
+            ->with('remember_me')
+            ->will($this->returnValue($element))
+        ;
+
+        $element
+            ->expects($this->exactly(2))
+            ->method('isChecked')
+            ->will($this->onConsecutiveCalls(true, false))
+        ;
+
+        $this->assertCorrectAssertion('checkboxChecked', array('remember_me'));
+        $this->assertWrongAssertion(
+            'checkboxChecked',
+            array('remember_me'),
+            'Behat\\Mink\\Exception\\ExpectationException',
+            'Checkbox "remember_me" is not checked, but it should be.'
+        );
+    }
+
+    public function testCheckboxNotChecked()
+    {
+        $page = $this->getMockBuilder('Behat\\Mink\\Element\\DocumentElement')
+            ->disableOriginalConstructor()
+            ->getMock()
+        ;
+
+        $element = $this->getMockBuilder('Behat\\Mink\\Element\\NodeElement')
+            ->disableOriginalConstructor()
+            ->getMock()
+        ;
+
+        $this->session
+            ->expects($this->exactly(2))
+            ->method('getPage')
+            ->will($this->returnValue($page))
+        ;
+
+        $page
+            ->expects($this->exactly(2))
+            ->method('findField')
+            ->with('remember_me')
+            ->will($this->returnValue($element))
+        ;
+
+        $element
+            ->expects($this->exactly(2))
+            ->method('isChecked')
+            ->will($this->onConsecutiveCalls(false, true))
+        ;
+
+        $this->assertCorrectAssertion('checkboxNotChecked', array('remember_me'));
+        $this->assertWrongAssertion(
+            'checkboxNotChecked',
+            array('remember_me'),
+            'Behat\\Mink\\Exception\\ExpectationException',
+            'Checkbox "remember_me" is checked, but it should not be.'
+        );
+    }
+
+    protected function assertCorrectAssertion($assertion, $arguments)
+    {
+        try {
+            call_user_func_array(array($this->assert, $assertion), $arguments);
+        } catch (\Exception $e) {
+            $this->fail('Correct assertion should not throw an exception: '.$e->getMessage());
+        }
+    }
+
+    protected function assertWrongAssertion($assertion, $arguments, $exceptionClass, $exceptionMessage)
+    {
+        try {
+            call_user_func_array(array($this->assert, $assertion), $arguments);
+            $this->fail('Wrong assertion should throw an exception');
+        } catch (\Exception $e) {
+            $this->assertInstanceOf($exceptionClass, $e);
+            $this->assertSame($exceptionMessage, $e->getMessage());
+        }
+    }
+}
diff --git a/vendor/composer/autoload_namespaces.php b/vendor/composer/autoload_namespaces.php
index 3cf0e3872c1..f4ab02be30b 100644
--- a/vendor/composer/autoload_namespaces.php
+++ b/vendor/composer/autoload_namespaces.php
@@ -14,8 +14,12 @@ return array(
     'VuFindHttp\\' => array($vendorDir . '/vufind-org/vufindhttp/src'),
     'VuFindCode\\' => array($vendorDir . '/vufind-org/vufindcode/src'),
     'Symfony\\Component\\Yaml\\' => array($vendorDir . '/symfony/yaml'),
+    'Symfony\\Component\\Process\\' => array($vendorDir . '/symfony/process'),
+    'Symfony\\Component\\CssSelector\\' => array($vendorDir . '/symfony/css-selector'),
     'SerialsSolutions' => array($vendorDir . '/serialssolutions/summon'),
     'ProxyManager\\' => array($vendorDir . '/ocramius/proxy-manager/src'),
     'PHPQRCode' => array($vendorDir . '/aferrandini/phpqrcode/lib'),
     'Less' => array($vendorDir . '/oyejorge/less.php/lib'),
+    'Behat\\Mink\\Driver' => array($vendorDir . '/behat/mink-zombie-driver/src'),
+    'Behat\\Mink' => array($vendorDir . '/behat/mink/src'),
 );
diff --git a/vendor/composer/autoload_real.php b/vendor/composer/autoload_real.php
index 7f73ff3e8b7..269d2176092 100644
--- a/vendor/composer/autoload_real.php
+++ b/vendor/composer/autoload_real.php
@@ -2,7 +2,7 @@
 
 // autoload_real.php @generated by Composer
 
-class ComposerAutoloaderInitc013b6451947464e0d11177f185bf9eb
+class ComposerAutoloaderInitc4a65bc36a0c8ed2b8f3216ed09d18dc
 {
     private static $loader;
 
@@ -19,9 +19,9 @@ class ComposerAutoloaderInitc013b6451947464e0d11177f185bf9eb
             return self::$loader;
         }
 
-        spl_autoload_register(array('ComposerAutoloaderInitc013b6451947464e0d11177f185bf9eb', 'loadClassLoader'), true, true);
+        spl_autoload_register(array('ComposerAutoloaderInitc4a65bc36a0c8ed2b8f3216ed09d18dc', 'loadClassLoader'), true, true);
         self::$loader = $loader = new \Composer\Autoload\ClassLoader();
-        spl_autoload_unregister(array('ComposerAutoloaderInitc013b6451947464e0d11177f185bf9eb', 'loadClassLoader'));
+        spl_autoload_unregister(array('ComposerAutoloaderInitc4a65bc36a0c8ed2b8f3216ed09d18dc', 'loadClassLoader'));
 
         $includePaths = require __DIR__ . '/include_paths.php';
         array_push($includePaths, get_include_path());
@@ -48,7 +48,7 @@ class ComposerAutoloaderInitc013b6451947464e0d11177f185bf9eb
     }
 }
 
-function composerRequirec013b6451947464e0d11177f185bf9eb($file)
+function composerRequirec4a65bc36a0c8ed2b8f3216ed09d18dc($file)
 {
     require $file;
 }
diff --git a/vendor/composer/installed.json b/vendor/composer/installed.json
index 101eebd548b..277252f985a 100644
--- a/vendor/composer/installed.json
+++ b/vendor/composer/installed.json
@@ -989,5 +989,224 @@
         ],
         "description": "Symfony Yaml Component",
         "homepage": "http://symfony.com"
+    },
+    {
+        "name": "symfony/process",
+        "version": "v2.5.6",
+        "version_normalized": "2.5.6.0",
+        "target-dir": "Symfony/Component/Process",
+        "source": {
+            "type": "git",
+            "url": "https://github.com/symfony/Process.git",
+            "reference": "9bbacbb3a7a27b17c0d51e2f126f59e0e588ad3a"
+        },
+        "dist": {
+            "type": "zip",
+            "url": "https://api.github.com/repos/symfony/Process/zipball/9bbacbb3a7a27b17c0d51e2f126f59e0e588ad3a",
+            "reference": "9bbacbb3a7a27b17c0d51e2f126f59e0e588ad3a",
+            "shasum": ""
+        },
+        "require": {
+            "php": ">=5.3.3"
+        },
+        "time": "2014-10-01 05:50:18",
+        "type": "library",
+        "extra": {
+            "branch-alias": {
+                "dev-master": "2.5-dev"
+            }
+        },
+        "installation-source": "dist",
+        "autoload": {
+            "psr-0": {
+                "Symfony\\Component\\Process\\": ""
+            }
+        },
+        "notification-url": "https://packagist.org/downloads/",
+        "license": [
+            "MIT"
+        ],
+        "authors": [
+            {
+                "name": "Symfony Community",
+                "homepage": "http://symfony.com/contributors"
+            },
+            {
+                "name": "Fabien Potencier",
+                "email": "fabien@symfony.com"
+            }
+        ],
+        "description": "Symfony Process Component",
+        "homepage": "http://symfony.com"
+    },
+    {
+        "name": "symfony/css-selector",
+        "version": "v2.5.6",
+        "version_normalized": "2.5.6.0",
+        "target-dir": "Symfony/Component/CssSelector",
+        "source": {
+            "type": "git",
+            "url": "https://github.com/symfony/CssSelector.git",
+            "reference": "7cdf543a3f31935aae58de4e6e607d4bdeb3f5dc"
+        },
+        "dist": {
+            "type": "zip",
+            "url": "https://api.github.com/repos/symfony/CssSelector/zipball/7cdf543a3f31935aae58de4e6e607d4bdeb3f5dc",
+            "reference": "7cdf543a3f31935aae58de4e6e607d4bdeb3f5dc",
+            "shasum": ""
+        },
+        "require": {
+            "php": ">=5.3.3"
+        },
+        "time": "2014-10-09 16:00:03",
+        "type": "library",
+        "extra": {
+            "branch-alias": {
+                "dev-master": "2.5-dev"
+            }
+        },
+        "installation-source": "dist",
+        "autoload": {
+            "psr-0": {
+                "Symfony\\Component\\CssSelector\\": ""
+            }
+        },
+        "notification-url": "https://packagist.org/downloads/",
+        "license": [
+            "MIT"
+        ],
+        "authors": [
+            {
+                "name": "Symfony Community",
+                "homepage": "http://symfony.com/contributors"
+            },
+            {
+                "name": "Jean-François Simon",
+                "email": "jeanfrancois.simon@sensiolabs.com"
+            },
+            {
+                "name": "Fabien Potencier",
+                "email": "fabien@symfony.com"
+            }
+        ],
+        "description": "Symfony CssSelector Component",
+        "homepage": "http://symfony.com"
+    },
+    {
+        "name": "behat/mink",
+        "version": "v1.6.0",
+        "version_normalized": "1.6.0.0",
+        "source": {
+            "type": "git",
+            "url": "https://github.com/Behat/Mink.git",
+            "reference": "090900a0049c441f1e072bbd837db4079b2250c5"
+        },
+        "dist": {
+            "type": "zip",
+            "url": "https://api.github.com/repos/Behat/Mink/zipball/090900a0049c441f1e072bbd837db4079b2250c5",
+            "reference": "090900a0049c441f1e072bbd837db4079b2250c5",
+            "shasum": ""
+        },
+        "require": {
+            "php": ">=5.3.1",
+            "symfony/css-selector": "~2.0"
+        },
+        "suggest": {
+            "behat/mink-browserkit-driver": "extremely fast headless driver for Symfony\\Kernel-based apps (Sf2, Silex)",
+            "behat/mink-goutte-driver": "fast headless driver for any app without JS emulation",
+            "behat/mink-selenium2-driver": "slow, but JS-enabled driver for any app (requires Selenium2)",
+            "behat/mink-zombie-driver": "fast and JS-enabled headless driver for any app (requires node.js)"
+        },
+        "time": "2014-09-26 09:25:05",
+        "type": "library",
+        "extra": {
+            "branch-alias": {
+                "dev-master": "1.6.x-dev"
+            }
+        },
+        "installation-source": "dist",
+        "autoload": {
+            "psr-0": {
+                "Behat\\Mink": "src/"
+            }
+        },
+        "notification-url": "https://packagist.org/downloads/",
+        "license": [
+            "MIT"
+        ],
+        "authors": [
+            {
+                "name": "Konstantin Kudryashov",
+                "email": "ever.zet@gmail.com",
+                "homepage": "http://everzet.com"
+            }
+        ],
+        "description": "Web acceptance testing framework for PHP 5.3",
+        "homepage": "http://mink.behat.org/",
+        "keywords": [
+            "browser",
+            "testing",
+            "web"
+        ]
+    },
+    {
+        "name": "behat/mink-zombie-driver",
+        "version": "v1.2.0",
+        "version_normalized": "1.2.0.0",
+        "source": {
+            "type": "git",
+            "url": "https://github.com/Behat/MinkZombieDriver.git",
+            "reference": "cf15a3a0cc4865bb55253cd033a03a20cee6d2d1"
+        },
+        "dist": {
+            "type": "zip",
+            "url": "https://api.github.com/repos/Behat/MinkZombieDriver/zipball/cf15a3a0cc4865bb55253cd033a03a20cee6d2d1",
+            "reference": "cf15a3a0cc4865bb55253cd033a03a20cee6d2d1",
+            "shasum": ""
+        },
+        "require": {
+            "behat/mink": "~1.6@dev",
+            "php": ">=5.3.1",
+            "symfony/process": "~2.1"
+        },
+        "time": "2014-09-26 12:26:25",
+        "type": "mink-driver",
+        "extra": {
+            "branch-alias": {
+                "dev-master": "1.2.x-dev"
+            }
+        },
+        "installation-source": "dist",
+        "autoload": {
+            "psr-0": {
+                "Behat\\Mink\\Driver": "src/"
+            }
+        },
+        "notification-url": "https://packagist.org/downloads/",
+        "license": [
+            "MIT"
+        ],
+        "authors": [
+            {
+                "name": "Konstantin Kudryashov",
+                "email": "ever.zet@gmail.com",
+                "homepage": "http://everzet.com"
+            },
+            {
+                "name": "Pascal Cremer",
+                "email": "b00gizm@gmail.com",
+                "homepage": "http://github.com/b00gizm"
+            }
+        ],
+        "description": "Zombie.js driver for Mink framework",
+        "homepage": "http://mink.behat.org/",
+        "keywords": [
+            "ajax",
+            "browser",
+            "headless",
+            "javascript",
+            "testing",
+            "zombie"
+        ]
     }
 ]
diff --git a/vendor/symfony/css-selector/Symfony/Component/CssSelector/.gitignore b/vendor/symfony/css-selector/Symfony/Component/CssSelector/.gitignore
new file mode 100644
index 00000000000..c49a5d8df5c
--- /dev/null
+++ b/vendor/symfony/css-selector/Symfony/Component/CssSelector/.gitignore
@@ -0,0 +1,3 @@
+vendor/
+composer.lock
+phpunit.xml
diff --git a/vendor/symfony/css-selector/Symfony/Component/CssSelector/CHANGELOG.md b/vendor/symfony/css-selector/Symfony/Component/CssSelector/CHANGELOG.md
new file mode 100644
index 00000000000..be10abee924
--- /dev/null
+++ b/vendor/symfony/css-selector/Symfony/Component/CssSelector/CHANGELOG.md
@@ -0,0 +1,7 @@
+CHANGELOG
+=========
+
+2.1.0
+-----
+
+ * none
diff --git a/vendor/symfony/css-selector/Symfony/Component/CssSelector/CssSelector.php b/vendor/symfony/css-selector/Symfony/Component/CssSelector/CssSelector.php
new file mode 100644
index 00000000000..7a12a8b7e1d
--- /dev/null
+++ b/vendor/symfony/css-selector/Symfony/Component/CssSelector/CssSelector.php
@@ -0,0 +1,83 @@
+<?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\CssSelector;
+
+use Symfony\Component\CssSelector\Parser\Shortcut\ClassParser;
+use Symfony\Component\CssSelector\Parser\Shortcut\ElementParser;
+use Symfony\Component\CssSelector\Parser\Shortcut\EmptyStringParser;
+use Symfony\Component\CssSelector\Parser\Shortcut\HashParser;
+use Symfony\Component\CssSelector\XPath\Extension\HtmlExtension;
+use Symfony\Component\CssSelector\XPath\Translator;
+
+/**
+ * CssSelector is the main entry point of the component and can convert CSS
+ * selectors to XPath expressions.
+ *
+ * $xpath = CssSelector::toXpath('h1.foo');
+ *
+ * This component is a port of the Python cssselector library,
+ * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect.
+ *
+ * @author Fabien Potencier <fabien@symfony.com>
+ *
+ * @api
+ */
+class CssSelector
+{
+    private static $html = true;
+
+    /**
+     * Translates a CSS expression to its XPath equivalent.
+     * Optionally, a prefix can be added to the resulting XPath
+     * expression with the $prefix parameter.
+     *
+     * @param mixed   $cssExpr The CSS expression.
+     * @param string  $prefix  An optional prefix for the XPath expression.
+     *
+     * @return string
+     *
+     * @api
+     */
+    public static function toXPath($cssExpr, $prefix = 'descendant-or-self::')
+    {
+        $translator = new Translator();
+
+        if (self::$html) {
+            $translator->registerExtension(new HtmlExtension($translator));
+        }
+
+        $translator
+            ->registerParserShortcut(new EmptyStringParser())
+            ->registerParserShortcut(new ElementParser())
+            ->registerParserShortcut(new ClassParser())
+            ->registerParserShortcut(new HashParser())
+        ;
+
+        return $translator->cssToXPath($cssExpr, $prefix);
+    }
+
+    /**
+     * Enables the HTML extension.
+     */
+    public static function enableHtmlExtension()
+    {
+        self::$html = true;
+    }
+
+    /**
+     * Disables the HTML extension.
+     */
+    public static function disableHtmlExtension()
+    {
+        self::$html = false;
+    }
+}
diff --git a/vendor/symfony/css-selector/Symfony/Component/CssSelector/Exception/ExceptionInterface.php b/vendor/symfony/css-selector/Symfony/Component/CssSelector/Exception/ExceptionInterface.php
new file mode 100644
index 00000000000..da01c2b2717
--- /dev/null
+++ b/vendor/symfony/css-selector/Symfony/Component/CssSelector/Exception/ExceptionInterface.php
@@ -0,0 +1,24 @@
+<?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\CssSelector\Exception;
+
+/**
+ * Interface for exceptions.
+ *
+ * This component is a port of the Python cssselector library,
+ * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect.
+ *
+ * @author Jean-François Simon <jeanfrancois.simon@sensiolabs.com>
+ */
+interface ExceptionInterface
+{
+}
diff --git a/vendor/symfony/css-selector/Symfony/Component/CssSelector/Exception/ExpressionErrorException.php b/vendor/symfony/css-selector/Symfony/Component/CssSelector/Exception/ExpressionErrorException.php
new file mode 100644
index 00000000000..151dbf03504
--- /dev/null
+++ b/vendor/symfony/css-selector/Symfony/Component/CssSelector/Exception/ExpressionErrorException.php
@@ -0,0 +1,24 @@
+<?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\CssSelector\Exception;
+
+/**
+ * ParseException is thrown when a CSS selector syntax is not valid.
+ *
+ * This component is a port of the Python cssselector library,
+ * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect.
+ *
+ * @author Jean-François Simon <jeanfrancois.simon@sensiolabs.com>
+ */
+class ExpressionErrorException extends ParseException implements ExceptionInterface
+{
+}
diff --git a/vendor/symfony/css-selector/Symfony/Component/CssSelector/Exception/InternalErrorException.php b/vendor/symfony/css-selector/Symfony/Component/CssSelector/Exception/InternalErrorException.php
new file mode 100644
index 00000000000..8a815fb9ea5
--- /dev/null
+++ b/vendor/symfony/css-selector/Symfony/Component/CssSelector/Exception/InternalErrorException.php
@@ -0,0 +1,24 @@
+<?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\CssSelector\Exception;
+
+/**
+ * ParseException is thrown when a CSS selector syntax is not valid.
+ *
+ * This component is a port of the Python cssselector library,
+ * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect.
+ *
+ * @author Jean-François Simon <jeanfrancois.simon@sensiolabs.com>
+ */
+class InternalErrorException extends ParseException implements ExceptionInterface
+{
+}
diff --git a/vendor/symfony/css-selector/Symfony/Component/CssSelector/Exception/ParseException.php b/vendor/symfony/css-selector/Symfony/Component/CssSelector/Exception/ParseException.php
new file mode 100644
index 00000000000..9c119f84c6a
--- /dev/null
+++ b/vendor/symfony/css-selector/Symfony/Component/CssSelector/Exception/ParseException.php
@@ -0,0 +1,24 @@
+<?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\CssSelector\Exception;
+
+/**
+ * ParseException is thrown when a CSS selector syntax is not valid.
+ *
+ * This component is a port of the Python cssselector library,
+ * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect.
+ *
+ * @author Fabien Potencier <fabien@symfony.com>
+ */
+class ParseException extends \Exception implements ExceptionInterface
+{
+}
diff --git a/vendor/symfony/css-selector/Symfony/Component/CssSelector/Exception/SyntaxErrorException.php b/vendor/symfony/css-selector/Symfony/Component/CssSelector/Exception/SyntaxErrorException.php
new file mode 100644
index 00000000000..529b891a3f5
--- /dev/null
+++ b/vendor/symfony/css-selector/Symfony/Component/CssSelector/Exception/SyntaxErrorException.php
@@ -0,0 +1,73 @@
+<?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\CssSelector\Exception;
+
+use Symfony\Component\CssSelector\Parser\Token;
+
+/**
+ * ParseException is thrown when a CSS selector syntax is not valid.
+ *
+ * This component is a port of the Python cssselector library,
+ * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect.
+ *
+ * @author Jean-François Simon <jeanfrancois.simon@sensiolabs.com>
+ */
+class SyntaxErrorException extends ParseException implements ExceptionInterface
+{
+    /**
+     * @param string $expectedValue
+     * @param Token  $foundToken
+     *
+     * @return SyntaxErrorException
+     */
+    public static function unexpectedToken($expectedValue, Token $foundToken)
+    {
+        return new self(sprintf('Expected %s, but %s found.', $expectedValue, $foundToken));
+    }
+
+    /**
+     * @param string $pseudoElement
+     * @param string $unexpectedLocation
+     *
+     * @return SyntaxErrorException
+     */
+    public static function pseudoElementFound($pseudoElement, $unexpectedLocation)
+    {
+        return new self(sprintf('Unexpected pseudo-element "::%s" found %s.', $pseudoElement, $unexpectedLocation));
+    }
+
+    /**
+     * @param int $position
+     *
+     * @return SyntaxErrorException
+     */
+    public static function unclosedString($position)
+    {
+        return new self(sprintf('Unclosed/invalid string at %s.', $position));
+    }
+
+    /**
+     * @return SyntaxErrorException
+     */
+    public static function nestedNot()
+    {
+        return new self('Got nested ::not().');
+    }
+
+    /**
+     * @return SyntaxErrorException
+     */
+    public static function stringAsFunctionArgument()
+    {
+        return new self('String not allowed as function argument.');
+    }
+}
diff --git a/vendor/symfony/css-selector/Symfony/Component/CssSelector/LICENSE b/vendor/symfony/css-selector/Symfony/Component/CssSelector/LICENSE
new file mode 100644
index 00000000000..0b3292cf902
--- /dev/null
+++ b/vendor/symfony/css-selector/Symfony/Component/CssSelector/LICENSE
@@ -0,0 +1,19 @@
+Copyright (c) 2004-2014 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/css-selector/Symfony/Component/CssSelector/Node/AbstractNode.php b/vendor/symfony/css-selector/Symfony/Component/CssSelector/Node/AbstractNode.php
new file mode 100644
index 00000000000..f5324e191b0
--- /dev/null
+++ b/vendor/symfony/css-selector/Symfony/Component/CssSelector/Node/AbstractNode.php
@@ -0,0 +1,40 @@
+<?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\CssSelector\Node;
+
+/**
+ * Abstract base node class.
+ *
+ * This component is a port of the Python cssselector library,
+ * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect.
+ *
+ * @author Jean-François Simon <jeanfrancois.simon@sensiolabs.com>
+ */
+abstract class AbstractNode implements NodeInterface
+{
+    /**
+     * @var string
+     */
+    private $nodeName;
+
+    /**
+     * @return string
+     */
+    public function getNodeName()
+    {
+        if (null === $this->nodeName) {
+            $this->nodeName = preg_replace('~.*\\\\([^\\\\]+)Node$~', '$1', get_called_class());
+        }
+
+        return $this->nodeName;
+    }
+}
diff --git a/vendor/symfony/css-selector/Symfony/Component/CssSelector/Node/AttributeNode.php b/vendor/symfony/css-selector/Symfony/Component/CssSelector/Node/AttributeNode.php
new file mode 100644
index 00000000000..e2fa9a294c5
--- /dev/null
+++ b/vendor/symfony/css-selector/Symfony/Component/CssSelector/Node/AttributeNode.php
@@ -0,0 +1,124 @@
+<?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\CssSelector\Node;
+
+/**
+ * Represents a "<selector>[<namespace>|<attribute> <operator> <value>]" node.
+ *
+ * This component is a port of the Python cssselector library,
+ * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect.
+ *
+ * @author Jean-François Simon <jeanfrancois.simon@sensiolabs.com>
+ */
+class AttributeNode extends AbstractNode
+{
+    /**
+     * @var NodeInterface
+     */
+    private $selector;
+
+    /**
+     * @var string
+     */
+    private $namespace;
+
+    /**
+     * @var string
+     */
+    private $attribute;
+
+    /**
+     * @var string
+     */
+    private $operator;
+
+    /**
+     * @var string
+     */
+    private $value;
+
+    /**
+     * @param NodeInterface $selector
+     * @param string        $namespace
+     * @param string        $attribute
+     * @param string        $operator
+     * @param string        $value
+     */
+    public function __construct(NodeInterface $selector, $namespace, $attribute, $operator, $value)
+    {
+        $this->selector = $selector;
+        $this->namespace = $namespace;
+        $this->attribute = $attribute;
+        $this->operator = $operator;
+        $this->value = $value;
+    }
+
+    /**
+     * @return NodeInterface
+     */
+    public function getSelector()
+    {
+        return $this->selector;
+    }
+
+    /**
+     * @return string
+     */
+    public function getNamespace()
+    {
+        return $this->namespace;
+    }
+
+    /**
+     * @return string
+     */
+    public function getAttribute()
+    {
+        return $this->attribute;
+    }
+
+    /**
+     * @return string
+     */
+    public function getOperator()
+    {
+        return $this->operator;
+    }
+
+    /**
+     * @return string
+     */
+    public function getValue()
+    {
+        return $this->value;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function getSpecificity()
+    {
+        return $this->selector->getSpecificity()->plus(new Specificity(0, 1, 0));
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function __toString()
+    {
+        $attribute = $this->namespace ? $this->namespace.'|'.$this->attribute : $this->attribute;
+
+        return 'exists' === $this->operator
+            ? sprintf('%s[%s[%s]]', $this->getNodeName(), $this->selector, $attribute)
+            : sprintf("%s[%s[%s %s '%s']]", $this->getNodeName(), $this->selector, $attribute, $this->operator, $this->value);
+    }
+}
diff --git a/vendor/symfony/css-selector/Symfony/Component/CssSelector/Node/ClassNode.php b/vendor/symfony/css-selector/Symfony/Component/CssSelector/Node/ClassNode.php
new file mode 100644
index 00000000000..a7a59a33a9f
--- /dev/null
+++ b/vendor/symfony/css-selector/Symfony/Component/CssSelector/Node/ClassNode.php
@@ -0,0 +1,75 @@
+<?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\CssSelector\Node;
+
+/**
+ * Represents a "<selector>.<name>" node.
+ *
+ * This component is a port of the Python cssselector library,
+ * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect.
+ *
+ * @author Jean-François Simon <jeanfrancois.simon@sensiolabs.com>
+ */
+class ClassNode extends AbstractNode
+{
+    /**
+     * @var NodeInterface
+     */
+    private $selector;
+
+    /**
+     * @var string
+     */
+    private $name;
+
+    /**
+     * @param NodeInterface $selector
+     * @param string        $name
+     */
+    public function __construct(NodeInterface $selector, $name)
+    {
+        $this->selector = $selector;
+        $this->name = $name;
+    }
+
+    /**
+     * @return NodeInterface
+     */
+    public function getSelector()
+    {
+        return $this->selector;
+    }
+
+    /**
+     * @return string
+     */
+    public function getName()
+    {
+        return $this->name;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function getSpecificity()
+    {
+        return $this->selector->getSpecificity()->plus(new Specificity(0, 1, 0));
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function __toString()
+    {
+        return sprintf('%s[%s.%s]', $this->getNodeName(), $this->selector, $this->name);
+    }
+}
diff --git a/vendor/symfony/css-selector/Symfony/Component/CssSelector/Node/CombinedSelectorNode.php b/vendor/symfony/css-selector/Symfony/Component/CssSelector/Node/CombinedSelectorNode.php
new file mode 100644
index 00000000000..4e085ea4e1a
--- /dev/null
+++ b/vendor/symfony/css-selector/Symfony/Component/CssSelector/Node/CombinedSelectorNode.php
@@ -0,0 +1,92 @@
+<?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\CssSelector\Node;
+
+/**
+ * Represents a combined node.
+ *
+ * This component is a port of the Python cssselector library,
+ * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect.
+ *
+ * @author Jean-François Simon <jeanfrancois.simon@sensiolabs.com>
+ */
+class CombinedSelectorNode extends AbstractNode
+{
+    /**
+     * @var NodeInterface
+     */
+    private $selector;
+
+    /**
+     * @var string
+     */
+    private $combinator;
+
+    /**
+     * @var NodeInterface
+     */
+    private $subSelector;
+
+    /**
+     * @param NodeInterface $selector
+     * @param string        $combinator
+     * @param NodeInterface $subSelector
+     */
+    public function __construct(NodeInterface $selector, $combinator, NodeInterface $subSelector)
+    {
+        $this->selector = $selector;
+        $this->combinator = $combinator;
+        $this->subSelector = $subSelector;
+    }
+
+    /**
+     * @return NodeInterface
+     */
+    public function getSelector()
+    {
+        return $this->selector;
+    }
+
+    /**
+     * @return string
+     */
+    public function getCombinator()
+    {
+        return $this->combinator;
+    }
+
+    /**
+     * @return NodeInterface
+     */
+    public function getSubSelector()
+    {
+        return $this->subSelector;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function getSpecificity()
+    {
+        return $this->selector->getSpecificity()->plus($this->subSelector->getSpecificity());
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function __toString()
+    {
+        $combinator = ' ' === $this->combinator ? '<followed>' : $this->combinator;
+
+        return sprintf('%s[%s %s %s]', $this->getNodeName(), $this->selector, $combinator, $this->subSelector);
+    }
+}
diff --git a/vendor/symfony/css-selector/Symfony/Component/CssSelector/Node/ElementNode.php b/vendor/symfony/css-selector/Symfony/Component/CssSelector/Node/ElementNode.php
new file mode 100644
index 00000000000..9ab13c3f243
--- /dev/null
+++ b/vendor/symfony/css-selector/Symfony/Component/CssSelector/Node/ElementNode.php
@@ -0,0 +1,77 @@
+<?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\CssSelector\Node;
+
+/**
+ * Represents a "<namespace>|<element>" node.
+ *
+ * This component is a port of the Python cssselector library,
+ * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect.
+ *
+ * @author Jean-François Simon <jeanfrancois.simon@sensiolabs.com>
+ */
+class ElementNode extends AbstractNode
+{
+    /**
+     * @var string|null
+     */
+    private $namespace;
+
+    /**
+     * @var string|null
+     */
+    private $element;
+
+    /**
+     * @param string|null $namespace
+     * @param string|null $element
+     */
+    public function __construct($namespace = null, $element = null)
+    {
+        $this->namespace = $namespace;
+        $this->element = $element;
+    }
+
+    /**
+     * @return null|string
+     */
+    public function getNamespace()
+    {
+        return $this->namespace;
+    }
+
+    /**
+     * @return null|string
+     */
+    public function getElement()
+    {
+        return $this->element;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function getSpecificity()
+    {
+        return new Specificity(0, 0, $this->element ? 1 : 0);
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function __toString()
+    {
+        $element = $this->element ?: '*';
+
+        return sprintf('%s[%s]', $this->getNodeName(), $this->namespace ? $this->namespace.'|'.$element : $element);
+    }
+}
diff --git a/vendor/symfony/css-selector/Symfony/Component/CssSelector/Node/FunctionNode.php b/vendor/symfony/css-selector/Symfony/Component/CssSelector/Node/FunctionNode.php
new file mode 100644
index 00000000000..ecd11a50b00
--- /dev/null
+++ b/vendor/symfony/css-selector/Symfony/Component/CssSelector/Node/FunctionNode.php
@@ -0,0 +1,96 @@
+<?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\CssSelector\Node;
+
+use Symfony\Component\CssSelector\Parser\Token;
+
+/**
+ * Represents a "<selector>:<name>(<arguments>)" node.
+ *
+ * This component is a port of the Python cssselector library,
+ * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect.
+ *
+ * @author Jean-François Simon <jeanfrancois.simon@sensiolabs.com>
+ */
+class FunctionNode extends AbstractNode
+{
+    /**
+     * @var NodeInterface
+     */
+    private $selector;
+
+    /**
+     * @var string
+     */
+    private $name;
+
+    /**
+     * @var Token[]
+     */
+    private $arguments;
+
+    /**
+     * @param NodeInterface $selector
+     * @param string        $name
+     * @param Token[]       $arguments
+     */
+    public function __construct(NodeInterface $selector, $name, array $arguments = array())
+    {
+        $this->selector = $selector;
+        $this->name = strtolower($name);
+        $this->arguments = $arguments;
+    }
+
+    /**
+     * @return NodeInterface
+     */
+    public function getSelector()
+    {
+        return $this->selector;
+    }
+
+    /**
+     * @return string
+     */
+    public function getName()
+    {
+        return $this->name;
+    }
+
+    /**
+     * @return Token[]
+     */
+    public function getArguments()
+    {
+        return $this->arguments;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function getSpecificity()
+    {
+        return $this->selector->getSpecificity()->plus(new Specificity(0, 1, 0));
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function __toString()
+    {
+        $arguments = implode(', ', array_map(function (Token $token) {
+            return "'".$token->getValue()."'";
+        }, $this->arguments));
+
+        return sprintf('%s[%s:%s(%s)]', $this->getNodeName(), $this->selector, $this->name, $arguments ? '['.$arguments.']' : '');
+    }
+}
diff --git a/vendor/symfony/css-selector/Symfony/Component/CssSelector/Node/HashNode.php b/vendor/symfony/css-selector/Symfony/Component/CssSelector/Node/HashNode.php
new file mode 100644
index 00000000000..7fb407579b6
--- /dev/null
+++ b/vendor/symfony/css-selector/Symfony/Component/CssSelector/Node/HashNode.php
@@ -0,0 +1,75 @@
+<?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\CssSelector\Node;
+
+/**
+ * Represents a "<selector>#<id>" node.
+ *
+ * This component is a port of the Python cssselector library,
+ * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect.
+ *
+ * @author Jean-François Simon <jeanfrancois.simon@sensiolabs.com>
+ */
+class HashNode extends AbstractNode
+{
+    /**
+     * @var NodeInterface
+     */
+    private $selector;
+
+    /**
+     * @var string
+     */
+    private $id;
+
+    /**
+     * @param NodeInterface $selector
+     * @param string        $id
+     */
+    public function __construct(NodeInterface $selector, $id)
+    {
+        $this->selector = $selector;
+        $this->id = $id;
+    }
+
+    /**
+     * @return NodeInterface
+     */
+    public function getSelector()
+    {
+        return $this->selector;
+    }
+
+    /**
+     * @return string
+     */
+    public function getId()
+    {
+        return $this->id;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function getSpecificity()
+    {
+        return $this->selector->getSpecificity()->plus(new Specificity(1, 0, 0));
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function __toString()
+    {
+        return sprintf('%s[%s#%s]', $this->getNodeName(), $this->selector, $this->id);
+    }
+}
diff --git a/vendor/symfony/css-selector/Symfony/Component/CssSelector/Node/NegationNode.php b/vendor/symfony/css-selector/Symfony/Component/CssSelector/Node/NegationNode.php
new file mode 100644
index 00000000000..2529689095e
--- /dev/null
+++ b/vendor/symfony/css-selector/Symfony/Component/CssSelector/Node/NegationNode.php
@@ -0,0 +1,75 @@
+<?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\CssSelector\Node;
+
+/**
+ * Represents a "<selector>:not(<identifier>)" node.
+ *
+ * This component is a port of the Python cssselector library,
+ * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect.
+ *
+ * @author Jean-François Simon <jeanfrancois.simon@sensiolabs.com>
+ */
+class NegationNode extends AbstractNode
+{
+    /**
+     * @var NodeInterface
+     */
+    private $selector;
+
+    /**
+     * @var NodeInterface
+     */
+    private $subSelector;
+
+    /**
+     * @param NodeInterface $selector
+     * @param NodeInterface $subSelector
+     */
+    public function __construct(NodeInterface $selector, NodeInterface $subSelector)
+    {
+        $this->selector = $selector;
+        $this->subSelector = $subSelector;
+    }
+
+    /**
+     * @return NodeInterface
+     */
+    public function getSelector()
+    {
+        return $this->selector;
+    }
+
+    /**
+     * @return NodeInterface
+     */
+    public function getSubSelector()
+    {
+        return $this->subSelector;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function getSpecificity()
+    {
+        return $this->selector->getSpecificity()->plus($this->subSelector->getSpecificity());
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function __toString()
+    {
+        return sprintf('%s[%s:not(%s)]', $this->getNodeName(), $this->selector, $this->subSelector);
+    }
+}
diff --git a/vendor/symfony/css-selector/Symfony/Component/CssSelector/Node/NodeInterface.php b/vendor/symfony/css-selector/Symfony/Component/CssSelector/Node/NodeInterface.php
new file mode 100644
index 00000000000..1601c33a6ed
--- /dev/null
+++ b/vendor/symfony/css-selector/Symfony/Component/CssSelector/Node/NodeInterface.php
@@ -0,0 +1,44 @@
+<?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\CssSelector\Node;
+
+/**
+ * Interface for nodes.
+ *
+ * This component is a port of the Python cssselector library,
+ * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect.
+ *
+ * @author Jean-François Simon <jeanfrancois.simon@sensiolabs.com>
+ */
+interface NodeInterface
+{
+    /**
+     * Returns node's name.
+     *
+     * @return string
+     */
+    public function getNodeName();
+
+    /**
+     * Returns node's specificity.
+     *
+     * @return Specificity
+     */
+    public function getSpecificity();
+
+    /**
+     * Returns node's string representation.
+     *
+     * @return string
+     */
+    public function __toString();
+}
diff --git a/vendor/symfony/css-selector/Symfony/Component/CssSelector/Node/PseudoNode.php b/vendor/symfony/css-selector/Symfony/Component/CssSelector/Node/PseudoNode.php
new file mode 100644
index 00000000000..4f2d538f6f5
--- /dev/null
+++ b/vendor/symfony/css-selector/Symfony/Component/CssSelector/Node/PseudoNode.php
@@ -0,0 +1,75 @@
+<?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\CssSelector\Node;
+
+/**
+ * Represents a "<selector>:<identifier>" node.
+ *
+ * This component is a port of the Python cssselector library,
+ * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect.
+ *
+ * @author Jean-François Simon <jeanfrancois.simon@sensiolabs.com>
+ */
+class PseudoNode extends AbstractNode
+{
+    /**
+     * @var NodeInterface
+     */
+    private $selector;
+
+    /**
+     * @var string
+     */
+    private $identifier;
+
+    /**
+     * @param NodeInterface $selector
+     * @param string        $identifier
+     */
+    public function __construct(NodeInterface $selector, $identifier)
+    {
+        $this->selector = $selector;
+        $this->identifier = strtolower($identifier);
+    }
+
+    /**
+     * @return NodeInterface
+     */
+    public function getSelector()
+    {
+        return $this->selector;
+    }
+
+    /**
+     * @return string
+     */
+    public function getIdentifier()
+    {
+        return $this->identifier;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function getSpecificity()
+    {
+        return $this->selector->getSpecificity()->plus(new Specificity(0, 1, 0));
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function __toString()
+    {
+        return sprintf('%s[%s:%s]', $this->getNodeName(), $this->selector, $this->identifier);
+    }
+}
diff --git a/vendor/symfony/css-selector/Symfony/Component/CssSelector/Node/SelectorNode.php b/vendor/symfony/css-selector/Symfony/Component/CssSelector/Node/SelectorNode.php
new file mode 100644
index 00000000000..49f417f2860
--- /dev/null
+++ b/vendor/symfony/css-selector/Symfony/Component/CssSelector/Node/SelectorNode.php
@@ -0,0 +1,75 @@
+<?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\CssSelector\Node;
+
+/**
+ * Represents a "<selector>(::|:)<pseudoElement>" node.
+ *
+ * This component is a port of the Python cssselector library,
+ * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect.
+ *
+ * @author Jean-François Simon <jeanfrancois.simon@sensiolabs.com>
+ */
+class SelectorNode extends AbstractNode
+{
+    /**
+     * @var NodeInterface
+     */
+    private $tree;
+
+    /**
+     * @var null|string
+     */
+    private $pseudoElement;
+
+    /**
+     * @param NodeInterface $tree
+     * @param null|string   $pseudoElement
+     */
+    public function __construct(NodeInterface $tree, $pseudoElement = null)
+    {
+        $this->tree = $tree;
+        $this->pseudoElement = $pseudoElement ? strtolower($pseudoElement) : null;
+    }
+
+    /**
+     * @return NodeInterface
+     */
+    public function getTree()
+    {
+        return $this->tree;
+    }
+
+    /**
+     * @return null|string
+     */
+    public function getPseudoElement()
+    {
+        return $this->pseudoElement;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function getSpecificity()
+    {
+        return $this->tree->getSpecificity()->plus(new Specificity(0, 0, $this->pseudoElement ? 1 : 0));
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function __toString()
+    {
+        return sprintf('%s[%s%s]', $this->getNodeName(), $this->tree, $this->pseudoElement ? '::'.$this->pseudoElement : '');
+    }
+}
diff --git a/vendor/symfony/css-selector/Symfony/Component/CssSelector/Node/Specificity.php b/vendor/symfony/css-selector/Symfony/Component/CssSelector/Node/Specificity.php
new file mode 100644
index 00000000000..96bbd11f515
--- /dev/null
+++ b/vendor/symfony/css-selector/Symfony/Component/CssSelector/Node/Specificity.php
@@ -0,0 +1,78 @@
+<?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\CssSelector\Node;
+
+/**
+ * Represents a node specificity.
+ *
+ * This component is a port of the Python cssselector library,
+ * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect.
+ *
+ * @see http://www.w3.org/TR/selectors/#specificity
+ *
+ * @author Jean-François Simon <jeanfrancois.simon@sensiolabs.com>
+ */
+class Specificity
+{
+    const A_FACTOR = 100;
+    const B_FACTOR = 10;
+    const C_FACTOR = 1;
+
+    /**
+     * @var int
+     */
+    private $a;
+
+    /**
+     * @var int
+     */
+    private $b;
+
+    /**
+     * @var int
+     */
+    private $c;
+
+    /**
+     * Constructor.
+     *
+     * @param int $a
+     * @param int $b
+     * @param int $c
+     */
+    public function __construct($a, $b, $c)
+    {
+        $this->a = $a;
+        $this->b = $b;
+        $this->c = $c;
+    }
+
+    /**
+     * @param Specificity $specificity
+     *
+     * @return Specificity
+     */
+    public function plus(Specificity $specificity)
+    {
+        return new self($this->a + $specificity->a, $this->b + $specificity->b, $this->c + $specificity->c);
+    }
+
+    /**
+     * Returns global specificity value.
+     *
+     * @return int
+     */
+    public function getValue()
+    {
+        return $this->a * self::A_FACTOR + $this->b * self::B_FACTOR + $this->c * self::C_FACTOR;
+    }
+}
diff --git a/vendor/symfony/css-selector/Symfony/Component/CssSelector/Parser/Handler/CommentHandler.php b/vendor/symfony/css-selector/Symfony/Component/CssSelector/Parser/Handler/CommentHandler.php
new file mode 100644
index 00000000000..97c3f8dd24c
--- /dev/null
+++ b/vendor/symfony/css-selector/Symfony/Component/CssSelector/Parser/Handler/CommentHandler.php
@@ -0,0 +1,46 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\CssSelector\Parser\Handler;
+
+use Symfony\Component\CssSelector\Parser\Reader;
+use Symfony\Component\CssSelector\Parser\TokenStream;
+
+/**
+ * CSS selector comment handler.
+ *
+ * This component is a port of the Python cssselector library,
+ * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect.
+ *
+ * @author Jean-François Simon <jeanfrancois.simon@sensiolabs.com>
+ */
+class CommentHandler implements HandlerInterface
+{
+    /**
+     * {@inheritdoc}
+     */
+    public function handle(Reader $reader, TokenStream $stream)
+    {
+        if ('/*' !== $reader->getSubstring(2)) {
+            return false;
+        }
+
+        $offset = $reader->getOffset('*/');
+
+        if (false === $offset) {
+            $reader->moveToEnd();
+        } else {
+            $reader->moveForward($offset + 2);
+        }
+
+        return true;
+    }
+}
diff --git a/vendor/symfony/css-selector/Symfony/Component/CssSelector/Parser/Handler/HandlerInterface.php b/vendor/symfony/css-selector/Symfony/Component/CssSelector/Parser/Handler/HandlerInterface.php
new file mode 100644
index 00000000000..c7a48c0d6eb
--- /dev/null
+++ b/vendor/symfony/css-selector/Symfony/Component/CssSelector/Parser/Handler/HandlerInterface.php
@@ -0,0 +1,34 @@
+<?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\CssSelector\Parser\Handler;
+
+use Symfony\Component\CssSelector\Parser\Reader;
+use Symfony\Component\CssSelector\Parser\TokenStream;
+
+/**
+ * CSS selector handler interface.
+ *
+ * This component is a port of the Python cssselector library,
+ * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect.
+ *
+ * @author Jean-François Simon <jeanfrancois.simon@sensiolabs.com>
+ */
+interface HandlerInterface
+{
+    /**
+     * @param Reader      $reader
+     * @param TokenStream $stream
+     *
+     * @return bool
+     */
+    public function handle(Reader $reader, TokenStream $stream);
+}
diff --git a/vendor/symfony/css-selector/Symfony/Component/CssSelector/Parser/Handler/HashHandler.php b/vendor/symfony/css-selector/Symfony/Component/CssSelector/Parser/Handler/HashHandler.php
new file mode 100644
index 00000000000..2227ea62a6a
--- /dev/null
+++ b/vendor/symfony/css-selector/Symfony/Component/CssSelector/Parser/Handler/HashHandler.php
@@ -0,0 +1,67 @@
+<?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\CssSelector\Parser\Handler;
+
+use Symfony\Component\CssSelector\Parser\Reader;
+use Symfony\Component\CssSelector\Parser\Token;
+use Symfony\Component\CssSelector\Parser\TokenStream;
+use Symfony\Component\CssSelector\Parser\Tokenizer\TokenizerEscaping;
+use Symfony\Component\CssSelector\Parser\Tokenizer\TokenizerPatterns;
+
+/**
+ * CSS selector comment handler.
+ *
+ * This component is a port of the Python cssselector library,
+ * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect.
+ *
+ * @author Jean-François Simon <jeanfrancois.simon@sensiolabs.com>
+ */
+class HashHandler implements HandlerInterface
+{
+    /**
+     * @var TokenizerPatterns
+     */
+    private $patterns;
+
+    /**
+     * @var TokenizerEscaping
+     */
+    private $escaping;
+
+    /**
+     * @param TokenizerPatterns $patterns
+     * @param TokenizerEscaping $escaping
+     */
+    public function __construct(TokenizerPatterns $patterns, TokenizerEscaping $escaping)
+    {
+        $this->patterns = $patterns;
+        $this->escaping = $escaping;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function handle(Reader $reader, TokenStream $stream)
+    {
+        $match = $reader->findPattern($this->patterns->getHashPattern());
+
+        if (!$match) {
+            return false;
+        }
+
+        $value = $this->escaping->escapeUnicode($match[1]);
+        $stream->push(new Token(Token::TYPE_HASH, $value, $reader->getPosition()));
+        $reader->moveForward(strlen($match[0]));
+
+        return true;
+    }
+}
diff --git a/vendor/symfony/css-selector/Symfony/Component/CssSelector/Parser/Handler/IdentifierHandler.php b/vendor/symfony/css-selector/Symfony/Component/CssSelector/Parser/Handler/IdentifierHandler.php
new file mode 100644
index 00000000000..346532ec151
--- /dev/null
+++ b/vendor/symfony/css-selector/Symfony/Component/CssSelector/Parser/Handler/IdentifierHandler.php
@@ -0,0 +1,67 @@
+<?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\CssSelector\Parser\Handler;
+
+use Symfony\Component\CssSelector\Parser\Reader;
+use Symfony\Component\CssSelector\Parser\Token;
+use Symfony\Component\CssSelector\Parser\TokenStream;
+use Symfony\Component\CssSelector\Parser\Tokenizer\TokenizerEscaping;
+use Symfony\Component\CssSelector\Parser\Tokenizer\TokenizerPatterns;
+
+/**
+ * CSS selector comment handler.
+ *
+ * This component is a port of the Python cssselector library,
+ * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect.
+ *
+ * @author Jean-François Simon <jeanfrancois.simon@sensiolabs.com>
+ */
+class IdentifierHandler implements HandlerInterface
+{
+    /**
+     * @var TokenizerPatterns
+     */
+    private $patterns;
+
+    /**
+     * @var TokenizerEscaping
+     */
+    private $escaping;
+
+    /**
+     * @param TokenizerPatterns $patterns
+     * @param TokenizerEscaping $escaping
+     */
+    public function __construct(TokenizerPatterns $patterns, TokenizerEscaping $escaping)
+    {
+        $this->patterns = $patterns;
+        $this->escaping = $escaping;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function handle(Reader $reader, TokenStream $stream)
+    {
+        $match = $reader->findPattern($this->patterns->getIdentifierPattern());
+
+        if (!$match) {
+            return false;
+        }
+
+        $value = $this->escaping->escapeUnicode($match[0]);
+        $stream->push(new Token(Token::TYPE_IDENTIFIER, $value, $reader->getPosition()));
+        $reader->moveForward(strlen($match[0]));
+
+        return true;
+    }
+}
diff --git a/vendor/symfony/css-selector/Symfony/Component/CssSelector/Parser/Handler/NumberHandler.php b/vendor/symfony/css-selector/Symfony/Component/CssSelector/Parser/Handler/NumberHandler.php
new file mode 100644
index 00000000000..208f83c08fe
--- /dev/null
+++ b/vendor/symfony/css-selector/Symfony/Component/CssSelector/Parser/Handler/NumberHandler.php
@@ -0,0 +1,58 @@
+<?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\CssSelector\Parser\Handler;
+
+use Symfony\Component\CssSelector\Parser\Reader;
+use Symfony\Component\CssSelector\Parser\Token;
+use Symfony\Component\CssSelector\Parser\TokenStream;
+use Symfony\Component\CssSelector\Parser\Tokenizer\TokenizerPatterns;
+
+/**
+ * CSS selector comment handler.
+ *
+ * This component is a port of the Python cssselector library,
+ * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect.
+ *
+ * @author Jean-François Simon <jeanfrancois.simon@sensiolabs.com>
+ */
+class NumberHandler implements HandlerInterface
+{
+    /**
+     * @var TokenizerPatterns
+     */
+    private $patterns;
+
+    /**
+     * @param TokenizerPatterns $patterns
+     */
+    public function __construct(TokenizerPatterns $patterns)
+    {
+        $this->patterns = $patterns;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function handle(Reader $reader, TokenStream $stream)
+    {
+        $match = $reader->findPattern($this->patterns->getNumberPattern());
+
+        if (!$match) {
+            return false;
+        }
+
+        $stream->push(new Token(Token::TYPE_NUMBER, $match[0], $reader->getPosition()));
+        $reader->moveForward(strlen($match[0]));
+
+        return true;
+    }
+}
diff --git a/vendor/symfony/css-selector/Symfony/Component/CssSelector/Parser/Handler/StringHandler.php b/vendor/symfony/css-selector/Symfony/Component/CssSelector/Parser/Handler/StringHandler.php
new file mode 100644
index 00000000000..2663fe87b51
--- /dev/null
+++ b/vendor/symfony/css-selector/Symfony/Component/CssSelector/Parser/Handler/StringHandler.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\CssSelector\Parser\Handler;
+
+use Symfony\Component\CssSelector\Exception\InternalErrorException;
+use Symfony\Component\CssSelector\Exception\SyntaxErrorException;
+use Symfony\Component\CssSelector\Parser\Reader;
+use Symfony\Component\CssSelector\Parser\Token;
+use Symfony\Component\CssSelector\Parser\TokenStream;
+use Symfony\Component\CssSelector\Parser\Tokenizer\TokenizerEscaping;
+use Symfony\Component\CssSelector\Parser\Tokenizer\TokenizerPatterns;
+
+/**
+ * CSS selector comment handler.
+ *
+ * This component is a port of the Python cssselector library,
+ * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect.
+ *
+ * @author Jean-François Simon <jeanfrancois.simon@sensiolabs.com>
+ */
+class StringHandler implements HandlerInterface
+{
+    /**
+     * @var TokenizerPatterns
+     */
+    private $patterns;
+
+    /**
+     * @var TokenizerEscaping
+     */
+    private $escaping;
+
+    /**
+     * @param TokenizerPatterns $patterns
+     * @param TokenizerEscaping $escaping
+     */
+    public function __construct(TokenizerPatterns $patterns, TokenizerEscaping $escaping)
+    {
+        $this->patterns = $patterns;
+        $this->escaping = $escaping;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function handle(Reader $reader, TokenStream $stream)
+    {
+        $quote = $reader->getSubstring(1);
+
+        if (!in_array($quote, array("'", '"'))) {
+            return false;
+        }
+
+        $reader->moveForward(1);
+        $match = $reader->findPattern($this->patterns->getQuotedStringPattern($quote));
+
+        if (!$match) {
+            throw new InternalErrorException(sprintf('Should have found at least an empty match at %s.', $reader->getPosition()));
+        }
+
+        // check unclosed strings
+        if (strlen($match[0]) === $reader->getRemainingLength()) {
+            throw SyntaxErrorException::unclosedString($reader->getPosition() - 1);
+        }
+
+        // check quotes pairs validity
+        if ($quote !== $reader->getSubstring(1, strlen($match[0]))) {
+            throw SyntaxErrorException::unclosedString($reader->getPosition() - 1);
+        }
+
+        $string = $this->escaping->escapeUnicodeAndNewLine($match[0]);
+        $stream->push(new Token(Token::TYPE_STRING, $string, $reader->getPosition()));
+        $reader->moveForward(strlen($match[0]) + 1);
+
+        return true;
+    }
+}
diff --git a/vendor/symfony/css-selector/Symfony/Component/CssSelector/Parser/Handler/WhitespaceHandler.php b/vendor/symfony/css-selector/Symfony/Component/CssSelector/Parser/Handler/WhitespaceHandler.php
new file mode 100644
index 00000000000..806cfbb5135
--- /dev/null
+++ b/vendor/symfony/css-selector/Symfony/Component/CssSelector/Parser/Handler/WhitespaceHandler.php
@@ -0,0 +1,44 @@
+<?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\CssSelector\Parser\Handler;
+
+use Symfony\Component\CssSelector\Parser\Reader;
+use Symfony\Component\CssSelector\Parser\Token;
+use Symfony\Component\CssSelector\Parser\TokenStream;
+
+/**
+ * CSS selector whitespace handler.
+ *
+ * This component is a port of the Python cssselector library,
+ * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect.
+ *
+ * @author Jean-François Simon <jeanfrancois.simon@sensiolabs.com>
+ */
+class WhitespaceHandler implements HandlerInterface
+{
+    /**
+     * {@inheritdoc}
+     */
+    public function handle(Reader $reader, TokenStream $stream)
+    {
+        $match = $reader->findPattern('~^[ \t\r\n\f]+~');
+
+        if (false === $match) {
+            return false;
+        }
+
+        $stream->push(new Token(Token::TYPE_WHITESPACE, $match[0], $reader->getPosition()));
+        $reader->moveForward(strlen($match[0]));
+
+        return true;
+    }
+}
diff --git a/vendor/symfony/css-selector/Symfony/Component/CssSelector/Parser/Parser.php b/vendor/symfony/css-selector/Symfony/Component/CssSelector/Parser/Parser.php
new file mode 100644
index 00000000000..c622383e841
--- /dev/null
+++ b/vendor/symfony/css-selector/Symfony/Component/CssSelector/Parser/Parser.php
@@ -0,0 +1,399 @@
+<?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\CssSelector\Parser;
+
+use Symfony\Component\CssSelector\Exception\SyntaxErrorException;
+use Symfony\Component\CssSelector\Node;
+use Symfony\Component\CssSelector\Parser\Tokenizer\Tokenizer;
+
+/**
+ * CSS selector parser.
+ *
+ * This component is a port of the Python cssselector library,
+ * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect.
+ *
+ * @author Jean-François Simon <jeanfrancois.simon@sensiolabs.com>
+ */
+class Parser implements ParserInterface
+{
+    /**
+     * @var Tokenizer
+     */
+    private $tokenizer;
+
+    /**
+     * Constructor.
+     *
+     * @param null|Tokenizer $tokenizer
+     */
+    public function __construct(Tokenizer $tokenizer = null)
+    {
+        $this->tokenizer = $tokenizer ?: new Tokenizer();
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function parse($source)
+    {
+        $reader = new Reader($source);
+        $stream = $this->tokenizer->tokenize($reader);
+
+        return $this->parseSelectorList($stream);
+    }
+
+    /**
+     * Parses the arguments for ":nth-child()" and friends.
+     *
+     * @param Token[] $tokens
+     *
+     * @throws SyntaxErrorException
+     *
+     * @return array
+     */
+    public static function parseSeries(array $tokens)
+    {
+        foreach ($tokens as $token) {
+            if ($token->isString()) {
+                throw SyntaxErrorException::stringAsFunctionArgument();
+            }
+        }
+
+        $joined = trim(implode('', array_map(function (Token $token) {
+            return $token->getValue();
+        }, $tokens)));
+
+        $int = function ($string) {
+            if (!is_numeric($string)) {
+                throw SyntaxErrorException::stringAsFunctionArgument();
+            }
+
+            return (int) $string;
+        };
+
+        switch (true) {
+            case 'odd' === $joined:
+                return array(2, 1);
+            case 'even' === $joined:
+                return array(2, 0);
+            case 'n' === $joined:
+                return array(1, 0);
+            case false === strpos($joined, 'n'):
+                return array(0, $int($joined));
+        }
+
+        $split = explode('n', $joined);
+        $first = isset($split[0]) ? $split[0] : null;
+
+        return array(
+            $first ? ('-' === $first || '+' === $first ? $int($first.'1') : $int($first)) : 1,
+            isset($split[1]) && $split[1] ? $int($split[1]) : 0,
+        );
+    }
+
+    /**
+     * Parses selector nodes.
+     *
+     * @param TokenStream $stream
+     *
+     * @return array
+     */
+    private function parseSelectorList(TokenStream $stream)
+    {
+        $stream->skipWhitespace();
+        $selectors = array();
+
+        while (true) {
+            $selectors[] = $this->parserSelectorNode($stream);
+
+            if ($stream->getPeek()->isDelimiter(array(','))) {
+                $stream->getNext();
+                $stream->skipWhitespace();
+            } else {
+                break;
+            }
+        }
+
+        return $selectors;
+    }
+
+    /**
+     * Parses next selector or combined node.
+     *
+     * @param TokenStream $stream
+     *
+     * @throws SyntaxErrorException
+     *
+     * @return Node\SelectorNode
+     */
+    private function parserSelectorNode(TokenStream $stream)
+    {
+        list($result, $pseudoElement) = $this->parseSimpleSelector($stream);
+
+        while (true) {
+            $stream->skipWhitespace();
+            $peek = $stream->getPeek();
+
+            if ($peek->isFileEnd() || $peek->isDelimiter(array(','))) {
+                break;
+            }
+
+            if (null !== $pseudoElement) {
+                throw SyntaxErrorException::pseudoElementFound($pseudoElement, 'not at the end of a selector');
+            }
+
+            if ($peek->isDelimiter(array('+', '>', '~'))) {
+                $combinator = $stream->getNext()->getValue();
+                $stream->skipWhitespace();
+            } else {
+                $combinator = ' ';
+            }
+
+            list($nextSelector, $pseudoElement) = $this->parseSimpleSelector($stream);
+            $result = new Node\CombinedSelectorNode($result, $combinator, $nextSelector);
+        }
+
+        return new Node\SelectorNode($result, $pseudoElement);
+    }
+
+    /**
+     * Parses next simple node (hash, class, pseudo, negation).
+     *
+     * @param TokenStream $stream
+     * @param bool        $insideNegation
+     *
+     * @throws SyntaxErrorException
+     *
+     * @return array
+     */
+    private function parseSimpleSelector(TokenStream $stream, $insideNegation = false)
+    {
+        $stream->skipWhitespace();
+
+        $selectorStart = count($stream->getUsed());
+        $result = $this->parseElementNode($stream);
+        $pseudoElement = null;
+
+        while (true) {
+            $peek = $stream->getPeek();
+            if ($peek->isWhitespace()
+                || $peek->isFileEnd()
+                || $peek->isDelimiter(array(',', '+', '>', '~'))
+                || ($insideNegation && $peek->isDelimiter(array(')')))
+            ) {
+                break;
+            }
+
+            if (null !== $pseudoElement) {
+                throw SyntaxErrorException::pseudoElementFound($pseudoElement, 'not at the end of a selector');
+            }
+
+            if ($peek->isHash()) {
+                $result = new Node\HashNode($result, $stream->getNext()->getValue());
+            } elseif ($peek->isDelimiter(array('.'))) {
+                $stream->getNext();
+                $result = new Node\ClassNode($result, $stream->getNextIdentifier());
+            } elseif ($peek->isDelimiter(array('['))) {
+                $stream->getNext();
+                $result = $this->parseAttributeNode($result, $stream);
+            } elseif ($peek->isDelimiter(array(':'))) {
+                $stream->getNext();
+
+                if ($stream->getPeek()->isDelimiter(array(':'))) {
+                    $stream->getNext();
+                    $pseudoElement = $stream->getNextIdentifier();
+
+                    continue;
+                }
+
+                $identifier = $stream->getNextIdentifier();
+                if (in_array(strtolower($identifier), array('first-line', 'first-letter', 'before', 'after'))) {
+                    // Special case: CSS 2.1 pseudo-elements can have a single ':'.
+                    // Any new pseudo-element must have two.
+                    $pseudoElement = $identifier;
+
+                    continue;
+                }
+
+                if (!$stream->getPeek()->isDelimiter(array('('))) {
+                    $result = new Node\PseudoNode($result, $identifier);
+
+                    continue;
+                }
+
+                $stream->getNext();
+                $stream->skipWhitespace();
+
+                if ('not' === strtolower($identifier)) {
+                    if ($insideNegation) {
+                        throw SyntaxErrorException::nestedNot();
+                    }
+
+                    list($argument, $argumentPseudoElement) = $this->parseSimpleSelector($stream, true);
+                    $next = $stream->getNext();
+
+                    if (null !== $argumentPseudoElement) {
+                        throw SyntaxErrorException::pseudoElementFound($argumentPseudoElement, 'inside ::not()');
+                    }
+
+                    if (!$next->isDelimiter(array(')'))) {
+                        throw SyntaxErrorException::unexpectedToken('")"', $next);
+                    }
+
+                    $result = new Node\NegationNode($result, $argument);
+                } else {
+                    $arguments = array();
+                    $next = null;
+
+                    while (true) {
+                        $stream->skipWhitespace();
+                        $next = $stream->getNext();
+
+                        if ($next->isIdentifier()
+                            || $next->isString()
+                            || $next->isNumber()
+                            || $next->isDelimiter(array('+', '-'))
+                        ) {
+                            $arguments[] = $next;
+                        } elseif ($next->isDelimiter(array(')'))) {
+                            break;
+                        } else {
+                            throw SyntaxErrorException::unexpectedToken('an argument', $next);
+                        }
+                    }
+
+                    if (empty($arguments)) {
+                        throw SyntaxErrorException::unexpectedToken('at least one argument', $next);
+                    }
+
+                    $result = new Node\FunctionNode($result, $identifier, $arguments);
+                }
+            } else {
+                throw SyntaxErrorException::unexpectedToken('selector', $peek);
+            }
+        }
+
+        if (count($stream->getUsed()) === $selectorStart) {
+            throw SyntaxErrorException::unexpectedToken('selector', $stream->getPeek());
+        }
+
+        return array($result, $pseudoElement);
+    }
+
+    /**
+     * Parses next element node.
+     *
+     * @param TokenStream $stream
+     *
+     * @return Node\ElementNode
+     */
+    private function parseElementNode(TokenStream $stream)
+    {
+        $peek = $stream->getPeek();
+
+        if ($peek->isIdentifier() || $peek->isDelimiter(array('*'))) {
+            if ($peek->isIdentifier()) {
+                $namespace = $stream->getNext()->getValue();
+            } else {
+                $stream->getNext();
+                $namespace = null;
+            }
+
+            if ($stream->getPeek()->isDelimiter(array('|'))) {
+                $stream->getNext();
+                $element = $stream->getNextIdentifierOrStar();
+            } else {
+                $element = $namespace;
+                $namespace = null;
+            }
+        } else {
+            $element = $namespace = null;
+        }
+
+        return new Node\ElementNode($namespace, $element);
+    }
+
+    /**
+     * Parses next attribute node.
+     *
+     * @param Node\NodeInterface $selector
+     * @param TokenStream        $stream
+     *
+     * @throws SyntaxErrorException
+     *
+     * @return Node\AttributeNode
+     */
+    private function parseAttributeNode(Node\NodeInterface $selector, TokenStream $stream)
+    {
+        $stream->skipWhitespace();
+        $attribute = $stream->getNextIdentifierOrStar();
+
+        if (null === $attribute && !$stream->getPeek()->isDelimiter(array('|'))) {
+            throw SyntaxErrorException::unexpectedToken('"|"', $stream->getPeek());
+        }
+
+        if ($stream->getPeek()->isDelimiter(array('|'))) {
+            $stream->getNext();
+
+            if ($stream->getPeek()->isDelimiter(array('='))) {
+                $namespace = null;
+                $stream->getNext();
+                $operator = '|=';
+            } else {
+                $namespace = $attribute;
+                $attribute = $stream->getNextIdentifier();
+                $operator = null;
+            }
+        } else {
+            $namespace = $operator = null;
+        }
+
+        if (null === $operator) {
+            $stream->skipWhitespace();
+            $next = $stream->getNext();
+
+            if ($next->isDelimiter(array(']'))) {
+                return new Node\AttributeNode($selector, $namespace, $attribute, 'exists', null);
+            } elseif ($next->isDelimiter(array('='))) {
+                $operator = '=';
+            } elseif ($next->isDelimiter(array('^', '$', '*', '~', '|', '!'))
+                && $stream->getPeek()->isDelimiter(array('='))
+            ) {
+                $operator = $next->getValue().'=';
+                $stream->getNext();
+            } else {
+                throw SyntaxErrorException::unexpectedToken('operator', $next);
+            }
+        }
+
+        $stream->skipWhitespace();
+        $value = $stream->getNext();
+
+        if ($value->isNumber()) {
+            // if the value is a number, it's casted into a string
+            $value = new Token(Token::TYPE_STRING, (string) $value->getValue(), $value->getPosition());
+        }
+
+        if (!($value->isIdentifier() || $value->isString())) {
+            throw SyntaxErrorException::unexpectedToken('string or identifier', $value);
+        }
+
+        $stream->skipWhitespace();
+        $next = $stream->getNext();
+
+        if (!$next->isDelimiter(array(']'))) {
+            throw SyntaxErrorException::unexpectedToken('"]"', $next);
+        }
+
+        return new Node\AttributeNode($selector, $namespace, $attribute, $operator, $value->getValue());
+    }
+}
diff --git a/vendor/symfony/css-selector/Symfony/Component/CssSelector/Parser/ParserInterface.php b/vendor/symfony/css-selector/Symfony/Component/CssSelector/Parser/ParserInterface.php
new file mode 100644
index 00000000000..b27f79f4a6e
--- /dev/null
+++ b/vendor/symfony/css-selector/Symfony/Component/CssSelector/Parser/ParserInterface.php
@@ -0,0 +1,34 @@
+<?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\CssSelector\Parser;
+
+use Symfony\Component\CssSelector\Node\SelectorNode;
+
+/**
+ * CSS selector parser interface.
+ *
+ * This component is a port of the Python cssselector library,
+ * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect.
+ *
+ * @author Jean-François Simon <jeanfrancois.simon@sensiolabs.com>
+ */
+interface ParserInterface
+{
+    /**
+     * Parses given selector source into an array of tokens.
+     *
+     * @param string $source
+     *
+     * @return SelectorNode[]
+     */
+    public function parse($source);
+}
diff --git a/vendor/symfony/css-selector/Symfony/Component/CssSelector/Parser/Reader.php b/vendor/symfony/css-selector/Symfony/Component/CssSelector/Parser/Reader.php
new file mode 100644
index 00000000000..2a6c4bbd439
--- /dev/null
+++ b/vendor/symfony/css-selector/Symfony/Component/CssSelector/Parser/Reader.php
@@ -0,0 +1,125 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\CssSelector\Parser;
+
+/**
+ * CSS selector reader.
+ *
+ * This component is a port of the Python cssselector library,
+ * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect.
+ *
+ * @author Jean-François Simon <jeanfrancois.simon@sensiolabs.com>
+ */
+class Reader
+{
+    /**
+     * @var string
+     */
+    private $source;
+
+    /**
+     * @var int
+     */
+    private $length;
+
+    /**
+     * @var int
+     */
+    private $position = 0;
+
+    /**
+     * @param string $source
+     */
+    public function __construct($source)
+    {
+        $this->source = $source;
+        $this->length = strlen($source);
+    }
+
+    /**
+     * @return bool
+     */
+    public function isEOF()
+    {
+        return $this->position >= $this->length;
+    }
+
+    /**
+     * @return int
+     */
+    public function getPosition()
+    {
+        return $this->position;
+    }
+
+    /**
+     * @return int
+     */
+    public function getRemainingLength()
+    {
+        return $this->length - $this->position;
+    }
+
+    /**
+     * @param int $length
+     * @param int $offset
+     *
+     * @return string
+     */
+    public function getSubstring($length, $offset = 0)
+    {
+        return substr($this->source, $this->position + $offset, $length);
+    }
+
+    /**
+     * @param string $string
+     *
+     * @return int
+     */
+    public function getOffset($string)
+    {
+        $position = strpos($this->source, $string, $this->position);
+
+        return false === $position ? false : $position - $this->position;
+    }
+
+    /**
+     * @param string $pattern
+     *
+     * @return bool
+     */
+    public function findPattern($pattern)
+    {
+        $source = substr($this->source, $this->position);
+
+        if (preg_match($pattern, $source, $matches)) {
+            return $matches;
+        }
+
+        return false;
+    }
+
+    /**
+     * @param int $length
+     */
+    public function moveForward($length)
+    {
+        $this->position += $length;
+    }
+
+    /**
+     */
+    public function moveToEnd()
+    {
+        $this->position = $this->length;
+    }
+}
diff --git a/vendor/symfony/css-selector/Symfony/Component/CssSelector/Parser/Shortcut/ClassParser.php b/vendor/symfony/css-selector/Symfony/Component/CssSelector/Parser/Shortcut/ClassParser.php
new file mode 100644
index 00000000000..bb9653ce016
--- /dev/null
+++ b/vendor/symfony/css-selector/Symfony/Component/CssSelector/Parser/Shortcut/ClassParser.php
@@ -0,0 +1,50 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\CssSelector\Parser\Shortcut;
+
+use Symfony\Component\CssSelector\Node\ClassNode;
+use Symfony\Component\CssSelector\Node\ElementNode;
+use Symfony\Component\CssSelector\Node\SelectorNode;
+use Symfony\Component\CssSelector\Parser\ParserInterface;
+
+/**
+ * CSS selector class parser shortcut.
+ *
+ * This component is a port of the Python cssselector library,
+ * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect.
+ *
+ * @author Jean-François Simon <jeanfrancois.simon@sensiolabs.com>
+ */
+class ClassParser implements ParserInterface
+{
+    /**
+     * {@inheritdoc}
+     */
+    public function parse($source)
+    {
+        // Matches an optional namespace, optional element, and required class
+        // $source = 'test|input.ab6bd_field';
+        // $matches = array (size=5)
+        //     0 => string 'test:input.ab6bd_field' (length=22)
+        //     1 => string 'test:' (length=5)
+        //     2 => string 'test' (length=4)
+        //     3 => string 'input' (length=5)
+        //     4 => string 'ab6bd_field' (length=11)
+        if (preg_match('/^(([a-z]+)\|)?([\w-]+|\*)?\.([\w-]+)$/i', trim($source), $matches)) {
+            return array(
+                new SelectorNode(new ClassNode(new ElementNode($matches[2] ?: null, $matches[3] ?: null), $matches[4])),
+            );
+        }
+
+        return array();
+    }
+}
diff --git a/vendor/symfony/css-selector/Symfony/Component/CssSelector/Parser/Shortcut/ElementParser.php b/vendor/symfony/css-selector/Symfony/Component/CssSelector/Parser/Shortcut/ElementParser.php
new file mode 100644
index 00000000000..eae18b94679
--- /dev/null
+++ b/vendor/symfony/css-selector/Symfony/Component/CssSelector/Parser/Shortcut/ElementParser.php
@@ -0,0 +1,46 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\CssSelector\Parser\Shortcut;
+
+use Symfony\Component\CssSelector\Node\ElementNode;
+use Symfony\Component\CssSelector\Node\SelectorNode;
+use Symfony\Component\CssSelector\Parser\ParserInterface;
+
+/**
+ * CSS selector element parser shortcut.
+ *
+ * This component is a port of the Python cssselector library,
+ * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect.
+ *
+ * @author Jean-François Simon <jeanfrancois.simon@sensiolabs.com>
+ */
+class ElementParser implements ParserInterface
+{
+    /**
+     * {@inheritdoc}
+     */
+    public function parse($source)
+    {
+        // Matches an optional namespace, required element or `*`
+        // $source = 'testns|testel';
+        // $matches = array (size=4)
+        //     0 => string 'testns:testel' (length=13)
+        //     1 => string 'testns:' (length=7)
+        //     2 => string 'testns' (length=6)
+        //     3 => string 'testel' (length=6)
+        if (preg_match('/^(([a-z]+)\|)?([\w-]+|\*)$/i', trim($source), $matches)) {
+            return array(new SelectorNode(new ElementNode($matches[2] ?: null, $matches[3])));
+        }
+
+        return array();
+    }
+}
diff --git a/vendor/symfony/css-selector/Symfony/Component/CssSelector/Parser/Shortcut/EmptyStringParser.php b/vendor/symfony/css-selector/Symfony/Component/CssSelector/Parser/Shortcut/EmptyStringParser.php
new file mode 100644
index 00000000000..0031f7cfef3
--- /dev/null
+++ b/vendor/symfony/css-selector/Symfony/Component/CssSelector/Parser/Shortcut/EmptyStringParser.php
@@ -0,0 +1,44 @@
+<?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\CssSelector\Parser\Shortcut;
+
+use Symfony\Component\CssSelector\Node\ElementNode;
+use Symfony\Component\CssSelector\Node\SelectorNode;
+use Symfony\Component\CssSelector\Parser\ParserInterface;
+
+/**
+ * CSS selector class parser shortcut.
+ *
+ * This shortcut ensure compatibility with previous version.
+ * - The parser fails to parse an empty string.
+ * - In the previous version, an empty string matches each tags.
+ *
+ * This component is a port of the Python cssselector library,
+ * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect.
+ *
+ * @author Jean-François Simon <jeanfrancois.simon@sensiolabs.com>
+ */
+class EmptyStringParser implements ParserInterface
+{
+    /**
+     * {@inheritdoc}
+     */
+    public function parse($source)
+    {
+        // Matches an empty string
+        if ($source == '') {
+            return array(new SelectorNode(new ElementNode(null, '*')));
+        }
+
+        return array();
+    }
+}
diff --git a/vendor/symfony/css-selector/Symfony/Component/CssSelector/Parser/Shortcut/HashParser.php b/vendor/symfony/css-selector/Symfony/Component/CssSelector/Parser/Shortcut/HashParser.php
new file mode 100644
index 00000000000..28c7d296f1b
--- /dev/null
+++ b/vendor/symfony/css-selector/Symfony/Component/CssSelector/Parser/Shortcut/HashParser.php
@@ -0,0 +1,50 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\CssSelector\Parser\Shortcut;
+
+use Symfony\Component\CssSelector\Node\ElementNode;
+use Symfony\Component\CssSelector\Node\HashNode;
+use Symfony\Component\CssSelector\Node\SelectorNode;
+use Symfony\Component\CssSelector\Parser\ParserInterface;
+
+/**
+ * CSS selector hash parser shortcut.
+ *
+ * This component is a port of the Python cssselector library,
+ * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect.
+ *
+ * @author Jean-François Simon <jeanfrancois.simon@sensiolabs.com>
+ */
+class HashParser implements ParserInterface
+{
+    /**
+     * {@inheritdoc}
+     */
+    public function parse($source)
+    {
+        // Matches an optional namespace, optional element, and required id
+        // $source = 'test|input#ab6bd_field';
+        // $matches = array (size=5)
+        //     0 => string 'test:input#ab6bd_field' (length=22)
+        //     1 => string 'test:' (length=5)
+        //     2 => string 'test' (length=4)
+        //     3 => string 'input' (length=5)
+        //     4 => string 'ab6bd_field' (length=11)
+        if (preg_match('/^(([a-z]+)\|)?([\w-]+|\*)?#([\w-]+)$/i', trim($source), $matches)) {
+            return array(
+                new SelectorNode(new HashNode(new ElementNode($matches[2] ?: null, $matches[3] ?: null), $matches[4])),
+            );
+        }
+
+        return array();
+    }
+}
diff --git a/vendor/symfony/css-selector/Symfony/Component/CssSelector/Parser/Token.php b/vendor/symfony/css-selector/Symfony/Component/CssSelector/Parser/Token.php
new file mode 100644
index 00000000000..4adfca889d8
--- /dev/null
+++ b/vendor/symfony/css-selector/Symfony/Component/CssSelector/Parser/Token.php
@@ -0,0 +1,160 @@
+<?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\CssSelector\Parser;
+
+/**
+ * CSS selector token.
+ *
+ * This component is a port of the Python cssselector library,
+ * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect.
+ *
+ * @author Jean-François Simon <jeanfrancois.simon@sensiolabs.com>
+ */
+class Token
+{
+    const TYPE_FILE_END   = 'eof';
+    const TYPE_DELIMITER  = 'delimiter';
+    const TYPE_WHITESPACE = 'whitespace';
+    const TYPE_IDENTIFIER = 'identifier';
+    const TYPE_HASH       = 'hash';
+    const TYPE_NUMBER     = 'number';
+    const TYPE_STRING     = 'string';
+
+    /**
+     * @var int
+     */
+    private $type;
+
+    /**
+     * @var string
+     */
+    private $value;
+
+    /**
+     * @var int
+     */
+    private $position;
+
+    /**
+     * @param int    $type
+     * @param string $value
+     * @param int    $position
+     */
+    public function __construct($type, $value, $position)
+    {
+        $this->type = $type;
+        $this->value = $value;
+        $this->position = $position;
+    }
+
+    /**
+     * @return int
+     */
+    public function getType()
+    {
+        return $this->type;
+    }
+
+    /**
+     * @return string
+     */
+    public function getValue()
+    {
+        return $this->value;
+    }
+
+    /**
+     * @return int
+     */
+    public function getPosition()
+    {
+        return $this->position;
+    }
+
+    /**
+     * @return bool
+     */
+    public function isFileEnd()
+    {
+        return self::TYPE_FILE_END === $this->type;
+    }
+
+    /**
+     * @param array $values
+     *
+     * @return bool
+     */
+    public function isDelimiter(array $values = array())
+    {
+        if (self::TYPE_DELIMITER !== $this->type) {
+            return false;
+        }
+
+        if (empty($values)) {
+            return true;
+        }
+
+        return in_array($this->value, $values);
+    }
+
+    /**
+     * @return bool
+     */
+    public function isWhitespace()
+    {
+        return self::TYPE_WHITESPACE === $this->type;
+    }
+
+    /**
+     * @return bool
+     */
+    public function isIdentifier()
+    {
+        return self::TYPE_IDENTIFIER === $this->type;
+    }
+
+    /**
+     * @return bool
+     */
+    public function isHash()
+    {
+        return self::TYPE_HASH === $this->type;
+    }
+
+    /**
+     * @return bool
+     */
+    public function isNumber()
+    {
+        return self::TYPE_NUMBER === $this->type;
+    }
+
+    /**
+     * @return bool
+     */
+    public function isString()
+    {
+        return self::TYPE_STRING === $this->type;
+    }
+
+    /**
+     * @return string
+     */
+    public function __toString()
+    {
+        if ($this->value) {
+            return sprintf('<%s "%s" at %s>', $this->type, $this->value, $this->position);
+        }
+
+        return sprintf('<%s at %s>', $this->type, $this->position);
+    }
+}
diff --git a/vendor/symfony/css-selector/Symfony/Component/CssSelector/Parser/TokenStream.php b/vendor/symfony/css-selector/Symfony/Component/CssSelector/Parser/TokenStream.php
new file mode 100644
index 00000000000..05d715b961a
--- /dev/null
+++ b/vendor/symfony/css-selector/Symfony/Component/CssSelector/Parser/TokenStream.php
@@ -0,0 +1,182 @@
+<?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\CssSelector\Parser;
+
+use Symfony\Component\CssSelector\Exception\InternalErrorException;
+use Symfony\Component\CssSelector\Exception\SyntaxErrorException;
+
+/**
+ * CSS selector token stream.
+ *
+ * This component is a port of the Python cssselector library,
+ * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect.
+ *
+ * @author Jean-François Simon <jeanfrancois.simon@sensiolabs.com>
+ */
+class TokenStream
+{
+    /**
+     * @var Token[]
+     */
+    private $tokens = array();
+
+    /**
+     * @var bool
+     */
+    private $frozen = false;
+
+    /**
+     * @var Token[]
+     */
+    private $used = array();
+
+    /**
+     * @var int
+     */
+    private $cursor = 0;
+
+    /**
+     * @var Token|null
+     */
+    private $peeked = null;
+
+    /**
+     * @var bool
+     */
+    private $peeking = false;
+
+    /**
+     * Pushes a token.
+     *
+     * @param Token $token
+     *
+     * @return TokenStream
+     */
+    public function push(Token $token)
+    {
+        $this->tokens[] = $token;
+
+        return $this;
+    }
+
+    /**
+     * Freezes stream.
+     *
+     * @return TokenStream
+     */
+    public function freeze()
+    {
+        $this->frozen = true;
+
+        return $this;
+    }
+
+    /**
+     * Returns next token.
+     *
+     * @throws InternalErrorException If there is no more token
+     *
+     * @return Token
+     */
+    public function getNext()
+    {
+        if ($this->peeking) {
+            $this->peeking = false;
+            $this->used[] = $this->peeked;
+
+            return $this->peeked;
+        }
+
+        if (!isset($this->tokens[$this->cursor])) {
+            throw new InternalErrorException('Unexpected token stream end.');
+        }
+
+        return $this->tokens[$this->cursor ++];
+    }
+
+    /**
+     * Returns peeked token.
+     *
+     * @return Token
+     */
+    public function getPeek()
+    {
+        if (!$this->peeking) {
+            $this->peeked = $this->getNext();
+            $this->peeking = true;
+        }
+
+        return $this->peeked;
+    }
+
+    /**
+     * Returns used tokens.
+     *
+     * @return Token[]
+     */
+    public function getUsed()
+    {
+        return $this->used;
+    }
+
+    /**
+     * Returns nex identifier token.
+     *
+     * @throws SyntaxErrorException If next token is not an identifier
+     *
+     * @return string The identifier token value
+     */
+    public function getNextIdentifier()
+    {
+        $next = $this->getNext();
+
+        if (!$next->isIdentifier()) {
+            throw SyntaxErrorException::unexpectedToken('identifier', $next);
+        }
+
+        return $next->getValue();
+    }
+
+    /**
+     * Returns nex identifier or star delimiter token.
+     *
+     * @throws SyntaxErrorException If next token is not an identifier or a star delimiter
+     *
+     * @return null|string The identifier token value or null if star found
+     */
+    public function getNextIdentifierOrStar()
+    {
+        $next = $this->getNext();
+
+        if ($next->isIdentifier()) {
+            return $next->getValue();
+        }
+
+        if ($next->isDelimiter(array('*'))) {
+            return;
+        }
+
+        throw SyntaxErrorException::unexpectedToken('identifier or "*"', $next);
+    }
+
+    /**
+     * Skips next whitespace if any.
+     */
+    public function skipWhitespace()
+    {
+        $peek = $this->getPeek();
+
+        if ($peek->isWhitespace()) {
+            $this->getNext();
+        }
+    }
+}
diff --git a/vendor/symfony/css-selector/Symfony/Component/CssSelector/Parser/Tokenizer/Tokenizer.php b/vendor/symfony/css-selector/Symfony/Component/CssSelector/Parser/Tokenizer/Tokenizer.php
new file mode 100644
index 00000000000..c850276728c
--- /dev/null
+++ b/vendor/symfony/css-selector/Symfony/Component/CssSelector/Parser/Tokenizer/Tokenizer.php
@@ -0,0 +1,78 @@
+<?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\CssSelector\Parser\Tokenizer;
+
+use Symfony\Component\CssSelector\Parser\Handler;
+use Symfony\Component\CssSelector\Parser\Reader;
+use Symfony\Component\CssSelector\Parser\Token;
+use Symfony\Component\CssSelector\Parser\TokenStream;
+
+/**
+ * CSS selector tokenizer.
+ *
+ * This component is a port of the Python cssselector library,
+ * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect.
+ *
+ * @author Jean-François Simon <jeanfrancois.simon@sensiolabs.com>
+ */
+class Tokenizer
+{
+    /**
+     * @var Handler\HandlerInterface[]
+     */
+    private $handlers;
+
+    /**
+     * Constructor.
+     */
+    public function __construct()
+    {
+        $patterns = new TokenizerPatterns();
+        $escaping = new TokenizerEscaping($patterns);
+
+        $this->handlers = array(
+            new Handler\WhitespaceHandler(),
+            new Handler\IdentifierHandler($patterns, $escaping),
+            new Handler\HashHandler($patterns, $escaping),
+            new Handler\StringHandler($patterns, $escaping),
+            new Handler\NumberHandler($patterns),
+            new Handler\CommentHandler(),
+        );
+    }
+
+    /**
+     * Tokenize selector source code.
+     *
+     * @param Reader $reader
+     *
+     * @return TokenStream
+     */
+    public function tokenize(Reader $reader)
+    {
+        $stream = new TokenStream();
+
+        while (!$reader->isEOF()) {
+            foreach ($this->handlers as $handler) {
+                if ($handler->handle($reader, $stream)) {
+                    continue 2;
+                }
+            }
+
+            $stream->push(new Token(Token::TYPE_DELIMITER, $reader->getSubstring(1), $reader->getPosition()));
+            $reader->moveForward(1);
+        }
+
+        return $stream
+            ->push(new Token(Token::TYPE_FILE_END, null, $reader->getPosition()))
+            ->freeze();
+    }
+}
diff --git a/vendor/symfony/css-selector/Symfony/Component/CssSelector/Parser/Tokenizer/TokenizerEscaping.php b/vendor/symfony/css-selector/Symfony/Component/CssSelector/Parser/Tokenizer/TokenizerEscaping.php
new file mode 100644
index 00000000000..76386c93714
--- /dev/null
+++ b/vendor/symfony/css-selector/Symfony/Component/CssSelector/Parser/Tokenizer/TokenizerEscaping.php
@@ -0,0 +1,82 @@
+<?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\CssSelector\Parser\Tokenizer;
+
+/**
+ * CSS selector tokenizer escaping applier.
+ *
+ * This component is a port of the Python cssselector library,
+ * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect.
+ *
+ * @author Jean-François Simon <jeanfrancois.simon@sensiolabs.com>
+ */
+class TokenizerEscaping
+{
+    /**
+     * @var TokenizerPatterns
+     */
+    private $patterns;
+
+    /**
+     * @param TokenizerPatterns $patterns
+     */
+    public function __construct(TokenizerPatterns $patterns)
+    {
+        $this->patterns = $patterns;
+    }
+
+    /**
+     * @param string $value
+     *
+     * @return string
+     */
+    public function escapeUnicode($value)
+    {
+        $value = $this->replaceUnicodeSequences($value);
+
+        return preg_replace($this->patterns->getSimpleEscapePattern(), '$1', $value);
+    }
+
+    /**
+     * @param string $value
+     *
+     * @return string
+     */
+    public function escapeUnicodeAndNewLine($value)
+    {
+        $value = preg_replace($this->patterns->getNewLineEscapePattern(), '', $value);
+
+        return $this->escapeUnicode($value);
+    }
+
+    /**
+     * @param string $value
+     *
+     * @return string
+     */
+    private function replaceUnicodeSequences($value)
+    {
+        return preg_replace_callback($this->patterns->getUnicodeEscapePattern(), function ($match) {
+            $c = hexdec($match[1]);
+
+            if (0x80 > $c %= 0x200000) {
+                return chr($c);
+            }
+            if (0x800 > $c) {
+                return chr(0xC0 | $c >> 6).chr(0x80 | $c & 0x3F);
+            }
+            if (0x10000 > $c) {
+                return chr(0xE0 | $c >> 12).chr(0x80 | $c >> 6 & 0x3F).chr(0x80 | $c & 0x3F);
+            }
+        }, $value);
+    }
+}
diff --git a/vendor/symfony/css-selector/Symfony/Component/CssSelector/Parser/Tokenizer/TokenizerPatterns.php b/vendor/symfony/css-selector/Symfony/Component/CssSelector/Parser/Tokenizer/TokenizerPatterns.php
new file mode 100644
index 00000000000..6fc98b71e12
--- /dev/null
+++ b/vendor/symfony/css-selector/Symfony/Component/CssSelector/Parser/Tokenizer/TokenizerPatterns.php
@@ -0,0 +1,160 @@
+<?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\CssSelector\Parser\Tokenizer;
+
+/**
+ * CSS selector tokenizer patterns builder.
+ *
+ * This component is a port of the Python cssselector library,
+ * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect.
+ *
+ * @author Jean-François Simon <jeanfrancois.simon@sensiolabs.com>
+ */
+class TokenizerPatterns
+{
+    /**
+     * @var string
+     */
+    private $unicodeEscapePattern;
+
+    /**
+     * @var string
+     */
+    private $simpleEscapePattern;
+
+    /**
+     * @var string
+     */
+    private $newLineEscapePattern;
+
+    /**
+     * @var string
+     */
+    private $escapePattern;
+
+    /**
+     * @var string
+     */
+    private $stringEscapePattern;
+
+    /**
+     * @var string
+     */
+    private $nonAsciiPattern;
+
+    /**
+     * @var string
+     */
+    private $nmCharPattern;
+
+    /**
+     * @var string
+     */
+    private $nmStartPattern;
+
+    /**
+     * @var string
+     */
+    private $identifierPattern;
+
+    /**
+     * @var string
+     */
+    private $hashPattern;
+
+    /**
+     * @var string
+     */
+    private $numberPattern;
+
+    /**
+     * @var string
+     */
+    private $quotedStringPattern;
+
+    /**
+     * Constructor.
+     */
+    public function __construct()
+    {
+        $this->unicodeEscapePattern = '\\\\([0-9a-f]{1,6})(?:\r\n|[ \n\r\t\f])?';
+        $this->simpleEscapePattern = '\\\\(.)';
+        $this->newLineEscapePattern = '\\\\(?:\n|\r\n|\r|\f)';
+        $this->escapePattern = $this->unicodeEscapePattern.'|\\\\[^\n\r\f0-9a-f]';
+        $this->stringEscapePattern = $this->newLineEscapePattern.'|'.$this->escapePattern;
+        $this->nonAsciiPattern = '[^\x00-\x7F]';
+        $this->nmCharPattern = '[_a-z0-9-]|'.$this->escapePattern.'|'.$this->nonAsciiPattern;
+        $this->nmStartPattern = '[_a-z]|'.$this->escapePattern.'|'.$this->nonAsciiPattern;
+        $this->identifierPattern = '(?:'.$this->nmStartPattern.')(?:'.$this->nmCharPattern.')*';
+        $this->hashPattern = '#((?:'.$this->nmCharPattern.')+)';
+        $this->numberPattern = '[+-]?(?:[0-9]*\.[0-9]+|[0-9]+)';
+        $this->quotedStringPattern = '([^\n\r\f%s]|'.$this->stringEscapePattern.')*';
+    }
+
+    /**
+     * @return string
+     */
+    public function getNewLineEscapePattern()
+    {
+        return '~^'.$this->newLineEscapePattern.'~';
+    }
+
+    /**
+     * @return string
+     */
+    public function getSimpleEscapePattern()
+    {
+        return '~^'.$this->simpleEscapePattern.'~';
+    }
+
+    /**
+     * @return string
+     */
+    public function getUnicodeEscapePattern()
+    {
+        return '~^'.$this->unicodeEscapePattern.'~i';
+    }
+
+    /**
+     * @return string
+     */
+    public function getIdentifierPattern()
+    {
+        return '~^'.$this->identifierPattern.'~i';
+    }
+
+    /**
+     * @return string
+     */
+    public function getHashPattern()
+    {
+        return '~^'.$this->hashPattern.'~i';
+    }
+
+    /**
+     * @return string
+     */
+    public function getNumberPattern()
+    {
+        return '~^'.$this->numberPattern.'~';
+    }
+
+    /**
+     * @param string $quote
+     *
+     * @return string
+     */
+    public function getQuotedStringPattern($quote)
+    {
+        return '~^'.sprintf($this->quotedStringPattern, $quote).'~i';
+    }
+}
diff --git a/vendor/symfony/css-selector/Symfony/Component/CssSelector/README.md b/vendor/symfony/css-selector/Symfony/Component/CssSelector/README.md
new file mode 100644
index 00000000000..e0212b1570c
--- /dev/null
+++ b/vendor/symfony/css-selector/Symfony/Component/CssSelector/README.md
@@ -0,0 +1,48 @@
+CssSelector Component
+=====================
+
+CssSelector converts CSS selectors to XPath expressions.
+
+The component only goal is to convert CSS selectors to their XPath
+equivalents:
+
+```php
+use Symfony\Component\CssSelector\CssSelector;
+
+print CssSelector::toXPath('div.item > h4 > a');
+```
+
+HTML and XML are different
+--------------------------
+
+The `CssSelector` component comes with an `HTML` extension which is enabled by
+default. If you need to use this component with `XML` documents, you have to
+disable this `HTML` extension. That's because, `HTML` tag & attribute names
+are always lower-cased, but case-sensitive in `XML`:
+
+```php
+// disable `HTML` extension:
+CssSelector::disableHtmlExtension();
+
+// re-enable `HTML` extension:
+CssSelector::enableHtmlExtension();
+```
+
+When the `HTML` extension is enabled, tag names are lower-cased, attribute
+names are lower-cased, the following extra pseudo-classes are supported:
+`checked`, `link`, `disabled`, `enabled`, `selected`, `invalid`, `hover`,
+`visited`, and the `lang()` function is also added.
+
+Resources
+---------
+
+This component is a port of the Python lxml library, which is copyright Infrae
+and distributed under the BSD license.
+
+Current code is a port of https://github.com/SimonSapin/cssselect/releases/tag/v0.7.1
+
+You can run the unit tests with the following command:
+
+    $ cd path/to/Symfony/Component/CssSelector/
+    $ composer.phar install
+    $ phpunit
diff --git a/vendor/symfony/css-selector/Symfony/Component/CssSelector/Tests/CssSelectorTest.php b/vendor/symfony/css-selector/Symfony/Component/CssSelector/Tests/CssSelectorTest.php
new file mode 100644
index 00000000000..50daeccd1d2
--- /dev/null
+++ b/vendor/symfony/css-selector/Symfony/Component/CssSelector/Tests/CssSelectorTest.php
@@ -0,0 +1,64 @@
+<?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\CssSelector\Tests;
+
+use Symfony\Component\CssSelector\CssSelector;
+
+class CssSelectorTest extends \PHPUnit_Framework_TestCase
+{
+    public function testCssToXPath()
+    {
+        $this->assertEquals('descendant-or-self::*', CssSelector::toXPath(''));
+        $this->assertEquals('descendant-or-self::h1', CssSelector::toXPath('h1'));
+        $this->assertEquals("descendant-or-self::h1[@id = 'foo']", CssSelector::toXPath('h1#foo'));
+        $this->assertEquals("descendant-or-self::h1[@class and contains(concat(' ', normalize-space(@class), ' '), ' foo ')]", CssSelector::toXPath('h1.foo'));
+        $this->assertEquals('descendant-or-self::foo:h1', CssSelector::toXPath('foo|h1'));
+    }
+
+    /** @dataProvider getCssToXPathWithoutPrefixTestData */
+    public function testCssToXPathWithoutPrefix($css, $xpath)
+    {
+        $this->assertEquals($xpath, CssSelector::toXPath($css, ''), '->parse() parses an input string and returns a node');
+    }
+
+    public function testParseExceptions()
+    {
+        try {
+            CssSelector::toXPath('h1:');
+            $this->fail('->parse() throws an Exception if the css selector is not valid');
+        } catch (\Exception $e) {
+            $this->assertInstanceOf('\Symfony\Component\CssSelector\Exception\ParseException', $e, '->parse() throws an Exception if the css selector is not valid');
+            $this->assertEquals("Expected identifier, but <eof at 3> found.", $e->getMessage(), '->parse() throws an Exception if the css selector is not valid');
+        }
+    }
+
+    public function getCssToXPathWithoutPrefixTestData()
+    {
+        return array(
+            array('h1', "h1"),
+            array('foo|h1', "foo:h1"),
+            array('h1, h2, h3', "h1 | h2 | h3"),
+            array('h1:nth-child(3n+1)', "*/*[name() = 'h1' and (position() - 1 >= 0 and (position() - 1) mod 3 = 0)]"),
+            array('h1 > p', "h1/p"),
+            array('h1#foo', "h1[@id = 'foo']"),
+            array('h1.foo', "h1[@class and contains(concat(' ', normalize-space(@class), ' '), ' foo ')]"),
+            array('h1[class*="foo bar"]', "h1[@class and contains(@class, 'foo bar')]"),
+            array('h1[foo|class*="foo bar"]', "h1[@foo:class and contains(@foo:class, 'foo bar')]"),
+            array('h1[class]', "h1[@class]"),
+            array('h1 .foo', "h1/descendant-or-self::*/*[@class and contains(concat(' ', normalize-space(@class), ' '), ' foo ')]"),
+            array('h1 #foo', "h1/descendant-or-self::*/*[@id = 'foo']"),
+            array('h1 [class*=foo]', "h1/descendant-or-self::*/*[@class and contains(@class, 'foo')]"),
+            array('div>.foo', "div/*[@class and contains(concat(' ', normalize-space(@class), ' '), ' foo ')]"),
+            array('div > .foo', "div/*[@class and contains(concat(' ', normalize-space(@class), ' '), ' foo ')]"),
+        );
+    }
+}
diff --git a/vendor/symfony/css-selector/Symfony/Component/CssSelector/Tests/Node/AbstractNodeTest.php b/vendor/symfony/css-selector/Symfony/Component/CssSelector/Tests/Node/AbstractNodeTest.php
new file mode 100644
index 00000000000..16a3a34d649
--- /dev/null
+++ b/vendor/symfony/css-selector/Symfony/Component/CssSelector/Tests/Node/AbstractNodeTest.php
@@ -0,0 +1,32 @@
+<?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\CssSelector\Tests\Node;
+
+use Symfony\Component\CssSelector\Node\NodeInterface;
+
+abstract class AbstractNodeTest extends \PHPUnit_Framework_TestCase
+{
+    /** @dataProvider getToStringConversionTestData */
+    public function testToStringConversion(NodeInterface $node, $representation)
+    {
+        $this->assertEquals($representation, (string) $node);
+    }
+
+    /** @dataProvider getSpecificityValueTestData */
+    public function testSpecificityValue(NodeInterface $node, $value)
+    {
+        $this->assertEquals($value, $node->getSpecificity()->getValue());
+    }
+
+    abstract public function getToStringConversionTestData();
+    abstract public function getSpecificityValueTestData();
+}
diff --git a/vendor/symfony/css-selector/Symfony/Component/CssSelector/Tests/Node/AttributeNodeTest.php b/vendor/symfony/css-selector/Symfony/Component/CssSelector/Tests/Node/AttributeNodeTest.php
new file mode 100644
index 00000000000..1fd090f5a6e
--- /dev/null
+++ b/vendor/symfony/css-selector/Symfony/Component/CssSelector/Tests/Node/AttributeNodeTest.php
@@ -0,0 +1,37 @@
+<?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\CssSelector\Tests\Node;
+
+use Symfony\Component\CssSelector\Node\AttributeNode;
+use Symfony\Component\CssSelector\Node\ElementNode;
+
+class AttributeNodeTest extends AbstractNodeTest
+{
+    public function getToStringConversionTestData()
+    {
+        return array(
+            array(new AttributeNode(new ElementNode(), null, 'attribute', 'exists', null), 'Attribute[Element[*][attribute]]'),
+            array(new AttributeNode(new ElementNode(), null, 'attribute', '$=', 'value'), "Attribute[Element[*][attribute $= 'value']]"),
+            array(new AttributeNode(new ElementNode(), 'namespace', 'attribute', '$=', 'value'), "Attribute[Element[*][namespace|attribute $= 'value']]"),
+        );
+    }
+
+    public function getSpecificityValueTestData()
+    {
+        return array(
+            array(new AttributeNode(new ElementNode(), null, 'attribute', 'exists', null), 10),
+            array(new AttributeNode(new ElementNode(null, 'element'), null, 'attribute', 'exists', null), 11),
+            array(new AttributeNode(new ElementNode(), null, 'attribute', '$=', 'value'), 10),
+            array(new AttributeNode(new ElementNode(), 'namespace', 'attribute', '$=', 'value'), 10),
+        );
+    }
+}
diff --git a/vendor/symfony/css-selector/Symfony/Component/CssSelector/Tests/Node/ClassNodeTest.php b/vendor/symfony/css-selector/Symfony/Component/CssSelector/Tests/Node/ClassNodeTest.php
new file mode 100644
index 00000000000..e0ab45accc3
--- /dev/null
+++ b/vendor/symfony/css-selector/Symfony/Component/CssSelector/Tests/Node/ClassNodeTest.php
@@ -0,0 +1,33 @@
+<?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\CssSelector\Tests\Node;
+
+use Symfony\Component\CssSelector\Node\ClassNode;
+use Symfony\Component\CssSelector\Node\ElementNode;
+
+class ClassNodeTest extends AbstractNodeTest
+{
+    public function getToStringConversionTestData()
+    {
+        return array(
+            array(new ClassNode(new ElementNode(), 'class'), 'Class[Element[*].class]'),
+        );
+    }
+
+    public function getSpecificityValueTestData()
+    {
+        return array(
+            array(new ClassNode(new ElementNode(), 'class'), 10),
+            array(new ClassNode(new ElementNode(null, 'element'), 'class'), 11),
+        );
+    }
+}
diff --git a/vendor/symfony/css-selector/Symfony/Component/CssSelector/Tests/Node/CombinedSelectorNodeTest.php b/vendor/symfony/css-selector/Symfony/Component/CssSelector/Tests/Node/CombinedSelectorNodeTest.php
new file mode 100644
index 00000000000..9547298a6fd
--- /dev/null
+++ b/vendor/symfony/css-selector/Symfony/Component/CssSelector/Tests/Node/CombinedSelectorNodeTest.php
@@ -0,0 +1,35 @@
+<?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\CssSelector\Tests\Node;
+
+use Symfony\Component\CssSelector\Node\CombinedSelectorNode;
+use Symfony\Component\CssSelector\Node\ElementNode;
+
+class CombinedSelectorNodeTest extends AbstractNodeTest
+{
+    public function getToStringConversionTestData()
+    {
+        return array(
+            array(new CombinedSelectorNode(new ElementNode(), '>', new ElementNode()), 'CombinedSelector[Element[*] > Element[*]]'),
+            array(new CombinedSelectorNode(new ElementNode(), ' ', new ElementNode()), 'CombinedSelector[Element[*] <followed> Element[*]]'),
+        );
+    }
+
+    public function getSpecificityValueTestData()
+    {
+        return array(
+            array(new CombinedSelectorNode(new ElementNode(), '>', new ElementNode()), 0),
+            array(new CombinedSelectorNode(new ElementNode(null, 'element'), '>', new ElementNode()), 1),
+            array(new CombinedSelectorNode(new ElementNode(null, 'element'), '>', new ElementNode(null, 'element')), 2),
+        );
+    }
+}
diff --git a/vendor/symfony/css-selector/Symfony/Component/CssSelector/Tests/Node/ElementNodeTest.php b/vendor/symfony/css-selector/Symfony/Component/CssSelector/Tests/Node/ElementNodeTest.php
new file mode 100644
index 00000000000..1db6a591a2f
--- /dev/null
+++ b/vendor/symfony/css-selector/Symfony/Component/CssSelector/Tests/Node/ElementNodeTest.php
@@ -0,0 +1,35 @@
+<?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\CssSelector\Tests\Node;
+
+use Symfony\Component\CssSelector\Node\ElementNode;
+
+class ElementNodeTest extends AbstractNodeTest
+{
+    public function getToStringConversionTestData()
+    {
+        return array(
+            array(new ElementNode(), 'Element[*]'),
+            array(new ElementNode(null, 'element'), 'Element[element]'),
+            array(new ElementNode('namespace', 'element'), 'Element[namespace|element]'),
+        );
+    }
+
+    public function getSpecificityValueTestData()
+    {
+        return array(
+            array(new ElementNode(), 0),
+            array(new ElementNode(null, 'element'), 1),
+            array(new ElementNode('namespace', 'element'),1),
+        );
+    }
+}
diff --git a/vendor/symfony/css-selector/Symfony/Component/CssSelector/Tests/Node/FunctionNodeTest.php b/vendor/symfony/css-selector/Symfony/Component/CssSelector/Tests/Node/FunctionNodeTest.php
new file mode 100644
index 00000000000..ee3ce51ba54
--- /dev/null
+++ b/vendor/symfony/css-selector/Symfony/Component/CssSelector/Tests/Node/FunctionNodeTest.php
@@ -0,0 +1,47 @@
+<?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\CssSelector\Tests\Node;
+
+use Symfony\Component\CssSelector\Node\ElementNode;
+use Symfony\Component\CssSelector\Node\FunctionNode;
+use Symfony\Component\CssSelector\Parser\Token;
+
+class FunctionNodeTest extends AbstractNodeTest
+{
+    public function getToStringConversionTestData()
+    {
+        return array(
+            array(new FunctionNode(new ElementNode(), 'function'), 'Function[Element[*]:function()]'),
+            array(new FunctionNode(new ElementNode(), 'function', array(
+                new Token(Token::TYPE_IDENTIFIER, 'value', 0),
+            )), "Function[Element[*]:function(['value'])]"),
+            array(new FunctionNode(new ElementNode(), 'function', array(
+                new Token(Token::TYPE_STRING, 'value1', 0),
+                new Token(Token::TYPE_NUMBER, 'value2', 0),
+            )), "Function[Element[*]:function(['value1', 'value2'])]"),
+        );
+    }
+
+    public function getSpecificityValueTestData()
+    {
+        return array(
+            array(new FunctionNode(new ElementNode(), 'function'), 10),
+            array(new FunctionNode(new ElementNode(), 'function', array(
+                new Token(Token::TYPE_IDENTIFIER, 'value', 0),
+            )), 10),
+            array(new FunctionNode(new ElementNode(), 'function', array(
+                new Token(Token::TYPE_STRING, 'value1', 0),
+                new Token(Token::TYPE_NUMBER, 'value2', 0),
+            )), 10),
+        );
+    }
+}
diff --git a/vendor/symfony/css-selector/Symfony/Component/CssSelector/Tests/Node/HashNodeTest.php b/vendor/symfony/css-selector/Symfony/Component/CssSelector/Tests/Node/HashNodeTest.php
new file mode 100644
index 00000000000..8554b226d6c
--- /dev/null
+++ b/vendor/symfony/css-selector/Symfony/Component/CssSelector/Tests/Node/HashNodeTest.php
@@ -0,0 +1,33 @@
+<?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\CssSelector\Tests\Node;
+
+use Symfony\Component\CssSelector\Node\HashNode;
+use Symfony\Component\CssSelector\Node\ElementNode;
+
+class HashNodeTest extends AbstractNodeTest
+{
+    public function getToStringConversionTestData()
+    {
+        return array(
+            array(new HashNode(new ElementNode(), 'id'), 'Hash[Element[*]#id]'),
+        );
+    }
+
+    public function getSpecificityValueTestData()
+    {
+        return array(
+            array(new HashNode(new ElementNode(), 'id'), 100),
+            array(new HashNode(new ElementNode(null, 'id'), 'class'), 101),
+        );
+    }
+}
diff --git a/vendor/symfony/css-selector/Symfony/Component/CssSelector/Tests/Node/NegationNodeTest.php b/vendor/symfony/css-selector/Symfony/Component/CssSelector/Tests/Node/NegationNodeTest.php
new file mode 100644
index 00000000000..edf4552bac8
--- /dev/null
+++ b/vendor/symfony/css-selector/Symfony/Component/CssSelector/Tests/Node/NegationNodeTest.php
@@ -0,0 +1,33 @@
+<?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\CssSelector\Tests\Node;
+
+use Symfony\Component\CssSelector\Node\ClassNode;
+use Symfony\Component\CssSelector\Node\NegationNode;
+use Symfony\Component\CssSelector\Node\ElementNode;
+
+class NegationNodeTest extends AbstractNodeTest
+{
+    public function getToStringConversionTestData()
+    {
+        return array(
+            array(new NegationNode(new ElementNode(), new ClassNode(new ElementNode(), 'class')), 'Negation[Element[*]:not(Class[Element[*].class])]'),
+        );
+    }
+
+    public function getSpecificityValueTestData()
+    {
+        return array(
+            array(new NegationNode(new ElementNode(), new ClassNode(new ElementNode(), 'class')), 10),
+        );
+    }
+}
diff --git a/vendor/symfony/css-selector/Symfony/Component/CssSelector/Tests/Node/PseudoNodeTest.php b/vendor/symfony/css-selector/Symfony/Component/CssSelector/Tests/Node/PseudoNodeTest.php
new file mode 100644
index 00000000000..bc57813cc8f
--- /dev/null
+++ b/vendor/symfony/css-selector/Symfony/Component/CssSelector/Tests/Node/PseudoNodeTest.php
@@ -0,0 +1,32 @@
+<?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\CssSelector\Tests\Node;
+
+use Symfony\Component\CssSelector\Node\ElementNode;
+use Symfony\Component\CssSelector\Node\PseudoNode;
+
+class PseudoNodeTest extends AbstractNodeTest
+{
+    public function getToStringConversionTestData()
+    {
+        return array(
+            array(new PseudoNode(new ElementNode(), 'pseudo'), 'Pseudo[Element[*]:pseudo]'),
+        );
+    }
+
+    public function getSpecificityValueTestData()
+    {
+        return array(
+            array(new PseudoNode(new ElementNode(), 'pseudo'), 10),
+        );
+    }
+}
diff --git a/vendor/symfony/css-selector/Symfony/Component/CssSelector/Tests/Node/SelectorNodeTest.php b/vendor/symfony/css-selector/Symfony/Component/CssSelector/Tests/Node/SelectorNodeTest.php
new file mode 100644
index 00000000000..5badf71d16d
--- /dev/null
+++ b/vendor/symfony/css-selector/Symfony/Component/CssSelector/Tests/Node/SelectorNodeTest.php
@@ -0,0 +1,34 @@
+<?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\CssSelector\Tests\Node;
+
+use Symfony\Component\CssSelector\Node\ElementNode;
+use Symfony\Component\CssSelector\Node\SelectorNode;
+
+class SelectorNodeTest extends AbstractNodeTest
+{
+    public function getToStringConversionTestData()
+    {
+        return array(
+            array(new SelectorNode(new ElementNode()), 'Selector[Element[*]]'),
+            array(new SelectorNode(new ElementNode(), 'pseudo'), 'Selector[Element[*]::pseudo]'),
+        );
+    }
+
+    public function getSpecificityValueTestData()
+    {
+        return array(
+            array(new SelectorNode(new ElementNode()), 0),
+            array(new SelectorNode(new ElementNode(), 'pseudo'), 1),
+        );
+    }
+}
diff --git a/vendor/symfony/css-selector/Symfony/Component/CssSelector/Tests/Node/SpecificityTest.php b/vendor/symfony/css-selector/Symfony/Component/CssSelector/Tests/Node/SpecificityTest.php
new file mode 100644
index 00000000000..1f200cffe4f
--- /dev/null
+++ b/vendor/symfony/css-selector/Symfony/Component/CssSelector/Tests/Node/SpecificityTest.php
@@ -0,0 +1,40 @@
+<?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\CssSelector\Tests\Node;
+
+use Symfony\Component\CssSelector\Node\Specificity;
+
+class SpecificityTest extends \PHPUnit_Framework_TestCase
+{
+    /** @dataProvider getValueTestData */
+    public function testValue(Specificity $specificity, $value)
+    {
+        $this->assertEquals($value, $specificity->getValue());
+    }
+
+    /** @dataProvider getValueTestData */
+    public function testPlusValue(Specificity $specificity, $value)
+    {
+        $this->assertEquals($value + 123, $specificity->plus(new Specificity(1, 2, 3))->getValue());
+    }
+
+    public function getValueTestData()
+    {
+        return array(
+            array(new Specificity(0, 0, 0), 0),
+            array(new Specificity(0, 0, 2), 2),
+            array(new Specificity(0, 3, 0), 30),
+            array(new Specificity(4, 0, 0), 400),
+            array(new Specificity(4, 3, 2), 432),
+        );
+    }
+}
diff --git a/vendor/symfony/css-selector/Symfony/Component/CssSelector/Tests/Parser/Handler/AbstractHandlerTest.php b/vendor/symfony/css-selector/Symfony/Component/CssSelector/Tests/Parser/Handler/AbstractHandlerTest.php
new file mode 100644
index 00000000000..a06dca013ba
--- /dev/null
+++ b/vendor/symfony/css-selector/Symfony/Component/CssSelector/Tests/Parser/Handler/AbstractHandlerTest.php
@@ -0,0 +1,67 @@
+<?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\CssSelector\Tests\Parser\Handler;
+
+use Symfony\Component\CssSelector\Parser\Reader;
+use Symfony\Component\CssSelector\Parser\Token;
+use Symfony\Component\CssSelector\Parser\TokenStream;
+
+/**
+ * @author Jean-François Simon <contact@jfsimon.fr>
+ */
+abstract class AbstractHandlerTest extends \PHPUnit_Framework_TestCase
+{
+    /** @dataProvider getHandleValueTestData */
+    public function testHandleValue($value, Token $expectedToken, $remainingContent)
+    {
+        $reader = new Reader($value);
+        $stream = new TokenStream();
+
+        $this->assertTrue($this->generateHandler()->handle($reader, $stream));
+        $this->assertEquals($expectedToken, $stream->getNext());
+        $this->assertRemainingContent($reader, $remainingContent);
+    }
+
+    /** @dataProvider getDontHandleValueTestData */
+    public function testDontHandleValue($value)
+    {
+        $reader = new Reader($value);
+        $stream = new TokenStream();
+
+        $this->assertFalse($this->generateHandler()->handle($reader, $stream));
+        $this->assertStreamEmpty($stream);
+        $this->assertRemainingContent($reader, $value);
+    }
+
+    abstract public function getHandleValueTestData();
+    abstract public function getDontHandleValueTestData();
+    abstract protected function generateHandler();
+
+    protected function assertStreamEmpty(TokenStream $stream)
+    {
+        $property = new \ReflectionProperty($stream, 'tokens');
+        $property->setAccessible(true);
+
+        $this->assertEquals(array(), $property->getValue($stream));
+    }
+
+    protected function assertRemainingContent(Reader $reader, $remainingContent)
+    {
+        if ('' === $remainingContent) {
+            $this->assertEquals(0, $reader->getRemainingLength());
+            $this->assertTrue($reader->isEOF());
+        } else {
+            $this->assertEquals(strlen($remainingContent), $reader->getRemainingLength());
+            $this->assertEquals(0, $reader->getOffset($remainingContent));
+        }
+    }
+}
diff --git a/vendor/symfony/css-selector/Symfony/Component/CssSelector/Tests/Parser/Handler/CommentHandlerTest.php b/vendor/symfony/css-selector/Symfony/Component/CssSelector/Tests/Parser/Handler/CommentHandlerTest.php
new file mode 100644
index 00000000000..3961bf7d55a
--- /dev/null
+++ b/vendor/symfony/css-selector/Symfony/Component/CssSelector/Tests/Parser/Handler/CommentHandlerTest.php
@@ -0,0 +1,55 @@
+<?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\CssSelector\Tests\Parser\Handler;
+
+use Symfony\Component\CssSelector\Parser\Handler\CommentHandler;
+use Symfony\Component\CssSelector\Parser\Reader;
+use Symfony\Component\CssSelector\Parser\Token;
+use Symfony\Component\CssSelector\Parser\TokenStream;
+
+class CommentHandlerTest extends AbstractHandlerTest
+{
+    /** @dataProvider getHandleValueTestData */
+    public function testHandleValue($value, Token $unusedArgument, $remainingContent)
+    {
+        $reader = new Reader($value);
+        $stream = new TokenStream();
+
+        $this->assertTrue($this->generateHandler()->handle($reader, $stream));
+        // comments are ignored (not pushed as token in stream)
+        $this->assertStreamEmpty($stream);
+        $this->assertRemainingContent($reader, $remainingContent);
+    }
+
+    public function getHandleValueTestData()
+    {
+        return array(
+            // 2nd argument only exists for inherited method compatibility
+            array('/* comment */', new Token(null, null, null), ''),
+            array('/* comment */foo', new Token(null, null, null), 'foo'),
+        );
+    }
+
+    public function getDontHandleValueTestData()
+    {
+        return array(
+            array('>'),
+            array('+'),
+            array(' '),
+        );
+    }
+
+    protected function generateHandler()
+    {
+        return new CommentHandler();
+    }
+}
diff --git a/vendor/symfony/css-selector/Symfony/Component/CssSelector/Tests/Parser/Handler/HashHandlerTest.php b/vendor/symfony/css-selector/Symfony/Component/CssSelector/Tests/Parser/Handler/HashHandlerTest.php
new file mode 100644
index 00000000000..b7fa00a2255
--- /dev/null
+++ b/vendor/symfony/css-selector/Symfony/Component/CssSelector/Tests/Parser/Handler/HashHandlerTest.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\CssSelector\Tests\Parser\Handler;
+
+use Symfony\Component\CssSelector\Parser\Handler\HashHandler;
+use Symfony\Component\CssSelector\Parser\Token;
+use Symfony\Component\CssSelector\Parser\Tokenizer\TokenizerPatterns;
+use Symfony\Component\CssSelector\Parser\Tokenizer\TokenizerEscaping;
+
+class HashHandlerTest extends AbstractHandlerTest
+{
+    public function getHandleValueTestData()
+    {
+        return array(
+            array('#id', new Token(Token::TYPE_HASH, 'id', 0), ''),
+            array('#123', new Token(Token::TYPE_HASH, '123', 0), ''),
+
+            array('#id.class', new Token(Token::TYPE_HASH, 'id', 0), '.class'),
+            array('#id element', new Token(Token::TYPE_HASH, 'id', 0), ' element'),
+        );
+    }
+
+    public function getDontHandleValueTestData()
+    {
+        return array(
+            array('id'),
+            array('123'),
+            array('<'),
+            array('<'),
+            array('#'),
+        );
+    }
+
+    protected function generateHandler()
+    {
+        $patterns = new TokenizerPatterns();
+
+        return new HashHandler($patterns, new TokenizerEscaping($patterns));
+    }
+}
diff --git a/vendor/symfony/css-selector/Symfony/Component/CssSelector/Tests/Parser/Handler/IdentifierHandlerTest.php b/vendor/symfony/css-selector/Symfony/Component/CssSelector/Tests/Parser/Handler/IdentifierHandlerTest.php
new file mode 100644
index 00000000000..44d35749845
--- /dev/null
+++ b/vendor/symfony/css-selector/Symfony/Component/CssSelector/Tests/Parser/Handler/IdentifierHandlerTest.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\CssSelector\Tests\Parser\Handler;
+
+use Symfony\Component\CssSelector\Parser\Handler\IdentifierHandler;
+use Symfony\Component\CssSelector\Parser\Token;
+use Symfony\Component\CssSelector\Parser\Tokenizer\TokenizerPatterns;
+use Symfony\Component\CssSelector\Parser\Tokenizer\TokenizerEscaping;
+
+class IdentifierHandlerTest extends AbstractHandlerTest
+{
+    public function getHandleValueTestData()
+    {
+        return array(
+            array('foo', new Token(Token::TYPE_IDENTIFIER, 'foo', 0), ''),
+            array('foo|bar', new Token(Token::TYPE_IDENTIFIER, 'foo', 0), '|bar'),
+            array('foo.class', new Token(Token::TYPE_IDENTIFIER, 'foo', 0), '.class'),
+            array('foo[attr]', new Token(Token::TYPE_IDENTIFIER, 'foo', 0), '[attr]'),
+            array('foo bar', new Token(Token::TYPE_IDENTIFIER, 'foo', 0), ' bar'),
+        );
+    }
+
+    public function getDontHandleValueTestData()
+    {
+        return array(
+            array('>'),
+            array('+'),
+            array(' '),
+            array('*|foo'),
+            array('/* comment */'),
+        );
+    }
+
+    protected function generateHandler()
+    {
+        $patterns = new TokenizerPatterns();
+
+        return new IdentifierHandler($patterns, new TokenizerEscaping($patterns));
+    }
+}
diff --git a/vendor/symfony/css-selector/Symfony/Component/CssSelector/Tests/Parser/Handler/NumberHandlerTest.php b/vendor/symfony/css-selector/Symfony/Component/CssSelector/Tests/Parser/Handler/NumberHandlerTest.php
new file mode 100644
index 00000000000..675fd05b43e
--- /dev/null
+++ b/vendor/symfony/css-selector/Symfony/Component/CssSelector/Tests/Parser/Handler/NumberHandlerTest.php
@@ -0,0 +1,50 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\CssSelector\Tests\Parser\Handler;
+
+use Symfony\Component\CssSelector\Parser\Handler\NumberHandler;
+use Symfony\Component\CssSelector\Parser\Token;
+use Symfony\Component\CssSelector\Parser\Tokenizer\TokenizerPatterns;
+
+class NumberHandlerTest extends AbstractHandlerTest
+{
+    public function getHandleValueTestData()
+    {
+        return array(
+            array('12', new Token(Token::TYPE_NUMBER, '12', 0), ''),
+            array('12.34', new Token(Token::TYPE_NUMBER, '12.34', 0), ''),
+            array('+12.34', new Token(Token::TYPE_NUMBER, '+12.34', 0), ''),
+            array('-12.34', new Token(Token::TYPE_NUMBER, '-12.34', 0), ''),
+
+            array('12 arg', new Token(Token::TYPE_NUMBER, '12', 0), ' arg'),
+            array('12]', new Token(Token::TYPE_NUMBER, '12', 0), ']'),
+        );
+    }
+
+    public function getDontHandleValueTestData()
+    {
+        return array(
+            array('hello'),
+            array('>'),
+            array('+'),
+            array(' '),
+            array('/* comment */'),
+        );
+    }
+
+    protected function generateHandler()
+    {
+        $patterns = new TokenizerPatterns();
+
+        return new NumberHandler($patterns);
+    }
+}
diff --git a/vendor/symfony/css-selector/Symfony/Component/CssSelector/Tests/Parser/Handler/StringHandlerTest.php b/vendor/symfony/css-selector/Symfony/Component/CssSelector/Tests/Parser/Handler/StringHandlerTest.php
new file mode 100644
index 00000000000..89eff8bd282
--- /dev/null
+++ b/vendor/symfony/css-selector/Symfony/Component/CssSelector/Tests/Parser/Handler/StringHandlerTest.php
@@ -0,0 +1,50 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\CssSelector\Tests\Parser\Handler;
+
+use Symfony\Component\CssSelector\Parser\Handler\StringHandler;
+use Symfony\Component\CssSelector\Parser\Token;
+use Symfony\Component\CssSelector\Parser\Tokenizer\TokenizerPatterns;
+use Symfony\Component\CssSelector\Parser\Tokenizer\TokenizerEscaping;
+
+class StringHandlerTest extends AbstractHandlerTest
+{
+    public function getHandleValueTestData()
+    {
+        return array(
+            array('"hello"', new Token(Token::TYPE_STRING, 'hello', 1), ''),
+            array('"1"', new Token(Token::TYPE_STRING, '1', 1), ''),
+            array('" "', new Token(Token::TYPE_STRING, ' ', 1), ''),
+            array('""', new Token(Token::TYPE_STRING, '', 1), ''),
+            array("'hello'", new Token(Token::TYPE_STRING, 'hello', 1), ''),
+
+            array("'foo'bar", new Token(Token::TYPE_STRING, 'foo', 1), 'bar'),
+        );
+    }
+
+    public function getDontHandleValueTestData()
+    {
+        return array(
+            array('hello'),
+            array('>'),
+            array('1'),
+            array(' '),
+        );
+    }
+
+    protected function generateHandler()
+    {
+        $patterns = new TokenizerPatterns();
+
+        return new StringHandler($patterns, new TokenizerEscaping($patterns));
+    }
+}
diff --git a/vendor/symfony/css-selector/Symfony/Component/CssSelector/Tests/Parser/Handler/WhitespaceHandlerTest.php b/vendor/symfony/css-selector/Symfony/Component/CssSelector/Tests/Parser/Handler/WhitespaceHandlerTest.php
new file mode 100644
index 00000000000..f5f9e71dc22
--- /dev/null
+++ b/vendor/symfony/css-selector/Symfony/Component/CssSelector/Tests/Parser/Handler/WhitespaceHandlerTest.php
@@ -0,0 +1,44 @@
+<?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\CssSelector\Tests\Parser\Handler;
+
+use Symfony\Component\CssSelector\Parser\Handler\WhitespaceHandler;
+use Symfony\Component\CssSelector\Parser\Token;
+
+class WhitespaceHandlerTest extends AbstractHandlerTest
+{
+    public function getHandleValueTestData()
+    {
+        return array(
+            array(' ', new Token(Token::TYPE_WHITESPACE, ' ', 0), ''),
+            array("\n", new Token(Token::TYPE_WHITESPACE, "\n", 0), ''),
+            array("\t", new Token(Token::TYPE_WHITESPACE, "\t", 0), ''),
+
+            array(' foo', new Token(Token::TYPE_WHITESPACE, ' ', 0), 'foo'),
+            array(' .foo', new Token(Token::TYPE_WHITESPACE, ' ', 0), '.foo'),
+        );
+    }
+
+    public function getDontHandleValueTestData()
+    {
+        return array(
+            array('>'),
+            array('1'),
+            array('a'),
+        );
+    }
+
+    protected function generateHandler()
+    {
+        return new WhitespaceHandler();
+    }
+}
diff --git a/vendor/symfony/css-selector/Symfony/Component/CssSelector/Tests/Parser/ParserTest.php b/vendor/symfony/css-selector/Symfony/Component/CssSelector/Tests/Parser/ParserTest.php
new file mode 100644
index 00000000000..0454d9faa6f
--- /dev/null
+++ b/vendor/symfony/css-selector/Symfony/Component/CssSelector/Tests/Parser/ParserTest.php
@@ -0,0 +1,248 @@
+<?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\CssSelector\Tests\Parser;
+
+use Symfony\Component\CssSelector\Exception\SyntaxErrorException;
+use Symfony\Component\CssSelector\Node\FunctionNode;
+use Symfony\Component\CssSelector\Node\SelectorNode;
+use Symfony\Component\CssSelector\Parser\Parser;
+use Symfony\Component\CssSelector\Parser\Token;
+
+class ParserTest extends \PHPUnit_Framework_TestCase
+{
+    /** @dataProvider getParserTestData */
+    public function testParser($source, $representation)
+    {
+        $parser = new Parser();
+
+        $this->assertEquals($representation, array_map(function (SelectorNode $node) {
+            return (string) $node->getTree();
+        }, $parser->parse($source)));
+    }
+
+    /** @dataProvider getParserExceptionTestData */
+    public function testParserException($source, $message)
+    {
+        $parser = new Parser();
+
+        try {
+            $parser->parse($source);
+            $this->fail('Parser should throw a SyntaxErrorException.');
+        } catch (SyntaxErrorException $e) {
+            $this->assertEquals($message, $e->getMessage());
+        }
+    }
+
+    /** @dataProvider getPseudoElementsTestData */
+    public function testPseudoElements($source, $element, $pseudo)
+    {
+        $parser = new Parser();
+        $selectors = $parser->parse($source);
+        $this->assertCount(1, $selectors);
+
+        /** @var SelectorNode $selector */
+        $selector = $selectors[0];
+        $this->assertEquals($element, (string) $selector->getTree());
+        $this->assertEquals($pseudo, (string) $selector->getPseudoElement());
+    }
+
+    /** @dataProvider getSpecificityTestData */
+    public function testSpecificity($source, $value)
+    {
+        $parser = new Parser();
+        $selectors = $parser->parse($source);
+        $this->assertCount(1, $selectors);
+
+        /** @var SelectorNode $selector */
+        $selector = $selectors[0];
+        $this->assertEquals($value, $selector->getSpecificity()->getValue());
+    }
+
+    /** @dataProvider getParseSeriesTestData */
+    public function testParseSeries($series, $a, $b)
+    {
+        $parser = new Parser();
+        $selectors = $parser->parse(sprintf(':nth-child(%s)', $series));
+        $this->assertCount(1, $selectors);
+
+        /** @var FunctionNode $function */
+        $function = $selectors[0]->getTree();
+        $this->assertEquals(array($a, $b), Parser::parseSeries($function->getArguments()));
+    }
+
+    /** @dataProvider getParseSeriesExceptionTestData */
+    public function testParseSeriesException($series)
+    {
+        $parser = new Parser();
+        $selectors = $parser->parse(sprintf(':nth-child(%s)', $series));
+        $this->assertCount(1, $selectors);
+
+        /** @var FunctionNode $function */
+        $function = $selectors[0]->getTree();
+        $this->setExpectedException('Symfony\Component\CssSelector\Exception\SyntaxErrorException');
+        Parser::parseSeries($function->getArguments());
+    }
+
+    public function getParserTestData()
+    {
+        return array(
+            array('*', array('Element[*]')),
+            array('*|*', array('Element[*]')),
+            array('*|foo', array('Element[foo]')),
+            array('foo|*', array('Element[foo|*]')),
+            array('foo|bar', array('Element[foo|bar]')),
+            array('#foo#bar', array('Hash[Hash[Element[*]#foo]#bar]')),
+            array('div>.foo', array('CombinedSelector[Element[div] > Class[Element[*].foo]]')),
+            array('div> .foo', array('CombinedSelector[Element[div] > Class[Element[*].foo]]')),
+            array('div >.foo', array('CombinedSelector[Element[div] > Class[Element[*].foo]]')),
+            array('div > .foo', array('CombinedSelector[Element[div] > Class[Element[*].foo]]')),
+            array("div \n>  \t \t .foo", array('CombinedSelector[Element[div] > Class[Element[*].foo]]')),
+            array('td.foo,.bar', array('Class[Element[td].foo]', 'Class[Element[*].bar]')),
+            array('td.foo, .bar', array('Class[Element[td].foo]', 'Class[Element[*].bar]')),
+            array("td.foo\t\r\n\f ,\t\r\n\f .bar", array('Class[Element[td].foo]', 'Class[Element[*].bar]')),
+            array('td.foo,.bar', array('Class[Element[td].foo]', 'Class[Element[*].bar]')),
+            array('td.foo, .bar', array('Class[Element[td].foo]', 'Class[Element[*].bar]')),
+            array("td.foo\t\r\n\f ,\t\r\n\f .bar", array('Class[Element[td].foo]', 'Class[Element[*].bar]')),
+            array('div, td.foo, div.bar span', array('Element[div]', 'Class[Element[td].foo]', 'CombinedSelector[Class[Element[div].bar] <followed> Element[span]]')),
+            array('div > p', array('CombinedSelector[Element[div] > Element[p]]')),
+            array('td:first', array('Pseudo[Element[td]:first]')),
+            array('td :first', array('CombinedSelector[Element[td] <followed> Pseudo[Element[*]:first]]')),
+            array('a[name]', array('Attribute[Element[a][name]]')),
+            array("a[ name\t]", array('Attribute[Element[a][name]]')),
+            array('a [name]', array('CombinedSelector[Element[a] <followed> Attribute[Element[*][name]]]')),
+            array('a[rel="include"]', array("Attribute[Element[a][rel = 'include']]")),
+            array('a[rel = include]', array("Attribute[Element[a][rel = 'include']]")),
+            array("a[hreflang |= 'en']", array("Attribute[Element[a][hreflang |= 'en']]")),
+            array('a[hreflang|=en]', array("Attribute[Element[a][hreflang |= 'en']]")),
+            array('div:nth-child(10)', array("Function[Element[div]:nth-child(['10'])]")),
+            array(':nth-child(2n+2)', array("Function[Element[*]:nth-child(['2', 'n', '+2'])]")),
+            array('div:nth-of-type(10)', array("Function[Element[div]:nth-of-type(['10'])]")),
+            array('div div:nth-of-type(10) .aclass', array("CombinedSelector[CombinedSelector[Element[div] <followed> Function[Element[div]:nth-of-type(['10'])]] <followed> Class[Element[*].aclass]]")),
+            array('label:only', array('Pseudo[Element[label]:only]')),
+            array('a:lang(fr)', array("Function[Element[a]:lang(['fr'])]")),
+            array('div:contains("foo")', array("Function[Element[div]:contains(['foo'])]")),
+            array('div#foobar', array('Hash[Element[div]#foobar]')),
+            array('div:not(div.foo)', array('Negation[Element[div]:not(Class[Element[div].foo])]')),
+            array('td ~ th', array('CombinedSelector[Element[td] ~ Element[th]]')),
+            array('.foo[data-bar][data-baz=0]', array("Attribute[Attribute[Class[Element[*].foo][data-bar]][data-baz = '0']]")),
+        );
+    }
+
+    public function getParserExceptionTestData()
+    {
+        return array(
+            array('attributes(href)/html/body/a', SyntaxErrorException::unexpectedToken('selector', new Token(Token::TYPE_DELIMITER, '(', 10))->getMessage()),
+            array('attributes(href)', SyntaxErrorException::unexpectedToken('selector', new Token(Token::TYPE_DELIMITER, '(', 10))->getMessage()),
+            array('html/body/a', SyntaxErrorException::unexpectedToken('selector', new Token(Token::TYPE_DELIMITER, '/', 4))->getMessage()),
+            array(' ', SyntaxErrorException::unexpectedToken('selector', new Token(Token::TYPE_FILE_END, '', 1))->getMessage()),
+            array('div, ', SyntaxErrorException::unexpectedToken('selector', new Token(Token::TYPE_FILE_END, '', 5))->getMessage()),
+            array(' , div', SyntaxErrorException::unexpectedToken('selector', new Token(Token::TYPE_DELIMITER, ',', 1))->getMessage()),
+            array('p, , div', SyntaxErrorException::unexpectedToken('selector', new Token(Token::TYPE_DELIMITER, ',', 3))->getMessage()),
+            array('div > ', SyntaxErrorException::unexpectedToken('selector', new Token(Token::TYPE_FILE_END, '', 6))->getMessage()),
+            array('  > div', SyntaxErrorException::unexpectedToken('selector', new Token(Token::TYPE_DELIMITER, '>', 2))->getMessage()),
+            array('foo|#bar', SyntaxErrorException::unexpectedToken('identifier or "*"', new Token(Token::TYPE_HASH, 'bar', 4))->getMessage()),
+            array('#.foo', SyntaxErrorException::unexpectedToken('selector', new Token(Token::TYPE_DELIMITER, '#', 0))->getMessage()),
+            array('.#foo', SyntaxErrorException::unexpectedToken('identifier', new Token(Token::TYPE_HASH, 'foo', 1))->getMessage()),
+            array(':#foo', SyntaxErrorException::unexpectedToken('identifier', new Token(Token::TYPE_HASH, 'foo', 1))->getMessage()),
+            array('[*]', SyntaxErrorException::unexpectedToken('"|"', new Token(Token::TYPE_DELIMITER, ']', 2))->getMessage()),
+            array('[foo|]', SyntaxErrorException::unexpectedToken('identifier', new Token(Token::TYPE_DELIMITER, ']', 5))->getMessage()),
+            array('[#]', SyntaxErrorException::unexpectedToken('identifier or "*"', new Token(Token::TYPE_DELIMITER, '#', 1))->getMessage()),
+            array('[foo=#]', SyntaxErrorException::unexpectedToken('string or identifier', new Token(Token::TYPE_DELIMITER, '#', 5))->getMessage()),
+            array(':nth-child()', SyntaxErrorException::unexpectedToken('at least one argument', new Token(Token::TYPE_DELIMITER, ')', 11))->getMessage()),
+            array('[href]a', SyntaxErrorException::unexpectedToken('selector', new Token(Token::TYPE_IDENTIFIER, 'a', 6))->getMessage()),
+            array('[rel:stylesheet]', SyntaxErrorException::unexpectedToken('operator', new Token(Token::TYPE_DELIMITER, ':', 4))->getMessage()),
+            array('[rel=stylesheet', SyntaxErrorException::unexpectedToken('"]"', new Token(Token::TYPE_FILE_END, '', 15))->getMessage()),
+            array(':lang(fr', SyntaxErrorException::unexpectedToken('an argument', new Token(Token::TYPE_FILE_END, '', 8))->getMessage()),
+            array(':contains("foo', SyntaxErrorException::unclosedString(10)->getMessage()),
+            array('foo!', SyntaxErrorException::unexpectedToken('selector', new Token(Token::TYPE_DELIMITER, '!', 3))->getMessage()),
+        );
+    }
+
+    public function getPseudoElementsTestData()
+    {
+        return array(
+            array('foo', 'Element[foo]', ''),
+            array('*', 'Element[*]', ''),
+            array(':empty', 'Pseudo[Element[*]:empty]', ''),
+            array(':BEfore', 'Element[*]', 'before'),
+            array(':aftER', 'Element[*]', 'after'),
+            array(':First-Line', 'Element[*]', 'first-line'),
+            array(':First-Letter', 'Element[*]', 'first-letter'),
+            array('::befoRE', 'Element[*]', 'before'),
+            array('::AFter', 'Element[*]', 'after'),
+            array('::firsT-linE', 'Element[*]', 'first-line'),
+            array('::firsT-letteR', 'Element[*]', 'first-letter'),
+            array('::Selection', 'Element[*]', 'selection'),
+            array('foo:after', 'Element[foo]', 'after'),
+            array('foo::selection', 'Element[foo]', 'selection'),
+            array('lorem#ipsum ~ a#b.c[href]:empty::selection', 'CombinedSelector[Hash[Element[lorem]#ipsum] ~ Pseudo[Attribute[Class[Hash[Element[a]#b].c][href]]:empty]]', 'selection'),
+        );
+    }
+
+    public function getSpecificityTestData()
+    {
+        return array(
+            array('*', 0),
+            array(' foo', 1),
+            array(':empty ', 10),
+            array(':before', 1),
+            array('*:before', 1),
+            array(':nth-child(2)', 10),
+            array('.bar', 10),
+            array('[baz]', 10),
+            array('[baz="4"]', 10),
+            array('[baz^="4"]', 10),
+            array('#lipsum', 100),
+            array(':not(*)', 0),
+            array(':not(foo)', 1),
+            array(':not(.foo)', 10),
+            array(':not([foo])', 10),
+            array(':not(:empty)', 10),
+            array(':not(#foo)', 100),
+            array('foo:empty', 11),
+            array('foo:before', 2),
+            array('foo::before', 2),
+            array('foo:empty::before', 12),
+            array('#lorem + foo#ipsum:first-child > bar:first-line', 213),
+        );
+    }
+
+    public function getParseSeriesTestData()
+    {
+        return array(
+            array('1n+3', 1, 3),
+            array('1n +3', 1, 3),
+            array('1n + 3', 1, 3),
+            array('1n+ 3', 1, 3),
+            array('1n-3', 1, -3),
+            array('1n -3', 1, -3),
+            array('1n - 3', 1, -3),
+            array('1n- 3', 1, -3),
+            array('n-5', 1, -5),
+            array('odd', 2, 1),
+            array('even', 2, 0),
+            array('3n', 3, 0),
+            array('n', 1, 0),
+            array('+n', 1, 0),
+            array('-n', -1, 0),
+            array('5', 0, 5),
+        );
+    }
+
+    public function getParseSeriesExceptionTestData()
+    {
+        return array(
+            array('foo'),
+            array('n+'),
+        );
+    }
+}
diff --git a/vendor/symfony/css-selector/Symfony/Component/CssSelector/Tests/Parser/ReaderTest.php b/vendor/symfony/css-selector/Symfony/Component/CssSelector/Tests/Parser/ReaderTest.php
new file mode 100644
index 00000000000..03c054eaaee
--- /dev/null
+++ b/vendor/symfony/css-selector/Symfony/Component/CssSelector/Tests/Parser/ReaderTest.php
@@ -0,0 +1,101 @@
+<?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\CssSelector\Tests\Parser;
+
+use Symfony\Component\CssSelector\Parser\Reader;
+
+class ReaderTest extends \PHPUnit_Framework_TestCase
+{
+    public function testIsEOF()
+    {
+        $reader = new Reader('');
+        $this->assertTrue($reader->isEOF());
+
+        $reader = new Reader('hello');
+        $this->assertFalse($reader->isEOF());
+
+        $this->assignPosition($reader, 2);
+        $this->assertFalse($reader->isEOF());
+
+        $this->assignPosition($reader, 5);
+        $this->assertTrue($reader->isEOF());
+    }
+
+    public function testGetRemainingLength()
+    {
+        $reader = new Reader('hello');
+        $this->assertEquals(5, $reader->getRemainingLength());
+
+        $this->assignPosition($reader, 2);
+        $this->assertEquals(3, $reader->getRemainingLength());
+
+        $this->assignPosition($reader, 5);
+        $this->assertEquals(0, $reader->getRemainingLength());
+    }
+
+    public function testGetSubstring()
+    {
+        $reader = new Reader('hello');
+        $this->assertEquals('he', $reader->getSubstring(2));
+        $this->assertEquals('el', $reader->getSubstring(2, 1));
+
+        $this->assignPosition($reader, 2);
+        $this->assertEquals('ll', $reader->getSubstring(2));
+        $this->assertEquals('lo', $reader->getSubstring(2, 1));
+    }
+
+    public function testGetOffset()
+    {
+        $reader = new Reader('hello');
+        $this->assertEquals(2, $reader->getOffset('ll'));
+        $this->assertFalse($reader->getOffset('w'));
+
+        $this->assignPosition($reader, 2);
+        $this->assertEquals(0, $reader->getOffset('ll'));
+        $this->assertFalse($reader->getOffset('he'));
+    }
+
+    public function testFindPattern()
+    {
+        $reader = new Reader('hello');
+
+        $this->assertFalse($reader->findPattern('/world/'));
+        $this->assertEquals(array('hello', 'h'), $reader->findPattern('/^([a-z]).*/'));
+
+        $this->assignPosition($reader, 2);
+        $this->assertFalse($reader->findPattern('/^h.*/'));
+        $this->assertEquals(array('llo'), $reader->findPattern('/^llo$/'));
+    }
+
+    public function testMoveForward()
+    {
+        $reader = new Reader('hello');
+        $this->assertEquals(0, $reader->getPosition());
+
+        $reader->moveForward(2);
+        $this->assertEquals(2, $reader->getPosition());
+    }
+
+    public function testToEnd()
+    {
+        $reader = new Reader('hello');
+        $reader->moveToEnd();
+        $this->assertTrue($reader->isEOF());
+    }
+
+    private function assignPosition(Reader $reader, $value)
+    {
+        $position = new \ReflectionProperty($reader, 'position');
+        $position->setAccessible(true);
+        $position->setValue($reader, $value);
+    }
+}
diff --git a/vendor/symfony/css-selector/Symfony/Component/CssSelector/Tests/Parser/Shortcut/ClassParserTest.php b/vendor/symfony/css-selector/Symfony/Component/CssSelector/Tests/Parser/Shortcut/ClassParserTest.php
new file mode 100644
index 00000000000..6efdd676576
--- /dev/null
+++ b/vendor/symfony/css-selector/Symfony/Component/CssSelector/Tests/Parser/Shortcut/ClassParserTest.php
@@ -0,0 +1,44 @@
+<?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\CssSelector\Tests\Parser\Shortcut;
+
+use Symfony\Component\CssSelector\Node\SelectorNode;
+use Symfony\Component\CssSelector\Parser\Shortcut\ClassParser;
+
+/**
+ * @author Jean-François Simon <jeanfrancois.simon@sensiolabs.com>
+ */
+class ClassParserTest extends \PHPUnit_Framework_TestCase
+{
+    /** @dataProvider getParseTestData */
+    public function testParse($source, $representation)
+    {
+        $parser = new ClassParser();
+        $selectors = $parser->parse($source);
+        $this->assertCount(1, $selectors);
+
+        /** @var SelectorNode $selector */
+        $selector = $selectors[0];
+        $this->assertEquals($representation, (string) $selector->getTree());
+    }
+
+    public function getParseTestData()
+    {
+        return array(
+            array('.testclass', 'Class[Element[*].testclass]'),
+            array('testel.testclass', 'Class[Element[testel].testclass]'),
+            array('testns|.testclass', 'Class[Element[testns|*].testclass]'),
+            array('testns|*.testclass', 'Class[Element[testns|*].testclass]'),
+            array('testns|testel.testclass', 'Class[Element[testns|testel].testclass]'),
+        );
+    }
+}
diff --git a/vendor/symfony/css-selector/Symfony/Component/CssSelector/Tests/Parser/Shortcut/ElementParserTest.php b/vendor/symfony/css-selector/Symfony/Component/CssSelector/Tests/Parser/Shortcut/ElementParserTest.php
new file mode 100644
index 00000000000..b30b5ee7acd
--- /dev/null
+++ b/vendor/symfony/css-selector/Symfony/Component/CssSelector/Tests/Parser/Shortcut/ElementParserTest.php
@@ -0,0 +1,43 @@
+<?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\CssSelector\Tests\Parser\Shortcut;
+
+use Symfony\Component\CssSelector\Node\SelectorNode;
+use Symfony\Component\CssSelector\Parser\Shortcut\ElementParser;
+
+/**
+ * @author Jean-François Simon <jeanfrancois.simon@sensiolabs.com>
+ */
+class ElementParserTest extends \PHPUnit_Framework_TestCase
+{
+    /** @dataProvider getParseTestData */
+    public function testParse($source, $representation)
+    {
+        $parser = new ElementParser();
+        $selectors = $parser->parse($source);
+        $this->assertCount(1, $selectors);
+
+        /** @var SelectorNode $selector */
+        $selector = $selectors[0];
+        $this->assertEquals($representation, (string) $selector->getTree());
+    }
+
+    public function getParseTestData()
+    {
+        return array(
+            array('*', 'Element[*]'),
+            array('testel', 'Element[testel]'),
+            array('testns|*', 'Element[testns|*]'),
+            array('testns|testel', 'Element[testns|testel]'),
+        );
+    }
+}
diff --git a/vendor/symfony/css-selector/Symfony/Component/CssSelector/Tests/Parser/Shortcut/EmptyStringParserTest.php b/vendor/symfony/css-selector/Symfony/Component/CssSelector/Tests/Parser/Shortcut/EmptyStringParserTest.php
new file mode 100644
index 00000000000..b7c3539c67a
--- /dev/null
+++ b/vendor/symfony/css-selector/Symfony/Component/CssSelector/Tests/Parser/Shortcut/EmptyStringParserTest.php
@@ -0,0 +1,35 @@
+<?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\CssSelector\Tests\Parser\Shortcut;
+
+use Symfony\Component\CssSelector\Node\SelectorNode;
+use Symfony\Component\CssSelector\Parser\Shortcut\EmptyStringParser;
+
+/**
+ * @author Jean-François Simon <jeanfrancois.simon@sensiolabs.com>
+ */
+class EmptyStringParserTest extends \PHPUnit_Framework_TestCase
+{
+    public function testParse()
+    {
+        $parser = new EmptyStringParser();
+        $selectors = $parser->parse('');
+        $this->assertCount(1, $selectors);
+
+        /** @var SelectorNode $selector */
+        $selector = $selectors[0];
+        $this->assertEquals('Element[*]', (string) $selector->getTree());
+
+        $selectors = $parser->parse('this will produce an empty array');
+        $this->assertCount(0, $selectors);
+    }
+}
diff --git a/vendor/symfony/css-selector/Symfony/Component/CssSelector/Tests/Parser/Shortcut/HashParserTest.php b/vendor/symfony/css-selector/Symfony/Component/CssSelector/Tests/Parser/Shortcut/HashParserTest.php
new file mode 100644
index 00000000000..d2ce891ec82
--- /dev/null
+++ b/vendor/symfony/css-selector/Symfony/Component/CssSelector/Tests/Parser/Shortcut/HashParserTest.php
@@ -0,0 +1,44 @@
+<?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\CssSelector\Tests\Parser\Shortcut;
+
+use Symfony\Component\CssSelector\Node\SelectorNode;
+use Symfony\Component\CssSelector\Parser\Shortcut\HashParser;
+
+/**
+ * @author Jean-François Simon <jeanfrancois.simon@sensiolabs.com>
+ */
+class HashParserTest extends \PHPUnit_Framework_TestCase
+{
+    /** @dataProvider getParseTestData */
+    public function testParse($source, $representation)
+    {
+        $parser = new HashParser();
+        $selectors = $parser->parse($source);
+        $this->assertCount(1, $selectors);
+
+        /** @var SelectorNode $selector */
+        $selector = $selectors[0];
+        $this->assertEquals($representation, (string) $selector->getTree());
+    }
+
+    public function getParseTestData()
+    {
+        return array(
+            array('#testid', 'Hash[Element[*]#testid]'),
+            array('testel#testid', 'Hash[Element[testel]#testid]'),
+            array('testns|#testid', 'Hash[Element[testns|*]#testid]'),
+            array('testns|*#testid', 'Hash[Element[testns|*]#testid]'),
+            array('testns|testel#testid', 'Hash[Element[testns|testel]#testid]'),
+        );
+    }
+}
diff --git a/vendor/symfony/css-selector/Symfony/Component/CssSelector/Tests/Parser/TokenStreamTest.php b/vendor/symfony/css-selector/Symfony/Component/CssSelector/Tests/Parser/TokenStreamTest.php
new file mode 100644
index 00000000000..8f3253a7d59
--- /dev/null
+++ b/vendor/symfony/css-selector/Symfony/Component/CssSelector/Tests/Parser/TokenStreamTest.php
@@ -0,0 +1,95 @@
+<?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\CssSelector\Tests\Parser;
+
+use Symfony\Component\CssSelector\Parser\Token;
+use Symfony\Component\CssSelector\Parser\TokenStream;
+
+class TokenStreamTest extends \PHPUnit_Framework_TestCase
+{
+    public function testGetNext()
+    {
+        $stream = new TokenStream();
+        $stream->push($t1 = new Token(Token::TYPE_IDENTIFIER, 'h1', 0));
+        $stream->push($t2 = new Token(Token::TYPE_DELIMITER, '.', 2));
+        $stream->push($t3 = new Token(Token::TYPE_IDENTIFIER, 'title', 3));
+
+        $this->assertSame($t1, $stream->getNext());
+        $this->assertSame($t2, $stream->getNext());
+        $this->assertSame($t3, $stream->getNext());
+    }
+
+    public function testGetPeek()
+    {
+        $stream = new TokenStream();
+        $stream->push($t1 = new Token(Token::TYPE_IDENTIFIER, 'h1', 0));
+        $stream->push($t2 = new Token(Token::TYPE_DELIMITER, '.', 2));
+        $stream->push($t3 = new Token(Token::TYPE_IDENTIFIER, 'title', 3));
+
+        $this->assertSame($t1, $stream->getPeek());
+        $this->assertSame($t1, $stream->getNext());
+        $this->assertSame($t2, $stream->getPeek());
+        $this->assertSame($t2, $stream->getPeek());
+        $this->assertSame($t2, $stream->getNext());
+    }
+
+    public function testGetNextIdentifier()
+    {
+        $stream = new TokenStream();
+        $stream->push(new Token(Token::TYPE_IDENTIFIER, 'h1', 0));
+
+        $this->assertEquals('h1', $stream->getNextIdentifier());
+    }
+
+    public function testFailToGetNextIdentifier()
+    {
+        $this->setExpectedException('Symfony\Component\CssSelector\Exception\SyntaxErrorException');
+
+        $stream = new TokenStream();
+        $stream->push(new Token(Token::TYPE_DELIMITER, '.', 2));
+        $stream->getNextIdentifier();
+    }
+
+    public function testGetNextIdentifierOrStar()
+    {
+        $stream = new TokenStream();
+
+        $stream->push(new Token(Token::TYPE_IDENTIFIER, 'h1', 0));
+        $this->assertEquals('h1', $stream->getNextIdentifierOrStar());
+
+        $stream->push(new Token(Token::TYPE_DELIMITER, '*', 0));
+        $this->assertNull($stream->getNextIdentifierOrStar());
+    }
+
+    public function testFailToGetNextIdentifierOrStar()
+    {
+        $this->setExpectedException('Symfony\Component\CssSelector\Exception\SyntaxErrorException');
+
+        $stream = new TokenStream();
+        $stream->push(new Token(Token::TYPE_DELIMITER, '.', 2));
+        $stream->getNextIdentifierOrStar();
+    }
+
+    public function testSkipWhitespace()
+    {
+        $stream = new TokenStream();
+        $stream->push($t1 = new Token(Token::TYPE_IDENTIFIER, 'h1', 0));
+        $stream->push($t2 = new Token(Token::TYPE_WHITESPACE, ' ', 2));
+        $stream->push($t3 = new Token(Token::TYPE_IDENTIFIER, 'h1', 3));
+
+        $stream->skipWhitespace();
+        $this->assertSame($t1, $stream->getNext());
+
+        $stream->skipWhitespace();
+        $this->assertSame($t3, $stream->getNext());
+    }
+}
diff --git a/vendor/symfony/css-selector/Symfony/Component/CssSelector/Tests/XPath/Fixtures/ids.html b/vendor/symfony/css-selector/Symfony/Component/CssSelector/Tests/XPath/Fixtures/ids.html
new file mode 100644
index 00000000000..5799fad25ec
--- /dev/null
+++ b/vendor/symfony/css-selector/Symfony/Component/CssSelector/Tests/XPath/Fixtures/ids.html
@@ -0,0 +1,48 @@
+<html id="html"><head>
+  <link id="link-href" href="foo" />
+  <link id="link-nohref" />
+</head><body>
+<div id="outer-div">
+ <a id="name-anchor" name="foo"></a>
+ <a id="tag-anchor" rel="tag" href="http://localhost/foo">link</a>
+ <a id="nofollow-anchor" rel="nofollow" href="https://example.org">
+    link</a>
+ <ol id="first-ol" class="a b c">
+   <li id="first-li">content</li>
+   <li id="second-li" lang="En-us">
+     <div id="li-div">
+     </div>
+   </li>
+   <li id="third-li" class="ab c"></li>
+   <li id="fourth-li" class="ab
+c"></li>
+   <li id="fifth-li"></li>
+   <li id="sixth-li"></li>
+   <li id="seventh-li">  </li>
+ </ol>
+ <p id="paragraph">
+   <b id="p-b">hi</b> <em id="p-em">there</em>
+   <b id="p-b2">guy</b>
+   <input type="checkbox" id="checkbox-unchecked" />
+   <input type="checkbox" id="checkbox-disabled" disabled="" />
+   <input type="text" id="text-checked" checked="checked" />
+   <input type="hidden" />
+   <input type="hidden" disabled="disabled" />
+   <input type="checkbox" id="checkbox-checked" checked="checked" />
+   <input type="checkbox" id="checkbox-disabled-checked"
+          disabled="disabled" checked="checked" />
+   <fieldset id="fieldset" disabled="disabled">
+     <input type="checkbox" id="checkbox-fieldset-disabled" />
+     <input type="hidden" />
+   </fieldset>
+ </p>
+ <ol id="second-ol">
+ </ol>
+ <map name="dummymap">
+   <area shape="circle" coords="200,250,25" href="foo.html" id="area-href" />
+   <area shape="default" id="area-nohref" />
+ </map>
+</div>
+<div id="foobar-div" foobar="ab bc
+cde"><span id="foobar-span"></span></div>
+</body></html>
diff --git a/vendor/symfony/css-selector/Symfony/Component/CssSelector/Tests/XPath/Fixtures/lang.xml b/vendor/symfony/css-selector/Symfony/Component/CssSelector/Tests/XPath/Fixtures/lang.xml
new file mode 100644
index 00000000000..14f8dbed681
--- /dev/null
+++ b/vendor/symfony/css-selector/Symfony/Component/CssSelector/Tests/XPath/Fixtures/lang.xml
@@ -0,0 +1,11 @@
+<test>
+  <a id="first" xml:lang="en">a</a>
+  <b id="second" xml:lang="en-US">b</b>
+  <c id="third" xml:lang="en-Nz">c</c>
+  <d id="fourth" xml:lang="En-us">d</d>
+  <e id="fifth" xml:lang="fr">e</e>
+  <f id="sixth" xml:lang="ru">f</f>
+  <g id="seventh" xml:lang="de">
+    <h id="eighth" xml:lang="zh"/>
+  </g>
+</test>
diff --git a/vendor/symfony/css-selector/Symfony/Component/CssSelector/Tests/XPath/Fixtures/shakespear.html b/vendor/symfony/css-selector/Symfony/Component/CssSelector/Tests/XPath/Fixtures/shakespear.html
new file mode 100644
index 00000000000..15d1ad33a31
--- /dev/null
+++ b/vendor/symfony/css-selector/Symfony/Component/CssSelector/Tests/XPath/Fixtures/shakespear.html
@@ -0,0 +1,308 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+	"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en" debug="true">
+<head>
+	<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
+</head>
+<body>
+	<div id="test">
+	<div class="dialog">
+	<h2>As You Like It</h2>
+	<div id="playwright">
+	  by William Shakespeare
+	</div>
+	<div class="dialog scene thirdClass" id="scene1">
+	  <h3>ACT I, SCENE III. A room in the palace.</h3>
+	  <div class="dialog">
+	  <div class="direction">Enter CELIA and ROSALIND</div>
+	  </div>
+	  <div id="speech1" class="character">CELIA</div>
+	  <div class="dialog">
+	  <div id="scene1.3.1">Why, cousin! why, Rosalind! Cupid have mercy! not a word?</div>
+	  </div>
+	  <div id="speech2" class="character">ROSALIND</div>
+	  <div class="dialog">
+	  <div id="scene1.3.2">Not one to throw at a dog.</div>
+	  </div>
+	  <div id="speech3" class="character">CELIA</div>
+	  <div class="dialog">
+	  <div id="scene1.3.3">No, thy words are too precious to be cast away upon</div>
+	  <div id="scene1.3.4">curs; throw some of them at me; come, lame me with reasons.</div>
+	  </div>
+	  <div id="speech4" class="character">ROSALIND</div>
+	  <div id="speech5" class="character">CELIA</div>
+	  <div class="dialog">
+	  <div id="scene1.3.8">But is all this for your father?</div>
+	  </div>
+	  <div class="dialog">
+	  <div id="scene1.3.5">Then there were two cousins laid up; when the one</div>
+	  <div id="scene1.3.6">should be lamed with reasons and the other mad</div>
+	  <div id="scene1.3.7">without any.</div>
+	  </div>
+	  <div id="speech6" class="character">ROSALIND</div>
+	  <div class="dialog">
+	  <div id="scene1.3.9">No, some of it is for my child's father. O, how</div>
+	  <div id="scene1.3.10">full of briers is this working-day world!</div>
+	  </div>
+	  <div id="speech7" class="character">CELIA</div>
+	  <div class="dialog">
+	  <div id="scene1.3.11">They are but burs, cousin, thrown upon thee in</div>
+	  <div id="scene1.3.12">holiday foolery: if we walk not in the trodden</div>
+	  <div id="scene1.3.13">paths our very petticoats will catch them.</div>
+	  </div>
+	  <div id="speech8" class="character">ROSALIND</div>
+	  <div class="dialog">
+	  <div id="scene1.3.14">I could shake them off my coat: these burs are in my heart.</div>
+	  </div>
+	  <div id="speech9" class="character">CELIA</div>
+	  <div class="dialog">
+	  <div id="scene1.3.15">Hem them away.</div>
+	  </div>
+	  <div id="speech10" class="character">ROSALIND</div>
+	  <div class="dialog">
+	  <div id="scene1.3.16">I would try, if I could cry 'hem' and have him.</div>
+	  </div>
+	  <div id="speech11" class="character">CELIA</div>
+	  <div class="dialog">
+	  <div id="scene1.3.17">Come, come, wrestle with thy affections.</div>
+	  </div>
+	  <div id="speech12" class="character">ROSALIND</div>
+	  <div class="dialog">
+	  <div id="scene1.3.18">O, they take the part of a better wrestler than myself!</div>
+	  </div>
+	  <div id="speech13" class="character">CELIA</div>
+	  <div class="dialog">
+	  <div id="scene1.3.19">O, a good wish upon you! you will try in time, in</div>
+	  <div id="scene1.3.20">despite of a fall. But, turning these jests out of</div>
+	  <div id="scene1.3.21">service, let us talk in good earnest: is it</div>
+	  <div id="scene1.3.22">possible, on such a sudden, you should fall into so</div>
+	  <div id="scene1.3.23">strong a liking with old Sir Rowland's youngest son?</div>
+	  </div>
+	  <div id="speech14" class="character">ROSALIND</div>
+	  <div class="dialog">
+	  <div id="scene1.3.24">The duke my father loved his father dearly.</div>
+	  </div>
+	  <div id="speech15" class="character">CELIA</div>
+	  <div class="dialog">
+	  <div id="scene1.3.25">Doth it therefore ensue that you should love his son</div>
+	  <div id="scene1.3.26">dearly? By this kind of chase, I should hate him,</div>
+	  <div id="scene1.3.27">for my father hated his father dearly; yet I hate</div>
+	  <div id="scene1.3.28">not Orlando.</div>
+	  </div>
+	  <div id="speech16" class="character">ROSALIND</div>
+	  <div title="wtf" class="dialog">
+	  <div id="scene1.3.29">No, faith, hate him not, for my sake.</div>
+	  </div>
+	  <div id="speech17" class="character">CELIA</div>
+	  <div class="dialog">
+	  <div id="scene1.3.30">Why should I not? doth he not deserve well?</div>
+	  </div>
+	  <div id="speech18" class="character">ROSALIND</div>
+	  <div class="dialog">
+	  <div id="scene1.3.31">Let me love him for that, and do you love him</div>
+	  <div id="scene1.3.32">because I do. Look, here comes the duke.</div>
+	  </div>
+	  <div id="speech19" class="character">CELIA</div>
+	  <div class="dialog">
+	  <div id="scene1.3.33">With his eyes full of anger.</div>
+	  <div class="direction">Enter DUKE FREDERICK, with Lords</div>
+	  </div>
+	  <div id="speech20" class="character">DUKE FREDERICK</div>
+	  <div class="dialog">
+	  <div id="scene1.3.34">Mistress, dispatch you with your safest haste</div>
+	  <div id="scene1.3.35">And get you from our court.</div>
+	  </div>
+	  <div id="speech21" class="character">ROSALIND</div>
+	  <div class="dialog">
+	  <div id="scene1.3.36">Me, uncle?</div>
+	  </div>
+	  <div id="speech22" class="character">DUKE FREDERICK</div>
+	  <div class="dialog">
+	  <div id="scene1.3.37">You, cousin</div>
+	  <div id="scene1.3.38">Within these ten days if that thou be'st found</div>
+	  <div id="scene1.3.39">So near our public court as twenty miles,</div>
+	  <div id="scene1.3.40">Thou diest for it.</div>
+	  </div>
+	  <div id="speech23" class="character">ROSALIND</div>
+	  <div class="dialog">
+	  <div id="scene1.3.41">                  I do beseech your grace,</div>
+	  <div id="scene1.3.42">Let me the knowledge of my fault bear with me:</div>
+	  <div id="scene1.3.43">If with myself I hold intelligence</div>
+	  <div id="scene1.3.44">Or have acquaintance with mine own desires,</div>
+	  <div id="scene1.3.45">If that I do not dream or be not frantic,--</div>
+	  <div id="scene1.3.46">As I do trust I am not--then, dear uncle,</div>
+	  <div id="scene1.3.47">Never so much as in a thought unborn</div>
+	  <div id="scene1.3.48">Did I offend your highness.</div>
+	  </div>
+	  <div id="speech24" class="character">DUKE FREDERICK</div>
+	  <div class="dialog">
+	  <div id="scene1.3.49">Thus do all traitors:</div>
+	  <div id="scene1.3.50">If their purgation did consist in words,</div>
+	  <div id="scene1.3.51">They are as innocent as grace itself:</div>
+	  <div id="scene1.3.52">Let it suffice thee that I trust thee not.</div>
+	  </div>
+	  <div id="speech25" class="character">ROSALIND</div>
+	  <div class="dialog">
+	  <div id="scene1.3.53">Yet your mistrust cannot make me a traitor:</div>
+	  <div id="scene1.3.54">Tell me whereon the likelihood depends.</div>
+	  </div>
+	  <div id="speech26" class="character">DUKE FREDERICK</div>
+	  <div class="dialog">
+	  <div id="scene1.3.55">Thou art thy father's daughter; there's enough.</div>
+	  </div>
+	  <div id="speech27" class="character">ROSALIND</div>
+	  <div class="dialog">
+	  <div id="scene1.3.56">So was I when your highness took his dukedom;</div>
+	  <div id="scene1.3.57">So was I when your highness banish'd him:</div>
+	  <div id="scene1.3.58">Treason is not inherited, my lord;</div>
+	  <div id="scene1.3.59">Or, if we did derive it from our friends,</div>
+	  <div id="scene1.3.60">What's that to me? my father was no traitor:</div>
+	  <div id="scene1.3.61">Then, good my liege, mistake me not so much</div>
+	  <div id="scene1.3.62">To think my poverty is treacherous.</div>
+	  </div>
+	  <div id="speech28" class="character">CELIA</div>
+	  <div class="dialog">
+	  <div id="scene1.3.63">Dear sovereign, hear me speak.</div>
+	  </div>
+	  <div id="speech29" class="character">DUKE FREDERICK</div>
+	  <div class="dialog">
+	  <div id="scene1.3.64">Ay, Celia; we stay'd her for your sake,</div>
+	  <div id="scene1.3.65">Else had she with her father ranged along.</div>
+	  </div>
+	  <div id="speech30" class="character">CELIA</div>
+	  <div class="dialog">
+	  <div id="scene1.3.66">I did not then entreat to have her stay;</div>
+	  <div id="scene1.3.67">It was your pleasure and your own remorse:</div>
+	  <div id="scene1.3.68">I was too young that time to value her;</div>
+	  <div id="scene1.3.69">But now I know her: if she be a traitor,</div>
+	  <div id="scene1.3.70">Why so am I; we still have slept together,</div>
+	  <div id="scene1.3.71">Rose at an instant, learn'd, play'd, eat together,</div>
+	  <div id="scene1.3.72">And wheresoever we went, like Juno's swans,</div>
+	  <div id="scene1.3.73">Still we went coupled and inseparable.</div>
+	  </div>
+	  <div id="speech31" class="character">DUKE FREDERICK</div>
+	  <div class="dialog">
+	  <div id="scene1.3.74">She is too subtle for thee; and her smoothness,</div>
+	  <div id="scene1.3.75">Her very silence and her patience</div>
+	  <div id="scene1.3.76">Speak to the people, and they pity her.</div>
+	  <div id="scene1.3.77">Thou art a fool: she robs thee of thy name;</div>
+	  <div id="scene1.3.78">And thou wilt show more bright and seem more virtuous</div>
+	  <div id="scene1.3.79">When she is gone. Then open not thy lips:</div>
+	  <div id="scene1.3.80">Firm and irrevocable is my doom</div>
+	  <div id="scene1.3.81">Which I have pass'd upon her; she is banish'd.</div>
+	  </div>
+	  <div id="speech32" class="character">CELIA</div>
+	  <div class="dialog">
+	  <div id="scene1.3.82">Pronounce that sentence then on me, my liege:</div>
+	  <div id="scene1.3.83">I cannot live out of her company.</div>
+	  </div>
+	  <div id="speech33" class="character">DUKE FREDERICK</div>
+	  <div class="dialog">
+	  <div id="scene1.3.84">You are a fool. You, niece, provide yourself:</div>
+	  <div id="scene1.3.85">If you outstay the time, upon mine honour,</div>
+	  <div id="scene1.3.86">And in the greatness of my word, you die.</div>
+	  <div class="direction">Exeunt DUKE FREDERICK and Lords</div>
+	  </div>
+	  <div id="speech34" class="character">CELIA</div>
+	  <div class="dialog">
+	  <div id="scene1.3.87">O my poor Rosalind, whither wilt thou go?</div>
+	  <div id="scene1.3.88">Wilt thou change fathers? I will give thee mine.</div>
+	  <div id="scene1.3.89">I charge thee, be not thou more grieved than I am.</div>
+	  </div>
+	  <div id="speech35" class="character">ROSALIND</div>
+	  <div class="dialog">
+	  <div id="scene1.3.90">I have more cause.</div>
+	  </div>
+	  <div id="speech36" class="character">CELIA</div>
+	  <div class="dialog">
+	  <div id="scene1.3.91">                  Thou hast not, cousin;</div>
+	  <div id="scene1.3.92">Prithee be cheerful: know'st thou not, the duke</div>
+	  <div id="scene1.3.93">Hath banish'd me, his daughter?</div>
+	  </div>
+	  <div id="speech37" class="character">ROSALIND</div>
+	  <div class="dialog">
+	  <div id="scene1.3.94">That he hath not.</div>
+	  </div>
+	  <div id="speech38" class="character">CELIA</div>
+	  <div class="dialog">
+	  <div id="scene1.3.95">No, hath not? Rosalind lacks then the love</div>
+	  <div id="scene1.3.96">Which teacheth thee that thou and I am one:</div>
+	  <div id="scene1.3.97">Shall we be sunder'd? shall we part, sweet girl?</div>
+	  <div id="scene1.3.98">No: let my father seek another heir.</div>
+	  <div id="scene1.3.99">Therefore devise with me how we may fly,</div>
+	  <div id="scene1.3.100">Whither to go and what to bear with us;</div>
+	  <div id="scene1.3.101">And do not seek to take your change upon you,</div>
+	  <div id="scene1.3.102">To bear your griefs yourself and leave me out;</div>
+	  <div id="scene1.3.103">For, by this heaven, now at our sorrows pale,</div>
+	  <div id="scene1.3.104">Say what thou canst, I'll go along with thee.</div>
+	  </div>
+	  <div id="speech39" class="character">ROSALIND</div>
+	  <div class="dialog">
+	  <div id="scene1.3.105">Why, whither shall we go?</div>
+	  </div>
+	  <div id="speech40" class="character">CELIA</div>
+	  <div class="dialog">
+	  <div id="scene1.3.106">To seek my uncle in the forest of Arden.</div>
+	  </div>
+	  <div id="speech41" class="character">ROSALIND</div>
+	  <div class="dialog">
+	  <div id="scene1.3.107">Alas, what danger will it be to us,</div>
+	  <div id="scene1.3.108">Maids as we are, to travel forth so far!</div>
+	  <div id="scene1.3.109">Beauty provoketh thieves sooner than gold.</div>
+	  </div>
+	  <div id="speech42" class="character">CELIA</div>
+	  <div class="dialog">
+	  <div id="scene1.3.110">I'll put myself in poor and mean attire</div>
+	  <div id="scene1.3.111">And with a kind of umber smirch my face;</div>
+	  <div id="scene1.3.112">The like do you: so shall we pass along</div>
+	  <div id="scene1.3.113">And never stir assailants.</div>
+	  </div>
+	  <div id="speech43" class="character">ROSALIND</div>
+	  <div class="dialog">
+	  <div id="scene1.3.114">Were it not better,</div>
+	  <div id="scene1.3.115">Because that I am more than common tall,</div>
+	  <div id="scene1.3.116">That I did suit me all points like a man?</div>
+	  <div id="scene1.3.117">A gallant curtle-axe upon my thigh,</div>
+	  <div id="scene1.3.118">A boar-spear in my hand; and--in my heart</div>
+	  <div id="scene1.3.119">Lie there what hidden woman's fear there will--</div>
+	  <div id="scene1.3.120">We'll have a swashing and a martial outside,</div>
+	  <div id="scene1.3.121">As many other mannish cowards have</div>
+	  <div id="scene1.3.122">That do outface it with their semblances.</div>
+	  </div>
+	  <div id="speech44" class="character">CELIA</div>
+	  <div class="dialog">
+	  <div id="scene1.3.123">What shall I call thee when thou art a man?</div>
+	  </div>
+	  <div id="speech45" class="character">ROSALIND</div>
+	  <div class="dialog">
+	  <div id="scene1.3.124">I'll have no worse a name than Jove's own page;</div>
+	  <div id="scene1.3.125">And therefore look you call me Ganymede.</div>
+	  <div id="scene1.3.126">But what will you be call'd?</div>
+	  </div>
+	  <div id="speech46" class="character">CELIA</div>
+	  <div class="dialog">
+	  <div id="scene1.3.127">Something that hath a reference to my state</div>
+	  <div id="scene1.3.128">No longer Celia, but Aliena.</div>
+	  </div>
+	  <div id="speech47" class="character">ROSALIND</div>
+	  <div class="dialog">
+	  <div id="scene1.3.129">But, cousin, what if we assay'd to steal</div>
+	  <div id="scene1.3.130">The clownish fool out of your father's court?</div>
+	  <div id="scene1.3.131">Would he not be a comfort to our travel?</div>
+	  </div>
+	  <div id="speech48" class="character">CELIA</div>
+	  <div class="dialog">
+	  <div id="scene1.3.132">He'll go along o'er the wide world with me;</div>
+	  <div id="scene1.3.133">Leave me alone to woo him. Let's away,</div>
+	  <div id="scene1.3.134">And get our jewels and our wealth together,</div>
+	  <div id="scene1.3.135">Devise the fittest time and safest way</div>
+	  <div id="scene1.3.136">To hide us from pursuit that will be made</div>
+	  <div id="scene1.3.137">After my flight. Now go we in content</div>
+	  <div id="scene1.3.138">To liberty and not to banishment.</div>
+	  <div class="direction">Exeunt</div>
+	  </div>
+	</div>
+	</div>
+</div>
+</body>
+</html>
diff --git a/vendor/symfony/css-selector/Symfony/Component/CssSelector/Tests/XPath/TranslatorTest.php b/vendor/symfony/css-selector/Symfony/Component/CssSelector/Tests/XPath/TranslatorTest.php
new file mode 100644
index 00000000000..30f7189f06f
--- /dev/null
+++ b/vendor/symfony/css-selector/Symfony/Component/CssSelector/Tests/XPath/TranslatorTest.php
@@ -0,0 +1,324 @@
+<?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\CssSelector\Tests\XPath;
+
+use Symfony\Component\CssSelector\XPath\Extension\HtmlExtension;
+use Symfony\Component\CssSelector\XPath\Translator;
+
+class TranslatorTest extends \PHPUnit_Framework_TestCase
+{
+    /** @dataProvider getXpathLiteralTestData */
+    public function testXpathLiteral($value, $literal)
+    {
+        $this->assertEquals($literal, Translator::getXpathLiteral($value));
+    }
+
+    /** @dataProvider getCssToXPathTestData */
+    public function testCssToXPath($css, $xpath)
+    {
+        $translator = new Translator();
+        $translator->registerExtension(new HtmlExtension($translator));
+        $this->assertEquals($xpath, $translator->cssToXPath($css, ''));
+    }
+
+    /** @dataProvider getXmlLangTestData */
+    public function testXmlLang($css, array $elementsId)
+    {
+        $translator = new Translator();
+        $document = new \SimpleXMLElement(file_get_contents(__DIR__.'/Fixtures/lang.xml'));
+        $elements = $document->xpath($translator->cssToXPath($css));
+        $this->assertEquals(count($elementsId), count($elements));
+        foreach ($elements as $element) {
+            $this->assertTrue(in_array($element->attributes()->id, $elementsId));
+        }
+    }
+
+    /** @dataProvider getHtmlIdsTestData */
+    public function testHtmlIds($css, array $elementsId)
+    {
+        $translator = new Translator();
+        $translator->registerExtension(new HtmlExtension($translator));
+        $document = new \DOMDocument();
+        $document->strictErrorChecking = false;
+        $internalErrors = libxml_use_internal_errors(true);
+        $document->loadHTMLFile(__DIR__.'/Fixtures/ids.html');
+        $document = simplexml_import_dom($document);
+        $elements = $document->xpath($translator->cssToXPath($css));
+        $this->assertCount(count($elementsId), $elementsId);
+        foreach ($elements as $element) {
+            if (null !== $element->attributes()->id) {
+                $this->assertTrue(in_array($element->attributes()->id, $elementsId));
+            }
+        }
+        libxml_clear_errors();
+        libxml_use_internal_errors($internalErrors);
+    }
+
+    /** @dataProvider getHtmlShakespearTestData */
+    public function testHtmlShakespear($css, $count)
+    {
+        $translator = new Translator();
+        $translator->registerExtension(new HtmlExtension($translator));
+        $document = new \DOMDocument();
+        $document->strictErrorChecking = false;
+        $document->loadHTMLFile(__DIR__.'/Fixtures/shakespear.html');
+        $document = simplexml_import_dom($document);
+        $bodies = $document->xpath('//body');
+        $elements = $bodies[0]->xpath($translator->cssToXPath($css));
+        $this->assertEquals($count, count($elements));
+    }
+
+    public function getXpathLiteralTestData()
+    {
+        return array(
+            array('foo', "'foo'"),
+            array("foo's bar", '"foo\'s bar"'),
+            array("foo's \"middle\" bar", 'concat(\'foo\', "\'", \'s "middle" bar\')'),
+            array("foo's 'middle' \"bar\"", 'concat(\'foo\', "\'", \'s \', "\'", \'middle\', "\'", \' "bar"\')'),
+        );
+    }
+
+    public function getCssToXPathTestData()
+    {
+        return array(
+            array('*', "*"),
+            array('e', "e"),
+            array('*|e', "e"),
+            array('e|f', "e:f"),
+            array('e[foo]', "e[@foo]"),
+            array('e[foo|bar]', "e[@foo:bar]"),
+            array('e[foo="bar"]', "e[@foo = 'bar']"),
+            array('e[foo~="bar"]', "e[@foo and contains(concat(' ', normalize-space(@foo), ' '), ' bar ')]"),
+            array('e[foo^="bar"]', "e[@foo and starts-with(@foo, 'bar')]"),
+            array('e[foo$="bar"]', "e[@foo and substring(@foo, string-length(@foo)-2) = 'bar']"),
+            array('e[foo*="bar"]', "e[@foo and contains(@foo, 'bar')]"),
+            array('e[hreflang|="en"]', "e[@hreflang and (@hreflang = 'en' or starts-with(@hreflang, 'en-'))]"),
+            array('e:nth-child(1)', "*/*[name() = 'e' and (position() = 1)]"),
+            array('e:nth-last-child(1)', "*/*[name() = 'e' and (position() = last() - 0)]"),
+            array('e:nth-last-child(2n+2)', "*/*[name() = 'e' and (last() - position() - 1 >= 0 and (last() - position() - 1) mod 2 = 0)]"),
+            array('e:nth-of-type(1)', "*/e[position() = 1]"),
+            array('e:nth-last-of-type(1)', "*/e[position() = last() - 0]"),
+            array('div e:nth-last-of-type(1) .aclass', "div/descendant-or-self::*/e[position() = last() - 0]/descendant-or-self::*/*[@class and contains(concat(' ', normalize-space(@class), ' '), ' aclass ')]"),
+            array('e:first-child', "*/*[name() = 'e' and (position() = 1)]"),
+            array('e:last-child', "*/*[name() = 'e' and (position() = last())]"),
+            array('e:first-of-type', "*/e[position() = 1]"),
+            array('e:last-of-type', "*/e[position() = last()]"),
+            array('e:only-child', "*/*[name() = 'e' and (last() = 1)]"),
+            array('e:only-of-type', "e[last() = 1]"),
+            array('e:empty', "e[not(*) and not(string-length())]"),
+            array('e:EmPTY', "e[not(*) and not(string-length())]"),
+            array('e:root', "e[not(parent::*)]"),
+            array('e:hover', "e[0]"),
+            array('e:contains("foo")', "e[contains(string(.), 'foo')]"),
+            array('e:ConTains(foo)', "e[contains(string(.), 'foo')]"),
+            array('e.warning', "e[@class and contains(concat(' ', normalize-space(@class), ' '), ' warning ')]"),
+            array('e#myid', "e[@id = 'myid']"),
+            array('e:not(:nth-child(odd))', "e[not(position() - 1 >= 0 and (position() - 1) mod 2 = 0)]"),
+            array('e:nOT(*)', "e[0]"),
+            array('e f', "e/descendant-or-self::*/f"),
+            array('e > f', "e/f"),
+            array('e + f', "e/following-sibling::*[name() = 'f' and (position() = 1)]"),
+            array('e ~ f', "e/following-sibling::f"),
+            array('div#container p', "div[@id = 'container']/descendant-or-self::*/p"),
+        );
+    }
+
+    public function getXmlLangTestData()
+    {
+        return array(
+            array(':lang("EN")', array('first', 'second', 'third', 'fourth')),
+            array(':lang("en-us")', array('second', 'fourth')),
+            array(':lang(en-nz)', array('third')),
+            array(':lang(fr)', array('fifth')),
+            array(':lang(ru)', array('sixth')),
+            array(":lang('ZH')", array('eighth')),
+            array(':lang(de) :lang(zh)', array('eighth')),
+            array(':lang(en), :lang(zh)', array('first', 'second', 'third', 'fourth', 'eighth')),
+            array(':lang(es)', array()),
+        );
+    }
+
+    public function getHtmlIdsTestData()
+    {
+        return array(
+            array('div', array('outer-div', 'li-div', 'foobar-div')),
+            array('DIV', array('outer-div', 'li-div', 'foobar-div')),  // case-insensitive in HTML
+            array('div div', array('li-div')),
+            array('div, div div', array('outer-div', 'li-div', 'foobar-div')),
+            array('a[name]', array('name-anchor')),
+            array('a[NAme]', array('name-anchor')), // case-insensitive in HTML:
+            array('a[rel]', array('tag-anchor', 'nofollow-anchor')),
+            array('a[rel="tag"]', array('tag-anchor')),
+            array('a[href*="localhost"]', array('tag-anchor')),
+            array('a[href*=""]', array()),
+            array('a[href^="http"]', array('tag-anchor', 'nofollow-anchor')),
+            array('a[href^="http:"]', array('tag-anchor')),
+            array('a[href^=""]', array()),
+            array('a[href$="org"]', array('nofollow-anchor')),
+            array('a[href$=""]', array()),
+            array('div[foobar~="bc"]', array('foobar-div')),
+            array('div[foobar~="cde"]', array('foobar-div')),
+            array('[foobar~="ab bc"]', array('foobar-div')),
+            array('[foobar~=""]', array()),
+            array('[foobar~=" \t"]', array()),
+            array('div[foobar~="cd"]', array()),
+            array('*[lang|="En"]', array('second-li')),
+            array('[lang|="En-us"]', array('second-li')),
+            // Attribute values are case sensitive
+            array('*[lang|="en"]', array()),
+            array('[lang|="en-US"]', array()),
+            array('*[lang|="e"]', array()),
+            // ... :lang() is not.
+            array(':lang("EN")', array('second-li', 'li-div')),
+            array('*:lang(en-US)', array('second-li', 'li-div')),
+            array(':lang("e")', array()),
+            array('li:nth-child(3)', array('third-li')),
+            array('li:nth-child(10)', array()),
+            array('li:nth-child(2n)', array('second-li', 'fourth-li', 'sixth-li')),
+            array('li:nth-child(even)', array('second-li', 'fourth-li', 'sixth-li')),
+            array('li:nth-child(2n+0)', array('second-li', 'fourth-li', 'sixth-li')),
+            array('li:nth-child(+2n+1)', array('first-li', 'third-li', 'fifth-li', 'seventh-li')),
+            array('li:nth-child(odd)', array('first-li', 'third-li', 'fifth-li', 'seventh-li')),
+            array('li:nth-child(2n+4)', array('fourth-li', 'sixth-li')),
+            array('li:nth-child(3n+1)', array('first-li', 'fourth-li', 'seventh-li')),
+            array('li:nth-child(n)', array('first-li', 'second-li', 'third-li', 'fourth-li', 'fifth-li', 'sixth-li', 'seventh-li')),
+            array('li:nth-child(n-1)', array('first-li', 'second-li', 'third-li', 'fourth-li', 'fifth-li', 'sixth-li', 'seventh-li')),
+            array('li:nth-child(n+1)', array('first-li', 'second-li', 'third-li', 'fourth-li', 'fifth-li', 'sixth-li', 'seventh-li')),
+            array('li:nth-child(n+3)', array('third-li', 'fourth-li', 'fifth-li', 'sixth-li', 'seventh-li')),
+            array('li:nth-child(-n)', array()),
+            array('li:nth-child(-n-1)', array()),
+            array('li:nth-child(-n+1)', array('first-li')),
+            array('li:nth-child(-n+3)', array('first-li', 'second-li', 'third-li')),
+            array('li:nth-last-child(0)', array()),
+            array('li:nth-last-child(2n)', array('second-li', 'fourth-li', 'sixth-li')),
+            array('li:nth-last-child(even)', array('second-li', 'fourth-li', 'sixth-li')),
+            array('li:nth-last-child(2n+2)', array('second-li', 'fourth-li', 'sixth-li')),
+            array('li:nth-last-child(n)', array('first-li', 'second-li', 'third-li', 'fourth-li', 'fifth-li', 'sixth-li', 'seventh-li')),
+            array('li:nth-last-child(n-1)', array('first-li', 'second-li', 'third-li', 'fourth-li', 'fifth-li', 'sixth-li', 'seventh-li')),
+            array('li:nth-last-child(n-3)', array('first-li', 'second-li', 'third-li', 'fourth-li', 'fifth-li', 'sixth-li', 'seventh-li')),
+            array('li:nth-last-child(n+1)', array('first-li', 'second-li', 'third-li', 'fourth-li', 'fifth-li', 'sixth-li', 'seventh-li')),
+            array('li:nth-last-child(n+3)', array('first-li', 'second-li', 'third-li', 'fourth-li', 'fifth-li')),
+            array('li:nth-last-child(-n)', array()),
+            array('li:nth-last-child(-n-1)', array()),
+            array('li:nth-last-child(-n+1)', array('seventh-li')),
+            array('li:nth-last-child(-n+3)', array('fifth-li', 'sixth-li', 'seventh-li')),
+            array('ol:first-of-type', array('first-ol')),
+            array('ol:nth-child(1)', array('first-ol')),
+            array('ol:nth-of-type(2)', array('second-ol')),
+            array('ol:nth-last-of-type(1)', array('second-ol')),
+            array('span:only-child', array('foobar-span')),
+            array('li div:only-child', array('li-div')),
+            array('div *:only-child', array('li-div', 'foobar-span')),
+            array('p:only-of-type', array('paragraph')),
+            array('a:empty', array('name-anchor')),
+            array('a:EMpty', array('name-anchor')),
+            array('li:empty', array('third-li', 'fourth-li', 'fifth-li', 'sixth-li')),
+            array(':root', array('html')),
+            array('html:root', array('html')),
+            array('li:root', array()),
+            array('* :root', array()),
+            array('*:contains("link")', array('html', 'outer-div', 'tag-anchor', 'nofollow-anchor')),
+            array(':CONtains("link")', array('html', 'outer-div', 'tag-anchor', 'nofollow-anchor')),
+            array('*:contains("LInk")', array()),  // case sensitive
+            array('*:contains("e")', array('html', 'nil', 'outer-div', 'first-ol', 'first-li', 'paragraph', 'p-em')),
+            array('*:contains("E")', array()),  // case-sensitive
+            array('.a', array('first-ol')),
+            array('.b', array('first-ol')),
+            array('*.a', array('first-ol')),
+            array('ol.a', array('first-ol')),
+            array('.c', array('first-ol', 'third-li', 'fourth-li')),
+            array('*.c', array('first-ol', 'third-li', 'fourth-li')),
+            array('ol *.c', array('third-li', 'fourth-li')),
+            array('ol li.c', array('third-li', 'fourth-li')),
+            array('li ~ li.c', array('third-li', 'fourth-li')),
+            array('ol > li.c', array('third-li', 'fourth-li')),
+            array('#first-li', array('first-li')),
+            array('li#first-li', array('first-li')),
+            array('*#first-li', array('first-li')),
+            array('li div', array('li-div')),
+            array('li > div', array('li-div')),
+            array('div div', array('li-div')),
+            array('div > div', array()),
+            array('div>.c', array('first-ol')),
+            array('div > .c', array('first-ol')),
+            array('div + div', array('foobar-div')),
+            array('a ~ a', array('tag-anchor', 'nofollow-anchor')),
+            array('a[rel="tag"] ~ a', array('nofollow-anchor')),
+            array('ol#first-ol li:last-child', array('seventh-li')),
+            array('ol#first-ol *:last-child', array('li-div', 'seventh-li')),
+            array('#outer-div:first-child', array('outer-div')),
+            array('#outer-div :first-child', array('name-anchor', 'first-li', 'li-div', 'p-b', 'checkbox-fieldset-disabled', 'area-href')),
+            array('a[href]', array('tag-anchor', 'nofollow-anchor')),
+            array(':not(*)', array()),
+            array('a:not([href])', array('name-anchor')),
+            array('ol :Not(li[class])', array('first-li', 'second-li', 'li-div', 'fifth-li', 'sixth-li', 'seventh-li')),
+            // HTML-specific
+            array(':link', array('link-href', 'tag-anchor', 'nofollow-anchor', 'area-href')),
+            array(':visited', array()),
+            array(':enabled', array('link-href', 'tag-anchor', 'nofollow-anchor', 'checkbox-unchecked', 'text-checked', 'checkbox-checked', 'area-href')),
+            array(':disabled', array('checkbox-disabled', 'checkbox-disabled-checked', 'fieldset', 'checkbox-fieldset-disabled')),
+            array(':checked', array('checkbox-checked', 'checkbox-disabled-checked')),
+        );
+    }
+
+    public function getHtmlShakespearTestData()
+    {
+        return array(
+            array('*', 246),
+            array('div:contains(CELIA)', 26),
+            array('div:only-child', 22), // ?
+            array('div:nth-child(even)', 106),
+            array('div:nth-child(2n)', 106),
+            array('div:nth-child(odd)', 137),
+            array('div:nth-child(2n+1)', 137),
+            array('div:nth-child(n)', 243),
+            array('div:last-child', 53),
+            array('div:first-child', 51),
+            array('div > div', 242),
+            array('div + div', 190),
+            array('div ~ div', 190),
+            array('body', 1),
+            array('body div', 243),
+            array('div', 243),
+            array('div div', 242),
+            array('div div div', 241),
+            array('div, div, div', 243),
+            array('div, a, span', 243),
+            array('.dialog', 51),
+            array('div.dialog', 51),
+            array('div .dialog', 51),
+            array('div.character, div.dialog', 99),
+            array('div.direction.dialog', 0),
+            array('div.dialog.direction', 0),
+            array('div.dialog.scene', 1),
+            array('div.scene.scene', 1),
+            array('div.scene .scene', 0),
+            array('div.direction .dialog ', 0),
+            array('div .dialog .direction', 4),
+            array('div.dialog .dialog .direction', 4),
+            array('#speech5', 1),
+            array('div#speech5', 1),
+            array('div #speech5', 1),
+            array('div.scene div.dialog', 49),
+            array('div#scene1 div.dialog div', 142),
+            array('#scene1 #speech1', 1),
+            array('div[class]', 103),
+            array('div[class=dialog]', 50),
+            array('div[class^=dia]', 51),
+            array('div[class$=log]', 50),
+            array('div[class*=sce]', 1),
+            array('div[class|=dialog]', 50), // ? Seems right
+            array('div[class!=madeup]', 243), // ? Seems right
+            array('div[class~=dialog]', 51), // ? Seems right
+        );
+    }
+}
diff --git a/vendor/symfony/css-selector/Symfony/Component/CssSelector/XPath/Extension/AbstractExtension.php b/vendor/symfony/css-selector/Symfony/Component/CssSelector/XPath/Extension/AbstractExtension.php
new file mode 100644
index 00000000000..1b147e9ecf6
--- /dev/null
+++ b/vendor/symfony/css-selector/Symfony/Component/CssSelector/XPath/Extension/AbstractExtension.php
@@ -0,0 +1,63 @@
+<?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\CssSelector\XPath\Extension;
+
+/**
+ * XPath expression translator abstract extension.
+ *
+ * This component is a port of the Python cssselector library,
+ * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect.
+ *
+ * @author Jean-François Simon <jeanfrancois.simon@sensiolabs.com>
+ */
+abstract class AbstractExtension implements ExtensionInterface
+{
+    /**
+     * {@inheritdoc}
+     */
+    public function getNodeTranslators()
+    {
+        return array();
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function getCombinationTranslators()
+    {
+        return array();
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function getFunctionTranslators()
+    {
+        return array();
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function getPseudoClassTranslators()
+    {
+        return array();
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function getAttributeMatchingTranslators()
+    {
+        return array();
+    }
+}
diff --git a/vendor/symfony/css-selector/Symfony/Component/CssSelector/XPath/Extension/AttributeMatchingExtension.php b/vendor/symfony/css-selector/Symfony/Component/CssSelector/XPath/Extension/AttributeMatchingExtension.php
new file mode 100644
index 00000000000..1b1f00f2863
--- /dev/null
+++ b/vendor/symfony/css-selector/Symfony/Component/CssSelector/XPath/Extension/AttributeMatchingExtension.php
@@ -0,0 +1,173 @@
+<?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\CssSelector\XPath\Extension;
+
+use Symfony\Component\CssSelector\XPath\Translator;
+use Symfony\Component\CssSelector\XPath\XPathExpr;
+
+/**
+ * XPath expression translator attribute extension.
+ *
+ * This component is a port of the Python cssselector library,
+ * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect.
+ *
+ * @author Jean-François Simon <jeanfrancois.simon@sensiolabs.com>
+ */
+class AttributeMatchingExtension extends AbstractExtension
+{
+    /**
+     * {@inheritdoc}
+     */
+    public function getAttributeMatchingTranslators()
+    {
+        return array(
+            'exists' => array($this, 'translateExists'),
+            '='      => array($this, 'translateEquals'),
+            '~='     => array($this, 'translateIncludes'),
+            '|='     => array($this, 'translateDashMatch'),
+            '^='     => array($this, 'translatePrefixMatch'),
+            '$='     => array($this, 'translateSuffixMatch'),
+            '*='     => array($this, 'translateSubstringMatch'),
+            '!='     => array($this, 'translateDifferent'),
+        );
+    }
+
+    /**
+     * @param XPathExpr $xpath
+     * @param string    $attribute
+     * @param string    $value
+     *
+     * @return XPathExpr
+     */
+    public function translateExists(XPathExpr $xpath, $attribute, $value)
+    {
+        return $xpath->addCondition($attribute);
+    }
+
+    /**
+     * @param XPathExpr $xpath
+     * @param string    $attribute
+     * @param string    $value
+     *
+     * @return XPathExpr
+     */
+    public function translateEquals(XPathExpr $xpath, $attribute, $value)
+    {
+        return $xpath->addCondition(sprintf('%s = %s', $attribute, Translator::getXpathLiteral($value)));
+    }
+
+    /**
+     * @param XPathExpr $xpath
+     * @param string    $attribute
+     * @param string    $value
+     *
+     * @return XPathExpr
+     */
+    public function translateIncludes(XPathExpr $xpath, $attribute, $value)
+    {
+        return $xpath->addCondition($value ? sprintf(
+            '%1$s and contains(concat(\' \', normalize-space(%1$s), \' \'), %2$s)',
+            $attribute,
+            Translator::getXpathLiteral(' '.$value.' ')
+        ) : '0');
+    }
+
+    /**
+     * @param XPathExpr $xpath
+     * @param string    $attribute
+     * @param string    $value
+     *
+     * @return XPathExpr
+     */
+    public function translateDashMatch(XPathExpr $xpath, $attribute, $value)
+    {
+        return $xpath->addCondition(sprintf(
+            '%1$s and (%1$s = %2$s or starts-with(%1$s, %3$s))',
+            $attribute,
+            Translator::getXpathLiteral($value),
+            Translator::getXpathLiteral($value.'-')
+        ));
+    }
+
+    /**
+     * @param XPathExpr $xpath
+     * @param string    $attribute
+     * @param string    $value
+     *
+     * @return XPathExpr
+     */
+    public function translatePrefixMatch(XPathExpr $xpath, $attribute, $value)
+    {
+        return $xpath->addCondition($value ? sprintf(
+            '%1$s and starts-with(%1$s, %2$s)',
+            $attribute,
+            Translator::getXpathLiteral($value)
+        ) : '0');
+    }
+
+    /**
+     * @param XPathExpr $xpath
+     * @param string    $attribute
+     * @param string    $value
+     *
+     * @return XPathExpr
+     */
+    public function translateSuffixMatch(XPathExpr $xpath, $attribute, $value)
+    {
+        return $xpath->addCondition($value ? sprintf(
+            '%1$s and substring(%1$s, string-length(%1$s)-%2$s) = %3$s',
+            $attribute,
+            strlen($value) - 1,
+            Translator::getXpathLiteral($value)
+        ) : '0');
+    }
+
+    /**
+     * @param XPathExpr $xpath
+     * @param string    $attribute
+     * @param string    $value
+     *
+     * @return XPathExpr
+     */
+    public function translateSubstringMatch(XPathExpr $xpath, $attribute, $value)
+    {
+        return $xpath->addCondition($value ? sprintf(
+            '%1$s and contains(%1$s, %2$s)',
+            $attribute,
+            Translator::getXpathLiteral($value)
+        ) : '0');
+    }
+
+    /**
+     * @param XPathExpr $xpath
+     * @param string    $attribute
+     * @param string    $value
+     *
+     * @return XPathExpr
+     */
+    public function translateDifferent(XPathExpr $xpath, $attribute, $value)
+    {
+        return $xpath->addCondition(sprintf(
+            $value ? 'not(%1$s) or %1$s != %2$s' : '%s != %s',
+            $attribute,
+            Translator::getXpathLiteral($value)
+        ));
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function getName()
+    {
+        return 'attribute-matching';
+    }
+}
diff --git a/vendor/symfony/css-selector/Symfony/Component/CssSelector/XPath/Extension/CombinationExtension.php b/vendor/symfony/css-selector/Symfony/Component/CssSelector/XPath/Extension/CombinationExtension.php
new file mode 100644
index 00000000000..639e9249521
--- /dev/null
+++ b/vendor/symfony/css-selector/Symfony/Component/CssSelector/XPath/Extension/CombinationExtension.php
@@ -0,0 +1,93 @@
+<?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\CssSelector\XPath\Extension;
+
+use Symfony\Component\CssSelector\XPath\XPathExpr;
+
+/**
+ * XPath expression translator combination extension.
+ *
+ * This component is a port of the Python cssselector library,
+ * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect.
+ *
+ * @author Jean-François Simon <jeanfrancois.simon@sensiolabs.com>
+ */
+class CombinationExtension extends AbstractExtension
+{
+    /**
+     * {@inheritdoc}
+     */
+    public function getCombinationTranslators()
+    {
+        return array(
+            ' ' => array($this, 'translateDescendant'),
+            '>' => array($this, 'translateChild'),
+            '+' => array($this, 'translateDirectAdjacent'),
+            '~' => array($this, 'translateIndirectAdjacent'),
+        );
+    }
+
+    /**
+     * @param XPathExpr $xpath
+     * @param XPathExpr $combinedXpath
+     *
+     * @return XPathExpr
+     */
+    public function translateDescendant(XPathExpr $xpath, XPathExpr $combinedXpath)
+    {
+        return $xpath->join('/descendant-or-self::*/', $combinedXpath);
+    }
+
+    /**
+     * @param XPathExpr $xpath
+     * @param XPathExpr $combinedXpath
+     *
+     * @return XPathExpr
+     */
+    public function translateChild(XPathExpr $xpath, XPathExpr $combinedXpath)
+    {
+        return $xpath->join('/', $combinedXpath);
+    }
+
+    /**
+     * @param XPathExpr $xpath
+     * @param XPathExpr $combinedXpath
+     *
+     * @return XPathExpr
+     */
+    public function translateDirectAdjacent(XPathExpr $xpath, XPathExpr $combinedXpath)
+    {
+        return $xpath
+            ->join('/following-sibling::', $combinedXpath)
+            ->addNameTest()
+            ->addCondition('position() = 1');
+    }
+
+    /**
+     * @param XPathExpr $xpath
+     * @param XPathExpr $combinedXpath
+     *
+     * @return XPathExpr
+     */
+    public function translateIndirectAdjacent(XPathExpr $xpath, XPathExpr $combinedXpath)
+    {
+        return $xpath->join('/following-sibling::', $combinedXpath);
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function getName()
+    {
+        return 'combination';
+    }
+}
diff --git a/vendor/symfony/css-selector/Symfony/Component/CssSelector/XPath/Extension/ExtensionInterface.php b/vendor/symfony/css-selector/Symfony/Component/CssSelector/XPath/Extension/ExtensionInterface.php
new file mode 100644
index 00000000000..22312659429
--- /dev/null
+++ b/vendor/symfony/css-selector/Symfony/Component/CssSelector/XPath/Extension/ExtensionInterface.php
@@ -0,0 +1,67 @@
+<?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\CssSelector\XPath\Extension;
+
+/**
+ * XPath expression translator extension interface.
+ *
+ * This component is a port of the Python cssselector library,
+ * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect.
+ *
+ * @author Jean-François Simon <jeanfrancois.simon@sensiolabs.com>
+ */
+interface ExtensionInterface
+{
+    /**
+     * Returns node translators.
+     *
+     * These callables will receive the node as first argument and the translator as second argument.
+     *
+     * @return callable[]
+     */
+    public function getNodeTranslators();
+
+    /**
+     * Returns combination translators.
+     *
+     * @return callable[]
+     */
+    public function getCombinationTranslators();
+
+    /**
+     * Returns function translators.
+     *
+     * @return callable[]
+     */
+    public function getFunctionTranslators();
+
+    /**
+     * Returns pseudo-class translators.
+     *
+     * @return callable[]
+     */
+    public function getPseudoClassTranslators();
+
+    /**
+     * Returns attribute operation translators.
+     *
+     * @return callable[]
+     */
+    public function getAttributeMatchingTranslators();
+
+    /**
+     * Returns extension name.
+     *
+     * @return string
+     */
+    public function getName();
+}
diff --git a/vendor/symfony/css-selector/Symfony/Component/CssSelector/XPath/Extension/FunctionExtension.php b/vendor/symfony/css-selector/Symfony/Component/CssSelector/XPath/Extension/FunctionExtension.php
new file mode 100644
index 00000000000..ff8f333ada0
--- /dev/null
+++ b/vendor/symfony/css-selector/Symfony/Component/CssSelector/XPath/Extension/FunctionExtension.php
@@ -0,0 +1,209 @@
+<?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\CssSelector\XPath\Extension;
+
+use Symfony\Component\CssSelector\Exception\ExpressionErrorException;
+use Symfony\Component\CssSelector\Exception\SyntaxErrorException;
+use Symfony\Component\CssSelector\Node\FunctionNode;
+use Symfony\Component\CssSelector\Parser\Parser;
+use Symfony\Component\CssSelector\XPath\Translator;
+use Symfony\Component\CssSelector\XPath\XPathExpr;
+
+/**
+ * XPath expression translator function extension.
+ *
+ * This component is a port of the Python cssselector library,
+ * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect.
+ *
+ * @author Jean-François Simon <jeanfrancois.simon@sensiolabs.com>
+ */
+class FunctionExtension extends AbstractExtension
+{
+    /**
+     * {@inheritdoc}
+     */
+    public function getFunctionTranslators()
+    {
+        return array(
+            'nth-child'        => array($this, 'translateNthChild'),
+            'nth-last-child'   => array($this, 'translateNthLastChild'),
+            'nth-of-type'      => array($this, 'translateNthOfType'),
+            'nth-last-of-type' => array($this, 'translateNthLastOfType'),
+            'contains'         => array($this, 'translateContains'),
+            'lang'             => array($this, 'translateLang'),
+        );
+    }
+
+    /**
+     * @param XPathExpr    $xpath
+     * @param FunctionNode $function
+     * @param bool         $last
+     * @param bool         $addNameTest
+     *
+     * @return XPathExpr
+     *
+     * @throws ExpressionErrorException
+     */
+    public function translateNthChild(XPathExpr $xpath, FunctionNode $function, $last = false, $addNameTest = true)
+    {
+        try {
+            list($a, $b) = Parser::parseSeries($function->getArguments());
+        } catch (SyntaxErrorException $e) {
+            throw new ExpressionErrorException(sprintf('Invalid series: %s', implode(', ', $function->getArguments())), 0, $e);
+        }
+
+        $xpath->addStarPrefix();
+        if ($addNameTest) {
+            $xpath->addNameTest();
+        }
+
+        if (0 === $a) {
+            return $xpath->addCondition('position() = '.($last ? 'last() - '.($b - 1) : $b));
+        }
+
+        if ($a < 0) {
+            if ($b < 1) {
+                return $xpath->addCondition('false()');
+            }
+
+            $sign = '<=';
+        } else {
+            $sign = '>=';
+        }
+
+        $expr = 'position()';
+
+        if ($last) {
+            $expr = 'last() - '.$expr;
+            $b--;
+        }
+
+        if (0 !== $b) {
+            $expr .= ' - '.$b;
+        }
+
+        $conditions = array(sprintf('%s %s 0', $expr, $sign));
+
+        if (1 !== $a && -1 !== $a) {
+            $conditions[] = sprintf('(%s) mod %d = 0', $expr, $a);
+        }
+
+        return $xpath->addCondition(implode(' and ', $conditions));
+
+        // todo: handle an+b, odd, even
+        // an+b means every-a, plus b, e.g., 2n+1 means odd
+        // 0n+b means b
+        // n+0 means a=1, i.e., all elements
+        // an means every a elements, i.e., 2n means even
+        // -n means -1n
+        // -1n+6 means elements 6 and previous
+    }
+
+    /**
+     * @param XPathExpr    $xpath
+     * @param FunctionNode $function
+     *
+     * @return XPathExpr
+     */
+    public function translateNthLastChild(XPathExpr $xpath, FunctionNode $function)
+    {
+        return $this->translateNthChild($xpath, $function, true);
+    }
+
+    /**
+     * @param XPathExpr    $xpath
+     * @param FunctionNode $function
+     *
+     * @return XPathExpr
+     */
+    public function translateNthOfType(XPathExpr $xpath, FunctionNode $function)
+    {
+        return $this->translateNthChild($xpath, $function, false, false);
+    }
+
+    /**
+     * @param XPathExpr    $xpath
+     * @param FunctionNode $function
+     *
+     * @return XPathExpr
+     *
+     * @throws ExpressionErrorException
+     */
+    public function translateNthLastOfType(XPathExpr $xpath, FunctionNode $function)
+    {
+        if ('*' === $xpath->getElement()) {
+            throw new ExpressionErrorException('"*:nth-of-type()" is not implemented.');
+        }
+
+        return $this->translateNthChild($xpath, $function, true, false);
+    }
+
+    /**
+     * @param XPathExpr    $xpath
+     * @param FunctionNode $function
+     *
+     * @return XPathExpr
+     *
+     * @throws ExpressionErrorException
+     */
+    public function translateContains(XPathExpr $xpath, FunctionNode $function)
+    {
+        $arguments = $function->getArguments();
+        foreach ($arguments as $token) {
+            if (!($token->isString() || $token->isIdentifier())) {
+                throw new ExpressionErrorException(
+                    'Expected a single string or identifier for :contains(), got '
+                    .implode(', ', $arguments)
+                );
+            }
+        }
+
+        return $xpath->addCondition(sprintf(
+            'contains(string(.), %s)',
+            Translator::getXpathLiteral($arguments[0]->getValue())
+        ));
+    }
+
+    /**
+     * @param XPathExpr    $xpath
+     * @param FunctionNode $function
+     *
+     * @return XPathExpr
+     *
+     * @throws ExpressionErrorException
+     */
+    public function translateLang(XPathExpr $xpath, FunctionNode $function)
+    {
+        $arguments = $function->getArguments();
+        foreach ($arguments as $token) {
+            if (!($token->isString() || $token->isIdentifier())) {
+                throw new ExpressionErrorException(
+                    'Expected a single string or identifier for :lang(), got '
+                    .implode(', ', $arguments)
+                );
+            }
+        }
+
+        return $xpath->addCondition(sprintf(
+            'lang(%s)',
+            Translator::getXpathLiteral($arguments[0]->getValue())
+        ));
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function getName()
+    {
+        return 'function';
+    }
+}
diff --git a/vendor/symfony/css-selector/Symfony/Component/CssSelector/XPath/Extension/HtmlExtension.php b/vendor/symfony/css-selector/Symfony/Component/CssSelector/XPath/Extension/HtmlExtension.php
new file mode 100644
index 00000000000..aef80523dd0
--- /dev/null
+++ b/vendor/symfony/css-selector/Symfony/Component/CssSelector/XPath/Extension/HtmlExtension.php
@@ -0,0 +1,238 @@
+<?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\CssSelector\XPath\Extension;
+
+use Symfony\Component\CssSelector\Exception\ExpressionErrorException;
+use Symfony\Component\CssSelector\Node\FunctionNode;
+use Symfony\Component\CssSelector\XPath\Translator;
+use Symfony\Component\CssSelector\XPath\XPathExpr;
+
+/**
+ * XPath expression translator HTML extension.
+ *
+ * This component is a port of the Python cssselector library,
+ * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect.
+ *
+ * @author Jean-François Simon <jeanfrancois.simon@sensiolabs.com>
+ */
+class HtmlExtension extends AbstractExtension
+{
+    /**
+     * Constructor.
+     *
+     * @param Translator $translator
+     */
+    public function __construct(Translator $translator)
+    {
+        $translator
+            ->getExtension('node')
+            ->setFlag(NodeExtension::ELEMENT_NAME_IN_LOWER_CASE, true)
+            ->setFlag(NodeExtension::ATTRIBUTE_NAME_IN_LOWER_CASE, true);
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function getPseudoClassTranslators()
+    {
+        return array(
+            'checked'  => array($this, 'translateChecked'),
+            'link'     => array($this, 'translateLink'),
+            'disabled' => array($this, 'translateDisabled'),
+            'enabled'  => array($this, 'translateEnabled'),
+            'selected' => array($this, 'translateSelected'),
+            'invalid'  => array($this, 'translateInvalid'),
+            'hover'    => array($this, 'translateHover'),
+            'visited'  => array($this, 'translateVisited'),
+        );
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function getFunctionTranslators()
+    {
+        return array(
+            'lang' => array($this, 'translateLang'),
+        );
+    }
+
+    /**
+     * @param XPathExpr $xpath
+     *
+     * @return XPathExpr
+     */
+    public function translateChecked(XPathExpr $xpath)
+    {
+        return $xpath->addCondition(
+            '(@checked '
+            ."and (name(.) = 'input' or name(.) = 'command')"
+            ."and (@type = 'checkbox' or @type = 'radio'))"
+        );
+    }
+
+    /**
+     * @param XPathExpr $xpath
+     *
+     * @return XPathExpr
+     */
+    public function translateLink(XPathExpr $xpath)
+    {
+        return $xpath->addCondition("@href and (name(.) = 'a' or name(.) = 'link' or name(.) = 'area')");
+    }
+
+    /**
+     * @param XPathExpr $xpath
+     *
+     * @return XPathExpr
+     */
+    public function translateDisabled(XPathExpr $xpath)
+    {
+        return $xpath->addCondition(
+            "("
+                ."@disabled and"
+                ."("
+                    ."(name(.) = 'input' and @type != 'hidden')"
+                    ." or name(.) = 'button'"
+                    ." or name(.) = 'select'"
+                    ." or name(.) = 'textarea'"
+                    ." or name(.) = 'command'"
+                    ." or name(.) = 'fieldset'"
+                    ." or name(.) = 'optgroup'"
+                    ." or name(.) = 'option'"
+                .")"
+            .") or ("
+                ."(name(.) = 'input' and @type != 'hidden')"
+                ." or name(.) = 'button'"
+                ." or name(.) = 'select'"
+                ." or name(.) = 'textarea'"
+            .")"
+            ." and ancestor::fieldset[@disabled]"
+        );
+        // todo: in the second half, add "and is not a descendant of that fieldset element's first legend element child, if any."
+    }
+
+    /**
+     * @param XPathExpr $xpath
+     *
+     * @return XPathExpr
+     */
+    public function translateEnabled(XPathExpr $xpath)
+    {
+        return $xpath->addCondition(
+            '('
+                .'@href and ('
+                    ."name(.) = 'a'"
+                    ." or name(.) = 'link'"
+                    ." or name(.) = 'area'"
+                .')'
+            .') or ('
+                .'('
+                    ."name(.) = 'command'"
+                    ." or name(.) = 'fieldset'"
+                    ." or name(.) = 'optgroup'"
+                .')'
+                .' and not(@disabled)'
+            .') or ('
+                .'('
+                    ."(name(.) = 'input' and @type != 'hidden')"
+                    ." or name(.) = 'button'"
+                    ." or name(.) = 'select'"
+                    ." or name(.) = 'textarea'"
+                    ." or name(.) = 'keygen'"
+                .')'
+                ." and not (@disabled or ancestor::fieldset[@disabled])"
+            .') or ('
+                ."name(.) = 'option' and not("
+                    ."@disabled or ancestor::optgroup[@disabled]"
+                .')'
+            .')'
+        );
+    }
+
+    /**
+     * @param XPathExpr    $xpath
+     * @param FunctionNode $function
+     *
+     * @return XPathExpr
+     *
+     * @throws ExpressionErrorException
+     */
+    public function translateLang(XPathExpr $xpath, FunctionNode $function)
+    {
+        $arguments = $function->getArguments();
+        foreach ($arguments as $token) {
+            if (!($token->isString() || $token->isIdentifier())) {
+                throw new ExpressionErrorException(
+                    'Expected a single string or identifier for :lang(), got '
+                    .implode(', ', $arguments)
+                );
+            }
+        }
+
+        return $xpath->addCondition(sprintf(
+            'ancestor-or-self::*[@lang][1][starts-with(concat('
+            ."translate(@%s, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz'), '-')"
+            .', %s)]',
+            'lang',
+            Translator::getXpathLiteral(strtolower($arguments[0]->getValue()).'-')
+        ));
+    }
+
+    /**
+     * @param XPathExpr $xpath
+     *
+     * @return XPathExpr
+     */
+    public function translateSelected(XPathExpr $xpath)
+    {
+        return $xpath->addCondition("(@selected and name(.) = 'option')");
+    }
+
+    /**
+     * @param XPathExpr $xpath
+     *
+     * @return XPathExpr
+     */
+    public function translateInvalid(XPathExpr $xpath)
+    {
+        return $xpath->addCondition('0');
+    }
+
+    /**
+     * @param XPathExpr $xpath
+     *
+     * @return XPathExpr
+     */
+    public function translateHover(XPathExpr $xpath)
+    {
+        return $xpath->addCondition('0');
+    }
+
+    /**
+     * @param XPathExpr $xpath
+     *
+     * @return XPathExpr
+     */
+    public function translateVisited(XPathExpr $xpath)
+    {
+        return $xpath->addCondition('0');
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function getName()
+    {
+        return 'html';
+    }
+}
diff --git a/vendor/symfony/css-selector/Symfony/Component/CssSelector/XPath/Extension/NodeExtension.php b/vendor/symfony/css-selector/Symfony/Component/CssSelector/XPath/Extension/NodeExtension.php
new file mode 100644
index 00000000000..d71baaa96bc
--- /dev/null
+++ b/vendor/symfony/css-selector/Symfony/Component/CssSelector/XPath/Extension/NodeExtension.php
@@ -0,0 +1,271 @@
+<?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\CssSelector\XPath\Extension;
+
+use Symfony\Component\CssSelector\Node;
+use Symfony\Component\CssSelector\XPath\Translator;
+use Symfony\Component\CssSelector\XPath\XPathExpr;
+
+/**
+ * XPath expression translator node extension.
+ *
+ * This component is a port of the Python cssselector library,
+ * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect.
+ *
+ * @author Jean-François Simon <jeanfrancois.simon@sensiolabs.com>
+ */
+class NodeExtension extends AbstractExtension
+{
+    const ELEMENT_NAME_IN_LOWER_CASE    = 1;
+    const ATTRIBUTE_NAME_IN_LOWER_CASE  = 2;
+    const ATTRIBUTE_VALUE_IN_LOWER_CASE = 4;
+
+    /**
+     * @var int
+     */
+    private $flags;
+
+    /**
+     * Constructor.
+     *
+     * @param int $flags
+     */
+    public function __construct($flags = 0)
+    {
+        $this->flags = $flags;
+    }
+
+    /**
+     * @param int     $flag
+     * @param bool    $on
+     *
+     * @return NodeExtension
+     */
+    public function setFlag($flag, $on)
+    {
+        if ($on && !$this->hasFlag($flag)) {
+            $this->flags += $flag;
+        }
+
+        if (!$on && $this->hasFlag($flag)) {
+            $this->flags -= $flag;
+        }
+
+        return $this;
+    }
+
+    /**
+     * @param int $flag
+     *
+     * @return bool
+     */
+    public function hasFlag($flag)
+    {
+        return $this->flags & $flag;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function getNodeTranslators()
+    {
+        return array(
+            'Selector'         => array($this, 'translateSelector'),
+            'CombinedSelector' => array($this, 'translateCombinedSelector'),
+            'Negation'         => array($this, 'translateNegation'),
+            'Function'         => array($this, 'translateFunction'),
+            'Pseudo'           => array($this, 'translatePseudo'),
+            'Attribute'        => array($this, 'translateAttribute'),
+            'Class'            => array($this, 'translateClass'),
+            'Hash'             => array($this, 'translateHash'),
+            'Element'          => array($this, 'translateElement'),
+        );
+    }
+
+    /**
+     * @param Node\SelectorNode $node
+     * @param Translator        $translator
+     *
+     * @return XPathExpr
+     */
+    public function translateSelector(Node\SelectorNode $node, Translator $translator)
+    {
+        return $translator->nodeToXPath($node->getTree());
+    }
+
+    /**
+     * @param Node\CombinedSelectorNode $node
+     * @param Translator                $translator
+     *
+     * @return XPathExpr
+     */
+    public function translateCombinedSelector(Node\CombinedSelectorNode $node, Translator $translator)
+    {
+        return $translator->addCombination($node->getCombinator(), $node->getSelector(), $node->getSubSelector());
+    }
+
+    /**
+     * @param Node\NegationNode $node
+     * @param Translator        $translator
+     *
+     * @return XPathExpr
+     */
+    public function translateNegation(Node\NegationNode $node, Translator $translator)
+    {
+        $xpath = $translator->nodeToXPath($node->getSelector());
+        $subXpath = $translator->nodeToXPath($node->getSubSelector());
+        $subXpath->addNameTest();
+
+        if ($subXpath->getCondition()) {
+            return $xpath->addCondition(sprintf('not(%s)', $subXpath->getCondition()));
+        }
+
+        return $xpath->addCondition('0');
+    }
+
+    /**
+     * @param Node\FunctionNode $node
+     * @param Translator        $translator
+     *
+     * @return XPathExpr
+     */
+    public function translateFunction(Node\FunctionNode $node, Translator $translator)
+    {
+        $xpath = $translator->nodeToXPath($node->getSelector());
+
+        return $translator->addFunction($xpath, $node);
+    }
+
+    /**
+     * @param Node\PseudoNode $node
+     * @param Translator      $translator
+     *
+     * @return XPathExpr
+     */
+    public function translatePseudo(Node\PseudoNode $node, Translator $translator)
+    {
+        $xpath = $translator->nodeToXPath($node->getSelector());
+
+        return $translator->addPseudoClass($xpath, $node->getIdentifier());
+    }
+
+    /**
+     * @param Node\AttributeNode $node
+     * @param Translator         $translator
+     *
+     * @return XPathExpr
+     */
+    public function translateAttribute(Node\AttributeNode $node, Translator $translator)
+    {
+        $name = $node->getAttribute();
+        $safe = $this->isSafeName($name);
+
+        if ($this->hasFlag(self::ATTRIBUTE_NAME_IN_LOWER_CASE)) {
+            $name = strtolower($name);
+        }
+
+        if ($node->getNamespace()) {
+            $name = sprintf('%s:%s', $node->getNamespace(), $name);
+            $safe = $safe && $this->isSafeName($node->getNamespace());
+        }
+
+        $attribute = $safe ? '@'.$name : sprintf('attribute::*[name() = %s]', Translator::getXpathLiteral($name));
+        $value = $node->getValue();
+        $xpath = $translator->nodeToXPath($node->getSelector());
+
+        if ($this->hasFlag(self::ATTRIBUTE_VALUE_IN_LOWER_CASE)) {
+            $value = strtolower($value);
+        }
+
+        return $translator->addAttributeMatching($xpath, $node->getOperator(), $attribute, $value);
+    }
+
+    /**
+     * @param Node\ClassNode $node
+     * @param Translator     $translator
+     *
+     * @return XPathExpr
+     */
+    public function translateClass(Node\ClassNode $node, Translator $translator)
+    {
+        $xpath = $translator->nodeToXPath($node->getSelector());
+
+        return $translator->addAttributeMatching($xpath, '~=', '@class', $node->getName());
+    }
+
+    /**
+     * @param Node\HashNode $node
+     * @param Translator    $translator
+     *
+     * @return XPathExpr
+     */
+    public function translateHash(Node\HashNode $node, Translator $translator)
+    {
+        $xpath = $translator->nodeToXPath($node->getSelector());
+
+        return $translator->addAttributeMatching($xpath, '=', '@id', $node->getId());
+    }
+
+    /**
+     * @param Node\ElementNode $node
+     *
+     * @return XPathExpr
+     */
+    public function translateElement(Node\ElementNode $node)
+    {
+        $element = $node->getElement();
+
+        if ($this->hasFlag(self::ELEMENT_NAME_IN_LOWER_CASE)) {
+            $element = strtolower($element);
+        }
+
+        if ($element) {
+            $safe = $this->isSafeName($element);
+        } else {
+            $element = '*';
+            $safe = true;
+        }
+
+        if ($node->getNamespace()) {
+            $element = sprintf('%s:%s', $node->getNamespace(), $element);
+            $safe = $safe && $this->isSafeName($node->getNamespace());
+        }
+
+        $xpath = new XPathExpr('', $element);
+
+        if (!$safe) {
+            $xpath->addNameTest();
+        }
+
+        return $xpath;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function getName()
+    {
+        return 'node';
+    }
+
+    /**
+     * Tests if given name is safe.
+     *
+     * @param string $name
+     *
+     * @return bool
+     */
+    private function isSafeName($name)
+    {
+        return 0 < preg_match('~^[a-zA-Z_][a-zA-Z0-9_.-]*$~', $name);
+    }
+}
diff --git a/vendor/symfony/css-selector/Symfony/Component/CssSelector/XPath/Extension/PseudoClassExtension.php b/vendor/symfony/css-selector/Symfony/Component/CssSelector/XPath/Extension/PseudoClassExtension.php
new file mode 100644
index 00000000000..d230dd7c483
--- /dev/null
+++ b/vendor/symfony/css-selector/Symfony/Component/CssSelector/XPath/Extension/PseudoClassExtension.php
@@ -0,0 +1,162 @@
+<?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\CssSelector\XPath\Extension;
+
+use Symfony\Component\CssSelector\Exception\ExpressionErrorException;
+use Symfony\Component\CssSelector\XPath\XPathExpr;
+
+/**
+ * XPath expression translator pseudo-class extension.
+ *
+ * This component is a port of the Python cssselector library,
+ * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect.
+ *
+ * @author Jean-François Simon <jeanfrancois.simon@sensiolabs.com>
+ */
+class PseudoClassExtension extends AbstractExtension
+{
+    /**
+     * {@inheritdoc}
+     */
+    public function getPseudoClassTranslators()
+    {
+        return array(
+            'root'          => array($this, 'translateRoot'),
+            'first-child'   => array($this, 'translateFirstChild'),
+            'last-child'    => array($this, 'translateLastChild'),
+            'first-of-type' => array($this, 'translateFirstOfType'),
+            'last-of-type'  => array($this, 'translateLastOfType'),
+            'only-child'    => array($this, 'translateOnlyChild'),
+            'only-of-type'  => array($this, 'translateOnlyOfType'),
+            'empty'         => array($this, 'translateEmpty'),
+        );
+    }
+
+    /**
+     * @param XPathExpr $xpath
+     *
+     * @return XPathExpr
+     */
+    public function translateRoot(XPathExpr $xpath)
+    {
+        return $xpath->addCondition('not(parent::*)');
+    }
+
+    /**
+     * @param XPathExpr $xpath
+     *
+     * @return XPathExpr
+     */
+    public function translateFirstChild(XPathExpr $xpath)
+    {
+        return $xpath
+            ->addStarPrefix()
+            ->addNameTest()
+            ->addCondition('position() = 1');
+    }
+
+    /**
+     * @param XPathExpr $xpath
+     *
+     * @return XPathExpr
+     */
+    public function translateLastChild(XPathExpr $xpath)
+    {
+        return $xpath
+            ->addStarPrefix()
+            ->addNameTest()
+            ->addCondition('position() = last()');
+    }
+
+    /**
+     * @param XPathExpr $xpath
+     *
+     * @return XPathExpr
+     *
+     * @throws ExpressionErrorException
+     */
+    public function translateFirstOfType(XPathExpr $xpath)
+    {
+        if ('*' === $xpath->getElement()) {
+            throw new ExpressionErrorException('"*:first-of-type" is not implemented.');
+        }
+
+        return $xpath
+            ->addStarPrefix()
+            ->addCondition('position() = 1');
+    }
+
+    /**
+     * @param XPathExpr $xpath
+     *
+     * @return XPathExpr
+     *
+     * @throws ExpressionErrorException
+     */
+    public function translateLastOfType(XPathExpr $xpath)
+    {
+        if ('*' === $xpath->getElement()) {
+            throw new ExpressionErrorException('"*:last-of-type" is not implemented.');
+        }
+
+        return $xpath
+            ->addStarPrefix()
+            ->addCondition('position() = last()');
+    }
+
+    /**
+     * @param XPathExpr $xpath
+     *
+     * @return XPathExpr
+     */
+    public function translateOnlyChild(XPathExpr $xpath)
+    {
+        return $xpath
+            ->addStarPrefix()
+            ->addNameTest()
+            ->addCondition('last() = 1');
+    }
+
+    /**
+     * @param XPathExpr $xpath
+     *
+     * @return XPathExpr
+     *
+     * @throws ExpressionErrorException
+     */
+    public function translateOnlyOfType(XPathExpr $xpath)
+    {
+        if ('*' === $xpath->getElement()) {
+            throw new ExpressionErrorException('"*:only-of-type" is not implemented.');
+        }
+
+        return $xpath->addCondition('last() = 1');
+    }
+
+    /**
+     * @param XPathExpr $xpath
+     *
+     * @return XPathExpr
+     */
+    public function translateEmpty(XPathExpr $xpath)
+    {
+        return $xpath->addCondition('not(*) and not(string-length())');
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function getName()
+    {
+        return 'pseudo-class';
+    }
+}
diff --git a/vendor/symfony/css-selector/Symfony/Component/CssSelector/XPath/Translator.php b/vendor/symfony/css-selector/Symfony/Component/CssSelector/XPath/Translator.php
new file mode 100644
index 00000000000..5675aa61064
--- /dev/null
+++ b/vendor/symfony/css-selector/Symfony/Component/CssSelector/XPath/Translator.php
@@ -0,0 +1,299 @@
+<?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\CssSelector\XPath;
+
+use Symfony\Component\CssSelector\Exception\ExpressionErrorException;
+use Symfony\Component\CssSelector\Node\FunctionNode;
+use Symfony\Component\CssSelector\Node\NodeInterface;
+use Symfony\Component\CssSelector\Node\SelectorNode;
+use Symfony\Component\CssSelector\Parser\Parser;
+use Symfony\Component\CssSelector\Parser\ParserInterface;
+
+/**
+ * XPath expression translator interface.
+ *
+ * This component is a port of the Python cssselector library,
+ * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect.
+ *
+ * @author Jean-François Simon <jeanfrancois.simon@sensiolabs.com>
+ */
+class Translator implements TranslatorInterface
+{
+    /**
+     * @var ParserInterface
+     */
+    private $mainParser;
+
+    /**
+     * @var ParserInterface[]
+     */
+    private $shortcutParsers = array();
+
+    /**
+     * @var Extension\ExtensionInterface
+     */
+    private $extensions = array();
+
+    /**
+     * @var array
+     */
+    private $nodeTranslators = array();
+
+    /**
+     * @var array
+     */
+    private $combinationTranslators = array();
+
+    /**
+     * @var array
+     */
+    private $functionTranslators = array();
+
+    /**
+     * @var array
+     */
+    private $pseudoClassTranslators = array();
+
+    /**
+     * @var array
+     */
+    private $attributeMatchingTranslators = array();
+
+    /**
+     * Constructor.
+     */
+    public function __construct(ParserInterface $parser = null)
+    {
+        $this->mainParser = $parser ?: new Parser();
+
+        $this
+            ->registerExtension(new Extension\NodeExtension())
+            ->registerExtension(new Extension\CombinationExtension())
+            ->registerExtension(new Extension\FunctionExtension())
+            ->registerExtension(new Extension\PseudoClassExtension())
+            ->registerExtension(new Extension\AttributeMatchingExtension())
+        ;
+    }
+
+    /**
+     * @param string $element
+     *
+     * @return string
+     */
+    public static function getXpathLiteral($element)
+    {
+        if (false === strpos($element, "'")) {
+            return "'".$element."'";
+        }
+
+        if (false === strpos($element, '"')) {
+            return '"'.$element.'"';
+        }
+
+        $string = $element;
+        $parts = array();
+        while (true) {
+            if (false !== $pos = strpos($string, "'")) {
+                $parts[] = sprintf("'%s'", substr($string, 0, $pos));
+                $parts[] = "\"'\"";
+                $string = substr($string, $pos + 1);
+            } else {
+                $parts[] = "'$string'";
+                break;
+            }
+        }
+
+        return sprintf('concat(%s)', implode($parts, ', '));
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function cssToXPath($cssExpr, $prefix = 'descendant-or-self::')
+    {
+        $selectors = $this->parseSelectors($cssExpr);
+
+        /** @var SelectorNode $selector */
+        foreach ($selectors as $index => $selector) {
+            if (null !== $selector->getPseudoElement()) {
+                throw new ExpressionErrorException('Pseudo-elements are not supported.');
+            }
+
+            $selectors[$index] = $this->selectorToXPath($selector, $prefix);
+        }
+
+        return implode(' | ', $selectors);
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function selectorToXPath(SelectorNode $selector, $prefix = 'descendant-or-self::')
+    {
+        return ($prefix ?: '').$this->nodeToXPath($selector);
+    }
+
+    /**
+     * Registers an extension.
+     *
+     * @param Extension\ExtensionInterface $extension
+     *
+     * @return Translator
+     */
+    public function registerExtension(Extension\ExtensionInterface $extension)
+    {
+        $this->extensions[$extension->getName()] = $extension;
+
+        $this->nodeTranslators = array_merge($this->nodeTranslators, $extension->getNodeTranslators());
+        $this->combinationTranslators = array_merge($this->combinationTranslators, $extension->getCombinationTranslators());
+        $this->functionTranslators = array_merge($this->functionTranslators, $extension->getFunctionTranslators());
+        $this->pseudoClassTranslators = array_merge($this->pseudoClassTranslators, $extension->getPseudoClassTranslators());
+        $this->attributeMatchingTranslators = array_merge($this->attributeMatchingTranslators, $extension->getAttributeMatchingTranslators());
+
+        return $this;
+    }
+
+    /**
+     * @param string $name
+     *
+     * @return Extension\ExtensionInterface
+     *
+     * @throws ExpressionErrorException
+     */
+    public function getExtension($name)
+    {
+        if (!isset($this->extensions[$name])) {
+            throw new ExpressionErrorException(sprintf('Extension "%s" not registered.', $name));
+        }
+
+        return $this->extensions[$name];
+    }
+
+    /**
+     * Registers a shortcut parser.
+     *
+     * @param ParserInterface $shortcut
+     *
+     * @return Translator
+     */
+    public function registerParserShortcut(ParserInterface $shortcut)
+    {
+        $this->shortcutParsers[] = $shortcut;
+
+        return $this;
+    }
+
+    /**
+     * @param NodeInterface $node
+     *
+     * @return XPathExpr
+     *
+     * @throws ExpressionErrorException
+     */
+    public function nodeToXPath(NodeInterface $node)
+    {
+        if (!isset($this->nodeTranslators[$node->getNodeName()])) {
+            throw new ExpressionErrorException(sprintf('Node "%s" not supported.', $node->getNodeName()));
+        }
+
+        return call_user_func($this->nodeTranslators[$node->getNodeName()], $node, $this);
+    }
+
+    /**
+     * @param string        $combiner
+     * @param NodeInterface $xpath
+     * @param NodeInterface $combinedXpath
+     *
+     * @return XPathExpr
+     *
+     * @throws ExpressionErrorException
+     */
+    public function addCombination($combiner, NodeInterface $xpath, NodeInterface $combinedXpath)
+    {
+        if (!isset($this->combinationTranslators[$combiner])) {
+            throw new ExpressionErrorException(sprintf('Combiner "%s" not supported.', $combiner));
+        }
+
+        return call_user_func($this->combinationTranslators[$combiner], $this->nodeToXPath($xpath), $this->nodeToXPath($combinedXpath));
+    }
+
+    /**
+     * @param XPathExpr $xpath
+     * @param FunctionNode $function
+     *
+     * @return XPathExpr
+     *
+     * @throws ExpressionErrorException
+     */
+    public function addFunction(XPathExpr $xpath, FunctionNode $function)
+    {
+        if (!isset($this->functionTranslators[$function->getName()])) {
+            throw new ExpressionErrorException(sprintf('Function "%s" not supported.', $function->getName()));
+        }
+
+        return call_user_func($this->functionTranslators[$function->getName()], $xpath, $function);
+    }
+
+    /**
+     * @param XPathExpr $xpath
+     * @param string    $pseudoClass
+     *
+     * @return XPathExpr
+     *
+     * @throws ExpressionErrorException
+     */
+    public function addPseudoClass(XPathExpr $xpath, $pseudoClass)
+    {
+        if (!isset($this->pseudoClassTranslators[$pseudoClass])) {
+            throw new ExpressionErrorException(sprintf('Pseudo-class "%s" not supported.', $pseudoClass));
+        }
+
+        return call_user_func($this->pseudoClassTranslators[$pseudoClass], $xpath);
+    }
+
+    /**
+     * @param XPathExpr $xpath
+     * @param string    $operator
+     * @param string    $attribute
+     * @param string    $value
+     *
+     * @throws ExpressionErrorException
+     *
+     * @return XPathExpr
+     */
+    public function addAttributeMatching(XPathExpr $xpath, $operator, $attribute, $value)
+    {
+        if (!isset($this->attributeMatchingTranslators[$operator])) {
+            throw new ExpressionErrorException(sprintf('Attribute matcher operator "%s" not supported.', $operator));
+        }
+
+        return call_user_func($this->attributeMatchingTranslators[$operator], $xpath, $attribute, $value);
+    }
+
+    /**
+     * @param string $css
+     *
+     * @return SelectorNode[]
+     */
+    private function parseSelectors($css)
+    {
+        foreach ($this->shortcutParsers as $shortcut) {
+            $tokens = $shortcut->parse($css);
+
+            if (!empty($tokens)) {
+                return $tokens;
+            }
+        }
+
+        return $this->mainParser->parse($css);
+    }
+}
diff --git a/vendor/symfony/css-selector/Symfony/Component/CssSelector/XPath/TranslatorInterface.php b/vendor/symfony/css-selector/Symfony/Component/CssSelector/XPath/TranslatorInterface.php
new file mode 100644
index 00000000000..b26cf5b0c39
--- /dev/null
+++ b/vendor/symfony/css-selector/Symfony/Component/CssSelector/XPath/TranslatorInterface.php
@@ -0,0 +1,45 @@
+<?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\CssSelector\XPath;
+
+use Symfony\Component\CssSelector\Node\SelectorNode;
+
+/**
+ * XPath expression translator interface.
+ *
+ * This component is a port of the Python cssselector library,
+ * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect.
+ *
+ * @author Jean-François Simon <jeanfrancois.simon@sensiolabs.com>
+ */
+interface TranslatorInterface
+{
+    /**
+     * Translates a CSS selector to an XPath expression.
+     *
+     * @param string $cssExpr
+     * @param string $prefix
+     *
+     * @return XPathExpr
+     */
+    public function cssToXPath($cssExpr, $prefix = 'descendant-or-self::');
+
+    /**
+     * Translates a parsed selector node to an XPath expression
+     *
+     * @param SelectorNode $selector
+     * @param string       $prefix
+     *
+     * @return XPathExpr
+     */
+    public function selectorToXPath(SelectorNode $selector, $prefix = 'descendant-or-self::');
+}
diff --git a/vendor/symfony/css-selector/Symfony/Component/CssSelector/XPath/XPathExpr.php b/vendor/symfony/css-selector/Symfony/Component/CssSelector/XPath/XPathExpr.php
new file mode 100644
index 00000000000..f0f2f987678
--- /dev/null
+++ b/vendor/symfony/css-selector/Symfony/Component/CssSelector/XPath/XPathExpr.php
@@ -0,0 +1,140 @@
+<?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\CssSelector\XPath;
+
+/**
+ * XPath expression translator interface.
+ *
+ * This component is a port of the Python cssselector library,
+ * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect.
+ *
+ * @author Jean-François Simon <jeanfrancois.simon@sensiolabs.com>
+ */
+class XPathExpr
+{
+    /**
+     * @var string
+     */
+    private $path;
+
+    /**
+     * @var string
+     */
+    private $element;
+
+    /**
+     * @var string
+     */
+    private $condition;
+
+    /**
+     * @param string  $path
+     * @param string  $element
+     * @param string  $condition
+     * @param bool    $starPrefix
+     */
+    public function __construct($path = '', $element = '*', $condition = '', $starPrefix = false)
+    {
+        $this->path = $path;
+        $this->element = $element;
+        $this->condition = $condition;
+
+        if ($starPrefix) {
+            $this->addStarPrefix();
+        }
+    }
+
+    /**
+     * @return string
+     */
+    public function getElement()
+    {
+        return $this->element;
+    }
+
+    /**
+     * @param $condition
+     *
+     * @return XPathExpr
+     */
+    public function addCondition($condition)
+    {
+        $this->condition = $this->condition ? sprintf('%s and (%s)', $this->condition, $condition) : $condition;
+
+        return $this;
+    }
+
+    /**
+     * @return string
+     */
+    public function getCondition()
+    {
+        return $this->condition;
+    }
+
+    /**
+     * @return XPathExpr
+     */
+    public function addNameTest()
+    {
+        if ('*' !== $this->element) {
+            $this->addCondition('name() = '.Translator::getXpathLiteral($this->element));
+            $this->element = '*';
+        }
+
+        return $this;
+    }
+
+    /**
+     * @return XPathExpr
+     */
+    public function addStarPrefix()
+    {
+        $this->path .= '*/';
+
+        return $this;
+    }
+
+    /**
+     * Joins another XPathExpr with a combiner.
+     *
+     * @param string    $combiner
+     * @param XPathExpr $expr
+     *
+     * @return XPathExpr
+     */
+    public function join($combiner, XPathExpr $expr)
+    {
+        $path = $this->__toString().$combiner;
+
+        if ('*/' !== $expr->path) {
+            $path .= $expr->path;
+        }
+
+        $this->path = $path;
+        $this->element = $expr->element;
+        $this->condition = $expr->condition;
+
+        return $this;
+    }
+
+    /**
+     * @return string
+     */
+    public function __toString()
+    {
+        $path = $this->path.$this->element;
+        $condition = null === $this->condition || '' === $this->condition ? '' : '['.$this->condition.']';
+
+        return $path.$condition;
+    }
+}
diff --git a/vendor/symfony/css-selector/Symfony/Component/CssSelector/composer.json b/vendor/symfony/css-selector/Symfony/Component/CssSelector/composer.json
new file mode 100644
index 00000000000..5b4231d7947
--- /dev/null
+++ b/vendor/symfony/css-selector/Symfony/Component/CssSelector/composer.json
@@ -0,0 +1,35 @@
+{
+    "name": "symfony/css-selector",
+    "type": "library",
+    "description": "Symfony CssSelector Component",
+    "keywords": [],
+    "homepage": "http://symfony.com",
+    "license": "MIT",
+    "authors": [
+        {
+            "name": "Fabien Potencier",
+            "email": "fabien@symfony.com"
+        },
+        {
+            "name": "Jean-François Simon",
+            "email": "jeanfrancois.simon@sensiolabs.com"
+        },
+        {
+            "name": "Symfony Community",
+            "homepage": "http://symfony.com/contributors"
+        }
+    ],
+    "require": {
+        "php": ">=5.3.3"
+    },
+    "autoload": {
+        "psr-0": { "Symfony\\Component\\CssSelector\\": "" }
+    },
+    "target-dir": "Symfony/Component/CssSelector",
+    "minimum-stability": "dev",
+    "extra": {
+        "branch-alias": {
+            "dev-master": "2.5-dev"
+        }
+    }
+}
diff --git a/vendor/symfony/css-selector/Symfony/Component/CssSelector/phpunit.xml.dist b/vendor/symfony/css-selector/Symfony/Component/CssSelector/phpunit.xml.dist
new file mode 100644
index 00000000000..3eb0a1ece0c
--- /dev/null
+++ b/vendor/symfony/css-selector/Symfony/Component/CssSelector/phpunit.xml.dist
@@ -0,0 +1,25 @@
+<?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"
+>
+    <testsuites>
+        <testsuite name="Symfony CssSelector Component Test Suite">
+            <directory>./Tests/</directory>
+        </testsuite>
+    </testsuites>
+
+    <filter>
+        <whitelist>
+            <directory>./</directory>
+            <exclude>
+                <directory>./Resources</directory>
+                <directory>./Tests</directory>
+                <directory>./vendor</directory>
+            </exclude>
+        </whitelist>
+    </filter>
+</phpunit>
diff --git a/vendor/symfony/process/Symfony/Component/Process/.gitignore b/vendor/symfony/process/Symfony/Component/Process/.gitignore
new file mode 100644
index 00000000000..c49a5d8df5c
--- /dev/null
+++ b/vendor/symfony/process/Symfony/Component/Process/.gitignore
@@ -0,0 +1,3 @@
+vendor/
+composer.lock
+phpunit.xml
diff --git a/vendor/symfony/process/Symfony/Component/Process/CHANGELOG.md b/vendor/symfony/process/Symfony/Component/Process/CHANGELOG.md
new file mode 100644
index 00000000000..2f3c1beb74b
--- /dev/null
+++ b/vendor/symfony/process/Symfony/Component/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/Symfony/Component/Process/Exception/ExceptionInterface.php b/vendor/symfony/process/Symfony/Component/Process/Exception/ExceptionInterface.php
new file mode 100644
index 00000000000..75c1c9e5d80
--- /dev/null
+++ b/vendor/symfony/process/Symfony/Component/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/Symfony/Component/Process/Exception/InvalidArgumentException.php b/vendor/symfony/process/Symfony/Component/Process/Exception/InvalidArgumentException.php
new file mode 100644
index 00000000000..926ee2118b0
--- /dev/null
+++ b/vendor/symfony/process/Symfony/Component/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/Symfony/Component/Process/Exception/LogicException.php b/vendor/symfony/process/Symfony/Component/Process/Exception/LogicException.php
new file mode 100644
index 00000000000..be3d490dde8
--- /dev/null
+++ b/vendor/symfony/process/Symfony/Component/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/Symfony/Component/Process/Exception/ProcessFailedException.php b/vendor/symfony/process/Symfony/Component/Process/Exception/ProcessFailedException.php
new file mode 100644
index 00000000000..7523a5e9cd4
--- /dev/null
+++ b/vendor/symfony/process/Symfony/Component/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/Symfony/Component/Process/Exception/ProcessTimedOutException.php b/vendor/symfony/process/Symfony/Component/Process/Exception/ProcessTimedOutException.php
new file mode 100644
index 00000000000..d45114696f6
--- /dev/null
+++ b/vendor/symfony/process/Symfony/Component/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/Symfony/Component/Process/Exception/RuntimeException.php b/vendor/symfony/process/Symfony/Component/Process/Exception/RuntimeException.php
new file mode 100644
index 00000000000..adead2536b1
--- /dev/null
+++ b/vendor/symfony/process/Symfony/Component/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/Symfony/Component/Process/ExecutableFinder.php b/vendor/symfony/process/Symfony/Component/Process/ExecutableFinder.php
new file mode 100644
index 00000000000..6ae74dca174
--- /dev/null
+++ b/vendor/symfony/process/Symfony/Component/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 (defined('PHP_WINDOWS_VERSION_BUILD')) {
+            $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) && (defined('PHP_WINDOWS_VERSION_BUILD') || is_executable($file))) {
+                    return $file;
+                }
+            }
+        }
+
+        return $default;
+    }
+}
diff --git a/vendor/symfony/process/Symfony/Component/Process/LICENSE b/vendor/symfony/process/Symfony/Component/Process/LICENSE
new file mode 100644
index 00000000000..0b3292cf902
--- /dev/null
+++ b/vendor/symfony/process/Symfony/Component/Process/LICENSE
@@ -0,0 +1,19 @@
+Copyright (c) 2004-2014 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/Symfony/Component/Process/PhpExecutableFinder.php b/vendor/symfony/process/Symfony/Component/Process/PhpExecutableFinder.php
new file mode 100644
index 00000000000..7854487a26b
--- /dev/null
+++ b/vendor/symfony/process/Symfony/Component/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 (false !== ($hhvm = getenv('PHP_BINARY')) ? $hhvm : 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 (defined('PHP_WINDOWS_VERSION_BUILD')) {
+            $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/Symfony/Component/Process/PhpProcess.php b/vendor/symfony/process/Symfony/Component/Process/PhpProcess.php
new file mode 100644
index 00000000000..93948e1db01
--- /dev/null
+++ b/vendor/symfony/process/Symfony/Component/Process/PhpProcess.php
@@ -0,0 +1,73 @@
+<?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
+{
+    private $executableFinder;
+
+    /**
+     * 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())
+    {
+        parent::__construct(null, $cwd, $env, $script, $timeout, $options);
+
+        $this->executableFinder = new PhpExecutableFinder();
+    }
+
+    /**
+     * 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()) {
+            if (false === $php = $this->executableFinder->find()) {
+                throw new RuntimeException('Unable to find the PHP executable.');
+            }
+            $this->setCommandLine($php);
+        }
+
+        parent::start($callback);
+    }
+}
diff --git a/vendor/symfony/process/Symfony/Component/Process/Process.php b/vendor/symfony/process/Symfony/Component/Process/Process.php
new file mode 100644
index 00000000000..7503dadefc2
--- /dev/null
+++ b/vendor/symfony/process/Symfony/Component/Process/Process.php
@@ -0,0 +1,1509 @@
+<?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;
+
+/**
+ * Process is a thin wrapper around proc_* functions to easily
+ * start independent PHP processes.
+ *
+ * @author Fabien Potencier <fabien@symfony.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 ProcessPipes */
+    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') || defined('PHP_WINDOWS_VERSION_BUILD'))) {
+            $this->cwd = getcwd();
+        }
+        if (null !== $env) {
+            $this->setEnv($env);
+        }
+
+        $this->input = $input;
+        $this->setTimeout($timeout);
+        $this->useFileHandles = defined('PHP_WINDOWS_VERSION_BUILD');
+        $this->pty = false;
+        $this->enhanceWindowsCompatibility = true;
+        $this->enhanceSigchildCompatibility = !defined('PHP_WINDOWS_VERSION_BUILD') && $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
+     *
+     * @return Process The process itself
+     *
+     * @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 (defined('PHP_WINDOWS_VERSION_BUILD') && $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;
+
+        $this->processPipes->unblock();
+
+        if ($this->tty) {
+            return;
+        }
+
+        $this->processPipes->write(false, $this->input);
+        $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 = defined('PHP_WINDOWS_VERSION_BUILD') ? $this->isRunning() : $this->processPipes->hasOpenHandles();
+            $close = !defined('PHP_WINDOWS_VERSION_BUILD') || !$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, defined('PHP_WINDOWS_VERSION_BUILD') ? !$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);
+        $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, defined('PHP_WINDOWS_VERSION_BUILD') ? !$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);
+        $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 (defined('PHP_WINDOWS_VERSION_BUILD') && !$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 (defined('PHP_WINDOWS_VERSION_BUILD') && $tty) {
+            throw new RuntimeException('TTY mode is not supported on Windows platform.');
+        }
+
+        $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 Deprecated since version 2.5, to be removed in 3.0.
+     *             This method is deprecated in favor of getInput.
+     */
+    public function getStdin()
+    {
+        return $this->getInput();
+    }
+
+    /**
+     * Gets the Process input.
+     *
+     * @return null|string The Process input
+     */
+    public function getInput()
+    {
+        return $this->input;
+    }
+
+    /**
+     * Sets the contents of STDIN.
+     *
+     * Deprecation: As of Symfony 2.5, this method only accepts scalar values.
+     *
+     * @param string|null $stdin The new contents
+     *
+     * @return self The current Process instance
+     *
+     * @deprecated Deprecated since version 2.5, to be removed in 3.0.
+     *             This method is deprecated in favor of setInput.
+     *
+     * @throws LogicException           In case the process is running
+     * @throws InvalidArgumentException In case the argument is invalid
+     */
+    public function setStdin($stdin)
+    {
+        return $this->setInput($stdin);
+    }
+
+    /**
+     * Sets the input.
+     *
+     * This content will be passed to the underlying process standard input.
+     *
+     * @param string|null $input The content
+     *
+     * @return self The current Process instance
+     *
+     * @throws LogicException In case the process is running
+     */
+    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 (defined('PHP_WINDOWS_VERSION_BUILD')) {
+            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()
+    {
+        $this->processPipes = new ProcessPipes($this->useFileHandles, $this->tty, $this->pty, $this->outputDisabled);
+        $descriptors = $this->processPipes->getDescriptors();
+
+        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;
+        $err = self::ERR;
+        $callback = function ($type, $data) use ($that, $callback, $out, $err) {
+            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, defined('PHP_WINDOWS_VERSION_BUILD') ? !$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)
+    {
+        if ($close) {
+            $result = $this->processPipes->readAndCloseHandles($blocking);
+        } else {
+            $result = $this->processPipes->read($blocking);
+        }
+
+        foreach ($result as $type => $data) {
+            if (3 == $type) {
+                $this->fallbackExitcode = (int) $data;
+            } else {
+                call_user_func($this->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/Symfony/Component/Process/ProcessBuilder.php b/vendor/symfony/process/Symfony/Component/Process/ProcessBuilder.php
new file mode 100644
index 00000000000..71633cd7fac
--- /dev/null
+++ b/vendor/symfony/process/Symfony/Component/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 an unescaped 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.
+     *
+     * Deprecation: As of Symfony 2.5, this method only accepts string values.
+     *
+     * @param string|null $input The input as a string
+     *
+     * @return ProcessBuilder
+     *
+     * @throws InvalidArgumentException In case the argument is invalid
+     */
+    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
+     *
+     * @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/Symfony/Component/Process/ProcessPipes.php b/vendor/symfony/process/Symfony/Component/Process/ProcessPipes.php
new file mode 100644
index 00000000000..9ed1def9f29
--- /dev/null
+++ b/vendor/symfony/process/Symfony/Component/Process/ProcessPipes.php
@@ -0,0 +1,382 @@
+<?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;
+
+/**
+ * ProcessPipes manages descriptors and pipes for the use of proc_open.
+ */
+class ProcessPipes
+{
+    /** @var array */
+    public $pipes = array();
+    /** @var array */
+    private $files = array();
+    /** @var array */
+    private $fileHandles = array();
+    /** @var array */
+    private $readBytes = array();
+    /** @var bool    */
+    private $useFiles;
+    /** @var bool    */
+    private $ttyMode;
+    /** @var bool    */
+    private $ptyMode;
+    /** @var bool    */
+    private $disableOutput;
+
+    const CHUNK_SIZE = 16384;
+
+    public function __construct($useFiles, $ttyMode, $ptyMode = false, $disableOutput = false)
+    {
+        $this->useFiles = (bool) $useFiles;
+        $this->ttyMode = (bool) $ttyMode;
+        $this->ptyMode = (bool) $ptyMode;
+        $this->disableOutput = (bool) $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
+        if ($this->useFiles && !$this->disableOutput) {
+            $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');
+                }
+            }
+            $this->readBytes = array(
+                Process::STDOUT => 0,
+                Process::STDERR => 0,
+            );
+        }
+    }
+
+    public function __destruct()
+    {
+        $this->close();
+        $this->removeFiles();
+    }
+
+    /**
+     * Sets non-blocking mode on pipes.
+     */
+    public function unblock()
+    {
+        foreach ($this->pipes as $pipe) {
+            stream_set_blocking($pipe, 0);
+        }
+    }
+
+    /**
+     * Closes file handles and pipes.
+     */
+    public function close()
+    {
+        $this->closeUnixPipes();
+        foreach ($this->fileHandles as $handle) {
+            fclose($handle);
+        }
+        $this->fileHandles = array();
+    }
+
+    /**
+     * Closes Unix pipes.
+     *
+     * Nothing happens in case file handles are used.
+     */
+    public function closeUnixPipes()
+    {
+        foreach ($this->pipes as $pipe) {
+            fclose($pipe);
+        }
+        $this->pipes = array();
+    }
+
+    /**
+     * Returns an array of descriptors for the use of proc_open.
+     *
+     * @return array
+     */
+    public function getDescriptors()
+    {
+        if ($this->disableOutput) {
+            $nullstream = fopen(defined('PHP_WINDOWS_VERSION_BUILD') ? 'NUL' : '/dev/null', 'c');
+
+            return array(
+                array('pipe', 'r'),
+                $nullstream,
+                $nullstream,
+            );
+        }
+
+        if ($this->useFiles) {
+            // 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'),
+            );
+        }
+
+        if ($this->ttyMode) {
+            return array(
+                array('file', '/dev/tty', 'r'),
+                array('file', '/dev/tty', 'w'),
+                array('file', '/dev/tty', 'w'),
+            );
+        } elseif ($this->ptyMode && Process::isPtySupported()) {
+            return array(
+                array('pty'),
+                array('pty'),
+                array('pty'),
+            );
+        }
+
+        return array(
+            array('pipe', 'r'), // stdin
+            array('pipe', 'w'), // stdout
+            array('pipe', 'w'), // stderr
+        );
+    }
+
+    /**
+     * Returns an array of filenames indexed by their related stream in case these pipes use temporary files.
+     *
+     * @return array
+     */
+    public function getFiles()
+    {
+        if ($this->useFiles) {
+            return $this->files;
+        }
+
+        return array();
+    }
+
+    /**
+     * Reads data in file handles and pipes.
+     *
+     * @param bool    $blocking Whether to use blocking calls or not.
+     *
+     * @return array An array of read data indexed by their fd.
+     */
+    public function read($blocking)
+    {
+        return array_replace($this->readStreams($blocking), $this->readFileHandles());
+    }
+
+    /**
+     * Reads data in file handles and pipes, closes them if EOF is reached.
+     *
+     * @param bool    $blocking Whether to use blocking calls or not.
+     *
+     * @return array An array of read data indexed by their fd.
+     */
+    public function readAndCloseHandles($blocking)
+    {
+        return array_replace($this->readStreams($blocking, true), $this->readFileHandles(true));
+    }
+
+    /**
+     * Returns if the current state has open file handles or pipes.
+     *
+     * @return bool
+     */
+    public function hasOpenHandles()
+    {
+        if (!$this->useFiles) {
+            return (bool) $this->pipes;
+        }
+
+        return (bool) $this->pipes && (bool) $this->fileHandles;
+    }
+
+    /**
+     * Writes stdin data.
+     *
+     * @param bool        $blocking Whether to use blocking calls or not.
+     * @param string|null $stdin    The data to write.
+     */
+    public function write($blocking, $stdin)
+    {
+        if (null === $stdin) {
+            fclose($this->pipes[0]);
+            unset($this->pipes[0]);
+
+            return;
+        }
+
+        $writePipes = array($this->pipes[0]);
+        unset($this->pipes[0]);
+        $stdinLen = strlen($stdin);
+        $stdinOffset = 0;
+
+        while ($writePipes) {
+            $r = null;
+            $w = $writePipes;
+            $e = null;
+
+            if (false === $n = @stream_select($r, $w, $e, 0, $blocking ? ceil(Process::TIMEOUT_PRECISION * 1E6) : 0)) {
+                // if a system call has been interrupted, forget about it, let's try again
+                if ($this->hasSystemCallBeenInterrupted()) {
+                    continue;
+                }
+                break;
+            }
+
+            // nothing has changed, let's wait until the process is ready
+            if (0 === $n) {
+                continue;
+            }
+
+            if ($w) {
+                $written = fwrite($writePipes[0], (binary) substr($stdin, $stdinOffset), 8192);
+                if (false !== $written) {
+                    $stdinOffset += $written;
+                }
+                if ($stdinOffset >= $stdinLen) {
+                    fclose($writePipes[0]);
+                    $writePipes = null;
+                }
+            }
+        }
+    }
+
+    /**
+     * Reads data in file handles.
+     *
+     * @param bool    $close Whether to close file handles or not.
+     *
+     * @return array An array of read data indexed by their fd.
+     */
+    private function readFileHandles($close = false)
+    {
+        $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;
+    }
+
+    /**
+     * Reads data in file pipes streams.
+     *
+     * @param bool    $blocking Whether to use blocking calls or not.
+     * @param bool    $close    Whether to close file handles or not.
+     *
+     * @return array An array of read data indexed by their fd.
+     */
+    private function readStreams($blocking, $close = false)
+    {
+        if (empty($this->pipes)) {
+            usleep(Process::TIMEOUT_PRECISION * 1E4);
+
+            return array();
+        }
+
+        $read = array();
+
+        $r = $this->pipes;
+        $w = null;
+        $e = null;
+
+        // let's have a look if something changed in streams
+        if (false === $n = @stream_select($r, $w, $e, 0, $blocking ? ceil(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) {
+            $type = array_search($pipe, $this->pipes);
+
+            $data = '';
+            while ('' !== $dataread = (string) fread($pipe, self::CHUNK_SIZE)) {
+                $data .= $dataread;
+            }
+
+            if ('' !== $data) {
+                $read[$type] = $data;
+            }
+
+            if (false === $data || (true === $close && feof($pipe) && '' === $data)) {
+                fclose($this->pipes[$type]);
+                unset($this->pipes[$type]);
+            }
+        }
+
+        return $read;
+    }
+
+    /**
+     * Returns true if a system call has been interrupted.
+     *
+     * @return bool
+     */
+    private 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');
+    }
+
+    /**
+     * Removes temporary files
+     */
+    private function removeFiles()
+    {
+        foreach ($this->files as $filename) {
+            if (file_exists($filename)) {
+                @unlink($filename);
+            }
+        }
+        $this->files = array();
+    }
+}
diff --git a/vendor/symfony/process/Symfony/Component/Process/ProcessUtils.php b/vendor/symfony/process/Symfony/Component/Process/ProcessUtils.php
new file mode 100644
index 00000000000..35ae17c5088
--- /dev/null
+++ b/vendor/symfony/process/Symfony/Component/Process/ProcessUtils.php
@@ -0,0 +1,108 @@
+<?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 (defined('PHP_WINDOWS_VERSION_BUILD')) {
+            if ('' === $argument) {
+                return escapeshellarg($argument);
+            }
+
+            $escapedArgument = '';
+            $quote =  false;
+            foreach (preg_split('/(")/i', $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
+     */
+    public static function validateInput($caller, $input)
+    {
+        if (null !== $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')) {
+                return (string) $input;
+            }
+
+            throw new InvalidArgumentException(sprintf('%s only accepts strings.', $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/Symfony/Component/Process/README.md b/vendor/symfony/process/Symfony/Component/Process/README.md
new file mode 100644
index 00000000000..29d1cf93304
--- /dev/null
+++ b/vendor/symfony/process/Symfony/Component/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.phar install
+    $ phpunit
diff --git a/vendor/symfony/process/Symfony/Component/Process/Tests/AbstractProcessTest.php b/vendor/symfony/process/Symfony/Component/Process/Tests/AbstractProcessTest.php
new file mode 100644
index 00000000000..c5737e1a9e3
--- /dev/null
+++ b/vendor/symfony/process/Symfony/Component/Process/Tests/AbstractProcessTest.php
@@ -0,0 +1,1104 @@
+<?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\ProcessTimedOutException;
+use Symfony\Component\Process\Exception\LogicException;
+use Symfony\Component\Process\Process;
+use Symfony\Component\Process\Exception\RuntimeException;
+use Symfony\Component\Process\ProcessPipes;
+
+/**
+ * @author Robert Schönthal <seroscho@googlemail.com>
+ */
+abstract class AbstractProcessTest extends \PHPUnit_Framework_TestCase
+{
+    public function testThatProcessDoesNotThrowWarningDuringRun()
+    {
+        @trigger_error('Test Error', E_USER_NOTICE);
+        $process = $this->getProcess("php -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(1.8, $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 * ProcessPipes::CHUNK_SIZE plus
+        // another byte which will never be read.
+        $expectedOutputSize = ProcessPipes::CHUNK_SIZE * 2 + 2;
+
+        $code = sprintf('echo str_repeat(\'*\', %d);', $expectedOutputSize);
+        $p = $this->getProcess(sprintf('php -r %s', 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('php -r %s', 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('php -r %s', escapeshellarg($code)));
+        $p->setInput($expected);
+        $p->run();
+
+        $this->assertEquals($expectedLength, strlen($p->getOutput()));
+        $this->assertEquals($expectedLength, strlen($p->getErrorOutput()));
+    }
+
+    public function testSetInputWhileRunningThrowsAnException()
+    {
+        $process = $this->getProcess('php -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.
+     */
+    public function testInvalidInput($value)
+    {
+        $process = $this->getProcess('php -v');
+        $process->setInput($value);
+    }
+
+    public function provideInvalidInputValues()
+    {
+        return array(
+            array(array()),
+            array(new NonStringifiable()),
+            array(fopen('php://temporary', 'w')),
+        );
+    }
+
+    /**
+     * @dataProvider provideInputValues
+     */
+    public function testValidInput($expected, $value)
+    {
+        $process = $this->getProcess('php -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'),
+            // to maintain BC, supposed to be removed in 3.0
+            array('stringifiable', new Stringifiable()),
+        );
+    }
+
+    public function chainedCommandsOutputProvider()
+    {
+        if (defined('PHP_WINDOWS_VERSION_BUILD')) {
+            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('php -r %s', 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('php -r %s', 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('php -r %s', 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('php -r %s', escapeshellarg('$n = 0; while ($n < 3) { file_put_contents(\'php://stderr\', \'ERROR\'); $n++; }')));
+
+        $p->run();
+        $p->clearErrorOutput();
+        $this->assertEmpty($p->getErrorOutput());
+    }
+
+    public function testGetOutput()
+    {
+        $p = $this->getProcess(sprintf('php -r %s', 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('php -r %s', 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('php -r %s', escapeshellarg('$n=0;while ($n<3) {echo \' foo \';$n++;}')));
+
+        $p->run();
+        $p->clearOutput();
+        $this->assertEmpty($p->getOutput());
+    }
+
+    public function testZeroAsOutput()
+    {
+        if (defined('PHP_WINDOWS_VERSION_BUILD')) {
+            // 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 (defined('PHP_WINDOWS_VERSION_BUILD')) {
+            $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 (defined('PHP_WINDOWS_VERSION_BUILD')) {
+            $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 (defined('PHP_WINDOWS_VERSION_BUILD')) {
+            $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 (!defined('PHP_WINDOWS_VERSION_BUILD')) {
+            $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('php -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('php -h');
+        $process->run();
+        $this->assertTrue(strlen($process->getOutput()) > 0);
+    }
+
+    public function testGetExitCodeIsNullOnStart()
+    {
+        $process = $this->getProcess('php -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('php -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('php -m');
+        $process->run();
+        $this->assertSame(0, $process->getExitCode());
+    }
+
+    public function testStatus()
+    {
+        $process = $this->getProcess('php -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('php -r "sleep(4);"');
+        $process->start();
+        $this->assertTrue($process->isRunning());
+        $process->stop();
+        $this->assertFalse($process->isRunning());
+    }
+
+    public function testIsSuccessful()
+    {
+        $process = $this->getProcess('php -m');
+        $process->run();
+        $this->assertTrue($process->isSuccessful());
+    }
+
+    public function testIsSuccessfulOnlyAfterTerminated()
+    {
+        $process = $this->getProcess('php -r "sleep(1);"');
+        $process->start();
+        while ($process->isRunning()) {
+            $this->assertFalse($process->isSuccessful());
+            usleep(300000);
+        }
+
+        $this->assertTrue($process->isSuccessful());
+    }
+
+    public function testIsNotSuccessful()
+    {
+        $process = $this->getProcess('php -r "usleep(500000);throw new \Exception(\'BOUM\');"');
+        $process->start();
+        $this->assertTrue($process->isRunning());
+        $process->wait();
+        $this->assertFalse($process->isSuccessful());
+    }
+
+    public function testProcessIsNotSignaled()
+    {
+        if (defined('PHP_WINDOWS_VERSION_BUILD')) {
+            $this->markTestSkipped('Windows does not support POSIX signals');
+        }
+
+        $process = $this->getProcess('php -m');
+        $process->run();
+        $this->assertFalse($process->hasBeenSignaled());
+    }
+
+    public function testProcessWithoutTermSignalIsNotSignaled()
+    {
+        if (defined('PHP_WINDOWS_VERSION_BUILD')) {
+            $this->markTestSkipped('Windows does not support POSIX signals');
+        }
+
+        $process = $this->getProcess('php -m');
+        $process->run();
+        $this->assertFalse($process->hasBeenSignaled());
+    }
+
+    public function testProcessWithoutTermSignal()
+    {
+        if (defined('PHP_WINDOWS_VERSION_BUILD')) {
+            $this->markTestSkipped('Windows does not support POSIX signals');
+        }
+
+        $process = $this->getProcess('php -m');
+        $process->run();
+        $this->assertEquals(0, $process->getTermSignal());
+    }
+
+    public function testProcessIsSignaledIfStopped()
+    {
+        if (defined('PHP_WINDOWS_VERSION_BUILD')) {
+            $this->markTestSkipped('Windows does not support POSIX signals');
+        }
+
+        $process = $this->getProcess('php -r "sleep(4);"');
+        $process->start();
+        $process->stop();
+        $this->assertTrue($process->hasBeenSignaled());
+    }
+
+    public function testProcessWithTermSignal()
+    {
+        if (defined('PHP_WINDOWS_VERSION_BUILD')) {
+            $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('php -r "sleep(4);"');
+        $process->start();
+        $process->stop();
+
+        $this->assertEquals($termSignal, $process->getTermSignal());
+    }
+
+    public function testProcessThrowsExceptionWhenExternallySignaled()
+    {
+        if (defined('PHP_WINDOWS_VERSION_BUILD')) {
+            $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('php -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('php -r "while (true) {}"');
+        $process->start();
+
+        // PHP will deadlock when it tries to cleanup $process
+    }
+
+    public function testRunProcessWithTimeout()
+    {
+        $timeout = 0.5;
+        $process = $this->getProcess('php -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 (defined('PHP_WINDOWS_VERSION_BUILD')) {
+            // 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('php -r "sleep(3);"');
+        $process->checkTimeout();
+    }
+
+    public function testCheckTimeoutOnTerminatedProcess()
+    {
+        $process = $this->getProcess('php -v');
+        $process->run();
+        $process->checkTimeout();
+    }
+
+    public function testCheckTimeoutOnStartedProcess()
+    {
+        $timeout = 0.5;
+        $precision = 100000;
+        $process = $this->getProcess('php -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());
+    }
+
+    /**
+     * @group idle-timeout
+     */
+    public function testIdleTimeout()
+    {
+        $process = $this->getProcess('php -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());
+        }
+    }
+
+    /**
+     * @group idle-timeout
+     */
+    public function testIdleTimeoutNotExceededWhenOutputIsSent()
+    {
+        $process = $this->getProcess('php -r "echo \'foo\'; sleep(1); echo \'foo\'; sleep(1); echo \'foo\'; sleep(1); "');
+        $process->setTimeout(2);
+        $process->setIdleTimeout(1.5);
+
+        try {
+            $process->run();
+            $this->fail('A timeout exception was expected.');
+        } catch (ProcessTimedOutException $ex) {
+            $this->assertTrue($ex->isGeneralTimeout());
+            $this->assertFalse($ex->isIdleTimeout());
+            $this->assertEquals(2, $ex->getExceededTimeout());
+        }
+    }
+
+    public function testStartAfterATimeout()
+    {
+        $process = $this->getProcess('php -r "$n = 1000; while ($n--) {echo \'\'; usleep(1000); }"');
+        $process->setTimeout(0.1);
+
+        try {
+            $process->run();
+            $this->fail('An exception should have been raised.');
+        } catch (\Exception $e) {
+        }
+        $process->start();
+        usleep(1000);
+        $process->stop();
+    }
+
+    public function testGetPid()
+    {
+        $process = $this->getProcess('php -r "usleep(500000);"');
+        $process->start();
+        $this->assertGreaterThan(0, $process->getPid());
+        $process->wait();
+    }
+
+    public function testGetPidIsNullBeforeStart()
+    {
+        $process = $this->getProcess('php -r "sleep(1);"');
+        $this->assertNull($process->getPid());
+    }
+
+    public function testGetPidIsNullAfterRun()
+    {
+        $process = $this->getProcess('php -m');
+        $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('php -m');
+        $process->signal(SIGHUP);
+    }
+
+    /**
+     * @dataProvider provideMethodsThatNeedARunningProcess
+     */
+    public function testMethodsThatNeedARunningProcess($method)
+    {
+        $process = $this->getProcess('php -m');
+        $this->setExpectedException('Symfony\Component\Process\Exception\LogicException', sprintf('Process must be started before calling %s.', $method));
+        call_user_func(array($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('php -r "sleep(1);"');
+        $process->start();
+        try {
+            call_user_func(array($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 (defined('PHP_WINDOWS_VERSION_BUILD')) {
+            $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 (defined('PHP_WINDOWS_VERSION_BUILD')) {
+            $this->markTestSkipped('POSIX signals do not work on Windows');
+        }
+
+        $process = $this->getProcess('php -r "sleep(3);"');
+        $process->start();
+        $process->signal(-4);
+    }
+
+    /**
+     * @expectedException \Symfony\Component\Process\Exception\RuntimeException
+     */
+    public function testSignalWithWrongNonIntSignal()
+    {
+        if (defined('PHP_WINDOWS_VERSION_BUILD')) {
+            $this->markTestSkipped('POSIX signals do not work on Windows');
+        }
+
+        $process = $this->getProcess('php -r "sleep(3);"');
+        $process->start();
+        $process->signal('Céphalopodes');
+    }
+
+    public function testDisableOutputDisablesTheOutput()
+    {
+        $p = $this->getProcess('php -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('php -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('php -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('php -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('php -r "usleep(500000);"');
+        $p->disableOutput();
+        $this->setExpectedException($exception, $exceptionMessage);
+        call_user_func(array($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('php -r "usleep(500000);"');
+        $p->disableOutput();
+        $p->start();
+        $this->setExpectedException('Symfony\Component\Process\Exception\LogicException', 'Output has been disabled.');
+        call_user_func(array($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 (defined('PHP_WINDOWS_VERSION_BUILD')) {
+            // 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/Symfony/Component/Process/Tests/ExecutableFinderTest.php b/vendor/symfony/process/Symfony/Component/Process/Tests/ExecutableFinderTest.php
new file mode 100644
index 00000000000..5fbe1e0aa70
--- /dev/null
+++ b/vendor/symfony/process/Symfony/Component/Process/Tests/ExecutableFinderTest.php
@@ -0,0 +1,147 @@
+<?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;
+
+    public 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 (defined('PHP_WINDOWS_VERSION_BUILD')) {
+            $this->markTestSkipped('Cannot run test on windows');
+        }
+
+        if (ini_get('open_basedir')) {
+            $this->markTestSkipped('Cannot test when open_basedir is set');
+        }
+
+        ini_set('open_basedir', dirname(PHP_BINARY).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');
+        }
+
+        $execPath = __DIR__.'/SignalListener.php';
+
+        $this->setPath('');
+        ini_set('open_basedir', PHP_BINARY.PATH_SEPARATOR.'/');
+
+        $finder = new ExecutableFinder();
+        $result = $finder->find($this->getPhpBinaryName(), false);
+
+        $this->assertSamePath(PHP_BINARY, $result);
+    }
+
+    private function assertSamePath($expected, $tested)
+    {
+        if (defined('PHP_WINDOWS_VERSION_BUILD')) {
+            $this->assertEquals(strtolower($expected), strtolower($tested));
+        } else {
+            $this->assertEquals($expected, $tested);
+        }
+    }
+
+    private function getPhpBinaryName()
+    {
+        return basename(PHP_BINARY, defined('PHP_WINDOWS_VERSION_BUILD') ? '.exe' : '');
+    }
+}
diff --git a/vendor/symfony/process/Symfony/Component/Process/Tests/NonStopableProcess.php b/vendor/symfony/process/Symfony/Component/Process/Tests/NonStopableProcess.php
new file mode 100644
index 00000000000..2183e48c643
--- /dev/null
+++ b/vendor/symfony/process/Symfony/Component/Process/Tests/NonStopableProcess.php
@@ -0,0 +1,37 @@
+<?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/Symfony/Component/Process/Tests/PhpExecutableFinderTest.php b/vendor/symfony/process/Symfony/Component/Process/Tests/PhpExecutableFinderTest.php
new file mode 100644
index 00000000000..e16f3f8bed1
--- /dev/null
+++ b/vendor/symfony/process/Symfony/Component/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 = $f->find();
+
+        $this->assertEquals($f->find(), $current.' --php', '::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 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 (defined('PHP_WINDOWS_VERSION_BUILD')) {
+            $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/Symfony/Component/Process/Tests/PhpProcessTest.php b/vendor/symfony/process/Symfony/Component/Process/Tests/PhpProcessTest.php
new file mode 100644
index 00000000000..df66ad624be
--- /dev/null
+++ b/vendor/symfony/process/Symfony/Component/Process/Tests/PhpProcessTest.php
@@ -0,0 +1,29 @@
+<?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\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());
+    }
+}
diff --git a/vendor/symfony/process/Symfony/Component/Process/Tests/PipeStdinInStdoutStdErrStreamSelect.php b/vendor/symfony/process/Symfony/Component/Process/Tests/PipeStdinInStdoutStdErrStreamSelect.php
new file mode 100644
index 00000000000..89d1f6a1aca
--- /dev/null
+++ b/vendor/symfony/process/Symfony/Component/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 && strlen($out) < 1) {
+        $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 && strlen($err) < 1) {
+        $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/Symfony/Component/Process/Tests/ProcessBuilderTest.php b/vendor/symfony/process/Symfony/Component/Process/Tests/ProcessBuilderTest.php
new file mode 100644
index 00000000000..56e40520754
--- /dev/null
+++ b/vendor/symfony/process/Symfony/Component/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 (defined('PHP_WINDOWS_VERSION_BUILD')) {
+            $this->assertEquals('"/usr/bin/php" "-v"', $proc->getCommandLine());
+        } else {
+            $this->assertEquals("'/usr/bin/php' '-v'", $proc->getCommandLine());
+        }
+
+        $proc = $pb->setArguments(array('-i'))->getProcess();
+        if (defined('PHP_WINDOWS_VERSION_BUILD')) {
+            $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 (defined('PHP_WINDOWS_VERSION_BUILD')) {
+            $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 (defined('PHP_WINDOWS_VERSION_BUILD')) {
+            $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 (defined('PHP_WINDOWS_VERSION_BUILD')) {
+            $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 (defined('PHP_WINDOWS_VERSION_BUILD')) {
+            $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 (defined('PHP_WINDOWS_VERSION_BUILD')) {
+            $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 (defined('PHP_WINDOWS_VERSION_BUILD')) {
+            $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.
+     */
+    public function testInvalidInput()
+    {
+        $builder = ProcessBuilder::create();
+        $builder->setInput(array());
+    }
+}
diff --git a/vendor/symfony/process/Symfony/Component/Process/Tests/ProcessFailedExceptionTest.php b/vendor/symfony/process/Symfony/Component/Process/Tests/ProcessFailedExceptionTest.php
new file mode 100644
index 00000000000..c48648f5173
--- /dev/null
+++ b/vendor/symfony/process/Symfony/Component/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/Symfony/Component/Process/Tests/ProcessInSigchildEnvironment.php b/vendor/symfony/process/Symfony/Component/Process/Tests/ProcessInSigchildEnvironment.php
new file mode 100644
index 00000000000..3977bcdcf1e
--- /dev/null
+++ b/vendor/symfony/process/Symfony/Component/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/Symfony/Component/Process/Tests/ProcessUtilsTest.php b/vendor/symfony/process/Symfony/Component/Process/Tests/ProcessUtilsTest.php
new file mode 100644
index 00000000000..8ba94c114d2
--- /dev/null
+++ b/vendor/symfony/process/Symfony/Component/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 (defined('PHP_WINDOWS_VERSION_BUILD')) {
+            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/Symfony/Component/Process/Tests/SigchildDisabledProcessTest.php b/vendor/symfony/process/Symfony/Component/Process/Tests/SigchildDisabledProcessTest.php
new file mode 100644
index 00000000000..fdae5ec25e4
--- /dev/null
+++ b/vendor/symfony/process/Symfony/Component/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/Symfony/Component/Process/Tests/SigchildEnabledProcessTest.php b/vendor/symfony/process/Symfony/Component/Process/Tests/SigchildEnabledProcessTest.php
new file mode 100644
index 00000000000..3fea3ba1cd3
--- /dev/null
+++ b/vendor/symfony/process/Symfony/Component/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 (defined('PHP_WINDOWS_VERSION_BUILD')) {
+            $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/Symfony/Component/Process/Tests/SignalListener.php b/vendor/symfony/process/Symfony/Component/Process/Tests/SignalListener.php
new file mode 100644
index 00000000000..32910e17068
--- /dev/null
+++ b/vendor/symfony/process/Symfony/Component/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/Symfony/Component/Process/Tests/SimpleProcessTest.php b/vendor/symfony/process/Symfony/Component/Process/Tests/SimpleProcessTest.php
new file mode 100644
index 00000000000..cd206ea4c39
--- /dev/null
+++ b/vendor/symfony/process/Symfony/Component/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;
+
+    public 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('php -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('php -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('php -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/Symfony/Component/Process/composer.json b/vendor/symfony/process/Symfony/Component/Process/composer.json
new file mode 100644
index 00000000000..b5dbfe1390a
--- /dev/null
+++ b/vendor/symfony/process/Symfony/Component/Process/composer.json
@@ -0,0 +1,31 @@
+{
+    "name": "symfony/process",
+    "type": "library",
+    "description": "Symfony Process Component",
+    "keywords": [],
+    "homepage": "http://symfony.com",
+    "license": "MIT",
+    "authors": [
+        {
+            "name": "Fabien Potencier",
+            "email": "fabien@symfony.com"
+        },
+        {
+            "name": "Symfony Community",
+            "homepage": "http://symfony.com/contributors"
+        }
+    ],
+    "require": {
+        "php": ">=5.3.3"
+    },
+    "autoload": {
+        "psr-0": { "Symfony\\Component\\Process\\": "" }
+    },
+    "target-dir": "Symfony/Component/Process",
+    "minimum-stability": "dev",
+    "extra": {
+        "branch-alias": {
+            "dev-master": "2.5-dev"
+        }
+    }
+}
diff --git a/vendor/symfony/process/Symfony/Component/Process/phpunit.xml.dist b/vendor/symfony/process/Symfony/Component/Process/phpunit.xml.dist
new file mode 100644
index 00000000000..fcb230a0625
--- /dev/null
+++ b/vendor/symfony/process/Symfony/Component/Process/phpunit.xml.dist
@@ -0,0 +1,23 @@
+<?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"
+>
+    <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>
-- 
GitLab