diff --git a/composer.json b/composer.json
index f58b5af869f7d2df3965073e9a491b76e51308dc..e100a674cbeb3beb4d1e46863ff4ece7356f60f4 100644
--- a/composer.json
+++ b/composer.json
@@ -7,6 +7,7 @@
     "php": ">=5.4.2",
     "sdboyer/gliph": "0.1.*",
     "symfony/class-loader": "2.4.*",
+    "symfony/css-selector": "2.4.*",
     "symfony/dependency-injection": "2.4.*",
     "symfony/event-dispatcher": "2.4.*",
     "symfony/http-foundation": "2.4.*",
diff --git a/composer.lock b/composer.lock
index f8712885d8671df99d0219c7cd69293a8e39bb4b..a99f00eb04fcd973841111eac58462c21bc248d5 100644
--- a/composer.lock
+++ b/composer.lock
@@ -3,7 +3,7 @@
         "This file locks the dependencies of your project to a known state",
         "Read more about it at http://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file"
     ],
-    "hash": "764a98eeaf89d9f52b9c32d343036de0",
+    "hash": "cc429f39777a4435a2d1415648978f97",
     "packages": [
         {
             "name": "doctrine/annotations",
@@ -1188,6 +1188,59 @@
             "homepage": "http://symfony.com",
             "time": "2013-11-26 16:40:27"
         },
+        {
+            "name": "symfony/css-selector",
+            "version": "v2.4.4",
+            "target-dir": "Symfony/Component/CssSelector",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/symfony/CssSelector.git",
+                "reference": "479a5b409723f596ffc3b5178034e4d76ce615b3"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/symfony/CssSelector/zipball/479a5b409723f596ffc3b5178034e4d76ce615b3",
+                "reference": "479a5b409723f596ffc3b5178034e4d76ce615b3",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.3.3"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "2.4-dev"
+                }
+            },
+            "autoload": {
+                "psr-0": {
+                    "Symfony\\Component\\CssSelector\\": ""
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Fabien Potencier",
+                    "email": "fabien@symfony.com",
+                    "homepage": "http://fabien.potencier.org",
+                    "role": "Lead Developer"
+                },
+                {
+                    "name": "Symfony Community",
+                    "homepage": "http://symfony.com/contributors"
+                },
+                {
+                    "name": "Jean-François Simon",
+                    "email": "jeanfrancois.simon@sensiolabs.com"
+                }
+            ],
+            "description": "Symfony CssSelector Component",
+            "homepage": "http://symfony.com",
+            "time": "2014-04-18 20:37:09"
+        },
         {
             "name": "symfony/debug",
             "version": "v2.3.4",
diff --git a/core/modules/simpletest/src/WebTestBase.php b/core/modules/simpletest/src/WebTestBase.php
index a120883ac2e38732b4b67d31d0f9302a9cf8eb2a..ec50d4dd70f367bc02f8a2cfd79c62c5dff85e34 100644
--- a/core/modules/simpletest/src/WebTestBase.php
+++ b/core/modules/simpletest/src/WebTestBase.php
@@ -24,6 +24,7 @@
 use Drupal\Core\Datetime\DrupalDateTime;
 use Drupal\block\Entity\Block;
 use Symfony\Component\HttpFoundation\Request;
+use Symfony\Component\CssSelector\CssSelector;
 
 /**
  * Test case for typical Drupal tests.
@@ -2338,6 +2339,22 @@ protected function xpath($xpath, array $arguments = array()) {
     }
   }
 
+  /**
+   * Performs a CSS selection based search on the contents of the internal
+   * browser. The search is relative to the root element (HTML tag normally) of
+   * the page.
+   *
+   * @param $selector string
+   *   CSS selector to use in the search.
+   *
+   * @return \SimpleXMLElement
+   *   The return value of the xpath search performed after converting the css
+   *   selector to an XPath selector.
+   */
+  protected function cssSelect($selector) {
+    return $this->xpath(CssSelector::toXPath($selector));
+  }
+
   /**
    * Get all option elements, including nested options, in a select.
    *
diff --git a/core/modules/tour/src/Tests/TourTest.php b/core/modules/tour/src/Tests/TourTest.php
index 5c99036d881ec06f696c9610f4eaab245fbe9011..17e7d148ed6871d88e90a0983114cd849317684b 100644
--- a/core/modules/tour/src/Tests/TourTest.php
+++ b/core/modules/tour/src/Tests/TourTest.php
@@ -53,12 +53,6 @@ public static function getInfo() {
   public function testTourFunctionality() {
     // Navigate to tour-test-1 and verify the tour_test_1 tip is found with appropriate classes.
     $this->drupalGet('tour-test-1');
-    $elements = $this->xpath('//li[@data-id=:data_id and @class=:classes and ./h2[contains(., :text)]]', array(
-      ':classes' => 'tip-module-tour-test tip-type-text tip-tour-test-1',
-      ':data_id' => 'tour-test-1',
-      ':text' => 'The first tip',
-    ));
-    $this->assertEqual(count($elements), 1, 'Found English variant of tip 1.');
 
     // Test the TourTestBase class assertTourTips() method.
     $tips = array();
@@ -75,16 +69,13 @@ public function testTourFunctionality() {
     ));
     $this->assertEqual(count($elements), 1, 'Found Token replacement.');
 
-    $elements = $this->xpath('//li[@data-id=:data_id and ./h2[contains(., :text)]]', array(
-      ':data_id' => 'tour-test-2',
-      ':text' => 'The quick brown fox',
-    ));
+    $elements = $this->cssSelect("li[data-id=tour-test-1] h2:contains('The first tip')");
+    $this->assertEqual(count($elements), 1, 'Found English variant of tip 1.');
+
+    $elements = $this->cssSelect("li[data-id=tour-test-2] h2:contains('The quick brown fox')");
     $this->assertNotEqual(count($elements), 1, 'Did not find English variant of tip 2.');
 
-    $elements = $this->xpath('//li[@data-id=:data_id and ./h2[contains(., :text)]]', array(
-      ':data_id' => 'tour-test-1',
-      ':text' => 'La pioggia cade in spagna',
-    ));
+    $elements = $this->cssSelect("li[data-id=tour-test-1] h2:contains('La pioggia cade in spagna')");
     $this->assertNotEqual(count($elements), 1, 'Did not find Italian variant of tip 1.');
 
     // Ensure that plugins work.
@@ -93,16 +84,10 @@ public function testTourFunctionality() {
 
     // Navigate to tour-test-2/subpath and verify the tour_test_2 tip is found.
     $this->drupalGet('tour-test-2/subpath');
-    $elements = $this->xpath('//li[@data-id=:data_id and ./h2[contains(., :text)]]', array(
-      ':data_id' => 'tour-test-2',
-      ':text' => 'The quick brown fox',
-    ));
+    $elements = $this->cssSelect("li[data-id=tour-test-2] h2:contains('The quick brown fox')");
     $this->assertEqual(count($elements), 1, 'Found English variant of tip 2.');
 
-    $elements = $this->xpath('//li[@data-id=:data_id and ./h2[contains(., :text)]]', array(
-      ':data_id' => 'tour-test-1',
-      ':text' => 'The first tip',
-    ));
+    $elements = $this->cssSelect("li[data-id=tour-test-1] h2:contains('The first tip')");
     $this->assertNotEqual(count($elements), 1, 'Did not find English variant of tip 1.');
 
     // Enable Italian language and navigate to it/tour-test1 and verify italian
@@ -110,16 +95,10 @@ public function testTourFunctionality() {
     language_save(new Language(array('id' => 'it')));
     $this->drupalGet('it/tour-test-1');
 
-    $elements = $this->xpath('//li[@data-id=:data_id and ./h2[contains(., :text)]]', array(
-      ':data_id' => 'tour-test-1',
-      ':text' => 'La pioggia cade in spagna',
-    ));
+    $elements = $this->cssSelect("li[data-id=tour-test-1] h2:contains('La pioggia cade in spagna')");
     $this->assertEqual(count($elements), 1, 'Found Italian variant of tip 1.');
 
-    $elements = $this->xpath('//li[@data-id=:data_id and ./h2[contains(., :text)]]', array(
-      ':data_id' => 'tour-test-1',
-      ':text' => 'The first tip',
-    ));
+    $elements = $this->cssSelect("li[data-id=tour-test-2] h2:contains('The quick brown fox')");
     $this->assertNotEqual(count($elements), 1, 'Did not find English variant of tip 1.');
 
     language_save(new Language(array('id' => 'en')));
@@ -174,18 +153,12 @@ public function testTourFunctionality() {
 
     // Navigate to tour-test-1 and verify the new tip is found.
     $this->drupalGet('tour-test-1');
-    $elements = $this->xpath('//li[@data-id=:data_id and ./h2[contains(., :text)]]', array(
-      ':data_id' => 'tour-code-test-1',
-      ':text' => 'The rain in spain',
-    ));
+    $elements = $this->cssSelect("li[data-id=tour-code-test-1] h2:contains('The rain in spain')");
     $this->assertEqual(count($elements), 1, 'Found the required tip markup for tip 4');
 
     // Verify that the weight sorting works by ensuring the lower weight item
     // (tip 4) has the 'End tour' button.
-    $elements = $this->xpath('//li[@data-id=:data_id and @data-text=:text]', array(
-      ':data_id' => 'tour-code-test-1',
-      ':text' => 'End tour',
-    ));
+    $elements = $this->cssSelect("li[data-id=tour-code-test-1][data-text='End tour']");
     $this->assertEqual(count($elements), 1, 'Found code tip was weighted last and had "End tour".');
 
     // Test hook_tour_alter().
diff --git a/core/vendor/composer/ClassLoader.php b/core/vendor/composer/ClassLoader.php
index a7105553143a422546083f2bb49dd6a79a280a6a..f438e319cd51748608389f2fef6149a592b67241 100644
--- a/core/vendor/composer/ClassLoader.php
+++ b/core/vendor/composer/ClassLoader.php
@@ -266,7 +266,7 @@ public function unregister()
     public function loadClass($class)
     {
         if ($file = $this->findFile($class)) {
-            includeFile($file);
+            include $file;
 
             return true;
         }
@@ -291,25 +291,8 @@ public function findFile($class)
             return $this->classMap[$class];
         }
 
-        $file = $this->findFileWithExtension($class, '.php');
-
-        // Search for Hack files if we are running on HHVM
-        if ($file === null && defined('HHVM_VERSION')) {
-            $file = $this->findFileWithExtension($class, '.hh');
-        }
-
-        if ($file === null) {
-            // Remember that this class does not exist.
-            return $this->classMap[$class] = false;
-        }
-
-        return $file;
-    }
-
-    private function findFileWithExtension($class, $ext)
-    {
         // PSR-4 lookup
-        $logicalPathPsr4 = strtr($class, '\\', DIRECTORY_SEPARATOR) . $ext;
+        $logicalPathPsr4 = strtr($class, '\\', DIRECTORY_SEPARATOR) . '.php';
 
         $first = $class[0];
         if (isset($this->prefixLengthsPsr4[$first])) {
@@ -338,7 +321,7 @@ private function findFileWithExtension($class, $ext)
                 . strtr(substr($logicalPathPsr4, $pos + 1), '_', DIRECTORY_SEPARATOR);
         } else {
             // PEAR-like class name
-            $logicalPathPsr0 = strtr($class, '_', DIRECTORY_SEPARATOR) . $ext;
+            $logicalPathPsr0 = strtr($class, '_', DIRECTORY_SEPARATOR) . '.php';
         }
 
         if (isset($this->prefixesPsr0[$first])) {
@@ -364,15 +347,8 @@ private function findFileWithExtension($class, $ext)
         if ($this->useIncludePath && $file = stream_resolve_include_path($logicalPathPsr0)) {
             return $file;
         }
-    }
-}
 
-/**
- * Scope isolated include.
- *
- * Prevents access to $this/self from included files.
- */
-function includeFile($file)
-{
-    include $file;
+        // Remember that this class does not exist.
+        return $this->classMap[$class] = false;
+    }
 }
diff --git a/core/vendor/composer/autoload_files.php b/core/vendor/composer/autoload_files.php
index 2ca5d44933d191b4d91a1250d7a9b647ae95c293..c47ff8ce02687b8ee0b1453412a9132bc23c4d19 100644
--- a/core/vendor/composer/autoload_files.php
+++ b/core/vendor/composer/autoload_files.php
@@ -6,8 +6,8 @@
 $baseDir = dirname(dirname($vendorDir));
 
 return array(
-    $vendorDir . '/guzzlehttp/streams/src/functions.php',
     $vendorDir . '/kriswallsmith/assetic/src/functions.php',
+    $vendorDir . '/guzzlehttp/streams/src/functions.php',
     $vendorDir . '/guzzlehttp/guzzle/src/functions.php',
     $baseDir . '/core/lib/Drupal.php',
 );
diff --git a/core/vendor/composer/autoload_namespaces.php b/core/vendor/composer/autoload_namespaces.php
index b6e4ab82c25b8a1589e087be5ba368cd1182493d..e32355368463ccc467ab779e79d536c5d16b31d6 100644
--- a/core/vendor/composer/autoload_namespaces.php
+++ b/core/vendor/composer/autoload_namespaces.php
@@ -22,6 +22,7 @@
     'Symfony\\Component\\EventDispatcher\\' => array($vendorDir . '/symfony/event-dispatcher'),
     'Symfony\\Component\\DependencyInjection\\' => array($vendorDir . '/symfony/dependency-injection'),
     'Symfony\\Component\\Debug\\' => array($vendorDir . '/symfony/debug'),
+    'Symfony\\Component\\CssSelector\\' => array($vendorDir . '/symfony/css-selector'),
     'Symfony\\Component\\ClassLoader\\' => array($vendorDir . '/symfony/class-loader'),
     'Symfony\\Cmf\\Component\\Routing' => array($vendorDir . '/symfony-cmf/routing'),
     'Psr\\Log\\' => array($vendorDir . '/psr/log'),
diff --git a/core/vendor/composer/autoload_real.php b/core/vendor/composer/autoload_real.php
index 0ecdb36774e7d47ab993702dd89f365e3dad9ddd..233f4c59d5f82e524d8293ac6aac25f9d3cb1224 100644
--- a/core/vendor/composer/autoload_real.php
+++ b/core/vendor/composer/autoload_real.php
@@ -49,14 +49,9 @@ public static function getLoader()
 
         $includeFiles = require __DIR__ . '/autoload_files.php';
         foreach ($includeFiles as $file) {
-            composerRequireDrupal8($file);
+            require $file;
         }
 
         return $loader;
     }
 }
-
-function composerRequireDrupal8($file)
-{
-    require $file;
-}
diff --git a/core/vendor/composer/installed.json b/core/vendor/composer/installed.json
index ed8df0cbbb6c34e7f79ecc48292650cf91ac5355..2f33f03248f2e18bac29e43162d8390d2075bf54 100644
--- a/core/vendor/composer/installed.json
+++ b/core/vendor/composer/installed.json
@@ -825,212 +825,6 @@
             "string"
         ]
     },
-    {
-        "name": "guzzle/common",
-        "version": "v3.7.1",
-        "version_normalized": "3.7.1.0",
-        "target-dir": "Guzzle/Common",
-        "source": {
-            "type": "git",
-            "url": "https://github.com/guzzle/common.git",
-            "reference": "v3.7.1"
-        },
-        "dist": {
-            "type": "zip",
-            "url": "https://api.github.com/repos/guzzle/common/zipball/v3.7.1",
-            "reference": "v3.7.1",
-            "shasum": ""
-        },
-        "require": {
-            "php": ">=5.3.2",
-            "symfony/event-dispatcher": ">=2.1"
-        },
-        "time": "2013-07-05 20:17:54",
-        "type": "library",
-        "extra": {
-            "branch-alias": {
-                "dev-master": "3.7-dev"
-            }
-        },
-        "installation-source": "dist",
-        "autoload": {
-            "psr-0": {
-                "Guzzle\\Common": ""
-            }
-        },
-        "notification-url": "https://packagist.org/downloads/",
-        "license": [
-            "MIT"
-        ],
-        "description": "Common libraries used by Guzzle",
-        "homepage": "http://guzzlephp.org/",
-        "keywords": [
-            "collection",
-            "common",
-            "event",
-            "exception"
-        ]
-    },
-    {
-        "name": "guzzle/stream",
-        "version": "v3.7.1",
-        "version_normalized": "3.7.1.0",
-        "target-dir": "Guzzle/Stream",
-        "source": {
-            "type": "git",
-            "url": "https://github.com/guzzle/stream.git",
-            "reference": "v3.7.1"
-        },
-        "dist": {
-            "type": "zip",
-            "url": "https://api.github.com/repos/guzzle/stream/zipball/v3.7.1",
-            "reference": "v3.7.1",
-            "shasum": ""
-        },
-        "require": {
-            "guzzle/common": "self.version",
-            "php": ">=5.3.2"
-        },
-        "suggest": {
-            "guzzle/http": "To convert Guzzle request objects to PHP streams"
-        },
-        "time": "2013-06-27 00:50:43",
-        "type": "library",
-        "extra": {
-            "branch-alias": {
-                "dev-master": "3.7-dev"
-            }
-        },
-        "installation-source": "dist",
-        "autoload": {
-            "psr-0": {
-                "Guzzle\\Stream": ""
-            }
-        },
-        "notification-url": "https://packagist.org/downloads/",
-        "license": [
-            "MIT"
-        ],
-        "authors": [
-            {
-                "name": "Michael Dowling",
-                "email": "mtdowling@gmail.com",
-                "homepage": "https://github.com/mtdowling"
-            }
-        ],
-        "description": "Guzzle stream wrapper component",
-        "homepage": "http://guzzlephp.org/",
-        "keywords": [
-            "Guzzle",
-            "component",
-            "stream"
-        ]
-    },
-    {
-        "name": "guzzle/parser",
-        "version": "v3.7.1",
-        "version_normalized": "3.7.1.0",
-        "target-dir": "Guzzle/Parser",
-        "source": {
-            "type": "git",
-            "url": "https://github.com/guzzle/parser.git",
-            "reference": "v3.7.1"
-        },
-        "dist": {
-            "type": "zip",
-            "url": "https://api.github.com/repos/guzzle/parser/zipball/v3.7.1",
-            "reference": "v3.7.1",
-            "shasum": ""
-        },
-        "require": {
-            "php": ">=5.3.2"
-        },
-        "time": "2013-06-11 00:24:07",
-        "type": "library",
-        "extra": {
-            "branch-alias": {
-                "dev-master": "3.7-dev"
-            }
-        },
-        "installation-source": "dist",
-        "autoload": {
-            "psr-0": {
-                "Guzzle\\Parser": ""
-            }
-        },
-        "notification-url": "https://packagist.org/downloads/",
-        "license": [
-            "MIT"
-        ],
-        "description": "Interchangeable parsers used by Guzzle",
-        "homepage": "http://guzzlephp.org/",
-        "keywords": [
-            "URI Template",
-            "cookie",
-            "http",
-            "message",
-            "url"
-        ]
-    },
-    {
-        "name": "guzzle/http",
-        "version": "v3.7.1",
-        "version_normalized": "3.7.1.0",
-        "target-dir": "Guzzle/Http",
-        "source": {
-            "type": "git",
-            "url": "https://github.com/guzzle/http.git",
-            "reference": "v3.7.1"
-        },
-        "dist": {
-            "type": "zip",
-            "url": "https://api.github.com/repos/guzzle/http/zipball/v3.7.1",
-            "reference": "v3.7.1",
-            "shasum": ""
-        },
-        "require": {
-            "guzzle/common": "self.version",
-            "guzzle/parser": "self.version",
-            "guzzle/stream": "self.version",
-            "php": ">=5.3.2"
-        },
-        "suggest": {
-            "ext-curl": "*"
-        },
-        "time": "2013-07-02 19:53:26",
-        "type": "library",
-        "extra": {
-            "branch-alias": {
-                "dev-master": "3.7-dev"
-            }
-        },
-        "installation-source": "dist",
-        "autoload": {
-            "psr-0": {
-                "Guzzle\\Http": ""
-            }
-        },
-        "notification-url": "https://packagist.org/downloads/",
-        "license": [
-            "MIT"
-        ],
-        "authors": [
-            {
-                "name": "Michael Dowling",
-                "email": "mtdowling@gmail.com",
-                "homepage": "https://github.com/mtdowling"
-            }
-        ],
-        "description": "HTTP libraries used by Guzzle",
-        "homepage": "http://guzzlephp.org/",
-        "keywords": [
-            "Guzzle",
-            "client",
-            "curl",
-            "http",
-            "http client"
-        ]
-    },
     {
         "name": "symfony/debug",
         "version": "v2.3.4",
@@ -2317,5 +2111,60 @@
             "rest",
             "web service"
         ]
+    },
+    {
+        "name": "symfony/css-selector",
+        "version": "v2.4.4",
+        "version_normalized": "2.4.4.0",
+        "target-dir": "Symfony/Component/CssSelector",
+        "source": {
+            "type": "git",
+            "url": "https://github.com/symfony/CssSelector.git",
+            "reference": "479a5b409723f596ffc3b5178034e4d76ce615b3"
+        },
+        "dist": {
+            "type": "zip",
+            "url": "https://api.github.com/repos/symfony/CssSelector/zipball/479a5b409723f596ffc3b5178034e4d76ce615b3",
+            "reference": "479a5b409723f596ffc3b5178034e4d76ce615b3",
+            "shasum": ""
+        },
+        "require": {
+            "php": ">=5.3.3"
+        },
+        "time": "2014-04-18 20:37:09",
+        "type": "library",
+        "extra": {
+            "branch-alias": {
+                "dev-master": "2.4-dev"
+            }
+        },
+        "installation-source": "dist",
+        "autoload": {
+            "psr-0": {
+                "Symfony\\Component\\CssSelector\\": ""
+            }
+        },
+        "notification-url": "https://packagist.org/downloads/",
+        "license": [
+            "MIT"
+        ],
+        "authors": [
+            {
+                "name": "Fabien Potencier",
+                "email": "fabien@symfony.com",
+                "homepage": "http://fabien.potencier.org",
+                "role": "Lead Developer"
+            },
+            {
+                "name": "Symfony Community",
+                "homepage": "http://symfony.com/contributors"
+            },
+            {
+                "name": "Jean-François Simon",
+                "email": "jeanfrancois.simon@sensiolabs.com"
+            }
+        ],
+        "description": "Symfony CssSelector Component",
+        "homepage": "http://symfony.com"
     }
 ]
diff --git a/core/vendor/symfony/css-selector/Symfony/Component/CssSelector/.gitignore b/core/vendor/symfony/css-selector/Symfony/Component/CssSelector/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..c49a5d8df5c6548379f00c77fe572a7217bce218
--- /dev/null
+++ b/core/vendor/symfony/css-selector/Symfony/Component/CssSelector/.gitignore
@@ -0,0 +1,3 @@
+vendor/
+composer.lock
+phpunit.xml
diff --git a/core/vendor/symfony/css-selector/Symfony/Component/CssSelector/CHANGELOG.md b/core/vendor/symfony/css-selector/Symfony/Component/CssSelector/CHANGELOG.md
new file mode 100644
index 0000000000000000000000000000000000000000..be10abee924cefbb9c75643bf588a292ba051cb7
--- /dev/null
+++ b/core/vendor/symfony/css-selector/Symfony/Component/CssSelector/CHANGELOG.md
@@ -0,0 +1,7 @@
+CHANGELOG
+=========
+
+2.1.0
+-----
+
+ * none
diff --git a/core/vendor/symfony/css-selector/Symfony/Component/CssSelector/CssSelector.php b/core/vendor/symfony/css-selector/Symfony/Component/CssSelector/CssSelector.php
new file mode 100644
index 0000000000000000000000000000000000000000..7a12a8b7e1d899c59485ae1f7ee1f0d28e7bb1c5
--- /dev/null
+++ b/core/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/core/vendor/symfony/css-selector/Symfony/Component/CssSelector/Exception/ExceptionInterface.php b/core/vendor/symfony/css-selector/Symfony/Component/CssSelector/Exception/ExceptionInterface.php
new file mode 100644
index 0000000000000000000000000000000000000000..da01c2b271772a7157c16e4dc59443b6c2cb686f
--- /dev/null
+++ b/core/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/core/vendor/symfony/css-selector/Symfony/Component/CssSelector/Exception/ExpressionErrorException.php b/core/vendor/symfony/css-selector/Symfony/Component/CssSelector/Exception/ExpressionErrorException.php
new file mode 100644
index 0000000000000000000000000000000000000000..151dbf0350467a2098472ecf95c9bf8ff11dc26b
--- /dev/null
+++ b/core/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/core/vendor/symfony/css-selector/Symfony/Component/CssSelector/Exception/InternalErrorException.php b/core/vendor/symfony/css-selector/Symfony/Component/CssSelector/Exception/InternalErrorException.php
new file mode 100644
index 0000000000000000000000000000000000000000..8a815fb9ea5f0de1078d99b217bda8237f7434bb
--- /dev/null
+++ b/core/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/core/vendor/symfony/css-selector/Symfony/Component/CssSelector/Exception/ParseException.php b/core/vendor/symfony/css-selector/Symfony/Component/CssSelector/Exception/ParseException.php
new file mode 100644
index 0000000000000000000000000000000000000000..9c119f84c6a3757652ad722c5a74b576f5b19def
--- /dev/null
+++ b/core/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/core/vendor/symfony/css-selector/Symfony/Component/CssSelector/Exception/SyntaxErrorException.php b/core/vendor/symfony/css-selector/Symfony/Component/CssSelector/Exception/SyntaxErrorException.php
new file mode 100644
index 0000000000000000000000000000000000000000..529b891a3f5af6336a0afab94c332101eac31c47
--- /dev/null
+++ b/core/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/core/vendor/symfony/css-selector/Symfony/Component/CssSelector/LICENSE b/core/vendor/symfony/css-selector/Symfony/Component/CssSelector/LICENSE
new file mode 100644
index 0000000000000000000000000000000000000000..0b3292cf9023507c2f1f93ddfee7dd8e15838048
--- /dev/null
+++ b/core/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/core/vendor/symfony/css-selector/Symfony/Component/CssSelector/Node/AbstractNode.php b/core/vendor/symfony/css-selector/Symfony/Component/CssSelector/Node/AbstractNode.php
new file mode 100644
index 0000000000000000000000000000000000000000..f5324e191b0d0a955dd341995ddec3ec2814b416
--- /dev/null
+++ b/core/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/core/vendor/symfony/css-selector/Symfony/Component/CssSelector/Node/AttributeNode.php b/core/vendor/symfony/css-selector/Symfony/Component/CssSelector/Node/AttributeNode.php
new file mode 100644
index 0000000000000000000000000000000000000000..e2fa9a294c513af52e11b41137cdeb3796aec0de
--- /dev/null
+++ b/core/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/core/vendor/symfony/css-selector/Symfony/Component/CssSelector/Node/ClassNode.php b/core/vendor/symfony/css-selector/Symfony/Component/CssSelector/Node/ClassNode.php
new file mode 100644
index 0000000000000000000000000000000000000000..a7a59a33a9f48a1e39b0303a27595667e93c3c2b
--- /dev/null
+++ b/core/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/core/vendor/symfony/css-selector/Symfony/Component/CssSelector/Node/CombinedSelectorNode.php b/core/vendor/symfony/css-selector/Symfony/Component/CssSelector/Node/CombinedSelectorNode.php
new file mode 100644
index 0000000000000000000000000000000000000000..4e085ea4e1a72fb5fa46fee8f72f7704e0693a28
--- /dev/null
+++ b/core/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/core/vendor/symfony/css-selector/Symfony/Component/CssSelector/Node/ElementNode.php b/core/vendor/symfony/css-selector/Symfony/Component/CssSelector/Node/ElementNode.php
new file mode 100644
index 0000000000000000000000000000000000000000..9ab13c3f243744f1a95427849c313d848989360d
--- /dev/null
+++ b/core/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/core/vendor/symfony/css-selector/Symfony/Component/CssSelector/Node/FunctionNode.php b/core/vendor/symfony/css-selector/Symfony/Component/CssSelector/Node/FunctionNode.php
new file mode 100644
index 0000000000000000000000000000000000000000..ecd11a50b00d949f9c1a46a4f3f6af483917c182
--- /dev/null
+++ b/core/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/core/vendor/symfony/css-selector/Symfony/Component/CssSelector/Node/HashNode.php b/core/vendor/symfony/css-selector/Symfony/Component/CssSelector/Node/HashNode.php
new file mode 100644
index 0000000000000000000000000000000000000000..7fb407579b61bda2b1eb268034592052542611d3
--- /dev/null
+++ b/core/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/core/vendor/symfony/css-selector/Symfony/Component/CssSelector/Node/NegationNode.php b/core/vendor/symfony/css-selector/Symfony/Component/CssSelector/Node/NegationNode.php
new file mode 100644
index 0000000000000000000000000000000000000000..2529689095e5b8c65944183911f861ec1bbc68da
--- /dev/null
+++ b/core/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/core/vendor/symfony/css-selector/Symfony/Component/CssSelector/Node/NodeInterface.php b/core/vendor/symfony/css-selector/Symfony/Component/CssSelector/Node/NodeInterface.php
new file mode 100644
index 0000000000000000000000000000000000000000..1601c33a6ed3032c76eada0ecc85408504df90fe
--- /dev/null
+++ b/core/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/core/vendor/symfony/css-selector/Symfony/Component/CssSelector/Node/PseudoNode.php b/core/vendor/symfony/css-selector/Symfony/Component/CssSelector/Node/PseudoNode.php
new file mode 100644
index 0000000000000000000000000000000000000000..4f2d538f6f522dcc1b2f14bbea2fc86d59764360
--- /dev/null
+++ b/core/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/core/vendor/symfony/css-selector/Symfony/Component/CssSelector/Node/SelectorNode.php b/core/vendor/symfony/css-selector/Symfony/Component/CssSelector/Node/SelectorNode.php
new file mode 100644
index 0000000000000000000000000000000000000000..49f417f2860c2e631157c851e85807e0167e6b35
--- /dev/null
+++ b/core/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/core/vendor/symfony/css-selector/Symfony/Component/CssSelector/Node/Specificity.php b/core/vendor/symfony/css-selector/Symfony/Component/CssSelector/Node/Specificity.php
new file mode 100644
index 0000000000000000000000000000000000000000..96bbd11f515ce2f40783c11135d2f5e36f170b36
--- /dev/null
+++ b/core/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/core/vendor/symfony/css-selector/Symfony/Component/CssSelector/Parser/Handler/CommentHandler.php b/core/vendor/symfony/css-selector/Symfony/Component/CssSelector/Parser/Handler/CommentHandler.php
new file mode 100644
index 0000000000000000000000000000000000000000..97c3f8dd24c657f9251b5ebf3c81e20fe669e491
--- /dev/null
+++ b/core/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/core/vendor/symfony/css-selector/Symfony/Component/CssSelector/Parser/Handler/HandlerInterface.php b/core/vendor/symfony/css-selector/Symfony/Component/CssSelector/Parser/Handler/HandlerInterface.php
new file mode 100644
index 0000000000000000000000000000000000000000..c7a48c0d6eb1b4b5dbd2e3c8da73ae05d3ad7b0d
--- /dev/null
+++ b/core/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/core/vendor/symfony/css-selector/Symfony/Component/CssSelector/Parser/Handler/HashHandler.php b/core/vendor/symfony/css-selector/Symfony/Component/CssSelector/Parser/Handler/HashHandler.php
new file mode 100644
index 0000000000000000000000000000000000000000..2227ea62a6aaed22d900a3a90daec75f843ba12e
--- /dev/null
+++ b/core/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/core/vendor/symfony/css-selector/Symfony/Component/CssSelector/Parser/Handler/IdentifierHandler.php b/core/vendor/symfony/css-selector/Symfony/Component/CssSelector/Parser/Handler/IdentifierHandler.php
new file mode 100644
index 0000000000000000000000000000000000000000..346532ec1512141df8bda83225451aff0b4d58cf
--- /dev/null
+++ b/core/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/core/vendor/symfony/css-selector/Symfony/Component/CssSelector/Parser/Handler/NumberHandler.php b/core/vendor/symfony/css-selector/Symfony/Component/CssSelector/Parser/Handler/NumberHandler.php
new file mode 100644
index 0000000000000000000000000000000000000000..208f83c08fe778653dac3209f0b1168716854ed9
--- /dev/null
+++ b/core/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/core/vendor/symfony/css-selector/Symfony/Component/CssSelector/Parser/Handler/StringHandler.php b/core/vendor/symfony/css-selector/Symfony/Component/CssSelector/Parser/Handler/StringHandler.php
new file mode 100644
index 0000000000000000000000000000000000000000..2663fe87b5112e27e86781251604fe2097c99598
--- /dev/null
+++ b/core/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/core/vendor/symfony/css-selector/Symfony/Component/CssSelector/Parser/Handler/WhitespaceHandler.php b/core/vendor/symfony/css-selector/Symfony/Component/CssSelector/Parser/Handler/WhitespaceHandler.php
new file mode 100644
index 0000000000000000000000000000000000000000..806cfbb513520035f9907b7d1e203260fa11a0e5
--- /dev/null
+++ b/core/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/core/vendor/symfony/css-selector/Symfony/Component/CssSelector/Parser/Parser.php b/core/vendor/symfony/css-selector/Symfony/Component/CssSelector/Parser/Parser.php
new file mode 100644
index 0000000000000000000000000000000000000000..6c7c3be583ba8c8b869c68e6647713770f7cb91a
--- /dev/null
+++ b/core/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/core/vendor/symfony/css-selector/Symfony/Component/CssSelector/Parser/ParserInterface.php b/core/vendor/symfony/css-selector/Symfony/Component/CssSelector/Parser/ParserInterface.php
new file mode 100644
index 0000000000000000000000000000000000000000..b27f79f4a6e4addada16c36da3b3699d7ca2e623
--- /dev/null
+++ b/core/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/core/vendor/symfony/css-selector/Symfony/Component/CssSelector/Parser/Reader.php b/core/vendor/symfony/css-selector/Symfony/Component/CssSelector/Parser/Reader.php
new file mode 100644
index 0000000000000000000000000000000000000000..2a6c4bbd43964be598c930917991fbbfa7df9d24
--- /dev/null
+++ b/core/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/core/vendor/symfony/css-selector/Symfony/Component/CssSelector/Parser/Shortcut/ClassParser.php b/core/vendor/symfony/css-selector/Symfony/Component/CssSelector/Parser/Shortcut/ClassParser.php
new file mode 100644
index 0000000000000000000000000000000000000000..db352334f0a2415fd273be89fb4617fe129d75db
--- /dev/null
+++ b/core/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/core/vendor/symfony/css-selector/Symfony/Component/CssSelector/Parser/Shortcut/ElementParser.php b/core/vendor/symfony/css-selector/Symfony/Component/CssSelector/Parser/Shortcut/ElementParser.php
new file mode 100644
index 0000000000000000000000000000000000000000..eae18b94679fd0959b3630f1009df722e4791f84
--- /dev/null
+++ b/core/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/core/vendor/symfony/css-selector/Symfony/Component/CssSelector/Parser/Shortcut/EmptyStringParser.php b/core/vendor/symfony/css-selector/Symfony/Component/CssSelector/Parser/Shortcut/EmptyStringParser.php
new file mode 100644
index 0000000000000000000000000000000000000000..0031f7cfef3be0c74e488b4813ebde2a401190e4
--- /dev/null
+++ b/core/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/core/vendor/symfony/css-selector/Symfony/Component/CssSelector/Parser/Shortcut/HashParser.php b/core/vendor/symfony/css-selector/Symfony/Component/CssSelector/Parser/Shortcut/HashParser.php
new file mode 100644
index 0000000000000000000000000000000000000000..95d7d5f91174f9cb04a0bb03c2ab4d84cdea4ac1
--- /dev/null
+++ b/core/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/core/vendor/symfony/css-selector/Symfony/Component/CssSelector/Parser/Token.php b/core/vendor/symfony/css-selector/Symfony/Component/CssSelector/Parser/Token.php
new file mode 100644
index 0000000000000000000000000000000000000000..4adfca889d866303688a4438bb3ab420cc38a068
--- /dev/null
+++ b/core/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/core/vendor/symfony/css-selector/Symfony/Component/CssSelector/Parser/TokenStream.php b/core/vendor/symfony/css-selector/Symfony/Component/CssSelector/Parser/TokenStream.php
new file mode 100644
index 0000000000000000000000000000000000000000..05d715b961a8391c555fa8b64a859f06d01d8276
--- /dev/null
+++ b/core/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/core/vendor/symfony/css-selector/Symfony/Component/CssSelector/Parser/Tokenizer/Tokenizer.php b/core/vendor/symfony/css-selector/Symfony/Component/CssSelector/Parser/Tokenizer/Tokenizer.php
new file mode 100644
index 0000000000000000000000000000000000000000..c850276728c749b57787e6960ff363d38ffe4ab4
--- /dev/null
+++ b/core/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/core/vendor/symfony/css-selector/Symfony/Component/CssSelector/Parser/Tokenizer/TokenizerEscaping.php b/core/vendor/symfony/css-selector/Symfony/Component/CssSelector/Parser/Tokenizer/TokenizerEscaping.php
new file mode 100644
index 0000000000000000000000000000000000000000..c90fc1044d3a9c5d43e29f190ddd6b21b27fad16
--- /dev/null
+++ b/core/vendor/symfony/css-selector/Symfony/Component/CssSelector/Parser/Tokenizer/TokenizerEscaping.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;
+
+/**
+ * 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 (array $match) {
+            $code = $match[1];
+
+            if (bin2hex($code) > 0xFFFD) {
+                $code = '\\FFFD';
+            }
+
+            return mb_convert_encoding(pack('H*', $code), 'UTF-8', 'UCS-2BE');
+        }, $value);
+    }
+}
diff --git a/core/vendor/symfony/css-selector/Symfony/Component/CssSelector/Parser/Tokenizer/TokenizerPatterns.php b/core/vendor/symfony/css-selector/Symfony/Component/CssSelector/Parser/Tokenizer/TokenizerPatterns.php
new file mode 100644
index 0000000000000000000000000000000000000000..6fc98b71e12658f037b07adefde47b391e690d68
--- /dev/null
+++ b/core/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/core/vendor/symfony/css-selector/Symfony/Component/CssSelector/README.md b/core/vendor/symfony/css-selector/Symfony/Component/CssSelector/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..623649bedbb23678cbac55434b43d1468e5366a3
--- /dev/null
+++ b/core/vendor/symfony/css-selector/Symfony/Component/CssSelector/README.md
@@ -0,0 +1,44 @@
+CssSelector Component
+=====================
+
+CssSelector converts CSS selectors to XPath expressions.
+
+The component only goal is to convert CSS selectors to their XPath
+equivalents:
+
+    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`:
+
+    // 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@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/core/vendor/symfony/css-selector/Symfony/Component/CssSelector/Tests/CssSelectorTest.php b/core/vendor/symfony/css-selector/Symfony/Component/CssSelector/Tests/CssSelectorTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..50daeccd1d27819f4edff05235c489cd5f344926
--- /dev/null
+++ b/core/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/core/vendor/symfony/css-selector/Symfony/Component/CssSelector/Tests/Node/AbstractNodeTest.php b/core/vendor/symfony/css-selector/Symfony/Component/CssSelector/Tests/Node/AbstractNodeTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..16a3a34d6497d2ecb92c1c880d23fdfa72828312
--- /dev/null
+++ b/core/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/core/vendor/symfony/css-selector/Symfony/Component/CssSelector/Tests/Node/AttributeNodeTest.php b/core/vendor/symfony/css-selector/Symfony/Component/CssSelector/Tests/Node/AttributeNodeTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..1fd090f5a6e8c1f1109282f65d85f24f28f29289
--- /dev/null
+++ b/core/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/core/vendor/symfony/css-selector/Symfony/Component/CssSelector/Tests/Node/ClassNodeTest.php b/core/vendor/symfony/css-selector/Symfony/Component/CssSelector/Tests/Node/ClassNodeTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..e0ab45accc31de8f51013ab80e37f239d16657fd
--- /dev/null
+++ b/core/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/core/vendor/symfony/css-selector/Symfony/Component/CssSelector/Tests/Node/CombinedSelectorNodeTest.php b/core/vendor/symfony/css-selector/Symfony/Component/CssSelector/Tests/Node/CombinedSelectorNodeTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..9547298a6fdf3faee1450dee4539d80f049b5cd5
--- /dev/null
+++ b/core/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/core/vendor/symfony/css-selector/Symfony/Component/CssSelector/Tests/Node/ElementNodeTest.php b/core/vendor/symfony/css-selector/Symfony/Component/CssSelector/Tests/Node/ElementNodeTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..1db6a591a2f5c5047b818f10e8eb723620530539
--- /dev/null
+++ b/core/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/core/vendor/symfony/css-selector/Symfony/Component/CssSelector/Tests/Node/FunctionNodeTest.php b/core/vendor/symfony/css-selector/Symfony/Component/CssSelector/Tests/Node/FunctionNodeTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..ee3ce51ba549954ecf473d313fa96638e8ab98fd
--- /dev/null
+++ b/core/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/core/vendor/symfony/css-selector/Symfony/Component/CssSelector/Tests/Node/HashNodeTest.php b/core/vendor/symfony/css-selector/Symfony/Component/CssSelector/Tests/Node/HashNodeTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..8554b226d6c7fe3fb00ad21784826f3595c5bbeb
--- /dev/null
+++ b/core/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/core/vendor/symfony/css-selector/Symfony/Component/CssSelector/Tests/Node/NegationNodeTest.php b/core/vendor/symfony/css-selector/Symfony/Component/CssSelector/Tests/Node/NegationNodeTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..edf4552bac8b8dadae6cb6c7e5c76688903770d3
--- /dev/null
+++ b/core/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/core/vendor/symfony/css-selector/Symfony/Component/CssSelector/Tests/Node/PseudoNodeTest.php b/core/vendor/symfony/css-selector/Symfony/Component/CssSelector/Tests/Node/PseudoNodeTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..bc57813cc8fe16300834a2ab1e5c100d6e2870ae
--- /dev/null
+++ b/core/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/core/vendor/symfony/css-selector/Symfony/Component/CssSelector/Tests/Node/SelectorNodeTest.php b/core/vendor/symfony/css-selector/Symfony/Component/CssSelector/Tests/Node/SelectorNodeTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..5badf71d16d1bb9f92714e24414f91ca541607e3
--- /dev/null
+++ b/core/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/core/vendor/symfony/css-selector/Symfony/Component/CssSelector/Tests/Node/SpecificityTest.php b/core/vendor/symfony/css-selector/Symfony/Component/CssSelector/Tests/Node/SpecificityTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..1f200cffe4f0447e13b5db8bdaee1458f7b8be72
--- /dev/null
+++ b/core/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/core/vendor/symfony/css-selector/Symfony/Component/CssSelector/Tests/Parser/Handler/AbstractHandlerTest.php b/core/vendor/symfony/css-selector/Symfony/Component/CssSelector/Tests/Parser/Handler/AbstractHandlerTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..a06dca013bae787e5ec14790dfcf87b07b1fc49f
--- /dev/null
+++ b/core/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/core/vendor/symfony/css-selector/Symfony/Component/CssSelector/Tests/Parser/Handler/CommentHandlerTest.php b/core/vendor/symfony/css-selector/Symfony/Component/CssSelector/Tests/Parser/Handler/CommentHandlerTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..3961bf7d55ad9ee48d6356cd3ea02a34ff9c6eca
--- /dev/null
+++ b/core/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/core/vendor/symfony/css-selector/Symfony/Component/CssSelector/Tests/Parser/Handler/HashHandlerTest.php b/core/vendor/symfony/css-selector/Symfony/Component/CssSelector/Tests/Parser/Handler/HashHandlerTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..b7fa00a2255eed45b8420cd3bb22d955f50dae98
--- /dev/null
+++ b/core/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/core/vendor/symfony/css-selector/Symfony/Component/CssSelector/Tests/Parser/Handler/IdentifierHandlerTest.php b/core/vendor/symfony/css-selector/Symfony/Component/CssSelector/Tests/Parser/Handler/IdentifierHandlerTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..44d35749845ab724364517fd32861f34ac155dbd
--- /dev/null
+++ b/core/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/core/vendor/symfony/css-selector/Symfony/Component/CssSelector/Tests/Parser/Handler/NumberHandlerTest.php b/core/vendor/symfony/css-selector/Symfony/Component/CssSelector/Tests/Parser/Handler/NumberHandlerTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..675fd05b43ef895ab439939ef0c04deb2bb46349
--- /dev/null
+++ b/core/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/core/vendor/symfony/css-selector/Symfony/Component/CssSelector/Tests/Parser/Handler/StringHandlerTest.php b/core/vendor/symfony/css-selector/Symfony/Component/CssSelector/Tests/Parser/Handler/StringHandlerTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..89eff8bd2825bb02f8af446d605cb812deba6bed
--- /dev/null
+++ b/core/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/core/vendor/symfony/css-selector/Symfony/Component/CssSelector/Tests/Parser/Handler/WhitespaceHandlerTest.php b/core/vendor/symfony/css-selector/Symfony/Component/CssSelector/Tests/Parser/Handler/WhitespaceHandlerTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..f5f9e71dc228782051938ca231c5d61589419ef6
--- /dev/null
+++ b/core/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/core/vendor/symfony/css-selector/Symfony/Component/CssSelector/Tests/Parser/ParserTest.php b/core/vendor/symfony/css-selector/Symfony/Component/CssSelector/Tests/Parser/ParserTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..0454d9faa6f75d28aba8660bb2517885c817bce4
--- /dev/null
+++ b/core/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/core/vendor/symfony/css-selector/Symfony/Component/CssSelector/Tests/Parser/ReaderTest.php b/core/vendor/symfony/css-selector/Symfony/Component/CssSelector/Tests/Parser/ReaderTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..03c054eaaeeb797d2d36865c74cf0e6b5d2a9070
--- /dev/null
+++ b/core/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/core/vendor/symfony/css-selector/Symfony/Component/CssSelector/Tests/Parser/Shortcut/ClassParserTest.php b/core/vendor/symfony/css-selector/Symfony/Component/CssSelector/Tests/Parser/Shortcut/ClassParserTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..6efdd67657630f5aacfbb3895a47d82b7e442d1d
--- /dev/null
+++ b/core/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/core/vendor/symfony/css-selector/Symfony/Component/CssSelector/Tests/Parser/Shortcut/ElementParserTest.php b/core/vendor/symfony/css-selector/Symfony/Component/CssSelector/Tests/Parser/Shortcut/ElementParserTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..b30b5ee7acd1fed1ae34bf7724034bd995bdbe69
--- /dev/null
+++ b/core/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/core/vendor/symfony/css-selector/Symfony/Component/CssSelector/Tests/Parser/Shortcut/EmptyStringParserTest.php b/core/vendor/symfony/css-selector/Symfony/Component/CssSelector/Tests/Parser/Shortcut/EmptyStringParserTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..b7c3539c67a97f1041a06d1dff549a5e169e9bc7
--- /dev/null
+++ b/core/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/core/vendor/symfony/css-selector/Symfony/Component/CssSelector/Tests/Parser/Shortcut/HashParserTest.php b/core/vendor/symfony/css-selector/Symfony/Component/CssSelector/Tests/Parser/Shortcut/HashParserTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..d2ce891ec8206ddc49720caf1fe99951b44214f1
--- /dev/null
+++ b/core/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/core/vendor/symfony/css-selector/Symfony/Component/CssSelector/Tests/Parser/TokenStreamTest.php b/core/vendor/symfony/css-selector/Symfony/Component/CssSelector/Tests/Parser/TokenStreamTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..8f3253a7d59f5953dff20ce9dabb383523f12f87
--- /dev/null
+++ b/core/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/core/vendor/symfony/css-selector/Symfony/Component/CssSelector/Tests/XPath/Fixtures/ids.html b/core/vendor/symfony/css-selector/Symfony/Component/CssSelector/Tests/XPath/Fixtures/ids.html
new file mode 100644
index 0000000000000000000000000000000000000000..5799fad25ecfb33bca8ab42c615253160c061636
--- /dev/null
+++ b/core/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/core/vendor/symfony/css-selector/Symfony/Component/CssSelector/Tests/XPath/Fixtures/lang.xml b/core/vendor/symfony/css-selector/Symfony/Component/CssSelector/Tests/XPath/Fixtures/lang.xml
new file mode 100644
index 0000000000000000000000000000000000000000..14f8dbed681f6f52eb9c7f7bbc021ccdee4533bb
--- /dev/null
+++ b/core/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/core/vendor/symfony/css-selector/Symfony/Component/CssSelector/Tests/XPath/Fixtures/shakespear.html b/core/vendor/symfony/css-selector/Symfony/Component/CssSelector/Tests/XPath/Fixtures/shakespear.html
new file mode 100644
index 0000000000000000000000000000000000000000..15d1ad33a3192dd9e141a5ac006465fd7f4315ba
--- /dev/null
+++ b/core/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/core/vendor/symfony/css-selector/Symfony/Component/CssSelector/Tests/XPath/TranslatorTest.php b/core/vendor/symfony/css-selector/Symfony/Component/CssSelector/Tests/XPath/TranslatorTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..30f7189f06f18ba248e02af0515a12b0dbd99b6e
--- /dev/null
+++ b/core/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/core/vendor/symfony/css-selector/Symfony/Component/CssSelector/XPath/Extension/AbstractExtension.php b/core/vendor/symfony/css-selector/Symfony/Component/CssSelector/XPath/Extension/AbstractExtension.php
new file mode 100644
index 0000000000000000000000000000000000000000..1b147e9ecf6e8bbccd752f053b608458acc7fb35
--- /dev/null
+++ b/core/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/core/vendor/symfony/css-selector/Symfony/Component/CssSelector/XPath/Extension/AttributeMatchingExtension.php b/core/vendor/symfony/css-selector/Symfony/Component/CssSelector/XPath/Extension/AttributeMatchingExtension.php
new file mode 100644
index 0000000000000000000000000000000000000000..1b1f00f2863e84b7cfafe08d380cf7d824d7f08b
--- /dev/null
+++ b/core/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/core/vendor/symfony/css-selector/Symfony/Component/CssSelector/XPath/Extension/CombinationExtension.php b/core/vendor/symfony/css-selector/Symfony/Component/CssSelector/XPath/Extension/CombinationExtension.php
new file mode 100644
index 0000000000000000000000000000000000000000..639e9249521904690e987d0eaa67bb7d5db81586
--- /dev/null
+++ b/core/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/core/vendor/symfony/css-selector/Symfony/Component/CssSelector/XPath/Extension/ExtensionInterface.php b/core/vendor/symfony/css-selector/Symfony/Component/CssSelector/XPath/Extension/ExtensionInterface.php
new file mode 100644
index 0000000000000000000000000000000000000000..65ab287770f27ac4f87790caec74246e0ccaffe4
--- /dev/null
+++ b/core/vendor/symfony/css-selector/Symfony/Component/CssSelector/XPath/Extension/ExtensionInterface.php
@@ -0,0 +1,65 @@
+<?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.
+     *
+     * @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/core/vendor/symfony/css-selector/Symfony/Component/CssSelector/XPath/Extension/FunctionExtension.php b/core/vendor/symfony/css-selector/Symfony/Component/CssSelector/XPath/Extension/FunctionExtension.php
new file mode 100644
index 0000000000000000000000000000000000000000..ff8f333ada06903c2a60a8dd3750a654dd395410
--- /dev/null
+++ b/core/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/core/vendor/symfony/css-selector/Symfony/Component/CssSelector/XPath/Extension/HtmlExtension.php b/core/vendor/symfony/css-selector/Symfony/Component/CssSelector/XPath/Extension/HtmlExtension.php
new file mode 100644
index 0000000000000000000000000000000000000000..aef80523dd0910b192239caeeb681e88d6ff3f5e
--- /dev/null
+++ b/core/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/core/vendor/symfony/css-selector/Symfony/Component/CssSelector/XPath/Extension/NodeExtension.php b/core/vendor/symfony/css-selector/Symfony/Component/CssSelector/XPath/Extension/NodeExtension.php
new file mode 100644
index 0000000000000000000000000000000000000000..f86f2b967266adae658206a1bb1fabbd4b2065be
--- /dev/null
+++ b/core/vendor/symfony/css-selector/Symfony/Component/CssSelector/XPath/Extension/NodeExtension.php
@@ -0,0 +1,270 @@
+<?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 Translator
+     */
+    private $translator;
+
+    /**
+     * @var int
+     */
+    private $flags;
+
+    /**
+     * Constructor.
+     *
+     * @param Translator $translator
+     * @param int        $flags
+     */
+    public function __construct(Translator $translator, $flags = 0)
+    {
+        $this->translator = $translator;
+        $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
+     *
+     * @return XPathExpr
+     */
+    public function translateSelector(Node\SelectorNode $node)
+    {
+        return $this->translator->nodeToXPath($node->getTree());
+    }
+
+    /**
+     * @param Node\CombinedSelectorNode $node
+     *
+     * @return XPathExpr
+     */
+    public function translateCombinedSelector(Node\CombinedSelectorNode $node)
+    {
+        return $this->translator->addCombination($node->getCombinator(), $node->getSelector(), $node->getSubSelector());
+    }
+
+    /**
+     * @param Node\NegationNode $node
+     *
+     * @return XPathExpr
+     */
+    public function translateNegation(Node\NegationNode $node)
+    {
+        $xpath = $this->translator->nodeToXPath($node->getSelector());
+        $subXpath = $this->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
+     *
+     * @return XPathExpr
+     */
+    public function translateFunction(Node\FunctionNode $node)
+    {
+        $xpath = $this->translator->nodeToXPath($node->getSelector());
+
+        return $this->translator->addFunction($xpath, $node);
+    }
+
+    /**
+     * @param Node\PseudoNode $node
+     *
+     * @return XPathExpr
+     */
+    public function translatePseudo(Node\PseudoNode $node)
+    {
+        $xpath = $this->translator->nodeToXPath($node->getSelector());
+
+        return $this->translator->addPseudoClass($xpath, $node->getIdentifier());
+    }
+
+    /**
+     * @param Node\AttributeNode $node
+     *
+     * @return XPathExpr
+     */
+    public function translateAttribute(Node\AttributeNode $node)
+    {
+        $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 = $this->translator->nodeToXPath($node->getSelector());
+
+        if ($this->hasFlag(self::ATTRIBUTE_VALUE_IN_LOWER_CASE)) {
+            $value = strtolower($value);
+        }
+
+        return $this->translator->addAttributeMatching($xpath, $node->getOperator(), $attribute, $value);
+    }
+
+    /**
+     * @param Node\ClassNode $node
+     *
+     * @return XPathExpr
+     */
+    public function translateClass(Node\ClassNode $node)
+    {
+        $xpath = $this->translator->nodeToXPath($node->getSelector());
+
+        return $this->translator->addAttributeMatching($xpath, '~=', '@class', $node->getName());
+    }
+
+    /**
+     * @param Node\HashNode $node
+     *
+     * @return XPathExpr
+     */
+    public function translateHash(Node\HashNode $node)
+    {
+        $xpath = $this->translator->nodeToXPath($node->getSelector());
+
+        return $this->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/core/vendor/symfony/css-selector/Symfony/Component/CssSelector/XPath/Extension/PseudoClassExtension.php b/core/vendor/symfony/css-selector/Symfony/Component/CssSelector/XPath/Extension/PseudoClassExtension.php
new file mode 100644
index 0000000000000000000000000000000000000000..d230dd7c483f97fd4475c74e9ccde9fe20745caf
--- /dev/null
+++ b/core/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/core/vendor/symfony/css-selector/Symfony/Component/CssSelector/XPath/Translator.php b/core/vendor/symfony/css-selector/Symfony/Component/CssSelector/XPath/Translator.php
new file mode 100644
index 0000000000000000000000000000000000000000..5a8eb99017a1b58149f267319c5ae939f736beac
--- /dev/null
+++ b/core/vendor/symfony/css-selector/Symfony/Component/CssSelector/XPath/Translator.php
@@ -0,0 +1,301 @@
+<?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($this))
+            ->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 $selector) {
+            if (null !== $selector->getPseudoElement()) {
+                throw new ExpressionErrorException('Pseudo-elements are not supported.');
+            }
+        }
+
+        $translator = $this;
+
+        return implode(' | ', array_map(function (SelectorNode $selector) use ($translator, $prefix) {
+            return $translator->selectorToXPath($selector, $prefix);
+        }, $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);
+    }
+
+    /**
+     * @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/core/vendor/symfony/css-selector/Symfony/Component/CssSelector/XPath/TranslatorInterface.php b/core/vendor/symfony/css-selector/Symfony/Component/CssSelector/XPath/TranslatorInterface.php
new file mode 100644
index 0000000000000000000000000000000000000000..b26cf5b0c399184d9a621939a0706429cd20a988
--- /dev/null
+++ b/core/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/core/vendor/symfony/css-selector/Symfony/Component/CssSelector/XPath/XPathExpr.php b/core/vendor/symfony/css-selector/Symfony/Component/CssSelector/XPath/XPathExpr.php
new file mode 100644
index 0000000000000000000000000000000000000000..f0f2f987678ed719c86342a46b31a1682cc976f0
--- /dev/null
+++ b/core/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/core/vendor/symfony/css-selector/Symfony/Component/CssSelector/composer.json b/core/vendor/symfony/css-selector/Symfony/Component/CssSelector/composer.json
new file mode 100644
index 0000000000000000000000000000000000000000..1ab133f3181456690bab77bfa0180f66c4ff0a99
--- /dev/null
+++ b/core/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.4-dev"
+        }
+    }
+}
diff --git a/core/vendor/symfony/css-selector/Symfony/Component/CssSelector/phpunit.xml.dist b/core/vendor/symfony/css-selector/Symfony/Component/CssSelector/phpunit.xml.dist
new file mode 100644
index 0000000000000000000000000000000000000000..a19dc00b348f1a680903cfaf34ecea5a77633084
--- /dev/null
+++ b/core/vendor/symfony/css-selector/Symfony/Component/CssSelector/phpunit.xml.dist
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<phpunit backupGlobals="false"
+         backupStaticAttributes="false"
+         colors="true"
+         convertErrorsToExceptions="true"
+         convertNoticesToExceptions="true"
+         convertWarningsToExceptions="true"
+         processIsolation="false"
+         stopOnFailure="false"
+         syntaxCheck="false"
+         bootstrap="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>