summaryrefslogtreecommitdiff
path: root/www/wiki/vendor/symfony
diff options
context:
space:
mode:
authorYaco <franco@reevo.org>2020-06-04 11:01:00 -0300
committerYaco <franco@reevo.org>2020-06-04 11:01:00 -0300
commitfc7369835258467bf97eb64f184b93691f9a9fd5 (patch)
treedaabd60089d2dd76d9f5fb416b005fbe159c799d /www/wiki/vendor/symfony
first commit
Diffstat (limited to 'www/wiki/vendor/symfony')
-rw-r--r--www/wiki/vendor/symfony/css-selector/.gitignore3
-rw-r--r--www/wiki/vendor/symfony/css-selector/CHANGELOG.md13
-rw-r--r--www/wiki/vendor/symfony/css-selector/CssSelectorConverter.php65
-rw-r--r--www/wiki/vendor/symfony/css-selector/Exception/ExceptionInterface.php24
-rw-r--r--www/wiki/vendor/symfony/css-selector/Exception/ExpressionErrorException.php24
-rw-r--r--www/wiki/vendor/symfony/css-selector/Exception/InternalErrorException.php24
-rw-r--r--www/wiki/vendor/symfony/css-selector/Exception/ParseException.php24
-rw-r--r--www/wiki/vendor/symfony/css-selector/Exception/SyntaxErrorException.php73
-rw-r--r--www/wiki/vendor/symfony/css-selector/LICENSE19
-rw-r--r--www/wiki/vendor/symfony/css-selector/Node/AbstractNode.php42
-rw-r--r--www/wiki/vendor/symfony/css-selector/Node/AttributeNode.php107
-rw-r--r--www/wiki/vendor/symfony/css-selector/Node/ClassNode.php70
-rw-r--r--www/wiki/vendor/symfony/css-selector/Node/CombinedSelectorNode.php83
-rw-r--r--www/wiki/vendor/symfony/css-selector/Node/ElementNode.php72
-rw-r--r--www/wiki/vendor/symfony/css-selector/Node/FunctionNode.php87
-rw-r--r--www/wiki/vendor/symfony/css-selector/Node/HashNode.php70
-rw-r--r--www/wiki/vendor/symfony/css-selector/Node/NegationNode.php66
-rw-r--r--www/wiki/vendor/symfony/css-selector/Node/NodeInterface.php46
-rw-r--r--www/wiki/vendor/symfony/css-selector/Node/PseudoNode.php70
-rw-r--r--www/wiki/vendor/symfony/css-selector/Node/SelectorNode.php70
-rw-r--r--www/wiki/vendor/symfony/css-selector/Node/Specificity.php88
-rw-r--r--www/wiki/vendor/symfony/css-selector/Parser/Handler/CommentHandler.php48
-rw-r--r--www/wiki/vendor/symfony/css-selector/Parser/Handler/HandlerInterface.php33
-rw-r--r--www/wiki/vendor/symfony/css-selector/Parser/Handler/HashHandler.php58
-rw-r--r--www/wiki/vendor/symfony/css-selector/Parser/Handler/IdentifierHandler.php58
-rw-r--r--www/wiki/vendor/symfony/css-selector/Parser/Handler/NumberHandler.php54
-rw-r--r--www/wiki/vendor/symfony/css-selector/Parser/Handler/StringHandler.php77
-rw-r--r--www/wiki/vendor/symfony/css-selector/Parser/Handler/WhitespaceHandler.php46
-rw-r--r--www/wiki/vendor/symfony/css-selector/Parser/Parser.php384
-rw-r--r--www/wiki/vendor/symfony/css-selector/Parser/ParserInterface.php36
-rw-r--r--www/wiki/vendor/symfony/css-selector/Parser/Reader.php114
-rw-r--r--www/wiki/vendor/symfony/css-selector/Parser/Shortcut/ClassParser.php51
-rw-r--r--www/wiki/vendor/symfony/css-selector/Parser/Shortcut/ElementParser.php47
-rw-r--r--www/wiki/vendor/symfony/css-selector/Parser/Shortcut/EmptyStringParser.php46
-rw-r--r--www/wiki/vendor/symfony/css-selector/Parser/Shortcut/HashParser.php51
-rw-r--r--www/wiki/vendor/symfony/css-selector/Parser/Token.php149
-rw-r--r--www/wiki/vendor/symfony/css-selector/Parser/TokenStream.php175
-rw-r--r--www/wiki/vendor/symfony/css-selector/Parser/Tokenizer/Tokenizer.php75
-rw-r--r--www/wiki/vendor/symfony/css-selector/Parser/Tokenizer/TokenizerEscaping.php78
-rw-r--r--www/wiki/vendor/symfony/css-selector/Parser/Tokenizer/TokenizerPatterns.php112
-rw-r--r--www/wiki/vendor/symfony/css-selector/README.md20
-rw-r--r--www/wiki/vendor/symfony/css-selector/Tests/CssSelectorConverterTest.php76
-rw-r--r--www/wiki/vendor/symfony/css-selector/Tests/Node/AbstractNodeTest.php34
-rw-r--r--www/wiki/vendor/symfony/css-selector/Tests/Node/AttributeNodeTest.php37
-rw-r--r--www/wiki/vendor/symfony/css-selector/Tests/Node/ClassNodeTest.php33
-rw-r--r--www/wiki/vendor/symfony/css-selector/Tests/Node/CombinedSelectorNodeTest.php35
-rw-r--r--www/wiki/vendor/symfony/css-selector/Tests/Node/ElementNodeTest.php35
-rw-r--r--www/wiki/vendor/symfony/css-selector/Tests/Node/FunctionNodeTest.php47
-rw-r--r--www/wiki/vendor/symfony/css-selector/Tests/Node/HashNodeTest.php33
-rw-r--r--www/wiki/vendor/symfony/css-selector/Tests/Node/NegationNodeTest.php33
-rw-r--r--www/wiki/vendor/symfony/css-selector/Tests/Node/PseudoNodeTest.php32
-rw-r--r--www/wiki/vendor/symfony/css-selector/Tests/Node/SelectorNodeTest.php34
-rw-r--r--www/wiki/vendor/symfony/css-selector/Tests/Node/SpecificityTest.php63
-rw-r--r--www/wiki/vendor/symfony/css-selector/Tests/Parser/Handler/AbstractHandlerTest.php70
-rw-r--r--www/wiki/vendor/symfony/css-selector/Tests/Parser/Handler/CommentHandlerTest.php55
-rw-r--r--www/wiki/vendor/symfony/css-selector/Tests/Parser/Handler/HashHandlerTest.php49
-rw-r--r--www/wiki/vendor/symfony/css-selector/Tests/Parser/Handler/IdentifierHandlerTest.php49
-rw-r--r--www/wiki/vendor/symfony/css-selector/Tests/Parser/Handler/NumberHandlerTest.php50
-rw-r--r--www/wiki/vendor/symfony/css-selector/Tests/Parser/Handler/StringHandlerTest.php50
-rw-r--r--www/wiki/vendor/symfony/css-selector/Tests/Parser/Handler/WhitespaceHandlerTest.php44
-rw-r--r--www/wiki/vendor/symfony/css-selector/Tests/Parser/ParserTest.php253
-rw-r--r--www/wiki/vendor/symfony/css-selector/Tests/Parser/ReaderTest.php102
-rw-r--r--www/wiki/vendor/symfony/css-selector/Tests/Parser/Shortcut/ClassParserTest.php45
-rw-r--r--www/wiki/vendor/symfony/css-selector/Tests/Parser/Shortcut/ElementParserTest.php44
-rw-r--r--www/wiki/vendor/symfony/css-selector/Tests/Parser/Shortcut/EmptyStringParserTest.php36
-rw-r--r--www/wiki/vendor/symfony/css-selector/Tests/Parser/Shortcut/HashParserTest.php45
-rw-r--r--www/wiki/vendor/symfony/css-selector/Tests/Parser/TokenStreamTest.php96
-rw-r--r--www/wiki/vendor/symfony/css-selector/Tests/XPath/Fixtures/ids.html48
-rw-r--r--www/wiki/vendor/symfony/css-selector/Tests/XPath/Fixtures/lang.xml11
-rw-r--r--www/wiki/vendor/symfony/css-selector/Tests/XPath/Fixtures/shakespear.html308
-rw-r--r--www/wiki/vendor/symfony/css-selector/Tests/XPath/TranslatorTest.php398
-rw-r--r--www/wiki/vendor/symfony/css-selector/XPath/Extension/AbstractExtension.php65
-rw-r--r--www/wiki/vendor/symfony/css-selector/XPath/Extension/AttributeMatchingExtension.php175
-rw-r--r--www/wiki/vendor/symfony/css-selector/XPath/Extension/CombinationExtension.php83
-rw-r--r--www/wiki/vendor/symfony/css-selector/XPath/Extension/ExtensionInterface.php69
-rw-r--r--www/wiki/vendor/symfony/css-selector/XPath/Extension/FunctionExtension.php190
-rw-r--r--www/wiki/vendor/symfony/css-selector/XPath/Extension/HtmlExtension.php213
-rw-r--r--www/wiki/vendor/symfony/css-selector/XPath/Extension/NodeExtension.php242
-rw-r--r--www/wiki/vendor/symfony/css-selector/XPath/Extension/PseudoClassExtension.php148
-rw-r--r--www/wiki/vendor/symfony/css-selector/XPath/Translator.php267
-rw-r--r--www/wiki/vendor/symfony/css-selector/XPath/TranslatorInterface.php47
-rw-r--r--www/wiki/vendor/symfony/css-selector/XPath/XPathExpr.php129
-rw-r--r--www/wiki/vendor/symfony/css-selector/composer.json37
-rw-r--r--www/wiki/vendor/symfony/css-selector/phpunit.xml.dist31
84 files changed, 6793 insertions, 0 deletions
diff --git a/www/wiki/vendor/symfony/css-selector/.gitignore b/www/wiki/vendor/symfony/css-selector/.gitignore
new file mode 100644
index 00000000..c49a5d8d
--- /dev/null
+++ b/www/wiki/vendor/symfony/css-selector/.gitignore
@@ -0,0 +1,3 @@
+vendor/
+composer.lock
+phpunit.xml
diff --git a/www/wiki/vendor/symfony/css-selector/CHANGELOG.md b/www/wiki/vendor/symfony/css-selector/CHANGELOG.md
new file mode 100644
index 00000000..4061ff20
--- /dev/null
+++ b/www/wiki/vendor/symfony/css-selector/CHANGELOG.md
@@ -0,0 +1,13 @@
+CHANGELOG
+=========
+
+2.8.0
+-----
+
+ * Added the `CssSelectorConverter` class as a non-static API for the component.
+ * Deprecated the `CssSelector` static API of the component.
+
+2.1.0
+-----
+
+ * none
diff --git a/www/wiki/vendor/symfony/css-selector/CssSelectorConverter.php b/www/wiki/vendor/symfony/css-selector/CssSelectorConverter.php
new file mode 100644
index 00000000..8d66dbd0
--- /dev/null
+++ b/www/wiki/vendor/symfony/css-selector/CssSelectorConverter.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;
+
+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;
+
+/**
+ * CssSelectorConverter is the main entry point of the component and can convert CSS
+ * selectors to XPath expressions.
+ *
+ * @author Christophe Coevoet <stof@notk.org>
+ */
+class CssSelectorConverter
+{
+ private $translator;
+
+ /**
+ * @param bool $html Whether HTML support should be enabled. Disable it for XML documents
+ */
+ public function __construct($html = true)
+ {
+ $this->translator = new Translator();
+
+ if ($html) {
+ $this->translator->registerExtension(new HtmlExtension($this->translator));
+ }
+
+ $this->translator
+ ->registerParserShortcut(new EmptyStringParser())
+ ->registerParserShortcut(new ElementParser())
+ ->registerParserShortcut(new ClassParser())
+ ->registerParserShortcut(new HashParser())
+ ;
+ }
+
+ /**
+ * Translates a CSS expression to its XPath equivalent.
+ *
+ * Optionally, a prefix can be added to the resulting XPath
+ * expression with the $prefix parameter.
+ *
+ * @param string $cssExpr The CSS expression
+ * @param string $prefix An optional prefix for the XPath expression
+ *
+ * @return string
+ */
+ public function toXPath($cssExpr, $prefix = 'descendant-or-self::')
+ {
+ return $this->translator->cssToXPath($cssExpr, $prefix);
+ }
+}
diff --git a/www/wiki/vendor/symfony/css-selector/Exception/ExceptionInterface.php b/www/wiki/vendor/symfony/css-selector/Exception/ExceptionInterface.php
new file mode 100644
index 00000000..e4c5ae1b
--- /dev/null
+++ b/www/wiki/vendor/symfony/css-selector/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 cssselect 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/www/wiki/vendor/symfony/css-selector/Exception/ExpressionErrorException.php b/www/wiki/vendor/symfony/css-selector/Exception/ExpressionErrorException.php
new file mode 100644
index 00000000..fd5deeab
--- /dev/null
+++ b/www/wiki/vendor/symfony/css-selector/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 cssselect 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
+{
+}
diff --git a/www/wiki/vendor/symfony/css-selector/Exception/InternalErrorException.php b/www/wiki/vendor/symfony/css-selector/Exception/InternalErrorException.php
new file mode 100644
index 00000000..e60e5ed0
--- /dev/null
+++ b/www/wiki/vendor/symfony/css-selector/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 cssselect 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
+{
+}
diff --git a/www/wiki/vendor/symfony/css-selector/Exception/ParseException.php b/www/wiki/vendor/symfony/css-selector/Exception/ParseException.php
new file mode 100644
index 00000000..3b0b0ee8
--- /dev/null
+++ b/www/wiki/vendor/symfony/css-selector/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 cssselect 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/www/wiki/vendor/symfony/css-selector/Exception/SyntaxErrorException.php b/www/wiki/vendor/symfony/css-selector/Exception/SyntaxErrorException.php
new file mode 100644
index 00000000..cb3158a5
--- /dev/null
+++ b/www/wiki/vendor/symfony/css-selector/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 cssselect 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
+{
+ /**
+ * @param string $expectedValue
+ * @param Token $foundToken
+ *
+ * @return self
+ */
+ 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 self
+ */
+ public static function pseudoElementFound($pseudoElement, $unexpectedLocation)
+ {
+ return new self(sprintf('Unexpected pseudo-element "::%s" found %s.', $pseudoElement, $unexpectedLocation));
+ }
+
+ /**
+ * @param int $position
+ *
+ * @return self
+ */
+ public static function unclosedString($position)
+ {
+ return new self(sprintf('Unclosed/invalid string at %s.', $position));
+ }
+
+ /**
+ * @return self
+ */
+ public static function nestedNot()
+ {
+ return new self('Got nested ::not().');
+ }
+
+ /**
+ * @return self
+ */
+ public static function stringAsFunctionArgument()
+ {
+ return new self('String not allowed as function argument.');
+ }
+}
diff --git a/www/wiki/vendor/symfony/css-selector/LICENSE b/www/wiki/vendor/symfony/css-selector/LICENSE
new file mode 100644
index 00000000..a677f437
--- /dev/null
+++ b/www/wiki/vendor/symfony/css-selector/LICENSE
@@ -0,0 +1,19 @@
+Copyright (c) 2004-2019 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/www/wiki/vendor/symfony/css-selector/Node/AbstractNode.php b/www/wiki/vendor/symfony/css-selector/Node/AbstractNode.php
new file mode 100644
index 00000000..1d5d8ff7
--- /dev/null
+++ b/www/wiki/vendor/symfony/css-selector/Node/AbstractNode.php
@@ -0,0 +1,42 @@
+<?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 cssselect library,
+ * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect.
+ *
+ * @author Jean-François Simon <jeanfrancois.simon@sensiolabs.com>
+ *
+ * @internal
+ */
+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/www/wiki/vendor/symfony/css-selector/Node/AttributeNode.php b/www/wiki/vendor/symfony/css-selector/Node/AttributeNode.php
new file mode 100644
index 00000000..1caccb6b
--- /dev/null
+++ b/www/wiki/vendor/symfony/css-selector/Node/AttributeNode.php
@@ -0,0 +1,107 @@
+<?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 cssselect library,
+ * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect.
+ *
+ * @author Jean-François Simon <jeanfrancois.simon@sensiolabs.com>
+ *
+ * @internal
+ */
+class AttributeNode extends AbstractNode
+{
+ private $selector;
+ private $namespace;
+ private $attribute;
+ private $operator;
+ 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/www/wiki/vendor/symfony/css-selector/Node/ClassNode.php b/www/wiki/vendor/symfony/css-selector/Node/ClassNode.php
new file mode 100644
index 00000000..69462e8e
--- /dev/null
+++ b/www/wiki/vendor/symfony/css-selector/Node/ClassNode.php
@@ -0,0 +1,70 @@
+<?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 cssselect library,
+ * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect.
+ *
+ * @author Jean-François Simon <jeanfrancois.simon@sensiolabs.com>
+ *
+ * @internal
+ */
+class ClassNode extends AbstractNode
+{
+ private $selector;
+ 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/www/wiki/vendor/symfony/css-selector/Node/CombinedSelectorNode.php b/www/wiki/vendor/symfony/css-selector/Node/CombinedSelectorNode.php
new file mode 100644
index 00000000..2aa583aa
--- /dev/null
+++ b/www/wiki/vendor/symfony/css-selector/Node/CombinedSelectorNode.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\Node;
+
+/**
+ * Represents a combined node.
+ *
+ * This component is a port of the Python cssselect library,
+ * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect.
+ *
+ * @author Jean-François Simon <jeanfrancois.simon@sensiolabs.com>
+ *
+ * @internal
+ */
+class CombinedSelectorNode extends AbstractNode
+{
+ private $selector;
+ private $combinator;
+ 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/www/wiki/vendor/symfony/css-selector/Node/ElementNode.php b/www/wiki/vendor/symfony/css-selector/Node/ElementNode.php
new file mode 100644
index 00000000..54869af6
--- /dev/null
+++ b/www/wiki/vendor/symfony/css-selector/Node/ElementNode.php
@@ -0,0 +1,72 @@
+<?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 cssselect library,
+ * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect.
+ *
+ * @author Jean-François Simon <jeanfrancois.simon@sensiolabs.com>
+ *
+ * @internal
+ */
+class ElementNode extends AbstractNode
+{
+ private $namespace;
+ private $element;
+
+ /**
+ * @param string|null $namespace
+ * @param string|null $element
+ */
+ public function __construct($namespace = null, $element = null)
+ {
+ $this->namespace = $namespace;
+ $this->element = $element;
+ }
+
+ /**
+ * @return string|null
+ */
+ public function getNamespace()
+ {
+ return $this->namespace;
+ }
+
+ /**
+ * @return string|null
+ */
+ 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/www/wiki/vendor/symfony/css-selector/Node/FunctionNode.php b/www/wiki/vendor/symfony/css-selector/Node/FunctionNode.php
new file mode 100644
index 00000000..677affaa
--- /dev/null
+++ b/www/wiki/vendor/symfony/css-selector/Node/FunctionNode.php
@@ -0,0 +1,87 @@
+<?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 cssselect library,
+ * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect.
+ *
+ * @author Jean-François Simon <jeanfrancois.simon@sensiolabs.com>
+ *
+ * @internal
+ */
+class FunctionNode extends AbstractNode
+{
+ private $selector;
+ private $name;
+ private $arguments;
+
+ /**
+ * @param NodeInterface $selector
+ * @param string $name
+ * @param Token[] $arguments
+ */
+ public function __construct(NodeInterface $selector, $name, array $arguments = [])
+ {
+ $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/www/wiki/vendor/symfony/css-selector/Node/HashNode.php b/www/wiki/vendor/symfony/css-selector/Node/HashNode.php
new file mode 100644
index 00000000..ebf9a987
--- /dev/null
+++ b/www/wiki/vendor/symfony/css-selector/Node/HashNode.php
@@ -0,0 +1,70 @@
+<?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 cssselect library,
+ * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect.
+ *
+ * @author Jean-François Simon <jeanfrancois.simon@sensiolabs.com>
+ *
+ * @internal
+ */
+class HashNode extends AbstractNode
+{
+ private $selector;
+ 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/www/wiki/vendor/symfony/css-selector/Node/NegationNode.php b/www/wiki/vendor/symfony/css-selector/Node/NegationNode.php
new file mode 100644
index 00000000..bf97caeb
--- /dev/null
+++ b/www/wiki/vendor/symfony/css-selector/Node/NegationNode.php
@@ -0,0 +1,66 @@
+<?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 cssselect library,
+ * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect.
+ *
+ * @author Jean-François Simon <jeanfrancois.simon@sensiolabs.com>
+ *
+ * @internal
+ */
+class NegationNode extends AbstractNode
+{
+ private $selector;
+ private $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/www/wiki/vendor/symfony/css-selector/Node/NodeInterface.php b/www/wiki/vendor/symfony/css-selector/Node/NodeInterface.php
new file mode 100644
index 00000000..d919e20c
--- /dev/null
+++ b/www/wiki/vendor/symfony/css-selector/Node/NodeInterface.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\Node;
+
+/**
+ * Interface for nodes.
+ *
+ * This component is a port of the Python cssselect library,
+ * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect.
+ *
+ * @author Jean-François Simon <jeanfrancois.simon@sensiolabs.com>
+ *
+ * @internal
+ */
+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/www/wiki/vendor/symfony/css-selector/Node/PseudoNode.php b/www/wiki/vendor/symfony/css-selector/Node/PseudoNode.php
new file mode 100644
index 00000000..3842c695
--- /dev/null
+++ b/www/wiki/vendor/symfony/css-selector/Node/PseudoNode.php
@@ -0,0 +1,70 @@
+<?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 cssselect library,
+ * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect.
+ *
+ * @author Jean-François Simon <jeanfrancois.simon@sensiolabs.com>
+ *
+ * @internal
+ */
+class PseudoNode extends AbstractNode
+{
+ private $selector;
+ 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/www/wiki/vendor/symfony/css-selector/Node/SelectorNode.php b/www/wiki/vendor/symfony/css-selector/Node/SelectorNode.php
new file mode 100644
index 00000000..057107f6
--- /dev/null
+++ b/www/wiki/vendor/symfony/css-selector/Node/SelectorNode.php
@@ -0,0 +1,70 @@
+<?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 cssselect library,
+ * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect.
+ *
+ * @author Jean-François Simon <jeanfrancois.simon@sensiolabs.com>
+ *
+ * @internal
+ */
+class SelectorNode extends AbstractNode
+{
+ private $tree;
+ private $pseudoElement;
+
+ /**
+ * @param NodeInterface $tree
+ * @param string|null $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 string|null
+ */
+ 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/www/wiki/vendor/symfony/css-selector/Node/Specificity.php b/www/wiki/vendor/symfony/css-selector/Node/Specificity.php
new file mode 100644
index 00000000..a11b7f73
--- /dev/null
+++ b/www/wiki/vendor/symfony/css-selector/Node/Specificity.php
@@ -0,0 +1,88 @@
+<?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 cssselect 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>
+ *
+ * @internal
+ */
+class Specificity
+{
+ const A_FACTOR = 100;
+ const B_FACTOR = 10;
+ const C_FACTOR = 1;
+
+ private $a;
+ private $b;
+ private $c;
+
+ /**
+ * @param int $a
+ * @param int $b
+ * @param int $c
+ */
+ public function __construct($a, $b, $c)
+ {
+ $this->a = $a;
+ $this->b = $b;
+ $this->c = $c;
+ }
+
+ /**
+ * @return self
+ */
+ public function plus(self $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;
+ }
+
+ /**
+ * Returns -1 if the object specificity is lower than the argument,
+ * 0 if they are equal, and 1 if the argument is lower.
+ *
+ * @return int
+ */
+ public function compareTo(self $specificity)
+ {
+ if ($this->a !== $specificity->a) {
+ return $this->a > $specificity->a ? 1 : -1;
+ }
+
+ if ($this->b !== $specificity->b) {
+ return $this->b > $specificity->b ? 1 : -1;
+ }
+
+ if ($this->c !== $specificity->c) {
+ return $this->c > $specificity->c ? 1 : -1;
+ }
+
+ return 0;
+ }
+}
diff --git a/www/wiki/vendor/symfony/css-selector/Parser/Handler/CommentHandler.php b/www/wiki/vendor/symfony/css-selector/Parser/Handler/CommentHandler.php
new file mode 100644
index 00000000..a29775ca
--- /dev/null
+++ b/www/wiki/vendor/symfony/css-selector/Parser/Handler/CommentHandler.php
@@ -0,0 +1,48 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\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 cssselect library,
+ * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect.
+ *
+ * @author Jean-François Simon <jeanfrancois.simon@sensiolabs.com>
+ *
+ * @internal
+ */
+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/www/wiki/vendor/symfony/css-selector/Parser/Handler/HandlerInterface.php b/www/wiki/vendor/symfony/css-selector/Parser/Handler/HandlerInterface.php
new file mode 100644
index 00000000..de931f67
--- /dev/null
+++ b/www/wiki/vendor/symfony/css-selector/Parser/Handler/HandlerInterface.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\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 cssselect library,
+ * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect.
+ *
+ * @author Jean-François Simon <jeanfrancois.simon@sensiolabs.com>
+ *
+ * @internal
+ */
+interface HandlerInterface
+{
+ /**
+ * @return bool
+ */
+ public function handle(Reader $reader, TokenStream $stream);
+}
diff --git a/www/wiki/vendor/symfony/css-selector/Parser/Handler/HashHandler.php b/www/wiki/vendor/symfony/css-selector/Parser/Handler/HashHandler.php
new file mode 100644
index 00000000..e451328f
--- /dev/null
+++ b/www/wiki/vendor/symfony/css-selector/Parser/Handler/HashHandler.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\Tokenizer\TokenizerEscaping;
+use Symfony\Component\CssSelector\Parser\Tokenizer\TokenizerPatterns;
+use Symfony\Component\CssSelector\Parser\TokenStream;
+
+/**
+ * CSS selector comment handler.
+ *
+ * This component is a port of the Python cssselect library,
+ * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect.
+ *
+ * @author Jean-François Simon <jeanfrancois.simon@sensiolabs.com>
+ *
+ * @internal
+ */
+class HashHandler implements HandlerInterface
+{
+ private $patterns;
+ private $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/www/wiki/vendor/symfony/css-selector/Parser/Handler/IdentifierHandler.php b/www/wiki/vendor/symfony/css-selector/Parser/Handler/IdentifierHandler.php
new file mode 100644
index 00000000..1591fcb5
--- /dev/null
+++ b/www/wiki/vendor/symfony/css-selector/Parser/Handler/IdentifierHandler.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\Tokenizer\TokenizerEscaping;
+use Symfony\Component\CssSelector\Parser\Tokenizer\TokenizerPatterns;
+use Symfony\Component\CssSelector\Parser\TokenStream;
+
+/**
+ * CSS selector comment handler.
+ *
+ * This component is a port of the Python cssselect library,
+ * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect.
+ *
+ * @author Jean-François Simon <jeanfrancois.simon@sensiolabs.com>
+ *
+ * @internal
+ */
+class IdentifierHandler implements HandlerInterface
+{
+ private $patterns;
+ private $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/www/wiki/vendor/symfony/css-selector/Parser/Handler/NumberHandler.php b/www/wiki/vendor/symfony/css-selector/Parser/Handler/NumberHandler.php
new file mode 100644
index 00000000..5955903c
--- /dev/null
+++ b/www/wiki/vendor/symfony/css-selector/Parser/Handler/NumberHandler.php
@@ -0,0 +1,54 @@
+<?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\Tokenizer\TokenizerPatterns;
+use Symfony\Component\CssSelector\Parser\TokenStream;
+
+/**
+ * CSS selector comment handler.
+ *
+ * This component is a port of the Python cssselect library,
+ * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect.
+ *
+ * @author Jean-François Simon <jeanfrancois.simon@sensiolabs.com>
+ *
+ * @internal
+ */
+class NumberHandler implements HandlerInterface
+{
+ private $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/www/wiki/vendor/symfony/css-selector/Parser/Handler/StringHandler.php b/www/wiki/vendor/symfony/css-selector/Parser/Handler/StringHandler.php
new file mode 100644
index 00000000..9869176b
--- /dev/null
+++ b/www/wiki/vendor/symfony/css-selector/Parser/Handler/StringHandler.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\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\Tokenizer\TokenizerEscaping;
+use Symfony\Component\CssSelector\Parser\Tokenizer\TokenizerPatterns;
+use Symfony\Component\CssSelector\Parser\TokenStream;
+
+/**
+ * CSS selector comment handler.
+ *
+ * This component is a port of the Python cssselect library,
+ * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect.
+ *
+ * @author Jean-François Simon <jeanfrancois.simon@sensiolabs.com>
+ *
+ * @internal
+ */
+class StringHandler implements HandlerInterface
+{
+ private $patterns;
+ private $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, ["'", '"'])) {
+ 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/www/wiki/vendor/symfony/css-selector/Parser/Handler/WhitespaceHandler.php b/www/wiki/vendor/symfony/css-selector/Parser/Handler/WhitespaceHandler.php
new file mode 100644
index 00000000..396467af
--- /dev/null
+++ b/www/wiki/vendor/symfony/css-selector/Parser/Handler/WhitespaceHandler.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\Token;
+use Symfony\Component\CssSelector\Parser\TokenStream;
+
+/**
+ * CSS selector whitespace handler.
+ *
+ * This component is a port of the Python cssselect library,
+ * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect.
+ *
+ * @author Jean-François Simon <jeanfrancois.simon@sensiolabs.com>
+ *
+ * @internal
+ */
+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/www/wiki/vendor/symfony/css-selector/Parser/Parser.php b/www/wiki/vendor/symfony/css-selector/Parser/Parser.php
new file mode 100644
index 00000000..f07985ac
--- /dev/null
+++ b/www/wiki/vendor/symfony/css-selector/Parser/Parser.php
@@ -0,0 +1,384 @@
+<?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 cssselect library,
+ * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect.
+ *
+ * @author Jean-François Simon <jeanfrancois.simon@sensiolabs.com>
+ *
+ * @internal
+ */
+class Parser implements ParserInterface
+{
+ private $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
+ *
+ * @return array
+ *
+ * @throws SyntaxErrorException
+ */
+ 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 [2, 1];
+ case 'even' === $joined:
+ return [2, 0];
+ case 'n' === $joined:
+ return [1, 0];
+ case false === strpos($joined, 'n'):
+ return [0, $int($joined)];
+ }
+
+ $split = explode('n', $joined);
+ $first = isset($split[0]) ? $split[0] : null;
+
+ return [
+ $first ? ('-' === $first || '+' === $first ? $int($first.'1') : $int($first)) : 1,
+ isset($split[1]) && $split[1] ? $int($split[1]) : 0,
+ ];
+ }
+
+ /**
+ * Parses selector nodes.
+ *
+ * @return array
+ */
+ private function parseSelectorList(TokenStream $stream)
+ {
+ $stream->skipWhitespace();
+ $selectors = [];
+
+ while (true) {
+ $selectors[] = $this->parserSelectorNode($stream);
+
+ if ($stream->getPeek()->isDelimiter([','])) {
+ $stream->getNext();
+ $stream->skipWhitespace();
+ } else {
+ break;
+ }
+ }
+
+ return $selectors;
+ }
+
+ /**
+ * Parses next selector or combined node.
+ *
+ * @return Node\SelectorNode
+ *
+ * @throws SyntaxErrorException
+ */
+ private function parserSelectorNode(TokenStream $stream)
+ {
+ list($result, $pseudoElement) = $this->parseSimpleSelector($stream);
+
+ while (true) {
+ $stream->skipWhitespace();
+ $peek = $stream->getPeek();
+
+ if ($peek->isFileEnd() || $peek->isDelimiter([','])) {
+ break;
+ }
+
+ if (null !== $pseudoElement) {
+ throw SyntaxErrorException::pseudoElementFound($pseudoElement, 'not at the end of a selector');
+ }
+
+ if ($peek->isDelimiter(['+', '>', '~'])) {
+ $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
+ *
+ * @return array
+ *
+ * @throws SyntaxErrorException
+ */
+ 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([',', '+', '>', '~'])
+ || ($insideNegation && $peek->isDelimiter([')']))
+ ) {
+ 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(['.'])) {
+ $stream->getNext();
+ $result = new Node\ClassNode($result, $stream->getNextIdentifier());
+ } elseif ($peek->isDelimiter(['['])) {
+ $stream->getNext();
+ $result = $this->parseAttributeNode($result, $stream);
+ } elseif ($peek->isDelimiter([':'])) {
+ $stream->getNext();
+
+ if ($stream->getPeek()->isDelimiter([':'])) {
+ $stream->getNext();
+ $pseudoElement = $stream->getNextIdentifier();
+
+ continue;
+ }
+
+ $identifier = $stream->getNextIdentifier();
+ if (\in_array(strtolower($identifier), ['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(['('])) {
+ $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([')'])) {
+ throw SyntaxErrorException::unexpectedToken('")"', $next);
+ }
+
+ $result = new Node\NegationNode($result, $argument);
+ } else {
+ $arguments = [];
+ $next = null;
+
+ while (true) {
+ $stream->skipWhitespace();
+ $next = $stream->getNext();
+
+ if ($next->isIdentifier()
+ || $next->isString()
+ || $next->isNumber()
+ || $next->isDelimiter(['+', '-'])
+ ) {
+ $arguments[] = $next;
+ } elseif ($next->isDelimiter([')'])) {
+ 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 [$result, $pseudoElement];
+ }
+
+ /**
+ * Parses next element node.
+ *
+ * @return Node\ElementNode
+ */
+ private function parseElementNode(TokenStream $stream)
+ {
+ $peek = $stream->getPeek();
+
+ if ($peek->isIdentifier() || $peek->isDelimiter(['*'])) {
+ if ($peek->isIdentifier()) {
+ $namespace = $stream->getNext()->getValue();
+ } else {
+ $stream->getNext();
+ $namespace = null;
+ }
+
+ if ($stream->getPeek()->isDelimiter(['|'])) {
+ $stream->getNext();
+ $element = $stream->getNextIdentifierOrStar();
+ } else {
+ $element = $namespace;
+ $namespace = null;
+ }
+ } else {
+ $element = $namespace = null;
+ }
+
+ return new Node\ElementNode($namespace, $element);
+ }
+
+ /**
+ * Parses next attribute node.
+ *
+ * @return Node\AttributeNode
+ *
+ * @throws SyntaxErrorException
+ */
+ private function parseAttributeNode(Node\NodeInterface $selector, TokenStream $stream)
+ {
+ $stream->skipWhitespace();
+ $attribute = $stream->getNextIdentifierOrStar();
+
+ if (null === $attribute && !$stream->getPeek()->isDelimiter(['|'])) {
+ throw SyntaxErrorException::unexpectedToken('"|"', $stream->getPeek());
+ }
+
+ if ($stream->getPeek()->isDelimiter(['|'])) {
+ $stream->getNext();
+
+ if ($stream->getPeek()->isDelimiter(['='])) {
+ $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([']'])) {
+ return new Node\AttributeNode($selector, $namespace, $attribute, 'exists', null);
+ } elseif ($next->isDelimiter(['='])) {
+ $operator = '=';
+ } elseif ($next->isDelimiter(['^', '$', '*', '~', '|', '!'])
+ && $stream->getPeek()->isDelimiter(['='])
+ ) {
+ $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([']'])) {
+ throw SyntaxErrorException::unexpectedToken('"]"', $next);
+ }
+
+ return new Node\AttributeNode($selector, $namespace, $attribute, $operator, $value->getValue());
+ }
+}
diff --git a/www/wiki/vendor/symfony/css-selector/Parser/ParserInterface.php b/www/wiki/vendor/symfony/css-selector/Parser/ParserInterface.php
new file mode 100644
index 00000000..c5af2036
--- /dev/null
+++ b/www/wiki/vendor/symfony/css-selector/Parser/ParserInterface.php
@@ -0,0 +1,36 @@
+<?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 cssselect library,
+ * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect.
+ *
+ * @author Jean-François Simon <jeanfrancois.simon@sensiolabs.com>
+ *
+ * @internal
+ */
+interface ParserInterface
+{
+ /**
+ * Parses given selector source into an array of tokens.
+ *
+ * @param string $source
+ *
+ * @return SelectorNode[]
+ */
+ public function parse($source);
+}
diff --git a/www/wiki/vendor/symfony/css-selector/Parser/Reader.php b/www/wiki/vendor/symfony/css-selector/Parser/Reader.php
new file mode 100644
index 00000000..076cb711
--- /dev/null
+++ b/www/wiki/vendor/symfony/css-selector/Parser/Reader.php
@@ -0,0 +1,114 @@
+<?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 cssselect library,
+ * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect.
+ *
+ * @author Jean-François Simon <jeanfrancois.simon@sensiolabs.com>
+ *
+ * @internal
+ */
+class Reader
+{
+ private $source;
+ private $length;
+ 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 array|false
+ */
+ 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/www/wiki/vendor/symfony/css-selector/Parser/Shortcut/ClassParser.php b/www/wiki/vendor/symfony/css-selector/Parser/Shortcut/ClassParser.php
new file mode 100644
index 00000000..3b920062
--- /dev/null
+++ b/www/wiki/vendor/symfony/css-selector/Parser/Shortcut/ClassParser.php
@@ -0,0 +1,51 @@
+<?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 cssselect library,
+ * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect.
+ *
+ * @author Jean-François Simon <jeanfrancois.simon@sensiolabs.com>
+ *
+ * @internal
+ */
+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=4)
+ // 0 => string 'test|input.ab6bd_field' (length=22)
+ // 1 => string 'test' (length=4)
+ // 2 => string 'input' (length=5)
+ // 3 => string 'ab6bd_field' (length=11)
+ if (preg_match('/^(?:([a-z]++)\|)?+([\w-]++|\*)?+\.([\w-]++)$/i', trim($source), $matches)) {
+ return [
+ new SelectorNode(new ClassNode(new ElementNode($matches[1] ?: null, $matches[2] ?: null), $matches[3])),
+ ];
+ }
+
+ return [];
+ }
+}
diff --git a/www/wiki/vendor/symfony/css-selector/Parser/Shortcut/ElementParser.php b/www/wiki/vendor/symfony/css-selector/Parser/Shortcut/ElementParser.php
new file mode 100644
index 00000000..392c6aab
--- /dev/null
+++ b/www/wiki/vendor/symfony/css-selector/Parser/Shortcut/ElementParser.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\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 cssselect library,
+ * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect.
+ *
+ * @author Jean-François Simon <jeanfrancois.simon@sensiolabs.com>
+ *
+ * @internal
+ */
+class ElementParser implements ParserInterface
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function parse($source)
+ {
+ // Matches an optional namespace, required element or `*`
+ // $source = 'testns|testel';
+ // $matches = array (size=3)
+ // 0 => string 'testns|testel' (length=13)
+ // 1 => string 'testns' (length=6)
+ // 2 => string 'testel' (length=6)
+ if (preg_match('/^(?:([a-z]++)\|)?([\w-]++|\*)$/i', trim($source), $matches)) {
+ return [new SelectorNode(new ElementNode($matches[1] ?: null, $matches[2]))];
+ }
+
+ return [];
+ }
+}
diff --git a/www/wiki/vendor/symfony/css-selector/Parser/Shortcut/EmptyStringParser.php b/www/wiki/vendor/symfony/css-selector/Parser/Shortcut/EmptyStringParser.php
new file mode 100644
index 00000000..276b5740
--- /dev/null
+++ b/www/wiki/vendor/symfony/css-selector/Parser/Shortcut/EmptyStringParser.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 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 cssselect library,
+ * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect.
+ *
+ * @author Jean-François Simon <jeanfrancois.simon@sensiolabs.com>
+ *
+ * @internal
+ */
+class EmptyStringParser implements ParserInterface
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function parse($source)
+ {
+ // Matches an empty string
+ if ('' == $source) {
+ return [new SelectorNode(new ElementNode(null, '*'))];
+ }
+
+ return [];
+ }
+}
diff --git a/www/wiki/vendor/symfony/css-selector/Parser/Shortcut/HashParser.php b/www/wiki/vendor/symfony/css-selector/Parser/Shortcut/HashParser.php
new file mode 100644
index 00000000..0ffcb6de
--- /dev/null
+++ b/www/wiki/vendor/symfony/css-selector/Parser/Shortcut/HashParser.php
@@ -0,0 +1,51 @@
+<?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 cssselect library,
+ * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect.
+ *
+ * @author Jean-François Simon <jeanfrancois.simon@sensiolabs.com>
+ *
+ * @internal
+ */
+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=4)
+ // 0 => string 'test|input#ab6bd_field' (length=22)
+ // 1 => string 'test' (length=4)
+ // 2 => string 'input' (length=5)
+ // 3 => string 'ab6bd_field' (length=11)
+ if (preg_match('/^(?:([a-z]++)\|)?+([\w-]++|\*)?+#([\w-]++)$/i', trim($source), $matches)) {
+ return [
+ new SelectorNode(new HashNode(new ElementNode($matches[1] ?: null, $matches[2] ?: null), $matches[3])),
+ ];
+ }
+
+ return [];
+ }
+}
diff --git a/www/wiki/vendor/symfony/css-selector/Parser/Token.php b/www/wiki/vendor/symfony/css-selector/Parser/Token.php
new file mode 100644
index 00000000..d641da86
--- /dev/null
+++ b/www/wiki/vendor/symfony/css-selector/Parser/Token.php
@@ -0,0 +1,149 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\CssSelector\Parser;
+
+/**
+ * CSS selector token.
+ *
+ * This component is a port of the Python cssselect library,
+ * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect.
+ *
+ * @author Jean-François Simon <jeanfrancois.simon@sensiolabs.com>
+ *
+ * @internal
+ */
+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';
+
+ private $type;
+ private $value;
+ 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;
+ }
+
+ /**
+ * @return bool
+ */
+ public function isDelimiter(array $values = [])
+ {
+ 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/www/wiki/vendor/symfony/css-selector/Parser/TokenStream.php b/www/wiki/vendor/symfony/css-selector/Parser/TokenStream.php
new file mode 100644
index 00000000..843e330b
--- /dev/null
+++ b/www/wiki/vendor/symfony/css-selector/Parser/TokenStream.php
@@ -0,0 +1,175 @@
+<?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 cssselect library,
+ * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect.
+ *
+ * @author Jean-François Simon <jeanfrancois.simon@sensiolabs.com>
+ *
+ * @internal
+ */
+class TokenStream
+{
+ /**
+ * @var Token[]
+ */
+ private $tokens = [];
+
+ /**
+ * @var Token[]
+ */
+ private $used = [];
+
+ /**
+ * @var int
+ */
+ private $cursor = 0;
+
+ /**
+ * @var Token|null
+ */
+ private $peeked;
+
+ /**
+ * @var bool
+ */
+ private $peeking = false;
+
+ /**
+ * Pushes a token.
+ *
+ * @return $this
+ */
+ public function push(Token $token)
+ {
+ $this->tokens[] = $token;
+
+ return $this;
+ }
+
+ /**
+ * Freezes stream.
+ *
+ * @return $this
+ */
+ public function freeze()
+ {
+ return $this;
+ }
+
+ /**
+ * Returns next token.
+ *
+ * @return Token
+ *
+ * @throws InternalErrorException If there is no more 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.
+ *
+ * @return string The identifier token value
+ *
+ * @throws SyntaxErrorException If next token is not an identifier
+ */
+ public function getNextIdentifier()
+ {
+ $next = $this->getNext();
+
+ if (!$next->isIdentifier()) {
+ throw SyntaxErrorException::unexpectedToken('identifier', $next);
+ }
+
+ return $next->getValue();
+ }
+
+ /**
+ * Returns nex identifier or star delimiter token.
+ *
+ * @return string|null The identifier token value or null if star found
+ *
+ * @throws SyntaxErrorException If next token is not an identifier or a star delimiter
+ */
+ public function getNextIdentifierOrStar()
+ {
+ $next = $this->getNext();
+
+ if ($next->isIdentifier()) {
+ return $next->getValue();
+ }
+
+ if ($next->isDelimiter(['*'])) {
+ 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/www/wiki/vendor/symfony/css-selector/Parser/Tokenizer/Tokenizer.php b/www/wiki/vendor/symfony/css-selector/Parser/Tokenizer/Tokenizer.php
new file mode 100644
index 00000000..fc65bc68
--- /dev/null
+++ b/www/wiki/vendor/symfony/css-selector/Parser/Tokenizer/Tokenizer.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\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 cssselect library,
+ * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect.
+ *
+ * @author Jean-François Simon <jeanfrancois.simon@sensiolabs.com>
+ *
+ * @internal
+ */
+class Tokenizer
+{
+ /**
+ * @var Handler\HandlerInterface[]
+ */
+ private $handlers;
+
+ public function __construct()
+ {
+ $patterns = new TokenizerPatterns();
+ $escaping = new TokenizerEscaping($patterns);
+
+ $this->handlers = [
+ 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.
+ *
+ * @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/www/wiki/vendor/symfony/css-selector/Parser/Tokenizer/TokenizerEscaping.php b/www/wiki/vendor/symfony/css-selector/Parser/Tokenizer/TokenizerEscaping.php
new file mode 100644
index 00000000..55ea4214
--- /dev/null
+++ b/www/wiki/vendor/symfony/css-selector/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 cssselect library,
+ * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect.
+ *
+ * @author Jean-François Simon <jeanfrancois.simon@sensiolabs.com>
+ *
+ * @internal
+ */
+class TokenizerEscaping
+{
+ private $patterns;
+
+ public function __construct(TokenizerPatterns $patterns)
+ {
+ $this->patterns = $patterns;
+ }
+
+ /**
+ * @param string $value
+ *
+ * @return string
+ */
+ public function escapeUnicode($value)
+ {
+ $value = $this->replaceUnicodeSequences($value);
+
+ return preg_replace($this->patterns->getSimpleEscapePattern(), '$1', $value);
+ }
+
+ /**
+ * @param string $value
+ *
+ * @return string
+ */
+ public function escapeUnicodeAndNewLine($value)
+ {
+ $value = preg_replace($this->patterns->getNewLineEscapePattern(), '', $value);
+
+ return $this->escapeUnicode($value);
+ }
+
+ /**
+ * @param string $value
+ *
+ * @return string
+ */
+ private function replaceUnicodeSequences($value)
+ {
+ return preg_replace_callback($this->patterns->getUnicodeEscapePattern(), function ($match) {
+ $c = hexdec($match[1]);
+
+ if (0x80 > $c %= 0x200000) {
+ return \chr($c);
+ }
+ if (0x800 > $c) {
+ return \chr(0xC0 | $c >> 6).\chr(0x80 | $c & 0x3F);
+ }
+ if (0x10000 > $c) {
+ return \chr(0xE0 | $c >> 12).\chr(0x80 | $c >> 6 & 0x3F).\chr(0x80 | $c & 0x3F);
+ }
+ }, $value);
+ }
+}
diff --git a/www/wiki/vendor/symfony/css-selector/Parser/Tokenizer/TokenizerPatterns.php b/www/wiki/vendor/symfony/css-selector/Parser/Tokenizer/TokenizerPatterns.php
new file mode 100644
index 00000000..bc6130d7
--- /dev/null
+++ b/www/wiki/vendor/symfony/css-selector/Parser/Tokenizer/TokenizerPatterns.php
@@ -0,0 +1,112 @@
+<?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 cssselect library,
+ * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect.
+ *
+ * @author Jean-François Simon <jeanfrancois.simon@sensiolabs.com>
+ *
+ * @internal
+ */
+class TokenizerPatterns
+{
+ private $unicodeEscapePattern;
+ private $simpleEscapePattern;
+ private $newLineEscapePattern;
+ private $escapePattern;
+ private $stringEscapePattern;
+ private $nonAsciiPattern;
+ private $nmCharPattern;
+ private $nmStartPattern;
+ private $identifierPattern;
+ private $hashPattern;
+ private $numberPattern;
+ private $quotedStringPattern;
+
+ 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/www/wiki/vendor/symfony/css-selector/README.md b/www/wiki/vendor/symfony/css-selector/README.md
new file mode 100644
index 00000000..7c4c4116
--- /dev/null
+++ b/www/wiki/vendor/symfony/css-selector/README.md
@@ -0,0 +1,20 @@
+CssSelector Component
+=====================
+
+The CssSelector component converts CSS selectors to XPath expressions.
+
+Resources
+---------
+
+ * [Documentation](https://symfony.com/doc/current/components/css_selector.html)
+ * [Contributing](https://symfony.com/doc/current/contributing/index.html)
+ * [Report issues](https://github.com/symfony/symfony/issues) and
+ [send Pull Requests](https://github.com/symfony/symfony/pulls)
+ in the [main Symfony repository](https://github.com/symfony/symfony)
+
+Credits
+-------
+
+This component is a port of the Python cssselect library
+[v0.7.1](https://github.com/SimonSapin/cssselect/releases/tag/v0.7.1),
+which is distributed under the BSD license.
diff --git a/www/wiki/vendor/symfony/css-selector/Tests/CssSelectorConverterTest.php b/www/wiki/vendor/symfony/css-selector/Tests/CssSelectorConverterTest.php
new file mode 100644
index 00000000..cd0fd785
--- /dev/null
+++ b/www/wiki/vendor/symfony/css-selector/Tests/CssSelectorConverterTest.php
@@ -0,0 +1,76 @@
+<?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 PHPUnit\Framework\TestCase;
+use Symfony\Component\CssSelector\CssSelectorConverter;
+
+class CssSelectorConverterTest extends TestCase
+{
+ public function testCssToXPath()
+ {
+ $converter = new CssSelectorConverter();
+
+ $this->assertEquals('descendant-or-self::*', $converter->toXPath(''));
+ $this->assertEquals('descendant-or-self::h1', $converter->toXPath('h1'));
+ $this->assertEquals("descendant-or-self::h1[@id = 'foo']", $converter->toXPath('h1#foo'));
+ $this->assertEquals("descendant-or-self::h1[@class and contains(concat(' ', normalize-space(@class), ' '), ' foo ')]", $converter->toXPath('h1.foo'));
+ $this->assertEquals('descendant-or-self::foo:h1', $converter->toXPath('foo|h1'));
+ $this->assertEquals('descendant-or-self::h1', $converter->toXPath('H1'));
+ }
+
+ public function testCssToXPathXml()
+ {
+ $converter = new CssSelectorConverter(false);
+
+ $this->assertEquals('descendant-or-self::H1', $converter->toXPath('H1'));
+ }
+
+ /**
+ * @expectedException \Symfony\Component\CssSelector\Exception\ParseException
+ * @expectedExceptionMessage Expected identifier, but <eof at 3> found.
+ */
+ public function testParseExceptions()
+ {
+ $converter = new CssSelectorConverter();
+ $converter->toXPath('h1:');
+ }
+
+ /** @dataProvider getCssToXPathWithoutPrefixTestData */
+ public function testCssToXPathWithoutPrefix($css, $xpath)
+ {
+ $converter = new CssSelectorConverter();
+
+ $this->assertEquals($xpath, $converter->toXPath($css, ''), '->parse() parses an input string and returns a node');
+ }
+
+ public function getCssToXPathWithoutPrefixTestData()
+ {
+ return [
+ ['h1', 'h1'],
+ ['foo|h1', 'foo:h1'],
+ ['h1, h2, h3', 'h1 | h2 | h3'],
+ ['h1:nth-child(3n+1)', "*/*[(name() = 'h1') and (position() - 1 >= 0 and (position() - 1) mod 3 = 0)]"],
+ ['h1 > p', 'h1/p'],
+ ['h1#foo', "h1[@id = 'foo']"],
+ ['h1.foo', "h1[@class and contains(concat(' ', normalize-space(@class), ' '), ' foo ')]"],
+ ['h1[class*="foo bar"]', "h1[@class and contains(@class, 'foo bar')]"],
+ ['h1[foo|class*="foo bar"]', "h1[@foo:class and contains(@foo:class, 'foo bar')]"],
+ ['h1[class]', 'h1[@class]'],
+ ['h1 .foo', "h1/descendant-or-self::*/*[@class and contains(concat(' ', normalize-space(@class), ' '), ' foo ')]"],
+ ['h1 #foo', "h1/descendant-or-self::*/*[@id = 'foo']"],
+ ['h1 [class*=foo]', "h1/descendant-or-self::*/*[@class and contains(@class, 'foo')]"],
+ ['div>.foo', "div/*[@class and contains(concat(' ', normalize-space(@class), ' '), ' foo ')]"],
+ ['div > .foo', "div/*[@class and contains(concat(' ', normalize-space(@class), ' '), ' foo ')]"],
+ ];
+ }
+}
diff --git a/www/wiki/vendor/symfony/css-selector/Tests/Node/AbstractNodeTest.php b/www/wiki/vendor/symfony/css-selector/Tests/Node/AbstractNodeTest.php
new file mode 100644
index 00000000..59555133
--- /dev/null
+++ b/www/wiki/vendor/symfony/css-selector/Tests/Node/AbstractNodeTest.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 PHPUnit\Framework\TestCase;
+use Symfony\Component\CssSelector\Node\NodeInterface;
+
+abstract class AbstractNodeTest extends 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/www/wiki/vendor/symfony/css-selector/Tests/Node/AttributeNodeTest.php b/www/wiki/vendor/symfony/css-selector/Tests/Node/AttributeNodeTest.php
new file mode 100644
index 00000000..4d600740
--- /dev/null
+++ b/www/wiki/vendor/symfony/css-selector/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 [
+ [new AttributeNode(new ElementNode(), null, 'attribute', 'exists', null), 'Attribute[Element[*][attribute]]'],
+ [new AttributeNode(new ElementNode(), null, 'attribute', '$=', 'value'), "Attribute[Element[*][attribute $= 'value']]"],
+ [new AttributeNode(new ElementNode(), 'namespace', 'attribute', '$=', 'value'), "Attribute[Element[*][namespace|attribute $= 'value']]"],
+ ];
+ }
+
+ public function getSpecificityValueTestData()
+ {
+ return [
+ [new AttributeNode(new ElementNode(), null, 'attribute', 'exists', null), 10],
+ [new AttributeNode(new ElementNode(null, 'element'), null, 'attribute', 'exists', null), 11],
+ [new AttributeNode(new ElementNode(), null, 'attribute', '$=', 'value'), 10],
+ [new AttributeNode(new ElementNode(), 'namespace', 'attribute', '$=', 'value'), 10],
+ ];
+ }
+}
diff --git a/www/wiki/vendor/symfony/css-selector/Tests/Node/ClassNodeTest.php b/www/wiki/vendor/symfony/css-selector/Tests/Node/ClassNodeTest.php
new file mode 100644
index 00000000..aa80c927
--- /dev/null
+++ b/www/wiki/vendor/symfony/css-selector/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 [
+ [new ClassNode(new ElementNode(), 'class'), 'Class[Element[*].class]'],
+ ];
+ }
+
+ public function getSpecificityValueTestData()
+ {
+ return [
+ [new ClassNode(new ElementNode(), 'class'), 10],
+ [new ClassNode(new ElementNode(null, 'element'), 'class'), 11],
+ ];
+ }
+}
diff --git a/www/wiki/vendor/symfony/css-selector/Tests/Node/CombinedSelectorNodeTest.php b/www/wiki/vendor/symfony/css-selector/Tests/Node/CombinedSelectorNodeTest.php
new file mode 100644
index 00000000..435eaa6a
--- /dev/null
+++ b/www/wiki/vendor/symfony/css-selector/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 [
+ [new CombinedSelectorNode(new ElementNode(), '>', new ElementNode()), 'CombinedSelector[Element[*] > Element[*]]'],
+ [new CombinedSelectorNode(new ElementNode(), ' ', new ElementNode()), 'CombinedSelector[Element[*] <followed> Element[*]]'],
+ ];
+ }
+
+ public function getSpecificityValueTestData()
+ {
+ return [
+ [new CombinedSelectorNode(new ElementNode(), '>', new ElementNode()), 0],
+ [new CombinedSelectorNode(new ElementNode(null, 'element'), '>', new ElementNode()), 1],
+ [new CombinedSelectorNode(new ElementNode(null, 'element'), '>', new ElementNode(null, 'element')), 2],
+ ];
+ }
+}
diff --git a/www/wiki/vendor/symfony/css-selector/Tests/Node/ElementNodeTest.php b/www/wiki/vendor/symfony/css-selector/Tests/Node/ElementNodeTest.php
new file mode 100644
index 00000000..e0797ff0
--- /dev/null
+++ b/www/wiki/vendor/symfony/css-selector/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 [
+ [new ElementNode(), 'Element[*]'],
+ [new ElementNode(null, 'element'), 'Element[element]'],
+ [new ElementNode('namespace', 'element'), 'Element[namespace|element]'],
+ ];
+ }
+
+ public function getSpecificityValueTestData()
+ {
+ return [
+ [new ElementNode(), 0],
+ [new ElementNode(null, 'element'), 1],
+ [new ElementNode('namespace', 'element'), 1],
+ ];
+ }
+}
diff --git a/www/wiki/vendor/symfony/css-selector/Tests/Node/FunctionNodeTest.php b/www/wiki/vendor/symfony/css-selector/Tests/Node/FunctionNodeTest.php
new file mode 100644
index 00000000..0932393e
--- /dev/null
+++ b/www/wiki/vendor/symfony/css-selector/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 [
+ [new FunctionNode(new ElementNode(), 'function'), 'Function[Element[*]:function()]'],
+ [new FunctionNode(new ElementNode(), 'function', [
+ new Token(Token::TYPE_IDENTIFIER, 'value', 0),
+ ]), "Function[Element[*]:function(['value'])]"],
+ [new FunctionNode(new ElementNode(), 'function', [
+ new Token(Token::TYPE_STRING, 'value1', 0),
+ new Token(Token::TYPE_NUMBER, 'value2', 0),
+ ]), "Function[Element[*]:function(['value1', 'value2'])]"],
+ ];
+ }
+
+ public function getSpecificityValueTestData()
+ {
+ return [
+ [new FunctionNode(new ElementNode(), 'function'), 10],
+ [new FunctionNode(new ElementNode(), 'function', [
+ new Token(Token::TYPE_IDENTIFIER, 'value', 0),
+ ]), 10],
+ [new FunctionNode(new ElementNode(), 'function', [
+ new Token(Token::TYPE_STRING, 'value1', 0),
+ new Token(Token::TYPE_NUMBER, 'value2', 0),
+ ]), 10],
+ ];
+ }
+}
diff --git a/www/wiki/vendor/symfony/css-selector/Tests/Node/HashNodeTest.php b/www/wiki/vendor/symfony/css-selector/Tests/Node/HashNodeTest.php
new file mode 100644
index 00000000..ad6765b8
--- /dev/null
+++ b/www/wiki/vendor/symfony/css-selector/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\ElementNode;
+use Symfony\Component\CssSelector\Node\HashNode;
+
+class HashNodeTest extends AbstractNodeTest
+{
+ public function getToStringConversionTestData()
+ {
+ return [
+ [new HashNode(new ElementNode(), 'id'), 'Hash[Element[*]#id]'],
+ ];
+ }
+
+ public function getSpecificityValueTestData()
+ {
+ return [
+ [new HashNode(new ElementNode(), 'id'), 100],
+ [new HashNode(new ElementNode(null, 'id'), 'class'), 101],
+ ];
+ }
+}
diff --git a/www/wiki/vendor/symfony/css-selector/Tests/Node/NegationNodeTest.php b/www/wiki/vendor/symfony/css-selector/Tests/Node/NegationNodeTest.php
new file mode 100644
index 00000000..90b684ce
--- /dev/null
+++ b/www/wiki/vendor/symfony/css-selector/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\ElementNode;
+use Symfony\Component\CssSelector\Node\NegationNode;
+
+class NegationNodeTest extends AbstractNodeTest
+{
+ public function getToStringConversionTestData()
+ {
+ return [
+ [new NegationNode(new ElementNode(), new ClassNode(new ElementNode(), 'class')), 'Negation[Element[*]:not(Class[Element[*].class])]'],
+ ];
+ }
+
+ public function getSpecificityValueTestData()
+ {
+ return [
+ [new NegationNode(new ElementNode(), new ClassNode(new ElementNode(), 'class')), 10],
+ ];
+ }
+}
diff --git a/www/wiki/vendor/symfony/css-selector/Tests/Node/PseudoNodeTest.php b/www/wiki/vendor/symfony/css-selector/Tests/Node/PseudoNodeTest.php
new file mode 100644
index 00000000..4e78776c
--- /dev/null
+++ b/www/wiki/vendor/symfony/css-selector/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 [
+ [new PseudoNode(new ElementNode(), 'pseudo'), 'Pseudo[Element[*]:pseudo]'],
+ ];
+ }
+
+ public function getSpecificityValueTestData()
+ {
+ return [
+ [new PseudoNode(new ElementNode(), 'pseudo'), 10],
+ ];
+ }
+}
diff --git a/www/wiki/vendor/symfony/css-selector/Tests/Node/SelectorNodeTest.php b/www/wiki/vendor/symfony/css-selector/Tests/Node/SelectorNodeTest.php
new file mode 100644
index 00000000..85e3bdac
--- /dev/null
+++ b/www/wiki/vendor/symfony/css-selector/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 [
+ [new SelectorNode(new ElementNode()), 'Selector[Element[*]]'],
+ [new SelectorNode(new ElementNode(), 'pseudo'), 'Selector[Element[*]::pseudo]'],
+ ];
+ }
+
+ public function getSpecificityValueTestData()
+ {
+ return [
+ [new SelectorNode(new ElementNode()), 0],
+ [new SelectorNode(new ElementNode(), 'pseudo'), 1],
+ ];
+ }
+}
diff --git a/www/wiki/vendor/symfony/css-selector/Tests/Node/SpecificityTest.php b/www/wiki/vendor/symfony/css-selector/Tests/Node/SpecificityTest.php
new file mode 100644
index 00000000..bf48d49f
--- /dev/null
+++ b/www/wiki/vendor/symfony/css-selector/Tests/Node/SpecificityTest.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\Tests\Node;
+
+use PHPUnit\Framework\TestCase;
+use Symfony\Component\CssSelector\Node\Specificity;
+
+class SpecificityTest extends 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 [
+ [new Specificity(0, 0, 0), 0],
+ [new Specificity(0, 0, 2), 2],
+ [new Specificity(0, 3, 0), 30],
+ [new Specificity(4, 0, 0), 400],
+ [new Specificity(4, 3, 2), 432],
+ ];
+ }
+
+ /** @dataProvider getCompareTestData */
+ public function testCompareTo(Specificity $a, Specificity $b, $result)
+ {
+ $this->assertEquals($result, $a->compareTo($b));
+ }
+
+ public function getCompareTestData()
+ {
+ return [
+ [new Specificity(0, 0, 0), new Specificity(0, 0, 0), 0],
+ [new Specificity(0, 0, 1), new Specificity(0, 0, 1), 0],
+ [new Specificity(0, 0, 2), new Specificity(0, 0, 1), 1],
+ [new Specificity(0, 0, 2), new Specificity(0, 0, 3), -1],
+ [new Specificity(0, 4, 0), new Specificity(0, 4, 0), 0],
+ [new Specificity(0, 6, 0), new Specificity(0, 5, 11), 1],
+ [new Specificity(0, 7, 0), new Specificity(0, 8, 0), -1],
+ [new Specificity(9, 0, 0), new Specificity(9, 0, 0), 0],
+ [new Specificity(11, 0, 0), new Specificity(10, 11, 0), 1],
+ [new Specificity(12, 11, 0), new Specificity(13, 0, 0), -1],
+ ];
+ }
+}
diff --git a/www/wiki/vendor/symfony/css-selector/Tests/Parser/Handler/AbstractHandlerTest.php b/www/wiki/vendor/symfony/css-selector/Tests/Parser/Handler/AbstractHandlerTest.php
new file mode 100644
index 00000000..aaed55c2
--- /dev/null
+++ b/www/wiki/vendor/symfony/css-selector/Tests/Parser/Handler/AbstractHandlerTest.php
@@ -0,0 +1,70 @@
+<?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 PHPUnit\Framework\TestCase;
+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 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([], $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/www/wiki/vendor/symfony/css-selector/Tests/Parser/Handler/CommentHandlerTest.php b/www/wiki/vendor/symfony/css-selector/Tests/Parser/Handler/CommentHandlerTest.php
new file mode 100644
index 00000000..de400478
--- /dev/null
+++ b/www/wiki/vendor/symfony/css-selector/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 [
+ // 2nd argument only exists for inherited method compatibility
+ ['/* comment */', new Token(null, null, null), ''],
+ ['/* comment */foo', new Token(null, null, null), 'foo'],
+ ];
+ }
+
+ public function getDontHandleValueTestData()
+ {
+ return [
+ ['>'],
+ ['+'],
+ [' '],
+ ];
+ }
+
+ protected function generateHandler()
+ {
+ return new CommentHandler();
+ }
+}
diff --git a/www/wiki/vendor/symfony/css-selector/Tests/Parser/Handler/HashHandlerTest.php b/www/wiki/vendor/symfony/css-selector/Tests/Parser/Handler/HashHandlerTest.php
new file mode 100644
index 00000000..9444f510
--- /dev/null
+++ b/www/wiki/vendor/symfony/css-selector/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\TokenizerEscaping;
+use Symfony\Component\CssSelector\Parser\Tokenizer\TokenizerPatterns;
+
+class HashHandlerTest extends AbstractHandlerTest
+{
+ public function getHandleValueTestData()
+ {
+ return [
+ ['#id', new Token(Token::TYPE_HASH, 'id', 0), ''],
+ ['#123', new Token(Token::TYPE_HASH, '123', 0), ''],
+
+ ['#id.class', new Token(Token::TYPE_HASH, 'id', 0), '.class'],
+ ['#id element', new Token(Token::TYPE_HASH, 'id', 0), ' element'],
+ ];
+ }
+
+ public function getDontHandleValueTestData()
+ {
+ return [
+ ['id'],
+ ['123'],
+ ['<'],
+ ['<'],
+ ['#'],
+ ];
+ }
+
+ protected function generateHandler()
+ {
+ $patterns = new TokenizerPatterns();
+
+ return new HashHandler($patterns, new TokenizerEscaping($patterns));
+ }
+}
diff --git a/www/wiki/vendor/symfony/css-selector/Tests/Parser/Handler/IdentifierHandlerTest.php b/www/wiki/vendor/symfony/css-selector/Tests/Parser/Handler/IdentifierHandlerTest.php
new file mode 100644
index 00000000..c54ba537
--- /dev/null
+++ b/www/wiki/vendor/symfony/css-selector/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\TokenizerEscaping;
+use Symfony\Component\CssSelector\Parser\Tokenizer\TokenizerPatterns;
+
+class IdentifierHandlerTest extends AbstractHandlerTest
+{
+ public function getHandleValueTestData()
+ {
+ return [
+ ['foo', new Token(Token::TYPE_IDENTIFIER, 'foo', 0), ''],
+ ['foo|bar', new Token(Token::TYPE_IDENTIFIER, 'foo', 0), '|bar'],
+ ['foo.class', new Token(Token::TYPE_IDENTIFIER, 'foo', 0), '.class'],
+ ['foo[attr]', new Token(Token::TYPE_IDENTIFIER, 'foo', 0), '[attr]'],
+ ['foo bar', new Token(Token::TYPE_IDENTIFIER, 'foo', 0), ' bar'],
+ ];
+ }
+
+ public function getDontHandleValueTestData()
+ {
+ return [
+ ['>'],
+ ['+'],
+ [' '],
+ ['*|foo'],
+ ['/* comment */'],
+ ];
+ }
+
+ protected function generateHandler()
+ {
+ $patterns = new TokenizerPatterns();
+
+ return new IdentifierHandler($patterns, new TokenizerEscaping($patterns));
+ }
+}
diff --git a/www/wiki/vendor/symfony/css-selector/Tests/Parser/Handler/NumberHandlerTest.php b/www/wiki/vendor/symfony/css-selector/Tests/Parser/Handler/NumberHandlerTest.php
new file mode 100644
index 00000000..b43d3694
--- /dev/null
+++ b/www/wiki/vendor/symfony/css-selector/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 [
+ ['12', new Token(Token::TYPE_NUMBER, '12', 0), ''],
+ ['12.34', new Token(Token::TYPE_NUMBER, '12.34', 0), ''],
+ ['+12.34', new Token(Token::TYPE_NUMBER, '+12.34', 0), ''],
+ ['-12.34', new Token(Token::TYPE_NUMBER, '-12.34', 0), ''],
+
+ ['12 arg', new Token(Token::TYPE_NUMBER, '12', 0), ' arg'],
+ ['12]', new Token(Token::TYPE_NUMBER, '12', 0), ']'],
+ ];
+ }
+
+ public function getDontHandleValueTestData()
+ {
+ return [
+ ['hello'],
+ ['>'],
+ ['+'],
+ [' '],
+ ['/* comment */'],
+ ];
+ }
+
+ protected function generateHandler()
+ {
+ $patterns = new TokenizerPatterns();
+
+ return new NumberHandler($patterns);
+ }
+}
diff --git a/www/wiki/vendor/symfony/css-selector/Tests/Parser/Handler/StringHandlerTest.php b/www/wiki/vendor/symfony/css-selector/Tests/Parser/Handler/StringHandlerTest.php
new file mode 100644
index 00000000..baa72735
--- /dev/null
+++ b/www/wiki/vendor/symfony/css-selector/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\TokenizerEscaping;
+use Symfony\Component\CssSelector\Parser\Tokenizer\TokenizerPatterns;
+
+class StringHandlerTest extends AbstractHandlerTest
+{
+ public function getHandleValueTestData()
+ {
+ return [
+ ['"hello"', new Token(Token::TYPE_STRING, 'hello', 1), ''],
+ ['"1"', new Token(Token::TYPE_STRING, '1', 1), ''],
+ ['" "', new Token(Token::TYPE_STRING, ' ', 1), ''],
+ ['""', new Token(Token::TYPE_STRING, '', 1), ''],
+ ["'hello'", new Token(Token::TYPE_STRING, 'hello', 1), ''],
+
+ ["'foo'bar", new Token(Token::TYPE_STRING, 'foo', 1), 'bar'],
+ ];
+ }
+
+ public function getDontHandleValueTestData()
+ {
+ return [
+ ['hello'],
+ ['>'],
+ ['1'],
+ [' '],
+ ];
+ }
+
+ protected function generateHandler()
+ {
+ $patterns = new TokenizerPatterns();
+
+ return new StringHandler($patterns, new TokenizerEscaping($patterns));
+ }
+}
diff --git a/www/wiki/vendor/symfony/css-selector/Tests/Parser/Handler/WhitespaceHandlerTest.php b/www/wiki/vendor/symfony/css-selector/Tests/Parser/Handler/WhitespaceHandlerTest.php
new file mode 100644
index 00000000..67509ef1
--- /dev/null
+++ b/www/wiki/vendor/symfony/css-selector/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 [
+ [' ', new Token(Token::TYPE_WHITESPACE, ' ', 0), ''],
+ ["\n", new Token(Token::TYPE_WHITESPACE, "\n", 0), ''],
+ ["\t", new Token(Token::TYPE_WHITESPACE, "\t", 0), ''],
+
+ [' foo', new Token(Token::TYPE_WHITESPACE, ' ', 0), 'foo'],
+ [' .foo', new Token(Token::TYPE_WHITESPACE, ' ', 0), '.foo'],
+ ];
+ }
+
+ public function getDontHandleValueTestData()
+ {
+ return [
+ ['>'],
+ ['1'],
+ ['a'],
+ ];
+ }
+
+ protected function generateHandler()
+ {
+ return new WhitespaceHandler();
+ }
+}
diff --git a/www/wiki/vendor/symfony/css-selector/Tests/Parser/ParserTest.php b/www/wiki/vendor/symfony/css-selector/Tests/Parser/ParserTest.php
new file mode 100644
index 00000000..de350934
--- /dev/null
+++ b/www/wiki/vendor/symfony/css-selector/Tests/Parser/ParserTest.php
@@ -0,0 +1,253 @@
+<?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 PHPUnit\Framework\TestCase;
+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 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([$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->{method_exists($this, $_ = 'expectException') ? $_ : 'setExpectedException'}('Symfony\Component\CssSelector\Exception\SyntaxErrorException');
+ Parser::parseSeries($function->getArguments());
+ }
+
+ public function getParserTestData()
+ {
+ return [
+ ['*', ['Element[*]']],
+ ['*|*', ['Element[*]']],
+ ['*|foo', ['Element[foo]']],
+ ['foo|*', ['Element[foo|*]']],
+ ['foo|bar', ['Element[foo|bar]']],
+ ['#foo#bar', ['Hash[Hash[Element[*]#foo]#bar]']],
+ ['div>.foo', ['CombinedSelector[Element[div] > Class[Element[*].foo]]']],
+ ['div> .foo', ['CombinedSelector[Element[div] > Class[Element[*].foo]]']],
+ ['div >.foo', ['CombinedSelector[Element[div] > Class[Element[*].foo]]']],
+ ['div > .foo', ['CombinedSelector[Element[div] > Class[Element[*].foo]]']],
+ ["div \n> \t \t .foo", ['CombinedSelector[Element[div] > Class[Element[*].foo]]']],
+ ['td.foo,.bar', ['Class[Element[td].foo]', 'Class[Element[*].bar]']],
+ ['td.foo, .bar', ['Class[Element[td].foo]', 'Class[Element[*].bar]']],
+ ["td.foo\t\r\n\f ,\t\r\n\f .bar", ['Class[Element[td].foo]', 'Class[Element[*].bar]']],
+ ['td.foo,.bar', ['Class[Element[td].foo]', 'Class[Element[*].bar]']],
+ ['td.foo, .bar', ['Class[Element[td].foo]', 'Class[Element[*].bar]']],
+ ["td.foo\t\r\n\f ,\t\r\n\f .bar", ['Class[Element[td].foo]', 'Class[Element[*].bar]']],
+ ['div, td.foo, div.bar span', ['Element[div]', 'Class[Element[td].foo]', 'CombinedSelector[Class[Element[div].bar] <followed> Element[span]]']],
+ ['div > p', ['CombinedSelector[Element[div] > Element[p]]']],
+ ['td:first', ['Pseudo[Element[td]:first]']],
+ ['td :first', ['CombinedSelector[Element[td] <followed> Pseudo[Element[*]:first]]']],
+ ['a[name]', ['Attribute[Element[a][name]]']],
+ ["a[ name\t]", ['Attribute[Element[a][name]]']],
+ ['a [name]', ['CombinedSelector[Element[a] <followed> Attribute[Element[*][name]]]']],
+ ['[name="foo"]', ["Attribute[Element[*][name = 'foo']]"]],
+ ["[name='foo[1]']", ["Attribute[Element[*][name = 'foo[1]']]"]],
+ ["[name='foo[0][bar]']", ["Attribute[Element[*][name = 'foo[0][bar]']]"]],
+ ['a[rel="include"]', ["Attribute[Element[a][rel = 'include']]"]],
+ ['a[rel = include]', ["Attribute[Element[a][rel = 'include']]"]],
+ ["a[hreflang |= 'en']", ["Attribute[Element[a][hreflang |= 'en']]"]],
+ ['a[hreflang|=en]', ["Attribute[Element[a][hreflang |= 'en']]"]],
+ ['div:nth-child(10)', ["Function[Element[div]:nth-child(['10'])]"]],
+ [':nth-child(2n+2)', ["Function[Element[*]:nth-child(['2', 'n', '+2'])]"]],
+ ['div:nth-of-type(10)', ["Function[Element[div]:nth-of-type(['10'])]"]],
+ ['div div:nth-of-type(10) .aclass', ["CombinedSelector[CombinedSelector[Element[div] <followed> Function[Element[div]:nth-of-type(['10'])]] <followed> Class[Element[*].aclass]]"]],
+ ['label:only', ['Pseudo[Element[label]:only]']],
+ ['a:lang(fr)', ["Function[Element[a]:lang(['fr'])]"]],
+ ['div:contains("foo")', ["Function[Element[div]:contains(['foo'])]"]],
+ ['div#foobar', ['Hash[Element[div]#foobar]']],
+ ['div:not(div.foo)', ['Negation[Element[div]:not(Class[Element[div].foo])]']],
+ ['td ~ th', ['CombinedSelector[Element[td] ~ Element[th]]']],
+ ['.foo[data-bar][data-baz=0]', ["Attribute[Attribute[Class[Element[*].foo][data-bar]][data-baz = '0']]"]],
+ ];
+ }
+
+ public function getParserExceptionTestData()
+ {
+ return [
+ ['attributes(href)/html/body/a', SyntaxErrorException::unexpectedToken('selector', new Token(Token::TYPE_DELIMITER, '(', 10))->getMessage()],
+ ['attributes(href)', SyntaxErrorException::unexpectedToken('selector', new Token(Token::TYPE_DELIMITER, '(', 10))->getMessage()],
+ ['html/body/a', SyntaxErrorException::unexpectedToken('selector', new Token(Token::TYPE_DELIMITER, '/', 4))->getMessage()],
+ [' ', SyntaxErrorException::unexpectedToken('selector', new Token(Token::TYPE_FILE_END, '', 1))->getMessage()],
+ ['div, ', SyntaxErrorException::unexpectedToken('selector', new Token(Token::TYPE_FILE_END, '', 5))->getMessage()],
+ [' , div', SyntaxErrorException::unexpectedToken('selector', new Token(Token::TYPE_DELIMITER, ',', 1))->getMessage()],
+ ['p, , div', SyntaxErrorException::unexpectedToken('selector', new Token(Token::TYPE_DELIMITER, ',', 3))->getMessage()],
+ ['div > ', SyntaxErrorException::unexpectedToken('selector', new Token(Token::TYPE_FILE_END, '', 6))->getMessage()],
+ [' > div', SyntaxErrorException::unexpectedToken('selector', new Token(Token::TYPE_DELIMITER, '>', 2))->getMessage()],
+ ['foo|#bar', SyntaxErrorException::unexpectedToken('identifier or "*"', new Token(Token::TYPE_HASH, 'bar', 4))->getMessage()],
+ ['#.foo', SyntaxErrorException::unexpectedToken('selector', new Token(Token::TYPE_DELIMITER, '#', 0))->getMessage()],
+ ['.#foo', SyntaxErrorException::unexpectedToken('identifier', new Token(Token::TYPE_HASH, 'foo', 1))->getMessage()],
+ [':#foo', SyntaxErrorException::unexpectedToken('identifier', new Token(Token::TYPE_HASH, 'foo', 1))->getMessage()],
+ ['[*]', SyntaxErrorException::unexpectedToken('"|"', new Token(Token::TYPE_DELIMITER, ']', 2))->getMessage()],
+ ['[foo|]', SyntaxErrorException::unexpectedToken('identifier', new Token(Token::TYPE_DELIMITER, ']', 5))->getMessage()],
+ ['[#]', SyntaxErrorException::unexpectedToken('identifier or "*"', new Token(Token::TYPE_DELIMITER, '#', 1))->getMessage()],
+ ['[foo=#]', SyntaxErrorException::unexpectedToken('string or identifier', new Token(Token::TYPE_DELIMITER, '#', 5))->getMessage()],
+ [':nth-child()', SyntaxErrorException::unexpectedToken('at least one argument', new Token(Token::TYPE_DELIMITER, ')', 11))->getMessage()],
+ ['[href]a', SyntaxErrorException::unexpectedToken('selector', new Token(Token::TYPE_IDENTIFIER, 'a', 6))->getMessage()],
+ ['[rel:stylesheet]', SyntaxErrorException::unexpectedToken('operator', new Token(Token::TYPE_DELIMITER, ':', 4))->getMessage()],
+ ['[rel=stylesheet', SyntaxErrorException::unexpectedToken('"]"', new Token(Token::TYPE_FILE_END, '', 15))->getMessage()],
+ [':lang(fr', SyntaxErrorException::unexpectedToken('an argument', new Token(Token::TYPE_FILE_END, '', 8))->getMessage()],
+ [':contains("foo', SyntaxErrorException::unclosedString(10)->getMessage()],
+ ['foo!', SyntaxErrorException::unexpectedToken('selector', new Token(Token::TYPE_DELIMITER, '!', 3))->getMessage()],
+ ];
+ }
+
+ public function getPseudoElementsTestData()
+ {
+ return [
+ ['foo', 'Element[foo]', ''],
+ ['*', 'Element[*]', ''],
+ [':empty', 'Pseudo[Element[*]:empty]', ''],
+ [':BEfore', 'Element[*]', 'before'],
+ [':aftER', 'Element[*]', 'after'],
+ [':First-Line', 'Element[*]', 'first-line'],
+ [':First-Letter', 'Element[*]', 'first-letter'],
+ ['::befoRE', 'Element[*]', 'before'],
+ ['::AFter', 'Element[*]', 'after'],
+ ['::firsT-linE', 'Element[*]', 'first-line'],
+ ['::firsT-letteR', 'Element[*]', 'first-letter'],
+ ['::Selection', 'Element[*]', 'selection'],
+ ['foo:after', 'Element[foo]', 'after'],
+ ['foo::selection', 'Element[foo]', 'selection'],
+ ['lorem#ipsum ~ a#b.c[href]:empty::selection', 'CombinedSelector[Hash[Element[lorem]#ipsum] ~ Pseudo[Attribute[Class[Hash[Element[a]#b].c][href]]:empty]]', 'selection'],
+ ['video::-webkit-media-controls', 'Element[video]', '-webkit-media-controls'],
+ ];
+ }
+
+ public function getSpecificityTestData()
+ {
+ return [
+ ['*', 0],
+ [' foo', 1],
+ [':empty ', 10],
+ [':before', 1],
+ ['*:before', 1],
+ [':nth-child(2)', 10],
+ ['.bar', 10],
+ ['[baz]', 10],
+ ['[baz="4"]', 10],
+ ['[baz^="4"]', 10],
+ ['#lipsum', 100],
+ [':not(*)', 0],
+ [':not(foo)', 1],
+ [':not(.foo)', 10],
+ [':not([foo])', 10],
+ [':not(:empty)', 10],
+ [':not(#foo)', 100],
+ ['foo:empty', 11],
+ ['foo:before', 2],
+ ['foo::before', 2],
+ ['foo:empty::before', 12],
+ ['#lorem + foo#ipsum:first-child > bar:first-line', 213],
+ ];
+ }
+
+ public function getParseSeriesTestData()
+ {
+ return [
+ ['1n+3', 1, 3],
+ ['1n +3', 1, 3],
+ ['1n + 3', 1, 3],
+ ['1n+ 3', 1, 3],
+ ['1n-3', 1, -3],
+ ['1n -3', 1, -3],
+ ['1n - 3', 1, -3],
+ ['1n- 3', 1, -3],
+ ['n-5', 1, -5],
+ ['odd', 2, 1],
+ ['even', 2, 0],
+ ['3n', 3, 0],
+ ['n', 1, 0],
+ ['+n', 1, 0],
+ ['-n', -1, 0],
+ ['5', 0, 5],
+ ];
+ }
+
+ public function getParseSeriesExceptionTestData()
+ {
+ return [
+ ['foo'],
+ ['n+'],
+ ];
+ }
+}
diff --git a/www/wiki/vendor/symfony/css-selector/Tests/Parser/ReaderTest.php b/www/wiki/vendor/symfony/css-selector/Tests/Parser/ReaderTest.php
new file mode 100644
index 00000000..ff9ea909
--- /dev/null
+++ b/www/wiki/vendor/symfony/css-selector/Tests/Parser/ReaderTest.php
@@ -0,0 +1,102 @@
+<?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 PHPUnit\Framework\TestCase;
+use Symfony\Component\CssSelector\Parser\Reader;
+
+class ReaderTest extends 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(['hello', 'h'], $reader->findPattern('/^([a-z]).*/'));
+
+ $this->assignPosition($reader, 2);
+ $this->assertFalse($reader->findPattern('/^h.*/'));
+ $this->assertEquals(['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/www/wiki/vendor/symfony/css-selector/Tests/Parser/Shortcut/ClassParserTest.php b/www/wiki/vendor/symfony/css-selector/Tests/Parser/Shortcut/ClassParserTest.php
new file mode 100644
index 00000000..29d9d5f1
--- /dev/null
+++ b/www/wiki/vendor/symfony/css-selector/Tests/Parser/Shortcut/ClassParserTest.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\Tests\Parser\Shortcut;
+
+use PHPUnit\Framework\TestCase;
+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 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 [
+ ['.testclass', 'Class[Element[*].testclass]'],
+ ['testel.testclass', 'Class[Element[testel].testclass]'],
+ ['testns|.testclass', 'Class[Element[testns|*].testclass]'],
+ ['testns|*.testclass', 'Class[Element[testns|*].testclass]'],
+ ['testns|testel.testclass', 'Class[Element[testns|testel].testclass]'],
+ ];
+ }
+}
diff --git a/www/wiki/vendor/symfony/css-selector/Tests/Parser/Shortcut/ElementParserTest.php b/www/wiki/vendor/symfony/css-selector/Tests/Parser/Shortcut/ElementParserTest.php
new file mode 100644
index 00000000..79cc2270
--- /dev/null
+++ b/www/wiki/vendor/symfony/css-selector/Tests/Parser/Shortcut/ElementParserTest.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 PHPUnit\Framework\TestCase;
+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 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 [
+ ['*', 'Element[*]'],
+ ['testel', 'Element[testel]'],
+ ['testns|*', 'Element[testns|*]'],
+ ['testns|testel', 'Element[testns|testel]'],
+ ];
+ }
+}
diff --git a/www/wiki/vendor/symfony/css-selector/Tests/Parser/Shortcut/EmptyStringParserTest.php b/www/wiki/vendor/symfony/css-selector/Tests/Parser/Shortcut/EmptyStringParserTest.php
new file mode 100644
index 00000000..1cf742cf
--- /dev/null
+++ b/www/wiki/vendor/symfony/css-selector/Tests/Parser/Shortcut/EmptyStringParserTest.php
@@ -0,0 +1,36 @@
+<?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 PHPUnit\Framework\TestCase;
+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 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/www/wiki/vendor/symfony/css-selector/Tests/Parser/Shortcut/HashParserTest.php b/www/wiki/vendor/symfony/css-selector/Tests/Parser/Shortcut/HashParserTest.php
new file mode 100644
index 00000000..a7c79d69
--- /dev/null
+++ b/www/wiki/vendor/symfony/css-selector/Tests/Parser/Shortcut/HashParserTest.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\Tests\Parser\Shortcut;
+
+use PHPUnit\Framework\TestCase;
+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 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 [
+ ['#testid', 'Hash[Element[*]#testid]'],
+ ['testel#testid', 'Hash[Element[testel]#testid]'],
+ ['testns|#testid', 'Hash[Element[testns|*]#testid]'],
+ ['testns|*#testid', 'Hash[Element[testns|*]#testid]'],
+ ['testns|testel#testid', 'Hash[Element[testns|testel]#testid]'],
+ ];
+ }
+}
diff --git a/www/wiki/vendor/symfony/css-selector/Tests/Parser/TokenStreamTest.php b/www/wiki/vendor/symfony/css-selector/Tests/Parser/TokenStreamTest.php
new file mode 100644
index 00000000..44c751ac
--- /dev/null
+++ b/www/wiki/vendor/symfony/css-selector/Tests/Parser/TokenStreamTest.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\Tests\Parser;
+
+use PHPUnit\Framework\TestCase;
+use Symfony\Component\CssSelector\Parser\Token;
+use Symfony\Component\CssSelector\Parser\TokenStream;
+
+class TokenStreamTest extends 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->{method_exists($this, $_ = 'expectException') ? $_ : '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->{method_exists($this, $_ = 'expectException') ? $_ : '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/www/wiki/vendor/symfony/css-selector/Tests/XPath/Fixtures/ids.html b/www/wiki/vendor/symfony/css-selector/Tests/XPath/Fixtures/ids.html
new file mode 100644
index 00000000..5799fad2
--- /dev/null
+++ b/www/wiki/vendor/symfony/css-selector/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/www/wiki/vendor/symfony/css-selector/Tests/XPath/Fixtures/lang.xml b/www/wiki/vendor/symfony/css-selector/Tests/XPath/Fixtures/lang.xml
new file mode 100644
index 00000000..14f8dbed
--- /dev/null
+++ b/www/wiki/vendor/symfony/css-selector/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/www/wiki/vendor/symfony/css-selector/Tests/XPath/Fixtures/shakespear.html b/www/wiki/vendor/symfony/css-selector/Tests/XPath/Fixtures/shakespear.html
new file mode 100644
index 00000000..15d1ad33
--- /dev/null
+++ b/www/wiki/vendor/symfony/css-selector/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/www/wiki/vendor/symfony/css-selector/Tests/XPath/TranslatorTest.php b/www/wiki/vendor/symfony/css-selector/Tests/XPath/TranslatorTest.php
new file mode 100644
index 00000000..a9ab29e2
--- /dev/null
+++ b/www/wiki/vendor/symfony/css-selector/Tests/XPath/TranslatorTest.php
@@ -0,0 +1,398 @@
+<?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 PHPUnit\Framework\TestCase;
+use Symfony\Component\CssSelector\Node\ElementNode;
+use Symfony\Component\CssSelector\Node\FunctionNode;
+use Symfony\Component\CssSelector\Parser\Parser;
+use Symfony\Component\CssSelector\XPath\Extension\HtmlExtension;
+use Symfony\Component\CssSelector\XPath\Translator;
+use Symfony\Component\CssSelector\XPath\XPathExpr;
+
+class TranslatorTest extends 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, ''));
+ }
+
+ /**
+ * @expectedException \Symfony\Component\CssSelector\Exception\ExpressionErrorException
+ */
+ public function testCssToXPathPseudoElement()
+ {
+ $translator = new Translator();
+ $translator->registerExtension(new HtmlExtension($translator));
+ $translator->cssToXPath('e::first-line');
+ }
+
+ /**
+ * @expectedException \Symfony\Component\CssSelector\Exception\ExpressionErrorException
+ */
+ public function testGetExtensionNotExistsExtension()
+ {
+ $translator = new Translator();
+ $translator->registerExtension(new HtmlExtension($translator));
+ $translator->getExtension('fake');
+ }
+
+ /**
+ * @expectedException \Symfony\Component\CssSelector\Exception\ExpressionErrorException
+ */
+ public function testAddCombinationNotExistsExtension()
+ {
+ $translator = new Translator();
+ $translator->registerExtension(new HtmlExtension($translator));
+ $parser = new Parser();
+ $xpath = $parser->parse('*')[0];
+ $combinedXpath = $parser->parse('*')[0];
+ $translator->addCombination('fake', $xpath, $combinedXpath);
+ }
+
+ /**
+ * @expectedException \Symfony\Component\CssSelector\Exception\ExpressionErrorException
+ */
+ public function testAddFunctionNotExistsFunction()
+ {
+ $translator = new Translator();
+ $translator->registerExtension(new HtmlExtension($translator));
+ $xpath = new XPathExpr();
+ $function = new FunctionNode(new ElementNode(), 'fake');
+ $translator->addFunction($xpath, $function);
+ }
+
+ /**
+ * @expectedException \Symfony\Component\CssSelector\Exception\ExpressionErrorException
+ */
+ public function testAddPseudoClassNotExistsClass()
+ {
+ $translator = new Translator();
+ $translator->registerExtension(new HtmlExtension($translator));
+ $xpath = new XPathExpr();
+ $translator->addPseudoClass($xpath, 'fake');
+ }
+
+ /**
+ * @expectedException \Symfony\Component\CssSelector\Exception\ExpressionErrorException
+ */
+ public function testAddAttributeMatchingClassNotExistsClass()
+ {
+ $translator = new Translator();
+ $translator->registerExtension(new HtmlExtension($translator));
+ $xpath = new XPathExpr();
+ $translator->addAttributeMatching($xpath, '', '', '');
+ }
+
+ /** @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->assertCount(\count($elementsId), $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->assertCount($count, $elements);
+ }
+
+ public function getXpathLiteralTestData()
+ {
+ return [
+ ['foo', "'foo'"],
+ ["foo's bar", '"foo\'s bar"'],
+ ["foo's \"middle\" bar", 'concat(\'foo\', "\'", \'s "middle" bar\')'],
+ ["foo's 'middle' \"bar\"", 'concat(\'foo\', "\'", \'s \', "\'", \'middle\', "\'", \' "bar"\')'],
+ ];
+ }
+
+ public function getCssToXPathTestData()
+ {
+ return [
+ ['*', '*'],
+ ['e', 'e'],
+ ['*|e', 'e'],
+ ['e|f', 'e:f'],
+ ['e[foo]', 'e[@foo]'],
+ ['e[foo|bar]', 'e[@foo:bar]'],
+ ['e[foo="bar"]', "e[@foo = 'bar']"],
+ ['e[foo~="bar"]', "e[@foo and contains(concat(' ', normalize-space(@foo), ' '), ' bar ')]"],
+ ['e[foo^="bar"]', "e[@foo and starts-with(@foo, 'bar')]"],
+ ['e[foo$="bar"]', "e[@foo and substring(@foo, string-length(@foo)-2) = 'bar']"],
+ ['e[foo*="bar"]', "e[@foo and contains(@foo, 'bar')]"],
+ ['e[foo!="bar"]', "e[not(@foo) or @foo != 'bar']"],
+ ['e[foo!="bar"][foo!="baz"]', "e[(not(@foo) or @foo != 'bar') and (not(@foo) or @foo != 'baz')]"],
+ ['e[hreflang|="en"]', "e[@hreflang and (@hreflang = 'en' or starts-with(@hreflang, 'en-'))]"],
+ ['e:nth-child(1)', "*/*[(name() = 'e') and (position() = 1)]"],
+ ['e:nth-last-child(1)', "*/*[(name() = 'e') and (position() = last() - 0)]"],
+ ['e:nth-last-child(2n+2)', "*/*[(name() = 'e') and (last() - position() - 1 >= 0 and (last() - position() - 1) mod 2 = 0)]"],
+ ['e:nth-of-type(1)', '*/e[position() = 1]'],
+ ['e:nth-last-of-type(1)', '*/e[position() = last() - 0]'],
+ ['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 ')]"],
+ ['e:first-child', "*/*[(name() = 'e') and (position() = 1)]"],
+ ['e:last-child', "*/*[(name() = 'e') and (position() = last())]"],
+ ['e:first-of-type', '*/e[position() = 1]'],
+ ['e:last-of-type', '*/e[position() = last()]'],
+ ['e:only-child', "*/*[(name() = 'e') and (last() = 1)]"],
+ ['e:only-of-type', 'e[last() = 1]'],
+ ['e:empty', 'e[not(*) and not(string-length())]'],
+ ['e:EmPTY', 'e[not(*) and not(string-length())]'],
+ ['e:root', 'e[not(parent::*)]'],
+ ['e:hover', 'e[0]'],
+ ['e:contains("foo")', "e[contains(string(.), 'foo')]"],
+ ['e:ConTains(foo)', "e[contains(string(.), 'foo')]"],
+ ['e.warning', "e[@class and contains(concat(' ', normalize-space(@class), ' '), ' warning ')]"],
+ ['e#myid', "e[@id = 'myid']"],
+ ['e:not(:nth-child(odd))', 'e[not(position() - 1 >= 0 and (position() - 1) mod 2 = 0)]'],
+ ['e:nOT(*)', 'e[0]'],
+ ['e f', 'e/descendant-or-self::*/f'],
+ ['e > f', 'e/f'],
+ ['e + f', "e/following-sibling::*[(name() = 'f') and (position() = 1)]"],
+ ['e ~ f', 'e/following-sibling::f'],
+ ['div#container p', "div[@id = 'container']/descendant-or-self::*/p"],
+ ];
+ }
+
+ public function getXmlLangTestData()
+ {
+ return [
+ [':lang("EN")', ['first', 'second', 'third', 'fourth']],
+ [':lang("en-us")', ['second', 'fourth']],
+ [':lang(en-nz)', ['third']],
+ [':lang(fr)', ['fifth']],
+ [':lang(ru)', ['sixth']],
+ [":lang('ZH')", ['eighth']],
+ [':lang(de) :lang(zh)', ['eighth']],
+ [':lang(en), :lang(zh)', ['first', 'second', 'third', 'fourth', 'eighth']],
+ [':lang(es)', []],
+ ];
+ }
+
+ public function getHtmlIdsTestData()
+ {
+ return [
+ ['div', ['outer-div', 'li-div', 'foobar-div']],
+ ['DIV', ['outer-div', 'li-div', 'foobar-div']], // case-insensitive in HTML
+ ['div div', ['li-div']],
+ ['div, div div', ['outer-div', 'li-div', 'foobar-div']],
+ ['a[name]', ['name-anchor']],
+ ['a[NAme]', ['name-anchor']], // case-insensitive in HTML:
+ ['a[rel]', ['tag-anchor', 'nofollow-anchor']],
+ ['a[rel="tag"]', ['tag-anchor']],
+ ['a[href*="localhost"]', ['tag-anchor']],
+ ['a[href*=""]', []],
+ ['a[href^="http"]', ['tag-anchor', 'nofollow-anchor']],
+ ['a[href^="http:"]', ['tag-anchor']],
+ ['a[href^=""]', []],
+ ['a[href$="org"]', ['nofollow-anchor']],
+ ['a[href$=""]', []],
+ ['div[foobar~="bc"]', ['foobar-div']],
+ ['div[foobar~="cde"]', ['foobar-div']],
+ ['[foobar~="ab bc"]', ['foobar-div']],
+ ['[foobar~=""]', []],
+ ['[foobar~=" \t"]', []],
+ ['div[foobar~="cd"]', []],
+ ['*[lang|="En"]', ['second-li']],
+ ['[lang|="En-us"]', ['second-li']],
+ // Attribute values are case sensitive
+ ['*[lang|="en"]', []],
+ ['[lang|="en-US"]', []],
+ ['*[lang|="e"]', []],
+ // ... :lang() is not.
+ [':lang("EN")', ['second-li', 'li-div']],
+ ['*:lang(en-US)', ['second-li', 'li-div']],
+ [':lang("e")', []],
+ ['li:nth-child(3)', ['third-li']],
+ ['li:nth-child(10)', []],
+ ['li:nth-child(2n)', ['second-li', 'fourth-li', 'sixth-li']],
+ ['li:nth-child(even)', ['second-li', 'fourth-li', 'sixth-li']],
+ ['li:nth-child(2n+0)', ['second-li', 'fourth-li', 'sixth-li']],
+ ['li:nth-child(+2n+1)', ['first-li', 'third-li', 'fifth-li', 'seventh-li']],
+ ['li:nth-child(odd)', ['first-li', 'third-li', 'fifth-li', 'seventh-li']],
+ ['li:nth-child(2n+4)', ['fourth-li', 'sixth-li']],
+ ['li:nth-child(3n+1)', ['first-li', 'fourth-li', 'seventh-li']],
+ ['li:nth-child(n)', ['first-li', 'second-li', 'third-li', 'fourth-li', 'fifth-li', 'sixth-li', 'seventh-li']],
+ ['li:nth-child(n-1)', ['first-li', 'second-li', 'third-li', 'fourth-li', 'fifth-li', 'sixth-li', 'seventh-li']],
+ ['li:nth-child(n+1)', ['first-li', 'second-li', 'third-li', 'fourth-li', 'fifth-li', 'sixth-li', 'seventh-li']],
+ ['li:nth-child(n+3)', ['third-li', 'fourth-li', 'fifth-li', 'sixth-li', 'seventh-li']],
+ ['li:nth-child(-n)', []],
+ ['li:nth-child(-n-1)', []],
+ ['li:nth-child(-n+1)', ['first-li']],
+ ['li:nth-child(-n+3)', ['first-li', 'second-li', 'third-li']],
+ ['li:nth-last-child(0)', []],
+ ['li:nth-last-child(2n)', ['second-li', 'fourth-li', 'sixth-li']],
+ ['li:nth-last-child(even)', ['second-li', 'fourth-li', 'sixth-li']],
+ ['li:nth-last-child(2n+2)', ['second-li', 'fourth-li', 'sixth-li']],
+ ['li:nth-last-child(n)', ['first-li', 'second-li', 'third-li', 'fourth-li', 'fifth-li', 'sixth-li', 'seventh-li']],
+ ['li:nth-last-child(n-1)', ['first-li', 'second-li', 'third-li', 'fourth-li', 'fifth-li', 'sixth-li', 'seventh-li']],
+ ['li:nth-last-child(n-3)', ['first-li', 'second-li', 'third-li', 'fourth-li', 'fifth-li', 'sixth-li', 'seventh-li']],
+ ['li:nth-last-child(n+1)', ['first-li', 'second-li', 'third-li', 'fourth-li', 'fifth-li', 'sixth-li', 'seventh-li']],
+ ['li:nth-last-child(n+3)', ['first-li', 'second-li', 'third-li', 'fourth-li', 'fifth-li']],
+ ['li:nth-last-child(-n)', []],
+ ['li:nth-last-child(-n-1)', []],
+ ['li:nth-last-child(-n+1)', ['seventh-li']],
+ ['li:nth-last-child(-n+3)', ['fifth-li', 'sixth-li', 'seventh-li']],
+ ['ol:first-of-type', ['first-ol']],
+ ['ol:nth-child(1)', ['first-ol']],
+ ['ol:nth-of-type(2)', ['second-ol']],
+ ['ol:nth-last-of-type(1)', ['second-ol']],
+ ['span:only-child', ['foobar-span']],
+ ['li div:only-child', ['li-div']],
+ ['div *:only-child', ['li-div', 'foobar-span']],
+ ['p:only-of-type', ['paragraph']],
+ ['a:empty', ['name-anchor']],
+ ['a:EMpty', ['name-anchor']],
+ ['li:empty', ['third-li', 'fourth-li', 'fifth-li', 'sixth-li']],
+ [':root', ['html']],
+ ['html:root', ['html']],
+ ['li:root', []],
+ ['* :root', []],
+ ['*:contains("link")', ['html', 'outer-div', 'tag-anchor', 'nofollow-anchor']],
+ [':CONtains("link")', ['html', 'outer-div', 'tag-anchor', 'nofollow-anchor']],
+ ['*:contains("LInk")', []], // case sensitive
+ ['*:contains("e")', ['html', 'nil', 'outer-div', 'first-ol', 'first-li', 'paragraph', 'p-em']],
+ ['*:contains("E")', []], // case-sensitive
+ ['.a', ['first-ol']],
+ ['.b', ['first-ol']],
+ ['*.a', ['first-ol']],
+ ['ol.a', ['first-ol']],
+ ['.c', ['first-ol', 'third-li', 'fourth-li']],
+ ['*.c', ['first-ol', 'third-li', 'fourth-li']],
+ ['ol *.c', ['third-li', 'fourth-li']],
+ ['ol li.c', ['third-li', 'fourth-li']],
+ ['li ~ li.c', ['third-li', 'fourth-li']],
+ ['ol > li.c', ['third-li', 'fourth-li']],
+ ['#first-li', ['first-li']],
+ ['li#first-li', ['first-li']],
+ ['*#first-li', ['first-li']],
+ ['li div', ['li-div']],
+ ['li > div', ['li-div']],
+ ['div div', ['li-div']],
+ ['div > div', []],
+ ['div>.c', ['first-ol']],
+ ['div > .c', ['first-ol']],
+ ['div + div', ['foobar-div']],
+ ['a ~ a', ['tag-anchor', 'nofollow-anchor']],
+ ['a[rel="tag"] ~ a', ['nofollow-anchor']],
+ ['ol#first-ol li:last-child', ['seventh-li']],
+ ['ol#first-ol *:last-child', ['li-div', 'seventh-li']],
+ ['#outer-div:first-child', ['outer-div']],
+ ['#outer-div :first-child', ['name-anchor', 'first-li', 'li-div', 'p-b', 'checkbox-fieldset-disabled', 'area-href']],
+ ['a[href]', ['tag-anchor', 'nofollow-anchor']],
+ [':not(*)', []],
+ ['a:not([href])', ['name-anchor']],
+ ['ol :Not(li[class])', ['first-li', 'second-li', 'li-div', 'fifth-li', 'sixth-li', 'seventh-li']],
+ // HTML-specific
+ [':link', ['link-href', 'tag-anchor', 'nofollow-anchor', 'area-href']],
+ [':visited', []],
+ [':enabled', ['link-href', 'tag-anchor', 'nofollow-anchor', 'checkbox-unchecked', 'text-checked', 'checkbox-checked', 'area-href']],
+ [':disabled', ['checkbox-disabled', 'checkbox-disabled-checked', 'fieldset', 'checkbox-fieldset-disabled']],
+ [':checked', ['checkbox-checked', 'checkbox-disabled-checked']],
+ ];
+ }
+
+ public function getHtmlShakespearTestData()
+ {
+ return [
+ ['*', 246],
+ ['div:contains(CELIA)', 26],
+ ['div:only-child', 22], // ?
+ ['div:nth-child(even)', 106],
+ ['div:nth-child(2n)', 106],
+ ['div:nth-child(odd)', 137],
+ ['div:nth-child(2n+1)', 137],
+ ['div:nth-child(n)', 243],
+ ['div:last-child', 53],
+ ['div:first-child', 51],
+ ['div > div', 242],
+ ['div + div', 190],
+ ['div ~ div', 190],
+ ['body', 1],
+ ['body div', 243],
+ ['div', 243],
+ ['div div', 242],
+ ['div div div', 241],
+ ['div, div, div', 243],
+ ['div, a, span', 243],
+ ['.dialog', 51],
+ ['div.dialog', 51],
+ ['div .dialog', 51],
+ ['div.character, div.dialog', 99],
+ ['div.direction.dialog', 0],
+ ['div.dialog.direction', 0],
+ ['div.dialog.scene', 1],
+ ['div.scene.scene', 1],
+ ['div.scene .scene', 0],
+ ['div.direction .dialog ', 0],
+ ['div .dialog .direction', 4],
+ ['div.dialog .dialog .direction', 4],
+ ['#speech5', 1],
+ ['div#speech5', 1],
+ ['div #speech5', 1],
+ ['div.scene div.dialog', 49],
+ ['div#scene1 div.dialog div', 142],
+ ['#scene1 #speech1', 1],
+ ['div[class]', 103],
+ ['div[class=dialog]', 50],
+ ['div[class^=dia]', 51],
+ ['div[class$=log]', 50],
+ ['div[class*=sce]', 1],
+ ['div[class|=dialog]', 50], // ? Seems right
+ ['div[class!=madeup]', 243], // ? Seems right
+ ['div[class~=dialog]', 51], // ? Seems right
+ ];
+ }
+}
diff --git a/www/wiki/vendor/symfony/css-selector/XPath/Extension/AbstractExtension.php b/www/wiki/vendor/symfony/css-selector/XPath/Extension/AbstractExtension.php
new file mode 100644
index 00000000..1dce1edd
--- /dev/null
+++ b/www/wiki/vendor/symfony/css-selector/XPath/Extension/AbstractExtension.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 abstract extension.
+ *
+ * This component is a port of the Python cssselect library,
+ * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect.
+ *
+ * @author Jean-François Simon <jeanfrancois.simon@sensiolabs.com>
+ *
+ * @internal
+ */
+abstract class AbstractExtension implements ExtensionInterface
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function getNodeTranslators()
+ {
+ return [];
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getCombinationTranslators()
+ {
+ return [];
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getFunctionTranslators()
+ {
+ return [];
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getPseudoClassTranslators()
+ {
+ return [];
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getAttributeMatchingTranslators()
+ {
+ return [];
+ }
+}
diff --git a/www/wiki/vendor/symfony/css-selector/XPath/Extension/AttributeMatchingExtension.php b/www/wiki/vendor/symfony/css-selector/XPath/Extension/AttributeMatchingExtension.php
new file mode 100644
index 00000000..0571b3b7
--- /dev/null
+++ b/www/wiki/vendor/symfony/css-selector/XPath/Extension/AttributeMatchingExtension.php
@@ -0,0 +1,175 @@
+<?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 cssselect library,
+ * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect.
+ *
+ * @author Jean-François Simon <jeanfrancois.simon@sensiolabs.com>
+ *
+ * @internal
+ */
+class AttributeMatchingExtension extends AbstractExtension
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function getAttributeMatchingTranslators()
+ {
+ return [
+ 'exists' => [$this, 'translateExists'],
+ '=' => [$this, 'translateEquals'],
+ '~=' => [$this, 'translateIncludes'],
+ '|=' => [$this, 'translateDashMatch'],
+ '^=' => [$this, 'translatePrefixMatch'],
+ '$=' => [$this, 'translateSuffixMatch'],
+ '*=' => [$this, 'translateSubstringMatch'],
+ '!=' => [$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/www/wiki/vendor/symfony/css-selector/XPath/Extension/CombinationExtension.php b/www/wiki/vendor/symfony/css-selector/XPath/Extension/CombinationExtension.php
new file mode 100644
index 00000000..d962dc5a
--- /dev/null
+++ b/www/wiki/vendor/symfony/css-selector/XPath/Extension/CombinationExtension.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\XPath\Extension;
+
+use Symfony\Component\CssSelector\XPath\XPathExpr;
+
+/**
+ * XPath expression translator combination extension.
+ *
+ * This component is a port of the Python cssselect library,
+ * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect.
+ *
+ * @author Jean-François Simon <jeanfrancois.simon@sensiolabs.com>
+ *
+ * @internal
+ */
+class CombinationExtension extends AbstractExtension
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function getCombinationTranslators()
+ {
+ return [
+ ' ' => [$this, 'translateDescendant'],
+ '>' => [$this, 'translateChild'],
+ '+' => [$this, 'translateDirectAdjacent'],
+ '~' => [$this, 'translateIndirectAdjacent'],
+ ];
+ }
+
+ /**
+ * @return XPathExpr
+ */
+ public function translateDescendant(XPathExpr $xpath, XPathExpr $combinedXpath)
+ {
+ return $xpath->join('/descendant-or-self::*/', $combinedXpath);
+ }
+
+ /**
+ * @return XPathExpr
+ */
+ public function translateChild(XPathExpr $xpath, XPathExpr $combinedXpath)
+ {
+ return $xpath->join('/', $combinedXpath);
+ }
+
+ /**
+ * @return XPathExpr
+ */
+ public function translateDirectAdjacent(XPathExpr $xpath, XPathExpr $combinedXpath)
+ {
+ return $xpath
+ ->join('/following-sibling::', $combinedXpath)
+ ->addNameTest()
+ ->addCondition('position() = 1');
+ }
+
+ /**
+ * @return XPathExpr
+ */
+ public function translateIndirectAdjacent(XPathExpr $xpath, XPathExpr $combinedXpath)
+ {
+ return $xpath->join('/following-sibling::', $combinedXpath);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getName()
+ {
+ return 'combination';
+ }
+}
diff --git a/www/wiki/vendor/symfony/css-selector/XPath/Extension/ExtensionInterface.php b/www/wiki/vendor/symfony/css-selector/XPath/Extension/ExtensionInterface.php
new file mode 100644
index 00000000..36070228
--- /dev/null
+++ b/www/wiki/vendor/symfony/css-selector/XPath/Extension/ExtensionInterface.php
@@ -0,0 +1,69 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\CssSelector\XPath\Extension;
+
+/**
+ * XPath expression translator extension interface.
+ *
+ * This component is a port of the Python cssselect library,
+ * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect.
+ *
+ * @author Jean-François Simon <jeanfrancois.simon@sensiolabs.com>
+ *
+ * @internal
+ */
+interface ExtensionInterface
+{
+ /**
+ * Returns node translators.
+ *
+ * These callables will receive the node as first argument and the translator as second argument.
+ *
+ * @return callable[]
+ */
+ public function getNodeTranslators();
+
+ /**
+ * Returns combination translators.
+ *
+ * @return callable[]
+ */
+ public function getCombinationTranslators();
+
+ /**
+ * Returns function translators.
+ *
+ * @return callable[]
+ */
+ public function getFunctionTranslators();
+
+ /**
+ * Returns pseudo-class translators.
+ *
+ * @return callable[]
+ */
+ public function getPseudoClassTranslators();
+
+ /**
+ * Returns attribute operation translators.
+ *
+ * @return callable[]
+ */
+ public function getAttributeMatchingTranslators();
+
+ /**
+ * Returns extension name.
+ *
+ * @return string
+ */
+ public function getName();
+}
diff --git a/www/wiki/vendor/symfony/css-selector/XPath/Extension/FunctionExtension.php b/www/wiki/vendor/symfony/css-selector/XPath/Extension/FunctionExtension.php
new file mode 100644
index 00000000..a8e0b69f
--- /dev/null
+++ b/www/wiki/vendor/symfony/css-selector/XPath/Extension/FunctionExtension.php
@@ -0,0 +1,190 @@
+<?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 cssselect library,
+ * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect.
+ *
+ * @author Jean-François Simon <jeanfrancois.simon@sensiolabs.com>
+ *
+ * @internal
+ */
+class FunctionExtension extends AbstractExtension
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function getFunctionTranslators()
+ {
+ return [
+ 'nth-child' => [$this, 'translateNthChild'],
+ 'nth-last-child' => [$this, 'translateNthLastChild'],
+ 'nth-of-type' => [$this, 'translateNthOfType'],
+ 'nth-last-of-type' => [$this, 'translateNthLastOfType'],
+ 'contains' => [$this, 'translateContains'],
+ 'lang' => [$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 = [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
+ }
+
+ /**
+ * @return XPathExpr
+ */
+ public function translateNthLastChild(XPathExpr $xpath, FunctionNode $function)
+ {
+ return $this->translateNthChild($xpath, $function, true);
+ }
+
+ /**
+ * @return XPathExpr
+ */
+ public function translateNthOfType(XPathExpr $xpath, FunctionNode $function)
+ {
+ return $this->translateNthChild($xpath, $function, false, false);
+ }
+
+ /**
+ * @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);
+ }
+
+ /**
+ * @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())
+ ));
+ }
+
+ /**
+ * @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/www/wiki/vendor/symfony/css-selector/XPath/Extension/HtmlExtension.php b/www/wiki/vendor/symfony/css-selector/XPath/Extension/HtmlExtension.php
new file mode 100644
index 00000000..99c1166c
--- /dev/null
+++ b/www/wiki/vendor/symfony/css-selector/XPath/Extension/HtmlExtension.php
@@ -0,0 +1,213 @@
+<?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 cssselect library,
+ * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect.
+ *
+ * @author Jean-François Simon <jeanfrancois.simon@sensiolabs.com>
+ *
+ * @internal
+ */
+class HtmlExtension extends AbstractExtension
+{
+ 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 [
+ 'checked' => [$this, 'translateChecked'],
+ 'link' => [$this, 'translateLink'],
+ 'disabled' => [$this, 'translateDisabled'],
+ 'enabled' => [$this, 'translateEnabled'],
+ 'selected' => [$this, 'translateSelected'],
+ 'invalid' => [$this, 'translateInvalid'],
+ 'hover' => [$this, 'translateHover'],
+ 'visited' => [$this, 'translateVisited'],
+ ];
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getFunctionTranslators()
+ {
+ return [
+ 'lang' => [$this, 'translateLang'],
+ ];
+ }
+
+ /**
+ * @return XPathExpr
+ */
+ public function translateChecked(XPathExpr $xpath)
+ {
+ return $xpath->addCondition(
+ '(@checked '
+ ."and (name(.) = 'input' or name(.) = 'command')"
+ ."and (@type = 'checkbox' or @type = 'radio'))"
+ );
+ }
+
+ /**
+ * @return XPathExpr
+ */
+ public function translateLink(XPathExpr $xpath)
+ {
+ return $xpath->addCondition("@href and (name(.) = 'a' or name(.) = 'link' or name(.) = 'area')");
+ }
+
+ /**
+ * @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."
+ }
+
+ /**
+ * @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]'
+ .')'
+ .')'
+ );
+ }
+
+ /**
+ * @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()).'-')
+ ));
+ }
+
+ /**
+ * @return XPathExpr
+ */
+ public function translateSelected(XPathExpr $xpath)
+ {
+ return $xpath->addCondition("(@selected and name(.) = 'option')");
+ }
+
+ /**
+ * @return XPathExpr
+ */
+ public function translateInvalid(XPathExpr $xpath)
+ {
+ return $xpath->addCondition('0');
+ }
+
+ /**
+ * @return XPathExpr
+ */
+ public function translateHover(XPathExpr $xpath)
+ {
+ return $xpath->addCondition('0');
+ }
+
+ /**
+ * @return XPathExpr
+ */
+ public function translateVisited(XPathExpr $xpath)
+ {
+ return $xpath->addCondition('0');
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getName()
+ {
+ return 'html';
+ }
+}
diff --git a/www/wiki/vendor/symfony/css-selector/XPath/Extension/NodeExtension.php b/www/wiki/vendor/symfony/css-selector/XPath/Extension/NodeExtension.php
new file mode 100644
index 00000000..de222af3
--- /dev/null
+++ b/www/wiki/vendor/symfony/css-selector/XPath/Extension/NodeExtension.php
@@ -0,0 +1,242 @@
+<?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 cssselect library,
+ * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect.
+ *
+ * @author Jean-François Simon <jeanfrancois.simon@sensiolabs.com>
+ *
+ * @internal
+ */
+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;
+
+ private $flags;
+
+ /**
+ * @param int $flags
+ */
+ public function __construct($flags = 0)
+ {
+ $this->flags = $flags;
+ }
+
+ /**
+ * @param int $flag
+ * @param bool $on
+ *
+ * @return $this
+ */
+ 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 (bool) ($this->flags & $flag);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getNodeTranslators()
+ {
+ return [
+ 'Selector' => [$this, 'translateSelector'],
+ 'CombinedSelector' => [$this, 'translateCombinedSelector'],
+ 'Negation' => [$this, 'translateNegation'],
+ 'Function' => [$this, 'translateFunction'],
+ 'Pseudo' => [$this, 'translatePseudo'],
+ 'Attribute' => [$this, 'translateAttribute'],
+ 'Class' => [$this, 'translateClass'],
+ 'Hash' => [$this, 'translateHash'],
+ 'Element' => [$this, 'translateElement'],
+ ];
+ }
+
+ /**
+ * @return XPathExpr
+ */
+ public function translateSelector(Node\SelectorNode $node, Translator $translator)
+ {
+ return $translator->nodeToXPath($node->getTree());
+ }
+
+ /**
+ * @return XPathExpr
+ */
+ public function translateCombinedSelector(Node\CombinedSelectorNode $node, Translator $translator)
+ {
+ return $translator->addCombination($node->getCombinator(), $node->getSelector(), $node->getSubSelector());
+ }
+
+ /**
+ * @return XPathExpr
+ */
+ public function translateNegation(Node\NegationNode $node, Translator $translator)
+ {
+ $xpath = $translator->nodeToXPath($node->getSelector());
+ $subXpath = $translator->nodeToXPath($node->getSubSelector());
+ $subXpath->addNameTest();
+
+ if ($subXpath->getCondition()) {
+ return $xpath->addCondition(sprintf('not(%s)', $subXpath->getCondition()));
+ }
+
+ return $xpath->addCondition('0');
+ }
+
+ /**
+ * @return XPathExpr
+ */
+ public function translateFunction(Node\FunctionNode $node, Translator $translator)
+ {
+ $xpath = $translator->nodeToXPath($node->getSelector());
+
+ return $translator->addFunction($xpath, $node);
+ }
+
+ /**
+ * @return XPathExpr
+ */
+ public function translatePseudo(Node\PseudoNode $node, Translator $translator)
+ {
+ $xpath = $translator->nodeToXPath($node->getSelector());
+
+ return $translator->addPseudoClass($xpath, $node->getIdentifier());
+ }
+
+ /**
+ * @return XPathExpr
+ */
+ public function translateAttribute(Node\AttributeNode $node, Translator $translator)
+ {
+ $name = $node->getAttribute();
+ $safe = $this->isSafeName($name);
+
+ if ($this->hasFlag(self::ATTRIBUTE_NAME_IN_LOWER_CASE)) {
+ $name = strtolower($name);
+ }
+
+ if ($node->getNamespace()) {
+ $name = sprintf('%s:%s', $node->getNamespace(), $name);
+ $safe = $safe && $this->isSafeName($node->getNamespace());
+ }
+
+ $attribute = $safe ? '@'.$name : sprintf('attribute::*[name() = %s]', Translator::getXpathLiteral($name));
+ $value = $node->getValue();
+ $xpath = $translator->nodeToXPath($node->getSelector());
+
+ if ($this->hasFlag(self::ATTRIBUTE_VALUE_IN_LOWER_CASE)) {
+ $value = strtolower($value);
+ }
+
+ return $translator->addAttributeMatching($xpath, $node->getOperator(), $attribute, $value);
+ }
+
+ /**
+ * @return XPathExpr
+ */
+ public function translateClass(Node\ClassNode $node, Translator $translator)
+ {
+ $xpath = $translator->nodeToXPath($node->getSelector());
+
+ return $translator->addAttributeMatching($xpath, '~=', '@class', $node->getName());
+ }
+
+ /**
+ * @return XPathExpr
+ */
+ public function translateHash(Node\HashNode $node, Translator $translator)
+ {
+ $xpath = $translator->nodeToXPath($node->getSelector());
+
+ return $translator->addAttributeMatching($xpath, '=', '@id', $node->getId());
+ }
+
+ /**
+ * @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/www/wiki/vendor/symfony/css-selector/XPath/Extension/PseudoClassExtension.php b/www/wiki/vendor/symfony/css-selector/XPath/Extension/PseudoClassExtension.php
new file mode 100644
index 00000000..27fe47f9
--- /dev/null
+++ b/www/wiki/vendor/symfony/css-selector/XPath/Extension/PseudoClassExtension.php
@@ -0,0 +1,148 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\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 cssselect library,
+ * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect.
+ *
+ * @author Jean-François Simon <jeanfrancois.simon@sensiolabs.com>
+ *
+ * @internal
+ */
+class PseudoClassExtension extends AbstractExtension
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function getPseudoClassTranslators()
+ {
+ return [
+ 'root' => [$this, 'translateRoot'],
+ 'first-child' => [$this, 'translateFirstChild'],
+ 'last-child' => [$this, 'translateLastChild'],
+ 'first-of-type' => [$this, 'translateFirstOfType'],
+ 'last-of-type' => [$this, 'translateLastOfType'],
+ 'only-child' => [$this, 'translateOnlyChild'],
+ 'only-of-type' => [$this, 'translateOnlyOfType'],
+ 'empty' => [$this, 'translateEmpty'],
+ ];
+ }
+
+ /**
+ * @return XPathExpr
+ */
+ public function translateRoot(XPathExpr $xpath)
+ {
+ return $xpath->addCondition('not(parent::*)');
+ }
+
+ /**
+ * @return XPathExpr
+ */
+ public function translateFirstChild(XPathExpr $xpath)
+ {
+ return $xpath
+ ->addStarPrefix()
+ ->addNameTest()
+ ->addCondition('position() = 1');
+ }
+
+ /**
+ * @return XPathExpr
+ */
+ public function translateLastChild(XPathExpr $xpath)
+ {
+ return $xpath
+ ->addStarPrefix()
+ ->addNameTest()
+ ->addCondition('position() = last()');
+ }
+
+ /**
+ * @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');
+ }
+
+ /**
+ * @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()');
+ }
+
+ /**
+ * @return XPathExpr
+ */
+ public function translateOnlyChild(XPathExpr $xpath)
+ {
+ return $xpath
+ ->addStarPrefix()
+ ->addNameTest()
+ ->addCondition('last() = 1');
+ }
+
+ /**
+ * @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');
+ }
+
+ /**
+ * @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/www/wiki/vendor/symfony/css-selector/XPath/Translator.php b/www/wiki/vendor/symfony/css-selector/XPath/Translator.php
new file mode 100644
index 00000000..d0781267
--- /dev/null
+++ b/www/wiki/vendor/symfony/css-selector/XPath/Translator.php
@@ -0,0 +1,267 @@
+<?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 cssselect library,
+ * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect.
+ *
+ * @author Jean-François Simon <jeanfrancois.simon@sensiolabs.com>
+ *
+ * @internal
+ */
+class Translator implements TranslatorInterface
+{
+ private $mainParser;
+
+ /**
+ * @var ParserInterface[]
+ */
+ private $shortcutParsers = [];
+
+ /**
+ * @var Extension\ExtensionInterface[]
+ */
+ private $extensions = [];
+
+ private $nodeTranslators = [];
+ private $combinationTranslators = [];
+ private $functionTranslators = [];
+ private $pseudoClassTranslators = [];
+ private $attributeMatchingTranslators = [];
+
+ public function __construct(ParserInterface $parser = null)
+ {
+ $this->mainParser = $parser ?: new Parser();
+
+ $this
+ ->registerExtension(new Extension\NodeExtension())
+ ->registerExtension(new Extension\CombinationExtension())
+ ->registerExtension(new Extension\FunctionExtension())
+ ->registerExtension(new Extension\PseudoClassExtension())
+ ->registerExtension(new Extension\AttributeMatchingExtension())
+ ;
+ }
+
+ /**
+ * @param string $element
+ *
+ * @return string
+ */
+ public static function getXpathLiteral($element)
+ {
+ if (false === strpos($element, "'")) {
+ return "'".$element."'";
+ }
+
+ if (false === strpos($element, '"')) {
+ return '"'.$element.'"';
+ }
+
+ $string = $element;
+ $parts = [];
+ while (true) {
+ if (false !== $pos = strpos($string, "'")) {
+ $parts[] = sprintf("'%s'", substr($string, 0, $pos));
+ $parts[] = "\"'\"";
+ $string = substr($string, $pos + 1);
+ } else {
+ $parts[] = "'$string'";
+ break;
+ }
+ }
+
+ return sprintf('concat(%s)', implode(', ', $parts));
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function cssToXPath($cssExpr, $prefix = 'descendant-or-self::')
+ {
+ $selectors = $this->parseSelectors($cssExpr);
+
+ /** @var SelectorNode $selector */
+ foreach ($selectors as $index => $selector) {
+ if (null !== $selector->getPseudoElement()) {
+ throw new ExpressionErrorException('Pseudo-elements are not supported.');
+ }
+
+ $selectors[$index] = $this->selectorToXPath($selector, $prefix);
+ }
+
+ return implode(' | ', $selectors);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function selectorToXPath(SelectorNode $selector, $prefix = 'descendant-or-self::')
+ {
+ return ($prefix ?: '').$this->nodeToXPath($selector);
+ }
+
+ /**
+ * Registers an extension.
+ *
+ * @return $this
+ */
+ 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.
+ *
+ * @return $this
+ */
+ public function registerParserShortcut(ParserInterface $shortcut)
+ {
+ $this->shortcutParsers[] = $shortcut;
+
+ return $this;
+ }
+
+ /**
+ * @return XPathExpr
+ *
+ * @throws ExpressionErrorException
+ */
+ public function nodeToXPath(NodeInterface $node)
+ {
+ if (!isset($this->nodeTranslators[$node->getNodeName()])) {
+ throw new ExpressionErrorException(sprintf('Node "%s" not supported.', $node->getNodeName()));
+ }
+
+ return \call_user_func($this->nodeTranslators[$node->getNodeName()], $node, $this);
+ }
+
+ /**
+ * @param string $combiner
+ * @param NodeInterface $xpath
+ * @param NodeInterface $combinedXpath
+ *
+ * @return XPathExpr
+ *
+ * @throws ExpressionErrorException
+ */
+ public function addCombination($combiner, NodeInterface $xpath, NodeInterface $combinedXpath)
+ {
+ if (!isset($this->combinationTranslators[$combiner])) {
+ throw new ExpressionErrorException(sprintf('Combiner "%s" not supported.', $combiner));
+ }
+
+ return \call_user_func($this->combinationTranslators[$combiner], $this->nodeToXPath($xpath), $this->nodeToXPath($combinedXpath));
+ }
+
+ /**
+ * @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
+ *
+ * @return XPathExpr
+ *
+ * @throws ExpressionErrorException
+ */
+ 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/www/wiki/vendor/symfony/css-selector/XPath/TranslatorInterface.php b/www/wiki/vendor/symfony/css-selector/XPath/TranslatorInterface.php
new file mode 100644
index 00000000..0b5de83d
--- /dev/null
+++ b/www/wiki/vendor/symfony/css-selector/XPath/TranslatorInterface.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\XPath;
+
+use Symfony\Component\CssSelector\Node\SelectorNode;
+
+/**
+ * XPath expression translator interface.
+ *
+ * This component is a port of the Python cssselect library,
+ * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect.
+ *
+ * @author Jean-François Simon <jeanfrancois.simon@sensiolabs.com>
+ *
+ * @internal
+ */
+interface TranslatorInterface
+{
+ /**
+ * Translates a CSS selector to an XPath expression.
+ *
+ * @param string $cssExpr
+ * @param string $prefix
+ *
+ * @return string
+ */
+ public function cssToXPath($cssExpr, $prefix = 'descendant-or-self::');
+
+ /**
+ * Translates a parsed selector node to an XPath expression.
+ *
+ * @param SelectorNode $selector
+ * @param string $prefix
+ *
+ * @return string
+ */
+ public function selectorToXPath(SelectorNode $selector, $prefix = 'descendant-or-self::');
+}
diff --git a/www/wiki/vendor/symfony/css-selector/XPath/XPathExpr.php b/www/wiki/vendor/symfony/css-selector/XPath/XPathExpr.php
new file mode 100644
index 00000000..a1e244c9
--- /dev/null
+++ b/www/wiki/vendor/symfony/css-selector/XPath/XPathExpr.php
@@ -0,0 +1,129 @@
+<?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 cssselect library,
+ * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect.
+ *
+ * @author Jean-François Simon <jeanfrancois.simon@sensiolabs.com>
+ *
+ * @internal
+ */
+class XPathExpr
+{
+ private $path;
+ private $element;
+ 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;
+ }
+
+ /**
+ * @return $this
+ */
+ 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 $this
+ */
+ public function addNameTest()
+ {
+ if ('*' !== $this->element) {
+ $this->addCondition('name() = '.Translator::getXpathLiteral($this->element));
+ $this->element = '*';
+ }
+
+ return $this;
+ }
+
+ /**
+ * @return $this
+ */
+ public function addStarPrefix()
+ {
+ $this->path .= '*/';
+
+ return $this;
+ }
+
+ /**
+ * Joins another XPathExpr with a combiner.
+ *
+ * @param string $combiner
+ * @param XPathExpr $expr
+ *
+ * @return $this
+ */
+ public function join($combiner, self $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/www/wiki/vendor/symfony/css-selector/composer.json b/www/wiki/vendor/symfony/css-selector/composer.json
new file mode 100644
index 00000000..56ab35b8
--- /dev/null
+++ b/www/wiki/vendor/symfony/css-selector/composer.json
@@ -0,0 +1,37 @@
+{
+ "name": "symfony/css-selector",
+ "type": "library",
+ "description": "Symfony CssSelector Component",
+ "keywords": [],
+ "homepage": "https://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": "https://symfony.com/contributors"
+ }
+ ],
+ "require": {
+ "php": "^5.5.9|>=7.0.8"
+ },
+ "autoload": {
+ "psr-4": { "Symfony\\Component\\CssSelector\\": "" },
+ "exclude-from-classmap": [
+ "/Tests/"
+ ]
+ },
+ "minimum-stability": "dev",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "3.4-dev"
+ }
+ }
+}
diff --git a/www/wiki/vendor/symfony/css-selector/phpunit.xml.dist b/www/wiki/vendor/symfony/css-selector/phpunit.xml.dist
new file mode 100644
index 00000000..a8e537ef
--- /dev/null
+++ b/www/wiki/vendor/symfony/css-selector/phpunit.xml.dist
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:noNamespaceSchemaLocation="http://schema.phpunit.de/5.2/phpunit.xsd"
+ backupGlobals="false"
+ colors="true"
+ bootstrap="vendor/autoload.php"
+ failOnRisky="true"
+ failOnWarning="true"
+>
+ <php>
+ <ini name="error_reporting" value="-1" />
+ </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>